[
  {
    "path": ".gitattributes",
    "content": "*.java          text\n*.md            text\n*.yml           text\n*.xml           text\n*.gradle        text\n*.properties    text\nmvnw            text eol=lf\n*.sh            text eol=lf\n*.bat           text eol=crlf\n*.cmd           text eol=crlf\n*.jar           binary\n\nsrc/test/resources/samples/*.txt text eol=lf\nsrc/test/resources/samples/*.out text eol=lf\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "**NOTE:** The challenge has been closed for new submissions. No new pull requests for adding submissions are accepted at this time.\nThe final leaderboard has been published on Feb 4.\n\n#### Check List:\n\n- [ ] You have run `./mvnw verify` and the project builds successfully\n- [ ] Tests pass (`./test.sh <username>` shows no differences between expected and actual outputs)\n- [ ] All formatting changes by the build are committed\n- [ ] Your launch script is named `calculate_average_<username>.sh` (make sure to match casing of your GH user name) and is executable\n- [ ] Output matches that of `calculate_average_baseline.sh`\n- [ ] For new entries, or after substantial changes: When implementing custom hash structures, please point to where you deal with hash collisions (line number)\n\n* Execution time:\n* Execution time of reference implementation:\n\n<!--\nThanks for your submission. Please go through the checklist above before submitting your pull request.\nUse [x] to mark that the item has been completed.\n\nDue to the large number of entries created so far,\nplease submit only entries that are you are expecting to run in 10 seconds or less on the evaluation machine.\n\nPlease make sure that you have followed the defined rules (https://github.com/gunnarmorling/1brc?tab=readme-ov-file#rules-and-limits).\n-->\n"
  },
  {
    "path": ".github/workflows/maven.yml",
    "content": "#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nname: Build\n\non:\n  # Enable manual re-run\n  workflow_dispatch: { }\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - name: 'Check out repository'\n        uses: actions/checkout@v2\n        with:\n          submodules: 'true'\n\n      - name: Cache SDKMan\n        id: cache-sdkman\n        uses: actions/cache@v4\n        with:\n          path: ~/.sdkman\n          key: ${{ runner.os }}-sdkman\n\n      - name: 'Cache Maven packages'\n        uses: actions/cache@v3\n        with:\n          path: ~/.m2\n          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}\n          restore-keys: ${{ runner.os }}-m2\n\n      - name: 'Setup SDKMAN'\n        uses: sdkman/sdkman-action@b1f9b696c79148b66d3d3a06f7ea801820318d0f\n        id: sdkman\n\n      - name: 'Build project'\n        shell: bash\n        run: |\n          source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n          if [ -f ${{ format('src/main/java-22/dev/morling/onebrc/CalculateAverage_{0}.java', github.event.pull_request.user.login || '') }} ]; then\n            sdk install java 22.ea.32-open || true\n            sdk use java 22.ea.32-open\n          fi\n          ./mvnw --version\n          ./mvnw -B clean verify -Pci\n\n      - name: 'Test submission'\n        shell: bash\n        run: |\n          ./test_ci.sh ${{ github.event.pull_request.user.login }}\n        if: github.event_name == 'pull_request'\n"
  },
  {
    "path": ".gitignore",
    "content": "#Maven\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\nrelease.properties\n\n# Eclipse\n.project\n.classpath\n.settings/\nbin/\n\n# IntelliJ\n.idea\n*.ipr\n*.iml\n*.iws\n\n# NetBeans\nnb-configuration.xml\nnbactions.xml\n\n# Visual Studio Code\n.vscode\n.factorypath\n\n# OSX\n.DS_Store\n\n# Vim\n*.swp\n*.swo\n\n# patch\n*.orig\n*.rej\n\n# Local environment\n.env\n\n#JReleaser\nout/\n\n# 1BRC\n/measurements*.txt\n/*.out\nout_expected.txt\n/*-timing.json\n"
  },
  {
    "path": ".mvn/wrapper/maven-wrapper.properties",
    "content": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#   http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\ndistributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip\nwrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\n"
  },
  {
    "path": ".sdkmanrc",
    "content": "# Enable auto-env through the sdkman_auto_env config\n# Add key=value pairs of SDKs to use below\njava=21.0.1-open\n"
  },
  {
    "path": "ENVIRONMENT.md",
    "content": "# Environment\nThis file just contains some intel about the environment in use and what has been done to get it into that state.\n\n## Machine Type\n\n* Hetzner AX161, Dedicated Hosted Hardware\n* CPU: AMD EPYC 7502P 32 cores / 64 threads @ 2.5 GHz\n* Memory: 128 GB ECC DDR4 RAM\n* 2x SAMSUNG MZQL2960HCJR-00A07, 1 TB, Software RAID-1\n* CentOS 9, Linux 5.14.0-378.el9.x86_64\n\n## Configuration\n\n* SMT off\n* Turbo Boost Off\n* Filesystem EXT4 \n\n## Details\n\n### CPU\n``` \n$ cat /proc/cpuinfo \nprocessor\t: 0\nvendor_id\t: AuthenticAMD\ncpu family\t: 23\nmodel\t\t: 49\nmodel name\t: AMD EPYC 7502P 32-Core Processor\nstepping\t: 0\nmicrocode\t: 0x8301055\ncpu MHz\t\t: 2500.000\ncache size\t: 512 KB\nphysical id\t: 0\nsiblings\t: 32\ncore id\t\t: 0\ncpu cores\t: 32\napicid\t\t: 0\ninitial apicid\t: 0\nfpu\t\t: yes\nfpu_exception\t: yes\ncpuid level\t: 16\nwp\t\t: yes\nflags\t\t: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid aperfmperf rapl pni pclmulqdq monitor ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw ibs skinit wdt tce topoext perfctr_core perfctr_nb bpext perfctr_llc mwaitx cpb cat_l3 cdp_l3 hw_pstate ssbd mba ibrs ibpb stibp vmmcall fsgsbase bmi1 avx2 smep bmi2 cqm rdt_a rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 xsaves cqm_llc cqm_occup_llc cqm_mbm_total cqm_mbm_local clzero irperf xsaveerptr rdpru wbnoinvd arat npt lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif v_spec_ctrl umip rdpid overflow_recov succor smca sme sev sev_es\nbugs\t\t: sysret_ss_attrs spectre_v1 spectre_v2 spec_store_bypass retbleed smt_rsb\nbogomips\t: 4990.70\nTLB size\t: 3072 4K pages\nclflush size\t: 64\ncache_alignment\t: 64\naddress sizes\t: 43 bits physical, 48 bits virtual\npower management: ts ttp tm hwpstate cpb eff_freq_ro [13] [14]\n... more for all other cores\n```\n\n## Setup\n\n### Turn SMT off\nDisable during boot via boot-param, able to switch it on later again, if needed.\n\nAdd `nosmt` to grub boot config in `/etc/default/grub` \n\n```\n# Added nosmt to command line\nGRUB_CMDLINE_LINUX=\"biosdevname=0 crashkernel=auto rd.auto=1 consoleblank=0 nosmt\"\n```\n\nUpdate boot config:\n``` \nsudo grub2-mkconfig -o /boot/grub2/grub.cfg\n```\n\n### Turbo Off\nUsing the legacy `/etc/rc.local` concept to change things during boot:\n\n```\n# Turn SMT off via software as well, already got nosmt in grub\necho off >  /sys/devices/system/cpu/smt/control\n\n# Turn off turbo boost\necho 0 |tee /sys/devices/system/cpu/cpufreq/boost\n```\n### Reduce Swapping\nReduce from default 60 to 10% memory pressure by adding `vm.swappiness = 10` to `/etc/sysctl.conf`.\n\n## Verify\nCheck after boot if all settings have been applied. Can also be used to control these during runtime.\n\n* SMT off: `cat /sys/devices/system/cpu/smt/active` must be 0\n* SWAP: `cat /proc/sys/vm/swappiness` must be 10\n* Turbo off: `cat /sys/devices/system/cpu/cpufreq/boost` must be 0\n\n\n\n\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License."
  },
  {
    "path": "README.md",
    "content": "# 1️⃣🐝🏎️ The One Billion Row Challenge\n\n_Status Feb 4: The final leaderboards [have been published](https://www.morling.dev/blog/1brc-results-are-in/). Congrats to all the winners, and a big thank you to everyone participating in this challenge as well as to everyone helping to organize it!_\n\n_Status Feb 3: All entries have been evaluated and I am in the process of finalizing the leaderboards._\n\n_Status Feb 1: The challenge has been closed for new submissions. No new pull requests for adding submissions are accepted at this time.\nPending PRs will be evaluated over the next few days._\n\n_Status Jan 31: The challenge will close today at midnight UTC._\n\n_Status Jan 12: As there has been such a large number of entries to this challenge so far (100+), and this is becoming hard to manage, please only create new submissions if you expect them to run in 10 seconds or less on the evaluation machine._\n\n_Status Jan 1: This challenge is [open for submissions](https://www.morling.dev/blog/one-billion-row-challenge/)!_\n\n> **Sponsorship**\n>\n> A big thank you to my employer [Decodable](https://www.decodable.co/) for funding the evaluation environment and supporting this challenge!\n\nThe One Billion Row Challenge (1BRC) is a fun exploration of how far modern Java can be pushed for aggregating one billion rows from a text file.\nGrab all your (virtual) threads, reach out to SIMD, optimize your GC, or pull any other trick, and create the fastest implementation for solving this task!\n\n<img src=\"1brc.png\" alt=\"1BRC\" style=\"display: block; margin-left: auto; margin-right: auto; margin-bottom:1em; width: 50%;\">\n\nThe text file contains temperature values for a range of weather stations.\nEach row is one measurement in the format `<string: station name>;<double: measurement>`, with the measurement value having exactly one fractional digit.\nThe following shows ten rows as an example:\n\n```\nHamburg;12.0\nBulawayo;8.9\nPalembang;38.8\nSt. John's;15.2\nCracow;12.6\nBridgetown;26.9\nIstanbul;6.2\nRoseau;34.4\nConakry;31.2\nIstanbul;23.0\n```\n\nThe task is to write a Java program which reads the file, calculates the min, mean, and max temperature value per weather station, and emits the results on stdout like this\n(i.e. sorted alphabetically by station name, and the result values per station in the format `<min>/<mean>/<max>`, rounded to one fractional digit):\n\n```\n{Abha=-23.0/18.0/59.2, Abidjan=-16.2/26.0/67.3, Abéché=-10.0/29.4/69.0, Accra=-10.1/26.4/66.4, Addis Ababa=-23.7/16.0/67.0, Adelaide=-27.8/17.3/58.5, ...}\n```\n\nSubmit your implementation by Jan 31 2024 and become part of the leaderboard!\n\n## Results\n\nThese are the results from running all entries into the challenge on eight cores of a [Hetzner AX161](https://www.hetzner.com/dedicated-rootserver/ax161) dedicated server (32 core AMD EPYC™ 7502P (Zen2), 128 GB RAM).\n\n| # | Result (m:s.ms) | Implementation     | JDK | Submitter     | Notes     | Certificates |\n|---|-----------------|--------------------|-----|---------------|-----------|--------------|\n| 1 | 00:01.535 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java)| 21.0.2-graal | [Thomas Wuerthinger](https://github.com/thomaswue), [Quan Anh Mai](https://github.com/merykitty), [Alfonso² Peterssen](https://github.com/mukel) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/thomaswue_merykitty_mukel.pdf) |\n| 2 | 00:01.587 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_artsiomkorzun.java)| 21.0.2-graal | [Artsiom Korzun](https://github.com/artsiomkorzun) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/artsiomkorzun.pdf) |\n| 3 | 00:01.608 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jerrinot.java)| 21.0.2-graal | [Jaromir Hamala](https://github.com/jerrinot) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jerrinot.pdf) |\n|   | 00:01.880 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_serkan_ozal.java)| 21.0.1-open | [Serkan ÖZAL](https://github.com/serkan-ozal) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/serkan_ozal.pdf) |\n|   | 00:01.921 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_abeobk.java)| 21.0.2-graal | [Van Phu DO](https://github.com/abeobk) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/abeobk.pdf) |\n|   | 00:02.018 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_stephenvonworley.java)| 21.0.2-graal | [Stephen Von Worley](https://github.com/stephenvonworley) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/stephenvonworley.pdf) |\n|   | 00:02.157 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java)| 21.0.2-graal | [Roy van Rijn](https://github.com/royvanrijn) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/royvanrijn.pdf) |\n|   | 00:02.319 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yavuztas.java)| 21.0.2-graal | [Yavuz Tas](https://github.com/yavuztas) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/yavuztas.pdf) |\n|   | 00:02.332 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_mtopolnik.java)| 21.0.2-graal | [Marko Topolnik](https://github.com/mtopolnik) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/mtopolnik.pdf) |\n|   | 00:02.367 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykittyunsafe.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykitty) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/merykittyunsafe.pdf) |\n|   | 00:02.507 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonixunsafe.java)| 21.0.1-open | [gonix](https://github.com/gonix) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gonixunsafe.pdf) |\n|   | 00:02.557 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yourwass.java)| 21.0.1-open | [yourwass](https://github.com/yourwass) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/yourwass.pdf) |\n|   | 00:02.820 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_linl33.java)| 22.ea.32-open | [Li Lin](https://github.com/linl33) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/linl33.pdf) |\n|   | 00:02.995 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_tivrfoa.java)| 21.0.2-graal | [tivrfoa](https://github.com/tivrfoa) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/tivrfoa.pdf) |\n|   | 00:02.997 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonix.java)| 21.0.1-open | [gonix](https://github.com/gonix) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gonix.pdf) |\n|   | 00:03.095 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JamalMulla.java)| 21.0.2-graal | [Jamal Mulla](https://github.com/JamalMulla) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/JamalMulla.pdf) |\n|   | 00:03.210 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykitty.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykitty) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/merykitty.pdf) |\n|   | 00:03.298 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemanaNonIdiomatic.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemana) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/vemanaNonIdiomatic.pdf) |\n|   | 00:03.431 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_roman_r_m.java)| 21.0.1-graal | [Roman Musin](https://github.com/roman-r-m) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/roman_r_m.pdf) |\n|   | 00:03.469 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ebarlas.java)| 21.0.2-graal | [Elliot Barlas](https://github.com/ebarlas) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ebarlas.pdf) |\n|   | 00:03.698 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_hundredwatt.java)| 21.0.1-graal | [Jason Nochlin](https://github.com/hundredwatt) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/hundredwatt.pdf) |\n|   | 00:03.785 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_zerninv.java)| 21.0.2-graal | [zerninv](https://github.com/zerninv) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/zerninv.pdf) |\n|   | 00:03.820 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_iziamos.java)| 21.0.2-graal | [John Ziamos](https://github.com/iziamos) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/iziamos.pdf) |\n|   | 00:03.902 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jparera.java)| 21.0.1-open | [Juan Parera](https://github.com/jparera) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jparera.pdf) |\n|   | 00:03.966 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jincongho.java)| 21.0.1-open | [Jin Cong Ho](https://github.com/jincongho) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jincongho.pdf) |\n|   | 00:03.991 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vaidhy.java)| 21.0.1-graal | [Vaidhy Mayilrangam](https://github.com/vaidhy) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/vaidhy.pdf) |\n|   | 00:04.066 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JesseVanRooy.java)| 21.0.1-open | [JesseVanRooy](https://github.com/JesseVanRooy) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/JesseVanRooy.pdf) |\n|   | 00:04.101 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JaimePolidura.java)| 21.0.2-graal | [Jaime Polidura](https://github.com/JaimePolidura) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/JaimePolidura.pdf) |\n|   | 00:04.209 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_giovannicuccu.java)| 21.0.1-open | [Giovanni Cuccu](https://github.com/giovannicuccu) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/giovannicuccu.pdf) |\n|   | 00:04.474 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gamlerhart.java)| 21.0.1-open | [Roman Stoffel](https://github.com/gamlerhart) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gamlerhart.pdf) |\n|   | 00:04.676 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_plevart.java)| 21.0.2-tem | [Peter Levart](https://github.com/plevart) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/plevart.pdf) |\n|   | 00:04.684 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gigiblender.java)| 21.0.1-open | [Florin Blanaru](https://github.com/gigiblender) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gigiblender.pdf) |\n|   | 00:04.701 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ianopolousfast.java)| 21.0.1-open | [Dr Ian Preston](https://github.com/ianopolousfast) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ianopolousfast.pdf) |\n|   | 00:04.741 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_cliffclick.java)| 21.0.1-open | [Cliff Click](https://github.com/cliffclick) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/cliffclick.pdf) |\n|   | 00:04.800 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_parkertimmins.java)| 21.0.1-open | [Parker Timmins](https://github.com/parkertimmins) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/parkertimmins.pdf) |\n|   | 00:04.884 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_shipilev.java)| 21.0.1-open | [Aleksey Shipilëv](https://github.com/shipilev) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/shipilev.pdf) |\n|   | 00:04.920 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemana.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemana) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/vemana.pdf) |\n|   | 00:05.077 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jonathanaotearoa.java)| 21.0.2-graal | [Jonathan Wright](https://github.com/jonathan-aotearoa) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jonathanaotearoa.pdf) |\n|   | 00:05.142 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_arjenw.java)| 21.0.1-open | [Arjen Wisse](https://github.com/arjenw) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/arjenw.pdf) |\n|   | 00:05.167 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_melgenek.java)| 21.0.2-open | [Yevhenii Melnyk](https://github.com/melgenek) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/melgenek.pdf) |\n|   | 00:05.235 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_unbounded.java)| 21.0.1-open | [unbounded](https://github.com/unbounded) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/unbounded.pdf) |\n|   | 00:05.336 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_EduardoSaverin.java)| java | [Sumit Chaudhary](https://github.com/EduardoSaverin) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/EduardoSaverin.pdf) |\n|   | 00:05.354 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_armandino.java)| 21.0.2-graal | [Arman Sharif](https://github.com/armandino) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/armandino.pdf) |\n|   | 00:05.478 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_obourgain.java)| 21.0.1-open | [Olivier Bourgain](https://github.com/obourgain) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/obourgain.pdf) |\n|   | 00:05.559 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_PanagiotisDrakatos.java)| 21.0.1-graal | [Panagiotis Drakatos](https://github.com/PanagiotisDrakatos) | GraalVM native binary | [Certificate](http://gunnarmorling.github.io/1brc-certificates/PanagiotisDrakatos.pdf) |\n|   | 00:05.887 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_charlibot.java)| 21.0.1-graal | [Charlie Evans](https://github.com/charlibot) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/charlibot.pdf) |\n|   | 00:05.979 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_spullara.java)| 21.0.1-graal | [Sam Pullara](https://github.com/spullara) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/spullara.pdf) |\n|   | 00:06.166 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_isolgpus.java)| 21.0.1-open | [Jamie Stansfield](https://github.com/isolgpus) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/isolgpus.pdf) |\n|   | 00:06.257 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_flippingbits.java)| 21.0.1-graal | [Stefan Sprenger](https://github.com/flippingbits) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/flippingbits.pdf) |\n|   | 00:06.392 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_dpsoft.java)| 21.0.2-graal | [Diego Parra](https://github.com/dpsoft) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/dpsoft.pdf) |\n|   | 00:06.576 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_as-com.java)| 21.0.1-open | [Andrew Sun](https://github.com/as-com) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/as-com.pdf) |\n|   | 00:06.635 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_justplainlaake.java)| 21.0.1-graal | [Laake Scates-Gervasi](https://github.com/justplainlaake) | GraalVM native binary, uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/justplainlaake.pdf) |\n|   | 00:06.654 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jbachorik.java)| 21.0.1-graal | [Jaroslav Bachorik](https://github.com/jbachorik) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jbachorik.pdf) |\n|   | 00:06.715 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_algirdasrascius.java)| 21.0.1-open | [Algirdas Raščius](https://github.com/algirdasrascius) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/algirdasrascius.pdf) |\n|   | 00:06.884 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_rcasteltrione.java)| 21.0.1-graal | [rcasteltrione](https://github.com/rcasteltrione) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/rcasteltrione.pdf) |\n|   | 00:06.982 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ChrisBellew.java)| 21.0.1-open | [Chris Bellew](https://github.com/ChrisBellew) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ChrisBellew.pdf) |\n|   | 00:07.563 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_3j5a.java)| 21.0.1-graal | [3j5a](https://github.com/3j5a) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/3j5a.pdf) |\n|   | 00:07.680 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_C5H12O5.java)| 21.0.1-graal | [Xylitol](https://github.com/C5H12O5) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/C5H12O5.pdf) |\n|   | 00:07.712 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_anitasv.java)| 21.0.1-graal | [Anita SV](https://github.com/anitasv) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/anitasv.pdf) |\n|   | 00:07.730 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jotschi.java)| 21.0.1-open | [Johannes Schüth](https://github.com/jotschi) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jotschi.pdf) |\n|   | 00:07.894 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_tonivade.java)| 21.0.2-tem | [Antonio Muñoz](https://github.com/tonivade) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/tonivade.pdf) |\n|   | 00:07.925 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ricardopieper.java)| 21.0.1-graal | [Ricardo Pieper](https://github.com/ricardopieper) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ricardopieper.pdf) |\n|   | 00:07.948 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_Smoofie.java)| java | [Smoofie](https://github.com/Smoofie) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/Smoofie.pdf) |\n|   | 00:08.157 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JurenIvan.java)| 21.0.1-open | [JurenIvan](https://github.com/JurenIvan) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/JurenIvan.pdf) |\n|   | 00:08.167 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ddimtirov.java)| 21.0.1-tem | [Dimitar Dimitrov](https://github.com/ddimtirov) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ddimtirov.pdf) |\n|   | 00:08.214 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_deemkeen.java)| 21.0.1-open | [deemkeen](https://github.com/deemkeen) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/deemkeen.pdf) |\n|   | 00:08.255 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_mattiz.java)| 21.0.1-open | [Mathias Bjerke](https://github.com/mattiz) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/mattiz.pdf) |\n|   | 00:08.398 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_artpar.java)| 21.0.1-open | [Parth Mudgal](https://github.com/artpar) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/artpar.pdf) |\n|   | 00:08.489 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gnabyl.java)| 21.0.1-graal | [Bang NGUYEN](https://github.com/gnabyl) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gnabyl.pdf) |\n|   | 00:08.517 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ags313.java)| 21.0.1-graal | [ags](https://github.com/ags313) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ags313.pdf) |\n|   | 00:08.557 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_adriacabeza.java)| 21.0.1-graal | [Adrià Cabeza](https://github.com/adriacabeza) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/adriacabeza.pdf) |\n|   | 00:08.622 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java)| 21.0.1-graal | [Keshavram Kuduwa](https://github.com/kuduwa-keshavram) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/kuduwa_keshavram.pdf) |\n|   | 00:08.892 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_fatroom.java)| 21.0.1-open | [Roman Romanchuk](https://github.com/fatroom) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/fatroom.pdf) |\n|   | 00:08.896 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_anestoruk.java)| 21.0.1-open | [Andrzej Nestoruk](https://github.com/anestoruk) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/anestoruk.pdf) |\n|   | 00:09.020 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yemreinci.java)| 21.0.1-open | [yemreinci](https://github.com/yemreinci) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/yemreinci.pdf) |\n|   | 00:09.071 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gabrielreid.java)| 21.0.1-open | [Gabriel Reid](https://github.com/gabrielreid) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gabrielreid.pdf) |\n|   | 00:09.352 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_filiphr.java)| 21.0.1-graal | [Filip Hrisafov](https://github.com/filiphr) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/filiphr.pdf) |\n|   | 00:09.725 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_martin2038.java)| 21.0.2-graal | [Martin](https://github.com/martin2038) | GraalVM native binary | [Certificate](http://gunnarmorling.github.io/1brc-certificates/martin2038.pdf) |\n|   | 00:09.867 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ricardopieper.java)| 21.0.1-graal | [Ricardo Pieper](https://github.com/ricardopieper) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ricardopieper.pdf) |\n|   | 00:09.945 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_japplis.java)| 21.0.1-open | [Anthony Goubard](https://github.com/japplis) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/japplis.pdf) |\n|   | 00:10.092 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_phd3.java)| 21.0.1-graal | [Pratham](https://github.com/phd3) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/phd3.pdf) |\n|   | 00:10.127 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_artpar.java)| 21.0.1-open | [Parth Mudgal](https://github.com/artpar) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/artpar.pdf) |\n|   | 00:11.577 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_netrunnereve.java)| 21.0.1-open | [Eve](https://github.com/netrunnereve) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/netrunnereve.pdf) |\n|   | 00:10.473 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_raipc.java)| 21.0.1-open | [Anton Rybochkin](https://github.com/raipc) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/raipc.pdf) |\n|   | 00:11.119 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_lawrey.java)| 21.0.1-open | [lawrey](https://github.com/lawrey) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/lawrey.pdf) |\n|   | 00:11.156 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_YannMoisan.java)| java | [Yann Moisan](https://github.com/YannMoisan) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/YannMoisan.pdf) |\n|   | 00:11.167 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_palmr.java)| 21.0.1-open | [Nick Palmer](https://github.com/palmr) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/palmr.pdf) |\n|   | 00:11.352 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_karthikeyan97.java)| 21.0.1-open | [karthikeyan97](https://github.com/karthikeyan97) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/karthikeyan97.pdf) |\n|   | 00:11.363 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_godofwharf.java)| 21.0.2-tem | [Guruprasad Sridharan](https://github.com/godofwharf) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/godofwharf.pdf) |\n|   | 00:11.405 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_imrafaelmerino.java)| 21.0.1-graal | [Rafael Merino García](https://github.com/imrafaelmerino) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/imrafaelmerino.pdf) |\n|   | 00:11.406 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gabrielfoo.java)| 21.0.1-graal | [gabrielfoo](https://github.com/gabrielfoo) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gabrielfoo.pdf) |\n|   | 00:11.433 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jatingala.java)| 21.0.1-graal | [Jatin Gala](https://github.com/jatingala) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jatingala.pdf) |\n|   | 00:11.505 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_bufistov.java)| 21.0.1-open | [Dmitry Bufistov](https://github.com/dmitry-midokura) | uses Unsafe | [Certificate](http://gunnarmorling.github.io/1brc-certificates/bufistov.pdf) |\n|   | 00:11.744 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_slovdahl.java)| 21.0.2-tem | [Sebastian Lövdahl](https://github.com/slovdahl) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/slovdahl.pdf) |\n|   | 00:11.805 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_coolmineman.java)| 21.0.1-graal | [Cool_Mineman](https://github.com/coolmineman) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/coolmineman.pdf) |\n|   | 00:11.934 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_arjenvaneerde.java)| 21.0.1-open | [arjenvaneerde](https://github.com/arjenvaneerde) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/arjenvaneerde.pdf) |\n|   | 00:12.220 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_richardstartin.java)| 21.0.1-open | [Richard Startin](https://github.com/richardstartin) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/richardstartin.pdf) |\n|   | 00:12.495 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_SamuelYvon.java)| 21.0.1-graal | [Samuel Yvon](https://github.com/SamuelYvon) | GraalVM native binary | [Certificate](http://gunnarmorling.github.io/1brc-certificates/SamuelYvon.pdf) |\n|   | 00:12.568 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_MeanderingProgrammer.java)| 21.0.1-graal | [Vlad](https://github.com/MeanderingProgrammer) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/MeanderingProgrammer.pdf) |\n|   | 00:12.800 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yonatang.java)| java | [Yonatan Graber](https://github.com/yonatang) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/yonatang.pdf) |\n|   | 00:13.013 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thanhtrinity.java)| 21.0.1-graal | [Thanh Duong](https://github.com/thanhtrinity) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/thanhtrinity.pdf) |\n|   | 00:13.071 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ianopolous.java)| 21.0.1-open | [Dr Ian Preston](https://github.com/ianopolous) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ianopolous.pdf) |\n|   | 00:13.729 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_cb0s.java)| java | [Cedric Boes](https://github.com/cb0s) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/cb0s.pdf) |\n|   | 00:13.817 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_entangled90.java)| 21.0.1-open | [Carlo](https://github.com/entangled90) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/entangled90.pdf) |\n|   | 00:14.502 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_eriklumme.java)| 21.0.1-graal | [eriklumme](https://github.com/eriklumme) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/eriklumme.pdf) |\n|   | 00:14.772 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kevinmcmurtrie.java)| 21.0.1-open | [Kevin McMurtrie](https://github.com/kevinmcmurtrie) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/kevinmcmurtrie.pdf) |\n|   | 00:14.867 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_berry120.java)| 21.0.1-open | [Michael Berry](https://github.com/berry120) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/berry120.pdf) |\n|   | 00:14.900 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_Judekeyser.java)| java | [Judekeyser](https://github.com/Judekeyser) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/Judekeyser.pdf) |\n|   | 00:15.006 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_PawelAdamski.java)| java | [Paweł Adamski](https://github.com/PawelAdamski) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/PawelAdamski.pdf) |\n|   | 00:15.662 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_semotpan.java)| 21.0.1-open | [Serghei Motpan](https://github.com/semotpan) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/semotpan.pdf) |\n|   | 00:16.063 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_makohn.java)| 21.0.1-open | [Marek Kohn](https://github.com/makohn) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/makohn.pdf) |\n|   | 00:16.457 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_bytesfellow.java)| 21.0.1-open | [Aleksei](https://github.com/bytesfellow) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/bytesfellow.pdf) |\n|   | 00:16.953 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gauravdeshmukh.java)| 21.0.1-open | [Gaurav Anantrao Deshmukh](https://github.com/gauravdeshmukh) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gauravdeshmukh.pdf) |\n|   | 00:17.046 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_dkarampi.java)| 21.0.1-open | [Dimitris Karampinas](https://github.com/dkarampi) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/dkarampi.pdf) |\n|   | 00:17.086 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_breejesh.java)| java | [Breejesh Rathod](https://github.com/breejesh) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/breejesh.pdf) |\n|   | 00:17.490 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kgeri.java)| 21.0.1-open | [Gergely Kiss](https://github.com/kgeri) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/kgeri.pdf) |\n|   | 00:17.255 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_tkosachev.java)| 21.0.1-open | [tkosachev](https://github.com/tkosachev) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/tkosachev.pdf) |\n|   | 00:17.520 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_faridtmammadov.java)| 21.0.1-open | [Farid](https://github.com/faridtmammadov) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/faridtmammadov.pdf) |\n|   | 00:17.717 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_omarchenko4j.java)| 21.0.1-open | [Oleh Marchenko](https://github.com/omarchenko4j) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/omarchenko4j.pdf) |\n|   | 00:17.815 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_hallvard.java)| 21.0.1-open | [Hallvard Trætteberg](https://github.com/hallvard) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/hallvard.pdf) |\n|   | 00:17.932 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_plbpietrz.java)| 21.0.1-open | [Bartłomiej Pietrzyk](https://github.com/plbpietrz) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/plbpietrz.pdf) |\n|   | 00:18.251 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_seijikun.java)| 21.0.1-graal | [Markus Ebner](https://github.com/seijikun) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/seijikun.pdf) |\n|   | 00:18.448 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_moysesb.java)| 21.0.1-open | [Moysés Borges Furtado](https://github.com/moysesb) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/moysesb.pdf) |\n|   | 00:18.771 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_davecom.java)| 21.0.1-graal | [David Kopec](https://github.com/davecom) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/davecom.pdf) |\n|   | 00:18.902 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_maximz101.java)| 21.0.1-graal | [Maxime](https://github.com/maximz101) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/maximz101.pdf) |\n|   | 00:19.357 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_truelive.java)| 21.0.1-graalce | [Roman Schweitzer](https://github.com/truelive) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/truelive.pdf) |\n|   | 00:20.691 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_Kidlike.java)| 21.0.1-graal | [Kidlike](https://github.com/Kidlike) | GraalVM native binary | [Certificate](http://gunnarmorling.github.io/1brc-certificates/Kidlike.pdf) |\n|   | 00:21.989 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_couragelee.java)| 21.0.1-open | [couragelee](https://github.com/couragelee) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/couragelee.pdf) |\n|   | 00:22.188 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jgrateron.java)| 21.0.1-open | [Jairo Graterón](https://github.com/jgrateron) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jgrateron.pdf) |\n|   | 00:22.334 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_albertoventurini.java)| 21.0.1-open | [Alberto Venturini](https://github.com/albertoventurini) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/albertoventurini.pdf) |\n|   | 00:22.457 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_rby.java)| 21.0.1-open | [Ramzi Ben Yahya](https://github.com/rby) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/rby.pdf) |\n|   | 00:22.471 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_0xshivamagarwal.java)| 21.0.1-open | [Shivam Agarwal](https://github.com/0xshivamagarwal) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/0xshivamagarwal.pdf) |\n|   | 00:24.986 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_kumarsaurav123.java)| 21.0.1-open | [kumarsaurav123](https://github.com/kumarsaurav123) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/kumarsaurav123.pdf) |\n|   | 00:25.064 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_sudhirtumati.java)| 21.0.2-open | [Sudhir Tumati](https://github.com/sudhirtumati) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/sudhirtumati.pdf) |\n|   | 00:26.500 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_felix19350.java)| 21.0.1-open | [Bruno Félix](https://github.com/felix19350) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/felix19350.pdf) |\n|   | 00:28.381 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_bjhara.java)| 21.0.1-open | [Hampus](https://github.com/bjhara) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/bjhara.pdf) |\n|   | 00:29.741 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_xpmatteo.java)| 21.0.1-open | [Matteo Vaccari](https://github.com/xpmatteo) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/xpmatteo.pdf) |\n|   | 00:32.018 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_padreati.java)| 21.0.1-open | [Aurelian Tutuianu](https://github.com/padreati) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/padreati.pdf) |\n|   | 00:34.388 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_twobiers.java)| 21.0.1-tem | [Tobi](https://github.com/twobiers) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/twobiers.pdf) |\n|   | 00:35.875 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_MahmoudFawzyKhalil.java)| 21.0.1-open | [MahmoudFawzyKhalil](https://github.com/MahmoudFawzyKhalil) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/MahmoudFawzyKhalil.pdf) |\n|   | 00:36.180 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_hchiorean.java)| 21.0.1-open | [Horia Chiorean](https://github.com/hchiorean) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/hchiorean.pdf) |\n|   | 00:36.424 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_manishgarg90.java)| java | [Manish Garg](https://github.com/manishgarg90) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/manishgarg90.pdf) |\n|   | 00:38.340 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_AbstractKamen.java)| 21.0.1-open | [AbstractKamen](https://github.com/AbstractKamen) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/AbstractKamen.pdf) |\n|   | 00:41.982 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_criccomini.java)| 21.0.1-open | [Chris Riccomini](https://github.com/criccomini) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/criccomini.pdf) |\n|   | 00:42.893 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_javamak.java)| 21.0.1-open | [javamak](https://github.com/javamak) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/javamak.pdf) |\n|   | 00:46.597 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_maeda6uiui.java)| 21.0.1-open | [Maeda-san](https://github.com/maeda6uiui) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/maeda6uiui.pdf) |\n|   | 00:58.811 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_Ujjwalbharti.java)| 21.0.1-open | [Ujjwal Bharti](https://github.com/Ujjwalbharti) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/Ujjwalbharti.pdf) |\n|   | 01:05.094 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_muditsaxena.java)| 21.0.1-open | [Mudit Saxena](https://github.com/mudit-saxena) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/muditsaxena.pdf) |\n|   | 01:05.979 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_dqhieuu.java)| 21.0.1-graal | [Hieu Dao Quang](https://github.com/dqhieuu) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/dqhieuu.pdf) |\n|   | 01:06.790 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_khmarbaise.java)| 21.0.1-open | [Karl Heinz Marbaise](https://github.com/khmarbaise) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/khmarbaise.pdf) |\n|   | 01:06.944 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_santanu.java)| 21.0.1-open | [santanu](https://github.com/santanu) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/santanu.pdf) |\n|   | 01:07.014 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_pedestrianlove.java)| 21.0.1-open | [pedestrianlove](https://github.com/pedestrianlove) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/pedestrianlove.pdf) |\n|   | 01:07.101 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jeevjyot.java)| 21.0.1-open | [Jeevjyot Singh Chhabda](https://github.com/jeevjyot) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/jeevjyot.pdf) |\n|   | 01:08.811 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_alesj.java)| 21.0.1-open | [Aleš Justin](https://github.com/alesj) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/alesj.pdf) |\n|   | 01:08.908 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_itaske.java)| 21.0.1-open | [itaske](https://github.com/itaske) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/itaske.pdf) |\n|   | 01:09.595 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_agoncal.java)| 21.0.1-tem | [Antonio Goncalves](https://github.com/agoncal) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/agoncal.pdf) |\n|   | 01:09.882 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_rprabhu.java)| 21.0.1-open | [Prabhu R](https://github.com/rprabhu) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/rprabhu.pdf) |\n|   | 01:14.815 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_anandmattikopp.java)| 21.0.1-open | [twohardthings](https://github.com/anandmattikopp) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/anandmattikopp.pdf) |\n|   | 01:25.801 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ivanklaric.java)| 21.0.1-open | [ivanklaric](https://github.com/ivanklaric) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/ivanklaric.pdf) |\n|   | 01:33.594 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gnmathur.java)| 21.0.1-open | [Gaurav Mathur](https://github.com/gnmathur) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/gnmathur.pdf) |\n|   | 01:53.208 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_mahadev_k.java)| java | [Mahadev K](https://github.com/mahadev-k) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/mahadev_k.pdf) |\n|   | 01:56.607 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_abfrmblr.java)| 21.0.1-open | [Abhilash](https://github.com/abfrmblr) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/abfrmblr.pdf) |\n|   | 03:43.521 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yehwankim23.java)| 21.0.1-open | [김예환 Ye-Hwan Kim (Sam)](https://github.com/yehwankim23) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/yehwankim23.pdf) |\n|   | 03:59.760 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_fragmede.java)| 21.0.1-open | [Samson](https://github.com/fragmede) |  | [Certificate](http://gunnarmorling.github.io/1brc-certificates/fragmede.pdf) |\n|   | ---       | | | | |\n|   | 04:49.679 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_baseline.java) (Baseline) | 21.0.1-open | [Gunnar Morling](https://github.com/gunnarmorling) |  |\n\nNote that I am not super-scientific in the way I'm running the contenders\n(see [Evaluating Results](#evaluating-results) for the details).\nThis is not a high-fidelity micro-benchmark and there can be variations of up to +-3% between runs.\nSo don't be too hung up on the exact ordering of your entry compared to others in close proximity.\nThe primary purpose of this challenge is to learn something new, have fun along the way, and inspire others to do the same.\nThe leaderboard is only means to an end for achieving this goal.\nIf you observe drastically different results though, please open an issue.\n\nSee [Entering the Challenge](#entering-the-challenge) for instructions how to enter the challenge with your own implementation.\nThe [Show & Tell](https://github.com/gunnarmorling/1brc/discussions/categories/show-and-tell) features a wide range of 1BRC entries built using other languages, databases, and tools.\n\n### Bonus Results\n\nThis section lists results from running the fastest N entries with different configurations.\nAs entries have been optimized towards the specific conditions of the original challenge description and set-up\n(such as size of the key set),\nchallenge entries may perform very differently across different configurations.\nThese bonus results are provided here for informational purposes only.\nFor the 1BRC challenge, only the results in the previous section are of importance.\n\n#### 32 Cores / 64 Threads\n\nFor officially evaluating entries into the challenge, each contender is run on eight cores of the evaluation machine (AMD EPYC™ 7502P).\nHere are the results from running the top 50 entries (as of commit [e1fb378a](https://github.com/gunnarmorling/1brc/commit/e1fb378acce53d8c3035ee4813ae377aaf51aa3c), Feb 2) on all 32 cores / 64 threads (i.e. SMT is enabled) of the machine:\n\n| # | Result (m:s.ms) | Implementation     | JDK | Submitter     | Notes     |\n|---|-----------------|--------------------|-----|---------------|-----------|\n| 1 | 00:00.323 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jerrinot.java)| 21.0.2-graal | [Jaromir Hamala](https://github.com/jerrinot) | GraalVM native binary, uses Unsafe |\n| 2 | 00:00.326 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java)| 21.0.2-graal | [Thomas Wuerthinger](https://github.com/thomaswue), [Quan Anh Mai](https://github.com/merykitty), [Alfonso² Peterssen](https://github.com/mukel) | GraalVM native binary, uses Unsafe |\n| 3 | 00:00.349 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_artsiomkorzun.java)| 21.0.2-graal | [Artsiom Korzun](https://github.com/artsiomkorzun) | GraalVM native binary, uses Unsafe |\n|   | 00:00.351 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_abeobk.java)| 21.0.2-graal | [Van Phu DO](https://github.com/abeobk) | GraalVM native binary, uses Unsafe |\n|   | 00:00.389 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_stephenvonworley.java)| 21.0.2-graal | [Stephen Von Worley](https://github.com/stephenvonworley) | GraalVM native binary, uses Unsafe |\n|   | 00:00.408 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yavuztas.java)| 21.0.2-graal | [Yavuz Tas](https://github.com/yavuztas) | GraalVM native binary, uses Unsafe |\n|   | 00:00.415 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java)| 21.0.2-graal | [Roy van Rijn](https://github.com/royvanrijn) | GraalVM native binary, uses Unsafe |\n|   | 00:00.499 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_mtopolnik.java)| 21.0.2-graal | [Marko Topolnik](https://github.com/mtopolnik) | GraalVM native binary, uses Unsafe |\n|   | 00:00.602 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_roman_r_m.java)| 21.0.1-graal | [Roman Musin](https://github.com/roman-r-m) | GraalVM native binary, uses Unsafe |\n|   | 00:00.623 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonixunsafe.java)| 21.0.1-open | [gonix](https://github.com/gonixunsafe) | uses Unsafe |\n|   | 00:00.710 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JamalMulla.java)| 21.0.2-graal | [Jamal Mulla](https://github.com/JamalMulla) | GraalVM native binary, uses Unsafe |\n|   | 00:00.727 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_tivrfoa.java)| 21.0.2-graal | [tivrfoa](https://github.com/tivrfoa) | GraalVM native binary, uses Unsafe |\n|   | 00:00.774 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_serkan_ozal.java)| 21.0.1-open | [Serkan ÖZAL](https://github.com/serkan-ozal) | uses Unsafe |\n|   | 00:00.788 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ebarlas.java)| 21.0.2-graal | [Elliot Barlas](https://github.com/ebarlas) | GraalVM native binary, uses Unsafe |\n|   | 00:00.832 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_zerninv.java)| 21.0.2-graal | [zerninv](https://github.com/zerninv) | GraalVM native binary, uses Unsafe |\n|   | 00:00.840 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonix.java)| 21.0.1-open | [gonix](https://github.com/gonix) |  |\n|   | 00:00.857 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JaimePolidura.java)| 21.0.2-graal | [Jaime Polidura](https://github.com/JaimePolidura) | GraalVM native binary, uses Unsafe |\n|   | 00:00.880 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_iziamos.java)| 21.0.2-graal | [John Ziamos](https://github.com/iziamos) | GraalVM native binary, uses Unsafe |\n|   | 00:00.939 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_shipilev.java)| 21.0.1-open | [Aleksey Shipilëv](https://github.com/shipilev) |  |\n|   | 00:01.026 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JesseVanRooy.java)| 21.0.1-open | [JesseVanRooy](https://github.com/JesseVanRooy) | uses Unsafe |\n|   | 00:01.118 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jonathanaotearoa.java)| 21.0.2-graal | [Jonathan Wright](https://github.com/jonathan-aotearoa) | GraalVM native binary |\n|   | 00:01.140 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_armandino.java)| 21.0.2-graal | [Arman Sharif](https://github.com/armandino) | GraalVM native binary, uses Unsafe |\n|   | 00:01.143 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_cliffclick.java)| 21.0.1-open | [Cliff Click](https://github.com/cliffclick) | uses Unsafe |\n|   | 00:01.169 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_melgenek.java)| 21.0.2-open | [Yevhenii Melnyk](https://github.com/melgenek) |  |\n|   | 00:01.188 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemanaNonIdiomatic.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemanaNonIdiomatic) | uses Unsafe |\n|   | 00:01.193 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gigiblender.java)| 21.0.1-open | [Florin Blanaru](https://github.com/gigiblender) | uses Unsafe |\n|   | 00:01.234 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_obourgain.java)| 21.0.1-open | [Olivier Bourgain](https://github.com/obourgain) | uses Unsafe |\n|   | 00:01.242 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykittyunsafe.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykittyunsafe) | uses Unsafe |\n|   | 00:01.252 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jincongho.java)| 21.0.1-open | [Jin Cong Ho](https://github.com/jincongho) | uses Unsafe |\n|   | 00:01.267 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_linl33.java)| 22.ea.32-open | [Li Lin](https://github.com/linl33) | uses Unsafe |\n|   | 00:01.363 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_plevart.java)| 21.0.2-tem | [Peter Levart](https://github.com/plevart) |  |\n|   | 00:01.380 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_hundredwatt.java)| 21.0.1-graal | [Jason Nochlin](https://github.com/hundredwatt) |  |\n|   | 00:01.391 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykitty.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykitty) |  |\n|   | 00:01.439 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_arjenw.java)| 21.0.1-open | [Arjen Wisse](https://github.com/arjenw) |  |\n|   | 00:01.446 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ianopolousfast.java)| 21.0.1-open | [Dr Ian Preston](https://github.com/ianopolousfast) |  |\n|   | 00:01.504 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_isolgpus.java)| 21.0.1-open | [Jamie Stansfield](https://github.com/isolgpus) |  |\n|   | 00:01.514 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemana.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemana) |  |\n|   | 00:01.516 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vaidhy.java)| 21.0.1-graal | [Vaidhy Mayilrangam](https://github.com/vaidhy) | uses Unsafe |\n|   | 00:01.586 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yourwass.java)| 21.0.1-open | [yourwass](https://github.com/yourwass) | uses Unsafe |\n|   | 00:01.647 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_dpsoft.java)| 21.0.2-graal | [Diego Parra](https://github.com/dpsoft) |  |\n|   | 00:01.694 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_parkertimmins.java)| 21.0.1-open | [Parker Timmins](https://github.com/parkertimmins) |  |\n|   | 00:01.694 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_charlibot.java)| 21.0.1-graal | [Charlie Evans](https://github.com/charlibot) | uses Unsafe |\n|   | 00:01.702 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_spullara.java)| 21.0.1-graal | [Sam Pullara](https://github.com/spullara) |  |\n|   | 00:01.733 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_EduardoSaverin.java)| java | [Sumit Chaudhary](https://github.com/EduardoSaverin) | uses Unsafe |\n|   | 00:01.742 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_unbounded.java)| 21.0.1-open | [unbounded](https://github.com/unbounded) |  |\n|   | 00:02.241 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_flippingbits.java)| 21.0.1-graal | [Stefan Sprenger](https://github.com/flippingbits) | uses Unsafe |\n|   | 00:02.294 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_giovannicuccu.java)| 21.0.1-open | [Giovanni Cuccu](https://github.com/giovannicuccu) |  |\n|   | 00:02.990 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_PanagiotisDrakatos.java)| 21.0.1-graal | [Panagiotis Drakatos](https://github.com/PanagiotisDrakatos) | GraalVM native binary |\n|   | 00:03.205 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jparera.java)| 21.0.1-open | [Juan Parera](https://github.com/jparera) |  |\n|   | 00:10.929 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gamlerhart.java)| 21.0.1-open | [Roman Stoffel](https://github.com/gamlerhart) |  |\n\n#### 10K Key Set\n\nThe 1BRC challenge data set contains 413 distinct weather stations, whereas the rules allow for 10,000 different station names to occur.\nHere are the results from running the top 40 entries (as of commit [e1fb378a](https://github.com/gunnarmorling/1brc/commit/e1fb378acce53d8c3035ee4813ae377aaf51aa3c), Feb 2) against 1,000,000,000 measurement values across 10K stations (created via _./create_measurements3.sh 1000000000_),\nusing eight cores on the evaluation machine:\n\n| # | Result (m:s.ms) | Implementation     | JDK | Submitter     | Notes     |\n|---|-----------------|--------------------|-----|---------------|-----------|\n| 1 | 00:02.957 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_artsiomkorzun.java)| 21.0.2-graal | [Artsiom Korzun](https://github.com/artsiomkorzun) | GraalVM native binary, uses Unsafe |\n| 2 | 00:03.058 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_mtopolnik.java)| 21.0.2-graal | [Marko Topolnik](https://github.com/mtopolnik) | GraalVM native binary, uses Unsafe |\n| 3 | 00:03.186 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_stephenvonworley.java)| 21.0.2-graal | [Stephen Von Worley](https://github.com/stephenvonworley) | GraalVM native binary, uses Unsafe |\n|   | 00:03.998 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java)| 21.0.2-graal | [Roy van Rijn](https://github.com/royvanrijn) | GraalVM native binary, uses Unsafe |\n|   | 00:04.042 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jerrinot.java)| 21.0.2-graal | [Jaromir Hamala](https://github.com/jerrinot) | GraalVM native binary, uses Unsafe |\n|   | 00:04.289 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonixunsafe.java)| 21.0.1-open | [gonix](https://github.com/gonixunsafe) | uses Unsafe |\n|   | 00:04.522 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_tivrfoa.java)| 21.0.2-graal | [tivrfoa](https://github.com/tivrfoa) | GraalVM native binary, uses Unsafe |\n|   | 00:04.653 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JamalMulla.java)| 21.0.2-graal | [Jamal Mulla](https://github.com/JamalMulla) | GraalVM native binary, uses Unsafe |\n|   | 00:04.733 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gonix.java)| 21.0.1-open | [gonix](https://github.com/gonix) |  |\n|   | 00:04.836 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemanaNonIdiomatic.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemanaNonIdiomatic) | uses Unsafe |\n|   | 00:04.870 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java)| 21.0.2-graal | [Thomas Wuerthinger](https://github.com/thomaswue), [Quan Anh Mai](https://github.com/merykitty), [Alfonso² Peterssen](https://github.com/mukel) | GraalVM native binary, uses Unsafe |\n|   | 00:05.240 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_zerninv.java)| 21.0.2-graal | [zerninv](https://github.com/zerninv) | GraalVM native binary, uses Unsafe |\n|   | 00:05.394 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yavuztas.java)| 21.0.2-graal | [Yavuz Tas](https://github.com/yavuztas) | GraalVM native binary, uses Unsafe |\n|   | 00:05.906 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ebarlas.java)| 21.0.2-graal | [Elliot Barlas](https://github.com/ebarlas) | GraalVM native binary, uses Unsafe |\n|   | 00:06.086 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_abeobk.java)| 21.0.2-graal | [Van Phu DO](https://github.com/abeobk) | GraalVM native binary, uses Unsafe |\n|   | 00:06.379 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_iziamos.java)| 21.0.2-graal | [John Ziamos](https://github.com/iziamos) | GraalVM native binary, uses Unsafe |\n|   | 00:07.113 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_melgenek.java)| 21.0.2-open | [Yevhenii Melnyk](https://github.com/melgenek) |  |\n|   | 00:07.542 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jonathan-aotearoa.java)| 21.0.2-graal | [Jonathan Wright](https://github.com/jonathan-aotearoa) | GraalVM native binary |\n|   | 00:07.889 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gigiblender.java)| 21.0.1-open | [Florin Blanaru](https://github.com/gigiblender) | uses Unsafe |\n|   | 00:07.970 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_cliffclick.java)| 21.0.1-open | [Cliff Click](https://github.com/cliffclick) | uses Unsafe |\n|   | 00:08.857 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_serkan-ozal.java)| 21.0.1-open | [Serkan ÖZAL](https://github.com/serkan-ozal) |  |\n|   | 00:09.333 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_yourwass.java)| 21.0.1-open | [yourwass](https://github.com/yourwass) | uses Unsafe |\n|   | 00:09.722 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_shipilev.java)| 21.0.1-open | [Aleksey Shipilëv](https://github.com/shipilev) |  |\n|   | 00:09.777 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vaidhy.java)| 21.0.1-graal | [Vaidhy Mayilrangam](https://github.com/vaidhy) | uses Unsafe |\n|   | 00:10.263 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykittyunsafe.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykittyunsafe) | uses Unsafe |\n|   | 00:11.154 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_parkertimmins.java)| 21.0.1-open | [Parker Timmins](https://github.com/parkertimmins) |  |\n|   | 00:13.175 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_merykitty.java)| 21.0.1-open | [Quan Anh Mai](https://github.com/merykitty) |  |\n|   | 00:13.245 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_ianopolousfast.java)| 21.0.1-open | [Dr Ian Preston](https://github.com/ianopolousfast) |  |\n|   | 00:13.377 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_giovannicuccu.java)| 21.0.1-open | [Giovanni Cuccu](https://github.com/giovannicuccu) |  |\n|   | 00:13.761 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jparera.java)| 21.0.1-open | [Juan Parera](https://github.com/jparera) |  |\n|   | 00:14.441 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_plevart.java)| 21.0.2-tem | [Peter Levart](https://github.com/plevart) |  |\n|   | 00:15.548 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_jincongho.java)| 21.0.1-open | [Jin Cong Ho](https://github.com/jincongho) | uses Unsafe |\n|   | 00:17.906 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_hundredwatt.java)| 21.0.1-graal | [Jason Nochlin](https://github.com/hundredwatt) |  |\n|   | 00:18.770 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_linl33.java)| 22.ea.32-open | [Li Lin](https://github.com/linl33) | uses Unsafe |\n|   | 00:19.106 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_gamlerhart.java)| 21.0.1-open | [Roman Stoffel](https://github.com/gamlerhart) |  |\n|   | 00:20.151 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_roman_r_m.java)| 21.0.1-graal | [Roman Musin](https://github.com/roman-r-m) | GraalVM native binary, uses Unsafe; seg-faults occassionally |\n|   | 00:22.953 | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JaimePolidura.java)| 21.0.2-graal | [Jaime Polidura](https://github.com/JaimePolidura) | GraalVM native binary, uses Unsafe |\n|   | ---       | | | | |\n|   | DNF       | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_JesseVanRooy.java)| 21.0.1-open | [JesseVanRooy](https://github.com/JesseVanRooy) | Incorrect output |\n|   | DNF       | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_vemana.java)| 21.0.1-graal | [Subrahmanyam](https://github.com/vemana) | Doesn't complete in 60 sec |\n|   | DNF       | [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_arjenw.java)| 21.0.1-open | [Arjen Wisse](https://github.com/arjenw) | Incorrect output |\n\n## Prerequisites\n\n[Java 21](https://openjdk.org/projects/jdk/21/) must be installed on your system.\n\n## Running the Challenge\n\nThis repository contains two programs:\n\n* `dev.morling.onebrc.CreateMeasurements` (invoked via _create\\_measurements.sh_): Creates the file _measurements.txt_ in the root directory of this project with a configurable number of random measurement values\n* `dev.morling.onebrc.CalculateAverage` (invoked via _calculate\\_average\\_baseline.sh_): Calculates the average values for the file _measurements.txt_\n\nExecute the following steps to run the challenge:\n\n1. Build the project using Apache Maven:\n\n    ```\n    ./mvnw clean verify\n    ```\n\n2. Create the measurements file with 1B rows (just once):\n\n    ```\n    ./create_measurements.sh 1000000000\n    ```\n\n    This will take a few minutes.\n    **Attention:** the generated file has a size of approx. **12 GB**, so make sure to have enough diskspace.\n\n    If you're running the challenge with a non-Java language, there's a non-authoritative Python script to generate the measurements file at `src/main/python/create_measurements.py`. The authoritative method for generating the measurements is the Java program `dev.morling.onebrc.CreateMeasurements`.\n\n3. Calculate the average measurement values:\n\n    ```\n    ./calculate_average_baseline.sh\n    ```\n\n    The provided naive example implementation uses the Java streams API for processing the file and completes the task in ~2 min on environment used for [result evaluation](#evaluating-results).\n    It serves as the base line for comparing your own implementation.\n\n4. Optimize the heck out of it:\n\n    Adjust the `CalculateAverage` program to speed it up, in any way you see fit (just sticking to a few rules described below).\n    Options include parallelizing the computation, using the (incubating) Vector API, memory-mapping different sections of the file concurrently, using AppCDS, GraalVM, CRaC, etc. for speeding up the application start-up, choosing and tuning the garbage collector, and much more.\n\n## Flamegraph/Profiling\n\nA tip is that if you have [jbang](https://jbang.dev) installed, you can get a flamegraph of your program by running\n[async-profiler](https://github.com/jvm-profiling-tools/async-profiler) via [ap-loader](https://github.com/jvm-profiling-tools/ap-loader):\n\n`jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html -m dev.morling.onebrc.CalculateAverage_yourname target/average-1.0.0-SNAPSHOT.jar`\n\nor directly on the .java file:\n\n`jbang --javaagent=ap-loader@jvm-profiling-tools/ap-loader=start,event=cpu,file=profile.html src/main/java/dev/morling/onebrc/CalculateAverage_yourname`\n\nWhen you run this, it will generate a flamegraph in profile.html. You can then open this in a browser and see where your program is spending its time.\n\n## Rules and limits\n\n* Any of these Java distributions may be used:\n    * Any builds provided by [SDKMan](https://sdkman.io/jdks)\n    * Early access builds available on openjdk.net may be used (including EA builds for OpenJDK projects like Valhalla)\n    * Builds on [builds.shipilev.net](https://builds.shipilev.net/openjdk-jdk-lilliput/)\nIf you want to use a build not available via these channels, reach out to discuss whether it can be considered.\n* No external library dependencies may be used\n* Implementations must be provided as a single source file\n* The computation must happen at application _runtime_, i.e. you cannot process the measurements file at _build time_\n(for instance, when using GraalVM) and just bake the result into the binary\n* Input value ranges are as follows:\n    * Station name: non null UTF-8 string of min length 1 character and max length 100 bytes, containing neither `;` nor `\\n` characters. (i.e. this could be 100 one-byte characters, or 50 two-byte characters, etc.)\n    * Temperature value: non null double between -99.9 (inclusive) and 99.9 (inclusive), always with one fractional digit\n* There is a maximum of 10,000 unique station names\n* Line endings in the file are `\\n` characters on all platforms\n* Implementations must not rely on specifics of a given data set, e.g. any valid station name as per the constraints above and any data distribution (number of measurements per station) must be supported\n* The rounding of output values must be done using the semantics of IEEE 754 rounding-direction \"roundTowardPositive\"\n\n## Entering the Challenge\n\nTo submit your own implementation to 1BRC, follow these steps:\n\n* Create a fork of the [onebrc](https://github.com/gunnarmorling/onebrc/) GitHub repository.\n* Run `./create_fork.sh <your_GH_user>` to copy the baseline implementation to your personal files, or do this manually:\n  * Create a copy of _CalculateAverage\\_baseline.java_, named _CalculateAverage\\_<your_GH_user>.java_, e.g. _CalculateAverage\\_doloreswilson.java_.\n  * Create a copy of _calculate\\_average\\_baseline.sh_, named _calculate\\_average\\_<your_GH_user>.sh_, e.g. _calculate\\_average\\_doloreswilson.sh_.\n  * Adjust that script so that it references your implementation class name. If needed, provide any JVM arguments via the `JAVA_OPTS` variable in that script.\n    Make sure that script does not write anything to standard output other than calculation results.\n  * (Optional) OpenJDK 21 is used by default. If a custom JDK build is required, create a copy of _prepare\\_baseline.sh_, named _prepare\\_<your_GH_user>.sh_, e.g. _prepare\\_doloreswilson.sh_. Include the SDKMAN command `sdk use java [version]` in the your prepare script.\n  * (Optional) If you'd like to use native binaries (GraalVM), add all the required build logic to your _prepare\\_<your_GH_user>.sh_ script.\n* Make that implementation fast. Really fast.\n* Run the test suite by executing _/test.sh <your_GH_user>_; if any differences are reported, fix them before submitting your implementation.\n* Create a pull request against the upstream repository, clearly stating\n  * The name of your implementation class.\n  * The execution time of the program on your system and specs of the same (CPU, number of cores, RAM). This is for informative purposes only, the official runtime will be determined as described below.\n* I will run the program and determine its performance as described in the next section, and enter the result to the scoreboard.\n\n**Note:** I reserve the right to not evaluate specific submissions if I feel doubtful about the implementation (I.e. I won't run your Bitcoin miner ;).\n\nIf you'd like to discuss any potential ideas for implementing 1BRC with the community,\nyou can use the [GitHub Discussions](https://github.com/gunnarmorling/onebrc/discussions) of this repository.\nPlease keep it friendly and civil.\n\nThe challenge runs until Jan 31 2024.\nAny submissions (i.e. pull requests) created after Jan 31 2024 23:59 UTC will not be considered.\n\n## Evaluating Results\n\nResults are determined by running the program on a [Hetzner AX161](https://www.hetzner.com/dedicated-rootserver/ax161) dedicated server (32 core AMD EPYC™ 7502P (Zen2), 128 GB RAM).\n\nPrograms are run from  a RAM disk (i.o. the IO overhead for loading the file from disk is not relevant), using 8 cores of the machine.\nEach contender must pass the 1BRC test suite (_/test.sh_).\nThe `hyperfine` program is used for measuring execution times of the launch scripts of all entries, i.e. end-to-end times are measured.\nEach contender is run five times in a row.\nThe slowest and the fastest runs are discarded.\nThe mean value of the remaining three runs is the result for that contender and will be added to the results table above.\nThe exact same _measurements.txt_ file is used for evaluating all contenders.\nSee the script _evaluate.sh_ for the exact implementation of the evaluation steps.\n\n## Prize\n\nIf you enter this challenge, you may learn something new, get to inspire others, and take pride in seeing your name listed in the scoreboard above.\nRumor has it that the winner may receive a unique 1️⃣🐝🏎️ t-shirt, too!\n\n## FAQ\n\n_Q: Can I use Kotlin or other JVM languages other than Java?_\\\nA: No, this challenge is focussed on Java only. Feel free to inofficially share implementations significantly outperforming any listed results, though.\n\n_Q: Can I use non-JVM languages and/or tools?_\\\nA: No, this challenge is focussed on Java only. Feel free to inofficially share interesting implementations and results though. For instance it would be interesting to see how DuckDB fares with this task.\n\n_Q: I've got an implementation—but it's not in Java. Can I share it somewhere?_\\\nA: Whilst non-Java solutions cannot be formally submitted to the challenge, you are welcome to share them over in the [Show and tell](https://github.com/gunnarmorling/1brc/discussions/categories/show-and-tell) GitHub discussion area.\n\n_Q: Can I use JNI?_\\\nA: Submissions must be completely implemented in Java, i.e. you cannot write JNI glue code in C/C++. You could use AOT compilation of Java code via GraalVM though, either by AOT-compiling the entire application, or by creating a native library (see [here](https://www.graalvm.org/22.0/reference-manual/native-image/ImplementingNativeMethodsInJavaWithSVM/).\n\n_Q: What is the encoding of the measurements.txt file?_\\\nA: The file is encoded with UTF-8.\n\n_Q: Can I make assumptions on the names of the weather stations showing up in the data set?_\\\nA: No, while only a fixed set of station names is used by the data set generator, any solution should work with arbitrary UTF-8 station names\n(for the sake of simplicity, names are guaranteed to contain no `;` or `\\n` characters).\n\n_Q: Can I copy code from other submissions?_\\\nA: Yes, you can. The primary focus of the challenge is about learning something new, rather than \"winning\". When you do so, please give credit to the relevant source submissions. Please don't re-submit other entries with no or only trivial improvements.\n\n_Q: Which operating system is used for evaluation?_\\\nA: Fedora 39.\n\n_Q: My solution runs in 2 sec on my machine. Am I the fastest 1BRC-er in the world?_\\\nA: Probably not :) 1BRC results are reported in wallclock time, thus results of different implementations are only comparable when obtained on the same machine. If for instance an implementation is faster on a 32 core workstation than on the 8 core evaluation instance, this doesn't allow for any conclusions. When sharing 1BRC results, you should also always share the result of running the baseline implementation on the same hardware.\n\n_Q: Why_ 1️⃣🐝🏎️ _?_\\\nA: It's the abbreviation of the project name: **One** **B**illion **R**ow **C**hallenge.\n\n## 1BRC on the Web\n\nA list of external resources such as blog posts and videos, discussing 1BRC and specific implementations:\n\n* [The One Billion Row Challenge Shows That Java Can Process a One Billion Rows File in Two Seconds ](https://www.infoq.com/news/2024/01/1brc-fast-java-processing), by Olimpiu Pop (interview)\n* [Cliff Click discussing his 1BRC solution on the Coffee Compiler Club](https://www.youtube.com/watch?v=NJNIbgV6j-Y) (video)\n* [1️⃣🐝🏎️🦆 (1BRC in SQL with DuckDB)](https://rmoff.net/2024/01/03/1%EF%B8%8F%E2%83%A3%EF%B8%8F-1brc-in-sql-with-duckdb/), by Robin Moffatt (blog post)\n* [1 billion rows challenge in PostgreSQL and ClickHouse](https://ftisiot.net/posts/1brows/), by Francesco Tisiot (blog post)\n* [The One Billion Row Challenge with Snowflake](https://medium.com/snowflake/the-one-billion-row-challenge-with-snowflake-f612ae76dbd5), by Sean Falconer (blog post)\n* [One billion row challenge using base R](https://www.r-bloggers.com/2024/01/one-billion-row-challenge-using-base-r/), by  David Schoch (blog post)\n* [1 Billion Row Challenge with Apache Pinot](https://hubertdulay.substack.com/p/1-billion-row-challenge-in-apache), by Hubert Dulay (blog post)\n* [One Billion Row Challenge In C](https://www.dannyvankooten.com/blog/2024/1brc/), by Danny Van Kooten (blog post)\n* [One Billion Row Challenge in Racket](https://defn.io/2024/01/10/one-billion-row-challenge-in-racket/), by Bogdan Popa (blog post)\n* [The One Billion Row Challenge - .NET Edition](https://dev.to/mergeconflict/392-the-one-billion-row-challenge-net-edition), by Frank A. Krueger (podcast)\n* [One Billion Row Challenge](https://curiouscoding.nl/posts/1brc/), by Ragnar Groot Koerkamp (blog post)\n* [ClickHouse and The One Billion Row Challenge](https://clickhouse.com/blog/clickhouse-one-billion-row-challenge), by Dale McDiarmid (blog post)\n* [One Billion Row Challenge & Azure Data Explorer](https://nielsberglund.com/post/2024-01-28-one-billion-row-challenge--azure-data-explorer/), by Niels Berglund (blog post)\n* [One Billion Row Challenge - view from sidelines](https://www.chashnikov.dev/post/one-billion-row-challenge-view-from-sidelines), by Leo Chashnikov (blog post)\n* [1 billion row challenge in SQL and Oracle Database](https://geraldonit.com/2024/01/31/1-billion-row-challenge-in-sql-and-oracle-database/), by Gerald Venzl (blog post)\n* [One Billion Row Challenge: Learned So Far](https://gamlor.info/posts-output/2024-01-12-one-billion-row-challenge/en/), by Roman Stoffel (blog post)\n* [One Billion Row Challenge in Racket](https://defn.io/2024/01/10/one-billion-row-challenge-in-racket/), by Bogdan Popa (blog post)\n* [The 1 Billion row challenge with Singlestore](https://medium.com/@testily/the-1-billion-row-challenge-with-singlestore-224ce97e451f), by Anna Semjen (blog post)\n* [1BRC in .NET among fastest on Linux: My Optimization Journey](https://hotforknowledge.com/2024/01/13/1brc-in-dotnet-among-fastest-on-linux-my-optimization-journey/), by Victor Baybekov (blog post)\n* [One Billion Rows – Gerald’s Challenge](https://connor-mcdonald.com/2024/02/03/one-billion-rows-geralds-challenge/), by Connor McDonald (blog post)\n* [Reading a file insanely fast in Java](https://rmannibucau.metawerx.net/reading-a-file-insanely-fast-in-java.html), by Romain Manni-Bucau (blog post)\n* [#1BRC Timeline](https://tivrfoa.github.io/java/benchmark/performance/2024/02/05/1BRC-Timeline.html), by tivrfoa (blog post)\n* [1BRC - What a Journey](https://www.esolutions.tech/1brc-what-a-journey), by Marius Staicu (blog post)\n* [One Billion Rows Challenge in Golang](https://www.bytesizego.com/blog/one-billion-row-challenge-go), by Shraddha Agrawal (blog post)\n* [The Billion Row Challenge (1BRC) - Step-by-step from 71s to 1.7s](https://questdb.io/blog/billion-row-challenge-step-by-step/) by Marko Topolnik (blog post)\n* [Entering The One Billion Row Challenge With GitHub Copilot](https://devblogs.microsoft.com/java/entering-the-one-billion-row-challenge-with-github-copilot/) by Antonio Goncalves (blog post)\n* [DataFrame and The One Billion Row Challenge--How to use a Java DataFrame to save developer time, produce readable code, and not win any prizes](https://medium.com/@zakhav/dataframe-and-one-billion-row-challenge-97b3d0255dd1) by Vladimir Zakharov (blog post)\n## License\n\nThis code base is available under the Apache License, version 2.\n\n## Code of Conduct\n\nBe excellent to each other!\nMore than winning, the purpose of this challenge is to have fun and learn something new.\n"
  },
  {
    "path": "calculate_average_0xshivamagarwal.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\nif [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n    JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\nfi\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_0xshivamagarwal\n"
  },
  {
    "path": "calculate_average_3j5a.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--add-opens=java.base/jdk.internal.util=ALL-UNNAMED\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_3j5a\n"
  },
  {
    "path": "calculate_average_AbstractKamen.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_AbstractKamen\n"
  },
  {
    "path": "calculate_average_AlexanderYastrebov.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nINPUT=${1:-\"measurements.txt\"}\n\ntarget/AlexanderYastrebov/1brc \"$INPUT\"\n"
  },
  {
    "path": "calculate_average_C5H12O5.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_C5H12O5\n"
  },
  {
    "path": "calculate_average_ChrisBellew.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--add-modules jdk.incubator.vector --enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_chrisbellew"
  },
  {
    "path": "calculate_average_EduardoSaverin.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_EduardoSaverin\n"
  },
  {
    "path": "calculate_average_JaimePolidura.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_JaimePolidura_image ]; then\n\ttarget/CalculateAverage_JaimePolidura_image\nelse\n\techo \"Native image not found. Running in JVM mode\"\n\tJAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+UseTransparentHugePages -XX:+TrustFinalNonStaticFields\"\n\tjava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_JaimePolidura\nfi\n\n\n"
  },
  {
    "path": "calculate_average_JamalMulla.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\n\nif [ -f target/CalculateAverage_JamalMulla_image ]; then\n    target/CalculateAverage_JamalMulla_image\nelse\n    JAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -XX:+UseTransparentHugePages -XX:-TieredCompilation\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_JamalMulla\nfi"
  },
  {
    "path": "calculate_average_JesseVanRooy.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview -XX:-TieredCompilation -Dsun.stdout.encoding=UTF-8\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_JesseVanRooy\n"
  },
  {
    "path": "calculate_average_Judekeyser.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_Judekeyser\n"
  },
  {
    "path": "calculate_average_JurenIvan.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_JurenIvan\n"
  },
  {
    "path": "calculate_average_Kidlike.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f ./target/image_calculateaverage_Kidlike ]; then\n    ./target/image_calculateaverage_Kidlike\nelse\n    # -XX:+UseEpsilonGC\n    JAVA_OPTS=\"--enable-preview -Xms18g -Xmx18g -XX:+UnlockExperimentalVMOptions\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_Kidlike\nfi\n"
  },
  {
    "path": "calculate_average_MahmoudFawzyKhalil.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_MahmoudFawzyKhalil\n"
  },
  {
    "path": "calculate_average_MeanderingProgrammer.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_MeanderingProgrammer\n"
  },
  {
    "path": "calculate_average_PanagiotisDrakatos.sh",
    "content": "#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\nJAVA_OPTS=\"--enable-preview -Xms1536m  -Xmx10536m -XX:NewSize=256m -XX:MaxNewSize=512m -XX:MaxMetaspaceSize=512m -XX:+DisableExplicitGC -XX:+UseSerialGC -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_PanagiotisDrakatos\n"
  },
  {
    "path": "calculate_average_PawelAdamski.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xnoclassgc\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_PawelAdamski\n"
  },
  {
    "path": "calculate_average_SamuelYvon.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# THIS IS A DIRECT COPY OF royvanrijn's CALCULATE SCRIPT; I AM NOT FAMILIAR WITH AOT STUFF ON JAVA.\n# THANKS royvanrijn!!\n\nif [ -f target/CalculateAverage_SamuelYvon_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_SamuelYvon_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_SamuelYvon_image\nelse\n    JAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\n    if [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n        # On OS/X, my machine, this errors:\n        JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\n    fi\n    echo \"Choosing to run the app in JVM mode as no native image was found, use additional_build_step_SamuelYvon.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_SamuelYvon\nfi\n"
  },
  {
    "path": "calculate_average_Smoofie.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_Smoofie\n"
  },
  {
    "path": "calculate_average_Ujjwalbharti.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_Ujjwalbharti\n"
  },
  {
    "path": "calculate_average_YannMoisan.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_YannMoisan\n"
  },
  {
    "path": "calculate_average_abeobk.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_abeobk_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_abeobk_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_abeobk_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_abeobk.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_abeobk\nfi\n\n"
  },
  {
    "path": "calculate_average_abfrmblr.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview -Xms2g -Xmx2g\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_abfrmblr\n"
  },
  {
    "path": "calculate_average_adriacabeza.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-XX:+UseStringDeduplication -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+AlwaysPreTouch\"\njava --enable-preview  -classpath target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_adriacabeza\n\n"
  },
  {
    "path": "calculate_average_agoncal.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# sdk use java 21.0.1-tem\n\nJAVA_OPTS=\"--enable-preview -XX:+UseShenandoahGC -XX:+UseStringDeduplication -da\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_agoncal"
  },
  {
    "path": "calculate_average_ags313.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-server -Xnoclassgc -Xmx1G\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ags313\n"
  },
  {
    "path": "calculate_average_albertoventurini.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xnoclassgc\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_albertoventurini\n"
  },
  {
    "path": "calculate_average_alesj.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_alesj\n"
  },
  {
    "path": "calculate_average_algirdasrascius.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_algirdasrascius\n"
  },
  {
    "path": "calculate_average_anandmattikopp.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_anandmattikopp\n"
  },
  {
    "path": "calculate_average_anestoruk.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_anestoruk\n"
  },
  {
    "path": "calculate_average_anitasv.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_anitasv\n"
  },
  {
    "path": "calculate_average_arjenvaneerde.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_arjenvaneerde\n"
  },
  {
    "path": "calculate_average_arjenw.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms500m -Xmx500m --enable-preview -dsa -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:-AlwaysPreTouch\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_arjenw $@\n"
  },
  {
    "path": "calculate_average_armandino.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_armandino_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_armandino_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_armandino_image\nelse\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_armandino.sh to generate.\" 1>&2\n    JAVA_OPTS=\"--enable-preview -da -dsa -Xms128m -Xmx128m -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+AlwaysPreTouch\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_armandino\nfi\n"
  },
  {
    "path": "calculate_average_artpar.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_artpar\n"
  },
  {
    "path": "calculate_average_artsiomkorzun.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_artsiomkorzun_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_artsiomkorzun_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_artsiomkorzun_image\nelse\n    JAVA_OPTS=\"--enable-preview -Xmx128m -XX:+UseSerialGC -XX:-TieredCompilation\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_artsiomkorzun.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_artsiomkorzun\nfi"
  },
  {
    "path": "calculate_average_as-com.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector -XX:+UnlockExperimentalVMOptions -XX:ActiveProcessorCount=8 -Xms500m -Xmx500m -XX:CompilationMode=high-only -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_asun\n"
  },
  {
    "path": "calculate_average_baseline.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_baseline\n"
  },
  {
    "path": "calculate_average_baseline_original_rounding.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_baseline_original_rounding\n"
  },
  {
    "path": "calculate_average_berry120.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n#sdk use java 21.0.1-amzn\nJAVA_OPTS=\"-Xlog:gc=error --enable-preview --add-modules=jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_berry120\n"
  },
  {
    "path": "calculate_average_bjhara.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_bjhara\n"
  },
  {
    "path": "calculate_average_breejesh.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_breejesh\n"
  },
  {
    "path": "calculate_average_bytesfellow.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms12g -Xmx12g -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:-OmitStackTraceInFastThrow \" \njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_bytesfellow\n"
  },
  {
    "path": "calculate_average_cb0s.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Arguments\nJAVA_OPTS=\"--enable-preview -XX:MaxGCPauseMillis=1 -XX:-AlwaysPreTouch -XX:+UseParallelGC -XX:+TieredCompilation\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_cb0s\n"
  },
  {
    "path": "calculate_average_charlibot.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_charlibot\n"
  },
  {
    "path": "calculate_average_cliffclick.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_cliffclick\n"
  },
  {
    "path": "calculate_average_coolmineman.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_coolmineman\n"
  },
  {
    "path": "calculate_average_couragelee.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_couragelee\n"
  },
  {
    "path": "calculate_average_criccomini.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\n#JAVA_OPTS=\"-XX:+UseZGC -server -Xms700m -Xlog:gc\"\nJAVA_OPTS=\"-XX:+UseZGC -Xms700m\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_criccomini\n"
  },
  {
    "path": "calculate_average_davecom.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_davecom\n"
  },
  {
    "path": "calculate_average_davery22.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_davery22\n"
  },
  {
    "path": "calculate_average_ddimtirov.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# --enable-preview to use the new memory mapped segments\n# We don't allocate much, so just give it 1G heap and turn off GC; the AlwaysPreTouch was suggested by the ergonomics\n# Experimenting on the target VM config with various memory tweaks showed that UseTransparentHugePages gives us 10% boost\nJAVA_OPTS=\"--enable-preview -da -dsa -Xms1g -Xmx1g -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC  -XX:+AlwaysPreTouch -XX:+UseTransparentHugePages\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ddimtirov\n"
  },
  {
    "path": "calculate_average_deemkeen.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_deemkeen\n"
  },
  {
    "path": "calculate_average_dkarampi.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-XX:+AlwaysCompileLoopMethods\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_dkarampi\n"
  },
  {
    "path": "calculate_average_dmitry-midokura.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\n#JAVA_OPTS=\"-verbose:gc\"\nJAVA_OPTS=\"--enable-preview -Xmx128m -XX:+UseSerialGC -XX:-TieredCompilation\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_bufistov $1 $2\n"
  },
  {
    "path": "calculate_average_dpsoft.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:-EnableJVMCI -XX:+UseEpsilonGC -Xms128m -Xmx128m -XX:+AlwaysPreTouch -XX:+UseTransparentHugePages -XX:-TieredCompilation -XX:+TrustFinalNonStaticFields\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_dpsoft"
  },
  {
    "path": "calculate_average_dqhieuu.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_dqhieuu\n"
  },
  {
    "path": "calculate_average_ebarlas.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_ebarlas_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_ebarlas_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_ebarlas_image\nelse\n    echo \"Choosing to run the app in JVM mode as no native image was found, use prepare_ebarlas.sh to generate.\" 1>&2\n    java --enable-preview --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ebarlas\nfi\n"
  },
  {
    "path": "calculate_average_elh.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\ntarget/elh/1brc-go\n"
  },
  {
    "path": "calculate_average_entangled90.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_entangled90\n"
  },
  {
    "path": "calculate_average_eriklumme.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms6g -Xmx6g\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_eriklumme\n"
  },
  {
    "path": "calculate_average_faridtmammadov.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_faridtmammadov\n\n"
  },
  {
    "path": "calculate_average_fatroom.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-server -Xnoclassgc -Xms16G -Xmx16G\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_fatroom\n"
  },
  {
    "path": "calculate_average_felix19350.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# ParallelGC test - Time (measured by evaluate2.sh): 00:33.130\n# JAVA_OPTS=\"--enable-preview -XX:+UseParallelGC -XX:+UseTransparentHugePages\"\n\n# G1GC test - Time (measured by evaluate2.sh):  00:26.447\n# JAVA_OPTS=\"--enable-preview -XX:+UseG1GC -XX:+UseTransparentHugePages\"\n\n# ZGC test - Time (measured by evaluate2.sh): 00:22.813\nJAVA_OPTS=\"--enable-preview -XX:+UseZGC -XX:+UseTransparentHugePages\"\n\n# EpsilonGC test - for now doesnt work because heap space gets exhausted\n#JAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+AlwaysPreTouch\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_felix19350\n"
  },
  {
    "path": "calculate_average_filiphr.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_filiphr\n"
  },
  {
    "path": "calculate_average_flippingbits.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--add-modules=jdk.incubator.vector --enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_flippingbits\n"
  },
  {
    "path": "calculate_average_fragmede.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-Xmx16g\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_fragmede measurements.txt\n\n"
  },
  {
    "path": "calculate_average_gabrielfoo.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xmx64m\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+AlwaysPreTouch\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+TrustFinalNonStaticFields -XX:InlineSmallCode=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:CICompilerCount=2 -XX:CompileThreshold=1000\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gabrielfoo"
  },
  {
    "path": "calculate_average_gabrielreid.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gabrielreid\n"
  },
  {
    "path": "calculate_average_gamlerhart.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xmx512m -Xlog:all=error\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gamlerhart\n"
  },
  {
    "path": "calculate_average_gauravdeshmukh.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gauravdeshmukh\n"
  },
  {
    "path": "calculate_average_gigiblender.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gigiblender\n"
  },
  {
    "path": "calculate_average_giovannicuccu.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector -XX:-TieredCompilation\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_giovannicuccu\n"
  },
  {
    "path": "calculate_average_gnabyl.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"-XX:+UseStringDeduplication\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gnabyl\n"
  },
  {
    "path": "calculate_average_gnmathur.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gnmathur\n"
  },
  {
    "path": "calculate_average_godofwharf.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector -DpageSize=262144 -XX:+UseParallelGC -Xms2600m -XX:ParallelGCThreads=8 -XX:Tier4CompileThreshold=1000 -XX:Tier3CompileThreshold=500 -XX:Tier3CompileThreshold=250 -Dthreads=9 -Djava.util.concurrent.ForkJoinPool.common.parallelism=9\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_godofwharf 2>/dev/null"
  },
  {
    "path": "calculate_average_gonix.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\nexec cat < <(exec java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gonix)\n"
  },
  {
    "path": "calculate_average_gonixunsafe.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\n# Copied from @serkan-ozal\n# Unsure if it helps (maybe something within ~10ms),\n# but at least it doesn't seem to make anything worse.\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:MaxInlineSize=10000 -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-UseCountedLoopSafepoints -XX:GuaranteedSafepointInterval=0\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+TrustFinalNonStaticFields -da -dsa -XX:+UseNUMA -XX:-EnableJVMCI\"\nif [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\nfi\n\nexec cat < <(exec java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_gonixunsafe)\n"
  },
  {
    "path": "calculate_average_hallvard.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_hallvard\n"
  },
  {
    "path": "calculate_average_hchiorean.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms1000M -Xmx16G\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_hchiorean\n"
  },
  {
    "path": "calculate_average_hundredwatt.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_hundredwatt\n"
  },
  {
    "path": "calculate_average_ianopolous.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ianopolous\n"
  },
  {
    "path": "calculate_average_ianopolousfast.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0 -XX:-UseTransparentHugePages\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ianopolousfast\n"
  },
  {
    "path": "calculate_average_imrafaelmerino.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms1024m -Xms1024m -XX:+UseParallelGC -XX:MaxHeapFreeRatio=10 -XX:ParallelGCThreads=2\"\nCHUNK_SIZE=$((50 * 1024 * 1024))\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar \\\ndev.morling.onebrc.CalculateAverage_imrafaelmerino $CHUNK_SIZE\n"
  },
  {
    "path": "calculate_average_isolgpus.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_isolgpus\n"
  },
  {
    "path": "calculate_average_itaske.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_itaske\n"
  },
  {
    "path": "calculate_average_ivanklaric.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ivanklaric\n"
  },
  {
    "path": "calculate_average_iziamos.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nif [ -f target/CalculateAverage_iziamos_image ]; then\n    echo \"Using graal\" 1>&2\n    target/CalculateAverage_iziamos_image\nelse\n    echo \"Using openjdk\" 1>&2\n    JAVA_OPTS=\"--enable-preview\n      -XX:+UnlockExperimentalVMOptions \\\n      -XX:+UseEpsilonGC -Xms16m -Xmx16m -XX:-AlwaysPreTouch \\\n      -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:CompilationMode=high-only \\\n      -XX:C1MaxTrivialSize=500 -XX:-UseCountedLoopSafepoints -XX:+UseCMoveUnconditionally -XX:+DisableAttachMechanism \\\n      -XX:-PreserveFramePointer -Xnoclassgc -disablesystemassertions -XX:-UsePerfData  \\\n      -XX:-UseTransparentHugePages -XX:-UseCompressedOops\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_iziamos\nfi\n"
  },
  {
    "path": "calculate_average_japplis.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_japplis $*\n"
  },
  {
    "path": "calculate_average_jatingala.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jatingala\n"
  },
  {
    "path": "calculate_average_javamak.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xmx25G -Xms15G -XX:+UseParallelGC\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_javamak\n"
  },
  {
    "path": "calculate_average_jbachorik.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xmx512m -Xms512m\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jbachorik $@\n"
  },
  {
    "path": "calculate_average_jeevjyot.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jeevjyot\n"
  },
  {
    "path": "calculate_average_jerrinot.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# -XX:+UnlockDiagnosticVMOptions -XX:PrintAssemblyOptions=intel -XX:CompileCommand=print,*.CalculateAverage_mtopolnik::recordMeasurementAndAdvanceCursor\"\n# -XX:InlineSmallCode=10000 -XX:-TieredCompilation -XX:CICompilerCount=2 -XX:CompileThreshold=1000\\\nif [ -f target/CalculateAverage_jerrinot_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_jerrinot_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_jerrinot_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    echo \"Choosing to run the app in JVM mode as no native image was found, use prepare_jerrinot.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jerrinot\nfi\n"
  },
  {
    "path": "calculate_average_jgrateron.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jgrateron\n"
  },
  {
    "path": "calculate_average_jincongho.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector --enable-native-access=ALL-UNNAMED\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jincongho"
  },
  {
    "path": "calculate_average_jonathan-aotearoa.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_jonathan-aotearoa_image ]; then\n    echo \"Using native image 'target/CalculateAverage_jonathan-aotearoa_image'. Delete this file to select JVM mode.\" 1>&2\n    target/CalculateAverage_jonathan-aotearoa_image\nelse\n    JAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\n    JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\n    echo \"Running in JVM mode as no native image was found. Run 'prepare_jonathan-aotearoa.sh' to generate a native image.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jonathanaotearoa\nfi\n\n"
  },
  {
    "path": "calculate_average_jotschi.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jotschi\n\n"
  },
  {
    "path": "calculate_average_jparera.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector -XX:-TieredCompilation\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_jparera\n"
  },
  {
    "path": "calculate_average_justplainlaake.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_justplainlaake_image ]; then #if there is a native image, then lets run it. Else fallback to standard java execution\n    target/CalculateAverage_justplainlaake_image\nelse\n    java -XX:+UseG1GC --enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_justplainlaake\nfi\n\n"
  },
  {
    "path": "calculate_average_karthikeyan97.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xms10240m -Xmx40960m \"\n\nif [ -f target/CalculateAverage_karthikeyan97_image ]; then\n    #echo \"Picking up existing native image 'target/CalculateAverage_karthikeyan97_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_karthikeyan97_image -Xms10240m -Xmx40960m\nelse\n    #echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_karthikeyan97.sh to generate.\" 1>&2\n    java -Xms10240m -Xmx40960m  --enable-preview --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_karthikeyan97\n\nfi\n\n\n"
  },
  {
    "path": "calculate_average_kevinmcmurtrie.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_kevinmcmurtrie $1\n"
  },
  {
    "path": "calculate_average_kgeri.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS -Xmx99M --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_kgeri\n"
  },
  {
    "path": "calculate_average_khmarbaise.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Duser.language=en-US\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_khmarbaise\n"
  },
  {
    "path": "calculate_average_kuduwa-keshavram.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_kuduwa_keshavram\n"
  },
  {
    "path": "calculate_average_kumarsaurav123.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-Xms16G -Xmx32G --enable-preview\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_kumarsaurav123\n"
  },
  {
    "path": "calculate_average_lawrey.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS -Xmx99m --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_lawrey\n"
  },
  {
    "path": "calculate_average_linl33.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-Xrs --enable-preview --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions\"\nJAVA_OPTS=\"${JAVA_OPTS} -Xms128m -XX:+AlwaysPreTouch -XX:+AlwaysPreTouchStacks -XX:-UseTransparentHugePages\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseCompressedClassPointers -XX:+ForceUnreachable -XX:-CompactStrings\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:CodeEntryAlignment=64 -XX:OptoLoopAlignment=64 -XX:MaxLoopPad=16 -XX:ObjectAlignmentInBytes=64\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseLoopPredicate -XX:LoopStripMiningIter=0 -XX:LoopStripMiningIterShortLoop=0\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseCountedLoopSafepoints -XX:GuaranteedSafepointInterval=0 -XX:AllocatePrefetchStyle=0\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+TrustFinalNonStaticFields -XX:LockingMode=2 -XX:+UseSystemMemoryBarrier\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseDynamicNumberOfCompilerThreads -XX:-UseDynamicNumberOfGCThreads\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:ArchiveRelocationMode=0 -XX:-UsePerfData -XX:-UseNotificationThread -XX:-CheckIntrinsics\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseZGC -XX:-ZProactive -XX:+ZCollectionIntervalOnly -XX:ZCollectionInterval=0 -XX:-ZUncommit -XX:-ZBufferStoreBarriers -XX:ZIndexDistributorStrategy=1\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+UseEpsilonGC -XX:-UseCompressedOops\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseParallelGC -XX:-UseCompressedOops\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseG1GC -XX:-UseCompressedOops\"\nJAVA_OPTS=\"${JAVA_OPTS} -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD=-1\"\nJAVA_OPTS=\"${JAVA_OPTS} -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8\"\n\nJAVA_OPTS=\"${JAVA_OPTS} -Xlog:all=off -Xverify:none -XX:SharedArchiveFile=target/CalculateAverage_linl33_dynamic.jsa\"\n\nMALLOC_ARENA_MAX=1 java ${JAVA_OPTS} --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_linl33 2>/dev/null\n"
  },
  {
    "path": "calculate_average_maeda6uiui.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_maeda6uiui\n"
  },
  {
    "path": "calculate_average_mahadev-k.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_mahadev_k\n"
  },
  {
    "path": "calculate_average_makohn.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_makohn\n"
  },
  {
    "path": "calculate_average_manishgarg90.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_manishgarg90\n"
  },
  {
    "path": "calculate_average_martin2038.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nif [ -f target/CalculateAverage_martin2038_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_martin2038_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_martin2038_image\nelse\n    \n    #JAVA_OPTS=\"--enable-preview\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_martin2038.sh to generate.\" 1>&2 \n    # JAVA_OPTS=\"-XX:-EnableJVMCI -Xms16g -Xmx16g -XX:+AlwaysPreTouch -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC\"\n    JAVA_OPTS=\"\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_martin2038\n\nfi\n"
  },
  {
    "path": "calculate_average_mattiz.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_mattiz\n"
  },
  {
    "path": "calculate_average_maximz101.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview -Xmx6g\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_maximz101\n"
  },
  {
    "path": "calculate_average_melgenek.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+AlwaysPreTouch\"\n# These flags are mostly copied from the shipilev's branch. They don't really give a predictable benefit, but they don't hurt either.\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:CompileThreshold=2048 -XX:-UseCountedLoopSafepoints -XX:+TrustFinalNonStaticFields\"\n\nif [[ \"$(uname -s)\" == \"Linux\" ]]; then\n    JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\nfi\n\n# https://stackoverflow.com/a/23378780/7221823\nlogicalCpuCount=$([ $(uname) = 'Darwin' ] &&\n                       sysctl -n hw.logicalcpu_max ||\n                       lscpu -p | egrep -v '^#' | wc -l)\n# The required heap is proportional to the number of cores.\n# There's roughly 6MB heap per thread required for the 10k problem.\nrequiredMemory=$(echo \"(l(15 + 6 * $logicalCpuCount)/l(2))\" | bc -l)\nheapSize=$(echo \"scale=0; 2^(($requiredMemory+1)/1)\" | bc)\n\nJAVA_OPTS=\"$JAVA_OPTS -Xms${heapSize}m -Xmx${heapSize}m\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_melgenek\n"
  },
  {
    "path": "calculate_average_merykitty.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector -XX:-TieredCompilation\" # -XX:+UnlockDiagnosticVMOptions -XX:PrintAssemblyOptions=intel -XX:CompileCommand=print,*.CalculateAverage_merykitty::iterate\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_merykitty\n"
  },
  {
    "path": "calculate_average_merykittyunsafe.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector --enable-native-access=ALL-UNNAMED\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_merykittyunsafe\n"
  },
  {
    "path": "calculate_average_moysesb.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-XX:+UseZGC --enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_moysesb\n"
  },
  {
    "path": "calculate_average_mtopolnik.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_mtopolnik_image ]; then\n    echo \"Using native image 'target/CalculateAverage_mtopolnik_image'\" 1>&2\n    target/CalculateAverage_mtopolnik_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    echo \"Native image not found, using JVM mode.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_mtopolnik\nfi\n"
  },
  {
    "path": "calculate_average_mudit-saxena.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --enable-preview --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_muditsaxena -Xmx16384m\n"
  },
  {
    "path": "calculate_average_netrunnereve.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_netrunnereve\n"
  },
  {
    "path": "calculate_average_obourgain.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# runs with -Xmx24m on my machine, playing it safe with a larger heap\nJAVA_OPTS=\"-Xmx64m --enable-preview\"\n# to use some black magic options\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions\"\n# no GC, not needed\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UseEpsilonGC -XX:+AlwaysPreTouch\"\n# my finals are really final\nJAVA_OPTS=\"$JAVA_OPTS -XX:+TrustFinalNonStaticFields\"\n# to get CalculateAverage_obourgain$OpenAddressingMap::getOrCreate to inline. A compile command wasn't enough, it was still hitting 'already compiled into a big method'\nJAVA_OPTS=\"$JAVA_OPTS -XX:InlineSmallCode=10000\"\n# seems to be a bit faster\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:CICompilerCount=2 -XX:CompileThreshold=1000\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_obourgain\n"
  },
  {
    "path": "calculate_average_omarchenko4j.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_omarchenko4j\n"
  },
  {
    "path": "calculate_average_padreati.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_padreati\n"
  },
  {
    "path": "calculate_average_palmr.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_palmr\n"
  },
  {
    "path": "calculate_average_parkertimmins.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_parkertimmins\n"
  },
  {
    "path": "calculate_average_pedestrianlove.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_pedestrianlove\n"
  },
  {
    "path": "calculate_average_phd3.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# -agentpath:/Users/phd3/tools/async-profiler-2.9-macos/build/libasyncProfiler.so=start,event=cpu,file=profile.html\nJAVA_OPTS=\"\"\njava $JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_phd3\n"
  },
  {
    "path": "calculate_average_plbpietrz.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS -Xmx99m --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_plbpietrz\n"
  },
  {
    "path": "calculate_average_plevart.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules=jdk.incubator.vector\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:InlineSmallCode=15000 -XX:FreqInlineSize=400 -XX:MaxInlineSize=400\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_plevart $*\n"
  },
  {
    "path": "calculate_average_raipc.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--add-opens=java.base/java.lang=ALL-UNNAMED --add-opens java.base/jdk.internal.util=ALL-UNNAMED\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms128M -Xmx128M -XX:-AlwaysPreTouch -XX:-TieredCompilation -XX:CICompilerCount=1\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_raipc\n"
  },
  {
    "path": "calculate_average_rby.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_rby\n"
  },
  {
    "path": "calculate_average_rcasteltrione.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\ntime java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_rcasteltrione\n"
  },
  {
    "path": "calculate_average_ricardopieper.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_ricardopieper\n"
  },
  {
    "path": "calculate_average_richardstartin.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_richardstartin\n"
  },
  {
    "path": "calculate_average_roman-r-m.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_roman_r_m_image ]; then\n    echo \"Running native image 'target/CalculateAverage_roman_r_m_image'.\" 1>&2\n    target/CalculateAverage_roman_r_m_image\nelse\n    JAVA_OPTS=\"--enable-preview -XX:+UseTransparentHugePages\"\n    JAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\n    # epsilon GC needs enough memory or it makes things worse\n    # see https://stackoverflow.com/questions/58087596/why-are-repeated-memory-allocations-observed-to-be-slower-using-epsilon-vs-g1\n    JAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:-EnableJVMCI -XX:+UseEpsilonGC -Xmx1G -Xms1G -XX:+AlwaysPreTouch\"\n\n    echo \"Running on JVM\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_roman_r_m\nfi\n"
  },
  {
    "path": "calculate_average_royvanrijn.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_royvanrijn_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_royvanrijn_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_royvanrijn_image\nelse\n    JAVA_OPTS=\"--enable-preview -XX:+UnlockExperimentalVMOptions -XX:+TrustFinalNonStaticFields -dsa -XX:+UseNUMA\"\n    if [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n        # On OS/X, my machine, this errors:\n        JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\n    fi\n    echo \"Choosing to run the app in JVM mode as no native image was found, use additional_build_step_royvanrijn.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_royvanrijn\nfi\n\n"
  },
  {
    "path": "calculate_average_rprabhu.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_rprabhu\n"
  },
  {
    "path": "calculate_average_santanu.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_santanu\n"
  },
  {
    "path": "calculate_average_seijikun.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-XX:+UseParallelGC --enable-preview --add-modules jdk.incubator.vector\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_seijikun\n"
  },
  {
    "path": "calculate_average_semotpan.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_semotpan\n"
  },
  {
    "path": "calculate_average_serkan-ozal.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --enable-native-access=ALL-UNNAMED --add-modules=jdk.incubator.vector \"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:MaxInlineSize=10000 -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-UseCountedLoopSafepoints -XX:LoopStripMiningIter=0 -XX:GuaranteedSafepointInterval=0\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+TrustFinalNonStaticFields -da -dsa -XX:+UseNUMA -XX:-EnableJVMCI\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:SharedArchiveFile=target/CalculateAverage_serkan_ozal_cds.jsa\"\nJAVA_OPTS=\"$JAVA_OPTS -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\nif [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\nfi\n\n#echo \"Process started at $(date +%s%N | cut -b1-13)\"\neval \"exec 3< <({ java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_serkan_ozal; })\"\nread <&3 result\necho -e \"$result\"\n#echo \"Process finished at $(date +%s%N | cut -b1-13)\"\n"
  },
  {
    "path": "calculate_average_shipilev.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -Xms1g -Xmx1g -XX:-AlwaysPreTouch -XX:+UseTransparentHugePages\n-XX:-TieredCompilation -XX:-UseCountedLoopSafepoints -XX:+TrustFinalNonStaticFields -XX:CompileThreshold=2048\n--add-opens java.base/java.nio=ALL-UNNAMED --add-exports java.base/jdk.internal.ref=ALL-UNNAMED\n-XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=quiet\n-XX:CompileCommand=dontinline,dev.morling.onebrc.CalculateAverage_shipilev\\$ParsingTask::seqCompute\n-XX:CompileCommand=dontinline,dev.morling.onebrc.CalculateAverage_shipilev\\$MeasurementsMap::updateSlow\n-XX:CompileCommand=inline,dev.morling.onebrc.CalculateAverage_shipilev\\$Bucket::matches\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_shipilev\n"
  },
  {
    "path": "calculate_average_slovdahl.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"${JAVA_OPTS} --enable-preview -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions\"\nJAVA_OPTS=\"${JAVA_OPTS} -Xmx8g -Xms8g\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+TrustFinalNonStaticFields -XX:-UseCompressedOops\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_slovdahl\n"
  },
  {
    "path": "calculate_average_spullara.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_spullara\n\n"
  },
  {
    "path": "calculate_average_stephenvonworley.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_stephenvonworley_image ]; then\n    target/CalculateAverage_stephenvonworley_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_stephenvonworley.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_stephenvonworley\nfi\n\n"
  },
  {
    "path": "calculate_average_sudhirtumati.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview -Xmx128m -XX:+UseSerialGC -XX:-TieredCompilation\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_sudhirtumati\n"
  },
  {
    "path": "calculate_average_thanhtrinity.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_thanhtrinity"
  },
  {
    "path": "calculate_average_thomaswue.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_thomaswue_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_thomaswue_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_thomaswue_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_thomaswue.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_thomaswue\nfi\n\n"
  },
  {
    "path": "calculate_average_tivrfoa.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_tivrfoa_image ]; then\n    target/CalculateAverage_tivrfoa_image\nelse\n    JAVA_OPTS=\"--enable-preview\"\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_tivrfoa\nfi\n\n"
  },
  {
    "path": "calculate_average_tkosachev.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_tkosachev\n"
  },
  {
    "path": "calculate_average_tonivade.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xmx1G -Xms1G -XX:+AlwaysPreTouch -XX:+UseParallelGC -XX:-UseCompressedOops --enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_tonivade\n"
  },
  {
    "path": "calculate_average_truelive.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"-Xmx8G -Xms2G\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_truelive\n"
  },
  {
    "path": "calculate_average_twobiers.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"-XX:+UseShenandoahGC -XX:+UseStringDeduplication -XX:+UseTransparentHugePages -da\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_twobiers\n"
  },
  {
    "path": "calculate_average_unbounded.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview --add-modules jdk.incubator.vector -XX:-TieredCompilation  -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_unbounded\n"
  },
  {
    "path": "calculate_average_vaidhy.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_vaidhy\n"
  },
  {
    "path": "calculate_average_vemana.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Basics\nJAVA_OPTS=\"\"\nJAVA_OPTS=\"$JAVA_OPTS --enable-preview\"\nJAVA_OPTS=\"$JAVA_OPTS --add-exports java.base/jdk.internal.ref=ALL-UNNAMED\"\nJAVA_OPTS=\"$JAVA_OPTS --add-opens java.base/java.nio=ALL-UNNAMED\"\n#JAVA_OPTS=\"$JAVA_OPTS --add-modules jdk.incubator.vector\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockDiagnosticVMOptions\"\n\n# JIT parameters\n#JAVA_OPTS=\"$JAVA_OPTS -Xlog:class+load=info\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+LogCompilation\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+AlwaysCompileLoopMethods\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:TieredStopAtLevel=1\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:TieredStopAtLevel=1\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:CompileCommand=inline,*State.processLine()\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintAssembly\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:LogFile=../hotspot.log\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+DebugNonSafepoints\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:C1MaxInlineSize=150\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:C1InlineStackLimit=40\"\n\n#JAVA_OPTS=\"$JAVA_OPTS -XX:FreqInlineSize=500\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintCompilation\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintInlining\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:CompileThreshold=20 \"\n#JAVA_OPTS=\"$JAVA_OPTS -Xlog:async\"\n\n# GC parameters\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UseParallelGC\"\n\n#JAVA_OPTS=\"$JAVA_OPTS -Xlog:gc*=debug:file=/tmp/gc.log\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+UseEpsilonGC -Xlog:all=off\"\n#JAVA_OPTS=\"$JAVA_OPTS -XX:+PrintGC -XX:+PrintGCDetails\"\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_vemana \"$@\"\n"
  },
  {
    "path": "calculate_average_vemanaNonIdiomatic.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Basics\nJAVA_OPTS=\"\"\nJAVA_OPTS=\"$JAVA_OPTS --enable-preview\"\nJAVA_OPTS=\"$JAVA_OPTS --add-exports java.base/jdk.internal.ref=ALL-UNNAMED\"\nJAVA_OPTS=\"$JAVA_OPTS --add-opens java.base/java.nio=ALL-UNNAMED\"\n\n# JIT parameters\nJAVA_OPTS=\"$JAVA_OPTS -XX:+AlwaysCompileLoopMethods\"\n\n# GC parameters\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UseParallelGC\"\n\n\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_vemanaNonIdiomatic \"$@\"\n"
  },
  {
    "path": "calculate_average_xpmatteo.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nJAVA_OPTS=\"--enable-preview\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_xpmatteo\n\n"
  },
  {
    "path": "calculate_average_yavuztas.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_yavuztas_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_yavuztas_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_yavuztas_image\nelse\n    JAVA_OPTS=\"-XX:MaxGCPauseMillis=1 -XX:-AlwaysPreTouch -XX:+UseSerialGC -XX:+TieredCompilation --enable-preview\"\n    echo \"Choosing to run the app in JVM mode as no native image was found, use prepare_yavuztas.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_yavuztas\nfi\n"
  },
  {
    "path": "calculate_average_yehwankim23.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_yehwankim23\n"
  },
  {
    "path": "calculate_average_yemreinci.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nJAVA_OPTS=\"\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_yemreinci\n"
  },
  {
    "path": "calculate_average_yonatang.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# GC is overrated\nJAVA_OPTS=\"-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC -XX:+AlwaysPreTouch -Xms512m -Xmx512m\"\njava $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_yonatang\n"
  },
  {
    "path": "calculate_average_yourwass.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n\nJAVA_OPTS=\"-Xlog:all=off -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0 --enable-preview --enable-native-access=ALL-UNNAMED --add-modules jdk.incubator.vector\"\n\neval \"exec 3< <({ java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_yourwass; })\"\nread <&3 result\necho -e \"$result\"\n"
  },
  {
    "path": "calculate_average_zerninv.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -f target/CalculateAverage_zerninv_image ]; then\n    echo \"Picking up existing native image 'target/CalculateAverage_zerninv_image', delete the file to select JVM mode.\" 1>&2\n    target/CalculateAverage_zerninv_image\nelse\n    JAVA_OPTS=\"--enable-preview -Xmx512m -XX:+UseSerialGC -XX:-TieredCompilation\"\n    echo \"Chosing to run the app in JVM mode as no native image was found, use prepare_zerninv.sh to generate.\" 1>&2\n    java $JAVA_OPTS --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CalculateAverage_zerninv\nfi"
  },
  {
    "path": "checkout.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -x\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: checkout.sh <fork name>:<branch name>\"\n    exit 1\nfi\n\nparts=(${1//:/ })\necho \"  User: ${parts[0]}\"\necho \"Branch: ${parts[1]}\"\n\ngit branch -D ${parts[0]} &>/dev/null\n\ngit checkout -b ${parts[0]}\ngit fetch https://github.com/${parts[0]}/1brc.git ${parts[1]}\n# git fetch git@github.com:${parts[0]}/1brc.git ${parts[1]}\ngit reset --hard FETCH_HEAD\ngit rebase main\n"
  },
  {
    "path": "cleanup.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: cleanup.sh <fork name>\"\n    exit 1\nfi\n\ngit checkout .\ngit checkout main\ngit branch -D $1\ngit pull upstream main\n"
  },
  {
    "path": "create_fork.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -eo pipefail\n\nSOURCE_FORK=\"baseline\"\n\nusage() {\n  echo \"Usage: create_fork.sh [-s <source fork>] <fork name>\"\n  echo \"  -s <source fork>  The name of the fork to copy from (default: baseline)\"\n  echo \"  <fork name>       The name of the fork to create\"\n  exit 1\n}\n\n# Parse\nwhile getopts \":s:\" opt; do\n  case ${opt} in\n    s )\n      SOURCE_FORK=$OPTARG\n      ;;\n    \\? )\n      usage\n      exit 1\n      ;;\n    : )\n      echo \"Invalid option: $OPTARG requires an argument\" 1>&2\n      exit 1\n      ;;\n  esac\ndone\n\nFORK=${@:$OPTIND:1}\nif [ -z \"$FORK\" ]\n  then\n    usage\n    exit 1\nfi\n\n# validate the fork name has only [a-zA-Z0-9_] and then error otherwise to let the user fix\nif [[ ! \"$FORK\" =~ ^[a-zA-Z0-9_]+$ ]]; then\n  echo \"Fork name must only contain characters result in a valid Java class name  [a-zA-Z0-9_]\"\n  exit 1\nfi\n\n\n# helper function\nfunction substitute_in_file {\n  if [[ \"$OSTYPE\" == \"darwin\"* ]]; then\n    sed -i '' \"s/$1/$2/g\" $3\n  else\n    sed -i \"s/$1/$2/g\" $3\n  fi\n}\n\nset -x\n\n# create new fork\n\ncp -i prepare_$SOURCE_FORK.sh prepare_$FORK.sh\n\ncp -i calculate_average_$SOURCE_FORK.sh calculate_average_$FORK.sh\nsubstitute_in_file $SOURCE_FORK $FORK calculate_average_$FORK.sh\n\nif [ $SOURCE_FORK == \"baseline\" ]; then\n  cp -i src/main/java/dev/morling/onebrc/CalculateAverage_baseline.java src/main/java/dev/morling/onebrc/CalculateAverage_$FORK.java\n  substitute_in_file CalculateAverage_baseline CalculateAverage_$FORK src/main/java/dev/morling/onebrc/CalculateAverage_$FORK.java\nelse\n  cp -i src/main/java/dev/morling/onebrc/CalculateAverage_$SOURCE_FORK.java src/main/java/dev/morling/onebrc/CalculateAverage_$FORK.java\n  substitute_in_file $SOURCE_FORK $FORK src/main/java/dev/morling/onebrc/CalculateAverage_$FORK.java\nfi\n\n"
  },
  {
    "path": "create_measurements.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\njava --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CreateMeasurements $1\n"
  },
  {
    "path": "create_measurements2.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\njava --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CreateMeasurements2 $1\n"
  },
  {
    "path": "create_measurements3.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\njava --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CreateMeasurements3 $1\n"
  },
  {
    "path": "create_measurements_fast.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\njava --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.CreateMeasurementsFast $1\n"
  },
  {
    "path": "data/weather_stations.csv",
    "content": "# Adapted from https://simplemaps.com/data/world-cities\n# Licensed under Creative Commons Attribution 4.0 (https://creativecommons.org/licenses/by/4.0/)\nTokyo;35.6897\nJakarta;-6.1750\nDelhi;28.6100\nGuangzhou;23.1300\nMumbai;19.0761\nManila;14.5958\nShanghai;31.1667\nSão Paulo;-23.5500\nSeoul;37.5600\nMexico City;19.4333\nCairo;30.0444\nNew York;40.6943\nDhaka;23.7639\nBeijing;39.9040\nKolkāta;22.5675\nBangkok;13.7525\nShenzhen;22.5350\nMoscow;55.7558\nBuenos Aires;-34.5997\nLagos;6.4550\nIstanbul;41.0136\nKarachi;24.8600\nBangalore;12.9789\nHo Chi Minh City;10.7756\nŌsaka;34.6939\nChengdu;30.6600\nTehran;35.6892\nKinshasa;-4.3250\nRio de Janeiro;-22.9111\nChennai;13.0825\nXi’an;34.2667\nLahore;31.5497\nChongqing;29.5500\nLos Angeles;34.1141\nBaoding;38.8671\nLondon;51.5072\nParis;48.8567\nLinyi;35.1041\nDongguan;23.0475\nHyderābād;17.3850\nTianjin;39.1467\nLima;-12.0600\nWuhan;30.5872\nNanyang;32.9987\nHangzhou;30.2500\nFoshan;23.0292\nNagoya;35.1833\nTaipei;25.0375\nTongshan;34.2610\nLuanda;-8.8383\nZhoukou;33.6250\nGanzhou;25.8292\nKuala Lumpur;3.1478\nHeze;35.2333\nQuanzhou;24.9139\nChicago;41.8375\nNanjing;32.0608\nJining;35.4000\nHanoi;21.0283\nPune;18.5203\nFuyang;32.8986\nAhmedabad;23.0300\nJohannesburg;-26.2044\nBogotá;4.7111\nDar es Salaam;-6.8161\nShenyang;41.8025\nKhartoum;15.5006\nShangqiu;34.4259\nCangzhou;38.3037\nHong Kong;22.3000\nShaoyang;27.2418\nZhanjiang;21.1967\nYancheng;33.3936\nHengyang;26.8968\nRiyadh;24.6333\nZhumadian;32.9773\nSantiago;-33.4372\nXingtai;37.0659\nChattogram;22.3350\nBijie;27.3019\nShangrao;28.4419\nZunyi;27.7050\nSūrat;21.1702\nSurabaya;-7.2458\nHuanggang;30.4500\nMaoming;21.6618\nNanchong;30.7991\nXinyang;32.1264\nMadrid;40.4169\nBaghdad;33.3153\nQujing;25.5102\nJieyang;23.5533\nSingapore;1.3000\nPrayagraj;25.4358\nLiaocheng;36.4500\nDalian;38.9000\nYulin;22.6293\nChangde;29.0397\nQingdao;36.1167\nDouala;4.0500\nMiami;25.7840\nNangandao;35.2992\nPudong;31.2231\nXiangyang;32.0654\nDallas;32.7935\nHouston;29.7860\nZhengzhou;34.7492\nLu’an;31.7542\nDezhou;37.4513\nJinan;36.6667\nGiza;29.9870\nZhaotong;27.3328\nYichun;27.8041\nNairobi;-1.2864\nGuadalajara;20.6767\nPhiladelphia;40.0077\nAnkara;39.9300\nTai’an;36.2001\nDazhou;31.2152\nLangfang;39.5196\nYongzhou;26.4515\nToronto;43.7417\nSuihua;46.6384\nSaint Petersburg;59.9500\nQiqihar;47.3398\nSuzhou;33.6333\nMonterrey;25.6667\nBelo Horizonte;-19.9167\nWeinan;34.4996\nRangoon;16.7950\nZhangzhou;24.5093\nYuncheng;35.0304\nXianyang;34.3500\nGuilin;25.2819\nAtlanta;33.7628\nTaizhou;32.4831\nKāshān;33.9833\nBozhou;33.8626\nAbidjan;5.3167\nSuqian;33.9331\nHuaihua;27.5494\nJi’an;27.1172\nXiaoganzhan;30.9273\nPingdingshan;33.7350\nJiujiang;29.7048\nAlexandria;31.1975\nMianyang;31.4669\nSydney;-33.8678\nHuanglongsi;34.7950\nWashington;38.9047\nBarcelona;41.3825\nChangsha;28.1987\nChenzhou;25.7989\nAnqing;30.5000\nJiangmen;22.5833\nXinpu;34.5906\nYibin;28.7596\nYangzhou;32.3912\nMelbourne;-37.8142\nBerlin;52.5200\nHengshui;37.7348\nTimbío;2.3445\nKunming;25.0433\nYiyang;28.5833\nGuigang;23.0961\nChangchun;43.9000\nJiangguanchi;34.0244\nCasablanca;33.5333\nMeizhou;24.2998\nZhangjiakou;40.8108\nChifeng;42.2663\nÜrümqi;43.8225\nSuzhou;31.3000\nİzmir;38.4200\nLinfen;36.0812\nShantou;23.3735\nKabul;34.5253\nMogadishu;2.0392\nLuzhou;28.8918\nHefei;31.8639\nBoston;42.3188\nLiuzhou;24.3264\nZhaoqing;23.0500\nXiaoxita;30.7083\nShijiazhuang;38.0422\nNingbo;29.8750\nFuzhou;27.9814\nPhoenix;33.5722\nZhuzhou;27.8407\nAmman;31.9497\nChuzhou;32.3062\nJeddah;21.5433\nQingyuan;23.6842\nLoudi;27.7378\nBinzhou;37.3806\nDeyang;31.1289\nTaiyuan;37.8733\nKano;12.0000\nWuhu;31.3340\nNanning;22.8192\nHarbin;45.7500\nAbuja;9.0667\nYokohama;35.4442\nBaojishi;34.3609\nZaozhuang;34.8667\nXiamen;24.4797\nNeijiang;29.5872\nFuzhou;26.0769\nBaicheng;23.9010\nAnshan;41.1066\nMedan;3.5894\nYulinshi;38.2655\nWenzhou;27.9991\nChangzhou;31.8122\nPuyang;35.7639\nJiaozuo;35.2290\nNanchang;28.6842\nIbadan;7.3964\nHechi;24.6928\nDetroit;42.3834\nMontréal;45.5089\nBusan;35.1800\nHohhot;40.8151\nSeattle;47.6211\nAlgiers;36.7539\nHanzhong;33.0794\nTangshan;39.6292\nShiyan;32.6351\nLucknow;26.8500\nSiping;43.1715\nMashhad;36.3000\nBoankra;6.6944\nChangzhi;36.1953\nDubai;25.2631\nQinzhou;21.9500\nGuiyang;26.5794\nBengbu;32.9354\nSan Francisco;37.7558\nBazhou;31.8576\nQincheng;34.5809\nSuining;30.5098\nWuxi;31.5667\nLeshan;29.5854\nPutian;25.4394\nZhenjiang;32.2109\nFaisalabad;31.4167\nGuang’an;30.4673\nTongren;27.7233\nSanta Cruz;-17.7892\nQinhuangdao;39.9398\nTongliao;43.6172\nJinzhou;41.1144\nHeyuan;23.7503\nSan Diego;32.8313\nJaipur;26.9000\nXinzhou;38.4178\nLanzhou;36.0617\nWuzhou;23.4833\nAthens;37.9842\nAddis Ababa;9.0300\nChaoyang;41.5757\nBrasília;-15.7939\nTaichung;24.1439\nKuwait City;29.3697\nBudapest;47.4925\nShaoguan;24.8011\nShanwei;22.7664\nQuezon City;14.6300\nRizhao;35.4164\nKyiv;50.4500\nSanaa;15.3483\nMeishan;30.0575\nIncheon;37.4833\nGuatemala City;14.6099\nBirmingham;52.4800\nZhongshan;22.5333\nNingde;26.6617\nWeihai;37.5000\nDaqing;46.5979\nBursa;40.1833\nSalvador;-12.9747\nRome;41.8931\nHaikou;20.0200\nLa Paz;-16.5000\nXiangtan;27.8431\nPyongyang;39.0194\nMinneapolis;44.9635\nOmdurman;15.6500\nMalang;-7.9800\nMudanjiang;44.5861\nStuttgart;48.7775\nBrooklyn;40.6501\nKaohsiung;22.6150\nGuayaquil;-2.1900\nLisbon;38.7253\nLongyan;25.0881\nTieling;42.2841\nManchester;53.4794\nBaotou;40.6562\nHandan;36.6116\nCawnpore;26.4499\nDingxi;35.5806\nNanping;26.6448\nTampa;27.9945\nZigong;29.3498\nMaracaibo;10.6333\nChaozhou;23.6700\nMbuji-Mayi;-6.1500\nDenver;39.7620\nGulou;26.0865\nWeifang;36.7167\nHuai’an;33.5058\nZibo;36.7831\nAnkang;32.6877\nBaoshan;25.1211\nAntananarivo;-18.9333\nHuludao;40.7094\nMunich;48.1375\nYanjiang;30.1256\nSanto Domingo;18.4764\nSanming;26.2658\nTashkent;41.3111\nLongba;33.5350\nYangjiang;21.8556\nJiamusi;46.8081\nLuohe;33.5830\nLincang;23.8864\nMedellín;6.2308\nXuanzhou;30.9475\nYunfu;22.9242\nShaoxing;30.0000\nYantai;37.3997\nHuizhou;23.1115\nLishui;28.4500\nMirzāpur;25.1460\nHamburg;53.5500\nGuangyuan;32.4353\nCali;3.4206\nLusaka;-15.4167\nHuangshi;30.2018\nXining;36.6239\nOuagadougou;12.3686\nDaegu;35.8717\nFortaleza;-3.7275\nYaoundé;3.8667\nJilin;43.8519\nDandong;40.1167\nZhuhai;22.2769\nLianshan;40.7523\nYingkou;40.6653\nAntalya;36.8874\nNāgpur;21.1497\nQueens;40.7498\nAccra;5.5500\nBekasi;-6.2349\nGhāziābād;28.6700\nYuxi;24.3495\nLuoyang;34.6587\nBrisbane;-27.4678\nAnshun;26.2456\nDepok;-6.3940\nShangzhou;33.8680\nHuainan;32.4831\nColombo;6.9344\nKuaidamao;41.7302\nBaku;40.3667\nFukuoka;33.5833\nYan’an;36.5952\nJincheng;35.4906\nVancouver;49.2500\nNantong;31.9829\nTangerang;-6.1783\nCaracas;10.4806\nSanmenxia;34.7736\nLaibin;23.7333\nKonya;37.8667\nManaus;-3.1000\nEşfahān;32.6447\nQinbaling;35.7278\nBaltimore;39.3051\nMa’anshan;31.6858\nShengli;37.4500\nGaoping;30.7824\nTaizhou;28.6583\nHarare;-17.8292\nKowloon;22.3167\nLas Vegas;36.2333\nHavana;23.1367\nPerth;-31.9559\nPhnom Penh;11.5694\nPuning;23.2993\nHuaibei;33.9562\nQingyang;24.8141\nHaiphong;20.8651\nChongzuo;22.4167\nRawalpindi;33.6000\nYushan;31.3867\nSt. Louis;38.6359\nKumasi;6.6667\nVadodara;22.3000\nHezhou;24.4164\nPingliang;35.5412\nPortland;45.5371\nVishākhapatnam;17.7042\nGujranwala;32.1567\nBaicheng;45.6148\nGaziantep;37.0628\nFushun;41.8708\nRiverside;33.9381\nBamako;12.6458\nQuito;-0.2200\nMinsk;53.9000\nTijuana;32.5250\nBamenda;5.9614\nBoosaaso;11.2886\nIndore;22.7167\nŞanlıurfa;37.1583\nVienna;48.2083\nKaraj;35.8272\nKananga;-5.8970\nPeshawar;34.0144\nSapporo;43.0667\nEcatepec;19.6097\nPingxiang;27.6333\nOrlando;28.4773\nAleppo;36.2000\nSacramento;38.5677\nAlmaty;43.2775\nSan Juan;18.3985\nSan Antonio;29.4632\nYinchuan;38.4795\nThāne;19.1972\nSantos;-23.9369\nBlantyre;-15.7861\nBucharest;44.4325\nCuritiba;-25.4297\nMultan;30.1978\nTainan;22.9833\nXiping;40.0820\nPort Harcourt;4.8242\nWarsaw;52.2300\nJixi;45.2937\nSaidu Sharif;34.7500\nLiaoyang;41.2643\nBeihai;21.4667\nMeru;0.0500\nBrazzaville;-4.2694\nFuxin;42.0127\nWuwei;37.9278\nMersin;36.8000\nBhopāl;23.2500\nLubumbashi;-11.6647\nDenpasar;-8.6500\nDavao;7.0667\nShuyangzha;34.1299\nAdana;37.0000\nDamascus;33.5131\nBrussels;50.8467\nHyderabad City;25.3792\nDiyarbakır;37.9100\nSan Jose;37.3012\nChinchvad;18.6186\nMontevideo;-34.8836\nPittsburgh;40.4397\nShuozhou;39.3408\nCincinnati;39.1413\nBenxi;41.2920\nBaiyin;36.5448\nMosul;36.3400\nManhattan;40.7834\nCaloocan City;14.6500\nKampala;0.3136\nPatna;25.6000\nTegucigalpa;14.1000\nCleveland;41.4764\nSanzhou;30.8200\nChangshu;31.6500\nMecca;21.4225\nHeihe;50.2458\nJingdezhen;29.2942\nConakry;9.5092\nRecife;-8.0500\nIndianapolis;39.7771\nAustin;30.3005\nSangereng;-6.2889\nKansas City;39.1238\nZhongli;24.9650\nNovosibirsk;55.0333\nBilāspur;22.0900\nSemarang;-6.9667\nLudhiāna;30.9100\nNārāyanganj;23.6200\nStockholm;59.3294\nChengtangcun;35.0833\nĀgra;27.1800\nBalandougou;13.3558\nAgwār;27.1800\nLeón de los Aldama;21.1167\nYopougon;5.3167\nPuebla;19.0333\nMadurai;9.9252\nHebi;35.7497\nCórdoba;-31.4167\nShīrāz;29.6100\nJamshedpur;22.7925\nTabrīz;38.0814\nHuzhou;30.8925\nColumbus;39.9862\nSofia;42.7000\nKawasaki;35.5167\nSan José;9.9325\nAba;5.1167\nPalembang;-2.9861\nZhangjiajie;29.1255\nKōbe;34.6900\nJiaxing;30.7522\nCharlotte;35.2083\nGuiping;23.4000\nLianjiang;21.6146\nXimeicun;24.9633\nJianguang;28.1958\nYucheng;29.9888\nPanama City;8.9833\nXushan;30.1697\nBelém;-1.4558\nVirginia Beach;36.7335\nLeizhou;20.9147\nGwangju;35.1653\nNāsik;20.0000\nPorto Alegre;-30.0331\nValencia;10.1667\nOnitsha;6.1667\nAbu Dhabi;24.4667\nDaejeon;36.3510\nZapopan;20.7167\nBronx;40.8501\nYekaterinburg;56.8356\nHuazhou;32.6832\nKyōto;35.0117\nJinhua;29.1046\nAmsterdam;52.3728\nShuangyashan;46.6388\nPizhou;34.3422\nEl Kelaa des Srarhna;32.0481\nDakar;14.6928\nKharkiv;49.9925\nYangshe;31.8775\nGuyuan;36.0080\nRui’an;27.7780\nKhulna;22.8167\nMuscat;23.6139\nWenling;28.3797\nGaozhou;21.9135\nFarīdābād;28.4167\nChizhou;30.6583\nTel Aviv-Yafo;32.08\nUlaanbaatar;47.9203\nGoiânia;-16.6667\nFuqing;25.7232\nKayseri;38.7225\nWuzhong;37.9874\nBelgrade;44.8200\nPingdu;36.7833\nMilan;45.4669\nAurangābād;19.8800\nCopenhagen;55.6761\nYangquan;37.8576\nYutan;28.3147\nHuangshan;29.7132\nAuckland;-36.8406\nMakassar;-5.1619\nSantiago;19.4572\nMilwaukee;43.0642\nRājkot;22.3000\nPrague;50.0875\nSamsun;41.2903\nLiangshi;27.2578\nBarranquilla;10.9833\nSaitama;35.8614\nGuarulhos;-23.4628\nAl Başrah;30.5150\nMandalay;21.9831\nJuárez;31.7386\nXintai;35.9100\nWusong;30.9333\nMeerut;28.9800\nYushu;44.8249\nRongcheng;26.2312\nHuazhou;21.6540\nAdelaide;-34.9275\nBaishan;41.9377\nDayan;26.8808\nHaicheng;40.8523\nTripoli;32.8872\nJiangyin;31.9087\nYicheng;31.3697\nHuaiyin;33.5819\nPorto;41.1621\nCacuaco;-8.8053\nSoweto;-26.2678\nRosario;-32.9575\nCanagatan;18.0000\nHelsinki;60.1708\nJabalpur;23.1667\nProvidence;41.8230\nRucheng;32.3852\nNizhniy Novgorod;56.3269\nAhvāz;31.3203\nJepara;-6.5333\nShaoyang;32.9387\nComayagüela;14.0981\nLaiwu;36.1833\nSharjah;25.3575\nKalamboli;19.2333\nJingling;30.6667\nKazan;55.7964\nSuwon;37.2667\nYongcheng;33.9317\nSumedang;-6.8400\nCalgary;51.0500\nCần Thơ;10.0333\nYiwu;29.3081\nBagam;1.0833\nBeidao;34.6020\nVasai;19.4700\nXiangshui;26.5964\nJacksonville;30.3322\nAkçaabat;41.0167\nCampinas;-22.9058\nDadukou;26.5849\nMombasa;-4.0500\nLingcheng;22.7000\nNajafgarh;28.6092\nVila Velha;3.2167\nGāzipura;23.9889\nChelyabinsk;55.1500\nVārānasi;25.3189\nXinyu;27.7950\nQom;34.6400\nHargeysa;9.5631\nZhangye;38.9355\nHiroshima;34.3914\nMaiduguri;11.8333\nChiang Mai;18.7953\nDoha;25.2867\nMaputo;-25.9667\nMbandaka;0.0478\nPikine;14.7500\nMedina;24.4700\nSrīnagar;34.0900\nOmsk;54.9667\nDublin;53.3500\nLiaoyuan;42.8976\nCilacap;-7.7167\nYingtan;28.2333\nBandar Lampung;-5.4500\nSamara;53.2028\nGuankou;28.1417\nUlsan;35.5500\nDhanbād;23.7998\nDingzhou;38.5158\nLianyuan;27.6961\nRongcheng;29.8239\nKaiyuan;36.0656\nNay Pyi Taw;19.7475\nZhuji;29.7169\nKigali;-1.9536\nBukavu;-2.5000\nLeiyang;26.4179\nBafoussam;5.4667\nYichun;47.7235\nBenin City;6.3333\nRostov;47.2333\nXiantao;30.3833\nAmritsar;31.6400\nCallao;-12.0333\nSalt Lake City;40.7776\nAlīgarh;27.8800\nShagamu;6.8333\nYingchuan;34.1511\nCiudad Nezahualcóyotl;19.4081\nTbilisi;41.7225\nGuwāhāti;26.1722\nUfa;54.7261\nFès;34.0433\nSão Luís;-2.5283\nBiên Hòa;10.9500\nSevilla;37.2400\nN’Djamena;12.1100\nMexicali;32.6633\nNezahualcóyotl;19.4006\nIkare;7.5167\nNashville;36.1715\nTamale;9.4075\nXibeijie;39.7370\nYuyao;30.0372\nHāora;22.5800\nHanchuan;30.6520\nGongzhuling;43.5036\nKrasnoyarsk;56.0089\nCologne;50.9364\nBujumbura;-3.3833\nBishkek;42.8747\nZhufeng;36.0000\nSão Gonçalo;-22.8269\nYerevan;40.1814\nEzhou;30.3972\nNur-Sultan;51.1472\nTongjin;37.2333\nNouakchott;18.0858\nXiashi;30.5333\nRānchi;23.3600\nTaixing;32.1724\nVereeniging;-26.6736\nGwalior;26.2215\nZhongwei;37.5139\nGoyang;37.6500\nOslo;59.9133\nVijayavāda;16.5193\nChandīgarh;30.7500\nEdmonton;53.5344\nSendai;38.2682\nRaleigh;35.8324\nMizhou;35.9900\nTunis;36.8064\nXishan;27.6609\nBarquisimeto;10.0678\nHegang;47.3139\nVoronezh;51.6717\nPerm;58.0139\nChangwon;35.2708\nFangchenggang;21.6000\nShouguang;36.8833\nBogor;-6.5966\nCartagena;10.4000\nMatola;-25.9667\nJodhpur;26.2800\nMemphis;35.1087\nOgbomoso;8.1333\nRangapukur;25.5600\nManagua;12.1544\nSanya;18.2533\nShymkent;42.3167\nWutong;30.6326\nNiamey;13.5150\nShubrā al Khaymah;30.1286\nLinhai;28.8523\nDenizli;37.7667\nMaceió;-9.6658\nMonrovia;6.3133\nWafangdian;39.6271\nZhongxiang;31.1690\nLouisville;38.1663\nOdesa;46.4775\nThủ Đức;10.8266\nVolgograd;48.7086\nIslamabad;33.6931\nPort-au-Prince;18.5333\nXinyi;22.3559\nRaipur;21.2500\nArequipa;-16.4000\nRichmond;37.5295\nZaoyang;32.1287\nBuffalo;42.9018\nShuizhai;33.4433\nXingyi;25.0910\nKota;25.1800\nQuetta;30.1833\nKathmandu;27.7172\nOttawa;45.4247\nLilongwe;-13.9833\nAsmara;15.3228\nFreetown;8.4844\nVientiane;17.9667\nJerusalem;31.7784\nRiga;56.9489\nBangui;4.3733\nDushanbe;38.5367\nLomé;6.1319\nAshgabat;37.9500\nZagreb;45.8167\nLibreville;0.3903\nCotonou;6.3667\nPretoria;-25.7461\nVilnius;54.6872\nWinnipeg;49.8844\nQuebec City;46.8139\nChisinau;47.0228\nPort Moresby;-9.4789\nSkopje;41.9961\nDjibouti;11.5883\nGaza;31.5069\nKingston;17.9714\nRabat;34.0209\nSan Salvador;13.6989\nThe Hague;52.0800\nAsunción;-25.3000\nJuba;4.8500\nMaseru;-29.3100\nBissau;11.8500\nValletta;35.8983\nBratislava;48.1439\nKitchener;43.4186\nManama;26.2250\nTallinn;59.4372\nBeirut;33.8869\nCape Town;-33.9253\nTirana;41.3289\nSarajevo;43.8564\nWellington;-41.2889\nBanjul;13.4531\nHalifax;44.6475\nCanberra;-35.2931\nYamoussoukro;6.8161\nVictoria;48.4283\nNicosia;35.1725\nWindhoek;-22.5700\nSaint-Denis;-20.8789\nPorto-Novo;6.4972\nSucre;-19.0475\nLjubljana;46.0514\nNassau;25.0781\nBloemfontein;-29.1167\nFort-de-France;14.6000\nNew Delhi;28.6139\nGaborone;-24.6581\nParamaribo;5.8522\nDili;-8.5536\nDodoma;-6.1731\nGeorgetown;6.8058\nGibraltar;36.1333\nMalabo;3.7500\nSuva;-18.1416\nNouméa;-22.2758\nPristina;42.6633\nMale;4.1753\nPort Louis;-20.1644\nPodgorica;42.4413\nWillemstad;12.1080\nBern;46.9481\nGitega;-3.4283\nReykjavík;64.1467\nLuxembourg;49.6117\nPapeete;-17.5334\nPraia;14.9180\nSri Jayewardenepura Kotte;6.9108\nBridgetown;13.0975\nMoroni;-11.6990\nThimphu;27.4722\nMbabane;-26.3208\nHoniara;-9.4319\nPort of Spain;10.6667\nCastries;14.0167\nPutrajaya;2.9300\nCayenne;4.9330\nSão Tomé;0.3361\nPort-Vila;-17.7333\nBandar Seri Begawan;4.8903\nMonaco;43.7333\nApia;-13.8333\nTarawa;1.3382\nOranjestad;12.5186\nSaint Helier;49.1858\nMamoudzou;-12.7794\nMajuro;7.0833\nDouglas;54.1450\nGeorge Town;19.2866\nVictoria;-4.6167\nKingstown;13.1578\nAndorra la Vella;42.5000\nSaint John’s;17.1167\nNuku‘alofa;-21.1333\nNuuk;64.1814\nBelmopan;17.2514\nRoseau;15.3014\nBasseterre;17.3000\nTórshavn;62.0000\nRoad Town;18.4167\nPago Pago;-14.2740\nGrand Turk;21.4664\nMarigot;18.0706\nPalikir;6.9178\nFunafuti;-8.5167\nVaduz;47.1410\nLobamba;-26.4465\nAvarua;-21.2070\nSaint George’s;12.0500\nSan Marino;43.9346\nTifariti;26.1580\nPhilipsburg;18.0237\nCapitol Hill;15.2137\nStanley;-51.7000\nHamilton;32.2942\nVatican City;41.9040\nAlofi;-19.0560\nBasse-Terre;16.0104\nHagåtña;13.4745\nJamestown;-15.9251\nBrades;16.7928\nYaren;-0.5477\nGustavia;17.8958\nNgerulmud;7.5006\nSaint-Pierre;46.7811\nThe Valley;18.2167\nMata-Utu;-13.2825\nKingston;-29.0569\nLongyearbyen;78.2167\nAdamstown;-25.0667\nFlying Fish Cove;-10.4167\nKing Edward Point;-54.2833\nBareilly;28.3640\nQuảng Hà;15.9333\nDomaa-Ahenkro;7.2833\nOklahoma City;35.4676\nXingcheng;24.1681\nDongtai;32.8534\nYingcheng;24.1878\nChiba;35.6073\nAl Mijlad;11.0339\nPekanbaru;0.5092\nLuocheng;22.7645\nDnipro;48.4675\nDanyang;31.9948\nGodē;5.9527\nNatal;-6.9838\nNada;19.5000\nZamboanga City;6.9042\nKirkuk;35.4667\nBridgeport;41.1918\nNaples;40.8333\nWuchuan;21.4283\nHuilong;31.8131\nMorelia;19.7683\nMálaga;36.7194\nCebu City;10.3200\nAl Manşūrah;31.0500\nCoimbatore;11.0168\nSanto Domingo Este;18.4855\nSetagaya;35.6466\nSŏngnam;37.4333\nTaishan;22.2486\nTeresina;-5.0949\nSolāpur;17.6800\nTangier;35.7767\nKermānshāh;34.3142\nKrasnodar;45.0333\nBaidoa;3.1167\nGaalkacyo;6.7697\nAnqiu;36.3619\nFeicheng;36.1860\nSeberang Jaya;5.4000\nEl Alto;-16.5047\nKitakyūshū;33.8833\nMeishan;34.1736\nKhartoum North;15.6333\nKisangani;0.5153\nAguascalientes;21.8760\nMarrakech;31.6300\nDonetsk;48.0028\nTrujillo;-8.1120\nNew Orleans;30.0687\nTaihe;30.8706\nTrichinopoly;10.7903\nXin’an;34.3662\nTaihecun;45.7680\nKashgar;39.4681\nNaucalpan de Juárez;19.4753\nÇankaya;39.9244\nSantiago de Cuba;20.0217\nOwerri;5.4833\nPadang;-0.9500\nQingzhou;36.6967\nLichuan;30.2965\nSantiago del Estero;-27.7833\nDaye;30.1003\nHengzhou;22.6896\nFort Worth;32.7817\nHartford;41.7661\nEsenyurt;41.0470\nCampo Grande;-20.4839\nZhuanghe;39.6896\nBobo-Dioulasso;11.1833\nAd Dammām;26.4333\nQuzhou;28.9545\nLhasa;29.6534\nJiaozhou;36.2481\nBunia;1.5667\nTaguig City;14.5200\nCancún;21.1606\nMérida;20.9700\nYangchun;22.1717\nDengtalu;36.1386\nMorādābād;28.8389\nAntipolo;14.5842\nAbeokuta;7.1608\nBucheon;37.5000\nZhoushan;29.9887\nTiruppūr;11.1085\nNatal;-5.7833\nChihuahua;28.6353\nKlang;3.0333\nAs Sulaymānīyah;35.5572\nGurgaon;28.4560\nTurin;45.0792\nTucson;32.1541\nHai’an;32.5320\nAr Ramādī;33.4258\nLaiyang;36.9758\nSale;34.0333\nJalandhar;31.2569\nMarseille;43.2964\nBucaramanga;7.1333\nKaifeng Chengguanzhen;34.8519\nIkeja;6.6186\nEskişehir;39.7767\nSaltillo;25.4231\nGaomi;36.3833\nLiverpool;53.4075\nIpoh;4.5972\nOran;35.6969\nPortsmouth;50.8058\nSouthampton;50.9025\nHermosillo;29.0989\nCochabamba;-17.3833\nWeichanglu;37.1792\nShache;38.4261\nWuxi;26.5895\nLeping;28.9632\nHailun;47.4585\nMacheng;31.1817\nAkure;7.2500\nIlorin;8.5000\nYuci;37.6823\nSaratov;51.5333\nErbil;36.1912\nIguaçu;-22.7400\nPasig City;14.5750\nDehui;44.5333\nKālkāji Devi;28.5485\nBhubaneshwar;20.2700\nHonolulu;21.3294\nTongchuan;34.9057\nCheongju;36.6333\nChengxiang;31.4515\nThessaloníki;40.6403\nWarri;5.5167\nSakai;34.5733\nPointe-Noire;-4.8000\nRongjiawan;29.1409\nMediouna;33.4500\nButterworth;5.3992\nRenqiu;38.7094\nXindi;29.8182\nBhayandar;19.2900\nWu’an;36.6941\nSão Bernardo do Campo;-23.7000\nMāndvi;19.3000\nBarinas;8.6333\nZijinglu;34.7513\nGaoyou;32.7847\nCuliacán;24.8069\nHejian;38.4451\nYiyang;26.4103\nPuxi;35.2125\nAndrotsy;-24.1000\nMcAllen;26.2252\nQingping;34.5380\nOmaha;41.2627\nJoão Pessoa;-7.1200\nDongyang;29.2785\nQuerétaro;20.5875\nKraków;50.0614\nGeorge Town;5.4144\nAbaeté;-19.1583\nPalermo;2.8917\nValencia;39.4700\nXigazê;29.2500\nEl Paso;31.8476\nSeyhan;36.9831\nNiigata;37.9161\nHempstead;40.6629\nLeeds;53.8003\nHamamatsu;34.7108\nBağcılar;41.0344\nXiangxiang;27.7389\nBilbao;43.2569\nChaohucun;31.6783\nFuyang;30.0553\nHoms;34.7333\nKüçükçekmece;41.0000\nLubango;-14.9167\nZouping;36.8625\nKhŭjand;40.2833\nSan Luis Potosí;22.1511\nNottingham;52.9533\nCencheng;22.9297\nDali;25.6808\nHamhŭng;39.9167\nKorla;41.7259\nRājshāhi;24.3667\nErzurum;39.9086\nFrankfurt;50.1106\nAl ‘Ayn;24.2075\nSongzi;30.1772\nAlbuquerque;35.1054\nPatiāla;30.3400\nLaixi;36.8667\nBahawalpur;29.3956\nZhongba;31.7761\nKaduna;10.5167\nQingnian;36.8494\nSan Pedro Sula;15.5000\nQamdo;31.1375\nXinhualu;34.3962\nNerima;35.7355\nGuangshui;31.6189\nPietermaritzburg;-29.6167\nBaardheere;2.3333\nTlajomulco de Zúñiga;20.4736\nSamarinda;-0.5000\nChanghua;24.0667\nSizhan;39.0099\nCiudad Guayana;8.3667\nCúcuta;7.8942\nDhūlia;20.8997\nBurco;9.5279\nLicheng;31.4174\nŌta-ku;35.5613\nThiruvananthapuram;8.4875\nTyumen;57.1500\nNampula;-15.1167\nZaporizhzhia;47.8500\nKyaukse;21.6131\nChengguan;35.5256\nKumamoto;32.8031\nNehe;48.4800\nOsogbo;7.7667\nCabinda;-5.5600\nKermān;30.2833\nZunhua;40.1881\nRochester;43.1680\nValenzuela;14.7000\nOrūmīyeh;37.5486\nWugang;26.7345\nShuangqiao;35.0833\nTshikapa;-6.4167\nSão José dos Campos;-23.1789\nComodoro Rivadavia;-45.8647\nCagayan de Oro;8.4833\nTondo;14.6170\nLangzhong;31.5504\nQian’an;40.0059\nLviv;49.8425\nSarasota;27.3387\nReynosa;26.0922\nSanto André;-23.6572\nAn Najaf;32.0000\nSagamihara;35.5667\nGuli;28.9008\nMississauga;43.6000\nConcepción;-36.8282\nOkayama;34.6500\nAnlu;31.2575\nMwanza;-2.5167\nFresno;36.7830\nChangsha;22.3762\nTorreón;25.5394\nShihezi;44.3054\nEnugu;6.4528\nJaboatão;-8.1803\nTulsa;36.1283\nYanggok;37.6333\nYatou;37.1653\nEdogawa;35.7066\nAllentown;40.5961\nRibeirão Prêto;-21.1783\nXichang;27.8983\nLatakia;35.5167\nBhiwandi;19.2967\nCity of Parañaque;14.4700\nDasmariñas;14.3294\nDayton;39.7805\nSahāranpur;29.9640\nWarangal;17.9689\nSoledad;10.9167\nOsasco;-23.5328\nDashiqiao;40.6328\nBirmingham;33.5279\nNampo;38.7333\nShiliguri;26.7100\nBanjarmasin;-3.3200\nSha Tin;22.3802\nSalem;11.6500\nGeneral Santos;6.1167\nCocody;5.3500\nḨamāh;35.1333\nPendik;40.8747\nBacoor;14.4624\nVellore;12.9165\nShishi;24.7355\nGuadalupe;25.6775\nAdachi;35.7749\nQianxi;27.0284\nTolyatti;53.5089\nMacau;22.2006\nBauchi;10.3158\nHamilton;43.2567\nŁódź;51.7769\nMiluo Chengguanzhen;28.8049\nGaizhou;40.4019\nKarbalā’;32.6167\nLeling;37.7333\nJianshe;34.2189\nShizuoka;34.9756\nCharleston;32.8168\nJingcheng;32.0058\nKochi;9.9700\nMar del Plata;-38.0000\nCape Coral;26.6443\nTasikmalaya;-7.3161\nRasht;37.2808\nXinmin;41.9952\nShanhu;29.5908\nZhongshu;27.8116\nGorakhpur;26.7637\nZaragoza;41.6500\nWrocław;51.1100\nAcapulco de Juárez;16.8636\nBahār;34.9072\nKumul;42.8193\nMurcia;37.9861\nPinghu;30.7005\nPalermo;38.1157\nGuankou;30.9933\nTlaquepaque;20.6167\nSongyang;34.4603\nCh’ŏngjin;41.7833\nPuyang Chengguanzhen;35.7004\nQionghu;28.8417\nZhaodong;46.0635\nNarela;28.8527\nHuambo;-12.7767\nWenchang;31.0540\nVillavicencio;4.1500\nShulan;44.4079\nTlalnepantla;19.5367\nCatia La Mar;10.6000\nSargodha;32.0836\nAl Hufūf;25.3833\nDurango;24.0250\nJalingo;8.9195\nBouaké;7.6833\nMazatlán;23.2167\nSan Jose del Monte;14.8139\nAnsan;37.3167\nAbomey-Calavi;6.4486\nLingbao Chengguanzhen;34.5221\nHwasu-dong;37.1997\nSialkot City;32.4925\nHuế;16.4667\nBulawayo;-20.1700\nXiping;25.6005\nSanhe;39.9808\nCh’ŏnan;36.8167\nContagem;-19.9319\nJieshou;33.2605\nSelçuklu;37.8814\nĒrer Sātā;9.5667\nHonchō;35.6946\nDüsseldorf;51.2333\nIzhevsk;56.8500\nGuntūr;16.3008\nGuixi;28.2861\nSorocaba;-23.5017\nYıldırım;40.1100\nPetaling Jaya;3.0972\nTengyue;25.0208\nWuxue;29.8518\nRasūlpur;28.5700\nBhāvnagar;21.7600\nBrahmapur;19.3150\nQufu;35.6000\nGaobeidian;39.3257\nRuiming;25.8833\nColumbia;34.0378\nConcord;37.9722\nNoida;28.57\nGold Coast;-28.0167\nXinshi;31.0236\nTa‘izz;13.5789\nAracaju;-10.9167\nJeonju;35.8167\nBhāngar;22.5800\nJin’e;29.3395\nBarnaul;53.3333\nMakati City;14.5567\nRotterdam;51.9167\nChangping;40.2248\nBenghazi;32.1167\nKryvyi Rih;47.9086\nḨalwān;29.8453\nColorado Springs;38.8674\nSuohe;34.7879\nChimalhuacán;19.4167\nXinxing;39.8734\nBhilai;21.3667\nMangalore;12.9020\nPort-Bouët;5.2667\nZhuangyuan;37.3056\nGlasgow;55.8611\nNamangan;41.0011\nUlyanovsk;54.3167\nTân An;10.9050\nIrkutsk;52.2833\nBhilai;21.2100\nNāgercoil;8.1833\nJos;9.9167\nPontianak;-0.0206\nBazhou;39.1235\nTurpan;42.9512\nVilla Nueva;14.5314\nLas Piñas City;14.4500\nSpringfield;42.1155\nKnoxville;35.9692\nMeihekou;42.5279\nJurong;31.9579\nFeira de Santana;-12.2500\nKhabarovsk;48.4833\nZhugang;28.1277\nLeipzig;51.3400\nXinji;37.9423\nSerang;-6.1200\nJambi;-1.5900\nKandahār;31.6200\nSan Miguel de Tucumán;-26.8167\nGothenburg;57.7075\nYaroslavl;57.6167\nBaton Rouge;30.4420\nZhangshu;28.0667\nVladivostok;43.1333\nOgden;41.2279\nKuantan;3.8167\nRaurkela;22.2492\nCuttack;20.5236\nAr Rayyān;25.2500\nHaifa;32.8192\nMalanje;-9.5333\nBacolod;10.6765\nZhuozhou;39.4887\nGrand Rapids;42.9619\nUberlândia;-18.9231\nAlbany;42.6664\nTianchang;32.6853\nKawaguchi;35.8077\nItabashi;35.7512\nSuginami-ku;35.6995\nCimahi;-6.8712\nTuxtla;16.7528\nGaroua;9.3000\nḨafr al Bāţin;28.4342\nTumkūr;13.3400\nBalikpapan;-1.2768\nDurban;-29.8833\nKagoshima;31.6000\nAl Ḩillah;23.4895\nMakhachkala;42.9833\nSihui;23.3448\nIrapuato;20.6667\nBrampton;43.6833\nLuocheng;30.9793\nMbale;1.0806\nPereira;4.8143\nBakersfield;35.3529\nUvira;-3.4000\nDortmund;51.5167\nChuxiong;25.0461\nMission Viejo;33.6096\nZāhedān;29.4964\nNew Haven;41.3113\nShah Alam;3.0722\nWenlan;23.3989\nCuiabá;-15.5958\nShangzhi;45.2116\nEssen;51.4508\nBotou;38.0740\nMymensingh;24.7539\nAnyang;37.3833\nGenoa;44.4111\nDurgāpur;23.5500\nPort Sudan;19.6167\nAl Mafraq;32.3399\nPuente Alto;-33.6167\nDehra Dūn;30.3450\nAţ Ţā’if;21.2751\nWancheng;18.8000\nHachiōji;35.6664\nXiulin;29.7211\nFu’an;27.1000\nTomsk;56.4886\nTonalá;20.6167\nJuiz de Fora;-21.7619\nWorcester;42.2705\nKolwezi;-10.7167\nChāpra;25.7848\nBristol;51.4536\nLuofeng;37.3590\nLingyuan;41.2407\nIrbid;32.5500\nAl Maḩallah al Kubrá;30.9686\nWencheng;19.6167\nBremen;53.0833\nCiudad Bolívar;8.1219\nOrenburg;51.7667\nShenzhou;38.0005\nĀsansol;23.6800\nKuiju;36.8528\nZhenzhou;32.2739\nSurakarta;-7.5667\nDresden;51.0500\nKolhāpur;16.6917\nBenguela;-12.5500\nEnsenada;31.8578\nKemerovo;55.3667\nLanxi;29.2167\nDangyang;30.8258\nFarīdpur;23.6020\nHerāt;34.3419\nLuanzhou;39.7396\nHamadān;34.8064\nNovokuznetsk;53.7667\nNellore;14.4500\nPalma;39.5667\nChiclayo;-6.7630\nNānded;19.1500\nAjmer;26.4499\nAl Ḩudaydah;14.8022\nKimhae;35.2342\nProvo;40.2457\nRustenburg;-25.6667\nAmrāvati;20.9258\nPoznań;52.4083\nHuanghua;38.3710\nMuntinlupa City;14.3800\nLondrina;-23.3100\nNansana;0.3639\nTabūk;28.3972\nHeroica Matamoros;25.8797\nAkron;41.0798\nSamarkand;39.6547\nXingcheng;40.6189\nKaiyuan;42.5380\nHannover;52.3667\nValledupar;10.4833\nFengcheng;40.4543\nIxtapaluca;19.3186\nGhulja;43.9000\nCity of Calamba;14.2167\nAnanindeua;-1.3658\nXiangyang;34.2999\nFuding;27.2000\nAn Nāşirīyah;31.0439\nAl Ḩillah;32.4833\nIbagué;4.4333\nRyazan;54.6300\nKassala;15.4500\nTripoli;34.4367\nChang’an;29.4761\nKōtō-ku;35.6728\nNaberezhnyye Chelny;55.7000\nAksu;41.1850\nSalta;-24.7833\nAstrakhan;46.3500\nGulbarga;17.3290\nCadaado;6.1403\nLyon;45.7600\nWuhai;39.6844\nMingguang;32.7816\nAntwerp;51.2178\nYazd;31.8822\nTouba;14.8667\nArdabīl;38.2425\nBīkaner;28.0167\nAgartala;23.8333\nNdola;-12.9667\nHimeji;34.8167\nPalm Bay;27.9631\nTultitlán de Mariano Escobedo;19.6450\nAilan Mubage;43.9080\nBandar ‘Abbās;27.1833\nBắc Ninh;21.1833\nCiudad Apodaca;25.7817\nSanta Teresa del Tuy;10.2333\nMaipú;-33.5167\nPenza;53.2000\nSoacha;4.5872\nAl Qaţīf;26.5560\nPort Said;31.2625\nLoni;28.7500\nYucheng;36.9329\nSevastopol;44.6050\nMeknès;33.8950\nMixco;14.6338\nArāk;34.0917\nPohang;36.0322\nLongzhou;30.3200\nAnda;46.4078\nJinghong;22.0057\nSheffield;53.3808\nUtsunomiya;36.5551\nSuez;29.9667\nNuremberg;49.4539\nSurrey;49.1900\nHeshan;22.7697\nUjjain;23.1700\nJiaji;19.2431\nSanta Marta;11.2419\nJoinvile;-26.3204\nBeining;41.5961\nDes Moines;41.5725\nHải Dương;20.9397\nCarrefour;18.5344\nMaturín;9.7423\nHomyel’;52.4453\nLeicester;52.6344\nYanji;42.9044\nMacapá;0.0330\nYicheng;31.7117\nUlhāsnagar;19.2200\nAl ‘Āshir min Ramaḑān;30.3065\nLipetsk;52.6167\nAl ‘Amārah;31.8333\nBhīlwāra;25.3500\nEncheng;22.1879\nMurrieta;33.5719\nAden;12.8000\nKitwe;-12.8167\nMatsuyama;33.8333\nJhānsi;25.4486\nPingtung;22.6761\nLapu-Lapu City;10.3127\nMatsudo;35.7876\nMontería;8.7500\nIchikawa;35.7219\nNagqu;31.4766\nImus;14.4297\nHsinchu;24.8167\nKimberley;-28.7383\nJammu;32.7300\nBelas;-8.9983\nTalatona;-8.9167\nIle-Ife;7.4667\nPurnea;25.7780\nKirov;58.6000\nMykolaiv;46.9750\nMeicheng;30.6412\nTinnevelly;8.7136\nNiterói;-22.8833\nFarāh;32.3436\nSukkur;27.7061\nOujda-Angad;34.6867\nTaozhou;30.8956\nMarka;1.6833\nHigashi-ōsaka;34.6794\nJohor Bahru;1.4556\nHongjiang;27.1167\nBello;6.3333\nChimbote;-9.0745\nDuisburg;51.4347\nQaraghandy;49.8028\nMesa;33.4015\nToulouse;43.6045\nLikasi;-10.9833\nDengtacun;41.4237\nLembok;-8.5650\nZhijiang;30.4271\nChengjiao;35.4043\nBeipiao;41.8020\nSuoluntun;45.2279\nStaten Island;40.5834\nKota Bharu;6.1333\nCiudad López Mateos;19.5500\nCelaya;20.5222\nVinh;18.6667\nDuyun;26.2672\nLos Mochis;25.7835\n‘Ajmān;25.4136\nNyala;12.0500\nLarkana;27.5583\nWichita;37.6895\nNishinomiya-hama;34.7376\nCheboksary;56.1333\nYuanping;38.7299\nToledo;41.6638\nYueqing;28.1188\nEdinburgh;55.9533\nBelgaum;15.8500\nTula;54.2000\nGdańsk;54.3475\nShahe;36.8622\nSerra;-20.1289\nBrookhaven;40.8320\nGaoping;35.7911\nDunhua;43.3667\nAz Zarqā’;32.0833\nSylhet;24.9000\nKaihua;23.3715\nCaerdydd;51.4817\nJāmnagar;22.4700\nFuyuan;48.3614\nGaya;24.7500\nFlorianópolis;-27.6122\nChiniot;31.7194\nJiannan;31.3446\nŌita;33.2333\nBerbera;10.4356\nKaliningrad;54.7003\nMbeya;-8.9000\nNangong;37.3606\nAmbattūr;13.1143\nKatlehong;-26.3333\nKurashiki;34.5833\nBarura;23.3750\nSan Juan;-31.5342\nVila Velha;-20.3364\nMazār-e Sharīf;36.7000\nShekhupura;31.7111\nWorthing;50.8147\nPiura;-5.2000\nMandaluyong City;14.5800\nKartal;40.8872\nJiaojiangcun;28.6804\nHarrisburg;40.2752\nLaohekou;32.3849\nKâğıthane;41.0719\nAgege;6.6219\nAngeles City;15.1472\nSão José do Rio Prêto;-20.8081\nPasay City;14.5500\nBeian;48.2395\nFujin;47.2489\nSalt Lake City;22.6100\nBalashikha;55.8167\nXiaoyi;37.1449\nPort St. Lucie;27.2796\nLanús;-34.7000\nQingzhen;26.5555\nJiangshan;28.7412\nBa‘qūbah;33.7500\nKatsushika-ku;35.7434\nBuraydah;26.3333\nLongjiang;27.5820\nTân Uyên;11.0508\nLong Beach;33.7977\nMarikina City;14.6500\nManado;1.4931\nCampos;-21.7539\nKanazawa;36.5611\nIloilo;10.7167\nReno;39.5497\nCalabar;4.9767\nKuqa;41.7156\nPiraeus;37.9430\nMadison;43.0822\nJalgaon;21.0040\nCranbourne;-38.0996\nKowloon City;22.3282\nMauá;-23.6678\nFukuyama;34.4833\nXicheng;23.3629\nKikwit;-5.0386\nAmagasaki;34.7333\nPyeongtaek;36.9922\nKurnool;15.8300\nLittle Rock;34.7256\nMelaka;2.1944\nGeneral Trias;14.3833\nJian’ou;27.0387\nEsenler;41.0339\nHuadian;42.9633\nŢanţā;30.7833\nKota Kinabalu;5.9750\nKursk;51.7167\nMinzhu;43.7192\nStavropol;45.0500\nUdaipur;24.5800\nMogi das Cruzes;-23.5228\nMariupol;47.0958\nEslāmshahr;35.5606\nSan Nicolás de los Garza;25.7500\nGreenville;34.8354\nSham Shui Po;22.3307\nBarcelona;10.1333\nConstantine;36.3650\nTanbei;35.0907\nAdo-Ekiti;7.6167\nBatman;37.8870\nBandung;-6.9120\nBaisha;29.4774\nAvcılar;40.9792\nDenton;33.2175\nRodriguez;14.7167\nTaoyuan District;24.9913\nYongji;34.8670\nChauddagram;23.2283\nDanjiangkou;32.5408\nKahramanmaraş;37.5833\nFujisawa;35.3500\nAndijon;40.7833\nMathura;27.4925\nZürich;47.3744\nDiadema;-23.6861\nMachida;35.7106\nUlan-Ude;51.8272\nSpokane;47.6671\nNing’an;44.3439\nZhangjiakou Shi Xuanhua Qu;40.5944\nSunch’ŏn;39.4167\nJinchang;38.5168\nKashiwa;35.8676\nGuangming;45.3357\nSāngli;16.8667\nOakland;37.7904\nBeira;-19.8333\nKupang;-10.1702\nJeju;33.5097\nDavangere;14.4666\nCaxias do Sul;-29.1667\nManizales;5.1000\nYogyakarta;-7.8014\nCalicut;11.2500\nKoumassi;5.3000\nVeracruz;19.1903\nZanjān;36.6789\nWelkom;-27.9831\nShinagawa-ku;35.6092\nKenitra;34.2500\nAgadir;30.4333\nSomolu;6.5408\nUyo;5.0500\nSokoto;13.0622\nLancaster;40.0420\nMasan;35.1833\nHuili Chengguanzhen;26.6614\nSidi Bouzid;35.0381\nCusco;-13.5250\nPorto Velho;-8.7619\nSihŭng;37.3799\nXalapa;19.5400\nFlorencio Varela;-34.8167\nTver;56.8578\nTrabzon;41.0050\nMalatya;38.3486\nXunyang;32.8357\nUijeongbu;37.7486\nAkola;20.7000\nAomori;40.8223\nYan’an Beilu;44.0144\nOwo;7.1961\nAves;41.4400\nBuenaventura;3.8772\nPoughkeepsie;41.6950\nLaval;45.5833\nBoise;43.6005\nToyota;35.0824\nSanta Rosa;14.3167\nDaloa;6.8833\nElazığ;38.6744\nHpa-An;16.8906\nRahimyar Khan;28.4200\nBettiah;26.8014\nUgep;5.8000\nWinston-Salem;36.1029\nKushtia;23.9101\nMishan;45.5420\nHailin;44.5735\nSeremban;2.7222\nBoa Vista;2.8194\nLecheng;25.1307\nZhengjiatun;43.5130\nLuhansk;48.5667\nPencheng;29.6792\nMagnitogorsk;53.3833\nThủ Dầu Một;10.9667\nTakamatsu;34.3500\nSyracuse;43.0407\nEl Obeid;13.1833\nDa’an;45.5050\nXingren;25.4352\nBiñan;14.3333\nArusha;-3.3667\nFenyang;37.2647\nAjdābiyā;30.7556\nPaju;37.8667\nMataram;-8.5833\nCarapicuíba;-23.5192\nJhang City;31.2694\nTepic;21.5083\nJayapura;-2.5330\nRio Branco;-9.9747\nToyama;36.6959\nFangting;31.1282\nSanandaj;35.3144\nDelhi Cantonment;28.6000\nLinghai;41.1676\nShorāpur;16.5200\nToyonaka;34.7833\nSochi;43.5853\nBhāgalpur;25.2500\nBellary;15.1000\nIvanovo;57.0000\nKisumu;-0.0833\nAugusta;33.3645\nTürkmenabat;39.0833\nZaria;11.0667\nBryansk;53.2500\nKumi;36.1195\nAsyūţ;27.1833\nWanyuan;32.0691\nMaracay;10.2469\nPadiāla;30.5667\nYüreğir;36.9981\nJiexiu;37.0282\nStockton;37.9765\nBogra;24.8500\nSanta Fe;-31.6333\nCampina Grande;-7.2306\nNagasaki;32.7447\nSzczecin;53.4325\nMaringá;-23.4000\nPalm Coast;29.5389\nChattanooga;35.0660\nQazvīn;36.2667\nQuilon;8.8800\nJundiaí;-23.1858\nHirakata;34.8167\nGifu;35.4232\nKhayelitsha;-34.0403\nKūkatpalli;17.4849\nJiangjiafan;31.0238\nMaungdaw;20.8167\nKissimmee;28.3041\nDurham;35.9792\nDera Ghazi Khan;30.0331\nMiyazaki;31.9167\nBhātpāra;22.8700\nHazāribāgh;23.9800\nSandakan;5.8388\nTaytay;14.5692\nHejin;35.5914\nOlinda;-8.0000\nThanh Hóa;19.8075\nSurgut;61.2500\nNnewi;6.0167\nMinamisuita;34.7594\nThiès;14.7833\nBetsiboka;-16.9500\nBelgorod;50.6000\nTāngāil;24.2644\nYokosuka;35.2500\nNha Trang;12.2450\nMalabon;14.6600\nAl Jahrā’;29.3500\nYola;9.2300\nPasto;1.2078\nLobito;-12.3597\nAl Jubayl;27.0000\nSaurimo;-9.6500\nBologna;44.4939\nArlington;32.6998\nGujrat;32.5739\nAd Dīwānīyah;31.9892\nPiracicaba;-22.7253\nHancheng;35.4768\nKaramay;45.5799\nKākināda;16.9661\nSan-Pédro;4.7500\nTieli;46.9838\nCilegon;-6.0027\nDarbhanga;26.1700\nVictorville;34.5277\nGwoza;11.0861\nSaki;8.6667\nTétouan;35.5667\nAqtöbe;50.2836\nBibā;28.9218\nPlovdiv;42.1500\nOyo;7.8500\nIlesa;7.6167\nTarlac City;15.4869\nOkazaki;34.9543\nSirūr;18.8300\nCainta;14.5667\nḨā’il;27.5167\nGaroowe;8.4000\nOlomouc;49.5939\nYidu;30.3880\nLianzhou;24.7868\nCeel Baraf;3.2073\nFlorence;43.7714\nChristchurch;-43.5310\nNuevo Laredo;27.4861\nBrno;49.1925\nBawshar;23.5333\nLondon;42.9836\nNovi Sad;45.2542\nAurora;39.7083\nGusau;12.1500\nModesto;37.6375\nKaunas;54.8972\nSardārshahr;28.4401\nZêtang;29.2380\nLas Palmas;28.1272\nIchinomiya;35.3039\nTaunggyi;20.7836\nLancaster;34.6935\nFayetteville;36.0714\nCantonment;31.5167\nPānihāti;22.6900\nHuancayo;-12.0667\nBetim;-19.9678\nUsulután;13.3500\nSintra;38.7992\nChitungwiza;-17.9939\nHatay;36.2025\nIquitos;-3.7500\nSivas;39.7500\nHelixi;30.6267\nScranton;41.4044\nMamou;10.3833\nAl Kharj;24.1483\nManukau City;-37.0000\nStoke-on-Trent;53.0000\nCumaná;10.4500\nRohtak;28.8909\nVinnytsia;49.2333\nMāler Kotla;30.5167\nLipa City;13.9411\nMandaue City;10.3333\nBhawana;31.5661\nKhorramābād;33.4878\nAmbon;-3.7000\nTakasaki;36.3219\nButuan;8.9534\nToyohashi;34.7692\nKeelung;25.1333\nBaguio City;16.4119\nLa Florida;-33.5333\nGebze;40.8000\nLengshuijiang;27.6858\nPetare;10.4833\nAnguo;38.4177\nKita-ku;35.7528\nMadan;30.3392\nPanshi;42.9392\nBharatpur;27.6833\nAz Zubayr;30.3833\nCaucaia;-3.7167\nVitsyebsk;55.1917\nShinjuku;35.6939\nNicolás Romero;19.5833\nHuichang;34.9136\nNagano;36.6486\nBauru;-22.3150\nYanjiao;39.9432\nBochum;51.4819\nTecámac;19.7131\nAnápolis;-16.3339\nCoventry;52.4081\nOxnard;34.1964\nKorba;22.3500\nCibinong;-6.4850\nDāsarhalli;13.0465\nQardho;9.5000\nWŏnsan;39.1475\nKocaeli;40.7625\nNewcastle;-27.7464\nIligan;8.2300\nYoungstown;41.0993\nCabuyao;14.2750\nKayapınar;37.9400\nNakano;35.7073\nUtrecht;52.0833\nBengkulu;-3.7956\nOrizaba;18.8500\nBlumenau;-26.9333\nMontes Claros;-16.7306\nIndio;33.7346\nPétion-Ville;18.5128\nTungi;23.9000\nBuurhakaba;2.7833\nShuanghe;30.3866\nKonak;38.4189\nAsh Shuhadā’;30.6039\nPensacola;30.4413\nUmuahia;5.5333\nGedaref;14.0333\nPalu;-0.8950\nMardan;34.2012\nPokhara;28.2083\nMahilyow;53.9167\nWudalianchi;48.6433\nHrodna;53.6667\nSungai Petani;5.6500\nLinxia Chengguanzhen;35.6000\nSīkar;27.6200\nNam Định;20.4200\nVitória;-20.2889\nSasarām;24.9500\nKarūr;10.9601\nFranca;-20.5389\nVladimir;56.1286\nKarnāl;29.6860\nKismaayo;-0.3581\nSão Vicente;-23.9633\nKawagoe;35.9251\nVillahermosa;17.9892\nTaraz;42.9000\nCubal;-13.1117\nLuena;-11.7918\nIbb;13.9667\nYong’an;25.9733\nWuppertal;51.2667\nManisa;38.6306\nSan Fernando;15.0333\nChānda;19.9500\nMinatitlán;17.9833\nMalmö;55.6058\nNizhniy Tagil;57.9167\nSan Pedro;14.3583\nCuito;-12.3833\nHongzhai;34.9857\nGuédiawaye;14.7833\nWakayama;34.2333\nTin Shui Wai;22.4608\nPavlodar;52.3000\nGimpo;37.7000\nItaquaquecetuba;-23.4864\nNara;34.6844\nVan;38.4942\nCorrientes;-27.4833\nNeiva;2.9345\nArkhangelsk;64.5500\nBatangas;13.8300\nLicheng;24.4935\nKoshigaya;35.8911\nSinŭiju;40.1000\nCabimas;10.4000\nYakeshi;49.2842\nOruro;-17.9667\nAhmadnagar;19.0800\nĀvadi;13.1097\nSarai Alamgir;32.9000\nVarna;43.2167\nGorgān;36.8386\nTakatsuki;34.8500\nHolguín;20.8869\nQo‘qon;40.5286\nSemey;50.4333\nYingmen;39.9487\nCariacica;-20.2639\nPalmira;3.5833\nTapachula;14.9000\nBydgoszcz;53.1219\nAntofagasta;-23.6500\nAnaheim;33.8390\nRājahmundry;16.9800\nChita;52.0333\nBonita Springs;26.3558\nCaruaru;-8.2828\nNice;43.7034\nShāhjānpur;27.8800\nAntónio Enes;-16.2333\nCentral Coast;-33.3000\nPamukkale;37.9167\nWad Medani;14.4000\nÖskemen;49.9833\nTanch’ŏn;40.4580\nTokorozawa;35.7996\nHosūr;12.7409\nSerekunda;13.4333\nGreensboro;36.0956\nKūstī;13.1667\nCuddapah;14.4700\nSimferopol;44.9484\nSarıyer;41.1669\nSumqayıt;40.5917\nŌtsu;35.0167\nVitória da Conquista;-14.8658\nMakiivka;48.0556\nVũng Tàu;10.3833\nBrest;52.1347\nUruapan;19.4208\nGómez Palacio;25.5611\nYeosu;34.7333\nKaluga;54.5333\nMeram;37.8364\nMuzaffarpur;26.1225\nAlwar;27.5498\nLublin;51.2500\nLianran;24.9211\nBuôn Ma Thuột;12.6667\nCuernavaca;18.9186\nAlicante;38.3453\nEast London;-33.0175\nTarsus;36.9165\nMatadi;-5.8167\nIslip;40.7385\nCimanggis;-6.3645\nKaesŏng;37.9667\nBeni;0.5000\nSultanbeyli;40.9683\nHuntsville;34.6981\nRandburg;-26.0936\nJitpur;27.6666\nBeylikdüzü;41.0011\nPetrolina;-9.3928\nChinju;35.2000\nTangdong;25.9755\nReading;51.4542\nSambalpur;21.4700\nHangu;39.2320\nBelfast;54.5964\nShah Latif Town;24.8806\nIwaki;37.0505\nSalamanca;20.5703\nYingzhong;32.2381\nViña del Mar;-33.0244\nHirosaki;40.6031\nBielefeld;52.0211\nAz Zaqāzīq;30.5667\nNazrēt;8.5414\nCuenca;-2.8974\nTampere;61.4981\nBonn;50.7333\nAl Fayyūm;29.3084\nBlida;36.4722\nCiudad Obregón;27.4939\nUberaba;-19.7478\nCorpus Christi;27.7254\nAsan;36.7833\nRibeirão das Neves;-19.7669\nSoledad de Graciano Sánchez;22.1833\nMaebashi;36.3895\nKāmārhāti;22.6686\nGəncə;40.6828\nKendari;-3.9907\nBalıkesir;39.6333\nThái Nguyên;21.6000\nAsahikawa;43.7706\nSmolensk;54.7828\nDahūk;36.8667\nWŏnju;37.3417\nNakuru;-0.3000\nLafia;8.5000\nFort Wayne;41.0888\nGüngören;41.0225\nKoriyama;37.4004\nBamiantong;44.9164\nTaourirt;34.4169\nRāmpur;28.8000\nDebrecen;47.5300\nCabanatuan City;15.4908\nMarkham;43.8767\nFayetteville;35.0850\nPelotas;-31.7719\nRoodepoort;-26.1625\nVolzhskiy;48.8056\nAnn Arbor;42.2759\nBijāpur;16.8300\nSukabumi;-6.9181\nTharād;24.3926\nRatnāgiri;16.9944\nUlanhot;46.0726\nYunzhong;39.8143\nJackson;32.3157\nCotabato;7.2200\nAl Fallūjah;33.3500\nKōchi;33.5589\nMinna;9.6139\nBielsko-Biała;49.8225\nCanoas;-29.9200\nGwangmyeongni;37.4760\nCluj-Napoca;46.7667\nBari;41.1253\nPucallpa;-8.3833\nKuching;1.5575\nGonder;12.6075\nKikuyu;-1.2500\nMekele;13.4969\nGonaïves;19.4456\nGuasave;25.5744\nNaha;26.2122\nNantes;47.2181\nBinxian;35.0364\nShimoga;13.9333\nHotan;37.1000\nKaiyuan;23.7147\nCiudad del Este;-25.5167\nTemara;33.9267\nAntioch;37.9787\nUíge;-7.6167\nOsh;40.5333\nCórdoba;37.8845\nCamagüey;21.3839\nMobile;30.6782\nSan Salvador de Jujuy;-24.1833\nAl Kūt;32.4907\nCherepovets;59.1167\nLexington;38.0423\nSan Miguelito;9.0330\nOkene;7.5500\nTimişoara;45.7597\nMenongue;-14.6556\nJūnāgadh;21.5200\nKatsina;12.9889\nPoltava;49.5894\nMaroua;10.5971\nXiaoli;22.6782\nKaech’ŏn;39.6986\nAsan;36.3500\nTehuacán;18.4617\nAksaray;38.3742\nAttiecoubé;5.3333\nCoatzacoalcos;18.1500\nSaransk;54.1833\nNukus;42.4667\nPuerto Plata;19.8000\nHāpur;28.7309\nZalantun;48.0033\nMünster;51.9625\nTrichūr;10.5200\nAn Nhơn;13.9170\nTaubaté;-23.0250\nBinangonan;14.4514\nCirebon;-6.7071\nSafi;32.2833\nMitchells Plain;-34.0506\nBoaco;12.4719\nAsheville;35.5707\nCà Mau;9.1833\nTrenton;40.2237\nToshima;35.7261\nVologda;59.2167\nBarddhamān;23.2333\nTanza;14.3944\nBor;6.2125\nKasur;31.1167\nYakou;33.2937\nSanta Rosa;38.4458\nOrël;52.9686\nShahr-e Qods;35.7214\nKingston upon Hull;53.7444\nMannheim;49.4878\nSanta Ana;33.7367\nGuarujá;-23.9936\nPlaya del Carmen;20.6281\nPasir Gudang;1.5028\nDatang;22.9481\nPanvel;18.9944\nLansing;42.7142\nZarzal;4.3983\nLa Victoria;18.5500\nPort Elizabeth;-33.9581\nAlanya;36.5500\nNizāmābād;18.6720\nAl ‘Ajamī;31.0959\nQuy Nhơn;13.7667\nYakutsk;62.0272\nYokkaichi;34.9650\nPonta Grossa;-25.0994\nCatania;37.5000\nChalco;19.2647\nHenderson;36.0133\nGwangju;37.3667\nLongquan;25.9106\nKarlsruhe;49.0092\nShahrīār;35.6597\nKurgan;55.4408\nKasugai;35.2475\nSt. Paul;44.9478\nSariwŏn;38.5064\nSt. Catharines;43.1833\nKarawang;-6.3125\nLakeland;28.0557\nNiagara Falls;43.0600\nOulgaret;11.9570\nTaboão da Serra;-23.5328\nVladikavkaz;43.0400\nNghi Sơn;19.4170\nJuliaca;-15.4833\nParbhani;19.2700\nHisar;29.1500\nPuerto La Cruz;10.2000\nPuerto Princesa;9.7500\nPodolsk;55.4311\nMeguro;35.6415\nCiudad Victoria;23.7389\nCiudad Santa Catarina;25.6833\nSantarém;-2.4300\nNewark;40.7245\nVaughan;43.8333\nĀwasa;7.0500\nŌakashichō;34.6500\nYeşilyurt;38.2961\nPekalongan;-6.8833\nPondokaren;-6.2811\nAdıyaman;37.7639\nKurume;33.3167\nVila Nova de Gaia;41.1333\nPaulista;-7.9408\nOaxaca;17.0606\nArmenia;4.5300\nAkita;39.7200\nAwka;6.2000\nSan Bernardo;-33.5833\nCurepipe;-20.3188\nIksan;35.9439\nPachuca;20.1000\nAl Maţarīyah;31.1833\nSóc Trăng;9.6028\nBahía Blanca;-38.7167\nCoacalco;19.6333\nSan Juan del Río;20.3833\nFort Collins;40.5477\nLimeira;-22.5650\nPopayán;2.4542\nPraia Grande;-24.0061\nQianzhou;28.3185\nNewcastle;54.9800\nMāldah;25.0119\nCiudad General Escobedo;25.7933\nOyster Bay;40.7846\nMontpellier;43.6119\nPhan Thiết;10.9333\nStockport;53.4083\nAl Qunfudhah;19.1264\nBada Barabīl;22.1200\nTampico;22.2553\nBiałystok;53.1353\nCoatepeque;14.7000\nAsh Shāmīyah;31.9636\nMérida;8.4800\nChakwal;32.9303\nMurmansk;68.9706\nAr Raqqah;35.9500\nAfyonkarahisar;38.7578\nBihār;25.1970\nJember;-8.1727\nValladolid;41.6528\nReading;40.3400\nSpringfield;37.1943\nİskenderun;36.5817\nAl Mubarraz;25.4416\nPetrópolis;-22.5050\nAugsburg;48.3689\nNavotas;14.6667\nChernihiv;51.4939\nYangsan;35.3333\nComilla;23.4500\nIrvine;33.6772\nBradford;53.8000\nTagum;7.4478\nEspoo;60.2056\nValparaíso;-33.0461\nSilang;14.2306\nFinglas;53.4597\nRangpur;25.7500\nVigo;42.2314\nSikandarābād;28.4512\nBattalgazi;38.4228\nBāli;22.6500\nÇorum;40.5455\nIsmailia;30.5833\nVila Teixeira da Silva;-12.0072\nPānīpat;29.3875\nDelmas;18.5500\nStrasbourg;48.5833\nMabalacat;15.2167\nBatna;35.5500\nĀīzawl;23.7272\nTambov;52.7167\nDexing;28.9580\nIaşi;47.1622\nKunp’o;37.3500\nSan Lorenzo;-25.3400\nSanta Maria;14.8183\nSonpur;25.7000\nGroznyy;43.3125\nKherson;46.6425\nAnchorage;61.1508\nThe Woodlands;30.1738\nHong’an;47.2100\nResistencia;-27.4514\nGraz;47.0708\nKarīmnagar;18.4386\nBraşov;45.6667\nSumida;35.7107\nSekondi;4.9433\nSouth Bend;41.6767\nMorioka;39.7021\nSonīpat;28.9900\nSétif;36.1900\nAtyraū;47.1167\nIpswich;52.0594\nDewās;22.9600\nHulin;45.7671\nRockford;42.2596\nSavannah;32.0286\nItagüí;6.1667\nCroix-des-Bouquets;18.5761\nFarg‘ona;40.3864\nMagway;20.1500\nHuixquilucan;19.3611\nLincoln;40.8099\nIchalkaranji;16.7000\nPunto Fijo;11.7167\nVárzea Grande;-15.6500\nSincelejo;9.2950\nIbaraki;34.8164\nKatowice;50.2667\nAr Ruşayfah;32.0178\nCamaçari;-12.6978\nJersey City;40.7184\nSan Cristóbal;7.7682\nRound Lake Beach;42.3791\nBolton;53.5780\nSan Pablo;14.0700\nSuzano;-23.5428\nKorhogo;9.4167\nBhatinda;30.2300\nCascavel;-24.9556\nFlint;43.0236\nOstrava;49.8356\nTacna;-18.0147\nShreveport;32.4653\nAl Qurnah;31.0158\nJālna;19.8410\nAarhus;56.1572\nConstanţa;44.1667\nSan Juan Sacatepéquez;14.7189\nMyeik;12.4333\nFukushima;37.7608\nCoro;11.3950\nBago;17.3333\nPasarkemis;-6.1703\nFuquan;26.7039\nTongchuanshi;35.0800\nSannai;24.5984\nHuozhou;36.5726\nTemuco;-38.7333\nIhosy;-22.4036\nSterlitamak;53.6333\nTegal;-6.8667\nIca;-14.0667\nLucena;13.9333\nPlano;33.0502\nJining;41.0300\nChuncheon;37.8667\nMalārd;35.6658\nPematangsiantar;2.9600\nSatna;24.6005\nLong Xuyên;10.3736\nMyrtle Beach;33.7094\nGovernador Valadares;-18.8500\nPetrozavodsk;61.7833\nSanta Ana;13.9950\nMau;25.9417\nCompaniganj;22.8750\nWiesbaden;50.0825\nMingaora;34.7717\nDavenport;41.5565\nBukhara;39.7667\nSumbe;-11.2053\nViệt Trì;21.3000\nSunderland;54.9060\nBārāsat;22.7200\nCherkasy;49.4444\nMaastricht;50.8500\nÇorlu;41.1500\nKostroma;57.7681\nGyeongsan;35.8167\nCiego de Ávila;21.8481\nMamuju;-2.6833\nLos Alcarrizos;18.5167\nNizhnevartovsk;60.9500\nSan Mateo;14.6969\nShaowu;27.3417\nCanton;40.8078\nSfax;34.7400\nDinājpur;25.6167\nDire Dawa;9.6000\nGagnoa;6.1333\nKhmelnytskyi;49.4167\nFarrukhābād;27.3900\nLashkar Gāh;31.5831\nPosadas;-27.3667\nGatineau;45.4833\nWindsor;42.2833\nSanta Clarita;34.4175\nKunsan;35.9833\nMinato;35.6580\nQarshi;38.8667\nChula Vista;32.6281\nSaugor;23.8300\nKafr ad Dawwār;31.1311\nRatlām;23.3340\nYeosu;34.7607\nCrato;-7.4639\nMỹ Tho;10.3500\nVolta Redonda;-22.5228\nEugene;44.0564\nTsu;34.7184\nNovorossiysk;44.7167\nBijiao;22.9311\nSzékesfehérvár;47.1956\nSoubré;5.7833\nPalmas;-10.1844\nMajene;-3.5403\nSorong;-0.8667\nChandler;33.2825\nCraiova;44.3333\nThái Bình;20.4461\nBinjai;3.5986\nFuchū;35.6689\nGabela;-10.8500\nSakarya;40.7833\nDayr az Zawr;35.3333\nBrāhmanbāria;23.9656\nMito;36.3658\nSartā;36.4491\nPlymouth;50.3714\nSanto Domingo de los Colorados;-0.2542\nArnavutköy;41.1856\nNguru;12.8792\nMaradi;13.4833\nGombe;10.2904\nGijón;43.5333\nDrug;21.1900\nFloridablanca;7.2167\nHandwāra;34.4000\nQuilmes;-34.7167\nTalisay;10.2500\nKunduz;36.7286\nYoshkar-Ola;56.6328\nNalchik;43.4833\nAswān;24.0889\nIchihara;35.4981\nSalem;44.9233\nZhytomyr;50.2500\nImphāl;24.8074\nİnegöl;40.0806\nChernivtsi;48.3000\nTarija;-21.5333\nSiddhirganj;23.6833\nBimo;4.2558\nHeroica Nogales;31.3186\nBergen;60.3894\nSumaré;-22.8219\nFeni;23.0183\nSumy;50.9167\nAnantapur;14.6800\nWestminster;51.4947\nXiangkhoang;19.4167\nMarabá;-5.3500\nKütahya;39.4167\nGent;51.0536\nYao;34.6269\nDjelfa;34.6667\nBarueri;-23.5111\nBordeaux;44.8400\nNagaoka;37.4462\nSuncheon;34.9506\nJalālābād;34.4342\nEngels;51.5017\nMalolos;14.8433\nNogales;31.1833\nDezfūl;32.3825\nEd Daein;11.4608\nLuque;-25.2700\nPotosí;-19.5892\nConcord;35.3933\nSão José dos Pinhais;-25.5350\nOsmaniye;37.0750\nArrah;25.5514\nKyŏngju;35.8500\nDumai;1.6667\nTāluqān;36.7167\nDamanhūr;31.0361\nEl Fasher;13.6306\nMalkājgiri;17.4519\nNawabshah;26.2442\nTchibota;-4.1794\nAnnaba;36.9000\nGelsenkirchen;51.5167\nMönchengladbach;51.2000\nKakogawachō-honmachi;34.7500\nWollongong;-34.4331\nGilbert;33.3100\nNonthaburi;13.8667\nColumbus;32.5100\nMarilao;14.7581\nFukui;36.0641\nVenice;45.4397\nBoksburg;-26.2125\nQuảng Ngãi;15.1167\nOlongapo;14.8300\nCiudad Benito Juárez;25.6500\nHiratsuka;35.3167\nTiruvottiyūr;13.1600\nOumé;6.3833\nSōka;35.8254\nBunkyō-ku;35.7080\nAguadilla;18.4382\nAl Ḩamzah;31.7339\nLubbock;33.5657\nMossoró;-5.1878\nKotri;25.3660\nNorth Las Vegas;36.2883\nTuzla;40.8161\nSinga;13.1500\nMişrātah;32.3775\nIsparta;37.7647\nDerby;52.9217\nVerona;45.4386\nHuayin;34.5664\nSiverek;37.7500\nSt. Petersburg;27.7931\nNdulo;-11.4833\nRāniyah;36.2550\nGermiston;-26.2178\nTallahassee;30.4551\nMount Lavinia;6.8731\nEtāwah;26.7700\nHorlivka;48.3336\nAntsirabe;-19.8667\nOndo;7.0833\nIndaiatuba;-23.0903\nPuducherry;11.9167\nLaredo;27.5625\nẤp Đa Lợi;11.9333\nFoz do Iguaçu;-25.5400\nKhimki;55.8892\nSab‘ al Būr;33.4644\nGravataí;-29.9333\nChiayi;23.4800\nKediri;-7.8111\nDamaturu;11.7444\nTokushima;34.0703\nArua;3.0353\nPeoria;40.7520\nTurmero;10.2283\nPointe-à-Pitre;16.2411\nKuala Terengganu;5.3292\nCampeche;19.8500\nByatarayanpur;13.0659\nMawlamyine;16.4847\nGodomè;6.3667\nSan Pedro Carchá;15.4768\nMoçâmedes;-15.1953\nLa Paz;24.1422\nCentral District;22.2867\nSão Carlos;-22.0000\nVitoria-Gasteiz;42.8500\nWolverhampton;52.5833\nAvondale;33.3873\nLafayette;30.2082\nAsh Shaţrah;31.4097\nIrving;32.8583\nRishon LeẔiyyon;31.95\nMontgomery;32.3482\nÇekme;41.0369\nJhenida;23.5417\nBharatpur;27.2200\nGadda Madiral;18.7519\nShinozaki;33.9500\nGoma;-1.6794\nTacloban;11.2444\nTurku;60.4500\nRạch Giá;10.0167\nKanggye;40.9667\nTaganrog;47.2167\nKızıltepe;37.1939\nEl Geneina;13.4500\nLas Condes;-33.4117\nHakodate;41.7686\nUşak;38.6778\nJūnāgarh;19.8599\nBegusarai;25.4200\nSão José;-27.6000\nA Coruña;43.3667\nLos Teques;10.3411\nJinshi;29.6334\nChōfugaoka;35.6506\nTsing Yi Town;22.3456\nHigüey;18.6167\nJuazeiro do Norte;-7.2000\nBata;1.8650\nAl Minyā;28.1194\nAachen;50.7756\nBābol;36.5514\nKomsomol’sk-na-Amure;50.5667\nIwo;7.6333\nRivne;50.6192\nGalaţi;45.4233\nNatogyi;21.4167\nBraunschweig;52.2667\nKalār;34.6292\nAl Bayḑā’;32.7664\nYanbu;24.0883\nKurmuk;10.5500\nShibuya-ku;35.6637\nGāndhīdhām;23.0800\nManzhouli;49.5881\nVisalia;36.3276\nGdynia;54.5000\nRāmnagar;27.1700\nPalangkaraya;-2.2100\nChemnitz;50.8333\nChigasaki;35.3333\nBüyükçekmece;41.0200\nKhomeynī Shahr;32.7003\nCarmen;18.4167\nMcKinney;33.2016\nSahiwal;30.6611\nQā’em Shahr;36.4631\nBanikoara;11.3000\nKiel;54.3233\nSibu;2.3000\nYato;35.4833\nParaná;-31.7331\nSanta Clara;22.4069\nYamagata;38.2554\nKatihār;25.5300\nBeykoz;41.1342\nImperatriz;-5.5333\nOruro;-17.9799\nMerlo;-34.6653\nTsukuba-kenkyūgakuen-toshi;36.0835\nWilmington;34.2099\nKesbewa;6.7953\nBarnsley;53.5547\nChesapeake;36.6778\nSyktyvkar;61.6667\nGyőr;47.6842\nBirāṭnagar;26.4542\nHafizabad;32.0714\nSaskatoon;52.1333\nKrishnarājpur;13.0120\nAbertawe;51.6167\nAmericana;-22.7386\nMahajanga;-15.7167\nLong Khánh;10.9170\nNelamangala;13.1020\nJessore;23.1704\nBeichengqu;40.4348\nGlendale;33.5791\nTuy Hòa;13.0819\nGarland;32.9100\nSingrauliya;24.1100\nFuji;35.1613\nMokpo;34.7589\nKabinda;-6.1300\nTanga;-5.0667\nSanta Maria;-29.6833\nSabzevār;36.2125\nBānchpār;23.2000\nRāmgundam;18.7639\nTarapoto;-6.4833\nBahir Dar;11.6000\nBaruta;10.4322\nSapele;5.8261\nSasebo;33.1800\nMyitkyina;25.3833\nPandharpur;17.6778\nSakākā;29.9697\nHaeju;38.0333\nPetaẖ Tiqwa;32.0889\nGonzález Catán;-34.7667\nMasaurhi Buzurg;25.3500\nQyzylorda;44.8500\nDiaobingshancun;42.4391\nMan;7.4000\nZhangping;25.2938\nDagana;16.4833\nBạc Liêu;9.2833\nKennewick;46.1978\nLille;50.6278\nDüzce;40.8417\nIpatinga;-19.5000\nAnju;39.6200\nMarília;-22.2139\nWinter Haven;28.0118\nMonclova;26.9103\nStavanger;58.9700\nAbī al Khaşīb;30.4411\nAtushi;39.7162\nChimoio;-19.1167\nLimassol;34.6747\nIvano-Frankivsk;48.9228\nNovo Hamburgo;-29.6778\nHalle;51.4828\nArakawa;35.7361\nLongueuil;45.5333\nSzeged;46.2550\nViamão;-30.0808\nKošice;48.7167\nMatsumoto;36.2380\nTuticorin;8.7642\nBanda Aceh;5.5500\nShenmu;38.8270\nSprings;-26.2547\nTaiping;4.8500\nZinder;13.8053\nGangānagar;29.9200\nAs Sīb;23.6703\nP’yŏng-dong;39.2500\nScottsdale;33.6872\nĀmol;36.4697\nNorfolk;36.8945\nNyíregyháza;47.9531\nEindhoven;51.4333\nKilleen;31.0753\nWuyishan;27.7562\nMirpur Khas;25.5269\nSandnes;58.8517\nBeji;-6.3704\nPathein;16.7778\nNizhnekamsk;55.6333\nMagdeburg;52.1317\nNeya;34.7667\nRewa;24.5300\nChishui;28.5902\nCenturion;-25.8603\nUluberiya;22.4700\nDjougou;9.7000\nPākdasht;35.4817\nShakhty;47.7000\nNorth Hempstead;40.7912\nYork;39.9651\nAtlantic City;39.3797\nIbb;13.9759\nElche;38.2669\nAbhā;18.2169\nBulandshahr;28.4069\nGroningen;53.2167\nNashua;42.7491\nJacareí;-23.3053\nArlington;38.8786\nBrownsville;25.9975\nBole;44.8539\nGanda;-13.0858\nCannanore;11.8689\nNajafābād;32.6347\nBayamo;20.3817\nKamianske;48.5167\nBorūjerd;33.8972\nSingaraja;-8.1167\nMacaé;-22.3708\nMiri;4.3925\nMachala;-3.2667\nKasulu;-4.5800\nLongquan;28.0733\nGranada;37.1781\nBo;7.9564\nMessina;38.1936\nOral;51.2225\nBadalona;41.4333\nFormosa;-26.1833\nSan Cristóbal;18.4167\nArapiraca;-9.7519\nMambéré;5.5000\nDamboa;11.1500\nOkara;30.8092\nSaidpur;25.8004\nFreiburg im Breisgau;47.9950\nKhénifra;32.9394\nSaga;33.2667\nRāichūr;16.2000\nBurnaby;49.2667\nMeycauayan;14.7333\nSơn Tây;21.1333\nNazipur;25.0415\nRancagua;-34.1667\nKasukabe;35.9753\nDzerzhinsk;56.2333\nPhú Yên;21.4156\nBratsk;56.1167\nBarishal;22.7000\nJiayuguan;39.8112\nSanta Ana;14.5800\nEloy Alfaro;-2.1733\nEnvigado;6.1667\nBanfield;-34.7500\nGuadalupe;22.7528\nAgeoshimo;35.9774\nFremont;37.5265\nQarchak;35.4394\nGulfport;30.4274\nPurwokerto;-7.4278\nPuerto Vallarta;20.6458\nToluca;19.2925\nOrmoc;11.0106\nNeuquén;-38.9525\nFresnillo;23.1750\nSingkawang;0.9000\nOrsk;51.2000\nVizianagaram;18.1159\nManavgat;36.7833\nCotia;-23.6042\nPāli;25.7700\nSongadh;21.1670\nNoginsk;64.4833\nKropyvnytskyi;48.5000\nHaridwār;29.9450\nOrdu;40.9833\nTaitō;35.7126\nTernopil;49.5667\nBojnūrd;37.4750\nRondonópolis;-16.4667\nCobán;15.4833\nGuantánamo;20.1367\nKrefeld;51.3333\nPāthardi;19.1700\nŞabyā;17.1489\nKolpino;59.7333\nPetlād;22.4700\nKhanewal;30.3000\nMagé;-22.6528\nNinh Hòa;12.4917\nKhatīma;28.9200\nApapa;6.4500\nCholoma;15.6136\nCapiatá;-25.3500\nPallāvaram;12.9675\nNadiād;22.6900\nTarrasa;41.5611\nDaşoguz;41.8333\nProbolinggo;-7.7500\nCikupa;-6.4947\nEvansville;37.9881\nAraraquara;-21.7939\nQuetzaltenango;14.8333\nAngarsk;52.5500\nSousse;35.8333\nNyanza;-2.3500\nCox’s Bāzār;21.4272\nTakarazuka;34.8114\nAtsugichō;35.4333\nItapevi;-23.5489\nMarcory;5.3000\nToamasina;-18.1500\nPadangsidempuan;1.3786\nVarāmīn;35.3242\nMutare;-18.9667\nMubi;10.2604\nChuādānga;23.6440\nKorolëv;55.9167\nHunchun;42.8679\nBlagoveshchensk;50.2578\nVelikiy Novgorod;58.5210\nLongjin;22.8711\nRennes;48.1147\nAshdod;31.8\nCzęstochowa;50.8000\nCarlos Manuel de Céspedes;21.5767\nChapecó;-27.0958\nHialeah;25.8696\nŌta;36.2911\nSandton;-26.1070\nNavarre;30.4174\nIjebu-Ode;6.8208\nTilburg;51.5500\nCork;51.8972\nTanjore;10.7870\nBandar-e Būshehr;28.9264\nHachinohe;40.5123\nStaryy Oskol;51.2981\nKichha;28.9200\nSecunderābād;17.4399\nTiptūr;13.2600\nJi’an Shi;41.1231\nMallawī;27.7333\nJosé C. Paz;-34.5167\nBel Air South;39.5022\nRufisque;14.7167\nPresidente Prudente;-22.1256\nBarra do Dande;-8.4728\nHobart;-42.8806\nSwindon;51.5600\nLutsk;50.7500\nKatri;23.4800\nSambhal;28.5800\nGuéckédou;8.5667\nSabadell;41.5483\nNeyshābūr;36.2200\nNorth Port;27.0576\nRadom;51.4036\nSanta Luzia;-19.7700\nPolokwane;-23.9000\nChí Linh;21.1330\nTchaourou;8.8833\nDuekoué;6.7333\nSan Felipe;10.3353\nSāveh;35.0214\nSan Bernardino;34.1416\nPortland;43.6773\nSanto Tomas;14.0833\nOsisioma;5.1497\nLa Vega;19.2200\nNishitōkyō;35.7256\nDamietta;31.4167\nPangkalpinang;-2.1333\nJuazeiro;-9.4306\nKremenchuk;49.0631\nItabuna;-14.7858\nĀnand;22.5560\nCiputat;-6.3111\nAl Khubar;26.2833\nPeñalolén;-33.4833\nIslington;51.5440\nMainz;49.9833\nKonibodom;40.2833\nZākhū;37.1500\nEnterprise;36.0091\nBremerton;47.5436\nCórdoba;18.8942\nGreen Bay;44.5148\nTuluá;4.0833\nPleiku;13.9833\nHortolândia;-22.8583\nBitung;1.4472\nNaihāti;22.8900\nPetrel;38.4789\nKafue;-15.7667\nJiutepec;18.8833\nManta;-0.9500\nOsan;37.1498\nSan Miguel;13.4814\nButembo;0.1500\nNetanya;32.3286\nOviedo;43.3600\nItaboraí;-22.7439\nAppleton;44.2780\nZamora;19.9833\nAlor Setar;6.1183\nLuton;51.8783\nBabylon;40.6925\nLaâyoune;27.1536\nShashemenē;7.2000\nTân An;10.5333\nSpring Valley;36.0952\nDenov;38.2667\nCartagena;37.6000\nTacoma;47.2431\nYamunānagar;30.1330\nLübeck;53.8697\nZielona Góra;51.9333\nMaţraḩ;23.6167\nQostanay;53.2000\nBanjarbaru;-3.4425\nSa Đéc;10.3000\nWayaobu;37.1398\nValencia;7.9042\nNorwich;52.6286\nGujiao;37.9069\nAyacucho;-13.1631\nPetropavl;54.8833\nMadiun;-7.6300\nDongxing;21.5833\nZhubei;24.8333\nSão Leopoldo;-29.7600\nHebron;31.5333\nSpartanburg;34.9442\nMarg‘ilon;40.4711\nAr Ruseris;11.8500\nTrece Martires City;14.2833\nGangneung;37.7500\nRoanoke;37.2785\nCúa;10.1667\nAlmere;52.3667\nAs Samāwah;31.3167\nMonghyr;25.3810\nVantaa;60.2944\nKāpra;17.4859\nGolmud;36.4072\nComalcalco;18.2801\nGeneva;46.2017\nRegina;50.4547\nLa Victoria;10.2278\nShimla;31.1033\nNorthampton;52.2304\nBabruysk;53.1500\nMohammedia;33.6833\nErfurt;50.9833\nSete Lagoas;-19.4658\nSikasso;11.3167\nWarnes;-17.5167\nMóstoles;40.3333\nQuilicura;-33.3667\nChilas;35.4194\nCao Lãnh;10.4672\nEl Tigre;8.8858\nGokāk;16.1667\nDivinópolis;-20.1389\nGainesville;29.6804\nColombo;-25.2919\nJerez de la Frontera;36.6817\nPuri;19.8106\nSidi Bel Abbès;35.2000\nNandyāl;15.4800\nLimbe;4.0167\nKure;34.2500\nTumaco;1.8067\nPadova;45.4064\nIrákleio;35.3403\nDeltona;28.9050\nArroyo Naranjo;23.0436\nBhadrāvati;13.8485\nColón;9.3572\nLinz;48.3058\nOberhausen;51.4967\nCriciúma;-28.6775\nKuje;8.8822\nMytishchi;55.9167\nLyubertsy;55.6783\nPamplona;42.8167\nPanchkula;30.7400\nKalamazoo;42.2749\nPskov;57.8167\nBila Tserkva;49.7956\n‘Aqrah;36.7414\nPloieşti;44.9411\nIsesaki;36.3114\nNaga City;13.6244\nBurgas;42.5030\nBurhānpur;21.3000\nChungju;36.9667\nMaracanaú;-3.8667\nThousand Oaks;34.1914\nHickory;35.7410\nPagadian;7.8272\nLegazpi City;13.1333\nBarrancabermeja;7.0667\nBukit Mertajam;5.3631\nKirātot;32.8376\nAshaiman;5.7000\nTaisheng;23.2938\nSidon;33.5606\nRostock;54.0833\nGuarenas;10.4739\nSanta Cruz;28.4667\nPanabo;7.3000\nDongning;44.0608\nBorj Hammoud;33.8936\nKasangati;0.4378\nSolihull;52.4130\nBurutu;5.3500\nNasīm Shahr;35.5644\nMoratuwa;6.7991\nYonkers;40.9466\nIch’ŏn;37.2667\nMilton Keynes;52.0400\nMarawi City;8.0000\nPuerto Cabello;10.4667\nBeersheba;31.2589\nHuangyan;28.6500\nOulu;65.0142\nSanto Agostinho;-8.2897\nLubuklinggau;-3.2967\nMary;37.6000\nSunyani;7.3333\nCascais;38.7000\nNorthcote;-36.8019\nMoreno Valley;33.9244\nQinā;26.1667\nToledo;10.3833\nKharagpur;22.3302\nWaitakere;-36.8500\nFontana;34.0968\nMonywa;22.1083\nDindigul;10.3500\nRobertsonpet;12.9563\nMorogoro;-6.8242\nPingzhen;24.9439\nBanī Suwayf;29.0667\nCollege Station;30.5852\nBà Rịa;10.4992\nCidade de Nacala;-14.5428\nTalca;-35.4269\nFargo;46.8651\nPortoviejo;-1.0561\nParakou;9.3500\nHospet;15.2689\nTrieste;45.6503\nSan Carlos City;15.9281\nKodaira;35.7285\nItami;34.7833\nLingampalli;17.4865\nKalemie;-5.9128\nKamirenjaku;35.6836\nLoures;38.8333\nBiskra;34.8500\nIngrāj Bāzār;25.0044\nPhủ Từ Sơn;21.1189\nLa Ceiba;15.7792\nBené Beraq;32.0833\nNagareyama;35.8563\nOngole;15.5060\nZanzibar;-6.1650\nJiutai;44.1447\nBolu;40.7347\nZiguinchor;12.5833\nTernate;0.7800\nPuqi;29.7204\nQal‘at Bīshah;20.0000\nEllore;16.7117\nBetigeri;15.4430\nPasso Fundo;-28.2500\nBanjar;-7.3667\nKinh Môn;21.0330\nBingerville;5.3500\nBắc Giang;21.2667\nSejong;36.4870\nYachiyo;35.7224\nAmarillo;35.1984\nMandi Burewala;30.1500\nVĩnh Long;10.2500\nMokameh;25.3898\nCoquimbo;-29.9531\nTekirdağ;40.9778\nHuntington;40.8521\nParnamirim;-5.9167\nHolon;32.0167\nKukawa;12.9167\nBiysk;52.5333\nCharleroi;50.4000\nAberdeen;57.1500\nDeoghar;24.4800\nLa Guaira;10.6000\nBīrjand;32.8667\nChhindwāra;22.0570\nTimayy al Imdīd;30.9438\nMazabuka;-15.8467\nPoza Rica de Hidalgo;20.5333\nToruń;53.0222\nTanjungpinang;0.9188\nKassel;51.3158\nHaldia;22.0667\nLuxor;25.6833\nLạng Sơn;21.8478\nAt Tājī;33.5092\nTarakan;3.3000\nLas Tunas;20.9597\nAl Khawr;25.6900\nMatsue;35.4708\nArica;-18.4667\nHà Tĩnh;18.3333\nCosenza;39.3000\nAl Khums;32.6497\nHuacho;-11.1000\nEl Jadid;33.2333\nCajamarca;-7.1667\nNorwich;41.5495\nCiudad Madero;22.2500\nMai’Adua;13.1906\nJacobabad;28.2769\nAlmería;36.8403\nTokat;40.3139\nSātkhira;22.7188\nNéma;16.6167\nKhandwa;21.8200\nPulimaddi;15.4800\nMorena;26.5000\nSoio;-6.1333\nGuacara;10.2333\nOlympia;47.0417\nKabankalan;9.9833\nIsidro Casanova;-34.7000\nRio Claro;-22.4108\nSanta Tecla;13.6731\nIsanlu;8.1667\nAz Zāwīyah;32.7522\nKasama;-10.2117\nMaharagama;6.8494\nKouribga;32.8833\nAmroha;28.9044\nLahad Datu;5.0300\nChilpancingo;17.5500\nDrabar;33.4300\nWaterbury;41.5582\nLiège;50.6397\nBanja Luka;44.7725\nSalinas;36.6883\nHuntington;38.4109\nAlcalá de Henares;40.4818\nTaranto;40.4711\nKhowy;38.5519\nUripa;11.9167\nKankan;10.3833\nHuntington Beach;33.6960\nClarksville;36.5692\nMartapura;-3.4500\nCiudad del Carmen;18.6333\nBhind;26.5587\nChakradharpur;22.7000\nTocuyito;10.0889\nAlvorada;-29.9897\nRichmond;49.1667\nAraçatuba;-21.2089\nSanta Barbara;34.4285\nGemena;3.2500\nOradea;47.0722\nDesē;11.1333\nHelong;42.5404\nCroydon;51.3727\nBéni Mellal;32.3394\nMadhyamgram;22.7000\nMwene-Ditu;-7.0000\nKhammam;17.2473\nBhiwāni;28.7800\nHigashi-Hiroshima;34.4167\nN’Zérékoré;7.7500\nHuánuco;-9.9295\nRzeszów;50.0333\nEldoret;0.5167\nMbanza-Ngungu;-5.2500\nShrīrāmpur;22.7500\nHino;35.6713\nZipaquirá;5.0333\nRio Grande;-32.0350\nProkopyevsk;53.8833\nRajin;42.3444\nFuenlabrada;40.2833\nGhāndīnagar;23.2230\nBrescia;45.5389\nKusŏng;39.9667\nBaharampur;24.1000\nSūhāj;26.5500\nAcarigua;9.5597\nHugli;22.9089\nSan Pedro de Macorís;18.4500\nGlendale;34.1819\nMbarara;-0.6133\nParma;44.8015\nSunrise Manor;36.1783\nKenema;7.8758\nBrikama;13.2667\nSuzuka;34.8820\nKajo Kaji;3.8492\nKoronadal;6.5000\nCuautla;18.8167\nGrand Prairie;32.6871\nViranşehir;37.2306\nIskandar;41.5581\nKaraköprü;37.1847\nSosnowiec;50.2833\nTanauan;14.0833\nMyawadi;16.6878\nLa Serena;-29.9000\nSodo;6.8550\nTrondheim;63.4297\nMorbi;22.8200\nĀrba Minch’;6.0333\nPrato;43.8808\nOverland Park;38.8870\nTchitato;-7.3450\nMalema;-14.9486\nAnseong;37.0078\nYuzhno-Sakhalinsk;46.9500\nRichmond Hill;43.8667\nNarsingdi;23.9167\nGorontalo;0.5333\nGuanajuato;21.0178\nHagerstown;39.6401\nPeterborough;52.5662\nNampa;43.5844\nQuelimane;-17.8764\nTébessa;35.4000\nKumagaya;36.1474\nSan Fernando;7.8940\nRijeka;45.3272\nGastonia;35.2494\nMahbūbnagar;16.7488\nKaraman;37.1819\nLa Plata;-34.9211\nFatehpur;25.9300\nPāndhurnā;21.6000\nYamaguchi;34.1833\nLae;-6.7303\nMuar;2.0500\nCap-Haïtien;19.7600\nOakville;43.4500\nGodoy Cruz;-32.9167\nBūkān;36.5172\nMuş;38.7333\nHyesan;41.4000\nKielce;50.8742\nFrisco;33.1560\nKırıkkale;39.8417\nJalapa;14.6379\nRājendranagar;17.3198\nCastanhal;-1.2969\nGuanare;9.0436\nCedar Rapids;41.9662\nBasildon;51.5800\nFernando de la Mora;-25.3200\nLeganés;40.3281\nPābna;24.0167\nRāe Bareli;26.2236\nFlorencia;1.6139\nGeneral Mariano Alvarez;14.3000\nFianarantsoa;-21.4536\nSan Cristóbal;16.7370\nBago;10.5388\nValera;9.3206\nBournemouth;50.7200\nPasuruan;-7.6406\nArmavir;45.0000\nBalakovo;52.0333\nJhelum;32.9425\nDonostia;43.3200\nHemet;33.7341\nAydın;37.8481\nBatu;-7.8720\nOrai;25.9800\nManzanillo;19.0522\nAnjōmachi;34.9587\nLam Tin;22.3094\nMalaybalay;8.1564\nFerraz de Vasconcelos;-23.5411\nSanta Bárbara d’Oeste;-22.7544\nChibia;-15.1833\nOdawara;35.2500\nKishiwada;34.4667\nSaddiqabad;28.3006\nShahr-e Kord;32.3311\nRybinsk;58.0500\nAbū Ghurayb;33.2919\nChŏngju;39.6500\nCachoeiro de Itapemirim;-20.8489\nHagen;51.3667\nParadise;36.0872\nNgaoundéré;7.3167\nPak Kret;13.9125\nDonghua;35.2175\nBraga;41.5503\nSioux Falls;43.5396\nLas Heras;-32.8500\nAraure;9.5667\nDigos;6.7500\nPinar del Río;22.4122\nEl Progreso;15.4000\nNumazu;35.0956\nRāiganj;25.6200\nTachikawa;35.6942\nPrabumulih;-3.4328\nAngra dos Reis;-23.0067\nBhusāval;21.0500\nSan Francisco de Macorís;19.3000\nVancouver;45.6366\nSobral;-3.6739\nAl Ḩasakah;36.5117\nKlerksdorp;-26.8667\nKecskemét;46.9061\nGuatire;10.4717\nIquique;-20.2167\nEl Bosque;-33.5667\nKōfu;35.6621\nSan Diego;10.2558\nGharyān;32.1697\nThingangyun;16.8281\nPeoria;33.7843\nBārākpur;22.7642\nPadalarang;-6.8435\nTottori;35.5000\nChaedŏk;40.7988\nJōetsu;37.1479\nBahraigh;27.5750\nUcu Seles;-11.4047\nCalbayog City;12.0667\nWaco;31.5599\nKairouan;35.6772\nTambaram;12.8310\nCabo Frio;-22.8789\nShendi;16.6833\nLorain;41.4409\nErie;42.1167\nShibīn al Kawm;30.5586\nEd Damazin;11.7667\nUmreth;22.6986\nReims;49.2628\nDunhuang;40.1411\nMahesāna;23.6000\nNossa Senhora do Socorro;-10.8550\nBreda;51.5889\nGetafe;40.3047\nModena;44.6458\nGuri;37.6000\nJamaame;0.0667\nBasel;47.5547\nTân Châu;10.7739\nDinapore;25.6225\nSemnān;35.5728\nTemirtaū;50.0500\nToyokawa;34.8268\nNewport News;37.1051\nYei;4.0904\nAlasandigutta;15.6300\nLuzhang;25.8519\nAl Qāmishlī;37.0500\nFardīs;35.7167\nChūō-ku;35.6706\nGeelong;-38.1500\nVĩnh Châu;9.3330\nSiguiri;11.4189\nSeverodvinsk;64.5667\nBatāla;31.8186\nPotsdam;52.4000\nKottayam;9.5947\nItajaí;-26.9000\nTrảng Bàng;11.0330\nCuango;-9.1444\nAqtaū;43.6525\nOngata Rongai;-1.4000\nNiš;43.3192\nCuauhtémoc;28.4050\nAurora;41.7638\nNarashino;35.6804\nAbakan;53.7167\nBurlington;43.3167\nCuautitlán;19.6833\nOdense;55.3958\nLa Pintana;-33.5833\nPinrang;-3.7857\nIsiro;2.7833\nToulon;43.1258\nSorsogon;12.9742\nLagos de Moreno;21.3567\nSirsa;29.5333\nDourados;-22.2208\nAmadora;38.7333\nKāraikkudi;10.0735\nBrăila;45.2692\nUji;34.8844\nNova Friburgo;-22.2819\nFort Lauderdale;26.1412\nReggio di Calabria;38.1144\nBerazategui;-34.7167\nPhan Rang-Tháp Chàm;11.5667\nVallejo;38.1125\nDosquebradas;4.8333\nThanhlyin;16.7333\nYork;53.9601\nPetropavlovsk-Kamchatskiy;53.0167\nHimatnagar;23.6000\nAlleppey;9.4900\nEpe;6.5573\nSittwe;20.1670\nDam Dam;22.6200\nJaunpur;25.7300\nMurfreesboro;35.8490\nJīma;7.6667\nSucúa;-2.4600\nKindia;10.0497\nCurug;-6.3711\nGuna;24.6500\nLhokseumawe;5.1881\nRoxas City;11.5894\nFuntua;11.5204\nBoma;-5.8500\nTurbo;8.1000\nHinthada;17.6461\nÇanakkale;40.1519\nLa Rioja;-29.4125\nMadanapalle;13.5500\nPalopo;-3.0000\nNjeru;0.4311\nObuase;6.2000\nNijmegen;51.8475\nSaarbrücken;49.2333\nSan Luis Río Colorado;32.4767\nEdirne;41.6769\nTiaret;35.3667\nMahād;18.0830\nPurwakarta;-6.5533\nLongjing;42.7700\nSplit;43.5100\nIlhéus;-14.7889\nHosa’ina;7.5500\nBarra Mansa;-22.5439\nShivpuri;25.4300\nBhālswa Jahangirpur;28.7354\nHamm;51.6833\nTongjiang;47.6502\nAlmada;38.6803\nNorilsk;69.3333\nSpring Hill;28.4798\nMongu;-15.2775\nAl ‘Arīsh;31.1249\nDivo;5.8333\nUrayasu;35.6539\nBida;9.0804\nBade;24.9575\nPaita;-5.0911\nTorbalı;38.1619\nTownsville;-19.2500\nLangsa;4.4800\nDagupan City;16.0430\nTeziutlan;19.8178\nTempe;33.3881\nHigh Point;35.9910\nSultānpur Mazra;28.6981\nUnnāo;26.5500\nŞalālah;17.0197\nMedford;42.3372\nSalatiga;-7.3247\nMatosinhos;41.1833\nHamilton;-37.7833\nLin’an;23.6236\nChicoloapan;19.4167\nKandi;11.1286\nDanbury;41.4015\nMeiktila;20.8833\nDundo;-7.3801\nBejaïa;36.7511\nTitāgarh;22.7400\nLoum;4.7180\nBaranavichy;53.1333\nSanta María Texmelucan;19.2833\nKamakurayama;35.3197\nYangmei;24.9167\nIlford;51.5575\nLes Cayes;18.2000\nCiudad Valles;21.9833\nSantander;43.4628\nKadugli;11.0167\nLinhares;-19.3894\nLetpandan;17.7866\nKrasnogorsk;55.8217\nWārāseonī;21.7647\nMauli;30.6990\nSaint-Louis;16.0333\nRio Verde;-17.7450\nPlzeň;49.7475\nBiu;10.6111\nAit Melloul;30.3342\nComitán;16.2511\nSaint-Étienne;45.4347\nOrekhovo-Borisovo Yuzhnoye;55.6031\nOeiras;38.6833\nHabaswein;1.0100\nCatumbela;-12.4167\nSanta Cruz;14.5998\nEreğli;41.2792\nSầm Sơn;19.7333\nHarar;9.3111\nShibirghān;36.6650\nBurgos;42.3408\nChandannagar;22.8671\nCuddalore;11.7500\nOlsztyn;53.7778\nElk Grove;38.4161\nKotdwāra;29.7500\nMarāgheh;37.3906\nThành Phố Uông Bí;21.0356\nGliwice;50.2833\nBodrum;37.0378\nTebingtinggi;3.3283\nCianjur;-6.8200\nAlcorcón;40.3500\nOntario;34.0393\nChetumal;18.5036\nKhānaqīn;34.3333\nFrederick;39.4337\nSīrjān;29.4370\nTyre;33.2708\nMexico;15.0667\nMenemen;38.6000\nLudwigshafen;49.4811\nVero Beach South;27.6132\nSyzran;53.1667\nCarúpano;10.6722\nOcala;29.1780\nLubao;14.9333\nLuziânia;-16.2528\nOceanside;33.2247\nChīrāla;15.8246\nRatnapura;6.6806\nLeón;12.4344\nSan Andrés Tuxtla;18.4487\nTiantoujiao;23.0236\nCastellón de la Plana;39.9831\nPiedras Negras;28.7000\nBanhā;30.4667\nLinjiang;41.8471\nRancho Cucamonga;34.1247\nHạ Long;20.9500\nDeo;24.6561\nSilchar;24.8200\nTlemcen;34.8828\nHitachi;36.5991\nKindu;-2.9500\nShāhīn Shahr;32.8667\nLe Havre;49.4900\nGadag;15.4167\nAkhisar;38.9167\nPolomolok;6.2167\nMang La;14.3833\nSirājganj;24.4500\nTiruvannāmalai;12.1300\nRantau Prapat;2.3333\nBanyuwangi;-8.2186\nAlbacete;38.9956\nBīdar;17.9120\nSan Miguel;15.1458\nMülheim;51.4275\nSacaba;-17.4042\nGarden Grove;33.7787\nReggio Emilia;44.7000\nBarrie;44.3711\nKaolack;14.1389\nMoca;19.3833\nSão Caetano do Sul;-23.7000\nCape Coast;5.1000\nIzumo;35.3667\nBaliuag;14.9540\nOldenburg;53.1439\nSawangan;-6.4086\nPetite Rivière de l’Artibonite;19.1333\nNiiza;35.7935\nCazanga;-9.3000\nSurigao;9.7897\nBatumi;41.6458\nFrancisco Morato;-23.2817\nCary;35.7819\nVolgodonsk;47.5167\nBảo Lộc;11.5481\nRamat Gan;32.07\nPetarukan;-6.8961\nKohat;33.5833\nMakurdi;7.7306\nKamensk-Ural’skiy;56.4000\nLoja;-3.9833\nValsād;20.6100\nEscuintla;14.2978\nUssuriysk;43.8000\nSakura;35.7167\nConcepcion;15.3249\nMachilīpatnam;16.1700\nUppsala;59.8581\nTomakomai;42.6341\nPortmore;17.9500\nBordj Bou Arreridj;36.0667\nAplahoué;6.9333\nPembroke Pines;26.0128\nMalāyer;34.2969\nKluang;2.0336\nAs Suwayq;23.8494\nNovocherkassk;47.4222\nMétouia;33.9667\nMagwe;4.1333\nNishio;34.8333\nBayamón;18.3794\nSan Luis;-33.3000\nPuerto Montt;-41.4667\nMedinīpur;22.4240\nFenglu;24.6728\nSaḩāb;31.8667\nAl Marj;32.5005\nCaluquembe;-13.9208\nSŏsan;36.7817\nDamoh;23.8331\nToliara;-23.3500\nWarrington;53.3900\nGondomar;41.1500\nMinbya;20.3667\nJamālpur;24.9004\nSanta Rita;10.2003\nNeyveli;11.6088\nBāramūla;34.2000\nKalalé;10.2953\nOyama;36.3146\nWāpi;20.3720\nAmbato;-1.2417\nCalabozo;8.9219\nHŭich’ŏn;40.1707\nMahābād;36.7678\nItapecerica da Serra;-23.7172\nVilla Canales;14.4816\nBasuo;19.0920\nZlatoust;55.1667\nMalanville;11.8667\nJīnd;29.3167\nPalmdale;34.5944\nHaarlem;52.3833\nPátra;38.2500\nRíohacha;11.5442\nCatape;-13.7667\nTalas;38.6833\nKatha;24.1822\nManchester;42.9848\nTuguegarao;17.6133\nGuarapuava;-25.3833\nItu;-23.2642\nJutiapa;14.2917\nÇerkezköy;41.2833\nMogok;22.9167\nMukono;0.3533\nAl Kūfah;32.0300\nĀdoni;15.6244\nGrenoble;45.1715\nTabora;-5.0167\nSampit;-2.5333\nLafayette;40.3991\nTenāli;16.2390\nIwata;34.7179\nTakaoka;36.7541\nTam Kỳ;15.5667\nSkikda;36.8667\nSiirt;37.9250\nOsnabrück;52.2833\nKuytun;44.4264\nIpiales;0.8303\nFyzābād;26.7730\nKörfez;40.7833\nPerugia;43.1122\nUdipi;13.3389\nOshawa;43.9000\nTanjungbalai;2.9700\nObihiro;42.9167\nSanta Cruz;36.9789\nLeverkusen;51.0333\nKlaipėda;55.7500\nHadano;35.3667\nKushiro;42.9833\nMidsayap;7.1917\nIdlib;35.9333\nArnhem;51.9833\nKingswood;51.4600\nBéchar;31.6333\nConjeeveram;12.8308\nKandy;7.2964\nProddatūr;14.7300\nCienfuegos;22.1456\nNador;35.1667\nSaqqez;36.2464\nZhanlicun;23.2881\nEbo;-11.0000\nKökshetaū;53.2833\nNāngloi Jāt;28.6833\nFukang;44.1646\nTürkistan;43.3019\nPikit;7.0500\nHuddersfield;53.6450\nBocoio;-12.4667\nChillán;-36.6067\nMarysville;48.0809\nAbengourou;6.7333\nAbū Ḩulayfah;29.1322\nMuridke;31.8020\nTema;5.6667\nMetro;-5.1167\nMuskegon;43.2281\nIpswich;-27.6167\nMyingyan;21.4600\nQuibala;-10.7333\nTeresópolis;-22.4119\nCiudad Acuña;29.3242\nTunja;5.5333\n‘Unayzah;26.0906\nSan Marcos;10.6204\nTurgutlu;38.5000\nPocheon;37.8947\nNinh Bình;20.2539\nSão José de Ribamar;-2.5500\nWau;7.7000\nUbe;33.9500\nGölcük;40.6667\nMuzaffargarh;30.0694\nKebili;33.7050\nJizzax;40.1158\nKyaunggon;17.1000\nSimao;22.7807\nSan Martin Texmelucan de Labastida;19.2833\nBrahmanpara;23.6167\nNaic;14.3167\nJinggang;23.2723\nBandar-e Māhshahr;30.5589\nGodhra;22.7772\nAnaco;9.4333\nSullana;-4.9000\nVilleurbanne;45.7667\nZemun;44.8500\nSariaya;13.9667\nTuxtepec;18.1000\nSpringfield;39.7709\nMusashino;35.7177\nBhisho;-32.8494\nBenoni;-26.1883\nChitaldrug;14.2333\nAndong;36.5592\nHayward;37.6328\nRājapālaiyam;9.4204\nGuadalajara;40.6337\nMultai;21.7700\nRafsanjān;30.4067\nDijon;47.3167\nAl Ghardaqah;27.2578\nBontang;0.1333\nTulancingo;20.0833\nChittoor;13.2160\nSalihli;38.4811\nNdalatando;-9.3000\nElektrostal;55.7833\nJequié;-13.8630\nApeldoorn;52.2167\nTrà Vinh;9.9333\nĐồng Hới;17.4831\nKrishnanagar;23.4000\nSherbrooke;45.4000\nAsh Shīḩānīyah;25.3722\nKidapawan;7.0083\nSan Miguel;-34.5333\nPapantla de Olarte;20.4478\nDhamār;14.5500\nTân Phú;11.2720\nJosé María Ezeiza;-34.8333\nSouthend;51.5500\nIbirité;-20.0219\nSolingen;51.1667\nTacheng;46.7517\nZaranj;30.9600\nGeneral Roca;-39.0333\nBragança Paulista;-22.9531\nDarmstadt;49.8722\nZhengding;38.1522\nPindamonhangaba;-22.9239\nEnschede;52.2167\nGirón;7.0731\nUttarpāra;22.6700\nHeidelberg;49.4167\nKhōst;33.3331\nCeyhan;37.0289\nKoudougou;12.2500\nSaint-Marc;19.1167\nNewport;51.5886\nKhanpur;28.6453\nEde;7.7389\nHuaycan;-12.0181\nArad;46.1750\nMoga;30.8220\nFerkessédougou;9.5833\nZabrze;50.3025\nBingöl;38.8861\nSan Nicolás de los Arroyos;-33.3333\nBudaun;28.0500\nMiyakonojō;31.7167\nPandi;14.8667\nKramatorsk;48.7392\nAmersfoort;52.1500\nSeixal;38.6500\nLivorno;43.5519\nEkibastuz;51.6667\nHat Yai;7.0167\nHerne;51.5500\nChirchiq;41.4667\nLa Laguna;28.4853\nCatamarca;-28.4667\nAngers;47.4736\nJijiga;9.3500\nGeorge;-33.9667\nRavenna;44.4161\nHigashimurayama;35.7546\n’s-Hertogenbosch;51.6833\nBharūch;21.6948\nŌgaki;35.3594\nNan Zhuang;22.9839\nQuipungo;-14.8167\nCadiz;10.9500\nMolo;-0.2500\nChâu Đốc;10.7000\nZaanstad;52.4697\nGuimarães;41.4500\nTigaraksa;-6.2667\nMatsuzaka;34.5779\nMacuspana;17.7667\nAral;40.5480\nHoofddorp;52.3061\nSāmarrā’;34.1983\nIlagan;17.1489\nNew Bedford;41.6697\nRafael Castillo;-34.7167\nRío Cuarto;-33.1333\nRafaḩ;31.2886\nBariadi;-2.7919\nAlexandria;38.8185\nEnfield;51.6522\nDaiwanishi;34.8333\nGojra;31.1500\nTeixeira de Freitas;-17.5403\nPaterson;40.9147\nCamarajibe;-8.0219\nCorona;33.8616\nFethiye;36.6514\nMahlaing;21.0900\nŬiwang;37.3448\nSaharsa;25.8800\nCinere;-6.3333\nMerced;37.3057\nDanao;10.5333\nCalama;-22.4667\nChaoshan;23.0701\nNāblus;32.2222\nErzincan;39.7464\nWarner Robins;32.5961\nSalzburg;47.8000\nMandi Bahauddin;32.5797\nEl Eulma;36.1528\nItapetininga;-23.5917\nXiaping;26.7646\nPort Arthur;29.8554\nChlef;36.1647\nGuaymas;28.1667\nPathānkot;32.2668\nNazilli;37.9125\nKamina;-8.7386\nLajes;-27.8158\nMacon;32.8065\nPiteşti;44.8606\nKétou;7.3581\nAdzopé;6.1667\nPoblacion;10.4167\nHanam;37.5167\nCapas;15.3372\nGhorāhī;28.0333\nVidisha;23.5239\nCẩm Phả;21.0167\nEsmeraldas;0.9667\nAr Ramthā;32.5589\nKariya;34.9893\nAl Miqdādīyah;33.9786\nAlmetyevsk;54.9000\nDanzao;23.0427\nCagliari;39.2278\nHitachi-Naka;36.3967\nVĩnh Yên;21.3100\nNalgonda;17.0500\nRudarpur;28.9708\nKansas City;39.1235\nKisi;9.0833\nThānesar;29.9667\nEl Minié;34.4470\nLakewood;39.6977\nBorāzjān;29.2694\nGulu;2.7817\nSunnyvale;37.3836\nTimon;-5.0939\nPalo Negro;10.1600\nBytom;50.3483\nSouk Ahras;36.2864\nMiddelburg;-25.7684\nHorad Barysaw;54.2279\nRegensburg;49.0167\nFredericksburg;38.2992\nJorhāt;26.7500\nOxford;51.7519\nNeuss;51.2000\nHājīpur;25.6925\nCaxias;-4.8589\nBartın;41.6344\nSan Juan;14.6000\nMelitopol;46.8489\nZango;12.9333\nSasolburg;-26.8142\nKafr ash Shaykh;31.1117\nKitenkela;-1.5167\nBālurghāt;25.2200\nMadīnat as Sādis min Uktūbar;29.9361\nDibrugarh;27.4800\nVerāval;20.9000\nAlagoinhas;-12.1358\nEdremit;39.5922\nBandırma;40.3500\nSalavat;53.3667\nGandajika;-6.7500\nLucapa;-8.4228\nLeesburg;28.7672\nTama;35.6369\nRas Tanura;26.6500\nHòa Thành;11.2831\nHarrow;51.5836\nSeogwipo;33.2497\nTochigi;36.3813\nMoanda;-5.9342\nColima;19.2433\nBarreiras;-12.1483\nNaogaon;24.8000\nTete;-16.1667\nVillanueva;15.3167\nNoda;35.9500\nKanasín;20.9344\nIxtlahuaca;19.5689\nHoeryŏng;42.4333\nIringa;-7.7700\nSan Jose;12.3528\nKırşehir;39.1456\nNewcastle;-32.9167\nSievierodonetsk;48.9481\nSinpo;40.0347\nPaderborn;51.7181\nNevşehir;38.6264\nDutse;11.8283\nMinglanilla;10.2450\nChampaign;40.1142\nKiambu;-1.1667\nUeda;36.4019\nDahuaishu;36.2601\nAmatitlán;14.4741\nSingida;-4.8167\nShāntipur;23.2500\nMoriguchi;34.7375\nYilan;24.7500\nSiem Reap;13.3622\nGolmeh;33.7842\nFengyicun;23.6636\nHindupur;13.8300\nKawashiri;34.8301\nPoços de Caldas;-21.7878\nPeristéri;38.0167\nLogroño;42.4650\nDīla;6.4083\nSan Andres;14.5739\nCiudad Choluteca;13.3011\nBohicon;7.2000\nBaubau;-5.4667\nErode;11.3409\nRamu;3.9375\nHollywood;26.0293\nMudon;16.2578\nTaza;34.2167\nNek’emtē;9.0833\nTauranga;-37.6833\nGwangyang;34.9333\nMarbella;36.5167\nBeāwar;26.1011\nAbaetetuba;-1.7178\nKukichūō;36.0621\nConsolacion;10.4000\nGonbad-e Kāvūs;37.2500\nAl Manāqil;14.2500\nTororo;0.6928\nPasadena;29.6575\nMiass;55.0000\nMzuzu;-11.4581\nDelicias;28.1931\nNakhodka;42.8167\nQuevedo;-1.0333\nAsaka;35.7972\nSan Jose;15.7919\nFoggia;41.4642\nPomona;34.0585\nSayama;35.8530\nAş Şuwayḩirah as Sāḩil;24.3620\nEscondido;33.1348\nJaranwala;31.3342\nĐức Phổ;14.8100\nMiskolc;48.0833\nClermont-Ferrand;45.7831\nFlorencio Varela;-34.8167\nChichicastenango;14.9442\nManzanillo;20.3397\nVryheid;-27.7669\nTalcahuano;-36.7167\nKerch;45.3619\nM’Sila;35.7058\nPatos de Minas;-18.5817\nKolār;13.1333\nMariveles;14.4333\nCopiapó;-27.3664\nKragujevac;44.0142\nPôrto Seguro;-16.4333\nBadajoz;38.8803\nSoro;21.2900\nLalian;31.8253\nĐồng Xoài;11.5169\nNîmes;43.8380\nSumbawanga;-7.9667\nAraguaína;-7.1908\nChauk Azam;30.9648\nRimini;44.0594\nGubeng;-7.2729\nOcumare del Tuy;10.1136\nJoliet;41.5188\nAuchi;7.0667\nVilla de Álvarez;19.2500\nUrganch;41.5500\nKomaki;35.2910\nValdivia;-39.8139\nValle de Santiago;20.3928\nToda;35.8176\nShāhrūd;36.4181\nKutaisi;42.2500\nKashikishi;-9.3000\nLake Charles;30.2010\nPénjamo;20.4311\nOdivelas;38.7903\nMesquite;32.7602\nSaumlaki;-7.9750\nGloucester;51.8644\nMaīmanah;35.9333\nMauldin;34.7821\nPotchefstroom;-26.7150\nImabari;34.0667\nAbbottabad;34.1558\nConcordia;-31.4000\nWest Bromwich;52.5190\nPanama City;30.1995\nBellevue;47.5951\nCentro Habana;23.1333\nSagay;10.9000\nAğrı;39.7186\nHưng Yên;20.6500\n‘Ajlūn;32.3325\nAmasya;40.6500\nSantiago;16.6833\nBandar-e Anzalī;37.4728\nIruma;35.8358\nKastamonu;41.3764\nNaperville;41.7480\nDongsheng;22.8869\nSitārganj;28.9300\nMarvdasht;29.8742\nChingola;-12.5333\nRiobamba;-1.6731\nSzombathely;47.2351\nJean-Rabel;19.8500\nHābra;22.8300\nMostaganem;35.9333\nHarlingen;26.1916\nTuscaloosa;33.2348\nAl ‘Aqabah;29.5319\nPemba;-12.9667\nNowgong;26.3492\nQuilpué;-33.0500\nSibiu;45.7928\nYonago;35.4333\nDundee;56.4620\nDisūq;31.1422\nKopeysk;55.1000\nLüleburgaz;41.4056\nAl Ḩawīyah;21.4411\nSalamanca;40.9650\nMbanza Kongo;-6.2667\nNchelenge;-9.3533\nZhangaözen;43.3378\nTurbat;26.0031\nMati;6.9483\nMangghystaū;43.6905\nMalakal;9.5500\nElkhart;41.6916\nOsorno;-40.5725\nAl Qurayyāt;31.3167\nVólos;39.3667\nBacău;46.5833\nMogi Guaçu;-22.3719\nPyatigorsk;44.0500\nMoshi;-3.3349\nPayatas;14.7099\nTorrance;33.8346\nDar‘ā;32.6189\nRamapo;41.1404\nCairns;-16.9200\nBīr;18.9833\nPoole;50.7167\nRubtsovsk;51.5167\nNegombo;7.2111\nCam Ranh;11.9020\nMaquela do Zombo;-6.0500\nWamba;2.1442\nBinghamton;42.1014\nOdintsovo;55.6667\nDadu;26.7319\nFranco da Rocha;-23.3286\nHouma;29.5800\nMisato;35.8301\nLe Mans;48.0077\nEtah;27.6300\nKeren;15.7778\nTopeka;39.0346\nNārnaul;28.0444\nCalapan;13.4140\nColina;-33.2017\nKolomna;55.0833\nLárisa;39.6417\nYima;34.7473\nBhāndāria;22.4883\nPauktaw;20.1500\nAbohar;30.1334\nParnaíba;-2.9050\nGarcía;25.8167\nTaungdwingyi;20.0017\nUrdaneta;15.9761\nAalborg;57.0500\nBarrechid;33.2667\nArayat;15.1493\nSettat;33.0000\nKhairpur Mir’s;27.5333\nAix-en-Provence;43.5263\nBocaue;14.8000\nBaní;18.2900\nXintang;22.7824\nMatanzas;23.0511\nRoseville;38.7703\nSan Justo;-34.6833\nQūchān;37.1060\nYalova;40.6556\nBerezniki;59.4167\nKaithal;29.8015\nShillong;25.5744\nThanatpin;17.2942\nEreğli;37.5167\nVilla de Cura;10.0383\nKusatsu;35.0167\nDavid;8.4333\nKakamigahara;35.3988\nKhān Yūnis;31.3444\nFairfield;38.2583\nCuautitlán Izcalli;19.6500\nAl Mukallā;14.5333\nSantamesa;14.6000\nComayagua;14.4522\nOkinawa;26.3342\nFlores;16.9333\nBarranca;-10.7541\nKhasavyurt;43.2500\nSaguenay;48.4167\nGisenyi;-1.7000\nKumba;4.6333\nMehtar Lām;34.6683\nChhatarpur;24.9177\nBizerte;37.2778\nRuse;43.8231\nMalasiqui;15.9167\nDebre Birhan;9.6833\nBandundu;-3.3167\nKoiridih;24.1800\nTyler;32.3184\nQabr as Sitt;33.4472\nCoimbra;40.2111\nCalabayan;16.7667\nNawābganj;24.6000\nRewāri;28.1800\nBirkenhead;53.3930\nAltay;47.8666\nAshikaga;36.3402\nGhaznī;33.5492\nYopal;5.3500\nBilbays;30.4167\nJaú;-22.2958\nHuelva;37.2500\nKumbakonam;10.9602\nLévis;46.8000\nBhīmavaram;16.5430\nJaraguá do Sul;-26.4833\nJinjiang;19.7386\nBlackpool;53.8142\nCizre;37.3320\nPaghmān;34.5833\nLos Ángeles;-37.4667\nSannār;13.5500\nElbistan;38.2014\nBoca Chica;18.4539\nTelford;52.6766\nFullerton;33.8841\nKamālshahr;35.8653\nPreston;53.7590\nLichinga;-13.3167\nBrest;48.3900\nPueblo;38.2701\nTeluknaga;-6.0989\nMoundou;8.5667\nTetovo;42.0103\nNizip;37.0100\nLausanne;46.5198\nBahawalnagar;29.9928\nMaykop;44.6000\nFukayachō;36.1975\nAthens;33.9508\nSanta Maria;34.9333\nDehri;24.9100\nGweru;-19.4614\nTabaco;13.3500\nKelowna;49.8881\nKisaran;2.9833\nNamacunde;-17.3000\nMandsaur;24.0300\nBoulogne-Billancourt;48.8352\nRybnik;50.0833\nSurprise;33.6815\nNong’an;44.4190\nInezgane;30.3658\nRize;41.0247\nRio das Ostras;-22.5269\nVlorë;40.4667\nBondoukou;8.0333\nFujita;34.8674\nJahrom;28.5000\nCharleston;38.3484\nJyväskylä;62.2417\nLleida;41.6167\nMiddlesbrough;54.5767\nKhuzdar;27.8000\nTepatitlán de Morelos;20.8170\nLas Cruces;32.3265\nAbbotsford;49.0500\nBatu Pahat;1.8500\nKrugersdorp;-26.1000\nPorac;15.0719\nOzamiz City;8.1500\nPécs;46.0708\nLas Margaritas;16.3667\nTours;47.3936\nKovrov;56.3683\nShizhaobi;23.9210\nKokubunji;35.7109\nTottenham;51.5975\nMejicanos;13.7333\nEbina;35.4464\nParanaguá;-25.5208\nIguala de la Independencia;18.3450\nMetairie;29.9977\nThornton;39.9197\nMasaya;11.9764\nMédéa;36.2675\nYaritagua;10.0753\nXiangcheng;25.4775\nFusagasugá;4.3452\nOlathe;38.8833\nNāḩiyat Ghammās;31.7431\nLa Romana;18.4300\nGiá Rai;9.2500\nTanay;14.4972\nMedina Estates;5.6833\nItuzaingó;-34.6667\nTorbat-e Ḩeydarīyeh;35.2739\nQuảng Yên;20.9170\nMomostenango;15.0444\nDawei;14.0833\nKombolcha;11.0867\nKuwana;35.0667\nSubang;-6.5714\nAtbara;17.6972\nNorrköping;58.6000\nCarolina;18.4054\nPoblacion;14.3854\nPakpattan;30.3500\nChicacole;18.3000\nJicheon;36.1333\nBotucatu;-22.8858\nGainesville;34.2902\nMinō;34.8269\nShizuishan;39.2333\nLa Trinidad;16.4621\nWest Valley City;40.6886\nKoga;36.1782\nSale;53.4240\nCoquitlam;49.2839\nOrange;33.8038\nSan José del Cabo;23.0614\nJacmel;18.2353\nIshizaki;38.4176\nAl Khmissat;33.8167\nIngolstadt;48.7631\nÇarşamba;41.1992\nRenca;-33.4000\nWarren;42.4934\nBat Yam;32.0167\nCandelaria;13.9311\nTsuchiura;36.0667\nPīrānshahr;36.6956\nUmtata;-31.5800\nPasadena;34.1597\nDipolog;8.5872\nSancti Spíritus;21.9339\nBukoba;-1.3333\nKoganei;35.6995\nTultepec;19.6850\nDos Hermanas;37.2836\nJolo;6.0000\nMontero;-17.3422\nBoca del Rio;19.1056\nDabou;5.3167\nPhủ Lý;20.5411\nZama;35.4833\nBrusque;-27.0949\nShūnan;34.0500\nDumaguete City;9.3103\nMojokerto;-7.4722\nDarwin;-12.4381\nSilivri;41.0736\nMandya;12.5242\nCh’ungmu;34.8333\nTarragona;41.1187\nBirgañj;27.0000\nIğdır;39.9208\nPalhoça;-27.6444\nLira;2.2472\nCarcar;10.1167\nNegage;-7.7667\nGunungsitoli;1.2833\nBeaumont;30.0849\nYunxian Chengguanzhen;32.8082\nCunduacán;18.0667\nAtibaia;-23.1172\nRangkasbitung;-6.3667\nAmiens;49.8920\nBānkura;23.2500\nKigoma;-4.8833\nVila Franca de Xira;38.9500\nQuillacollo;-17.4000\nMyebon;20.0500\nGaranhuns;-8.8903\nMinoo;34.8333\nBima;-8.4600\nKisarazu;35.3760\nBurlington;36.0760\nLivingstone;-17.8500\nCuricó;-34.9833\nPorto Amboim;-10.7183\nParla;40.2372\nNasugbu;14.0667\nSiwān;26.2200\nLong Bình;10.9458\nIgboho;8.8333\nGingoog;8.8167\nMaia;41.2333\nUppsala;59.8601\nYaizu;34.8669\nKhargone;21.8229\nHampton;37.0551\nMarīvān;35.5269\nColumbia;38.9472\nHuehuetenango;15.3147\nInazawa;35.2647\nStara Zagora;42.4333\nQuimbele;-6.5167\nChech’ŏn;37.1333\nNorzagaray;14.9167\nPort-Gentil;-0.7167\nTiraspol;46.8403\nPageralam;-4.0217\nDebre Mark’os;10.3333\nTizi Ouzou;36.7169\nTây Ninh;11.3678\nGiresun;40.9153\nMaijdi;22.8333\nKsar El Kebir;35.0090\nTorrejón de Ardoz;40.4614\nTermiz;37.2167\nZinacantepec;19.2833\nMabacun;24.6807\nFloridablanca;14.9333\nSalerno;40.6806\nRionegro;6.1535\nAğcabədi;40.0528\nBlitar;-8.1000\nTârgu-Mureş;46.5456\nYuma;32.5995\nBrighton;50.8208\nToowoomba;-27.5667\nTobruk;32.0761\nSrīpur;24.2011\nElizabeth;40.6658\nRaigarh;21.8000\nSukrah;36.8833\nPyay;18.8167\nTabarre;18.5833\nRuda Śląska;50.2628\nShuangcheng;45.3503\nAngono;14.5234\nCartago;4.7000\nYelahanka;13.1007\nPaco;14.5830\nMay Pen;17.9650\nRacine;42.7274\nZafarwal;32.3463\nGreeley;40.4152\nAndīmeshk;32.4600\nIpetumodu;7.5070\nConchalí;-33.3833\nAgboville;5.9333\nDjakotomé;6.9000\nSanta Rita;-7.1139\nSilopi;37.2486\nDaraga;13.1619\nShahreẕā;32.0089\nMilagro;-2.1347\nNakhon Ratchasima;14.9750\nZābol;31.0286\nEl Oued;33.3683\nKent;47.3887\nAshqelon;31.6667\nMataró;41.5333\nBa Đồn;17.7547\nStamford;41.1039\nOdessa;31.8801\nTeófilo Otoni;-17.8578\nHagonoy;14.8333\nLaghouat;33.8000\nMörön;49.6356\nApatzingan de la Constitucion;19.0886\nAaley;33.8000\nFamalicão;41.4167\nNaga;10.2167\nTrois-Rivières;46.3500\nBloomington;40.4757\nVeszprém;47.0930\nZhangmu Touwei;22.9078\nMiramar;25.9773\nLonduimbali;-12.2186\nReẖovot;31.8981\nNavoiy;40.0844\nGrand Junction;39.0877\nSterling Heights;42.5809\nBatu Gajah;4.4667\nTando Allahyar;25.4667\nLuuq;3.6981\nIdfū;24.9778\nSégou;13.4500\nIsahaya;32.8500\nChikmagalūr;13.3167\nInnsbruck;47.2683\nŌme;35.7880\nCoral Springs;26.2702\nMarituba;-10.2833\nMatagalpa;12.9286\nJijel;36.8206\nJaramānā;33.4833\nJandira;-23.5278\nFerfer;5.0833\nGondiā;21.4500\nThandwe;18.4667\nHassan;13.0050\nPitalito;1.8989\nBibémi;9.3167\nAbiko;35.8667\nTalavera;15.5839\nKhorramshahr;30.4397\nLimoges;45.8353\nCrato;-7.2339\nOuargla;31.9500\nAr Rass;25.8667\nSinop;-11.8481\nSan Carlos;10.4929\nKipushi;-11.7625\nLincoln;53.2283\nPalwal;28.1430\nAnnecy;45.9160\nMogaung;25.3014\nÖdemiş;38.2311\nKamëz;41.3833\nZagnanado;7.2667\nCametá;-2.2439\nCubatão;-23.8953\nIbarra;0.3627\nSan Luis;16.2000\nPalenque;17.4333\nFerrara;44.8333\nSan Juan;18.8100\nĀwarē;8.2667\nKarabük;41.1986\nJohnson City;36.3406\nSaidpur;25.7781\nChicomba;-14.1333\nPālghāt;10.7792\nGuelph;43.5500\nBuea;4.1667\nLos Guayos;10.1833\nNanqiaotou;22.7217\nJi-Paraná;-10.8853\nBatang;-6.9081\nGuagua;14.9667\nSpanish Town;17.9959\nCarrollton;32.9890\nChittandikavundanūr;10.6931\nSurat Thani;9.1397\nNarita;35.7767\nApopa;13.8000\nRelizane;35.7372\nFürth;49.4667\nLào Cai;22.4806\nAntsiranana;-12.3000\nLashio;22.9333\nSilay;10.8000\nParepare;-4.0167\nCity of Isabela;6.7000\nThaton;16.9333\nZwolle;52.5167\nNueva Concepción;14.1997\nMarand;38.4331\nKānchrāpāra;22.9456\nQuibdó;5.6922\nGirardot;4.3050\nPouso Alegre;-22.2281\nTychy;50.1236\nRustavi;41.5472\nBassila;9.0167\nMidland;32.0243\nCholula de Rivadabia;19.0633\nTrinidad;-14.8292\nOnomichi;34.4167\nKislovodsk;43.9167\nKozan;37.4500\nUdon Thani;17.4167\nJīroft;28.6781\nBatticaloa;7.7167\nChās;23.6300\nYakima;46.5923\nBongaigaon;26.4769\nBattambang;13.1000\nVitória de Santo Antão;-8.1264\nMukeriān;31.9500\nMalambo;10.8500\nLeiden;52.1600\nHuejutla de Reyes;21.1333\nZhaozhou;37.7527\nLakewood;40.0763\nErgani;38.2692\nLucheng;30.0553\nHanumāngarh;29.5833\nÇayırova;40.8265\nSaïda;34.8303\nTaldyqorghan;45.0167\nÑemby;-25.3935\nCambridge;43.3972\nFengcheng;37.4313\nPonnagyun;20.3333\nMothīhāri;26.6500\nSerpukhov;54.9167\nMīt Ghamr;30.7167\nBellingham;48.7548\nYuba City;39.1357\nVilla Alemana;-33.0422\nCiénaga;11.0069\nTáriba;7.8167\nKibaha;-6.7667\nChinguar;-12.5500\nVästerås;59.6161\nWürzburg;49.7833\nMansa;-11.2000\nAlwāl;17.5047\nSongnim;38.7542\nSanto Tomas;7.5333\nKoidu;8.6439\nHoshangābād;22.7475\nOpole;50.6667\nNovocheboksarsk;56.1333\nAraras;-22.3572\nKhanna;30.7000\nPuno;-15.8433\nKoforidua;6.0833\nAhmadpur East;29.1439\nRosario;13.8460\nAvrankou;6.5500\nSalto;-31.3833\nMosquera;4.7078\nMissérété;6.5625\nVihari;30.0419\nAmherst;43.0117\nÖrebro;59.2739\nTemperley;-34.7667\nBaigou;39.1098\nTukuyu;-9.2500\nShiyan;23.1251\nZoetermeer;52.0667\nBan Bang Pu Mai;13.5441\nIwakuni;34.1664\nSinnūris;29.4072\nGarut;-7.2167\nSeto;35.2236\nBataysk;47.1667\nWhitby;43.8833\nBuôn Hồ;12.8544\nRomford;51.5768\nPinsk;52.1153\nTumen;42.9627\nRamos Mejía;-34.6500\nRudnyy;52.9667\nGuimba;15.6606\nMiramar;22.3375\nNefteyugansk;61.0833\nNāḩiyat Khān Banī Sa‘d;33.5700\nLa Granja;-33.5333\nSouth Lyon;42.4614\nAl Ḩajar al Aswad;33.4640\nGuasdualito;7.2467\nDomodedovo;55.4400\nUlm;48.4000\nDarnah;32.7667\nSanta Lucía Cotzumalguapa;14.3333\nNagda;23.4564\nKadoma;34.7333\nSalmās;38.2017\nSanta Clara;37.3646\nSt. George;37.0758\nAllada;6.6500\nJāzān;16.8892\nMaricá;-22.9189\nDessalines;19.2833\nKaspiysk;42.8803\nHeilbronn;49.1500\nAnderlecht;50.8333\nFort Smith;35.3495\nNeftekamsk;56.1417\nŌmiyachō;35.2221\nSan Ignacio;-5.1456\nBajos de Haina;18.4167\nBam;29.1061\nHigh Wycombe;51.6287\nMonza;45.5836\nPforzheim;48.8950\nŌsaki;38.5771\nJhārsugra;21.8500\nBalneário de Camboriú;-26.9953\nSantana de Parnaíba;-23.4439\nPalni;10.4500\nRosetta;31.4044\nPayakumbuh;-0.2333\nSimi Valley;34.2663\nPakokku;21.3320\nAngren;41.0167\nBasīrhat;22.6612\nDuitama;5.8333\nLeiria;39.7500\nLarache;35.1833\nNavadwīp;23.4088\nLatina;41.4672\nCambridge;52.2053\nÜnye;41.1333\nSan Fernando;16.6200\nExeter;50.7256\nGurabo al Medio;19.4739\nSanta Cruz;14.2833\nGuntakal;15.1700\nPithampur;22.6197\nIizuka;33.6500\nSabará;-19.8858\nCatabola;-12.1167\nSuhum;6.0333\nBagong Silangan;14.7094\nBarbacena;-21.2167\nBến Tre;10.2333\nHālīsahar;22.9500\nMatamoros;25.5330\nWestern Bicutan;14.5094\nRishra;22.7100\nHoima;1.4319\nDrohobych;49.3500\nPanevėžys;55.7333\nLeuwiliang;-6.5742\nMagelang;-7.4667\nJizhou;37.5455\nKampong Cham;11.9870\nGashua;12.8681\nShchelkovo;55.9167\nDover;39.1610\nChinautla;14.7029\nPātan;23.8500\nNovomoskovsk;54.0833\nNorman;35.2335\nCam Ranh;11.9136\nKumbo;6.2000\nSai Wan Ho;22.2877\nGiugliano in Campania;40.9319\nCagua;10.1875\nYuanlin;23.9611\nIndramayu;-6.3528\nColchester;51.8917\nGateshead;54.9500\nPakxé;15.1167\nBonao;18.9500\nHonchō;35.7580\nAbilene;32.4543\nMagalang;15.2167\nUruguaiana;-29.7550\nPorlamar;10.9556\nResende;-22.4689\nDaitōchō;34.7167\nMóng Cái;21.5333\nSawrān;36.6606\nLeón;42.6056\nSunām;30.1300\nCentral Signal Village;14.5106\nPolatlı;39.5842\nJirjā;26.3333\nFugu;39.0259\nJilib;0.5000\nAz Zulfī;26.2833\nBillings;45.7891\nLeeuwarden;53.2000\nOuahigouya;13.5833\nDūmā;33.5711\nJuticalpa;14.6664\nZhaxi;27.8440\nGexianzhuang;37.0694\nWolfsburg;52.4231\nSavannakhet;16.5500\nGorzów Wielkopolski;52.7333\nPonce;18.0127\nCai Lậy;10.4170\nGyumri;40.7894\nGlazoué;7.9736\nPervouralsk;56.9167\nNew Mirpur;33.1490\nNoksan;36.2039\nSan Pedro Garza García;25.6667\nMontreuil;48.8611\nSerik;36.9167\nAlgeciras;36.1275\nPāli;23.3500\nBimbo;4.3313\nHội An;15.8833\nSetúbal;38.5243\nMatsubara;34.5833\nBaia Mare;47.6667\nKadirli;37.3697\nKhrustalnyi;48.1214\nCherkessk;44.2222\nMalindi;-3.2236\nPobé;6.9667\nBergamo;45.6950\nKirishima;31.7406\nGapan;15.3122\nMagangué;9.2500\nJimaguayú;21.2667\nDebre Tabor;11.8500\nMaicao;11.3778\nDelgado;13.7167\nUruma;26.3792\nLehigh Acres;26.6120\nDerbent;42.0500\nMelipilla;-33.6253\nPati;-6.7415\nCádiz;36.5350\nDjidja;7.3333\nLongtian;24.3512\nSt. Cloud;45.5340\nNāndgaon;20.3070\nArecibo;18.4491\nMunūf;30.4658\nPunta Arenas;-53.1667\nVarginha;-21.5517\nMunch’ŏn;39.2590\nKilifi;-3.6333\nBhadrakh;21.0545\nZacatecas;22.7736\nSantana;-0.0350\nKaya;13.0833\nAlberton;-26.2672\nKenosha;42.5865\nIse;34.4833\nLianhe;47.1414\nBrits;-25.6344\nItatiba;-23.0058\nDimāpur;25.9200\nEd Damer;17.5900\nBragança;-1.0628\nPatnos;39.2358\nBayawan;9.3667\nGreenville;35.5943\nBarretos;-20.5569\nArvada;39.8320\nKâhta;37.7803\nBlackburn;53.7480\nMachiques;10.0667\nCiudad Hidalgo;19.6923\nSlough;51.5084\nPescara;42.4643\nGuelma;36.4619\nBehbahān;30.5958\nPearland;29.5581\nBaidyabāti;22.7900\nKotamobagu;0.7333\nMufulira;-12.5356\nPuerto Cortés;15.8833\nMaina;13.4692\nDharmavaram;14.4300\nEdéa;3.8000\nHonmachi;32.5000\nCiudad Ojeda;10.2000\nBento Gonçalves;-29.1708\nIndependence;39.0871\nFier;40.7250\nKamalia;30.7258\nGhazīpur;25.5833\nOrekhovo-Zuyevo;55.8000\nTexas City;29.4154\nSaint-Denis;48.9356\nChinandega;12.6297\nPuruliya;23.3333\nKashiwara;34.5167\nFāqūs;30.7282\nUrasoe;26.2458\nDorūd;33.4986\nGuarapari;-20.6500\nHòa Bình;20.8133\nKuopio;62.8925\nRibeirão Pires;-23.7153\nOndjiva;-17.0667\nPort-de-Paix;19.9500\nShuixi;22.5111\nWuling;39.4421\nSamandağ;36.0850\nRedding;40.5698\nTsuruoka;38.7272\nSoreang;-7.0372\nCiudad Guzmán;19.7000\nGudiyāttam;12.9476\nUpington;-28.4572\nChơn Thành;11.4292\nDoğubayazıt;39.5472\nMetz;49.1203\nPłock;52.5500\nBagaha;27.0992\nGurdāspur;32.0333\nTabuk;17.4069\nApartadó;7.8833\nSiracusa;37.0692\nApucarana;-23.5508\nPerpignan;42.6986\nValinhos;-22.9706\nChilapa de Álvarez;17.5944\nCachoeirinha;-29.9508\nGuelmim;28.9833\nNavojoa;27.0813\nKot Addu;30.4700\nLynchburg;37.4003\nZonguldak;41.4564\nBoulder;40.0248\nGöttingen;51.5339\nUnwana;5.8625\nVihiga;0.0500\nCatchiungo;-12.7864\nBarcelos;41.5167\nIlobu;7.8400\nKỳ Anh;18.0678\nSātāra;17.6833\nKallithéa;37.9500\nTizayuca;19.8333\nDarjeeling;27.0375\nMoḩammad Shahr;35.7483\nAl Manşūrah;12.8531\nCalumpit;14.9167\nOrléans;47.9025\nBāgalkot;16.1833\nEbetsu;43.1037\nFujimino;35.8795\nĐông Hòa;12.9931\nSertãozinho;-21.1381\nSöke;37.7508\nDordrecht;51.7958\nPoá;-23.5286\nLalo;6.9167\nGhardaïa;32.4833\nCandaba;15.0933\nNokha;27.6000\nSan Carlos;9.6500\nBesançon;47.2400\nBaraka;-4.1041\nAr Rustāq;23.3908\nHanda;34.8919\nIowa City;41.6559\nVárzea Paulista;-23.2114\nĀdīgrat;14.2667\nCatanduva;-21.1378\nNouadhibou;20.9333\nChelmsford;51.7300\nGudivāda;16.4300\nYüksekova;37.5690\nNaz̧arābād;35.9583\nPleven;43.4078\nRochester;44.0154\nAn;19.7833\nAjax;43.8583\nAlcobendas;40.5333\nBerkeley;37.8722\nXuqiaocun;30.4355\nDinalupihan;14.8833\nDongsheng;22.6199\nSopur;34.3000\nWaldorf;38.6085\nToledo;-24.7139\nElbląg;54.1667\nNazran;43.2167\nBanco Filipino International Village;14.4499\nAraucária;-25.5928\nBruges;51.2089\nSilifke;36.3761\nTotonicapán;14.9108\nThe Villages;28.9034\nPaulo Afonso;-9.4000\nGuaratinguetá;-22.8167\nHuaraz;-9.5333\nŢūz Khūrmātū;34.8772\nKasuga;33.5333\nAw Dheegle;1.9667\nApalit;14.9496\nBet Shemesh;31.7456\nGabès;33.8833\nBwana Mkubwa;-12.9833\nCharallave;10.2431\nDuluth;46.7756\nEast Los Angeles;34.0326\nCheltenham;51.9000\nNevinnomyssk;44.6333\nLahti;60.9833\nSaginaw;43.4199\nDimitrovgrad;54.1833\nGiyon;8.5333\nPhagwāra;31.2200\nTrento;46.0667\nIkoma;34.7000\nYongqing;39.2958\nPandacan;14.5940\nNowshera;34.0153\nButwāl;27.7000\nBarcarena Nova;-1.5058\nMartínez de la Torre;20.0667\nAkishima;35.7057\nBirigui;-21.2886\nLigao;13.2167\nPudukkottai;10.3833\nBottrop;51.5247\nSanta Cruz do Sul;-29.7178\nKōnosu;36.0659\nClovis;36.8278\nKaratepe;40.7333\nVotorantim;-23.5469\nLinköping;58.4158\nYulu;23.5193\nForlì;44.2333\nMalita;6.4000\nLa Asunción;11.0333\nNiğde;37.9667\nAizuwakamatsu;37.4948\nAïn Beïda;35.7964\nLeominster;42.5209\nLomas de Zamora;-34.7667\nBama;11.5189\nCodó;-4.4550\nSan Rafael;-34.6000\nChimaltenango;14.6622\nPetržalka;48.1333\nPlaridel;14.8869\nKabwe;-14.4333\nTahoua;14.8903\nNobeoka;32.5833\nGogounou;10.8386\nReutlingen;48.4833\nReutov;55.7622\nAgadez;16.9959\nUzhhorod;48.6239\nRound Rock;30.5270\nAdilābād;19.6667\nLuanshya;-13.1333\nKapaklı;41.3333\nObninsk;55.0931\nUribia;11.7139\nPiedecuesta;7.0833\nSalmān Bāk;33.1000\nTangjin;36.8931\nRouen;49.4428\nDąbrowa Górnicza;50.3214\nGuiguinto;14.8333\nHuanren;41.2671\nMachakos;-1.5167\nFujimi;35.8566\nCatacamas;14.8486\nArgenteuil;48.9500\nLos Baños;14.1667\nSan Martín;-33.0806\nXai-Xai;-25.0500\nRochdale;53.6136\nBanfora;10.6308\nOrsha;54.5092\nWałbrzych;50.7667\nLangley;49.1044\nNarasaraopet;16.2500\nTemixco;18.8500\nHeroica Guaymas;27.9183\nKyzyl;51.7167\nMonroe;32.5185\nPollāchi;10.6590\nMendoza;-32.8833\nNkongsamba;4.9500\nSamal;7.0500\nFacatativá;4.8167\nGuadalajara de Buga;3.9000\nCassongue;-11.8333\nBarnāla;30.3700\nManpo;41.1570\nTandil;-37.3167\nYavatmāl;20.4000\nBeppu;33.2795\nAraguari;-18.6489\nTatuí;-23.3556\nCambridge;42.3759\nShibuya;35.6536\nSassari;40.7267\nConselheiro Lafaiete;-20.6600\nBagé;-31.3308\nChittaurgarh;24.8894\nBerkane;34.9167\nBuzău;45.1531\nSantander de Quilichao;3.0167\nHelsingborg;56.0500\nCoronel;-37.0167\nKasese;0.1867\nClearwater;27.9790\nDharān;26.8167\nLugazi;0.3833\nTarogong;-7.2150\nBoké;10.9400\nSmithtown;40.8663\nHimamaylan;10.1000\nSan Antonio Enchisi;19.7072\nJoünié;33.9697\nTecomán;18.9089\nBongao;5.0292\nFatsa;41.0333\nPhatthaya;12.9357\nSwabi;34.1202\nQiaotou;36.9350\nKhon Kaen;16.4333\nKaratsu;33.4500\nRamenskoye;55.5667\nRa’s al Khaymah;25.7667\nKilis;36.7167\nSeaside;36.6224\nSandvika;59.8833\nAdjaouèrè;7.0000\nItapipoca;-3.4939\nGuanabacoa;23.1252\nWest Jordan;40.6024\nSabhā;27.0389\nShacheng;40.4027\nSayhāt;26.4750\nKars;40.6078\nValle de La Pascua;9.2033\nParachinar;33.9000\nRichardson;32.9716\nSan Ildefonso;15.0789\nKovilpatti;9.1744\nWest Palm Beach;26.7469\nTemple;31.1068\nNasushiobara;36.9617\nTōkai;35.0231\nDurrës;41.3111\nBurlington;44.4876\nRichmond;37.9477\nTurbaco;10.3500\nPedro Juan Caballero;-22.5300\nRawasari;-7.5800\nTrês Lagoas;-20.7511\nBerdiansk;46.7556\nWestminster;39.8837\nKōenchō;43.8028\nMangaldan;16.0700\nNiihama;33.9667\nPottstown;40.2508\nBānsbāria;22.9700\nPuerto Madryn;-42.7667\nBrandon;27.9367\nSliven;42.6833\nYessentuki;44.0333\nRock Hill;34.9415\nIriga City;13.4231\nJönköping;57.7828\nMeridian;43.6116\nSano;36.3145\nAriana;36.8625\nSloviansk;48.8533\nKoblenz;50.3597\nOktyabr’skiy;54.4667\nAl Muḑaybī;22.5667\nSogamoso;5.7167\nSalto;-23.2008\nZhijiang;27.4367\nHatsukaichi;34.3500\nSakiet ed Daier;34.8000\nCoeur d'Alene;47.7040\nCarlsbad;33.1246\nLas Delicias;28.2000\nSach’on;35.0667\nBijeljina;44.7500\nLowell;42.6389\nHeshan;23.8163\nErlangen;49.5833\nBremerhaven;53.5500\nCiudad de la Costa;-34.8167\nWaterloo;42.4918\nKaikkudi;9.8930\nBernal;-34.7000\nKamagaya;35.7768\nNorth Charleston;32.9067\nAlphen aan den Rijn;52.1333\nLa Piedad;20.3333\nHammersmith;51.4928\nPutatan;14.3984\nEsteban Echeverría;-34.8167\nAmbovombe;-25.1764\nSan Juan;13.8260\nSakété;6.7364\nEspejo;-33.5167\nGilroy;37.0046\nBāgh-e Malek;31.5231\nRotherham;53.4300\nKakegawa;34.7687\nDowney;33.9379\nIfanhim;6.6667\nGresham;45.5021\nBintulu;3.1700\nElgin;42.0383\nSaanich;48.4840\nDaet;14.1142\nĀsela;7.9500\nMatéri;10.6978\nKuşadası;37.8597\nKristiansand;58.1472\nPul-e Khumrī;35.9500\nRecklinghausen;51.5850\nNagahama;35.3833\nTawau;4.2448\nWalthamstow;51.5840\nQuilengues;-14.0814\nMulhouse;47.7500\nMazhang;21.2757\nPaarl;-33.7242\nHōfu;34.0500\nHikone;35.2667\nĪrānshahr;27.2025\nMaranguape;-3.8900\nRosario;14.4167\nNdali;9.8608\nUbá;-21.1200\nBukittinggi;-0.3097\nCaraguatatuba;-23.6200\nManolo Fortich;8.3675\nMidyat;37.4167\nMungo;-11.6667\nArafat;18.0464\nTecpán Guatemala;14.7667\nJendouba;36.5000\nAlkmaar;52.6333\nSa-ch’on;35.2347\nHualien;23.9722\nIoánnina;39.6636\nAkçakale;36.7108\nLibmanan;13.6964\nBergisch Gladbach;50.9918\nEuriápolis;-16.3778\nOsmānābād;18.1667\nRemscheid;51.1833\nNovyy Urengoy;66.0833\nMostar;43.3436\nMadrid;4.7344\nBurdur;37.7194\nLa Gi;10.6600\nHosan;36.2000\nTayabas;14.0167\nMopti;14.4900\nSokodé;8.9833\nCastelar;-34.6667\nSāhibganj;25.2500\nKhenchela;35.4167\nVicenza;45.5500\nBalāngīr;20.7200\nUtica;43.0962\nSan Carlos de Bariloche;-41.1500\nOtaru;43.1907\nGoth Tando Sumro;25.4500\nRājpura;30.4840\nKaposvár;46.3638\nBroken Arrow;36.0380\nHigashiōmi;35.1167\nBrovary;50.5111\nSanta Lucía;10.2606\nMawanella;7.2534\nKuningan;-6.9764\nCarora;10.1692\nMadhavaram;13.1482\nLaoag;18.1978\nTangjia;22.3566\nChampdani;22.8000\nŌshū;39.1445\nZahlé;33.8333\nMahāsamund;21.1100\nHabikino;34.5500\nKamyshin;50.0833\nCampo Largo;-25.4589\nShujālpur;23.4000\nDoncaster;53.5231\nDolgoprudnyy;55.9333\nShkodër;42.0681\nJena;50.9272\nTrincomalee;8.5667\nSubic;14.8769\nBaleraja;-6.5167\nOlmaliq;40.8500\nKawit;14.4333\nBou Saâda;35.2083\nPochuta;14.5500\nHezuo;34.9984\nEstelí;13.0933\nJaén;37.7667\nAraruama;-22.8728\nDassa-Zoumé;7.7500\nCosta Mesa;33.6667\nChico;39.7578\nBaybay;10.6833\nCorumbá;-19.0089\nNancy;48.6936\nKouandé;10.3317\nZhukovskiy;55.5972\nNsukka;6.8567\nSioux City;42.4959\nIchinoseki;38.9347\nFunchal;32.6500\nWythenshawe;53.3920\nColatina;-19.5389\nMaidstone;51.2720\nSutton Coldfield;52.5630\nLeague City;29.4874\nQalyūb;30.1997\nParral;26.9333\nTerni;42.5619\nMiami Gardens;25.9433\nTatalon;14.6242\nParintins;-2.6278\nTrier;49.7567\nTerrebonne;45.7000\nNamur;50.4667\nChangbang;30.4555\nPulilan;14.9020\nMurom;55.5667\nKalmunai;7.4167\nSabara Bangou;15.1177\nManzini;-26.4833\nTondabayashichō;34.5000\nPingquan;40.9937\nKazo;36.1314\nPompano Beach;26.2428\nKhardah;22.7200\nŌmuta;33.0333\nVilla Mercedes;-33.6667\nJawhar;2.7833\nWinterthur;47.4989\nTuzla;44.5381\nTarnów;50.0125\nGafsa;34.4167\nAsh Shaykh ‘Uthmān;12.8866\nNkpor;6.1500\nḨaraḑ;24.1456\nKhushab;32.2986\nNawāda;24.8800\nMuktsar;30.4743\nBasingstoke;51.2667\nKintampo;8.0522\nCatalão;-18.1700\nHounslow;51.4668\nAhuachapán;13.9167\nAl Aḩad al Masāriḩah;16.7097\nPuerto Barrios;15.7300\nFasā;28.9383\nAs Salamīyah;35.0118\nPelabuhanratu;-6.9878\nLos Minas;18.5000\nShinyanga;-3.6619\nSonsonate;13.7167\nMasindi;1.6836\nKiffa;16.6300\nBetūl Bazār;21.9200\nNikopol;47.5667\nFerozepore;30.9166\nDali;34.7953\nYenangyaung;20.4597\nQuíbor;9.9281\nOurinhos;-22.9744\nFranceville;-1.6333\nSan Buenaventura;34.2741\nSocopó;8.2322\nMascara;35.4000\nGenhe;50.7783\nEverett;47.9525\nMontego Bay;18.4667\nEl Centro;32.7865\nCiamis;-7.3281\nCaen;49.1800\nJeonghae;35.5667\nMsaken;35.7333\nBāneh;35.9975\nShirayamamachi;36.5166\nItele;6.7667\nSugar Land;29.5935\nTinaquillo;9.9167\nXishancun;23.6014\nDrammen;59.7378\nEl Monte;34.0739\nMarugame;34.2833\nBangaon;23.0435\nQal‘at Sukkar;31.8589\nMilton;43.5083\nYŏju;37.3000\nLewisville;33.0454\nRetalhuleu;14.5333\nTacurong;6.6800\nNavapolatsk;55.5333\nPisco;-13.7167\nDera Ismail Khan;31.8314\nLabé;11.3167\nAltamira;-3.2028\nCavite City;14.4833\nYevpatoriia;45.1939\nTaitung;22.7583\nItabira;-19.6189\nMalacatán;14.9106\nAl Fqih Ben Çalah;32.5000\nNaujan;13.3233\nQuezon;7.7306\nSandachō;34.8833\nUitenhage;-33.7500\nAguachica;8.3167\nGlan;5.8167\nCarmona;14.3167\nBayugan;8.7100\nDatia;25.6700\nK’ebrī Dehar;6.7333\nSehore;23.2000\nMedenine;33.3547\nKasserine;35.1667\nTaoyang;35.3754\nGualeguaychú;-33.0167\nBéja;36.7333\nTalisay;10.7333\nLingayen;16.0167\nLabo;14.1561\nYŏngju;36.8058\nWest Covina;34.0555\nPaleng;-1.4000\nTemecula;33.4928\nBagu Na Mohra;33.2200\nWitbank;-25.8770\nMaxixe;-23.8667\nBan Mangkon;13.6138\nBend;44.0563\nMineshita;35.1185\nTúxpam de Rodríguez Cano;20.9500\nSoma;39.1883\nNovoshakhtinsk;47.7667\nAcharnés;38.0833\nDouliu;23.7075\nSão Mateus;-18.7158\nBotoşani;47.7486\nŽilina;49.2228\nBalombo;-12.3500\nSalisbury;38.3756\nCrawley;51.1092\nNantang;22.4917\nFerizaj;42.3667\nIkeda;34.8167\nMaţrūḩ;31.3500\nSt. John's;47.4817\nSītāmarhi;26.6000\nSalford;53.4830\nMungeli;22.0700\nReus;41.1549\nMoortebeek;50.8547\nTaungoo;18.9333\nCawayan;9.9667\nGò Công;10.3667\nTādpatri;14.9200\nMoncton;46.1328\nYāsūj;30.6683\nTipitapa;12.1964\nAlto Hospicio;-20.2500\nJacksonville;34.7289\nIslāmābād;33.7300\nMaramag;7.7631\nJalpāiguri;26.5167\nBirnin Kebbi;12.4504\nGharbara;28.4962\nShāmli;29.4500\nŠiauliai;55.9333\nKhemis Sahel;35.2500\nSeversk;56.6000\nDagenham;51.5397\nEl Limón;10.3003\nMalate;14.5642\nInglewood;33.9566\nVilla Krause;-31.5833\nWembley;51.5528\nSarh;9.1500\nAn Nuhūd;12.7000\nKotmale;7.0167\nJoyabaj;14.9950\nDearborn;42.3127\nCentennial;39.5926\nKoszalin;54.2000\nTajimi;35.3328\nThunder Bay;48.3822\nDelft;52.0117\nBaía Farta;-12.6128\nTagbilaran City;9.6500\nCourbevoic;48.8978\nPavlohrad;48.5200\nEmmen;52.7833\nQueenstown;-31.9000\nChaman;30.9210\nPateros;14.5417\nUmm Qaşr;30.0342\nMusoma;-1.5000\nCarmen;7.2000\nSuriāpet;17.1415\nCharsadda;34.1500\nKogon Shahri;39.7275\nShikohābād;27.1000\nKefar Sava;32.1714\nAlchevsk;48.4778\nToufen;24.6832\nMorales;15.4725\nBurbank;34.1879\nManokwari;-0.8667\nBolzano;46.4981\nChorzów;50.3000\nErdenet;49.0278\nWa;10.0667\nLaunceston;-41.4419\nEjido;8.5466\nChongshan;18.7787\nIdkū;31.3000\nKishanganj;26.0794\nIlebo;-4.3167\nNamhkam;23.8333\nDieppe;46.0989\nLuján;-34.5667\nArzamas;55.4000\nMorón;-34.6500\nBanté;8.4167\nLongjiang;47.3404\nMaipú;-32.9667\nEdison;40.5360\nArtëm;43.3667\nSparks;39.5736\nTiaong;13.9500\nErechim;-27.6339\nNoyabrsk;63.2017\nMonastir;35.7694\nCatbalogan;11.7833\nAs Safīrah;36.0778\nChābahār;25.2919\nNakhon Si Thammarat;8.4364\nRānībennur;14.6167\nKŭlob;37.9092\nSalihorsk;52.8000\nAd Dakhla;23.7081\nJincheng;39.5529\nSandy Springs;33.9366\nRaba;-8.4614\nPatos;-7.0244\nMmabatho;-25.8500\nLokossa;6.6333\nLa Banda;-27.7333\nKemalpaşa;38.4278\nJamālpur;25.3000\nSơn La;21.3270\nPassos;-20.7189\nNautanwa;27.4300\nAkhmīm;26.5667\nBloomington;39.1637\nLogan;41.7399\nKomatsu;36.4083\nAihua;24.4629\nRoubaix;50.6901\nTemoaya;19.4686\nAchinsk;56.2817\nKailua;21.3920\nMingəçevir;40.7700\nContramaestre;20.3000\nCiudad Río Bravo;25.9861\nEl Cajon;32.8017\nVespasiano;-19.6919\nAtebubu;7.7500\nKhanty-Mansiysk;61.0000\nNusaybin;37.0750\nLo Barnechea;-33.3500\nAzare;11.6742\nAriquemes;-9.9161\nPaço do Lumiar;-2.5319\nGangāwati;15.4300\nHillsboro;45.5273\nKoutiala;12.3833\nKiryū;36.4052\nPushkino;56.0167\nYelets;52.6167\nOurense;42.3364\nBallia;25.7604\nBình Long;11.6527\nTikrīt;34.6100\nBulan;12.6697\nMiriālgūda;16.8667\nPlayas de Rosarito;32.3636\nLerma;19.2847\nTarīm;16.0500\nMaluñgun;6.2667\nMityana;0.4006\nPresidente Franco;-25.5333\nSouth Fulton;33.6273\nMazyr;52.0500\nRobāţ Karīm;35.4847\nKroonstad;-27.6456\nKonotop;51.2369\nKandhkot;28.4000\nSaint Helens;53.4500\nToride;35.9115\nŌnojō;33.5333\nMakrāna;27.0500\nGranada;11.9347\nAssis;-22.6619\nRenton;47.4784\nGirona;41.9833\nKongolo;-5.4000\nSheopur;25.6700\nSultan Kudarat;7.2333\nMoers;51.4592\nAlaşehir;38.3500\nLiberec;50.7667\nYozgat;39.8208\nTexcoco;19.5200\nNovara;45.4500\nTam Điệp;20.1556\nTourcoing;50.7239\nAl Fāw;29.9758\nBalanga;14.6800\nNdjamba;-14.7000\nMandeville;30.3751\nSan Mateo;37.5522\nColumbia;39.2004\nMasbate;12.2700\nSalzgitter;52.1500\nTezpur;26.6300\nBerdsk;54.7500\nKurichchi;10.9609\nNgong;-1.3667\nWaterloo;43.4667\nWorcester;52.1911\nDaly City;37.6862\nTādepallegūdem;16.8150\nBălţi;47.7667\nWłocławek;52.6592\nMaumere;-8.6222\nDavie;26.0789\nMasaka;-0.3411\nNanterre;48.8988\nSergiyev Posad;56.3000\nJurupa Valley;34.0010\nFrancistown;-21.1736\nFugangcun;23.5899\nOlanchito;15.4833\nTrindade;-16.6581\nLeme;-22.1861\nRoquetas de Mar;36.7642\nInzai;35.8333\nKhāk-e ‘Alī;36.1283\nMaldonado;-34.9000\nFulgāzi;23.1333\nSuruç;36.9764\nTechiman;7.5772\nBrājarājnagar;21.8167\nArapongas;-23.4189\nVilla Luzuriaga;-34.6667\nAquin;18.2833\nChikushino;33.5000\nCaseros;-34.6106\nSan Vicente de Baracaldo;43.2972\nGillingham;51.3850\nGinowan;26.2817\nTula de Allende;20.0500\nBrockton;42.0821\nKalamariá;40.5833\nSindangan;8.2386\nLower Hutt;-41.2167\nCoronel Fabriciano;-19.5189\nKwai Chung;22.3674\nKamianets-Podilskyi;48.6806\nAçailandia;-4.9469\nMubende;0.5575\nNatitingou;10.3000\nSéguéla;7.9667\nLongmont;40.1686\nElista;46.3167\nKalyani;22.9750\nKilinochchi;9.4004\nPaniqui;15.6681\nSaijō;33.9167\nIsehara;35.3833\nDolisie;-4.2000\nNegapatam;10.7667\nEastbourne;50.7700\nPazardzhik;42.2000\nWigan;53.5448\nRialto;34.1175\nLibertad;-34.6833\nSan Rafael;14.9500\nThika;-1.0396\nTelde;27.9985\nYunfu;28.6331\nBuxar;25.5605\nDongguazhen;25.0790\nSan Germán;18.0827\nSiegen;50.8833\nTantoyuca;21.3500\nVitry-sur-Seine;48.7875\nBiak;-1.1800\nZomba;-15.3833\nYishi;35.1379\nSongea;-10.6833\nHikkaduwa;6.1472\nEau Claire;44.8197\nBouskoura;33.4489\nLida;53.8833\nBūndi;25.4383\nMazatenango;14.5333\nHove;50.8352\nNyeri;-0.4167\nAmarāvati;16.5131\nMessaad;34.1542\nBumba;2.1844\nAraxá;-19.5928\nTurlock;37.5053\nWoodbridge;40.5611\nNorwalk;33.9069\nAlmirante Tamandaré;-25.3250\nSakado;35.9573\nSão Lourenço da Mata;-8.0019\nYilong;23.7081\nItanhaém;-24.1806\nNovokuybyshevsk;53.1000\nBergama;39.1167\nHighlands Ranch;39.5419\nSoasio;0.6833\nPiacenza;45.0500\nMiryang;35.5000\nRishīkesh;30.1083\nTanjungpandan;-2.7500\nHouzhuang;35.6390\nMengdingjie;23.5517\nHildesheim;52.1500\nXırdalan;40.4486\nParang;7.3744\nSatu Mare;47.7900\nNantou;23.9167\nCoatepec;19.4522\nSangju;36.4400\nSanta Rosa;-36.6167\nMumias;0.3333\nBhadreswar;22.8200\nGuihulñgan;10.1167\nHinche;19.1500\nNoginsk;55.8500\nLeuven;50.8833\nBethal;-26.4500\nAllen;33.1088\nHengnan;22.5337\nSan Felipe del Progreso;19.7125\nNíkaia;37.9667\nChaguanas;10.5167\nBahrain;35.2078\nBurzaco;-34.8167\nSundarnagar;31.5300\nSeoni;22.0800\nWichita Falls;33.9072\nCalasiao;16.0167\nPaoy Paet;13.6500\nNgã Bảy;9.8164\nMayarí;20.6592\nKapūrthala;31.3800\nRio Rancho;35.2873\nMositai;45.5266\nSabanalarga;6.8500\nDhangaḍhi̇̄;28.7136\nIgarassu;-7.8342\nKāshmar;35.2383\nAurangābād;24.7000\nVacaville;38.3587\nKlagenfurt;46.6167\nDelta;49.0847\nChilakalūrupet;16.0892\nVāsco Da Gāma;15.3981\nSpokane Valley;47.6626\nCharlottesville;38.0375\nChishtian;29.8000\nŞabrātah;32.7922\nTota;6.8000\nGütersloh;51.9000\nAl Jumayl;32.8528\nBoryeong;36.3333\nDhamtari;20.7100\nJingping;39.5189\nDeventer;52.2500\nShūshtar;32.0456\nTavşanlı;39.5333\nTeluk Intan;4.0259\nSanto Antônio de Jesus;-12.9692\nHồng Ngự;10.8330\nOued Zem;32.8667\nSūjāngarh;27.7000\nJeypore;18.8563\nChatham;42.4229\n‘Ibrī;23.2325\nBỉm Sơn;20.0781\nZheleznogorsk;52.3333\nSungai Penuh;-2.0589\nYên Bái;21.7000\nItauguá;-25.3833\nBalsas;-7.5328\nSanta Cruz;6.8333\nSan Luis de la Paz;21.3000\nAïn Oussera;35.4489\nCréteil;48.7911\nLiancheng;24.0515\nKawachinagano;34.4667\nIdaho Falls;43.4871\nKousséri;12.0833\nMestre;45.4906\nRadès;36.7667\nHāgere Hiywet;8.9833\nDaoukro;7.0500\nWeifen;38.4633\nKanoya;31.3831\nMenifee;33.6909\nOum el Bouaghi;35.8706\nAncona;43.6169\nMporokoso;-9.3833\nSololá;14.7667\nPort Blair;11.6683\nVimmerby;57.6667\nAboisso;5.4667\nChanwari;23.2000\nMuriaé;-21.1306\nSungailiat;-1.8561\nNew Kru Town;6.3733\nKpalimé;6.9000\nLeer;8.2979\nLee's Summit;38.9171\nUmuarama;-23.7658\nNāḩiyat al Iskandarīyah;32.9000\nKaiserslautern;49.4447\nGangtok;27.3300\nDiourbel;14.6550\nAhar;38.4847\nKōnan;35.3321\nChust;40.9978\nQuincy;42.2506\nMasjed Soleymān;31.9364\nGeita;-2.8714\nSumber;-6.7544\nMairiporã;-23.3189\nTorbat-e Jām;35.2439\nLamitan;6.6500\nRincón de Romos;22.2333\nRed Deer;52.2681\nShahrisabz;39.0500\nAubervilliers;48.9131\nTalipao;5.9760\nSan Angelo;31.4424\nSanta Cruz del Quiché;15.0500\nLynn;42.4781\nHolland;42.7677\nZelënodol’sk;55.8500\nFormosa;-15.5369\nNanxicun;23.4976\nBacabal;-4.2250\nPyinmana;19.7500\nBāmyān;34.8250\nKamloops;50.6761\nRayleigh;51.5864\nDunedin;-45.8742\nNabire;-3.3682\nRâmnicu Vâlcea;45.1047\nOcotlán;20.3514\nLa Libertad;-2.2333\nSisophon;13.5833\nJinotega;13.0908\nViseu;40.6667\nSanta Fe;35.6619\nMaribor;46.5575\nAshiya;34.7278\nDhuliān;24.6800\nBayeux;-7.1333\nKohīma;25.6700\nHemel Hempstead;51.7526\nSopron;47.6849\nGalle;6.0536\nZhudong;24.7366\nCiudad General Belgrano;-34.7167\nVista;33.1896\nSantiago de Compostela;42.8778\nChipata;-13.6453\nSan Ramón;-33.5333\nYashio;35.8225\nHerẕliyya;32.1653\nCatarman;12.4994\nBath;51.3800\nJanakpur;26.7286\nTenancingo;18.9608\nSan Fernando;36.4667\nHalf Way Tree;18.0106\nInagi;35.6379\nVị Thanh;9.7833\nSan Joaquín;-33.4792\nIsulan;6.6333\nColombes;48.9236\nPetapa;14.4962\nPernik;42.6000\nSidi Slimane;34.2600\nWangqing;43.3126\nDarlington;54.5270\nGävle;60.6747\nSibolga;1.7425\nFulham;51.4828\nTumbes;-3.5708\nArauca;7.0903\nLevallois-Perret;48.8950\nChārīkār;35.0131\nLa Reina;-33.4500\nOrem;40.2981\nSepatan;-6.1143\nKomae;35.6348\nLa Marsa;36.8764\nYishui;35.7904\nMarmagao;15.4020\nSan Francisco Solano;-34.7667\nZiftá;30.7142\nKakamega;0.2822\nSchwerin;53.6333\nSunrise;26.1547\nLabuan;5.3000\nGuercif;34.2333\nCompton;33.8930\nÇankırı;40.5986\nErrachidia;31.9319\nLingtang;23.6032\nYotsukaidō;35.6698\nČeské Budějovice;48.9747\nArden-Arcade;38.6017\nRío Gallegos;-51.6233\nFenggang;23.6283\nTataouine;32.9306\nTripunittura;9.9528\nLudwigsburg;48.8975\nWajir;1.7500\nEaling;51.5175\nLéogâne;18.5108\nNisshin;35.1320\nXiancun;23.2374\nŌbu;35.0117\nAl Badrashayn;29.8520\nNaxçıvan;39.2089\nWimbledon;51.4220\nĐông Hà;16.8303\nÍlion;38.0333\nNetrakona;24.8819\nCiudad Lázaro Cárdenas;17.9561\nMtwara;-10.2736\nŢalkhā;31.0547\nGjakovë;42.3833\nPrizren;42.2128\nBình Hòa;10.9061\nBen Arous;36.7472\nWatford;51.6550\nMonte Chingolo;-34.7333\nSan Isidro;14.4685\nBen Guerir;32.2300\nVanadzor;40.8128\nCisauk;-6.3333\nHastings;50.8500\nDrobeta-Turnu Severin;44.6333\nAl Fujayrah;25.1223\nLos Cerrillos;-33.5000\nTartu;58.3833\nMakeni;8.8817\nSuceava;47.6514\nAmstelveen;52.3000\nNéa Smýrni;37.9500\nHradec Králové;50.2092\nNuneaton;52.5230\nŞırnak;37.5200\nMiaoli;24.5700\nSouth Gate;33.9447\nCiudad de Melilla;35.2825\nStevenage;51.9017\nÚstí nad Labem;50.6583\nOrpington;51.3741\nMagadan;59.5667\nSanta Monica;34.0235\nPardubice;50.0386\nBender;46.8333\nOulad Teïma;30.4000\nJaffna;9.6647\nQueluz;38.7514\nAulnay-sous-Bois;48.9386\nUmeå;63.8250\nMasvingo;-20.0744\nBrixton;51.4575\nEdmonton;51.6154\nSettsu;34.7772\nOuidah;6.3667\nHartlepool;54.6900\nWakō;35.7812\nUpper Bicutan;14.4873\nCadereyta Jiménez;25.6000\nPoitiers;46.5800\nJabālyā;31.5281\nWestminster;33.7523\nFuengirola;36.5417\nChester;53.1900\nLobnya;56.0167\nSan Leandro;37.7074\nHemei;24.1167\nSolwezi;-12.1433\nGrand Bourg;-34.4833\nKalibo;11.7072\nSan Antonio;14.4656\nAma;35.2004\nAbomey;7.1856\nZhunan;24.6833\nGlyfáda;37.8667\nKitanagoya;35.2456\nRemedios de Escalada;-34.7167\nBabahoyo;-1.8167\nJangipur;24.4700\nAcayucan;17.9422\nZhezqazghan;47.7833\nDobrich;43.5667\nXicotepec de Juárez;20.3000\nŢarţūs;34.8833\nHigashiyamato;35.7454\nCatanzaro;38.9000\nEast Ham;51.5323\nKennedy Town;22.2800\nWakiso;0.3981\nValjevo;44.2667\nBromley;51.4070\nHayes;51.5127\nGermantown;39.1755\nJalal-Abad;40.9333\nBhola;22.6863\nTala;20.6525\nYoro;15.1333\nPrešov;49.0017\nBismarck;46.8143\nWarabi;35.8256\nBalkanabat;39.5167\nIpil;7.7822\nTakasagochō-takasemachi;34.7667\nPerintalmanna;10.9765\nMechelen;51.0278\nAs Salţ;32.0333\nClifton;40.8630\nMukacheve;48.4414\nTangxing;35.7261\nChinnachauku;14.4732\nNabatîyé;33.3833\nDaxincun;38.4427\nAl Wakrah;25.1800\nBayanan;14.4078\nViana do Castelo;41.7000\nApizaco;19.4167\nAylesbury;51.8168\nSesto San Giovanni;45.5333\nPodujevë;42.9167\nState College;40.7909\nProsperidad;8.6057\nBertoua;4.5833\nAlabel;6.1023\nVersailles;48.8053\nAntehiroka;-18.8500\nCoronel Oviedo;-25.4167\nDārayyā;33.4500\nAyase;35.4333\nCiudad de Ceuta;35.8867\nLower Bicutan;14.5033\nÉbolowa;2.9167\nSabaneta;6.1500\nClichy;48.9044\nTorre del Greco;40.7853\nHawthorne;33.9147\nMaasin;10.1300\nSan Juan de los Morros;9.9010\nLawrence;42.7002\nSalina Cruz;16.1833\nSan Baudilio de Llobregat;41.3458\nCitrus Heights;38.6948\nAthurugiriya;6.8922\nEdgware;51.6185\nBurnley;53.7890\nWhittier;33.9678\nMardin;37.3131\nXishancun;23.2589\nDeurne;51.2247\nMpanda;-6.3500\nEzpeleta;-34.7517\nLarnaca;34.9167\nMingxing;37.4264\nMādabā;31.7167\nNakhon Sawan;15.7133\nSaint Albans;51.7550\nVilla Celina;-34.7006\nIssy-les-Moulineaux;48.8239\nLoznica;44.5333\nTucupita;9.0575\nAth Thawrah;35.8367\nTacámbaro de Codallos;19.2356\nOdienné;9.5000\nKeratsíni;37.9667\nCiudad Lerdo;25.5500\nOwariasahi;35.2165\nPiatra Neamţ;46.9275\nDeerfield Beach;26.3050\nSan Fernando;10.2833\nKouvola;60.8681\nKuznetsk;53.1167\nToledo;39.8567\nBusto Arsizio;45.6120\nEl Bayadh;33.6831\nPonnāni;10.7700\nKarakol;42.4903\nComo;45.8103\nShumen;43.2833\nXuddur;4.1200\nÁgios Dimítrios;37.9333\nPori;61.4833\nManfalūţ;27.3167\nMitrovicë;42.8833\nBaj Baj;22.4828\nCozumel;20.5104\nLouga;15.6167\nAtakpamé;7.5269\nPuerto Maldonado;-12.6000\nHeṭauḍā;27.4167\nUpper Darby;39.9490\nCicero;41.8445\nVeliko Tarnovo;43.0778\nDar el Beïda;36.7142\nPurmerend;52.5000\nNazareth;32.7019\nUman;48.7500\nNabunturan;7.6008\nNagaoka;34.9333\nOsijek;45.5556\nChervonohrad;50.3822\nLucerne;47.0500\nBūmahen;35.7297\nKunitachi;35.6839\nShek Tong Tsui;22.2871\nPine Hills;28.5818\nTecate;32.5728\nNewmarket;44.0500\nIlioúpoli;37.9333\nBarahona;18.2000\nHo;6.6119\nPhuket;7.8881\nLe Bardo;36.8092\nBuena Park;33.8572\nKayes;14.4500\nChampigny-sur-Marne;48.8172\nHaskovo;41.9333\nChatham;51.3700\nBatley;53.7167\nEsteio;-29.8608\nReşiţa;45.3008\nRueil-Malmaison;48.8760\nShinkai;35.8367\nMiami Beach;25.8171\nKirtipur;27.6667\nCasoria;40.9000\nTallaght;53.2886\nWest Rembo;14.5667\nScunthorpe;53.5809\nSchiedam;51.9167\nDudley;52.5080\nAlhambra;34.0840\nBan Talat Rangsit;13.9833\nSilao;20.9478\nTârgu Jiu;45.0342\nEl Palomar;-34.6167\nAl Khānkah;30.1601\nKiyose;35.7857\nOwendo;0.2833\nTanuku;16.7500\nSilver Spring;39.0028\nLakewood;33.8471\nMountain View;37.4001\nJuchitán de Zaragoza;16.4333\nWhite Rock;49.0250\nElbasan;41.1111\nCampo Formoso;-10.5089\nÉvosmos;40.6689\nWeston-super-Mare;51.3460\nNéa Ionía;38.0333\nZaandam;52.4333\nPaisley;55.8456\nSouth Shields;54.9950\nSaint-Maur-des-Fossés;48.7994\nBilecik;40.1431\nHuolu;38.0874\nHandeni;-5.4242\nBel-Air;14.5639\nBanī Mazār;28.5000\nDaugavpils;55.8750\nIvanteyevka;55.9833\nDrancy;48.9300\nLos Reyes de Salgado;19.5833\nCinisello Balsamo;45.5500\nKashiba;34.5333\nHakkari;37.5770\nRubí;41.4933\nBury;53.5930\nLe Kram;36.8333\nArāria;26.1500\nDome;5.6550\nChalándri;38.0167\nTârgovişte;44.9244\nGalway;53.2719\nBarreiro;38.6667\nPaysandú;-32.3214\nLomas del Mirador;-34.6667\nCabadbaran;9.1228\nNew Rochelle;40.9304\nTejupilco;18.9058\nCiudadela;-34.6333\nAigáleo;37.9920\nViedma;-40.8000\nRagusa;36.9250\nLebanon;40.3412\nSomerville;42.3908\nFocşani;45.7000\nZuwārah;32.9333\nQuatre Bornes;-20.2654\nYauco;18.0344\nShancheng;34.7904\nKuniyamuttūr;10.9638\nFnidq;35.8500\nSremska Mitrovica;44.9700\nPuerto Ayacucho;5.6631\nChiquimula;14.7833\nSidi Qacem;34.2167\nKirdāsah;30.0320\nLa Rochelle;46.1600\nIzumiōtsu;34.5000\nLelystad;52.5000\nTustin;33.7311\nAlabang;14.4184\nMansfield;53.1444\nBracknell;51.4160\nBalagtas;14.8145\nAvilés;43.5561\nNakhon Pathom;13.8206\nMahdia;35.5000\nMilpitas;37.4336\nUbon Ratchathani;15.2281\nBistriţa;47.1333\nWeligama;5.9739\nCarlisle;54.8910\nGarissa;-0.4569\nLisala;2.1486\nNitra;48.3069\nZográfos;37.9783\nEast Kilbride;55.7644\nBellflower;33.8880\nFrontera;26.9260\nBanská Bystrica;48.7353\nKatano;34.7833\nRa‘ananna;32.1833\nPerote;19.5620\nKafr az Zayyāt;30.8247\nAveiro;40.6333\nTambacounda;13.7689\nBurton upon Trent;52.8019\nPau;43.3000\nUngoofaaru;5.6681\nEvanston;42.0464\nKensington;51.5000\nThornton Heath;51.4002\nFaranah;10.0333\nBokhtar;37.8364\nMoulay Abdallah;33.1978\nCannes;43.5513\nWang Tau Hom;22.3408\nAlameda;37.7668\nAl Muḩarraq;26.2500\nGodāwari̇̄;28.9100\nMaghāghah;28.6500\nKuacjok;8.3100\nMadhubani;26.3700\nMalappuram;11.0588\nSucat;14.4600\nCrewe;53.0990\nCửa Lô;18.8167\nGladbeck;51.5667\nSan Miguel de Allende;20.9142\nSankt Gallen;47.4242\nGouda;52.0111\nKargilik;37.8850\nMaroúsi;38.0500\nMontrouge;48.8172\nLimbé;19.7056\nNewcastle under Lyme;53.0109\nChingford;51.6230\nKorydallós;37.9833\nHarrogate;53.9919\nCaxito;-8.5800\nMao;19.5667\nOkegawa;36.0057\nVirac;13.5833\nLas Piedras;-34.7167\nRugby;52.3700\nBerbérati;4.2614\nTamazunchale;21.2667\nZrenjanin;45.3833\nFouchana;36.7000\nSurt;31.2050\nPančevo;44.8706\nVlaardingen;51.9000\nNerkunram;13.0667\nJōyō;34.8531\nLuodong;24.6767\nAbéché;13.8331\nAïn Temouchent;35.3044\nPalmerston North;-40.3550\nCheyenne;41.1350\nPalaió Fáliro;37.9333\nTamworth;52.6330\nChiryū;35.0014\nWatsonville;36.9206\nAntibes;43.5808\nKarlstad;59.3783\nNandi Hills;0.1003\nRamla;31.9275\nJinja;0.4233\nTamanrasset;22.7850\nZadar;44.1194\nIxtaczoquitlán;18.8500\nBenalmádena;36.6000\nMusashimurayama;35.7548\nBella Vista;-34.5333\nArta;11.5236\nVincennes;48.8478\nTafo;6.7358\nTissemsilt;35.6072\nJoensuu;62.6000\nRioverde;21.9300\nMatehuala;23.6528\nDavis;38.5553\nDarhan;49.4689\nTeyateyaneng;-29.1511\nZacatecoluca;13.5000\nPawtucket;41.8744\nZlín;49.2331\nSpijkenisse;51.8500\nAvaniyāpuram;9.8818\nCalais;50.9481\nJinsha;23.5287\nKiyosu;35.1998\nSiuri;23.9100\nPrey Veng;11.4833\nDazaifu;33.5167\nInowrocław;52.7931\nBitola;41.0319\nSan Andrés;12.5847\nPoblacion;10.2500\nTangalla;6.0167\nLowestoft;52.4800\nSouthall;51.5121\nLongkoucun;23.5726\nCaguas;18.2319\nHekinan;34.8847\nYoshikawa;35.8939\nAssab;13.0167\nBagumbayan;14.4744\nGosport;50.7948\nNabeul;36.4542\nCao Bằng;22.6667\nIvry-sur-Seine;48.8078\nUxbridge;51.5404\nBirobidzhan;48.8000\nGrays;51.4750\nTsurugashima;35.9345\nTulcea;45.1900\nNew Britain;41.6759\nLauderhill;26.1605\nEl Kef;36.1822\n‘Izbat al Burj;31.5031\nGerli;-34.6833\nSalima;-13.7833\nSaint-Louis du Nord;19.9333\nBlagoevgrad;42.0119\nŞa‘dah;16.9400\nMaharlika Village;14.4989\nWalton upon Thames;51.3868\nNeuilly-sur-Seine;48.8881\nBusia;0.4669\nNoisy-le-Grand;48.8478\nGalátsi;38.0167\nŞirvan;39.9323\nKodungallūr;10.2338\nKamuli;0.9450\nFada Ngourma;12.0500\nYawata-shimizui;34.8667\nSan José de las Lajas;22.9678\nThakhèk;17.4000\nCuscatancingo;13.7333\nSan Dionisio;14.4839\nCentreville;38.8390\nFeltham;51.4496\nSan Antonio;-25.3797\nPavia;10.7750\nLappeenranta;61.0667\nGaura;25.4961\nMount Vernon;40.9136\nBaldwin Park;34.0829\nChiyoda-ku;35.6940\nCabo San Lucas;22.8897\nKolonnawa;6.9283\nOroquieta;8.4833\nWandsworth;51.4550\nCastelldefels;41.2800\nKarakax;37.2714\nAbancay;-13.6333\nCamden;39.9361\nToyoake;35.0509\nWilde;-34.7000\nHavířov;49.7831\nTorremolinos;36.6218\nAjaccio;41.9267\nStara Pazova;44.9833\nBorongan;11.6094\nMatara;5.9500\nNizwá;22.9333\nNajrān;17.4917\nVíctor Larco Herrera;-8.1333\nČačak;43.8914\nWalsall;52.5800\nCergy;49.0361\nSihanoukville;10.6333\nNeyyāttinkara;8.4000\nLa Chorrera;8.8792\nAl Qūşīyah;27.4143\nVarisshiyakuni;11.6400\nKireka;0.3467\nPantin;48.8966\nHalmstad;56.6739\nCapelle aan den IJssel;51.9333\nVénissieux;45.6978\nTarīn Kōṯ;32.6267\nGivatayim;32.0714\nYoussoufia;32.2500\nMitcham;51.4009\nMisantla;19.9333\nSalamá;15.1052\nYambol;42.4833\nBitlis;38.4000\nMartínez;-34.4833\nSlatina;44.4297\nRamos Arizpe;25.5500\nPhitsanulok;16.8158\nSamraong;14.2500\nZinjibār;13.1283\nHatogaya-honchō;35.8267\nTamarac;26.2056\nĐiện Biên Phủ;21.3833\nBorj el Qoblé;33.2631\nRedondo Beach;33.8577\nNew Westminster;49.2069\nKumanovo;42.1322\nValle Hermoso;25.6736\nWilmington;39.7415\nNovi Pazar;43.1500\nMindelo;16.8860\nGardēz;33.6000\nChiang Rai;19.9094\nTynemouth;55.0170\nAbnūb;27.2667\nPaignton;50.4353\nĀksum;14.1208\nJinxing;37.9869\nHuauchinango;20.1767\nHuatusco;19.1489\nBayonne;40.6668\nGuaynabo;18.3832\nFujiidera;34.5667\nAïn Harrouda;33.6372\nKashiwara;34.5833\nŢūkh;30.3539\nDimbokro;6.6500\nPassaic;40.8574\nVeenendaal;52.0167\nAgía Paraskeví;38.0117\nSagaing;21.8822\nVillanueva y Geltrú;41.2243\nSzolnok;47.1747\nEncarnación;-27.3333\nViladecáns;41.3158\nRochester;51.3750\nVushtrri;42.8222\nMoquegua;-17.2000\nHeroica Caborca;30.7167\nWashington;54.9000\nRivera;-30.9025\nAshford;51.1465\nGeorgiyevsk;44.1500\nAssen;53.0000\nCastellammare di Stabia;40.6947\nL’Aquila;42.3500\nCortazar;20.4830\nEskilstuna;59.3708\nAntony;48.7539\nFinchley;51.5990\nHornchurch;51.5565\nLiepāja;56.5117\nActon;51.5135\nKati;12.7504\nBouira;36.3800\nPortici;40.8197\nTamlūk;22.3000\nEast Orange;40.7651\nSan José del Guaviare;2.5667\nTaman Johor Jaya;1.5333\nGaithersburg;39.1346\nPonta Delgada;37.7400\nHihyā;30.6687\nAl Minshāh;26.4833\nVilla Domínico;-34.6917\nSabinas;27.8489\nPruszków;52.1667\nMerthyr Tudful;51.7430\nEastvale;33.9617\nAl Buraymī;24.2592\nKitamoto;36.0269\nŞəki;41.2000\nAfragola;40.9167\nHorad Zhodzina;54.1000\nArima;10.6333\nAdrar;27.8742\nAl Qurayn;30.6161\nWaterlooville;50.8800\nValle de Bravo;19.1925\nKarlskrona;56.1608\nKāyankulam;9.1720\nVäxjö;56.8769\nApac;1.9850\nTomigusuku;26.1611\nBayombong;16.4833\nBignay;14.7456\nVýronas;37.9617\nBuynaksk;42.8167\nBankra;22.6300\nBan Suan;13.3616\nAreguá;-25.2953\nKatwijk;52.2000\nBoston;52.9740\nBanda del Río Salí;-26.8500\nHämeenlinna;60.9944\nVaasa;63.1000\nBayt Lāhyā;31.5539\nScarborough;54.2773\nUnion City;40.7675\nChiapa de Corzo;16.7080\nCupang;14.4315\nTunasan;14.3725\nTäby;59.4333\nStreatham;51.4279\nFarnborough;51.2900\nCabedelo;-6.9808\nBarking;51.5400\nMolepolole;-24.4067\nPotenza;40.6333\nEl Prat de Llobregat;41.3246\nTeresa;14.5586\nLynwood;33.9240\nSkokie;42.0360\nPatuakhāli;22.3542\nKozáni;40.3000\nArrecife;28.9625\nAltamira;22.3375\nGuamúchil;25.4639\nSiemianowice Śląskie;50.2758\nStourbridge;52.4575\nTwickenham;51.4490\nFryazino;55.9500\nAcámbaro;20.0361\nMaisons-Alfort;48.8058\nLechang;35.6415\nBolgatanga;10.7833\nMartil;35.6167\nPetroúpoli;38.0333\nLaeken;50.8778\nSchenectady;42.8025\nKraljevo;43.7234\nÉpinay-sur-Seine;48.9553\nHereford;52.0560\nKhagaul;25.5790\nTroyes;48.2997\nCollado-Villalba;40.6333\nBayburt;40.2597\nGranollers;41.6083\nNālūt;31.8685\nZacapa;14.9667\nLos Polvorines;-34.5000\nSan Jose;10.7433\nGampaha;7.0917\nSouth San Francisco;37.6538\nPrilep;41.3464\nTrnava;48.3775\nSarcelles;48.9956\nDewsbury;53.6910\nSundapālaiyam;11.0014\nBilwi;14.0297\nGoz-Beida;12.2236\nLoughborough;52.7700\nBrentwood;40.7839\nWrecsam;53.0460\nSan Marcos;14.9653\nSamut Sakhon;13.5486\nPervomaisk;48.0500\nDon Bosco;14.4817\nTatabánya;47.5862\nLa Seyne-sur-Mer;43.1000\nLa Línea de la Concepción;36.1611\nDaljā;27.6500\nKettering;52.3931\nForest;50.8131\nCălăraşi;44.2000\nMagong;23.5667\nMalden;42.4305\nVillejuif;48.7919\nAmeca;20.5486\nRundu;-17.9167\nAkurana;7.3650\nAmbarawa;-7.2667\nHurlingham;-34.5883\nKitale;1.0167\nNagakute;35.1840\nScheveningen;52.1081\nPaphos;34.7667\nGuayama;17.9743\nKaronga;-9.9333\nEtterbeek;50.8333\nSongkhla;7.2061\nKresek;-6.1314\nSoroti;1.7150\nOuezzane;34.8000\nTagajō;38.2938\nAs Suwaydā’;32.7125\nEuclides da Cunha;-10.5078\nWamena;-4.0975\nPopondetta;-8.7656\nEłk;53.8214\nFaro;37.0161\nFaīẕābād;37.1166\nAlba Iulia;46.0669\nCosamaloapan;18.3667\nSokhumi;43.0000\nEllesmere Port;53.2790\nCherbourg;49.6333\nLe Blanc-Mesnil;48.9387\nBondy;48.9022\nYamatotakada;34.5167\nBeccar;-34.4667\nManouba;36.8078\nNagari;13.3214\nBangor;54.6600\nInhambane;-23.8650\nQal‘ah-ye Now;34.9867\nRuncorn;53.3419\nSeinäjoki;62.7917\nTaunton;51.0190\nLittlehampton;50.8094\nFlorence-Graham;33.9682\nLatacunga;-0.9319\nTwin Rivers;40.2631\nVaslui;46.6383\nChoi Hung;22.3350\nGorno-Altaysk;51.9600\nLalmanirhat;25.9167\nHasuda;35.9945\nMarano di Napoli;40.9000\nDédougou;12.4667\nLegnano;45.5781\nRuislip;51.5760\nŌsakasayama;34.5000\nTaal;13.8833\nAndoharanofotsy;-18.9750\nMukōchō;34.9500\nNkhotakota;-12.9167\nSuresnes;48.8700\nBellevue;48.8710\nTsushima;35.1771\nLa Habra;33.9282\nAnuradhapura;8.3350\nKratie;12.4800\nBan Rangsit;14.0167\nBeledweyne;4.7358\nMaduraivayal;13.0631\nWallasey;53.4158\nJette;50.8667\nTandag;9.0789\nDar Naim;18.0333\nKhartsyzk;48.0333\nMontebello;34.0155\nIganga;0.6150\nBarrow in Furness;54.1108\nNorth Bergen;40.7938\nSaraburi;14.5286\nBrookline;42.3243\nRayong;12.6742\nStryi;49.2500\nGiurgiu;43.9008\nGlew;-34.8833\nFort Portal;0.6544\nSaint-Ouen;48.9123\nRovaniemi;66.5000\nBobigny;48.9106\nPico Rivera;33.9901\nKolda;12.8833\nSantarém;39.2339\nFussa;35.7333\nNapier;-39.4903\nLinares;24.8597\nChornomorsk;46.3017\nMadang;-5.2167\nAş Şaff;29.5772\nLytkarino;55.5833\nBebington;53.3500\nTirur;10.9000\nKırklareli;41.7347\nBerriozábal;16.8003\nRuhengeri;-1.5000\nMacclesfield;53.2500\nDon Galo;14.5072\nVratsa;43.2000\nYala;6.5425\nPuerto Limón;10.0022\nChambéry;45.5700\nBraintree;51.8780\nGia Nghĩa;11.9833\nFontenay-sous-Bois;48.8517\nPortugalete;43.3194\nSuileng;47.2460\nPoonamallee;13.0465\nThe Hammocks;25.6700\nKoja;26.3344\nPinagkaisahan;14.5229\nNonoichi;36.5194\nSanta Rosa de Copán;14.7667\nCoyhaique;-45.5667\nJidd Ḩafş;26.2190\nMonterey Park;34.0497\nLimerick;52.6653\nLeskovac;42.9981\nMislata;39.4750\nSidi Bennour;32.6500\nLongxing;35.6091\nRaharpur;24.8194\nHunedoara;45.7697\nRafael Calzada;-34.7833\nLa Mesa;32.7703\nRoyal Tunbridge Wells;51.1320\nAt Tawāhī;12.7833\nTrang;7.5575\nGardena;33.8943\nBan Bang Kaeo;13.6371\nTakaishi;34.5167\nPuteaux;48.8850\nAntsinanantsena;-18.8333\nKyustendil;42.2833\nRevere;42.4189\nMedford;42.4234\nOyem;1.6000\nCupertino;37.3168\nLokoja;7.8019\nJuigalpa;12.1083\nTrujillo;15.9186\nTczew;54.0875\nWellingborough;52.2939\nLorient;47.7500\nNorth Miami;25.9008\nChakapara;22.6300\nTemascalcingo;19.9147\nTezonapa;18.6058\nVejle;55.7167\nNausori;-18.0244\nTaylorsville;40.6569\nZushi;35.2833\nŚwidnica;50.8500\nIrvington;40.7243\nWest Allis;43.0068\nBungoma;0.5667\nPinotepa;16.3412\nSidi Yahya Zaer;33.7105\nAlfortville;48.8050\nÉvry;48.6239\nMidalt;32.6800\nIrákleio;38.0500\nItānagar;27.1000\nUžice;43.8500\nUnion;40.6953\nSamut Prakan;13.5897\nAntigua Guatemala;14.5667\nSuharekë;42.3800\nAzrou;33.4417\nKlimovsk;55.3667\nSamannūd;30.9622\nKasungu;-13.0333\nHod HaSharon;32.15\nRódos;36.4412\nStavroúpoli;40.6667\nTacuarembó;-31.7333\nKronjo;-6.0667\nFolkestone;51.0810\nMérida;38.9000\nAl Hoceïma;35.2472\nMeaux;48.9603\nOcosingo;16.9072\nWhite Plains;41.0220\nHamura;35.7672\nHoboken;40.7452\nPursat;12.5333\nZumpango;19.7969\nRoyal Leamington Spa;52.2920\nDzerzhinskiy;55.6333\nArtemisa;22.8136\nCrosby;53.4872\nKarīmganj;24.8700\nYevlax;40.6172\nMūndka;28.6794\nCerro de Pasco;-10.6864\nLiuhu;35.5449\nRijswijk;52.0456\nSartrouville;48.9372\nClamart;48.8014\nStratford;51.5423\nHuamantla;19.3133\nSevran;48.9333\nKruševac;43.5833\nSouth Whittier;33.9336\nMineiros;-17.5689\nQiryat Ata;32.8\nAversa;40.9667\nTenkodogo;11.7833\nDosso;13.0500\nNaval;11.5833\nBāruipur;22.3654\nBoudouaou;36.7300\nMandapeta;16.8700\nChelles;48.8833\nPort Coquitlam;49.2625\nRosh Ha‘Ayin;32.0956\nGllogovc;42.6236\nKitgum;3.2889\nBârlad;46.2167\nDapaong;10.8667\nCaridad;14.4828\nNovohrad-Volynskyi;50.5833\nBabīlā;33.4728\nMargate;26.2466\nBékéscsaba;46.6790\nChaniá;35.5167\nDayr al Balaḩ;31.4189\nShijōnawate;34.7400\nOak Lawn;41.7139\nLegionowo;52.4000\nBhīmunipatnam;17.8846\nCarson City;39.1511\nFountainebleau;25.7723\nSlavonski Brod;45.1667\nHilden;51.1714\nAmpelókipoi;40.6500\nNuevo Casas Grandes;30.4167\nAcatzingo;18.9817\nUmm el Faḥm;32.5194\nBiel/Bienne;47.1333\nKidderminster;52.3885\nLipjan;42.5300\nCoconut Creek;26.2803\nKaruhatan;14.6883\nBoac;13.4500\nMariano Acosta;-34.7167\nAltrincham;53.3838\nNacaome;13.5333\nMafeteng;-29.8167\nPansol;14.6514\nElenga;24.3386\nChinhoyi;-17.3497\nMy Drarga;30.3800\nWeymouth;50.6130\nGümüşhane;40.4597\nPithāpuram;17.1167\nCaacupé;-25.3861\nMelo;-32.3667\nBarri;51.4050\nVilla Hayes;-25.1000\nBelize City;17.4986\nCatemaco;18.4167\nMiragoâne;18.4458\nFountain Valley;33.7105\nMaun;-19.9833\nNikšić;42.7778\nUshuaia;-54.8019\nBerwyn;41.8433\nPijijiapan;15.6917\nBagong Pag-Asa;14.6622\nLeith;55.9800\nSan Pedro;25.7578\nEsplugas de Llobregat;41.3767\nNational City;32.6654\nWote;-1.7833\nZalău;47.1911\nTirupparangunram;9.8815\nArcadia;34.1342\nSfântu-Gheorghe;45.8636\nAbū Qīr;31.3167\nMuğla;37.2167\nÉvora;38.5667\nVillarrica;-25.7500\nMadhipura;25.9200\nPhra Nakhon Si Ayutthaya;14.3478\nMoyobamba;-6.0333\nMocoa;1.1500\nGreenford;51.5299\nZouerate;22.7333\nTrenčín;48.8919\nRahovec;42.3994\nMendi;-6.1478\nJelgava;56.6483\nSaint-Quentin;49.8486\nFrancisco I. Madero;25.7753\nCastelo Branco;39.8167\nRio Tinto;41.1780\nSan Giorgio a Cremano;40.8333\nQuiapo;14.6000\nVigan;17.5747\nMollet;41.5356\nSankt Pölten;48.2000\nMassy;48.7309\nZalaegerszeg;46.8392\nFuchū;34.3926\nDunfermline;56.0719\nGallarate;45.6649\nHà Giang;22.8333\nIba;15.3333\nRowley Regis;52.4880\nOhrid;41.1169\nCorbeil-Essonnes;48.6139\nFlorida;-34.5167\nGuliston;40.4833\nMadīnat Ḩamad;26.1128\nNew Brunswick;40.4870\nNeath;51.6600\nM.Ə. Rəsulzadə;40.4344\nBootle;53.4457\nSkien;59.2081\nHamilton;55.7770\nMarikina Heights;14.6534\nLautoka;-17.6242\nHuntington Park;33.9800\nErcolano;40.8000\nCakung;-6.2507\nButa;2.8000\nVaulx-en-Velin;45.7768\nAmalāpuram;16.5787\nLancaster;54.0489\nIbiza;38.9089\nLampang;18.3000\nVranje;42.5542\nTanjombato;-18.9500\nEltham;51.4510\nCagnes-sur-Mer;43.6644\nPerth Amboy;40.5202\nBādurpalle;17.5468\nShiogama;38.3144\nAl Karnak;25.7186\nCintalapa de Figueroa;16.6978\nKyaliwajjala;0.3800\nGabrovo;42.8667\nGutao;37.1989\nPadangpanjang;-0.4500\nMikkeli;61.6833\nChake Chake;-5.2395\nMorden;51.4015\nCumbernauld;55.9450\nChoisy-le-Roi;48.7630\nBrentwood;51.6200\nMuban Saeng Bua Thong;13.9424\nTamiami;25.7556\nArwal;25.2500\nRuma;45.0000\nGjilan;42.4647\nBayonne;43.4900\nWillenhall;52.5798\nWestchester;25.7471\nLa Jagua de Ibirico;9.5667\nLouangphabang;19.8833\nShiraoka;36.0191\nAndover;51.2080\nPlainfield;40.6154\nPrachuap Khiri Khan;11.8167\nOak Park;41.8872\nGao;16.2667\nTulcán;0.8117\nKorçë;40.6167\nParamount;33.8977\nMuktāgācha;24.7662\nAl Ma‘allā’;12.7897\nAspen Hill;39.0927\nSherpur;24.6650\nRosny-sous-Bois;48.8667\nAmpitatafika;-18.9333\nSakon Nakhon;17.1564\nAlajuela;10.1640\nQalqīlyah;32.1903\nKabale;-1.2500\nLiberia;10.6333\nMarondera;-18.1897\nYeovil;50.9452\nMoskovskiy;55.6000\nNes Ẕiyyona;31.9333\nSan Vicente;13.6453\nCologno Monzese;45.5286\nKendale Lakes;25.7081\nSutton in Ashfield;53.1250\nEl Ghâzîyé;33.5186\nSanto Cristo;14.6603\nNoisy-le-Sec;48.8894\nScafati;40.7536\nRho;45.5333\nHrazdan;40.5000\nTargovishte;43.2500\nBuena Vista Tomatlán;19.2102\nMaha Sarakham;16.1772\nValladolid;20.6894\nJiménez;27.1300\nBoujad;32.7667\nChahār Dangeh;35.6031\nTakeo;10.9833\nAlytus;54.4014\nBodø;67.2827\nSanturce-Antiguo;43.3303\nTam Hiệp;10.9497\nBang Bua Thong;13.9099\nAloha;45.4920\nGennevilliers;48.9333\nChong Nonsi;13.6965\nCatford;51.4452\nMyrnohrad;48.2911\nIwakura;35.2794\nLevittown;40.7241\nElmshorn;53.7519\nWest New York;40.7857\nNoveleta;14.4333\nTakahama;34.9275\nBloomfield;40.8098\nCollegno;45.0775\nGopālpur;24.5583\nJinotepe;11.8472\nAin El Aouda;33.8111\nLa Garenne-Colombes;48.9056\nSuzukawa;35.3730\nLamía;38.9000\nMangochi;-14.4667\nQiryat Ono;32.0636\nLənkəran;38.7536\nVila Real;41.2958\nKardzhali;41.6500\nLoreto;22.2667\nPlacentia;33.8807\nAliso Viejo;33.5792\nChoma;-16.7711\nPen-y-Bont ar Ogwr;51.5072\nCojutepeque;13.7167\nLivry-Gargan;48.9192\nWheaton;39.0492\nKsar Hellal;35.6429\nTeplice;50.6444\nEdenvale;-26.1411\nEger;47.8990\nḨarastā;33.5667\nRosemead;34.0689\nKunnamkulam;10.6500\nJihlava;49.4003\nWhangarei;-35.7250\nSombor;45.7833\nQasbat Tadla;32.6000\nFlorin;38.4832\nUpplands Väsby;59.5167\nBinondo;14.6000\nTizimín;21.1425\nKendrāparha;20.5000\nSurbiton;51.3940\nTlapa de Comonfort;17.5461\nKasuya;33.6108\nGuozhen;34.3668\nPuttalam;8.0330\nStretford;53.4466\nCuetzalan;20.0333\nSalekhard;66.5333\nSar-e Pul;36.2214\nEvere;50.8667\nGarges-lès-Gonesse;48.9728\nJūrmala;56.9681\nCheshunt;51.7020\nKomotiní;41.1000\nCountry Club;25.9407\nRosso;16.5128\nCovina;34.0903\nLevakant;37.8667\nLa Courneuve;48.9322\nHalle-Neustadt;51.4789\nBastia;42.7008\nChanganācheri;9.4667\nBodupāl;17.4139\nLongchamps;-34.8500\nPlainview;14.5777\nBarendrecht;51.8500\nSkenderaj;42.7467\nJarash;32.2723\nBangued;17.5965\nLakewood;41.4822\nBeni Yakhlef;33.6555\nLa Goulette;36.8181\nBarnet;51.6444\nGori;41.9817\nKirkcaldy;56.1107\nAbovyan;40.2739\nColcapirhua;-17.4167\nBagneux;48.7983\nClondalkin;53.3203\nNorth Bethesda;39.0393\nAzemmour;33.2878\nSutton;51.3656\nGbadolite;4.2750\nWest Bridgford;52.9320\nMaḩmūd-e Rāqī;35.0206\nGuadalupe Nuevo;14.5587\nMeudon;48.8123\nLissone;45.6167\nColonia del Sol;22.9125\nVilla Alsina;-34.6667\nBeckenham;51.4080\nLuwero;0.8331\nVidin;44.0000\nMa‘ān;30.1962\nGracias;14.5833\nÖstersund;63.1792\nSelibe Phikwe;-21.9758\nAl Balyanā;26.2333\nTlalmanalco;19.2044\nCypress;33.8171\nTubod;8.0500\nBagnolet;48.8692\nCampobasso;41.5667\nMerksem;51.2428\nAl Khārjah;25.4400\nAshton;53.4897\nKotelniki;55.6617\nNichelino;44.9955\nSemera;11.7922\nPaderno Dugnano;45.5719\nEl‘ad;32.0522\nŚwiętochłowice;50.2919\nPākaur;24.6300\nMairena del Aljarafe;37.3333\nYumbe;3.4650\nMpigi;0.2300\nKangar;6.4333\nManali;13.1667\nBelfort;47.6400\nHuancavelica;-12.7864\nDollard-des-Ormeaux;45.4833\nCerritos;33.8678\nJbaïl;34.1236\nStrood;51.3930\nLuleå;65.5844\nCouva;10.4167\nInverness;57.4778\nWaterford;52.2567\nFigueras;42.2667\nSan Felíu de Llobregat;41.3833\nSalisbury;51.0700\nRamat HaSharon;32.15\nKaédi;16.1506\nAyr;55.4580\nMeoqui;28.2722\nSan Isidro;-34.4667\nCantel;14.8112\nIsla;18.0292\nCorroios;38.6147\nChâtillon;48.8000\nXam Nua;20.4150\nJosé Mármol;-34.7833\nWokingham;51.4100\nKarlovy Vary;50.2306\nBanbury;52.0610\nTalence;44.8000\nBihāt;25.4253\nPejë;42.6603\nRye;41.0075\nSanto Niño;14.5033\nSchagen;52.7833\nMantes-la-Jolie;48.9908\nRovenky;48.0833\nAsadābād;34.8742\nBiləcəri;40.4314\nNellikkuppam;11.7667\nMiddelburg;51.5000\nTulum;20.2119\nGobārdānga;22.8700\nKrasnoznamensk;55.6008\nLlavallol;-34.7667\nNueva Loja;0.0847\nShertallai;9.6869\nSeregno;45.6500\nKita;13.0504\nSerowe;-22.3833\nMandeville;18.0333\nBirendranagar;28.6000\nBakau;13.4833\nNong Khai;17.8681\nBindura;-17.3000\nNorth Highlands;38.6713\nIsiolo;0.3500\nAntelope;38.7153\nMercedes;-33.2500\nEverett;42.4064\nUniversity;28.0771\nSijua;23.7692\nBorgerhout;51.2117\nMalakoff;48.8169\nUrmston;53.4487\nMadīnat ‘Īsá;26.1736\nVilla de Zaachila;16.9508\nInuma;36.0001\nÁlimos;37.9167\nFaya;17.9169\nHavant;50.8517\nKanye;-24.9833\nTorre Annunziata;40.7569\nChalon-sur-Saône;46.7806\nLeribe;-28.8734\nHinckley;52.5413\nNjombe;-9.3333\nLa Mirada;33.9025\nRipollet;41.4969\nKanash;55.5069\nMelito di Napoli;40.9167\nChalungalpādam;9.6896\nMamburao;13.2233\nKsar;18.1022\nWorksop;53.3042\nMorley;53.7492\nInvercargill;-46.4131\nWelling;51.4594\nAl ‘Ayyāţ;29.6167\nKerkrade;50.8667\nZąbki;52.2928\nKarmiel;32.9136\nNew Amsterdam;6.2500\nḨajjah;15.6950\nCharenton-le-Pont;48.8265\nKokkola;63.8367\nTepalcatepec;19.1833\nInđija;45.0500\nPuerto Lempira;15.2653\nHammam-Lif;36.7333\nCaluire-et-Cuire;45.7953\nBang Kruai;13.8042\nDock Sur;-34.6417\nLe Cannet;43.5769\nChitré;7.9667\nBadulla;6.9847\nNagykanizsa;46.4550\nNaj‘ Ḩammādī;26.0500\nCuilapa;14.2783\nSan Adrián de Besós;41.4305\nSantiago;8.1004\nLindi;-9.9969\nAl Badārī;26.9925\nRāmachandrapuram;16.8500\nMrirt;33.1667\nFleet;51.2834\nMiddleton;53.5550\nAweil;8.7800\nBhārella;23.5506\nBois-Colombes;48.9175\nMurshidābād;24.1800\nNelson;-41.2708\nDori;14.0300\nValenciennes;50.3581\nTōgō;35.0966\nYuchengcun;23.5633\nArtigas;-30.4667\nCoatbridge;55.8625\nŠibenik;43.7350\nDaijiazhuang;38.1345\nCobija;-11.0333\nBron;45.7394\nChorley;53.6530\nHammam Sousse;35.8589\nFarim;12.4833\nBen Zakkay;31.8558\nVanves;48.8208\nSlobozia;44.5639\nMafamude;41.1152\nKumatori;34.4014\nSanta María Atzompa;17.0794\nVilvoorde;50.9281\nDonggangli;39.9733\nArlington;42.4187\nRezé;47.1917\nKafr al Kurdī;31.1429\nFareham;50.8500\nMelun;48.5406\nRozzano;45.3833\nIgualada;41.5814\nGbarnga;6.9980\nJerada;34.3117\nAlexandria;43.9686\nDiamond Harbour;22.1910\nJáltipan de Morelos;17.9703\nPalayan City;15.5422\nCastleford;53.7160\nClaypole;-34.8000\nThun;46.7667\nStains;48.9500\nBaclaran;14.5319\nHackensack;40.8891\nYambio;4.5650\nKingston upon Thames;51.4103\nBerchem;51.1833\nArendal;58.4608\nPinneberg;53.6333\nNueva Gerona;21.8847\nTindouf;27.6753\nSykiés;40.6500\nBluefields;12.0139\nTarbes;43.2300\nBellinzona;46.1954\nPattani;6.8664\nGagny;48.8833\nLecherías;10.1889\nBoulogne-sur-Mer;50.7264\nTrelleborg;55.3667\nActopan;19.5036\nDhāka;26.7200\nBắc Kạn;22.1333\nAlcantarilla;37.9722\nHeroica Ciudad de Tlaxiaco;17.2077\nArras;50.2920\nCleveland Heights;41.5113\nNewbury;51.4010\nCoyotepec;19.7756\nInongo;-1.9500\nBridgwater;51.1280\nHoboken;51.1667\nĀdwa;14.1667\nTeoloyucan;19.7442\nConcepción;-23.4000\nWhitney;36.1008\nPinyahan;14.6400\nVarkkallai;8.7340\nPort Loko;8.7667\nDunaújváros;46.9806\nWan Tau Tong;22.4423\nNogent-sur-Marne;48.8375\nRazgrad;43.5333\nDesio;45.6167\nSalvatierra;20.2156\nZugdidi;42.5083\nMochudi;-24.4167\nQiryat Bialik;32.8333\nEl Aïoun;34.5852\nBakhtiyārpur;25.4667\nNorth Lauderdale;26.2113\nBoumerdes;36.7603\nTinnanūr;13.1145\nUmm al Qaywayn;25.5533\nXonobod;40.8000\nÁgioi Anárgyroi;38.0267\nSalem;42.5129\nDuncan;48.7787\nIten;0.6731\nLaindon;51.5740\nRohnert Park;38.3479\nPalladam;10.9900\nKapan;39.2011\nParacho de Verduzco;19.6500\nVillaflores;16.2355\nEmpalme;27.9617\nFreeport;40.6515\nKatsuren-haebaru;26.1911\nCaerphilly;51.5780\nLlanelli;51.6840\nBaler;15.7583\nTrujillo Alto;18.3599\nIngeniero Pablo Nogués;-34.4667\nNueva Rosita;27.9390\nLa Paz;14.3169\nKrus na Ligas;14.6442\nDesamparados;9.8967\nOakland Park;26.1780\nKalmar;56.6614\nWilkes-Barre;41.2469\nSukuta;13.4167\nBushenyi;-0.5417\nCaloundra;-26.7986\nGuruvāyūr;10.5947\nŌizumi;36.2478\nTemsia;30.3600\nKirkby;53.4800\nCampbell;37.2802\nWattrelos;50.7000\nAnnemasse;46.1958\nPlaya Vicente;17.8333\nBeverwijk;52.4833\nMatale;7.4667\nErmezinde;41.2170\nBuli;14.4430\nLe Kremlin-Bicêtre;48.8100\nVeles;41.7153\nOr Yehuda;32.0333\nHaedo;-34.6500\nSan Bruno;37.6256\nGambēla;8.2500\nŠtip;41.7358\nMurzuq;25.9000\nDrogheda;53.7150\nShefar‘am;32.8056\nCacém;38.7704\nConcord;43.2305\nMińsk Mazowiecki;52.1833\nMunro;-34.5333\nSagauli;26.7833\nGreenacres;26.6270\nKoboko;3.4100\nLai Châu;22.3992\nFranconville;48.9889\nRamsgate;51.3360\nPorur;13.0356\nHódmezővásárhely;46.4304\nSmall Heath;52.4629\nKampong Chhnang;12.2500\nNorth Miami Beach;25.9302\nPallisa;1.1675\nUman;20.8833\nSilistra;44.1172\nJuan Rodríguez Clara;18.0000\nAziylal;31.9669\nKalutara;6.5869\nPomigliano d’Arco;40.9167\nSvay Rieng;11.0833\nArmavir;40.1500\nKwīhā;13.4769\nCleethorpes;53.5533\nKula;45.6000\nMinas;-34.3667\nHicksville;40.7637\nJefferson City;38.5676\nWoonsocket;42.0010\nBishops Stortford;51.8720\nGarbahaarrey;3.3500\nBalintawak;14.6506\nBan Sai Ma Tai;13.8444\nCoalville;52.7240\nBlyth;55.1260\nSaronno;45.6255\nPhulwāria;25.4697\nDubrovnik;42.6403\nBlanes;41.6740\nCiudad Melchor Múzquiz;27.8775\nQuinhámel;11.8833\nDayr Mawās;27.6333\nMelmadai;9.9264\nTonalá;16.0914\nTemascal;18.2394\nGuarda;40.5333\nSi Sa Ket;15.1069\nFribourg;46.8000\nSaint-Martin-d’Hères;45.1672\nKenton;51.5878\nLeighton Buzzard;51.9165\nKampot;10.6000\nArnold;53.0050\nMiercurea-Ciuc;46.3594\nBerat;40.7000\nAit Ourir;31.5644\nLe Perreux-Sur-Marne;48.8422\nMyrhorod;49.9667\nBambari;5.7653\nArdahan;41.1111\nZagora;30.3306\nLe Pré-Saint-Gervais;48.8850\nQapshaghay;43.8844\nNebbi;2.4792\nIlkeston;52.9710\nPoissy;48.9294\nŻyrardów;52.0500\nNakama;33.8208\nSan José;-34.3333\nVillafranca del Panadés;41.3447\nMatoupu;38.3198\nAberdare;51.7130\nViborg;56.4333\nXico;19.4170\nLālganj;25.8700\nKahama;-3.8375\nCesano Maderno;45.6307\nCachan;48.7919\nMadipakkam;12.9623\nSavigny-sur-Orge;48.6797\nDouai;50.3714\nHerne Bay;51.3700\nSanta Bárbara;14.9167\nAnnandale;38.8324\nPlacilla de Peñuelas;-33.1156\nAmudālavalasa;18.4167\nEmbu;-0.5389\nPuntarenas;9.9667\nBiougra;30.2144\nNarathiwat;6.4167\nMugnano di Napoli;40.9094\nÉchirolles;45.1436\nKenge;-4.8056\nTuvāgudi;10.7564\nKānkuria;24.6580\nMambajao;9.2500\nZghartā;34.4000\nCiampino;41.8000\nZacatelco;19.2167\nPujali;22.4679\nMorshansk;53.4500\nVilla Adelina;-34.5175\nNola;3.5333\nArzano;40.9167\nLusambo;-4.9729\nSayula de Alemán;17.8833\nVillepinte;48.9550\nNgozi;-2.9083\nBurjasot;39.5064\nTeaneck;40.8900\nBicester;51.9000\nMarcq-en-Baroeul;50.6711\nKisii;-0.6833\nChittaranjan;23.8700\nRivas;11.4386\nCorsico;45.4333\nVredenburg;-32.9000\nNeuilly-sur-Marne;48.8537\nWilrijk;51.1667\nOshakati;-17.7833\nPanaji;15.4989\nMalbork;54.0333\nCalpulalpan;19.5869\nWood Green;51.5981\nFamagusta;35.1250\nRomblon;12.5500\nDenton;53.4554\nPuerto Francisco de Orellana;-0.4625\nHallandale Beach;25.9854\nZacatlán;19.9319\nBinəqədi;40.4661\nNallūr;11.1003\nHighbury;51.5520\nWalkden;53.5239\nMiyoshidai;35.8284\nShengli;37.9842\nCananea;30.9819\nAl Bayḑā’;13.9790\nChartres;48.4560\nPärnu;58.3833\nŞəmkir;40.8297\nWhitley Bay;55.0456\nKoekelberg;50.8667\nEz Zahra;36.7439\nBletchley;51.9940\nImpfondo;1.6333\nParavūrkambolam;8.8168\nCulver City;34.0058\nTalas;42.5167\nBan Na Pa;13.3956\nDún Dealgan;54.0090\nAnnapolis;38.9706\nBillingham;54.6100\nMariano Escobedo;18.9167\nLovech;43.1347\nMontclair;40.8253\nAirdrie;55.8600\nBjelovar;45.9000\nSensuntepeque;13.8667\nGrugliasco;45.0680\nBeeston;52.9270\nBouar;5.9500\nSoccorro;14.6179\nLong Eaton;52.8980\nMontana;43.4075\nCamberley;51.3350\nValley Stream;40.6647\nAgualva;38.7700\nL’Haÿ-les-Roses;48.7800\nSidi Yahia El Gharb;34.3058\nDunstable;51.8860\nHouilles;48.9261\nEl Golea;30.6000\nLuebo;-5.3500\nSwords;53.4597\nPort-Margot;19.7500\nVillefranche-sur-Saône;45.9833\nKanie;35.1322\nChachoengsao;13.6903\nPhônsavan;19.4600\nXaçmaz;41.4708\nChelsea;42.3959\nNorth Shields;55.0097\nBrčko;44.8783\nTumba;59.2000\nBugiri;0.5694\nWaipahu;21.3859\nPierrefitte-sur-Seine;48.9656\nSamrong;13.6421\nKoumra;8.9100\nSurin;14.8864\nSainte-Geneviève-des-Bois;48.6369\nJordan;10.6000\nBell Gardens;33.9663\nBentota;6.4200\nMassawa;15.6097\nAthis-Mons;48.7074\nSan Roque;14.4800\nNueva Italia de Ruiz;19.0194\nEffia-Kuma;4.9167\nSanta Elena;-2.2267\nLincoln Park;42.2432\nPioltello;45.5000\nAventura;25.9566\nFort Lee;40.8509\nĀlamat’ā;12.4167\nSan Gabriel;34.0949\nVernier;46.2000\nLes Lilas;48.8800\nSant’Antimo;40.9422\nWickford;51.6114\nĀzezo;12.5586\nSan Juan Despí;41.3668\nTouggourt;33.1000\nKālihāti;24.3833\nDáfni;37.9500\nMiahuatlán de Porfirio Díaz;16.3327\nPark Ridge;42.0125\nFlorida;-34.1000\nParavūr Tekkumbhāgam;8.8110\nCelje;46.2358\nCabaret;18.7343\nSareh Mowndeh;13.4000\nChâtenay-Malabry;48.7653\nRedcar;54.6180\nKaffrine;14.1014\nPánuco;22.0500\nCreil;49.2583\nLydenburg;-25.0960\nNortholt;51.5467\nHerohalli;12.9911\nBridlington;54.0819\nOlteniţa;44.0867\nHanwell;51.5090\nIstog;42.7833\nBezons;48.9261\nTaibao;23.4500\nPremiá de Mar;41.4920\nBollate;45.5500\nConflans-Sainte-Honorine;48.9992\nDurazno;-33.3667\nEl Hajeb;33.6928\nBan Doi Suthep;18.7944\nVaraždin;46.3081\nKeizer;45.0028\nFalkirk;56.0011\nBugembe;0.4675\nFāraskūr;31.3297\nTromsø;69.6828\nZinacantán;16.7601\nNyköping;58.7531\nAbasolo;20.4511\nVilleneuve-Saint-Georges;48.7325\nAyutuxtepeque;13.7356\nRomainville;48.8840\nLe Plessis-Robinson;48.7811\nZaïo;34.9333\nLambaréné;-0.6883\nMission Bend;29.6948\nEsch-sur-Alzette;49.4969\nTuyên Quang;21.8167\nVrilíssia;38.0333\nCholargós;38.0000\nAdjumani;3.3772\nBərdə;40.3744\nPalaiseau;48.7145\nCasalecchio di Reno;44.4833\nDover;51.1295\nRiacho de Santana;-13.6089\nTunceli;39.1064\nKlinë;42.6167\nBucha;50.5486\nLa Presa;32.7110\nAgía Varvára;38.0000\nSchiltigheim;48.6078\nLa Puente;34.0323\nWołomin;52.3500\nTomatlán;19.9333\nEscuinapa;22.9822\nArgyroúpoli;37.9000\nChoybalsan;48.0783\nHitchin;51.9470\nShangzhuangcun;23.5226\nAm-Timan;11.0333\nRainham;51.3600\nMassamá;38.7568\nBrugherio;45.5508\nTrujillo;9.4170\nKranj;46.2333\nSpalding;52.7858\nStanton;33.8003\nAttingal;8.6800\nDighwāra;25.7443\nKikinda;45.8333\nZeghanghane;35.1500\nEast Meadow;40.7197\nBrzeg;50.8667\nThonon-les-Bains;46.3627\nLa Huacana;18.9625\nAli Sabieh;11.1500\nLimbiate;45.5972\nYihezhuang;39.1373\nVillemomble;48.8833\nBelleville;40.7950\nNorthglenn;39.9108\nHoogvliet;51.8667\nMontclair;34.0715\nMannar;8.9772\nReforma;17.8658\nGrantham;52.9180\nPandaul;26.2517\nFalun;60.6072\nKajaani;64.2311\nTenosique;17.4756\nSalto del Guairá;-24.0200\nRichmond West;25.6105\nVillagrán;20.5170\nSoteapan;18.2333\nGabú;12.2833\nSan Carlos;11.1236\nHanover Park;41.9818\nŌharu;35.1751\nCarshalton;51.3652\nRukungiri;-0.7900\nHarima;34.7167\nSchaffhausen;47.7000\nBửu Long;10.9600\nSalt;41.9761\nPāppinisshēri;11.9500\nNanchital de Lázaro Cárdenas del Río;18.0667\nAizumi;34.1266\nFoothill Farms;38.6867\nTozeur;33.9167\nBečej;45.6167\nMadukkarai;10.9057\nEwell;51.3500\nAtaq;14.5364\nFusō;35.3591\nColwyn Bay;53.2900\nMabole;7.0000\nBanī Suhaylā;31.3428\nHuyton;53.4111\nBossangoa;6.4833\nBibhutpur;25.6878\nCalumpang;14.6249\nSaint-Mandé;48.8422\nAlacuás;39.4583\nPutla Villa de Guerrero;17.0321\nSenhora da Hora;41.1860\nPrijepolje;43.5439\nPinner;51.5932\nAl Qunayţirah;33.1256\nNishihara;26.2228\nChaiyaphum;15.8056\nRiccione Marina;44.0000\nDeal;51.2226\nKendall West;25.7065\nPāppākurichchi;10.8137\nMotozintla;15.3632\nNzega;-4.2169\nPontoise;49.0516\nLetchworth;51.9780\nCernusco sul Naviglio;45.5167\nRichfield;44.8763\nMarijampolė;54.5472\nMaassluis;51.9333\nOmetepec;16.6833\nTicul;20.3953\nKearns;40.6519\nRumonge;-3.9667\nPak Tin Pa;22.3364\nHyde;53.4474\nParras de la Fuente;25.4403\nAbingdon;51.6670\nFresnes;48.7550\nSan Vicente;9.9636\nRatchaburi;13.5356\nElmont;40.7033\nPaso del Macho;18.9667\nPaso de Ovejas;19.2850\nPardigūda;17.3974\nBorehamwood;51.6578\nTit Mellil;33.5533\nZapotiltic;19.6270\nTrowbridge;51.3200\nWāris Alīganj;25.0100\nAngri;40.7333\nEbebiyín;2.1500\nEarley;51.4330\nTemple City;34.1022\nRutherglen;55.8280\nWigston Magna;52.5812\nChillum;38.9666\nButajīra;8.1208\nIxtapan de la Sal;18.8333\nGöyçay;40.6531\nPóvoa de Santa Iria;38.8620\nBangaon;25.8673\nHillerød;55.9333\nSan Miguel;14.6000\nWinchester;36.1365\nPurral;9.9594\nBuchanan;5.8808\nTancítaro;19.3384\nChur;46.8500\nClichy-sous-Bois;48.9102\nChatou;48.8897\nYehud;32.0333\nSan Juan Evangelista;17.8833\nAmecameca de Juárez;19.1238\nChāvakkād;10.5890\nSouth Miami Heights;25.5886\nLichfield;52.6820\nMangalam;10.8450\nPrestwich;53.5333\nBoende;-0.2810\nKrong Kep;10.4875\nEgypt Lake-Leto;28.0177\nMinamishiro;36.0227\nKornwestheim;48.8598\nShanawān;30.5031\nRodolfo Sánchez Taboada;31.7958\nKamenicë;42.5839\nRoanne;46.0367\nErmont;48.9922\nGostivar;41.8000\nByumba;-1.5761\nDidcot;51.6060\nLes Mureaux;48.9875\nViry-Châtillon;48.6713\nBuenaventura Lakes;28.3349\nWestmont;33.9417\nDāganbhuiya;22.9127\nLauderdale Lakes;26.1682\nEcclesfield;53.4429\nBeja;38.0333\nVršac;45.1167\nCradock;-32.1833\nAgen;44.2049\nSint-Joost-ten-Node;50.8500\nChampotón;19.3500\nAmbano;-19.8000\nTurkauliyā;26.6079\nKaippakanchēri;10.9380\nVillaricca;40.9167\nDarwen;53.6980\nChuhuiv;49.8372\nAosta;45.7333\nFontenay-aux-Roses;48.7893\nSaintard;18.8240\nKōryō;34.5500\nWest Hollywood;34.0883\nSuong;11.9167\nPaidha;2.4167\nProject Six;14.6561\nGanshoren;50.8667\nNorristown;40.1225\nManhattan Beach;33.8894\nBarangka;14.6297\nTimbuktu;16.7733\nVilliers-sur-Marne;48.8275\nVillanueva;22.3536\nPabellón de Arteaga;22.1500\nLuboń;52.3333\nRoi Et;16.0531\nMỹ Hòa;10.3655\nThiais;48.7650\nLaḩij;13.0500\nSavalou;7.9333\nGisborne;-38.6625\nSestao;43.3108\nMetamórfosi;38.0500\nKaisarianí;37.9683\nBragança;41.8067\nPhatthalung;7.5000\nSānkrāil;22.5700\nMontigny-le-Bretonneux;48.7711\nNeuchâtel;47.0000\nMidvale;40.6148\nKartārpur;31.4427\nFrattamaggiore;40.9333\nPapendrecht;51.8333\nGentilly;48.8133\nBan Bang Krang;13.8422\nMechraa Bel Ksiri;34.5600\nPallijkarani;12.9333\nSan Salvador El Seco;19.1333\nQazax;41.0933\nBria;6.5369\nSan Donato Milanese;45.4167\nWatertown Town;42.3700\nElesvaram;17.2833\nMagdalena de Kino;30.6167\nBexleyheath;51.4590\nBussum;52.2833\nBan Ang Sila;13.3364\nMaīdān Shahr;34.3972\nArtvin;41.1833\nGiv‘at Shemu’él;32.0781\nNéa Filadélfeia;38.0367\nBarguna;22.1500\nTrappes;48.7775\nVigneux-sur-Seine;48.7001\nSan Pedro de Ycuamandiyú;-24.1000\nIbrā’;22.6833\nDikhil;11.1167\nAwbārī;26.5833\nPinhal Novo;38.6310\nOcotal;13.6336\nBeidaying;39.9686\nBrighouse;53.7070\nCollege Park;38.9960\nSaint Neots;52.2280\nSanta Maria Capua Vetere;41.0833\nUniversity City;38.6657\nMotherwell;55.7839\nCiudad Sabinas Hidalgo;26.5000\nSan Rafael Abajo;9.8943\nDragash;42.0611\nNaryn;41.4333\nFair Lawn;40.9359\nLong Beach;40.5887\nSan Martin De Porres;14.4817\nQornet Chahouâne;33.9200\nEscárcega;18.6067\nMetepec;19.2511\nAldaya;39.4639\nPontypridd;51.6020\nBusia;0.4633\nKendal;54.3260\nKalasin;16.4342\nFort Liberté;19.6678\nChamtha;25.5789\nHuatabampo;26.8275\nChichester;50.8365\nSmolyan;41.5833\nIsingiro;-0.7950\nSwakopmund;-22.6833\nMontgomery Village;39.1788\nHoma Bay;-0.5167\nFair Oaks;38.8653\nMerauke;-8.4932\nNu‘ayjah;25.2525\nWishaw;55.7742\nAzogues;-2.7333\nOstróda;53.7000\nPerry Barr;52.5249\nLens;50.4322\nLa Unión;13.3369\nWest Ham;51.5340\nSwadlincote;52.7740\nBulwell;53.0010\nŠid;45.1167\nSliema;35.9122\nSingia;25.8424\nLe Chesnay;48.8203\nKararān;30.7720\nEastchester;40.9536\nBor;44.1303\nVandiyūr;9.9092\nFushë Kosovë;42.6300\nEastpointe;42.4657\nCâmpulung;45.2678\nFrome;51.2279\nUttaradit;17.6231\nBarros Blancos;-34.7542\nLidingö;59.3667\nZumpango del Río;17.6500\nShariff Aguak;6.8647\nKeşlə;40.3978\nGrigny;48.6562\nZhaoyu;37.3512\nHuntington Station;40.8446\nKampong Speu;11.4520\nKakata;6.5300\nMoscháto;37.9500\nBresso;45.5333\nVentspils;57.3906\nSaint-Cloud;48.8400\nTambo;14.5164\nSidi Smai’il;32.8167\nDandenong;-37.9810\nCiudad Sahagun;19.7714\nPuyo;-1.4861\nLohāgāra;22.0181\nNorth Providence;41.8616\nGolden Glades;25.9129\nBell;33.9801\nCity of Orange;40.7681\nHendrik-Ido-Ambacht;51.8500\nSomoto;13.4842\nBalangkas;14.7381\nMount Lebanon;40.3752\nKovin;44.7500\nKoh Kong;11.6167\nGoussainville;49.0325\nNauāgarhi;25.3443\nNagtala;22.3693\nBègles;44.8086\nSan Giuseppe Vesuviano;40.8333\nChumphon;10.4939\nCabarroguis;16.5103\nSursand;26.6500\nWik’ro;13.7833\nKericho;-0.3692\nBanlung;13.7468\nDiemen;52.3333\nLongton;52.9877\nMandera;3.9167\nFoster City;37.5553\nEnglewood;39.6468\nCurridabat;9.9160\nKaçanik;42.2467\nZiniaré;12.5833\nGlendale Heights;41.9196\nSisak;45.4872\nBromsgrove;52.3353\nPaiporta;39.4278\nBirkirkara;35.8967\nGérakas;38.0333\nBaldwin;40.6511\nPont-y-pŵl;51.7030\nDana Point;33.4733\nKyrenia;35.3403\nBent Jbaïl;33.1258\nMažeikiai;56.3167\nWest Little River;25.8571\nMukdahan;16.5431\nAdrogue;-34.8000\nVandœuvre-lès-Nancy;48.6567\nRis-Orangis;48.6537\nDedza;-14.3667\nAgblangandan;6.3667\nPothuhera;7.4199\nKurunegala;7.4833\nSan Juan;9.9609\nPérigueux;45.1929\nTimimoun;29.2500\nMontfermeil;48.9000\nWahga;31.6047\nBang Phongphang;13.6791\nTarakeswar;22.8900\nSotteville-lès-Rouen;49.4092\nSpring Valley;41.1151\nPilar;-26.8700\nSan Carlos;-34.8000\nDagestanskiye Ogni;42.1167\nWelk’īt’ē;8.2833\nBeverly Hills;34.0786\nAix-les-Bains;45.6885\nAci Catena;37.6000\nHarper;4.3667\nVilāngudi;9.9458\nChester;39.8456\nRillieux-la-Pape;45.8214\nKamateró;38.0597\nUniondale;40.7176\nCramlington;55.0820\nBarañáin;42.8000\nLiévin;50.4228\nArfoud;31.4361\nKrimpen aan den IJssel;51.9167\nMenton;43.7750\nBoscombe;50.7250\nNarapalli;17.4875\nDurango;43.1689\nKitui;-1.3667\nNethirimangalam;10.8000\nSalgótarján;48.1040\nOullins;45.7150\nHarpenden;51.8175\nSabalpur;25.6053\nHertford;51.7966\nKokhma;56.9311\nI-n-Salah;27.1936\nSoledad de Doblado;19.0447\nKiryas Joel;41.3411\nSavigny-le-Temple;48.5841\nGarfield;40.8791\nLeticia;-4.2167\nRury;51.2386\nCôte-Saint-Luc;45.4687\nDemnat;31.7311\nYverdon-les-Bains;46.7785\nFranklin Square;40.7002\nNavan;53.6528\nBourg-la-Reine;48.7796\nBou Arfa;32.5309\nÁlamo;20.9167\nDarlaston;52.5708\nMarhaura;25.9700\nBangassou;4.7374\nAnosipatrana;-18.9333\nYerres;48.7171\nVilliers-le-Bel;49.0094\nJuneau;58.4546\nChachapoyas;-6.2167\nCuitzeo del Porvenir;19.9686\nKulat;-8.8243\nRumbek;6.8060\nLes Pavillons-sous-Bois;48.9000\nEl Salto;23.7823\nSannois;48.9722\nKiryandongo;1.9525\nSan Andrés de la Barca;41.4478\nHelena;46.5965\nSaint-Laurent-du-Var;43.6680\nMaranga;25.7592\nLawndale;33.8884\nChon Buri;13.3611\nNibria;22.6100\nKampong Thom;12.7000\nMolde;62.7375\nStepney;51.5152\nActopan;20.2681\nSan Pablo;37.9629\nTeapa;17.5483\nUlundi;-28.3350\nPompeu;-19.2239\nZug;47.1681\nKaita;34.3722\nMirzāpur;24.1083\nBenetúser;39.4250\nLambersart;50.6500\nLimeil-Brévannes;48.7464\nNavolato;24.7656\nIthaca;42.4442\nRumuruti;0.2600\nAtlatlahucan;18.9350\nJérémie;18.6500\nDaventry;52.2578\nBabati;-4.2167\nShumerlya;55.5333\nGuyancourt;48.7714\nLong Branch;40.2965\nSanta Ana;14.5277\nMehdya;34.2597\nMchinji;-13.8167\nCambuslang;55.8190\nGiżycko;54.0400\nVilleneuve-la-Garenne;48.9372\nIbanda;-0.1347\nContla;19.3333\nKhorugh;37.4833\nVleuten;52.1081\nKuli;24.7366\nBanqiao;25.0143\nChato;-2.6378\nIpu;-4.3257\nShek Wai Kok;22.3753\nVoúla;37.8500\nBay Shore;40.7288\nBeldānga;23.9300\nSaranga;22.5400\nZaqatala;41.6336\nPando;-34.7167\nBlackrock;53.3015\nSan Pablo;9.9918\nİmişli;39.8697\nSiliana;36.0819\nPort Chester;41.0051\nSan Fernando;24.8504\nSzekszárd;46.3560\nRhyl;53.3210\nBir Jdid;33.3737\nCheung Chau;22.2106\nCastaños;26.7833\nWete;-5.0567\nPéfki;38.0667\nSterling;39.0052\nSan Vicente dels Horts;41.3932\nNāravārikuppam;13.1913\nKoprivnica;46.1500\nBřevnov;50.0833\nOceanside;40.6328\nLeyton;51.5700\nTuxpan;19.5661\nBurlingame;37.5859\nArcueil;48.8075\nYstad;55.4167\nAshington;55.1810\nCongleton;53.1620\nEaubonne;48.9922\nSoissons;49.3817\nMirganj;26.3638\nAïn Taoujdat;33.9333\nWest Falls Church;38.8648\nDiffa;13.3171\nLomme;50.6455\nIxhuatlancillo;18.9000\nDieppe;49.9200\nDesnogorsk;54.1500\nUdomlya;57.8833\nSabirabad;40.0128\nKayunga;0.7033\nMartorell;41.4744\nRidley;39.8854\nMégrine;36.7667\nTung Tau Tsuen;22.3334\nUngheni;47.2167\nTrípoli;37.5167\nCatarroja;39.4028\nČakovec;46.3858\nVīrapāndi;11.0625\nLongbridge;52.3950\nBregenz;47.5050\nBearsden;55.9192\nParkville;39.3832\nSiraha;26.6528\nSan Carlos;37.4982\nMelton Mowbray;52.7661\nAvellaneda;-34.6625\nSanta Paula;34.3545\nMoyale;3.5270\nQiman al ‘Arūs;29.3005\nJamay;20.2944\nFarnworth;53.5452\nTuxpan;21.8667\nSimri Bakhriārpur;25.7216\nKrabi;8.0592\nCarouge;46.1833\nMiami Lakes;25.9125\nPuerto Escondido;15.8619\nLamu;-2.2694\nKefar Yona;32.3171\nNinomiya;35.2995\nĀsosa;10.0667\nNāsriganj;25.0500\nSalyan;39.5950\nShenley Brook End;52.0090\nTomares;37.3764\nTecax;20.2019\nSan Lorenzo;37.6733\nHeemstede;52.3500\nPoint Fortin;10.1667\nBoscoreale;40.7667\nCamaligan;13.6208\nKantai;26.2142\nKętrzyn;54.0833\nJaynagar-Majilpur;22.1752\nMizumaki;33.8548\nConsett;54.8500\nBilston;52.5660\nMiacatlán;18.7722\nMount Hagen;-5.8600\nLos Reyes de Juárez;18.9267\nDaulatkhān;22.6000\nNogales;18.8167\nPakwach;2.4619\nGolo-Djigbé;6.5403\nPerunkalattu;12.9182\nKafr Baţnā;33.5000\nArmilla;37.1500\nChatan;26.3200\nGarbagnate Milanese;45.5771\nAs Sarw;31.2387\nMutsamudu;-12.1675\nCahul;45.9167\nCenon;44.8578\nBloxwich;52.6140\nGeldrop;51.4222\nTahla;34.0500\nPānchla;22.5400\nVicente López;-34.5333\nBournville;52.4299\nBillericay;51.6280\nMiddletown;41.4459\nOtjiwarongo;-20.4642\nDübendorf;47.4167\nCharentsavan;40.4097\nSai Mai;13.8882\nSubotica;46.1003\nÄnew;37.8833\nTreinta y Tres;-33.2333\nGorleston-on-Sea;52.5757\nNutley;40.8192\nStung Treng;13.5167\nMuñiz;-34.5333\nAldridge;52.6060\nEast Palo Alto;37.4671\nNewton Aycliffe;54.6200\nSaint-Sébastien-sur-Loire;47.2081\nDietikon;47.4000\nMiahuatlán;18.5667\nHakha;22.6455\nArapoti;-24.1578\nAmbohijanaka;-18.9833\nDouglas;51.8764\nVilleparisis;48.9503\nCamas;37.4020\nSucy-en-Brie;48.7697\nColonia del Sacramento;-34.4714\nUpminster;51.5557\nDalsingh Sarai;25.6680\nKyegegwa;0.4803\nDoba;8.6600\nAğdaş;40.6500\nOak Park;42.4649\nWesthoughton;53.5490\nLa Madeleine;50.6558\nNorthfield;52.4080\nHindley;53.5355\nChiavari;44.3167\nCheadle Hulme;53.3761\nCardito;40.9500\nLeiderdorp;52.1667\nMzimba;-11.9000\nNuwara Eliya;6.9667\nMāmidālapādu;15.8310\nRahway;40.6077\nMelrose;42.4556\nKatima Mulilo;-17.5039\nSaint-Gratien;48.9719\nMortsel;51.1667\nParacuaro;19.1464\nHaverhill;52.0800\nFenoarivo;-18.9333\nKings Norton;52.4072\nBačka Palanka;45.2500\nChalatenango;14.0333\nSèvres;48.8239\nVallauris;43.5805\nBalham;51.4434\nPūnch;33.7703\nLaurel;39.0949\nTaverny;49.0264\nSuisun City;38.2473\nLinden;6.0000\nEstoril;38.7042\nRocha;-34.4833\nKamphaeng Phet;16.4811\nCoulsdon;51.3211\nGuadalupe;9.9494\nRafael Delgado;18.8167\nNokha;25.1015\nNewton Mearns;55.7716\nBurbank;41.7444\nGolden Gate;26.1844\nHackney;51.5414\nVichy;46.1278\nSiquijor;9.1800\nHunucmá;21.0153\nQualiano;40.9167\nBrunoy;48.6979\nPenonomé;8.5187\nGhatāro Chaturbhuj;25.8146\nQahā;30.2833\nMponela;-13.5167\nChamps-Sur-Marne;48.8529\nEnglewood;40.8917\nSamut Songkhram;13.4097\nEast Niles;35.3683\nRyde;50.7271\nSan Pedro;9.9332\nSogrāha;25.4798\nLoyola Heights;14.6403\nKoelwār;25.5805\nGinan;35.3896\nBishop Auckland;54.6630\nApatin;45.6667\nBāruni;25.4751\nLouang Namtha;20.9500\nArmentières;50.6881\nArriaga;16.2361\nPakxan;18.3964\nManga;11.6667\nWellington;52.7001\nAltepexi;18.3676\nBuri Ram;14.9942\nÖlgiy;48.9683\nComalapa;15.6602\nClydebank;55.8997\nTixtla de Guerrero;17.5667\nMons-en-Baroeul;50.6369\nIheddadene;35.1500\nGosforth;55.0070\nÉlancourt;48.7847\nBetio;1.3500\nJālhalli;13.0333\nMissour;33.0500\nMendefera;14.8833\nBarnstaple;51.0800\nDrexel Hill;39.9495\nDunleary;53.3000\nSalua;22.6100\nMelíssia;38.0500\nPrinces Town;10.2667\nMāvelikara;9.2670\nGedera;31.8139\nFrankfort;38.1924\nWallington;51.3647\nKoulikoro;12.8833\nLe Bouscat;44.8651\nTapiales;-34.7058\nMarket Harborough;52.4775\nOcatlán;19.3167\nKočani;41.9167\nCartago;9.8667\nEṭ Ṭīra;32.2322\nTemerin;45.4167\nCormeilles-en-Parisis;48.9739\nZawyat ech Cheïkh;32.6414\nShīshgarh;28.7200\nMitú;1.1983\nRēzekne;56.5127\nKarunāgapalli;9.0544\nDroylsden;53.4828\nBuwenge;0.6503\nOrly;48.7439\nLe Grand-Quevilly;49.4072\nOegstgeest;52.1833\nAlençon;48.4306\nBergenfield;40.9236\nThornaby on Tees;54.5585\nVevey;46.4667\nZaouiet Sousse;35.7833\nVilāchcheri;9.8937\nClifton;52.9040\nErdington;52.5236\nLosino-Petrovskiy;55.8744\nJoinville-le-Pont;48.8214\nDharmapuram;8.3839\nKathu;7.9112\nOuésso;1.6136\nAlboraya;39.5000\nPlymstock;50.3569\nSāndi;27.3000\nSitrah;26.1200\nPhulpur;24.9550\nStratton Saint Margaret;51.5860\nDon Bosco;-34.7000\nMytilíni;39.1000\nDesamparados;10.0315\nEwa Gentry;21.3344\nBelmont;37.5154\nSwinton;53.5122\nDeuil-la-Barre;48.9767\nHamar;60.7945\nDroitwich;52.2670\nArcahaie;18.7718\nMasrakh;26.1054\nBiarritz;43.4800\nRenens;46.5333\nSimaria;25.4221\nSonzacate;13.7356\nSāhibpur Kamāl;25.4167\nRamotswa;-24.8667\nMililani Town;21.4465\nHarborne;52.4600\nNørresundby;57.0667\nLobatse;-25.2167\nPenarth;51.4300\nReisterstown;39.4550\nCherán;19.6833\nSombrerete;23.6333\nMuggiò;45.6000\nBatken;40.0667\nBan Bang Phun;13.9968\nSan Francisco;9.9083\nVoorschoten;52.1333\nEaston;40.6858\nBéthune;50.5303\nBongor;10.2806\nSaint-Nicolas;50.6333\nMongo;12.1837\nPortishead;51.4840\nKoper;45.5500\nXoxocotla;18.6850\nPoranki;16.4743\nChapala;20.2961\nSan Juan de Aznalfarache;37.3667\nVelenje;46.3625\nGenet;9.0500\nPānapur;25.6729\nGuastatoya;14.8539\nCiudad Altamirano;18.3583\nAshtown;53.3754\nHamtramck;42.3954\nLemon Grove;32.7331\nMadingou;-4.1536\nCaversham;51.4670\nMahārājgani;26.1075\nAlwaye;10.1167\nArar;30.9833\nMartín Coronado;-34.6000\nNsanje;-16.9167\nAl Ghayz̧ah;16.2106\nCerro Azul;21.2000\nWednesfield;52.5998\nSeriate;45.6847\nLa Huerta;14.4972\nShtime;42.4333\nItambé;-15.2450\nMonsey;41.1181\nWhitefield;53.5521\nLe Petit-Quevilly;49.4311\nStalybridge;53.4834\nGarhara;25.4407\nPiastów;52.1833\nZalingei;12.9000\nCamborne;50.2130\nKingswinford;52.4981\nSan Juan Zitlaltepec;19.7167\nWeingarten;47.8092\nPompei;40.7500\nSimria;25.9663\nKimbe;-5.5575\nOulad Tayeb;33.9598\nZabrat;40.4872\nJonava;55.0722\nLindenhurst;40.6858\nSan Buenaventura;27.0625\nŌji;34.5947\nLa Paz;-34.7617\nMaisons-Laffitte;48.9469\nBailleston;55.8474\nEnnis;52.8463\nBelmont;42.3960\nMaychew;12.7833\nChester-le-Street;54.8594\nCatió;11.2833\nNeuilly-Plaisance;48.8619\nHirrīyat Raznah;30.6028\nArbroath;56.5610\nSint-Amandsberg;51.0539\nSan Juan de Alicante;38.4014\nFarnley;53.7876\nTamiahua;21.2788\nMontigny-lès-Cormeilles;48.9944\nOadby;52.5987\nCarlos A. Carrillo;18.3667\nFrontera;18.5336\nSirkhandi Bhitha;26.6244\nTexistepec;17.9000\nSouth Pasadena;34.1103\nKościan;52.0833\nMaracena;37.2000\nMairwa;26.2322\nLitherland;53.4727\nSundararaopeta;16.8031\nStanmore;51.6180\nAcomb;53.9550\nShark;40.5569\nSaint-Ouen-l’Aumône;49.0447\nBougado;41.3370\nLeisure City;25.4935\nRodez;44.3506\nBayanhongor;46.1917\nCazones de Herrera;20.7000\nFontaine;45.1939\nBlenheim;-41.5167\nBridgeton;39.4286\nSeveso;45.6434\nChaville;48.8086\nVoinjama;8.4167\nPalm Springs;26.6348\nSheldon;52.4500\nNakhon Phanom;17.4069\nMeyrin;46.2167\nBillinghurst;-34.5667\nOrmskirk;53.5665\nFailsworth;53.5102\nAnkaraobato;-18.9000\nBedēsa;8.9000\nEysines;44.8853\nUtena;55.5000\nGeneral Emilio Aguinaldo;14.1833\nOxkutzkab;20.3028\nMalinalco;18.9483\nUkkāyapalle;14.4898\nSuphan Buri;14.4675\nSélibaby;15.1592\nDongola;19.1698\nBishopbriggs;55.9046\nLittleover;52.9060\nNewquay;50.4120\nSuitland;38.8492\nImperial Beach;32.5693\nBelper;53.0290\nMahādebnagar;24.6896\nSan Juan de Vilasar;41.5053\nLormont;44.8792\nUlaangom;49.9833\nMīt Namā;30.1453\nKarian;25.8594\nKraskovo;55.6586\nMeda;45.6667\nWest Whittier-Los Nietos;33.9759\nClevedon;51.4380\nNapindan;14.5398\nDiego Martin;10.7167\nTysons;38.9215\nLoos;50.6128\nChandlers Ford;50.9840\nNewton in Makerfield;53.4500\nHolborn;51.5204\nKemisē;10.7167\nBang Sao Thong;13.5812\nMotul;21.1667\nAtoyac de Álvarez;17.2000\nBajina Bašta;43.9731\nPenwortham;53.7400\nTorcy;48.8502\nSainte-Thérèse;45.6333\nHovd;48.0042\nSan Juan de Dios;9.8800\nKrathum Baen;13.6631\nCəlilabad;39.2089\nLodi;40.8784\nCastilleja de la Cuesta;37.3833\nMarch;52.5510\nOak Ridge;28.4727\nFarsley;53.8116\nAmnat Charoen;15.8500\nSanga;34.6002\nEl Cerrito;37.9196\nMontgeron;48.7039\nEl Tarf;36.7669\nFriern Barnet;51.6126\nOttobrunn;48.0667\nKafr Shukr;30.5470\nCoral Terrace;25.7464\nSinghāra Buzurg;25.7964\nHuntingdon;52.3364\nBispham;53.8520\nGöygöl;40.5905\nSidi Lmokhtar;31.5700\nNar’yan-Mar;67.6333\nKidsgrove;53.0874\nBambang;14.5228\nCroix;50.6781\nBelgrave;52.6566\nNorthwood;51.6010\nKanchanaburi;14.0194\nMontmorency;48.9906\nRockville Centre;40.6643\nSantiago Ixcuintla;21.8110\nKibuku;1.0375\nOnex;46.1833\nZwedru;6.0667\nTipasa;36.5942\nGuiseley;53.8750\nIves Estates;25.9632\nVélizy-Villacoublay;48.7834\nLongjumeau;48.6943\nFray Bentos;-33.1333\nDe Meern;52.0781\nCloverleaf;29.7882\nSceaux;48.7786\nSan Giovanni la Punta;37.5833\nVisby;57.6290\nPenistone;53.5250\nMill Creek East;47.8361\nCliffside Park;40.8222\nOssett;53.6800\nMaywood;33.9886\nBāgalūr;13.1328\nSanta Iria da Azóia;38.8464\nChocamán;18.9978\nSabunçu;40.4425\nKérkyra;39.6239\nCharo;19.7500\nHeredia;9.9985\nNorton;54.5890\nSainte-Foy-lès-Lyon;45.7300\nMaplewood;40.7330\nMelrose Park;41.9030\nRumphi;-11.0167\nTerrytown;29.9014\nJethuli;25.5378\nDip;26.2369\nVellalūr;10.9775\nChiconcuac;19.5500\nTlacolula de Matamoros;16.9542\nNuevo San Juan Parangaricutiro;19.4000\nFânzeres;41.1667\nPeekskill;41.2884\nMahthi;25.7281\nMaghull;53.5174\nOjinaga;29.5644\nHunasamaranhalli;13.1435\nEmiliano Zapata;17.7446\nTassin-la-Demi-Lune;45.7640\nKitajima;34.1256\nAtherton;53.5230\nJuvisy-sur-Orge;48.6883\nHacı Zeynalabdin;40.6233\nVaikam;9.7667\nCacahoatán;14.9898\nMohale’s Hoek;-30.1500\nTiverton;50.9030\nKānke;23.4348\nMorsang-sur-Orge;48.6618\nZapote;9.9203\nVukovar;45.3444\nWewak;-3.5500\nPlumstead;51.4900\nMīzan Teferī;7.0000\nMontigny-lès-Metz;49.1006\nHorwich;53.5920\nTbeng Meanchey;13.8167\nSoledad;36.4432\nMaesteg;51.6100\nBathgate;55.9024\nCarteret;40.5849\nSzczytno;53.5667\nKajiado;-1.8500\nKaga Bandoro;7.0000\nUniversity Park;32.8506\nTruro;50.2600\nHesarghatta;13.1391\nBartoszyce;54.2500\nRāja Pākar;25.7350\nEkeren;51.2833\nLe Mée-sur-Seine;48.5333\nPortalegre;39.3167\nKondalāmpatti;11.6262\nSouth Bradenton;27.4612\nYate;51.5402\nDegollado;20.4667\nNorth Guwāhāti;26.1900\nValle Nacional;17.7667\nNovo Mesto;45.8000\nCotija de la Paz;19.8100\nSouthbourne;50.7220\nCusano Milanino;45.5500\nStoke Gifford;51.5170\nFortín de las Flores;18.9000\nChinnasekkadu;13.1609\nLeek;53.1080\nEdegem;51.1500\nShārūnah;28.5667\nBāzārak;35.3128\nTequixquiac;19.9097\nHérouville-Saint-Clair;49.2044\nChevilly-Larue;48.7664\nSonāgāzi;22.8492\nRiverbank;37.7260\nBalasore;21.4942\nKirkstall;53.8160\nAbū Şīr Banā;30.9000\nDongta;38.0824\nDronfield;53.3024\nBuxton;53.2590\nSühbaatar;50.2364\nRawson;-43.3000\nRoyton;53.5660\nBaalbek;34.0063\nRothwell;53.7485\nLe Plessis-Trévise;48.8111\nAbim;2.7019\nBundibugyo;0.7125\nHornsey;51.5870\nFalmouth;50.1500\nKasamatsuchō;35.3672\nKanmaki;34.5627\nHerndon;38.9699\nChausa;25.5283\nNorth Lynnwood;47.8533\nFalagueira;38.7589\nCastelnau-le-Lez;43.6369\nLop Buri;14.8000\nPanniyannūr;11.7538\nCibitoke;-2.8886\nAllende;28.3333\nElmwood Park;41.9225\nLandover;38.9241\nGan Yavne;31.7886\nBailey's Crossroads;38.8477\nXingangli;39.9101\nCormano;45.5500\nCarlow;52.8306\nButaleja;0.9250\nChitipa;-9.7019\nSaint-Pol-sur-Mer;51.0314\nWoodlesford;53.7567\nSão João da Madeira;40.8972\nTralee;52.2675\nGarches;48.8456\nFatick;14.3333\nTuktukan;14.5280\nLa Celle-Saint-Cloud;48.8411\nSaint-Michel-sur-Orge;48.6325\nKafr Qāsim;32.1151\nRosemont;38.5478\nDammarie-lè-Lys;48.5177\nVilla Sarmiento;-34.6333\nDecatur;33.7711\nChanthaburi;12.6086\nBaabda;33.8333\nGjirokastër;40.0667\nVilleneuve-le-Roi;48.7333\nMantes-la-Ville;48.9750\nDollis Hill;51.5641\nFrattaminore;40.9500\nValmiera;57.5500\nHuskvarna;57.7919\nBakhri;25.5989\nVrbas;45.5667\nBontoc;17.0900\nAtar;20.5167\nBanī Murr;27.2272\nAl Jawf;24.2167\nCottingham;53.7822\nSaint-Maurice;48.8183\nSan Fernando;34.2886\nCaazapá;-26.2000\nRenfrew;55.8780\nTchibanga;-2.9333\nWillowbrook;33.9209\nSuchiapa;16.6220\nSenago;45.5833\nQalansuwa;32.2822\nMecayapan;18.2167\nStamford;52.6560\nHellemmes-Lille;50.6283\nOwando;-0.4833\nStellenbosch;-33.9367\nCelbridge;53.3380\nKudrovo;59.9000\nGuaranda;-1.6000\nHebburn;54.9720\nFengdeng;38.5515\nWasquehal;50.6694\nPort Laoise;53.0308\nMapastepec;15.4411\nTabount;30.8800\nLeigh-on-Sea;51.5425\nNkhata Bay;-11.6000\nAchères;48.9602\nBariārpur;25.6860\nFada;17.1833\nLe Bourget;48.9344\nKyenjojo;0.6100\nCalne;51.4380\nSibiti;-3.6858\nBehat;26.2435\nSatun;6.6147\nSaint-Cyr-l’École;48.8003\nPhetchaburi;13.1119\nAl Madāmūd;25.7333\nBāuria;22.4521\nTohoué;6.3967\nHythe;50.8690\nNakasi;-18.0667\nNovate Milanese;45.5333\nPeto;20.1256\nPeterlee;54.7600\nWatauga;32.8719\nCiudad Miguel Alemán;26.4003\nAshland;37.6942\nNerupperichchal;11.1610\nSeaham;54.8400\nTanki Leendert;12.5418\nAlfafar;39.4222\nAl ‘Azīzīyah;32.5308\nShoreham-by-Sea;50.8340\nAţ Ţafīlah;30.8400\nNogent-sur-Oise;49.2756\nMontereau-faut-Yonne;48.3853\nPakri;25.5876\nCopiague;40.6707\nMaywood;41.8798\nYonabaru;26.1995\nKiboga;0.9200\nGoodmayes;51.5631\nAllschwil;47.5500\nPalmers Green;51.6178\nLa Lucila;-34.4833\nKėdainiai;55.2833\nMohiuddīnnagar;25.7428\nSukhodilsk;48.3500\nKagadi;0.9411\nBiddulph;53.1200\nWorcester Park;51.3752\nChilly-Mazarin;48.7025\nKillingworth;55.0318\nOpfikon;47.4333\nTena;-0.9890\nNaas;53.2158\nJasmine Estates;28.2930\nSacavém;38.7944\nTeopisca;16.5425\nSunbāţ;30.8057\nHidalgotitlán;17.7833\nLingolsheim;48.5575\nCaterham;51.2803\nNyon;46.3833\nHatton;6.8897\nAarau;47.4000\nMosta;35.9097\nSelby;53.7818\nCoudekerque-Branche;51.0253\nBuyende;1.1475\nFleury-les-Aubrais;47.9312\nShōwa;35.6279\nKayanza;-2.9167\nDrapetsóna;37.9467\nMillbrae;37.5994\nDouar Toulal;33.8951\nGröbenzell;48.2000\nAbbots Langley;51.7010\nBonga;7.2667\nPeterhead;57.5091\nRonchin;50.6047\nPul-e ‘Alam;33.9808\nOgre;56.8186\nKilkenny;52.6477\nCudahy;33.9631\nWest Puente Valley;34.0513\nLami;-18.1167\nKotido;3.0061\nBellshill;55.8160\nEast San Gabriel;34.1157\nBlue Island;41.6578\nZimatlán de Álvarez;16.8667\nNtcheu;-14.8333\nDavyhulme;53.4559\nHialeah Gardens;25.8878\nTepatlaxco;19.0667\nMoyo;3.6504\nBiləsuvar;39.4583\nItaosy;-18.9167\nBedelē;8.4500\nLlandudno;53.3250\nSaint-Fons;45.7086\nMonserrato;39.2500\nQuedgeley;51.8250\nPhra Pradaeng;13.6592\nTrentola;40.9762\nSouthgate;51.6316\nOulad Fraj;32.9667\nSibut;5.7333\nAl Qays;28.4833\nBurnham-on-Sea;51.2376\nSavanna-la-Mar;18.2167\nSancoale;15.4670\nPrestatyn;53.3310\nSoisy-sous-Montmorency;48.9878\nBry-sur-Marne;48.8411\nMulanje;-16.0258\nJosé Cardel;19.3667\nCiudad Hidalgo;14.6792\nNorth Plainfield;40.6209\nDumjor;22.6400\nDukinfield;53.4739\nJēkabpils;56.4994\nMödling;48.0856\nWoodlawn;38.7332\nIschia;40.7500\nKannānkurichchi;11.6969\nAntrim;54.7173\nJarājūs;25.8681\nBafatá;12.1719\nEcclesall;53.3620\n‘Abasān al Kabīrah;31.3237\nAhfir;34.9514\nRoselle;40.6527\nPožega;45.3331\nSaint Paul’s Bay;35.9483\nPhichit;16.4431\nKhizrpur;30.5843\nMouila;-1.8639\nArtashat;39.9539\nMīrpeta;17.3200\nKrommenie;52.5000\nAldama;28.8386\nMahiari;22.5900\nFrimley;51.3143\nLoei;17.4853\nBhopatpur;26.4495\nBingley;53.8460\nSvay Pak;11.6467\nAl Bāḩah;20.0125\nPalau;27.9167\nPahsara;25.5482\nThe Crossings;25.6708\nDover;40.0019\nSanta Catarina Juquila;16.2379\nSant Just Desvern;41.3833\nVandalūr;12.8924\nMolesey;51.4010\nMbaïki;3.8833\nHillside;40.6961\nTatahuicapan;18.2500\nConnahs Quay;53.2180\nSoroca;48.1667\nArese;45.5500\nTelšiai;55.9833\nFgura;35.8725\nAyutla de los Libres;16.9000\nGreat Linford;52.0680\nCercola;40.8667\nMassapequa;40.6676\nHoughton Regis;51.9039\nZāwiyat Razīn;30.4122\nParaguarí;-25.6333\nWexford;52.3342\nSunny Isles Beach;25.9385\nSão Filipe;14.8950\nUliastay;47.7428\nVista Hermosa de Negrete;20.2717\nPhetchabun;16.4169\nMullingar;53.5224\nLiversedge;53.7067\nCentral Falls;41.8901\nSant’Antonio Abate;40.7333\nMaltby;53.4260\nÉragny;49.0172\nCran-Gévrier;45.9036\nKeynsham;51.4135\nTapalpa;19.9445\nAḑ Ḑāli‘;13.6967\nAlblasserdam;51.8702\nFâches-Thumesnil;50.5989\nAcala;16.5533\nKew Green;51.5308\nSarso;26.2333\nBourne;52.7684\nBella Unión;-30.2500\nAssebroek;51.2000\nAshtarak;40.2975\nBroughty Ferry;56.4672\nWest Carson;33.8229\nWest Rancho Dominguez;33.9057\nGhāt;24.9644\nDumra;26.5671\nBedlington;55.1330\nAl Karak;31.1833\nThalwil;47.2833\nHayesville;44.9793\nTonypandy;51.6223\nReinach;47.4833\nCoalcomán de Vázquez Pallares;18.7775\nGoroka;-6.0833\nSaint-Lambert;45.5000\nChamalières;45.7736\nAcatlán de Osorio;18.2086\nOpuwo;-18.0556\nAldo Bonzi;-34.7083\nKitagata;35.4358\nCarmelo;-34.0000\nMelegnano;45.3588\nValinda;34.0400\nMoulins;46.5647\nIjevan;40.8792\nMont-Saint-Aignan;49.4625\nSalinas de Hidalgo;22.6280\nCalella;41.6169\nDayr Abū Ḩinnis;27.7864\nMorwa;25.8030\nFour Square Mile;39.6808\nMayahaura;22.1834\nHadleigh;51.5535\nMānjha;26.4061\nNong Bua Lamphu;17.2042\nEast Barnet;51.6430\nColumbia Heights;45.0484\nMoston;53.5156\nSchlieren;47.4000\nBozoum;6.3172\nHampton;51.4220\nChennevières-sur-Marne;48.7983\nViroflay;48.8000\nTauragė;55.2522\nHighgate;51.5716\nHacıqabul;40.0433\nNorth Bellmore;40.6904\nLeicester;8.4500\nLennox;33.9380\nColne;53.8554\nGhosāi;25.5562\nLe Pecq;48.8967\nYmittós;37.9500\nWestbury;51.2600\nNilaiyūr;9.8572\nChemax;20.6550\nMaralal;1.1000\nClitheroe;53.8711\nPully;46.5167\nGhanzi;-21.7000\nVirovitica;45.8333\nSan Francisco;13.7000\nRedhill;51.2393\nBonneuil-sur-Marne;48.7742\nVauréal;49.0300\nWarminster;51.2050\nHarihans;26.1457\nSenguio;19.7539\nBischheim;48.6139\nCanelones;-34.5167\nHarpur;26.4527\nWellington;50.9755\nMalgrat de Mar;41.6456\nUkmergė;55.2500\nTécpan de Galeana;17.2500\nElmwood Park;40.9049\nSanta Lucía;-34.4525\nUtazu;34.3106\nObock;11.9667\nPajapan;18.2667\nLealman;27.8197\nLe Raincy;48.8992\nMountlake Terrace;47.7921\nAlajuelita;9.9035\nTávros;37.9667\nDevizes;51.3528\nÉcully;45.7744\nOrhei;47.3833\nDumri;25.4014\nAdliswil;47.3167\nSakri;26.2197\nWibsey;53.7672\nMurugampālaiyam;11.0806\nLa Esperanza;14.3000\nDingle;53.3774\nBoom;51.0833\nWolfratshausen;47.9133\nHorsforth;53.8370\nUlao;25.4165\nAl Hamalah;26.1497\nAd Dirāz;26.2186\nEl Astillero;43.4017\nEl Rosario;22.9922\nMcNair;38.9513\nLauālāgaon;25.4940\nEl Dorado;24.3228\nMoreton;53.4010\nMahisi;25.8540\nÖndörhaan;47.3233\nCowley;51.7330\nNéa Erythraía;38.0833\nBonnyrigg;55.8747\nLomita;33.7933\nFern Down;50.8100\nAmdjarass;16.0658\nGavarr;40.3589\nQuba;41.3597\nNeder-Over-Heembeek;50.9000\nMineola;40.7470\nStaines-upon-Thames;51.4340\nDolores;-33.5333\nTadaoka-higashi;34.4871\nDawlish;50.5810\nHyattsville;38.9613\nLangley Park;38.9897\nGalhinna;7.4161\nBasatpur;26.0011\nErumāpālaiyam;11.6324\nOstermundigen;46.9550\nWest Hempstead;40.6959\nRathfarnham;53.2988\nPachmīr;25.4077\nİsmayıllı;40.7900\nAti;13.2133\nNan;18.7833\nNew Brighton;53.4320\nShirley;51.3813\nCosham;50.8424\nĆuprija;43.9231\nPeraía;40.5000\nHigh Blantyre;55.7930\nNailsea;51.4300\nYasothon;15.7972\nEnfield Lock;51.6686\nCleckheaton;53.7250\nMānikpur;25.9100\nBeinasco;45.0167\nGobabis;-22.4333\nPaso de Carrasco;-34.8714\nKokopo;-4.3500\nZaghouan;36.4000\nBasford;52.9780\nBhogpur;31.5500\nPorthcawl;51.4800\nBanī Ḩasan ash Shurūq;27.9314\nBan Rawai;7.7707\nBubanza;-3.0833\nMilton;53.0500\nLes Clayes-sous-Bois;48.8206\nMālancha;24.6660\nArājpur;25.5197\nSenta;45.9314\nKeota;25.6440\nHarpur Pūsa;25.9667\nKimwanyi;0.4533\nSzigethalom;47.3154\nHilsea;50.8300\nGreystones;53.1440\nEldama Ravine;0.0500\nLynbrook;40.6579\nUsmānpur;24.9218\nPalisades Park;40.8472\nŁomianki;52.3333\nFloirac;44.8364\nZinvié;6.6167\nAğsu;40.5692\nAğstafa;41.1189\nDhobauli;25.4008\nKilwinning;55.6550\nHeckmondwike;53.7080\nWoodhouse;53.3580\nLuganville;-15.5333\nBaikatpur;25.4939\nRaghudebbati;22.5300\nTyldesley;53.5166\nLakhnaur;26.2020\nComrat;46.3167\nPariharpur;26.7114\nTecuala;22.4004\nSan Josecito;10.0126\nKirkland;45.4500\nLa Crescenta-Montrose;34.2322\nMaurepas;48.7628\nUpton;53.3850\nQormi;35.8794\nHaslingden;53.7050\nArvayheer;46.2661\nCiudad de Huitzuco;18.3000\nBiyahmū;29.3675\nTepoztlán;18.9853\nTlaxcala;19.3151\nKidbrooke;51.4621\nSantiago Tulantepec;20.0397\nDokolo;1.9186\nSherrelwood;39.8390\nMohan Eghu;25.4002\nMwanza;-15.5986\nCattolica;43.9667\nKotsyubyns’ke;50.4883\nNahāzāri;22.4347\nSan Rafael Arriba;9.8778\nMaldon;51.7318\nFazakerley;53.4676\nMorristown;40.7967\nUlcinj;41.9200\nPetit-Goâve;18.4314\nSeacroft;53.8222\nTidjikja;18.5500\nCiudad Guadalupe Victoria;24.4497\nAlbany;37.8897\nMahibadhoo;3.7575\nLeagrave;51.9030\nAbdullahnagar;25.7683\nRāmpur Jalālpur;25.6712\nWestmount;45.4833\nAttapu;14.8000\nFomboni;-12.2800\nVisaginas;55.5980\nBaguley;53.3990\nMorges;46.5167\nSaynshand;44.8917\nEvergreen Park;41.7213\nKapsabet;0.3333\nKavieng;-2.5667\nClayton;53.7820\nKfar Aabîda;34.2264\nSouth El Monte;34.0493\nSan Isidro;9.9737\nKalyānpur Bamaiya;25.7140\nWondelgem;51.0889\nKhusropur;25.4817\nShipley;53.8330\nWest Wickham;51.3765\nGiria;24.5167\nSligo;54.2667\nInírida;3.8653\nNorth Amityville;40.7005\nPupri;26.4708\nMajītha;31.7571\nWest Drayton;51.5043\nDhamaun;25.5999\nNéo Psychikó;38.0000\nSironko;1.2306\nEllinikó;37.8667\nHermosa Beach;33.8653\nḨawsh al Baḩdalīyah;33.4292\nGlanerbrug;52.2150\nPećinci;44.9000\nSouth San Jose Hills;34.0123\nKarahia;26.4054\nCárdenas;22.0103\nIzamal;20.9314\nLarkhall;55.7370\nBayshore Gardens;27.4345\nLezhë;41.7819\nHatch End;51.6010\nShankar Saraiyā;26.5967\nKahhalé;33.8219\nAjā;30.9414\nHednesford;52.7115\nDeysbrook;53.4290\nTelavi;41.9167\nLa Crucecita;15.7753\nKorem;12.5000\nWhickham;54.9456\nNoisiel;48.8547\nMoroto;2.5300\nHerceg Novi;42.4530\nBaharu;22.2040\nLons-le-Saunier;46.6744\nSeabrook;38.9802\nBredbury;53.4200\nBaildon;53.8510\nLa Cruz;23.9214\nMau Dhaneshpur;25.5899\nBrookfield;41.8245\nMontmagny;48.9736\nHawthorne;40.9579\nMont-Royal;45.5161\nRaiyam;26.2702\nÁgios Ioánnis Réntis;37.9667\nSolothurn;47.2167\nKamwenge;0.1861\nBaro;25.4487\nSweetwater;25.7785\nCheam;51.3600\nFerndale;42.4592\nGrajales;19.2500\nLaï;9.4000\nNetherton;52.4908\nSaltash;50.4080\nBudva;42.2881\nCanovellas;41.6176\nWest Derby;53.4338\nArnouville-lès-Gonesse;48.9872\nMacas;-2.3667\nPartick;55.8699\nMālhīpur;25.4069\nTillabéri;14.2120\nAkassato;6.5000\nSouth Hayling;50.7876\nMukhtārpur Salkani;25.6643\nBan Houayxay;20.2631\nKisoro;-1.2850\nScarborough;11.1833\nBrusciano;40.9167\nClifton;53.9721\nJagdispur;22.6500\nPemberton;53.5360\nJohnstone;55.8346\nOcteville;49.6269\nHargāwān;25.1428\nMorriston;51.6647\nƏhmədli;40.3839\nKulhudhuffushi;6.6225\nRamnagar;22.3245\nSaint-Leu-la-Forêt;49.0169\nCarrigaline;51.8166\nBinningen;47.5333\nMariana;14.6194\nJouy-le-Moutier;49.0108\nSant’Arpino;40.9575\nPljevlja;43.3567\nRoyston;52.0471\nAddlestone;51.3695\nBuikwe;0.3442\nSaint-Jean-de-la-Ruelle;47.9131\nKundal;25.7620\nLe Vésinet;48.8939\nAlbal;39.3972\nBububu;-6.1658\nBarharwa Kalān;26.5434\nKelandis;-8.5616\nHendaye;43.3586\nYoung;-32.7000\nBrackley;52.0320\nWinthrop;42.3761\nMerrifield;38.8731\nKawai;34.5783\nTlaltetela;19.3167\nDhūmnagar;26.7560\nRibeira Grande;17.1830\nMao;14.1194\nBraunstone;52.6160\nJaypul;22.7833\nEast Massapequa;40.6742\nCedar Mill;45.5355\nNorwood;39.1605\nLagawe;16.7975\nCarrières-sous-Poissy;48.9478\nMeddappakkam;12.9166\nTengampudūr;8.1158\nHazel Grove;53.3750\nMarly-le-Roi;48.8669\nLoreto;26.0128\nHūn;29.1268\nKédougou;12.5500\nAmbohidrapeto;-18.9000\nOteapan;18.0000\nBou Djeniba;32.9000\nWallisellen;47.4150\nGopālnagar;24.8063\nPuréparo de Echaíz;19.9092\nMasamagrell;39.5703\nPoint Pleasant;40.0772\nHuixcolotla;18.9219\nGreenfield;36.3242\nItāhri;25.3130\nMansa Konko;13.4667\nHarrison;40.7431\nWombwell;53.5160\nHärnösand;62.6361\nPrestwick;55.4956\nLelydorp;5.6967\nJwaneng;-24.6019\nRutherford;40.8203\nBellwood;41.8829\nClonmel;52.3539\nNorth Babylon;40.7314\nPedreiras;-4.5696\nBuckley;53.1720\nYiewsley;51.5130\nThe Mumbles;51.5730\nMangrauni;26.3667\nVicente Guerrero;23.7500\nHostomel;50.5893\nPālda;22.6800\nCerritos;22.4275\nBanstead;51.3220\nJuchique de Ferrer;19.8333\nWhittlesey;52.5580\nSiyəzən;41.0761\nŌyamazaki;34.9028\nPtuj;46.4194\nBromborough;53.3360\nVerwood;50.8815\nChertsey;51.3902\nLeposaviq;43.1000\nCountry Walk;25.6330\nSudley;38.7878\nLognes;48.8361\nBasse Santa Su;13.3167\nWest Chester;39.9601\nNorth Massapequa;40.7031\nHythe;51.0716\nMelksham;51.3710\nProgreso;-34.6650\nTarrafal;15.2780\nTsetserleg;47.4769\nBiały Kamień;50.7814\nCasandrino;40.9333\nRwamagana;-1.9500\nGoulmima;31.6944\nArenys de Mar;41.5819\nNorth Bay Shore;40.7602\nLansdale;40.2417\nAcasusso;-34.4667\nMésa Geitoniá;34.7024\nStraşeni;47.1333\nKanhauli Manohar;25.9755\nSinghwara;26.1842\nPendlebury;53.5075\nDover;40.8859\nHybla Valley;38.7484\nNantwich;53.0670\nSanta Rosalía;27.3389\nGarhpura;25.6638\nMayuge;0.4578\nKingstowne;38.7625\nPéfka;40.6500\nBeausoleil;43.7419\nPalanga;55.9167\nNorth Valley Stream;40.6840\nAmblecote;52.4600\nMontargis;47.9969\nErmúa;43.1875\nChurriana de la Vega;37.1500\nBidston;53.4020\nŻabbar;35.8772\nFranconia;38.7682\nToyoyama;35.2505\nPūluvappatti;10.9630\nSchofield Barracks;21.4936\nGornalwood;52.5230\nBillapādu;16.6364\nSan Fernando;16.8717\nLymington;50.7500\nSangre Grande;10.5667\nXaignabouli;19.2500\nEilendorf;50.7794\nHessle;53.7239\nFiladelfia;-22.3400\nCarrières-sur-Seine;48.9108\nSidi Zouine;31.6706\nLlantrisant;51.5420\nRosyth;56.0339\nLe Hochet;-20.1350\nLyantonde;-0.4069\nTarxien;35.8658\nPrachin Buri;14.0567\nHasanpur Juned;25.5915\nRock Ferry;53.3730\nErongarícuaro;19.5833\nSalaspils;56.8667\nPetite-Synthe;51.0231\nSaffron Walden;52.0220\nDogāchi;24.6195\nBois-d’Arcy;48.8014\nSuchindram;8.1544\nSing Buri;14.8911\nBarton upon Irwell;53.4760\nBurke Centre;38.7903\nAit Yaazem;33.7333\nBostonia;32.8189\nSainte-Marthe-sur-le-Lac;45.5300\nTorit;4.4081\nVynnyky;49.8156\nThornbury;51.6094\nMadera;29.1900\nTunapuna;10.6333\nEppelheim;49.4000\nSouth Orange Village;40.7491\nPorto Novo;17.0190\nPrilly;46.5333\nGines;37.3875\nTanakkangulam;9.8877\nViljandi;58.3667\nRoosevelt;40.6797\nOrange Walk;18.0750\nStapleford;52.9290\nSaatlı;39.9311\nLākho;25.4113\nRedruth;50.2330\nLucé;48.4383\nMārupe;56.9069\nDumont;40.9452\nSan Pablo Atlazalpan;19.2172\nPerivale;51.5383\nTabernes Blanques;39.5064\nPuerto Ayora;-0.7500\nEnghien-les-Bains;48.9697\nSa Kaeo;13.8206\nKidlington;51.8230\nGundūr;10.7339\nNgora;1.4575\nHuitzilan;19.9667\nVilla Unión;23.1883\nValparaíso;22.7667\nPapágos;37.9900\nTimperley;53.3870\nArmthorpe;53.5352\nBaynāla;22.5277\nAl Mālikīyah;26.1008\nLittle Hulton;53.5300\nPuttalam;8.0981\nLys-lès-Lannoy;50.6714\nSidlice;54.3471\nThônex;46.1833\nValbom;41.1333\nKhaşab;26.1833\nAnosy Avaratra;-18.8000\nKenley;51.3242\nRottingdean;50.8150\nMarlow;51.5700\nBrierley Hill;52.4795\nWhitby;54.4858\nJuan Aldama;24.2910\nBrownsville;25.8216\nSwinton;53.4877\nSāsan;25.6883\nKukës;42.0833\nHiệp Hòa;10.9289\nPathum Thani;14.0500\nHarrow Weald;51.6040\nEzequiel Montes;20.6667\nIdylwood;38.8896\nValenton;48.7450\nIselin;40.5697\nEsquimalt;48.4306\nSha Kok Mei;22.3784\nWanstead;51.5778\nLa Llagosta;41.5156\nKaliro;0.8944\nGuachochi;26.8194\nTak;16.8711\nBalaungi;30.7306\nBryn Mawr-Skyway;47.4949\nRustington;50.8102\nKamrāwān;25.6956\nTakoma Park;38.9810\nBabhani Bholwa;26.0876\nRossington;53.4759\nSudbury;51.5537\nFüzuli;39.6003\nPhayao;19.1653\nFatehpur;25.5089\nIlkley;53.9250\nDeux-Montagnes;45.5333\nSaint-Brice-sous-Forêt;48.9986\nMiahuatlán;18.2833\nHaubourdin;50.6092\nManafwa;0.9564\nLongwy;49.5197\nOvenden;53.7432\nBreyten;-26.3000\nLowton;53.4710\nPatcham;50.8640\nCanet de Mar;41.5911\nGuerrero Negro;27.9589\nChildwall;53.3950\nWattignies;50.5850\nShenley Church End;52.0220\nBusembatia;0.7750\nChāndi;25.7296\nGlassmanor;38.8181\nPlungė;55.9167\nBelsandi Tāra;25.7722\nMatam;15.6167\nRāje;26.2216\nNewport Pagnell;52.0870\nTân Vạn;10.9119\nWahiawa;21.5012\nSan Ġwann;35.9094\nMugalivakkam;13.0205\nSaint-André;50.6603\nIjra;26.3119\nBirqāsh;30.1692\nShiremoor;55.0366\nBoskoop;52.0667\nMarsabit;2.3333\nUdelnaya;55.6333\nDjambala;-2.5500\nWoodmere;40.6375\nBellaire;29.7040\nSan Nicolás de los Ranchos;19.0667\nTabhka Khās;25.6518\nIllizi;26.5080\nKretinga;55.8900\nPetersfield;51.0038\nTrstenik;43.6186\nChaddesden;52.9301\nAnta;41.0073\nCalkiní;20.3667\nBhatranha;25.9846\nAvon;48.4089\nTirumalaiyampālaiyam;10.8790\nMarib;15.4606\nMassapequa Park;40.6817\nRive-de-Gier;45.5294\nVicente Guerrero;30.7264\nEgg Buckland;50.4006\nErmita;14.5830\nEast Riverdale;38.9600\nTempoal de Sánchez;21.5167\nPrimrose;-26.1833\nPinewood;25.8697\nNacozari de García;30.3833\nPrescot;53.4286\nEl Parral;16.3662\nHillcrest Heights;38.8373\nManassas Park;38.7709\nMakokou;0.5667\nMexicaltzingo;19.2092\nLodwar;3.1167\nMontesson;48.9086\nNeubiberg;48.0833\nShirebrook;53.2048\nWest Boldon;54.9450\nĀndipālaiyam;11.0920\nSan Ignacio;17.1588\nAnzin;50.3714\nAdelphi;39.0017\nFraserburgh;57.6930\nArbon;47.5167\nNtungamo;-0.8819\nCachoeira Alta;-18.7628\nBeur;25.5690\nNew Milford;40.9337\nClayton;38.6444\nSāhit;25.5888\nRamonville-Saint-Agne;43.5461\nWalsall Wood;52.6277\nPhrae;18.1453\nKeetmanshoop;-26.5786\nBodmin;50.4660\nAstara;38.4561\nBommayapālaiyam;11.9922\nMollerusa;41.6317\nHollinwood;53.5183\nZveçan;42.9000\nStreetly;52.5770\nOulad Hamdane;32.3333\nSpitalfields;51.5166\nWollaston;52.4619\nPuerto Carreño;6.1833\nAylestone;52.6040\nPerumbakkam;12.9055\nL’Ancienne-Lorette;46.8000\nOgíjares;37.1167\nPueblo Nuevo;17.1576\nTukums;56.9667\nBull Run;38.7802\nConisbrough;53.4790\nStruga;41.1775\nDayālpur Sāpha;25.7122\nOcean Pointe;21.3145\nGreenville;5.0167\nFort Bonifacio;14.5311\nCaerfyrddin;51.8560\nThorpe Saint Andrew;52.6354\nPalmetto Estates;25.6211\nElesbão Veloso;-6.2019\nFour Corners;44.9290\nSan Juan Bautista;-26.6333\nBellmore;40.6569\nManappakkam;13.0108\nNalambūr;13.0867\nCourcouronnes;48.6239\nSendafa;9.1500\nQusar;41.4264\nSanta Cruz Amilpas;17.0667\nSan Miguel Xoxtla;19.1833\nHawick;55.4220\nOjus;25.9563\nMongat;41.4667\nNarhan;25.6941\nWolverton;52.0626\nJamira;25.5535\nLinlithgow;55.9791\nWalnut Park;33.9682\nBurslem;53.0426\nBordj Mokhtar;21.3289\nBroadwater;50.8282\nVengavasal;12.8991\nMariakerke;51.0728\nJanāi;22.7157\nCastellanza;45.6167\nPersan;49.1533\nHall in Tirol;47.2833\nTamarakulam;8.1325\nVincent;34.0983\nRanong;9.9619\nArtesia;33.8676\nMilford Haven;51.7142\nAnenecuilco;18.7781\nSenglea;35.8878\nRakvere;59.3500\nMoussoro;13.6333\nMahikeng;-25.8656\nSrbobran;45.5333\nAldama;22.9194\nSouth Houston;29.6611\nDaharia;25.5307\nAltamirano;16.7361\nNorth Arlington;40.7874\nStanford;37.4252\nGopālpur;26.1317\nBaranzate;45.5167\nMouvaux;50.7033\nNakhon Nayok;14.2069\nChojnów;51.2667\nBalaxanı;40.4617\nSedgley;52.5400\nSolaro;45.6150\nSouthborough;51.1598\nKotwāpatti Rāmpur;25.7153\nMassakory;13.0000\nNaama;33.2678\nMorangis;48.7064\nKiratpur Rājārām;25.8560\nŠilutė;55.3500\nKabugao;18.0239\nKoulamoutou;-1.1333\nLa Grange;41.8072\nVaredo;45.6000\nBarwat Pasrāin;26.7925\nWeehawken;40.7677\nMinehead;51.2038\nBačka Topola;45.8167\nAuray;47.6678\nMonte di Procida;40.8000\nBāhāgalpur;24.5934\nFloral Park;40.7227\nMuragācha;22.6900\nBacalar;18.6769\nCoseley;52.5500\nChard;50.8728\nBuckingham;51.9950\nTullamore;53.2667\nKerugoya;-0.5000\nKinkala;-4.3614\nLomma;55.6667\nBela;25.8103\nSutton on Hull;53.7806\nParkway;38.4993\nSouth River;40.4455\nOttaikkālmantapam;10.8827\nArpajon;48.5903\nWezembeek-Oppem;50.8333\nAl Ḩazm;16.1642\nĀlampur Gonpura;25.5404\nKraainem;50.8619\nMidsomer Norton;51.2842\nSimri;26.1639\nBelwāra;25.7443\nMilngavie;55.9421\nAscensión;31.0928\nFleury-Mérogis;48.6294\nÁngel R. Cabada;18.5969\nMontévrain;48.8753\nCăuşeni;46.6333\nCorsham;51.4340\nChhapra;26.4005\nFontenay-le-Fleury;48.8136\nAlotau;-10.3167\nSouthwick;50.8360\nLye;52.4590\nVilla Corzo;16.1848\nBarentu;15.1167\nAyodhyāpattanam;11.6755\nBijelo Polje;43.0400\nAnadyr;64.7333\nThatto Heath;53.4352\nParihāra;25.5378\nMaliana;-8.9917\nEriceira;38.9620\nRichmond;-41.3333\nTenango del Aire;19.1575\nAleg;17.0500\nParihārpur;26.4026\nNew Cassel;40.7602\nIsla Mujeres;21.2084\nBlunsdon Saint Andrew;51.6100\nNeykkārappatti;11.6225\nSisai;26.1899\nAsperg;48.9000\nAltay;46.3728\nBartica;6.4000\nWhakatane;-37.9600\nTitel;45.2047\nRahui;25.2728\nGlenmont;39.0698\nBrownhills;52.6470\nStone Ridge;38.9294\nWestbury;40.7599\nLwengo;-0.3911\nSukhothai;17.0000\nPatālia;25.6600\nVilla Juárez;27.1278\nIsla Vista;34.4128\nMahespur;24.8616\nAllestree;52.9519\nEckington;53.3080\nWhite Center;47.5086\nÉpinay-sous-Sénart;48.6931\nDesri;25.6691\nHoyland Nether;53.4985\nJaltenango;15.8725\nChepstow;51.6420\nMaqsūda;26.2410\nGiffnock;55.8051\nFoammulah;-0.2932\nPeshkopi;41.6833\nTarguist;34.9500\nLa Palma;33.8504\nCharābidya;22.3271\nWallingford;51.5990\nUthai Thani;15.3800\nSeaford;40.6678\nCastle Bromwich;52.5050\nVaires-sur-Marne;48.8742\nEdineţ;48.1667\nBillère;43.3025\nNuevo Ideal;24.8875\nSarmastpur;25.9490\nHévié;6.4167\nGreat Driffield;54.0050\nCherryland;37.6792\nChilwell;52.9160\nMarungūr;8.1721\nSaucillo;28.0333\nEl Carmen;13.7167\nSeïada;35.6700\nTari;-5.8489\nSedaví;39.4271\nGombe;0.1811\nOrmesby;54.5492\nKhānpur;25.8572\nPrinceton Meadows;40.3347\nGhordaur;25.7089\nNohsa;25.5653\nVoisins-le-Bretonneux;48.7583\nSanta María Jalapa del Marqués;16.4401\nPhra Samut Chedi;13.5976\nLa Magdalena Chichicaspa;19.4181\nSchwyz;47.0167\nSaint Budeaux;50.4033\nKürdəmir;40.3383\nBlundellsands;53.4800\nMountain Ash;51.6814\nChandi;22.3503\nRayón;19.1481\nSaint-Max;48.7011\nCuencamé de Ceniceros;24.8667\nKapchorwa;1.4000\nEarlestown;53.4500\nSnaresbrook;51.5870\nLa Tour-de-Peilz;46.4500\nDzuunmod;47.7069\nKnutsford;53.3025\nEl Fuerte;26.4214\nKamnik;46.2257\nGoh;24.9845\nCadereyta;20.7000\nKanungu;-0.8969\nZombo;2.5131\nSanta Venera;35.8897\nSanta María Huazolotitlán;16.3041\nSanta Ana;9.9320\nAinsdale;53.6021\nJalpura;25.4862\nKottāram;8.1188\nAsbury Park;40.2226\nNamanga;-2.5500\nSaktipur;23.8640\nRadviliškis;55.8000\nNorridge;41.9637\nHarper Woods;42.4390\nParilla;17.9119\nKarrānah;26.2306\nBou Fekrane;33.7667\nMarauatpur;25.6165\nZubin Potok;42.9167\nSanta Ana;30.5406\nHaddon;39.9063\nBerkley;42.4986\nChāndpura;25.4966\nHolyhead;53.3090\nParkstone;50.7100\nPhôngsali;21.6833\nCalvizzano;40.9000\nChinsali;-10.5522\nHazel Park;42.4619\nCampbelltown;-34.0733\nLas Veredas;23.1500\nSukurhutu;23.4433\nKenmore;42.9646\nWordsley;52.4830\nLiestal;47.4667\nTrbovlje;46.1500\nEscuintla;15.3193\nPacific Grove;36.6188\nChêne-Bougeries;46.1833\nParo;27.4333\nPānāpur Langa;25.7230\nSarpavaram;17.0102\nJasauli;26.4996\nCulcheth;53.4517\nCromer;52.9310\nNorth New Hyde Park;40.7460\nSākhmohan;25.6325\nEcublens;46.5276\nLibertad;-34.6333\nLerma;19.8000\nQuthing;-30.4001\nKidal;18.4389\nGwanda;-20.9389\nWest Park;25.9840\nSan Pedro Jicayán;16.4167\nMasallı;39.0342\nMasho Khel;33.9103\nFayrōz Kōh;34.5225\nNalerigu;10.5333\nGaurihar Khāliqnagar;25.9356\nLeopold;-38.1892\nSouth Farmingdale;40.7175\nWoolton;53.3740\nKatarmāla;25.5036\nEscaldes-Engordany;42.5089\nLeāma;26.2140\nBaucau;-8.4667\nHalawa;21.3753\nForécariah;9.4300\nKillamarsh;53.3205\nWest University Place;29.7157\nHuétor Vega;37.1500\nCanegrate;45.5667\nSisauna;26.1320\nSaint-André-les-Vergers;48.2797\nHarpur Bochaha;25.5919\nHighland Park;40.5006\nBhabānipur;24.7153\nBandlagūda;17.3543\nParsa;25.7721\nLe Grand-Saconnex;46.2333\nCēsis;57.3167\nSandridge;51.7808\nFairview;40.8182\nPort Antonio;18.1757\nBegampur;22.3705\nJesenice;46.4366\nAbergavenny;51.8240\nEl Menzel;33.8389\nWarsop;53.2000\nKotia;26.2750\nMarabella;10.3000\nGourock;55.9538\nChiautla de Tapia;18.3000\nOlton;52.4377\nSan Josecito;9.8885\nTadjourah;11.7833\nTierra Colorada;17.1656\nBoumia;32.7228\nOzurgeti;41.9406\nForres;57.6080\nWhitefish Bay;43.1131\nEisenstadt;47.8500\nBandwār;25.5093\nHwlffordd;51.8000\nGarh Sisai;25.6253\nOulad Ayyad;32.3333\nAhirauliyā;26.5091\nVilla Unión;23.9667\nBelobaka;-15.6833\nKoog aan de Zaan;52.4667\nSandown;50.6551\nBottesford;53.5521\nRorschach;47.4667\nBerriozar;42.8361\nLake Stickney;47.8733\nLa Pointe;19.9500\nDebar;41.5250\nSonoita;31.8614\nBang Phlat;13.8247\nBargoed;51.6900\nLykóvrysi;38.0667\nSalida;37.7083\nProgreso;32.5842\nHambantota;6.1244\nParlier;36.6087\nDjanet;24.5550\nBiassono;45.6333\nOyam;2.2350\nMaxcanú;20.5833\nCoacoatzintla;19.6500\nDeodha;25.7815\nMuttanampālaiyam;11.0845\nMāmidipalli;17.2516\nMagugpo Poblacion;7.3821\nEwa Beach;21.3181\nEscazú;9.9160\nHœnheim;48.6242\nSahtāh;25.8567\nTrentham;52.9663\nNaxxar;35.9150\nSigulda;57.1500\nMalvinas Argentinas;-31.3697\nBusumbala;13.3333\nSoalandy;-18.9903\nDhanupra;25.6992\nPincourt;45.3833\nCowley;51.5280\nBaruun-Urt;46.6814\nKey Biscayne;25.6908\nAr Rommani;33.5333\nKemp Mill;39.0412\nFalls Church;38.8847\nAmtala;22.2200\nNinga;25.4616\nWilkinsburg;40.4442\nMuna;20.4800\nStiring-Wendel;49.2000\nCarnoustie;56.5010\nLemon Hill;38.5172\nTonyrefail;51.5840\nEast Rancho Dominguez;33.8949\nBariārpur Kāndh;25.9391\nClarkston;33.8117\nBrislington;51.4316\nHusepur;26.4609\nUcar;40.5183\nBharokhara;25.8655\nBilauri;25.7703\nCandelaria;18.1835\nChicago Ridge;41.7034\nSantiago Tangamandapio;19.9500\nAphaur;25.8828\nThames Ditton;51.3890\nCudworth;53.5784\nKavaratti;10.5626\nArdmore;40.0033\nWealdstone;51.5957\nBirsfelden;47.5533\nMarsaskala;35.8625\nNewport;39.0856\nNorth Fair Oaks;37.4754\nDasraha Bhogrājpur;25.5691\nVellānūr;13.1500\nMathila;25.4715\nNeftçala;39.3586\nSaidpur;33.7421\nForest Park;41.8683\nHaydock;53.4678\nVillars-sur-Glâne;46.7833\nJamsaut;25.6100\nVille-d’Avray;48.8261\nPākkam;13.1436\nBhainsahi;26.4404\nGillingham;51.0375\nLambeth;51.4900\nLinslade;51.9243\nBelwa;26.1056\nZefýri;38.0667\nSai Kung Tuk;22.3814\nNor Hachn;40.3019\nSarafand;33.4517\nHanzviur;34.1400\nEdgewater;40.8237\nFlower Hill;39.1676\nEast Cleveland;41.5317\nKaabong;3.5200\nStreet;51.1235\nOakham;52.6705\nBan Bang Sai;13.3847\nYuscarán;13.9417\nRaynes Park;51.4033\nVelivennu;16.8443\nNegēlē;5.3167\nHawaiian Gardens;33.8304\nBukedea;1.3475\nWillowick;41.6342\nCanatlán;24.5200\nGladeview;25.8395\nKhāngāon;25.5146\nKronshagen;54.3333\nSan Pedro Ixcatlán;18.1500\nRāmpur Kudarkatti;26.0672\nBharra;25.4398\nBhālpatti;26.1853\nPierre;44.3748\nAstley;53.5008\nFederal Heights;39.8651\nCetinje;42.3800\nRáth Tó;53.5060\nTalant;47.3364\nOlhanpur;25.8855\nMayilādi;8.1550\nCollingswood;39.9160\nSjenica;43.2667\nKarmauli;26.4502\nBishopstoke;50.9679\nBegampur;22.7400\nCayey;18.1150\nAkhaltsikhe;41.6389\nKippax;53.7669\nDéville-lès-Rouen;49.4697\nBāgnān;22.4700\nBāwāli;22.4150\nRyhope;54.8679\nKalinagar;22.4383\nPelsall;52.6310\nSan Gregorio di Catania;37.5667\nNatshal;22.1957\nHuntington;38.7916\nBirchington;51.3770\nRoselle Park;40.6653\nBhansia;26.0992\nBelauncha;26.2124\nUniversity Heights;41.4948\nChaital;22.5106\nNao Kothi;25.5196\nEtchojoa;26.8667\nKuressaare;58.2500\nDugny;48.9536\nStocksbridge;53.4780\nRisca;51.6080\nFlixton;53.4470\nLarbert;56.0229\nGonzález;22.8281\nDishāshah;28.9831\nVillecresnes;48.7214\nChauki;25.4573\nPlav;42.6000\nPapraur;25.4413\nMīt Damsīs;30.8267\nBexley;39.9650\nWaimalu;21.3913\nSaint Ann’s Bay;18.4360\nPietà;35.8931\nTovuz;40.9922\nWestmont;39.9082\nPantelhó;17.0067\nErmoúpoli;37.4333\nAkil;20.2656\nSultānpur;25.6214\nSan Luis de La Loma;17.2714\nAscot;51.4084\nHemiksem;51.1500\nKonand;25.1729\nKibiito;0.4775\nBorsbeek;51.2000\nBar;42.1000\nShorewood;43.0913\nKumi;1.4608\nLemington;54.9720\nNdélé;8.4092\nBithān;25.6954\nÉpinay-sur-Orge;48.6739\nHenley on Thames;51.5357\nOlympia Heights;25.7240\nRoyston;53.6100\nAng Thong;14.5925\nShtërpcë;42.2333\nCraponne;45.7453\nChichihualco;17.6550\nAberaman;51.7000\nHolbeach;52.8037\nTavistock;50.5450\nLiskeard;50.4536\nNew Silksworth;54.8710\nBradford-on-Avon;51.3470\nMesrā;23.4339\nLittle Falls;40.8762\nHirnyk;48.0500\nChatteris;52.4560\nWyandanch;40.7496\nMännedorf;47.2553\nTres Ríos;9.9072\nHorsell;51.3286\nShāhpur Baghauni;25.8831\nNew Carrollton;38.9656\nRahiār Kunchi;25.8627\nIndiana;40.6220\nPaura Madan Singh;25.7917\nImsida;35.8978\nNilavārappatti;11.6081\nMarton;54.5372\nChanteloup-les-Vignes;48.9783\nShepton Mallet;51.1930\nWicklow;52.9779\nĐà Nẵng;16.0748\nSeonār;25.4142\nBoudenib;31.9497\nWhitchurch;52.9690\nPanamarattuppatti;11.5620\nCapodrise;41.0500\nPonteland;55.0480\nLa Grange Park;41.8308\nSamayanallūr;9.9792\nCastlebar;53.8608\nAyapango;19.1264\nBuckhurst Hill;51.6320\nSinop;42.0267\nMānsinghpur Bijrauli;25.7552\nStanwell;51.4570\nOrmesson-sur-Marne;48.7858\nNewport;52.7691\nEccleston;53.4539\nDhāmua;22.2875\nBeaumont;45.7517\nBothell East;47.8064\nKoila Dewa;26.4079\nTetela del Volcán;18.8931\nCupar;56.3200\nDudhpura;25.7964\nBardīha Turki;25.8059\nPlatón Sánchez;21.2833\nArniya;25.7150\nPachāhi;26.1932\nKaith;25.4776\nMaromme;49.4819\nDomžale;46.1394\nStranraer;54.9020\nGżira;35.9050\nKumharsan;25.6421\nLathasepura;25.8131\nBāzid Chak Kasturi;25.6559\nSomnāha;25.9518\nTixkokob;21.0022\nLongbenton;55.0000\nCorinda;-27.4833\nAcanceh;20.8133\nSečanj;45.3667\nAvocado Heights;34.0391\nSwieqi;35.9208\nCoatesville;39.9849\nKingston;41.2652\nMudichchur;12.9110\nCarpinteria;34.3962\nMariental;-24.6333\nDrochia;48.0333\nSahuli;26.1118\nŻebbuġ;35.8731\nWoodland Park;40.8904\nDelémont;47.3667\nAdalpur;26.1910\nAmwa Majhār;26.7362\nNieuw Nickerie;5.9333\nMaili;21.4133\nMeliana;39.5272\nLydney;51.7286\nMannarai;11.1172\nBarnoldswick;53.9147\nPajacuarán;20.1178\nMontigny-en-Gohelle;50.4278\nLa Trinitaria;16.1191\nDruskininkai;54.0167\nPhulmālik;25.4132\nJarville-la-Malgrange;48.6694\nKibuye;-2.0617\nRidgefield Park;40.8543\nRangvāsa;22.6435\nHandsworth;53.3700\nTubmanburg;6.8667\nNovi Bečej;45.6000\nAmolatar;1.6350\nKargahiā Purab;26.7887\nKampel;22.6167\nBocas del Toro;9.3403\nChettipālaiyam;10.9125\nPongalūr;10.9654\nEvington;52.6210\nCrosne;48.7147\nNārsingi;17.3876\nSan Ignacio Cohuirimpo;27.0500\nWilnecote;52.6081\nInverurie;57.2800\nCuatro Ciénegas de Carranza;26.9861\nSan Juanito;27.9700\nLaunceston;50.6370\nBhawānīpur;26.2385\nSteinbach am Taunus;50.1667\nPuck;54.7000\nSerere;1.5000\nNova Gorica;45.9558\nŻejtun;35.8556\nHellesdon;52.6485\nBishunpur;25.8029\nBroadstone;50.7605\nRāmnagar Bankat;26.7595\nMarquette-lès-Lille;50.6758\nAbasingammedda;7.3167\nÄlta;59.2500\nSteinkjer;64.0148\nNa Sceirí;53.5828\nTlahualilo de Zaragoza;26.1083\nPerūr;10.9752\nLittleport;52.4568\nGhanīpur Bejha;25.9281\nQutubpur;25.6279\nPelham;40.9000\nCroissy-sur-Seine;48.8778\nAlagappapuram;8.1468\nNairn;57.5860\nSugarland Run;39.0309\nGaillard;46.1850\nPsychikó;38.0108\nProcida;40.7667\nIaloveni;46.9500\nHome Gardens;33.8783\nMokarrampur;26.2176\nRāmpur Rajwa;25.7057\nDumri;25.7350\nValga;57.7833\nNaranja;25.5164\nFords;40.5359\nCornelius;45.5188\nObo;5.4000\nDaru;-9.0833\nTilehurst;51.4579\nSrîfa;33.2814\nLamphun;18.5864\nCaudebec-lès-Elbeuf;49.2808\nIfield;51.1234\nGrover Beach;35.1204\nMulti;22.2847\nChilmil;25.4563\nRed Bank;40.3480\nSītalpur;25.7764\nPierre-Bénite;45.7036\nTottington;53.6130\nTinqueux;49.2500\nAmesbury;51.1730\nCuapiaxtla de Madero;18.9167\nValadares;41.0937\nRokiškis;55.9667\nMahamda;25.8108\nSan Antonio;9.9781\nEmeryville;37.8382\nShildon;54.6300\nAţ Ţūr;28.2417\nMauji;25.6585\nChai Nat;15.1872\nChāndpur;22.4368\nNayānagar;25.7465\nPhaphot;25.6817\nHelston;50.1000\nSolindābād;25.8463\nMorsand;25.9335\nSāhāpur;22.5200\nAberbargoed;51.6968\nKanoni;0.1728\nChoppington;55.1450\nKotor;42.4300\nSalisbury;40.7454\nCiudad Tula;23.0000\nGhoswāri;25.4687\nPipra Dewās;25.4636\nZaandijk;52.4667\nSihma;25.6992\nSan Ġiljan;35.9186\nHînceşti;46.8167\nAttard;35.8928\nChapeltown;53.4620\nTərtər;40.3450\nDumri;25.4750\nKrapina;46.1600\nNueva Palmira;-33.8833\nLas Tablas;7.7667\nSîngerei;47.6333\nSohāna;30.6833\nCulfa;38.9558\nAvranches;48.6844\nSānrha;25.7979\nGorey;52.6770\nCaldicot;51.5910\nQufādah;28.5812\nTlalixtac de Cabrera;17.0667\nSan Marzano sul Sarno;40.7697\nTeotlaltzingo;19.2326\nIgny;48.7422\nEncamp;42.5361\nFosses;49.0981\nThorigny-sur-Marne;48.8788\nTramore;52.1588\nMasar;25.5577\nSimarwāra Durgāpur;25.8520\nSomerville;40.5696\nBulgan;48.8119\nDunbar;56.0027\nKoini;26.4226\nKaithinia;26.2317\nLālganj;25.7297\nMeghaul;25.6400\nSan Gregorio Atzompa;19.0224\nEttimadai;10.8911\nTaraclia;45.9000\nZamora;-4.0692\nWarfield;51.4420\nGanvié;6.4667\nMuthābana;24.9203\nNorth Merrick;40.6871\nAnáhuac;28.4800\nVõru;57.8486\nBeyləqan;39.7756\nMahisānrh;25.7358\nMandalgovĭ;45.7667\nPatchogue;40.7621\nCesa;40.9667\nKondaparti;17.9219\nGlenfield;52.6491\nHithadhoo;-0.6094\nMāmobihāt;26.1466\nRāmkali;22.3351\nAurāhi;26.0355\nBroughton Astley;52.5278\nKhunays;35.7122\nMālīnagar;25.9967\nAmgachia;22.4156\nBararam;26.1572\nDhangaraha;26.0204\nKilchberg;47.3247\nNaruār;26.2388\nKanchanpur;25.6636\nAmatlán de los Reyes;18.8457\nXicoténcatl;22.9958\nGa-Kgapane;-23.6490\nHakkila;60.2869\nChicalim;15.3994\nAlum Rock;37.3694\nRío Grande;18.3789\nQalāt;32.1061\nManatí;18.4283\nGangāpur Athar;25.8214\nEybens;45.1486\nTekit;20.5322\nSikandarpur;25.3256\nBamaiya Harlāl;25.6664\nAssomada;15.0960\nOuédo;6.4833\nAioun;16.6667\nChoix;26.7061\nRogerstone;51.5906\nSallaumines;50.4197\nNewman;37.3156\nFăleşti;47.5722\nNeuville-lès-Dieppe;49.9267\nJagatpur;26.3738\nTzucacab;20.0708\nChuy;-33.6964\nFerney-Voltaire;46.2558\nHasbrouck Heights;40.8618\nCaño Martin Peña;18.4309\nBarwell;52.5682\nIkkarai Boluvāmpatti;10.9669\nSouth Normanton;53.1070\nKilsyth;55.9800\nFloreşti;47.8933\nIzola;45.5344\nMalaudh;30.6333\nGamharia;26.0561\nCimişlia;46.5167\nHorbury;53.6595\nLatifpur;22.3777\nRiver Edge;40.9269\nRobertsport;6.7500\nKhānpur Khairanti;26.1456\nSouth Miami;25.7079\nBougival;48.8650\nOtumba;19.6989\nLlantwit Major;51.4062\nSemri;25.6246\nKaithwār;26.1678\nClayton le Moors;53.7750\nHathaura;26.1744\nNakasongola;1.3150\nYeadon;39.9325\nBoxley;51.3024\nMalaimāchchampatti;10.9058\nCoahuitlán;20.2667\nRabat;35.8817\nJahāngīrpur Sālkhani;25.8335\nCam;51.7011\nUniversity of California-Santa Barbara;34.4151\nSerravalle;43.9694\nTelkathu;26.1124\nMurska Sobota;46.6667\nHārua;24.5249\nOdayārpatti;11.6663\nWidnau;47.3997\nByureghavan;40.3147\nKhundāwandpur;25.6689\nUkhāi Purbāri Patti;26.2471\nVanimo;-2.6667\nBan Son Loi;13.9122\nBiltine;14.5275\nŻurrieq;35.8292\nBhachhi;26.3404\nThakurainia;26.2098\nHiguera de Zaragoza;25.9500\nBures-sur-Yvette;48.6967\nGuttenberg;40.7928\nWallington;40.8536\nMamnūr;17.9092\nElektrėnai;54.7861\nMirzānagar;25.7726\nRossmoor;33.7887\nNawānagar;25.3861\nNorth Wantagh;40.6983\nBradwell;52.0500\nBound Brook;40.5676\nBerane;42.8400\nChalkāri;23.7582\nKundiawa;-6.0167\nKarsaut;26.1298\nAn Cabhán;53.9910\nNāzira;22.2180\nSignal Hill;33.8030\nBalzan;35.8981\nŠkofja Loka;46.1672\nLa Riviera;38.5683\nBol;13.4600\nBhāsaula Dānāpur;25.5509\nOak Hills;45.5405\nEpalinges;46.5500\nLa Junta;28.4778\nLe Plessis-Bouchard;49.0028\nSidney;48.6506\nGurmia;25.8190\nPontardulais;51.7100\nSāgarpur;26.2306\nBhadwār;25.5576\nAvanāshipālaiyam;10.9696\nPahārpur;25.7225\nChilón;17.1055\nMahadipur;24.8566\nBeauchamp;49.0139\nSakaddi;25.5771\nCasapulla;41.0667\nLeven;56.1950\nHalachó;20.4764\nWilton Manors;26.1593\nLe Portel;50.7067\nVaucresson;48.8425\nRadstock;51.2930\nNaifaru;5.4444\nClawson;42.5367\nSanniquellie;7.3622\nIarpur;22.2998\nWeißenthurm;50.4144\nSibkund;25.3041\nMariehamn;60.1000\nSandiacre;52.9230\nGaurdah;25.7097\nQax;41.4225\nPachrukhi;26.1593\nFatehpur Bāla;25.8338\nHillcrest;35.3790\nShanhūr;25.8604\nGroslay;48.9867\nKatrīdih;25.0829\nJasauli Patti;26.4912\nHazrat Shiura;25.5976\nḨadībū;12.6500\nCherry Creek;39.6094\nBan Chang Phuak;18.8032\nSuffern;41.1138\nGlastonbury;51.1485\nPiedmont;37.8225\nPérenchies;50.6681\nRāmpur;25.9256\nBonhill;55.9830\nSant’Agnello;40.6294\nBucksburn;57.1770\nView Park-Windsor Hills;33.9955\nCullercoats;55.0330\nKahla;26.3747\nNālikkalpatti;11.6021\nSaraunja;25.7690\nTekpanja;22.2101\nTorre Boldone;45.7167\nLohna;26.2314\nSan Juan Ixcaquixtla;18.4500\nKandiyankovil;11.0147\nAkjoujt;19.7500\nAucamville;43.6686\nÉvian-les-Bains;46.4006\nLongford;53.7270\nMadhuban;25.8838\nRye;50.9500\nGadaul;26.1287\nMagas;43.1667\nNorth Lindenhurst;40.7072\nAmiāwār;25.0405\nCospicua;35.8822\nChānp;26.1951\nTataltepec de Valdés;16.3064\nDayr as Sanqūrīyah;28.4833\nSummit;41.7877\nRezina;47.7333\nLoikaw;19.6742\nVille-la-Grand;46.2022\nHucclecote;51.8500\nGreat Neck;40.8029\nChak Pahār;25.7986\nHetanpur;25.5821\nEast Bakersfield;35.3832\nBedwas;51.5926\nPaola;35.8728\nChak Habib;25.7238\nLansdowne;39.9408\nNorthbrook;39.2467\nMontmeló;41.5547\nWaipio;21.4143\nAnenii Noi;46.8833\nBrevik;59.3500\nReinosa;43.0019\nLittle Ferry;40.8464\nStrumica;41.4375\nKaruzi;-3.1000\nBakhra;26.0333\nVinica;41.8828\nAzīzpur Chānde;25.7932\nBeni Abbès;30.0800\nBrimington;53.2580\nChakla Waini;25.9081\nProbištip;41.9936\nNijgaon Parānpur;25.1559\nWest Auckland;54.6318\nSānwas;25.1795\nAmuru;2.8186\nCălăraşi;47.2500\nJõhvi;59.3575\nKanyākulam;8.2012\nPokhraira;26.0711\nAhumada;30.6186\nBirżebbuġa;35.8256\nPattanam;10.9808\nLázaro Cárdenas;28.3897\nAtherstone;52.5787\nTokatippa;16.2836\nDaşkəsən;40.5244\nSalinas;-34.7833\nKralendijk;12.1444\nGraçanicë;42.6000\nWestwood Lakes;25.7237\nBela Crkva;44.8975\nRoatán;16.3230\nTimberlane;29.8781\nDarby;39.9210\nWest Haverstraw;41.2063\nAyotoxco de Guerrero;20.1000\nCitrus;34.1160\nDel Aire;33.9167\nKirundo;-2.5900\nAl Maḩwīt;15.4694\nAda;45.8000\nJurbarkas;55.0833\nCharuānwān;25.1348\nSiparia;10.1333\nTrat;12.2417\nMellieħa;35.9564\nInwood;40.6219\nHaapsalu;58.9394\nLascano;-33.6739\nPotomac Park;35.3636\nSarnen;46.8961\nCoamo;18.0765\nPhangnga;8.4644\nSantana;0.2583\nBiržai;56.2000\nChoyr;46.3606\nOrdubad;38.9081\nBukomansimbi;-0.1667\nOlaine;56.7833\nWatervliet;42.7243\nButha-Buthe;-28.7833\nNaftalan;40.5067\nBududa;1.0100\nWoodlyn;39.8774\nAltdorf;46.8667\nVilkaviškis;54.6500\nSamux;40.7700\nNew Hyde Park;40.7323\nRichmond Heights;25.6347\nKwale;-4.1744\nLa Massana;42.5444\nBirao;10.2940\nMuyinga;-2.8500\nNeves;0.3592\nBrookdale;40.8348\nNisporeni;47.0833\nKuldīga;56.9667\nEast Rockaway;40.6432\nVrnjačka Banja;43.6236\nNenagh;52.8632\nMojkovac;42.9600\nWest Perrine;25.6061\nĦamrun;35.8861\nBlacklick Estates;39.9049\nMaywood;40.9025\nCapitola;36.9773\nRoslyn;40.1311\nKanjiža;46.0667\nBrentwood;40.3734\nEast Whittier;33.9244\nLake Hiawatha;40.8816\nNueva Ocotepeque;14.4333\nCastillos;-34.1989\nBauska;56.4083\nWood-Ridge;40.8508\nAugust;37.9797\nCharter Oak;34.1025\nStonegate;39.5357\nKatakwi;1.9150\nBulisa;2.1217\nKeansburg;40.4469\nJacinto City;29.7663\nLincoln Village;39.9532\nPájaros;18.3610\nMakamba;-4.1333\nBasco;20.4500\nRaseiniai;55.3667\nSaldus;56.6667\nTshabong;-26.0200\nOrange Cove;36.6211\nBoulder Hill;41.7113\nAuki;-8.7667\nTivat;42.4300\nPostojna;45.7759\nWest Athens;33.9235\nThinadhoo;0.5302\nPedra Badejo;15.1370\nBladensburg;38.9424\nAiea;21.3865\nRiver Road;44.0833\nBois-des-Filion;45.6667\nKirkwall;58.9810\nRožaje;42.8400\nHani i Elezit;42.1475\nNew Square;41.1410\nPlainedge;40.7241\nSamdrup Jongkhar;26.8000\nKolonia;6.9639\nNtchisi;-13.3667\nVrhnika;45.9624\nMarina del Rey;33.9765\nLogatec;45.9167\nSouth Amboy;40.4852\nGizo;-8.1056\nRîşcani;47.9572\nSant Julià de Lòria;42.4650\nLeisure World;39.1023\nLeonia;40.8638\nVictoria;36.0436\nKasane;-17.8167\nWangdue Phodrang;27.4833\nSeven Corners;38.8658\nŽabalj;45.3667\nEvinayong;1.4500\nCoral Hills;38.8706\nSiġġiewi;35.8542\nGrosuplje;45.9551\nStans;46.9500\nDangriga;16.9667\nAmuria;2.0300\nThyolo;-16.0667\nConshohocken;40.0772\nEwo;-0.8667\nLerwick;60.1550\nManatuto;-8.5167\nOdžaci;45.5167\nTemple Hills;38.8106\nDerby;39.8400\nWestgate;26.6994\nHarwood Heights;41.9663\nHaledon;40.9363\nRio Claro;10.3042\nSremski Karlovci;45.2000\nPrienai;54.6333\nGleno;-8.7239\nStony Brook University;40.9098\nCollingdale;39.9151\nTalsi;57.2444\nMokhotlong;-29.2885\nBogota;40.8751\nCorozal;18.4000\nMonaghan;54.2478\nCaldwell;40.8389\nJoniškis;56.2333\nNorth Kensington;39.0393\nDobele;56.6167\nRakai;-0.7100\nGlodeni;47.7667\nGədəbəy;40.5656\nKočevje;45.6430\nLa Cresta;35.3972\nSorø;55.4333\nPazin;45.2403\nAudubon;39.8906\nCheviot;39.1577\nPaide;58.8833\nHillcrest;41.1298\nAnykščiai;55.5333\nSwissvale;40.4206\nBuba;11.5833\nMalverne;40.6746\nUniversity of California-Davis;38.5378\nBasarabeasca;46.3336\nZərdab;40.2183\nRubirizi;-0.2661\nBroadview Park;26.0978\nVarėna;54.2111\nKrško;45.9500\nPhalombe;-15.8033\nFunadhoo;6.1482\nKaišiadorys;54.8667\nBrokopondo;5.0667\nTevragh Zeina;18.0994\nBalakən;41.7258\nSlovenska Bistrica;46.3903\nNaujoji Akmenė;56.3167\nKoné;-21.0590\nBeočin;45.2000\nAlebtong;2.2500\nPort Maria;18.3702\nNangan;26.1598\nSembabule;-0.0800\nMtskheta;41.8464\nSokobanja;43.6500\nGreymouth;-42.4500\nMontpelier;44.2659\nLitija;46.0667\nYeghegnadzor;39.7611\nFalmouth;18.4900\nGuadalupe;0.3800\nBentiu;9.2600\nAjdovščina;45.8861\nDebe;10.2000\nEsperanza;27.5800\nDowa;-13.6667\nLuba;3.4500\nAračinovo;42.0264\nYardımlı;38.9206\nBorgo Maggiore;43.9450\nVittoriosa;35.8881\nDiekirch;49.8681\nSen Monorom;12.4500\nĀdaži;57.0667\nKelmė;55.6333\nLeova;46.4833\nLudza;56.5500\nEydhafushi;5.1038\nRavne na Koroškem;46.5437\nGoranboy;40.6103\nKičevo;41.5142\nRuyigi;-3.4833\nBriceni;48.3611\nLerik;38.7753\nOcniţa;48.3853\nKrāslava;55.8833\nSlovenj Gradec;46.5094\nMobaye;4.3167\nMongomo;1.6287\nKəlbəcər;40.1067\nLapovo;44.1833\nHola;-1.5000\nTeleneşti;47.5028\nRadovljica;46.3425\nAizkraukle;56.6042\nNovobërdë;42.6000\nDonduşeni;48.2167\nŞtefan Vodă;46.5153\nTrindade;0.3000\nLīvāni;56.3667\nIn Guezzam;19.5686\nBrežice;45.9048\nNovi Kneževac;46.0500\nGulbene;57.1667\nKiruhura;-0.2100\nObiliq;42.6900\nOğuz;41.0708\nLimbaži;57.5167\nLuqa;35.8597\nSalavan;15.7167\nCriuleni;47.2167\nŠalčininkai;54.3167\nMadona;56.8500\nKovačica;45.1117\nMedvode;46.1382\nRos Comáin;53.6333\nMengeš;46.1626\nKerema;-7.9667\nAlūksne;57.4167\nMae Hong Son;19.3011\nBogatić;44.8333\nPasvalys;56.0594\nSiteki;-26.4500\nSal Rei;16.1770\nEenhana;-17.4658\nLorengau;-2.0306\nJõgeva;58.7469\nPunakha;27.5833\nPõlva;58.0536\nMitoma;-0.6150\nEspargos;16.7560\nKavadarci;41.4328\nJakar;27.5500\nBački Petrovac;45.3606\nSchaan;47.1667\nPreiļi;56.3000\nKupiškis;55.8333\nViqueque;-8.8500\nJunik;42.4761\nKudahuvadhoo;2.6711\nLucea;18.4500\nRutana;-3.9167\nPuerto Baquerizo Moreno;-0.9025\nRapla;58.9944\nGlarus;47.0333\nCəbrayıl;39.4000\nBač;45.3833\nAppenzell;47.3333\nSežana;45.7034\nZarasai;55.7333\nZagorje;46.1342\nMuramvya;-3.2500\nRogaška Slatina;46.2314\nPrevalje;46.5438\nEchternach;49.8117\nMamushë;42.3167\nMarsa;35.8833\nTrakai;54.6333\nŞoldăneşti;47.8167\nMwatate;-3.5047\nOutapi;-17.5167\nGħaxaq;35.8483\nČrnomelj;45.5711\nIdrija;46.0025\nRanillug;42.4920\nLija;35.9014\nBalvi;57.1333\nCarrick on Shannon;53.9440\nHrastnik;46.1479\nMolėtai;55.2333\nSisimiut;66.9389\nStratford;-39.3333\nHalba;34.5506\nXocavənd;39.7953\nFulin;29.3489\nMasunga;-20.6667\nGospić;44.5460\nWiltz;49.9667\nCacheu;12.2667\nBabək;39.1519\nNieuw Amsterdam;5.8833\nKazlų Rūda;54.7500\nPetnjica;42.9089\nMali Iđoš;45.7069\nŠakiai;54.9500\nThaba-Tseka;-29.5333\nKanifing;13.4500\nTriesen;47.1000\nXagħra;36.0503\nPartesh;42.4019\nNapak;2.1156\nSkuodas;56.2667\nKalangala;-0.3214\nKirakira;-10.4500\nTarrafal;16.5660\nĶekava;56.8333\nAlbina;5.5000\nPembroke;35.9264\nSlovenske Konjice;46.3383\nGrevenmacher;49.6806\nDanilovgrad;42.6100\nPalé;-1.4069\nSmiltene;57.4333\nLiquiçá;-8.5935\nIlulissat;69.2167\nNadur;36.0381\nIgnalina;55.3500\nVrapčište;41.8337\nŽalec;46.2510\nPunta Gorda;16.1005\nSamtse;27.0333\nGevgelija;41.1392\nBu’aale;1.0833\nAībak;36.2653\nMauren;47.2167\nIklin;35.9042\nŠentjur;46.2176\nBled;46.3688\nOrdino;42.5550\nTuzi;42.3656\nBolama;11.5767\nEschen;47.2167\nPonta do Sol;17.2020\nIrig;45.1000\nDispur;26.1500\nBalzers;47.0667\nKlaksvík;62.2375\nTolmin;46.1857\nViligili;0.7569\nKuala Belait;4.5828\nBururi;-3.9500\nČoka;45.9333\nŠilalė;55.4833\nRadoviš;41.6381\nKalkara;35.8892\nOpovo;45.0519\nImqabba;35.8442\nMiklavž na Dravskem Polju;46.5057\nBueng Kan;18.3672\nSevnica;46.0092\nRemich;49.5444\nValka;57.7667\nPakruojis;55.9667\nFuerte Olimpo;-21.0375\nŠvenčionys;55.1333\nQıvraq;39.3997\nŞuşa;39.7583\nBlack River;18.0257\nTrzin;46.1353\nDravograd;46.5903\nFloriana;35.8933\nTržič;46.3581\nJoão Teves;15.0680\nNwoya;2.6350\nIlirska Bistrica;45.5679\nTa’ Xbiex;35.8992\nGudja;35.8483\nCerknica;45.7964\nMarsaxlokk;35.8417\nLaško;46.1563\nRuše;46.5386\nZreče;46.3750\nŠempeter pri Gorici;45.9284\nDingli;35.8603\nBensonville;6.4456\nLa Palma;8.4100\nCalheta de São Miguel;15.1860\nKirkop;35.8419\nWabag;-5.4919\nGħargħur;35.9241\nCanillo;42.5667\nŽiri;46.0469\nGornja Radgona;46.6752\nButalangu;0.8228\nDomagnano;43.9500\nKaberamaido;1.7667\nKalvarija;54.4167\nOmuthiya;-18.3606\nXewkija;36.0331\nQobustan;40.5367\nAğdam;39.9833\nTrebnje;45.9104\nDeçan;42.5333\nKärdla;58.9981\nPlandište;45.2269\nLazdijai;54.2333\nRibnica;45.7400\nPiran;45.5283\nJanjanbureh;13.5341\nCankuzo;-3.2194\nŠoštanj;46.3798\nBrezovica;46.0207\nMassenya;11.4000\nLjutomer;46.5168\nImġarr;35.9197\nBerovo;41.7078\nSão João dos Angolares;0.1333\nMongar;27.2750\nAnkaran;45.5793\nKruševo;41.3700\nImtarfa;35.8908\nXai;20.6914\nColonia;9.5167\nSveti Nikole;41.8650\nTutin;42.9875\nCantemir;46.2667\nXgħajra;35.8864\nŠenčur;46.2430\nAlibunar;45.0806\nIvančna Gorica;45.9374\nMalishevë;42.4828\nAinaro;-8.9833\nŻebbuġ;36.0708\nFish Town;5.1964\nQrendi;35.8342\nŠkofljica;45.9836\nLenart v Slovenskih Goricah;46.5742\nUlbroka;56.9333\nBuala;-8.1333\nMežica;46.5206\nŽelezniki;46.2182\nDemir Kapija;41.4114\nSaulkrasti;57.2500\nGolubovci;42.3344\nRietavas;55.7167\nGroningen;5.8000\nMetlika;45.6517\nQaqortoq;60.7222\nŠtore;46.2219\nGħajnsielem;36.0269\nVeymandoo;2.1881\nBalaka;-14.9889\nŞahbuz;39.4072\nBirštonas;54.6028\nTrashigang;27.3326\nBorovnica;45.9197\nPorto Inglês;15.1380\nDelčevo;41.9661\nAasiaat;68.7097\nSafi;35.8333\nRogašovci;46.8053\nRače;46.4529\nLethem;3.3833\nMabaruma;8.2000\nPolzela;46.2809\nLendava;46.5631\nBogdanci;41.2031\nDamān;20.4169\nVojnik;46.2933\nThulusdhoo;4.3742\nŽitište;45.4833\nFiorentino;43.9106\nManadhoo;5.7628\nSowa Town;-20.5636\nBopolu;7.0667\nTa Khmau;11.4833\nSão Domingos;15.0280\nRadlje ob Dravi;46.6152\nKerewan;13.5000\nRadenci;46.6500\nFontana;36.0364\nAranđelovac;44.3042\nRasdhoo;4.2631\nDhihdhoo;6.8874\nMozirje;46.3381\nTrashi Yangtse;27.5833\nBarclayville;4.6797\nKolašin;42.8236\nTriesenberg;47.1181\nMuta;46.6167\nAmudat;1.9522\nTrongsa;27.4994\nNegotino;41.4839\nCerklje na Gorenjskem;46.2488\nSannat;36.0244\nQala;36.0353\nŠmarje;46.2281\nKllokot;42.3667\nCestos City;5.4667\nTofol;5.3258\nRuggell;47.2450\nAcquaviva;43.9457\nMahdia;5.2667\nSpodnje Hoče;46.4996\nIvanjica;43.5811\nVevčani;41.2403\nČrna na Koroškem;46.4697\nBeltinci;46.6060\nIg;45.9692\nKabarnet;0.4940\nAfega;-13.8019\nPrebold;46.2369\nNida;55.3033\nPivka;45.6833\nVianden;49.9336\nZhemgang;27.2134\nSariwŏn-si;38.5242\nLaçın;39.6408\nKerċem;36.0406\nLovrenc na Pohorju;46.5381\nCapellen;49.6444\nHeydərabad;39.7203\nOnverwacht;5.5931\nNaklo;46.2749\nGradsko;41.5775\nStraža;45.7864\nCidade Velha;14.9160\nPriboj;43.5836\nSemič;45.6546\nMigori;-1.0634\nTotness;5.8775\nSpodnji Duplek;46.5053\nŠentjernej;45.8389\nMiren;45.8962\nFelidhoo;3.4717\nChiradzulu;-15.7000\nSame;-9.0000\nJagodina;43.9750\nSofifi;0.7244\nVipava;45.8476\nAmbrolauri;42.5194\nTulagi;-9.1014\nZgornja Kungota;46.6388\nRadeče;46.0658\nValandovo;41.3169\nDamongo;9.0833\nDjibloho;1.5889\nOrmož;46.4086\nVuzenica;46.5992\nLifford;54.8340\nMunxar;36.0303\nKriva Palanka;42.2017\nBohinjska Bistrica;46.2742\nDivača;45.6820\nKratovo;42.0783\nŽabljak;43.1550\nGamprin;47.2167\nŠmartno;46.0441\nKrivogaštani;41.3358\nNyamira;-0.5633\nZrnovci;41.8542\nMislinja;46.4431\nSopište;41.9500\nVodice;46.1833\nTrim;53.5550\nRogatec;46.2243\nGħarb;36.0611\nOdranci;46.5856\nSelnica ob Dravi;46.5514\nDragomer;46.0189\nNazarje;46.3202\nVreed-en-Hoop;6.8076\nOplotnica;46.3860\nŠabac;44.7558\nMachinga;-14.9667\nVarakļāni;56.6000\nMirna;45.9476\nPehčevo;41.7592\nRopaži;56.9718\nGusinje;42.5619\nTurnišče;46.6194\nPlasnica;41.4667\nSmederevo;44.6633\nPārūn;35.4167\nArilje;43.7531\nTearce;42.0775\nVladičin Han;42.7000\nCerkno;46.1283\nXızı;40.9078\nSotik Post;-0.7813\nBovec;46.3378\nNova Varoš;43.4667\nKanal;46.0880\nPoljčane;46.3135\nClervaux;50.0500\nIsangel;-19.5300\nMurang’a;-0.7167\nTabor;46.2108\nNova Crnja;45.6667\nMogila;41.1083\nMoravče;46.1356\nHorjul;46.0230\nKuršumlija;43.1408\nDornava;46.4299\nKranjska Gora;46.4854\nAleksandrovac;43.4553\nXékong;15.3503\nŠmartno;46.3297\nKidričevo;46.4060\nXocalı;39.9111\nLeulumoega;-13.8167\nNilandhoo;3.0567\nTaro;-6.7111\nSchellenberg;47.2336\nSanto António;1.6367\nPlužine;43.1500\nGornji Milanovac;44.0212\nVitanje;46.3825\nFaetano;43.9256\nGorenja Vas;46.1069\nSafotu;-13.4528\nSvrljig;43.4167\nNovo Selo;41.4128\nLjubno;46.3333\nOranjestad;17.4833\nNovaci;41.0419\nRosoman;41.5161\nLata;-10.7167\nKomenda;46.2073\nČrenšovci;46.5747\nMontegiardino;43.9089\nBenedikt;46.6065\n‘Amrān;15.6594\nRaška;43.2856\nPirot;43.1519\nProkuplje;43.2339\nStari Trg;45.7142\nMirna Peč;45.8580\nAsau;-13.5194\nBrus;43.3836\nSurdulica;42.6950\nBosilovo;41.4406\nDaga;27.0667\nGorišnica;46.4122\nUb;44.4500\nLučani;43.8667\nMuli;2.9217\nGornji Grad;46.2961\nPesnica;46.6099\nKobarid;46.2464\nAndrijevica;42.7300\nSredišče ob Dravi;46.3933\nSveta Trojica v Slovenskih Goricah;46.5756\nVeržej;46.5818\nLufilufi;-13.8500\nDobrova;46.0533\nVidem pri Ptuju;46.3699\nPožega;43.8459\nNeno;-15.3981\nIsale;-3.3444\nDobrovnik;46.6515\nJegunovce;42.0731\nSiaya;0.0667\nVelika Polana;46.5719\nMahonda;-5.9897\nKonče;41.4958\nDolenjske Toplice;45.7545\nKostanjevica na Krki;45.8463\nSmederevska Palanka;44.3655\nDol;46.0884\nChikwawa;-16.0350\nPreddvor;46.3052\nZgornja Hajdina;46.4057\nSan Lawrenz;36.0550\nNamutumba;0.8363\nFonadhoo;1.8342\nStarše;46.4664\nSodražica;45.7616\nBabušnica;43.0680\nVlasotince;42.9667\nLjubovija;44.1869\nLajkovac;44.3667\nRostuša;41.6100\nMajšperk;46.3500\nKosjerić;44.0000\nP’yŏngsŏng-si;39.2828\nMionica;44.2500\nVelike Lašče;45.8363\nBela Palanka;43.2178\nAsaba;6.1833\nMoravske-Toplice;46.6927\nVidem;45.8484\nDobrna;46.3381\nVailoa;-13.7558\nAïn Defla;36.2583\nBukwo;1.2928\nNkurenkuru;-17.6167\nObleševo;41.8833\nKapenguria;1.2333\nPuconci;46.7039\nŠirvintos;55.0361\nMokronog;45.9426\nRankovce;42.1719\nPetrovec;41.9389\nRečica;46.3247\nYenagoa;4.9267\nUmm Şalāl ‘Alī;25.4697\nLakatoro;-16.1069\nKozje;46.0740\nKomen;45.8159\nKriževci;46.5631\nHvalba;61.6000\nQubadlı;39.3439\nAranguez;10.6472\nMaracha;3.2883\nMarkovci;46.3956\nŠmarješke Toplice;45.8622\nPožarevac;44.6200\nKrupanj;44.3667\nKarbinci;41.8167\nVasilevo;41.4758\nBangar;4.7086\nKnjaževac;43.5000\nPicos;15.0830\nLuče;46.3565\nGrad;46.7977\nZaječar;43.9042\nPodčetrtek;46.1573\nApače;46.6967\nParaćin;43.8667\nLebane;42.9167\nLukovica;46.1686\nĐà Lạt;11.9359\nBinyin;1.4175\nGħasri;36.0583\nThe Bottom;17.6261\nRača;44.2333\nMila;36.4481\nTigoa;-11.5583\nCirkulane;46.3436\nDobrovo;45.9989\nZgornje Gorje;46.3801\nSaleaula;-13.4501\nBulambuli;1.1600\nŠentrupert;45.9769\nAileu;-8.7281\nMakedonski Brod;41.5133\nAleksinac;43.5383\nKobilje;46.6837\nVwawa;-9.1081\nPlanken;47.1833\nStaro Nagoričane;42.2000\nZgornje Jezersko;46.3951\nOsečina;44.3667\nDemir Hisar;41.2208\nWeno;7.4500\nJincheng;24.4167\nSveti Jurij;46.5683\nKuzma;46.8333\nDespotovac;44.0833\nČajetina;43.7500\nNamayingo;0.2398\nCankova;46.7193\nLozovo;41.7817\nSanta Cruz;14.1167\nCentar Župa;41.4775\nLjig;44.2213\nButebo;1.1944\nJuršinci;46.4853\nKoani;-6.1333\nImdina;35.8858\nNova Vas;45.7726\nDestrnik;46.4923\nVarvarin;43.7167\nSkopun;61.9125\nGornji Petrovci;46.8050\nRibnica;46.5372\nKon Tum;14.3544\nŠavnik;42.9500\nPodlehnik;46.3361\nBusesa;0.6263\nDharamshāla;32.2186\nDhuusamarreeb;5.5350\nBuabidi;8.4667\nBrvenica;41.9672\nBelčišta;41.3028\nMakole;46.3174\nCrna Trava;42.8101\nTrnovska Vas;46.5231\nMali Zvornik;44.3992\nJurovski Dol;46.6087\nHvannasund;62.2833\nTišina;46.6558\nŠalovci;46.8250\nVitomarci;46.5248\nDogbo;6.8167\nLuuka Town;0.7642\nDolneni;41.4264\nAbakaliki;6.3249\nBraslovče;46.2884\nBlace;43.2906\nSveta Ana;46.6497\nDoljevac;43.1968\nCerkvenjak;46.5660\nPombas;17.1490\nAz̧ Z̧a‘āyin;25.5669\nBatočina;44.1500\nHrib-Loški Potok;45.7015\nPodvelka;46.5864\nNsiika;-0.2958\nNegotin;44.2167\nRubanda;-1.1864\nNtara;0.0047\nŠkocjan;45.9069\nBistrica ob Sotli;46.0589\nToftir;62.0978\nKalungu;-0.1681\nNelspruit;-25.4745\nBupoto;0.9061\nČučer-Sandevo;42.0975\nVeliko Gradište;44.7500\nPorkeri;61.4814\nSanta Luċija;36.0431\nDimitrovgrad;43.0167\nTomaž pri Ormožu;46.4833\nAl Jabīn;14.7040\nVelika Plana;44.3333\nPetrovac na Mlavi;44.3783\nSvilajnac;44.2167\nBoljevac;43.8247\nZelenikovo;41.8867\nHodoš;46.8285\nKole;2.4286\nNarok;-1.0833\nOuled Djellal;34.4167\nKladovo;44.6039\nMparo;-1.1844\nOl Kalou;-0.2730\nKasanda;0.5467\nKasaali;-0.6167\nŠentilj;46.6817\nBojnik;43.0142\nKakumiro;0.7811\nŽelino;41.9794\nBogovinje;41.9233\nKinoni;-0.6583\nSārī;36.5633\nKoronadal;6.2541\nKibingo;-0.5700\nPailin;12.8489\nStudeničani;41.9158\nKara;9.5511\nSolčava;46.4201\nTopola;44.2525\nSuai;-9.3129\nPante Macassar;-9.2000\nRazkrižje;46.5182\nWaitangi;-43.9514\nKalaki;1.8160\nChiesanuova;43.9061\nSaltangará;62.1156\nMulifanua;-13.8333\nLospalos;-8.5167\nFort Wellington;6.4000\nIlinden;41.9945\nRabak;13.1850\nTsirang;27.0219\nTutong;4.8067\nMerošina;43.2833\nViti;42.3214\nSefwi Wiawso;6.2158\nDobje;46.1369\nHongseong;36.6009\nMersch;49.7500\nMuan;34.9897\nBangolo;7.0123\nSaratamata;-15.2875\nStrendur;62.1096\nKurumul;-5.8550\nPalenga;2.5764\nLamwo;3.5300\nOsilnica;45.5289\nŽitorađa;43.1833\nKoceljeva;44.4708\nAgago;2.9847\nMorant Bay;17.8819\nStar Dojran;41.1865\nŽužemberk;45.8339\nMadīnat ash Shamāl;26.1167\nGadžin Han;43.2203\nĆićevac;43.7167\nZavrč;46.3917\nBhararisain;30.0986\nĪlām;33.6374\nLipkovo;42.1553\nBosilegrad;42.5005\nVladimirci;44.6167\nHaa;27.3825\nRažanj;43.6667\nTvøroyri;61.5544\nKučevo;44.4833\nBoorama;9.9361\nSan Jose;10.1800\nSharan;33.1757\nDambai;8.0689\nMedveđa;42.8333\nGoaso;6.8000\nŞuḩār;24.3420\nŞərur;39.5544\nRedange-sur-Attert;49.7652\nGaoua;10.2992\nCocieri;47.3000\nFuglafjørður;62.2448\nFámjin;61.5264\nRekovac;43.8667\nKnić;43.9167\nSamamea;-13.9333\nNhlangano;-27.1167\nNīlī;33.7218\nTabuk;17.4084\nSarpang;26.8639\nNabilatuk;2.0525\nNova Sintra;14.8710\nSédhiou;12.7000\nPagėgiai;55.1333\nQəbələ;40.9825\nPemagatshel;27.0333\nIgreja;15.0339\nVágur;61.4733\nSafotulafai;-13.6817\nQacha’s Nek;-30.1167\nŽabari;44.3562\nMalo Crniće;44.5667\nTsimasham;27.0989\nPala;9.3646\nDalandzadgad;43.5708\nPader;3.0500\nOtuke;2.4442\nDəvəçi;41.2012\nEl Meghaïer;33.9506\nNorðragøta;62.1990\nLeava;-14.2933\nBuka;-5.4219\nAnouvông;18.8989\nNakapiripirit;1.9167\nSatupa‘itea;-13.7659\nMakedonska Kamenica;42.0208\nGolubac;44.6530\nMajdanpek;44.4167\nŞūr;22.5667\nRibeira Brava;16.6150\nŽetale;46.2750\nRustavi;42.2897\nSørvágur;62.0717\nKostel;45.5088\nResen;41.0893\nCova Figueira;14.8900\nVransko;46.1720\nEiði;62.2995\nOyrarbakki;62.2079\nPili;13.7177\nVestmanna;62.1548\nGaigirgordub;9.5586\nKyankwanzi;1.2000\nKvívík;62.1186\nPhôn-Hông;18.4953\nSumba;61.4055\nSandavágur;62.0537\nTrgovište;42.3514\nSola;-13.8750\nHov;61.5068\nTanjung Selor;2.8500\nViðareiði;62.3600\nŽagubica;44.1979\nSandur;61.8344\nEl Fula;11.7175\nLupane;-18.9315\nLoango;-4.6307\nLaascaanood;8.4774\nNtoroko;1.0500\nHúsavík;61.8099\nGeorgetown;-7.9286\nLhuentse;27.6500\nCeerigaabo;10.6162\nKunoy;62.2917\nSkálavík;61.8314\nWé;-20.9167\nKirkja;62.3263\nSieyik;9.3833\nEdinburgh of the Seven Seas;-37.0675\nSkúvoy;61.7710\nGasa;27.9167\nHaymā’;19.9569\nIdrī;27.4471\nUnión Chocó;8.0778\nBardaï;21.3533\nPreševo;42.3067\nBujanovac;42.4667\nKitamilo;0.2367\nSundsvall;62.4000\nXiongzhou;38.9786\nUdine;46.0667\nKalisz;51.7575\nIzumisano;34.4000\nLegnica;51.2083\nWakefield;53.6800\nPouytenga;12.2500\nXiegang;22.9614\nKani;35.4261\nKadaiyanallūr;9.0743\nDebre Zeyit;8.7500\nLuckeesarai;25.1678\nDzolokpuita;6.7862\nChikusei;36.3071\nTellicherry;11.7489\nAndria;41.2167\nAd Dujayl;33.8389\nTinsukia;27.5000\nGwelej;14.7500\nBabīlē;9.2167\nRa’s Ghārib;28.3597\nAlaminos;16.1553\nPili;13.5561\nFengning;41.2013\nUrgut Shahri;39.4190\nDhār;22.5992\nSayaxché;16.5167\nFederal Way;47.3091\nHanau;50.1328\nManteca;37.7927\nOton;10.6931\nHasilpur;29.6967\nSilvassa;20.2700\nTsuyama;35.0692\nBislig;8.2133\nLafayette;39.9946\nItārsi;22.6200\nArezzo;43.4633\nBallarat;-37.5608\nKārwār;14.8136\nSakata;38.9145\nAbhar;36.1511\nTobolsk;58.1953\nKhamīs Mushayţ;18.3000\nCottbus;51.7606\nHesperia;34.3975\nLa Crosse;43.8241\nAl Jammālīyah;31.1792\nIfakara;-8.1000\nChía;4.8500\nBreves;-1.6819\nWeldiya;11.8306\nRiberalta;-11.0128\nSarapul;56.4667\nMīāneh;37.4239\nSenahú;15.4164\nItoshima;33.5539\nRiverview;27.8227\nEs Senia;35.6478\nKontagora;10.4030\nIxmiquilpan;20.4861\nKingsport;36.5224\nEdinburg;26.3196\nKhambhāt;22.3000\nKallūru;15.8162\nZárate;-34.0833\nReyhanlı;36.2692\nBowling Green;36.9716\nSaku;36.2488\nM’lang;6.9500\nKoytendag;37.5000\nItaituba;-4.2758\nDongducheon;37.9167\nWorcester;-33.6450\nVotkinsk;57.0500\nPaulínia;-22.7611\nIseyin;7.9667\nAdjarra;6.5333\nMariano Roque Alonso;-25.2122\nFanyang;31.0847\nRāmnagar;29.4000\nOodweyne;9.4000\nCarmel;39.9650\nChitose;42.8210\nKawkareik;16.5556\nLongview;32.5193\nAttock Khurd;33.7667\nTracy;37.7269\nOldham;53.5444\nTrelew;-43.2500\nLugo;43.0167\nPrescott Valley;34.5980\nKambar;27.5868\nHammamet;36.4000\nWitten;51.4333\nMunakata;33.8000\nParagominas;-2.9958\nSerov;59.6000\nCaotun;23.9830\nAşağıçinik;41.2719\nSan Cugat del Vallés;41.4735\nQuilenda;-10.6333\nHadera;32.45\nTubarão;-28.4667\nBafra;41.5722\nBrantford;43.1667\nBeaverton;45.4779\nPortsmouth;43.0580\nPortsmouth;36.8468\nOcozocoautla de Espinosa;16.8000\nValença;-13.3700\nLas Rozas de Madrid;40.4917\nYacuiba;-22.0153\nBodināyakkanūr;10.0000\nLorca;37.6798\nItuiutaba;-18.9667\nVillupuram;11.9401\nTucuruí;-3.7678\nLysychansk;48.9169\nJamundí;3.2667\nFishers;39.9588\nCesena;44.1389\nItacoatiara;-3.1428\nVīrappanchathiram;11.3553\nUkhta;63.5667\nTomohon;1.3244\nBuin;-33.7333\nBarra do Piraí;-22.4700\nColón;13.7167\nParaíso;18.3961\nTandwa;26.5500\nZerakpur;30.6500\nQuvasoy;40.3000\nPaletwa;21.3000\nTela;15.7833\nGreece;43.2460\nHarihar;14.5129\nBalayan;13.9333\nIida;35.5150\nCaieiras;-23.3644\nDo Gonbadān;30.3586\nCambé;-23.2758\nKāzerūn;29.6194\nTiddim;23.3758\nEscalante;10.8333\nJaperi;-22.6431\nIguatu;-6.3589\nWujiaqu;44.1670\nChākdaha;23.0800\nArifwala;30.2981\nNova Lima;-19.9858\nVanderbijlpark;-26.6992\nAmalner;21.0500\nŌmura;32.9000\nLongquan;40.3703\nKimilili;0.7833\nLeninsk-Kuznetskiy;54.6575\nKelo;9.3100\nMezhdurechensk;53.6864\nDovzhansk;48.0778\nSandy;40.5709\nTiruchengodu;11.3790\nBendigo;-36.7500\nSan Tan Valley;33.1786\nKamisu;35.8899\nLongkeng;24.0341\nMuzaffarabad;34.3583\nSivakāsi;9.4500\nParamagudi;9.5494\nMons;50.4500\nItaperuna;-21.2050\nJinbi;25.7356\nXiluodu;28.2360\nEmmiganūr;15.7333\nNagīna;29.4430\nSaint-Michel de l’Atalaye;19.3667\nPesaro;43.9167\nBoli;45.7564\nVāniyambādi;12.6825\nShirē;14.1000\nTiruttani;13.1800\nAliağa;38.8008\nClosepet;12.7230\nYi Xian;39.3444\nEsslingen;48.7333\nHương Thủy;16.4000\nCáceres;39.4833\nShimada;34.8363\nAllinagaram;10.0119\nLecce;40.3500\nHanford;36.3274\nGuaíba;-30.1139\nBogo;10.7361\nErbaa;40.6667\nBalamban;10.4667\nSarov;54.9333\nBoca Raton;26.3752\nRubio;7.7000\nDaltonganj;24.0333\nMianwali;32.5853\nYalamakūru;15.7680\nRawānduz;36.6119\nMiddletown;39.5033\nLivonia;42.3972\nSan Martín Jilotepeque;14.7830\nBirecik;37.0250\nJinshan;25.1496\nGerona;15.6069\nNāḩiyat al Karmah;33.3833\nSolikamsk;59.6433\nSiguatepeque;14.6000\nAbreu e Lima;-7.9117\nBarletta;41.3167\nCarson;33.8374\nValongo;41.1833\nAl Jīzah;31.7000\nToms River;39.9895\nDod Ballāpur;13.2920\nLagarto;-10.9169\nLawang;-7.8300\nLopez;13.8840\nBouna;9.2667\nJaworzno;50.2044\nBehshahr;36.6922\nKanuma;36.5671\nGera;50.8806\nLawrence;38.9597\nGrudziądz;53.4875\nAlvand;36.1892\nGatchina;59.5684\nMichurinsk;52.8833\nDaanbantayan;11.2500\nSlidell;30.2887\nBayan Hot;38.8556\nGreenburgh;41.0330\nShibata;37.9479\nAlessandria;44.9167\nSanta Cruz Xoxocotlán;17.0296\nGlazov;58.1333\nBlacksburg;37.2300\nMarmaris;36.8500\nHelmond;51.4833\nSan Marcos;33.1350\nKwekwe;-18.9167\nTatakan;-6.1116\nCape Breton;46.1389\nAzumino;36.3039\nManacapuru;-3.3000\nWangjia;30.6218\nMonkayo;7.8239\nLemery;13.9167\nKabacan;7.1167\nYunnanyi;25.3916\nChiantla;15.3567\nItaúna;-20.0750\nMenderes;38.2540\nSanjō;37.6368\nHigashi-Matsuyama;36.0422\nSimeulu;2.6300\nPuerto Padre;21.1950\nVoskresensk;55.3167\nVilhena;-12.7406\nIndanan;6.0000\nMikhaylovsk;45.1333\nSanta Barbara;16.0031\nGoodyear;33.2614\nJaén;-5.7083\nPiraquara;-25.4419\nLa Spezia;44.1000\nEdmond;35.6689\nBedford;52.1350\nMayagüez;18.2003\nLinquan;37.9513\nIserlohn;51.3833\nFall River;41.7136\nAkşehir;38.3575\nContai;21.7800\nBafang;5.1500\nSuffolk;36.6953\nTerre Haute;39.4660\nHilversum;52.2333\nSamālūţ;28.3097\nAvignon;43.9500\nOss;51.7667\nPhú Thọ;21.4003\nErciş;39.0311\nWukari;7.8704\nPalimbang;6.2167\nAkot;21.1000\nRafaela;-31.2667\nVelikiye Luki;56.3333\nKilosa;-6.8300\nItumbiara;-18.4167\nHanamaki Onsen;39.3886\nDüren;50.8000\nMissoula;46.8751\nBoundiali;9.5167\nAzua;18.4600\nLaiyuan;39.3515\nItapeva;-23.9819\nFoumban;5.7167\nTatvan;38.5022\nRāyachoti;14.0583\nNaju;35.0333\nFlensburg;54.7819\nLethbridge;49.6942\nTübingen;48.5200\nRoswell;34.0391\nSablayan;12.8428\nRongwo;35.5165\nSan Sebastián de los Reyes;40.5469\nGrahamstown;-33.2996\nYumbo;3.5850\nKitakami;39.2867\nBauan;13.7917\nGießen;50.5833\nKot Kapūra;30.5833\nSaint-Jean-sur-Richelieu;45.3167\nVineland;39.4653\nLavras;-21.2450\nAcajutla;13.5900\nGoalundo Ghāt;23.7333\nTonacatepeque;13.7833\nPlantation;26.1259\nKendu Bay;-0.3596\nAlafaya;28.5280\nClarington;43.9350\nSatsumasendai;31.8167\nUbatuba;-23.4339\nSão João da Boa Vista;-21.9689\nÇaycuma;41.4267\nAmbohimangakely;-18.9167\nFunza;4.7167\nModi‘in Makkabbim Re‘ut;31.9077\nPickering;43.8354\nSouthport;53.6475\nŢurayf;31.6775\nSinendé;10.3447\nMogi Mirim;-22.4319\nKirkland;47.6970\nWeiyuan;23.5025\nJulu;37.2200\nKāvali;14.9130\nHamilton;40.2046\nSalaman;6.6333\nTalara;-4.5799\nYao;12.8508\nPeñaflor;-33.6167\nJauharabad;32.2919\nPāloncha;17.6018\nVotuporanga;-20.4228\nJalalpur Jattan;32.7667\nCaçapava;-23.1008\nHoover;33.3763\nSão Félix do Xingu;-6.6333\nAvaré;-23.0989\nLachhmangarh Sīkar;27.8225\nCáceres;-16.0711\nLawton;34.6175\nMaladzyechna;54.3208\nPhusro;23.7700\nAgua Prieta;31.3258\nAuburn;32.6087\nChauk;20.8833\nImizuchō;36.7306\nItajubá;-22.4258\nPongotan;7.1269\nCaimbambo;-12.9000\nNorwalk;41.1144\nO'Fallon;38.7850\nGwadar;25.1264\nCambambe;-9.7586\nVictorias;10.9000\nPinamalayan;13.0364\nKatiola;8.1333\nChililabombwe;-12.3667\nBiga;40.2281\nEslāmābād-e Gharb;34.1094\nArsuz;36.4128\nPisa;43.7167\nFundación;10.5214\nSahagún;8.9500\nSão João del Rei;-21.1358\nSão Sebastião;-23.8040\nMa‘arrat an Nu‘mān;35.6386\nNanaimo;49.1642\nMancherāl;18.8679\nChalchuapa;13.9833\nKansk;56.2000\nKiselëvsk;54.0000\nZwickau;50.7167\nPistoia;43.9333\nChino;33.9836\nCaucasia;7.9833\nCompostela;7.6667\nOcaña;8.2333\nMihara;34.4000\nMijas;36.6000\nSankeshwar;16.2700\nKairāna;29.3953\nRichard-Toll;16.4667\nUacu Cungo;-11.3583\nSan José Pinula;14.5446\nLuau;-10.7044\nKadiri;14.1200\nNecochea;-38.5500\nBarwaaqo;3.4833\nMöng Tun;20.3000\nAfmadow;0.5156\nEl Puerto de Santa María;36.6000\nAalst;50.9383\nPresidencia Roque Sáenz Peña;-26.7833\nDover;43.1887\nCiudad de Atlixco;18.9000\nPolangui;13.2922\nWaukegan;42.3698\nOlavarría;-36.9000\nBogo;11.0167\nLucca;43.8417\nChosica;-11.9361\nBuckeye;33.4314\nTown 'n' Country;28.0106\nLeping;37.6130\nSerdar;38.9833\nCantaura;9.3005\nKamensk-Shakhtinskiy;48.3206\nBanga;6.3000\nConda;-11.1667\nCheektowaga;42.9082\nSurallah;6.3667\nGitarama;-2.0696\nHinigaran;10.2667\nCalabanga;13.7089\nAkyazı;40.6833\nBloomington;44.8306\nPrijedor;44.9667\nCaracase;3.7533\nToviklin;6.8333\nLéré;9.7700\nSégbana;10.9278\nBan Laem Chabang;13.0833\nPassi;11.1000\nShwebo;22.5667\nHumpata;-15.0725\nSaundatti;15.7833\nMurcia;10.6000\nNirmal;19.1000\nQiantangcun;23.6742\nKūhdasht;33.5350\nCandeias;-12.6678\nSan Francisco;30.9000\nSanta Catarina Pinula;14.5644\nRāsipuram;11.4700\nCalauan;14.1500\nAïn M’Lila;36.0367\nChimbas;-31.5000\nMount Pleasant;32.8537\nBhakkar;31.6278\nHeerlen;50.8833\nDunkerque;51.0383\nSolana;17.6522\nDongchuan;25.5086\nDanlí;14.0328\nMadgaon;15.2736\nHalifax;53.7250\nMontelíbano;7.9750\nKōka;34.9667\nFlorence;34.1780\nSan Luis;20.1881\nJamūī;24.9200\nBaras;14.5167\nMaravatío de Ocampo;19.8933\nPaingkyon;17.0242\nOotacamund;11.4100\nNewton;42.3316\nKimje;35.8017\nSakiet ez Zit;34.8000\nNirāla;19.5000\nAroroy;12.5125\nGrimsby;53.5675\nEchague;16.7056\nLa Grita;8.1333\nBayramaly;37.6167\nSan Fabian;16.1500\nSangrūr;30.2506\nJumri Tilaiyā;24.4289\nLivermore;37.6868\nZhob;31.3417\nBerisso;-34.8728\nNorton;-17.8833\nSakai;36.1669\nMettupālaiyam;11.2341\nPingyuanjie;23.7472\nMaiquetía;10.5958\nJanzūr;32.8172\nRatingen;51.3000\nTacaná;15.2415\nMakilala;6.9667\nPonta Porã;-22.5358\nChangting;25.8670\nFarīdkot;30.6700\nSão Pedro da Aldeia;-22.8389\nCalaca;13.9300\nAruppukkottai;9.5139\nLeshou;38.1902\nSinjār;36.3225\nJilotepec;19.9519\nRapid City;44.0716\nSłupsk;54.4658\nSudbury;46.4900\nSão Gonçalo do Amarante;-5.7928\nJataí;-17.8808\nDecatur;39.8557\nSassandra;4.9500\nDalton;34.7690\nCamiling;15.6867\nConroe;30.3238\nChiclana de la Frontera;36.4167\nWislane;30.2167\nBuzuluk;52.7833\nShuangshuicun;22.4356\nEl Ejido;36.7831\nJagüey Grande;22.5292\nDipalpur;30.6708\nBaggao;17.9347\nSanta Cruz do Capibaribe;-7.9569\nLünen;51.6167\nPalangotu Adwār;32.7888\nAnakāpalle;17.6913\nCeylanpınar;36.8461\nNahualá;14.8429\nPergamino;-33.8836\nFukuroi;34.7502\nBinmaley;16.0323\nConsolación del Sur;22.5083\nKoidu-Bulma;8.4405\nNew Braunfels;29.6994\nCipolletti;-38.9333\nParedes;41.2000\nBrindisi;40.6333\nEnde;-8.8333\nNabua;13.4083\nDenan;6.5000\nLimpio;-25.1683\nTiflet;33.8931\nKumārapālaiyam;11.4416\nMobara;35.4285\nBantayan;11.2000\nChongoroi;-13.5667\nBi’r al ‘Abd;31.0181\nHoundé;11.5000\nHānsi;29.1000\nJackson;42.2431\nItabaiana;-10.6850\nHeyunkeng;23.9293\nWulan;36.5585\nSão Cristóvão;-11.0150\nMenglang;22.5586\nQaraçuxur;40.3967\nAd Diwem;14.0000\nChiguayante;-36.9167\nMuncie;40.1989\nVillingen-Schwenningen;48.0603\nCampana;-34.1667\nDingcheng;19.6803\nCandelaria;3.4000\nKalpitiya;8.1667\nTroy;42.5817\nShahdol;23.2800\nTuncheng;19.3633\nGubkin;51.2833\nCárdenas;23.0428\nYaofeng;35.1395\nKharian;32.8110\nWidekum;5.8717\nLongonjo;-12.9067\nDucheng;23.2445\nSão Roque;-23.5289\nKattagan;40.2000\nClarkstown;41.1319\nGarulia;22.8200\nKeffi;8.8464\nGotenba;35.3087\nNovotroitsk;51.2039\nNīmbāhera;24.6200\nPariaman;-0.6261\nTagaytay;14.1000\nCabiao;15.2522\nLugang;24.0500\nSanta Rosa Jauregui;20.7418\nHomosassa Springs;28.8119\nSan Antonio;-33.5933\nKameoka;35.0167\nGuasavito;25.5655\nTreviso;45.6722\nMaratturai;11.1000\nPort Huron;42.9821\nYabēlo;4.8833\nSārni;22.1040\nShaoshanzhan;27.9100\nTorrente;39.4365\nSeoni Mālwa;22.4508\nKonstanz;47.6667\nLongchuan;25.1945\nKaizuka;34.4333\nHövsan;40.3744\nKhowrāsgān;32.6539\nJaorā;23.6300\nBugulma;54.5364\nShchëkino;54.0000\nPotiskum;11.7104\nGuinobatan;13.1833\nNapa;38.2975\nBāsoda;23.8515\nJastrzębie-Zdrój;49.9500\nDhārāpuram;10.7300\nIga;34.7667\nKhemis Miliana;36.2600\nSan Pedro Sacatepéquez;14.9664\nLonghua;41.3170\nSharūrah;17.4833\nKitakōriyamachō;34.6500\nUshiku;35.9794\nNorth Vancouver;49.3641\nCacoal;-11.4386\nChiquinquirá;5.6333\nCoari;-4.0850\nSpringdale;36.1901\nGuanambi;-14.2228\nYeysk;46.7111\nSekimachi;35.4958\nNewport Beach;33.6151\nLa Dorada;5.4538\nDharmapuri;12.1270\nWoolwich;51.4880\nKrishnagiri;12.5317\nAl Hindīyah;32.5442\nCachoeira do Sul;-30.0394\nPilkhua;28.7120\nBrossard;45.4667\nChita;35.0000\nAnderson;40.0891\nSan Ramon;37.7624\nGeneral Rodríguez;-34.6167\nBatarasa;8.6700\nKineshma;57.4333\nLake Forest;33.6605\nJunín;-34.5833\nColonie;42.7396\nMhow;22.5500\nDapitan;8.6549\nWarder;6.9667\nHarda Khās;22.3441\nMission;26.2039\nCaratinga;-19.7900\nAuburn;47.3039\nBrooklyn Park;45.1112\nTakayama;36.1460\nDerry;54.9917\nMaga;10.8500\nLuancheng;37.8846\nBryan;30.6650\nSumenep;-7.0049\nSpringfield;39.9300\nHattiesburg;31.3074\nWalvisbaai;-22.9561\nMoriyama;35.0586\nTshilenge;-6.2500\nBahlā’;22.9680\nKorgas;44.2125\nRepentigny;45.7333\nWestland;42.3192\nAlbany;31.5776\nMarl;51.6667\nDhorāji;21.7337\nSambava;-14.2667\nCiudad Mante;22.7333\nJacobina;-11.1808\nScience City of Muñoz;15.7153\nArujá;-23.3967\nGuider;9.9342\nChirundu;-16.0500\nSenador Canedo;-16.7594\nParacatu;-17.2217\nTorrevieja;37.9778\nFort Myers;26.6194\nYokotemachi;39.3113\nHabiganj;24.3808\nSabanalarga;10.6300\nWorms;49.6319\nConcepción Tutuapa;15.2833\nBais;9.5907\nTire;38.0833\nVilla Altagracia;18.6667\nDmitrov;56.3500\nVélez-Málaga;36.7833\nChannapatna;12.6514\nBolinao;16.3881\nSerra Talhada;-7.9858\nPará de Minas;-19.8600\nChigorodó;7.6675\nCukai;4.2332\nEl Milia;36.7500\nAtascocita;29.9777\nTiruppattūr;12.5000\nLqoliaa;30.2908\nFredrikstad;59.2053\nCereté;8.8833\nJi’an;23.9500\nPhúc Yên;21.2333\nBhawānipatna;19.9100\nZheleznogorsk;56.2500\nTalavera de la Reina;39.9583\nArona;28.0996\nFelipe Carrillo Puerto;19.5786\nRedwood City;37.5025\nIjuí;-28.3878\nNantingcun;20.8040\nSirsilla;18.3800\nPontevedra;42.4333\nChilliwack;49.1577\nBuuhoodle;8.2311\nFarmington Hills;42.4860\nAlton;38.9037\nLafey;3.1508\nTila;17.3667\nSan Antonio;15.3078\nChingleput;12.6918\nYurga;55.7231\nMelbourne;28.1086\nMaco;7.3619\nMian Channun;30.4397\nRedditch;52.3000\nTaytay;10.8167\nSerrinha;-11.6639\nWutiancun;23.1852\nSantana do Livramento;-30.8908\nRivadavia;-31.5303\nSiaton;9.0667\nTual;-5.6368\nMānsa;29.9906\nBoukoumbé;10.1833\nBhalwal;32.2656\nSeropédica;-22.7439\nWuyi;37.7965\nLa Trinidad;15.9833\nMarsala;37.7981\nKateríni;40.2667\nVelbert;51.3333\nWilliamsburg;37.2693\nPozzuoli;40.8231\nAl Ḩayy;32.1667\nMabinay;9.7333\nChelghoum el Aïd;36.1667\nTanjay;9.5167\nHukou;24.9000\nXiedian;35.4190\nNakatsu;33.5992\nUfeyn;10.6500\nBhaktapur;27.6722\nBarra do Corda;-5.5058\nShīrvān;37.3967\nSorriso;-12.5450\nStockton-on-Tees;54.5700\nMadera;36.9630\nKongjiazhuangcun;40.7536\nSaunda;23.6600\nNowy Sącz;49.6239\nCalatrava;10.6000\nKaranganyar;-7.6033\nMinden;52.2883\nWarwick;41.7062\nCranston;41.7658\nCruzeiro do Sul;-7.6308\nRivadavia;-33.1833\nChulucanas;-5.0961\nKātoya;23.6500\nŌmihachiman;35.1283\nMuroran;42.3152\nPolatsk;55.4833\nBaytown;29.7587\nEl Estor;15.5333\nShikokuchūō;33.9833\nCarmen;7.3606\nLargo;27.9088\nPatrocínio;-18.9439\nCampo Mourão;-24.0458\nChaykovskiy;56.7667\nAtambua;-9.1061\nOleksandriia;48.6667\nHengelo;52.2656\nBulacan;14.7928\nBekobod;40.2167\nPuerto Iguazú;-25.6000\nMaple Ridge;49.2167\nLa Louvière;50.4667\nGrosseto;42.7667\nPilar;-34.4588\nSiasi;5.5462\nHarlow;51.7790\nKankakee;41.1020\nPeterborough;44.3000\nJohns Creek;34.0333\nUbay;10.0560\nHengkou;32.7378\nVarese;45.8167\nCaldas;6.0900\nUst’-Ilimsk;58.0000\nAshoknagar;24.5800\nAzov;47.1000\nAracruz;-19.8200\nCampo Limpo;-23.2064\nKadi;23.3009\nTimóteo;-19.5828\nWatampone;-4.5386\nNorderstedt;53.7064\nMannārgudi;10.6653\nXindian;25.3172\nImam Qasim;32.3014\nBargarh;21.3333\nFlagstaff;35.1872\nPlanaltina;-15.4528\nParanavaí;-23.0728\nShuibian;24.1263\nBuhi;13.4347\nAnapa;44.8667\nDessau-Roßlau;51.8333\nKimitsu;35.3304\nMatão;-21.6033\nKentaū;43.5167\nFranklin;35.9200\nItá;-25.4833\nMatalam;7.0833\nKāmāreddipet;18.3205\nAfşin;38.2500\nGobernador Gálvez;-33.0256\nYanggao;21.3298\nLambunao;11.0500\nShiji;23.5607\nSenhor do Bonfim;-10.4628\nAthi River;-1.4500\nNovouralsk;57.2500\nBarili;10.1167\nSan Jose;13.8772\nSefrou;33.8300\nKashiwazaki;37.3719\nPanzos;15.3986\nComitancillo;15.0906\nArni;12.6677\nTaroudannt;30.4710\nKapalong;7.5854\nSint-Niklaas;51.1667\nAquiraz;-3.9008\nSan Cristóbal Verapaz;15.3650\nJoplin;37.0757\nOrihuela;38.0856\nTagoloan;8.5333\nAhenkro;7.1164\nSan Francisco;8.5050\nYonezawa;37.9222\nRandfontein;-26.1797\nBolpur;23.6700\nParma;41.3843\nMalapatan;5.9667\nLayton;41.0770\nLos Patios;7.8333\nMeybod;32.2444\nIpojuca;-8.4000\nBafut;6.0833\nGamagōri;34.8431\nAkiruno;35.7289\nAnderson;34.5211\nSan Ramón;10.2182\nEchizen;35.9035\nNeumünster;54.0714\nSokcho;38.2069\nGumlā;23.0444\nSamā’il;23.3000\nBulanık;39.0950\nRafḩā;29.6386\nPeruvancha;17.3600\nĀdīgala;10.4236\nCalandala;-9.0667\nSimdega;22.6200\nUvinza;-5.1036\nManmād;20.2510\nTākestān;36.0697\nSuramāla;13.7500\nValdemoro;40.1908\nKottagūdem;17.5500\nLívingston;15.8300\nArsikere;13.3139\nMbalmayo;3.5167\nNamsan;42.2275\nZarzis;33.5000\nAndahuaylas;-13.6575\nJamshoro;25.4244\nTall ‘Afar;36.3742\nMeïganga;6.5300\nJaen;15.3392\nBalad;34.0164\nQo‘ng‘irot Shahri;43.0758\nSt. Joseph;39.7598\nPoblacion;6.8000\nMasallātah;32.5822\nVila do Conde;41.3528\nNatori-shi;38.1715\nManresa;41.7264\nSan Carlos del Zulia;9.0000\nPlymouth;45.0225\nKoktokay;47.0004\nKathri;26.4583\nCapenda Camulemba;-9.5647\nFiumicino;41.7667\nPátzcuaro;19.5164\nTurhal;40.3900\nMabai;23.0188\nCalarcá;4.5333\nJinhe;22.7815\nBen Gardane;33.1389\nIdah;7.0833\nRobles;10.3500\nYenakiieve;48.2311\nBaracoa;20.3486\nPatikul;6.0667\nZephyrhills;28.2409\nLangarūd;37.1969\nYalta;44.4994\nJiangna;23.6128\nManhuaçu;-20.2581\nTorres Vedras;39.0833\nTissamaharama;6.2833\nGyōda;36.1389\nFlorence;34.8303\nHannō;35.8557\nAlfenas;-21.4289\nMandiraja Kulon;-7.4722\nMangatarem;15.7874\nPleasanton;37.6663\nKadoma;-18.3400\nPingyi;35.5104\nKrasnyi Luch;48.1333\nEséka;3.6500\nIwamizawa;43.1962\nBauang;16.5333\nDobni Para;22.5200\nBoynton Beach;26.5281\nAfgooye;2.1413\nTīkamgarh;24.7472\nJuventino Rosas;20.6500\nVilla María;-32.4103\nSorgun;39.8144\nSkarżysko-Kamienna;51.1167\nTexarkana;33.4500\nEastleigh;50.9667\nKlin;56.3333\nFolsom;38.6668\nOzërsk;55.7500\nBahārestān;32.4797\nHuaral;-11.5000\nPagbilao;13.9720\nPato Branco;-26.2289\nMooka;36.4404\nBéziers;43.3476\nMadīnat as Sādāt;30.3811\nPototan;10.9500\nSahuayo de Morelos;20.0575\nBamberg;49.8914\nMosigkau;51.8333\nFrancisco Beltrão;-26.0808\nJelenia Góra;50.9033\nTelêmaco Borba;-24.3239\nLimay;14.5619\nPèrèrè;9.7994\nCuamba;-14.8167\nPharr;26.1685\nKoch Bihār;26.3242\nMaizuru;35.4667\nKizugawa;34.7333\nArkonam;13.0778\nHengbei;23.8787\nMacabebe;14.9081\nHomestead;25.4665\nSubulussalam;2.6422\nDelmenhorst;53.0506\nToboali;-2.9997\nEssaouira;31.5131\nTierralta;8.1728\nValdosta;30.8502\nDondo;-19.6167\nAlīgūdarz;33.4006\nKortrijk;50.8333\nArlit;18.7333\nMoju;-1.8839\nUpland;34.1178\nArgao;9.8833\nBamban;15.2742\nBandar Emām;30.4356\nKuvango;-14.4667\nManbij;36.5275\nPattoki;31.0214\nVyborg;60.7106\nDias d’Ávila;-12.6128\nBan Tha Khlong;14.0894\nUsol’ye-Sibirskoye;52.7500\nNewark;40.0706\nElizabethtown;37.7031\nHasselt;50.9305\nSan Pedro Pinula;14.6667\nSt. Augustine;29.8976\nViersen;51.2561\nRancho Cordova;38.5737\nKambam;9.7375\nBustos;14.9500\nQorveh;35.1664\nPéhonko;10.2283\nKropotkin;45.4333\nChino Hills;33.9508\nPinheiro;-2.5208\nChengbin;19.9991\nChitembo;-13.5167\nPerris;33.7898\nBor;56.3500\nBodhan;18.6700\nSchaumburg;42.0308\nNarra;9.2833\nKendall;25.6697\nBalqash;46.8481\nVilla Victoria;19.4333\nFray Bartolomé de Las Casas;15.8456\nLinkou;45.2819\nHermosa;14.8333\nBasavakalyān;17.8744\nRoosendaal;51.5333\nPalencia;42.0167\nCamarillo;34.2230\nNuman;9.4536\nPuli;23.9667\nBebedouro;-20.9494\nKhemis el Khechna;36.6500\nHuebampo;26.6667\nGuildford;51.2365\nAnniston;33.6712\nTrês Rios;-22.1169\nSanta Catalina;9.3331\nSumter;33.9392\nHonjō;36.2436\nArmant;25.6167\nUnaí;-16.3639\nJonesboro;35.8212\nBakhmut;48.5947\nHammond;41.6168\nRheine;52.2833\nMarburg;50.8100\nTecamachalco;18.8667\nSanta Inês;-3.6669\nFuning;39.8879\nManaoag;16.0439\nDaying;37.3043\nUmingan;15.9289\nCarmichael;38.6318\nAraripina;-7.5500\nAş Şuwayrah;32.9403\nVorkuta;67.5000\nHarunabad;29.6130\nFukuchiyama;35.3000\nGelendzhik;44.5750\nArlington Heights;42.0955\nTsubame;37.6731\nBalkh;36.7581\nGandía;38.9667\nNipāni;16.4800\nMorgantown;39.6383\nSiedlce;52.1650\nShūsh;32.1942\nBongabong;12.7469\nTalakag;8.2319\nToyooka;35.5500\nNikkō;36.7198\nDongguan;39.0140\nNagua;19.3800\nAl Musayyib;32.7786\nRyūgasaki;35.9116\nPyapon;16.2860\nKahror Pakka;29.6236\nCaserta;41.0667\nMafra;38.9411\nMontepuez;-13.1167\nAira;31.7283\nFāzilka;30.4030\nSarqan;45.4100\nAit Ali;30.1765\nChernogorsk;53.8167\nTuban;-6.9000\nItapetinga;-15.2489\nEl Viejo;12.6631\nJablah;35.3500\nDschang;5.4500\nBalashov;51.5469\nShostka;51.8657\nGurupi;-11.7289\nDartford;51.4400\nAsti;44.9000\nCotuí;19.0600\nE’erguna;50.2411\nSo-Awa;6.4667\nWyoming;42.8908\nFancheng;39.1891\nGravatá;-8.2008\nKeshod;21.3000\nİdil;37.3410\nPalma Soriano;20.2139\nShājāpur;23.4264\nStakhanov;48.5681\nPalo;11.1583\nCiudad Sandino;12.1667\nNabari;34.6276\nIbiúna;-23.6564\nVenado Tuerto;-33.7500\nSangolquí;-0.3344\nAnzhero-Sudzhensk;56.0833\nTroisdorf;50.8161\nChintāmani;13.4000\nInfanta;14.7425\nPasco;46.2506\nHoumt Souk;33.8667\nSanto Ângelo;-28.2989\nKai;35.6608\nRānāghāt;23.1800\nToyomamachi-teraike;38.6918\nNahāvand;34.1886\nPadre Hurtado;-33.5667\nDaisen;39.4531\nBerdychiv;49.8919\nLod;31.9519\nLins;-21.6786\nSurendranagar;22.7000\nSouthfield;42.4765\nAlcalá de Guadaira;37.3333\nEspinal;4.2000\nSanta Rosa;15.4239\nDayong;22.4707\nQuixadá;-4.9708\nZhlobin;52.9000\nTocumen;9.0800\nPilar;12.9244\nJocotán;14.8167\nSan Ramón de la Nueva Orán;-23.1333\nWausau;44.9620\nGbawe;5.5767\nTailai;46.3909\nRochester Hills;42.6645\nVilla Elisa;-25.5075\nToba Tek Singh;30.9711\nTindivanam;12.2267\nLoveland;40.4166\nPiotrków Trybunalski;51.4000\nJabuticabal;-21.2550\nIju;6.6107\nOvalle;-30.6000\nCatacaos;-5.2653\nRio Largo;-9.4778\nWilhelmshaven;53.5286\nKengtung;21.2917\nXinglong;40.4146\nSrīvilliputtūr;9.5120\nAlexandria;31.2923\nPinamungahan;10.2667\nTiznit;29.7167\nGoiana;-7.5608\nShadrinsk;56.1333\nZhongcheng;28.6014\nPuqiancun;23.5723\nBayreuth;49.9481\nSentani;-2.5636\nArjona;10.2586\nTosu;33.3833\nKyōtanabe;34.8167\nPittsburg;38.0182\nLüneburg;53.2525\nHammond;30.5061\nDubna;56.7333\nSouth Jordan;40.5570\nNakatsugawa;35.4876\nBattle Creek;42.2985\nBethlehem;40.6266\nRedenção;-8.0289\nFajardo;18.3331\nBonāb;37.3428\nSapiranga;-29.6378\nGangammapeta;18.3330\nTirumangalam;9.8216\nMangalagiri;16.4300\nKawartha Lakes;44.3500\nBombo;0.5778\nLibon;13.3000\nSasagawa;37.2865\nItapira;-22.4361\nCarpina;-7.8500\nCiudad Real;38.9833\nBugallon;15.9167\nAmbājogāi;18.7300\nGūdūr;14.1473\nAcacías;3.9878\nApple Valley;34.5352\nĪṭahari̇̄;26.6631\nPozorrubio;16.1167\nArdakān;32.3061\nPalencia;14.6676\nAfak;32.0625\nDabra;25.8857\nTatebayashi;36.2448\nMolina de Segura;38.0548\nDorsten;51.6600\nGela;37.0667\nTura;25.5200\nDĩ An;10.9039\nDalaguete;9.7612\nTongye;37.9679\nWheeling;40.0752\nFlower Mound;33.0343\nEstepona;36.4264\nWisil;5.4333\nHoorn;52.6500\nAmakusa;32.4667\nSão Bento do Sul;-26.2500\nSamundri;31.0639\nEsperanza;6.7167\nHarrisonburg;38.4362\nBalingasag;8.7500\nToffo;6.8500\nCastrop-Rauxel;51.5500\nWandiwāsh;12.5000\nKandori;35.6833\nPéda-Houéyogbé;6.4500\nGravesend;51.4415\nCedar Park;30.5105\nDarhan;49.6167\nOshkosh;44.0227\nPiraçununga;-21.9961\nTanguiéta;10.6167\nMiki;34.7936\nGrand-Bassam;5.2000\nStanderton;-26.9500\nCopacabana;6.3333\nSan Juan Opico;13.8833\nNizhyn;51.0474\nAprilia;41.5833\nWinchester;39.1735\nBozüyük;39.9078\nSkellefteå;64.7500\nCanindé;-4.3589\nDumangas;10.8333\nNovoaltaysk;53.3833\nSaquarema;-22.9200\nEllicott City;39.2774\nOuaké;9.6617\nDetmold;51.9378\nPalmeira dos Índios;-9.4069\nPocatello;42.8724\nAlicia;16.7787\nJoão Monlevade;-19.8100\nPedro Brand;18.5667\nMajalengka;-6.8353\nUspantán;15.3458\nBongouanou;6.6500\nRāmhormoz;31.2800\nTatsunochō-tominaga;34.8508\nTarn Tāran;31.4519\nKhomeyn;33.6422\nÇınar;37.7242\nHilton Head Island;32.1896\nCurvelo;-18.7558\nMineral’nyye Vody;44.2167\nCherry Hill;39.9034\nLandshut;48.5397\nAlmelo;52.3500\nMankono;8.0500\nHāveri;14.7935\nMeshgīn Shahr;38.3972\nKara-Balta;42.8333\nVriddhāchalam;11.5000\nAl Qā’im;34.3688\nOuro Prêto;-20.3853\nYelabuga;55.7667\nKallakkurichchi;11.7380\nMajadahonda;40.4728\nSharm ash Shaykh;27.9122\nBrookes Point;8.7833\nSanta Rosa;-27.8708\nKonin;52.2167\nMansfield;40.7656\nWoodbury;44.9057\nArnsberg;51.3833\nPrince George;53.9169\nKostiantynivka;48.5333\nSamadiāla;21.3422\nNova Serrana;-19.8667\nLala;7.9667\nLehi;40.4136\nYurihonjō;39.3859\nInuyama;35.3786\nTürkoğlu;37.3914\nCunhinga;-12.2333\nBawku;11.0500\nYegoryevsk;55.3833\nKasama;36.3452\nBolingbrook;41.6901\nChaigoubu;40.6687\nBeyşehir;37.6764\nGobindgarh;30.6709\nTupi;6.3333\nSiuna;13.7347\nBrick;40.0600\nDale City;38.6473\nPattukkottai;10.4300\nMérignac;44.8386\nMissouri City;29.5630\nLinares;-35.8500\nMysłowice;50.2333\nJingzhou;37.6911\nIrecê;-11.3039\nShrewsbury;52.7080\nQuillota;-32.8667\nTroitsk;54.0833\nBula;13.4694\nPicos;-7.0769\nEl Hamma;33.8864\nBandar-e Genāveh;29.5839\nLanxi;46.2664\nPaterna;39.5028\nBagan Si Api-api;2.1667\nJose Abad Santos;5.9167\nLa Estrella;6.1667\nMackay;-21.1411\nBrakpan;-26.2353\nLake Jackson;29.0516\nZhuolu;40.3753\nKirovo-Chepetsk;58.5500\nVinhedo;-23.0300\nSödertälje;59.1958\nLüdenscheid;51.2167\nOstrowiec Świętokrzyski;50.9333\nAltoona;40.5082\nChapadinha;-3.7419\nShibukawa;36.3894\nSault Ste. Marie;46.5333\nNepālgañj;28.0500\nBelek;36.8500\nCarles;11.5667\nReconquista;-29.1443\nOstend;51.2258\nSan Fernando;10.1667\nFarroupilha;-29.2250\nWenping;27.1930\nSangāreddi;17.6294\nTokār;18.4253\nShakargarh;32.2628\nTan-Tan;28.4333\nSambrial;32.4750\nChapayevsk;52.9833\nSanta Rosa de Cabal;4.8667\nMoa;20.6397\nŌtawara;36.8711\nDoral;25.8152\nOwensboro;37.7575\nBaghlān;36.1328\nNaqadeh;36.9547\nLuján de Cuyo;-32.9980\nEsbjerg;55.4833\nBacacay;13.2925\nMorong;14.5119\nSanwal;27.6061\nCatanauan;13.5917\nAlegrete;-29.7839\nÇatalca;41.1417\nVsevolozhsk;60.0333\nTürkmenbaşy;40.0167\nSotik;-0.6800\nPalín;14.4039\nPadre Las Casas;-38.7667\nSan Vicente del Caguán;2.1167\nBelovo;54.4167\nXiangjiaba;28.6282\nVirudunagar;9.5680\nSaint-Nazaire;47.2736\nBakıxanov;40.4217\nHương Trà;16.4675\nTrês Corações;-21.6947\nTocoa;15.6833\nPacatuba;-3.9839\nSiruguppa;15.6000\nAmparo;-22.7031\nCrateús;-5.1778\nPavia;45.1853\nEde;52.0500\nAracati;-4.5619\nBrandenburg;52.4167\nBroomfield;39.9542\nKeshan;48.0263\nYafran;32.0629\nRedlands;34.0512\nSipalay;9.7500\nPenafiel;41.2060\nCamalig;13.1333\nCleveland;35.1817\nPililla;14.4833\nLa Lima;15.4330\nConcepción del Uruguay;-32.4833\nBelo Jardim;-8.3358\nPigcawayan;7.2833\nAschaffenburg;49.9667\nDambulla;7.8578\nZogbodomé;7.0833\nMelton;-37.6833\nLong Mỹ;9.6814\nPiła;53.1500\nOstrów Wielkopolski;51.6494\nDothan;31.2336\nPatzún;14.6833\nCajamar;-23.3558\nNilanga;18.1161\nGoya;-29.1333\nGumaca;13.9210\nWarora;20.2300\nTurbaná;10.2833\nLajeado;-29.4669\nIshioka;36.1908\nCasa Nova;-9.1619\nRedmond;47.6763\nSaymayl;36.8583\nShahrixon;40.7167\nNanfengcun;23.7460\nColón;22.7225\nFarshūţ;26.0549\nTibati;6.4667\nCremona;45.1333\nFramingham;42.3085\nMyaydo;19.3667\nSanto Tirso;41.3333\nCalauag;13.9575\nAl Līth;20.1500\nBelo Tsiribihina;-19.7000\nNadi;-17.8000\nMerzifon;40.8750\nJackson;35.6538\nKawm Umbū;24.4667\nMun’gyŏng;36.5939\nYukuhashi;33.7333\nQuixeramobim;-5.1989\nJanesville;42.6854\nValença;-22.2458\nMandlā;22.6000\nBouaflé;6.9833\nRāyadrug;14.6997\nBinalbagan;10.2000\nTalibon;10.1167\nParang;5.9167\nJuana Díaz;18.0532\nLubin;51.4000\nDondo;-9.6942\nFlorida;21.5294\nGoa;13.6983\nAlexandroúpoli;40.8500\nBocholt;51.8333\nCarpi;44.7833\nKatori;35.8977\nRāyagada;19.1700\nTenkāsi;8.9564\nLisburn;54.5167\nQuartu Sant’Elena;39.2413\nBunbury;-33.3272\nSarnia;42.9994\nWood Buffalo;57.6042\nBenidorm;38.5342\nBāpatla;15.9044\nIzmail;45.3517\nMārkāpur;15.7300\nShujaabad;29.8803\nOrani;14.8000\nSan Francisco del Rincón;21.0228\nGanthier;18.5333\nKaukhāli;22.6333\nVilla Tunari;-16.9747\nMansfield;32.5690\nMalaut;30.1900\nIzalco;13.7333\nRatangarh;28.0787\nKonongo;6.6167\nHuwei;23.7200\nPlacetas;22.3158\nVerkhnyaya Pyshma;56.9761\nWaukesha;43.0087\nWarzat;30.9167\nCabudare;10.0331\nMelong;5.1211\nYinying;37.9410\nMauban;14.1911\nAyvalık;39.3167\nGibara;21.1072\nÉrd;47.3784\nEntebbe;0.0500\nBaiquan;47.6018\nFatehābād;29.5200\nAliaga;15.5036\nAn Nu‘mānīyah;32.5000\nMinxiong;23.5504\nCorozal;9.3333\nWenatchee;47.4360\nBundaberg;-24.8661\nThohoyandou;-22.9500\nDjemmal;35.6400\nDaytona Beach;29.1995\nCastle Rock;39.3763\nPan’an;34.7575\nKopargo;9.8375\nSankaranayinār Kovil;9.1600\nMoriya;35.9514\nRittō;35.0167\nHujra Shah Muqim;30.7408\nTumauini;17.2667\nEjura;7.3833\nSan Marcos;29.8734\nBadvel;14.7500\nCaçador;-26.7750\nEsperanza;19.5800\nUnion City;37.6032\nKabirwala;30.4053\nChâteauguay;45.3800\nNovomoskovsk;48.6328\nRizal;15.7100\nZenica;44.2017\nLoulé;37.1500\nStafford;52.8070\nVālpārai;10.3276\nKladno;50.1500\nAltamura;40.8167\nSūratgarh;29.3177\nChekhov;55.1500\nEldersburg;39.4041\nXangongo;-16.7467\nTogoch’alē;9.6014\nConway;35.0753\nBūr Fu’ād;31.2500\nSão Sebastião do Paraíso;-20.9169\nCaldas Novas;-17.7439\nDandeli;15.2667\nBopa;6.5833\nKovel;51.2167\nSanta María La Pila;15.6056\nTinambac;13.8183\nSan Pascual;13.8000\nImerintsiatosika;-18.9833\nGuzhou;25.9452\nEniwa;42.8826\nSesvete;45.8269\nRongcheng;39.0500\nZhanggu;30.8795\nRocklin;38.8075\nRohri;27.6831\nImola;44.3531\nLimonade;19.6667\nSheboygan;43.7403\nCasas Adobes;32.3423\nSt. Charles;38.7954\nRhondda;51.6159\nSatyamangalam;11.5167\nKempten;47.7333\nVilla del Rosario;7.8339\nSanlúcar de Barrameda;36.7667\nAz Zubaydīyah;32.7588\nPhú Quốc;10.2289\nRaha;-4.8311\nAl ‘Āmirāt;23.5242\nOshnavīyeh;37.0389\nNihtaur;29.3300\nFanzhuang;37.7771\nCahama;-16.2833\nCianorte;-23.6628\nNansang;20.8889\nShangchuankou;36.3283\nQuilāndi;11.4390\nBadhan;10.7139\nCelle;52.6256\nNikki;9.9333\nVictoria;15.5781\nQingquan;38.7823\nGarzón;2.1819\nIsnā;25.3000\nMinami-Alps;35.6083\nSaldanha;-32.9978\nMaple Grove;45.1089\nCataguases;-21.3889\nTournai;50.6056\nRussas;-4.9400\nWalnut Creek;37.9024\nDublin;37.7161\nNorth Richland Hills;32.8604\nSan Juan de los Lagos;21.2489\nSolok;-0.7883\nUwajima;33.2167\nNowrangapur;19.2300\nMassa;44.0333\nSuwałki;54.0989\nGary;41.5905\nGlen Burnie;39.1560\nColmar;48.0817\nBristol;36.5572\nDecatur;34.5731\nVelsen-Zuid;52.4667\nYitiaoshan;37.1889\nRoxas;10.3197\nWest Bend;43.4173\nSan Pedro;-33.6794\nIndang;14.2000\nMacaíba;-5.8578\nSaint-Jérôme;45.7833\nDon Carlos;7.6808\nKollegāl;12.0628\nSamch’ŏk;37.4500\nLa Paz;15.4431\nGniezno;52.5358\nFedosiia;45.0489\nBom Jesus da Lapa;-13.2550\nCawayan;11.9303\nFernandópolis;-20.2839\nAnan;33.9167\nPoptún;16.3222\nSabae;35.9565\nLodi;38.1218\nOngjang;37.9371\nLima;40.7410\nFlorida;18.3643\nMansehra;34.3339\nChisec;15.8125\nAqsū;52.0333\nPlaneta Rica;8.4089\nYanghe;38.2727\nKorba;36.5667\nBafia;4.7500\nKo Samui;9.5000\nBrumado;-14.2039\nPongnam;37.2200\nLiuhe;42.2669\nKamsar;10.6500\nFulda;50.5508\nParādīp Garh;20.3160\nMamungan;8.1167\nHuishi;35.6918\nAd Darb;17.7167\nNecoclí;8.4167\nMocuba;-16.8500\nMinusinsk;53.7000\nRenk;11.8300\nAparri;18.3575\nSmila;49.2167\nMococa;-21.4678\nTanabe;33.7333\nBagumbayan;6.5339\nOliveira de Azemeis;40.8400\nBuenavista;8.9744\nPurísima de Bustos;21.0333\nLakeville;44.6774\nMocuba;-16.8496\nBlaine;45.1696\nArcoverde;-8.4189\nSan Leonardo;15.3611\nWagga Wagga;-35.1189\nStargard Szczeciński;53.3333\nTianguá;-3.7319\nSay’ūn;15.9430\nPālghar;19.6900\nDinslaken;51.5667\nPoinciana;28.1217\nSousa;-6.7608\nAl Aḩmadī;29.0769\nNoblesville;40.0355\nWum;6.3833\nSan Pedro Ayampuc;14.7785\nSōja;34.6728\nNghĩa Lộ;21.5758\nPanna;24.7200\nAalen;48.8333\nLake Elsinore;33.6847\nGłogów;51.6589\nTangub;8.0667\nIlkal;15.9592\nBay;14.1833\nAlamada;7.3868\nConcórdia;-27.2339\nCannock;52.6910\nBeypore;11.1800\nJarabacoa;19.1167\nSwedru;5.5306\nŌdate;40.2714\nZapotlanejo;20.6228\nPalo Alto;37.3905\nDoboj;44.7333\nCastillejos;14.9333\nIgbanke;6.3869\nLippstadt;51.6667\nDrummondville;45.8833\nSagunto;39.6764\nMbaké;14.7917\nNābha;30.3700\nMiagao;10.6442\nOtukpo;7.1904\nTuburan;10.7333\nSipocot;13.7675\nSanza Pombo;-7.3333\nTulare;36.1995\nCuyapo;15.7778\nLala Musa;32.7003\nAsh Shiḩr;14.7608\nRogers;36.3170\nIxtlahuacán de los Membrillos;20.3500\nYorba Linda;33.8890\nRenukūt;24.2000\nTuymazy;54.6000\nChengjiao Chengguanzhen;34.4362\nBishnupur;23.0739\nLodja;-3.5242\nCeará-Mirim;-5.6339\nParkersburg;39.2623\nZamość;50.7167\nConceição do Coité;-11.5639\nXinhua;23.6272\nEagan;44.8170\nRājsamand;25.0700\nBergen op Zoom;51.5000\nGopālganj;26.4700\nWeston;26.1006\nSanta Barbara;10.8231\nUrun-Islāmpur;17.0500\nModāsa;23.4700\nLa Barca;20.2833\nPrzemyśl;49.7833\nTalipparamba;12.0368\nWanzhuang;39.5683\nMalkāpur;20.8850\nZanhuang;37.6590\nDhenkānāl;20.6700\nKstovo;56.1667\nViterbo;42.4186\nLongview;46.1461\nTzaneen;-23.8333\nTrapani;38.0175\nAntalaha;-14.8833\nBay City;43.5902\nDubuque;42.5002\nTepotzotlán;19.7161\nPorterville;36.0643\nFranklin;40.4759\nEtāwa;24.1800\nLongshan;26.4519\nXo‘jayli Shahri;42.4000\nMount Vernon;48.4203\nUllāl;12.8000\nPalatine;42.1180\nFuefuki;35.6473\nEmbu-Guaçu;-23.8322\nİslahiye;37.0250\nRosales;15.8944\nChicacao;14.5428\nSouthampton;40.8997\nEl Paso de Robles;35.6394\nSausar;21.6500\nYuquan;40.4202\nWest Des Moines;41.5521\nKashima;35.9656\nSanta Catarina Otzolotepec;18.5667\nManaure;11.7792\nLushar;36.4971\nSaint John;45.2806\nTôlan̈aro;-25.0325\nHashima;35.3199\nAyolas;-27.4000\nZihuatanejo;17.6444\nSahaswān;28.0680\nSa’ada;31.6258\nOmīdīyeh;30.7458\nSiddipet;18.1018\nHerford;52.1333\nCuilco;15.4078\nKissidougou;9.1905\nKoratla;18.8215\nGuangping;36.4791\nAnkazoabokely;-21.5036\nWeiyuan;36.8413\nChegutu;-18.1400\nVenustiano Carranza;16.3000\nPelileo;-1.3306\nYachimata;35.6667\nCaicó;-6.4578\nTejen;37.3833\nAgoo;16.3220\nItamaraju;-17.0389\nRüsselsheim;49.9950\nRio Negro;-26.1000\nHobyo;5.3514\nCosmópolis;-22.6458\nSupaul;26.1260\nMoita;38.6500\nSan Mateo;16.8833\nSherman;33.6273\nTabatinga;-4.2525\nDolores Hidalgo Cuna de la Independencia Nacional;21.1516\nIlidža;43.8167\nAflao;6.1468\nJaniuay;10.9500\nKānhangād;12.3000\nLa Carlota;10.4167\nCastro;-24.7908\nVidnoye;55.5500\nRockville;39.0834\nHaverhill;42.7838\nBongabon;15.6321\nLupon;6.8969\nRío Grande;-53.7833\nGüines;22.8475\nHanover;39.8118\nShawnee;39.0158\nFukutsu;33.7667\nVirginia;-28.1064\nMiddletown;40.3892\nCedeño;6.7100\nRome;34.2662\nGodalming;51.1800\nNueva Guinea;11.6867\nCoonoor;11.3450\nPessac;44.8067\nOld Bridge;40.4004\nGohna;29.1300\nEl Seibo;18.7630\nPabianice;51.6500\nKerpen;50.8719\nArcot;12.9000\nCapanema;-1.1958\nGenk;50.9662\nJanaúba;-15.8028\nBulancak;40.9333\nBotolan;15.2896\nPulivendla;14.4167\nÇumra;37.5750\nBorås;57.7211\nArāmbāgh;22.8800\nHīt;33.6450\nSouth Hill;47.1198\nOpol;8.5167\nKarimama;12.0667\nOcoyoacac;19.2739\nBelogorsk;50.9167\nQarqan;38.1338\nPidugurālla;16.4793\nGwacheon;37.4333\nDeKalb;41.9314\nPetaluma;38.2423\nSaiki;32.9667\nIshim;56.1167\nSammamish;47.6017\nSan Antonio Suchitepéquez;14.5333\nGeorgetown;30.6660\nValence;44.9333\nAngat;14.9281\nCaledon;43.8667\nGukovo;48.0500\nXieqiaocun;30.4973\nCarbondale;37.7221\nUrla;38.3222\nKavála;40.9333\nRechytsa;52.3639\nSan Remigio;11.0000\nDelray Beach;26.4550\nDundalk;39.2704\nPuliyankudi;9.1725\nHuquan;39.7603\nKalush;49.0442\nKenner;30.0109\nShiojiri;36.1150\nAlbany;44.6272\nZeist;52.0906\nSlavyansk-na-Kubani;45.2500\nAnkeny;41.7288\nIlo;-17.6459\nItaberaba;-12.5278\nOas;13.2589\nMalvar;14.0417\nCastro Valley;37.7088\nBethesda;38.9866\nSaratoga Springs;43.0674\nKampung Tengah;1.4897\nKazanlak;42.6167\nDangbo;6.5000\nKungur;57.4333\nLençóis Paulista;-22.5986\nRoxas;17.1167\nOberá;-27.4833\nLantapan;8.0000\nUnião dos Palmares;-9.1628\nChibok;10.8697\nSingaparna;-7.3497\nSangamner;19.5700\nSan Gil;6.5592\nSindelfingen;48.7133\nDon Torcuato;-34.5000\nCorvallis;44.5698\nSeraing;50.5833\nEl Carmen de Bolívar;9.7167\nStupino;54.8833\nMost;50.5031\nAsenovgrad;42.0167\nMadirovalo;-16.4333\nVenâncio Aires;-29.6058\nAmes;42.0256\nTigbauan;10.6747\nGlens Falls;43.3109\nSan Francisco El Alto;14.9500\nXibang;30.9412\nLahat;-3.7970\nKiamba;5.9833\nAnamur;36.0243\nCoron;12.0000\nMichigan City;41.7092\nMenzel Temime;36.7833\nWeimar;50.9833\nVillasis;15.9000\nSanto Tomé;-31.6667\nNeuwied;50.4286\nLutayan;6.6000\nGopichettipālaiyam;11.4549\nNieuwegein;52.0333\nXiantangcun;23.7940\nIna;35.8275\nSirsi;28.6400\nTupã;-21.9350\nSolano;16.5183\nDhūri;30.3685\nJagraon;30.7800\nDaule;-1.8667\nNagcarlan;14.1364\nZarechnyy;53.2000\nBordj Menaïel;36.7417\nIstaravshan;39.9108\nVictoria;28.8287\nSinnar;19.8500\nLadysmith;-28.5597\nVillach;46.6167\nBourges;47.0844\nAlīpur Duār;26.4890\nTorquay;50.4700\nPurulhá;15.2353\nGloucester;39.7924\nSt. Albert;53.6303\nRoeselare;50.9447\nFerrol;43.4844\nBāqershahr;35.5325\nXarardheere;4.6544\nJocotitlán;19.7072\nRāth;25.5800\nVaijāpur;19.9200\nLos Amates;15.2667\nIcó;-6.4008\nBeloretsk;53.9667\nJaisalmer;26.9167\nJanuária;-15.4878\nWeirton;40.4060\nTāndūr;17.2300\nIshimbay;53.4500\nLeszno;51.8458\nPeruíbe;-24.3100\nĀrān Bīdgol;34.0575\nKorosten;50.9500\nJamjamāl;35.5333\nBirnin Konni;13.7904\nNovi;42.4786\nDeveli;38.3886\nQuezon;9.2350\nIdappādi;11.5835\nVilla Curuguaty;-24.4800\nDormagen;51.1000\nPlauen;50.4833\nSandefjord;59.1306\nPālitāna;21.5200\nOdendaalsrus;-27.8667\nChunian;30.9639\nḨalabjah;35.1833\nViana;-20.3900\nRosenheim;47.8500\nMarinilla;6.1738\nAlpharetta;34.0704\nFormiga;-20.4639\nMecheria;33.5500\nWesley Chapel;28.2106\nEsquipulas;14.6167\nCaripito;10.1124\nMaasin;5.8667\nPokrovsk;48.2828\nBan Lam Sam Kaeo;13.9728\nSvyetlahorsk;52.6333\nMarovoay;-16.1111\nSoloma;15.7167\nBāzār-e Yakāwlang;34.7333\nRa’s al Khafjī;28.4167\nChiquimulilla;14.0858\nItō;34.9657\nTādepalle;16.4833\nBucak;37.4592\nDonskoy;53.9658\nYanagawa;33.1597\nMiyoshi;35.0894\nIsabela;10.2000\nSaravia;10.8833\nBertioga;-23.8539\nHilongos;10.3667\nNeubrandenburg;53.5569\nGadwāl;16.2300\nYattir;31.4478\nSibulan;9.3500\nJatani;20.1700\nChipindo;-13.8244\nSeydişehir;37.4183\nKodād;16.9978\nSanto Domingo Tehuantepec;16.3184\nMeulaboh;4.1333\nChokwé;-24.5253\nBinga;2.4000\nWaltham;42.3889\nSodegaura;35.4300\nCruz das Almas;-12.6700\nRahat;31.3925\nSan Felipe;-32.7500\nTamana;32.9281\nApaseo el Alto;20.4500\nLaguna Niguel;33.5275\nHiriyūr;13.9446\nSan Clemente;33.4499\nQinggang;46.6900\nVittoria;36.9500\nPirané;-25.7328\nGrevenbroich;51.0883\nDhuburi;26.0200\nAtimonan;14.0036\nNānpāra;27.8700\nLingshou;38.3063\nSantiago Tianguistenco;19.1797\nNawalgarh;27.8500\nEstância;-11.2678\nTenri;34.5967\nNorth Little Rock;34.7807\nIrún;43.3378\nFraijanes;14.4622\nOuricuri;-7.8828\nPomezia;41.6693\nTohāna;29.7000\nCiénaga de Oro;8.8833\nSamāstipur;25.8629\nSalto de Agua;17.4167\nCrotone;39.0833\nGhardimaou;36.4500\nBamei;24.2634\nTuao;17.7350\nSangmélima;2.9333\nSheikhpura;25.1403\nNawá;32.8889\nAt Tall;33.6000\nAsbest;57.0000\nPóvoa de Varzim;41.3800\nNiksar;40.5833\nPenedo;-10.2900\nFairbanks;64.8353\nSibalom;10.7883\nTiquisate;14.2833\nKangbao;41.8513\nMāhdāsht;35.7194\nMaidenhead;51.5217\nSimav;39.0833\nEden Prairie;44.8488\nArmūr;18.7900\nWest Hartford;41.7669\nQuimper;47.9967\nLugano;46.0050\nChik Ballāpur;13.4300\nPflugerville;30.4515\nAsahi;35.7167\nSanta Cruz;15.7667\nYangqingcun;21.3594\nTsuruga;35.6452\nPonferrada;42.5461\nCasper;42.8420\nJose Pañganiban;14.2922\nBoadilla del Monte;40.4069\nVigevano;45.3167\nBurnsville;44.7648\nAthni;16.7300\nKlintsy;52.7500\nMidoun;33.8000\nSittingbourne;51.3400\nBognor Regis;50.7824\nZvornik;44.3833\nBhairāhawā;27.5000\nSherkot;29.3500\nNankana Sahib;31.4500\nDikirnis;31.0883\nWoking;51.3050\nZarand;30.8128\nKurihara;38.7301\nGrand Forks;47.9214\nRanders;56.4570\nVelika Gorica;45.7000\nEscada;-8.3592\nChincha Alta;-13.4500\nVisnagar;23.7000\nGuiglo;6.5500\nBrentwood;37.9356\nTajumulco;15.0839\nGraaff-Reinet;-32.2522\nHerten;51.6000\nMoncada;15.7331\nWenxicun;28.1565\nAïn Sefra;32.7500\nGalgamuwa;8.0000\nRouiba;36.7333\nBhabhua;25.0500\nBudënnovsk;44.7833\nBadr Ḩunayn;23.7800\nKhulayş;22.1539\nAsaka;40.6333\nGreenwich;41.0665\nRolândia;-23.3100\nGranby;45.4000\nMillcreek;40.6892\nCarrara;44.0792\nShiroi;35.7915\nElmira;42.0938\nBalboa Heights;8.9500\nNago;26.5917\nMercedes;-34.6500\nSanto Antônio do Descoberto;-15.9400\nWundanyi;-3.3983\nRānipet;12.9247\nSebring;27.4770\nChełm;51.1322\nAbū Qurqāş;27.9333\nCoon Rapids;45.1755\nMedicine Hat;50.0417\nBannu;32.9864\nVolsk;52.0500\nTartagal;-22.5000\nMeshkīn Dasht;35.7469\nKaga;36.3028\nWāshīm;20.1000\nQurayyāt;23.3200\nBossier City;32.5224\nNovaya Balakhna;56.4899\nGrande Prairie;55.1708\nKōshizuka;32.8860\nOudtshoorn;-33.5833\nBansalan;6.7833\nSan Fernando;7.9178\nHamilton;39.3939\nChidambaram;11.4070\nItupeva;-23.1531\nŁomża;53.1764\nCalinog;11.1333\nSanta Ana;15.0939\nTaylor;42.2260\nPuerto Asís;0.5167\nLower Merion;40.0282\nÇaldıran;39.1419\nBatatais;-20.8911\nKasongo;-4.4500\nSirsi;14.6195\nSão Borja;-28.6608\nPesqueira;-8.3617\nLakewood;47.1628\nPalmela;38.5667\nFujioka;36.2587\nYurimaguas;-5.9000\nLāharpur;27.7200\nGreenwood;39.6019\nTighenif;35.4167\nNkawkaw;6.5500\nBellevue;41.1485\nPavlovskiy Posad;55.7667\nMut;36.6333\nCruz Alta;-28.6386\nRossosh;50.2000\nWidnes;53.3630\nKapatagan;7.9000\nSumbawa Besar;-8.5000\nBodītī;6.8667\nCamaquã;-30.8528\nMargate;51.3850\nOriximiná;-1.7658\nŻory;50.0500\nKolomyia;48.5167\nQoryooley;1.7833\nRevda;56.8053\nAnse à Galets;18.8333\nBorisoglebsk;51.3667\nKotlas;61.2500\nDeva;45.8781\nZelenogorsk;56.1000\nBainet;18.1833\nCamboriú;-27.0250\nMoore;35.3293\nShangtangcun;21.5989\nCouncil Bluffs;41.2369\nRowlett;32.9155\nEl Wak;2.8028\nMobārakeh;32.3464\nLeninogorsk;54.6000\nŢūlkarm;32.3117\nBerekum;7.4500\nSpring;30.0613\nWels;48.1500\nNarwāna;29.6167\nKayes;-4.1681\nPort Charlotte;26.9918\nTendō;38.3623\nMenzel Bourguiba;37.1500\nVilla Carlos Paz;-31.4000\nBensalem;40.1086\nReston;38.9497\nBergheim;50.9667\nTefé;-3.3539\nKolding;55.4917\nFriedrichshafen;47.6500\nRiosucio;5.4208\nSiddhapur;23.9167\nNanjangūd;12.1200\nTarnowskie Góry;50.4444\nSan Juan Chamelco;15.4257\nBoryspil;50.3500\nCaràzinho;-28.2839\nCaltanissetta;37.4903\nMeihua;37.8862\nKatueté;-24.2481\nDearborn Heights;42.3164\nTuapse;44.1044\nPuerto Peñasco;31.3167\nAurora;13.3500\nFigueira da Foz;40.1500\nAnalavory;-18.9667\nChistopol;55.3647\nCamotán;14.8167\nItoman;26.1236\nPort Orange;29.1085\nOgōshi;32.8833\nPenápolis;-21.4200\nItapecuru Mirim;-3.3928\nHorsens;55.8583\nEncinitas;33.0492\nSpringfield;44.0538\nMitoyo;34.1825\nIpirá;-12.1578\nGreat Falls;47.5022\nAsker;59.8331\nCambanugoy;7.5386\nNaro-Fominsk;55.3833\nGrajaú;-5.8189\nMorada Nova;-5.1069\nOstuncalco;14.8693\nPacajus;-4.1728\nViareggio;43.8672\nBaao;13.4535\nJhārgrām;22.4500\nRāmanāthapuram;9.3639\nManicaragua;22.1500\nZaraza;9.3394\nCandon;17.1958\nSan Francisco;-31.4356\nQiryat Gat;31.6061\nRocky Mount;35.9685\nLa Democracia;15.6333\nAr Rastan;34.9167\nSan Antonio del Táchira;7.8145\nDiphu;25.8300\nSanto Domingo;15.5900\nPolevskoy;56.4500\nPlato;9.7919\nYangiyŭl;41.1125\nSätbayev;47.9000\nPiripiri;-4.2728\nSarandí;-34.6833\nDerik;37.3658\nMielec;50.2833\nSchwäbisch Gmünd;48.8000\nHita;33.3167\nAisai;35.1528\nSanto Amaro;-12.5469\nMontauban;44.0181\nSão Miguel dos Campos;-9.7808\nKapchagay;43.8833\nCamabatela;-8.1833\nLysva;58.1003\nIlobasco;13.8400\nTríkala;39.5500\nCoroatá;-4.1300\nXinmin;35.1180\nFairfield;41.1775\nSungo;-11.2333\nRubizhne;49.0336\nSt. Thomas;42.7750\nSayyid Şādiq;35.3536\nOrion;14.6206\nSibay;52.7000\nSawahlunto;-0.6828\nCabatuan;10.8833\nItogon;16.3700\nOffenburg;48.4667\nWanparti;16.3623\nHato Mayor;18.7667\nAirdrie;51.2917\nSanta Catarina Ixtahuacán;14.8000\nDjibo;14.1011\nIztapa;13.9331\nCajazeiras;-6.8900\nUzunköprü;41.2669\nGarbsen;52.4183\nCommerce City;39.8641\nAraranguá;-28.9350\nPontiac;42.6493\nKozluk;38.1944\nFano;43.8333\nUdamalpet;10.5855\nWellington;26.6461\nSlutsk;53.0333\nRio do Sul;-27.2139\nKhagaria;25.5022\nVacaria;-28.5119\nHürth;50.8775\nTigaon;13.6319\nDumraon;25.5526\nNordre Fåle;59.7500\nAbuyog;10.7458\nKindamba;-3.7275\nBarberena;14.3167\nAcaraú;-2.8858\nBocaranga;6.9844\nWesel;51.6586\nTrollhättan;58.2828\nHalton Hills;43.6300\nHamden;41.3961\nSan Rafael;37.9905\nTulunan;6.8333\nAdjohon;6.7000\nNahariyya;33.0058\nObando;14.7083\nChāmrājnagar;11.9231\nIdiofa;-4.9668\nGaibandha;25.3290\nSkhirate;33.8500\nNavegantes;-26.8989\nRosario;16.2333\nBarabai;-2.5833\nPanruti;11.7700\nNekā;36.6508\nCampo Bom;-29.6789\nYongyang;27.1017\nJinoba-an;9.6018\nAcerra;40.9500\nBurhaniye;39.5000\nMalay;11.8997\nPlymouth;41.8783\nWoodland;38.6712\nMarietta;33.9533\nCastilla;12.9553\nTamba;35.1833\nOda;5.9236\nAl Qurayyā;35.0025\nChapel Hill;35.9271\nChalkída;38.4625\nVelampālaiyam;11.1376\nNambuangongo;-8.0167\nSennan;34.3628\nVillamaría;5.0000\nLaoang;12.5667\nCubulco;15.1083\nTomaszów Mazowiecki;51.5167\nShihe;39.2708\nDongcun;38.2800\nMatanao;6.7500\nMeriden;41.5369\nKoga;33.7333\nCalulo;-10.0007\nGubat;12.9189\nBristol;41.6812\nStralsund;54.3092\nIgarapé-Miri;-1.9750\nZamora;41.5033\nIbitinga;-21.7578\nPalm Harbor;28.0847\nDruzhkivka;48.6203\nLangenfeld;51.1167\nAutlán de Navarro;19.7667\nSavona;44.3080\nJupiter;26.9200\nHendersonville;36.3063\nKangān;27.8389\nPiscataway;40.5467\nSan Vicente del Raspeig;38.3964\nBełchatów;51.3667\nRāzampeta;14.1954\nAtotonilco el Alto;20.5333\nMatera;40.6667\nNeu-Ulm;48.3833\nMirassol;-20.8189\nGreifswald;54.0833\nHashimoto;34.3167\nKumertau;52.7667\nPonnūru;16.0667\nParacale;14.2797\nYongbei;26.6897\nRzhev;56.2500\nMolfetta;41.2000\nÇivril;38.3014\nClay;43.1808\nConsuelito;18.5600\nBelladère;18.8667\nSão Gabriel;-30.3358\nKakuma;3.7167\nMossel Bay;-34.1833\nMedellin;11.1286\nOlbia;40.9167\nJiguaní;20.3731\nDes Plaines;42.0345\nArankhola;24.6610\nParkent;41.2944\nSayanogorsk;53.0500\nBor;37.8833\nLakhdaria;36.5622\nMaimbung;5.9333\nKathua;32.3850\nEsmeraldas;-19.7628\nBarneveld;52.1333\nYame;33.1994\nSan Mateo Ixtatán;15.8333\nNorth Lakhimpur;27.2414\nAfula;32.6064\nManhiça;-25.4000\nBenevento;41.1333\nBelebey;54.1000\nBābolsar;36.7025\nLabinsk;44.6333\nLianzhuang;37.1146\nSanford;28.7891\nSan Simon;14.9980\nCamocim;-2.9019\nGarín;-34.4167\nGunupur;19.0800\nShimotsuke;36.3872\nAlfonso;14.1379\nChandralapādu;16.7150\nUrus-Martan;43.1333\nĀbyek;36.0400\nHuntersville;35.4060\nSan Mariano;16.9833\nBenevides;-1.3608\nTowada;40.6127\nSuifenhe;44.3998\nEuless;32.8508\nAranjuez;40.0333\nSarāvān;27.3708\nVinukonda;16.0500\nKananya;11.1856\nAsh Shaykh Zuwayd;31.2119\nSanyō-Onoda;34.0000\nRāpar;23.5700\nBanane;0.5000\nIlog;10.0333\nNiort;46.3258\nGohadi;26.4328\nSigaboy;6.6536\nHorqueta;-23.3442\nSan Marcos;8.6611\nBayjī;34.9292\nLagoa Santa;-19.6269\nKribi;2.9350\nPāchora;20.6700\nBuqda Caqable;4.0600\nMaués;-3.3836\nShegaon;20.7944\nRagay;13.8217\nXinfeng;24.9167\nBougouni;11.4167\nHardenberg;52.5667\nHuajiang;25.7491\nSardhana;29.1450\nHeerhugowaard;52.6667\nShuya;56.8500\nAguacatán;15.3429\nUriangato;20.1333\nHuehuetoca;19.8342\nSan Francisco;10.6500\nGuerra;18.5500\nHamburg;42.7394\nLesosibirsk;58.2358\nZhoujiajing;31.1116\nChibuto;-24.6833\nRichland;46.2824\nSaint-Louis du Sud;18.2667\nPalmares;-8.6828\nJōsō;36.0236\nPasrur;32.2681\nMouscron;50.7333\nSantee;32.8554\nIrosin;12.7050\nNarasapur;16.4361\nSaint-Hyacinthe;45.6167\nOgōri;33.4000\nGoianésia;-15.3169\nAlcoy;38.6983\nSan Luis;15.0400\nUnna;51.5347\nAgrigento;37.3167\nCamajuaní;22.4678\nMontenegro;-29.6889\nSanta Isabel do Pará;-1.2989\nRoxas;12.5833\nProkhladnyy;43.7500\nDhone;15.3960\nKesennuma;38.9081\nYara;20.2767\nEsfarāyen;37.0764\nOuinhri;7.0000\nMorón;22.1108\nLos Andes;-32.8333\nLucas do Rio Verde;-13.0500\nManchester;41.7753\nHyūga;32.4167\nBinnāguri;26.4600\nHua Hin;12.5686\nTiruvālūr;10.7730\nGannan;47.9117\nEsperanza;8.6760\nRājgarh;28.6400\nAleksandrov;56.3936\nIbaan;13.8176\nSonabedha;18.7300\nMotril;36.7500\nEl Salvador;8.5667\nTahara;34.6688\nZahirābād;17.6814\nKokomo;40.4640\nMansalay;12.5204\nChikuma;36.5339\nCalatagan;13.8322\nShirakawa;37.1263\nHalesowen;52.4502\nOued Lill;36.8333\nChichibu;35.9918\nTianningcun;30.8938\nSanta María Chiquimula;15.0292\nZengcun;38.2451\nMasantol;14.9000\nKattaqo’rg’on Shahri;39.8989\nEuskirchen;50.6597\nRanchuelo;22.3764\nCanlaon;10.3833\nPamplona;7.3781\nFlorida;3.3275\nJaguariúna;-22.6800\nNūzvīd;16.7800\nSandīla;27.0800\nConstanza;18.9100\nUpleta;21.7300\nDāmghān;36.1683\nWani;20.0556\nMetapán;14.3314\nLiantangcun;22.9517\nUpi;7.0106\nTaunton;41.9036\nFaenza;44.2856\nBilhorod-Dnistrovskyi;46.1833\nSt. Clair Shores;42.4925\nXikeng;24.0505\nGöppingen;48.7025\nTowson;39.3944\nCamacupa;-12.0256\nDoetinchem;51.9667\nYaguajay;22.3303\nKélibia;36.8500\nBarra do Garças;-15.8900\nRass el Djebel;37.2150\nGattaran;18.0611\nPānskura;22.4200\nMyaungmya;16.5833\nPedro Leopoldo;-19.6178\nMpondwe;0.0400\nPipariā;22.7570\nLac-Brome;45.2167\nTimargara;34.8278\nBoufarik;36.5750\nCaldwell;43.6453\nWuyang;27.0570\nUna;20.8200\nJovellanos;22.8106\nBarotac Nuevo;10.9000\nBezerros;-8.2333\nBeauvais;49.4303\nMikhaylovka;50.0667\nBaganga;7.5752\nPalompon;11.0500\nSurubim;-7.8319\nIzberbash;42.5633\nSucun;31.0554\nAsingan;16.0023\nLohārdagā;23.4300\nAbaji;8.4756\nCerignola;41.2667\nYanguancun;30.4541\nKaş;36.2000\nOrland Park;41.6075\nQaskeleng;43.2000\nAldershot;51.2483\nKitahiroshima;42.9855\nAketi;2.7333\nStonecrest;33.6842\nRāmpur Hat;24.1700\nCogan;10.5833\nSillod;20.3000\nFelgueiras;41.3667\nEjmiatsin;40.1728\nTokoname;34.8865\nBalancán;17.8000\nLambayeque;-6.7000\nSunshi;38.7631\nDumanjog;10.0500\nIskitim;54.6400\nGuarabira;-6.8550\nPalm Beach Gardens;26.8466\nSan Pedro;-24.2196\nDate;37.8191\nMulbāgal;13.1635\nMa’erkang;31.9046\nMoncalieri;45.0005\nSan Fernando;-34.5833\nKokawa;34.2664\nSérres;41.0833\nJiantang;27.8205\nRoyal Oak;42.5084\nIshikari;43.1667\nPunta Alta;-38.8800\nBiguaçu;-27.4939\nLa Gomera;14.0833\nKosai;34.7184\nPebane;-17.2667\nNyagan;62.1333\nŞatrovka;39.9319\nStalowa Wola;50.5667\nMelchor Ocampo;19.7083\nSamaná;19.2000\nHunsūr;12.3036\nHuaniu;34.5658\nAntsalova;-18.6667\nMatamey;13.4000\nBlue Springs;39.0124\nFredericton;45.9636\nChoshi;35.7346\nShoreline;47.7564\nTōgane;35.5599\nÁvila;40.6500\nGengzhuangqiao;37.4453\nTønsberg;59.2981\nTanauan;11.1167\nChivilcoy;-34.9000\nSan Luis;18.5500\nPula;44.8703\nBakwa-Kalonji;-4.3500\nTikhvin;59.6500\nMidwest City;35.4630\nBenslimane;33.6167\nLonāvale;18.7481\nNew Corella;7.5866\nPradera;3.4167\nAbington;40.1108\nGaspar;-26.9308\nRoermond;51.2000\nBowie;38.9549\nJackson;40.0980\nMizuho;35.3918\nZempoala;19.9167\nXiezhou;34.9124\nHameln;52.1000\nApex;35.7237\nAmbahikily;-21.6000\nKawthoung;9.9833\nMeleuz;52.9500\nKhlong Luang;14.0647\nAllanmyo;19.3783\nSāmalkot;17.0531\nŽivinice;44.4500\nAleksin;54.5167\nBerëzovskiy;56.9000\nPing’an;36.5020\nKālna;23.2200\nNaugaon Sādāt;28.9833\nQianwu;22.1635\nEl Cerrito;3.6667\nSanta Maria;6.5500\nMogoditshane;-24.6333\nKothāpet;19.3333\nKeonjhargarh;21.6300\nCiudad Cuauhtémoc;22.1833\nBędzin;50.3333\nTikhoretsk;45.8667\nGrand-Popo;6.2833\nUnjha;23.8000\nBiała Podlaska;52.0333\nOrito;0.6661\nJasaan;8.6500\nQŭnghirot;43.0704\nMinokamo;35.4402\nSīra;13.7450\nTiruvallūr;13.1231\nMācherla;16.4800\nMeerbusch;51.2667\nCampo Alegre;-9.7819\nQueen Creek;33.2454\nPavlovo;55.9667\nKandukūr;15.2167\nJerez de García Salinas;22.6481\nDiriamba;11.8564\nFloriano;-6.7669\nKrasnotur’insk;59.7733\nLeander;30.5728\nSalsk;46.4833\nMonte Plata;18.8100\nMoknine;35.6333\nMilagros;12.2192\nBartlett;35.2337\nBeni Enzar;35.2667\nSt. Cloud;28.2363\nWiwilí;13.6197\nBinalonan;16.0500\nAlangalang;11.2061\nSantiago Tuxtla;18.4654\nCosquín;-31.2436\nNova Odessa;-22.7797\nUson;12.2253\nPonte Nova;-20.4158\nKettering;39.6956\nIçara;-28.7128\nBuluan;6.7154\nYanam;16.7333\nFoumbot;5.5000\nBail-Hongal;15.8137\nLa Plata;2.3900\nHagonoy;6.6833\nCuvelai;-15.6667\nGörlitz;51.1528\nUki;32.6450\nFrankfurt (Oder);52.3419\nRichards Bay;-28.7694\nKędzierzyn-Koźle;50.3500\nSankt Augustin;50.7700\nBarwāni;22.0300\nSendhwa;21.6847\nEldorado;-26.4000\nM’diq;35.6858\nStolberg;50.7667\nCoruripe;-10.1258\nRiosucio;7.4406\nSattenapalle;16.3962\nBobbili;18.5667\nIpele;7.1333\nIrpin;50.5167\nKrymsk;44.9233\nParker;39.5084\nAndradina;-20.8958\nKudamatsu;34.0167\nSt. Peters;38.7825\nHuaixiangcun;22.4817\nMora;10.0088\nNova Esperança;-6.7333\nAzzaba;36.7333\nNasīrabād;26.3000\nBulungu;-4.5500\nWeymouth;42.1981\nFoligno;42.9500\nGūdalur;11.5014\nShicun;38.5383\nSarapiquí;10.4853\nTalagante;-33.6667\nVrindāvan;27.5800\nPaços de Ferreira;41.2667\nEschweiler;50.8167\nBorūjen;31.9678\nKan’onjichō;34.1272\nGuáimaro;21.0589\nRîbniţa;47.7667\nLunglei;22.8800\nMoramanga;-18.9469\nMaricopa;33.0408\nRaxaul;26.9833\nDehdasht;30.7950\nAlvarado;18.7811\nManfredonia;41.6333\nGeneral Pico;-35.6667\nLangenhagen;52.4394\nSemara;26.7394\nLian;14.0333\nBura;3.1722\nNeryungri;56.6833\nMoreno;-8.1186\nChini;23.3916\nTiwi;13.4585\nTama;34.4886\nOosterhout;51.6431\nPuerto Boyacá;6.0000\nCuemba;-12.1500\nRamon;16.7833\nGangārāmpur;25.4000\nSan Pedro Sacatepéquez;14.6862\nPoblacion;10.4667\nDen Helder;52.9333\nPaombong;14.8311\nBagheria;38.0833\nTalegaon Dābhāde;18.7200\nVerviers;50.5833\nKharar;30.7400\nLagonoy;13.7353\nAcambay;19.9539\nAlcobaça;39.5528\nNedumangād;8.6033\nWaiblingen;48.8303\nIxtahuacán;15.4167\nJacundá;-4.4508\nLinares;38.0833\nBasey;11.2817\nMurakami;38.2240\nLenexa;38.9609\nCuneo;44.3833\nColomba;14.7167\nTilakpur;28.5278\nTivoli;41.9667\nAthiémé;6.5833\nHighland;34.1113\nKāndi;23.9595\nViseu;-1.1969\nAnjangaon;21.1500\nAr Riqqah;29.1489\nPangantocan;7.8331\nTaquaritinga;-21.4058\nMengla;21.4866\nSalgueiro;-8.0669\nCui’erzhuang;38.2897\nPlacer;11.8689\nDiglipur;13.2667\nNōgata;33.7417\nOpava;49.9381\nLibungan;7.2500\nKhāsh;28.2211\nAjodhya;26.8036\nManicoré;-5.8089\nTāybād;34.7400\nTrani;41.2667\nKengri;12.9122\nHohoe;7.1490\nBianyang;25.6194\nBartolomé Masó;20.1686\nTomé-Açu;-2.4189\nMount Prospect;42.0641\nLake Havasu City;34.5006\nHassa;36.7994\nMagsaysay;6.7667\nKūt-e ‘Abdollāh;31.2414\nRegistro;-24.4878\nBelampalli;19.0756\nAmealco;20.1881\nAmarante;41.2667\nShali;43.1500\nRopar;30.9664\nPeriya Semūr;11.3700\nWinneba;5.3500\nAraci;-11.3328\nMota;11.0833\nGulariyā;28.2056\nMonte Alegre;-2.0078\nOke-Mesi;7.8167\nPithorāgarh;29.5800\nZgierz;51.8500\nPila;14.2333\nBlainville;45.6700\nTursunzoda;38.5108\nTakizawa;39.7347\nFinote Selam;10.7000\nLimoeiro do Norte;-5.1458\nXinqing;48.2363\nBihać;44.8167\nFréjus;43.4330\nSarikei;2.1256\nSan Andrés Villa Seca;14.5667\nDiffun;16.5936\nIrati;-25.4669\nUrbiztondo;15.8227\nXánthi;41.1333\nZarrīn Shahr;32.3897\nAntratsyt;48.1167\nKhān Shaykhūn;35.4389\nLongmen;35.6119\nAcul du Nord;19.6833\nLozova;48.8892\nBisceglie;41.2431\nQuezaltepeque;13.8333\nGeneral Tinio;15.3500\nNyenga;0.3800\nIntibucá;14.3167\nRangewala;30.8222\nNawucun;22.0039\nYongqing;34.7522\nViramgām;23.1200\nFrýdek-Místek;49.6856\nUnion;42.1258\nAmbilobe;-13.2000\nSiliancun;22.7155\nTinley Park;41.5670\nBambang;16.3872\nTsévié;6.4333\nBoituva;-23.2833\nBaden-Baden;48.7628\nPortimão;37.1369\nLingen;52.5231\nWangguanzhuang;37.0183\nVolzhsk;55.8703\nHoogeveen;52.7333\nChangling;44.2700\nHidaka;35.9078\nToki;35.4192\nMadhupur;24.2600\nCatu;-12.3497\nParsippany-Troy Hills;40.8601\nXiva;41.3833\nNarbonne;43.1836\nBatac;18.0554\nHashtgerd;35.9619\nJaru;-10.4389\nGus’-Khrustal’nyy;55.6167\nAsadābād;34.7825\nTucano;-10.9628\nXihu;23.9594\nAtchampeta;15.5412\nUmm Ruwaba;12.9046\nRengo;-34.4167\nLa Roche-sur-Yon;46.6705\nOvar;40.8667\nTūyserkān;34.5481\nDeSoto;32.5992\nMartin;49.0650\nApatity;67.5667\nAzul;-36.7833\nTauá;-6.0028\nBhongīr;17.5100\nMulanay;13.5222\nZile;40.3000\nAsturias;10.5679\nNarutochō-mitsuishi;34.1667\nSan Agustín Acasaguastlán;14.9500\nSacapulas;15.2892\nMercedes;14.1093\nLimoeiro;-7.8750\nMonte Mor;-22.9467\nChicopee;42.1764\nCanterbury;51.2800\nNāmakkal;11.2167\nCorby;52.4877\nGhātāl;22.6700\nEl Banco;8.9983\nKuala Kapuas;-3.0013\nManapla;10.9580\nButhidaung;20.8667\nPulheim;51.0000\nBelén de Escobar;-34.3333\nMadison;34.7114\nHarpanahalli;14.7877\nSchweinfurt;50.0500\nHorizonte;-4.0989\nKhorramdarreh;36.2072\nVillarrica;-39.2667\nPorirua;-41.1333\nWest Haven;41.2739\nJaguaquara;-13.5308\nSan Remo;43.8175\nMāngrol;21.1200\nPorto Alexandre;-15.8000\nTonekābon;36.8164\nHyères;43.1199\nYamasá;18.7667\nSmyrna;33.8633\nRolim de Moura;-11.7254\nAurora;44.0000\nBitonto;41.1167\nOttappālam;10.7700\nWylie;33.0362\nBarbalha;-7.3050\nTaliwang;-8.7336\nPallíni;38.0000\nChallakere;14.3120\nVannes;47.6559\nPolūr;12.5000\nPuttūr;13.4500\nDiamond Bar;33.9992\nSonglindian;39.4100\nSan Isidro;15.3097\nChonthrhu;32.4865\nHattingen;51.3992\nBad Homburg;50.2167\nPombal;39.9161\nChristchurch;50.7300\nHervey Bay;-25.2900\nIslāmpur;26.2700\nModica;36.8672\nApple Valley;44.7457\nDompu;-8.5364\nAgbangnizoun;7.0667\nChino;35.9955\nPunganūru;13.3667\nBávaro;18.7167\nJuruti;-2.1519\nEqbālīyeh;36.2314\nAcıpayam;37.4250\nNāndod;21.8706\nKonan;35.0000\nSanta Cruz;10.2358\nCarigara;11.3000\nFunato;34.2500\nZhushan;23.6889\nUcuma;-12.8500\nSanta Isabel;-23.3158\nDikwella South;5.9667\nOxchuc;16.7833\nŎjŏk-tong;40.2167\nKhurai;24.0437\nEnsenada;-34.8644\nKeighley;53.8670\nEstancia;11.4500\nBilis Qooqaani;0.2822\nHuaishu;38.0828\nCajicá;4.9167\nViçosa do Ceará;-3.5619\nPontevedra;10.3667\nPôrto Ferreira;-21.8539\nIndaial;-26.8978\nAlenquer;-1.9419\nSara;11.2500\nPinto;40.2500\nBarreirinhas;-2.7469\nLiushi;38.5445\nBáguanos;20.7631\nBradenton;27.4901\nMinamiuonuma;37.0655\nBrookhaven;33.8743\nSakurai;34.5167\nSanta Cruz;13.4833\nLuquembo;-10.7333\nWayne;40.9481\nKāsaragod;12.5000\nSohna;28.2500\nMali;23.1277\nHacienda Heights;33.9970\nSarpsborg;59.2858\nBarranqueras;-27.4833\nAnnaka;36.3263\nKampen;52.5500\nCholet;47.0600\nManhattan;39.1886\nXielu;37.0359\nTiruvalla;9.3856\nTaquara;-29.6508\nTerneuzen;51.3333\nDandarah;26.1681\nChota;-6.5614\nTigard;45.4237\nMonte Santo;-10.4378\nSaruhanlı;38.7342\nSamāna;30.1500\nJinchang;38.4858\nMasinloc;15.5333\nTeramo;42.6589\nSan Manuel;16.0656\nOstrołęka;53.0667\nBad Salzuflen;52.0833\nSāgar;14.1667\nAntanifotsy;-19.6800\nRāhuri;19.3800\nManjeri;11.1197\nKızılpınar;41.2667\nSidhi;24.4200\nChenab Nagar;31.7528\nDayin;38.9358\nNihonmatsu;37.5849\nTrento;8.0459\nCava de’ Tirreni;40.7000\nJalapa;13.9222\nMontesilvano;42.5142\nTapas;11.2622\nMbulungu;-6.0667\nUmm Qurūn;25.2500\nNordhorn;52.4319\nSão José do Rio Pardo;-21.5958\nShidong;23.6193\nKotka;60.4667\nŞabbāshahr;35.5833\nCornillon;18.6667\nQingan;46.8719\nJavānrūd;34.8067\nPalmaner;13.2007\nHuixtla;15.1000\nChaozhou;22.5500\nPārvatipuram;18.7800\nMinalabac;13.5700\nTlacotepec;18.6882\nPopeşti-Leordeni;44.3800\nSado;38.0183\nSiena;43.3183\nEl Rama;12.1617\nPiekary Śląskie;50.3833\nJalor;25.3500\nKāliyāganj;25.6300\nHanyū;36.1726\nCachoeiras de Macacu;-22.4628\nBandar-e Torkaman;36.9017\nTarma;-11.4186\nYucaipa;34.0336\nBristol;40.1216\nZarafshon Shahri;41.6081\nXingcheng;40.1399\nValle del Guamuez;0.4253\nVikārābād;17.3300\nRuteng;-8.6127\nManglaur;29.8000\nHashtpar;37.8008\nAnkadinondry-Sakay;-19.0000\nDaudnagar;25.0300\nRotorua;-38.1378\nIxhuatlán de Madero;20.6833\nNarva;59.3758\nPeabody;42.5335\nBarra;-11.0889\nTokmok;42.8333\nMansāla;15.9417\nBir Ali Ben Khalifa;34.7339\nBan Om Noi;13.7001\nZhigulevsk;53.3997\nUmred;20.8500\nTitay;7.8703\nSouthaven;34.9514\nApopka;28.7015\nTagkawayan;13.9667\nChèddra;13.4428\nAcará;-1.9608\nBadūria;22.7400\nJuanjuí;-7.1802\nAvellino;40.9167\nSultānganj;25.2460\nDholka;22.7200\nGoālpāra;26.1700\nCuenca;40.0667\nPuerto Libertador;7.9067\nHorizon West;28.4417\nCabagan;17.4333\nMillcreek;42.0859\nGhōriyān;34.3400\nChilibre;9.1500\nNew Plymouth;-39.0578\nPatancheruvu;17.5333\nChystiakove;48.0219\nAshta;23.0175\nTuni;17.3500\nSevern;39.1355\nLiski;50.9667\nNeustadt;49.3500\nMarkala;13.6739\nTrês Pontas;-21.3669\nAn Nimāş;19.1200\nJaggayyapeta;16.8920\nChenārān;36.6456\nSvobodnyy;51.4000\nSalo;60.3861\nImpasugong;8.3028\nA Yun Pa;13.3939\nBacaadweyn;7.1917\nSanto Domingo;22.5833\nColton;34.0538\nBījār;35.8729\nKentwood;42.8852\nMagpet;7.1167\nKitaotao;7.6406\nPassau;48.5744\nZongo;4.3433\nSão Francisco do Sul;-26.2428\nSão Francisco;-15.9489\nHamada;34.9000\nZaragoza;15.4492\nSibonga;10.0333\nPasacao;13.5103\nMinnetonka;44.9322\nKongoussi;13.3333\nAjuy;11.1725\nWheaton;41.8561\nHuesca;42.1333\nCangola;-7.9667\nPort Shepstone;-30.7500\nDevakottai;9.9976\nElda;38.4789\nMarco de Canavezes;41.1833\nDauis;9.6250\nTilhar;27.9800\nKrasnokamsk;58.0833\nUpata;8.0204\nColmenar Viejo;40.6589\nAl Majāridah;19.1167\nWetzlar;50.5667\nGuiuan;11.0300\nVelletri;41.6667\nEnerhodar;47.4989\nFrechen;50.9167\nShāhpur;16.7000\nZhangjiazhuang;38.1753\nCambundi Catembo;-10.0756\nEncarnación de Díaz;21.5167\nWest Sacramento;38.5557\nAnzio;41.4472\nNaka;36.4574\nAcireale;37.6167\nDongshan;24.6319\nLakhminia;25.4126\nMorondava;-20.2847\nLucban;14.1133\nPorto Feliz;-23.2150\nFrutal;-20.0250\nCasa Grande;32.9069\nThérmi;40.5500\nGudermes;43.3500\nGuernica;-34.9167\nPirapora;-17.3478\nSan Manuel;15.3333\nRumia;54.5667\nYangmei;22.8728\nDangila;11.2667\nMutsu;41.2928\nBarbosa;6.4390\nXincheng;39.9883\nNormal;40.5217\nOlímpia;-20.7369\nSanto Estêvão;-12.4300\nPryluky;50.6000\nPuttūr;12.7648\nBarobo;8.5292\nMolave;8.0933\nVertientes;21.2569\nYaozhuangcun;30.9113\nCapivari;-22.9950\nSão Bento do Una;-8.5228\nBuenavista;10.7000\nHowell;40.1819\nSan Jacinto;33.7970\nAurora;7.9484\nAkbou;36.4667\nTame;6.4667\nCanguçu;-31.3950\nIrinjālakuda;10.3514\nAçu;-5.5769\nKarlovac;45.4833\nVyksa;55.3167\nWoerden;52.0833\nKalamáta;37.0378\nAsunción Mita;14.3333\nSan Bartolomé;27.9254\nNovato;38.0920\nMladenovac;44.4333\nLeopoldina;-21.5319\nSan Severo;41.6951\nAcopiara;-6.0950\nSagua la Grande;22.8086\nHamtic;10.7000\nMandi Dabwāli;29.9477\nPasaje;-3.3269\nPinellas Park;27.8589\nLa Ceja;6.0306\nSimojovel de Allende;17.1333\nPadre Garcia;13.8833\nRoskilde;55.6500\nGalveston;29.2484\nEdina;44.8914\nAhlen;51.7633\nArsenyev;44.1667\nPanjakent;39.5000\nKleve;51.7900\nSan Estanislao;-24.6500\nVenkatagiri;13.9667\nKelaa Kebira;35.8667\nNeibu;22.6500\nHyosha;0.6975\n‘Alīābād-e Katūl;36.9083\nJiāganj;24.2300\nSihor;21.7000\nSison;16.1667\nMafra;-26.1108\nLorica;9.2419\nLower Paxton;40.3183\nChone;-0.6833\nTomiya;38.4000\nImarichō-kō;33.2667\nBani;16.1869\nJangaon;17.7227\nUsa;33.5320\nKobryn;52.2167\nKorāput;18.8120\nHerriman;40.4899\nMongaguá;-24.0869\nClorinda;-25.2833\nElyria;41.3760\nSan Joaquin;10.6000\nWolfenbüttel;52.1622\nPoprad;49.0594\nKrasnokamensk;50.1000\nTutóia;-2.7619\nCanoinhas;-26.1769\nUnião da Vitória;-26.2300\nSan José Villa de Allende;19.3747\nMalkara;40.8933\nCapitão Poço;-1.7450\nFatwa;25.5096\nGranadilla de Abona;28.1167\nEl Tumbador;14.8667\nGrand Island;40.9218\nMinami-Sōma;37.6422\nThongwa;16.7547\nSan Miguel Ixtahuacán;15.2500\nHuaiyang;37.7558\nBargny;14.6939\nÅlesund;62.4740\nBurauen;10.9833\nPiaseczno;52.0667\nIbajay;11.8211\nNaguilian;16.5333\nTorrelavega;43.3531\nJiyyammavalasa;18.7900\nSironj;24.1000\nGranja;-3.1200\nKahnūj;27.9500\nAn Nabk;34.0167\nMiyakojima;24.8056\nBato;13.3578\nHorishni Plavni;49.0167\nBad Kreuznach;49.8500\nPacora;9.0800\nMandamāri;18.9822\nSertolovo;60.1500\nPresident Roxas;7.1544\nBaşkale;38.0475\nLacey;47.0462\nClaveria;8.6100\nQabqa;36.2667\nBentonville;36.3547\nCaetité;-14.0689\nCihanbeyli;38.6581\nMethuen Town;42.7340\nVictoria;13.1719\nVyazma;55.2107\nAlaminos;14.0635\nBoa Viagem;-5.1278\nTamboril;19.4800\nDiu;20.7150\nBikramganj;25.2107\nPhaltan;17.9800\nPordenone;45.9500\nGlendora;34.1449\nTekkeköy;41.2125\nMarechal Deodoro;-9.7100\nRincón de la Victoria;36.7167\nSmyrna;35.9687\nSapé;-7.0950\nGirardota;6.3764\nFlorissant;38.7996\nIbbenbüren;52.2778\nAmbohibary;-19.6167\nNaviraí;-23.0650\nTaxco de Alarcón;18.5564\nLeon;10.7808\nStratford;41.2070\nDelmiro Gouveia;-9.3858\nRoman;46.9300\nPlaisance;19.6000\nVillareal;39.9378\nCivitavecchia;42.1000\nWelland;42.9833\nKhurda;20.1833\nBasankusu;1.2222\nNovovolynsk;50.7333\nCangandala;-9.7833\nDelano;35.7662\nThomazeau;18.6500\nAbdul Hakim;30.5500\nCruz del Eje;-30.7333\nPortel;-1.9358\nKannapolis;35.4764\nBurla;21.5098\nBelorechensk;44.7686\nHoffman Estates;42.0640\nBuíque;-8.6233\nTūndla;27.2000\nChajul;15.4872\nBelle-Anse;18.2333\nSanta Eulalia;15.7333\nSagua de Tánamo;20.5858\nAmpanihy;-24.6833\nYendi;9.4324\nBeaumont;33.9076\nGādarwāra;22.9235\nĀlbū Kamāl;34.4536\nWangjiazhai;26.6895\nIzumi;32.0833\nBar Bigha;25.2186\nSan Onofre;9.7333\nTrinidad;21.8042\nPola de Siero;43.3833\nKhattan;33.3700\nZangāreddigūdem;17.1229\nDungu;3.6167\nKālpi;26.1200\nAd Dabbah;18.0502\nMabini;13.7167\nTimashevsk;45.6167\nCalviá;39.5656\nEilat;29.5569\nKandangan;-2.7833\nPeranāmpattu;12.9387\nSanta Ignacia;15.6167\nParobé;-29.6289\nMetpalli;18.8492\nNtoum;0.3844\nRacibórz;50.0833\nĀnaiyūr;9.9615\nCaldas da Rainha;39.4072\nBandō;36.0484\nCaramoan;13.7707\nEl Bagre;7.5942\nBattipaglia;40.6167\nCardona;14.4861\nCovilhã;40.2833\nAguadulce;8.2400\nForbesganj;26.3000\nLivingston;55.8834\nCathedral City;33.8362\nShimencun;30.6263\nItupiranga;-5.1350\nMulongo;-7.8333\nHuazangsi;36.9836\nTsukubamirai;35.9631\nKarviná;49.8542\nİncirliova;37.8547\nBöblingen;48.6856\nMaubin;16.7300\nSpeyer;49.3194\nIsfara;40.1167\nSolnechnogorsk;56.1833\nBaham;5.3333\nCaleta Olivia;-46.4333\nMazara del Vallo;37.6500\nTulsīpur;28.1278\nJaspur;29.2833\nGummersbach;51.0333\nEl Talar de Pacheco;-34.4719\nBowringpet;12.9912\nBurien;47.4762\nMarigot;18.2333\nCampo Belo;-20.8969\nCerca la Source;19.1667\nTachilek;20.4500\nGuapimirim;-22.5369\nShahr-e Bābak;30.1164\nChieti;42.3500\nRovigo;45.0809\nSão Miguel do Guamá;-1.6269\nGuarne;6.2800\nQabb Eliâs;33.7986\nBozeman;45.6833\nMāndvi;22.8333\nBantacan;7.5483\nNorth Bay;46.3000\nKnysna;-34.0356\nPau d’Alho;-7.8969\nHorsham;51.0620\nZhexiang;24.2591\nBhavāni;11.4455\nButare;-2.6000\nOcampo;13.5594\nTucurú;15.3000\nScandicci;43.7544\nSidlaghatta;13.3900\nKizhake Chālakudi;10.3000\nRibeira do Pombal;-10.8339\nUzlovaya;53.9833\nCumanayagua;22.1522\nRavensburg;47.7831\nTrairi;-3.2778\nUtrera;37.1830\nSūsangerd;31.5608\nArao;32.9833\nKalawana;6.5315\nSatte;36.0781\nNentón;15.8012\nCutervo;-6.3778\nSanta Cruz del Sur;20.7194\nMontijo;38.6833\nKyzyl-Kyya;40.2611\nSeveromorsk;69.0692\nWillich;51.2631\nTadmur;34.5600\nMisterbianco;37.5183\nHassan Abdal;33.8195\nMarpalli;17.5389\nHumaitá;-7.5061\nRastatt;48.8500\nRongat;12.4667\nCheremkhovo;53.1500\nSegovia;40.9481\nSibsāgar;26.9800\nSan Narciso;13.5677\nCuyotenango;14.5421\nLaksar;29.7490\nTwin Falls;42.5645\nDouyu;37.9007\nRepalle;16.0172\nChinnamanūr;10.0412\nSakubva;-18.9833\nSnezhinsk;56.0833\nLaval;48.0733\nKuchaiburi;22.2700\nHannan;34.3597\nZabīd;14.2000\nNanao;37.0431\nFangcun;37.9799\nHilsa;25.3200\nVyāra;21.1200\nTimbaúba;-7.5050\nEnid;36.4063\nSakaidechō;34.3167\nPadrauna;26.9000\nDunwoody;33.9418\nLevittown;40.1533\nArles;43.6767\nJesús Menéndez;21.1633\nPalm Desert;33.7378\nHouten;52.0333\nEsher;51.3691\nBas Limbé;19.8000\nGoslar;51.9072\nGombong;-7.6000\nIrondequoit;43.2096\nPardwāl;32.3286\nCampos do Jordão;-22.7394\nNazarovo;56.0000\nUmán;20.8500\nGuisa;20.2608\nPontal;-21.0225\nYūki;36.3055\nAringay;16.3982\nKalamansig;6.5667\nEast Hartford;41.7634\nNaugachhia;25.4000\nSujānpur;32.3127\nKyōtango;35.6242\nMozhga;56.4500\nYe;15.2467\nKirishi;59.4500\nCuyahoga Falls;41.1641\nGoba;7.0000\nLouveira;-23.0864\nMiyako;39.6414\nKizlyar;43.8500\nCataingan;12.0028\nGoshogawara;40.8080\nPeine;52.3203\nSusono;35.1739\nÇermik;38.1372\nMoss;59.4592\nFafe;41.4500\nNicoya;10.1024\nNakagawa;33.5000\nBanī Walīd;31.7619\nMarana;32.4355\nHigashiura;34.9771\nNovovyatsk;58.5083\nMishawaka;41.6742\nPozi;23.4611\nTŭrtkŭl;41.5500\nLongwan;38.9564\nBeloeil;45.5667\nEl Jem;35.2967\nSanta Lucía del Camino;17.0667\nMahalapye;-23.1000\nPuławy;51.4167\nMweka;-4.8500\nColumbus;39.2093\nHaskah Mēnah;34.1000\nTroy;42.7354\nBelleville;44.1667\nBeruniy;41.6833\nGloria;12.9722\nMilford city;41.2255\nNorthwich;53.2590\nPeddāpuram;17.0800\nYasu;35.0667\nCollierville;35.0470\nYerba Buena;-26.8167\nChbar Mon;11.4500\nBaranoa;10.8000\nSantiago;-29.1919\nShakhtarsk;48.0333\nGhŭlakandoz;40.1617\nLa Calera;-32.7867\nHerning;56.1333\nMetema;12.9667\nNichinan;31.6022\nSittard;51.0000\nSilkeborg;56.1833\nDonsol;12.9083\nLörrach;47.6167\nTebourba;36.8333\nIkot Okoro;4.9000\nQinhe;36.5047\nEl Nido;11.1956\nClacton-on-Sea;51.7918\nGrapevine;32.9343\nNettuno;41.4667\nAmulung;17.8387\nArtur Nogueira;-22.5731\nKabarore;-1.6211\nStarogard Gdański;53.9667\nMirabel;45.6500\nNahuizalco;13.7833\nSan Ignacio;-26.8867\nWeert;51.2500\nParāsia;22.1913\nWao;7.6404\nBiaora;23.9163\nChinú;9.0833\nAmora;38.6265\nĀqchah;36.9114\nChatrā;24.2045\nTājūrā’;32.8818\nBhadrāchalam;17.6688\nEmden;53.3669\nArdea;41.6167\nPeñablanca;17.6258\nBaicheng;41.7957\nTammampatti;11.4381\nWandan;22.5897\nSummerville;33.0016\nCasalnuovo di Napoli;40.9167\nPananaw;5.9833\nPalpalá;-24.2500\nSihorā;23.4871\nHuanghuajie;27.9950\nMacaúbas;-13.0189\nRivoli;45.0697\nNanjian;25.0530\nXiazhai;27.6909\nKameyama;34.8558\nSão Joaquim da Barra;-20.5808\nErftstadt;50.8167\nDowners Grove;41.7949\nAlta Floresta;-9.8758\nCerquilho Velho;-23.1650\nMantova;45.1564\nMurray;40.6498\nVargem Grande Paulista;-23.6028\nLindong;43.9673\nSojat;25.9200\nBhainsa;19.1000\nBorovichi;58.4000\nSanta Lucía;21.0281\nAarsâl;34.1794\nZargar;37.8000\nItararé;-24.1125\nChhāgalnāiya;23.0395\nPerambalūr;11.2300\nDéressia;9.7603\nRoslavl;53.9500\nHaripur;33.9942\nGogrial;8.5300\nShankou;24.5032\nHaverford;39.9868\nMiyoshi;34.8000\nPontevedra;11.4833\nIJmuiden;52.4586\nAlbi;43.9289\nSesto Fiorentino;43.8333\nCatalina Foothills;32.3046\nSardasht;36.1542\nEast Honolulu;21.2975\nUpper Buchanan;5.9161\nShawinigan;46.5667\nTepeapulco;19.7856\nPaine;-33.8167\nKahemba;-7.2829\nPhalodi;27.1310\nCeel Dheere;5.3683\nGodinlabe;5.8794\nSechura;-5.5576\nPorvoo;60.3944\nNohar;29.1800\nAl Wajh;26.2833\nAbū Ḩamad;19.5433\nNenjiang;49.1745\nJiuzhou;39.5054\nHarderwijk;52.3500\nHeidenheim;48.6761\nDraper;40.4957\nAlcala;15.8468\nEjeda;-24.3500\nGrasse;43.6667\nChikugo;33.2092\nLeonberg;48.8014\nBigadiç;39.3925\nChomutov;50.4611\nVryburg;-26.9500\nMailiao;23.7500\nMenggala;-4.4750\nBuguruslan;53.6583\nKapadvanj;23.0200\nFrankenthal;49.5333\nXankəndi;39.8153\nSlonim;53.0833\nConcepción;-27.3333\nGediz;39.0417\nSanta Rita;14.9953\nMājalgaon;19.1500\nÇine;37.6117\nBergkamen;51.6167\nPrattipādu;16.1878\nMojo;8.6500\n‘Akko;32.9278\nKarapınar;37.7147\nGualán;15.1333\nSosúa;19.7500\nSulleru;18.5333\nCarmen de Viboral;6.0833\nSesimbra;38.4437\nNoshiromachi;40.2121\nRosario;8.3814\nLucan;53.3544\nAdeje;28.1167\nTomisato;35.7000\nSuzaka;36.6511\nGodda;24.8270\nDumarao;11.2631\nRidder;50.3500\nBatajnica;44.9022\nChesterfield;38.6589\nZyryanovsk;49.7453\nZongshizhuang;37.8615\nGronau;52.2125\nMbouda;5.6333\nAraklı;40.9333\nSmethwick;52.4931\nCimitarra;6.3167\nGuaxupé;-21.3050\nLiujiaxia;35.9423\nBedford;32.8464\nBerber;18.0306\nTōkamachi;37.1333\nBad Oeynhausen;52.2000\nMaría la Baja;10.0000\nWofotang;38.6190\nOdiongan;12.4000\nHikari;33.9619\nSt. Louis Park;44.9488\nViana;-3.2200\nWaalwijk;51.6833\nKiblawan;6.6167\nJiashizhuang;37.8683\nÖzgön;40.7667\nDonglizhuang;37.9351\nOkhtyrka;50.3074\nMuhanga;-2.0845\nChioggia;45.2196\nAzusa;34.1386\nAsakura;33.4167\nVillaguay;-31.8500\nKīlvishāram;12.9143\nEast Brunswick;40.4281\nNomimachi;36.4470\nVargem Grande;-3.5428\nPio Duran;13.0333\nDulag;10.9525\nNowshahr;36.6489\nMidori;36.3948\nWelwyn Garden City;51.8062\nEmpoli;43.7167\nCarmen;9.8167\nVinzons;14.1739\nAd Darwa;33.4167\nSamaniego;1.3500\nMinalin;14.9667\nEuclid;41.5903\nCwmbran;51.6530\nMulukukú;13.1764\nChangyŏn;38.2517\nYong’an;31.0206\nAl Aaroui;35.0029\nBeberibe;-4.1800\nMalabang;7.5903\nÓbidos;-1.9178\nPanay;11.5553\nMcLean;38.9436\nLibertador General San Martín;-23.8000\nSông Đốc;9.0333\nSanta Rosa;-3.4522\nRheda-Wiedenbrück;51.8417\nCoral Gables;25.7037\nMonopoli;40.9500\nAgustín Codazzi;10.0367\nMartigues;43.4053\nLecco;45.8500\nBantvāl;12.8905\nFarajok;3.8724\nSan Benedetto del Tronto;42.9500\nWejherowo;54.6000\nLincoln;38.8774\nNikaweratiya;7.7475\nLesnoy;58.6333\nSaray;41.4411\nFreising;48.4028\nAlsdorf;50.8833\nVerrettes;19.0500\nJeffersonville;38.3376\nLa Libertad;15.5000\nPorto Nacional;-10.7078\nTunuyán;-33.5667\nGuntakal Junction;15.1200\nCeres;37.5952\nLa Reja;-34.6394\nWashington;39.7469\nKifisiá;38.0833\nDachau;48.2603\nSungurlu;40.1610\nVich;41.9304\nLibona;8.3333\nJaggisettigūdem;17.1167\nStarachowice;51.0500\nHuaquillas;-3.4814\nAscoli Piceno;42.8500\nBiloxi;30.4426\nJales;-20.2689\nLawrence;39.8674\nDumingag;8.1550\nIranduba;-3.2850\nCaraballeda;10.6167\nSanto Domingo Suchitepéquez;14.4667\nBornheim;50.7592\nGooty;15.1210\nAl Mayādīn;35.0183\nPoway;32.9871\nSaint-Herblain;47.2122\nCedar Hill;32.5810\nMartina Franca;40.7000\nInabanga;10.0333\nYamaga;33.0169\nPedreira;-22.7419\nErlin;23.9229\nOmitama;36.2393\nBarotac Viejo;11.0500\nWaingapu;-9.6500\nShuishang;23.4319\nBrandon;49.8483\nOrangetown;41.0527\nSanare;9.7822\nPrudentópolis;-25.2128\nLal-lo;18.2000\nPoções;-14.5300\nMaţāy;28.4167\nPortage;42.2000\nRowland Heights;33.9716\nNiagara Falls;43.0921\nJasdan;22.0300\nSuwa;36.0391\nAmi;36.0308\nBacolor;14.9984\nHørsholm;55.8803\nKozlu;41.4333\nNyaungu;21.2000\nBoucan Carré;18.9667\nShādegān;30.6497\nGarmsār;35.2183\nSettimo Torinese;45.1333\nCongonhas;-20.5000\n’Aïn Azel;35.8433\nNew Washington;11.6483\nRimouski;48.4500\nMasagua;14.2084\nCuxhaven;53.8611\nAngol;-37.8000\nBegoro;6.3833\nWakema;16.6000\nLeiktho;19.2222\nVoluntari;44.4925\nGiddarbāha;30.2000\nJalandhar Cantonment;31.2860\nNāngal Township;31.3850\nNamtu;23.0925\nSiocon;7.7067\nDublin;40.1112\nEl Dorado Hills;38.6750\nGumia;23.8106\nDongshan;22.0635\nStraubing;48.8833\nBarnstable;41.6655\nHomnābād;17.7707\nBokāro;23.7871\nCorato;41.1500\nŌamishirasato;35.5167\nMangapet;18.2500\nZutphen;52.1400\nSanmu;35.6000\nHelsingør;56.0361\nRidderkerk;51.8667\nBeveren;51.2000\nKurganinsk;44.8667\nSaint-Priest;45.6972\nMahayag;8.1297\nGavá;41.3072\nSoest;51.5711\nDuyên Hải;9.6331\nSan Pedro Mixtepec;16.0000\nVite;17.2711\nWest Orange;40.7893\nHoskote;13.0721\nTuba;16.3928\nTibigan;9.9500\nIshigaki;24.3406\nDornbirn;47.4167\nBabaeski;41.4325\nItapagé;-3.6869\nÉvreux;49.0200\nKołobrzeg;54.1761\nHojāi;26.0028\nDamāvand;35.7178\nMooresville;35.5847\nSpring Hill;35.7437\nAubagne;43.2908\nSadāseopet;17.6203\nLongtoushan Jiezi;27.1157\nKalima;-2.5667\nIbiporã;-23.2689\nChinchiná;4.9825\nDěčín;50.7736\nRoswell;33.3730\nTarnobrzeg;50.5833\nDurham;54.7761\nXique-Xique;-10.8229\nInhumas;-16.3578\nLilh;32.6900\nCampi Bisenzio;43.8167\nAsh Shaykh Badr;34.9833\nPangkou;38.6457\nKefamenanu;-9.4467\nZhujiacun;26.3164\nRio Grande da Serra;-23.7439\nBeypazarı;40.1703\nTitao;13.7667\nBhatkal;13.9853\nÇan;40.0275\nZawiercie;50.5000\nLeesburg;39.1057\nBrianka;48.5133\nTurda;46.5667\nJoshīmath;30.5550\nFinike;36.3000\nDonetsk;48.3333\nRancho Santa Margarita;33.6318\nTuckahoe;37.5878\nAlta Gracia;-31.6667\nBalimbing;5.0728\nShimotsuchō-kominami;34.1500\nTitusville;28.5727\nPaterno;37.5667\nGlenview;42.0825\nYongping;37.0103\nKashira;54.8333\nShelekhov;52.2167\nVila Verde;41.6500\nEna;35.4492\nMengmeng;23.4718\nPerth;56.3958\nCarepa;7.7578\nTobias Barreto;-11.1839\nSaint-Malo;48.6500\nSkierniewice;51.9667\nWauwatosa;43.0616\nOkaya;36.0671\nStillwater;36.1317\nOtradnyy;53.3667\nTonami;36.6475\nPallipālaiyam;11.3679\nStade;53.6008\nBhamo;24.2667\nMinot;48.2375\nSanta Cruz do Rio Pardo;-22.8989\nBasoko;1.2333\nHigashine;38.4313\nSan Francisco;16.8017\nDiamantina;-18.2489\nBan Plai Bua Phatthana;13.9032\nMattanūr;11.9310\nSantana do Ipanema;-9.3778\nMīt Salsīl;31.1667\nTakeochō-takeo;33.1947\nSoest;52.1833\nWilson;35.7311\nCharleville-Mézières;49.7719\nGolpāyegān;33.4536\nPativilca;-10.6958\nVigia;-0.8578\nRio de Mouro;38.7689\nJiquilisco;13.3167\nPakenham;-38.0712\nLousada;41.3000\nDumka;24.4200\nTalisay;14.1000\nÁgueda;40.5744\nRío Cauto;20.5636\nKuilsrivier;-34.0333\nYecun;33.7663\nHennef;50.7833\nMalinao;13.4000\nMedia;46.1500\nOno;34.8497\nGüroymak;38.5769\nLuwuk;-0.9396\nNewark;37.5201\nPenco;-36.7333\nSogod;10.3833\nHerzogenrath;50.8667\nVyshniy Volochëk;57.5833\nAl Madrah Samā’il;23.3103\nAmbatondrazaka;-17.8256\nVuyyūru;16.3667\nHitachi-ota;36.5383\nAmahai;-3.3331\nPilar;11.4878\nKikugawa;34.7500\nUmarkhed;19.6000\nRoseville;42.5074\nOberursel;50.2033\nSnizhne;48.0167\nIpiaú;-14.1369\nBan Bang Mae Nang;13.8815\nRieti;42.4044\n‘Āmūdā;37.1042\nSan Lorenzo;-28.1200\nJitaicun;36.3533\nVikramasingapuram;8.6700\nChaïdári;38.0167\nBunawan;8.1781\nManappārai;10.6075\nCatriel;-37.8667\nBrive-la-Gaillarde;45.1583\nDonggang;22.4667\nKutno;52.2333\nPunalūr;9.0170\nLa Vega;2.0008\nChenalhó;16.9333\nMonroe;40.3191\nCarcassonne;43.2100\nLivny;52.4239\nAznā;33.4558\nCunén;15.3379\nPoso;-1.4000\nCapão Bonito;-24.0058\nIsabel;10.9300\nLandau;49.2000\nNandikotkūr;15.8670\nSanta Ana Chiautempan;19.3167\nMēla Gūdalūr;9.4405\nPilar;14.6667\nNanto;36.5878\nAtalaia;-9.5019\nQingyuan;24.5004\nMataquescuintla;14.5336\nBorgne;19.8500\nSan Andrés de Sotavento;9.1500\nSumisip;6.4167\nEast Lansing;42.7480\nSanski Most;44.7667\nChaparral;3.7500\nLiulin;36.5570\nJobabo;20.9078\nVilla Constitución;-33.2333\nGosen;37.7444\nParacambi;-22.6108\nPerinton;43.0781\nGeneral Martín Miguel de Güemes;-24.6667\nMentor;41.6893\nTangdukou;26.9949\nBothell;47.7735\nDaxiang;22.3775\nYehe;37.9416\nOuled Moussa;36.6831\nTalghar;43.3000\nKingisepp;59.3667\nYabrūd;33.9667\nAquidauana;-20.4708\nVideira;-27.0078\nTomioka;36.2599\nAlbuera;10.9186\nFellbach;48.8086\nŞowme‘eh Sarā;37.3117\nBairāgnia;26.7406\nAyapel;8.3167\nAyungon;9.8584\nHaeryong;34.9131\nKampli;15.4063\nSaravena;6.9556\nAs Sa‘dīyah;34.1906\nSan Luis Obispo;35.2669\nKasumbalesa;-12.2564\nWaspán;14.7408\nBurleson;32.5170\nSelu;19.4551\nDouz;33.4500\nZarinsk;53.7089\nEast Providence;41.8065\nHuatan;24.0316\nMarhanets;47.6480\nPadra;22.2300\nMiddletown;41.5476\nSchwerte;51.4458\nUrrao;6.3156\nTres Arroyos;-38.3667\nDülmen;51.8308\nPrievidza;48.7711\nEgg Harbor;39.3787\nBlois;47.5939\nNysa;50.4714\nQiutouzhen;37.9841\nCalimaya;19.1608\nHà Tiên;10.3833\nSaranambana;-17.2500\nNeunkirchen;49.3500\nBanisilan;7.5000\nNorala;6.5500\nNoboribetsu;42.4128\nAl Quşayr;34.5119\nDracena;-21.4825\nGuajará-Mirim;-10.7828\nFrosinone;41.6333\nKabasalan;7.7968\nFujiyoshida;35.4875\nPuñal;19.4000\nGarhwa;24.1100\nWangtan;39.2847\nSanuki;34.3200\nTuy;14.0167\nRoldanillo;4.4167\nFilderstadt;48.6803\nFastiv;50.0747\nNanzhuangzhen;23.7210\nRondon do Pará;-4.7758\nQuva;40.5247\nYashan;22.4776\nBebandem;-8.4046\nValencia;8.2592\nAgrínio;38.6167\nCornélio Procópio;-23.1808\nObra;24.4200\nVeldhoven;51.4200\nSumpango;14.6464\nDongzhuosu;38.0658\nMelle;52.2044\nSan Rafael;10.0417\nBrea;33.9254\nCiudad Serdán;18.9833\nLohja;60.2500\nBorča;44.8700\nSalina;38.8136\nPotomac;39.0141\nLábrea;-7.2589\nMarechal Cândido Rondon;-24.5558\nHyvinkää;60.6333\nWodzisław Śląski;50.0000\nLukavac;44.5500\nTaebaek;37.1667\nHioki;31.6117\nOranienburg;52.7544\nShimeo;33.5914\nFangguan;39.3237\nNilambūr;11.2769\nLa Caleta;18.4639\nCordon;16.6667\nCoelho Neto;-4.2569\nLubny;50.0186\nTamagawa;33.6389\nSan Francisco de los Romo;22.0833\nEvesham;39.8605\nBerëzovskiy;55.6167\nMontevista;7.7053\nVercelli;45.3256\nZwijndrecht;51.8167\nJablonec nad Nisou;50.7244\nAland;17.5642\nThoubāl;24.6300\nStepnogorsk;52.3497\nHof;50.3167\nCabreúva;-23.3075\nAnandpur;21.2141\nIzunokuni;35.0333\nFarmington;36.7555\nSuluova;40.8333\nMānvi;15.9833\nJeomchon;36.6028\nFaratsiho;-19.4000\nBocaiúva;-17.1078\nYalvaç;38.2956\nMuara Teweh;-0.9535\nNakai;33.5833\nBeringen;51.0333\nPuerto Villarroel;-16.8667\nShimenzhai;40.0892\nJocotepec;20.2861\nSicklerville;39.7452\nSouth Brunswick;40.3840\nPuerto Tejada;3.2500\nEusébio;-3.8900\nTodupulai;9.8969\nNarvacan;17.4192\nCiudad Tecún Umán;14.6833\nBhālki;18.0435\nLower Tungawan;7.6047\nCornwall;45.0275\nCristalina;-16.7689\nDhupgāri;26.6000\nItapema;-27.0900\nOcoee;28.5796\nHilo;19.6883\nNawāshahr;31.1167\nRodgau;50.0167\nGryazi;52.5000\nḨadīthah;34.1397\nOro Valley;32.4208\nSena Madureira;-9.0658\nLa Independencia;16.2000\nDendermonde;51.0333\nConceição do Araguaia;-8.2578\nRío Tercero;-32.1833\nKurayoshi;35.4333\nDharmaragar;24.3785\nMontecristi;-1.0500\nDingle;11.0500\nMinster;51.4210\nKasaoka;34.5039\nTorzhok;57.0333\nTerracina;41.2833\nFort Pierce;27.4255\nTallbīsah;34.8333\nZhongzhai;25.7783\nJangamguda;17.5092\nWake Forest;35.9632\nChichigalpa;12.5722\nCamp Perrin;18.3167\nKilmarnock;55.6111\nGotha;50.9489\nAnshan;39.7144\nCapannori;43.8500\nJammalamadugu;14.8500\nCavaillon;18.3000\nLodi;45.3167\nFuxing;24.0341\nBanī ‘Ubayd;31.0234\nPagalungan;7.0592\nSan Lorenzo;-32.7500\nHenrietta;43.0555\nJoal-Fadiout;14.1667\nBeavercreek;39.7310\nTakashima;35.3500\nLabutta;16.1467\nSantiago Atitlán;14.6386\nMarino;41.7667\nSão Gabriel da Cachoeira;-0.1300\nLupao;15.8794\nBünde;52.2000\nAcaxochitlán;20.1667\nLaguna;-28.4828\nBatroûn;34.2500\nKaufbeuren;47.8800\nPuertollano;38.6833\nMairinque;-23.5464\nMaragogipe;-12.7778\nTingo María;-9.2953\nMegion;61.0500\nKafr al Baţţīkh;31.3234\nStrongsville;41.3128\nXingji;38.4682\nAmboasary;-25.0500\nWittenberg;51.8671\nCampechuela;20.2333\nKoupéla;12.1794\nBājil;15.0583\nSaint-Brieuc;48.5136\nManono;-7.2947\nRockwall;32.9169\nAttleboro;41.9311\nKikuchi;32.9833\nBruchsal;49.1333\nHokota;36.1587\nTayug;16.0267\nEl Valle del Espíritu Santo;10.9833\nFarrukhnagar;17.0778\nKrosno;49.6833\nShima;34.3333\nChâlons-en-Champagne;48.9575\nAlbstadt;48.2119\nChepén;-7.2271\nBridgewater;40.5934\nNawai;26.3824\nNova Venécia;-18.7108\nLagoa da Prata;-20.0228\nLivramento de Nossa Senhora;-13.6428\nWeinheim;49.5500\nPiro;25.3300\nSalon-de-Provence;43.6406\nOurém;39.6500\nFreeport City;26.5286\nSalto de Pirapora;-23.6489\nMindat;21.3667\nPhan Rí Cửa;11.1739\nPagsanjan;14.2667\nErkrath;51.2239\nMaluso;6.5500\nKaruvambram;11.0271\nParaguaçu Paulista;-22.4197\nCaiguantun;26.3363\nLumba-a-Bayabao;7.8833\nWinter Garden;28.5421\nMladá Boleslav;50.4125\nPearl City;21.4031\nHaymana;39.4311\nAcatlán de Pérez Figueroa;18.5333\nMiddletown;40.1790\nChangchong;26.3404\nMata de São João;-12.5300\nAribinda;14.2292\nChajarí;-30.7667\nTantangan;6.6167\nXisa;23.4372\nNocera Inferiore;40.7500\nKumta;14.4264\nAlcira;39.1500\nSalvador;20.2094\nVoi;-3.3906\nStouffville;43.9667\nKariya;34.7517\nMonte Carmelo;-18.7250\nWarud;21.4167\nCascina;43.6833\nHaltom City;32.8176\nHokuto;41.8241\nRājgarh;24.0300\nSanta María Huatulco;15.8500\nOlhão;37.0260\nAltamonte Springs;28.6615\nBeaufort West;-32.3500\nRemedios;22.4922\nJones;16.5583\nWestfield;40.0341\nKitakata;37.6511\nRāmeswaram;9.2880\nSète;43.4053\nErith;51.4800\nDrachten;53.1000\nElmhurst;41.8973\nAliwal North;-30.7000\nTalagutong;6.2667\nCuautepec de Hinojosa;20.1500\nBaiji;26.0231\nAlcamo;37.9778\nBrühl;50.8333\nRadā‘;14.4151\nGaya;11.8878\nMajurwa;26.1036\nSeohāra;29.2200\nArantāngi;10.1686\nSão Sebastião do Passé;-12.5128\nSan Isidro;9.3403\nBom Conselho;-9.1700\nHeusden;51.6998\nGuacharachi;27.1500\nOrtega;3.9167\nBusaar;2.6722\nItabirito;-20.2528\nManacor;39.5700\nPort Macquarie;-31.4333\nChimteppa;38.4667\nXiluo;23.7827\nBountiful;40.8721\nSan Pelayo;8.9667\nNāyudupet;13.9000\nPinamar;-37.1000\nLittleton;39.5915\nOtwock;52.1167\nNongzhangjie;24.6160\nShazhou;40.1376\nBāfq;31.6033\nCarnot;4.9400\nCiudad de Huajuapam de León;17.8097\nHuntsville;30.7009\nDehgolān;35.2781\nBirāk;27.5333\nGeorgina;44.3000\nDębica;50.0500\nSainthia;23.9451\nDunakeszi;47.6303\nSiyāna;28.6269\nWest Seneca;42.8374\nKamen’-na-Obi;53.7833\nGarango;11.8000\nMemmingen;47.9878\nSan Jacinto;16.0725\nVictoria;14.2250\nMedemblik;52.6833\nNæstved;55.2250\nAguilar;15.8899\nCharkhi Dādri;28.5900\nSvitlovodsk;49.0503\nBingmei;25.7408\nVictoriaville;46.0500\nBasud;14.0667\nParigi;-7.6914\nVallenar;-28.5708\nRuzayevka;54.0667\nFalkensee;52.5583\nGaoua;10.3167\nGračanica;44.6892\nBiella;45.5667\nMamanguape;-6.8389\nDowlaiswaram;16.9506\nMorgan Hill;37.1325\nJoão Pinheiro;-17.7442\nBrejo Santo;-7.4928\nTank;32.1300\nLørenskog;59.8989\nJedeïda;36.8333\nBarnagar;23.0489\nBrejo da Madre de Deus;-8.1458\nNumata;36.6460\nAngul;20.8381\nSundargarh;22.1200\nSan Pedro Perulapán;13.7667\nSeabra;-12.4189\nQarabulaq;42.5167\nSugito;36.0258\nNimule;3.5961\nNanjō;26.1631\nCampo Maior;-4.8278\nCheramkod;11.6000\nAngadanan;16.7571\nĀstāneh-ye Ashrafīyeh;37.2597\nWiener Neustadt;47.8167\nBeiwanglizhen;37.7604\nKeller;32.9335\nShangshan;23.4792\nTangjiacun;20.8425\nAksay;47.2500\nGuledagudda;16.0502\nRadomsko;51.0667\nConcepcion;11.2000\nLiuquan;39.3658\nMelūr;10.0313\nHassi Messaoud;31.7000\nKyle;29.9932\nTremembé;-22.9578\nYirga ‘Alem;6.7500\nMontemorelos;25.1872\nSakura;36.6853\nWebster;43.2294\nBuguias;16.8033\nChâteauroux;46.8103\nLittle Elm;33.1858\nYaopu;26.1708\nNova Kakhovka;46.7550\nTateyama;34.9966\nTres Valles;18.2367\nRabinal;15.0833\nIwanuma;38.1043\nMaria Aurora;15.7967\nPrescott;34.5849\nSayreville;40.4656\nAnekal;12.7105\nSidcup;51.4263\nUrbandale;41.6390\nShaḩḩāt;32.8250\nColotenango;15.4054\nKimry;56.8667\nShchūchīnsk;52.9333\nDarcheh;32.6153\nKutum;14.2056\nParma;65.9230\nSenigallia;43.7131\nSan Jose;13.6981\nBorlänge;60.4856\nYatağan;37.3425\n‘Ayn al ‘Arab;36.8910\nPederneiras;-22.3517\nRasskazovo;52.6667\nManjuyod;9.6833\nBaião;-2.7908\nBacnotan;16.7197\nLapa;-25.7700\nAshburn;39.0277\nAl ‘Azīzīyah;32.9083\nSierra Vista;31.5630\nNadym;65.5333\nĀz̄arshahr;37.7722\nMarau;-28.4489\nBolívar;1.9708\nTurnhout;51.3167\nSanta Bárbara;15.3167\nNeustadt am Rübenberge;52.5000\nNandigāma;16.7833\nDráma;41.1500\nPemangkat;1.1768\nNasipit;8.9884\nHoubu;36.4370\nVolkhov;59.9167\nBarras;-4.2469\nCutler Bay;25.5765\nZhovti Vody;48.3500\nZevenaar;51.9167\nNsawam;5.8000\nKatipunan;8.5134\nMount Pleasant;41.1119\nJisr ash Shughūr;35.8126\nNagaizumi;35.1377\nKaarst;51.2167\nNoordwijk;52.2333\nJacaltenango;15.6667\nBalcarce;-37.8456\nPalm Springs;33.8017\nUruará;-3.7178\nPresidente Dutra;-5.2900\nManchester;39.9652\nEllenabad;29.4500\nNidadavole;16.9200\nRiverton;40.5176\nDolores;12.0378\nPiendamó;2.6408\nPyu;18.4819\nYaoquan;34.5851\nTori-Bossito;6.5031\nAbū al Maţāmīr;30.9084\nLancaster;42.9099\nTaketoyo;34.8511\nLehrte;52.3667\nLake Ridge;38.6847\nCulasi;11.4272\nMawlaik;23.2833\nDeinze;50.9833\nŚwidnik;51.2167\nEtten-Leur;51.5667\nSeferhisar;38.2000\nAlaplı;41.1833\nSan Pascual;13.1286\nArboletes;8.8517\nLoon;9.8000\nGarça;-22.2153\nRājaldesar;28.0300\nMedak;18.0460\nKikuyō;32.8625\nVernon;50.2670\nTiberias;32.7944\nRibeirão;-8.5139\nDalli Rājhara;20.5800\nYuanli;24.4168\nJora;26.3421\nDenia;38.8444\nBanaybanay;6.9664\nFairfield;39.3301\nVlissingen;51.4500\nLabangan;7.8667\nBietigheim-Bissingen;48.9667\nMasuda;34.6667\nQingfengdian;38.6084\nChangtoushang;19.3441\nGeneral Pacheco;-34.4500\nBarwāh;22.2539\nWest Lafayette;40.4432\nBulalacao;12.3333\nGoose Creek;32.9927\nTsiroanomandidy;-18.7698\nPetatlán;17.5383\nProstějov;49.4722\nAlbufeira;37.0897\nMount Laurel;39.9483\nPorsa;26.6700\nSan Juan y Martínez;22.2667\nParaíso do Tocantins;-10.1758\nTongoma;8.6500\nAnanipalle;13.6500\nWallingford;41.4589\nSihora;23.0000\nLos Banos;37.0630\nSvishtov;43.6167\nFond du Lac;43.7718\nBassano del Grappa;45.7667\nGeneral Mamerto Natividad;15.6030\nÇayeli;41.0880\nTuodian;24.6907\nBrentwood;35.9918\nEqlīd;30.8989\nMaitum;6.0333\nRaisen;23.3300\nVolksrust;-27.3667\nRheden;52.0167\nManakara;-22.1500\nLombard;41.8741\nSão Benedito;-4.0489\nPlainfield;41.6207\nSonqor;34.7836\nCateel;7.7900\nMauriti;-7.3889\nMandaon;12.2259\nKorogwe;-5.1558\nChar Fasson;22.1861\nDounan;23.6833\nTinajdad;31.5000\nDikili;39.0667\nGuinayangan;13.9000\nKrasnodon;48.3000\nXanxerê;-26.8769\nOgimachi;33.2500\nAddanki;15.8110\nNilothi;28.8167\nLas Matas de Farfán;18.8700\nLompoc;34.6618\nHarsīn;34.2722\nPanambi;-28.2928\nNijkerk;52.2333\nJānakammapeta;14.8840\nLabason;8.0647\nBurke;38.7773\nHagi;34.4000\nKuybyshev;55.4500\nJinku;23.0398\nAlghero;40.5600\nRoghun;38.6978\nSaint-Eustache;45.5700\nYutiancun;25.8747\nOtofuke;42.9942\nBadian;9.8694\nSan Cristóbal Totonicapán;14.9197\nYartsevo;55.0667\nMoorhead;46.8673\nWānkāner;22.6161\nTalatamaty;-18.8333\nGoshikichō-aihara-minamidani;34.3000\nBarpeta;26.3200\nKaštel Stari;43.5500\nCimerak;-7.7422\nSan Vicente de Tagua Tagua;-34.4394\nAl Midhnab;25.8601\nRudauli;26.7500\nPantanal;18.5333\nMaştağa;40.5328\nMaracaju;-21.6139\nBakamune;7.7831\nXinjun;28.7232\nBoyabat;41.4653\nDe Bilt;52.1167\nMenghan;21.8526\nLimache;-33.0167\nVenray;51.5333\nAbqaiq;25.9350\nKamen;51.5917\nIstres;43.5151\nPinhal;-22.1908\nComendador;18.8833\nZongolica;18.6642\nJiaohe;38.0228\nMucaba;-7.1667\nHinatuan;8.3661\nCasale;18.8014\nSurčin;44.8000\nJaro;11.1894\nPardés H̱anna Karkur;32.4711\nKhutubi;44.1874\nSan Germán;20.6011\nSão Gonçalo do Amarante;-3.6058\nMankato;44.1715\nHimi;36.8567\nGravina in Puglia;40.8167\nQiryat Moẕqin;32.8333\nYatomi;35.1167\nNandazhang;38.1031\nLoreto;8.1856\nBāniyās;35.1822\nJaito;30.4514\nPittsfield;42.4517\nKalilangan;7.7464\nVilleta;5.0083\n’Aïn Arnat;36.1833\nMarki;52.3333\nTavas;37.5728\nĀzādshahr;37.0869\nCiudad Constitución;25.0322\nErkelenz;51.0833\nChikodi;16.4300\nTanghin-Dassouri;12.2667\nŞān al Ḩajar al Qiblīyah;30.9769\nEl Asintal;14.6000\nKāyalpattanam;8.5638\nChefchaouene;35.1714\nLaurel;14.0500\nToboso;10.7167\nWismar;53.9000\nAl Kiswah;33.3500\nSevilla;4.2689\nMahbūbābād;17.5973\nSanta Elena;14.1797\nMadridejos;11.2667\nTamu;24.2167\nKattivākkam;13.2167\nMoises Padilla;10.2667\nBarauli;26.3815\nChusovoy;58.3167\nZhangliangcun;37.1256\nKonārak;25.3603\nKharik;25.3679\nMacenta;8.5504\nBarhiya;25.2833\nEṭ Ṭaiyiba;32.2667\nTakāb;36.4008\nTaniyama-chūō;31.5211\nRoseller Lim;7.6583\nShinshiro;34.9159\nWaslala;13.3367\nXihuachi;35.8164\nDanville;37.8121\nOf;40.9450\nSan Sebastián Huehuetenango;15.3833\nGuambog;7.3092\nPaoskoto;13.7833\nNorth Brunswick;40.4505\nAlès;44.1281\nÇeşme;38.3236\nCové;7.2333\nPonte de Lima;41.7667\nAngoulême;45.6500\nZhongbu;23.4082\nBirsk;55.4167\nAmbāsamudram;8.7037\nDildārnagar;25.4309\nRaduzhnyy;62.1333\nQuinte West;44.1833\nPresidente Epitácio;-21.7633\nEl Cuá;13.3678\nLota;-37.0833\nPontes e Lacerda;-15.2258\nYeola;20.0420\nBahía Honda;22.9064\nMaïssade;19.1667\nSanta Cruz;32.6833\nZhangcun;38.1262\nHokuto;35.7765\nAbucay;14.7222\nAnse Rouge;19.6333\nThe Colony;33.0925\nOdenton;39.0661\nWangyuanqiao;38.3849\nSouthington;41.6050\nDilbeek;50.8333\nBerubāri;26.3603\nPedro Celestino Negrete;24.7260\nMuttayyāpuram;8.7498\nMakinohara;34.7333\nHeist-op-den-Berg;51.0833\nZharkent;44.1667\nSiegburg;50.8014\nSouth Upi;6.8548\nBolvadin;38.7167\nGurrampod;16.8667\nBerkeley;39.9156\nSawākin;19.1025\nAlenquer;39.0500\nGifhorn;52.4886\nWest Babylon;40.7129\nShakopee;44.7745\nLinden;40.6251\nEstância Velha;-29.6478\nDouar Bni Malek;34.7800\nAltadena;34.1927\nShimabara;32.7878\nPirthīpur;25.1853\nShināş;24.7500\nHueyapan de Ocampo;18.1500\nHeinsberg;51.0631\nTešanj;44.6142\nSaoner;21.3858\nLokeren;51.1000\nShōranūr;10.7700\nEsperanza;-31.4167\nKing’s Lynn;52.7540\nSūrampatti;11.3411\nGallatin;36.3782\nVahdat;38.5531\nAkbarpur;26.5200\nRantepao;-2.9690\nSan Lorenzo;13.4217\nSan Clemente;-35.5500\nMaḩallāt;33.9111\nKemer;36.6000\nCivitanova Marche;43.3000\nKōta;34.8645\nAndes;5.5833\nAnakaputtur;12.9823\nPaso de los Libres;-29.7167\nGermering;48.1333\nShuilou;22.3360\nBorken;51.8333\nHố Nai;10.9725\nNova Viçosa;-17.8919\nAguazul;5.1731\nQuirinópolis;-18.4478\nSevanagala;6.3867\nChicamán;15.3483\nKalaiyā;27.0333\nWentzville;38.8153\nVéroia;40.5203\nCiechanów;52.8667\nVergína;40.5167\nYepocapa;14.5000\nLaatzen;52.3167\nKobayashi;31.9944\nNansan;23.7784\nHoddesdon;51.7590\nPřerov;49.4556\nTiel;51.8833\nVillaba;11.2167\nBan Pet;16.4379\nCumaribo;4.4333\nSinghanakhon;7.2389\nSão Lourenço do Sul;-31.3650\nLaungowāl;30.2167\nSanto Tomas;15.0000\nMiura;35.1500\nLubao;-5.3850\nJesús María;21.9667\nNueva Valencia;10.5259\nMusina;-22.3381\nBuffalo Grove;42.1675\nKārmegh;26.5307\nNaranjo;10.1053\nAlhaurín de la Torre;36.6667\nEntre Rios;-11.9419\nPanitan;11.4639\nAmadeo;14.1728\nPeriyakulam;10.1200\nLa Mata;19.1000\nGualeguay;-33.1500\nNettetal;51.3167\nJatibonico;21.9464\nAlbano Laziale;41.7333\nOakley;37.9929\nJājpur;21.2140\nMiranda;3.2500\nOsinniki;53.6167\nCuchi;-14.6500\nBourg-en-Bresse;46.2056\nItapa-Ekiti;7.8131\nAkdağmadeni;39.6658\nSidi Mohamed Lahmar;34.7167\nLimbdi;22.5685\nLoufan;38.0694\nAtenco;19.5167\nPalmas;-26.4839\nSamborondón;-1.9611\nZvolen;48.5706\nEagle Mountain;40.3137\nSieradz;51.6000\nShenjiatun;40.7695\nDreieich;50.0000\nHuizen;52.3000\nLucena;37.4000\nThomassique;19.0833\nNurmijärvi;60.4667\nAwaji;34.4333\nOrlândia;-20.7203\nMajhaul;25.5570\nKārsiyāng;26.8800\nVawkavysk;53.1667\nBukama;-9.2000\nSan Francisco Menéndez;13.8425\nProper Bansud;12.8594\nVera Cruz;-12.9600\nCatonsville;39.2646\nObita;32.8252\nAmberg;49.4444\nHillsborough;40.4985\nSanta Quitéria;-4.3319\nEisenach;50.9761\nShetou;23.9076\nSanto Antônio da Platina;-23.2950\nAurich;53.4714\nCabo Bojador;26.1333\nWoodbridge;38.6409\nTucuran;7.8547\nLeigh;53.4975\nFianga;9.9153\nMombaça;-5.7428\nSarıkamış;40.3381\nOrmond Beach;29.2985\nCurrais Novos;-6.2608\nSansanné-Mango;10.3556\nHwange;-18.3647\nUnião;-4.5858\nCacocum;20.7439\nAvezzano;42.0411\nYaguate;18.3300\nMoline;41.4821\nMariel;22.9936\nLlanera;15.6625\nHuber Heights;39.8595\nKotabumi;-4.8333\nLa Orotava;28.3667\nEdmonds;47.8115\nDusheng;38.3804\nNuevo San Carlos;14.6000\nNyunzu;-5.9500\nLa Tebaida;4.4500\nImperia;43.8833\nCharlottetown;46.2403\nKöniz;46.9333\nBalabac;7.9833\nManassas;38.7479\nBhatpalli;18.4314\nMaroantsetra;-15.4333\nMaulavi Bāzār;24.4808\nSanarate;14.7950\nThān;22.5667\nMachalí;-34.1825\nKasai;34.9333\nNāndūra Buzurg;20.8333\nDanville;36.5831\nVilla Bisonó;19.5600\nAkaiwa;34.7553\nEl Charco;2.4775\nLiloy;8.1228\nTineghir;31.5147\nSan Rafael del Sur;11.8458\nAraioses;-2.8900\nShebekino;50.4167\nCastres;43.6000\nCortlandt;41.2552\nMascouche;45.7500\nCuihua;27.7527\nSanta Rita;11.4522\nFuttsu;35.3041\nCarranglan;15.9608\nEnfield;41.9839\nSanta Cruz;13.0831\nAlerce;-41.4000\nWest Vancouver;49.3667\nCapão da Canoa;-29.7608\nPahrump;36.2235\nPolanco;8.5319\nBelleville;38.5164\nQuezon;15.5542\nShepetivka;50.1833\nBeverly;42.5681\nShū;43.5983\nPresident Quirino;6.7000\nTomé;-36.6167\nMidland;43.6241\nTactic;15.3167\nYangcunzai;23.4338\nCoppell;32.9639\nSalaberry-de-Valleyfield;45.2500\nBalykchy;42.4611\nUden;51.6500\nChannelview;29.7914\nMyanaung;18.2833\nSão Lourenço;-22.1158\nLiantang;22.9352\nItápolis;-21.5958\nWancheng;37.6273\nClaveria;12.9035\nMachang;26.5634\nPuyallup;47.1793\nNiquelândia;-14.4739\nPorangatu;-13.4408\nNāthdwāra;24.9300\nNalhāti;24.3000\nAritao;16.2973\nQuesada;10.3441\nBan Wat Lak Hok;13.5633\nNakano;36.7420\nQəzyan;39.2914\nRouyn-Noranda;48.2333\nQā’en;33.7256\nSeevetal;53.3833\nSan Donà di Piave;45.6298\nRancho Palos Verdes;33.7554\nHomburg;49.3167\nManiwa;35.0758\nBilāsipāra;26.2328\nBeitbridge;-22.2167\nRemanso;-9.6219\nCoronel Suárez;-37.4667\nPratāpgarh;24.0300\nMorarano Chrome;-17.7500\nAnsbach;49.3000\nMatnog;12.5856\nNārāyanpet;16.7445\nBacong;9.2464\nDacun;34.7201\nKollo;13.0167\nMacerata;43.3003\nGay;51.4167\nMozdok;43.7333\nMampong;7.0667\nSarakhs;36.5450\nAlcalde Díaz;9.1200\nSbiba;35.5467\nPuerto Real;36.5292\nNordhausen;51.5050\nSafonovo;55.1167\nDiyadin;39.5400\nPuerto del Rosario;28.5000\nSaidpur Dabra;25.3207\nGolāghāt;26.5200\nSchwabach;49.3292\nMinamishimabara;32.6667\nMonterotondo;42.0500\nGreenock;55.9500\nSidrolândia;-20.9319\nMontenegro;4.5671\nMemāri;23.2000\nAmontada;-3.3608\nCáceres;7.6667\nPuerto Galera;13.5000\nLingquan;36.9985\nCoachella;33.6905\nMonchegorsk;67.9333\nDronten;52.5167\nSoran;49.7833\nAnda;16.2896\nLitian Gezhuang;39.8151\nCoburg;50.2667\nPoti;42.1500\nSarāb;37.9414\nSu-ngai Kolok;6.0333\nYagoua;10.3428\nLinton Hall;38.7551\nBarcellona-Pozzo di Gotto;38.1500\nCoyuca de Catalán;18.3256\nKorenovsk;45.4686\nSan José de Bocay;13.5428\nMyedu;23.1833\nPeachtree Corners;33.9670\nWoodlawn;39.3054\nXinleitou;37.9752\nSoliman;36.7000\nKibawe;7.5678\nTequila;20.8794\nMoatize;-16.1167\nMerano;46.6696\nSanta Rosa del Sur;7.9667\nVasto;42.1116\nShimotsuma;36.1844\nYinggen;19.0372\nFenoarivo Atsinanana;-17.3814\nKolchugino;56.3167\nBillerica;42.5587\nBeigang;23.5667\nRajaori;33.3800\nTādif;36.3481\nSpassk-Dal’niy;44.6000\nKirchheim unter Teck;48.6483\nNürtingen;48.6333\nPine Bluff;34.2116\nVargem Grande do Sul;-21.8319\nPāmban;9.2790\nSpanish Fork;40.1101\nHongfengcun;21.9231\nSan;13.3004\nMedianeira;-25.2950\nIshaka;-0.5450\nTulun;54.5667\nWunstorf;52.4275\nPedra Branca;-5.4539\nBragadiru;44.3708\nNaga;7.7978\nSan Pedro Necta;15.5000\nKasibu;16.3181\nDaram;11.6341\nBayt al Faqīh;14.5161\nJaraguá;-15.7569\nNanbaishezhen;37.7526\nColomiers;43.6139\nSassuolo;44.5517\nSan Miguel;8.9322\nJardinópolis;-21.0178\nTramandaí;-29.9850\nSocorro;13.0583\nWijchen;51.8000\nIhnāsyā al Madīnah;29.0833\nTabogon;10.9333\nDhamdāha;25.7435\nSānand;22.9800\nOqtosh Shahri;39.9269\nSatka;55.0500\nSanta Cruz;17.0853\nSanta Maria da Vitória;-13.3978\nCiudad Vieja;14.5233\nTagudin;16.9361\nEberswalde;52.8333\nChojnice;53.7000\nAmuntai;-2.4177\nWujie;24.7000\nFitchburg;42.5912\nHempfield;40.2847\nNanbei;35.3167\nKearny;40.7528\nTimmins;48.4667\nMikołów;50.1667\nMalilipot;13.3167\nKönigswinter;50.6736\nIndi;17.1773\nPatzicía;14.6336\nPīleru;13.6549\nBuddh Gaya;24.6981\nDacun;23.9911\nMyski;53.7000\nSanta Cruz de Los Taques;11.8231\nRājgīr;25.0300\nGonzaga;18.2614\nBorba;-4.3878\nStrezhevoy;60.7333\nPueblo Nuevo;8.5008\nKwidzyn;53.7358\nPodilsk;47.7419\nVarash;51.3444\nPanchimalco;13.6167\nYakacık;36.7500\nSarandë;39.8750\nRāmganj Mandi;24.6472\nUst’-Kut;56.7833\nSanto Domingo;9.9880\nDohazāri;22.1628\nGatunda;-1.4350\nŚwinoujście;53.9167\nSipe Sipe;-17.4500\nJayamkondacholapuram;11.2127\nNanmeng;39.1773\nMaplewood;44.9842\nYangtangxu;21.6172\nPatulul;14.4167\nArraiján;8.9500\nTuchín;9.1858\nHerstal;50.6667\nYuzawa;39.1641\nLidköping;58.5000\nSaint-Germain-en-Laye;48.8989\nCantù;45.7333\nCopán;14.8375\nFredericia;55.5667\nPeddapalli;18.6162\nParanaíba;-19.6769\nMableton;33.8133\nSorel-Tracy;46.0333\nNaini Tal;29.3919\nMasaki;33.7833\nPilate;19.6667\nKarabulak;43.3167\nSchertz;29.5650\nAmbohitrimanjaka;-18.8667\nLadispoli;41.9544\nYarumal;7.0000\nNewnan;33.3767\nThionville;49.3589\nAyagöz;47.9667\nKitaibaraki;36.8019\nAmancio;20.8197\nAlmenara;-16.1005\nHellevoetsluis;51.8167\nGaolincun;39.0887\nClermont;28.5325\nMondragon;12.5167\nNorth Fort Myers;26.7244\nSchwäbisch Hall;49.1122\nBaichigan;39.5275\nTālcher;20.9500\nGeel;51.1667\nSinanpaşa;38.7500\nMaayon;11.3903\nAlcala;17.9031\nPaliā Kalān;28.4500\nVerkhnyaya Salda;58.0456\nMarlborough;42.3494\nVineyard;38.4740\nErzin;36.9533\nAgar;23.7118\nSanto Tomas;16.2833\nKomoro;36.3275\nMorrinhos;-17.7319\nBury Saint Edmunds;52.2474\nZduńska Wola;51.6000\nNovo Horizonte;-21.4678\nLeinfelden-Echterdingen;48.6928\nNew Tecumseth;44.0833\nMersa;11.6667\nTabarka;36.9544\nCoram;40.8812\nNowa Sól;51.8000\nVilla Ángela;-27.5833\nLasam;18.0667\nSzigetszentmiklós;47.3456\nAntequera;37.0183\nSovetsk;55.0808\nPatti;31.2800\nSherghāti;24.5700\nLa Libertad;10.0333\nCompiègne;49.4149\nHückelhoven;51.0608\nTanxia;23.9475\nTiegan;38.1536\nMarlboro;40.3427\nEl Tocuyo;9.7822\nQiryat Yam;32.8333\nVavveru;14.5594\nGuácimo;10.2025\nBensheim;49.6667\nNiquero;20.0472\nArauquita;7.0303\nGirau do Ponciano;-9.8839\nChaves;41.7406\nHatfield;51.7636\nGanta;7.2375\nFreiberg;50.9119\nSão Mateus do Sul;-25.8739\nKovvūr;17.0170\nSumoto;34.3500\nJärvenpää;60.4750\nAnyuan;34.8839\nSan Jose de Urquico;15.4781\nVillanueva;8.5833\nYingzhou Linchang;18.4199\nSan Juan;16.6667\nUnzen;32.8353\nConstitución;-35.3333\nTemryuk;45.2667\nHalfeti;37.2489\nAnglet;43.4850\nSão Manuel;-22.7308\nAmami;28.3783\nVallehermoso;10.3333\nTagbina;8.4578\nGuaduas;5.0694\nParaíba do Sul;-22.1619\nMatiguás;12.8372\nShanhe;35.4844\nArdeşen;41.1900\nPenn Hills;40.4762\nAmbositra;-20.5167\nBartlett;41.9804\nTampakan;6.4500\nPilāni;28.3700\nKabuga;-1.9667\nMarcianise;41.0333\nJeremoabo;-10.0669\nMobo;12.3372\nOstfildern;48.7333\nLemgo;52.0272\nJiquipilas;16.5333\nMucuri;-18.0858\nBazar-Korgon;41.0417\nHollister;36.8555\nUpper Hutt;-41.1333\nCiudad Darío;12.7322\nBullhead City;35.1205\nDois Vizinhos;-25.7500\nBolesławiec;51.2667\nLancaster;32.5922\nPirmasens;49.2000\nChambas;22.1967\nSint-Truiden;50.8167\nNabas;11.8278\nMaarssen;52.1351\nSegovia;7.0781\nUozu;36.8273\nGrove City;39.8654\nMarion;42.0451\nBrookfield;43.0640\nBagua Grande;-5.7572\nPuerto Gaitán;4.3142\nPyt’-Yakh;60.7500\nDowlatābād;32.7997\nDelaware;40.2851\nGap;44.5594\nMaddela;16.3411\nMambusao;11.4300\nKatō;34.9167\nNovozybkov;52.5333\nJogbani;26.4024\nLarantuka;-8.3133\nTaicheng;38.7206\nBarr Eliâs;33.7750\nLobo;13.6500\nOsório;-29.8869\nWoburn;42.4869\nColumbia;35.6238\nGermantown;35.0829\nPartāpnagar;25.4145\nKrishnarājāsāgara;12.4398\nInhambupe;-11.7839\nChebarkul;54.9833\nShelton;41.3060\nRomny;50.7428\nMaragondon;14.2667\nCovington;39.0334\nDelījān;33.9906\nBalaoan;16.8167\nWestfield;42.1382\nCiudad Piar;7.4522\nYomitan;26.3961\nTirukkoyilūr;11.9500\nKitob;39.1336\nPugachev;52.0167\nBarreiros;-8.8167\nApóstoles;-27.9167\nWoodstock;43.1306\nMangaratiba;-22.9600\nNowgong;25.0574\nPromissão;-21.5369\nKadūr;13.5529\nRio Real;-11.4833\nCiudad Barrios;13.7667\nWageningen;51.9667\nChiredzi;-21.0389\nAhlat;38.7528\nTianzhong;23.8595\nCuito Cuanavale;-15.1667\nValladolid;10.4667\nAbadan;38.0517\nCaeté;-19.8800\nSão Bento;-2.6958\nZoumi;34.8000\nSanta Eulalia del Río;38.9847\nSamālkha;29.2300\nZhujiezhen;23.7460\nBañga;11.6389\nTomar;39.6000\nPereslavl’-Zalesskiy;56.7381\nNeumarkt;49.2833\nSabalgarh;26.2500\nGonābād;34.3528\nFriendswood;29.5110\nPālampur;32.1097\nThe Acreage;26.7740\nJhābua;22.7677\nLugoj;45.7056\nQeshm;26.9581\nPie de Pató;5.5333\nWeißenfels;51.2000\nKīlakkarai;9.2314\nBoucherville;45.6000\nKhowrmūj;28.6489\nYalutorovsk;56.6500\nPachrūkha;26.7373\nSivaganga;9.8433\nArys;42.4333\nSiay;7.7056\nEssex;39.3021\nKomono;35.0200\nBuchholz in der Nordheide;53.3167\nSciacca;37.5092\nBarra de São Francisco;-18.7550\nNanuque;-17.8389\nNabarūh;31.0942\nChannarāyapatna;12.9000\nVellakkovil;10.9300\nBuxtehude;53.4769\nMontélimar;44.5581\nKhawr Fakkān;25.3333\nLa Unión;4.5331\nBayındır;38.2192\nSoe;-9.8667\nSanto Antônio de Pádua;-21.5389\nPechora;65.1667\nLöhne;52.2000\nDouar Laouamra;31.8000\nManalapan;40.2800\nLeyte;11.3667\nPanglao;9.5833\nRovereto;45.8833\nBraine-l’Alleud;50.6806\nLordegān;31.5081\nRizal;12.4667\nAgano;37.8344\nHuaura;-11.1000\nIslāmpur;25.1407\nXinguara;-7.0950\nIesi;43.5236\nBan Bang Khu Lat;13.9134\nMailapur;13.0210\nMaihar;24.2620\nDuncanville;32.6460\nTaysan;13.7833\nMurtajāpur;20.7300\nUray;60.1333\nFreital;51.0167\nCabatuan;16.9589\nDingras;18.1036\nCumbal;0.9078\nPayabon;9.7667\nAugusto Correa;-1.0219\nHalberstadt;51.8958\nYian;47.8804\nAl Qā‘idah;13.7569\nMaintal;50.1500\nLilio;14.1300\nCedar Falls;42.5195\nAndradas;-22.0678\nMagburaka;8.7169\nMilton;34.1353\nCorigliano Calabro;39.6000\nYajalón;17.1833\nOlintepeque;14.8833\nCauquenes;-35.9667\nLishaocun;22.7236\nHofheim;50.0833\nCamaná;-16.6167\nAracataca;10.5937\nHeemskerk;52.5167\nAizawa;35.5288\nSirinhaém;-8.5908\nZainsk;55.3000\nWeslaco;26.1599\nBegamganj;23.5992\nLake Oswego;45.4129\nJunnar;19.2000\nImbituba;-28.2400\nŌzu;33.5000\nUchqŭrghon Shahri;41.1214\nJipijapa;-1.3486\nIlıca;39.9458\nMalalag;6.6000\nTúquerres;1.0833\nGlenrothes;56.1980\nFonds Verrettes;18.3833\nLancaster;39.7248\nEboli;40.6169\nBeyneū;45.3247\nAmpana;-0.8667\nHailākāndi;24.6839\nSchorndorf;48.8000\nPlaridel;8.6214\nJāle;26.3800\nMolina;-35.1144\nBalud;12.0369\nMajibacoa;20.9172\nFindlay;41.0469\nLeramatang;-8.4000\nBelaya Kalitva;48.1833\nSan Fernando de Henares;40.4256\nTietê;-23.1019\nGourcy;13.2167\nArawa;-6.2250\nNew Berlin;42.9726\nKunigal;13.0232\nTosya;41.0172\nÁguas Belas;-9.1167\nOświęcim;50.0381\nPovažská Bystrica;49.1139\nL’Asile;18.3833\nSanto Niño;6.4333\nItoigawa;37.0390\nSarāqib;35.8636\nKasumigaura;36.1517\nHavza;40.9667\nUttarkāshi;30.7300\nSecunda;-26.5161\nNawābganj;28.5400\nSejenane;37.0564\nSindgi;16.9200\nBāsudebpur;21.1197\nCamargo;27.6670\nTipton;52.5259\nSantiago Nonualco;13.5167\nHutchinson;38.0671\nHolly Springs;35.6526\nMtsensk;53.2833\nTutayev;57.8833\nFrench Valley;33.5999\nVyshneve;50.3869\nHangu;33.5333\nLongtang;26.1984\nKālimpong;27.0600\nRaxruhá;15.8666\nNinove;50.8333\nDraguignan;43.5403\nMedgidia;44.2503\nSecurity-Widefield;38.7489\nKambia;9.1167\nSoavinandriana;-19.1667\nOroqen Zizhiqi;50.5667\nSagae;38.3809\nVendrell;41.2201\nRaub;3.7931\nZacualpa;15.0272\nNeu Isenburg;50.0500\nSkövde;58.3833\nHurst;32.8353\nAmursk;50.2167\nBaksan;43.6825\nOtavalo;0.2303\nRomeoville;41.6318\nMaddaloni;41.0333\nCrystal Lake;42.2333\nAltagracia de Orituco;9.8504\nSiniloan;14.4167\nUnión de Reyes;22.8003\nFondi;41.3500\nJanīn;32.4611\nJayrūd;33.8067\nJalalabad;35.8800\nZhongbai;26.7723\nAlashankou;45.1733\nEttlingen;48.9333\nVavuniya;8.7500\nTarauacá;-8.1608\nMatsoandakana;-14.9667\nRevelganj;25.7800\nJiaozishan;26.3342\nBangkinang;0.3500\nVölklingen;49.2500\nPamplona;9.4667\nBaco;13.3584\nAlimodian;10.8196\nKyaukme;22.5392\nTago;9.0192\nPojuca;-12.3659\nFasano;40.8333\nIdangansālai;11.6272\nLangen;49.9833\nHuamachuco;-7.8120\nHalle;50.7361\nVoghera;44.9925\nZimapan;20.7333\nOssining;41.1559\nRauma;61.1333\nSan Nicolas;16.0700\nAcevedo;1.8192\nVilla de San Diego de Ubaté;5.3072\nXinlizhuang;39.2832\nYecapixtla;18.8833\nTivaouane;14.9500\nAtmakūr;15.8779\nClinton;38.7499\nPoblacion;7.5086\nAhaus;52.0667\nWeibo;38.0290\nSão José de Mipibu;-6.0750\nPalauig;15.4336\nAyirāpuram;9.8781\nMeadow Woods;28.3698\nMagsaysay;12.3117\nCarol Stream;41.9181\nBrighton;39.9716\nRio Negrinho;-26.2539\nAgoncillo;13.9334\nÉcija;37.5333\nKīsh;26.5578\nNueva Santa Rosa;14.3811\nSan Nicolas;18.1750\nKırkağaç;39.1039\nNorthampton;40.2104\nMatías Romero;16.8798\nBetun;-9.4953\nMichalovce;48.7553\nGuaíra;-20.3178\nSoria;41.7667\nWālājāpet;12.9255\nNūrpur;29.1500\nSrebrenik;44.7000\nWinslow;39.7027\nWürselen;50.8167\nClarin;8.2000\nPamplona;13.5925\nBādepalli;16.7549\nWaxahachie;32.4035\nKurobeshin;36.8667\nVeruela;8.0698\nVillamontes;-21.2608\nToukountouna;10.4986\nApsheronsk;44.4667\nReynoldsburg;39.9588\nLíbano;4.9167\nBosconia;9.9761\nDolores;16.5142\nMibu;36.4422\nLa Rinconada;37.4833\nKalingalan Caluang;5.8833\nTodos Santos Cuchumatán;15.5116\nBuldon;7.5167\nSogod;10.7500\nTalacogon;8.4488\nNiederkassel;50.8167\nSteyr;48.0333\nBenenitra;-23.4522\nCaraga;7.3283\nSalcedo;19.3780\nPirna;50.9622\nIsfisor;40.2433\nSolan;30.9050\nShengang;24.1648\nShankarpur Khawās;25.2016\nMettmann;51.2500\nLloret de Mar;41.7000\nPlasencia;40.0275\nAsamankese;5.8667\nStreamwood;42.0209\nCittà di Castello;43.4608\nTafí Viejo;-26.7333\nSanto Antônio;-29.8178\nYomra;40.9667\nArucas;28.1184\nQuincy;39.9336\nŢabas;33.5958\nKhāchrod;23.4232\nSchio;45.7111\nAlicia;7.5060\nXonqa;41.4742\nManay;7.2108\nRāni;25.5564\nLa Chaux-de-Fonds;47.1013\nSocorro;-22.5908\nModugno;41.0833\nNovodvinsk;64.4167\nRosário;-2.9339\nRamallah;31.9000\nCharaut;26.5322\nValrico;27.9193\nJoué-lés-Tours;47.3514\nMarratxi;39.6421\nArcos;-20.2914\nVilla del Carbón;19.7272\nSeram;17.1830\nTakikawa;43.5578\nStirling;56.1166\nIndian Trail;35.0699\nStendal;52.6000\nTianchang;37.9981\nSanjiang;24.7265\nSan Giuliano Milanese;45.4000\nXiushui;24.0356\nOneşti;46.2586\nFarīmān;35.7069\nVetapālem;15.7800\nTrofa;41.3374\nYangfang;40.5723\nSan José de Ocoa;18.5500\nGradačac;44.8789\nMitsuke;37.5316\nPokrov;47.6533\nNarón;43.5500\nOliveira;-20.6958\nSan Juan del Cesar;10.7667\nBenjamin Constant;-4.3755\nDamulog;7.4853\nNiutuo;39.2618\nHobbs;32.7281\nDoğanşehir;38.0958\nTlalixcoyan;18.8031\nPresidente Venceslau;-21.8761\nSanta Maria da Boa Vista;-8.8089\nÇiftlikköy;40.6603\nCarini;38.1333\nSayansk;54.1167\nAbinsk;44.8667\nParral;-36.1500\nRusape;-18.5367\nTonbridge;51.1987\nTangpingcun;22.0292\nCape Girardeau;37.3109\nEccles;53.4824\nOviedo;28.6580\nTāki;22.5900\nWhanganui;-39.9325\nAxochiapan;18.5000\nSirohi;24.8850\nSual;16.0661\nTeboulba;35.6700\nPehowa;29.9800\nDraa el Mizan;36.5333\nCanela;-29.3658\nAbrantes;39.4633\nMoanda;-1.5667\nSopot;54.4500\nApan;19.7000\nPuerto Berrío;6.4900\nSan Dionisio;11.2711\nShibata;38.0566\nTamba-Sasayama;35.0725\nShijiazhuangnan;37.9383\nWarren;41.2390\nSão Francisco do Conde;-12.6278\nMapandan;16.0260\nRosário do Sul;-30.2578\nCacuso;-8.2333\nMarcos Paz;-34.7667\nKøge;55.4561\nOraiókastro;40.7333\nCabugao;17.7947\nTarazá;7.5881\nKirkkonummi;60.1167\nBetamcherla;15.4667\nThakraha;26.7419\nSikandra Rao;27.7000\nPlant City;28.0140\nSandino;22.0803\nHigashimatsushima;38.4263\nSidi Bibi;30.2333\nBasista;15.8524\nIlmenau;50.6839\nOspino;9.3000\nAmla;21.9248\nSzczecinek;53.7167\nSan Raimundo;14.7647\nSungandiancun;36.2221\nYelizovo;53.1833\nBrasschaat;51.2931\nWaregem;50.8811\nPenumūr;13.3667\nCaluya;11.9320\nSalinas;-16.1185\nCayambe;0.0439\nBirmitrapur;22.4000\nUrbana;40.1107\nManggar;-2.8900\nJacarèzinho;-23.1608\nTuntum;-5.2578\nDubbo;-32.2569\nAndroka;-25.1167\nDwārka;22.2403\nJosé María Morelos;19.7500\nXiwanzi;40.9717\nBaikonur;45.6167\nSan Fernando;13.5661\nChangchunpu;27.2388\nColinas;-6.0258\nSama;43.3000\nSão Mateus do Maranhão;-4.0400\nOlive Branch;34.9610\nAl Mālikīyah;37.1667\nSanta Helena;-2.2308\nÍlhavo;40.6000\nSusurluk;39.9139\nWesseling;50.8167\nMonreale;38.0817\nAmbatomainty;-17.6833\nKachkanar;58.7000\nGabaldon;15.4506\nSouma;36.5183\nGorinchem;51.8306\nSeverna Park;39.0870\nWheeling;42.1308\nLandgraaf;50.9083\nNuevitas;21.5403\nBougara;36.5333\nMehidpur;23.4888\nRoy;41.1714\nPenfield;43.1602\nToumodi;6.5520\nBangar;16.9000\nIssaquah;47.5439\nInashiki;35.9565\nKurchatov;51.6667\nCaivano;40.9500\nPala Oua;9.3500\nRtishchevo;52.2667\nLos Palacios y Villafranca;37.1625\nAncud;-41.8667\nMargosatubig;7.5783\nValencia;9.2833\nYoshinogawa;34.0631\nDibaya-Lubwe;-4.1500\nItabaianinha;-11.2739\nSamal;14.7678\nKadiyam;16.9167\nVasylkiv;50.1775\nBuchireddipālem;14.5380\nMira;45.4375\nUmi;33.5675\nWesterville;40.1241\nHitachiomiya;36.5425\nTshela;-4.9667\nDubno;50.3931\nGaleana;24.8333\nAkçakoca;41.0833\nKhairtal;27.8346\nTeijlingen;52.2150\nGrants Pass;42.4333\nBitterfeld;51.6167\nMarinha Grande;39.7500\nŌmagari;39.4531\nSakuragawa;36.3273\nHaverstraw;41.2055\nTaşköprü;41.5097\nAltos;-5.0389\nLluchmayor;39.4900\nSkelmersdale;53.5500\nCampina Grande do Sul;-25.3058\nBautzen;51.1814\nVeghel;51.6167\nMission;49.1337\nHuzūrābād;18.2000\nIbusuki;31.2528\nPervomaisk;48.6297\nRājula;21.0500\nSarikishty;38.4667\nDabola;10.7500\nTuusula;60.4333\nFürstenfeldbruck;48.1778\nYako;12.9667\nLynnwood;47.8284\nCalexico;32.6849\nCajibío;2.6333\nGujō;35.7486\nAborlan;9.4386\nLos Palacios;22.5822\nOlutanga;7.3106\nSimão Dias;-10.7378\nNishiwaki;34.9903\nJamindan;11.4094\nMaasin;10.8833\nNaushahro Firoz;26.8422\nReal;14.6667\nDzhankoi;45.7086\nBarbacoas;1.6717\nAlingsås;57.9300\nSibaté;4.4908\nBraintree;42.2039\nBuug;7.7286\nMamun;32.2824\nSan Andres;13.5961\nChamperico;14.2930\nRoyal Palm Beach;26.7038\nMechelen-aan-de-Maas;50.9967\nGreat Yarmouth;52.6060\nNové Zámky;47.9856\nTōkai;36.4730\nGroton;41.3598\nKönigs Wusterhausen;52.2917\nMetlaoui;34.3333\nLand O' Lakes;28.2075\nMisawa;40.6831\nVangaindrano;-23.3500\nLa Unión;14.9667\nSan José de Las Matas;19.3300\nÁbrego;8.0000\nMariinsk;56.2000\nBayan;36.1148\nXiaguanying;35.9427\nGuariba;-21.3600\nAz̧ Z̧āhirīyah;31.4078\nAlderetes;-26.8167\nBettendorf;41.5657\nKrasnoufimsk;56.6167\nMuaná;-1.5278\nNindirí;12.0031\nDarāw;24.4000\nSan Felipe Orizatlán;21.1719\nPacifica;37.6113\nNigel;-26.4203\nLanyi;38.7048\nŻary;51.6333\nCottage Grove;44.8161\nUryupinsk;50.8000\nYuzhnoukrainsk;47.8217\nMonan;38.2621\nPhulbāni;20.4700\nBoa Esperança;-21.0900\nFalāvarjān;32.5553\nGomoh;23.8735\nDubrājpur;23.8000\nPatnongon;10.9142\nMinas;21.4894\nKardítsa;39.3667\nKhalkhāl;37.6272\nKakching;24.6085\nCaibarién;22.5158\nJarosław;50.0186\nKonakovo;56.7000\nSiyang;27.2116\nItiúba;-10.6908\nAmérico Brasiliense;-21.7361\nBacknang;48.9464\nClovis;34.4376\nVestavia Hills;33.4518\nBorbon;10.8333\nSanto Domingo;13.2350\nVentanas;-1.4500\nBarru;-4.3587\nVillenave-d’Ornon;44.7806\nVárzea Alegre;-6.7889\nHolyoke;42.2125\nYanqi;42.0586\nVillagarcía de Arosa;42.5977\nCoto Brus;8.8890\nEvans;33.5619\nCuruçá;-0.7339\nKamp-Lintfort;51.5000\nGenç;38.7500\nChacabuco;-34.6333\nNakhyaungcharīpāra;21.4167\nAntsohihy;-14.8762\nSan Jacinto de Buena Fe;-0.8986\nHanumānnagar;26.5394\nTayasan;9.9167\nVenlo;51.3667\nPort Talbot;51.5906\nKaka;37.3500\nCaltagirone;37.2375\nIbara;34.6000\nLaur;15.5797\nUsinsk;66.0000\nSharypovo;55.5333\nAtamyrat;37.8531\nAlekseyevka;50.6333\nBol’shoy Kamen’;43.1167\nGūdārah;34.8169\nMoncada;41.4867\nDom Pedrito;-30.9828\nTorre-Pacheco;37.7333\nNavgilem;40.1333\nŞarkışla;39.3500\nKatsuragi;34.4833\nSabang;5.8942\nGrimbergen;50.9333\nKrasnyy Sulin;47.8833\nJagdīspur;25.4674\nPathanāmthitta;9.2648\nLyudinovo;53.8667\nApache Junction;33.3985\nGoribidnūr;13.6111\nPitangueiras;-21.0094\nMaule;-35.5333\nZavolzhye;56.6500\nShrewsbury;42.2842\nPen;18.7500\nTāsgaon;17.0300\nGampola;7.1647\nDicle;38.3750\nBahādurganj;26.2617\nBarrancas;11.0000\nBat Khela;34.6200\nCerveteri;42.0000\nTaounate;34.5358\nCheyyār;12.6620\nOrange;-33.2833\nSu’ao;24.6000\nAnosiala;-18.7833\nMenomonee Falls;43.1487\nPhenix City;32.4585\nDengtangcun;23.6821\nPapenburg;53.0667\nBagabag;16.6044\nSavelugu;9.6167\nLuna;16.8500\nGuayacanes;18.4533\nXinpo;21.6645\nSitalkuchi;26.1697\nSan Juan Cancuc;16.9333\nPost Falls;47.7213\nIzobil’nyy;45.3667\nXinqiao;39.2694\nGoes;51.5000\nRaalte;52.3833\nLa Vergne;36.0200\nOleiros;43.3333\nVaudreuil-Dorion;45.4000\nSampués;9.1833\nRūdsar;37.1375\nVisconde do Rio Branco;-21.0103\nBoryslav;49.2881\nClifton Park;42.8587\nParkland;47.1417\nYamen;22.3017\nUster;47.3500\nYuzhnouralsk;54.4500\nSpoleto;42.7565\nSan Andres;13.3231\nDālkola;25.8758\nMasamba;-2.5531\nMount Juliet;36.1990\nSan Pédro Jocopilas;15.0953\nGüira de Melena;22.8019\nHot Springs;34.4892\nLes Abricots;18.6333\nAristóbulo del Valle;-27.1167\nAmambaí;-23.1039\nQaratog;38.5500\nFormia;41.2667\nCoondapoor;13.6313\nHajīn;34.6894\nWinter Springs;28.6889\nMixquiahuala de Juarez;20.2311\nAndkhōy;36.9500\nCatende;-8.6669\nMonrovia;34.1650\nBom Jardim;-7.7958\nLuuk;5.9676\nHaugesund;59.4464\nObala;4.1667\nOlot;42.1822\nMullaittivu;9.2833\nPrattville;32.4597\nOhangaron;40.9061\nGreven;52.0917\nArgun;43.2944\nKapiri Mposhi;-13.9772\nTunduma;-9.3000\nGaspar Hernández;19.6200\nSanchahe;36.3780\nSrīnagar;30.2200\nCarpentersville;42.1227\nIchchāpuram;19.1200\nAmarante do Maranhão;-5.5669\nSantiago;25.4333\nSighetu Marmaţiei;47.9286\nSītākund;22.6200\nPuri;-7.6833\nČeská Lípa;50.6886\nWest Fargo;46.8573\nShakhtīnsk;49.7100\nBasavana Bāgevādi;16.5728\nAkhtubinsk;48.2833\nEast Point;33.6696\nAmargosa;-13.0300\nIpueiras;-4.5419\nSpišská Nová Ves;48.9439\nKehl;48.5667\nDibulla;11.2667\nTupelo;34.2692\nRosenberg;29.5456\nPeachtree City;33.3942\nSanta Rita do Sapucaí;-22.2519\nThāna Bhawan;29.5833\nMa‘arratmişrīn;36.0000\nMahanoro;-19.9000\nLa Quinta;33.6536\nSunbury;-37.5811\nPatía;2.1667\nMabuhay;7.4176\nLampa;-33.2833\nMalavalli;12.3800\nGuaraciaba do Norte;-4.1669\nEmirdağ;39.0167\nAl Qaryatayn;34.2283\nRāwatbhāta;24.9300\nMarantao;7.9500\nJalapa;17.7000\nDajiecun;36.2965\nSan Marcelino;14.9742\nEsperantina;-3.9019\nMalmesbury;-33.4500\nSantiago Sacatepéquez;14.6530\nHatta;24.1341\nCuritibanos;-27.2828\nGeraldton;-28.7744\nAfuá;-0.1569\nSārangpur;23.5700\nTrou du Nord;19.6333\nMatina;10.0099\nMechanicsville;37.6263\nTambulig;8.0700\nDaiyue;39.5284\nYolöten;37.3000\nUchaly;54.3167\nVilla González;19.5333\nGalloway;39.4914\nNalayh;47.7725\nBaocheng;18.6431\nKalbā;25.0742\nGranadero Baigorria;-32.8500\nSun City;33.6165\nBamendjou;5.4000\nHoughton le Spring;54.8410\nKahrīzak;35.5175\nSão Gonçalo dos Campos;-12.4328\nMahē;11.7011\nMagallanes;12.8283\nBonito;-8.4700\nKalinkavichy;52.1250\nOras;12.1414\nSan Antonio;14.9486\nPorteirinha;-15.7428\nChieri;45.0139\nLahār;26.1940\nGreenfield;42.9619\nKanigiri;15.4000\nRio Pardo;-29.9900\nEsplanada;-11.7958\nBantay;17.5839\nBayur;-0.2610\nIgarapé-Açu;-1.1269\nSalinópolis;-0.6289\nMorsi;21.3180\nBouznika;33.7897\nRisalpur Cantonment;34.0049\nJelilyüzi;43.9749\nSão Fidélis;-21.6458\nWangsicun;37.9975\nAl Hāshimīyah;32.3664\nParaty;-23.2194\nKnurów;50.2167\nProgreso;21.2800\nFrolovo;49.7667\nOleśnica;51.2000\nAlapayevsk;57.8500\nEl Bordo;2.1142\nOwasso;36.2878\nBindki;26.0300\nAliança;-7.6028\nShiji;22.2198\nTosno;59.5500\nLiwonde;-15.0667\nPortage;41.5856\nFermo;43.1608\nKishmat Dhanbāri;24.6167\nRatia;29.6833\nFengguangcun;23.9062\nChanderi;24.7200\nDalnegorsk;44.5500\nMaibara;35.3167\nItarema;-2.9200\nPedro II;-4.4338\nRock Island;41.4699\nMankayan;16.8567\nRafiganj;24.8200\nGoryachiy Klyuch;44.6333\nMalgobek;43.5000\nNandaime;11.7569\nItaqui;-29.1250\nComapa;14.1114\nChrzanów;50.1333\nGajendragarh;15.7363\nSanta Rosa de Osos;6.6500\nPilibangan;29.4888\nMölndal;57.6500\nShaxi;22.3067\nLebanon;36.2040\nAgudos;-22.4739\nTamamura;36.3044\nChâtelet;50.4000\nWarendorf;51.9539\nKérou;10.8250\nHolubivske;48.6375\nYugorsk;61.3167\nNakodar;31.1300\nTudela;42.0653\nPingxiangcheng;36.9819\nMelgar;4.2039\nDīnhāta;26.1300\nPunārakh;25.4930\nBesni;37.6942\nMoerdijk;51.6500\nLierre;51.1333\nDon Benito;38.9545\nSitangkai;4.6615\nBochil;17.0167\nSeika;34.7667\nNew Albany;38.3090\nMaşyāf;35.0653\nMol;51.1833\nCheltenham;40.0781\nDaying;39.0786\nPetroşani;45.4122\nPatāmundai;20.5700\nKizilyurt;43.2167\nTibú;8.6500\nBasilisa;10.0654\nMartinez;37.9985\nLębork;54.5500\nRiviera Beach;26.7813\nChorkŭh;39.9739\nKoryazhma;61.3167\nHendon;51.5837\nCoatepec Harinas;18.9000\nMusiri;10.9333\nEwing;40.2650\nMieres;43.2508\nTunzi;35.5782\nAguelmous;33.1500\nHolstebro;56.3572\nKaman;39.3575\nMangai;-4.0499\nSan Enrique;11.0697\nAndilamena;-17.0167\nIrbit;57.6667\nFrankston;-38.1580\nCisterna di Latina;41.5908\nVarberg;57.1167\nHekou;22.5174\nAdelanto;34.5814\nPleasant Grove;40.3716\nMoalboal;9.9500\nObburdon;40.4278\nImbatug;8.3128\nVästervik;57.7500\nLeavenworth;39.3239\nLicata;37.1083\nMuskogee;35.7432\nSuhl;50.6106\nCiudad Manuel Doblado;20.7303\nProtvino;54.8833\nSilves;37.1869\nRezh;57.3667\nAnzhou;38.8663\nZīra;30.9700\nBaishi Airikecun;40.8035\nKannan;35.0889\nKāramadai;11.2428\nYasynuvata;48.1167\nOregon City;45.3418\nLanguyan;5.2667\nManazary;-19.0500\nBeslan;43.1833\nLa Ciotat;43.1769\nErding;48.2833\nPāthri;19.2500\nYongjing;23.9223\nZuojiawu;39.9514\nNanshuicun;22.0316\nJosé de Freitas;-4.7558\nQulsary;46.9833\nMandoto;-19.5667\nElixku;38.6803\nBeni Khiar;36.4667\nAriyalūr;11.1333\nTuensang;26.2716\nSagnay;13.6039\nBartlesville;36.7365\nKampene;-3.5968\nDar Chabanne;36.4700\nTimbó;-26.8228\nTuttlingen;47.9850\nTsubata;36.6692\nMagsaysay;9.0167\nCoatepeque;13.9167\nKyshtym;55.7000\nBeckum;51.7550\nLesozavodsk;45.4667\nRobertsganj;24.7000\nCanaman;13.6481\nAutazes;-3.5864\nManucan;8.5161\nPartizansk;43.1167\nAzuqueca de Henares;40.5647\nSan Luis;13.8333\nMonatélé;4.2667\nVilleta;-25.5100\nColón;8.0378\nDabutou;36.0708\nBrighton;43.1175\nWoodley;51.4530\nSanta Ana;7.6453\nLakshmeshwar;15.1300\nSaratoga Springs;40.3450\nNetishyn;50.3300\nYovon;38.3167\nŞuhut;38.5311\nSan Miguel Chicaj;15.1000\nCaimito;22.9575\nXindian;37.1341\nAourir;30.4833\nUruaçu;-14.5250\nFuchūchō;34.5650\nSantaluz;-11.2558\nAurora;16.9918\nSōma;37.7967\nSokol;59.4667\nDagua;3.6667\nMizunami;35.3618\nNumancia;11.7042\nChimboy Shahri;42.9295\nKomatsushimachō;34.0003\nPihānī;27.6199\nBeiya;36.4640\nAccrington;53.7534\nEnrile;17.5622\nAgogo;6.8000\nSayula;19.8836\nSankaridrug;11.4800\nPimenta Bueno;-11.6725\nYejituo;39.8634\nMangalia;43.8172\nGuilderland;42.7080\nCuenca;13.9167\nIkongo;-21.8833\nTorres Novas;39.4667\nQalādizay;36.1833\nKanada;33.7760\nRossano;39.5667\nPennsauken;39.9649\nPorsgrunn;59.1156\nTaxisco;14.0716\nZhaoqiao;37.9398\nTrumbull;41.2602\nLajedo;-8.6639\nMek’ī;8.1500\nYasugichō;35.4283\nJaral del Progreso;20.3667\nWangtuan;36.8624\nSanta Pola;38.1897\nLa Macarena;2.1828\nKöneürgench;42.3333\nDargaz;37.4444\nMbulu;-3.8500\nChippenham;51.4590\nKambove;-10.8764\nDanihe;39.8489\nTucker;33.8436\nEsik;43.3500\nLas Navas;12.3400\nPūrna;19.1800\nAraçuaí;-16.8500\nNamlea;-3.2500\nBrant;43.1167\nHuzūrnagar;16.9000\nCloppenburg;52.8500\nEsquel;-42.9000\nCantanhede;40.3462\nCambrils;41.0670\nCastricum;52.5500\nFranklin;42.8854\nOakton;38.8887\nZhetisay;40.7753\nKulp;38.5017\nPinerolo;44.8873\nMaur;30.0833\nBelalcázar;2.6547\nNeiba;18.4900\nCoesfeld;51.9500\nKinel;53.2222\nBulicun;24.3657\nGuápiles;10.2070\nKodaikānal;10.2300\nShirdi;19.7700\nNatick;42.2847\nUddevalla;58.3500\nSanta Cruz Verapaz;15.3736\nHaomen;37.3760\nLewiston;44.0915\nBindé;11.7500\nLakeshore;42.2399\nMontluçon;46.3408\nSongo;-15.6142\nSholinghur;13.1200\nDinas;7.6161\nTocancipá;4.9657\nSouth Valley;35.0093\nNuoro;40.3167\nLimburg;50.3833\nEkpé;6.4000\n‘Afrīn;36.5083\nDashtobod;40.1269\nBeloit;42.5230\nUpper Arlington;40.0272\nInnisfil;44.3000\nChandanais;22.2000\nBarra Bonita;-22.4947\nMingjian;23.8510\nFrancavilla Fontana;40.5333\nVoerde;51.6000\nŞile;41.1764\nGasan;13.3167\nTaastrup;55.6500\nMasasi;-10.7296\nNargund;15.7200\nÁguilas;37.4042\nSão Paulo de Olivença;-3.4500\nKharagpur;25.1245\nVillajoyosa;38.5053\nDeLand;29.0225\nMamfe;5.7667\nKaniama;-7.5696\nArroyomolinos;40.2667\nAparecida;-22.8472\nSimbahan;6.3000\nWildomar;33.6173\nEmsdetten;52.1728\nCassino;41.5000\nNueve de Julio;-35.4500\nSanta Helena de Goiás;-17.8139\nSan Juan Cotzal;15.4353\nSan Miguel Acatán;15.7000\nMa‘alot Tarshīḥā;33.0167\nSelçuk;37.9500\nCamamu;-13.9450\nMühlhausen;51.2167\nSonsón;5.7097\nSanok;49.5500\nPakribarawān;24.9540\nZaventem;50.8833\nHuehuetán;15.0000\nAketao;39.1468\nJalārpet;12.5703\nEstahbān;29.1267\nCareiro;-3.7678\nDama;30.5009\nTaguasco;22.0050\nCabanglasan;8.0772\nUto;32.6828\nSaint-Raphaël;43.4252\nYorktown;41.2727\nKotma;23.2038\nUdhampur;32.9160\nSankt Ingbert;49.3000\nIsla de Maipo;-33.7500\nPetit-Trou de Nippes;18.5333\nBanaz;38.7333\nMorohongō;35.9415\nNyaungdon;17.0461\nKerava;60.4000\nDagami;11.0611\nLa Vallée de Jacmel;18.2667\nMorecambe;54.0730\nFarafenni;13.5667\nRapu-Rapu;13.1833\nPrinceton;25.5396\nRende;39.3333\nJasło;49.7478\nNarsampet;17.9285\nSan Pablo;7.4825\nYahyalı;38.1000\nKurtalan;37.9261\nCapalonga;14.3314\nOeiras;-7.0250\nSão Miguel d’Oeste;-26.7250\nSantiago Juxtlahuaca;17.3333\nBronkhorst;52.0833\nCzechowice-Dziedzice;49.9131\nVempalle;14.3667\nAndover;42.6466\nWai;17.9500\nMahna;30.2280\nSan Bernardo del Viento;9.3500\nRifu;38.3303\nClaremont;34.1259\nMedchal;17.6297\nSiayan;8.2517\nGarhākota;23.7791\nCentral Islip;40.7836\nGeorgetown;38.2247\nPandan;11.7206\nChelmsford;42.6000\nPingshang;23.3974\nOak Creek;42.8803\nAnloga;5.7919\nCommack;40.8435\nAndújar;38.0392\nBad Vilbel;50.1781\nSan Carlos Sija;14.9833\nBarira;7.4706\nSmarhon’;54.4836\nOnteniente;38.8222\nMālpura;26.2800\nZhmerynka;49.0500\nPalapye;-22.5500\nBombardopolis;19.7000\nWokha;26.1000\nKalāleh;37.3808\nMoorpark;34.2861\nBan Mueang Na Tai;19.5932\nIngelheim;49.9747\nTlokweng;-24.6667\nAţ Ţurrah;32.6368\nMerrillville;41.4728\nHellendoorn;52.3667\nEstero;26.4276\nCumberland;41.9703\nLunsar;8.6833\nAugusta;37.2500\nTomelloso;39.1578\nZacatepec;18.6833\nAmpasina-Maningory;-17.2167\nGutalac;7.9833\nBautista;15.8103\nAl Jabāyish;30.9549\nTambolaka;-9.4333\nPaiçandu;-23.4578\nMeyzieu;45.7667\nClaveria;9.5742\nAvdiivka;48.1333\nTarikere;13.7104\nSomma Vesuviana;40.8725\nVirú;-8.4143\nPartūr;19.5911\nRoseville;45.0155\nVohipeno;-17.1667\nCanicattì;37.3667\nDunedin;28.0329\nDietzenbach;50.0167\nSan Antonio;13.9000\nCento;44.7333\nSibuco;7.2928\nMokokchūng;26.3200\nRāmsar;36.9031\nFarmers Branch;32.9272\nSaparua;-3.5749\nMatanog;7.4667\nCalumet City;41.6134\nAdrano;37.6667\nSarıgöl;38.2403\nItaitinga;-3.9689\nMarion;40.5973\nCativá;9.3600\nConegliano;45.8868\nJagna;9.6500\nKalakkādu;8.5138\nDumbéa;-22.1500\nZvishavane;-20.3333\nSegrate;45.4900\nShiggaon;14.9910\nVelasco Ibarra;-1.0439\nGuayaramerín;-10.8000\nPylaía;40.6000\nCasiguran;12.8731\nPorta Westfalica;52.2167\nItapicuru;-11.3169\nFraiburgo;-27.0258\nSan Andrés Itzapa;14.6167\nSalinas;-2.2167\nMiyajima;33.1500\nAddison;41.9313\nLa Libertad;13.4833\nChortoq;41.0689\nSinsheim;49.2500\nChipinge;-20.2000\nHole Narsipur;12.7863\nZhentang;21.8662\nBoyarka;70.7670\nPraya;-8.7223\nGeiro;-6.1428\nSan Lorenzo de Guayubín;19.6200\nFarafangana;-22.8167\nKamenka;53.1833\nWinsen;53.3667\nBelluno;46.1403\nWinchester;51.0632\nAmbohibary;-18.9000\nKakhovka;46.8000\nChernyakhovsk;54.6347\nPrince Albert;53.2000\nChītāpur;17.1201\nSetouchi;34.6667\nToretsk;48.3917\nVyazniki;56.2500\nLeyland;53.6920\nKumo;10.0431\nSix-Fours-les-Plages;43.1009\nDayr Ḩāfir;36.1569\nSambir;49.5167\nMengdong;23.1499\nTallkalakh;34.6683\nMiranda de Ebro;42.6833\nẔefat;32.9658\nSion;46.2333\nPrestea;5.4333\nSavanūr;14.9731\nKarak;33.1167\nSanta Cruz;-6.2289\nRichmond;39.8318\nMedina;8.9167\nEstreito;-6.5608\nAtami;35.0960\nKita Chauhāttar;25.6770\nCarrollwood;28.0577\nGuacarí;3.7667\nKundian;32.4522\nUmarga;17.8400\nPak Chong;14.6796\nVárzea da Palma;-17.5978\nOlney;39.1465\nGuimbal;10.6667\nUsuki;33.1333\nLeganes;10.7833\nBerg en Dal;51.8167\nSūrandai;8.9773\nVavatenina;-17.4667\nIsumi;35.2539\nUravakonda;14.9500\nTeruel;40.3456\nAl Ḩişn;32.4583\nSvetlograd;45.3500\nSantiago de Tolú;9.5333\nSanta Ana;18.4589\nGuane;22.2006\nMatanzas;18.2428\nBurriana;39.8894\nBaraidih;25.9798\nSochaczew;52.2333\nOuro Preto d’Oeste;-10.7481\nPambujan;12.5667\nCamiri;-20.1000\nZaidpur;26.8300\nOrangevale;38.6881\nMacomia;-12.2377\nImzouren;35.1500\nBalasan;11.4728\nEvergem;51.0167\nTřebíč;49.2150\nShīyāli;11.2390\nSanta Fe;11.1500\nBoyarka;50.3292\nCieszyn;49.7500\nLixingcun;23.0852\nMendez-Nuñez;14.1286\nSlagelse;55.4049\nPola;13.1439\nGürpınar;38.3269\nBedēsa;6.8830\nCâmara de Lobos;32.6953\nKilimli;41.4833\nGaribaldi;-29.2558\nKaroi;-16.8100\nDundee;-28.1725\nHaguenau;48.8200\nYpané;-25.4500\nLökbatan;40.3272\nRandallstown;39.3723\nAl ‘Aqīq;20.2685\nUsilampatti;9.9700\nBariri;-22.0744\nGuskhara;23.4928\nCha-am;12.7992\nRiverhead;40.9408\nSchoten;51.2500\nPalmares;10.0466\nGahanna;40.0251\nMeridian;32.3846\nAlatyr;54.8500\nNova Cruz;-6.4778\nSaint-Chamond;45.4775\nMörfelden-Walldorf;50.0000\nGladstone;-23.8427\nMinami-Bōsō;35.0432\nMeppen;52.6936\nCoevorden;52.6667\nDimitrovgrad;42.0500\nBuhriz;33.7000\nJuban;12.8478\nKarumattampatti;11.1093\nGigante;2.3867\nHamidiye;40.0997\nTilingzhai;40.2353\nYangambi;0.7675\nJosé Bonifácio;-21.0528\nLeer;53.2308\nYerköy;39.6381\nSimiganj;38.6525\nDouzhuang;39.4323\nToritama;-8.0067\nLa Porte;29.6689\nŌfunato;39.0680\nŞaḩneh;34.4814\nLa Troncal;-2.4000\nZorgo;12.2500\nMorong;14.6800\nNewton;8.3333\nGuamá Abajo;19.9758\nQuimbaya;4.6333\nAngra do Heroísmo;38.6558\nIkot Abasi;4.5704\nNanzhiqiu;37.7492\nSungaiselam;-2.3839\nInver Grove Heights;44.8247\nMahabo;-20.3833\nSavonlinna;61.8681\nFreehold;40.2233\nAkouda;35.8714\nHilliard;40.0353\nCutral-Có;-38.9333\nSun Prairie;43.1825\nLanciano;42.2333\nYayladağı;35.9025\nYeonil;36.0000\nKraśnik;50.9167\nTambé;-7.4100\nBathurst;-33.4200\nVichuga;57.2000\nLage;51.9889\nShenjiabang;30.5783\nCharqueadas;-29.9550\nSaint-Benoît;-21.0339\nKahoku;36.7198\nCegléd;47.1743\nCartagena del Chairá;1.3500\nRio Brilhante;-21.8019\nAlém Paraíba;-21.8878\nBom Jesus do Itabapoana;-21.1339\nKamata;33.5632\nAïne Draham;36.7833\nRadebeul;51.1000\nTamuín;22.0000\nAuxerre;47.7986\nCopperas Cove;31.1192\nTahuna;3.6119\nTorrington;41.8349\nArmenia;13.7500\nPilar;-9.5972\nRiachão do Jacuípe;-11.8100\nPilão Arcado;-10.0018\nUnnan;35.2833\nBuxin;23.9523\nPentecoste;-3.7928\nMedia Luna;20.1444\nCasimiro de Abreu;-22.4808\nÜrgüp;38.6314\nEl Mirage;33.5905\nMillerovo;48.9167\nOuro Branco;-20.5208\nDatteln;51.6539\nLa Palma;22.7472\nOsimo;43.4833\nCieza;38.2392\nItaberaí;-16.0200\nCoventry;41.6934\nWildwood;38.5800\nSan Juan;26.1903\nSulop;6.5986\nAkçadağ;38.3450\nGalapagar;40.5764\nWinsford;53.1940\nYarumal;7.0306\nOakville;38.4479\nQadsayyā;33.5333\nAllacapan;18.2270\nSaarlouis;49.3167\nTangancícuaro de Arista;19.8889\nLangford Station;48.4506\nŌzu;32.8790\nBradford West Gwillimbury;44.1333\nSan Juan Capistrano;33.5008\nJieshang;25.6989\nYellandu;17.6000\nIeper;50.8508\nGandara;12.0130\nGuaramirim;-26.4728\nTrinidad;10.0795\nYecla;38.6167\nNyamata;-2.2050\nSan Luis;32.4911\nYarīm;14.2972\nBou Salem;36.6167\nLuga;58.7333\nGiddalūr;15.3784\nTall Salḩab;35.2609\nBaba I;6.0622\nBrunswick;41.2465\nCrema;45.3667\nMananara Avaratra;-16.1667\nCansanção;-10.6708\nMahasolo;-19.1167\nVoznesensk;47.5725\nFonseca;10.8333\nSalisbury;35.6658\nLingig;8.0381\nMassapê;-3.5228\nVille Bonheur;18.8167\nGorizia;45.9333\nTecuci;45.8467\nAbra de Ilog;13.4448\nMuddebihāl;16.3300\nSafidon;29.4200\nSan Luis;8.4964\nWermelskirchen;51.1500\nMirnyy;62.5500\nTooele;40.5393\nIzkī;22.9339\nCuraçá;-8.9919\nVedāranniyam;10.3774\nKōṯah-ye ‘As̲h̲rō;34.4492\nVenaria Reale;45.1167\nYefremov;53.1500\nRāwatsār;29.2800\nUmarkot;25.3614\nVadigenhalli;13.2900\nMunai;7.9758\nCrailsheim;49.1347\nRūdarpur;26.4293\nNevers;46.9933\nAfogados da Ingazeira;-7.7508\nBodocó;-7.7778\nTřinec;49.6778\nAhrensburg;53.6747\nOwings Mills;39.4115\nIgarapé;-20.0700\nNova Olinda do Norte;-3.8878\nMâcon;46.3063\nTamra;32.8536\nLingsugūr;16.1700\nWedel;53.5833\nTienen;50.8000\nMatou;39.5503\nGreer;34.9330\nJiaoxi;24.8167\nPaxtaobod;40.9283\nNgororero;-1.8650\nIkalamavony;-21.1500\nSan Vicente de Chucurí;6.8833\nHīrākud;21.5250\nCampbell River;50.0244\nLake Stevens;48.0024\nAdamantina;-21.6847\nWavre;50.7167\nAl Ḩamdānīyah;36.2697\nAzazga;36.7453\nTamura;37.4333\nSan Luis de Sincé;9.2500\nNorthbrook;42.1292\nIyo;33.7500\nBagamoyo;-6.4444\nRingsaker;61.0242\nPuerto López;4.0833\nKempen;51.3658\nPayao;7.5857\nPiskent;40.8992\nFereydūn Kenār;36.6864\nCasilda;-33.0500\nFormigine;44.6072\nTalanga;14.4047\nĀllagadda;15.1322\nSeelze;52.3961\nFiravahana;-18.6333\nGlastonbury;41.6921\nMlimba;-8.7786\nFotadrevo;-24.0500\nCaucagua;10.2822\nKulittalai;10.9357\nBeidou;23.8747\nMānāmadurai;9.6956\nKalaa Srira;35.8236\nBlagoveshchensk;55.0350\nAloguinsan;10.2229\nTarkwa;5.3000\nCampoalegre;2.6867\nḐulay‘ Rashīd;25.5067\nShaqrā’;25.2483\nHatibanda;24.2105\nDabaga;17.2667\nMenen;50.7956\nKorkino;54.9000\nMeppel;52.7000\nNgaoundal;6.5000\nBalingen;48.2731\nCamoapa;12.3842\nDhāmnod;22.2093\nBethlehem;42.5856\nDueñas;11.0667\nBaja;46.1833\nArmação dos Búzios;-22.7469\nMilaor;13.5956\nLaoac East;16.0333\nSeiyo;33.3628\nEşme;38.4000\nSteinfurt;52.1475\nKhodābandeh;36.1194\nArsin;40.9500\nOdorheiu Secuiesc;46.3139\nAnse-à-Veau;18.5167\nSanta Cruz;-34.6372\nMisungwi;-2.8500\nGundlupēt;11.8000\nAguaí;-22.0603\nSan Javier;37.8037\nBalarāmpur;26.2432\nAznakayevo;54.8500\nVictoria;-38.2333\nBarugo;11.3167\nDeggendorf;48.8333\nBarra do Choça;-14.8808\nGoch;51.6839\nNăvodari;44.3211\nFeijó;-8.1639\nNorth Ridgeville;41.3852\nSint-Pieters-Leeuw;50.7833\nAngamāli;10.2000\nVemalwāda;18.4667\nPaithan;19.4800\nTôrres;-29.3350\nKalarūch;34.5731\nMadhubani;26.5147\nSanta Cruz das Palmeiras;-21.8269\nDiaowo;39.4812\nBugasong;11.0447\nGuying;38.0887\nMosonmagyaróvár;47.8737\nCapelinha;-17.6908\nMogpog;13.4833\nDel Rio;29.3708\nDabouziya;33.3064\nSanta Maria;14.4750\nNarsīpatnam;17.6650\nIława;53.5964\nAksay;51.1678\nHoulong;24.6167\nCastelo;-20.6039\nGoshen;41.5743\nAbulug;18.4441\nYangquan;37.0749\nJalajala;14.3557\nApodi;-5.6639\nEspiye;40.9500\nBonifacio;8.0527\nBallesteros;18.4108\nSan Dimas;34.1082\nDupnitsa;42.2650\nSōsa;35.7075\nYhú;-25.0600\nShingū;33.7153\nSpringville;40.1638\nAwa;34.1014\nBenton;34.5776\nPhra Phutthabat;14.7212\nZhitiqara;52.1908\nHinesville;31.8248\nBanda;24.0449\nBiharamulo;-2.6333\nSarpol-e Z̄ahāb;34.4611\nDzierżoniów;50.7281\nZelenokumsk;44.4167\nBuenos Aires;2.9167\nAbashiri;44.0167\nSanta Maria;15.9808\nShangzhen;33.7116\nSão Luís do Quitunde;-9.3178\nLa Blanca;14.5791\nMerseburg;51.3544\nZweibrücken;49.2500\nKasba;25.8564\nSocorro;31.6383\nIJsselstein;52.0167\nMadakalavāripalli;14.7475\nOfunato;39.0819\nInca;39.7167\nSpanaway;47.0979\nRichmond;37.7307\nQaşr al Qarabūllī;32.7500\nRandolph;42.1778\nBarsinghausen;52.3000\nTábor;49.4144\nBugojno;44.0572\nHeunghae;36.1167\nBetafo;-19.8400\nPleasant Hill;37.9539\nFalls;40.1686\nAnkola;14.6605\nGuarambaré;-25.4900\nCachoeira;-12.6178\nBayog;7.8474\nEsposende;41.5333\nPlayas;-2.6300\nZhangzhengqiao;38.4042\nParnarama;-5.6819\nOcuilan de Arteaga;19.0000\nSabaneta;19.4833\nCañete;-37.7994\nTiruvūr;17.1000\nHemer;51.3833\nUniversity Place;47.2147\nStow;41.1765\nSkhira;34.3006\nKópavogur;64.1108\nCameron Highlands;4.5000\nSongcaozhen;37.7562\nCentenario;-38.8000\nHumenné;48.9358\nCícero Dantas;-10.6000\nQuilevo;-7.6167\nNew Panamao;5.9667\nBāft;29.2331\nMnasra;34.7667\nÁno Liósia;38.0833\nKaneohe;21.4062\nGotō;32.7000\nBanes;20.9697\nOława;50.9333\nGerāsh;27.6672\nIturama;-19.7278\nXincheng;38.2679\nInabe;35.1156\nDegāna;26.8951\nCuruzú Cuatiá;-29.7833\nHisuā;24.8336\nVassouras;-22.4039\nNola;40.9333\nFruit Cove;30.0972\nMonroe;35.0063\nYouwangjie;24.8695\nMinas de Matahambre;22.5822\nSimunul;4.8980\nSirīpur;25.9970\nShinjō;38.7667\nRisod;19.9700\nRâmnicu Sărat;45.3800\nExmouth;50.6200\nPingtang;22.7542\nJaguaribe;-5.8908\nBelhi;26.5769\nShamsābād;17.2603\nZamānia;25.4194\nDouglasville;33.7384\nCasale Monferrato;45.1342\nAlmora;29.5971\nFairborn;39.8010\nBiwong;3.1333\nKorschenbroich;51.1833\nTalayan;6.9844\nSan Manuel;17.0167\nTandubas;5.1340\nLommel;51.2333\nKallidaikurichi;8.6859\nSanta Ana Nextlalpan;19.7167\nButte;45.9020\nVibo Valentia;38.6753\nSibutu;4.8500\nDakota Ridge;39.6192\nMachachi;-0.5100\nTōon;33.7833\nToda Bhīm;26.9167\nOildale;35.4293\nKohtla-Järve;59.3978\nQingyang;36.1985\nCariari;10.4349\nMason;39.3571\nMissão Velha;-7.2500\nOswego;41.6834\nBorne;25.5431\nSão Sebastião;-9.9339\nPinukpuk;17.5731\nGadsden;34.0086\nPlainfield;39.6954\nPenalva;-3.2939\nGuindulman;9.7620\nÚbeda;38.0117\nGulkevichi;45.3594\nBusinga;3.3397\nBogorodsk;56.1167\nZnojmo;48.8556\nPangururan;2.6075\nLautaro;-38.5167\nSan Quintin;15.9844\nSan José Poaquil;14.8167\nCambrai;50.1767\nSão Desidério;-12.3628\nPuqiancun;20.0263\nManitowoc;44.0991\nLufkin;31.3217\nÇınarcık;40.6422\nCaldono;2.8000\nGeneral Nakar;14.7631\nTepeji del Río de Ocampo;19.9039\nKomárno;47.7633\nCedar City;37.6834\nDatang;26.3909\nShāhīn Dezh;36.6792\nVitrolles;43.4600\nNāz̧erābād;31.5775\nDeer Park;29.6898\nGyapekurom;7.5833\nLexington;42.4456\nQuinchía;5.3379\nRafaḩ;31.2808\nKokrajhar;26.4000\nMcMinnville;45.2110\nDao;11.3800\nPalapag;12.5470\nGoianira;-16.4958\nTobelo;1.7319\nCravinhos;-21.3403\nTabango;11.3067\nŞereflikoçhisar;38.9444\nTynaarlo;53.0833\nInitao;8.5000\nPeyziwat;39.4905\nCantilan;9.3356\nDerry;42.8888\nNowy Targ;49.4667\nViernheim;49.5417\nMarignane;43.4160\nTermoli;42.0000\nGeldern;51.5197\nByādgi;14.6733\nGrodzisk Mazowiecki;52.1167\nBiberach;48.1000\nShisō;35.0000\nSan Martín Sacatepéquez;14.8246\nCishan;36.5780\nRío Verde Arriba;19.3200\nPulgaon;20.7260\nIrvine;55.6201\nValuyki;50.2167\nWoodridge;41.7370\nBassin Bleu;19.7833\nRomans-sur-Isère;45.0464\nPaşcani;47.2494\nBinche;50.4000\nFungurume;-10.6167\nUonuma;37.2301\nDimona;31.0667\nSan Agustín;1.9000\nMascalucia;37.5667\nAnnigeri;15.4251\nBoğazlıyan;39.1942\nCâmpina;45.1300\nSan Remigio;10.8331\nSanta Ana;11.0680\nChand Chaur;25.7276\nVillena;38.6350\nPontneddfechan;51.7554\nPrairieville;30.3151\nNew City;41.1542\nTobias Fornier;10.5178\nPiombino;42.9348\nZhuqi;23.5065\nLochem;52.1615\nVictoria Falls;-17.9333\nMahasoabe;-21.5833\nAtiquizaya;13.9667\nMatozinhos;-19.5578\nStuhr;53.0167\nCastelfranco Veneto;45.6667\nLianga;8.6330\nSan Antonio de los Baños;22.8889\nRéo;12.3167\nZhaitangcun;24.5133\nCookeville;36.1482\nLupi Viejo;13.7908\nSpruce Grove;53.5450\nSan Juan Nepomuceno;9.9500\nYinchengpu;39.8189\nShikārpūr;28.2814\nDartmouth;41.6138\nCatmon;10.6667\nMajagual;8.5000\nWestlake;41.4524\nAnkazomiriotra;-19.6500\nSneek;53.0325\nTortosa;40.8125\nDīvāndarreh;35.9139\nEirunepé;-6.6597\nBrumadinho;-20.1428\nMaromandia;-14.2167\nSibagat;8.8219\nMizuho;35.7720\nMerritt Island;28.3139\nShamsābād;27.0200\nBacarra;18.2519\nBaltiysk;54.6500\nVadavalli;11.0258\nOulad Zemam;32.3500\nNaguilian;17.0167\nKondapalle;16.6167\nElmina;5.0833\nLewiston;46.3934\nPôrto de Moz;-1.7478\nFurmanov;57.2500\nDescalvado;-21.9039\nOjiya;37.3144\nTuriaçu;-1.6628\nSındırgı;39.2400\nAlmendralejo;38.6833\nDatu Paglas;6.7669\nKadingilan;7.6003\nNizhneudinsk;54.9333\nMidlothian;32.4669\nLebowakgomo;-24.2000\nXinyuan;22.5149\nBatan;11.5853\nBen Ahmed;33.0655\nDhekiajuli;26.7037\nCapoocan;11.2944\nMoose Jaw;50.3933\nKen Caryl;39.5770\nLandskrona;55.8706\nDebagrām;23.6833\nBozdoğan;37.6728\nBāmaur;26.3390\nCustódia;-8.0875\nTiruchendūr;8.4946\nUelzen;52.9647\nCamiri;-20.0386\nCooper City;26.0463\nBan Pak Phun;8.5391\nEl Ksar;34.3900\nTekes;43.2181\nWoodstock;34.1026\nLa Trinidad;12.9678\nCôtes de Fer;18.1833\nGolungo Alto;-9.1333\nBell Ville;-32.6333\nBhawānīpur Rājdhām;25.6501\nDidouche Mourad;36.4484\nMartinez;33.5209\nSouth Riding;38.9120\nGeraardsbergen;50.7667\nValparaiso;41.4783\nBatobato;6.8361\nChuri;23.6549\nVillafranca di Verona;45.3500\nReghin;46.7758\nXiadian;39.9435\nLéo;11.1000\nMazarrón;37.5983\nSertânia;-8.0706\nOlkusz;50.2813\nDej;47.0872\nPoço Redondo;-9.8058\nBad Nauheim;50.3667\nMasiu;7.8167\n‘Ajab Shīr;37.4831\nParkland;26.3219\nVilla Riva;19.1667\nMella;20.3694\nWalla Walla;46.0671\nJishi;35.8511\nPenticton;49.4911\nJaguarari;-10.2600\nLeawood;38.9075\nFatehpur Sīkri;27.0911\nBelen;36.4889\nEncrucijada;22.6169\nChilecito;-29.1667\nMidsalip;8.0328\nGraham;47.0322\nRahachow;53.1000\nSapa Sapa;5.0899\nRubengera;-2.0519\nSukhoy Log;56.9167\nWarwick;52.2800\nComé;6.4000\nPuerto Rico;1.9142\nVyatskiye Polyany;56.2239\nRonda;36.7372\nCarmel;41.3899\nTucumã;-6.7519\nBanate;11.0500\nGetafe;10.1500\nJamikunta;18.2864\nPatrātu;23.6700\nSan Antero;9.3833\nSchwedt (Oder);53.0500\nVechta;52.7306\nRexburg;43.8226\nŌno;35.9797\nMacuro;10.6500\nMenlo Park;37.4685\nSicuani;-14.2720\nLianmuqin Kancun;42.8833\nKorsakov;46.6333\nIbaté;-21.9550\nBarra do Bugres;-15.0728\nSão Domingos do Maranhão;-5.5758\nCorinto;3.1739\nMildura;-34.1889\nZhanjia;34.7564\nAsse;50.9000\nSakaiminato;35.5333\nChascomús;-35.5750\nDarsi;15.7667\nManatí;21.3144\nAleshtar;33.8633\nBatouri;4.4333\nRheinfelden (Baden);47.5611\nFomento;22.1053\nSão Bento;-6.4858\nAyvacık;39.6011\nShangcaiyuan;24.6817\nCottonwood Heights;40.6137\nJhanjhārpur;26.2647\nMakhdumpur;25.0720\nManlius;43.0490\nIriba;15.1167\nŌsawa;33.2000\nAn’gang;35.9900\nCastro;-42.4667\nColumbio;6.7000\nIperó;-23.3503\nShaliuhe;39.8728\nCaçapava do Sul;-30.5119\nKearney;40.7011\nMercedes;-29.2000\nKavundappādi;11.4248\nPort Moody;49.2831\nPikesville;39.3893\nOrodara;10.9800\nNiangoloko;10.2833\nTaishi;34.8333\nSlobodskoy;58.7208\nRodas;22.3428\nPôrto União;-26.2378\nSan Vicente;10.5281\nAr Raḩmānīyah;31.1062\nSahuarita;31.9323\nCrown Point;41.4143\nCalape;9.8833\nĀrumuganeri;8.5717\nNānjikkottai;10.7453\nTimberwood Park;29.6995\nKos;36.8500\nPruszcz Gdański;54.2667\nBôca do Acre;-8.7519\nCity Bell;-34.8500\nMadikeri;12.4209\nBoxtel;51.5833\nHlukhiv;51.6765\nDate;42.4719\nAl Mindak;20.1833\nShalingzicun;40.6807\nChimbarongo;-34.7089\nVác;47.7752\nXinbu;24.8478\nNautan Dube;26.7118\nCastro-Urdiales;43.3844\nWarminster;40.2043\nNokia;61.4767\nGölbaşı;37.7839\nShōbara;34.8544\nAranda de Duero;41.6833\nUdaipur;23.5389\nBaturité;-4.3289\nArteijo;43.3044\nSan Sebastián de Mariquita;5.2500\nAbbiategrasso;45.4000\nLoughton;51.6494\nEpe;52.3500\nRadnor;40.0287\nKolín;50.0281\nLa Virginia;4.9167\nHayama;35.2725\nVintar;18.2306\nPerşembe;41.0656\nUmaria;23.5247\nDupax Del Norte;16.3075\nBrejo;-3.6839\nSouthport;-27.9667\nConceição de Jacuípe;-12.3269\nPandami;5.5333\nTayshet;55.9500\nTavda;58.0500\nMilot;19.6047\nHuangzhuang;39.9905\nBethel Park;40.3238\nAmparafaravola;-17.5833\nPantelimon;44.4500\nGīmbī;9.1667\nSalina;43.1023\nGlossop;53.4430\nPolice;53.5333\nSherpur;25.6539\nKusapín;9.1800\nKareli;22.9153\nKārkala;13.2000\nHāngal;14.7646\nTynda;55.1667\nKaarina;60.4000\nMohnyin;24.7833\nSão Luís Gonzaga;-28.4078\nLos Gatos;37.2304\nObukhiv;50.1109\nBrooklyn Center;45.0681\nWatari;38.0442\nCanavieiras;-15.6750\nAnserma;5.2381\nOldenzaal;52.3167\nAlmeirim;-1.5228\nAlamnagar;25.5610\nMuconda;-10.6000\nWisbech;52.6640\nRencun;22.6585\nTemascalapa;19.8000\nPalmira;22.2444\nWaikabubak;-9.6358\nPivijay;10.4667\nShatura;55.5667\nPuerto Cumarebo;11.4861\nCamacan;-15.4189\nZgorzelec;51.1500\nSan Roque;36.2097\nDjenné;13.9000\nBragado;-35.1167\nCoxim;-18.5069\nEpsom;51.3360\nPetersburg;37.2043\nRoss;40.5256\nDipaculao;15.9833\nAndırın;37.5764\nCastelfranco Emilia;44.5967\nGoldsboro;35.3778\nFucheng;35.3678\nDumalinao;7.8167\nMinamikyūshū;31.3778\nKhvāf;34.5764\nDe Aar;-30.6500\nSan Lazzaro di Savena;44.4716\nPříbram;49.6883\nAravan;40.5150\nCorrentina;-13.3428\nLucera;41.5000\nLawrence;40.2954\nForchheim;49.7197\nAsakuchi;34.5247\nRedmond;44.2612\nKakira;0.5036\nÁgua Preta;-8.7000\nShimotoba;34.8838\nUpper Merion;40.0902\nLower Makefield;40.2309\nVohitromby;-23.3000\nKamaishi;39.2758\nFuquay-Varina;35.5953\nLaojiezi;26.8600\nPalmeira das Missões;-27.8989\nLampertheim;49.6000\nAlabaster;33.2198\nKovūr;14.4833\nLumbang;14.2970\nRio das Pedras;-22.8428\nBungoōno;32.9833\nMassafra;40.5833\nSānchor;24.7517\nKnokke-Heist;51.3414\nUmarkot;19.6653\nMashiki;32.8006\nAmbodimanga II;-17.2667\nSan Luis;22.2828\nWakabadai;45.4156\nPuebloviejo;10.9972\nMushie;-3.0167\nKadınhanı;38.2397\nPurāini;25.1426\nForbe Oroya;-11.5220\nDidy;-18.1167\nFranklin;42.0862\nRusera;25.7600\nGillette;44.2752\nSarıkaya;39.4936\nBiritiba-Mirim;-23.5728\nYamanashi;35.6934\nMaragogi;-9.0122\nKennesaw;34.0260\nDolores;14.0157\nLas Mercedes;8.5104\nLiptovský Mikuláš;49.0842\nItzehoe;53.9250\nCarapeguá;-25.7690\nOsvaldo Cruz;-21.7967\nBardejov;49.2933\nGumdag;39.2061\nGyzylgaya;40.6219\nZumbo;-15.6167\nHinda;-4.6133\nColombia;20.9906\nFallbrook;33.3693\nJülich;50.9222\nMaḩallat Damanah;31.0754\nPueblo West;38.3465\nLeamington;42.0667\nAyorou;14.7350\nTeykovo;56.8547\nCharthāwal;29.5500\nEsperança;-7.0333\nChernushka;56.5167\nSayram;42.3000\nPullman;46.7336\nMassango;-11.3167\nLa Uruca;9.9575\nÖrnsköldsvik;63.2908\nBembe;-7.1000\nDara;15.3500\nDellys;36.9133\nBernburg;51.8000\nBadoc;17.9267\nBaraguá;21.6819\nDehlorān;32.6942\nBuloqboshi;40.6222\nGandu;-13.7439\nKetti;11.4000\nAalsmeer;52.2667\nSō;31.6536\nŌiso;35.3069\nŢafas;32.7356\nWernigerode;51.8350\nCiudad del Plata;-34.7667\nTrëkhgornyy;54.8000\nLa Mesa;4.6303\nTawsalun;21.4060\nSt. Charles;41.9193\nErraguntla;14.6333\nAraban;37.4247\nCurralinho;-1.8139\nKifrī;34.6833\nUnchagao;16.6988\nOisterwijk;51.5833\nArbaoua;34.9000\nManises;39.4833\nŞāfītā;34.8167\nSan Felipe;21.4833\nPuerto Escondido;8.9500\nKuji;40.1905\nSpring Valley;32.7317\nSatānā;20.5797\nAchim;53.0653\nQuţūr;30.9735\nCampos Novos;-27.4019\nMatalom;10.2833\nBaraawe;1.1133\nAmerican Fork;40.3783\nSão João da Barra;-21.6400\nPresidente Figueiredo;-2.0172\nBuco Zau;-4.7950\nMonteiro;-7.8889\nSão Miguel Arcanjo;-23.8778\nYlöjärvi;61.5500\nPayshamba Shahri;40.0078\nÉpinal;48.1744\nYufu;33.1833\nTuraiyūr;11.1686\nBocas de Satinga;2.3469\nMānwat;19.3000\nKaizu;35.2206\nAnsongo;15.6650\nIngenio;27.9214\nChancay;-11.5653\nElk Grove Village;42.0064\nTārānagar;28.6689\nMandaguari;-23.5478\nRushden;52.2880\nMotosu;35.4830\nPombal;-6.7700\nAltenburg;50.9850\nBilzen;50.8667\nSilvia;2.6167\nBaiyan;26.3584\nNurlat;54.4333\nClarence;43.0196\nEast Lake;28.1206\nIstra;55.9167\nDiplahan;7.6911\nRedan;33.7394\nDeurne;51.4667\nCamaiore;43.9333\nEspigão D’Oeste;-11.5247\nMayantoc;15.6203\nConcón;-32.9167\nFavara;37.3186\nOğuzeli;36.9650\nDobryanka;58.4667\nShiroishi;38.0025\nGoleta;34.4361\nEl Difícil;9.8500\nAkivīdu;16.5823\nYorii;36.1183\nPlaisir;48.8183\nPtolemaḯda;40.5167\nSanta Cruz del Norte;23.1556\nRedcliff;-19.0333\nSadābād;27.4500\nMateur;37.0400\nCururupu;-1.8278\nEast Kelowna;49.8625\nAvanos;38.7150\nParatinga;-12.6908\nNaumburg;51.1500\nBalindong;7.9167\nSão José do Belmonte;-7.8608\nOstrogozhsk;50.8667\nDes Moines;47.3914\nInzá;2.5500\nJaguariaíva;-24.2508\nNagdha Simla;24.6143\nŞarköy;40.6039\nSanha;25.4020\nMinamisatsuma;31.4169\nKävlinge;55.7939\nPeñaranda;15.3531\nPlettenberg Bay;-34.0500\nShimanto;33.0000\nCranberry;40.7104\nLugo;44.4167\nVught;51.6500\nWobulenzi;0.7200\nUtraula;27.3200\nFürstenwalde;52.3667\nMioveni;44.9569\nKulebaki;55.4167\nNāspur;18.8300\nCzeladź;50.3333\nRéthymno;35.3689\nSamdhin;27.1370\nSherwood;34.8507\nKalyandrug;14.5500\nNossa Senhora da Glória;-10.2178\nZarqān;29.7742\nAlubijid;8.5714\nHampden;40.2602\nSlantsy;59.1167\nYankou;27.5950\nFalmouth;41.5913\nKolachel;8.1767\nGoiatuba;-18.0128\nEspinho;41.0100\nLevice;48.2164\nMilazzo;38.2170\nChiché;15.0106\nAmés;42.9000\nGeesthacht;53.4375\nBarreirinha;-2.8025\nNouna;12.7333\nJimalalud;9.9797\nBeixinzhuang;38.7914\nShiyeli;44.1789\nLa Calera;-31.3439\nDelbrück;51.7667\nAndover;45.2571\nSão José da Tapera;-9.5578\nKāngayam;11.0054\nSan Pedro de Ribas;41.2592\nStaryy Beyneu;45.1834\nLandecy;46.1834\nPlottier;-38.9500\nMallig;17.2086\nRokhaty;38.6000\nVirei;-15.7167\nTotana;37.7711\nKaysville;41.0290\nMaputsoe;-28.8950\nLa Concepción;11.9369\nDraa Ben Khedda;36.7349\nBijaynagar;25.9300\nZangang;39.0524\nTawaramoto;34.5566\nMadīnat al Ḩabbānīyah;33.3667\nIgbaras;10.7167\nZentsujichó;34.2167\nGramado;-29.3789\nWaddinxveen;52.0500\nCachoeira Paulista;-22.6650\nHerrenberg;48.5967\nSalamína;37.9667\nGeorgsmarienhütte;52.2000\nStatesboro;32.4375\nZaojiao;34.4727\nPekin;40.5678\nBalimbing;7.9000\nDumfries;55.0700\nSan Pedro de Urabá;8.2833\nBedworth;52.4750\nPoint Pedro;9.8167\nFoça;38.6667\nTubao;16.3500\nĀreka;7.0710\nDhahran;26.2667\nCarangola;-20.7328\nGuararapes;-21.2608\nKōnan;33.5667\nKukshi;22.2068\nKristianstad;56.0337\nFerreñafe;-6.7183\nNorth Olmsted;41.4149\nKiranomena;-18.2833\nKalisizo;-0.5350\nMenglie;22.5833\nNagarote;12.2650\nDracut;42.6832\nRādhanpur;23.8300\nNarsinghgarh;23.7000\nNacogdoches;31.6134\nBuguey;18.2882\nCanton;34.2467\nSão Raimundo Nonato;-9.0150\nWheat Ridge;39.7728\nChâtellerault;46.8178\nBerasia;23.6146\nNieuw-Vennep;52.2644\nSébaco;12.8553\nOudenaarde;50.8500\nCatubig;12.4000\nCuranilahue;-37.4764\nHarker Heights;31.0572\nNamerikawa;36.7644\nRochester;43.2990\nMiguel Alves;-4.1658\nRome;43.2260\nMangūr;17.9373\nBambadinca;12.0333\nGödöllő;47.6000\nRibeira Grande;37.8167\nIlhabela;-23.7778\nSalug;8.1075\nKottaikuppam;11.9613\nMessaména;3.7333\nSan Carlos Alzatate;14.5000\nShimizuchō;35.0990\nBramsche;52.4000\nJaguaruana;-4.8339\nNagato;34.3722\nCapulhuac;19.2000\nJoão Câmara;-5.5378\nKangasala;61.4639\nTamparan;7.8790\nLower Macungie;40.5303\nTummapāla;17.7166\nOer-Erkenschwick;51.6422\nCaramoran;13.9833\nCheb;50.0794\nAntsohimbondrona;-13.0833\nBauko;16.9917\nRosmalen;51.7167\nWindsor;51.4791\nWevelgem;50.8081\nPrimorsko-Akhtarsk;46.0500\nXangda;32.2056\nPoconé;-16.2569\nKingman;35.2170\nPedana;16.2667\nGrottaglie;40.5333\nBizen;34.7453\nWrześnia;52.3333\nMassillon;40.7838\nJāsim;32.9667\nAguilares;-27.4333\nBandeirantes;-23.1100\nNovovoronezh;51.3167\nDongxianpo;39.5610\nItamarandiba;-17.8569\nBuyan;23.9961\nSaint-Médard-en-Jalles;44.8964\nCruces;22.3419\nWaiyuanshan;24.7443\nŌdachō-ōda;35.1833\nShima;39.5544\nDouar Oulad Hssine;33.0680\nWallsend;54.9910\nMalangas;7.6317\nPervari;37.9331\nTermas de Río Hondo;-27.4833\nPalmeira;-25.4289\nQuintero;-32.7833\nYaguarón;-25.5621\nColíder;-10.8128\nNālchiti;22.6350\nYaese;26.1582\nRadolfzell am Bodensee;47.7333\nJiming;40.1884\nMutki;38.4092\nGuaratuba;-25.8828\nSerdobsk;52.4667\nYuzhne;46.6300\nMasatepe;11.9147\nDonggou;35.5621\nQuitilipi;-26.8667\nZapala;-38.9000\nDar Ould Zidouh;32.3167\nShentang;22.2915\nTongxiao;24.4833\nSavage;44.7545\nSami;21.2933\nAlba;44.7000\nTirebolu;41.0056\nRenkum;51.9833\nPartinico;38.0500\nTongkou;38.7952\nSan Lucas Tolimán;14.6333\nRemedios;7.0275\nUglich;57.5333\nNorak;38.3833\nClaveria;18.6061\nStadskanaal;52.9833\nCabaiguán;22.0839\nVohilava;-21.0667\nGurupá;-1.4050\nOristano;39.9058\nBekoratsaka;-16.1000\nPolillo;14.7167\nLumding;25.7500\nBahharet Oulad Ayyad;34.7702\nChūō;35.5996\nCourcelles;50.4578\nItampolo;-24.6833\nKochugaon;26.5518\nPandua;23.0800\nMoche;-8.1706\nAsilah;35.4667\nAndriba;-17.5833\nMataas Na Kahoy;13.9667\nNilka;43.7826\nSigma;11.4214\nSergio Osmeña Sr;8.3003\nDeptford;39.8157\nDesert Hot Springs;33.9550\nNanyuki;0.0167\nSakhnīn;32.8667\nMohyliv-Podilskyi;48.4500\nCentereach;40.8681\nPichucalco;17.5167\nPaipa;5.8333\nWindsor;40.4690\nNamegata;35.9905\nSanta Rita;10.5367\nWarwick;41.2597\nShahedian;37.6546\nO'Fallon;38.5974\nMarialva;-23.4850\nCalubian;11.4467\nCañuelas;-35.0333\nKomagane;35.7288\nSanta Catarina Mita;14.4500\nFangyuan;23.9250\nMajidpur;23.5796\nI‘zāz;36.5866\nYenice;39.9308\nLālgola;24.4200\nSitges;41.2339\nSão Gabriel;-19.0169\nJyväskylän Maalaiskunta;62.2889\nTuzantán;15.1333\nMarrero;29.8871\nWest Odessa;31.8389\nDreux;48.7372\nBayaguana;18.7500\nBangor;44.8323\nGalapa;10.9167\nPiuí;-20.4650\nBagrāmī;34.4911\nGuachavés;1.2219\nBaradères;18.4825\nTemascaltepec de González;19.0433\nMerida;10.9098\nHoyerswerda;51.4333\nTuljāpur;18.0000\nTuricato;19.0500\nCacolo;-10.1333\nGongguan;24.5053\nMontebelluna;45.7753\nIgrejinha;-29.5739\nSasaguri;33.6239\nEl Oro de Hidalgo;19.8008\nRuy Barbosa;-12.2839\nKatagami;39.8832\nLouvain-la-Neuve;50.6667\nDomingos Martins;-20.3628\nSão José do Egito;-7.4733\nNíjar;36.9667\nTouba;8.2833\nGevelsberg;51.3167\nUbajara;-3.8544\nVal-d’Or;48.1000\nAmatenango de la Frontera;15.5333\nSão Gotardo;-19.3108\nIvisan;11.5217\nBuzovna;40.5161\nMasi-Manimba;-4.7790\nOrtaköy;38.7372\nBoghni;36.5437\nPantabangan;15.8086\nNewburgh;41.5531\n’Aïn Abid;36.2325\nFarrokh Shahr;32.2714\nAvola;36.9167\nGallipoli;40.4139\nIvaiporã;-24.2478\nSan Sebastián;14.5667\nOwen Sound;44.5667\nAl ‘Aydābī;17.2370\nVelikiy Ustyug;60.7667\nNeedham;42.2814\nShikārpur;14.2700\nGanderkesee;53.0358\nWeil am Rhein;47.5947\nClearfield;41.1030\nAl ’Attawia;31.8347\nGubbio;43.3500\nKavār;29.2050\nMława;53.1167\nSan Giuliano Terme;43.7625\nChum Phae;16.5431\nRahīmpur;25.4894\nBocana de Paiwas;12.7878\nValkenswaard;51.3500\nSpringfield;38.7810\nGeneral José de San Martín;-26.5375\nRāhatgarh;23.7800\nWillingboro;40.0280\nMonção;-3.4919\nYıldızeli;39.8642\nJalpatagua;14.1364\nUithoorn;52.2333\nKasimov;54.9333\nJamālpur;25.4112\nFengrenxu;24.1757\nSri Mādhopur;27.4667\nFair Oaks;38.6504\nKuroishi;40.6426\nParacuru;-3.4100\nSitionuevo;10.7833\nHolladay;40.6600\nHaan;51.1667\nAguada de Pasajeros;22.3847\nKotovsk;52.5833\nJesús María;-30.9833\nDongmaying;39.1221\nMirnyy;62.7667\nSiquirres;10.0901\nEl Palmar;14.6500\nBalyqshy;47.0667\nMaebara;35.1140\nSarno;40.8167\nSyracuse;41.0859\nDania Beach;26.0593\nJerez;14.1000\nGadarpur;29.0437\nFlorence;38.9899\nŽepče;44.4333\nNavalcarnero;40.2847\nPontefract;53.6910\nIrituia;-1.7689\nWeyhe;52.9936\nMagsingal;17.6850\nLemery;11.2333\nNueva Imperial;-38.7433\nTekkali;18.6057\nPresident Roxas;11.4297\nChmistâr;33.9667\nTecozautla;20.5333\nExu;-7.5133\nEnnery;19.4833\nNorth Huntingdon;40.3294\nCastelvetrano;37.6833\nCueto;20.6481\nTanmen;19.2429\nMorro Agudo;-20.7314\nDeori Khās;23.3902\nMussoorie;30.4500\nChorbog;38.6667\nAyabe;35.3000\nOuro Fino;-22.2828\nTitlāgarh;20.3000\nMahemdāvād;22.8300\nKreuztal;50.9667\nFrederico Westphalen;-27.3589\nInkhil;33.0000\nBābura;25.6838\nWaterloo;50.7167\nSan Andrés Xecul;14.9000\nMae Sot;16.7131\nCarballo;43.2167\nYawatahama-shi;33.4667\nMundelein;42.2693\nTredyffrin;40.0663\nNardò;40.1797\nKosonsoy;41.2500\nNaugatuck;41.4890\nPasadena;39.1552\nWhitstable;51.3610\nSouth Kingstown;41.4458\nÓzd;48.2192\nCicero;43.1662\nHusainābād;24.5285\nSanta Cruz;10.1819\nLos Altos;37.3684\nZima;53.9167\nDimataling;7.5297\nSosnogorsk;63.6000\nWanghong Yidui;38.1993\nHuangxicun;24.4684\nQo‘rg‘ontepa;40.7336\nChanguinola;9.4300\nDasol;15.9896\nIbaraki;36.2869\nŁowicz;52.1000\nPuerto Wilches;7.3500\nVerbania;45.9228\nOkagaki;33.8536\nCarlsbad;32.4010\nMasqaţ;23.5889\nChinnālapatti;10.2875\nBünyan;38.8486\nAiken;33.5303\nMarks;51.7167\nRheinberg;51.5467\nKostopil;50.8833\nDuluth;34.0053\nLaramie;41.3099\nBagac;14.5951\nWestville;-29.8310\nJam;27.8236\nSanta Fé do Sul;-20.2108\nTongeren;50.7794\nNeira;5.1664\nHalden;59.1264\nCibolo;29.5634\nSavé;8.0333\nQārā;29.8833\nHitoyoshi;32.2167\nRiga;26.6553\nMograne;34.4167\nNetivot;31.4167\nTiquipaya;-17.3333\nStratford;43.3708\nYingyangcun;22.0974\nKaminokawa;36.4393\nMonjas;14.5010\nÇay;38.5926\nAraçoiaba da Serra;-23.5053\nBarrinha;-21.1936\nPeriyanāyakkanpālaiyam;11.1544\nTrebinje;42.7089\nFăgăraş;45.8447\nPosse;-14.0928\nPulupandan;10.5167\nLa Verne;34.1207\nChantal;18.2000\nWenxian Chengguanzhen;32.9421\nMārgrām;24.1516\nDevanhalli;13.2300\nLloydminster;53.2783\nLaguna Hills;33.5918\nRío Bravo;14.4011\nGuamo;4.0833\nShepparton;-36.3833\nBolobo;-2.1667\nAtwater;37.3529\nBuey Arriba;20.1736\nNewark;39.6776\nAl Ḩusaynīyah;30.8617\nRadcliffe;53.5615\nMamaroneck;40.9443\nPointe-Claire;45.4500\nPodili;15.6040\nKudymkar;59.0167\nYahşihan;39.8503\nBurgdorf;52.4500\nVinkovci;45.2911\nEyvān;33.8272\nShrīgonda;18.6160\nBuenavista;13.7394\nNgudu;-2.9667\nCândido Mota;-22.7464\nCuauhtémoc;19.3281\nAraguatins;-5.6508\nOstuni;40.7333\nCaracal;44.1125\nKandalaksha;67.1569\nManduria;40.4000\nYaita;36.8067\nParambu;-6.2108\nDuanshan;25.7943\nVienne;45.5242\nIporá;-16.4419\nSiraway;7.5853\nYby Yaú;-22.9631\nMānsa;23.4300\nBittou;11.2575\nPalaiya Āyakkudi;10.4560\nRosignano Marittimo;43.4000\nGuanhães;-18.7750\nKarera;25.4581\nMaryville;35.7468\nCulleredo;43.2883\nGata;7.8500\nPindaré-Mirim;-3.6078\nTaozhuangcun;30.9694\nVitória do Mearim;-3.4619\nPerico;22.7753\nNorwood;42.1861\nCoria del Río;37.2833\nSan Antonio Ilotenango;15.0544\nMaināguri;26.5640\nBurgess Hill;50.9535\nBielsk Podlaski;52.7667\nShawnee;35.3531\nCambita Garabitos;18.4500\nBrasília de Minas;-16.2078\nParacelis;17.1811\nKhānah Sūr;36.4731\nSan Juan Ixcoy;15.6000\nLobos;-35.1833\nYingshouyingzi;40.5451\nLake Magdalene;28.0875\nAmbatomiady;-19.6833\nMarigliano;40.9333\nMaubeuge;50.2775\nAlamogordo;32.8837\nMalakanagiri;18.3500\nSakaraha;-22.9167\nDanghara;38.0983\nEshtehārd;35.7239\nLagos;37.1028\nSaratoga;37.2684\nSan Narciso;15.0167\nLushnjë;40.9333\nBogoroditsk;53.7667\nVarto;39.1731\nFlores da Cunha;-29.0289\nWerl;51.5500\nOrillia;44.6000\nMinaçu;-13.5328\nŁuków;51.9272\nChitral;35.8511\nSibanicú;21.2389\nSabana Grande de Boyá;18.9500\nTewksbury;42.6120\nTokmak;47.2514\nNorth Royalton;41.3138\nPuthupalli;9.5594\nSovetskiy;61.3614\nKalgoorlie;-30.7489\nSki;59.7419\nEspinosa;-14.9081\nTouros;-5.1989\nHadagalli;15.0200\nNantan;35.1000\nLakeside;30.1356\nBenguema;8.3333\nLavras da Mangabeira;-6.7528\nKūttānallūr;10.7069\nTairan Camp;6.6500\nSakhipur;24.3167\nPortão;-29.7019\nBembèrèkè;10.2250\nVohitrandriana;-20.7500\nNeuruppin;52.9331\nLivingston;40.7855\nEgra;21.9000\nItabela;-16.5750\nIllescas;40.1167\nMuritiba;-12.6258\nOak Ridge;35.9639\nTāramangalam;11.7000\nBest;51.5167\nMānāvadar;21.5000\nTijucas;-27.2408\nSchönebeck;52.0167\nGuanta;10.2383\nNicholasville;37.8906\nMarar;25.5392\nƏmircan;40.4264\nLeusden;52.1333\nChagne;10.9500\nNew Bern;35.0955\nSan Miguel;10.7833\nLaGrange;33.0274\nItapemirim;-21.0108\nBochnia;49.9833\nAndranovory;-23.1333\nCanguaretama;-6.3800\nMatões;-5.5189\nAmbanja;-13.6786\nOmaezaki;34.6379\nChengam;12.3112\nSăcele;45.6200\nParsuram;23.2135\nKamisato;36.2516\nArcos de la Frontera;36.7500\nInami;34.7488\nDyurtyuli;55.4833\nNova Russas;-4.7000\nXingang;23.5600\nMocímboa da Praia;-11.3500\nNazaré da Mata;-7.7419\nBalatan;13.3167\nBallwin;38.5950\nSanta Vitória do Palmar;-33.5189\nLa Paz;8.2801\nDolo Odo;4.1667\nCleburne;32.3568\nNartkala;43.5500\nWarrnambool;-38.3833\nJoão Alfredo;-7.8558\nSan Isidro;11.4167\nNiles;42.0278\nBel Air North;39.5543\nRostov;57.1833\nEinbeck;51.8167\nSalou;41.0796\nWestfield;40.6516\nTanguá;-22.7300\nTaiobeiras;-15.8078\nMossendjo;-2.9500\nOrcutt;34.8691\nŻywiec;49.6892\nKanzakimachi-kanzaki;33.3167\nCornelius;35.4724\nTunduru;-11.0667\nGanassi;7.8269\nFabriano;43.3333\nLohmar;50.8167\nPichanal;-23.3167\nBela Cruz;-3.0508\nBannūr;12.3329\nAlma;48.5500\nAglipay;16.4889\nGamu;17.0500\nCabrobó;-8.5119\nDevarshola;11.5437\nTsuruno;40.8087\nColinas do Tocantins;-8.0589\nRāghopur;26.1785\nManāwar;22.2300\nUran;18.8900\nLeh;34.1642\nSeaTac;47.4444\nBeverley;53.8450\nVicência;-7.6569\nVoorhees;39.8450\nSan Gregorio de Nigua;18.3833\nGarner;35.6936\nTepetlaoxtoc;19.5731\nPísek;49.3089\nUnterschleißheim;48.2833\nSarayköy;37.9265\nEnnepetal;51.2833\nRío Blanco;12.9325\nCapela;-10.5028\nMyszków;50.5833\nGurnee;42.3708\nAnilao;10.9785\nWest Warwick;41.6986\nLaranjeiras do Sul;-25.4078\nQahderījān;32.5767\nJonuta;18.0333\nMinas Novas;-17.2189\nOpelika;32.6612\nNovoyavorovskoye;49.9311\nAlegre;-20.7639\nRasrā;25.8500\nKeles;41.4033\nEstrêla;-29.5019\nHajdúböszörmény;47.6667\nHopkinsville;36.8381\nJarinu;-23.1014\nTekeli;44.8300\nGuaíra;-24.0800\nColgong;25.2633\nSan Ramón;12.9236\nSouthlake;32.9545\nDuanzhuang;36.5796\nSynelnykove;48.3178\nNovo Cruzeiro;-17.4678\nXinzhaidian;37.8136\nTreviglio;45.5214\nCatolé do Rocha;-6.3439\nAmagá;6.0500\nOrangeville;43.9167\nNanwucun;37.3885\nToribío;2.9581\nEmmen;47.0833\nOlopa;14.6833\nPrinceton;40.3562\nBowling Green;41.3776\nFort Erie;42.9167\nSāgwāra;23.6681\nMadruga;22.9164\nPápa;47.3237\nAnse-à-Foleur;19.9000\nJuquitiba;-23.9319\nCiudad Melchor de Mencos;17.0667\nAndernach;50.4397\nRio Branco do Sul;-25.1900\nMilford Mill;39.3444\nFārsān;32.2553\nTirwa;26.9633\nGobernador Virasora;-28.0500\nYanai;33.9667\nYunoshima;35.8059\nTo‘raqo‘rg‘on;41.0000\nTaunusstein;50.1333\nPhú Mỹ;10.5906\nNorth Andover;42.6713\nBielawa;50.7000\nBanamba;13.5500\nAungban;20.6667\nThung Song;8.1669\nTorrijos;13.3167\nOsterholz-Scharmbeck;53.2167\nVilla Donato Guerra;19.3083\nCanyon Lake;29.8761\nHolbæk;55.7156\nKuttuparamba;11.8300\nDécines-Charpieu;45.7694\nSuzak;40.8981\nVictoria;-32.6167\nAnjad;22.0417\nThuận Tiến;10.0894\nSan Andrés del Rabanedo;42.6167\nNorth Chicago;42.3172\nWuyuan;41.0896\nMont-de-Marsan;43.8900\nRapallo;44.3500\nChimākurti;15.5819\nMiddle River;39.3436\nFounougo;11.4808\nSokuluk;42.8600\nDrexel Heights;32.1453\nMotomiya;37.5132\nUzynaghash;43.2297\nAlcázar de San Juan;39.4056\nSardrūd;38.0286\nNorth Tonawanda;43.0457\nPuerto de la Cruz;28.4167\nPokhrām;25.9358\nRehli;23.6300\nKirov;54.0833\nDraveil;48.6852\nBlagodarnyy;45.1000\nMetu;8.3000\nGorna Oryahovitsa;43.1333\nShāhpura;25.6300\nKailahun;8.2772\nG’ijduvon Shahri;40.1000\nRio Preto da Eva;-2.6989\nAsprópyrgos;38.0667\nNanyō;38.0551\nHellín;38.5167\nCalafell;41.2004\nFerry Pass;30.5205\nOb;54.9917\nGaggenau;48.8039\nAr Ruḩaybah;33.7436\nAskøy;60.4667\nQuillabamba;-12.8681\nBad Hersfeld;50.8683\nXinpo;19.7738\nJima Abajo;19.1300\nLalla Mimouna;34.8500\nEl Fanar;33.8667\nMukumbura;-16.2000\nNewington;41.6870\nPantao-Ragat;8.0500\nFeteşti;44.4150\nAfonso Cláudio;-20.0739\nOno;35.9797\nMotema;8.6167\nWalsrode;52.8667\nTchindjendje;-12.8167\nSanta Maria;17.3719\nBeşiri;37.9210\nSlavgorod;52.9833\nMaguing;7.9000\nKórinthos;37.9386\nTskhinvali;42.2257\nItaporanga d’Ajuda;-10.9978\nBandar-e Lengeh;26.5581\nAsh Shinān;27.1782\nAarschot;50.9842\nYpacaraí;-25.3833\nKalpatta;11.6088\nUst’-Dzheguta;44.0872\nFriedberg;48.3500\nSali;14.4383\nBālā Kōh;36.5753\nHorki;54.2667\nBalungao;15.9000\nHirakawachō;40.5841\nMahugaon;22.5748\nTogitsu;32.8289\nCandijay;9.8180\nIguape;-24.7081\nDalin;23.5989\nHuanta;-12.9397\nTélimélé;10.9050\nGranger;41.7374\nAdilcevaz;38.8058\nMorristown;36.2043\nWeatherford;32.7536\nTsuru;35.5515\nPop;40.8736\nKoratgi;15.6081\nDumalag;11.3039\nCarlos Barbosa;-29.2978\nKafr Nubl;35.6139\nMyōkō;37.0252\nKālappatti;11.0794\nMadhepur;26.1775\nAbū Şuwayr;30.5633\nVilla Comaltitlán;15.1667\nPittsford;43.0733\nRotterdam;42.8133\nAl Madad;13.7167\nCandelaria;15.6333\nGraneros;-34.0647\nBretten;49.0364\nBalete;11.5553\nShetang;34.5568\nDaheba;28.0259\nIguig;17.7517\nNorthport;33.2586\nGaldácano;43.2306\nChimichagua;9.2500\nSalay;8.8667\nGaraimāri;24.0217\nAnse à Pitre;18.0500\nSouk et Tnine Jorf el Mellah;34.4833\nKondopoga;62.2000\nTalwāra;31.9376\nJāmtāra;23.9500\nLawrenceville;33.9523\nMannārgudi;11.2761\nGalesburg;40.9506\nPānakkudi;8.3492\nXunjiansi;23.9620\nMāgadi;12.9700\nLas Nieves;8.7351\nWallkill;41.4854\nKibiti;-7.7296\nGukeng;23.6500\nCihuatlán;19.2500\nDauin;9.2000\nKuah;6.3167\nValdepeñas;38.7667\nGūdalūr;11.1455\nKombissiri;12.0667\nVinces;-1.5500\nDayr Abū Sa‘īd;32.5025\nJinka;5.7833\nNavāpur;21.1700\nCalintaan;12.5756\nTemse;51.1167\nFriedberg;50.3333\nQuezaltepeque;14.6333\nSalāya;22.3200\nAugustów;53.8436\nLewe;19.6333\nZionsville;39.9897\nMatsubushi;35.9258\nGorodets;56.6500\nSocorro;6.5333\nBudaörs;47.4607\nHighland Park;42.1823\nTrutnov;50.5606\nPadada;6.6333\nSue;33.5872\nPetite Rivière de Nippes;18.4833\nPinhão;-25.6958\nBergen;52.6667\nPiagapo;8.0000\nMozhaysk;55.5167\nShangpa;26.9052\n‘Aynkāwah;36.2292\nQarataū;43.1667\nCandelária;-29.6689\nYoshida;34.7709\nMarogong;7.6667\nZaragoza;14.6498\nRendsburg;54.3000\nNeuburg;48.7333\nTameslouht;31.5000\nKottūru;14.8262\nNorthfleet;51.4400\nHafnarfjörður;64.0200\nDahana;38.0583\nAgde;43.3108\nLaSalle;42.2167\nAustintown;41.0932\nMakato;11.7120\nGreenville;33.3850\nPlympton;50.3860\nBirūr;13.5972\nTizi Gheniff;36.5891\nCrevillente;38.2486\nIkoto;4.0783\nEl Kseur;36.6844\nSalem;42.7902\nLes Palmes;18.3333\nGuotang;23.8414\nTaşova;40.7500\nParaipaba;-3.4389\nBra;44.7000\nPlanadas;3.1964\nMilford;42.1565\nMathba;22.3000\nLiberty;39.2394\nMiramar;-38.2667\nTabio;4.9158\nBrodnica;53.2597\nXiaba;27.8825\nMucari;-9.4667\nMīnūdasht;37.2289\nAgno;16.1161\nSottaiyampālaiyam;11.4053\nConguaco;14.0470\nDu Yar;15.2617\nL’Arbaa Naït Irathen;36.6367\nMotala;58.5333\nKrishnarājpet;12.6662\nSainte-Julie;45.5833\nShibancun;22.1539\nBarbosa;5.9330\nPlacer;9.6570\nHakmana;6.0796\nLandhaura;29.8200\nBontoc;10.3500\nShubrākhīt;31.0275\nRagan Sur;17.3167\nYong’ancun;23.1788\nNattam;10.2249\nPervomaiskyi;49.3869\nBugarama;-2.6972\nSan Roque;12.5330\nCondega;13.3617\nMundi;22.0700\nSelargius;39.2537\nSão Luís de Montes Belos;-16.5250\nSoledade;-28.8178\nHeesch;51.7333\nSheohar;26.5200\nUychi;41.0294\nAmbalavao;-21.8333\nNelson;53.8346\nTacuba;13.9000\nMeschede;51.3500\nWaltrop;51.6167\nIrará;-12.0500\nVilla Regina;-39.1000\nCulemborg;51.9500\nSaint-Étienne-du-Rouvray;49.3786\nHengchun;22.0000\nGongyefu;41.8378\nChikuzen;33.4570\nMalème Hodar;14.0883\nWerne an der Lippe;51.6667\nSaalfeld;50.6500\nCampo Alegre de Lourdes;-9.5158\nCanosa di Puglia;41.2167\nJalawlā’;34.2719\nNan’ao;38.5162\nAmbinanitelo;-15.3500\nIbrāhīmpatnam;16.6056\nDegeh Bur;8.2167\nDevarkonda;16.6919\nSāho;25.9718\nAndranomanelatra;-19.7833\nCasma;-9.4742\nĀrda;32.3087\nSanford;35.4875\nSanta Rita;14.8667\nBuenavista;10.0833\nMerzig;49.4500\nBourgoin-Jallieu;45.5861\nMonterey;36.5919\nPitanga;-24.7569\nUar Esgudud;1.2667\nBaxdo;5.7889\nSabanilla;17.3167\nCarpentras;44.0558\nBourèm Guindou;16.9004\nTsitondroina;-21.3000\nAsipovichy;53.2933\nEvaz;27.7600\nVernon;41.8364\nEast Lake-Orient Park;27.9970\nPitou;23.8775\nKelkheim (Taunus);50.1378\nSan Lucas Sacatepéquez;14.6095\nLeduc;53.2594\nBalabagan;7.5333\nDala;-11.0342\nSint-Michielsgestel;51.6433\nSouthgate;42.2047\nMurlīganj;25.9000\nHengshuicun;22.3674\nArlon;49.6833\nEastern Goleta Valley;34.4448\nPattikonda;15.4000\nSantana do Acaraú;-3.4608\nIzegem;50.9172\nEsmeralda;21.8561\nTönisvorst;51.3208\nCarinhanha;-14.3050\nVyshhorod;50.5833\nGiannitsá;40.7833\nAllūru;15.1317\nPignon;19.3333\nParipiranga;-10.6878\nOosterend;53.0036\nPuente-Genil;37.3833\nFresno;5.1556\nSchwelm;51.2667\nSan Jacinto;12.5683\nSantiago de Baney;3.7000\nZamboanguita;9.1000\nBenito Soliven;16.9833\nDzyarzhynsk;53.6833\nGeneral Alvear;-34.9667\nCasa Branca;-21.7739\nSan Rafael;20.1889\nAncón;8.9700\nMeißen;51.1667\nMandalī;33.7333\nInagawa;34.8951\nZhangguzhuang;38.0584\nChamblee;33.8842\nRaytown;38.9944\nVilla Dolores;-31.9333\nLeonding;48.2792\nPārdi;20.5200\nXalatlaco;19.1811\nAral;46.7833\nTequisquiapan;20.5206\nVilla Gesell;-37.2556\nMocajuba;-2.5839\nNepānagar;21.4558\nCarney;39.4050\nSan Luis;15.7167\nAlgonquin;42.1629\nChangzhi;22.6833\nKınık;39.0939\nSavanette;18.6833\nVaihingen an der Enz;48.9328\nN’Gaous;35.5550\nCapim;-1.6750\nLākheri;25.6700\nHeywood;53.5900\nComiso;36.9500\nOlocuilta;13.5667\nKabalo;-6.0500\nHosdurga;13.7963\nLandsberg;48.0478\nPurificación;3.8667\nDedovsk;55.8500\nRota;36.6167\nMbanga;4.5092\nNauhata;25.9971\nRietberg;51.8000\nMahón;39.8894\nAntsampandrano;-19.9167\nPasuquin;18.3342\nNanga Eboko;4.6708\nBella Vista;36.4667\nVadakku Valliyūr;8.3833\nSwarzędz;52.4083\nPilón;19.9053\nGloucester;42.6260\nHattersheim;50.0722\nCrofton;39.0144\nJāmai;22.1964\nPetrich;41.3953\nRhennouch;33.9300\nMisilmeri;38.0333\nIgarapava;-20.0383\nParabiago;45.5583\nFlandes;4.2833\nManjo;4.8500\nArtëmovskiy;57.3564\nAlushta;44.6672\nRancharia;-22.2289\nBrecht;51.3500\nZaltbommel;51.8000\nSantiago do Cacém;38.0167\nSpinea;45.4931\nBan Bang Khu Wat;13.9576\nAtascadero;35.4827\nAlquízar;22.8067\nCalimete;22.5339\nBonou;6.9000\nShuangtian;22.8640\nCarmo do Paranaíba;-19.0008\nMangdongshan;24.1169\nLabasa;-16.4311\nRedondela;42.2833\nCentral;30.5593\nChiknāyakanhalli;13.4161\nMashan;37.0017\nBayramiç;39.8128\nAtbasar;51.8000\nXinmin;25.4831\nVattalkundu;10.1630\nPiraju;-23.1936\nKitaakita;40.2260\nVallentuna;59.5333\nAsha;55.0000\nBosanska Krupa;44.8833\nOzumba;19.0392\nManticao;8.4042\nParaparaumu;-40.9167\nLicab;15.5400\nBrunssum;50.9500\nSouth Ubian;5.1833\nToksun;42.7918\nSumilao;8.3281\nMatinhos;-25.8178\nSan Agustín Chahal;15.7500\nNorth Cowichan;48.8236\nGotse Delchev;41.5667\nNowy Dwór Mazowiecki;52.4333\nNew Smyrna Beach;29.0249\nKumalarang;7.7478\nWinter Park;28.5989\nArniquet;18.1500\nOrchard Park;42.7516\nEagle;43.7223\nTournefeuille;43.5853\nBanning;33.9460\nBāglung;28.2667\nAlbany;-35.0228\nDembī Dolo;8.5333\nGüstrow;53.7939\nĀtmakūr;14.6167\nKottakota;13.6573\nLavezares;12.5333\nJuchitepec;19.0997\nUttamapālaiyam;9.8000\nYangshuling;40.9942\nAntsahalava;-19.5833\nOelde;51.8333\nMūdbidri;12.9101\nRiesa;51.3081\nLādwa;29.9958\nEast Windsor;40.2606\nPoás;10.1060\nSevenoaks;51.2781\nKönigsbrunn;48.2689\nSonāmukhi;23.3000\nKhunti;23.0140\nGarfield Heights;41.4199\nWinnenden;48.8764\nBad Zwischenahn;53.1836\nMahendragarh;28.2800\nSanto Domingo;17.6414\nFiguil;9.7667\nUdaipur;27.7289\nGarchitorena;13.8833\nJohnston;41.8274\nChichaoua;31.5333\nBudaka;1.0167\nNakrekal;17.1667\nJa‘ār;13.2231\nDanville;40.1426\nTakanezawa;36.6310\nBurton;42.9974\nMcCandless;40.5836\nRiihimäki;60.7333\nNazaré;-13.0350\nPueblo Nuevo Viñas;14.2333\nHobart;41.5140\nBuenos Aires;9.1985\nFleming Island;30.0988\nFountain;38.6886\nTexarkana;33.4360\nSchwandorf;49.3283\nMunsan;37.8529\nOslob;9.5500\nMonfalcone;45.8000\nFritissa;33.6167\nNieuwkoop;52.1833\nOrlová;49.8452\nTōmi;36.3594\nDesenzano del Garda;45.4689\nMaddagiri;13.6600\nHisor;38.5264\nXiaobazi;27.3401\nBrāhmana Periya Agrahāram;11.3690\nTimizart;36.8000\nEast Fishkill;41.5567\nRösrath;50.9000\nLikino-Dulevo;55.7167\nReddish;53.4383\nAns;50.6625\nPoggibonsi;43.4667\nBulung’ur Shahri;39.7600\nPhuntsholing;26.8500\nKavajë;41.1842\nVinaroz;40.4686\nWindsor;41.8710\nFridley;45.0841\nGyula;46.6500\nKiskunfélegyháza;46.7052\nMatthews;35.1195\nKamalāpuram;15.3044\nCapim Grosso;-11.3808\nLakewood Ranch;27.4185\nLāmerd;27.3423\nParsa;26.0021\nAth;50.6167\nSexmoan;14.9333\nKostomuksha;64.5833\nJacksonville;34.8807\nRa’s al ‘Ayn;36.8503\nSchererville;41.4861\nSopó;4.9167\nNorthampton;42.3266\nŞūrān;35.2897\nBenhao;18.6122\nShibushi;31.5000\nErie;40.0404\nWellesley;42.3043\nFitchburg;42.9859\nPālpā;27.8667\nAgui;34.9329\nQuivicán;22.8247\nPrainha;-1.8000\nMatouying;39.2922\nHazleton;40.9505\nNovaya Usman’;51.6439\nKailāras;26.3050\nParagould;36.0555\nDapa;9.7578\nBoxmeer;51.6500\nHinunangan;10.4000\nGragnano;40.6957\nRāikot;30.6500\nDivnogorsk;55.9594\nMondragone;41.1000\nGlenville;42.8869\nCarmona;37.4667\nOrange;44.1383\nCapitán Bermúdez;-32.8167\nNortheim;51.7067\nNamaacha;-25.9667\nKhmilnyk;49.5569\nPlaine du Nord;19.6833\nDuzhuang;40.0121\nPoona-Piagapo;8.0833\nBrétigny-sur-Orge;48.6114\nFloresta;-8.6008\nSeguin;29.5891\nBlankenfelde;52.3500\nAnadia;40.4333\nBühl;48.6953\nMoñitos;9.2503\nBethany;45.5614\nCarmagnola;44.8500\nTruskavets;49.2806\nSan Marcos;11.9081\nJimenez;8.3333\nKaminoyama;38.1496\nLugus;5.7000\nCañada de Gómez;-32.8167\nShiqiao;34.1418\nFundão;40.1333\nViacha;-16.6533\nShotley Bridge;54.8700\nIkaruga;34.6088\nFandriana;-20.2333\nTabuleiro do Norte;-5.2481\nAmarpur;25.0397\nPrado;-17.3408\nDeodrug;16.4167\nKirkwood;38.5788\nSherobod;37.6667\nWinterswijk;51.9667\nGarupá;-27.4833\nBethlehem;31.7031\nAipe;3.2167\nPatjirwa;26.8084\nWest Windsor;40.2897\nCottica;3.8542\nCiying;25.3595\nSanta Quitéria do Maranhão;-3.5158\nFalkenberg;56.9053\nNalbāri;26.4450\nShaker Heights;41.4744\nReinbek;53.5089\nPontedera;43.6625\nAleysk;52.5000\nItuberá;-13.7319\nGoriar;25.5513\nOktyabr’sk;49.4556\nKakiri;0.4200\nLa Concordia;-0.0067\nSant’Anastasia;40.8667\nPerry Hall;39.4068\nEvesham;52.0920\nPrimero de Enero;21.9453\nGonglang;24.8391\nSan Cristóbal;22.7169\nBraço do Norte;-28.2750\nReda;54.6167\nGlória do Goitá;-7.9992\nKodumur;15.6833\nCyangugu;-2.4833\nBogdanovich;56.7803\nCatandica;-18.0564\nMadīnat Zāyid;23.6522\nSpringe;52.2167\nLaplace;30.0731\nMagna;40.7634\nKōshū;35.7043\nBan Phai;16.0730\nGates;43.1514\nOld Harbour;17.9333\nLaranjal Paulista;-23.0118\nPawāyan;28.0667\nChambly;45.4311\nBaixo Guandu;-19.5189\nTabuelan;10.8500\nRio Pardo de Minas;-15.6100\nNarsimlāpet;17.5100\nVestal;42.0492\nIxtapa;16.8167\nNāhan;30.5500\nNirasaki;35.7089\nChili;43.0845\nPonot;8.4428\nBella Vista;-28.4667\nBenavente;38.9667\nMirandópolis;-21.1336\nDalfsen;52.5000\nBabatngon;11.4207\nItaperuçu;-25.2200\nBagre;-1.9000\nKūdligi;14.9050\nSomotillo;13.0447\nCandelaria;28.3547\nLa Dorada;0.3436\nSan Manuel;15.7975\nAlatri;41.7250\nDongwang;38.3242\nGagarin;55.5500\nRussellville;35.2762\nAmpatuan;6.8348\nTocache Nuevo;-8.1889\nSan Javier;-35.5924\nRoseaux;18.6000\nCervia;44.2586\nOfaqim;31.3167\nŚrem;52.0886\nDhabauli;25.8346\nLimoeiro de Anadia;-9.7414\nEmmendingen;48.1214\nStoughton;42.1192\nTanglou;22.1888\nLangedijk;52.6936\nThabazimbi;-24.6000\nCajati;-24.7361\nHendījān;30.2364\nTondela;40.5167\nLake in the Hills;42.1913\nSortöbe;42.8600\nTudiyalūr;11.0816\nLa Calera;4.7531\nHöxter;51.7667\nGermī;39.0297\nBaleno;12.4739\nNivelles;50.5833\nMacau;-5.1150\nRosa Zarate;0.3300\nDīnānagar;32.1500\nMabini;9.8650\nXizhou;24.1156\nToqsu;41.5417\nVihti;60.4051\nHanawa;40.2158\nJauja;-11.7750\nKrotoszyn;51.6833\nCaicedonia;4.3333\nTetela de Ocampo;19.8167\nLas Rosas;16.3667\nBarabinsk;55.3500\nNava;28.4214\nAcatenango;14.5544\nPucón;-39.2767\nHirado;33.3667\nSébikhotane;14.7469\nPilar;9.8333\nChahe;27.1746\nLansing;41.5648\nQueensbury;43.3568\nHeshancun;30.6344\nPetrovsk;52.3167\nItatiaia;-22.4914\nWhitehall;40.6571\nBalakliia;49.4564\nSrungavarapukota;18.1167\nKroměříž;49.2989\nCifuentes;22.6208\nQuakers Hill;-33.7344\nZhonghechang;27.8886\nHenstedt-Ulzburg;53.7833\nBorzya;50.3833\nKuzhittura;8.3165\nTudela;8.2472\nRehoboth;-23.3167\nNovyi Rozdil;49.4703\nOkotoks;50.7250\nBāgha Purāna;30.6881\nTakahashi;34.7914\nShangluhu;23.2538\nAsago;35.3333\nMateare;12.2356\nCarapó;-22.6339\nTibiao;11.2892\nStanford le Hope;51.5140\nSummerlin South;36.1242\nLaoaoba;26.8377\nGoio-Erê;-24.1850\nOgawa;36.0567\nBentley;53.5510\nHerentals;51.1833\nShāhpura;27.3897\nSønderborg;54.9138\nBalzar;-1.3600\nNongstoin;25.5200\nOyabe;36.6755\nNew Iberia;30.0049\nHarelbeke;50.8567\nLosal;27.4000\nLepe;37.2542\nZhongtai;35.0675\nPijnacker;52.0167\nSanta Rita de Cássia;-11.0089\nProsper;33.2394\nHeerenveen;52.9500\nMorrisville;35.8368\nAndoharanomaitso;-21.4667\nKalwākurti;16.6500\nJamestown;42.0976\nMount Olive;40.8662\nWest Springfield;42.1253\nOakleaf Plantation;30.1689\nAmbatolampy;-19.3861\nJeffersontown;38.2049\nBānswāda;18.3833\nBussy-Saint-Georges;48.8422\nPires do Rio;-17.3008\nIbaiti;-23.8489\nZhailuo;26.8794\nÁguas Santas;41.2090\nSan Salvador;20.2833\nYangiyer;40.2667\nLeichlingen;51.1167\nAmaliáda;37.8000\nEsparza;9.9959\nFichē;9.8000\nCecina;43.3167\nOulad Yaïch;32.4167\nTaza;35.0639\nMalmal;26.4833\nCheshire;41.5113\nRajpur;22.3053\nSantiago;9.2654\nPitoa;9.3833\nZeitz;51.0478\nHatonuevo;11.0694\nPropriá;-10.2111\nCasselberry;28.6624\nNaranjito;-2.1667\nNueva Concepción;14.1333\nAlagoa Grande;-7.0822\nHājipur;31.9771\nIdar-Oberstein;49.7114\nḨarīr;36.5517\nVittorio Veneto;45.9833\nMahārājpur;25.0194\nNovi Ligure;44.7592\nToucheng;24.8500\nMadison Heights;42.5073\nKarakoçan;38.9500\nExtrema;-22.8550\nAgawam;42.0657\nPassira;-7.9950\nPalotina;-24.2839\nQincun;37.8360\nGriesheim;49.8639\nJujutla;13.7833\nBasay;9.4167\nMatihāni;25.3595\nMaracanã;-0.7650\nGyöngyös;47.7833\nFerdows;34.0186\nSaint Bernard;10.2833\nHarūr;12.0510\nDouar Oulad Aj-jabri;32.2567\nDoña Remedios Trinidad;15.0000\nWitney;51.7800\nSaito;32.1167\nTaungup;18.8500\nUmargām;20.1700\nPāvugada;14.1000\nQuijingue;-10.7528\nMehlville;38.5018\nOlching;48.2000\nByaroza;52.5500\nAioi;34.8000\nGeislingen an der Steige;48.6244\nBihpur;25.3889\nSan Carlos;8.8006\nWalnut;34.0334\nGevaş;38.2978\nTeltow;52.4022\nPazarcık;37.4860\nFenoarivobe;-18.4497\nValencia;9.6097\nİhsaniye;39.0333\nBaunatal;51.2589\nHarrison;41.0236\nMampikony;-16.0917\nKartaly;53.0500\nIsnos;1.9333\nMagdalena;14.2000\nBaishaling;24.0950\nPokhvistnevo;53.6500\nMonroeville;40.4262\nOeiras do Pará;-2.0028\nDubăsari;47.2667\nCabricán;15.0768\nSanto Niño;17.8861\nRūdehen;35.7378\nNaranjal;-2.6728\nTarāna;23.3300\nLushoto;-4.7928\nEl Copey;10.1500\nKpandu;7.0000\nMcDonough;33.4397\nLacey;39.8564\nIzu;34.9765\nStockbridge;33.5254\nVillaviciosa de Odón;40.3583\nBaradero;-33.8000\nArivonimamo;-19.0333\nLillehammer;61.1167\nTha Yang;12.9658\nAzángaro;-14.9099\nGiarre;37.7333\nIlave;-16.0836\nWegberg;51.1417\nKobyłka;52.3333\nMechernich;50.6000\nSept-Îles;50.2167\nMūvattupula;9.9798\nLučenec;48.3286\nTriggiano;41.0667\nBamba;17.0333\nGingee;12.2528\nBarão de Cocais;-19.9458\nSeaford;50.7700\nSaugus;42.4681\nOulad Hammou;33.2499\nArari;-3.4539\nVenezuela;21.7511\nCarauari;-4.8828\nGlen Ellyn;41.8666\nVilla Allende;-31.3000\nPerumbalam;10.8000\nAssisi;43.0758\nLongaví;-35.9667\nBiłgoraj;50.5500\nAberdeen;45.4649\nTsushima;34.2000\nImbituva;-25.2300\nStafford;39.7049\nHigashikagawa;34.2500\nSeseña;40.1036\nLíšeň;49.2075\nCoyaima;3.8333\nBonito Oriental;15.7333\nMpika;-11.8300\nRāisinghnagar;29.5342\nGorlice;49.6547\nKolambugan;8.1144\nChortkiv;49.0167\nDatu Piang;7.0178\nKaranjiā;21.7626\nConceição da Barra;-18.5928\nCircasia;4.6167\nBom Jesus;-4.4200\nKotagiri;11.4167\nSerra Negra;-22.6119\nCarbonia;39.1672\nMogliano Veneto;45.5619\nGuararema;-23.4150\nRāmanayyapeta;17.3203\nAlmus;40.3748\nYemanzhelinsk;54.7667\nLuís Correia;-2.8789\nTaiwa;38.4373\nAllen Park;42.2595\nRaseborg;59.9750\nAshShajarah;32.6417\nAlotenango;14.4878\nHuanghuajing;24.1989\nManaquiri;-3.4281\nBrownsburg;39.8337\nCiro Redondo;22.0189\nManer;25.6500\nJeffrey’s Bay;-34.0333\nPongoz;40.7500\nWarin Chamrap;15.2008\nPershotravensk;48.3464\nAr Ruţbah;33.0381\nSan Giovanni in Persiceto;44.6408\nAltınova;40.6975\nGaotan;32.3227\nPādiyanallūr;13.2004\nReina Mercedes Viejo;16.9872\nTangutūru;15.3400\nLibacao;11.4833\nBan Chang;12.7208\nMilton;42.2412\nSighişoara;46.2169\nToli;45.9313\nBermejo;-22.7322\nBacoli;40.8000\nOrchards;45.6890\nSāngola;17.4378\nEagle Pass;28.7125\nLagdo;9.0500\nBārughutu;23.8038\nBenicarló;40.4167\nPedras de Fogo;-7.4019\nOlindina;-11.3669\nTalusan;7.4263\nPilar do Sul;-23.8128\nKhust;48.1814\nGuamal;9.1472\nBridgewater;41.9728\nBaesweiler;50.9000\nSamayac;14.5821\nShakīso;5.7500\nMollendo;-17.0231\nDjugu;1.9184\nTrês Marias;-18.2058\nForest Hills;42.9577\nLeimen;49.3481\nBakhor;38.5500\nSpring;40.3038\nGusev;54.5833\nOltinko‘l;43.0758\nGrimma;51.2386\nIllkirch-Graffenstaden;48.5300\nWetter (Ruhr);51.3881\nEsztergom;47.7856\nArerāj;26.5527\nBellaa;30.0314\nPiešťany;48.5842\nKevelaer;51.5833\nBelpasso;37.5833\nMajayjay;14.1463\nVakfıkebir;41.0475\nSvendborg;55.0594\nMainit;9.5369\nAjka;47.1006\nCabangan;15.1333\nAlga;49.9028\nSafājā;26.7333\nÅkersberga;59.4833\nHiji;33.3694\nObama;35.4957\nZacoalco de Torres;20.2333\nIndependence;38.9510\nCuartero;11.3428\nBad Neuenahr-Ahrweiler;50.5447\nDar Bel Hamri;34.1889\nSanta Cruz Cabrália;-16.2778\nBardaskan;35.2608\nEnterprise;31.3275\nNainijor;25.6811\nNunspeet;52.3833\nČapljina;43.1118\nBranford;41.2843\nCaucete;-31.6500\nTuku;23.6911\nÇiftlik;38.1667\nNavahrudak;53.5833\nSan Miniato;43.6833\nKłodzko;50.4333\nAlmazora;39.9403\nRapperswil-Jona;47.2167\nQujingpu;38.0814\nHonchō;41.8957\nĀron;24.3811\nHenderson;37.8397\nGuma;37.6168\nKushtagi;15.7562\nOrvault;47.2717\nCentre Wellington;43.7000\nBo‘ka;40.8136\nBabar;35.1692\nGlen Cove;40.8709\nShuiding;44.0500\nDajabón;19.5667\nArqalyq;50.2481\nGeilenkirchen;50.9653\nAloran;8.4146\nOppegård;59.7925\nKhrestivka;48.1464\nMima;34.0500\nSzentendre;47.7044\nIpubi;-7.6519\nSan Felipe Jalapa de Díaz;18.0716\nLa Paz Centro;12.3397\nSandrandahy;-20.3500\nTsinjoarivo;-19.6333\nLlallagua;-18.4167\nVadnagar;23.7850\nAmbohijanahary;-17.4000\nBayang;7.7930\nMaryland Heights;38.7189\nTalisay;14.1356\nGreenville;33.1116\nPô;11.1667\nMoulay Bousselham;34.8786\nLangdu;23.3129\nShaler;40.5229\nImito;-20.4167\nYangyuhe;33.8614\nGuaimaca;14.5333\nBlerick;51.3667\nPeniche;39.3500\nNakhal;23.3833\nTainai;38.0597\nSahavato;-20.6000\nNallıhan;40.1836\nKoewarasan;5.7697\nHazar;39.4450\nKhulm;36.6833\nTara;56.8833\nXochistlahuaca;16.7914\nBixby;35.9454\nMādhura;26.3388\nNeptune;40.2105\nKushva;58.2833\nCitong;23.7729\nLathrop;37.8090\nNew Milford;41.6042\nAşağı Göycəli;41.1158\nVillazón;-22.0911\nVícar;36.8317\nAhmadābād;25.3019\nShirley;40.7936\nLincoln;-34.8500\nTehuipango;18.5167\nEast Haven;41.2988\nStratford-upon-Avon;52.1928\nYahaba;39.6060\nBujaru;-1.5150\nSorochinsk;52.4167\nSueca;39.2026\nKakuda;37.9770\nDame-Marie;18.5667\nKhātegaon;22.5957\nSan Pedro del Pinatar;37.8167\nSan Andrés Sajcabajá;15.1756\nLa Oliva;28.6167\nMuchun;39.8833\nGarden City;37.9753\nGameleira;-8.5844\nOakdale;44.9876\nAnajás;-0.9869\nVarandarapilli;10.4167\nTimbiras;-4.2550\nUchturpan;41.2136\nKasangulu;-4.5911\nPunceres;9.9661\nCharkhāri;25.4000\nSouth Laurel;39.0603\nDois Irmãos;-29.5800\nQuiroga;19.6638\nCareiro da Várzea;-3.2208\nPachor;23.7098\nTsinjoarivo;-18.9333\nRidgecrest;35.6308\nKriens;47.0333\nHikawa;35.3929\nAmpasimanolotra;-18.8194\nKupiansk;49.7064\nChíos;38.3725\nPedernales;18.0333\nSan Isidro;12.3880\nHuitiupán;17.2333\nNiuchangqiao;26.6247\nSan Antonio del Monte;13.7167\nBouka;10.2167\nKholmsk;47.0500\nWilmslow;53.3250\nDingalan;15.3833\nImatra;61.1833\nTernivka;48.5231\nDanvers;42.5740\nAmbohitompoina;-19.7500\nNochistlán de Mejía;21.3642\nSan Martín de los Andes;-40.1667\nAlgemesí;39.1897\nMocímboa;-11.3196\nShalqar;47.8333\nKashima;33.1036\nDahmani;35.9500\nBitam;2.0833\nMateus Leme;-19.9858\nMillville;39.3903\nJaguarão;-32.5658\nSundern;51.3167\nSabaneta;8.7522\nThetford;52.4100\nQibray;41.3897\nEl Sauce;12.8861\nTenares;19.3700\nWappinger;41.5899\nKahului;20.8715\nLarreynaga;12.5939\nTlalpujahua de Rayón;19.8052\nSanta Bárbara;14.4333\nValente;-11.4119\nSanta Bárbara;-19.9589\nRambouillet;48.6444\nShilan;21.9053\nKent;41.1490\nGuaçuí;-20.7758\nKongsberg;59.6694\nLudwigsfelde;52.2997\nWilliamsport;41.2399\nSens;48.1975\nAlitagtag;13.8650\nDodge City;37.7611\nArraial do Cabo;-22.9658\nCártama;36.7114\nWilmette;42.0771\nPiraí;-22.6289\nAndenne;50.4833\nMolíns de Rey;41.4139\nThātha;25.4988\nPomerode;-26.7408\nBignona;12.8167\nMahaplag;10.6072\nHādīshahr;38.8367\nTopki;55.2833\nVilla Luvianos;18.9200\nChalhuanca;-14.2950\nSalinas Victoria;25.9667\nAtlautla;19.0000\nMboro;15.1500\nTraipu;-9.9708\nPorto Sant’Elpidio;43.2667\nApaxco de Ocampo;19.9800\nLufeng;24.5738\nZolotonosha;49.6833\nÐakovo;45.3100\nSandūr;15.1000\nŌuda-yamaguchi;34.5167\nSoron;27.8800\nSoignies;50.5667\nPau dos Ferros;-6.1108\nFūman;37.2239\nVeendam;53.1000\nChicago Heights;41.5100\nBernards;40.6761\nBurnie;-41.0636\nClinton;32.3540\nMaloyaroslavets;55.0167\nArnstadt;50.8342\nLapuyan;7.6325\nTualatin;45.3772\nIguaí;-14.7558\nPāyakarāopeta;17.4161\nViñales;22.6153\nAndapa;-14.6500\nUchinada;36.6536\nZarraga;10.8167\nPitogo;7.4536\nLagoa Vermelha;-28.2089\nPenukonda;14.0847\nZakopane;49.3000\nHayang;35.9167\nMukher;18.7008\nHavran;39.5583\nGabasumdo;35.2554\nAxim;4.8667\nMananjary;-21.2311\nLimoeiro do Ajuru;-1.8950\nStatesville;35.7842\nGioia del Colle;40.8000\nBorşa;47.6553\nLong Thành;10.8667\nJarrow;54.9814\nKitsuki;33.4167\nMirano;45.5000\nDi Linh;11.5778\nMarion;40.5497\nItako;35.9471\nPirapòzinho;-22.2753\nLainate;45.5667\nNova Prata;-28.7839\nK’olīto;7.3122\nLeon Postigo;8.1514\nLebrija;36.9194\nBoca da Mata;-9.6408\nMazenod;-29.4642\nBatgram;34.6833\nBandipura;34.4225\nÁgios Nikólaos;35.1833\nTimaru;-44.3931\nZongdi;25.5909\nSūlūru;13.7000\nAyyagarpet;17.2197\nTroyan;42.8833\nLongtan;40.7830\nZarechnyy;56.8167\nSupía;5.4667\nArgelia;2.2431\nNarat;43.3198\nKapellen;51.3167\nUkiha;33.3500\nCurtea de Argeş;45.1392\nMargate;-30.8500\nOcean;40.2520\nMankāchar;25.5300\nNorth Kingstown;41.5687\nSan Juan Guichicovi;16.9667\nMiramas;43.5822\nWashington;37.1303\nLohne;52.6667\nChoba;4.8906\nHulst;51.2833\nPadre Bernardo;-15.1600\nVīrakeralam;11.0077\nLier;59.8675\nIbotirama;-12.1850\nSanta Perpetua de Moguda;41.5375\nGojō;34.3486\nVillareal;11.5667\nWangtang;19.9327\nImmokalee;26.4253\nMont-Dore;-22.2157\nAmbodibonara;-20.3388\nXima;37.9763\nMalargüe;-35.4750\nErice;38.0369\nShāhganj;26.0560\nItacaré;-14.2778\nManihāri;25.3500\nOktyabrsk;53.1667\nKobuleti;41.8111\nMorón de la Frontera;37.1222\nMaple Valley;47.3659\nBien Unido;10.1333\nCampos Gerais;-21.2350\nWiesloch;49.2942\nParimpūdi;17.1171\nEast Hampton;41.0117\nOrosháza;46.5667\nKarlskoga;59.3333\nSola;58.8561\nDuayaw-Nkwanta;7.1667\nBaytūnyā;31.8889\nShencottah;8.9733\nJaynagar;26.5833\nSādri;25.1800\nCabrero;-37.0333\nCorralillo;22.9856\nMalebennūr;14.3537\nMu’tah;31.1000\nBluffton;32.2135\nSantuario;6.1375\nConner;17.8086\nWaddān;29.1611\nNew London;41.3502\nNizao;18.2441\nBhānder;25.7358\nTongyangdao;41.7676\nTortona;44.8942\nMarolambo;-20.0500\nMount Pleasant;42.7129\nHaiyang;39.9534\nMarshalltown;42.0343\nGurlan;41.8500\nPiracuruca;-3.9278\nLapão;-11.3828\nRoşiori de Vede;44.1114\nMulchén;-37.7167\nNiimi;34.9739\nMalekān;37.1508\nWest Islip;40.7041\nSanta María de Jesús;14.4933\nCiudad Bolívar;5.8500\nCoromandel;-18.4728\nMiguel Calmon;-11.4289\nNeckarsulm;49.1917\nDrimmelen;51.6833\nTemescal Valley;33.7581\nRasiāri;26.0464\nTeno;-34.8667\nOverath;50.9500\nNew Windsor;41.4742\nİpsala;40.9217\nAshford;51.4340\nSanta Rita do Passa Quatro;-21.7100\nCangas;42.2642\nPanchānandapur;24.9339\nAbarkūh;31.1267\nMacalelon;13.7500\nMontbéliard;47.5100\nChillán Viejo;-36.6229\nBidur;27.8961\nSchloß Holte-Stukenbrock;51.8833\nRamon Magsaysay;8.0053\nVerkhniy Ufaley;56.0667\nStrausberg;52.5833\nManbengtang;22.0896\nTerlizzi;41.1333\nIlchester;39.2187\nReoti;25.8500\nSürmene;40.9142\nMarapanim;-0.7139\nWasco;35.5938\nVilla El Carmen;11.9794\nAleksandrovskoye;44.7167\nLagoa Sêca;-7.1708\nLunel;43.6769\nXovos;40.2197\nTracuateua;-1.0719\nNovo Oriente;-5.5339\nPalanas;12.1464\nBo’ao;19.1606\nSan Felipe;14.6206\nRonse;50.7500\nKedu;25.7103\nLongdian;37.9033\nRockledge;28.3203\nNavrongo;10.8847\nEast Grinstead;51.1300\nChaska;44.8164\nMadison;32.4738\nSilao;25.0836\nZirndorf;49.4500\nTicuantepe;12.0231\nSipacapa;15.2128\nDigboi;27.3932\nRheinbach;50.6333\nOak Forest;41.6054\nRāver;21.2431\nCitrus Park;28.0730\nBurntwood;52.6831\nBarcelos;-0.9750\nVimercate;45.6167\nChettipālaiyam;11.1667\nSliedrecht;51.8167\nPaouignan;7.6937\nSan Isidro;16.8667\nPanauti;27.5844\nZhongshan;34.9430\nKlosterneuburg;48.3042\nCuerámaro;20.6258\nTall Rif‘at;36.4733\nHaliyāl;15.3294\nNuevo Arraiján;8.9200\nRamsey;45.2617\nItaí;-23.4178\nGonesse;48.9875\nBadiangan;10.9860\nBakhchysarai;44.7528\nTsaravary;-21.2500\nAalten;51.9333\nFrankfort;-27.2833\nBehara;-24.9500\nPorto Calvo;-9.0450\nTakahagi;36.7192\nStaraya Russa;58.0000\nAytos;42.7000\nBoralday;43.3603\nHuaquechula;18.7667\nAschersleben;51.7500\nNewtown;41.3988\nIúna;-20.3458\nTāzah Khūrmātū;35.3028\nMason City;43.1487\nGarmisch-Partenkirchen;47.5000\nWassenaar;52.1500\nSangyuan;38.6211\nHaqqulobod;40.9061\nChintalapalle;15.0400\nBalch Springs;32.7194\nWilliston;48.1814\nRāmpur;26.2126\nBathnāha;26.6433\nSantana do Paraíso;-19.3639\nOurilândia do Norte;-6.7550\nConverse;29.5091\nSaint-Constant;45.3700\nHennigsdorf;52.6378\nClarksburg;39.2246\nVādippatti;10.0843\nBan Phonla Krang;14.9192\nUbatã;-14.2139\nSihecun;22.4729\nAwara;36.2113\nMagarao;13.6619\nGranite City;38.7296\nShort Pump;37.6549\nSavur;37.5375\nHeiligenhaus;51.3167\nErmelo;52.3000\nCastro Alves;-12.7658\nSan Jose;10.0083\nGradignan;44.7725\nAtitalaquia;20.0583\nIchikikushikino;31.7167\nMiranda;-20.2408\nEnna;37.5633\nSwatara;40.2463\nHuntley;42.1599\nGrimsby;43.2000\nIxchiguán;15.1642\nTeutônia;-29.4478\nBuldan;38.0450\nTepehuacán de Guerrero;21.0131\nAlbignasego;45.3500\nAkitakata;34.6631\nBergerac;44.8500\nBhuban;20.8820\nDuptiair;23.9910\nEl Alia;37.1667\nSanta Eugenia;42.5667\nMadattukkulam;10.5587\nSandanski;41.5681\nBourzanga;13.6781\nConchal;-22.3300\nJajce;44.3417\nRappang;-3.8447\nSan Giovanni Rotondo;41.7000\nSantana;-12.9828\nAfzalpur;17.2000\nGarden City;42.3244\nSibinal;15.1333\nLiugoucun;40.9455\nGreen;40.9483\nGuanxi;24.8000\nBaden;48.0075\nSan Juan de Urabá;8.7667\nBrzozów;49.7000\nDongen;51.6333\nĀmangal;16.8499\nMärsta;59.6167\nQingshan;27.3500\nSebeş;45.9600\nEstarreja;40.7500\nTaraka;7.8994\nHénin-Beaumont;50.4217\nPereyaslav-Khmel’nyts’kyy;50.0650\nFremont;41.4395\nCoffs Harbour;-30.3022\nRangia;26.4700\nPrior Lake;44.7246\nGubkinskiy;64.4333\nCaboolture;-27.0667\nMcHenry;42.3387\nMargherita;27.2800\nSaguiaran;8.0333\nWągrowiec;52.8000\nNelliyalam;11.5255\nMel Bhuvanagiri;11.4380\nMiki;34.2682\nGalatina;40.1667\nWangen im Allgäu;47.6858\nHohen Neuendorf;52.6667\nSadalgi;16.4200\nBāgepalli;13.7800\nLiqizhuang;39.9703\nSan Agustín Tlaxiaca;20.1144\nNeenah;44.1669\nTalāja;21.3500\nBenicia;38.0725\nTauramena;5.0167\nJirwa;26.0064\nVilyeyka;54.4980\nMundo Novo;-11.8589\nFidenza;44.8667\nWillebroek;51.0667\nQuezon;17.3119\nPorto da Folha;-9.9169\nTwentynine Palms;34.1478\nWest Linn;45.3670\nNguti;5.3167\nMayskiy;43.6500\nWestport;41.1428\nAlakamisy Itenina;-21.6333\nWethersfield;41.7013\nWerkendam;51.8000\nBinə;40.4539\nTurrialba;9.8897\nSzentes;46.6510\nSikonge;-5.6333\nMantena;-18.7819\nTianwei;23.9023\nZomin Shaharchasi;39.9631\nBankāpur;14.9230\nLa Garde;43.1256\nKsebia;34.2933\nSoanierana Ivongo;-16.9167\nJoaçaba;-27.1778\nAssèmini;39.2833\nMiandrarivo;-19.4333\nSuār;29.0270\nPlum;40.5024\nKāko;25.2259\nBijbiāra;33.7938\nAmbinanisakana;-16.9500\nNayoro;44.3559\nAntsiatsiaka;-17.0000\nLabrador;16.0339\nScicli;36.7914\nTlaxcoapan;20.0953\nSol’-Iletsk;51.1667\nVohipaho;-23.5500\nSan Juan;17.7431\nDaphne;30.6263\nLibenge;3.6500\nTarragona;7.0491\nPāmidi;14.9500\nGeldermalsen;51.8833\nBamessi;6.0333\nFalconara Marittima;43.6333\nUnterhaching;48.0658\nAmatepec;18.6500\nAlmuñécar;36.7339\nSan Sebastián de Yalí;13.3061\nLaranjeiras;-10.8061\nDasūya;31.8168\nRužomberok;49.0786\nHamminkeln;51.7319\nJiangdi;27.0120\nMesagne;40.5667\nParacuellos de Jarama;40.5500\nSpringettsbury;39.9907\nMandi;31.7200\nPueblo Bello;10.4167\nWakefield;42.5035\nSrīnivāspur;13.3378\nChengannūr;9.3200\nBlagnac;43.6364\nQuarrata;43.8475\nAr Rudayyif;34.3833\nBuriti;-3.9419\nChiriguaná;9.3667\nZuitou;34.0622\nSanta Margarita;12.0378\nTarui;35.3663\nParit Buntar;5.1167\nPacasmayo;-7.4003\nPearl;32.2730\nMarcos Juárez;-32.7000\nAndranomavo;-16.5667\nKantābānji;20.4671\nAragua de Barcelona;9.4575\nRājgarh;27.2360\nMandabe;-21.0500\nAlbania;11.1597\nIdigny;7.4833\nWellington;11.3655\nGilarchāt;22.0703\nSaumur;47.2600\nOurika Wawrmas;30.7167\nLochearn;39.3461\nCelendín;-6.8667\nAripuanã;-10.1767\nAlvin;29.3872\nPaianía;37.9500\nPantar;8.0667\nQā’emīyeh;29.8519\nManjacaze;-24.7117\nHutto;30.5396\nNoicattaro;41.0333\nIbimirim;-8.5408\nChuimatan;35.7166\nSan Luis Jilotepeque;14.6500\nUyuni;-20.4667\nKarpinsk;59.7667\nPuerto Colombia;11.0167\nLagindingan;8.5833\nHolbrook;40.7944\nSanta María Ixhuatán;14.1833\nSkopin;53.8167\nLauf;49.5103\nHancun;39.4062\nŞafāshahr;30.6131\nKamyshlov;56.8333\nSapian;11.4939\nNiscemi;37.1500\nAcapetahua;15.2333\nTurek;52.0167\nPutignano;40.8500\nAl Quţayfah;33.7389\nLauri;25.1396\nNew Lenox;41.5095\nThomasville;35.8813\nZnamensk;48.5833\nKhānābād;36.6831\nCrestview;30.7477\nYōrō;35.3084\nMiracema;-21.4119\nPemberton;39.9562\nBuritizeiro;-17.3508\nNādbai;27.2300\nSun City Center;27.7150\nJaltenco;19.7511\nPınarbaşı;38.7220\nEhingen an der Donau;48.2833\nAmbodiangezoka;-14.6000\nSabaa Aiyoun;33.9000\nKarasuk;53.7167\nAuburn;42.9338\nIglesias;39.3167\nButzbach;50.4367\nSarayönü;38.2661\nFlémalle-Haute;50.6011\nBoisbriand;45.6200\nMiyanaga;33.7167\nMajagua;21.9244\nJinju;22.7073\nCândido Sales;-15.5050\nTamorot;34.9333\nKarumāndi Chellipālaiyam;11.3019\nShoreview;45.0842\nPérama;37.9667\nBozyazı;36.1000\nMoon;40.5081\nHeppenheim;49.6431\nIpixuna;-7.0508\nShangxiao;35.4969\nSofiyivs’ka Borshchahivka;50.4114\nLamego;41.1008\nSanta Rosa de Viterbo;-21.4728\nLauaan;11.1429\nPérez;-33.0000\nBafoulabé;13.8064\nZottegem;50.8667\nSolânea;-6.7778\nBugho;10.8000\nTamayo;18.4000\nMauganj;24.6800\nSan Pablo;7.6578\nUlubey;40.8761\nGladstone;39.2134\nChivasso;45.1910\nNepomuceno;-21.2358\nQarah Ẕīā’ od Dīn;38.8914\nDyatkovo;53.6000\nFortul;6.7922\nCavaillon;43.8375\nDeer Park;40.7623\nDardoq;40.8156\nObertshausen;50.0667\nBishunpur Sundar;26.0579\nSombrio;-29.1039\nAlhaurín el Grande;36.6331\nSachse;32.9726\nLos Córdobas;8.9000\nJarocin;51.9667\nNovoaleksandrovsk;45.5000\nŌtake;34.2333\nGuruzāla;16.5800\nMacrohon;10.0797\nTōin;35.0741\nMalitbog;8.5361\nApam;5.2789\nEidsvoll;60.3475\nCodajás;-3.8369\nKey West;24.5642\nSanteramo in Colle;40.8000\nFrancavilla al Mare;42.4167\nSemiluki;51.6833\nCarrollton;33.5818\nMorales;2.7603\nMariano Comense;45.7000\nChuanliaocun;28.2611\nNarasannapeta;18.4151\nEureka;40.7943\nMerrimack;42.8547\nMontreux;46.4333\nPiracaia;-23.0539\nḨukūmatī Baghrān;33.0669\nVadakkanandal;11.7739\nWooster;40.8172\nPoytug‘;40.9000\nJardim;-7.5819\nPolysayevo;54.6014\nMuchamiel;38.4136\nWanlaweyn;2.6167\nPfaffenhofen;48.5333\nTekkalakote;15.5348\nHukeri;16.2300\nShingū;33.7167\nWeiterstadt;49.9000\nAsheboro;35.7158\nFortuna Foothills;32.6616\nShelek;43.5972\nManāsa;24.4800\nSanto Antônio do Tauá;-1.1519\nVernon Hills;42.2340\nSouth Windsor;41.8353\nIesolo;45.5331\nTaloda;21.5607\nMaevatanana;-16.9500\nKirzhach;56.1500\nBrasiléia;-11.0100\nRatau;-29.3828\nBeuningen;51.8667\nTubize;50.6930\nKiruna;67.8489\nYuanyangzhen;34.7847\nKiskunhalas;46.4319\nDondon;19.5333\nKudachi;16.4800\nKrasnoarmeysk;56.1000\nBetong;5.7731\nNova Esperança;-23.1839\nDum Duma;27.5688\nLanquín;15.5758\nMasanwa;-3.1833\nHuşi;46.6742\nWieliczka;49.9894\nMizque;-17.9333\nAz Zabadānī;33.7250\nSegezha;63.7333\nMaski;15.9581\nSan Giovanni Lupatoto;45.3833\nPlainview;40.7832\nPandag;6.7411\nSiófok;46.9239\nPlanalto;-14.6700\nKirovsk;48.6333\nJászberény;47.5000\nSibi;12.3786\nLas Flores;-36.0139\nCaetés;-8.7728\nMelgaço;-1.8039\nFrías;-28.6333\nParamus;40.9455\nPoro;10.6290\nCuajinicuilapa;16.4717\nMaçka;40.8167\nDeogarh;21.5383\nRich;32.2583\nBétera;39.5922\nLemoore;36.2949\nVeranópolis;-28.9358\nJumilla;38.4792\nHorn Lake;34.9512\nGiussano;45.7000\nAş Şanamayn;33.0711\nMirassol d’Oeste;-15.6750\nUpper Dublin;40.1502\nOkuta;9.2199\nMühlacker;48.9500\nDalnerechensk;45.9333\nSan Benito Abad;8.9333\nChintalapūdi;17.0667\nPura;15.6248\nMangaldai;26.4300\nCasiguran;16.2833\nSuperior;46.6941\nCambuí;-22.6119\nWyszków;52.5928\nSan Alberto;7.7525\nKirovsk;67.6167\nKhā̃dbāri̇̄;27.3667\nOldbury;52.5050\nWerota;11.9167\nTemple Terrace;28.0436\nLichtenburg;-26.1500\nSamokov;42.3371\nBeohāri;24.0242\nNilakkottai;10.1700\nSchleswig;54.5181\nFarmington;41.7288\nDois Córregos;-22.3661\nSeverouralsk;60.1500\nSan Antonio del Sur;20.0569\nFălticeni;47.4597\nWindsor;38.5422\nBubong;8.0167\nGroß-Gerau;49.9192\nMabini;16.0697\nQuilalí;13.5683\nRuskin;27.7065\nCesenatico;44.2000\nLa Unión;-40.2833\nValdagno;45.6500\nRedenção;-4.2258\nGanjing;35.3338\nMadalum;7.8530\nCampos Sales;-7.0739\nBudhlāda;29.9300\nSafīpur;26.7300\nZhaicun;22.6174\nDel Gallego;13.9233\nNacimiento;-37.5000\nRīngas;27.3700\nKayapa;16.3583\nMigdal Ha‘Emeq;32.6714\nCharata;-27.2167\nMount Gambier;-37.8294\nManoli;15.7800\nMannachchanellūr;10.9078\nBouknadel;34.1333\nSão João Nepomuceno;-21.5400\nHaines City;28.1102\nXincun;21.6960\nSanta Josefa;7.9842\nTerdāl;16.5000\nVadakku Viravanallur;8.6979\nHorsham;40.1993\nSão Bernardo;-3.3608\nEast Chicago;41.6469\nÁgua Azul do Norte;-6.7908\nMakubetsu;42.9085\nEl Monte;-33.6833\nTabira;-7.5908\nAl ‘Awwāmīyah;26.5833\nUbaidullāhganj;22.9983\nNordenham;53.5000\nSanta Lucia;17.1222\nLicey al Medio;19.4300\nAurillac;44.9261\nAirmadidi;1.4333\nAït Faska;31.5058\nHjørring;57.4636\nLilancheng;39.2011\nRenigunta;13.6500\nKsour Essaf;35.4300\nSiquinalá;14.3082\nTālīkota;16.4800\nBalboa;2.0436\nŌra;36.2524\nKirovsk;59.8667\nAru;2.8617\nSelm;51.6833\nPati do Alferes;-22.4289\nBingen am Rhein;49.9667\nWall;40.1674\nGūdūru;15.7748\nSan Juan Atitán;15.4333\nArida;34.0833\nCaririaçu;-7.0419\nRandolph;40.8434\nBrawley;32.9783\nMansfield;41.7892\nThatcham;51.4050\nSouth Portland;43.6310\nLiushuquan;39.3512\nArrecifes;-34.0667\nKami;33.6000\nCanarana;-11.6850\nSanger;36.6990\nOndokuzmayıs;41.4944\nVignola;44.4808\nSangerhausen;51.4667\nTopoľčany;48.5542\nPort Alfred;-33.5917\nWalpole;42.1464\nSapouy;11.5544\nCabot;34.9766\nNavabad;38.5667\nManito;13.1235\nWhitehaven;54.5480\nLamut;16.6517\nPanchari Bazar;23.2900\nBurgos;17.0667\nSinait;17.8667\nLa Teste-de-Buch;44.6200\nCotoca;-17.7536\nPensilvania;5.5000\nSão João Batista;-27.2758\nIlha Solteira;-20.4272\nİncesu;38.6222\nKernersville;36.1065\nConversano;40.9667\nFrauenfeld;47.5500\nBourdoud;34.5922\nPoldokhtar;33.1536\nOwatonna;44.0912\nBuenavista;13.2500\nPukekohe East;-37.2000\nTermini Imerese;37.9833\nSan Pablo;17.4478\nKalfou;10.2833\nSusquehanna;40.3111\nSun City West;33.6695\nArzignano;45.5167\nRāman;29.9504\nBad Honnef am Rhein;50.6450\nChitarpur;23.5794\nTiruppattūr;10.1300\nShuanghe;33.0320\nŠumperk;49.9653\nKurchaloy;43.2044\nMaheshwar;22.1769\nBeramanja;-13.3333\nBangzha;24.8345\nSora;41.7167\nKluczbork;50.9833\nBuddayyakota;13.6593\nDengjiazhuang;37.7051\nMahitsy;-18.7500\nLindau;47.5458\nChinna Salem;11.6342\nBushey;51.6429\nDugda;23.7452\nTeustepe;12.4206\nFarnham;51.2150\nBozkır;37.1886\nGeretsried;47.8667\nFleetwood;53.9220\nSaikaichō-kobagō;32.9333\nSanchez-Mira;18.5611\nFriedrichsdorf;50.2556\nKottapeta;16.7167\nBoureït;34.9833\nPerevalsk;48.4333\nBuesaco;1.3833\nPolasara;19.7815\nMontemor-o-Velho;40.1667\nItaíba;-8.9478\nYapacani;-17.4028\nAmbatomborona;-19.4000\nUnion City;33.5942\nSemīrom;31.4142\nRancho Grande;13.2353\nGulām;25.7965\nBatavia;41.8479\nElefsína;38.0333\nVertou;47.1689\nLanaken;50.8925\nÉtampes;48.4343\nXishan;23.0636\nPaducah;37.0711\nIradan;40.2600\nInfanta;15.8208\nPaz de Ariporo;5.8833\nDongfeng;22.2479\nCañas;10.4457\nLa Máquina;14.3021\nMint Hill;35.1783\nGressier;18.5500\nŚwiecie;53.4167\nMalyn;50.7689\nBurlington;42.5022\nTrindade;-7.7619\nKöthen;51.7500\nAttimarappatti;8.7297\nSierra Bullones;9.8167\nBom Jesus dos Perdões;-23.1350\nBarki Ballia;25.4223\nPotrerillos;15.2167\nConde;-11.8139\nHaoping;32.5992\nVsetín;49.3387\nEl Progreso;14.3500\nPhulera;26.8700\nNew Milton;50.7600\nKhashuri;41.9975\nLabytnangi;66.6572\nTavira;37.1167\nBaykan;38.1639\nRaghunāthpur;23.5500\nHomewood;33.4619\nGembloux;50.5667\nHumberto de Campos;-2.5978\nYuanchang;23.6420\nCasillas;14.4171\nBig Spring;32.2389\nWinona;44.0505\nConception Bay South;47.5167\nNagar;27.4247\nAmbatofotsy;-21.7500\nCastel Volturno;41.0500\nKulmbach;50.1000\nLice;38.4500\nIaçu;-12.7669\nTholen;51.5333\nPuerto Varas;-41.3167\nMarimba;-8.3667\nEl Quetzal;14.7667\nRosario de la Frontera;-25.8000\nNorco;33.9252\nAracoiaba;-4.3708\nWetteren;51.0000\nBessemer;33.3712\nAchern;48.6333\nSocorro;9.6181\nTaquari;-29.8000\nBobon;12.5167\nEmmeloord;52.7097\nAttili;16.7000\nNovopavlovsk;43.9500\nMahates;10.2333\nSasovo;54.3500\nUherské Hradiště;49.0697\nItapuranga;-15.5619\nOum Hadjer;13.2833\nNij Khari;22.0929\nMadira;16.9167\nDancagan;7.6119\nGrevená;40.0850\nToktogul;41.8722\nSantiago Papasquiaro;25.0439\nMungaoli;24.4084\nOltiariq;40.3917\nLakshmīcharīpāra;22.7900\nMizdah;31.4450\nHelmstedt;52.2281\nSaint-Bruno-de-Montarville;45.5333\nRequínoa;-34.2786\nQueimadas;-10.9778\nZacualtipán;20.6500\nMahambo;-17.4833\nSeondha;26.1542\nTroy;40.0437\nEast Hempfield;40.0825\nSan Sebastián Coatán;15.7333\nSouth Salt Lake;40.7057\nMantua;22.2908\nSankt Wendel;49.4667\nShāhedshahr;35.5714\nOdemira;37.5833\nLigang;22.8011\nLockport;41.5906\nLübbecke;52.3081\nRoseto degli Abruzzi;42.6833\nBāsopatti;26.5780\nTinipuka;-4.5485\nVierzon;47.2225\nZavodoukovsk;56.4833\nPuerto Píritu;10.0667\nBinidayan;7.8000\nTraun;48.2217\nCocal;-3.4708\nStein;50.9667\nSahaspur;29.1210\nVijāpur;23.5700\nHercules;38.0064\nTsarazaza;-20.1333\nCoração de Jesus;-16.6850\nDuiven;51.9500\nVillanueva de la Serena;38.9667\nKadamalaikkundu;9.8110\nSirumugai;11.3214\nGaoya;36.4609\nGajwel;17.8517\nTabina;7.4655\nAustin;43.6721\nMontichiari;45.4161\nMalaimbandy;-20.3333\nDiapaga;12.0667\nDano;11.1436\nŌguchi;35.3325\nMedina;41.1358\nRāghopur;25.5323\nPonta de Pedras;-1.3900\nSanto Antônio do Monte;-20.0869\nOupeye;50.7083\nCorreggio;44.7703\nIstmina;5.1667\nRidgewood;40.9821\nMaozhou;38.8600\nKimovsk;53.9667\nSirmatpur;25.3235\nTekman;39.6450\nKīranūr;11.6920\nTraralgon;-38.1958\nMarmara Ereğlisi;40.9697\nKoko;11.4232\nTubay;9.1650\nDemre;36.2472\nNāgod;24.5692\nMaintirano;-18.0667\nNatividad;16.0422\nEl Jícaro;13.7225\nNagai;38.1075\nSanta Ana;9.3190\nDolores;-36.3167\nTorrelodones;40.5756\nSan Vicente de Cañete;-13.0833\nNovelda;38.3850\nTosa;33.5000\nTalisayan;8.9917\nSanta Maria;17.4667\nYinajia;26.8239\nMimoso do Sul;-21.0639\nGrandview;38.8802\nŌmachi;36.5030\nMalaṅgawā;26.8667\nColumbine;39.5879\nDe Witt;43.0501\nWetzikon;47.3167\nĀgaro;7.8500\nLourinhã;39.2333\nTarangnan;11.9000\nAlegria;9.7243\nSan Martín;3.6944\nBeersel;50.7631\nAlaçam;41.6100\nSingarāyakonda;15.2500\nCiempozuelos;40.1592\nSanta María Colotepec;15.8833\nTeniente Primero Manuel Irala Fernández;-22.8140\nMola di Bari;41.0667\nSão Joaquim de Bicas;-20.0489\nHaisyn;48.8094\nWilsonville;45.3109\nErandio;43.3047\nWest Chicago;41.8960\nFelixstowe;51.9639\nMar de Ajó;-36.7203\nWoodburn;45.1472\nVitez;44.1585\nMiyaki;33.3249\nAltavas;11.5383\nBusselton;-33.6478\nKorkut;38.7386\nPszczyna;49.9833\nKunisakimachi-tsurugawa;33.5653\nAndasibe;-17.3333\nUpper Moreland;40.1572\nOxford;34.3627\nNova Soure;-11.2328\nSanta Lucia La Reforma;15.1333\nRoth;49.2461\nCochrane;51.1890\nVerl;51.8831\nInkster;42.2935\nPāveh;35.0433\nOulad Barhil;30.6408\nBaliqchi;40.9000\nSaintes;45.7464\nYany Kapu;45.9675\nFort Washington;38.7339\nRāmdiri;25.3118\nScandiano;44.5925\nHarsewinkel;51.9667\nWoodstock;42.3096\nColleyville;32.8913\nBagno a Ripoli;43.7500\nTriunfo;-29.9428\nNechí;8.1000\nHuejotzingo;19.1594\nKireyevsk;53.9333\nHasköy;38.6822\nUpper Macungie;40.5694\nCláudio;-20.4428\nLouis Trichardt;-23.0500\nPrata;-19.3069\nBaheri;25.9426\nBatabanó;22.7167\nGolborne;53.4758\nMerkānam;12.1942\nUreshinomachi-shimojuku;33.1333\nPereira Barreto;-20.6383\nMarshfield;42.1140\nBatalha;-4.0239\nMontgomery;40.2411\nMogtédo;12.2833\nNanpingcun;39.7530\nAdra;36.7478\nDiébougou;10.9667\nSão Miguel do Iguaçu;-25.3478\nLopez Jaena;8.5500\nFirmat;-33.4500\nHarbiye;36.1167\nCamas;45.6005\nKouhu;23.5763\nWest Melbourne;28.0694\nForest Grove;45.5243\nBan Piang Luang;19.6493\nAllen;12.5013\nVaterstetten;48.1050\nHolt;42.6416\nStevens Point;44.5241\nLanling;23.0033\nJaruco;23.0428\nBandar-e Deylam;30.0542\nOulad Said;32.6320\nAyuquitan;9.4644\nTipo-Tipo;6.5333\nPfungstadt;49.8056\nLos Arabos;22.7400\nOverijse;50.7833\nXaxim;-26.9619\nOlesa de Montserrat;41.5450\nLa Esperanza;14.8719\nNogi;36.2332\nIshii;34.0742\nRinteln;52.1906\nCarahue;-38.7089\nPanelas;-8.6639\nManyoni;-5.7500\nPinillos;8.9167\nSalor;41.3833\nLamzoudia;31.5833\nThetford Mines;46.1000\nLondonderry;42.8796\nNorth Tustin;33.7636\nMimata;31.7307\nZaprešić;45.8572\nUttaramerūr;12.6160\nDitzingen;48.8264\nVillanueva;12.9647\nIgaci;-9.5369\nLennestadt;51.1236\nHaiwei;19.4275\nLibourne;44.9200\nBalabanovo;55.1833\nOtradnoye;59.7833\nBusuanga;12.1335\nVnukovo;55.5997\nSangrāmpur;26.4752\nIrugūr;11.0178\nBudai;23.3600\nYolombó;6.5978\nKamonkoli;1.0750\nWitham;51.7978\nCayo Mambí;20.6647\nPalma;-10.7758\nNesher;32.7711\nFujikawaguchiko;35.4973\nSan Pedro Masahuat;13.5500\nḨaql;29.2833\nUnisan;13.8413\nBoquim;-11.1469\nChanhassen;44.8546\nVeenoord;52.9875\nLa Valette-du-Var;43.1383\nBejucal;22.9328\nTegalbuleud;-7.3578\nJardim;-21.4800\nSarrat;18.1578\nRottweil;48.1681\nPauri;30.1500\nNabīnagar;24.6200\nMata Grande;-9.1178\nFengruncun;34.8537\nAndhra Thārhi;26.3771\nNāmrup;27.1939\nḐubā;27.3493\nWiehl;50.9500\nErlun;23.7910\nOliva;38.9194\nCourtenay;49.6878\nPodatūrpeta;13.2817\nŞarkîkaraağaç;38.0803\nẤp Khánh Hòa;10.6333\nHorb am Neckar;48.4453\nVynohradiv;48.1397\nLower Providence;40.1485\nMərdəkan;40.4922\nKazincbarcika;48.2531\nAsh Shūnah ash Shamālīyah;32.6100\nWałcz;53.2667\nPangil;14.4000\nIndependência;-5.3958\nVāsudevanallūr;9.2417\nKocaali;41.0547\nLegnago;45.1929\nPlettenberg;51.2167\nSan Nicolas;13.9283\nJalpan;21.2167\nDelitzsch;51.5264\nTougué;11.4400\nPenha;-26.7689\nCamalaniugan;18.2756\nIlaiyānkudi;9.6271\nAbay;49.6311\nPanāgar;23.3000\nAraira;10.4525\nSan Miguel;10.0000\nYanyan;24.4166\nLātehār;23.7442\nOud-Beijerland;51.8167\nRudolstadt;50.7169\nMimasaka;35.0086\nStaßfurt;51.8667\nIdstein;50.2206\nSolano;0.6983\nZhongcun;35.3615\nThiene;45.7072\nBaarn;52.2167\nTimurni;22.3712\nWādi;17.0700\nJaisinghpur;26.6318\nShrīrangapattana;12.4140\nYanaul;56.2833\nBoo;59.3167\nMahwah;41.0816\nRajākheri;23.8593\nMaaseik;51.1019\nTirorā;21.4072\nBrilon;51.3956\nLadera Ranch;33.5492\nSão José do Norte;-32.0150\nSaidpur;25.5500\nBorçka;41.3636\nDemba;-5.5000\nRosemount;44.7466\nIraquara;-12.2489\nAvanigadda;16.0197\nTumbao;7.1167\nAin Aicha;34.4833\nMercer Island;47.5661\nTalugtug;15.7789\nTanabi;-20.6258\nSalaga;8.5500\nBungku;-2.5333\nSomoniyon;38.4422\nJevargi;17.0139\nPalm River-Clair Mel;27.9239\nSkawina;49.9833\nKorostyshiv;50.3186\nClayton;35.6590\nPalm City;27.1735\nKirkby in Ashfield;53.0990\nZheleznovodsk;44.1394\nHarbel;6.2833\nDalmine;45.6500\nReading;42.5351\nHermanus;-34.4167\nSenador Pompeu;-5.5878\nLimonar;22.9561\nAlmonte;37.2667\nCaloto;3.0333\nXiaoli;38.9999\nJilikŭl;37.4928\nExeter;40.3139\nSandoná;1.2833\nElk River;45.3314\nVistahermosa;3.1239\nHazelwood;38.7931\nTamboril;-4.8319\nMudgal;16.0119\nSabanagrande;10.8000\nBan Khamen;13.8823\nSan José;1.6967\nUlongué;-14.7167\nSamtredia;42.1625\nLeandro N. Alem;-27.6000\nBaar;47.2000\nMarkkleeberg;51.2778\nHamme;51.0833\nWumayingcun;38.0094\nInta;66.0833\nHalfmoon;42.8640\nRuvo di Puglia;41.1167\nLa Unión;1.6019\nYamagata;35.5061\nWarrington;40.2489\nSuşehri;40.1658\nOzëry;54.8500\nRānia;29.5300\nVangviang;18.9333\nFarkhor;37.5000\nŞaydnāyā;33.6967\nÖhringen;49.2000\nChiromo;-16.5500\nCorrente;-10.4428\nKingsville;27.5094\nNagtipunan;16.2167\nHeiloo;52.6000\nAlbergaria-a-Velha;40.6936\nXenia;39.6829\nAcatlán;20.4242\nCuijk;51.7296\nTapa;30.2979\nMeckenheim;50.6333\nBom Jardim;-22.1519\nPaete;14.3667\nKeystone;28.1312\nAreia Branca;-4.9558\nGalt;38.2698\nLafayette;37.8919\nOttumwa;41.0195\nDhing;26.4679\nFormosa do Rio Preto;-11.0478\nKasrāwad;22.1274\nMengdan;24.2752\nRockaway;40.9602\nCota;4.8167\nDerby;37.5571\nKariba;-16.5167\nMombin Crochu;19.3667\nSilver Springs Shores;29.1126\nMonreal;12.6440\nBanga;31.1887\nStaunton;38.1593\nMagog;45.2667\nUla;37.1036\nFlorence;33.0590\nKola;22.4300\nPitangui;-19.6828\nPallappatti;10.7198\nMednogorsk;51.4222\nWorkington;54.6365\nChocontá;5.1467\nMoscow;46.7308\nMadūru;14.7000\nWesterlo;51.0833\nSalem;37.2864\nSalamanca;-31.7667\nCamillus;43.0539\nKovancılar;38.7217\nMoron;18.5600\nOnda;39.9625\nPaoay;18.0625\nPinal de Amoles;21.1342\nRequena;-5.0569\nFairland;39.0803\nNewport;41.4801\nKhalāri;23.6506\nHudson;42.7639\nBurē;10.7000\nKochubeyevskoye;44.6706\nAnajatuba;-3.2639\nBad Oldesloe;53.8117\nLengir;42.1819\nBarberton;41.0095\nDedham;42.2467\nMerelbeke;51.0000\nKhed Brahma;24.0299\nSiswa;26.7027\nDhāriwāl;31.9561\nNorden;53.5967\nPoblacion;10.1614\nSalzkotten;51.6708\nLaon;49.5639\nCaledonia;42.7986\nKalayaan;14.3280\nPetershagen;52.3833\nMejorada del Campo;40.3967\nPooler;32.1043\nFlores Costa Cuca;14.6500\nGuéné;11.7306\nElói Mendes;-21.6100\nDrodro;1.7667\nCajuru;-21.2753\nSprockhövel;51.3667\nEl Ghiate;32.0331\nXiaolongtan;23.8099\nNijverdal;52.3667\nSan Felipe;15.0619\nSafsaf;34.5581\nBarra dos Coqueiros;-10.9089\nCatembe;-26.0050\nCave Spring;37.2254\nHastings;40.5961\nTiruvattār;8.3307\nKościerzyna;54.1167\nPezinok;48.2919\nMuret;43.4611\nAridagawa;34.0575\nSastamala;61.3417\nApiaí;-24.5097\nEdwardsville;38.7922\nNagarpāra;25.4155\nZittau;50.8961\nJaleshwar;26.6500\nSolin;43.5317\nPagudpud;18.5614\nGenzano di Roma;41.7022\nQuirino;17.1356\nDe Pere;44.4308\nSeal Beach;33.7542\nShaqlāwah;36.4056\nMorozovsk;48.3667\nCambre;43.2830\nAthens;34.7843\nTōno;39.3279\nGhoti Budrukh;19.7167\nJenks;35.9981\nSahāwar;27.8000\nSteenbergen;51.5833\nGöle;40.7928\nPortogruaro;45.7833\nSezze;41.5000\nPiranhas;-9.6239\nBayonet Point;28.3254\nOtuzco;-7.9000\nReserva;-24.6500\nGreat Sankey;53.3918\nAş Şaqlāwīyah;33.3964\nSanta María Tonameca;15.7458\nMayāng Imphāl;24.6000\nUmga;24.6396\nRaahe;64.6833\nBan Pa Sak;16.8477\nBelvidere;42.2543\nOkemos;42.7057\nSikandarpur;26.0333\nMinowa;35.9150\nSan Francisco Zapotitlán;14.5833\nValls;41.2883\nNedre Eiker;59.7647\nWatertown;43.9734\nPurwā;26.4700\nReedley;36.5988\nGyál;47.3861\nIcatu;-2.7758\nSaiha;22.4800\nBardsīr;29.9275\nAklvidu;16.6000\nAimorés;-19.4958\nAtkarsk;51.8667\nRangāpāra;26.8377\nBoussé;12.6667\nPālakodu;12.3037\nSovetskaya Gavan’;48.9667\nWalker;42.9853\nNovi Travnik;44.1748\nVilla Tapia;19.3000\nNinohe;40.2713\nEreymentaū;51.6167\nSohāgpur;22.7000\nTarpon Springs;28.1493\nSho‘rchi;38.0111\nSaltpond;5.2000\nWolfsberg;46.8419\nĀshkhāneh;37.5614\nBarstow;34.8661\nTulsīpur;27.5500\nCalpe;38.6450\nSaky;45.1336\nLe Ray;44.0771\nFranklin;39.4948\nSahjanwa;26.7500\nSão João da Ponte;-15.9289\nNewberg;45.3075\nBystrc;49.2247\nDhāmnagar;20.9141\nWil;47.4667\nSand;59.1343\nTirumuruganpūndi;11.1649\nDalupo;19.3908\nĀdīs Zemen;12.1167\nSanto Tomás;-14.4510\nUauá;-9.8419\nDbarwa;15.1000\nMontalbán;10.2522\nKabanga;-2.9022\nMatriz de Camarajibe;-9.1519\nPallapatti;9.4664\nPreah Vihear;13.8167\nVicuña;-30.0333\nKrems an der Donau;48.4167\nKamo;37.6663\nWhitehorse;60.7029\nNittedal;60.0731\nPitsea;51.5690\nAntsirabe Avaratra;-13.9667\nTateyama;36.6636\nDimasalang;12.1933\nFidirana;-19.5000\nMundargi;15.2070\nJitotol;17.0833\nMa‘bar;14.7940\nWaldkraiburg;48.2167\nSandusky;41.4468\nTernate;14.2833\nNarasingapuram;11.6038\nArnold;39.0437\nWujiaying;33.1871\nNainpur;22.4300\nRidgefield;41.3065\nPiritiba;-11.7300\nIki;33.7497\nGeneral Luna;13.6881\nEspelkamp;52.3772\nBiałogard;54.0000\nQuisqueya;18.5542\nRădăuţi;47.8425\nYuzhang;25.3561\nSlavutych;51.5206\nBloomingdale;27.8784\nTurnu Măgurele;43.7517\nNorton Shores;43.1621\nRāmshīr;30.8947\nZhuangwei;24.7702\nŻagań;51.6167\nDainyor;35.9194\nSultepec;18.8667\nUvarovo;51.9833\nAmpahana;-14.7500\nTirumala;13.6833\nTrussville;33.6405\nCalliaqua;13.1308\nVila do Conde;-7.2600\nBaroy;8.0333\nMalanguan;40.1873\nLüdinghausen;51.7667\nSantiago de Chuco;-8.1502\nEhden;34.2919\nMahatalaky;-24.7833\nBalete;14.0167\nSan Enrique;10.4167\nKobo;12.1500\nWest Milford;41.1060\nAnkazomborona;-16.1167\nZwevegem;50.8000\nVillarrobledo;39.2667\nWoolwich;43.5667\nCaballococha;-3.9058\nAvon Lake;41.4944\nEdgewood;39.4190\nMorton Grove;42.0423\nChandili;19.2467\nSolsona;18.0961\nÜbach-Palenberg;50.9197\nValparaíso;-21.2278\nBay Point;38.0329\nWarstein;51.4500\nMagenta;45.4603\nWyandotte;42.2113\nMuskego;42.8860\nSanta Gertrudes;-22.4569\nMogalturru;16.4167\nRonnenberg;52.3194\nVoorst;52.2333\nCaransebeş;45.4214\nMātābhānga;26.3420\nMadaoua;14.0762\nPiat;17.7919\nTsaratanana;-16.7972\nRomulus;42.2237\nOlpe;51.0167\nShivganj;25.1500\nEchemmaia Est;32.0786\nBalarāmpur;23.0972\nNorfolk;42.0324\nAjnāla;31.8400\nEaston;42.0362\nMulakumūd;8.2681\nPonneri;13.3200\nSandomierz;50.6833\nTaquaritinga do Norte;-7.9001\nRishton;40.3567\nMeiningen;50.5500\nSchmallenberg;51.1490\nDodola;6.9833\nPatnāgarh;20.7083\nSão João dos Patos;-6.4950\nJabonga;9.3431\nTugaya;7.8840\nShitan;22.4546\nTrebišov;48.6278\nSanto Tomas;17.4000\nNewton Abbot;50.5290\nPāta Kalidindi;16.5014\nPamplona;18.4661\nNorthdale;28.1058\nQabāţīyah;32.4097\nOmurtag;43.1000\nMarysville;40.2279\nHarstad;68.8011\nFrancisco Sá;-16.4102\nNemuro;43.3301\nMarín;42.3933\nCalahorra;42.3000\nEl Milagro;-8.0284\nBroadstairs;51.3589\nOuaoula;31.8667\nKungsbacka;57.4833\nSahasoa;-21.9833\nLitoměřice;50.5342\nSharya;58.3667\nRawtenstall;53.6990\nÜshtöbe;45.2422\nOttaviano;40.8500\nDouar Olad. Salem;32.8739\nYarmouth;41.6756\nSinj;43.7000\nVerukulambu;8.2953\nLiangwu;23.6012\nBrandon;32.2778\nPavlovsk;50.4578\nAso;32.9483\nShamgarh;24.1800\nAnivorano Avaratra;-12.7333\nStutterheim;-32.5667\nVinnamāla;13.9074\nVenice;27.1184\nAraquari;-26.3700\nLeoben;47.3817\nTirutturaippūndi;10.5300\nCampo Magro;-25.3689\nZhuchangba;26.6615\nBad Soden am Taunus;50.1333\nMontevarchi;43.5286\nDakṣiṇkāli̇̄;27.6089\nDongxiaozhai;40.1149\nLucena;10.8833\nBřeclav;48.7589\nNāyanakulam;9.9611\nSuchitoto;13.9333\nPindwāra;24.7945\nTamilisan;7.9761\nChāpar;26.2839\nSanta Rosa;10.4456\nTumwater;46.9891\nAnastácio;-20.4839\nVēttakkāranpudūr;10.5637\nDickinson;46.8918\nSpringfield;39.9281\nGemerek;39.1819\nBūndu;23.1609\nSebastian;27.7822\nKulachi;31.9286\nGorantla;13.9892\nZhenbeibu;38.6275\nSarandi;-27.9439\nZarautz;43.2833\nPão de Açúcar;-9.7478\nArdmore;34.1949\nPweto;-8.4667\nSomerset;40.5083\nFort Dodge;42.5098\nSão Joaquim;-28.2939\nDelfzijl;53.3333\nSão Mamede de Infesta;41.2000\nJunqueiro;-9.9250\nNavalgund;15.5700\nIsernhagen-Süd;52.4342\nMequon;43.2352\nWright;30.4445\nSan Benito;26.1298\nPepa;-7.7106\nTekāri;24.9425\nZanesville;39.9565\nPatian;5.8444\nBhirāha;25.7978\nScotch Plains;40.6332\nWierden;52.3500\nHulbuk;37.8050\nOga;39.8868\nRaisio;60.4858\nApollo Beach;27.7618\nArmidale;-30.5000\nVelūr;11.1114\nTuburan;6.6000\nFort Hood;31.1357\nDerry;40.2709\nPāsighāt;28.0700\nKakonko;-3.2796\nVillanueva;4.6087\nG’allaorol Shahri;40.0214\nBurdeos;14.8436\nZiketan;35.5885\nMoses Lake;47.1279\nČeský Těšín;49.7461\nBuy;58.4833\nHodonín;48.8489\nŞamaxı;40.6303\nSeia;40.4220\nLuzilândia;-3.4578\nTres Isletas;-26.3500\nBelsand;26.4436\nAstorga;-23.2328\nAparecida do Taboado;-20.0869\nAlgeciras;2.5333\nTamahú;15.3069\nChinobod;40.8767\nJalolquduq;40.7194\nOirase;40.5992\nMarco;-3.1239\nBintuni;-2.1167\nExtremoz;-5.7058\nKungälv;57.8667\nIpameri;-17.7219\nDix Hills;40.8033\nPetrinja;45.4406\nMiguel Pereira;-22.4539\nGiulianova;42.7500\nČadca;49.4358\nFiruzoba;40.3000\nMonte Cristi;19.8667\nGose;34.4667\nJacaré;-18.9058\nChebba;35.2372\nCanindé de São Francisco;-9.6419\nSão Geraldo do Araguaia;-6.4008\nLoma Linda;34.0450\nCalamar;10.2500\nSucre;-1.2600\nIgaraçu do Tietê;-22.5092\nChannagiri;14.0240\nJuayúa;13.8333\nMedford;40.8220\nTanglin;37.4377\nAlbenga;44.0500\nArad;31.25\nVizela;41.3667\nKhārupatia;26.5184\nTakhli;15.2667\nSrvanampatti;11.0764\nMummidivaram;16.6500\nShangtianba;28.0390\nDorohoi;47.9597\nOleshky;46.6333\nSagbayan;9.9167\nAshton in Makerfield;53.4870\nCarrascal;9.3683\nItabaiana;-7.3289\nPort St. John;28.4757\nRickmansworth;51.6383\nLas Cabras;-34.2917\nMacia;-25.0333\nWest Memphis;35.1530\nÁlvares Machado;-22.0789\nHomer Glen;41.6043\nKhajurāho;24.8500\nKonstancin-Jeziorna;52.0833\nZion;42.4603\nHannoversch Münden;51.4167\nRochefort;45.9421\nShama;5.0167\nSocastee;33.6871\nSūleswaranpatti;10.6388\nSanharó;-8.3608\nClinton;41.8435\nMalinao;11.6431\nLarvik;59.0811\nBuôn Trấp;12.4833\nPutten;52.2667\nIgreja Nova;-10.1253\nCarolina Forest;33.7651\nAl Qubbah;32.7667\nAshwarāopeta;17.2500\nPerrysburg;41.5377\nNossa Senhora das Dores;-10.4919\nWestmont;41.7948\nCollinsville;38.6770\nAin Dfali;34.5990\nBorre;59.3799\nĀlangulam;8.8640\nGarcia Hernandez;9.6144\nFreha;36.7620\nCartaxo;39.1500\nYanbu;22.7544\nAttendorn;51.1167\nSan Borja;-14.8583\nMurādpur;25.8000\nGelemso;8.8167\nPanglong;24.1003\nPaïta;-22.1337\nGreenbelt;38.9953\nBacolod;8.1892\nLes Irois;18.4000\nSugar Hill;34.1080\nPātakākāni;16.3422\nKarataş;36.5625\nNasukarasuyama;36.6569\nMau;26.2658\nMina;10.9333\nChanaur;25.8510\nKauswagan;8.1917\nAurora;-6.9428\nUrbano Santos;-3.2078\nSulmona;42.0480\nAmatán;17.3833\nYādiki;15.0500\nCorsicana;32.0824\nBuzen;33.6167\nAlicia;9.8957\nGrombalia;36.6000\nZernograd;46.8500\nValdivia;7.1636\nTuzluca;40.0494\nCanhotinho;-8.8819\nMekla;36.6876\nStarkville;33.4608\nLa Huerta;19.4833\nPirajuí;-21.9989\nHerzogenaurach;49.5700\nBela Vista de Goiás;-16.9728\nBorne;52.3000\nRavānsar;34.7153\nEl Retorno;2.3306\nBhadās;25.5184\nCedro;-6.6069\nFossano;44.5500\nBainbridge Island;47.6439\nSyke;52.9131\nCondado;-7.5858\nItaporanga;-7.3039\nSakai;36.1085\nRugeley;52.7599\nKaniv;49.7447\nSelma;36.5715\nAvon;41.4485\nEncruzilhada do Sul;-30.5439\nKhairā Tolā;26.8958\nWatsa;3.0372\nKosigi;15.8542\nSenboku;39.7017\nWaldshut-Tiengen;47.6231\nSālār;23.7748\nWestford;42.5864\nSan Agustín Loxicha;16.0167\nŌgawara;38.0494\nDubnica nad Váhom;48.9606\nRoissy-en-Brie;48.7906\nWhite Bear Lake;45.0656\nGoirle;51.5167\nZungeru;9.8128\nClarence-Rockland;45.4833\nMahdīshahr;35.7108\nBereket;39.2431\nSevan;40.5550\nAthens;39.3270\nHaaksbergen;52.1500\nCopertino;40.2667\nLimbach-Oberfrohna;50.8667\nPýrgos;37.6667\nSanaur;30.3018\nCoín;36.6667\nKumar Khad;26.5918\nPonca City;36.7235\nSpremberg;51.5717\nGollapūdi;16.5412\nNeftekumsk;44.7506\nVilankulo;-22.0000\nXinxing;47.1601\nEl Congo;13.9000\nWindham;41.7102\nBīrpur;26.5082\nLagonglong;8.8000\nGaz;32.8022\nLiushui;32.5959\nPacho;5.1306\nRiverside;39.7835\nLoha;18.9623\nSimsbury;41.8729\nShāhpur;21.2374\nLukaya;-0.1508\nFish Hawk;27.8511\nTocopilla;-22.0964\nMaksi;23.2600\nSenftenberg;51.5167\nVernon;49.0900\nCaibiran;11.5667\nAjim;33.7167\nTupanatinga;-8.7528\nRamain;7.9667\nPennādam;11.4039\nNorth Potomac;39.0955\nParis;33.6688\nStroitel;50.7833\nSoamanandrariny;-19.6500\nHujiachi;37.8917\nAnnūr;11.2325\nHelleland;58.8922\nYokadouma;3.5167\nPorto de Mós;39.6017\nBad Mergentheim;49.5000\nAlmansa;38.8682\nShamsābād;27.5364\nBijāwar;24.6235\nEl Bosque;17.0333\nMartos;37.7167\nKotelnich;58.3078\nOrbassano;45.0073\nBormujos;37.3667\nLisse;52.2500\nSelydove;48.1500\nQiaomaichuan;39.7866\nAmbohimasina;-19.6500\nSanta Ana;16.8069\nJocotenango;14.5868\nEl Factor;19.3200\nKoili Simra;25.4714\nWijk bij Duurstede;51.9833\nCraíbas;-9.6178\nNewport;50.7010\nVila Rica;-10.0119\nSendamangalam;11.2825\nRathenow;52.6000\nHusum;54.4667\nDole;47.0931\nVulcan;45.3811\nNocera Superiore;40.7417\nŢayyibat al Imām;35.2661\nDinuba;36.5453\nLanester;47.7647\nJoaquim Gomes;-9.1328\nFishkill;41.5129\nŚroda Wielkopolska;52.2333\nDighwa;26.2437\nHorquetas;10.3195\nMarple;53.3970\nAmarapura;21.8530\nGollalagunta;17.1672\nDalān;25.6030\nPuerto Guzmán;0.9636\nAsino;57.0000\nTadjmout;33.8667\nLatauna;26.0912\nVolendam;52.4994\nTirukkalikkunram;12.6067\nButurlinovka;50.8333\nDunaharaszti;47.3539\nKiên Lương;10.2856\nLa Montañita;1.4792\nMulgund;15.2807\nCedros;14.6000\nSarykemer;43.0106\nCuracaví;-33.4000\nKuju;23.7254\nRidgeland;32.4236\nCapão do Leão;-31.7628\nNerópolis;-16.4058\nPalmetto Bay;25.6219\nNueva Paz;22.7633\nDenison;33.7672\nDonmatías;6.4833\nDouar ’Ayn Dfali;33.9500\nSīlappādi;10.3940\nLa Paz;-30.7500\nNovo Aripuanã;-5.1214\nStjørdal;63.4750\nFaribault;44.2996\nKatrineholm;59.0000\nSaint-Laurent-du-Maroni;5.4976\nCogua;5.0667\nMarsella;4.9167\nRolling Meadows;42.0747\nCabrera;19.6300\nDazhuang;38.6951\nAlfter;50.7356\nManage;50.5000\nBoulsa;12.6667\nMahaiza;-19.9000\nSan Fernando;12.3167\nQuipapá;-8.8278\nRimavská Sobota;48.3811\nSan Agustin;12.5689\nSattahip;12.6636\nMairena del Alcor;37.3667\nCenterville;39.6339\nHajdúszoboszló;47.4333\nGotvand;32.2514\nGazojak;41.1833\nQiloane;-29.3625\nPallikondai;12.9167\nFormby;53.5586\nSan Juan Nepomuceno;-26.1167\nOak Harbor;48.2964\nMedford;39.8639\nOiapoque;3.8428\nLebedyn;50.5831\nPout;14.7739\nKalispell;48.2153\nSkoura;31.0606\nFeriana;34.9500\nNoto;36.8833\nHaren;52.7667\nAmbalamanasy II;-14.5167\nSouth Plainfield;40.5748\nBenbrook;32.6788\nChandrakona;22.7300\nSalqīn;36.1333\nGauripur;26.0800\nKyonpyaw;17.3000\nDiest;50.9847\nNorth Laurel;39.1285\nIbirapitanga;-14.1639\nPietrasanta;43.9452\nTehri;30.3800\nBela Vista;-22.1089\nIvrea;45.4674\nEmporia;38.4028\nMiddleborough;41.8803\nNorth Haven;41.3818\nSetti Fatma;31.2256\nVarel;53.3969\nBaraúna;-5.0800\nKrychaw;53.7194\nLālgudi;10.8700\nUchquduq Shahri;42.1567\nKailāshahar;24.3300\nNdora;-2.6033\nAuburn Hills;42.6735\nTupaciguara;-18.5928\nPingtang;26.0677\nVelingrad;42.0167\nKaltenkirchen;53.8397\nSarea Khās;26.6350\nIsa;32.0572\nSaint-Louis;47.5900\nHuilongping;28.1887\nWestchase;28.0597\nAngatuba;-23.4903\nKonnūr;16.2014\nQuezon;16.4894\nGuaiuba;-4.0400\nBulusan;12.7522\nMagallanes;14.1833\nBaiheqiao;22.9764\nLihe;34.0090\nTaupo;-38.6875\nGrootfontein;-19.5658\nBedburg;51.0000\nAnjozorobe;-18.4033\nKamiamakusa;32.5000\nPombos;-8.1492\nBurlington;40.8071\nSuonan;35.6634\nQuedlinburg;51.7917\nBaharly;38.4303\nRioblanco;3.5000\nFort Saskatchewan;53.7128\nBình Hòa;10.9353\nBeni Amrane;36.6686\nLos Barrios;36.1833\nLiria;39.6258\nSão José da Laje;-9.0100\nCalw;48.7167\nJequitinhonha;-16.4339\nAmbatotsipihina;-19.6333\nPelham;33.3114\nIbicaraí;-14.8650\nCastiglione delle Stiviere;45.4000\nKoilkuntla;15.2333\nLopary;-23.1833\nTsiatosika;-21.2000\nCanton;42.1750\nTegina;10.0706\nVänersborg;58.3806\nElkridge;39.1941\nMisato;38.5444\nBan Phru;6.9480\nBieruń Stary;50.0897\nAmstetten;48.1167\nDeyr;27.8417\nInhapim;-19.5489\nSonneberg;50.3500\nYangi Marg‘ilon;40.4311\nZaragoza;7.4940\nCavinti;14.2450\nAs Sulayyil;20.4597\nMapoteng;-29.1097\nLaguna Salada;19.6500\nItapissuma;-7.7764\nRita;10.4337\nBadou;7.5833\nFreeport;42.2891\nMonsefú;-6.8778\nMontecchio Maggiore;45.5037\nSemënov;56.8000\nHungund;16.0621\nRio Tinto;-6.8028\nKerrville;30.0398\nSolon;41.3865\nMarple;39.9654\nFort Mill;35.0061\nVentimiglia;43.7903\nGueznaia;35.7200\nSão Miguel do Guaporé;-11.6936\nPullappalli;9.7133\nHingham;42.2176\nZawyat an Nwaçer;33.3611\nPitogo;10.1210\nIbi;38.6272\nYugawara;35.1479\nGuapí;2.5703\nPuerto San José;13.9333\nWekiwa Springs;28.6984\nZolochiv;49.8075\nMiarinarivo;-17.6500\nElgin;57.6500\nTayga;56.0667\nKourou;5.1600\nLitvínov;50.6008\nHorley;51.1740\nOcara;-4.4908\nPonda;15.4034\nPiracanjuba;-17.3028\nHoh Ereg;41.0955\nAntonibe;-15.1167\nKelīshād va Sūdarjān;32.5542\nTangalan;11.7775\nSi Racha;13.1740\nWaltham Abbey;51.6846\nCatigbian;9.8333\nBcharré;34.2511\nNorth Augusta;33.5214\nSheghnān;37.6167\nAntanimieva;-22.2333\nLimbuhan;11.8836\nDöbeln;51.1194\nOldebroek;52.4500\nPakil;14.3833\nTranquebar;11.0292\nAllendale;42.9845\nAmbohimahamasina;-21.9333\nSehnde;52.3161\nSanta Apolonia;14.7833\nBloemendaal;52.4000\nBaud;20.8333\nQuellón;-43.0992\nSulya;12.5610\nEast Gwillimbury;44.1333\nFarmington;40.9845\nMacaparana;-7.5550\nBagulā;23.3350\nLisle;41.7918\nLalganj;26.1277\nFairfax;38.8531\nPerungudi;8.2792\nTecoluca;13.5333\nStepanavan;41.0096\nTrês Coroas;-29.5169\nFreudenstadt;48.4633\nKafr Sa‘d;31.3594\nEl Zulia;7.9333\nKingston;41.9295\nEmbarcación;-23.2167\nPaxtakor Shahri;40.3153\nPlainsboro;40.3377\nAldeias Altas;-4.6278\nHollola;60.9886\nLa Maná;-0.9300\nWajimazakimachi;37.3906\nHopa;41.3903\nKalach-na-Donu;48.7000\nAnchieta;-20.8056\nBiancavilla;37.6500\nRodniki;57.1167\nColumbus;41.4366\nSão Gonçalo do Sapucaí;-21.8919\nLaje;-13.1819\nCambará;-23.0458\nLoon op Zand;51.6667\nEl Tejar;14.6500\nTrês Passos;-27.4558\nJüchen;51.1011\nMaldegem;51.2000\nNanxingguo;37.6306\nGungu;-5.7333\nCarás;-9.0472\nAkwatia;6.0500\nTrês de Maio;-27.7728\nBogotol;56.2000\nBurgos;16.0465\nBhawānīgarh;30.2700\nGarmdarreh;35.7642\nCapoterra;39.1744\nQuesada;14.2723\nLubliniec;50.6833\nRajpur;21.9402\nKalawit;7.9051\nFresno;29.5357\nDongsheng;36.9996\nAndoany;-13.4000\nRingsted;55.4425\nIkeda;35.4423\nBazhajiemicun;38.8967\nHadžići;43.8217\nHonda;5.2042\nMonte Aprazível;-20.7728\nSacramento;-19.8650\nJawor;51.0500\nActon;42.4843\nMajdel Aanjar;33.7075\nKhenichet-sur Ouerrha;34.4333\nBarnegat;39.7668\nChinoz;40.9375\nSan Miguel Ocotenco;18.9894\nSokolov;50.1814\nMirandela;41.4853\nAlice Springs;-23.7000\nJurh;44.6961\nStarnberg;47.9972\nChamplin;45.1702\nOostkamp;51.1544\nPapillion;41.1511\nDouar Ouled Ayad;32.4167\nCandoni;9.8167\nTecolutla;20.4797\nGaojiayingcun;40.8814\nPalu;38.7039\nZemst;50.9722\nNyūzen;36.9335\nIbiapina;-3.9228\nMakhmūr;35.7756\nSaint-Dizier;48.6383\nColumbus;33.5088\nPedra Azul;-16.0050\nZeya;53.7333\nUpper Providence;40.1654\nPopovo;43.3500\nAbbeville;50.1058\nKasongo-Lunda;-6.4783\nLustenau;47.4271\nHillegom;52.2833\nBerehove;48.2025\nQuartier Militaire;-20.2500\nAlexânia;-16.0819\nKing of Prussia;40.0963\nHorgen;47.2667\nVélingara;13.1500\nKenilworth;52.3410\nJucás;-6.5250\nBelton;38.8192\nHirpardangal;23.8200\nTakehara;34.3333\nEl Maknassi;34.6042\nPadre Burgos;13.9226\nGrande-Synthe;51.0139\nLutz;28.1396\nChrudim;49.9511\nBaliguian;7.8088\nCranford;40.6564\nMirandola;44.8873\nWebster Groves;38.5866\nRamos;15.6667\nYesagyo;21.6333\nSan José;1.4744\nMakouda;36.7909\nManuel B. Gonnet;-34.8500\nNísia Floresta;-6.0908\nCockeysville;39.4804\nWandlitz;52.7500\nBrody;50.0781\nOstrów Mazowiecka;52.8000\nItuango;7.1667\nAuburn;44.0851\nWadsworth;41.0279\nLincoln;43.1300\nElburg;52.4500\nMandan;46.8290\nHonāvar;14.2809\nOulad Hassoune;31.6503\nTata;47.6526\nDunajská Streda;47.9944\nQifţ;25.9956\nNový Jičín;49.5944\nMosbach;49.3522\nBelmonte;-15.8628\nKuvandyk;51.4667\nHachimantai;39.9561\nKorbach;51.2833\nMansfield;42.0163\nBurlington;40.0641\nCuyo;10.8500\nKuna;43.4880\nFria;10.3804\nCeccano;41.5667\nConil de la Frontera;36.2667\nMaracás;-13.4408\nSamrāla;30.8360\nTecali;18.9000\nLuninyets;52.2500\nMuscatine;41.4195\nFunes;-32.9167\nDalyoni Bolo;39.7422\nFrontignan;43.4483\nWilloughby;41.6459\nBariārpur;25.2885\nSanta Lucía Utatlán;14.7667\nSouth Elgin;41.9906\nTadotsu;34.2729\nHerdecke;51.4000\nAyancık;41.9500\nRaul Soares;-20.1019\nIcod de los Vinos;28.3500\nTatarsk;55.2500\nEisenhüttenstadt;52.1450\nGelnhausen;50.2000\nKedia;23.7945\nVilaseca de Solcina;41.1110\nSalzwedel;52.8500\nAyt Mohamed;32.5667\nMetekora;22.1881\nLebu;-37.6000\nSoledad Atzompa;18.7550\nYellāpur;14.9637\nToda Rai Singh;26.0167\nBeni Khalled;36.6500\nKhromtaū;50.2503\nMunster;41.5468\nAlfreton;53.0970\nSan Juan Cotzocón;17.1667\nBadnāwar;23.0218\nSan Lorenzo;12.3783\nBauta;22.9919\nKreuzlingen;47.6333\nYukon;35.5201\nHighland;41.5483\nSarai Ranjan;25.7671\nMiantso;-18.7167\nVadakarai Kīl Pidāgai;9.0401\nSanto Antônio do Içá;-3.1019\nMandāwa;28.0500\nBonoufla;7.1333\nRavulapalem;16.7530\nQādirganj;24.9138\nPłońsk;52.6333\nAltea;38.5986\nCorinto;-18.3808\nSaginaw;32.8657\nSredneuralsk;56.9833\nGitega;-3.4260\nQuảng Trị;16.7469\nSaint-Ghislain;50.4500\nPokhuria;25.1307\nKoziatyn;49.7167\nBulle;46.6167\nPoggiomarino;40.8000\nCarletonville;-26.3581\nQianmotou;37.7952\nThiotte;18.2500\nZheleznogorsk-Ilimskiy;56.5833\nDillenburg;50.7333\nKrnov;50.0906\nLeutkirch im Allgäu;47.8256\nFountain Hills;33.6073\nLentini;37.2833\nFucecchio;43.7333\nLupeni;45.3603\nLermontov;44.1167\nNova Milanese;45.5833\nBenemérito;16.3333\nAchhnera;27.1800\nCaba;16.4316\nBurhar;23.2149\nKyeintali;18.0061\nPrincesa Isabel;-7.7369\nRāmpura;24.4670\nLubartów;51.4667\nPartizánske;48.6258\nCupira;-8.6169\nHavlíčkŭv Brod;49.6078\nKulgam;33.6400\nKáto Polemídia;34.6931\nSobradinho;-9.4550\nAşkale;39.9211\nIpatovo;45.7167\nUrucurituba;-3.1308\nBronnitsy;55.4261\nSeverobaykalsk;55.6500\nXiaping;24.6168\nMallasamudram;11.4933\nParsāgarhi;26.0935\nCaculé;-14.5028\nWesterstede;53.2500\nUnecha;52.8461\nDumaran;10.5333\nZărneşti;45.5667\nCanalete;8.7900\nNeusäß;48.4000\nSan Felíu de Guixols;41.7806\nAlcalá;4.6667\nĀdampur;31.4322\nSouthold;41.0432\nSan Ignacio de Velasco;-16.3667\nGamay;12.3833\nMaibog;10.1500\nSão Sepé;-30.1608\nWallenhorst;52.3500\nEl Paso;9.6622\nGerede;40.8006\nBad Salzungen;50.8117\nChantilly;38.8868\nWest Springfield;38.7771\nMontgomery;40.4260\nPesochin;49.9539\nKenmore;47.7516\nNagla;29.0100\nFloridia;37.0833\nRoseburg;43.2231\nDongshi;23.4748\nSonāri;27.0246\nRuwa;-17.8897\nTugatog;14.6629\nBrodósqui;-20.9908\nNorth Platte;41.1263\nBni Frassen;34.3833\nKurugodu;15.3460\nRon;15.6700\nElektrogorsk;55.8833\nKarahrūd;34.0600\nAhualulco de Mercado;20.6992\nCataño;18.4375\nFrederikshavn;57.4410\nSanto Tomás;10.7667\nMiyoshi;34.0260\nMaigo;8.1500\nMégara;37.9964\nRibas do Rio Pardo;-20.4428\nVega Baja;18.4406\nPace;30.6188\nNagykőrös;47.0332\nBondo;3.8167\nEschborn;50.1436\nSenden;48.3167\nDavlekanovo;54.2167\nNijlen;51.1667\nGersthofen;48.4167\nPatterson;37.4758\nTirat Karmel;32.7667\nJieshang;26.2663\nMuang Sing;21.2000\nSederot;31.5228\nMaple Heights;41.4094\nVillanueva de la Cañada;40.4500\nNeihuzhai;22.9745\nBarbasa;11.1961\nPissila;13.1667\nRock Springs;41.5947\nSonepur;20.8333\nTeguise;29.0611\nAssaré;-6.8739\nNasu;37.0198\nMartí;22.9522\nMedeiros Neto;-17.3739\nMuttupet;10.3950\nJacksonville Beach;30.2782\nHaar;48.1000\nMonte Caseros;-30.2500\nGālīkesh;37.2719\nBan Thoet Thai;20.3084\nAlmeirim;39.2000\nLensk;60.7333\n’s-Gravenzande;52.0000\nSakleshpur;12.8930\nḐank;23.5500\nAmbohimiadana;-19.2333\nBelo Oriente;-19.2200\nSluis;51.3083\nShuilin;23.5662\nCalamba;8.5583\nFrascati;41.8167\nLunbei;23.7789\nPajapita;14.7243\nSanta Helena;-24.8600\nHappy Valley;45.4358\nPiraí do Sul;-24.5258\nWaukee;41.5985\nBrotas;-22.2839\nRucphen;51.5333\nOrtona;42.3500\nNakūr;29.9189\nKumano;34.3358\nBrookings;44.3022\nRaritan;40.5070\nDoctor Mora;21.1425\nÉpernay;49.0403\nRiehen;47.5833\nGaoshu;22.8202\nJohnston;41.6910\nLaguna de Duero;41.5833\nVeinticinco de Mayo;-35.4167\nMoskva;37.6567\nCalabasas;34.1375\nTorre del Mar;36.7500\nBan Bang Rin;9.9531\nTeorama;8.4353\nÇağlayancerit;37.7506\nScherpenheuvel;51.0103\nGeneral Luna;9.7836\nCordeirópolis;-22.4819\nCuilapan de Guerrero;16.9972\nSan Lorenzo de Esmeraldas;1.2658\nCarandaí;-20.9539\nAkkuş;40.7931\nCalbiga;11.6333\nVernāg;33.5377\nAchkhoy-Martan;43.1939\nOrtigueira;-24.2078\nFarragut;35.8731\nChākia;26.4160\nSan José Ojetenam;15.2167\nTobatí;-25.2600\nKhirkiyān;22.1673\nSalcajá;14.8833\nCajidiocan;12.3667\nBeshariq;40.4358\nAvellaneda;-29.1175\nQaţanā;33.4333\nNyakrom;5.6167\nCullera;39.1639\nKarben;50.2322\nPiteå;65.3333\nGoumori;11.1833\nCaniço;32.6412\nVengattūr;13.0999\nLa Prairie;45.4200\nMelchor Romero;-34.9492\nPalmeiras de Goiás;-16.8050\nCide;41.8922\nWesterly;41.3635\nTaylors;34.9157\nSan Pablo Jocopilas;14.5833\nOlivet;47.8639\nNakagusuku;26.2678\nPíritu;9.9178\nMiantsoarivo;-19.2000\nMonteros;-27.1667\nWaverly;42.7401\nBermo;23.7878\nCollipulli;-37.9500\nTelica;12.5228\nMoncada;39.5456\nTiruverumbūr;10.7937\nWilmington;42.5609\nSimaria;25.5671\nSanto Tomé;-28.5500\nTaquarituba;-23.5328\nDouar Imoukkane;35.0298\nKirkintilloch;55.9380\nFangliao;22.3656\nCombs-la-Ville;48.6700\nBaile Átha Luain;53.4236\nLinda;39.1241\nMoirāng;24.3490\nYoshioka;36.4474\nWarrenton;-28.1114\nGriffin;33.2418\nJiucangzhou;38.2060\nKaler;25.1180\nNetphen;50.9147\nVilnohirsk;48.4781\nMinamata;32.2167\nZaruma;-3.6833\nNew Brighton;45.0658\nAñatuya;-28.4667\nOliveira do Bairro;40.5167\nTubungan;10.7833\nIguaba Grande;-22.8389\nLa Cruz de Río Grande;13.1122\nQiryat Mal’akhi;31.7333\nTeodoro Sampaio;-22.5328\nAlcobaça;-17.5189\nMine;34.1631\nKulattuppālaiyam;10.7613\nSheybān;31.4086\nShāhbāzpur;24.0531\nShiling;27.3576\nEast Retford;53.3228\nVelugodu;15.7817\nQiryat Shemona;33.2075\nTsaratanana;-21.1833\nRiachão das Neves;-11.7458\nPuchheim;48.1500\nPerāvūrani;10.3000\nUlukışla;37.5467\nGobō;33.8833\nCulion;11.8944\nKarlsfeld;48.2167\nBlangmangat;5.1881\nPalmar de Varela;10.7500\nTambaú;-21.7050\nSelim;40.4633\nOzuluama de Mascareñas;21.6667\nFarmington;44.6572\nAsafābād;19.3650\nSenador Guiomard;-10.1497\nKapolei;21.3399\nCarmen;8.9999\nNakashunbetsu;43.5552\nDevonport;-41.1800\nPilar de la Horadada;37.8667\nKūn Puhāl;33.0058\nTototlán;20.5333\nTighedouine;31.4236\nLagoa;37.1333\nPuenteareas;42.1667\nMentana;42.0167\nTadmaït;36.7427\nTecumseh;42.2431\nIbiá;-19.4778\nLoves Park;42.3364\nNevyansk;57.4833\nItaporã;-22.0789\n‘Ālī Shahr;28.9306\nTūkrah;32.5322\nBassar;9.2500\nLinstead;18.1368\nTouboro;7.7708\nWarburg;51.5000\nBeek en Donk;51.5347\nVan Buren;35.4483\nKolpashevo;58.3000\nHaywards Heath;51.0048\nCoração de Maria;-12.2328\nGuaraí;-8.8339\nVranov nad Topľou;48.8808\nYásica Arriba;19.6333\nColón;-33.8833\nKarhula;60.5155\nMolodohvardiisk;48.3444\nAreia;-6.9628\nClinton;41.1395\nSimpsonville;34.7287\nGormi;26.6003\nHulikal;11.3193\nAbreus;22.2806\nMontgomery;41.5399\nHimora;14.2861\nEsparraguera;41.5381\nColón;-32.2167\nFokino;42.9667\nAnkireddikuntapālem;16.2884\nChristiansburg;37.1406\nKodarmā;24.4675\nTnine Lgharbia;32.5719\nAllison Park;40.5730\nKoło;52.2000\nTrotwood;39.7926\nBedford;42.9406\nTapaktuan;3.2500\nPuerto Concordia;2.6833\nAmbohitrarivo;-17.4667\nWareham;41.7662\nRoxbury;40.8822\nSandviken;60.6167\nCrystal;45.0377\nBafilo;9.3500\nZunheboto;25.9667\nSidi Ifni;29.3833\nKilkís;40.9833\nMountain House;37.7673\nBalen;51.1667\nFleurus;50.4833\nLaguna Beach;33.5455\nOkahandja;-21.9833\nGif-sur-Yvette;48.7018\nLosser;52.2667\nParavai;9.9690\nMékhé;15.1167\nBallenger Creek;39.3807\nBaclayon;9.6227\nKomló;46.1912\nWeilheim;47.8333\nTashtagol;52.7667\nPitogo;13.7850\nTupiza;-21.4375\nSenda;24.4976\nPrieto Diaz;13.0408\nCholavandān;10.0167\nYunak;38.8172\nMangidy;-21.2500\nNanyangcun;34.7015\nSīwah;29.2000\nNiskayuna;42.8030\nNazareth;8.5562\nAmbohitoaka;-16.0167\nCâmpia Turzii;46.5486\nEastmont;47.8968\nGusinoozërsk;51.2833\nGarden City;40.7266\nGainsborough;53.4016\nMahela;-20.9667\nAzové;6.9500\nYuli;41.3351\nStoneham;42.4741\nBhatpurī;29.1700\nSanta Maria do Pará;-1.3519\nNikaho;39.2030\nKapfenberg;47.4394\nWulongpu;37.9356\nAmoucha;36.3880\nSearcy;35.2418\nOyonnax;46.2561\nMeiwa;34.5500\nÜberlingen;47.7667\nMercato San Severino;40.7833\nVigonza;45.4500\nStrakonice;49.2615\nLexington;33.9890\nWichian Buri;15.6565\nAchí;8.5667\nMinbu;20.1800\nFarahalana;-14.4333\nGardner;38.8122\nKeta;5.9167\nSeva;5.9845\nDindori;22.9414\nConceição das Alagoas;-19.9150\nGyêgu;33.0166\nUnion Hill-Novelty Hill;47.6788\nLysander;43.1799\nRastede;53.2500\nAndalatanosy;-24.6667\nShurugwi;-19.6667\nNiamtougou;9.7667\nMorris;40.7959\nHuixtán;16.6833\nCheriāl;17.9264\nYeadon;53.8690\nAnalamisampy;-22.4667\nCurumaní;9.2000\nHuaibaijie;35.7056\nGuanajay;22.9306\nOrobó;-7.7450\nTiruttangal;9.4833\nJunction City;39.0277\nBarbate de Franco;36.1833\nMakīnsk;52.6292\nTembagapura;-4.1428\nOndangwa;-17.9167\nGrajewo;53.6500\nWatertown;43.1893\nPawni;20.7800\nŌno;35.4706\nMarovato;-15.9000\nAiud;46.3122\nGreenfield;39.7937\nHopewell;37.2915\nAnkaramy;-13.9833\nVale de Cambra;40.8500\nAlâattin;37.4667\nBüdingen;50.2908\nPirenópolis;-15.8519\nAraçariguama;-23.4386\nOakdale;37.7618\nViga;13.8667\nFamaillá;-27.0500\nAnkilizato;-20.4000\nKrasnouralsk;58.3500\nZedelgem;51.1431\nXinsi;34.6503\nKrasnoarmeysk;51.0231\nYanshanbu;26.3326\nSoure;-0.7169\nFenyuan;24.0154\nShelbyville;35.4987\nBeixingzhuang;35.7033\nHudson;41.2399\nMiddletown;39.4450\nRoselle;41.9809\nBarakī Barak;33.9692\nNagold;48.5519\nAbu;24.5925\nVagos;40.5500\nKerūr;16.0138\nGuadalupe;2.0250\nDanwān;25.5292\nAl Fuḩayş;32.0167\nIvatsevichy;52.7167\nForbach;49.1900\nBrushy Creek;30.5128\nLuruaco;10.6083\nSarāri;26.2523\nKeene;42.9494\nLas Breñas;-27.0667\nWädenswil;47.2333\nDabeiba;7.0000\nKulkent;40.1500\nZeewolde;52.3333\nLaupheim;48.2289\nKanchika;16.4125\nManghit;42.1167\nDokuchaievsk;47.7506\nPointe à Raquettes;18.7833\nPalma di Montechiaro;37.1936\nMount Pearl Park;47.5189\nLa Democracia;14.2333\nItaocara;-21.6789\nEdgewater;28.9594\nZnamianka;48.7136\nŚwiebodzice;50.8667\nEdewecht;53.1258\nRivera;2.7853\nWertheim;49.7500\nMalacatancito;15.3167\nBad Kissingen;50.2000\nWest Goshen;39.9756\nOteiza;8.7437\nMaying;36.0448\nAyagawa;34.2496\nNasrullāhganj;22.6837\nCandelaria de La Frontera;14.1167\nSaint Austell;50.3400\nPillaiyārkuppam;11.8119\nGoulburn;-34.7547\nEspera Feliz;-20.6500\nSelvazzano Dentro;45.3833\nVreden;52.0333\nManosque;43.8342\nNixa;37.0453\nTervuren;50.8167\nMihama;34.7789\nLumbatan;7.7850\nGōtsuchō;35.0167\nAyos;3.9069\nIsilkul;54.9500\nSão Sebastião da Boa Vista;-1.7178\nMutuípe;-13.2289\nJogipet;17.8356\nEckernförde;54.4742\nThebes;38.3208\nEl Hermel;34.3914\nKitzingen;49.7333\nBuriti Bravo;-5.8369\nCamp Springs;38.8052\nHaderslev;55.2428\nPatacamaya;-17.2333\nTrezzano sul Naviglio;45.4333\nConceição da Feira;-12.5058\nGaroua Boulaï;5.8833\nPrāntij;23.4384\nArcos de Valdevez;41.8472\nKalat;29.0258\nRobertson;-33.8000\nGuryevsk;54.2833\nLengerich;52.1750\nAllen;-38.9667\nNazca;-14.8289\nPatharia;23.8992\nSanta Teresita;13.8664\nCandler-McAfee;33.7267\nMoncagua;13.5333\nCatamayo;-3.9833\nWinchester;42.4518\nMachesney Park;42.3666\nGlauchau;50.8233\nSan Cataldo;37.4833\nBanovići;44.4000\nBelton;31.0525\nMarshall;32.5370\nAināpur;16.4800\nNaciria;36.7500\nManki;14.1789\nAlnif;31.1167\nAlangāyam;12.6223\nAybastı;40.6867\nAmtali;22.1370\nKarachayevsk;43.7731\nEcoporanga;-18.3728\nSaint-Jean-de-Braye;47.9128\nKihei;20.7653\nRadcliff;37.8204\nButig;7.7239\nShaomi;26.4727\nNogoyá;-32.4000\nGoldasht;32.6267\nJarqo‘rg‘on;37.5083\nCartagena;-33.5425\nĀmodei;26.8975\nSingur;22.8100\nDziałdowo;53.2333\nRøyken;59.7336\nChincholi;17.4651\nItambacuri;-18.0364\nPhillaur;31.0300\nIvato;-20.6167\nTomarza;38.4472\nKatangi;23.4412\nChaves;-0.1600\nOnondaga;42.9686\nKhosrowshahr;37.9497\nNāḩiyat al Kifl;32.2242\nWhyalla;-33.0333\nCouëron;47.2156\nCinco Saltos;-38.8167\nCurchorem;15.2500\nPrairie Village;38.9874\nKāchhāri;22.0732\nKadiapattanam;8.1312\nSanta Fe de Antioquia;6.5500\nItaparica;-12.8878\nWettingen;47.4659\nKutina;45.4667\nPenzance;50.1190\nLazi;9.1280\nHowli;26.4224\nAcatlán;20.1444\nBéguédo;11.7833\nDiriomo;11.8753\nMagallanes;9.0225\nLeland;34.2042\nCachoeira do Arari;-1.0108\nAgrestina;-8.4500\nKigumba;1.8150\nOxford;39.5061\nNaqādah;25.9000\nVelsk;61.0667\nOliveira dos Brejinhos;-12.3169\nCottage Lake;47.7466\nRixensart;50.7167\nSarzana;44.1136\nBaravāt;29.0664\nLagoa Grande;-8.9969\nSvetlyy;54.6667\nTiruvankod;8.2452\nForney;32.7440\nAsaita;11.5667\nValašské Meziříčí;49.4718\nMontilla;37.5833\nMrągowo;53.8667\nAlhama de Murcia;37.8514\nŁęczna;51.3000\nBeşikdüzü;41.0494\nMassarosa;43.8667\nPetrila;45.4500\nVilla Park;41.8865\nSan Miguel de Papasquiaro;24.8304\nMoguer;37.2747\nIracemápolis;-22.5808\nKalachinsk;55.0500\nAnthem;33.8560\nBambuí;-20.0058\nParabcan;13.7100\nLadyzhyn;48.6897\nByala Slatina;43.4667\nSarangani;5.4120\nArroyito;-31.4167\nDom Pedro;-5.0328\nBuritis;-15.6178\nPerundurai;11.2777\nPinheiral;-22.5128\nBuenavista;8.2233\nDonaueschingen;47.9531\nTimmāpur;19.0484\nRosita;13.9239\nAmalfi;6.9167\nRāvar;31.2656\nAlta Floresta D’Oeste;-11.9283\nStaraya Kupavna;55.8000\nÁrta;39.1650\nPeters;40.2739\nAljaraque;37.2667\nManzanares;5.2519\nMetzingen;48.5367\nRaymore;38.8029\nSeynod;45.8889\nFrameries;50.4088\nSāmbhar;26.9103\nAmbriz;-7.8500\nLefkáda;38.7178\nŠaľa;48.1503\nApolda;51.0167\nEast Peoria;40.6736\nSupaul;25.9469\nFriesoythe;53.0206\nMondovì;44.3833\nAlnāvar;15.4273\nMandelieu-la-Napoule;43.5464\nPushkar;26.4903\nNaawan;8.4333\nZhengtun;25.1494\nMagdalena;20.9092\nUenohara;35.6302\nKhaw Zar Chaung Wa;15.0375\nOytal;42.9153\nPickerington;39.8890\nLucala;-9.6333\nSondrio;46.1697\nMānjhi;25.8384\nLlaillay;-32.8403\nSouk Tlet El Gharb;34.6211\nPachino;36.7167\nForquilhinha;-28.7469\nLochristi;51.1000\nLe Creusot;46.8014\nDuncan;34.5408\nSant’Arcangelo di Romagna;44.0633\nHuangzhai;38.0605\nTalwandi Sābo;29.9838\nQuemado de Güines;22.7900\nOuani;-12.1350\nLajas;22.4164\nDarton;53.5850\nTaulahā;26.9566\nAnnecy-le-Vieux;45.9192\nPudsey;53.7970\nEasley;34.8188\nTocantinópolis;-6.3289\nSingampunari;10.1815\nGoleniów;53.5636\nSaint-Genis-Laval;45.6960\nQādiān;31.8192\nMorombe;-21.7500\nBom Jesus;-9.0739\nLempäälä;61.3167\nArtémida;37.9667\nSek’ot’a;12.6253\nYahualica de González Gallo;21.1781\nEislingen;48.6933\nMedjez el Bab;36.6436\nCartersville;34.1644\nLos Llanos;18.6167\nBukkarāyasamudram;14.6944\nSun Valley;39.6104\nOmagh;54.5900\nUmbaúba;-11.3828\nPāpanāsam;10.9273\nJunnārdev;22.2000\nBhadaur;30.4764\nCorcoran;36.0841\nStadthagen;52.3247\nGonghe;35.3308\nQuaraí;-30.3878\nBurg;52.2725\nFlörsheim;50.0167\nFurukawa;36.2381\nBellview;30.4620\nBilthoven;52.1283\nMakó;46.2170\nGanapavaram;16.1233\nŞirvan;38.0633\nIsperih;43.7167\nGurmatkāl;16.8677\nBiswanath Chariali;26.7278\nYokoshibahikari;35.6658\nPuente Nacional;19.3333\nSan Antonio La Paz;14.7500\nChinameca;13.5000\nHuautla;21.0308\nParaopeba;-19.2739\nSardinata;8.0833\nSummit;40.7154\nGoianinha;-6.2669\nPāmarru;16.3270\nSivagiri;11.1200\nChāgallu;16.9833\nDawmat al Jandal;29.8153\nGölhisar;37.1408\nOshwe;-3.4188\nPorto Torres;40.8369\nSandbach;53.1460\nPiddig;18.1647\nWatertown;44.9094\nBatad;11.4167\nBélabo;4.9333\nPaese;45.6667\nAriano Irpino;41.1528\nMartellago;45.5467\nKadiria;36.5333\nBiggleswade;52.0855\nFougères;48.3525\nRío Ceballos;-31.1667\nWenceslau Guimarães;-13.6869\nCaravelas;-17.7319\nBraine-le-Comte;50.6000\nBuftea;44.5700\nGinosa;40.5000\nCruz;-2.9178\nBarra Velha;-26.6319\nDoutou;6.5500\nLas Torres de Cotillas;38.0264\nAgropoli;40.3500\nPogradec;40.9000\nHeide;54.1961\nSanto Antônio de Posse;-22.6058\nEustis;28.8563\nJaipur Chuhar;25.4187\nSevlievo;43.0256\nQuickborn;53.7333\nMutatá;7.2442\nKundgol;15.2561\nÁrgos;37.6167\nRadevormwald;51.2000\nJebba;9.1539\nNadvirna;48.6333\nGaoguzhuang;37.8364\nChester;37.3531\nSanta Fe;11.1856\nKhadyzhensk;44.4256\nSaktī;22.0300\nAmbohimanga;-18.7667\nAuch;43.6465\nVilcún;-38.6500\nGeertruidenberg;51.7000\nKannānendal;9.9649\nSucre;8.8139\nMaribojoc;9.7500\nKarnobat;42.6333\nUpper Allen;40.1800\nMalaba;0.6444\nZhedao;24.8098\nTaixi;23.7000\nKālchīni;26.6979\nẤp Phú Mỹ;9.7500\nVendram;16.5360\nZambrów;52.9833\nRupauli;25.8695\nGorgonzola;45.5333\nPadmanābhapuram;8.2446\nSouth Ockendon;51.5207\nSrīperumbūdūr;12.9680\nChatra Gobraura;26.4973\nDasnāpur;19.6536\nHalluin;50.7836\nIbatiba;-20.2364\nKoksijde;51.1000\nBetsizaraina;-19.9500\nSoyāgaon;20.5514\nEl Colegio;4.5808\nYuli;23.3875\nZirāpur;24.0222\nBoquira;-12.8228\nNamayumba;0.5281\nTepexi de Rodríguez;18.5797\nGardelegen;52.5264\nBloomingdale;41.9497\nŌtsuki;35.6106\nKopřivnice;49.5995\nAleksandrów Łódzki;51.8194\nOtopeni;44.5500\nArouca;40.9338\nSchwetzingen;49.3833\nJuatuba;-19.9519\nPalmas de Monte Alto;-14.2669\nArbi’a Tighadwiyn;31.4236\nSarapāka;17.6922\nŞā al Ḩajar;30.9647\nTiruppuvanam;9.8550\nTârnăveni;46.3297\nLincoln;41.9171\nVakon;6.5167\nBarra da Estiva;-13.6258\nZurbāţīyah;33.1500\nGubbi;13.3122\nKlatovy;49.3956\nSanta Isabel do Rio Negro;-0.4139\nHockenheim;49.3181\nPhulpur;25.5500\nDaxin;26.6210\nVernon;41.1973\nZvenigorod;55.7333\nDudelange;49.4833\nCasal di Principe;41.0167\nBorgomanero;45.7000\nMendeleyevsk;55.9000\nCornaredo;45.5000\nGoiás;-15.9339\nSevilimedu;12.8083\nZhucaoying;40.1759\nChaumont;48.1117\nGuérou;16.8167\nChankou;35.7754\nLa Cruz;-32.8281\nAtuntaqui;0.3317\nMasis;40.0633\nBinnish;35.9500\nTakahata;38.0027\nGuaratinga;-16.5839\nYahualica;20.9531\nGreenwood;34.1947\nSenekane;-29.2525\nChapa de Mota;19.8144\nCaraí;-17.1889\nPākāla;13.4667\nSan Jose;9.4167\nGīlān-e Gharb;34.1422\nCisnădie;45.7128\nHoogezand;53.1572\nUlus;41.5861\nVohimasina;-21.7333\nRajauli;24.6449\nḨārim;36.2000\nAnamalais;10.5830\nMorinda;30.7900\nWaldkirch;48.1000\nAnini-y;10.4325\nQorako‘l Shahri;39.5028\nColorado;-22.8378\nFantino;19.1200\nNatagaima;3.5833\nIngabu;17.8167\nSaurh;25.3789\nMārutūru;15.9862\nFernley;39.5627\nGuabo;-3.2388\nMontville;40.9135\nBronkhorstspruit;-25.8050\nIrauçuba;-3.7458\nPalestrina;41.8333\nSulejówek;52.2442\nMurayama;38.4833\nAmpasimanjeva;-21.7333\nLyman;48.9853\nEl Doncello;1.6833\nBiddeford;43.4673\nEl Tortuguero;12.8183\nSão João do Paraíso;-15.3139\nSalcedo;11.1500\nAcworth;34.0566\nHallim;33.3729\nPriego de Córdoba;37.4333\nHusnābād;17.0667\nBahçe;37.2000\nGuazacapán;14.0751\nRioja;-6.0500\nAlakamisy-Ambohimaha;-21.3167\nPingtan;23.2524\nNikolskoye;59.7000\nFeira Grande;-9.9000\nBan Pa Tueng;20.1339\nGardanne;43.4553\nItuporanga;-27.4139\nKuppam;12.7450\nLyndhurst;40.7965\nOuardenine;35.7200\nDjinet;36.8770\nDigor;40.3756\nLaja;-37.2667\nBristol;41.6827\nZoersel;51.2667\nBanbishancun;40.3700\nHerent;50.9081\nGujan-Mestras;44.6364\nWest Deptford;39.8431\nTupanciretã;-29.0808\nBasi;30.5872\nSão Miguel;-6.2119\nSanto Antônio;-6.3108\nTaveta;-3.3956\nSão Miguel do Araguaia;-13.2750\nColfontaine;50.4057\nRuston;32.5328\nKoduvilārpatti;9.9695\nCorail;18.5667\nIlsede;52.2667\nMandirituba;-25.7789\nUnchahra;24.3825\nBad Harzburg;51.8811\nḨamīdīyeh;31.4850\nWoensdrecht;51.4167\nAswāpuram;17.8348\nSan Felipe;31.0275\nHillsborough;40.5069\nReigate;51.2370\nBressanone;46.7165\nUgong;14.5842\nAlbertville;34.2633\nComacchio;44.7000\nLes Pennes-Mirabeau;43.4106\nLihuzhuang;39.6520\nMūlki;13.1000\nKoāth;25.3264\nThuân An;16.5489\nItigi;-5.7000\nRepelón;10.5500\nConselheiro Pena;-19.1719\nJāwad;24.5992\nNaregal;15.5732\nMartha Lake;47.8479\nSalvaterra de Magos;39.0167\nEppingen;49.1333\nCaojiachuan;34.9016\nGolden Valley;44.9901\nMarina;36.6810\nAfourar;32.2167\nRio Formoso;-8.6639\nNormanton;53.6970\nTakelsa;36.7833\nAndranovorivato;-21.6333\nCorinto;12.4819\nSahil;40.2200\nYavuzeli;37.3192\nLadário;-19.0050\nShabestar;38.1800\nBonney Lake;47.1791\nCoralville;41.6990\nHazebrouck;50.7250\nNova Zagora;42.4911\nCorinth;33.1434\nMoineşti;46.4333\nItamaracá;-7.7478\nOxford;33.5967\nGümüşhacıköy;40.8667\nCastrovillari;39.8167\nBato;13.6000\nFlores;-7.8658\nImbert;19.7500\nMandapam;9.2822\nMountain Brook;33.4871\nVilleneuve-sur-Lot;44.4081\nNangavaram;10.8692\nChesham;51.7120\nLuofa;39.4343\nLaventille;10.6500\nSan Agustin;16.5167\nMadakasīra;13.9369\nBavly;54.3833\nBad Rappenau;49.2333\nJugiāl;32.3684\nZundert;51.4667\nQarazhal;48.0253\nClarksville;38.3220\nBelonia;23.2500\nTabursuq;36.4572\nBellavista;-7.0668\nSem;59.2792\nOberwingert;47.5170\nQapqal;43.8340\nSão Jerônimo;-29.9589\nJiuru;22.7333\nSelouane;35.0667\nSilvania;4.4033\nHuejúcar;22.3167\nLom;43.8256\nAmbalaroka;-22.1333\nFlorida Ridge;27.5805\nMachico;32.7000\nWaynesboro;38.0674\nMadamba;7.8833\nHardi;26.0785\nChambersburg;39.9315\nPatpāra;26.4328\nSandhurst;51.3490\nKarlovo;42.6436\nBelas;38.7754\nKommunar;59.6333\nBeni Douala;36.6167\nNeu Wulmstorf;53.4628\nBemanonga;-20.2833\nHonmachi;36.0609\nPalmer;40.7007\nMillau;44.0986\nAmpanotokana;-18.7167\nNirmāli;26.3140\nSão Sebastião do Caí;-29.5869\nŚwiedbodzin;52.2500\nMaravilha;-26.7700\nIarintsena;-21.8167\nPailitas;8.9667\nArroyito;-23.1733\nVilla de Leyva;5.6333\nSalémata;12.6333\nUna;-15.2928\nVecsés;47.4057\nCrowborough;51.0600\nShiroishi;33.1811\nSilver Firs;47.8635\nMailavaram;16.7833\nCortona;43.2756\nCherry Hill;38.5696\nEl Pinar;-34.7972\nGuilford;41.3345\nWatertown;41.6160\nBloomington;34.0601\nPalafrugell;41.9174\nCunha;-23.0744\nMuelle de los Bueyes;12.0664\nYaojiafen;40.7158\nPalmital;-22.7889\nManlleu;42.0000\nParamirim;-13.4428\nLower;38.9819\nMerefa;49.8197\nKontich;51.1333\nMāngrol;25.3300\nTimbiquí;2.7667\nBataguaçu;-21.7139\nDarien;41.7448\nVersmold;52.0436\nTacaratu;-9.1058\nAmbodimotso Atsimo;-15.3833\nUst’-Katav;54.9333\nCuncolim;15.1773\nHorizon City;31.6799\nElsdorf;50.9333\nSan Martín;-31.4397\nJafaro;-24.9167\nTiquisio;8.5667\nSemikarakorsk;47.5167\nHastings;44.7318\nTaminango;1.5667\nTola;11.4392\nShendurjana;21.5217\nMazagão;-0.1150\nKueneng;-29.0161\nSonthofen;47.5158\nPóvoa de Lanhoso;41.5667\nChillicothe;39.3393\nTufānganj;26.3200\nAnkiabe-Salohy;-15.6000\nPhulaut;25.5114\nSeligenstadt;50.0333\nHlohovec;48.4333\nKozmodemyansk;56.3367\nPoço Verde;-10.7078\nImi-n-Tanout;31.1600\nChalchihuitán;17.0333\nAmaraji;-8.3758\nSan Bonifacio;45.4000\nKhānāpur;15.6394\nVilyuchinsk;52.9306\nKotli;33.5156\nCarutapera;-1.1950\nBānapur;19.7789\nRancho San Diego;32.7624\nAntsakabary;-15.0500\nOmutninsk;58.6667\nDeBary;28.8815\nEnsley;30.5259\nPicasent;39.3611\nTewkesbury;51.9900\nBarhampur;26.3042\nTân Phong;19.7322\nManakambahiny;-17.8000\nAndilanatoby;-17.9333\nMachagai;-26.9167\nGigaquit;9.5947\nBungotakada;33.5500\nBañolas;42.1194\nThenia;36.7278\nKhowai;24.0650\nSan Luis Talpa;13.4667\nKotovo;50.3000\nRichmond;51.4560\nConway;33.8401\nPascagoula;30.3666\n‘Adrā;33.6000\nMangalvedha;17.5167\nAxapusco;19.7194\nPitrufquén;-38.9833\nBirkerød;55.8333\nLa Porte;41.6069\nVereshchagino;58.1000\nNew Castle;40.9956\nSan Rafael del Yuma;18.4333\nXanten;51.6622\nBrambleton;38.9803\nCoreaú;-3.5328\nKemi;65.7361\nRemígio;-6.9028\nChalmette;29.9438\nIsernia;41.6028\nGuía de Isora;28.2110\nGuipos;7.7350\nWinter Gardens;32.8376\nMühldorf;48.2456\nYoqne‘am ‘Illit;32.6594\nNøtterøy;59.2011\nPolkowice;51.5000\nAnūppur;23.1034\nIisalmi;63.5667\nOpoczno;51.3772\nEast Ridge;34.9973\nAmposta;40.7106\nLooc;12.2605\nPedernales;0.0700\nEl Ksiba;32.5681\nMontclair;38.6111\nCaaporã;-7.5158\nWest Pensacola;30.4263\nTrinidad;-33.5333\nGummudipūndi;13.3995\nPort Hueneme;34.1618\nIsla-Cristina;37.1992\nMacArthur;10.8356\nMembakut;5.4667\nGoodlands;-20.0350\nHalle;52.0667\nTornio;65.8500\nRātu;23.4204\nDarreh Shahr;33.1397\nBhānpura;24.5108\nAmarpātan;24.3137\nTongzhou;25.7716\nMehnatobod;37.7167\nCabucgayan;11.4719\nOsterode;51.7286\nMatinha;-3.1008\nColangute;15.5450\nAmherstburg;42.1000\nHallein;47.6667\nParsippany;40.8645\nKaty;29.7905\nSamba Cango;-9.1000\nCaxambu;-21.9769\nParramos;14.6078\nLos Palmitos;9.3811\nLālru;30.4867\nLohutí;40.2500\nSermādevi;8.6873\nJózefów;52.1333\nFreire;-38.9558\nCaranavi;-15.8333\nAlmoradí;38.1097\nAyvacık;41.0036\nDax;43.7100\nGallup;35.5182\nPotters Bar;51.6980\nHad Oulad Issa;32.9519\nAzambuja;39.0667\nCasablanca;-33.3167\nSardulgarh;29.6970\nColônia Leopoldina;-8.9089\nShinhidaka;42.3413\nUruçuca;-14.5928\nOrzesze;50.1500\nColle di Val d’Elsa;43.4000\nGinebra;3.7500\nSouth Euclid;41.5240\nNew Hartford;43.0586\nMount Pleasant;43.5966\nSan Fernando;12.4858\nAyamonte;37.2000\nGros Islet;14.0810\nNāranammālpuram;8.7599\nMaghalleen;-30.0942\nHalewood;53.3599\nTādikombu;10.4390\nFukuyoshi;33.6832\nAlcântara;-2.4089\nSainte-Suzanne;19.5833\nFarakka;24.8200\nYabu;35.4000\nAlliance;40.9107\nNogales;-32.7350\nMashiko;36.4673\nCodlea;45.6969\nScarborough;43.5911\nOlho d’Água das Flores;-9.5358\nSmithfield;41.9014\nTigbao;7.8205\nSanta Teresa;-19.9358\nBrockville;44.5833\nRamona;33.0474\nSapulpa;36.0091\nMbandjok;4.4500\nOcotlán de Morelos;16.7914\nEssex;44.5196\nTidili Masfiywat;31.4667\nOzoir-la-Ferrière;48.7780\nCagwait;8.9181\nPiazza Armerina;37.3833\nNowa Ruda;50.5833\nSiilinjärvi;63.0750\nPueblo Juárez;17.7000\nEast Patchogue;40.7704\nForquilha;-3.7978\nItajuípe;-14.6778\nMa’mūnīyeh;35.2992\nKumla;59.1167\nFairhope;30.5209\nSan Martín de las Pirámides;19.7333\nChełmno;53.3492\nNellimarla;18.1667\nBornem;51.1000\nSanford;43.4244\nPendurti;17.8278\nPuerto Triunfo;5.8667\nSão Francisco de Paula;-29.4478\nSão Lourenço d’Oeste;-26.3589\nKosgi;16.9839\nSan Bernardo;1.5108\nAmizmiz;31.2167\nAmbatomanoina;-18.3167\nAllauch;43.3369\nCollingwood;44.5000\nG‘azalkent;41.5625\nGülşehir;38.7464\nMonsummano;43.8667\nPuruk Cahu;-0.6384\nDel City;35.4483\nPergine Valsugana;46.0667\nEl Callao;7.3463\nEtajima;34.2167\nSori;10.7281\nUnity;40.2811\nCorciano;43.1333\nZara;39.8950\nPalo del Colle;41.0500\nCan-Avid;12.0000\nMezdra;43.1500\nSrīvaikuntam;8.6318\nBilohorodka;50.4000\nChaudfontaine;50.5833\nQal’acha;40.1333\nMiguelópolis;-20.1794\nZonhoven;50.9853\nShanywathit;17.4244\nKurikka;62.6167\nVicksburg;32.3173\nAichach;48.4500\nSão Marcos;-28.9708\nChernogolovka;56.0000\nTinja;37.1667\nMoularès;34.4833\nHuy;50.5167\nGopavaram;14.7841\nSihu;23.6411\nAmerican Canyon;38.1796\nGermersheim;49.2167\nGökçebey;41.3081\nGöd;47.6906\nKaikalūr;16.5667\nBirmingham;42.5446\nKibeho;-2.6333\nEvans;40.3660\nStadtallendorf;50.8333\nCujubim;-9.3628\nKavak;41.0736\nDuarte;34.1610\nKobilo;15.9251\nXinzhai;26.6959\nBrent;30.4727\nKami;38.5718\nNovopokrovka;42.8708\nNoāmundi;22.1609\nKlamath Falls;42.2195\nShirhatti;15.2313\nAlcalá la Real;37.4500\nEyl;7.9667\nNāmagiripettai;11.4700\nNuenen;51.4733\nLisieux;49.1500\nManor;39.9848\nNerja;36.7469\nZerbst;51.9681\nMontecatini Terme;43.8828\nVicente Noble;18.3833\nTlaltenango de Sánchez Román;21.7815\nBayou Cane;29.6243\nŁaziska Górne;50.1500\nSedalia;38.7059\nMarvast;30.4775\nAshland;38.4592\nMānikganj;23.8500\nSan Jacinto;9.8311\nSão Felipe;-12.8469\nCassilândia;-19.1128\nNova Brasilândia d’Oeste;-11.7197\nFollonica;42.9189\nWülfrath;51.2833\nĀndippatti;9.9980\nNew Hope;45.0375\nMuhlenberg;40.3955\nBüren;51.5500\nMakulubita;0.5122\nEntroncamento;39.4653\nKangal;39.2367\nYenice;41.2000\nGranite Bay;38.7601\nWaghäusel;49.2500\nKant;42.8833\nNefta;33.8833\nGīnīr;7.1333\nRancheria Payau;7.8509\nBhojpur Kadīm;25.5841\nYucca Valley;34.1234\nSenaki;42.2689\nPalestina de los Altos;14.9333\nCrisópolis;-11.5108\nRāmnagar Farsāhi;25.8904\nDenain;50.3286\nParaíso;9.8432\nMililani Mauka;21.4756\nShāmgarh;25.8935\nPandan;14.0500\nSan Nicolás;22.7819\nFrederickson;47.0916\nChallans;46.8467\nHazel Dell;45.6797\nLindlar;51.0167\nMurree;33.9042\nNueva Granada;9.8031\nMillburn;40.7394\nTamgrout;30.2667\nMiddleton;43.1064\nLakato;-19.1833\nLa Resolana;19.6031\nSan Justo;-30.7833\nGeseke;51.6500\nZhoucun;37.4509\nHoogstraten;51.4000\nLeerdam;51.9000\nTolosa;11.0633\nBānki;20.3791\nBear;39.6189\nAlmasi;38.6833\nBad Krozingen;47.9167\nChilca;-12.5208\nScugog;44.0900\nSondershausen;51.3667\nGünzburg;48.4527\nInopacan;10.5000\nGaleras;9.1667\nZele;51.0667\nKara-Suu;40.7000\nSāmba;32.5624\nTehata;23.7274\nBelén de Umbría;5.2000\nWātrāp;9.6353\nRosario de Lerma;-24.9833\nAnagni;41.7422\nNang Rong;14.6283\nTong’anyi;35.3041\nFarum;55.8083\nArgenta;44.6153\nAcatic;20.7803\nBrunswick;43.9007\nDolton;41.6284\nNaryn;38.2000\nEeklo;51.1858\nĀthagarh;20.5600\nAmbohitromby;-18.9667\nSanta Rosa de Lima;14.3881\nPancas;-19.2250\nGrottaferrata;41.7883\nPudupattanam;12.5037\nShelby;35.2904\nClarin;9.9667\nPaiganapalli;12.4760\nQia’erbagecun;37.9766\nBuritirama;-10.7078\nJämsä;61.8667\nChinchali;16.5647\nKingsville;42.1000\nSavigliano;44.6500\nNambiyūr;11.3581\nLinamon;8.1833\nÁno Sýros;37.4500\nPorto Franco;-6.3378\nTukwila;47.4750\nMundgod;14.9714\nDenderleeuw;50.8833\nBarro;-7.1769\nRomano di Lombardia;45.5167\nBishunpur;26.0868\nChatiā;26.5396\nCajueiro;-9.3967\nHajnówka;52.7333\nMabitac;14.4333\nBaie-Comeau;49.2167\nAlejandro Korn;-34.9667\nGherla;47.0200\nBogandé;12.9667\nSanta Bárbara;5.8747\nRāybāg;16.4800\nDeán Funes;-30.4333\nVillagarzón;1.0294\nSouth Holland;41.5977\nMpwapwa;-6.3500\nWieluń;51.2206\nBlankenberge;51.3000\nSarreguemines;49.1100\nRocky River;41.4702\nCaombo;-8.7000\nParasi;24.1908\nTakaba;3.3963\nParkāl;18.2000\nMiorimivalana;-17.2167\nTerrier Rouge;19.6333\nLa Mornaghia;36.7667\nWang Nam Yen;13.5004\nLivadeiá;38.4333\nParamonga;-10.6744\nPanagyurishte;42.5000\nSidi Rahal;33.4720\nLlorente;11.4125\nSuzzara;44.9927\nManhumirim;-20.3578\nAtchoupa;6.5333\nAspe;38.3456\nVolnovakha;47.5994\nNubl;36.3756\nJuli;-16.2125\nSulphur;30.2286\nAlmaguer;1.9167\nXintian;23.1427\nHojambaz;38.1167\nDarien;41.0798\nEl Paujíl;1.5644\nRyazhsk;53.7000\nRosolini;36.8167\nLa Unión;37.6192\nAnori;-3.7728\nGökdepe;38.1578\nPuerto Natales;-51.7333\nGeneva;41.8833\nEnköping;59.6356\nLoncoche;-39.3667\nRose Hill;38.7872\nKhotkovo;56.2500\nAishō;35.1688\nChāgalamarri;14.9667\nTubbergen;52.4000\nSchramberg;48.2269\nEl Bâzoûrîyé;33.2539\nPrudnik;50.3228\nGivors;45.5906\nElverum;60.8819\nPalatka;60.1000\nHafshejān;32.2269\nBīrpur;25.5209\nChodavaram;17.8333\nMandza;-11.4167\nTarko-Sale;64.9167\nJindřichŭv Hradec;49.1442\nSint-Katelijne-Waver;51.0667\nGalūgāh;36.7272\nMetahāra;8.9000\nNaraura;28.1967\nKutná Hora;49.9483\nSanhe;36.5643\nTraunreut;47.9667\nSecaucus;40.7810\nHoliday;28.1864\nFatehgarh Chūriān;31.8643\nCumaral;4.2694\nOrleães;-28.3589\nCugir;45.8436\nGüimar;28.3150\nNavalpattu;10.7557\nTizi-n-Bechar;36.4311\nMatsuura;33.3333\nSoltau;52.9833\nOrós;-6.2439\nMī’ēso;9.2333\nUrk;52.6667\nSomers;41.3056\nAmbinanindrano;-20.6833\nCournon-d’Auvergne;45.7422\nBan Wat Sala Daeng;13.8097\nLehāra;26.1515\nKaraiyāmpudūr;11.0077\nNorth Salt Lake;40.8439\nMukilteo;47.9096\nLiberty Triangle;29.0760\nSanxing;24.6739\nPio XII;-3.8939\nAígio;38.2500\nGroß-Umstadt;49.8667\nKitcharao;9.4581\nTeteven;42.9167\nSão João;-8.8758\nBloomfield;41.8426\nSan Isidro;10.0299\nItapecerica;-20.4728\nColleferro;41.7333\nLorton;38.6983\nLos Vilos;-31.9167\nCarthage;36.8528\nSestu;39.2994\nRecanati;43.4000\nNarkher;21.4383\nParadise;47.5333\nSessa Aurunca;41.2333\nLakeside;32.8560\nSt. Andrews;34.0510\nUmrāpur;24.5863\nNāgamangala;12.8194\nPompéia;-22.1089\nRonda;10.0003\nSilva Jardim;-22.6508\nPark Forest;41.4817\nBeaune;47.0250\nBad Schwartau;53.9194\nConcepción Huista;15.6167\nSkive;56.5667\nGryfino;53.2531\nConcepción Chiquirichapa;14.8500\nSouth Lake Tahoe;38.9393\nBananeiras;-6.7500\nVaradero;23.1394\nAshland;42.1905\nCoswig;51.1333\nShisui;35.7249\nSchenefeld;53.6028\nKaltan;53.5167\nLubań;51.1181\nMobetsu;44.3564\nGarforth;53.7920\nAralık;39.8728\nGrand Island;43.0198\nLyskovo;56.0289\nMitry-Mory;48.9839\nYouganning;34.7356\nDickinson;29.4548\nBelovodskoe;42.8300\nAsni;31.2500\nLuna;18.3311\nBarcelona;12.8694\nKatākos;25.3339\nAsarganj;25.1500\nDaboh;26.0024\nAkonolinga;3.7667\nOshoba;40.7347\nMatanga;-23.5167\nAlgete;40.5978\nĀdēt;11.2667\nKrishnapur;24.4123\nVillanueva;10.4456\nPuzol;39.6167\nLugait;8.3411\nInjibara;10.9500\nAraripe;-7.2128\nVoiron;45.3642\nJiangjiadong;24.4985\nSilverdale;47.6663\nCarei;47.6839\nTanhaçu;-14.0208\nTraunstein;47.8667\nBruchköbel;50.1833\nSādpur;25.4758\nKattanam;9.1833\nPushchino;54.8333\nMusselburgh;55.9420\nBülach;47.5167\nNerekhta;57.4500\nDupax del Sur;16.2842\nSanta María Chilchotla;18.2333\nManuel Tames;20.1803\nMonte Sião;-22.4328\nVittal;12.7660\nBaldwin;40.3690\nAlfena;41.2381\nConceição de Macabu;-22.0850\nBonito;-21.1333\nHuseni;26.3768\nMonte Santo de Minas;-21.1900\nPalavūr;8.2055\nCranendonck;51.2853\nRio Maior;39.3333\nNizāmpatam;15.9000\nHindang;10.4339\nSelden;40.8714\nMoorestown;39.9784\nAguadas;5.6167\nLucélia;-21.7203\nTimmarāsanāyakkanūr;10.0015\nFierenana;-18.5500\nSan Antonio Sacatepéquez;14.9667\nAdigaratti;11.3357\nErval d’Oeste;-27.1939\nFerentino;41.6833\nBrezno;48.8039\nItororó;-15.1169\nMontecristo;8.2994\nSan Isidro de Lules;-26.9333\nCarrboro;35.9259\nChokkampatti;9.1259\nJagatpur;23.6048\nSan Juan de Río Coco;13.5444\nPeritoró;-4.3828\nVili;12.2833\nGannavaram;16.5333\nShāzand;33.9275\nSadao;6.6386\nHirekerūr;14.4551\nLos Llanos de Aridane;28.6500\nBobonong;-21.9704\nSan Víctor Abajo;19.4500\nBaixa Grande;-11.9600\nWestborough;42.2681\nKomatipoort;-25.4333\nSaponé;12.0528\nSan Salvo;42.0455\nLoanda;-22.9228\nMonroe;41.3043\nGauting;48.0678\nMaraú;-14.1028\nAgan;35.9167\nHancha;37.8572\nCauto Cristo;20.5619\nAnping;39.7034\nVarkaus;62.3167\nSeria;4.6141\nPleasant Prairie;42.5266\nGhatkesar;17.4494\nSeymour;38.9476\nYachiyo;36.1816\nBastos;-21.9167\nBezhetsk;57.7667\nStange;60.6494\nAntanambao;-19.6667\nGardner;42.5845\nDiamantino;-14.4089\nEast Moline;41.5199\nAmbalavato;-22.9667\nLino Lakes;45.1679\nWipperfürth;51.1167\nTsarasaotra;-20.4333\nTittagudi;11.4167\nPalāshi;23.7898\nUxbridge;44.1167\nXinnongcun;42.2357\nOulad Embarek;32.2833\nFlorencia;22.1475\nSuaza;1.9833\nBologoye;57.8833\nAl Brouj;32.5050\nNahorkatiya;27.2891\nAguinaldo;16.9789\nSahamadio;-22.5167\nPraia da Vitória;38.7333\nGoris;39.5078\nLuna;16.9667\nLuisiana;14.1850\nTaperoá;-13.5378\nQuirima;-10.9000\nWelench’ītī;8.6667\nBambalang;5.8867\nCarlos Casares;-35.6167\nEl Calafate;-50.3333\nVillapinzón;5.2167\nSchifferstadt;49.3833\nBrummen;52.0833\nFröndenberg;51.4719\nKaraağaç;36.5667\nChāndpur;25.5059\nSkegness;53.1436\nMariāni;26.6700\nFredonia;5.9167\nHino;35.0180\nDamua;22.1929\nCamanducaia;-22.7550\nVikhorevka;56.1167\nAndolofotsy;-18.7500\nFót;47.6181\nHyde Park;41.8011\nJangy-Nookat;40.2500\nAmpanety;-18.9750\nBohumín;49.9042\nWerdau;50.7333\nMilwaukie;45.4445\nJatāra;25.0096\nFurano;43.3420\nTrecate;45.4333\nAurād;18.2540\nImi n’Oulaoun;31.3094\nAkora;33.9925\nPayson;40.0355\nBahía de Caráquez;-0.6000\nLouisville;39.9710\nCherakhera;25.6869\nKhampat;23.7823\nSidi Taibi;34.1917\nLa Colonia Tovar;10.4056\nEssa;44.2500\nSirnia;25.4903\nSanto Anastácio;-21.9769\nKochas;25.2340\nSotouboua;8.5667\nElektrougli;55.7167\nVyškov;49.2775\nToguchin;55.2333\nZhangjiazhuang;39.7804\nPindobaçu;-10.7428\nPájara;28.3500\nFiadanana;-20.4333\nAlcudia;39.8525\nSaka;34.6167\nŢorqabeh;36.3103\nSteinhagen;52.0050\nEl Retén;10.6167\nSysert;56.5000\nPathrajolhania;26.1369\nAmbohipandrano;-19.1500\nAmbohimanambola;-19.8000\nEsperalvillo;18.8200\nLudlow;42.1921\nPālkonda;18.6000\nChợ Phước Hải;10.4283\nLindenwold;39.8173\nSidi Abdelkader;33.0494\nĀlampālaiyam;11.3635\nCandiac;45.3800\nAndāl;23.6000\nSokal;50.4833\nSitampiky;-16.6667\nBni Rzine;35.0108\nKarianga;-22.4167\nGallipoli;40.0556\nAnkililoaka;-22.7667\nAmbondro;-25.2500\nTsiamalao;-15.0500\nAbano Terme;45.3603\nOro-Medonte;44.5667\nChelak;39.9203\nŽďár nad Sázavou;49.5627\nBanting;5.7167\nClemmons;36.0319\nLiubotyn;49.9489\nSoanindrariny;-19.9000\nReichenbach/Vogtland;50.6167\nLuckenwalde;52.0833\nBugalagrande;4.2167\nPiedra Blanca;18.8438\nPontal do Paraná;-25.5768\nKlaukkala;60.3820\nAmpasimatera;-15.9333\nMorafeno;-15.4833\nZaliohouan;6.7833\nSan José de Jáchal;-30.2333\nOsmaneli;40.3500\nBarki Saria;24.1759\nAz Zuwaytīnah;30.9522\nDudinka;69.4064\nPulicat;13.4161\nTongobory;-23.5167\nPalma del Río;37.7000\nEl Coco;8.8834\nNurota;40.5650\nHualqui;-36.9600\nAlto-Cuilo;-8.2371\nLambari;-21.9758\nCastel San Pietro Terme;44.4000\nRoshal;55.6667\nTeghra English;25.4072\nCacongo;-5.2333\nAnah;34.3722\nXincheng;24.0514\nVarennes;45.6833\nKoskāpur;26.0216\nMerrick;40.6515\nRivalta di Torino;45.0340\nKyaukpyu;19.4264\nArnaud;18.4500\nTorhout;51.0661\nMadre de Deus;-12.7408\nAchampet;16.6299\nEnger;52.1333\nSan Guillermo;16.7244\nBholsar;25.2133\nMössingen;48.4064\nRipley;53.0500\nNördlingen;48.8511\nBanganapalle;15.3167\nNidderau;50.2500\nBussolengo;45.4667\nMae Sai;20.4333\nRangra;25.3803\nDebark’;13.1333\nPedra;-8.5006\nGuará;-20.4283\nÅs;59.6603\nNizhniy Lomov;53.5167\nKāmalāpuram;14.5983\nPurranque;-40.9167\nPunturin;14.7381\nPaldorak;40.4833\nQuela;-9.3833\nOderzo;45.7808\nSonkach;22.9717\nXo‘jaobod;40.6653\nKuknūr;15.4900\nBandar-e Gaz;36.7742\nVeresegyház;47.6505\nOliveira do Hospital;40.3589\nMoniquirá;5.9167\nHarvey;29.8876\nBhainsdehi;21.6449\nNarwar;25.6439\nDillingen;49.3500\nMadukkūr;10.4800\nUpper St. Clair;40.3336\nBaroda;25.5000\nJericho;31.8711\nArarat;39.8303\nBeldaur;25.5947\n’Aïn el Hammam;36.5714\nSánchez;19.2282\nZestaponi;42.1083\nHerborn;50.6825\nVico Equense;40.6667\nSão Vicente Ferrer;-2.8939\nKurovskoye;55.5833\nCercado Abajo;18.7300\nOsa;57.3000\nRio Rico;31.4957\nKamamaung;17.3469\nUbaitaba;-14.3128\nGuácima;9.9613\nWuustwezel;51.3833\nGerlingen;48.8000\nMorauna;26.1706\nChennimalai;11.1638\nSouth Whitehall;40.6154\nWildeshausen;52.9000\nVinany;-19.6167\nSamacá;5.5000\nKremenets;50.1081\nPallazzolo sull’Oglio;45.6000\nYangping;27.7607\nOvejas;9.5000\nPico Truncado;-46.7950\nSchortens;53.5333\nSotomayor;1.4933\nBālugān;19.7333\nEast Pennsboro;40.2886\nBuinsk;54.9667\nGamboma;-1.8764\nWade Hampton;34.8821\nCoquimatlán;19.2038\nLockport;43.1698\nRājgarh;22.6800\nVadamadurai;10.4408\nSultanpur;31.2235\nOzark;37.0365\nHays;38.8821\nHonnāli;14.2399\nPertuis;43.6950\nStrathroy-Caradoc;42.9575\nHorten;59.4208\nBourg-lès-Valence;44.9475\nMakakilo;21.3591\nKolāras;25.2193\nDerinkuyu;38.3736\nMiches;18.9800\nMāvalli;14.1000\nOlenegorsk;68.1500\nValkeakoski;61.2667\nKiseljak;43.9431\nSkanderborg;56.0417\nHexiang;19.5285\nSêrro;-18.6050\nMahināwān;26.0208\nBoussu;50.4331\nAvon;39.7601\nCarcagente;39.1222\nLetlhakane;-21.4167\nBlieskastel;49.2333\nEllamanda;16.1847\nMatheu;-34.3667\nJunqueirópolis;-21.5147\nCarquefou;47.2969\nHaßloch;49.3500\nCapinzal;-27.3439\nCugnaux;43.5378\nHumanes de Madrid;40.2539\nGrayslake;42.3405\nJicomé;19.6500\nKarmana;40.1422\nWachtberg;50.6242\nSamboan;9.5288\nHanmayingcun;41.2636\nWillmar;45.1216\nAomar;36.5000\nFālākāta;26.5300\nCeres;-15.3078\nArchena;38.1150\nHusainpur;31.3387\nFeltre;46.0186\nPacatu;-11.9578\nTamandaré;-8.7600\nDharmkot;30.9456\nUbaíra;-13.2678\nBlaj;46.1753\nMurrysville;40.4456\nArnold;38.4297\nGiovinazzo;41.1833\nPita;11.0800\nFort Walton Beach;30.4255\nKōtekāra;12.7929\nLebedinovka;42.8800\nSuroth;26.8098\nZülpich;50.7000\nBladel;51.3667\nKortenberg;50.8833\nTielt;50.9989\nBuckingham;40.3188\nKihihi;-0.7489\nIno;33.5487\nSivaslı;38.4833\nPolonne;50.1167\nKawayan;11.7000\nVinjamūr;14.8330\nMonte Alegre;-6.0678\nNadikūde;16.5941\nDumbarton;55.9500\nPontassieve;43.7750\nSouth Milwaukee;42.9120\nScobinţi;47.3833\nLastra a Signa;43.7667\nGermantown;43.2343\nSint-Andries;51.2000\nForst (Lausitz);51.7333\nDugulubgey;43.6500\nMedina;-16.2228\nMattigiri;12.6980\nLebanon;39.4254\nGhafurov;40.2200\nSidhapa;26.5355\nTala Yfassene;36.4583\nBruges;44.8828\nArroyo Seco;-33.1667\nGyömrő;47.4250\nParma Heights;41.3865\nIllapel;-31.6333\nSomanya;6.1039\nMougins;43.6000\nBanaue;16.9119\nLuacano;-11.2167\nNova Granada;-20.5339\nSivrihisar;39.4500\nChachahuantla;20.2756\nHarvey;41.6076\nMorrinhos;-3.2289\nDolyna;48.9703\nNa Klang;17.3043\nSultonobod;40.7644\nBlansko;49.3631\nFonte Boa;-2.5139\nBom Jesus;-18.2150\nElvas;38.8667\nPukhrāyān;26.2300\nSenica;48.6806\nMelena del Sur;22.7881\nZhangatas;43.5705\nMoḩammadābād;28.6689\nHernani;43.2667\nIriona;15.9694\nGreen Valley;31.8393\nCartaya;37.2833\nMäntsälä;60.6331\nPueblo Nuevo;13.3797\nCampestre;-21.7108\nQuaregnon;50.4333\nSondiha;24.8950\nXionglin;24.7742\nFoya Tangia;8.2713\nSugaon;26.7317\nMonte Azul;-15.1553\nOkha;53.5889\nStadtlohn;51.9925\nSenapparetti;10.9625\nKātpādi;12.9695\nKekem;5.1667\nYakkabog‘;38.9800\nMeinerzhagen;51.1167\nLagoa do Itaenga;-7.9358\nSapang Dalaga;8.5500\nMénaka;15.9167\nLincolnia;38.8158\nNorth Ogden;41.3123\nPozantı;37.4278\nSabanitas;9.3400\nNootdorp;52.0333\nMead Valley;33.8333\nCaoayan;17.5469\nSidi Chiker;31.7453\nSan Julián;-16.9064\nHörstel;52.2972\nPastores;14.5967\nShimogamo;34.6795\nCittadella;45.6500\nLittle Egg Harbor;39.5969\nMiracema do Tocantins;-9.5669\nCirencester;51.7190\nGaeta;41.2167\nPendembu;8.1000\nBotevgrad;42.9073\nCoolbaugh;41.1837\nHailsham;50.8647\nSenden;51.8572\nRocky Hill;41.6572\nProfesor Salvador Mazza;-22.0500\nArhavi;41.3333\nHelena;33.2837\nSabaudia;41.2998\nSão João de Pirabas;-0.7689\nDuderstadt;51.5125\nWasaga Beach;44.5206\nWare;51.8109\nAdrian;41.8994\nRhenen;51.9667\nLannion;48.7325\nNové Mesto nad Váhom;48.7547\nAlagoa Nova;-7.0473\nPittsburg;37.4129\nNeufahrn bei Freising;48.3159\nMill Creek;47.8631\nChapulhuacán;21.1547\nBagou;10.8147\nEncantado;-29.2358\nBatī;11.1833\nMurphy;33.0186\nHarpālpur;25.2877\nGandujie;35.8908\nDingolfing;48.6333\nBan Tha Pha;13.8437\nBulnes;-36.7333\nMarānchi;25.3544\nBaião;41.1667\nMiandrivazo;-19.5239\nJefferson;41.0003\nSouth St. Paul;44.8877\nSenec;48.2189\nSārangpur;25.7389\nKapay;8.0833\nLubalo;-9.1500\nBilgi;16.3472\nKarlapālem;15.9333\nMường Lay;22.0678\nSuwanee;34.0508\nBeroun;49.9642\nBobrov;51.1000\nCoronado;32.6649\nPohādi;26.0809\nMazinde;-4.8073\nNewmarket;52.2459\nFloreşti;46.7475\nItanhém;-17.1658\nNalua;22.1051\nĀmta;22.5834\nKorntal-Münchingen;48.8306\nSultanhisar;37.8897\nHiddenhausen;52.1667\nGil;30.8469\nAcquaviva delle Fonti;40.9000\nMar’’ina Horka;53.5167\nPak Phanang;8.3538\nMbala;-8.8333\nLibertyville;42.2870\nNishigō;37.1417\nSpennymoor;54.7000\nAlbertville;45.6758\nLa Cañada Flintridge;34.2097\nKawambwa;-9.7914\nMealhada;40.3833\nBhasāwar;27.0361\nCoronel Vivida;-25.9800\nNew Glasgow;45.5926\nCovington;47.3667\nCordeiro;-22.0289\nGorāya;31.1241\nSan Bernardino;-25.3106\nSalvaterra;-0.7528\nLoja;37.1667\nMakhtal;16.5012\nDouar Lamrabih;34.8167\nSidi Jaber;32.3833\nTullahoma;35.3721\nMagsaysay;8.0333\nStation des Essais M.V.A.;34.9352\nSunchales;-30.9333\nEly;52.3981\nAldan;58.6167\nHashtrūd;37.4714\nRyūyō;34.6783\nSpringfield;40.0986\nGjøvik;60.7957\nCasarano;40.0167\nNikolsk;53.7167\nVeroli;41.6833\nHarmanli;41.9333\nDonggou;19.6593\nSamthar;25.8400\nBibai;43.3329\nGioia Tauro;38.4333\nSivagiri;9.3300\nSusaki;33.3925\nRosamond;34.8658\nNew Canaan;41.1592\nBaden;47.4667\nMundra;22.8500\nQagan Us;36.3972\nArsk;56.1000\nAïn Cheggag;33.8833\nHem;50.6553\nTimaná;1.9833\nSan Mauro Torinese;45.1039\nSchwanewede;53.2333\nMarquette;46.5440\nAlatsinainy-Bakaro;-19.3167\nSidney;40.2891\nKurshab;40.6917\nSanrh Majhgawan;24.6845\nRāmchandrapur;23.9208\nNamegawa;36.0660\nMiracatu;-24.2808\nAltônia;-23.8739\nColonia General Felipe Ángeles;23.9167\nWilmot;43.4000\nAcri;39.5000\nBethany;35.5071\nLoutété;-4.2961\nLaboulaye;-34.1167\nRawicz;51.6092\nCaracaraí;1.8158\nTeonthar;24.9821\nBattle Ground;45.7766\nCarmen de Patagones;-40.7833\nBouguenais;47.1775\nKothia;25.7612\nTyrnyauz;43.4000\nPleszew;51.8833\nEruh;37.7497\nWittmund;53.5750\nBayt Ūmmar;31.6214\nBan Patong;7.8931\nKhvānsār;33.2206\nNova Xavantina;-14.6728\nRifādpur;25.2635\nSakae;35.8408\nLetterkenny;54.9566\nChodzież;52.9833\nSacile;45.9667\nBaskil;38.5697\nCinfães;41.1000\nSeydi;39.4167\nTondi;9.7417\nFara;11.5333\nPleasantville;39.3900\nStephenville;32.2147\nYorkville;41.6563\nChandragiri;13.5833\nGostyń;51.8792\nSartalillo;9.9759\nSão Joaquim do Monte;-8.4319\nBecerril;9.7000\nDorchester;50.7154\nBad Waldsee;47.9211\nL’Isle-sur-la-Sorgue;43.9194\nKarlshamn;56.1667\nTobe;33.7492\nGarhshankar;31.2154\nTakanabe;32.1280\nSan Lorenzo;1.5039\nTaşlıçay;39.6333\nMārahra;27.7500\nPuerto Quito;0.1272\nMuzambinho;-21.3758\nUetze;52.4661\nBeforona;-18.9667\nMontalto Uffugo;39.4000\nWest St. Paul;44.9018\nPargi;17.1756\nSnellville;33.8562\nCantanhede;-3.6328\nSan Martín;8.0472\nBhitarwār;25.7922\nFrøyland;58.8308\nBhojpur Jadīd;25.5880\nNguékhokh;14.5128\nSompeta;18.9300\nChepo;9.1700\nKashkar-Kyshtak;40.6200\nCanarana I;-13.5500\nPiove di Sacco;45.2977\nSanta Rita;15.2000\nAnnaberg-Buchholz;50.5800\nTenjo;4.9167\nBelūr;13.1642\nVillefontaine;45.6133\nMirador;-6.3708\nKampong Thum;12.7120\nYpsilanti;42.2440\nPennāgaram;12.1343\nIbirubá;-28.6278\nCarmo do Rio Claro;-20.9731\nKudra;25.0463\nVianen;51.9833\nKanniyākumāri;8.0911\nOstrov;57.3500\nPiñan;8.4822\nBaihar;22.1013\nAkanavāritota;16.5984\nYabayo;5.9500\nKubinka;55.5667\nButiá;-30.1200\nDereli;40.7333\nÇilimli;40.9000\nKuala Pembuang;-3.3871\nFive Corners;45.6883\nEssex;42.0833\nChã Grande;-8.2378\nGhogardīha;26.2799\nMiddle;39.0852\nCruzeiro do Oeste;-23.7850\nTolosa;43.1333\nDurbat;38.5333\nKulpahār;25.3190\nBaza;37.4833\nKhilchipur;24.0394\nLower Southampton;40.1541\nOroville;39.4999\nLa Corredoría;43.3853\nMedina del Campo;41.3000\nReggane;26.7000\nJoão Lisboa;-5.4478\nBryant;34.6152\nMarblehead;42.4992\nConcordia;6.0490\nTerenos;-20.4419\nParelhas;-6.6878\nElko;40.8381\nTilothu;24.8051\nMahājerān-e Kamar;34.0183\nTorrox;36.7500\nZłotów;53.3603\nBirnagar;25.9785\nKissa;7.0333\nOcós;14.5138\nBouansa;-4.2186\nOld Jamestown;38.8394\nHanahan;32.9302\nHuanuni;-18.2900\nJandaia do Sul;-23.6028\nMelzo;45.5000\nMandrosohasina;-19.5833\nVallam;10.7199\nParsāhi Sirsia;26.4676\nNorthfield;44.4550\nBequimão;-2.4489\nDanao;10.0167\nSandwich;41.7137\nĖsanboy;38.0833\nMayluu-Suu;41.2457\nTeculután;14.9877\nKloten;47.4500\nSonhauli;25.5108\nForest Lake;45.2536\nVilla Verde;16.6067\nBourne;41.7233\nKhowrzūq;32.7781\nWilnsdorf;50.8167\nAgoura Hills;34.1510\nEastwood;53.0180\nLe Puy-en-Velay;45.0433\nNhamundá;-2.1858\nMělník;50.3506\nAbaré;-8.7208\nSão José de Piranhas;-7.1208\nTsotsin-Yurt;43.2419\nRosas;42.2633\nOberkirch;48.5333\nCuité;-6.4850\nPiqua;40.1506\nAguas Zarcas;10.4223\nDepālpur;22.8509\nMonroe;41.9155\nLohur;38.3833\nValença do Piauí;-6.4078\nEncruzilhada;-15.5308\nSátiro Dias;-11.6000\nGreiz;50.6547\nMirfield;53.6807\nDan Gorayo;8.7278\nCardedeu;41.6406\nSão José do Rio Preto;-22.1508\nDonauwörth;48.7000\nLonār;19.9800\nLuperón;19.9000\nCabra;37.4667\nAbhayāpuri;26.3225\nNambūru;16.3600\nRumoi;43.9410\nHatvan;47.6681\nFarāshband;28.8714\nAtescatempa;14.1750\nOrvieto;42.7183\nSanta Rosa;-26.8667\nHirokawa;33.2415\nSelendi;38.7444\nItaiópolis;-26.3358\nMarneuli;41.4969\nJdour;32.1269\nSiripur;26.7336\nAzacualpa;15.3667\nPainesville;41.7240\nComăneşti;46.4297\nKyakhta;50.3500\nUrussanga;-28.5178\nJirkov;50.4999\nBamumkumbit;5.8167\nLeinefelde;51.3833\nCrest Hill;41.5723\nRajaudha;26.7046\nNāri Bhadaun;26.0065\nConcarneau;47.8753\nVilla Hidalgo;21.6762\nLichtenfels;50.1333\nRosedale;39.3266\nParaguaçu;-21.5331\nSergach;55.5333\nPorto Real do Colégio;-10.1858\nBethel;41.3747\nSimití;7.9667\nNeustrelitz;53.3647\nBīrpur;25.5181\nGlassboro;39.7014\nSmørumnedre;55.7333\nRovira;4.2500\nSherwood;45.3594\nEast Northport;40.8791\nOgden;43.1646\nLimerick;40.2323\nHakui;36.8936\nÁgua Branca;-9.2608\nHuanímaro;20.3675\nMinturno;41.2667\nDiguapo;25.6988\nSbeitla;35.2297\nQuissamã;-22.1069\nTepetlixpa;19.0006\nVoyenno-Antonovka;42.8722\nNáchod;50.4167\nBelém de São Francisco;-8.7578\nTelwa;25.8796\nSimri;25.6405\nShīrūru;13.9080\nLalín;42.6500\nAgarpur;25.1957\nPujehun;7.3506\nStebnyk;49.3000\nDel Carmen;9.8690\nAnicuns;-16.4608\nRequena;39.4861\nPedro Carbo;-1.8333\nTorgau;51.5603\nHaren;53.1667\nBella Vista;15.6167\nEdam;52.5167\nBrandýs nad Labem-Stará Boleslav;50.1894\nTsararafa;-22.7333\nCahors;44.4475\nRāmjībanpur;22.8300\nZossen;52.2167\nAcqui Terme;44.6761\nGoole;53.6992\nViadana;44.9267\nParnamirim;-8.0908\nPuerto Viejo;10.5737\nCruz Grande;16.7333\nBoromo;11.7500\nPerry;32.4720\nDračevo;41.9367\nAbrīsham;32.5550\nHolzminden;51.8297\nErragondapālem;16.0397\nYeniseysk;58.4667\nBideford;51.0160\nSchopfheim;47.6500\nRío Grande;19.7300\nKākdwīp;21.8791\nPāmūru;15.0944\nSukhāsan;25.4944\nMálaga;6.7833\nBichena;10.4500\nKleppe;58.7772\nCelorico de Basto;41.3833\nVīrarājendrapet;12.1964\nKęty;49.9000\nBhīkhi;30.0700\nOtegen Batyr;43.3333\nSaco;43.5390\nTelgte;51.9819\nQorasuv;40.7222\nGiengen an der Brenz;48.6217\nAmpefy;-19.0419\nBekatra Maromiandra;-22.1000\nHazlet;40.4265\nKannod;22.6676\nTaquarana;-9.6450\nPikalëvo;59.5333\nEl Viso del Alcor;37.3833\nMarion Oaks;29.0011\nImouzzer Kandar;33.7300\nBara Malehra;24.5681\nWhitpain;40.1578\nIvoti;-29.5908\nChipiona;36.7333\nIrlam;53.4450\nKotelnikovo;47.6333\nBothell West;47.8056\nPlainview;34.1911\nSnina;48.9881\nSão Luís Gonzaga do Maranhão;-4.3800\nAyaviri;-14.8818\nFrontino;6.7833\nToprakkale;37.0669\nAntsampandrano;-19.5333\nFoley;30.3983\nKuala Lipis;4.1800\nHeusenstamm;50.0500\nBaragoi;1.7833\nManaratsandry;-16.1833\nThimiri;12.8283\nPerdões;-21.0908\nSatsuma;31.9057\nHuércal-Overa;37.3833\nFort St. John;56.2465\nWeesp;52.3000\nMithi;24.7333\nSesheke;-17.4667\nUruçuí;-7.2333\nSaint-Dié-des-Vosges;48.2842\nNaaldwijk;51.9931\nKfar Kiddé;34.2028\nHaka;22.9833\nGuding;26.4876\nParaibano;-6.4328\nLancing;50.8320\nJāmbai;11.4678\nYuancun;27.4540\nJiangjiehe;27.2618\nLa Chapelle-sur-Erdre;47.2989\nJasidih;24.5138\nPattamadai;8.6726\nPlaisance-du-Touch;43.5656\nAraruna;-6.5578\nVillabate;38.0833\nMahaditra;-21.7500\nSangīn;32.0733\nDagohoy;9.9167\nSchilde;51.2333\nKürten;51.0500\nFukagawa;43.7233\nUdalguri;26.7537\nClifton;39.0764\nBhulwāl;32.8094\nDicholi;15.5932\nNaranjos;21.3472\nMairi;-11.7108\n’Ali Ben Sliman;31.9100\nSan Martín de la Vega;40.2094\nPalm Valley;30.2011\nMoaña;42.2833\nMayfield Heights;41.5174\nUetersen;53.6872\nNkoteng;4.5167\nAquidabã;-10.2833\nNesoddtangen;59.8086\nBerlin;41.6114\nAnagé;-14.6119\nŞiran;40.1894\nTolú Viejo;9.4500\nShāhpur;25.6029\nArtik;40.6172\nItarantim;-15.6600\nMölln;53.6269\nAmbatosoratra;-17.6167\nGuapiaçu;-20.7950\nMontrose;38.4689\nPeshtera;42.0333\nAdel;53.8489\nSan Marcos;14.4000\nEl Mansouria;33.7500\nFaversham;51.3177\nIssaba;7.0833\nVasiana;-19.6333\nMandiavato;-19.0833\nGuaymango;13.7500\nSlobozia;46.7333\nCallosa de Segura;38.1225\nKwinana;-32.2394\nMontgomery;41.7237\nZhaodianzi;39.9373\nMakurazaki;31.2728\nCastillo de Teayo;20.7500\nCassano d’Adda;45.5333\nOchtrup;52.2056\nPadre Las Casas;18.7333\nGlinde;53.5406\nKébémer;15.3667\nMohiuddinnagar;25.5737\nTsarabaria;-13.7500\nShirahama;33.6781\nWestbrook;43.6954\nBachi-Yurt;43.2242\nZhosaly;45.4893\nZverevo;48.0200\nSilla;39.3618\nNārāyankher;18.0333\nZwijndrecht;51.2167\nShenandoah;30.4019\nLiancourt;19.1356\nL’Assomption;45.8333\nNejo;9.5000\nBan Tha Kham;9.1058\nShakhunya;57.6667\nAlagir;43.0333\nKanekallu;14.8864\nKrasnohrad;49.3719\nShōnai;38.8499\nSoavina Antanety;-19.8000\nCarmo do Cajuru;-20.1839\nMalabuyoc;9.6500\nTarhzirt;32.4333\nAltagracia;11.5672\nTiruvādi;10.8805\nSāmalāpuram;11.0724\nBenicasim;40.0553\nYumbel;-37.1333\nPuerto Leguízamo;-0.1939\nAtlapexco;21.0042\nValderrama;11.0036\nCaridade;-4.2319\nSouth Burlington;44.4622\nGolden;39.7406\nFrankfort;41.4892\nNīlgiri;21.6466\nCarira;-10.3581\nHässleholm;56.1667\nHudson;42.3887\nLa Esmeralda;3.1739\nCasamassima;40.9500\nRantabe;-15.7000\nAmbalakirajy;-15.8333\nCanto do Buriti;-8.1100\nAnalapatsy;-24.2500\nMidalam;8.2167\nBan Tha Ton;20.0608\nMesquite;36.8032\nAmpasimena;-24.3667\nTrostyanets’;50.4811\nHaya;18.3461\nBulolo;-7.2000\nAndirá;-23.0508\nGiszowiec;50.2333\nEl Arenal;20.7754\nJubbah;28.0200\nKāmākhyānagar;20.9338\nWhitehall;39.9682\nZemio;5.0333\nCalatayud;41.3500\nNykøbing Falster;54.7654\nEast Hemet;33.7301\nCartavio;-7.8833\nEmet;39.3333\nTörökszentmiklós;47.1833\nGebre Guracha;9.8000\nRohār;25.9917\nTettnang;47.6708\nEnnigerloh;51.8367\nCeglie Messapico;40.6500\nHad Zraqtane;31.4500\nImperial;32.8390\nUsman;52.0500\nNorth Liberty;41.7438\nJhalidā;23.3654\nMulundo;7.9333\nLeek;53.1667\nWorld Golf Village;29.9654\nSīāhkal;37.1528\nMangualde;40.6042\nSleaford;52.9960\nPlattsburgh;44.6951\nWenden;50.9667\nUruburetama;-3.6250\nHauppauge;40.8211\nAït Tamlil;31.4800\nTomaszów Lubelski;50.4500\nXiaqiaotou;27.2167\nCoruche;38.9569\nQuatro Barras;-25.3658\nOlten;47.3500\nBressuire;46.8400\nRovato;45.5670\nEl Paraíso;15.0167\nMorlanwelz-Mariemont;50.4500\nNeviges;51.3128\nLiuliang;35.2695\nSalsomaggiore Terme;44.8148\nRolla;37.9459\nSão João Batista;-2.9550\nDoany;-14.3667\nSan Miguel;7.6500\nAllanridge;-27.7544\nPoperinge;50.8547\nBlankenburg;51.7953\nPecan Grove;29.6235\nMathurāpur;25.5112\nQuepos;9.4571\nEnnis;32.3254\nÄänekoski;62.6000\nGázi;35.3250\nVolketswil;47.3906\nForest Park;39.2861\nKomárom;47.7403\nMapai;-22.7306\nOregon;41.6524\nSand Springs;36.1353\nPoshkent;39.8833\nPradópolis;-21.3594\nBa;-17.5333\nOzorków;51.9667\nUtebo;41.7141\nWaldbröl;50.8789\nComapa;19.1667\nHasanparti;18.0681\nAmorebieta;43.2192\nBan Na San;8.7997\nHanumana;24.7789\nSchmalkalden;50.7167\nPortland;27.8942\nEschwege;51.1881\nKittūr;15.6000\nMajor Isidoro;-9.5319\nLebbeke;51.0000\nYosano;35.5653\nVīrapāndi;9.9633\nOs;60.2269\nSigna;43.7833\nBrandsen;-35.1667\nNottuln;51.9278\nSpoltore;42.4550\nNizhnyaya Tura;58.6208\nTevāram;9.8967\nDęblin;51.5667\nMokena;41.5327\nShafter;35.4794\nIdhnā;31.5586\nHamina;60.5667\nPrunedale;36.8064\nCastilho;-20.8722\nSantiago;17.2947\nSan Miguel;11.2942\nSaint-Lazare;45.4000\nKūysinjaq;36.0833\nPort Angeles;48.1141\nKinston;35.2747\nChestermere;51.0500\nLīkak;30.8950\nCampamento;14.5500\nSanto Amaro da Imperatriz;-27.6878\nJaggampeta;17.1833\nMonroe;47.8595\nMiamisburg;39.6322\nEl Castillo de La Concepción;11.0444\nSarstedt;52.2394\nCognac;45.6958\nSaint-Lô;49.1144\nNīlambūr;11.0590\nSalangaippālaiyam;11.4260\nCajolá;14.9252\nSinacaban;8.2854\nCarlisle;40.2000\nPichor;25.1756\nGubakha;58.8706\nSouthbury;41.4745\nAtarfe;37.2229\nCastellana Grotte;40.8833\nAriccia;41.7167\nKuusankoski;60.9083\nMihona;26.2837\nVolokolamsk;56.0333\nCantagalo;-21.9808\nForest Park;33.6209\nArcore;45.6333\nPuerto Armuelles;8.2833\nNosy Varika;-20.5833\nQuartier Morin;19.7000\nMustang;35.3917\nPiratini;-31.4478\nBhawānīpur;26.4361\nBuşrá ash Shām;32.5167\nBarroso;-21.1869\nYstrad Mynach;51.6419\nEchizen;35.9742\nRanbīrsinghpura;32.6079\nAlhandra;-7.3504\nSil-li;39.4880\nArlington;48.1701\nPescia;43.9017\nCoaraci;-14.6408\nNogales;31.3624\nMassy;41.0608\nHoward;44.5703\nKitatajima;35.9821\nLiuguang;26.9970\nBroadview Heights;41.3196\nMasterton;-40.9700\nMaple Shade;39.9520\nHuntsville;45.3333\nAgryz;56.5219\nBurghausen;48.1667\nBieruń;50.1333\nSalmon Creek;45.7099\nSulzbach-Rosenberg;49.5000\nGuantiankan;28.2966\nLake Zurich;42.1956\nCorner Brook;48.9287\nSt. John;41.4429\nCasa de Oro-Mount Helix;32.7640\nÇekerek;40.0731\nAd Dir‘īyah;24.7333\nZaouïa Aït Ishak;32.7600\nDillingen;48.5667\nPaulistana;-8.1439\nTingloy;13.6500\nMandaguaçu;-23.3469\nMosopa;-24.7792\nGrumo Nevano;40.9333\nSélestat;48.2594\nDesavilakku;11.6476\nNyandoma;61.6667\nKarcag;47.3111\nAlpinópolis;-20.8639\nWestminster;39.5796\nMaḩmūdābād Nemūneh;36.2886\nSimonésia;-20.1239\nPichidegua;-34.3586\nJnane Bouih;32.0308\nMickleover;52.9010\nKaruizawa;36.3484\nĀsasa;7.1000\nKatangi;21.7737\nArbaoun;36.4667\nEnkhuizen;52.7000\nCalvillo;21.8500\nMenzel Abderhaman;37.2300\nCarate Brianza;45.7667\nItatinga;-23.1017\nBrie-Comte-Robert;48.6925\nLower Allen;40.2082\nLakhna;25.4532\nMoosburg;48.4667\nNarsāpur;17.7374\nMarsberg;51.4500\nTrzebinia;50.1667\nPunjai Puliyampatti;11.3516\nCasalgrande;44.5833\nCulpeper;38.4704\nTradate;45.7000\nRegente Feijó;-22.2208\nWanluan;22.5727\nBorna;51.1167\nVárpalota;47.1989\nRío Segundo;-31.6501\nWittlich;49.9869\nVazante;-17.9869\nOschersleben;52.0167\nHongshui;38.5077\nTaketa;32.9667\nAndaingo Gara;-18.2000\nAyyāmpettai;10.8971\nLuénoufla;7.0667\nRybnoye;54.7333\nSuárez;2.9589\nTash-Kömür;41.3500\nPolonuevo;10.7833\nColotlán;22.1000\nHomewood;41.5591\nMeise;50.9333\nEupen;50.6333\nTalwandi Bhai;30.8558\nBabanūsah;11.3333\nStroud;41.0001\nKufstein;47.5833\nShelbyville;39.5352\nComodoro;-13.6593\nChopinzinho;-25.8558\nPuerto El Triunfo;13.2833\nDoujing;26.4789\nLackawanna;42.8182\nLieto;60.5000\nBan Bueng;13.3142\nCiriè;45.2353\nSanta Teresita;18.2519\nRhar el Melah;37.1667\nUrumita;10.5667\nAnguillara Sabazia;42.0833\nNakło nad Notecią;53.1403\nEnglewood;26.9717\nBad Tölz;47.7603\nDharmsāla;32.2153\nUniversal City;29.5521\nŽiar nad Hronom;48.5842\nSarsāwa;30.0160\nOulad Salmane;34.3356\nJakobstad;63.6667\nPôrto Grande;0.7128\nYuanhucun;44.1977\nSomeren;51.3833\nGilching;48.1103\nCabusao;13.7275\nMayen;50.3333\nRiverview;46.0613\nKonstantynów Łódzki;51.7500\nDurağan;41.4167\nArbutus;39.2428\nHolden;42.3561\nTīrthahalli;13.6884\nLajinha;-20.1508\nMajhua;26.0140\nBarreira;-4.2869\nTirmitine;36.6618\nYahotyn;50.2569\nCapoeiras;-8.7350\nAit Bousarane;31.7917\nAndrychów;49.8550\nHushihacun;40.8899\nKopa;25.8513\nWeil der Stadt;48.7508\nWaxhaw;34.9363\nPrichard;30.7735\nLloydminster;53.2807\nPugo;16.2833\nAlamo;26.1810\nGunri;25.6408\nVenadillo;4.7500\nRizal;17.5000\nWest Mifflin;40.3581\nKeszthely;46.7696\nIndargarh;25.9109\nJagalūr;14.5196\nEersel;51.3500\nKasba Maker;25.9591\nManjathala;11.3624\nMalacky;48.4358\nKalghatgi;15.1832\nRāwah;34.4686\nRanst;51.2000\nAlzey;49.7458\nMiddelkerke;51.1847\nMonte Alegre de Minas;-18.8708\nCherepanovo;54.2333\nOkhmalynka;47.5333\nNanuet;41.0957\nUtinga;-12.0819\nSint-Gillis-Waas;51.2167\nSparta;41.0486\nJoliette;46.0167\nMogiyon;39.2500\nStaveley;53.2694\nTublay;16.4764\nBan Thap Kwang;14.6103\nMidway;30.4169\nAtasū;48.6903\nBückeburg;52.2608\nLodhwe;24.6404\nTolentino;43.2086\nHechingen;48.3517\nDiinsoor;2.4106\nAnsermanuevo;4.8000\nRožňava;48.6583\nKhamaria;23.2129\nDāchepalle;16.6000\nCrespo;-32.0333\nAdria;45.0500\nPalera;25.0201\nRiom;45.8936\nKolbermoor;47.8500\nDiepenbeek;50.9072\nNocatee;30.0927\nXapuri;-10.6519\nYershov;51.3500\nEngelskirchen;50.9833\nHeinola;61.2000\nCapela do Alto;-23.4706\nMeerssen;50.8858\nBad Pyrmont;51.9867\nBad Aibling;47.8667\nEl Arahal;37.2667\nHemmingen;52.3236\nCaraúbas;-5.7928\nPidhorodne;48.5737\nCandelaria;22.7439\nAcıgöl;38.5500\nJasien;54.3399\nSokołów Podlaski;52.4000\nJājarm;36.9500\nPastrana;11.1333\nRhede;51.8333\nAysha;10.7500\nGarot;24.3234\nItuzaingó;-27.6000\nBuruanga;11.8438\nMeadowbrook;37.4301\nStowmarket;52.1900\nHoxut;42.2552\nPuerto Morelos;20.8536\nAltamont;42.1980\nYellowknife;62.4709\nIbicoara;-13.4108\nArvin;35.1944\nEssen;51.4667\nMonkseaton;55.0430\nOtsego;45.2660\nFukusaki;34.9503\nXihuangcun;37.1411\nSão João do Piauí;-8.3578\nHaiger;50.7422\nTöle Bī;43.6768\nSão Gabriel;-11.2289\nWaterford;41.3692\nSiruma;14.0219\nHunters Creek;28.3610\nBagaces;10.5157\nRolante;-29.6508\nValle Vista;33.7436\nThamaga;-24.7167\nTerek;43.4833\nAradíppou;34.9478\nBeloyarskiy;63.7167\nAshland;40.8668\nIbigawa;35.4873\nGrafton;42.2085\nWest Whiteland;40.0227\nBābai;22.7026\nSjöbo;55.6333\nBruz;48.0247\nMadisonville;37.3409\nCervantes;16.9917\nSeesen;51.8931\nKumārapuram;8.2922\nValavanūr;11.9205\nRadeberg;51.1167\nMüllheim;47.8000\nStevenson Ranch;34.3894\nSomandepalle;14.0078\nRio Verde de Mato Grosso;-18.9178\nCapinota;-17.7150\nYusufeli;40.8106\nSirvār;16.1739\nBad Berleburg;51.0497\nSquamish;49.7017\nKempston;52.1140\nPułtusk;52.7000\nWarrensburg;38.7627\nJesús María;20.6068\nTeminabuan;-1.4333\nTraiskirchen;48.0189\nErlanger;39.0109\nEspiritu;17.9806\nMarihatag;8.8008\nChinna Ganjām;15.6930\nRegensdorf;47.4333\nWhitemarsh;40.1040\nHurricane;37.1487\nPūranpur;28.5200\nHeishanzuicun;41.0354\nLos Álamos;-37.6272\nAlcoy;9.7082\nBužim;45.0500\nOrinda;37.8808\nHoltsville;40.8124\nSorada;19.7608\nLa Nucía;38.6172\nArdon;43.1833\nHoveyzeh;31.4619\nMagitang;35.9386\nEcht;51.1000\nGogogogo;-24.2667\nPalamós;41.8458\nGōdo;35.4174\nJiabong;11.7625\nYandrapalle;15.9062\nKantharalak;14.6536\nHeishuikeng;37.7905\nYumurtalık;36.7678\nRamsbottom;53.6484\nTadian;16.9961\nEast Dereham;52.6810\nŁańcut;50.0667\nKāveripatnam;12.4219\nDouar Ait Sidi Daoud;31.6345\nVila Real de Santo António;37.1939\nKushiro;42.9961\nBinka;21.0263\nVellmar;51.3500\nPozzallo;36.7303\nLodeynoye Pole;60.7167\nSipoo;60.3764\nSorgues;44.0083\nTime;58.7228\nSchwalmtal;51.2225\nDhānsāria;24.6400\nWervik;50.7797\nRoyan;45.6231\nBan Fang Tuen;19.5497\nLake Forest;42.2380\nOnga;33.8479\nFécamp;49.7575\nRivière-du-Loup;47.8333\nPariquera-Açu;-24.7150\nPerūru;14.3500\nQuixeré;-5.0739\nAlbolote;37.2306\nTirunāgeswaram;10.9646\nSalgado;-11.0319\nChiari;45.5197\nDashtigulho;37.7000\nStarodub;52.5833\nSirālkoppa;14.3807\nCobourg;43.9667\nDruten;51.8833\nLa Paz;10.8911\nParaisópolis;-22.5539\nEast St. Louis;38.6155\nDalanzadgad;43.5700\nSan Antonio Huista;15.6500\nTangbian;25.6539\nHolalkere;14.0429\nMino;35.5448\nSrikhanda;23.5984\nBarhampur;25.5976\nNārapala;14.7206\nLynn Haven;30.2337\nKoropí;37.9000\nVence;43.7225\nRiachão do Dantas;-11.0689\nItuaçu;-13.8128\nKapangan;16.5764\nScorzè;45.5719\nPurushottampur;19.5202\nMingjiujie;23.4558\nAngleton;29.1721\nFrutillar Alto;-41.1228\nIzra;32.8454\nKrasnystaw;50.9833\nRayevskiy;54.0658\nCabildo;-32.4275\nKamiichi;36.6984\nWassenberg;51.1000\nTajerouine;35.8833\nCocos;-14.1839\nMotru;44.8036\nMakronia;23.8476\nStabroek;51.3333\nMontemurlo;43.9333\nHalstenbek;53.6334\nLake Shore;39.1030\nBādkulla;23.2800\nJuquiá;-24.3208\nBalta;47.9361\nAmbatomirahavavy;-18.9333\nSan Vito dei Normanni;40.6556\nPauini;-7.7139\nChilkūru;16.9611\nMonte Azul Paulista;-20.9072\nSukhsena;25.7952\nParanapanema;-23.3886\nIiyama;36.8516\nBrigham City;41.5035\nMukaiengaru;44.0621\nPfullingen;48.4656\nChautāpal;17.2508\nBuerarema;-14.9589\nHaldensleben;52.2833\nMarchena;37.3333\nBagahi;26.7632\nKrasnogorskiy;41.1542\nHardinxveld-Giessendam;51.8167\nBurscheid;51.1000\nRaita;32.5495\nKhonj;27.8914\nBracciano;42.1000\nBergneustadt;51.0333\nTibagi;-24.5089\nNarni;42.5167\nAlmel;16.9200\nSebt Gzoula;32.1167\nLexington;35.8018\nSyosset;40.8157\nVenceslau Brás;-23.8739\nHidrolândia;-4.4078\nAltoona;41.6483\nDiadi;16.6600\nGuru Har Sahāi;30.7086\nTexcaltitlán;18.9297\nLiberal;37.0466\nAthār;26.0392\nAci Sant’Antonio;37.6000\nZerong;24.9692\nChaita;25.7671\nHaslett;42.7525\nKānp;25.8337\nĀbomsa;8.5833\nTaka;35.0503\nCampina Verde;-19.5358\nBouanri;10.2000\nOrange;30.1226\nKorsholm;63.1125\nHorseheads;42.1625\nKhetia;21.6712\nBan Mae Hia Nai;18.7433\nMonção;42.0733\nSidi Redouane;34.6833\nTapejara;-28.0678\nKirovgrad;57.4350\nSoure;40.0500\nKoppal;15.3500\nLebedyan;53.0167\nKralupy nad Vltavou;50.2411\nMâncio Lima;-7.6139\nHorizontina;-27.6258\nCutlerville;42.8403\nAgliana;43.9000\nSchkeuditz;51.4000\nKronberg;50.1833\nSanta Marinella;42.0333\nDumri;25.5356\nQandala;11.4711\nAtok;16.6272\nBan Mae Kha Tai;18.7433\nHenichesk;46.1667\nDolynska;48.1111\nMarechal Taumaturgo;-8.9408\nBakal;54.9333\nGroesbeek;51.7833\nSöğüt;40.0186\nLebach;49.4100\nMohana;25.9027\nShāhgarh;24.3137\nVohimasy;-22.1000\nSiroda;15.3292\nCorbetta;45.4667\nPahārpur;25.5681\nTsumeb;-19.2500\nAmpataka;-23.3500\nZachary;30.6643\nÇal;38.0836\nBan Mon Pin;19.9168\nPüttlingen;49.2833\nAmboanana;-19.1500\nÁguas Formosas;-17.0819\nNorton;41.9640\nLa Crau;43.1497\nShovot;41.6500\nLgov;51.6667\nSömmerda;51.1617\nQuitandinha;-25.8719\nGātāda;18.2844\nKamatgi;16.1190\nRāmpur Tilak;25.8513\nGülağaç;38.3956\nHuércal de Almería;36.8833\nCranbrook;49.5097\nŽatec;50.3273\nNakhl-e Taqī;27.5014\nLede;50.9667\nAroeiras;-7.5450\nKabūdarāhang;35.2083\nHochheim am Main;50.0167\nRāmpur;26.4424\nIsmailpur;25.3113\nNoci;40.8000\nStillwater;45.0573\nKottakota;17.7513\nJalakandāpuram;11.6986\nKīlmangalam;10.0933\nTorredembarra;41.1457\nAbdulino;53.6667\nFerguson;40.7432\nBandar-e Kong;26.5992\nKaria Ba Mohamed;34.3667\nJúlio de Castilhos;-29.2269\nDolný Kubín;49.2106\nJamiltepec;16.2783\nRizal;17.8478\nNova Olímpia;-14.7969\nPunta Gorda;26.8941\nMeylan;45.2086\nPokaran;26.9194\nDeerfield;42.1654\nBadger;64.8006\nSeminole;27.8435\nRiacho das Almas;-8.1339\nTwinsburg;41.3220\nUzhur;55.3175\nBhagabānpur;24.7765\nOberasbach;49.4219\nHindoria;23.9035\nLa Unión;5.9736\nGomīshān;37.0717\nEllensburg;46.9999\nLa Eliana;39.5661\nLumphat;13.5070\nAinan;32.9667\nWallingford Center;41.4499\nMure;34.3376\nMount Eliza;-38.1890\nForio;40.7333\nLouviers;49.2153\nNavraftor;37.7333\nGriffith;-34.2900\nRurrenabaque;-14.4422\nAntas;-10.4000\nBoiro;42.6500\nNaantali;60.4667\nHuehuetla;20.1075\nMarwa;25.3994\nCarambeí;-24.9178\nValenza;45.0140\nBredene;51.2336\nSukumo;32.9333\nKalmthout;51.3833\nVera;-29.4667\nNaples;26.1504\nLumberton;34.6312\nMaracaçumé;-2.0428\nPalmi;38.3667\nKaruppur;11.7170\nDadeldhurā;29.3000\nAberdeen;40.4165\nCuquío;20.9275\nSan Teodoro;13.4358\nVargem Alta;-20.6708\nTazishan;41.0937\nTora;21.3262\nVilavūr;8.2669\nClaremore;36.3146\nẤp Khánh Hưng;10.2000\nTak Bai;6.2592\nToshloq;40.4808\nPastavy;55.1167\nBad Driburg;51.7333\nLa Ligua;-32.4500\nAit Ben Daoudi;31.6345\nDiamante;-32.0667\nCastelfidardo;43.4642\nFive Forks;34.8069\nEl Rosal;4.8519\nLumbayanague;7.7833\nAporá;-11.6600\nMaitland;28.6295\nArita;33.2106\nIfanirea;-22.1833\nTlalnelhuayocan;19.5667\nRaisāri;26.1319\nNanthankulam;8.3331\nAkune;32.0167\nKurumbapālaiyam;11.1053\nAizumisato;37.4649\nWest Manchester;39.9456\nCerqueira César;-23.0356\nSanta Ana Jilotzingo;19.5333\nKasterlee;51.2500\nShichigahama;38.3045\nHermiston;45.8326\nLakshmaneswaram;16.4082\nVarzelândia;-15.7008\nShemonaīkha;50.6269\nNikolayevsk-na-Amure;53.1333\nLonderzeel;51.0000\nNayāgarh;20.1288\nMoissy-Cramayel;48.6261\nAshkezar;32.0006\nValle;-2.9500\nMoreni;44.9803\nBanni;25.4692\nMalanday;14.7194\nFond des Blancs;18.2833\nWhite Oak;39.2106\nÁguas de Lindóia;-22.4758\nEiheiji;36.0922\nRanomena;-23.4167\nLunéville;48.5894\nAchocalla;-16.5833\nAmares;41.6167\nDianópolis;-11.6258\nBeaconsfield;45.4333\nAmbodinonoka;-20.9833\nNanjanād;11.3669\nAbdurahmoni Jomí;37.9458\nBình Minh;10.0961\nViradouro;-20.8728\nBarhampur;26.3023\nIxtlahuacán del Río;20.8667\nBan Na Yang;12.8339\nBuriti dos Lopes;-3.1750\nSint-Genesius-Rode;50.7450\nPalma Campania;40.8667\nPaillaco;-40.0667\nSendamaram;9.0648\nSilvânia;-16.6589\nInajá;-8.9030\nSartell;45.6188\nBallincollig;51.8879\nMumbwa;-14.9853\nJadcherla;16.7667\nBezaha;-23.5000\nShirin;40.2269\nXinhua;37.8286\nSan Gabriel;16.6667\nMalimono;9.6183\nPreakness;40.9382\nShimomura;36.0696\nSaugerties;42.0891\nMahazoarivo;-22.3167\nTelpaneca;13.5319\nValenzano;41.0500\nGostynin;52.4167\nRawmarsh;53.4636\nPréveza;38.9500\nMaumelle;34.8522\nHazorasp;41.3167\nTârgu Neamţ;47.2025\nLakhnādon;22.6005\nCabaceiras do Paraguaçu;-12.5358\nZuidhorn;53.2500\nUmburanas;-10.7328\nPinole;37.9931\nSilver Spring;40.2503\nAnjahabe;-16.3667\nAkureyri;65.6833\nMiarinavaratra;-20.2167\nSpringwater;44.4333\nCofradía;15.4168\nDuero;9.7167\nTinton Falls;40.2708\nGuernica y Luno;43.3167\nKosatarosh;39.4000\nHaaltert;50.9000\nAmbalanirana;-18.7500\nTanambe;-17.3667\nNova Petrópolis;-29.3758\nKalugumalai;9.1494\nPruzhany;52.5567\nMatteson;41.5095\nCaowotan;37.2739\nSantander;9.4500\nProletarsk;46.7000\nManantenina;-24.2833\nBelamoty;-23.5500\nSchneverdingen;53.1167\nBajo Boquete;8.7800\nEl Bolsón;-41.9667\nBronte;37.7833\nDixon;38.4469\nArcata;40.8615\nAlsip;41.6701\nDankov;53.2500\nMartigny;46.1000\nBukungu;1.4361\nPitseng;-29.0097\nMill Hill;51.6200\nOnega;63.9167\nAmbatomena;-19.8500\nCumberland;39.6515\nRenningen;48.7661\nGhedi;45.4020\nOirschot;51.5000\nSan Rafael La Independencia;15.7167\nPeduasi;5.8500\nAburi;5.8500\nDevadānappatti;10.1467\nAmbatosia;-14.6667\nEitorf;50.7697\nKhokha;25.9741\nCaconde;-21.5289\nMidlothian;37.4856\nScituate;42.1992\nShimanovsk;52.0000\nCortes;9.7167\nDŭstí;37.3486\nBefandriana Atsimo;-22.1000\nBeshkent Shahri;38.8167\nUwchlan;40.0522\nHaukipudas;65.1833\nHeerde;52.3833\nLaukaa;62.4167\nTiruvadamarudūr;10.9065\nMitsinjo;-16.0000\nSan Sebastián Salitrillo;13.9500\nBeni Zouli;30.4839\nStord;59.8081\nBánovce nad Bebravou;48.7186\nOdžak;45.0106\nWarwick;40.1558\nKamienna Góra;50.7833\nHeanor;53.0140\nLas Terrenas;19.3200\nWodonga;-36.1214\nAci Castello;37.5556\nWinchester;38.0018\nSylvania;41.7100\nRibera;37.4994\nRizal;14.1083\nZola Predosa;44.4883\nVitré;48.1233\nMotomachi;43.8242\nSebaste;11.5901\nChichiriviche;10.9343\nChorozinho;-4.3000\nRaghunāthpur;25.8440\nDorval;45.4500\nPrenzlau;53.3167\nQitai;41.5494\nJiaoxiyakou;26.1274\nAvion;50.4097\nRāzole;16.4761\nKorsimoro;12.8250\nAltamira;19.6667\nNal Khera;23.8357\nAjacuba;20.0833\nQo’shko’pir;41.5333\nRawa Mazowiecka;51.7658\nMarktoberdorf;47.7667\nGuachucal;0.9667\nAppley Bridge;53.5790\nMontceau-les-Mines;46.6669\nBan Bo Haeo;18.3048\nMadalag;11.5269\nBourbonnais;41.1830\nKalynivka;49.4472\nSan Juan Ermita;14.7667\nDurango;37.2659\nJucuapa;13.5167\nItapororoca;-6.8300\nSanto Antônio do Sudoeste;-26.0700\nĀb Pakhsh;29.3606\nVillaquilambre;42.6167\nCentral Point;42.3764\nChoghādak;28.9864\nAnsonia;41.3443\nCastel Maggiore;44.5667\nBe’er Ya‘aqov;31.9436\nRubiataba;-15.1639\nPindoretama;-4.0278\nBaena;37.6167\nBergeijk;51.3167\nGautier;30.4106\nFihaonana;-18.6000\nKakraul;26.3620\nElumalai;9.8650\nMonroe;41.3379\nNáousa;40.6333\nAffton;38.5499\nTadó;5.2667\nNarangba;-27.2015\nNauen;52.6000\nCachoeirinha;-8.4858\nContamana;-7.3333\nBaturbāri;26.2281\nGuareí;-23.3728\nPonmana;8.3867\nItatira;-4.5289\nIpaba;-19.4139\nPolohy;47.4796\nPirkkala;61.4667\nHighland;40.4276\nAntonina;-25.4289\nSudbury;42.3847\nSan Sebastián de Buenavista;9.2403\nChapada dos Guimarães;-15.4608\nFakfak;-2.9167\nFox Crossing;44.2228\nMassaguet;12.4742\nPaks;46.6220\nFranklin Farm;38.9133\nMo i Rana;66.3128\nArroio do Meio;-29.4008\nPālaiyampatti;9.5392\nTonantins;-2.8728\nKabala;9.5833\nKāriyāpatti;9.6741\nTogba;7.1000\nBad Reichenhall;47.7247\nAugusta;44.3341\nHoppegarten;52.5167\nHala;26.8272\nNelidovo;56.2167\nConceição;-7.5619\nLouny;50.3571\nCocoa;28.3820\nAnzoátegui;4.6339\nSestri Levante;44.2733\nPadre Paraíso;-17.0719\nVélez;6.0103\nTādigadapa;16.4713\nAlfeld;51.9886\nBartow;27.8868\nKalabahi;-8.2167\nMuttenz;47.5167\nKovylkino;54.0403\nSan Julián;13.6976\nBoissy-Saint-Léger;48.7503\nVillanueva;10.6000\nRosedale;35.3886\nFushë-Krujë;41.4833\nTessenderlo;51.0697\nSirvel;15.3170\nAraç;41.2422\nEbbw Vale;51.7800\nPiatykhatky;48.4126\nMellacheruvu;16.8173\nSzázhalombatta;47.3004\nTaft;11.9058\nNunuñgan;7.8167\nTocaima;4.5000\nNefas Mewch’a;11.7333\nBrownwood;31.7127\nFutog;45.2333\nOulmes;33.4450\nTādikonda;16.4167\nMaimón;18.7700\nMolakālumuru;14.7178\nHopkins;44.9259\nKara-Köl;41.6311\nKalach;50.4333\nUmirim;-3.6769\nMonor;47.3475\nMilton;43.0406\nLe Pontet;43.9642\nAlzenau in Unterfranken;50.0667\nAnandpur;31.2393\nBerkovitsa;43.2333\nTaufkirchen;48.0500\nBradfordville;30.5735\nCrimmitschau;50.8181\nNgathainggyaung;17.4000\nTârgu Secuiesc;45.9969\nVilla Nueva;-32.4331\nHeguri;34.6292\nThomasville;30.8394\nAntotohazo;-18.4667\nYeddumailāram;17.5011\nBalilihan;9.7500\nOsny;49.0592\nKhorabar;26.7403\nVestby;59.5750\nDzüünharaa;48.8500\nKoriāpatti;26.1149\nPaglat;6.7811\nGossau;47.4167\nPôrto Acre;-9.5878\nSpringboro;39.5615\nMennzel Bou Zelfa;36.6817\nChowchilla;37.1095\nFerguson;38.7490\nAltus;34.6565\nLukovit;43.2000\nMāḩiş;31.9833\nStarobilsk;49.2829\nRājmahal;25.0500\nAvon;41.7907\nOr ‘Aqiva;32.5\nAscención de Guarayos;-15.8922\nCarlos Spegazzini;-34.8833\nKegalle;7.2531\nSoalkuchi;26.1700\nSanta Fe Springs;33.9329\nMarsciano;42.9167\nSortavala;61.7056\nBatalha;-9.6778\nMukkūdal;8.7431\nSzamotuły;52.6000\nMontrouis;18.9506\nLessines;50.7167\nSiderno Marina;38.2667\nMiddelburg;-31.4939\nBensenville;41.9579\nThorold;43.1167\nPalmeiras;-2.6450\nEast Lyme;41.3668\nBan Mai;14.9629\nOwego;42.0881\nNovyy Oskol;50.7583\nMānullahpatti;26.0619\nBremervörde;53.4833\nKiliia;45.4500\nBni Bouayach;35.0986\nCatarina;-6.1308\nWeißenburg;49.0306\nVilla Rica;2.5167\nDoñihue;-34.2261\nSan Lorenzo de El Escorial;40.5936\nEngenheiro Coelho;-22.4883\nBīdestān;36.2311\nGuaranésia;-21.2989\nColonia;40.5926\nRonkonkoma;40.8037\nKappiyara;8.2466\nYupiltepeque;14.1941\nBeltsville;39.0394\nKljuč;44.5333\nKinzau-Vuete;-5.4967\nShuangluan;40.9608\nOxon Hill;38.7884\nEmba;48.8267\nStekene;51.2000\nGoyty;43.1642\nIbititá;-11.5469\nConcord;38.5117\nOnalaska;43.8883\nRetiro;-36.0333\nKonz;49.7000\nBad Dürkheim;49.4594\nReota;25.8194\nFarias Brito;-6.9308\nAjaigarh;24.8988\nBlooming Grove;41.3948\nBuckhall;38.7239\nRufino;-34.2667\nLongjia;19.1487\nCamrose;53.0167\nRanquitte;19.4167\nLos Lagos;-39.8500\nGāndarbal;34.2262\nDomodossola;46.1161\nSalamina;5.4083\nTottiyam;10.9880\nCambridge;-37.8833\nJbabra;34.4314\nSchönefeld;52.3886\nKumbhrāj;24.3734\nBerea;41.3696\nAmmāpettai;10.7948\nMiyatoko;33.6992\nRound Lake;42.3435\nOttawa;41.3555\nCafarnaum;-11.6939\nÉdessa;40.8000\nMurambi;-1.8133\nWisconsin Rapids;44.3927\nJora Khurd;26.4893\nAbong Mbang;3.9833\nSanpaicun;24.6642\nDestelbergen;51.0500\nTsivory;-24.0683\nMorales;8.3133\nInhapi;-9.2189\nÇerkeş;40.8139\nLeteri;24.0598\nLaives;46.4228\nPicuí;-6.5550\nRutigliano;40.9333\nAsakapalle;17.7364\nCaiapônia;-16.9569\nSidi Allal Tazi;34.5197\nSurovikino;48.6000\nToflea;46.0637\nQaryat al Qī‘ān;32.0167\nAndéranboukan;15.4283\nDoura;12.0167\nMumford;5.2625\nIbipeba;-11.6408\nKeskin;39.6731\nPitimbu;-7.4708\nSantiago de María;13.4833\nSendārappatti;11.4373\nCarlos Chagas;-17.7028\nTummalapenta;14.8997\nNīār;38.2369\nLiuma;25.6682\nJhagarua;26.0059\nVovchansk;50.2881\nCapua;41.1056\nMarshfield;44.6627\nJaguaripe;-13.1128\nBagnols-sur-Cèze;44.1625\nVlotho;52.1667\nTerzigno;40.8000\nBoa Vista do Tupim;-12.6600\nRaghunāthpur;26.1145\nOrăştie;45.8500\nKavalerovo;44.2702\nSiddāpur;14.3470\nFilomeno Mata;20.2000\nSheridan;44.7961\nThorne;53.6083\nBaliangao;8.6667\nSan Rafael Pie de la Cuesta;14.9333\nItapiúna;-4.5639\nJiadong;22.4305\nBilar;9.7000\nPohādi;26.0387\nFreilassing;47.8333\nAcharipallam;8.1700\nMyślenice;49.8347\nMalnate;45.8000\nCreve Coeur;38.6620\nUghara;26.0563\nJohnstown;40.3260\nBönen;51.5986\nAshland;42.2573\nSouth Frontenac;44.5081\nGuanzhai;26.2697\nAntombana;-15.0000\nBonanza;14.0275\nSāhna;30.4293\nLora del Río;37.6500\nLimay;48.9933\nTamri;30.6950\nKulu;31.9600\nUnhel;23.3379\nCajari;-3.3208\nFayetteville;33.4501\nSivandipuram;8.7811\nSolrød Strand;55.5167\nBīmgal;18.7000\nJawkatiā;26.7308\nMalacacheta;-17.8419\nPorto Real;-22.4200\nBistāria;26.1262\nSkara;58.3833\nBombon;13.6867\nManganj;26.1388\nVanino;49.0873\nCimarron Hills;38.8597\nCarnaíba;-7.8050\nShaogang;38.1584\nKnightdale;35.7911\nTata;29.7428\nBeerse;51.3167\nCluses;46.0603\nUnquillo;-31.2333\nTatsuno;35.9824\nOrestiáda;41.5000\nOlho d’Água das Cunhãs;-4.1389\nTarifa;36.0140\nAmīnpur;17.5241\nBusovača;44.1000\nMontville;41.4636\nSaylac;11.3539\nPottanūr;11.1098\nGidi;23.6909\nSam Phran;13.7270\nMisato;39.4616\nTaió;-27.1158\nBhawānīpur;25.3944\nLahnstein;50.3011\nYoshimi;36.0399\nKuttālam;11.0758\nKunitomi;31.9906\nChubek;37.6167\nBalş;44.3500\nTimoktene;27.0217\nPayyannūr;12.1500\nPhelan;34.4398\nPaluan;13.4167\nFirminy;45.3881\nBrand;50.7489\nDenizciler;36.6500\nBudrio;44.5500\nBrook Park;41.4036\nVissannapeta;16.9500\nSan Carlos Park;26.4765\nVeternik;45.2533\nGerd Farāmarz Shāhedīyeh;31.9408\nAbrandābād-e Shāhedīyeh;31.9414\nCariús;-6.5369\nConceição do Almeida;-12.8089\nZhangshicun;24.5477\nTinajeros;14.6733\nPresidente Olegário;-18.4178\nDapi;23.6494\nMūkondapalli;12.7514\nPresidente Médici;-11.1758\nKasongan;-1.8959\nColina;-20.7136\nNeópolis;-10.3200\nMoloacán;17.9833\nNewton;38.0368\nKristiansund;63.1104\nBel Air;-20.2582\nOskarshamn;57.2650\nPitt Meadows;49.2333\nZagarolo;41.8333\nNigrán;42.1419\nCapanema;-25.6719\nPriozërsk;61.0500\nSan Celoni;41.6895\nPizarro;4.9500\nSanta Cruz Zenzontepec;16.5333\nKottá Kalidindi;16.5032\nMelville;40.7824\nSpringfield;36.4949\nSan Diego;10.3375\nWheatfield;43.0975\nTuruvanūr;14.2200\nRanzan;36.0565\nFeilding;-40.2167\nChouafaa;34.7667\nTinoc;16.6750\nTyāgadurgam;11.7411\nPoulton le Fylde;53.8470\nGuadix;37.3000\nBerkhampstead;51.7600\nAsunción Nochixtlán;17.4592\nShaoyu;34.0629\nOskū;37.9108\nBorgo San Lorenzo;43.9500\nHeusweiler;49.3375\nLangen;53.6116\nMiędzyrzecz;52.4483\nVera;37.2500\nSarotar;26.4291\nGuabiruba;-27.0858\nToyono;34.9189\nCordenons;45.9833\nPalestine;31.7544\nFátima;-10.6000\nBramhall;53.3570\nSan Blas Atempa;16.3167\nTha Bo;17.8494\nCampo de la Cruz;10.3778\nKherāmeh;29.5000\nWalcourt;50.2500\nLittau;47.0494\nBitkine;11.9817\nSiqueira Campos;-23.6889\nPonedera;10.6500\nRhaude;53.1667\nPlácido de Castro;-10.2758\nFoum el Anser;32.3718\nMūlanūr;10.7943\nKivsharivka;49.6303\nKitanakagusuku;26.3011\nCândido Mendes;-1.4469\nDniprorudne;47.3907\nKostrzyn nad Odrą;52.5883\nHatfield;40.2758\nBeloozërskiy;55.4589\nSomma Lombardo;45.6833\nSavignano sul Rubicone;44.0881\nNorth Myrtle Beach;33.8232\nNederland;29.9707\nMartinsburg;39.4582\nHopkinton;42.2255\nMayorga;10.9000\nSan Vicente Pacaya;14.4161\nApastepeque;13.6667\nNara;15.1800\nTrenton;42.1394\nParole;38.9863\nQaşr-e Shīrīn;34.5156\nWilton;41.2070\nPiatã;-13.1519\nMirangaba;-10.9539\nLos Alcázares;37.7436\nDeoria;26.1791\nArroio Grande;-32.2378\nItapaci;-14.9508\nUdaipura;23.0743\nFairwood;47.4467\nSharon;42.1085\nMiddelharnis;51.7500\nCesário Lange;-23.2267\nNerviano;45.5500\nTaft;31.7492\nLakeway;30.3544\nLogansport;40.7472\nLamrasla;32.0247\nBakhmach;51.1810\nOtrokovice;49.2099\nElizabeth City;36.2942\nAlbino;45.7606\nFelanitx;39.4692\nAstrea;9.5000\nVillorba;45.7333\nBékés;46.7667\nBad Segeberg;53.9167\nLevin;-40.6219\nYur’yev-Pol’skiy;56.5000\nZielonka;52.3008\nGheorgheni;46.7200\nBettioua;35.8000\nKorsun-Shevchenkivskyi;49.4261\nDuffel;51.1000\nSan José Tenango;18.1500\nSão José da Coroa Grande;-8.8978\nMontornés del Vallés;41.5444\nNipomo;35.0319\nKreminna;49.0500\nAmvrosiivka;47.7958\nFulwood;53.3650\nPhoenixville;40.1359\nSvatove;49.4150\nIcapuí;-4.7128\nCampos Belos;-13.0369\nFranklin Park;41.9361\nBadantola;25.2402\nReriutaba;-4.1419\nAlbert Lea;43.6548\nAlmondbury;53.6344\nFoxborough;42.0627\nSchwechat;48.1411\nSelma;32.4166\nFontaine-l’Évêque;50.4167\nSengés;-24.1128\nBuenavista;8.6833\nHampton;40.5844\nHeidenau;50.9833\nDurleşti;47.0333\nConcord;42.4620\nCagdianao;9.9167\nArroyo Grande;35.1241\nBodegraven;52.0822\nBudhni;22.7825\nHarrisburg;35.3125\nBelo Campo;-15.0378\nWörth am Rhein;49.0517\nHarinākunda;23.6500\nCaldas de Montbuy;41.6328\nSchwalmstadt;50.9333\nTallmadge;41.1023\nOmalūr;11.7300\nSanta Maria di Sala;45.5089\nSchwarzenbek;53.5042\nPinecrest;25.6650\nL’Isle-d’Abeau;45.6194\nTaku;33.2833\nVisé;50.7333\nMineros;-17.1178\nKadaň;50.3761\nFormoso do Araguaia;-11.7969\nSerra Dourada;-12.7608\nCinco Ranch;29.7395\nMonthey;46.2500\nVechelde;52.2608\nOmmen;52.5167\nGálvez;-32.0333\nBurlington;39.0223\nCarvin;50.4931\nNytva;57.9500\nIati;-9.0458\nCassano al Ionio;39.7833\nGarwolin;51.9000\nVettavalam;12.1077\nEkazhevo;43.2081\nYoichi;43.1953\nHessisch Oldendorf;52.1667\nPalos Hills;41.6986\nBorgaon;16.4200\nJussara;-15.8650\nShirāli;14.0297\nYutz;49.3589\nGothini;26.1626\nDo’stlik Shahri;40.5247\nPortsmouth;38.7538\nFairmont;39.4768\nAït Bouchta;35.1056\nAssa;28.6086\nNovopavlovka;42.8700\nPiúma;-20.8350\nMemuro-minami;42.9119\nTalata-Volonondry;-18.7500\nSaladas;-28.2500\nGalaat el Andeless;37.0625\nDurant;33.9949\nGroßenhain;51.2833\nSørum;59.9871\nEast Goshen;39.9934\nCariré;-3.9508\nStonington;41.3738\nMirante do Paranapanema;-22.2919\nBet She’an;32.5\nAlauli;25.6440\nQishe;24.9232\nKońskie;51.2000\nHāvi Bhauār;26.1091\nShika;37.0062\nCalera de Tango;-33.6302\nJalpa de Méndez;18.1764\nCastelo do Piauí;-5.3219\nAraçoiaba;-7.7900\nWindham;43.7981\nSerrita;-7.9328\nSanta Lucía Milpas Altas;14.5757\nPiossasco;44.9906\nFlórina;40.7833\nDobrush;52.4167\nWaalre;51.4000\nIllertissen;48.2167\nGitagum;8.5956\nAragarças;-15.8978\nMonforte de Lemos;42.5164\nBaependi;-21.9589\nWantagh;40.6686\nShaying;25.9740\nPembroke;42.0655\nSiloe;-29.9836\nBraniewo;54.3833\nGarching bei München;48.2500\nDehti;26.2115\nClive;41.6147\nSanta Fe;16.1592\nNiles;41.1879\nVertentes;-7.9028\nMeishan;23.5607\nOyama;35.3601\nTillmans Corner;30.5819\nRepublic;37.1452\nSikhio;14.9000\nConcepción de Ataco;13.8667\nNaarden;52.2953\nBekalta;35.6167\nManchester;38.5830\nNehbandān;31.5419\nPort Colborne;42.8833\nKosvik;58.1500\nKikube;1.3328\nPocinhos;-7.0769\nPisz;53.6333\nSan Cristóbal Cucho;14.9000\nGaropaba;-28.0228\nRibat Al Khayr;33.8200\nSlyudyanka;51.6333\nKoratagere;13.5220\nSikandra;24.9564\nSvilengrad;41.7667\nEski-Nookat;40.2658\nŞenkaya;40.5619\nNaula;25.5535\nTavares;28.7920\nSavaştepe;39.3839\nVennandūr;11.5150\nParaibuna;-23.3861\nAntanambao;-15.1667\nCondeúba;-14.8950\nNewburyport;42.8124\nKnik-Fairview;61.5082\nSipacate;13.9333\nPanórama;40.5833\nXochiatipan de Castillo;20.8333\nNyborg;55.3122\nDergaon;26.7000\nOcean Springs;30.4082\nGoffstown;43.0190\nBouarouss;34.3667\nIsfana;39.8389\nSomerset;41.7404\nWerdohl;51.2667\nAuerbach;50.5094\nSan Kamphaeng;18.7500\nVāyalpād;13.6500\nAlmeria;11.6206\nKhutāha;25.2645\nSeagoville;32.6530\nKishi;35.3364\nKottapalle;17.2918\nWashington;40.7877\nMarcos;18.0444\nGangwuzhen;25.9644\nVeldurti;15.5667\nIkniwn;31.1736\nWadowice;49.8833\nSan Antonio de Ibarra;0.3627\nAmbāla;17.6500\nŌi;35.3266\nKudavāsal;10.8582\nQuispamsis;45.4322\nBad Säckingen;47.5500\nKiyama;33.4270\nGreene;39.9543\nGibsonton;27.8260\nSunbury;51.4230\nAndalucía;4.1667\nSan Pedro;4.0000\nPúchov;49.1200\nSierpc;52.8833\nČitluk;43.2000\nPloemeur;47.7358\nŢāqah;17.0372\nBăicoi;45.0453\nMaripād;17.4031\nTordera;41.7008\nManga;-14.7558\nPinabacdao;11.6167\nChapelle;19.4167\nSan Jose;12.5310\nRikuzen-Takata;39.0280\nPieksämäki;62.3000\nLoay;9.6000\nMcAlester;34.9257\nŁask;51.5903\nNorth Hykeham;53.1833\nTrujillo;4.2500\nPadugupādu;14.4885\nDrăgăşani;44.6611\nDombóvár;46.3820\nAlpignano;45.1000\nAmsterdam;42.9420\nWemmel;50.9167\nGikongoro;-2.4697\nKingsland;30.8194\nNagnur;16.1400\nSon en Breugel;51.5167\nSarvestān;29.2736\nBaaqlîne;33.6797\nLake Ronkonkoma;40.8297\nSão Francisco de Assis;-29.5500\nĪlām;26.9080\nIpanema;-19.8008\nAmīngarh;16.0572\nKiangara;-17.9667\nMŭynoq;43.7667\nGlencoe;-28.1833\nVordingborg;55.0000\nIngá;-7.2678\nBelākoba;26.5744\nLenoir;35.9094\nConcord;39.8741\nSt. Marys;30.7567\nMont-Saint-Hilaire;45.5622\nKukraun;25.6858\nKlaeng;12.7778\nTremedal;-14.9758\nCudahy;42.9467\n‘Anbarābād;28.4758\nPānchgrām;24.1996\nAntsampanimahazo;-19.6400\nMaroaloka;-25.1667\nLavāsān;35.8231\nQuibaxi;-8.5000\nIsmaning;48.2264\nAvtury;43.1667\nTrinity;28.1809\nSteiner Ranch;30.3654\nSanto Antônio do Leverger;-15.8658\nRāmpur;21.0735\nSanta Cruz Naranjo;14.3833\nGhouazi;34.4667\nSint-Oedenrode;51.5636\nParchim;53.4167\nPratteln;47.5167\nBeruri;-3.9022\nVīrapāndi;11.1723\nTrês Barras;-26.1058\nAlmolonga;14.8122\nNew Castle;41.1841\nCentral;-11.1542\nHranice;49.5525\nAlto Araguaia;-17.3150\nSangenjo;42.4017\nBafanji;5.8361\nChâteauneuf-les-Martigues;43.3831\nBirstall;53.7320\nMenasha;44.2125\nJuanacatlán;20.5000\nManīn;33.6422\nMinamishibetsuchō;44.1786\nBathurst;47.6200\nRāyappanpatti;9.7997\nShirva;13.2465\nCuautitlán;19.4333\nTapauá;-5.6278\nLibjo;10.1960\nLebanon;44.5317\nWillimantic;41.7171\nSt. Michael;45.2014\nCalenzano;43.8667\nSanta Vitória;-18.8389\nSycamore;41.9957\nNorth Druid Hills;33.8185\nAlakamisy;-20.2000\nSaint-Augustin-de-Desmaures;46.7333\nUpper Grand Lagoon;30.1690\nMahesh Khunt;25.4500\nBexbach;49.3494\nShedbal;16.6892\nSolonópole;-5.7328\nGoshaingaon;26.4395\nSão Miguel do Tapuio;-5.5039\nPatar;40.3333\nHuitán;15.0486\nAtalaia do Norte;-4.3719\nAnkofa;-15.4000\nCharleston;39.4842\nBuadiposo-Buntong;7.9667\nMarcon;45.5543\nMaranello;44.5333\nCoronda;-31.9667\nBucay;17.5388\nManari;-8.9639\nColonial Heights;37.2650\nFeyẕābād;35.0144\nSan Vicente;6.2819\nBlythe;33.6219\nSona;45.4333\nSteubenville;40.3653\nWhitestown;43.1350\nMendes;-22.5269\nVohilengo;-17.3000\nAmbongo;-23.4500\nAmbiula;-7.4333\nMadeley;52.6370\nKelsterbach;50.0617\nMengjiacun;40.0186\nKuchinda;21.7436\nMatigou;37.6043\nGorham;43.7034\nJacksonville;39.7292\nQuanzhang;35.6613\nDīzīcheh;32.3836\nBobingen;48.2667\nSan Pedro;8.7333\nPescantina;45.4833\nManampatrana;-21.6500\nSoutheast;41.4032\nAnalaiva;-20.3333\nMadalena;-4.8569\nTsararivotra;-19.1714\nNatchitoches;31.7315\nPort-de-Bouc;43.4050\nInkollu;15.8300\nHerzele;50.8833\nGeneral Juan Madariaga;-37.0167\nGunjur;13.1833\nAlatsinainy Ialamarina;-21.5333\nOak Bay;48.4264\nMuḩradah;35.2500\nTall ‘Aran;36.1231\nBhucho Mandi;30.2129\nKharhiāl;20.2885\nAshtabula;41.8805\nPutte;51.0500\nRicaurte;1.2108\nBehenjy;-19.2000\nPiaçabuçu;-10.4086\nSanta Fe;12.1500\nAliyābād;12.6317\nLattes;43.5678\nValguarnera Caropepe;37.5000\nPastos Bons;-6.6019\nCanby;45.2652\nPlymouth;40.1115\nManthani;18.6500\nStilfontein;-26.8428\nTurmalina;-17.2858\nVillanueva del Pardillo;40.4833\nAbangaritos;10.2492\nAnda;9.7440\nCortes;9.2753\nLa Marque;29.3683\nBiro;9.9000\nScarsdale;40.9902\nFreudenberg;50.8997\nTsianisiha;-22.9000\nPūlla;16.8060\nSan Rafael;11.1728\nDahibhāt Mādhopur;26.2763\nTall Qaşab;36.2583\nMaryland City;39.1016\nJaicós;-7.3589\nHijuelas;-32.7986\nBoone;36.2111\nMabéhiri;5.6833\nCruz Machado;-26.0169\nCurti;15.4167\nSorrento;40.6278\nSouth Hadley;42.2567\nFuente-Álamo de Murcia;37.7394\nBelobaka;-18.9833\nAmboahangibe;-14.1333\nSilvāni;23.3026\nWhite Settlement;32.7554\nMunguía;43.3547\nVilāttikulam;9.1312\nSinzig;50.5453\nSevierville;35.8872\nZuhres;48.0181\nAntanambe;-16.4333\nOroszlány;47.4833\nBatié;9.8833\nIbrāhīmpatan;17.1017\nQal‘ah-ye Zāl;37.0150\nItaberá;-23.8619\nMaroteza;-22.3000\nShirosato;36.4792\nAmbovombe Afovoany;-20.7667\nKolonodale;-1.9833\nMatsakabanja;-15.9167\nTexistepeque;14.1333\nPolignano a Mare;41.0000\nTranoroa;-24.7000\nPomáz;47.6431\nSileby;52.7310\nMosbrough;53.3250\nYoboki;11.5167\nCastaic;34.4818\nMaridi;4.9100\nBusolwe;0.8492\nBeantake;-23.8000\nNeftegorsk;52.8000\nTárrega;41.6464\nNamayingo;0.3450\nMahazoma;-17.1667\nGinsheim-Gustavsburg;49.9833\nGeneral Deheza;-32.7564\nBemahatazana-Belobaka;-19.3500\nPimentel;19.1833\nDoruma;4.7333\nAshby de la Zouch;52.7460\nThānga;24.5500\nRypin;53.0667\nBaronissi;40.7462\nAlice;27.7556\nBrielle;51.9000\nFlora;18.2147\nOborniki;52.6500\nErvália;-20.8400\nArco;45.9167\nIbirataia;-14.0669\nAlton;26.2884\nOutat Oulad Al Haj;33.3333\nMessias;-9.3828\nCentralia;46.7223\nHương Canh;21.2833\nRemagen;50.5786\nOdaipatti;9.8323\nTowamencin;40.2417\nSabana de Torres;7.4000\nCrowley;32.5781\nPuurs;51.0761\nKharabali;47.4050\nOconomowoc;43.0996\nKongsvinger;60.1905\nAntenor Navarro;-6.7289\nMarabut;11.1167\nPontarlier;46.9061\nRedland;39.1339\nMelfi;41.0000\nJovellar;13.0667\nLaurel;37.6375\nFarmington;37.7822\nPelaya;8.6833\nPolicoro;40.2000\nSusner;23.9467\nPapanduva;-26.3700\nKakkalapalle;14.6415\nKreuzau;50.7470\nFrankenberg;51.0589\nColtauco;-34.3000\nZapotlán del Rey;20.4674\nGaoniang;26.8394\nHarwich;51.9340\nShorewood;41.5169\nLagoa da Canoa;-9.8300\nUnión de San Antonio;21.1280\nLobogo;6.6333\nJuazeirinho;-7.0678\nRājbalhāi;22.7600\nPyskowice;50.3833\nManambaro;-25.0333\nMcKeesport;40.3418\nBan Thum;16.4523\nCohoes;42.7732\nSaint Andrews;56.3404\nTres de Mayo;-26.4794\nGolitsyno;55.6147\nWeilerswist;50.7525\nBhai Rupa;30.4311\nBuchen in Odenwald;49.5217\nGuapiara;-24.1850\nKristinehamn;59.3000\nYaguachi Nuevo;-2.1200\nĀyikudi;9.0032\nMarmande;44.5000\nMonselice;45.2333\nCary;42.2129\nBroken Hill;-31.9500\nBay City;28.9838\nNguigmi;14.2532\nKirsanov;52.6500\nMadanpur;26.2103\nBiliran;11.5800\nSouth Fayette;40.3556\nBoqueirão;-7.4819\nAnadia;-9.6844\nPuquio;-14.6939\nBenavente;42.0031\nBerlín;13.5000\nHerve;50.6333\nMiędzyrzec Podlaski;51.9833\nPālaiyam;10.7256\nGalich;58.3833\nSerafina Corêa;-28.7119\nEslöv;55.8392\nYuanquan;40.5004\nKhirhar;26.5168\nAmbohitralanana;-15.2333\nSakardih;25.2280\nPorto San Giorgio;43.1833\nGroveland;28.6098\nCatarman;9.1333\nSan Bartolo Tutotepec;20.4000\nWangaratta;-36.3583\nSettiyārpatti;9.3935\nCullman;34.1775\nNorth Aurora;41.8086\nLillerød;55.8681\nGazantarak;39.9667\nOcean Acres;39.7430\nNorrtälje;59.7667\nArai;34.6833\nSan Rafael del Norte;13.2128\nNorth Canton;40.8742\nPanama City Beach;30.2370\nTiffin;41.1165\nBanhatti;16.3853\nHolzwickede;51.5000\nAl Qbab;32.7333\nJacupiranga;-24.6925\nJaguaretama;-5.6128\nBirhana;25.4489\nAlton;51.1498\nBan Mae Ngon Khilek;19.8021\nBuguda;19.8081\nArinos;-15.9169\nMontanha;-18.1269\nCenoví;19.2500\nDouar Oulad Mbarek;34.2833\nTaree;-31.9000\nFrederikssund;55.8333\nYanggezhuang;39.3831\nKāgvād;16.4800\nCarlentini;37.2833\nAmba Icharua;25.6140\nKukmor;56.1855\nBarão do Grajaú;-6.7558\nNazaré Paulista;-23.1808\nRio Claro;-22.7228\nSalgar;5.9617\nBon Air;37.5187\nManzanares;38.9964\nMitake;35.4344\nSchwalbach;49.2833\nColón;9.9096\nAsh Shaykhān;36.6917\nCesson-Sévigné;48.1208\nOrta Nova;41.3308\nWadgassen;49.2667\nIsola Capo Rizzuto;38.9589\nShangjing;24.6076\nZhongguyue;38.2833\nGretna;29.9101\nMiaojiaping;37.5777\nLongjia;36.0608\nSobinka;56.0000\nNgara;-2.5122\nSeyah Cheshmeh;39.0631\nSalonta;46.8000\nDoylestown;40.2962\nLas Heras;-46.5500\nPinili;17.9540\nBovisio Masciago;45.6167\nPātan;23.2864\nPorciúncula;-20.9628\nBechem;7.0833\nSão Benedito do Rio Preto;-3.3339\nBāţūfah;37.1744\nAgua Blanca;14.4833\nSapeaçu;-12.7278\nKöping;59.5167\nGodfrey;38.9577\nDaimiel;39.0833\nBan Phe;12.6287\nHlybokaye;55.1333\nPirapora do Bom Jesus;-23.3972\nSirari;-1.2244\nNão-Me-Toque;-28.4589\nOerlinghausen;51.9667\nLatsia;35.1000\nPortsmouth;41.5922\nDirba;30.0700\nSanta Elena;-30.9500\nTrossingen;48.0756\nEl Dorado;33.2184\nGrenchen;47.1906\nEsperanza;11.7369\nMorros;-2.8639\nCameron Park;38.6738\nOrsay;48.6981\nPortchester;50.8420\nBeni Fouda;36.2861\nPoyo;42.4333\nGautampura;22.9866\nReni;45.4575\nKiangan;16.7775\nGuttal;14.8333\nMinquan;37.4420\nSwellendam;-34.0231\nRockland;42.1295\nBishunpura;26.5436\nCalverton;39.0578\nCairu;-13.4869\nWinder;33.9917\nKahoku;38.4263\nSanary-sur-Mer;43.1192\nTroy;31.8021\nBalaguer;41.7904\nMonzón;41.9100\nZaslawye;54.0083\nTuruvekere;13.1637\nNova Pazova;44.9500\nLaç;41.6353\nSāram;23.7625\nZalţan;32.9500\nTolūprpatti;11.0244\nBanora Point;-28.2225\nBalighattam;17.6510\nZłotoryja;51.1333\nGlen Parva;52.5867\nDingjiagouxiang;35.5307\nDuijiang;27.0782\nStegen;47.4760\nCanapi;-9.1269\nAnoka;45.2099\nQal’at Mgouna;31.2414\nLaatatra;32.6315\nNīkshahr;26.2258\nEastlake;41.6581\nRuhango;-2.2325\nMadison;41.3398\nLinbian;22.4333\nTalitay;7.0353\nCipó;-11.1000\nAmacuzac;18.6000\nSierre;46.3000\nSchrobenhausen;48.5333\nKodumudi;11.0769\nBan Pong;13.8174\nItacarambi;-15.1019\nBahon;19.4694\nLousã;40.1125\nTábara Arriba;18.5694\nNew River;33.8835\nEstancia Pozo Colorado;-23.4136\nBan Mae Ka Hua Thung;19.0942\nCerrillos;-24.9000\nPirayú;-25.4800\nSchaesberg;50.9000\nTanque Novo;-13.5458\nYerrapālem;16.1500\nMount Washington;38.0430\nThị Trấn Ngải Giao;10.6406\nTizi Rached;36.6718\nAmbolomadinika;-21.9500\nSpanish Lake;38.7884\nLoboc;9.6333\nSibutao;8.6131\nSānwer;22.9742\nMilanówek;52.1333\nFraserpet;12.4587\nJucurutu;-6.0339\nRijen;51.5833\nCalceta;-0.8400\nDelran;40.0170\nVerdun;49.1597\nSalmon Arm;50.7022\nAlcochete;38.7500\nFanandrana;-18.1944\nPalanan;17.0589\nAsarcık;41.0314\nAshton;-44.0333\nMatipó;-20.2839\nNedugula;11.4764\nRio Maria;-7.3108\nTlahuelilpan;20.1297\nDharampuri;22.1495\nSokółka;53.4000\nBenito Juárez;20.8833\nKempele;64.9125\nFléron;50.6167\nKitahiroshima;34.6746\nEast Lampeter;40.0375\nPionki;51.4833\nDourbali;11.8050\nVarjota;-4.1939\nPreganziol;45.6000\nAl ‘Ashārah;34.9203\nMatagob;11.1469\nLibertad;11.7690\nBaxt;40.7139\nTufanbeyli;38.2646\nCerca Carvajal;19.2667\nLatifpur;24.1181\nZhoujia;35.2976\nVilliers;-27.0333\nKillingly;41.8311\nLa Garriga;41.6804\nLouth;53.3669\nPio IX;-6.8378\nPort Alberni;49.2339\nVerneuil-sur-Seine;48.9797\nChhapra Bahās;26.7266\nGuidan Roumdji;13.6575\nBoljoon;9.6333\nArsanjān;29.9125\nSchijndel;51.6167\nSantos Reyes Nopala;16.1000\nAttappampatti;11.4820\nNovo Airão;-2.6208\nEl Carmen de Chucurí;6.6981\nRestrepo;4.2500\nTotoró;2.5117\nRibeirão Branco;-24.2208\nSeoni Chhapāra;22.3939\nSan Alejo;13.4333\nBendorf;50.4297\nPianoro;44.3833\nAït Majdane;31.8514\nWebster;42.0521\nNerang;-27.9956\nBaquerizo Moreno;-1.9167\nDighaun;25.5549\nYayas de Viajama;18.6000\nDugo Selo;45.8058\nPernamitta;15.5333\nStrzelce Opolskie;50.5000\nPolyarnyy;69.2000\nAbejorral;5.7894\nSan Rafael Cedros;13.7333\nAgourai;33.6333\nSan Jorge;11.9833\nArauco;-37.2500\nDabas;47.1890\nEstelle;29.8447\nRāni Shakarpura;25.5534\nLam Luk Ka;13.9297\nKalanaur;32.0200\nManilva;36.3833\nTricase;39.9333\nBailén;38.0833\nInza;53.8500\nSan Bernardino;14.5333\nTotutla;19.2167\nSouthbridge;42.0604\nMawkanin;15.5106\nSìnnai;39.3026\nAïn Zaouïa;36.5483\nSame;-4.0667\nChedaopo;36.4008\nTougan;13.0667\nNoniyā;26.6763\nSaint-Cyr-sur-Loire;47.4028\nRocca di Papa;41.7667\nJomboy Shahri;39.6989\nVallières;19.4333\nAs Suqaylibīyah;35.3697\nPara;5.5167\nBarrhead;55.8010\nMagalhães de Almeida;-3.3958\nBalma;43.6103\nBethpage;40.7495\nBad Münder am Deister;52.1992\nLa Primavera;5.4906\nAwlouz;30.7000\nWayne;42.2774\nHinode;35.7421\nNew Philadelphia;40.4860\nColbún;-35.7000\nŞavşat;41.2433\nBelém;-6.7469\nGokavaram;17.2667\nFiladélfia;-10.7408\nPoção de Pedras;-4.7500\nGudipallipādu;14.4588\nBrignoles;43.4058\nYondó;7.0000\nKamudi;9.4090\nHumacao;18.1520\nKembhāvi;16.6500\nPisticci;40.3833\nZaysan;47.4667\nBakouma;5.6986\nKirksville;40.1986\nCubellas;41.2100\nMarche-en-Famenne;50.2167\nPataskala;40.0110\nAfrânio;-8.5000\nPont-à-Celles;50.5000\nSan Giovanni Valdarno;43.5644\nMansingha;26.7807\nWendlingen am Neckar;48.6747\nIvanovka;42.8864\nVimodrone;45.5139\nLubang;13.8586\nPhirangipuram;16.3000\nSt. Matthews;38.2497\nTenango de Doria;20.3356\nSulaco;14.9167\nToba;34.4813\nCompostela;21.2389\nRubano;45.4333\nBad Langensalza;51.1081\nFreienbach;47.2000\nSedeh Lanjān;32.3781\nSagrada Familia;-35.0000\nCortland;42.6004\nBan Song;8.6603\nNova Era;-19.7606\nKasimkota;17.6736\nMudukulattūr;9.3440\nKawa;17.0897\nSahel;34.9667\nNeerpelt;51.2333\nPassagem Franca;-6.1800\nTabernes de Valldigna;39.0722\nRegeneração;-6.2378\nHavelock;34.9078\nJenison;42.9063\nEbino;32.0333\nPerupālem;16.3705\nThale;51.7500\nRaunheim;50.0167\nMarktredwitz;50.0000\nShin-Kamigotō;32.9844\nCoalinga;36.1420\nDerhachi;50.1114\nRojales;38.0886\nSapucaia;-21.9950\nFanipal;53.7500\nParagaticherla;16.3324\nRio Bananal;-19.2650\nMiharu;37.4406\nTasquillo;20.6167\nZandvoort;52.3667\nKetama;34.9158\nChorhat;24.4274\nMorarano-Gara;-18.7100\nTagana-an;9.6964\nColchester;44.5545\nBílina;50.5481\nLaguna Woods;33.6099\nHöganäs;56.2000\nSan Juan Nonualco;13.5072\nCastelfiorentino;43.6000\nDighirpār;22.3034\nYeşilhisar;38.3500\nGuanagazapa;14.2333\nCherān;25.3610\nMiramichi;47.0196\nWittenberge;53.0000\nBăileşti;44.0308\nLemont;41.6695\nChadchan;17.1700\nPuerto Rico;-26.8000\nBan Tha Mai I;18.7461\nMārtahalli;11.9919\nDamme;52.5208\nAdelfia;41.0000\nKombai;9.8475\nPlast;54.3833\nScott;40.3875\nThornton;53.7898\nKarukh;34.4922\nKishundāspur;25.3334\nWindlesham;51.3600\nDharmāpuri;18.9475\nDar Chaifat;32.5500\nGoodlettsville;36.3330\nPudu;12.8667\nCafelândia;-21.8025\nAgaram;10.4433\nChallapalle;16.1175\nStowbtsy;53.4833\nKushk;33.2956\nPlainville;41.6741\nHatfield;53.5800\nPuerto Guzmán;0.9667\nConceição do Mato Dentro;-19.0369\nNiagara-on-the-Lake;43.2553\nSoumagne;50.6167\nRadzionków Nowy;50.3833\nLalībela;12.0317\nKrasnokumskoye;44.1778\nBerga;42.1000\nZiracuaretiro;19.4189\nLuz;-19.8008\nKolokondé;9.9000\nAmbatolahy;-20.0000\nCheraro;14.3958\nWoodcrest;33.8789\nForssa;60.8167\nGunjāpalle;14.3845\nKottapeta;15.7913\nKarachev;53.1167\nSanta Magdalena;12.6489\nSamaná;5.5833\nSake;-1.5741\nCarmo;-21.9339\nBahutāl;24.5600\nPuerto Caimito;8.8700\nKadogawa;32.4712\nSant’Elpidio a Mare;43.2295\nTirukkāttuppalli;10.8481\nSuvorov;54.1500\nLara;-38.0167\nConcorezzo;45.5897\nPavullo nel Frignano;44.3327\nAurāhi;26.1895\nNāranattenvanpatti;9.7233\nSulzbach;49.2833\nSão Raimundo das Mangabeiras;-7.0219\nBurgdorf;47.0500\nPenugonda;16.6569\nSan Isidro;12.9283\nOsuna;37.2333\nCorrentes;-9.1289\nGuaranda;8.4672\nEpitacio Huerta;20.1348\nCamilo Ponce Enríquez;-3.0500\nSkadovsk;46.1167\nLake Butler;28.4862\nNew Castle;39.9191\nSigmaringen;48.0867\nMalhada;-14.3358\nMỹ Lương;20.8667\nSaint-Lin--Laurentides;45.8500\nMori;34.8356\nCalafat;43.9858\nNidda;50.4128\nChambellan;18.5667\nAlcantara;12.2584\nBijni;26.4959\nAnosiarivo;-19.9167\nCenterton;36.3566\nZarumilla;-3.5014\nMareth;33.6333\nBolhrad;45.6855\nMontemor-o-Novo;38.6500\nGalaz;34.5500\nMahālandi;24.0738\nOttakkadai;9.9580\nMwingi;-0.9333\nSaguday;16.5394\nCalayan;19.2619\nConchas;-23.0134\nMujikharf;38.8500\nPuerto Aysén;-45.4000\nKafr Zaytā;35.3736\nCássia;-20.5828\nMehrān;33.1222\nAnacortes;48.4878\nSrīkūrmam;18.1600\nNadugadda;16.3539\nVeinticinco de Mayo;-37.7712\nBrookfield;41.4674\nArachchalūr;11.1627\nCadoneghe;45.4500\nGokarn;14.5500\nTapiramutá;-11.8469\nDijiasuoxiang;35.6883\nGachancipá;4.9908\nHope Mills;34.9710\nGescher;51.9569\nBedford;41.2250\nRaychikhinsk;49.7833\nHidrolândia;-16.9619\nSuesca;5.1000\nMannō;34.1923\nNorcross;33.9379\nBad Münstereifel;50.5531\nSaint-Égrève;45.2317\nGennep;51.7000\nLa Algaba;37.4500\nPirapemas;-3.7269\nArani;13.3346\nÇat;39.6111\nNümbrecht;50.9053\nFate;32.9430\nNizhnyaya Salda;58.0667\nKhunti Dhanaili;25.9376\nBakeshiyingcun;40.7237\nAmmon;43.4745\nIbirama;-27.0569\nBaie de Henne;19.6667\nSoavina;-18.9500\nBeaumont;53.3572\nPéruwelz;50.5167\nRattaphum;7.1412\nAlcantara;9.9715\nEmmiganūru;15.1500\nYeni Suraxanı;40.4311\nMorganton;35.7408\nStaphorst;52.6500\nArpaçay;40.8483\nKouka;11.9000\nBetulia;6.1122\nPalhālan;34.1823\nBrenham;30.1584\nKünzell;50.5500\nDazhangzi;40.6239\nSaint-Pierre-des-Corps;47.3908\nOak Grove;45.4156\nEutin;54.1378\nSanto Antônio do Amparo;-20.9458\nStockelsdorf;53.8833\nFairview;40.1735\nBerezhany;49.4464\nHeilbad Heiligenstadt;51.3789\nKamenz;51.2667\nFigline Valdarno;43.6167\nMilla’ab;31.4737\nLaurel;31.6956\nBad Wildungen;51.1167\nBarbastro;42.0361\nRiva del Garda;45.8833\nSaint-Julien-en-Genevois;46.1442\nStockerau;48.3858\nCosautlán;19.3333\nHorn-Bad Meinberg;51.8833\nAyacucho;-37.1333\nG‘uzor;38.6208\nWohlen;47.3506\nAmpère;-25.9150\nDomont;49.0275\nSohtha;25.6449\nPital;10.6024\nStockach;47.8514\nEast Finchley;51.5902\nSudipen;16.9000\nSouth Ogden;41.1722\nSaint-Maximin-la-Sainte-Baume;43.4533\nPenn;39.7994\nFreiberg am Neckar;48.9333\nKrasnoslobodsk;48.7000\nDiepholz;52.6072\nGuryevsk;54.7833\nTonj;7.2800\nSão Domingos do Prata;-19.8650\nSaviano;40.9167\nSouto Soares;-12.0889\nGussago;45.6000\nShumikha;55.2333\nMuniz Freire;-20.4639\nVolgorechensk;57.4439\nJaguaruna;-28.6150\nCajamarca;4.4167\nHrubieszów;50.8167\nPécel;47.4893\nCamocim de São Félix;-8.3589\nNederweert;51.2833\nTíogollo;10.3333\nBetroka;-23.2683\nTekanpur;25.9940\nFinnentrop;51.1731\nAmboanjo;-22.0000\nWilton;43.1502\nBanabuiú;-5.3100\nSan Casciano in Val di Pesa;43.6569\nBareggio;45.4667\nPrzasnysz;53.0167\nUryzhar;47.0900\nPisaflores;21.1933\nGonegandla;15.7170\nYizhu;23.3565\nUrandi;-14.7708\nHandlová;48.7272\nHolmdel;40.3768\nHayange;49.3297\nHeysham;54.0460\nSundarpur;26.3037\nMount Holly;35.3136\nNoordwijkerhout;52.2667\nSawankhalok;17.3099\nSvalyava;48.5472\nPeso da Régua;41.1653\nAttūr;8.3224\nPindorama;-21.1858\nAmbarès-et-Lagrave;44.9247\nKönigstein im Taunus;50.1833\nKaatsheuvel;51.6667\nAchaljāmu;24.0243\nBraunau am Inn;48.2583\nCruz do Espírito Santo;-7.1400\nLinnei;23.7591\nAubange;49.5667\nLyepyel;54.8750\nRustampur;25.5700\nMohanpur;25.5620\nTomas Oppus;10.2500\nGokarna;24.0306\nAltena;51.3000\nMont-Organisé;19.4000\nBoerne;29.7847\nNunna;16.5788\nKangaba;11.9333\nAmesbury;42.8530\nToledo;7.3131\nRentachintala;16.5524\nPoing;48.1667\nStreetsboro;41.2396\nCarovigno;40.7000\nRaspur Patasia;25.5616\nSītāmau;24.0147\nTecolotlán;20.2024\nMilledgeville;33.0874\nPeçanha;-18.5489\nBermeo;43.4200\nPodporozhye;60.9000\nShahritus;37.2667\nSalesópolis;-23.5319\nKinel’-Cherkassy;53.4683\nShongzhy;43.5417\nStuart;27.1959\nPeka;-28.9667\nBom Sucesso;-21.0328\nGrójec;51.8656\nSemra;26.6523\nChandia;23.6565\nGuoxing;24.0550\nWest Columbia;33.9932\nBaymak;52.5833\nErba;45.8167\nMiddlesex Centre;43.0500\nBakarpur Ogairah;25.3294\nBeckley;37.7877\nLérida;4.9000\nKodikulam;9.9932\nEggenstein-Leopoldshafen;49.0778\nFulshear;29.6930\nPiranga;-20.6850\nMula;38.0419\nXintangcun;23.9423\nTalsint;32.5398\nCalnali;20.9000\nAmbohipihaonana;-19.4333\nTamallalt;31.8289\nCacimba de Dentro;-6.6419\nKāmavarapukota;17.0033\nPiçarras;-26.7500\nVilla Isabela;19.8200\nSaint Ives;52.3344\nPinehurst;35.1922\nIlaka Atsinanana;-19.5531\nBawgalegyi;18.9144\nEl Rosario;13.5000\nMinakami;36.6786\nMinamichita;34.7151\nEl Segundo;33.9170\nFort Thomas;39.0801\nMurray;36.6146\nSão João dos Poleiros;-5.1139\nMohács;45.9959\nCham;49.2167\nCáqueza;4.4053\nPollensa;39.8772\nRibeirópolis;-10.5389\nClemson;34.6837\nÇukurca;37.2470\nGlenvar Heights;25.7090\nCamano;48.1865\nInverness;46.2000\nMassé;7.1578\nHīrna;9.2167\nPenzberg;47.7500\nBārnia;23.7311\nSada;43.3500\nTerre Neuve;19.6000\nUstka;54.5833\nCestas;44.7444\nChuarrancho;14.8167\nElbeuf;49.2858\nGuadarrama;40.6728\nNāyakanhatti;14.4644\nDour;50.3979\nHuruta;8.1500\nXianxi;24.1334\nAabenraa;55.0444\nTsuiki;33.6561\nPozoblanco;38.3833\nSanta Maria das Barreiras;-8.8550\nKozienice;51.5833\nMarienberg;50.6333\nSāyarpuram;8.6822\nMath Lohiyār;26.6247\nCondeixa-a-Nova;40.1167\nBarrington;41.7443\nFiorano Modenese;44.5333\nShoufeng;23.8667\nAraçagi;-6.8528\nLebanon;40.0324\nRubeho;-6.2578\nSantana do Cariri;-7.1878\nBalmazújváros;47.6167\nMebane;36.0852\nItirapina;-22.2528\nKarratha;-20.7364\nSaran;47.9514\nStony Plain;53.5264\nJičín;50.4367\nPetawawa;45.9000\nRāmāyampet;18.1166\nCampagna;40.6667\nBrzesko;49.9667\nCanudos;-9.9639\nSedan;49.7019\nLagoa Formosa;-18.7789\nRio Linda;38.6875\nAzaourissè;6.6944\nAdustina;-10.5328\nSaluzzo;44.6453\nRio Pomba;-21.2750\nBorda da Mata;-22.2739\nKonstantinovsk;47.5667\nBabenhausen;49.9667\nSidi Daoud;36.8500\nBloemhof;-27.6500\nKnaresborough;54.0084\nStafford;29.6271\nTraiguén;-38.2500\nElias Fausto;-23.0428\nGaneshpur;25.7678\nBurbaliq;40.3247\nFairview Park;41.4419\nBrixham;50.3940\nHannibal;39.7098\nEl Reno;35.5429\nDanville;37.6418\nUrucará;-2.5358\nPenamalūru;16.4681\nDilasag;16.4000\nGubin;51.9500\nCañon City;38.4430\nKruibeke;51.1667\nDefiance;41.2813\nWest Lampeter;39.9947\nBenešov;49.7828\nKusa;55.3500\nSão Vicente Férrer;-7.5908\nAnosibe-Ifanja;-18.8667\nEjea de los Caballeros;42.1292\nDouar Lamjaara;34.6147\nSa‘ādat Shahr;30.0775\nManlin;23.6630\nCapistrano;-4.4700\nJaboticatubas;-19.5139\nBelterra;-2.6358\nCodru;46.9753\nBroxburn;55.9340\nIgnacio de la Llave;18.6618\nAmarante;-6.2408\nHinsdale;41.8007\nLerum;57.7667\nGinatilan;9.6000\nSidi Yakoub;31.6667\nGainesville;33.6390\nPiñas;-3.6806\nShāhkot;31.0800\nLivinjipuram;8.1535\nXixinzhuangzhen;37.0165\nSan Juan del Sur;11.2533\nCastellaneta;40.6333\nXinlong;18.9534\nBasārh;25.9808\nZvenyhorodka;49.0833\nPontalina;-17.5258\nGurh;24.5026\nAvenel;40.5842\nBhit Bhagwānpur;26.1160\nRancho Mirage;33.7635\nLanderneau;48.4508\nKronach;50.2411\nLong’e;25.8061\nNandigaon;17.1190\nGeddes;43.0762\nRotselaar;50.9511\nWādī Ḩalfā’;21.8000\nLakhipur;26.2897\nSvitavy;49.7560\nSan Giovanni in Fiore;39.2642\nBargteheide;53.7167\nTolongoina;-21.5500\nKibungan;16.6939\nNavalmoral de la Mata;39.8983\nPreetz;54.2367\nMandritsara;-15.8333\nVilleneuve-Loubet;43.6581\nEppelborn;49.4022\nPodalakūr;14.3667\nEspartinas;37.3833\nYangi Mirishkor;38.8514\nAnosivelo;-22.7333\nTagounite;29.9833\nFerndale;39.1869\nNidgundi;16.7000\nTaxtako‘pir;43.0225\nTifton;31.4624\nNéa Mákri;38.0833\nPelham;43.0333\nAurora;41.3118\nFamy;14.4333\nKežmarok;49.1336\nAbelardo Luz;-26.5650\nOswego;43.4516\nResplendor;-19.3258\nNova Canaã;-14.7939\nKnemis Dades;31.3090\nAnalanampotsy;-17.1667\nThandla;23.0096\nEl Socorro;8.9936\nXinying;35.7060\nŁęczyca;52.0500\nBargūr;12.5429\nYabuki;37.2013\nConyers;33.6646\nIlakatra;-22.3500\nTullinge;59.2000\nMahires;34.5333\nSan Esteban;-32.7992\nCroatá;-4.4000\nSafety Harbor;28.0080\nChopadandi;18.5833\nCarmópolis de Minas;-20.5408\nRāmachandrapuran;17.3000\nStone;52.9000\nMacatuba;-22.5022\nSallanches;45.9364\nGhonchí;39.9589\nFundão;-19.9328\nTerrell;32.7340\nMartinsicuro;42.8833\nIluppur;10.5137\nGainesville;38.7931\nPiera;41.5222\nSadabe;-18.6333\nShklow;54.2236\nHindarx;40.0700\nGavrilov-Yam;57.3167\nAmbondromisotra;-20.3333\nMiqiao;35.4991\nGroves;29.9457\nOulad Amrane;32.2833\nXiulin;24.2167\nMenzelinsk;55.7333\nTorre Maggiore;41.6833\nMauguio;43.6164\nLos Lunas;34.8115\nDhulkot;21.6095\nMullānwāla;31.0619\nBan Cho Ho;15.0311\nDruzhba;41.2222\nÁgua Fria;-11.8669\nSchwarzenberg;50.5453\nDenville;40.8890\nHolzkirchen;47.8833\nStanley;53.7145\nAnnonay;45.2400\nTortum;40.2981\nSanto Tomás de Jánico;19.4000\nGrottammare;42.9897\nGunzenhausen;49.1147\nTurinsk;58.0333\nMilanoa;-13.5833\nAmbohitrolomahitsy;-18.7000\nPokrov;55.9117\nCapela;-9.4075\nHosakote;14.2817\nTsarahonenana;-15.4833\nSahamadio;-20.3000\nSelwyn;44.4167\nBruckmühl;47.8833\nArıcak;38.5644\nSeltso;53.3678\nKhutauna;26.4969\nSendurai;10.3934\nZafra;38.4167\nAsten;51.4000\nVedelago;45.6833\nEttaiyāpuram;9.1474\nSughrāin;25.7460\nFiliaşi;44.4000\nBefotaka;-14.5333\nNorwalk;41.2443\nPelitli;40.9833\nSint-Kruis;51.2117\nKhed;17.7189\nSan Miguelito;11.4025\nDzitbalché;20.3167\nAmbohitsimanova;-19.9500\nAntsahavaribe;-13.9833\nMarofoty;-22.9333\nManombo Atsimo;-22.9500\nAmbolidibe Atsinanana;-15.1000\nBykhaw;53.5167\nAshwaubenon;44.4796\nAntanimora Atsinanana;-24.8167\nLazarivo;-23.9000\nEtrotroka;-22.8833\nSeeheim-Jugenheim;49.7667\nAmbila;-21.9833\nDongjiangshui;33.3792\nDacaozhuang;37.5546\nRetiro;6.0572\nValencia;-0.9525\nAnkarongana;-15.4167\nCernavodă;44.3381\nSanta María;-26.6833\nAndranofasika;-16.3833\nCosta Marques;-12.4450\nHaslemere;51.0900\nLiuchuan;26.6549\nMarosangy;-21.0000\nGuben;51.9533\nNamysłów;51.0728\nLakhaura;26.7522\nWest Hempfield;40.0564\nMontagu;-33.7833\nBatuco;-33.2308\nBytów;54.1333\nMyrtle Grove;30.4158\nBeahitse;-24.1667\nAḑ Ḑulū‘īyah;34.0500\nScordia;37.3000\nSwansea;41.7571\nKompalle;17.4993\nRāmnagar;26.0773\nIsoanala;-23.8333\nSamarate;45.6167\nHuntington;40.8810\nRosário Oeste;-14.8358\nGaragoa;5.0833\nMiddelfart;55.4986\nLentate sul Seveso;45.6784\nMarahōm;33.8303\nLiuguoju;38.2571\nUsgao;15.4333\nKesath;25.4208\nSan Juan Lalana;17.4667\nPeñamiller;21.0519\nRātan;25.4349\nAiuaba;-6.5739\nSpringfield;40.6994\nLamas;-6.4167\nJericoacoara;-2.7939\nAshmyany;54.4250\nKelheim;48.9167\nGuisborough;54.5350\nPiriyāpatna;12.3365\nChettināyakkanpatti;10.3940\nBristol;36.6181\nMalta;42.9853\nSteffisburg;46.7667\nOsowa;54.4272\nGuadalupe Victoria;19.2833\nGrangemouth;56.0120\nSeara;-27.1489\nBhainsoda;24.4427\nVári;37.8333\nAreia Branca;-10.7578\nEscoublac;47.2858\nAsthānwān;25.2215\nSonāpur;25.3561\nCessnock;-32.8342\nBelle Glade;26.6916\nMiddletown;41.5175\nMattoon;39.4774\nAklanpa;8.1684\nGiaveno;45.0420\nAzeffoun;36.8961\nBelaur;25.4477\nJilotepec;19.6113\nReinheim;49.8269\nMugumu;-1.8333\nAbington;42.1180\nTourlaville;49.6408\nErumād;11.5681\nLoyalist;44.2500\nSanta Teresa;11.8039\nHeumen;51.7833\nKhirpai;22.7110\nFlowing Wells;32.2937\nAmbohimanambola;-18.9500\nNorthallerton;54.3378\nDomchānch;24.4748\nRipon;54.1380\nKalundborg;55.6814\nBelo;25.8747\nMarion;37.7345\nTobré;10.2000\nAcoyapa;11.9708\nTerra Santa;-2.1039\nLa Rinconada;-14.6325\nMátészalka;47.9500\nSarıoğlan;39.0833\nLa Sierpe;21.7606\nRiemst;50.8089\nSan Jacinto Amilpas;17.1006\nCêrro Azul;-24.8239\nPran Buri;12.3939\nBek’ojī;7.5833\nKrapkowice;50.4667\nLive Oak;36.9860\nFetromby;-18.5833\nKollūru;16.1833\nVadugappatti;10.1036\nDamascus;39.2701\nVatutine;49.0167\nTelua;26.6396\nAmérica Dourada;-11.4550\nSan José de Chiquitos;-17.8500\nSiloam Springs;36.1844\nFındıklı;41.1333\nBan Thung Tam Sao;6.9581\nMohanūr;11.0594\nBad Wörishofen;48.0058\nDēra;8.3333\nTubaran;7.7167\nIziaslav;50.1167\nBellingham;42.0777\nShelbyville;38.2067\nNeratovice;50.2593\nWestervoort;51.9667\nKaukauna;44.2773\nDormentes;-8.4469\nHennebont;47.8042\nSeverínia;-20.8089\nTurhāpatti;26.8511\nAgrate Brianza;45.5833\nBogatynia;50.9069\nRatba;34.7833\nKodala;19.6243\nRío Bueno;-40.3167\nBeldānga;24.8106\nDehāqān;31.9400\nSāhpur;25.7035\nShahbā;32.8542\nCalhoun;34.4910\nTakhatgarh;25.3300\nWest Haven;41.2083\nCinnaminson;40.0008\nTsundupalle;13.9809\nSão Caetano de Odivelas;-0.7500\nEaston;38.7760\nDilijan;40.7408\nJaparatuba;-10.5928\nUpper Gwynedd;40.2144\nFarmingville;40.8390\nZhukovka;53.5333\nMaşīf Sarsink;37.0333\nMorteros;-30.7000\nBürstadt;49.6333\nKumage;34.0495\nŌyodo;34.3906\nKatsuura;35.1500\nTichi;36.6675\nTrzcianka;53.0500\nSão Pedro do Sul;40.7500\nAlfajayucan;20.4000\nIchhāwar;23.2278\nVincennes;38.6759\nHajdúnánás;47.8500\nMitrapur;24.4371\nTongluo;24.4833\nMontbrison;45.6075\nAlto Santo;-5.5208\nBonito;-11.9658\nHünfeld;50.6667\n’Aïn Abessa;36.3000\nRoxana;10.3586\nMount Vernon;40.3854\nPosoltega;12.5447\nJanakkala;60.9167\nBridgeview;41.7403\nMarbach am Neckar;48.9333\nLa Quiaca;-22.1042\nTāwargeri;15.7667\nLeinì;45.1846\nStará Ľubovňa;49.3094\nSobrado de Paiva;41.0333\nHohenems;47.3667\nMedicina;44.4833\nKhaniādhāna;25.0298\nBina;26.0792\nMeiti;24.3517\nKajur;24.8768\nBoysun;38.2000\nBoden;65.8256\nQuepem;15.2200\nMidland;44.7500\nVilla Rica;33.7294\nUpper Saucon;40.5364\nEste;45.2333\nJāsk;25.6439\nPendleton;45.6757\nSin-le-Noble;50.3631\nBelaya Glina;46.0833\nEl Escorial;40.5817\nMeghauna;25.6904\nColwood;48.4236\nSinūnī;36.4575\nLeopoldshöhe;52.0167\nBella Vista;-22.1167\nWixom;42.5243\nDiksmuide;51.0333\nChinampa de Gorostiza;21.3667\nTruckee;39.3455\nPeriyakoduveri;11.4811\nTejuçuoca;-3.9889\nOuaouzgane;35.0167\nBandora;15.4082\nLocarno;46.1667\nVallegrande;-18.4833\nSāhar;26.5408\nAberdeen;46.9757\nLille;51.2333\nLibiąż;50.1000\nSaalfelden am Steinernen Meer;47.4269\nMonesiglio;44.4667\nBeinan;22.7833\nGrecia;10.0693\nWestchester;41.8492\nStrzegom;50.9611\nPanajachel;14.7361\nCampo do Brito;-10.7328\nIglino;54.8385\nSudak;44.8514\nFuying;40.8754\nBagnacavallo;44.4167\nNässjö;57.6500\nSidi Lamine;32.9000\nPindaí;-14.4928\nCâmpulung Moldovenesc;47.5308\nAuburn;42.1972\nJiblah;13.9167\nCayetano Germosén;19.3300\nSalūmbar;24.0800\nItariri;-24.2888\nBethlehem;-28.2240\nMadison;40.7586\nTromsdalen;69.6442\nSaidpur;25.5436\nPampa;35.5479\nAltıntaş;39.0615\nOcho Rios;18.4167\nWurzen;51.3667\nPedra Preta;-16.6228\nCentral Saanich;48.5142\nLa Paz;17.6739\nBan Nong Han;18.9000\nBuford;34.1192\nYağlıdere;40.9000\nŘíčany;49.9917\nDaireaux;-36.6000\nPatilār;27.0361\nPort Washington;40.8268\nBuntok;-1.7190\nUpper Chichester;39.8414\nOstrov;50.3060\nRājāpur;26.2861\nSumé;-7.6719\nAda;34.7662\nSan Roque;6.4853\nEkma;25.9670\nSimaria;24.7950\nKushima;31.4681\nLonigo;45.3833\nKauhava;63.1000\nVendôme;47.7928\nMikumi;-7.4072\nKlippansbruk;56.1167\nGraham;36.0589\nAnna;33.3472\nCarnaubal;-4.1669\nAdjahomé;7.0618\nEast Greenbush;42.6122\nGroßostheim;49.9167\nLaconia;43.5725\nLa Vista;41.1816\nStorrs;41.8083\nEl Piñón;10.4039\nJurāwanpur Karāri;25.5273\nMicoud;13.8190\nTerra Roxa d’Oeste;-24.1569\nCabeceiras de Basto;41.5333\nAue;50.5853\nLiangyi;35.2698\nBan Wang Nok Aen;16.8333\nIslāmpur;24.1513\nKawagoe;35.0167\nMadrid;9.2619\nVodil;40.1789\nTirmalgiri;17.4746\nKaiwen;27.1548\nKudatini;15.1500\nCeadîr-Lunga;46.0500\nKatosi;0.1528\nSūrappalli;11.7187\nShintomi;32.0689\nAston;39.8719\nSainte-Catherine;45.4000\nBhagwāngola;24.3485\nPotirendaba;-21.0428\nChorfa;36.3617\nIllzach;47.7822\nPozos;9.9536\nPort Hope;43.9500\nAyyampālaiyam;10.2253\nCerea;45.2000\nDhusar Tikāpatti;25.5214\nMoraga;37.8439\nCaravaggio;45.4978\nMachelen;50.9103\nErvādi;9.2500\nBad Lippspringe;51.7833\nCountry Club Hills;41.5636\nWyckoff;40.9989\nDouar Tabouda;34.7167\nYerbas Buenas;-35.7500\nTurgutreis;37.0167\nFort Carson;38.7095\nDonna;26.1468\nPonte de Sôr;39.2500\nSeacombe;53.4090\nLa Cruz;1.6047\nNovomichurinsk;54.0500\nMerchtem;50.9667\nSaint-Basile-le-Grand;45.5333\nMariestad;58.7000\nPovorino;51.2000\nSan Juan;9.1590\nMurehwa;-17.6500\nAl Mazār ash Shamālī;32.4725\nSeymour;41.3810\nRygge;59.3747\nHernando;34.8500\nAnamorós;13.7333\nFrancheville;45.7364\nUkiah;39.1464\nSidi Ettiji;32.1717\nKhirbat Ghazālah;32.7333\nMonsenhor Tabosa;-4.7889\nChestnuthill;40.9568\nSunagawa;43.4948\nMadhuban;26.4386\nMenomonie;44.8893\nUherský Brod;49.0251\nZirara;32.3500\nColle Salvetti;43.6000\nPorto Empedocle;37.2944\nGālivedu;14.0333\nCapurso;41.0500\nMensora;34.8356\nUbrique;36.6833\nKade;6.0833\nCenterville;40.9284\nAnsfelden;48.2083\nIbicuí;-14.8419\nWentang;23.9918\nIbitiara;-12.6519\nPipra Latīf;25.3579\nPochëp;52.9333\nTantéga;10.8500\nTiahounkossi;10.8167\nIllingen;49.3764\nRumilly;45.8667\nZumarraga;11.6390\nManamelkudi;10.0419\nPowder Springs;33.8659\nRāikal;18.9000\nKāmayakkavundanpatti;9.7386\nYoshinogari;33.3212\nZequ;35.0376\nHueytown;33.4239\nMariyammanahalli;15.1600\nBālasamudram;10.4190\nJamālpur;25.9549\nRožnov pod Radhoštěm;49.4585\nPôrto Murtinho;-21.6989\nUjre;12.9961\nSegbwema;8.0000\nGasparillo;10.3167\nMarui;24.8639\nBeek;50.9333\nPrinceton;33.1778\nBanbridge;54.3430\nPuerto Pilón;9.3600\nRājāsūr;17.8600\nTodi;42.7789\nPalagonia;37.3333\nBan Na Sai;17.7334\nFederación;-30.9833\nReggello;43.6833\nShiraoi;42.5512\nJinji;22.1650\nChorbogh;39.8667\nMillbrook;32.5027\nZeulenroda;50.6486\nGrimari;5.7167\nMennecy;48.5653\nHorad Smalyavichy;54.1000\nEast Highland Park;37.5770\nChittayankottai;10.2686\nNoale;45.5501\nAladağ;37.5465\nLake St. Louis;38.7846\nHarborcreek;42.1498\nWashougal;45.5825\nDallas;44.9221\nCodogno;45.1600\nMiyazu;35.5333\nAñisoc;1.8500\nĪlkhchī;37.9378\nBrunico;46.7963\nĀdra;23.5000\nMangueirinha;-25.9408\nSainte-Luce-sur-Loire;47.2494\nBarkot;30.8200\nAl Laţāminah;35.3208\nLong Beach;30.3608\nKājha;25.7747\nOdumase;7.3667\nKhargāpur;24.8230\nNorthenden;53.4075\nDenby Dale;53.5720\nTirhassaline;32.7833\nFalköping;58.1750\nAd Dīs;14.9100\nMifune;32.7146\nSanta María Petapa;16.8167\nBolivia;22.0750\nTapes;-30.6728\nKovdor;67.5594\nNakanoto;36.9889\nBacuri;-1.7028\nHannut;50.6667\nHatti;16.1984\nDigne-les-Bains;44.0925\nZhutian;22.5890\nGuaymate;18.5800\nIppy;6.2500\nÁgua Branca;-5.8900\nZapotlán de Juárez;19.9667\nGryfice;53.9147\nVesoul;47.6222\nRājnagar;24.8893\nRamón Santana;18.5500\nLumbreras;37.5633\nUmbertide;43.3000\nZhytkavichy;52.2333\nPeer;51.1328\nBatán;10.1041\nXinyuan;37.2953\nChełmża;53.1847\nIna;9.9833\nSwift Current;50.2881\nPupiales;0.8667\nHumble;29.9921\nSłubice;52.3500\nVemuladīvi;16.3408\nValdez;1.2500\nFairview Heights;38.5974\nMacetown;-44.8650\nSan Estanislao;10.4000\nBenipati;26.4442\nRed Wing;44.5817\nJohnstown;40.3499\nBeaver Dam;43.4688\nPunta Umbría;37.1667\nGuardamar del Segura;38.0897\nMorton;40.6135\nObra;24.8910\nSaraikela;22.6996\nGangāpur;25.5136\nShamsa;25.6230\nKirchlengern;52.2000\nBuritama;-21.0667\nChampāpur;26.8881\nCorabia;43.7736\nKurtamysh;54.9167\nAhmetli;38.5289\nWyke;53.7333\nKota;14.0333\nKeflavík;64.0167\nPirque;-33.6333\nEdmundston;47.3765\nCristinápolis;-11.4758\nBluffdale;40.4744\nBree;51.1333\nChinde;-18.5833\nWeybridge;51.3620\nBrackenheim;49.0833\nCentre de Flacq;-20.2002\nFiano Romano;42.1667\nHønefoss;60.1667\nBirsinghpur;24.7981\nNobsa;5.7667\nÇarşıbaşı;41.0833\nBesana in Brianza;45.7000\nFranklin;39.5954\nQuarteira;37.0690\nḨammām al ‘Alīl;36.1581\nLoxstedt;53.4699\nBerezan;50.3197\nHorodok;49.1667\nNanbu;40.4206\nYaypan;40.3758\nPalanisettipatti;9.9998\nSégou;6.6167\nRāhon;31.0527\nUchkeken;43.9333\nHampton Bays;40.8695\nLangenthal;47.2167\nBan Lam Narai;15.2000\nBayat;40.6460\nCelina;33.3154\nAz Zaydīyah;15.3292\nPedregulho;-20.2569\nCharqueada;-22.5097\nCiney;50.3000\nMapiri;-15.2500\nLugu;23.7500\nChennūr;14.5667\nGarðabær;64.0833\nDifferdange;49.5222\nSrīmushnam;11.4012\nHövelhof;51.8167\nChâteaurenard;43.8825\nSaint-Amand-les-Eaux;50.4481\nIvanava;52.1333\nPetersberg;50.5667\nQarqīn;37.4128\nMastchoh;40.3667\nBobangui;4.0500\nSantomera;38.0617\nRussell;45.2569\nAntanambao Mahatsara;-19.3167\nSultānābād;18.5333\nMaruim;-10.7378\nSānātikri;22.0198\nAl Ghāţ;26.0267\nKarema;-6.8205\nKisvárda;48.2167\nMakhu;31.1033\nLangrucun;36.9014\nSabotsy;-19.2333\nBady Bassitt;-20.9178\nLongchang;27.6627\nSan Miguel;11.4920\nDison;50.6167\nZhongzai;26.6877\nSaunshi;15.2167\nNyahanga;-2.3829\nRegenstauf;49.1236\nTōhoku;40.7279\nTadikalapūdi;16.8991\nTafresh;34.6919\nAz Zuwāydah;31.4284\nBelén;11.5028\nChangji;26.9471\nToro;4.6117\nDinmānpur;25.9112\nSunland Park;31.8201\nLoimaa;60.8500\nBarbacoas;9.4833\nKirchhain;50.8167\nHarenkarspel;52.7344\nClevelândia;-26.3958\nCloverly;39.1064\nYunshan;34.7610\nAmbohimalaza;-18.9167\nJadia;26.0937\nRakovník;50.1038\nDouglas;31.3602\nKozelsk;54.0353\nLoma Plata;-22.3833\nClearlake;38.9589\nBovolone;45.2500\nVienna;38.8996\nJakkampālaiyam;10.5264\nSlaný;50.2305\nBilohirsk;45.0544\nItaeté;-12.9858\nTasīl;32.8353\nLake Mary;28.7592\nAnorí;7.0736\nPocking;48.4000\nChittūr;11.6470\nLas Cabezas de San Juan;36.9817\nMcKinleyville;40.9488\nArteche;12.2694\nOdaiyakulam;10.5679\nBan Samo Khae;16.8408\nHayes;51.3780\nTaohongpozhen;36.9854\nDilārpur;25.3968\nHarlingen;53.1736\nTurkaguda;17.2728\nRolleston;-43.5833\nOlecko;54.0333\nStraelen;51.4500\nNorth Grenville;44.9667\nIspica;36.7833\nAl Ḩībah;28.7736\nShuili;23.7989\nPanukulan;14.9333\nPātapatnam;18.7500\nAngara-Débou;11.3289\nVerrières-le-Buisson;48.7475\nIslām Qal‘ah;34.6667\nBruntál;49.9883\nSava;40.4003\nĀgiripalle;16.6833\nSandhausen;49.3439\nRajni;25.8132\nLes Herbiers;46.8711\nAlegria;9.4667\nAgudo;-29.6450\nDomoni;-12.2586\nSpárti;37.0739\nBoshrūyeh;33.8683\nCuracautín;-38.4333\nVerkhivtseve;48.4812\nSouth Venice;27.0444\nBosobolo;4.1833\nUckfield;50.9700\nCenter Point;33.6447\nDyer;41.4977\nPortachuelo;-17.3572\nNeykkārappatti;10.4489\nAnantapalle;16.9767\nLa Falda;-31.0833\nSebt Aït Saghiouchen;34.0122\nChai Prakan;19.7322\nErlensee;50.1333\nJambaló;2.8500\nBangor;53.2280\nHeber;40.5070\nBissegem;50.8167\nChinácota;7.6167\nSchmelz;49.4167\nBanigbé;6.9000\nÉghezée;50.5833\nAddison;32.9590\nHerisau;47.3833\nTelfs;47.3069\nKannampālaiyam;10.9954\nCopparo;44.9000\nCotorra;9.0500\nMarkranstädt;51.3017\nWittstock;53.1636\nBaipingshan;26.1960\nWolf Trap;38.9395\nBeko;24.0415\nAcarape;-4.2242\nPenicuik;55.8260\nUstroń;49.7194\nThompson;41.6474\nDo‘stobod;40.8564\nDamdama;24.6300\nPrzeworsk;50.0667\nCarcarañá;-32.8500\nHam Lake;45.2545\nPearl River;41.0615\nBālkonda;18.8667\nEast Longmeadow;42.0597\nHebli;15.4858\nBassum;52.8494\nRealeza;-25.7669\nHuliyār;13.5833\nDivriği;39.3667\nCodroipo;45.9625\nNawada;25.5431\nPorumāmilla;15.0167\nSopelana;43.3814\nHude;53.1111\nChiva;39.4714\nMontivilliers;49.5461\nSahatavy;-17.4489\nEilenburg;51.4608\nFillmore;34.3989\nMiddletown;39.9094\nSan Dionisio;12.7625\nMomil;9.2333\nNorth Decatur;33.8074\nWarragul;-38.1500\nDouar Azla;35.5564\nKarambakkudi;10.4587\nVilla San José;-32.2000\nBrakel;51.7167\nSolapuram;9.3757\nSultonobod;38.4500\nNovoukrainka;48.3156\nBang Phae;13.6983\nIsrāin Kalān;25.9844\nSananduva;-27.9500\nKierspe;51.1333\nKallūr;17.2000\nNéa Alikarnassós;35.3167\nOtacílio Costa;-27.4828\nPinhalzinho;-26.8478\nBingawan;11.2333\nŌarai;36.3133\nGrosse Pointe Woods;42.4366\nTroutdale;45.5372\nGuelendeng;10.9183\nEl Peñol;6.2186\nDieburg;49.9000\nNarlıca;36.2333\nWardenburg;53.0617\nNew Port Richey;28.2468\nRestrepo;3.8250\nOrimattila;60.8042\nPuerto Pimentel;-6.8367\nSunnyside;46.3157\nYorkton;51.2139\nCorbélia;-24.7989\nEllington;41.9152\nAranyaprathet;13.6928\nOyten;53.0611\nOurém;-1.5478\nMichelstadt;49.6786\nPalagiano;40.5833\nShahriston;39.7667\nPeddaboddepalle;17.6606\nChamgardān;32.3936\nHalver;51.1833\nTarquinia;42.2492\nQueensbury;53.7683\nMusāpur;25.6417\nOstashkov;57.1500\nVillalbilla;40.4339\nSchiffweiler;49.3667\nFort Hunt;38.7361\nPonsacco;43.6167\nMorro da Fumaça;-28.6508\nLeopoldsburg;51.1169\nBelāri;25.9655\nFaxinal;-24.0008\nWiefelstede;53.2581\nPoplar Bluff;36.7632\nAlbemarle;35.3594\nYotoco;3.8667\nAcahay;-25.9100\nLyss;47.0667\nVallirana;41.3878\nLemay;38.5325\nWalldorf;49.3000\nOpa-locka;25.8997\nGuérande;47.3281\nStahnsdorf;52.3922\nTimezgana;34.5833\nLeso;11.6697\nNovoanninskiy;50.5333\nGarou;11.8053\nSusanville;40.4206\nSabana de La Mar;19.0700\nAdjud;46.1000\nAmbalabe;-15.1667\nPonders End;51.6460\nKodikkulam;9.6493\nKumiyama;34.8814\nBikou;32.7522\nCarlet;39.2264\nOspitaletto;45.5553\n’Ayn Bni Mathar;34.0889\nNorthbridge;42.1300\nMontalvânia;-14.4228\nBorodino;55.9056\nSayville;40.7478\nTiverton;41.6090\nChaona;35.0895\nKabo;7.6994\nFrogn;59.6989\nKotoura;35.5000\nAntsahanoro;-14.8333\nCrawfordsville;40.0428\nNanzuo;37.8369\nCivita Castellana;42.2961\nLeixlip;53.3643\nNiepołomice;50.0339\nAdwick le Street;53.5677\nGeneral Villegas;-35.0333\nMercedes;26.1533\nRansiki;-1.5000\nChâteau-Thierry;49.0464\nConcepción;-11.9185\nSadhoa;25.4049\nPetrovsk-Zabaykal’skiy;51.2667\nSan Antonio Oeste;-40.7333\nBan Kao;13.8667\nXiaozhengzhuang;39.6250\nSanta Cruz Muluá;14.5833\nBrahmadesam;11.5449\nPallappatti;10.3564\nErwitte;51.6167\nOlivehurst;39.0795\nWelby;39.8403\nHilltown;40.3415\nMezőkövesd;47.8167\nLlanquihue;-41.2581\nDewangarh;24.8637\nShāhpur;23.8937\nPorto Belo;-27.1578\nLanden;50.7547\nVero Beach;27.6463\nSered’;48.2886\nHathīaundha;25.7223\nHorodok;49.7822\nBenjamín Aceval;-24.9703\nBruck an der Mur;47.4106\nGangoli;13.6500\nMerimandroso;-18.7500\nCarhué;-37.1796\nUpala;10.8645\nSapatgrām;26.3373\nNonantola;44.6777\nWestport;41.5886\nIgaporã;-13.7728\nAndemaka;-22.3000\nZegzel;34.8407\nVemulūru;16.9337\nUdayagiri;14.8667\nPerchtoldsdorf;48.1167\nBois-Guillaume;49.4700\nHermitage;41.2305\nAmpahimanga;-19.0833\nYaojia;28.4547\nMerate;45.7000\nPianezza;45.1058\nWülflingen;47.5100\nLagoa do Carro;-7.8450\nCertaldo;43.5478\nGroßenkneten;52.9500\nMoreau;43.2469\nDyersburg;36.0465\nIshtixon Shahri;39.9664\nAraputanga;-15.4708\nWolcott;41.6007\nChautham;25.5439\nJasper;38.3933\nChilgazí;40.1500\nPayson;34.2433\nBuwama;0.0633\nClausthal-Zellerfeld;51.8050\nMistrató;5.3000\nBīleh Savār;39.3778\nÇaykara;40.7475\nHibbing;47.3980\nSan Pedro de Lloc;-7.4167\nJhandāpur;25.3995\nWendelstein;49.3536\nGalliate;45.4833\nBreaza;45.1872\nKolakalūru;16.3036\nFenoarivo;-23.1167\nSan Antonio Palopó;14.7000\nFairburn;33.5496\nIkast;56.1333\nSanta Anita;30.4500\nSan Gabriel;0.5983\nTahlequah;35.9112\nGriffith;41.5277\nAlabat;14.1023\nKöprüköy;39.9756\nElandakuttai;11.3992\nSan Cesareo;41.8167\nFenoarivo;-20.8667\nBouchabel;34.3833\nRadford;37.1229\nConwy;53.2800\nZulte;50.9167\nĀbīy Ādī;13.6231\nPonto Novo;-10.8619\nKujwa;33.5025\nCaidat Sidi Boubker El Haj;34.9148\nTaucha;51.3800\nOuadhia;36.5500\nTangainony;-22.7000\nAltinópolis;-21.0231\nSubachoque;4.9281\nLes Sables-d’Olonne;46.4972\nMasmouda;34.7862\nAlpedrete;40.6583\nTrélazé;47.4461\nBurrillville;41.9706\nSardoba;40.5422\nTotteridge;51.6354\nBarra de Santo Antônio;-9.4000\nGavinivāripālem;15.8378\nBabayurt;43.6003\nPuduppatti;11.5500\nBar;49.0781\nHuarmey;-10.0686\nLewes;50.8747\nBumpe;7.8919\nSulechów;52.0833\nNowogard;53.6667\nPelhřimov;49.4314\nYurihama;35.4899\nSanta Ana;13.9333\nAberdeen;39.5151\nAs Sukhnah;34.8868\nKhaira;26.3433\nParma;43.2651\nLake Wales;27.9195\nSāyalkudi;9.1692\nFinsterwalde;51.6282\nPursa;26.3019\nRylsk;51.5667\nBrüggen;51.2417\nSão Pedro do Sul;-29.6208\nSkhour Rehamna;32.4833\nAmarwāra;22.2978\nTankal;8.0000\nVontimitta;14.3833\nFüssen;47.5667\nHampton;42.9391\nOwase;34.0708\nGetúlio Vargas;-27.8900\nSeven Pagodas;12.6208\nTarqui;2.1106\nTaylor;30.5729\nPotenza Picena;43.3667\nUkrainka;50.1500\nBni Tajjit;32.2833\nRopczyce;50.0500\nCaldera;-27.0667\nPaidiipalli;18.0172\nParrita;9.5471\nSukth;41.3833\nHasanpur;26.1147\nToul;48.6750\nAmericus;32.0736\nAruvikkara;8.4219\nBaléyara;13.7840\nWest Norriton;40.1308\nAki;33.5000\nMezőtúr;47.0000\nWarrington;30.3835\nVardannāpet;17.7735\nBni Quolla;34.7380\nBad Essen;52.3214\nLos Muermos;-41.4000\nSassenheim;52.2258\nAmbarakaraka;-13.5000\nNdioum;16.5167\nFrankfort;40.2810\nColonial Park;40.2987\nCoulommiers;48.8156\nSpanish Springs;39.6568\nFullerton;40.6309\nMölnlycke;57.6667\nQazyan;40.4425\nAntadinga;-22.1500\nCunit;41.1976\nUtnūr;19.3667\nHongsi;35.5113\nSanta Marta de Tormes;40.9494\nSaint-Avertin;47.3667\nEbersbach an der Fils;48.7147\nCalera;33.1254\nChinggil;46.6660\nKālikāpur;26.4956\nWeener;53.1692\nAndapafito;-16.9167\nUndi;16.6000\nSamsikāpuram;9.4156\nBuffalo;45.1794\nRasulpur Dhuria;25.5693\nQuiindy;-25.9730\nEasthampton;42.2651\nCsongrád;46.7113\nVieux Fort;13.7280\nAltopascio;43.8167\nKodinsk;58.6833\nChāilāha;26.6738\nValmontone;41.7833\nMahavelona;-18.5167\nTracadie;47.5124\nTernat;50.8667\nAlsfeld;50.7511\nDalachi;36.6392\nMinamiminowa;35.8729\nKanan;34.4917\nŞemdinli;37.3080\nQuezon;14.0500\nBad Bentheim;52.3031\nFartura;-23.3883\nPrinzapolka;13.5008\nChenôve;47.2911\nJitwārpur Kumhra;25.7852\nMananasy-Tsitakondaza;-19.1500\nDegtyarsk;56.7000\nAquitania;5.5833\nReadington;40.5822\nMatelândia;-25.2408\nHüyük;37.9519\nHariharpāra;24.0468\nCipanas;-6.7330\nSérarou;9.5833\nVenturosa;-8.5747\nMyrza-Ake;40.7500\nBarharwā;24.8571\nKhat Azakane;32.2226\nQarabulaq;44.9089\nFiadanana;-20.8667\nBeaucaire;43.8072\nAlcañiz;41.0511\nNagasu;32.9297\nThundersley;51.5700\nClarksburg;39.2862\nGlória;-9.3389\nShāhpura;23.1366\nLéré;15.7117\nLübbenau/Spreewald;51.8667\nPaola;39.3667\nDespujols;12.5183\nAmbohibe;-17.4500\nFederal;-30.9500\nLeanja;-15.5500\nAndrorangavola;-20.5167\nHeggadadevankote;12.0881\nVijayapuri North;16.6028\nAntarvedi;16.3333\nDarién;3.9167\nNaivasha;-0.7167\nAmbalatany;-22.5333\nIssoire;45.5442\nAlarobia;-18.9667\nSchlüchtern;50.3500\nDublin;32.5360\nMount Pleasant;33.1586\nBetanty;-25.5667\nWestwood;42.2202\nPalmitos;-27.0678\nZunil;14.7836\nSāligrāma;12.5602\nBoudjima;36.8140\nCarterton;51.7600\nStäfa;47.2400\nDinan;48.4556\nNeustadt in Holstein;54.1072\nVohiposa;-20.9833\nTachiarai;33.3724\nRed Hill;33.7777\nL’Oulja;34.2894\nDoğanhisar;38.1447\nRiver Falls;44.8609\nTsiningia;-15.4833\nVohilengo;-22.5333\nRanohira;-22.4333\nDoria Sonāpur;26.1830\nSikeston;36.8854\nBay Village;41.4851\nAzzano Decimo;45.8833\nSansepolcro;43.5756\nDūbacherla;16.9116\nTaromske;48.4619\nInanantonana;-19.6500\nBambous;-20.2600\nHetton le Hole;54.8210\nMaigh Nuad;53.3816\nBevonotra;-14.0500\nSveti Ivan Zelina;45.9596\nGrandville;42.9004\nMajdal Shams;33.2692\nAntindra;-14.1333\nNova Ipixuna;-4.9208\nAnjangoveratra;-14.1333\nMilford;42.8178\nTürkeli;41.9486\nMohanpur Gaughāta;25.3345\nSouth Middleton;40.1324\nCorbera de Llobregat;41.4169\nKumārīpur;25.4425\nTodmorden;53.7130\nDianga;34.0587\nChornobaivka;46.7006\nDhemāji;27.4833\nTizi-n-Tleta;36.5457\nAnalila;-14.4500\nBitburg;49.9667\nForks;40.7358\nAz Zintān;31.9306\nPornic;47.1156\nAntsenavolo;-21.4000\nBuçimas;40.8917\nKasli;55.9000\nTarascon;43.8050\nManompana;-16.6833\nMangabe;-16.7167\nSan Tomas;15.8792\nVīraghattam;18.6833\nProspect Heights;42.1039\nAnkazondandy;-18.6833\nBilpura;23.2216\nShchigry;51.8667\nManturovo;58.3333\nVillers-lès-Nancy;48.6731\nRâşnov;45.5933\nNeston;53.2890\nBekitro;-24.5500\nFīshvar;27.7975\nYorito;15.0600\nMandrosonoro;-20.5833\nPiancó;-7.1978\nBracebridge;45.0333\nŚwidwin;53.7833\nKings Park;40.8881\nWashington;40.7050\nKastsyukovichy;53.3333\nSan Miguel Dueñas;14.5167\nBan Dung;17.6986\nDuxbury;42.0465\nSummerfield;38.9042\nKamyzyak;46.1167\nAlloa;56.1160\nKafia Kingi;9.2731\nVlagtwedde;52.9500\nCaetano;-14.3378\nPamiers;43.1164\nDarpa;26.8400\nTanakpur;29.0740\nGatesville;31.4445\nChiconquiaco;19.7500\nYaransk;57.3167\nÜsharal;46.1697\nPoço Fundo;-21.7808\nBarysh;53.6500\nChervonopartyzansk;48.0833\nSanta Catalina;17.5917\nWest Richland;46.3115\nErnagūdem;17.0020\nBastogne;50.0042\nChivolo;10.0261\nAndroy;-21.3333\nGanjām;19.3870\nHaddada;34.2236\nSabana Grande de Palenque;18.2667\nPochampalli;17.3473\nGargždai;55.7128\nGhomrassen;33.0592\nMurraysville;34.2919\nAvalpūndurai;11.2310\nMiddleburg Heights;41.3696\nYelur;15.7817\nPuliyūr;10.9499\nKyabé;9.4514\nCalbuco;-41.7667\nChembagarāmanpudūr;8.2461\nHot Springs Village;34.6566\nCoquimbito;-32.9667\nMuscle Shoals;34.7432\nDehaq;33.1047\nKadaiyam;8.8320\nBlanquefort;44.9106\nPawai;24.2664\nMiddle Smithfield;41.0918\nDunaivtsi;48.8873\nBhagta;30.4882\nRipon;37.7417\nBatalha;39.6500\nƏrkivan;39.0183\nSahambala;-17.9417\nKumaralingam;10.4894\nXixucun;36.6940\nVatomandry;-19.3308\nFremont;41.3535\nAugustinópolis;-5.4658\nRescaldina;45.6167\nTalitsa;57.0167\nAveiro;-3.6058\nEsquipulas;12.6639\nSan Julián;61.5240\nFirestone;40.1565\nBocşa;45.3747\nTarancón;40.0167\nBrofodoumé;5.5167\nPlavsk;53.7167\nContenda;-25.6758\nGalván;18.5039\nChhāpia;26.0831\nJitwārpur Nizāmat;25.8489\nCastanet-Tolosan;43.5156\nThe Dalles;45.6053\nSaraland;30.8479\nLidzbark Warmiński;54.1167\nChitila;44.5083\nBikin;46.8167\nMaardu;59.4781\nJastrebarsko;45.6719\nLa Grange;41.6787\nAramil;56.7000\nLuzhou;23.3687\nRutland;43.6092\nMarghita;47.3500\nStallings;35.1088\nAmāri;25.7179\nNorth Fayette;40.4204\nKolnād;12.9000\nVolpiano;45.2000\nMarco Island;25.9330\nSan Martino Buon Albergo;45.4167\nAïn Mediouna;34.5000\nComarapa;-17.9158\nTabatinga;-21.7169\nBellevue;44.4592\nNew Haven;41.0676\nCoos Bay;43.3789\nMuhammadābād;16.8731\nMaryborough;-25.5375\nBredasdorp;-34.5333\nGardendale;33.6677\nDassari;10.8158\nPoxoréo;-15.8369\nMottola;40.6333\nSertã;39.8000\nTocantins;-21.1750\nFairhaven;41.6394\nCardonal;20.6167\nRoh;24.8905\nSão Paulo do Potengi;-5.8950\nOverland;38.6966\nCurtorim;15.2800\nKönigslutter am Elm;52.2500\nBeernem;51.1428\nSan Bartolomé Jocotenango;15.1928\nWarsaw;41.2448\nJoaquim Nabuco;-8.6239\nEzzhiliga;33.3000\nPuraini;25.5968\nRichmond Hill;31.9012\nLewiston;43.1793\nTamazouzt;31.3833\nFort Drum;44.0450\nDvůr Králové nad Labem;50.4331\nBituruna;-26.1608\nSidi Allal el Bahraoui;33.9830\nBerea;34.8802\nGreater Napanee;44.2500\nBreisach am Rhein;48.0333\nSkvyra;49.7333\nJulita;10.9731\nAl Mu‘abbadah;37.0164\nYuvileine;48.5531\nIvdel;60.6833\nNuth;50.9167\nAldine;29.9123\nPichhor;25.9602\nOpelousas;30.5252\nVoss;60.7025\nBudakeszi;47.5123\nKatav-Ivanovsk;54.7500\nHedongcun;37.7546\nIndiaroba;-11.5189\nGiruá;-28.0278\nSakhā;31.0881\nMiguelturra;38.9667\nCasalpusterlengo;45.1778\nPonnamarāvati;10.2803\nUdayendram;12.6962\nGalatone;40.1500\nRumst;51.0833\nCoto de Caza;33.5959\nChhājli;30.0348\nWaterville;44.5441\nFort Mohave;35.0004\nTillsonburg;42.8667\nInce-in-Makerfield;53.5402\nKabayan;16.6233\nMachang;33.1912\nWadern;49.5167\nMandialaza;-18.6167\nSaint-Avold;49.1042\nBariariyā;26.5105\nJoão Neiva;-19.7578\nSt. Simons;31.1775\nAit Yazza;30.5063\nSuffield;41.9945\nLongmeadow;42.0475\nMountain Home;43.1324\nVatlūru;16.7009\nTsukumiura;33.0667\nHilvarenbeek;51.4833\nKavarna;43.4333\nSeshambe;38.5333\nAdrasmon;40.6486\nJussara;-11.0469\nIxhuatlán del Sureste;18.0170\nHollins;37.3434\nOverpelt;51.2167\nFos-sur-Mer;43.4544\nDixon;41.8439\nDickson;36.0637\nRakovski;42.2884\nBaeza;37.9833\nBarrocas;-11.5289\nAsh Shaddādah;36.0561\nSulat;11.8167\nAmawom;5.4667\nBāisāri;22.7900\nWarren;40.6323\nChenlu;35.0287\nGonohe;40.5312\nDerzhavīnsk;51.1000\nKumano;33.8886\nIbateguara;-8.9728\nExeter;42.9901\nPatton;40.8258\nKünzelsau;49.2833\nItaquitinga;-7.6678\nAmmūr;12.9750\nSurbo;40.4000\nJataúba;-7.9900\nCarugate;45.5500\nPhulwār;26.8148\nNioro du Rip;13.7500\nAnkli;16.4200\nSkalica;48.8422\nKalininsk;51.5000\nMount Dora;28.8142\nBalīgaon;25.4196\nSteinbach;49.5258\nLagunia Surajkanth;25.8304\nBiritinga;-11.6169\nCastillo;19.2200\nMuttunāyakkanpatti;11.7125\nPatos;40.6833\nBad Neustadt;50.3219\nSulphur Springs;33.1421\nLithia Springs;33.7811\nMatuga;0.4603\nMamadysh;55.7131\nNymburk;50.1861\nJamestown;46.9063\nKurāwar;23.5118\nJózefosław;52.1005\nVakhsh;37.7108\nTaurianova;38.3500\nSanta Rosa;-33.2500\nHaftkel;31.4469\nChilamattūru;13.8394\nKerman;36.7248\nLagoa Real;-14.0350\nTorelló;42.0492\nBabhangāwān;25.3674\nOvruch;51.3244\nVerkhnodniprovsk;48.6561\nDiang;4.5833\nSaint-Omer;50.7483\nRas el Oued;34.1500\nHarduli;22.9278\nJuma Shahri;39.7161\nPutyvl;51.3347\nLower Salford;40.2639\nYasnyy;51.0500\nSan Miguel;13.6411\nGoubellat;36.5333\nSanta Cruz de la Palma;28.6825\nMaddikera;15.2500\nMacedo de Cavaleiros;41.5389\nMelonguane;4.0045\nPereiro;-6.0450\nCastenaso;44.5097\nUlladulla;-35.3486\nPlochingen;48.7117\nOmegna;45.8781\nFontainebleau;48.4089\nItajibá;-14.2839\nHautmont;50.2481\nAlūr;15.3944\nHolly Springs;34.1681\nSanta Úrsula;28.4253\nTalladega;33.4333\nUusikaupunki;60.8000\nPijiño del Carmen;9.3333\nVictor;42.9894\nChinnavādampatti;11.0615\nBad Bramstedt;53.9186\nKyazanga;-0.3864\nNiederkrüchten;51.1989\nAcajutiba;-11.6619\nGuasca;4.8658\nKorsør;55.3336\nAbadiânia;-16.2039\nChokkanāthapuram;9.9921\nSanta Cecília;-26.9608\nCassina de’ Pecchi;45.5167\nKalocsa;46.5335\nHighland Village;33.0897\nMolinella;44.6167\nCrixás;-14.5489\nSaboeiro;-6.5419\nSilvi Paese;42.5500\nWeißwasser/Oberlausitz;51.5000\nRestinga Sêca;-29.8128\nFunyan Bīra;9.3500\nErshui;23.8167\nMiyota;36.3223\nWenwu;24.7413\nMatsushige;34.1339\nBarajor;24.7992\nBarod;23.7889\nZaṟah Sharan;33.1300\nJiaojiazhuang;38.2636\nSimmerath;50.6000\nUdala;21.5781\nGrenzach-Wyhlen;47.5517\nDrensteinfurt;51.7944\nCuarte de Huerva;41.5833\nGeneral Pinedo;-27.3167\nBunnik;52.0500\nAscheberg;51.7889\nKasumi;35.6333\nMvurwi;-17.0167\nGuinguinéo;14.2667\nIguatemi;-23.6800\nSan Giorgio Ionico;40.4500\nVellālāpuram;11.6525\nMorretes;-25.4769\nGlenn Heights;32.5506\nSi Satchanalai;17.4155\nPakaryā Harsidhi;26.6526\nTalaināyar Agrahāram;10.5614\nAartselaar;51.1333\nArumbāvūr;11.3810\nMount Clemens;42.5977\nMallāpuram;11.9823\nHanover;49.4433\nKela Khera;29.0900\nTēkkampatti;11.2559\nSpittal an der Drau;46.7917\nCoelemu;-36.4878\nFinale Emilia;44.8333\nSebt Bni Smith;35.1373\nUlverstone;-41.1667\nOswestry;52.8598\nElkton;39.6066\nRiposto;37.7333\nTerrace;54.5164\nYasnogorsk;54.5000\nTīrān;32.7025\nRattihalli;14.4167\nChapelle-lez-Herlaimont;50.4667\nYazu;35.4092\nMaskanah;35.9632\nKukkundūr;13.2404\nMwinilunga;-11.7172\nZhuolan;24.3222\nLangenau;48.4967\nHewitt;31.4520\nCastelnuovo Rangone;44.5500\nCrépy-en-Valois;49.2344\nAuburndale;28.0963\nDiscovery Bay;37.9063\nRenai;24.0462\nBuggānipalle;15.4741\nVallūr;13.2560\nIfanadiana;-21.3000\nOstroh;50.3333\nKanding;22.5194\nZhirnovsk;50.9833\nToui;8.6833\nDejen;10.1667\nLos Osos;35.3065\nPoté;-17.8069\nEinsiedeln;47.1167\nKuusamo;65.9667\nYakumo;42.2560\n‘Alavīcheh;33.0528\nNewton;41.6963\nAshikita;32.2991\nKinross;-26.4167\nVipparla;16.3023\nLoma de Cabrera;19.4220\nKysucké Nové Mesto;49.2983\nMayoyao;16.9736\nŞaḩnāyā;33.4242\nMarivorahona;-13.0833\nLady Lake;28.9241\nKot Bhāi;30.2678\nLagoa dos Gatos;-8.6578\nTondangi;17.2500\nMacomb;40.4709\nBrühl;49.4000\nNavelim;15.2428\nVarnsdorf;50.9116\nBarela;23.0968\nBengonbeyene;1.6931\nMatlock;53.1400\nMitchell;43.7294\nTemplin;53.1167\nAç-çahrij;31.8000\nDammāj;16.8939\nNovouzensk;50.4667\nOpera;45.3833\nPontivy;48.0686\nMecitözü;40.5200\nWailuku;20.8834\nBadarpur;24.8685\nNorth Whitehall;40.6797\nSertanópolis;-23.0589\nRakhiv;48.0500\nKasagi;34.2965\nManjīl;36.7433\nDacheng;23.8483\nValeggio sul Mincio;45.3500\nCasalmaggiore;44.9858\nSzarvas;46.8667\nMortara;45.2500\nWaremme;50.6975\nPorcia;45.9667\nChickasha;35.0409\nTōbetsu;43.2237\nKambadūru;14.3575\nUdiyāvara;13.3097\nMetković;43.0500\nManūjān;27.4064\nAlpine;32.8439\nTupi Paulista;-21.3808\nNewberry;40.1286\nItki Thākurgaon;23.3456\nGaillac;43.9006\nHuasca de Ocampo;20.2028\nLindås;60.6247\nRio do Antônio;-14.4108\nKinna;57.5167\nBhoj;16.5333\nDolo;45.4269\nKolwāra;25.3538\nTone;35.8578\nPassa Quatro;-22.3900\nShively;38.1970\nBolotnoye;55.6833\nSerpa;37.9447\nKallakkudi;10.9767\nMindelheim;48.0333\nKohīr;17.6000\nČeská Třebová;49.9019\nRossville;39.3572\nSeymour;35.8783\nCunco;-38.9167\nKara-Kulja;40.6333\nFort Leonard Wood;37.7562\nTuineje;28.3167\nOlmué;-32.9953\nBaia-Sprie;47.6592\nWeston;53.4130\nBŭston;40.5217\nBan Na Kham;14.0681\nRahden;52.4167\nSiswa;26.6214\nAnao-aon;9.7778\nShizukuishi;39.6963\nMangqu;35.5707\nMontijo;38.9100\nJędrzejów;50.6333\nEspumoso;-28.7250\nCorridonia;43.2500\nWeston;44.8906\nBoppard;50.2314\nAkdepe;42.0500\nPyāpali;15.2669\nGrovetown;33.4503\nBohodukhiv;50.1608\nTiruvāsaladi;11.4013\nÁgios Athanásios;34.7087\nMangawān;24.6675\nNorthborough;42.3231\nQaryat Sulūq;31.6686\nSaint-Rambert;45.4994\nAt-Bashy;41.1700\nPihra;24.6424\nFameck;49.2992\nKhamir;15.9889\nAntrim;39.7862\nIpuã;-20.4381\nMandal;58.0267\nKāuriya;26.1517\nYığılca;40.9667\nBorborema;-21.6200\nNajasa;21.0836\nSoliera;44.7381\nPānr;25.6884\nCumru;40.2811\nHille;52.3331\nBan Pang Mu;19.3336\nBlaydon;54.9630\nBonheiden;51.0333\nSouthchase;28.3793\nCastellarano;44.5667\nBonito;-1.3628\nPewaukee;43.0701\nMaullín;-41.6167\nWindham;42.8076\nDastgerd;32.8019\nSão João Evangelista;-18.5478\nArvika;59.6542\nTredegar;51.7776\nCaudry;50.1250\nRibnitz-Damgarten;54.2500\nPequannock;40.9627\nPahou;6.3833\nMastic;40.8096\nSvetogorsk;61.1167\nHaldībāri;26.3300\nMeco;40.5539\nBanqiao;35.8912\nRadzyń Podlaski;51.7828\nCorinto;13.8167\nUrziceni;44.7181\nEl Chal;16.6333\nAmbaguio;16.5316\nChiaravalle;43.6000\nButiama;-1.7667\nWanda;-25.9667\nDavorlim;15.2722\nWawizaght;32.1586\nKusāha;26.2077\nShimanto;33.2117\nGarrel;52.9581\nSan Policarpo;12.1791\nSolec Kujawski;53.0833\nMonkey Bay;-14.0833\nSeven Oaks;34.0475\nIpecaetá;-12.3000\nMonroe;39.4461\nSayō;35.0042\nBaiceng;25.3885\nCastiglione del Lago;43.1386\nLive Oak;29.5545\nWittenheim;47.8075\nAmānganj;24.4266\nKawasaki;33.6000\nSchriesheim;49.4736\nColchester;41.5621\nKüsnacht;47.3167\nMujuí dos Campos;-2.6847\nVadugapatti;11.1518\nKhao Yoi;13.2403\nSiemiatycze;52.4272\nNorth Reading;42.5816\nAzalea Park;28.5473\nLuduş;46.4778\nAnār;30.8733\nSovetsk;57.5833\nGreenwood Village;39.6153\nAlvarães;-3.2000\nAyaş;40.0172\nMuttukūru;14.2667\nMering;48.2625\nIndianola;41.3629\nLa Roda;39.2070\nRomit;38.7167\nBrooklyn Park;39.2170\nHugo;45.1671\nBobleshwar;16.8300\nDoda;30.3844\nVentaquemada;5.4167\nDaigo;36.7681\nMagdiwang;12.4833\nAmboavory;-17.3000\nBhānumukkala;15.3119\nBokoro;12.3667\nSaren;25.1149\nZelenogradsk;54.9667\nRellingen;53.6500\nNiceville;30.5290\nFiorenzuola d’Arda;44.9333\nViškovo;45.3778\nTremelo;50.9911\nPudtol;18.2356\nGrenaa;56.4161\nSutihār;25.8482\nGehrden;52.3117\nBan Duea;16.1253\nEl Palmar;8.0244\nIsorana;-21.3167\nJelcz-Laskowice;51.0333\nHartford;43.3223\nFeucht;49.3758\nAbaza;52.6481\nWilmington Island;32.0033\nBouc-Bel-Air;43.4544\nSinha;25.6902\nGenappe;50.6000\nBarra de Santa Rosa;-6.7200\nPannimadai;11.0823\nBan Nong Kathao;16.9833\nTeodoro Schmidt;-38.9949\nBailleul;50.7375\nBilaua;26.0501\nCumbum;15.5767\nLimanowa;49.7006\nParapatti;12.1083\nSträngnäs;59.3667\nCerro Maggiore;45.6000\nSenlis;49.2072\nBunkeflostrand;55.5500\nBarwon Heads;-38.2500\nVicovu de Sus;47.9258\nIfrane;33.5333\nBankheri;22.7696\nPanorama;-21.3564\nLinguère;15.3944\nNālwār;16.9333\nHorsham;-36.7167\nPasso de Camarajibe;-9.2378\nNeustadt bei Coburg;50.3289\nSanta Croce sull’ Arno;43.7202\nCandelaria;18.4042\nBatavia;42.9987\nForfar;56.6442\nGalanta;48.1889\nCapotille;19.4500\nShchuchyn;53.6167\nRio Grande City;26.3808\nPiquet Carneiro;-5.8039\nMadagh;35.0133\nSalinas da Margarida;-12.8708\nOber-Ramstadt;49.8333\nKalongo;3.0400\nMainburg;48.6500\nHofgeismar;51.4833\nBan Bang Muang;13.8273\nRatekau;53.9500\nLjungby;56.8333\nAltunhisar;37.9981\nTamaki;34.4902\nSembedu;13.1298\nManohisoa;-19.7833\nCampanha;-21.8389\nFlers;48.7483\nRelangi;16.7050\nIlovaisk;47.9250\nRiegelsberg;49.2942\nLa Solana;38.9414\nYeşilova;37.5069\nSalitre;-7.2839\nChurumuco de Morelos;18.6167\nNancagua;-34.6667\nSuknadānga;24.4600\nTaperoá;-7.2064\nBerea;37.5904\nEzine;39.7900\nItapiranga;-27.1689\nOutreau;50.7039\nJamao al Norte;19.6500\nSher Chakla;25.3848\nMian Sahib;28.1559\nErjie;24.6997\nPudur;9.0001\nBludenz;47.1533\nSatyāmangala;13.0193\nAl Hammam;33.1868\nLahoysk;54.2000\nBüttelborn;49.9022\nAnazzou;30.6333\nVieiro;43.6481\nKonārka;19.8878\nAla-Buka;41.4083\nFortuna;10.4483\nCoremas;-7.0139\nFeatherstone;53.7000\nBroxbourne;51.7495\nScottsboro;34.6438\nChubbuck;42.9263\nNorth Strabane;40.2279\nClark;40.6203\nMéridjonou;6.4619\nVictoria;12.4500\nMorlaix;48.5775\nTiruvalanjuli;10.9449\nKérouané;9.2704\nOdenthal;51.0333\nMoul El Bergui;32.5113\nGrain Valley;39.0171\nAgidel;55.9000\nGłuchołazy;50.3131\nSabinópolis;-18.6658\nJangīd;18.4475\nWālājābād;12.4994\nAravakkurichchi;10.7760\nGlenn Dale;38.9833\nTūprān;17.8447\nKlimavichy;53.6167\nSchroeder;-26.4128\nKanegasaki;39.1957\nRubiera;44.6500\nNarahia;26.3681\nJacaraci;-14.8500\nGomboussougou;11.4333\nPutaparti;14.1652\nLandázuri;6.2181\nRazan;35.3867\nAndrakata;-14.6167\nTulle;45.2658\nAmatitán;20.8333\nBan Khek Noi;16.8118\nDaisen;35.5000\nAtyrá;-25.2786\nVilla del Rosario;-31.5833\nNeutraubling;48.9936\nEvans;42.6528\nNova Resende;-21.1258\nGrande Saline;19.2500\nBarro Alto;-11.7608\nDattapulia;23.2404\nMendrisio;45.8667\nLynden;48.9502\nDurham;43.1174\nAzpeitia;43.1819\nSerinyol;36.3667\nAmbongamarina;-18.3250\nVila Bela da Santíssima Trindade;-15.0078\nChak Husaini;25.5169\nBāra;24.3146\nCalolziocorte;45.8000\nEdingen-Neckarhausen;49.4469\nBasāon;26.2082\nLibagon;10.3000\nMulakaledu;14.3648\nCarthage;37.1503\nMarkgröningen;48.9047\nMantua;39.7618\nSpringdale;39.8769\nRochedale;-27.6000\nWarni;18.5436\nAshtead;51.3100\nThoen;17.6100\nTendrara;33.0500\nOlonne-sur-Mer;46.5361\nGuipavas;48.4336\nMāndleshwar;22.1760\nVişeu de Sus;47.7092\nVeys;31.4825\nGroß-Zimmern;49.8726\nLokomby;-22.1833\nSerra Preta;-12.1600\nCastro Daire;40.9000\nMirzāpur;26.1616\nChaltyr;47.2848\nTiruppāchūr;13.1384\nOulad Bou Rahmoun;32.2954\nTubod;9.5547\nUvalde;29.2152\nBarakī;33.9333\nPedara;37.6167\nBaulia;25.3990\nSwallownest;53.3623\nGreat Baddow;51.7190\nLakkundi;15.3897\nSaint-Genis-Pouilly;46.2433\nSaloá;-8.9758\nHohenstein-Ernstthal;50.8000\nThree Lakes;25.6415\nPutaendo;-32.6278\nMünster;49.9167\nMackworth;52.9277\nMotiong;11.7833\nWakuya;38.5397\nAntarvedipālem;16.3319\nGreeneville;36.1680\nKrasnovishersk;60.4167\nGräfelfing;48.1189\nAvrillé;47.5069\nSan Luis del Palmar;-27.5167\nBrake;53.3333\nMaydolong;11.5000\nBar-le-Duc;48.7717\nHückeswagen;51.1450\nLiangwancun;28.4466\nHorw;47.0167\nChilcuautla;20.3333\nChīpurupalle;18.3114\nPoynton;53.3500\nEldorado;-24.5200\nGuática;5.3167\nAlta;69.9689\nŞüvəlan;40.4889\nRaposos;-19.9669\nBennington;42.8854\nKāttupputtūr;10.9833\nSanyi;24.4167\nPort Glasgow;55.9340\nGlasgow;39.6015\nSpringfield;49.9292\nNazaré;39.6000\nMalo;45.6582\nSeekonk;41.8379\nAmāha;26.1284\nNoto;37.3103\nMastic Beach;40.7664\nDevendranagar;24.6169\nYankton;42.8901\nJunín;-11.1500\nDouar El Arbaa Bou Quorra;34.7490\nLoviisa;60.4583\nFraga;41.5200\nCastellammare del Golfo;38.0264\nHindalgi;16.1364\nVilla Paranacito;-33.7000\nKishanpur Ratwāra;25.4822\nZevio;45.3728\nShāl;35.8983\nPenacova;40.2706\nBelokurikha;51.9833\nKurate;33.7919\nKawaminami;32.1920\nDriouch;34.9833\nEden;36.5027\nGuastalla;44.9167\nHayden;47.7680\nNiquinohomo;11.9047\nPort Orchard;47.5163\nCapinópolis;-18.6819\nTazert;31.6597\nPoronaysk;49.2167\nLedyard;41.4400\nKankipādu;16.4500\nIbipitanga;-12.8819\nSannicandro Garganico;41.8333\nWentorf bei Hamburg;53.4931\nSanta Luzia;-6.8719\nSan Vito al Tagliamento;45.9000\nAïn Jemaa;34.0333\nHallstahammar;59.6167\nHartselle;34.4391\nTagoloan;8.1333\nTenafly;40.9176\nPineto;42.6167\nBlomberg;51.9333\nKurichchi;11.5701\nSippola;60.7392\nDengshangcun;41.3442\nPrivolzhsk;57.3825\nSárvár;47.2500\nTapolca;46.8828\nKamitonda;33.6963\nSelb;50.1667\nLangelsheim;51.9381\nSanta Maria a Vico;41.0333\nRoanoke Rapids;36.4452\nChislehurst;51.4120\nRibeiro do Amparo;-11.0469\nBennane;35.6833\nPāli;26.0576\nXihuangni;38.3575\nMexborough;53.4992\nWitzenhausen;51.3422\nChellaston;52.8671\nBétérou;9.2000\nMani;13.2600\nGrodzisk Wielkopolski;52.2333\nYinhua;33.4530\nUiraúna;-6.5178\nVubatalai;11.3597\nPestovo;58.6000\nGrefrath;51.3363\nRobbinsville;40.2220\nBan Ton Thong Chai;18.3375\nCittà Sant’Angelo;42.5167\nOria;40.5000\nTámesis;5.6667\nJohnson City;42.1230\nSouk Et-Tleta des Oulad Hamdane;33.1047\nJackson;37.3792\nPullambādi;10.9667\nÇatalpınar;40.8790\nMajiagoucha;37.5033\nGagarin Shahri;40.6619\nWinkfield;51.4318\nLaxou;48.6856\nValangimān;10.8897\nWładysławowo;54.8000\nLaterza;40.6333\nFray Luis A. Beltrán;-32.7833\nTraverse City;44.7546\nKatkol;15.9500\nRobinson;40.4578\nVästerhaninge;59.1167\nSpitak;40.8372\nLa Apartada;8.1006\nPâ;11.5500\nSabbah;33.8036\nSão Lourenço da Serra;-23.8528\nParalímni;35.0333\nHumayingcun;41.1145\nBoksitogorsk;59.4833\nBarāri;25.5068\nIlha de Moçambique;-15.0367\nSalyan;28.3500\nKujūkuri;35.5333\nNorthview;43.0427\nAfzala;25.9319\nPeddapalle;14.4046\nKingersheim;47.7914\nRitterhude;53.1861\nDehmoí;40.2167\nUpper Southampton;40.1723\nWhite;40.6210\nBeckingen;49.3928\nBrejões;-13.1039\nCampodarsego;45.5000\nDentsville;34.0754\nCharām;30.7461\nSão Félix;-12.6050\nTerra Rica;-22.7089\nMéru;49.2358\nLaurinburg;34.7602\nThibodaux;29.7949\nUchiko;33.5330\nBerlare;51.0250\nAhram;28.8833\nMajholi;23.5011\nRizal;8.5272\nFranklin Park;40.5903\nQantīr;30.8000\nRevūr;16.8216\nBradley;41.1641\nMurray Bridge;-35.1170\nTarumã;-22.7469\nAttibele;12.7781\nVammala;61.3417\nTeolândia;-13.6019\nRío San Juan;19.6400\nBelchertown;42.2788\nAndrésy;48.9808\nNaduvattam;11.4808\nFlorencia;10.3665\nSanta Adélia;-21.2428\nClinton;42.4119\nNakanojōmachi;36.5898\nBedfordview;-26.1794\nAmbahive;-22.2000\nMasty;53.4170\nHārohalli;12.6807\nTartarugalzinho;1.5058\nGloversville;43.0491\nDomaniç;39.8033\nTalata Ampano;-21.5500\nSamobor;45.8000\nItajobi;-21.3178\nBen Taieb;35.0837\nKaguchi;11.4519\nMahaly;-24.1667\nGayéri;12.6500\nKaintragarh;20.7211\nChoszczno;53.1667\nBeech Grove;39.7157\nNitte;13.1823\nRomilly-sur-Seine;48.5158\nBellavista;-34.9333\nSisian;39.5208\nHuchuan;34.9249\nAlvinópolis;-20.1069\nAiyetoro Gbede;7.9833\nArnedo;42.2167\nAntsoso;-19.8167\nLakkampatti;11.4461\nBoguszów-Gorce;50.7667\nKesamudram;17.6875\nDepew;42.9118\nChāprā;23.5371\nHola Prystan;46.5167\nSāmbre;15.8800\nKurumbalūr;11.2360\nRichterswil;47.2167\nNiedernhausen;50.1617\nMoura;38.1333\nTazzarine;30.7722\nDembecha;10.5500\nKutchan;42.9017\nIanantsony;-23.5500\nSan Pedro Tapanatepec;16.3667\nMahuwa Singhrai;25.8168\nMata Roma;-3.6250\nLānjī;21.5018\nSpring Creek;40.7450\nMidar;34.9500\nLandsberg;51.5333\nZozocolco de Hidalgo;20.1333\nMeilen;47.2667\nAndondabe;-17.7667\nBan Mae Sun Luang;19.8305\nKimyogarlar;39.6672\nSakabansi;10.0442\nEloy;32.7470\nAmbodiriana;-19.5833\nGondomar;42.1111\nZacualpan;18.7197\nPont-à-Mousson;48.9044\nSilvino Lobos;12.3281\nYoungsville;30.0963\nParamati;11.1544\nJoghtāy;36.6350\nAustralind;-33.2800\nSommacampagna;45.4000\nGaspé;48.8333\nVennesla;58.3106\nBusko-Zdrój;50.4667\nAndover;37.6873\nMellila;33.3833\nBayserke;43.4797\nHudiksvall;61.7333\nCossato;45.5667\nGardabani;41.4500\nAndoain;43.2167\nPatnanungan;14.7833\nMiraí;-21.1950\nAmbohimierambe-Andranofito;-19.7833\nElk Plain;47.0425\nEl Arenal;20.2167\nSouthern Pines;35.1927\nBella Vista;-27.0333\nVandalia;39.8791\nBangui;18.5378\nOued Jdida;33.9333\nChirpan;42.1998\nŞefaatlı;39.5017\nKaleyānpur;26.4297\nRosarno;38.4850\nPiney Green;34.7498\nCirò Marina;39.3694\nIfatsy;-22.4000\nPhillipsburg;40.6894\nAmlash;37.0975\nAlangānallūr;10.0470\nNopala de Villagran;20.2528\nAnororo;-17.5167\nDorfen;48.2667\nIpauçu;-23.0569\nBela Vista do Paraíso;-22.9969\nDevarapalle;17.0347\nStaffanstorp;55.6333\nGualdo Tadino;43.2333\nTsiatajavona-Ankaratra;-19.3833\nHalwāra;30.7167\nKaonke;30.7659\nBhimphedi;27.5510\nTonawanda;43.0105\nSindhnūr;15.7700\nTrepuzzi;40.4000\nCamp Pendleton South;33.2329\nCanutama;-6.5339\nPorteiras;-7.5350\nRāmechhāp;27.3260\nSanta;17.4860\nTavagnacco;46.1333\nKochkor-Ata;41.0319\nRatzeburg;53.7000\nSaint-Jacques-de-la-Lande;48.0903\nBurshtyn;49.2600\nTatarikan;7.7333\nNadisāl;13.1326\nRâs Baalbek;34.2597\nBarţalah;36.3522\nClarksdale;34.1933\nAndranovelona;-19.6500\nLa Carolina;38.2667\nNatividade do Carangola;-21.0419\nAmbesisika;-16.5167\nFortuna;-5.7328\nAnpachi;35.3353\nBan Ho Mae Salong;20.1631\nNannestad;60.2456\nNisko;50.5200\nSanta Brígida;-9.7358\nGuayos;22.0497\nSahave;-21.0667\nAntequera;9.7812\nWhitman;42.0800\nGreenlawn;40.8632\nÇifteler;39.3831\nBemidji;47.4828\nKulunda;52.5667\nTayum;17.6165\nMutukula;-1.0000\nLohfelden;51.2716\nBurbach;50.7444\nYellāreddi;18.1859\nPākala;15.2694\nOpwijk;50.9667\nHanamsāgar;15.8722\nKyaukmyaung;22.5833\nJuruá;-3.4808\nVohilava;-20.7000\nCastañuelas;19.7000\nAlarobia Bemaha;-20.2000\nTeixeira;-7.2228\nKhallikot;19.6091\nSultandağı;38.5333\nLa Flèche;47.6997\nPunata;-17.5500\nJoubb Jannîne;33.6333\nTulchyn;48.6744\nPilisvörösvár;47.6211\nKök-Janggak;41.0333\nJiquiriçá;-13.2569\nKenora;49.7667\nKodāngipatti;9.9920\nRosà;45.7167\nAmirlī;34.7250\nSkipton;53.9625\nJulianadorp;52.8833\nChebrolu;16.8206\nTāti;23.3772\nHilchenbach;50.9983\nBiatorbágy;47.4712\nÖzdere;38.0175\nLongwood;28.7014\nTriunfo;-7.8378\nHenderson;36.3256\nVil’nyans’k;47.9445\nMahinog;9.1500\nNawāda;26.0881\nAhigbé Koffikro;5.4000\nAmbatoharanana;-17.3000\nKyzyl-Suu;42.3392\nHorta;38.5333\nThouars;46.9750\nMatungao;8.1333\nRoquebrune-sur-Argens;43.4433\nŞalkhad;32.4917\nRamainandro;-19.3000\nLeninsk;48.7000\nAlexándreia;40.6333\nLolotique;13.5500\nAmbinanindrano;-20.6500\nBāladharmāram;17.6703\nPetrovaradin;45.2500\nBijai;25.4711\nZollikon;47.3422\nAizubange;37.5615\nYlivieska;64.0750\nVeliki Preslav;43.1667\nSan Juan;10.2667\nChépica;-34.7333\nStein bei Nürnberg;49.4167\nMilenaka;-22.8333\nCalanogas;7.7500\nManambondro;-23.8000\nLagangilang;17.6103\nSasso Marconi;44.4000\nTaguatinga;-12.4061\nBarahari;25.7652\nUhingen;48.7058\nManandona;-20.0500\nĀlampur;15.8793\nPerunkolattūr;12.0430\nMykolaiv;49.5247\nMarofototra;-20.8667\nObando;4.5833\nBihpuriāgaon;26.8031\nKesariyā;26.3650\nAntanifotsy;-16.8667\nBuggenhout;51.0000\nPuerto Salgar;5.5000\nPontinia;41.4083\nSorso;40.7983\nWorthington;40.0950\nKoungheul;13.9833\nKopoky;-25.2000\nCarmignano;43.8167\nHaga;36.5483\nAnkisabe;-19.2833\nHereford;34.8225\nSwampscott;42.4757\nEsbiaat;32.2044\nItaú de Minas;-20.7389\nBevoay;-24.4833\nImanombo;-24.4333\nRukhāe;25.3269\nFront Royal;38.9260\nBreukelen;52.1717\nLummen;50.9833\nVillaviciosa;43.4833\nMutyālapalle;16.4019\nAmbatomanjaka;-18.8833\nSwansea;38.5507\nBajala;12.8537\nBacuag;9.6081\nDayton;39.2592\nQumqo‘rg‘on;37.8278\nSan Mateo del Mar;16.2000\nSan Vito;8.8400\nTiorpāra;22.2351\nTaywarah;33.5100\nCanteleu;49.4511\nAnkilimivory;-24.4667\nBeroy Atsimo;-23.9833\nMarkt Schwaben;48.1917\nGrão Mogol;-16.5589\nTetāri;25.3757\nRavels;51.3667\nSaint-Brevin-les-Pins;47.2464\nNovyi Buh;47.6833\nQuixelô;-6.2539\nBakel;14.9042\nShatrāna;29.9102\nAnalamary;-24.2333\nJisr ez Zarqā;32.5379\nClarines;9.9433\nMalkhaid;17.1950\nAnahidrano;-15.0833\nCherrapunji;25.2792\nPenrith;-33.7511\nDargeçit;37.5440\nNeu-Anspach;50.2931\nAnjoma-Ramartina;-19.6333\nBachhauta;25.5242\nSarmīn;35.9033\nAntanimenabaka;-16.9333\nTarlapalli;18.8345\nLapseki;40.3439\nSoalala;-16.1000\nTurnov;50.5873\nDouar Souk L‘qolla;35.0718\nMassalubrense;40.6167\nQiaoyang;35.0716\nQuan’ancun;25.1345\nKezi;-20.9167\nBefasy;-20.5667\nRiverdale;33.5639\nLālejīn;34.9747\nDalkeith;55.8958\nLieusaint;48.6322\nBehisatse;-21.8000\nAkora;26.4721\nAghbal;34.9394\nChaguaramas;9.3333\nBabhanganwa;26.1398\nWān Long;22.1667\nMitane;40.1016\nBikkavolu;16.9624\nLipno;52.8500\nVilla Ojo de Agua;-29.5167\nIharan̈a;-13.3500\nMadanpur;23.0200\nShlisselburg;59.9536\nDimiao;9.6167\nNakagawa;36.7363\nDoukouya;6.4333\nUsingen;50.3344\nVerdal;63.7930\nMashpee;41.6178\nTabant;31.6581\nOtley;53.9050\nAuriflama;-20.6858\n’Tlat Bni Oukil;32.5770\nBni Darkoul;35.0563\nPadavēdu;12.6730\nOmiš;43.4333\nCandói;-25.6628\nPlainfield;41.6992\nLinganaboyinacherla;16.3961\nYuchi;23.9000\nDahé;6.5167\nIporã;-24.0028\nSrīnagar;26.7830\nDrahichyn;52.1833\nGreensburg;40.3113\nCoribe;-13.8289\nJinta;37.8573\nKrasnohorivka;48.0116\nWoippy;49.1511\nSaint-Fargeau;48.5328\nCoconuco;2.2500\nLangenselbold;50.1833\nSidmant al Jabal;29.0856\nSardinal;10.5343\nGourrama;32.3333\nTiszaújváros;47.9333\nŁapy;52.9833\nSerhetabat;35.2833\nBotelhos;-21.6424\nCumayeri;40.8736\nKothanūru;16.0022\nTerkuvengānallūr;9.4052\nVohipeno;-22.3500\nCold Lake;54.4642\nEfkarpía;40.6833\nAssaí;-23.3728\nTall Abyaḑ;36.6975\nKārai;12.9377\nAnzegem;50.8336\nRaynham;41.9312\nDetva;48.5514\nĀlamūru;16.7833\nJoaíma;-16.6539\nTendūkheda;23.3962\nKānjikkovil;11.3689\nShepshed;52.7711\nWilliamstown;39.6874\nFritzlar;51.1333\nTanque Verde;32.2687\nSullivan;43.0923\nPallasovka;50.0500\nHeswall;53.3280\nSaint-Jean-de-Luz;43.3903\nTelmar;25.4237\nNioro;15.1833\nNobres;-14.7200\nVinanivao;-15.8833\nCzłuchów;53.6667\nSumidouro;-22.0500\nPresidente Getúlio;-27.0508\nStolac;43.0825\nSera;34.5868\nEchuca;-36.1333\nRixheim;47.7486\nMagione;43.1500\nNastola;60.9500\nDhanauri;29.7833\nSahakevo;-20.2833\nRadzymin;52.4167\nLevoča;49.0253\nMisaki;34.3169\nCabañas;14.9333\nMineral Wells;32.8169\nPotsdam;44.6774\nMontataire;49.2556\nNerchinsk;51.9944\nTarauna;26.2371\nCabral;18.2500\nGlasgow;37.0048\nShuichecun;24.0900\nVinci;43.7833\nSterling;41.7996\nImpruneta;43.6833\nEdenburg;-29.7347\nFarnborough;51.3591\nWoudrichem;51.8167\nBusto Garolfo;45.5478\nBuhuşi;46.7150\nMineral del Monte;20.1333\nCalifornia City;35.1578\nHima;0.2906\nMukāsi Pidāriyūr;11.2069\nMeerane;50.8519\nLons;43.3150\nBad Wurzach;47.9094\nAmersham;51.6770\nUppunda;13.8333\nLumino;0.3250\nAreado;-21.3589\nSanquelim;15.5027\nMalsch;48.8808\nKondrovo;54.8000\nKharki;23.9165\nKizel;59.0500\nSan Julian;11.7536\nMascote;-15.5628\nJever;53.5744\nPoděbrady;50.1425\nHolalagondi;15.4873\nMions;45.6631\nMori;42.1050\nHolliston;42.1977\nMondolfo;43.7500\nVrbovec;45.8833\nBom Jesus do Galho;-19.8289\nArona;45.7569\nDumariā;26.7652\nPenrith;54.6648\nEnniskillen;54.3447\nBhalil;33.8500\nNyzhnia Krynka;48.1144\nMetuchen;40.5424\nCollecchio;44.7500\nLebanon;37.6717\nDharphari;26.1501\nBan San Phak Wan Luang;18.7049\nWąbrzeźno;53.2833\nHendersonville;35.3247\nNagongera;0.7700\nAyní;39.3975\nStony Point;41.2593\nNarasingapuram;12.9728\nVuhledar;47.7794\nGafanha da Nazaré;40.6350\nBalassagyarmat;48.0786\nChâteau-d’Olonne;46.5042\nBatuan;12.4222\nManavālakurichi;8.1478\nMadānpur;25.8670\nBoulder City;35.8407\nFujisaki;40.6561\nBalhāpur;25.3511\nOftringen;47.3167\nGreat Bend;38.3593\nAudincourt;47.4828\nKannamanāyakkanūr;10.5527\nThuin;50.3333\nNzalat Laadam;32.1000\nInhuma;-6.6678\nBranchburg;40.5629\nTernitz;47.7167\nChegdomyn;51.1178\nCambuci;-21.5750\nPattensen;52.2667\nEkwāri;25.2833\nBom Lugar;-4.2200\nPouso Redondo;-27.2578\nFerrier;19.6167\nDionísio Cerqueira;-26.2550\nRotenburg an der Fulda;50.9961\nLucao;23.4133\nGaundrā;26.3683\nCehegín;38.0925\nNavashino;55.5500\nGabane;-24.6667\nCuevas del Almanzora;37.3000\nSanto Domingo Xenacoj;14.6822\nMonterrey;4.8783\nAmasra;41.7494\nGrândola;38.1700\nBelison;10.8381\nSprimont;50.5000\nGrimes;41.6779\nMercaderes;1.8000\nSpenge;52.1333\nKontiolahti;62.7667\nRomsey;50.9890\nBetsukai;43.3938\nHuasuo;35.4043\nBrwinów;52.1417\nFiadanana;-18.2167\nDarihat;24.9702\nIghrem n’Ougdal;31.2333\nBairia;25.5563\nBrasil Novo;-3.2619\nBroadlands;39.0168\nBissendorf;52.2333\nAnomabu;5.1667\nRājpur;25.0768\nPatrocínio Paulista;-20.6394\nWombourn;52.5302\nFortim;-4.4500\nBishops Cleeve;51.9470\nWarwick;40.2503\nSlochteren;53.2167\nSummerside;46.4000\nKatyr-Yurt;43.1700\nNevel;56.0333\nMarkacho;24.3263\nComox;49.6733\nOdlābāri;26.8364\nChikhli Kalān;22.2152\nPurísima de la Concepción;9.2333\nKarabanovo;56.3167\nPlérin;48.5344\nMontelupo Fiorentino;43.7333\nSinmpérékou;11.2333\nLas Guáranas;19.2000\nKottavalasa;17.9000\nAmay;50.5478\nHighland Springs;37.5516\nSurajpura;25.2576\nMaglie;40.1167\nSierra Vista Southeast;31.4525\nAmpohibe;-15.0333\nAnkadinandriana;-19.0667\nNova Timboteua;-1.2058\nKalasa;13.2340\nMontabaur;50.4375\nCândido de Abreu;-24.5669\nBaiersbronn;48.5058\nCassano delle Murge;40.8833\nMurgod;15.7800\nSylvan Lake;52.3083\nGundlapelle;16.4102\nSchwabmünchen;48.1789\nSozopol;42.4167\nCocorná;6.0569\nOstwald;48.5511\nAlginet;39.2625\nHemsworth;53.6100\nIvanić-Grad;45.7081\nSanjiang Nongchang;19.8798\nGryazovets;58.8833\nSumbal;34.2307\nMorpeth;55.1675\nHirono;40.4085\nAlindao;5.0333\nBayeux;49.2786\nAndorinha;-10.3450\nMuthallath al Azraq;31.8342\nTabuse;33.9547\nTornesch;53.7000\nBuritirama;-5.5928\nPresidente Dutra;-11.2958\nRamsey;41.0595\nTepetzintla;21.1452\nOldsmar;28.0506\nObanazawa;38.6000\nHerselt;51.0500\nCastel San Giorgio;40.7833\nBradley Gardens;40.5711\nKelamangalam;12.6031\nRoncade;45.6246\nLampa;-15.3636\nSaint Joseph;10.6556\nSchiffdorf;53.5355\nBurbage;52.5277\nGaruva;-26.0269\nNāgireddipalli;14.2701\nVilla San Giovanni;38.2167\nGantt;34.7837\nShimubi;19.1645\nWashington;39.7494\nMānjri;16.4200\nBriniamaro;10.7411\nGlen Allen;37.6660\nMorwell;-38.2333\nAït Yaïch;36.5811\nPiano di Sorrento;40.6333\nKrasnogvardeyskoye;45.8500\nAmbérieu-en-Bugey;45.9581\nFerndale;48.8526\nSirmaur;24.8365\nBerettyóújfalu;47.2167\nOnklou;9.5000\nBrunswick;31.1449\nHooksett;43.0709\nKārkūdalpatti;11.5002\nHarhorin;47.1972\nKushimoto;33.4667\nRiofrío;4.1561\nCabarete;19.7511\nBéré;9.3156\nNishinoomote;30.7322\nTiltil;-33.0817\nAlexander City;32.9229\nMuri;46.9333\nRokycany;49.7428\nMuch;50.9167\nEssau;13.4833\nSanderstead;51.3358\nPolāia Kalān;23.2119\nTsivilsk;55.8667\nEkenäs;59.9750\nMuy Muy;12.7625\nBo’ness;56.0168\nNeqāb;36.7081\nNarragansett;41.4291\nMaqat;47.6500\nDanilov;58.1833\nSan Ramón;-11.1247\nPilar;-31.6833\nSukhinichi;54.1000\nVargem da Roça;-11.6069\nRoncq;50.7536\nMonteroni di Lecce;40.3333\nPiraziz;40.9333\nBadhoevedorp;52.3333\nÇiçekdağı;39.6069\nTörökbálint;47.4367\nTeignmouth;50.5515\nTrinitapoli;41.3500\nTumbippādi;11.8080\nWildwood;28.7752\nNampicuan;15.7342\nOulad Driss;31.9536\nPenuganchiprolu;16.9167\nLarena;9.2490\nOrbetello;42.4394\nLope de Vega;12.2983\nHanover;42.1224\nMaravilla Tenejapa;16.2167\nSoledade;-7.0569\nZąbkowice Śląskie;50.5833\nPandhāna;21.6982\nWilsdruff;51.0522\nXincun;27.6739\nRío Negro;-40.7833\nHedehusene;55.6547\nÁgua Clara;-20.4500\nAndrorangavola;-21.5000\nGreendale;42.9371\nPānsemāl;21.6598\nMăgurele;44.3494\nAngical;-12.0069\nUch-Korgon;40.2300\nKarpi;25.1612\nBarhauna;25.6043\nUzun;38.3667\nArzgir;45.3694\nWymondham;52.5700\nDeming;32.2631\nFort Payne;34.4559\nSuwāsra;24.0698\nNegreşti-Oaş;47.8694\nAshiya;33.8938\nHaacht;50.9767\nChandauli;25.8972\nAskim;59.5861\nSolim;15.6200\nCowes;50.7595\nNewtown;39.9920\nVilla Alegre;-35.6667\nSikat;25.5186\nChifubu;-12.9333\nEraurā;24.6130\nBhānukumāri;26.3395\nKottacheruvu;14.1886\nWschowa;51.8000\nLingāl;16.2833\nOchakiv;46.6186\nDohta;26.2864\nZemamra;32.6215\nBarhi;23.9033\nTravagliato;45.5240\nVail;32.0217\nVillasanta;45.6053\nKerepestarcsa;47.5478\nĀlangudi;10.3604\nMassaranduba;-26.6108\nGulf Shores;30.2764\nOttweiler;49.3667\nLadson;33.0093\nWhite Oak;39.0451\nSuō-Ōshima;33.9276\nTroon;55.5400\nChelsea;33.3262\nOwosso;42.9955\nNgoulemakong;3.0833\nBombinhas;-27.1378\nGuilford;39.8811\nCarmen de Areco;-34.3858\nLubbeek;50.8817\nAntioch;42.4742\nMittweida;50.9856\nRehlingen-Siersburg;49.3686\nFraser;42.5388\nCandiba;-14.4108\nShintō;36.4384\nArdestān;33.3761\nMosina;52.2467\nVersoix;46.2833\nBerck-sur-Mer;50.4083\nRanomafana;-18.9583\nBarka Parbatta;25.3396\nHulyaypole;47.6644\nPataili;25.7872\nLauda-Königshofen;49.5686\nHammonton;39.6572\nZhutang;23.8528\nClaxton Bay;10.3405\nPaniem;15.5167\nKorangal;17.1070\nGreat Falls;39.0110\nMmopone;-24.5669\nIsny im Allgäu;47.6919\nZontecomatlán de López y Fuentes;20.7667\nPort Lincoln;-34.7322\nBaie du Tombeau;-20.1138\nSisa;-6.6142\nMahatsinjo;-17.7333\nEsquipulas Palo Gordo;14.9333\nGland;46.4200\nOżarów Mazowiecki;52.2167\nBan Du;19.9691\nQuinapundan;11.1578\nMangamila;-18.5667\nCafelândia;-24.6178\nWaunakee;43.1829\nMascali;37.7500\nBollullos par del Condado;37.3358\nCondoto;5.1000\nUdaipur Bithwār;26.2872\nChikitigarh;19.2023\nMonroe;33.7990\nFruitville;27.3328\nIlampillai;11.6066\nCanyon;34.9911\nBischofsheim;49.9890\nEl Paisnal;13.9667\nLatiano;40.5333\nDennis;41.7064\nSepīdān;30.2625\nBartabwa;0.8300\nGouré;13.9874\nBahçesaray;38.1286\nBoston;7.8697\nKulharia;25.3382\nBicas;-21.7250\nGuajiquiro;14.1000\nChandhaus;25.2977\nCicciano;40.9667\nLopik;51.9667\nBarja;33.6497\nBijaipur;26.0556\nHarsefeld;53.4500\nMaria;9.1960\nForster;-32.1806\nPalmview;26.2318\nAstravyets;54.6136\nBrad;46.1294\nLakhsetipet;18.8873\nPineville;31.3414\nDornakal;17.4447\nIchikawamisato;35.5652\nNeustadt an der Donau;48.8000\nMünsingen;48.4128\nArugollu;16.8253\nKuurne;50.8519\nSłupca;52.3000\nKātrāvulapalle;17.1277\nBan Kaeng;16.4119\nSailāna;23.4622\nCómbita;5.7500\nDavidson;35.4840\nSan Sebastián;13.7333\nSukhāsan;25.9644\nJurema;-8.7178\nKalývia Thorikoú;37.8333\nAleksandrovka;42.8528\nAnapoima;4.5503\nAyt ’Attou ou L’Arbi;31.5456\nRadomyshl;50.4947\nRahika;26.3803\nSalīmpur;25.2480\nPlewiska;52.3664\nAlzano Lombardo;45.7317\nEberbach;49.4667\nMarkdorf;47.7208\nMelmangalam;10.1000\nTavares;-7.6358\nLapua;62.9700\nSalem Lakes;42.5366\nCopalchí;9.8473\nKlášterec nad Ohří;50.3846\nTonya;40.8856\nKiri;-1.4955\nBarjora;23.4333\nMohania;25.1692\nNáfplio;37.5667\nRønne;55.0986\nSainte-Maxime;43.3089\nHavre de Grace;39.5480\nVedasandūr;10.5310\nGodella;39.5200\nUrbino;43.7252\nMoultrie;31.1591\nSokone;13.8833\nNoya;42.7833\nBaoshan;24.7428\nHershey;40.2806\nCruzília;-21.8389\nJaitpur;25.9132\nPriverno;41.4667\nCandeias;-20.7669\nBo;20.6736\nLangwedel;52.9999\nMount Vernon;38.3140\nZhabinka;52.2006\nGua;22.2136\nOlsberg;51.3500\nSan Francisco;15.6667\nMajia;35.4599\nDargahān;26.9636\nVilla Yapacaní;-17.4028\nSatwās;22.5363\nCadaval;39.2333\nWashington;38.5515\nOschatz;51.3003\nPualas;7.8167\nGrünstadt;49.5692\nAyomi;6.7833\nRío Branco;-32.5972\nUngutūru;16.8230\nTapejara;-23.7328\nBoninal;-12.7019\nMorris;41.3749\nWilbraham;42.1270\nYanhewan;36.7523\nSumbha;25.5789\nDarłowo;54.4208\nMarofinaritra;-15.0333\nŌki;33.2104\nAnderson Creek;35.2657\nRendon;32.5789\nKottaiyūr;10.1096\nBoa Nova;-14.3628\nWeigelstown;39.9852\nQazyqurt;41.7598\nÚstí nad Orlicí;49.9739\nApuiarés;-3.9489\nLudvika;60.1333\nBoula’wane;32.8607\nGanguvārpatti;10.1694\nQobustan;40.0842\nChelsfield;51.3582\nHasami;33.1379\nSanta Branca;-23.3969\nMūrak;35.3753\nBakun;16.7925\nTostado;-29.2333\nDomkonda;18.2536\nKārempūdi;16.4333\nBreza;44.0167\nKillarney;52.0588\nRaghunāthpur;25.5615\nKambainellūr;12.2071\nChippewa Falls;44.9358\nMocha;13.3203\nPaina;25.5406\nHatten;53.0083\nChaugāin;25.4801\nEggertsville;42.9665\nParaíso;18.0000\nDouarnenez;48.0922\nMiho;36.0045\nTlayacapan;18.9556\nPerdūr;13.3844\nStanytsia Luhanska;48.6449\nBoa Esperança do Sul;-21.9925\nLeno;45.3703\nEast Milton;30.6175\nWest Freehold;40.2324\nDumas;35.8613\nOuled Sidi Brahim;36.3667\nMount Barker;-35.0667\nBezou;32.0833\nOllioules;43.1394\nHanover;40.8197\nBagulin;16.6079\nIakora;-23.1000\nTijucas do Sul;-25.9278\nPucioasa;45.0742\nAltınekin;38.3078\nGoonellabah;-28.8167\nRed Bluff;40.1735\nGhaura;24.5059\nTepecoyo;13.7003\nSur Singh;31.3992\nHaaren;51.6000\nSison;9.6592\nTālbahat;25.0420\nBenaulim;15.2700\nTolland;41.8786\nTsimlyansk;47.6167\nKeāl;25.1218\nAmarāvati;16.5730\nLöbau;51.0944\nCorinth;34.9474\nUst’-Ordynskiy;52.8056\nPoço das Trincheiras;-9.3128\nÇobanlar;38.7014\nBelpukur;21.9851\nKearsley;53.5300\nAsagiri;32.2403\nBarra do Mendes;-11.8100\nKurikuppi;15.0700\nÁgua Boa;-17.9958\nMinignan;10.0000\nGeneral MacArthur;11.2486\nTiruppanandāl;11.0919\nPaulino Neves;-2.7189\nPlumtree;-20.4781\nAnkaramena;-25.0167\nGuiratinga;-16.3489\nJericho;40.7875\nMbuyapey;-26.2000\nSan Martín de Loba;8.8333\nFarap;39.1667\nBad Camberg;50.3000\nRobbinsdale;45.0261\nBayt Jālā;31.7150\nAbensberg;48.8000\nGreenwood;33.5126\nMorroa;9.3333\nIflissen;36.8636\nSopetrán;6.5017\nBāzidpur;26.1536\nVatra Dornei;47.3461\nPinhalzinho;-22.7800\nCefalù;38.0333\nBarroquinha;-3.0189\nMiddlesex;40.5744\nUndrājavaram;16.7866\nWörgl;47.4831\nScottsbluff;41.8684\nMurra;13.7592\nOleggio;45.6000\nEching;48.3000\nAlausí;-2.1900\nUibaí;-11.3369\nAlterosa;-21.2190\nLotte;52.2764\nMalvik;63.3728\nOrikhiv;47.5677\nLa Carlota;37.6667\nAraceli;10.5529\nCeres;-29.8667\nHutchinson;44.8855\nPainan;-1.3511\nAbony;47.1894\nRetirolândia;-11.4950\nSquinzano;40.4333\nAl Mu‘aḑḑamīyah;33.7421\nBela Simri;25.5295\nAnnāram;16.7840\nSan Carlos;6.1897\nTostedt;53.2833\nShort Hills;40.7389\nHudson;44.9639\nWest Lincoln;43.0667\nBelvedere Park;33.7489\nKhagra;25.3511\nShamalgan;43.3775\nLiedekerke;50.8667\nBongaree;-27.0813\nBan Don Kaeo;18.8567\nArtondale;47.3021\nPé de Serra;-11.8339\nKrasnyy Kut;50.9500\nManoel Vitorino;-14.1450\nDenzlingen;48.0683\nSerinhisar;37.5807\nSchwaz;47.3500\nImmenstadt im Allgäu;47.5667\nWangjiaxian;36.5443\nMaisach;48.2167\nSchneeberg;50.5942\nBokod;16.4914\nVilla Vásquez;19.7400\nFiesole;43.8072\nLocorotondo;40.7558\nHickory Hills;41.7248\nBensville;38.6176\nTorrijos;39.9833\nSanta María;-32.7469\nLockhart;29.8785\nDoddipatla;16.5167\nBelazao;-19.8833\nVerona;40.8323\nSidi Azzouz;31.7667\nCliftonville;51.3881\nRovinj;45.0833\nBarranco de Loba;8.9500\nVellodu;10.3048\nOurtzagh;34.5500\nPomorie;42.5683\nVembārpatti;10.2500\nMizil;45.0000\nGernsbach;48.7633\nColesville;39.0730\nZemrane;31.5339\nArgentan;48.7444\nDaulatnagar;25.3216\nVadasseri;8.1937\nTagalft;32.2389\nReidsville;36.3376\nUlchin;37.0013\nMatane;48.8500\nLāla;24.5542\nPonnampatti;10.3668\nRiedisheim;47.7483\nÖmerli;37.4025\nGraça;-4.0458\nHolzgerlingen;48.6392\nMantaly;-13.1667\nBålsta;59.5833\nGeldagana;43.2162\nPueblo Rico;5.2500\nDahāria;26.1807\nLuino;46.0000\nPeddavadlapūdi;16.4098\nLindenhurst;42.4175\nEl Rodeo;14.3906\nAlagoinha;-6.9500\nWingene;51.0500\nBrooks;50.5642\nMiddlewich;53.1920\nVempalle;13.5382\nSai Buri;6.7012\nYedapalli;18.6789\nBrazópolis;-22.4739\nTaggia;43.8439\nAmantea;39.1333\nNattappettai;12.8187\nKihoku;34.2114\nMannūr;17.2994\nTianguistengo;20.7278\nHlučín;49.8967\nCaselle Torinese;45.1775\nYamada;39.4677\nSassenberg;51.9897\nLagoa;37.7500\nBelmont;35.2212\nAuria;24.8563\nTemsamane;35.1167\nMuqui;-20.9519\nWashington Court House;39.5381\nCojedes;9.6167\nTokoroa;-38.2167\nTounfit;32.4667\nIhaddadene;31.2000\nAdams;40.7092\nBāri;25.8769\nSan Antonio;3.9167\nPolyarnyye Zori;67.3667\nSalempur;26.4588\nNatchez;31.5437\nAscensión;-15.6996\nSariosiyo;38.4133\nTururu;-3.5808\nPine;40.6437\nPalmer Ranch;27.2286\nLohiyār Ujain;26.6284\nZaouiat Moulay Bouchta El Khammar;34.4833\nLilburn;33.8897\nAnantarāzupeta;14.0014\nMarostica;45.7456\nIgrapiúna;-13.8258\nSanpozhen;39.6683\nKinogitan;8.9855\nNew Paltz;41.7577\nSainte-Anne-des-Plaines;45.7617\nKukdeshwar;24.4828\nSanta Maria do Suaçuí;-18.1900\nBalangiga;11.1097\nItinga;-16.6128\nSunset;25.7060\nSan Andrés Timilpan;19.8667\nTezu;27.9167\nBeasain;43.0458\nSīdī Barānī;31.6108\nBesārh;25.9537\nFisciano;40.7667\nGrafing bei München;48.0500\nAlsager;53.0961\nSitalpur;26.4050\nCotegipe;-12.0278\nPeumo;-34.3961\nWulong;23.3202\nNiederzier;50.8831\nVemulapūdi;17.6087\nTaglio;45.0167\nModakkurichchi;11.2329\nChudovo;59.1167\nAngermünde;53.0333\nGroveton;38.7605\nPazar;40.2620\nAyni;38.6667\nBan Nong Kula;16.6500\nDet Udom;14.9060\nKodigenahalli;13.8608\nÜzümlü;39.7100\nSaldaña;3.9347\nOzark;31.4508\nMānikpur;25.1339\nHopatcong;40.9541\nSan Cristóbal;-30.3167\nMoorestown-Lenola;39.9659\nTibri;31.9854\nEast Bridgewater;42.0352\nKannivādi;10.3794\nHettstedt;51.6333\nKoundara;12.4800\nDom Feliciano;-30.7039\nSankt Leon-Rot;49.2653\nYanshuiguan;36.8252\nRoyal Kunia;21.4053\nLockhart;28.6270\nTafrant;34.6250\nLangerwehe;50.8167\nValday;57.9667\nPak Thong Chai;14.7167\nTamār;23.0488\nVöhringen;48.2833\nNether Providence;39.8971\nGangaikondān;11.5389\nDoctor Juan Eulogio Estigarribia;-25.3700\nFeldkirchen;46.7236\nKartuzy;54.3333\nEmerald;-23.5208\nZolote;48.6833\nAbhwar;26.1740\nNacozari Viejo;30.4833\nO‘nhayot;41.0103\nLake Arbor;38.9105\nBlack Forest;39.0608\nItakura;36.2259\nFurukawamen;33.2384\nMatiçan;42.6449\nJacaraú;-6.6119\nRheinfelden;47.5500\nRozenburg;51.9058\nCiénega de Flores;25.9500\nAbadla;31.0167\nQuakenbrück;52.6772\nJasper;33.8508\nWhitewater;42.8372\nVærløse;55.7819\nNeuri;26.0076\nNawāda Gobindganj;26.4868\nBarkuhi;22.1901\nLakinsk;56.0333\nArtena;41.7333\nWest Nipissing / Nipissing Ouest;46.3667\nSidmouth;50.6800\nAssenede;51.2333\nManoharpur;22.3746\nUslar;51.6597\nMontfoort;52.0500\nCorat;40.5725\nMathurāpur;24.9073\nCervignano del Friuli;45.8231\nNorth Mankato;44.1810\nTsukawaki;33.2832\nMapanas;12.4750\nDuvva;16.7792\nYakhroma;56.2833\nRomitan Shahri;39.9333\nBog Walk;18.1020\nBuda;30.0758\nMarhamat;40.5000\nBhīmadolu;16.8144\nCaln;40.0014\nEstremoz;38.8500\nSadovoye;46.1269\nBan Mueang Nga;18.5997\nTergnier;49.6558\nIshikawa;37.1571\nDoranahalli;16.7324\nNyasvizh;53.2167\nKot Īsa Khān;31.1351\nEski Īkan;43.1833\nDharampur Bānde;25.6609\nLengede;52.2049\nMedvezhyegorsk;62.9000\nSumbas;37.4431\nAmbohimanga Atsimo;-20.8667\nTenerife;9.8989\nEl Barrio de la Soledad;16.8000\nBeekman;41.6042\nSan Rafael Petzal;15.4167\nCoronel Bogado;-27.1700\nOud-Turnhout;51.3167\nPhulwaria;25.9395\nBoha;29.8348\nBua Yai;15.5858\nZapolyarnyy;69.4167\nJuan L. Lacaze;-34.4311\nŪttukkottai;13.3354\nBideipur;21.0147\nMidlothian;41.6254\nAlgarrobo;10.1000\nRaydah;15.8233\nMirandiba;-8.1189\nKhiria;25.6047\nRājnagar;23.9500\nSimri;25.7523\nSibundoy;1.2033\nOrtahisar;38.6208\nTāmaraikkulam;10.1085\nGonzalez;30.5822\nGesuba;6.7242\nVikravāndi;12.0369\nNovohrodivka;48.2000\nViera West;28.2467\nDaean;35.4038\nByāhatti;15.4468\nRezzato;45.5150\nThame;51.7500\nTakerbouzt;36.4180\nOcotepec;17.2167\nCristópolis;-12.2339\nSantiago Ixtayutla;16.5667\nWang’anzhen;39.3989\nSantol;16.7667\nLebanon;43.6353\nVellarivalli;11.6003\nDippoldiswalde;50.8933\nKorneuburg;48.3453\nRānāpur;22.6470\nMankal;17.2014\nSvetlogorsk;54.9500\nMakarska;43.3000\nBārah;25.3885\nSaddle Brook;40.9033\nTarumirim;-19.2808\nMarechal Floriano;-20.4128\nFrei Miguelinho;-7.9408\nSines;37.9547\nOrizona;-17.0308\nNorth Auburn;38.9306\nSanto Antônio dos Lopes;-4.8689\nNova Olinda;-7.0919\nMongeri;8.3167\nBousso;10.4825\nWennigsen;52.2742\nKouroussa;10.6530\nGudūr;17.7956\nKashin;57.3500\nBondeno;44.8833\nCastelsarrasin;44.0400\nFrankenberg;50.9108\nSālotgi;17.1700\nTaki;34.4961\nDayr al Barshā;27.7500\nRosemère;45.6369\nBellair-Meadowbrook Terrace;30.1796\nBedford;42.4969\nVinto;-17.3833\nHasanpur;25.6330\nTranås;58.0333\nAvalēpalli;12.7714\nLubsko;51.8000\nEastham;53.3130\nBenito Juárez;-37.6667\nNirakpurpāli;25.3244\nKawaii;38.0045\nAlmoloya de Alquisiras;18.8500\nKelafo;5.5889\nBishenpur;24.6282\nGoshen;41.3817\nThonotosassa;28.0464\nStaszów;50.5642\nBökönbaev;42.1100\nItanhandu;-22.2958\nEntre Rios de Minas;-20.6708\nKīāshahr;37.4194\nHamworthy;50.7207\nYa‘bad;32.4467\nJodoigne;50.7167\nRasauli;26.1270\nSamāi;24.9788\nEl Porvenir de Velasco Suárez;15.4333\nLamont;35.2659\nCêrro Largo;-28.1489\nPilas;37.3017\nHard;47.4892\nLeirvik;59.7798\nEwarton;18.1833\nSanta Cruz de Bezana;43.4442\nJuan de Acosta;10.8333\nSatuba;-9.5628\nDouar Hammadi;31.6000\nVīraganūr;11.4761\nSaraykent;39.6936\nJiānganj;25.8661\nGermasógeia;34.7181\nBeloeil;50.5333\nArklow;52.7941\nShichinohe;40.7447\nNowy Tomyśl;52.3167\nBickley;51.4003\nKurwa Mathiā;26.8572\nThisted;56.9569\nHokuei;35.4833\nCambados;42.5000\nAnnāmalainagar;11.4000\nAhrensfelde;52.5762\nOrkney;-26.9789\nCromwell;41.6122\nMistassini;48.8229\nSihaul;25.9438\nMittegroßefehn;53.3833\nValença;42.0167\nBou Izakarn;29.1667\nIchtegem;51.1000\nUitgeest;52.5333\nChatham;39.6733\nAmriswil;47.5500\nOchër;57.8833\nDaparkha;26.1293\nChampasak;14.8833\nMill Valley;37.9086\nMilnrow;53.6101\nCecil;40.3147\nEppstein;50.1333\nBurglengenfeld;49.2000\nVan Buren;43.1211\nZherdevka;51.8500\nHayashima;34.6006\nFriedland;51.4167\nMonticello;45.2991\nZayda;32.8167\nMercerville;40.2360\nKrishnarāyapuram;10.9563\nAḑ Ḑab‘ah;31.0338\nBoa Esperança;-18.5400\nBrasilândia;-17.0100\nVenëv;54.3500\nVarde;55.6200\nMahrail;26.2952\nMurrhardt;48.9800\nSakaki;36.4618\nPüspökladány;47.3167\nDumri;26.9873\nBelambo;-19.4000\nLauchhammer;51.5000\nHaidarnagar;24.4883\nFort Bliss;31.8396\nCampos Altos;-19.6958\nBariyārpur;26.6347\nOrange;41.2827\nNilo Peçanha;-13.5989\nSanlúcar la Mayor;37.3831\nKaoma;-14.8000\nMirinzal;-2.0650\nIskapalli;14.7363\nCapitão Enéas;-16.3239\nMinamiaizu;37.2004\nStorozhynets;48.1597\nBad Ischl;47.7115\nAqköl;52.0000\nYulee;30.6350\nKubādupuram;16.4680\nLittle Lever;53.5630\nPaithān Kawai;26.1755\nSingalāndāpuram;11.4166\nMalepur;24.9740\nBainbridge;30.9052\nAdakplamé;7.4500\nNasiyanūr;11.3381\nWest Bradford;39.9633\nAldenhoven;50.8958\nRebouças;-25.6208\nUppidamangalam;10.9034\nBeronono;-18.2000\nBrookside;39.6665\nMedapādu;17.0044\nPapagaios;-19.4489\nPiquete;-22.6136\nKarma;23.6840\nBaianópolis;-12.3058\nSummerstrand;-33.9914\nPadaivedu;11.4401\nValbonne;43.6414\nMarchtrenk;48.1917\nKsibet el Mediouni;35.6900\nNeuenkirchen;52.2411\nSimões;-7.5989\nBelm;52.3000\nBhadarwāh;32.9800\nHunasagi;16.4575\nBovenden;51.5897\nTitiribí;6.0667\nSeirō;37.9745\nBeilen;52.8567\nMŭ’minobod;38.1083\nGłowno;51.9642\nPedro Velho;-6.4389\nRio Piracicaba;-19.9289\nPuerto Deseado;-47.7500\nWezep;52.4625\nVellakkinar;11.0736\nKadena;26.3616\nLauriyā Nandangarh;26.9833\nKnottingley;53.7050\nMucambo;-3.9089\nVeglie;40.3333\nGalatge;16.4200\nSidi Abdelkarim;33.1869\nGrand Falls;48.9578\nRose Belle;-20.4025\nOlgiate Olona;45.6333\nMayrtup;43.2036\nPolukallu;15.8284\nKerben;41.5000\nOstrzeszów;51.4167\nJefferson Valley-Yorktown;41.3180\nLakoucun;28.3412\nNioaque;-21.1350\nTurki;26.0381\nEggenfelden;48.4039\nIpiranga;-25.0239\nJīran;24.3087\nSan Ferdinando di Puglia;41.3000\nKakunodatemachi;39.5963\nNáfpaktos;38.3939\nLakeland North;47.3374\nArenoso;19.1800\nNovoulyanovsk;54.1667\nPélézi;7.2833\nKisanuki;31.3444\nSan Vicente;17.5947\nUxbridge;42.0593\nArlington;35.2594\nNarvik;68.4363\nFara in Sabina;42.2167\nKępno;51.2833\nSantiago Jocotepec;17.5833\nZimnicea;43.6522\nThong Pha Phum;14.7382\nRāyapalle;16.2836\nWaianae;21.4568\nLübben (Spreewald);51.9500\nSonbarsa;25.7069\nSkippack;40.2165\nClearview;44.3981\nSungai Guntung;0.2956\nAginiparru;16.6817\nNelas;40.5167\nLeverano;40.2833\nEynesil;41.0500\nNesebar;42.6500\nCheadle;52.9849\nRambha;19.4433\nBoutilimit;17.5504\nVetralla;42.3106\nSan José Acatempa;14.2667\nBhakua;26.5167\nGangavalli;11.4381\nSobrāon;31.1833\nChōsei;35.4167\nNetāpur Tānda;16.8321\nJabbeke;51.1833\nOvidiu;44.2700\nDebre Werk’;10.6667\nTorre del Campo;37.7667\nVedappatti;10.9988\nNaţanz;33.5133\nSpaichingen;48.0758\nMitontic;16.8667\nSöğütlü;40.9000\nFelixlândia;-18.7578\nFokino;53.4500\nFujikawa;35.5612\nDundigal;17.5781\nCalifornia;38.2969\nRicaurte;-2.8667\nNiška Banja;43.2933\nLeuna;51.3167\nFrederick;40.1088\nSābang;22.1830\nSāgar;16.6249\nSomerton;32.6007\nRāmpurwā;26.7544\nMaria da Fé;-22.3078\nGurinhém;-7.1239\nSher;26.3422\nTamm;48.9167\nBebra;50.9711\nSülüktü;39.9400\nSahalanona;-22.0500\nLukoyanov;55.0333\nBalua;26.3272\nTempio Pausania;40.9015\nHòa Thượng;21.6472\nAstolfo Dutra;-21.3150\nKaluvāya;14.5117\nLich;50.5217\nSaghar Sultānpur;26.1583\nAntanambaobe;-16.2500\nRio Azul;-25.7328\nLuling;29.9008\nMahatsinjony;-21.4167\nTibasosa;5.8333\nEast Wenatchee;47.4174\nElizabethton;36.3367\nTola Khadda;26.7396\nKalkar;51.7389\nAlvorada D’Oeste;-11.3417\nItalva;-21.4208\nSantiago de Anaya;20.3844\nStroud;51.7440\nGolub-Dobrzyń;53.1000\nEl Guetar;34.3372\nFatehpur;26.2813\nFarmington;42.9895\nRāmpur Shāmchand;25.5664\nMjölby;58.3333\nLomas de Sargentillo;-1.8833\nXexéu;-8.8019\nDamalcheruvu;13.4833\nFiadanana;-20.3333\nZazafotsy;-22.2000\nBamble;59.0197\nSanta Catalina;10.6039\nSint-Gillis-bij-Dendermonde;51.0189\nPelham;42.7335\nZhipingxiang;35.2949\nAracatu;-14.4278\nChaparral;32.0442\nGudikallu;15.7441\nVillacidro;39.4578\nGalmi;13.9660\nAmbohimitombo;-20.7167\nKivertsi;50.8331\nShitāb Diāra;25.7563\nGouveia;40.5000\nSarezzo;45.6500\nMahavelona;-19.1667\nDryden;42.4786\nMbini;1.5833\nSt. Clair;42.7833\nMcFarland;35.6781\nAdh Dhakhīrah;25.7347\nPetrovske;48.2833\nGondalga;17.5097\nTalwat;31.2883\nAkropong;5.9742\nMeckenbeuren;47.7000\nMignouré;7.4833\nLivingston;37.3875\nBang Racham;14.9000\nLatham;42.7427\nMoudjbara;34.5037\nKovilūr;12.5537\nFrunze;40.1267\nEnghien;50.7000\nCasatenovo;45.6983\nAndalgalá;-27.6000\nAllouez;44.4721\nXikou;23.5947\nAmbatomarina;-20.5833\nMarokarima;-21.2167\nOberhaching;48.0167\nMontepulciano;43.1000\nAmborondra;-21.9167\nSchmölln;50.8950\nWauconda;42.2749\nRío de Oro;8.2917\nVanono;-16.0333\nCovington;33.6049\nWanding;24.0833\nGullapuram;10.0657\nEl Carmen de Atrato;5.8983\nTsarahasina;-15.7667\nGekhi;43.1636\nMór;47.3717\nTall Banāt;36.2550\nBēylul;13.2644\nHuron;44.3623\nHantsavichy;52.7500\nMúggia;45.6000\nSrīnagar;25.9823\nCórdoba;0.8550\nMāndalgarh;25.2000\nAntohobe;-19.7667\nChumpak;41.8585\nBrainerd;46.3553\nNew Ulm;44.3120\nFāmenīn;35.1142\nKamituga;-3.0600\nShāndīz;36.3953\nShofirkon Shahri;40.1167\nLa Entrada;15.0500\nItaguaçu;-19.8019\nKumirimora;22.6939\nAmbodihara;-14.7500\nWadlakonda;17.7736\nBuchloe;48.0375\nChesterton;41.5997\nLariano;41.7333\nCampina da Lagoa;-24.5919\nGenthin;52.4000\nTalata-Vohimena;-20.8500\nVillalba;43.3000\nBealanana;-14.5500\nAßlar;50.5833\nKillai;11.4493\nHavelock North;-39.6667\nErbach;49.6569\nTaiyong;26.4726\nItamonte;-22.2839\nSolhan;38.9681\nWood Dale;41.9668\nBiscarrosse;44.3931\nDevipattinam;9.4770\nSkoczów;49.8006\nCollege Park;33.6363\nAmbohimiera;-21.0500\nDonji Vakuf;44.1500\nAlexandria;45.8776\nIraci;-8.8078\nJacksonville;31.9642\nBeraketa;-24.1833\nAmbahita;-24.0000\nKalandy;-15.7500\nVieste;41.8833\nBevato;-18.6833\nMahajamba;-15.7000\nSharonville;39.2825\nSaint-Gilles;43.6778\nJānapādu;16.4617\nThala;35.5667\nTierra Amarilla;-27.4822\nBatuan;9.8000\nBoechout;51.1500\nAnkiliabo;-21.7000\nMirdaul;26.2363\nTaphan Hin;16.2108\nBan Khlong;16.8353\nMontesarchio;41.0667\nSale;-38.1000\nSan Bartolo;15.0844\nTeploklyuchenka;42.5000\nLandau an der Isar;48.6667\nTaishi;34.5187\nMarotsiraka;-24.2833\nZeven;53.3000\nOostakker;51.1000\nErbach;48.3281\nSan Rafael Las Flores;14.4814\nVatolatsaka;-23.3000\nStatte;40.5667\nForest City;28.6619\nSan Pedro Pochutla;15.7476\nWoudenberg;52.0833\nPoço Branco;-5.6228\nMiarinarivo;-16.6167\nDunmore;41.4152\nBekipay;-16.2500\nBhikkiwind Uttār;31.3400\nChityāl;17.2333\nNachikatsuura;33.6261\nBeharona;-21.5167\nHilpoltstein;49.1833\nGuapó;-16.8308\nMarudūr;10.9160\nSonupur;25.8000\nRafaï;4.9731\nKurtkoti;15.3681\nDhāna;23.7470\nMisano Adriatico;43.9667\nHuangyadong;36.8039\nWeißenhorn;48.3000\nDubovka;49.0500\nGorbea;-39.1000\nÇaybaşı;41.0333\nMidleton;51.9160\nKhe Sanh;16.6193\nBairia;26.7373\nTako;35.7356\nTitara;26.2311\nKuraymah;18.5500\nCanmore;51.0890\nKadoli;15.8800\nLauterbach;50.6378\nKathevaram;16.2608\nNehrəm;39.1122\nMahuākherāganj;29.1300\nBoyovut;40.2822\nDueville;45.6333\nAltınoluk;39.5823\nPhilippsburg;49.2333\nBeesel;51.2833\nLyndhurst;41.5172\nAleksandrów Kujawski;52.8767\nDhutauli;25.5274\nChodov;50.2414\nAlfredo Chaves;-20.6350\nBolívar;4.3386\nAlcanena;39.4667\nWanzleben;52.0667\nBandar-e ‘Asalūyeh;27.4744\nBaduriātola;24.0928\nSterling;40.6205\nEast Norriton;40.1506\nBerre-l’Étang;43.4756\nPolavaram;17.2500\nEast Greenwich;41.6362\nPacaembu;-21.5622\nFergus Falls;46.2854\nVilanova del Camí;41.5733\nNoyon;49.5811\nSalaverry;-8.2214\nKiskőrös;46.6204\nTopliţa;46.9236\nPrimeira Cruz;-2.5100\nHobe Sound;27.0729\nSan Agustín de Guadalix;40.6781\nPetrolândia;-9.1828\nSpiesen-Elversberg;49.3167\nAnapurus;-3.6719\nJhaua;25.6250\nAthens;35.4573\nPalkūr;15.4144\nVedi;39.9106\nSesquilé;5.0453\nAntonivka;46.6791\nSugauna;26.4077\nWillow Grove;40.1469\nNynäshamn;58.9000\nNovellara;44.8500\nRed Oak;32.5212\nTapilula;17.2500\nPolotitlán de la Ilustración;20.2231\nPanapākkam;12.9210\nFagnano Olona;45.6667\nTucacas;10.7978\nPing’anbao;40.4901\nBinkolo;8.9500\nBadarwās;24.9752\nBahādurpur;25.4522\nVelānganni;10.6814\nCuriúva;-24.0328\nGömeç;39.3911\nSt. James;40.8761\nWakasa;35.5489\nChampādānga;22.8275\nBheja;26.1046\nChợ Mới;10.5500\nOlean;42.0819\nFujimi;35.9146\nMaracaí;-22.6106\nHidalgo;26.1090\nMoralzarzal;40.6750\nPirallahı;40.4708\nZhovkva;50.0667\nAurora;42.7382\nMarmeleiro;-26.1489\nLorsch;49.6539\nŠamorín;48.0267\nBrejo do Cruz;-6.3489\nOulad Chikh;32.8544\nToyloq Qishlog’i;39.6014\nMoberly;39.4179\nCircleville;39.6063\nKalādgi;16.2040\nGien;47.6981\nUrupês;-21.2019\nNewhaven;50.8000\nManor;30.3562\nBihārīganj;25.7341\nPuxinanã;-7.1608\nPaikpar;26.0966\nKamtaul;26.3280\nKamigōri;34.8736\nBarghāt;22.0306\nDiego de Almagro;-26.3911\nKettering;38.8888\nLlanera;43.4667\nPitlam;18.2227\nShepherdsville;37.9813\nSan Prisco;41.0833\nMcPherson;38.3714\nBayt Sāḩūr;31.7000\nMaumee;41.5696\nKaraund;25.9741\nKrumbach;48.2500\nLittleborough;53.6440\nNew Franklin;40.9525\nArbaa Laaounate;32.7446\nBergen;54.4167\nMelsungen;51.1333\nSun Lakes;33.2172\nEngenheiro Beltrão;-23.7969\nStrada;43.5833\nNāgāwaram;17.4875\nFrei Paulo;-10.5489\nTomiño;41.9833\nKodriva;22.5342\nQiblaí;38.6167\nKhmis Sidi al ’Aydi;33.1228\nPīrnagar;25.5982\nHājan;34.2989\nChaoyangdicun;42.0221\nHīdaj;36.2547\nPlouzané;48.3800\nJālihalli;16.3643\nSan Antonio de las Vueltas;22.5167\nAvanhandava;-21.4608\nTurki;26.0294\nPanjgirāin Kalān;30.6096\nWaycross;31.2108\nBodagudipādu;14.7669\nIvanec;46.2264\nIpanguaçu;-5.4978\nDouar Lehgagcha;32.5500\nLanuvio;41.6833\nTummalapenta;15.0278\nCavarzere;45.1370\nHigashimiyoshi;34.0368\nZhashkiv;49.2500\nNorth Battleford;52.7575\nGuapé;-20.7619\nCorupá;-26.4250\nJutaí;-2.7469\nKauhajoki;62.4319\nGura Humorului;47.5539\nWanze;50.5353\nDongshicuo;23.7021\nHatoyama;35.9815\nParuchūru;15.9667\nWommelgem;51.2000\nLuozi;-4.9480\nPembroke;45.8167\nJinmingsi;38.0512\nEttenheim;48.2556\nAvenal;36.0311\nMiami Springs;25.8195\nClemencia;10.5833\nPowell;40.1689\nGuamal;3.8800\nArroio dos Ratos;-30.0769\nSanto Augusto;-27.8508\nCasinhas;-7.7411\nGăeşti;44.7194\nLower Moreland;40.1346\nZhongliao;23.9039\nHaßfurt;50.0167\nToulal;32.3036\nZábřeh;49.8826\nMangalāpuram;11.5667\nCabo Verde;-21.4719\nSant’Angelo Lodigiano;45.2389\nOosterzele;50.9500\nCanals;38.9611\nWayland;42.3586\nHelensburgh;56.0166\nHammam el Rhezez;36.8900\nPowell;36.0358\nBan Tha Luang Lang;12.6376\nAlamo;37.8548\nArcozelo;41.0555\nDhubaria;24.0044\nCouvin;50.0500\nMargraten;50.8167\nGrünberg;50.6000\nWest Lealman;27.8192\nKonāje;12.8162\nSan Pietro Vernotico;40.4833\nAjjampur;13.7279\nUruana;-15.4978\nPlumstead;40.3878\nHorodyshche;49.2925\nSirugamani;10.8975\nSan Juan;10.6500\nTiruppālai;9.9825\nPilich;25.2379\nApostolove;47.6595\nForlimpopoli;44.1833\nPeri-Mirim;-2.5778\nWells Branch;30.4433\nDammennu;17.0308\nJoaquim Pires;-3.5078\nMachados;-7.6858\nLatisana;45.7833\nAmpasinambo;-20.5167\nSariq;37.6722\nYamanobe;38.2891\nGranville;48.8381\nRājupālem;15.1378\nAberystwyth;52.4140\nAchuapa;13.0536\nSauk Rapids;45.5981\nFátima;39.6255\nAk-Dovurak;51.1833\nAlagoinha;-8.4658\nDowbarān;28.4061\nMillbury;42.1925\nJupi;-8.7119\nLyaskovets;43.1000\nSelston;53.0700\nCherry Hill Mall;39.9384\nBalha;25.5468\nHöchstadt an der Aisch;49.7000\nRutherford;-32.7150\nBundāla;31.5333\nChāhatpur;26.2331\nJindayris;36.3947\nGhorādal;22.0519\nMichendorf;52.3129\nArzachena;41.0833\nCrispiano;40.6000\nUppāda;17.0883\nLeżajsk;50.2667\nGouka;8.1333\nKings Park West;38.8151\nLoganville;33.8353\nJardín;5.5986\nSt. Helens;45.8572\nEichstätt;48.8919\nAtomé-Avégamé;7.2333\nZarghūn Shahr;32.8500\nBeachwood;41.4759\nAmpthill;52.0263\nSóller;39.7667\nTeays Valley;38.4482\nHeliópolis;-10.6828\nMelenki;55.3333\nKadattūr;12.0861\nKolagallu;15.1500\nNeckargemünd;49.3939\nSarāyān;33.8603\nVerona;42.9892\nPuduppatti;9.7639\nIsāgarh;24.8391\nCarmópolis;-10.6478\nForest Hill;32.6619\nMarienheide;51.0833\nNallajerla;16.9500\nSouth Sioux City;42.4627\nNantucket;41.2831\nCuruá;-1.8878\nCarmo de Minas;-22.1219\nBellefontaine;40.3627\nAmrābād;16.3833\nPakra;25.3711\nSansare;14.7478\nChinna Mushidivāda;17.8057\nVerín;41.9408\nShōdoshima;34.4798\nKyzyl-Kyshtak;40.5444\nBhulath Gharbi;31.5344\nDārat ‘Izzah;36.2828\nRostamābād;36.8983\nKupino;54.3667\nPierrelatte;44.3775\nWorthington;43.6281\nPondūru;18.3508\nKaua Kol;24.8447\nKetsch;49.3658\nAtner;21.6238\nChiran;31.3783\nTorul;40.5572\nBeeville;28.4053\nMont-Laurier;46.5500\nMünchenstein;47.5167\nCastel San Giovanni;45.0500\nRichland;40.4490\n‘Alem T’ēna;8.3000\nGołdap;54.3161\nUzwil;47.4369\nTarumizu;31.5228\nBad Soden-Salmünster;50.2667\nAjas;34.3316\nMata;14.0436\nChandla;25.0715\nDyykan-Kyshtak;40.5100\nSattar;25.9550\nEphrata;40.1811\nArsali;24.3754\nMansidão;-10.7158\nGülchö;40.3167\nGosaingaon;25.3724\nColdwater;41.9465\nVillas;26.5504\nKhomām;37.3892\nBiedenkopf;50.9128\nWłodawa;51.5500\nBa Chúc;10.5000\nSampaloc;14.1625\nChinique;15.0411\nNurkot;32.2017\nMsata;-6.3362\nBollène;44.2803\nChâlette-sur-Loing;48.0117\nStrathmore;51.0378\nPalmeirais;-5.9778\nBandarbeyla;9.4833\nButtar;31.0038\nFilandia;4.6667\nTrzebnica;51.3050\nSan Juan La Laguna;14.7000\nDestin;30.3950\nAlleroy;43.2500\nSanta Coloma de Farnés;41.8624\nBhachhi Asli;26.0147\nSchoonhoven;51.9500\nBrandermill;37.4340\nDharmaram;18.3038\nBully-les-Mines;50.4419\nFutrono;-40.1333\nNybro;56.7333\nKādachchinallūr;11.3686\nRío Caribe;10.7008\nCaledon;-34.2300\nKotgīr;18.5722\nXireg;36.9257\nIpswich;42.6857\nKafr ‘Awān;32.4167\nEast Whiteland;40.0474\nSátoraljaújhely;48.4000\nHünxe;51.6417\nAuburn;38.8950\nWarrenville;41.8209\nBondāda;16.5295\nCarlópolis;-23.4250\nFallsburg;41.7391\nSaksohāra;25.3635\nTejutla;14.1667\nGenas;45.7314\nSolonytsivka;49.9942\nSão José do Cedro;-26.4550\nCamponogara;45.3833\nSabbavaram;17.7900\nBangāwān;26.0427\nNeunkirchen;50.7861\nMangha;23.3700\nAndaraí;-12.8069\nMotupe;-6.1519\nKawatana;33.0728\nMarshall;44.4488\nNamīn;38.4256\nHazel Crest;41.5732\nKollipara;16.2877\nCobh;51.8510\nBedford;38.8602\nCedar Lake;41.3696\nAltos del Rosario;8.8000\nKuleshovka;47.0833\nBusogo;-1.5572\nSão João do Triunfo;-25.6828\nHinabangan;11.7000\nSchermbeck;51.6950\nMassaranduba;-7.2000\nBlegny;50.6667\nNules;39.8525\nSnoqualmie;47.5293\nYongcong;26.0451\nManta;10.3564\nMahalpur;31.3618\nEl Crucero;11.9894\nTamsaout;29.5333\nMansāpur;26.5262\nKonaklı;36.5833\nArcadia;43.0870\nSaugeen Shores;44.4333\nBeacon;41.5036\nPalmito;9.3333\nChanal;16.6000\nMinneola;28.6067\nLas Rosas;-32.4833\nQuartucciu;39.2529\nMeruoca;-3.5419\nMount Vernon;38.7140\nKachchippalli;11.5950\nDallas;33.9152\nRaamsdonksveer;51.6833\nQuatá;-22.2475\nBan Nong Hoi;18.7500\nPallappālaiyam;10.9951\nBairo;26.0144\nLone Tree;39.5309\nCanton;40.5632\nSirigeri;15.6300\nAd Duraykīsh;34.8969\nFriesenheim;48.3731\nMcMinnville;35.6864\nKākan;26.1509\nWinsum;53.3312\nCamapuã;-19.5308\nSouth Park;40.2988\nGrammichele;37.2147\nWarrensville Heights;41.4363\nChannahon;41.4210\nBirstall;52.6736\nLakeland;35.2585\nUarini;-2.9900\nJimbolia;45.7931\nFontenay-le-Comte;46.4669\nDuvergé;18.3800\nCidelândia;-5.1739\nLanuza;9.2322\nSan Jorge;14.9253\nPātiram;25.3167\nLöningen;52.7167\nFranklin Park;40.4439\nChāmpāhāti;22.4000\nIhtiman;42.4374\nBasantpur;26.1331\nLappersdorf;49.0525\nDinant;50.2667\nThompson;55.7433\nGopālnagar;22.8289\nBeverstedt;53.4340\nKarnāwad;22.7361\nAn Thành B;10.1958\nPalestina;5.0833\nVázquez;21.1399\nDragør;55.5833\nBunhe;48.2206\nCastelfranco di Sotto;43.7000\nSirhāli Kalān;31.2783\nMelissa;33.2891\nVigodarzere;45.4500\nNikolayevsk;50.0333\nSivalārkulam;8.8700\nRoyal Wootton Bassett;51.5330\nSaint-Orens-de-Gameville;43.5514\nCaldeirão Grande;-11.0200\nEchelon;39.8482\nEttāpur;11.6625\nAlto Paraná;-23.1289\nSão Pedro do Piauí;-5.9289\nSaint-Paul-lès-Dax;43.7256\nQuierschied;49.3167\nItapagipe;-19.9089\nBad Laasphe;50.9303\nSalzano;45.5333\nEloxochitlán;18.5088\nLlanes;43.4214\nGarag;15.5750\nDoumé;8.0167\nBeyne-Heusay;50.6167\nMonte Alegre de Sergipe;-10.0269\nVelilla de San Antonio;40.3667\nRatnāpuram;18.6283\nShawangunk;41.6335\nSão Félix da Marinha;41.0340\nParjuār;26.4836\nŠternberk;49.7305\nLavaltrie;45.8833\nMutterstadt;49.4417\nAmboasary-Gara;-18.4333\nCallaway;30.1349\nMantenópolis;-18.8628\nAlto Longá;-5.2508\nIhorombe;-23.0000\nCaldas;-21.9239\nSpring Garden;39.9454\nBridport;50.7336\nOkinoshima;36.2091\nGran;60.4411\nIxcatepec;21.2333\nNicosia;37.7500\nPfullendorf;47.9242\nGłubczyce;50.2011\nRasūlpur;25.9938\nKankandighi;21.9744\nCajabamba;-7.6237\nSalisbury;40.5768\nChāwalhāti;26.4614\nSan Martino di Lupari;45.6557\nSanta Luzia;-15.4289\nNorth Branford;41.3645\nTalne;48.8863\nHösbach;50.0000\nBarāon;25.4551\nSowerby Bridge;53.7100\nNew Fairfield;41.4880\nSan Martín Zapotitlán;14.6000\nCastilla La Nueva;3.8333\nShiloh;38.5534\nBergen;52.8103\nTilāri;25.0040\nCayce;33.9459\nVirgem da Lapa;-16.8039\nMulakalūru;16.2776\nBeach Park;42.4260\nCrevalcore;44.7167\nHathwān;25.6672\nDakit;10.0600\nTakkolam;13.0164\nMangalapur;13.6245\nManivilundān;11.6004\nTrubchevsk;52.5667\nTorredonjimeno;37.7667\nSunjiayan;27.8776\nKirchheim bei München;48.1766\nConway;28.4968\nHaldipur;14.3333\nCañasgordas;6.7497\nKyzyl-Adyr;42.6200\nPeabiru;-23.9128\nRio de Contas;-13.5789\nMaheswa;25.9718\nCossimbāzār;24.1200\nŻnin;52.8500\nKarivalamvandanallūr;9.2715\nMontefiascone;42.5333\nNemocón;5.0500\nParanhos;-23.8928\nZelzate;51.2000\nMarion;35.2035\nMasangshy;42.9289\nChīmalapādu;16.8902\nUdayagiri;20.1242\nKastoriá;40.5167\nSaint-Martin-de-Crau;43.6397\nHersham;51.3681\nFenton;52.9977\nMelilli;37.1833\nKingston;41.9862\nManching;48.7186\nKaimana;-3.6444\nAfir;36.7676\nTerra Boa;-12.3919\nGopālasamudram;8.6747\nKhānāpur;19.0333\nSpeedway;39.7937\nBad Dürrheim;48.0167\nKorahia;26.5325\nZhukovo;55.0333\nPlougastel-Daoulas;48.3725\nUrucuia;-16.1328\nSan Javier;-30.5833\nGrez-Doiceau;50.7333\nSan Gennaro Vesuviano;40.8667\nQingxicun;24.5300\nCombarbalá;-31.1833\nBaras;13.6667\nBrecksville;41.3079\nWolsztyn;52.1167\nBetanzos;43.2792\nCeuti;38.0789\nUgo;39.1993\nNidzica;53.3667\nMajārhāt;25.9654\nMontespertoli;43.6500\nHaaren;50.7956\nSan Jacinto;14.6667\nUsmānpur;25.3487\nJānkinagar;25.8955\nRáquira;5.5333\nAghbala;32.4833\nMahārājpur;25.1040\nSantaquin;39.9708\nBan Mae Kaluang;19.0778\nBisee;14.0243\nHajdúsámson;47.6000\nLakewood Park;27.5390\nRommerskirchen;51.0347\nSchüttorf;52.3167\nHulkoti;15.4333\nValdemorillo;40.5017\nSaarwellingen;49.3542\nAuta;25.3882\nSouth Charleston;38.3426\nDrøbak;59.6667\nMaribondo;-9.5769\nWalton-on-the-Naze;51.8480\nKharv-e Soflá;36.1686\nSūrān;27.2856\nQuatis;-22.4069\nSidi Yahia;30.4969\nEndicott;42.0980\nItapetim;-7.3778\nKaharlyk;49.8522\nComines;50.7611\nBan Bung Kha;16.1675\nShangping;25.0897\nMarly;50.3489\nSan Rafael Oriente;13.3833\nKozy;49.8667\nHigh River;50.5808\nSan Marco in Lamis;41.7117\nSerra Branca;-7.4828\nBataredh;26.4250\nArara;-6.8278\nYork;43.1860\nManerbio;45.3667\nSpiez;46.6833\nWest End;26.6867\nSabana Iglesia;19.3300\nSigli;15.0631\nNovi Iskar;42.8000\nOuargaye;11.5000\nEichenau;48.1667\nPresidente Bernardes;-22.0061\nPalangarai;11.1978\nCarluke;55.7340\nNew Providence;40.6996\nKewatgāwān;25.8012\nFeldbach;46.9550\nMario Campos;-20.0558\nPānchgani;17.9200\nSchinnen;50.9500\nLourdes;43.0950\nMqam at Tolba;33.9375\nNārāyangarh;24.2708\nArruda dos Vinhos;38.9833\nBuşrá al Ḩarīr;32.8425\nBarhī;24.3045\nAmilly;47.9731\nReeuwijk;52.0500\nPrimavera;-8.3378\nOak Park;34.1850\nKolappalūr;11.5100\nLake Wylie;35.0997\nBilga;31.0500\nMarietta;39.4241\nBlytheville;35.9321\nCreutzwald;49.2053\nClinton;40.6315\nTrebur;49.9242\nNawāda;25.1021\nConnersville;39.6582\nChâteaudun;48.0708\nThara;26.7027\nVernouillet;48.7208\nGrass Valley;39.2238\nWestern Springs;41.8023\nMalone;44.7956\nJardim de Piranhas;-6.3789\nChalma;21.2167\nIlamatlán;20.7833\nBhankarpur;30.6500\nBāsmenj;37.9964\nFlint;53.2482\nCalderara di Reno;44.5667\nChañaral;-26.3444\nAlexandria;-6.4128\nSan Rafael;14.7333\nL’Union;43.6564\nKnittelfeld;47.2150\nMechtras;36.5448\nSant Sadurní d’Anoia;41.4261\nPatate;-1.3167\nLe Relecq-Kerhuon;48.4086\nNeustadt;49.5967\nCharxin;39.6967\nPort Neches;29.9765\nSamālsar;30.6364\nMoissac;44.1047\nWiesmoor;53.4000\nChimá;9.1500\nGlen Carbon;38.7580\nTezze sul Brenta;45.6862\nArendonk;51.3167\nBesigheim;48.9983\nPatti;38.1389\nGex;46.3333\nKüssnacht;47.0667\nLake Forest Park;47.7574\nAubergenville;48.9583\nGricignano d’Aversa;41.0000\nGeneral Belgrano;-35.7667\nLavagna;44.3167\nKofelē;7.0000\nLibertad;8.5583\nÁguas Vermelhas;-15.7469\nSault Ste. Marie;46.4817\nSan Juan de Betulia;9.2756\nDok Kham Tai;19.1620\nÇayıralan;39.3050\nManatí;10.4450\nMatias Barbosa;-21.8689\nLislique;13.8000\nRoudnice nad Labem;50.4254\nBirdāban;26.4012\nMayenne;48.3031\nMosgiel;-45.8750\nPôrto Esperidião;-15.8528\nLoreto;43.4389\nKissane Ltouqi;34.6000\nCasale sul Sile;45.6000\nKeisen;33.5788\nNeunkirchen;47.7269\nPentapādu Kasba;16.7939\nRoyse City;32.9762\nPervomaysk;54.8667\nLavello;41.0500\nLuchenza;-16.0167\nGoudomp;12.5778\nVitry-le-François;48.7247\nTrogir;43.5169\nPāiker;24.4388\nYecuatla;19.8521\nBacup;53.7040\nSondho Dullāh;25.9016\nUbstadt-Weiher;49.1656\nQuattro Castella;44.6333\nAndasibe;-18.9333\nBrunn am Gebirge;48.1069\nBāgli;22.6412\nHenderson;32.1576\nZehdenick;52.9833\nTuchola;53.6000\nMāyamānkurichchi;8.8855\nTummanatti;11.4284\nFereydūnshahr;32.9411\nGovindgarh;24.3785\nHathauri;25.9593\nFormello;42.0833\nKādiyāmpatti;11.8720\nStandish;53.5860\nSeabrook;29.5751\nSan Juan de Limay;13.1739\nUnión de Tula;19.9570\nBischwiller;48.7664\nPathra;24.8804\nAtaco;3.6000\nRionero in Vulture;40.9167\nVárzea Nova;-11.2589\nWasserburg am Inn;48.0617\nAl Ḩā’ir;25.7900\nFrederiksværk;55.9667\nJucuarán;13.2544\nSan Juan;14.4167\nDambal;15.2960\nAguilar;37.5167\nRio Casca;-20.2258\nKalārdasht;36.5167\nSevern;44.7500\nMartinsville;36.6826\nMangarwāra;26.0119\nParipueira;-9.4650\nLes Ponts-de-Cé;47.4244\nJobat;22.4160\nTenente Portela;-27.3708\nWickede;51.4964\nHissāramuruvani;15.7710\nDinklage;52.6667\nKaspi;41.9250\nAbre Campo;-20.3008\nGeneral Viamonte;-35.0000\nJaca;42.5500\nZehak;30.8939\nCostessey;52.6602\nAlbertirsa;47.2400\nLakkavaram;17.0628\nWake;34.8029\nTirmaigiri;16.7230\nWehr;47.6297\nBteghrîne;33.9300\nKalaiyamputtūr;10.4542\nHockessin;39.7837\nPendências;-5.2600\nSan Antonio Aguas Calientes;14.5333\nSirsia Hanumānganj;26.1381\nBad Salzdetfurth;52.0653\nSathmalpur;25.8749\nBichkunda;18.4000\nŬrtaowul;41.1908\nHarnes;50.4450\nMuisne;0.6108\nBarßel;53.1703\nIrondale;33.5439\nPont-Sainte-Maxence;49.3011\nFatehābād;26.0652\nTestour;36.5500\nBrig-Glis;46.3167\nTenambākkam;12.8102\nButler;40.8616\nNakskov;54.8333\nSan Jacinto del Cauca;8.2500\nBhagwānpur Desua;25.8124\nChiampo;45.5500\nKhoyniki;51.8892\nItano;34.1443\nRuza;55.7000\nLumberton;30.2562\nElavanasūr;11.7154\nAmondara;39.5178\nAraruna;-23.9319\nSan Clemente;15.7119\nGlenpool;35.9488\nEatontown;40.2913\nSangar;37.1811\nJimboomba;-27.8300\nArboga;59.3939\nGulni;24.9309\nEnglewood;39.8643\nOboyan;51.2000\nDores do Indaiá;-19.4628\nWernau;48.6886\nAkhty;41.4647\nJupiter Farms;26.9222\nInawashiro;37.5578\nCapaci;38.1667\nKeerbergen;51.0031\nRiver Ridge;29.9593\nPlover;44.4615\nKamalāpuram;11.7680\nNangavalli;11.7619\nTucapel;-37.2833\nPegnitz;49.7564\nMarshall;39.1147\nGolyshmanovo;56.3819\nTauberbischofsheim;49.6225\nCalcinaia;43.6833\nBardstown;37.8175\nItapuí;-22.2333\nBarsbüttel;53.5667\nEl Tabo;-33.4586\nStrand;59.0633\nBefandriana;-15.2667\nKing City;36.2164\nNewington;38.7358\nBollnäs;61.3481\nBarlinek;53.0000\nSendenhorst;51.8439\nAconibe;1.3000\nNemours;48.2686\nKhombole;14.7667\nKoskāpur;26.2669\nSaka;34.3412\nNishon Tumani;38.6558\nWath upon Dearne;53.5022\nLewisville;36.1030\nPottsville;40.6798\nSeyitgazi;39.4456\nMozarlândia;-14.7450\nSanta Bárbara;-37.6706\nSinghbāri;25.3946\nFåberg;61.1684\nPomfret;42.4029\nSerrolândia;-11.4158\nEraniel;8.2059\nMahtha;26.5988\nEspita;21.0128\nQigexingcun;42.0200\nShanyincun;37.9151\nPlattling;48.7667\nPritzwalk;53.1500\nRocky Point;40.9357\nRosas;2.2667\nLakhipur;24.8000\nAtlantic Beach;30.3375\nMorąg;53.9167\nKalikiri;13.6333\nPalos Verdes Estates;33.7872\nCarapebus;-22.1869\nBuchs;47.1667\nLuís Antônio;-21.5550\nChüy;42.8100\nOxford;42.1286\nPandireddigūdem;16.8000\nGmunden;47.9181\nDossenheim;49.4492\nCariamanga;-4.3200\nMatsushima;38.3802\nTahannawt;31.3514\nVeyrier;46.1667\nPaso de los Toros;-32.8112\nZelenodolsk;47.5631\nKallanai;10.0374\nCrissiumal;-27.5000\nNolensville;35.9572\nDommasandra;12.8781\nCarpenedolo;45.3654\nPushing;38.1833\nEiras;40.2421\nGrimstad;58.3405\nYengema;8.6167\nVarazze;44.3600\nSanta Marcela;18.2872\nShibām;15.9269\nVelen;51.8939\nSoyaniquilpan;19.9892\nSanta Filomena;-8.1628\nPāpampeta;14.6855\nCalle Larga;-32.8831\nPort Victoria;0.1000\nHopewell;40.5906\nCarros;43.7725\nAffoltern am Albis;47.2833\nRüti;47.2667\nMogeiro;-7.2989\nJoaquín V. González;-25.0833\nTachov;49.7954\nSan José de Maipo;-33.6833\nChalfont Saint Peter;51.6070\nEl Almendro;11.6781\nRibeira Brava;32.6833\nSainte-Sophie;45.8200\nGuéret;46.1706\nItagi;-14.1628\nDiósd;47.4042\nRoßdorf;49.8583\nPeddakūrapādu;16.4833\nPalombara Sabina;42.0667\nCavallino;40.3167\nElfers;28.2140\nForrest City;35.0135\nBarentin;49.5444\nBag‘dod;40.4606\nYozyovon;40.6619\nRödental;50.2833\nAutun;46.9511\nTōnoshō;35.8372\nLa Queue-en-Brie;48.7894\nFarādonbeh;32.0078\nNorth Walsham;52.8214\nKatagon;6.6333\nKilgore;32.3980\nYakage;34.6275\nNarhat;24.7774\nQal‘at al Maḑīq;35.4100\nFatehpur;25.2463\nDębno;52.7333\nIngeniero Maschwitz;-34.3667\nLincolnwood;42.0054\nNovi Marof;46.1667\nOttersberg;53.1000\nAmbodilazana;-18.1194\nKūdangulam;8.1903\nLüderitz;-26.6458\nDahu;24.3978\nSudbury;52.0417\nNova Veneza;-28.6369\nPuerto Morazán;12.7669\nKamikawa;36.2139\nFlitwick;52.0038\nBugugoucun;41.6904\nShīn;34.7833\nAubenas;44.6197\nČeský Krumlov;48.8111\nOudenbosch;51.5892\nNordestina;-10.8228\nCoolidge;32.9363\nTanagura;37.0299\nShetpe;44.1667\nCastiglion Fiorentino;43.3439\nTehachapi;35.1276\nItiruçu;-13.5319\nCowdenbeath;56.1100\nOdder;55.9725\nKasumkent;41.6667\nKūhbil;36.5133\nTarhūnah;32.4339\nFicarazzi;38.0833\nMoorreesburg;-33.1500\nPorto Recanati;43.4322\nTirumakūdal Narsipur;12.2121\nHüllhorst;52.2833\nBaş Göynük;41.3228\nDemerval Lobão;-5.3578\nShāhpura;23.1828\nGuillena;37.5333\nBombarral;39.2681\nTrebaseleghe;45.5833\nBan Chomphu Nuea;16.6833\nArma;25.1966\nAbrera;41.5165\nPicaña;39.4361\nChiroqchi;39.0336\nAl Muzayrīb;32.7109\nJitaúna;-14.0189\nEngenheiro Paulo de Frontin;-22.5500\nPuerto San Martín;-32.7167\nAmity;40.2905\nMiarinarivo;-18.9608\nHarwich;41.6957\nCremlingen;52.2489\nAš;50.2239\nSítio do Mato;-13.0850\nWeinsberg;49.1518\nVilāngurichchi;11.0709\nKallūr;16.1405\nSint-Michiels;51.1833\nMānākondūr;18.3981\nWolfhagen;51.3167\nFort Campbell North;36.6631\nPfarrkirchen;48.4167\nBerezne;51.0000\nWashington;40.1741\nReggada;29.5716\nSaint-Charles-Borromée;46.0500\nCapo d’Orlando;38.1500\nRabot;38.6167\nHashikami;40.4525\nFene;43.4667\nNosivka;50.9300\nBhagwatpur;25.7484\nMotobu;26.6575\nGlendale;43.1287\nNesconset;40.8467\nCharlton;42.1351\nStolin;51.8833\nKalavai;12.7691\nZella-Mehlis;50.6597\nZandhoven;51.2167\nSweden;43.1791\nBan Chorakhe Samphan;14.3258\nBrønderslev;57.2694\nErgolding;48.5833\nBocholt;51.1722\nMercedes Umaña;13.5667\nTurbihāl;15.7614\nPalmetto;27.5251\nPortage La Prairie;49.9728\nCocotitlán;19.2167\nRöthenbach an der Pegnitz;49.4847\nQal‘eh Ra’īsī;31.1900\nEl Tablón;1.4269\nSahri;25.4721\nUsumatlán;14.9489\nKolattūr;13.3295\nBeyla;8.6833\nFruita;39.1548\nLa Victoria;4.5214\nManí;4.8167\nBorodyanka;50.6474\nFranconia;40.3055\nHerbrechtingen;48.6253\nLake Station;41.5729\nTerebovlya;49.3000\nKiiminki;65.1333\nChợ Lách;10.2647\nSeravezza;44.0000\nCaçu;-18.5569\nOlfen;51.7167\nLos Chiles;10.9639\nRābor;29.2911\nDhanaura;25.1905\nKamianka;49.0333\nArakere;12.4133\nSlobozhanske;48.5342\nSargūr;11.9997\nBaruāri;26.0305\nMontegranaro;43.2333\nChenggong;23.1167\nGärtringen;48.6408\nLawang Bato;14.7300\nSuperior;39.9340\nClinton;41.2980\nFyzabad;10.1833\nChulumani;-16.4102\nAmmavārikuppam;13.1784\nCalcinato;45.4581\nAuburn;41.3666\nSvirsk;53.0833\nHarrow on the Hill;51.5655\nPanjīpāra;26.1369\nMohgaon;21.6394\nHaselünne;52.6667\nCairo Montenotte;44.4000\nAmbazoa;-25.3139\nGaura;24.9643\nOcaña;39.9569\nSebt Labrikiyne;32.2944\nPontecorvo;41.4626\nCampo de Criptana;39.4000\nSarria;42.7833\nFinneytown;39.2159\nPácora;5.5258\nAmbohidronono;-18.7500\nLos Alamos;35.8927\nUlvila;61.4333\nShin'onsen;35.6235\nEsneux;50.5333\nMahao;26.8675\nPalangavāngudi;10.7244\nNawā Nagar Nizāmat;26.2895\nMonteux;44.0356\nAjijic;20.3000\nSkoghall;59.3333\nGvardeysk;54.6667\nBarkāgaon;23.8651\nBrignais;45.6739\nHardiyā;26.9443\nKalappālangulam;9.1889\nSan Biagio di Callalta;45.6867\nParvomay;42.1000\nSmithfield;41.8349\nSerra Azul;-21.3108\nManamodu;11.1965\nEl Kansera;34.0419\nQazmalar;40.9814\nLahaina;20.8848\nBergen;51.6000\nNorth Tidworth;51.2370\nSillamäe;59.3931\nÖstringen;49.2194\nTorquay;-38.3333\nAlto Alegre dos Parecis;-12.1278\nDamaishan;24.5038\nBridgetown;39.1552\nĪnderbor;48.5500\nVohitrindry;-22.3833\nEmpedrado;-27.9333\nRāghopur;25.3180\nGiporlos;11.1208\nDouar Sidi Laaroussi;31.8450\nKachavaram;16.5700\nApricena;41.7667\nBeverungen;51.6628\nSovetskoe;41.0600\nBridgnorth;52.5350\nWoodinville;47.7570\nLas Vegas;35.6011\nArgentona;41.5558\nClayton;39.8689\nBedburg;51.7667\nGreat Bookham;51.2780\nCastelnuovo di Verona;45.4333\nBalatonfüred;46.9500\nRadomir;42.5500\nMorbegno;46.1333\nSan Jerónimo;6.4417\nChigwell;51.6225\nSabinov;49.1061\nRāpūr;14.2015\nGudgeri;15.1225\nMehsāri;25.7554\nBaghauni;25.9338\nPlaza Huincul;-38.9338\nCeyu;37.7939\nYamato;32.6858\nAndrews;32.3207\nJoure;52.9667\nRudrūr;18.6700\nLakshmīnārāyanapuram;11.7914\nBlue Ash;39.2480\nGuābāri;26.1511\nBrenes;37.5500\nBolintin Vale;44.4472\nMcCalla;33.3023\nMonfort Heights;39.1823\nCicuco;9.2667\nOcna Mureş;46.3900\nNorth Greenbush;42.6706\nRaffadali;37.4047\nVila Pouca de Aguiar;41.5006\nLincoln;40.1508\nChakwai;25.0543\nSankt Georgen im Schwarzwald;48.1247\nWeilburg;50.4833\nVasylivka;47.4435\nAsjen;34.8500\nMessadine;35.7619\nLa Grande;45.3242\nAgutaya;11.1520\nGangelt;50.9831\nAuriol;43.3694\nMarojala;-14.4833\nÇamardı;37.8330\nSarrebourg;48.7347\nHuguan Nongchang;21.2015\nDedemsvaart;52.6000\nWolvega;52.8761\nFouriesburg;-28.6227\nKanabūr;13.3523\nOrocó;-8.6200\nXaafuun;10.4167\nSharon;41.2340\nJāmi;18.0458\nAnsião;39.9167\nOncativo;-31.9167\nMiranda do Corvo;40.1000\nBaghambarpur;26.8075\nBarrafranca;37.3667\nMatinilla;9.9246\nMaglód;47.4439\nSimijaca;5.5019\nMandrāmo;24.1822\nUttoxeter;52.8980\nBelëv;53.8167\nCarnot-Moon;40.5187\nYzeure;46.5658\nSpilamberto;44.5333\nAlaverdi;41.1333\nHanımçiftliği;38.3833\nTinglayan;17.2650\nNako;-29.6481\nQuzanlı;40.1600\nKotturu;17.2958\nBou Arada;36.3500\nSteamboat Springs;40.4777\nLa Vega;4.9992\nMazatlán Villa de Flores;18.0167\nManuel Ribas;-24.5158\nPūdūru;16.1520\nKrasnozavodsk;56.4333\nThames Centre;43.0300\nBagadó;5.4167\nDuvvūru;14.8333\nLingamparti;17.2827\nPresidente Jânio Quadros;-14.6889\nAltos;-25.2333\nMounds View;45.1071\nToura;11.2436\nBolsover;53.2304\nSinguilucan;19.9675\nRogers;45.1865\nSomain;50.3575\nYelmalla;18.8241\nBaños;-1.3964\nSevūr;12.6865\nAbarán;38.2031\nSeclin;50.5483\nSilago;10.5291\nUyar;55.8267\nGavere;50.9333\nPhalaborwa;-23.9333\nPacatuba;-10.4528\nKirano;-21.8333\nVenkatagirikota;13.0000\nVilla Sandino;12.0500\nBachrā;23.6886\nOftersheim;49.3706\nMīnākshipuram;9.8815\nQal‘eh Ganj;27.5236\nAgdangan;13.8758\nArcachon;44.6586\nTracunhaém;-7.8050\nTerrasini Favarotta;38.1500\nSão João do Araguaia;-5.3578\nStezzano;45.6508\nSanta María de Ipire;8.6638\nVetlanda;57.4333\nVelykodolynske;46.3425\nMississippi Mills;45.2167\nAmbatondrakalavao;-19.4333\nGüçlükonak;37.4711\nKumarkhāli;22.3598\nMavorano;-21.7833\nIona;26.5160\nTeror;28.0590\nYvetot;49.6169\nBegowāl;31.6125\nSchleiden;50.5331\nRaymond Terrace;-32.7615\nSpreitenbach;47.4167\nMonteprandone;42.9167\nDomahani;23.7569\nSinincay;-2.8333\nStoughton;42.9237\nZabaykalsk;49.6514\nKotla;32.7522\nMazıdağı;37.4792\nAzle;32.8955\nPowell River;49.8353\nSete Barras;-24.3878\nAdi Keyh;14.8333\nPrudhoe;54.9610\nBonyhád;46.3006\nTriel-sur-Seine;48.9808\nKannudaiyāmpatti;10.6377\nBalya;39.7500\nGouandé;10.7828\nAlovera;40.5967\nWaltershausen;50.8975\nSouth Glengarry;45.2000\nPetushki;55.9333\nAdygeysk;44.8832\nHadamar;50.4500\nCulaba;11.6578\nMettet;50.3192\nShīnīlē;9.6667\nBargaon;25.3455\nClaiborne;32.5379\nBerkeley Heights;40.6764\nBarsaun;25.6316\nCastellbisbal;41.4767\nGanapavaram;15.9232\nBetatao;-18.2000\nGanapatipālaiyam;11.0309\nMūlaikkaraippatti;8.5454\nKapelle;51.4833\nRingnod;22.6113\nAmbalakindresy;-21.1667\nSali;26.9833\nChabāl Kalān;31.4818\nSanta Maria a Monte;43.7000\nUpperu;16.6500\nQulan;42.9100\nTapiratiba;-21.4678\nStrunino;56.3667\nOlivar Bajo;-34.2330\nTsiately;-23.3167\nMahaboboka;-22.9000\nBelemoka;-21.7833\nSpringbok;-29.6667\nBad Doberan;54.1069\nSan Antonio del Tequendama;4.6328\nNorth Perth;43.7300\nKaspiyskiy;45.3908\nTezontepec;19.8833\nGeneral Enrique Mosconi;-22.6000\nJennings;38.7231\nGurgunta;16.2875\nBamessing;5.9847\nPiratininga;-22.4128\nPharkia;25.9384\nLoveland;39.2677\nPeriya Pattanam;9.2726\nHonggu;36.2930\nMahatsinjo;-22.8000\nNeuhausen auf den Fildern;48.6844\nRosbach vor der Höhe;50.2986\nNoeux-les-Mines;50.4797\nSulingen;52.6667\nSirpur;19.4833\nBefeta;-21.2333\nAmbodiampana;-14.5333\nAnjiajia;-16.4833\nBihtā;25.5731\nWantage;51.5890\nNartan;43.5167\nMekra;25.4705\nDărmăneşti;46.3700\nSagay;9.1167\nTarnos;43.5406\nMercier;45.3200\nMilhã;-5.6750\nKaufungen;51.2811\nSouth Stormont;45.0833\nGovernador Celso Ramos;-27.3150\nJensen Beach;27.2437\nLokāpur;16.1656\nAndranomamy;-16.6000\nLeonforte;37.6417\nMedway;42.1535\nKsar Sghir;35.8419\nOlen;51.1500\nWest Monroe;32.5120\nSaraiya;25.6467\nKouti;6.5542\nScheeßel;53.1706\nSakoabe;-22.2000\nMoody;33.5986\nBan Bang Lamung;13.0470\nÇavdır;37.1550\nKathāniān;31.6373\nRatanpur;24.8996\nNorth Palm Beach;26.8217\nHersbruck;49.5081\nChos Malal;-37.3833\nGumani;9.4500\nVannivedu;12.9173\nSong Phi Nong;14.2306\nAmbohitsilaozana;-17.6833\nMonte Belo;-21.3258\nPudūr;11.2960\nBagaura;26.0388\nKūshk;32.6428\nAl Jumaylīyah;25.6208\nSoddy-Daisy;35.2571\nAtmākūr;16.3364\nSemri;25.3404\nAmbondrona;-21.2667\nTonoshō;34.4869\nAkseki;37.0519\nGlencullen;53.2230\nFannūj;26.5758\nLawaan;11.1408\nDover;40.5304\nAntônio Prado;-28.8578\nMacará;-4.3833\nNoceto;44.8167\nBagnolo Mella;45.4333\nBurgos;17.3331\nHarrison;36.2438\nNewton;35.6630\nMaryport;54.7128\nSaint-Colomban;45.7300\nGrand Terrace;34.0312\nAmpanefena;-13.8667\nHoniton;50.8000\nColesberg;-30.7167\nTreuchtlingen;48.9553\nPingtiancun;25.2225\nJacksonville;33.8088\nCusset;46.1344\nNova Londrina;-22.7658\nMorarano;-18.9000\nAmbodisakoana;-15.4167\nCedar Grove;40.8565\nBedford;41.3919\nClaye-Souilly;48.9450\nDorandā;24.4710\nBen;32.5444\nMorafeno;-21.1000\nGraulhet;43.7608\nMandritsara;-19.5500\nLowshān;36.6206\nVöcklabruck;48.0086\nHerzberg am Harz;51.6575\nCrayford;51.4491\nChernigovka;44.3406\nArohi;23.4270\nFrecheirinha;-3.7600\nGamboula;4.1333\nChinnakkāmpālaiyam;10.7064\nPeißenberg;47.7950\nSan Lucas;13.4144\nOrtaklar;37.8833\nMirabela;-16.2628\nKharar;22.7000\nAnnapolis Neck;38.9409\nStjørdalshalsen;63.4712\nBattulapalle;14.5167\nAlbatera;38.1786\nHosir;23.7735\nTetiiv;49.3708\nVieira do Minho;41.6333\nLacombe;52.4683\nAmersfoort;-27.0078\nĀtmakūru;14.6452\nManalalondo;-19.2500\nMarovandrika;-22.5167\nEvato;-22.6000\nBānsbāri;26.1934\nKaji;26.0249\nKyotera;-0.6317\nAlcácer do Sal;38.3725\nCampiglia Marittima;43.0667\nTenmalai;9.3129\nManambolo;-15.2833\nJuan de Herrera;18.8667\nSebt Bni Garfett;35.2500\nWest Carrollton;39.6701\nAbū Dīs;31.7625\nČelákovice;50.1606\nWächtersbach;50.2547\nRochester;42.6866\nSiderópolis;-28.5978\nHalásztelek;47.3608\nVilla Nueva;-32.9000\nAmborompotsy;-24.6667\nMarovato;-25.5333\nSanto Stino di Livenza;45.7333\nNotodden;59.6294\nBoortmeerbeek;50.9833\nVikāsnagar;30.4680\nRehti;22.7378\nParigi;13.8929\nBryn;53.4990\nBemanevika;-14.1333\nPharāha;24.8522\nAntsirabe Afovoany;-15.9500\nFehmarnsund;54.4454\nEl Marsa;36.8111\nKotra;22.7062\nAnkilimalinika;-22.9500\nSandrakatsy;-16.3333\nManambidala;-22.7500\nShahr-e Herāt;30.0547\nIsaka-Ivondro;-24.8000\nAndreba;-14.5833\nAmbararata;-15.0167\nGárdony;47.1973\nLa Chapelle-Saint-Luc;48.3119\nTabocas do Brejo Velho;-12.7058\nPallejá;41.4242\nMudhol;18.9667\nSolofra;40.8333\nSahavalanina-Antenina;-16.5667\nAnkilivalo;-20.2833\nBolongongo;-8.4667\nLinnich;50.9789\nPortland;36.5921\nMamborê;-24.3189\nSchodack;42.5297\nMangindrano;-14.2833\nLansdowne;39.0844\nMahāgama;25.0342\nAmbohimahavelona;-23.4333\nTāran;26.1570\nMineiros do Tietê;-22.4089\nAmboaboa;-15.9333\nCambridge;38.5515\nAmbahoabe;-16.7667\nBan Tat;17.2791\nPuttānattam;10.4670\nOulad Rahmoun;32.3278\nAnolaima;4.7617\nSolana Beach;32.9943\nAndohajango;-15.9000\nNorth Adams;42.6844\nShiwan;37.4786\nAmpitasimo;-17.7833\nIlafy;-17.8833\nMorungaba;-22.8800\nKirikera;13.7690\nBrieselang;52.5833\nMaktar;35.8606\nTranovaho;-25.3000\nAmpanavoana;-15.6667\nAmbatolampy;-18.9000\nParker;34.8513\nHanumantanpatti;9.7858\nBonneville;46.0789\nAntongomena-Bevary;-15.9500\nTrezzo sull’Adda;45.6089\nPlan-de-Cuques;43.3469\nZhdanivka;48.1500\nLauritsala;61.0708\nSunne;59.8333\nBni Khloug;32.6500\nWanderley;-12.1200\nHaslev;55.3333\nAmbakireny;-17.6667\nGalashiels;55.6194\nBejofo;-17.8333\nChapantongo;20.2833\nKalingiyam;11.4324\nGomparou;11.3000\nKanel;15.4833\nSirūr;16.0965\nSanta Luzia do Itanhy;-11.3508\nDorado;18.4657\nDivnoye;45.9072\nḨarmah;25.9261\nSt. Ann;38.7266\nUpanema;-5.6419\nKesabpur;22.9700\nKhajuri;25.9144\nMaroviro;-21.2333\nChero;25.2463\nBou Adel;34.5428\nLoyish Shaharchasi;39.8839\nGuisser;32.7667\nAmboise;47.4114\nSooke;48.3761\nGreen Valley;39.3414\nMeadville;41.6476\nChaiyo;14.6666\nMiami;36.8878\nAntri;26.0581\nRozhyshche;50.9131\nDagmāra;26.3953\nOatfield;45.4125\nJoppatowne;39.4181\nAntigua;28.4160\nBruay-sur-l’Escaut;50.3983\nTeutschenthal;51.4500\nMaizières-lès-Metz;49.2122\nBrzeg Dolny;51.2708\nMercogliano;40.9231\nPerez;14.1833\nMariánské Lázně;49.9647\nMontgomeryville;40.2502\nIfs;49.1383\nNagar;24.0914\nSan Juan Tecuaco;14.0836\nMotkūr;17.4500\nFraneker;53.2000\nPiketberg;-32.9000\nBorgosesia;45.7167\nConceição do Rio Verde;-21.8808\nSouth Daytona;29.1657\nItayanagi;40.6959\nGornyak;50.9833\nDāmarcherla;16.7269\nChinna Gollapālem;16.3701\nMontecorvino Rovella;40.7000\nSchongau;47.8167\nLicínio de Almeida;-14.6819\nNyāmti;14.1400\nPianiga;45.4583\nKent;41.4735\nDawson Creek;55.7606\nPalmital;-24.8928\nKarāhal;25.4909\nYavoriv;49.9469\nAnderlues;50.4080\nSaposoa;-6.9364\nTashi;34.4977\nTrenton;39.4792\nGrave;51.7667\nKashasha;-1.7578\nLarkspur;37.9393\nTimberlake;37.3167\nUlubey;38.4167\nArluno;45.5000\nBonita;32.6651\nKafr Buhum;35.0611\nGibraleón;37.3753\nSaúde;-10.9408\nPeraiyūr;9.7341\nMonte San Giovanni Campano;41.6333\nSyston;52.7000\nSantiago;9.8291\nSante Bennūr;14.1697\nLipari;38.4667\nSun Village;34.5596\nSanto Tomás La Unión;14.6333\nBroussard;30.1396\nMoka;15.2380\nOverlea;39.3642\nCantagalo;-25.3739\nNandyālampeta;14.7218\nYuza;39.0148\nHajdúhadház;47.6833\nHerk-de-Stad;50.9406\nProvins;48.5589\nÜllő;47.3854\nRibeirão do Pinhal;-23.4167\nClaremont;43.3790\nMogocha;53.7333\nKisara;17.5233\nBeelitz;52.2333\nMándra;38.0667\nKuyganyor;40.8611\nAndijon;40.6444\nLucena;-6.9000\nRushall;52.6110\nRokupr;9.0167\nMisaki;34.9979\nSanto Niño;11.9263\nJapoatã;-10.3469\nJagdīshpur;26.1526\nCroxley Green;51.6470\nMablethorpe;53.3409\nSothgaon;26.6046\nBalbalan;17.4436\nArês;-6.1939\nIbaretama;-4.8039\nRibeirão Bonito;-22.0669\nVelten;52.6833\nMar de Espanha;-21.8669\nSan Pablo;1.6725\nDe Haan;51.2731\nHāthidāh Buzurg;25.3716\nKingsbury;43.3440\nRidge;40.9068\nVadnais Heights;45.0570\nCastel Goffredo;45.2981\nEl Qâa;34.3436\nTakamori;35.5138\nGerpinnes;50.3369\nRivarolo Canavese;45.3312\nKakching Khunou;24.4047\nSanta Margarita;39.7033\nVaddāpalli;18.5324\nPell City;33.5610\nZhongling;28.9391\nLake Country;50.0833\nChamical;-30.3667\nVeľký Krtíš;48.2150\nBan Laem;13.2168\nDouar Oulad Youssef;32.4807\nKaviti;19.0167\nAsahi;35.0343\nPeligros;37.2333\nSim;54.9833\nKaeng Khoi;14.5864\nBig Bear City;34.2536\nHungen;50.4667\nMādugula;17.9167\nSan Mateo;9.7400\nBrzeziny;51.8000\nMagdalena Milpas Altas;14.5453\nFrutillar;-41.1258\nAvrig;45.7081\nPalacagüina;13.4550\nSaint-André-de-Cubzac;44.9947\nNiefern-Öschelbronn;48.9164\nUruoca;-3.3139\nAmbalarondra;-18.4667\nMilovice;50.2260\nKot Shamir;30.1191\nTrent Hills;44.3142\nTomar do Geru;-11.3728\nMalaryta;51.7833\nBeaufort;32.4597\nMöckern;52.1406\nTizgane;35.4136\nMesolóngi;38.3692\nPurén;-38.0319\nĀppukkudal;11.4684\nKilindoni;-7.9167\nEsmoriz;40.9550\nVyazemskiy;47.5250\nPilar;10.8070\nMarikal;16.6020\nKasba Tanora;32.4751\nWoodhaven;42.1320\nHoliday City-Berkeley;39.9639\nSainte-Marie;46.4500\nBarud;21.7497\nBelagal;15.8183\nSonāpur;26.3716\nValencia West;32.1355\nVilleneuve-lès-Avignon;43.9664\nKuala Kurun;-1.1016\nLe Chambon-Feugerolles;45.3961\nFlorange;49.3214\nMuthuswāmipuram;9.3900\nBrugg;47.4864\nGajhara;26.5237\nChodavaram;17.4380\nBassersdorf;47.4431\nĀlwārkurichchi;8.7838\nSiur;24.8166\nLaarne;51.0167\nVarzaneh;32.4197\nNew Hanover;40.3145\nKārvetnagar;13.4167\nStrombeek-Bever;50.9100\nHemsbach;49.5903\nSurkhakhi;43.1878\nGarkha;25.8293\nLynnfield;42.5356\nNovhorod-Siverskyi;51.9972\nSaint-Jean;43.6653\nArrigorriaga;43.2078\nPebberu;16.2167\nMānegaon;23.2062\nL’Isle-Adam;49.1111\nChoró;-4.8428\nDharhara;25.2543\nRaun;25.6462\nChurchdown;51.8800\nRichton Park;41.4816\nArhribs;36.8022\nLubaczów;50.1500\nBhandārso;26.1780\nGrumo Appula;41.0167\nBerja;36.8453\nChiatura;42.2903\nAlmirante;9.3000\nLimburgerhof;49.4222\nCornwall;41.4195\nOxapampa;-10.5740\nLauenburg;53.3833\nVoerendaal;50.8833\nPartiāla;16.4537\nMora;61.0167\nRasaunk;25.5537\nNew Kingman-Butler;35.2645\nEast Hampton;41.5696\nMagsaysay;10.8667\nUmri;26.5106\nCosta de Caparica;38.6446\nDorking;51.2325\nBohmte;52.3667\nNewcastle;47.5304\nEl Dorado;37.8210\nDorog;47.7194\nPittalavānipālem;15.9806\nBretzfeld;49.1833\nLevelland;33.5806\nChino Valley;34.7594\nGuelph/Eramosa;43.6300\nPuerto Jiménez;8.5338\nAndernos-les-Bains;44.7425\nBetma;22.6800\nZaragoza;28.4869\nWeddington;35.0228\nUmag;45.4333\nPastpār;25.8275\nAltenstadt;50.2856\nPola de Laviana;43.2358\nBloomsburg;41.0027\nCuisnahuat;13.6333\nNong Khae;14.3352\nDonwari;11.1197\nMalar;26.2237\nSala Consilina;40.4000\nLocri;38.2160\nSamashki;43.2906\nFlexeiras;-9.2728\nNaduhatti;11.4043\nSanta Rosa de Calamuchita;-32.0667\nFlorida City;25.4418\nWebb City;37.1412\nMéricourt;50.4022\nKulattūr;10.7052\nUrbana;39.3274\nBershad;48.3728\nSyasstroy;60.1500\nCheval;28.1459\nM’dhilla;34.2500\nSahasmal;26.2461\nRaismes;50.3892\nChettikulam;8.0943\nFuldatal;51.3484\nGohpur;26.8818\nIvaí;-25.0108\nNorthlake;41.9142\nJaroměř;50.3503\nRafína;38.0167\nSalobreña;36.7467\nBaghra;25.5597\nSebiston;38.2500\nBraselton;34.1087\nHolly Hill;29.2442\nChitauria;25.4869\nCanet-en-Roussillon;42.7056\nAttanūr;11.5006\nFrancofonte;37.2333\nManjanādi;12.8700\nẤp Phú Hải;11.1667\nCanillá;15.1671\nBamhnī;22.4822\nTruro;45.3647\nGyomaendrőd;46.9361\nBozkurt;37.8167\nSteinheim;51.8658\nAmos;48.5667\nKafr Rūmā;35.6342\nÚjfehértó;47.7989\nGeneral Las Heras;-34.9333\nPlaya Grande;15.9833\nBarahkurwa;26.1460\nKaredu;15.1833\nBānu Chhapra;26.8098\nWhite House;36.4648\nThikriwāla;30.4328\nSouakene;35.1167\nMiraíma;-3.5689\nKriftel;50.0828\nMamarappatti;11.4845\nAtri;42.5833\nDubak;18.1914\nPerehinske;48.8103\nNova Ponte;-19.1983\nAmha;26.0518\nWawarsing;41.7526\nGorokhovets;56.2000\nJilava;44.3328\nBamber Bridge;53.7281\nKortemark;51.0286\nBuharkent;37.9617\nBan Sop Tia;18.3895\nPecica;46.1700\nKrupka;50.6846\nSi Mustapha;36.7247\nRānti;26.3519\nRosario del Tala;-32.3000\nTeroual;34.6667\nFonsorbes;43.5361\nTaldom;56.7333\nThe Nation / La Nation;45.3500\nSonosari;-7.8014\nChandwā;23.6756\nRaia;15.4969\nHvardiiske;45.1142\nGuymon;36.6903\nCoringa;16.8000\nLandeh;30.9817\nPachchaimalaiyankottai;10.2736\nKaragwe;0.6769\nPichilemu;-34.3919\nHarrison;39.2584\nBan Muang Ngam;7.3536\nRompicherla;16.2098\nOulad Ouchchih;35.0939\nSan Vicente;14.1061\nSuzu;37.4363\nMedleri;14.6667\nMikashevichy;52.2203\nZuvvaladinne;14.8080\nVohimarina;-21.6400\nSan Anselmo;37.9821\nHedensted;55.7725\nSankt Veit an der Glan;46.7667\nVinings;33.8608\nOissel;49.3419\nPorecatu;-22.7558\nBurj al ‘Arab;30.8489\nTerrabona;12.7311\nFontanafredda;45.9667\nSławno;54.3583\nAshibetsu;43.5182\nSarahandrano;-14.7833\nNovi Pazar;43.3500\nUtehia;26.4800\nIkhlāspur;25.0589\nBad Urach;48.4931\nSan Miguel Panán;14.5333\nGaimersheim;48.8167\nVidauban;43.4272\nAntanandava;-19.0833\nKishunpur;25.3272\nPuliyampatti;11.6653\nLe Haillan;44.8717\nGreenville;40.1043\nFostoria;41.1600\nKalyazin;57.2333\nLaamarna;31.8944\nSanta Ana de Yacuma;-13.7444\nSangtŭda;38.0333\nSimeria;45.8500\nSão Sebastião do Uatumã;-2.5719\nNacajuca;18.1692\nSanta Fe;29.3889\nSan Francisco de Mostazal;-33.9799\nStupava;48.2747\nKanra;36.2430\nTacaimbó;-8.3158\nMalmédy;50.4167\nDiari;9.8452\nValverde del Camino;37.5667\nOrangeburg;33.4928\nRognac;43.4878\nWadersloh;51.7386\nNovo Lino;-8.9150\nKłobuck;50.9167\nPuduvayal;10.1034\nMedfield;42.1848\nEnamadala;16.2281\nSuamico;44.6354\nFort Lewis;47.0955\nWaconia;44.8422\nOakland;41.0313\nSantiago Amoltepec;16.6167\nSamahuta;25.8542\nMajanji;0.2408\nSt. Marys;41.4574\nIferhounene;36.5338\nLaukaria;26.7184\nLymm;53.3834\nKnowsley;53.4498\nSāvalgi;16.6710\nRantoul;40.3031\nLos Hidalgos;19.7300\nOneonta;42.4551\nBrock Hall;38.8604\nZag;28.0167\nTepetzintla;19.9667\nHirschaid;49.8167\nJoanópolis;-22.9303\nDalby;-27.1813\nSant’Agata di Militello;38.0680\nErumaippatti;11.1467\nIngersoll;43.0392\nKumari;25.6564\nKyōtamba;35.1699\nĀvadattūr;11.7014\nEufaula;31.9102\nParasurāmpūr;14.3200\nLumberton;39.9569\nRio Vermelho;-18.2939\nBarka Gaon;26.1440\nDināra;25.2500\nOlintla;20.1000\nMuswellbrook;-32.2654\nSenduriā;26.7469\nOrange City;28.9348\nSan Salvador;-31.6167\nSaint David’s;12.0444\nIsāpur;25.4122\nPont-du-Château;45.7983\nOxford;41.4313\nBrunsbüttel;53.8964\nLamballe;48.4686\nPīr Maker;25.9622\nWarwick;-28.2152\nShirataka;38.1831\nCheney;47.4901\nBad Abbach;48.9333\nSteinheim am der Murr;48.9667\nAlpen;51.5750\nYemva;62.6000\nPalos de la Frontera;37.2283\nBaker;30.5832\nD'Iberville;30.4709\nSnezhnogorsk;69.2000\nBeniel;38.0464\nVilla Aldama;19.6506\nQiaotouba;33.8116\nPort Royal;32.3557\nHattem;52.4667\nKuçovë;40.8039\nSinalunga;43.2167\nRío Segundo;10.0013\nBan Bang Non;9.9923\nChakai;26.0884\nAltavilla Vicentina;45.5167\nSason;38.3803\nPidigan;17.5703\nDabat;12.9842\nLibrazhd-Qendër;41.1969\nJefferson;34.1373\nPanzgām;34.4840\nPaullo;45.4167\nGundugolanu;16.7833\nBetton;48.1825\nSaint-Germain-lès-Arpajon;48.5953\nSaint-Estève;42.7133\nBrus Laguna;15.7500\nMountain Home;36.3351\nVrchlabí;50.6270\nDongyuancun;28.3190\nNemili;12.9783\nAnao;15.7304\nSagopshi;43.4847\nAthens;32.2041\nƏlət;39.9411\nBlaricum;52.2667\nItāmāti;20.1333\nMade;51.6764\nOunagha;31.5333\nSpondon;52.9200\nKāttukkottai;11.6026\nBasbiti;26.0939\nLadenburg;49.4667\nMorazán;14.9322\nVejer de la Frontera;36.2500\nAhermoumou;33.8184\nKallupatti;9.7167\nZofingen;47.2833\nChennampatti;11.7011\nPandalkudi;9.3947\nDerventa;44.9800\nGundelfingen;48.0425\nKhasanya;43.4333\nGrand Baie;-20.0184\nLalmatie;-20.0184\nSulz am Neckar;48.3628\nGraben-Neudorf;49.1592\nHobro;56.6333\nChok Chai;14.7333\nVardenis;40.1806\nBayona;42.1178\nGrünwald;48.0483\nKānkon;15.0109\nMakuyu;-0.9000\nChallapata;-18.9000\nFernandina Beach;30.6571\nLakeland South;47.2786\nBeaconsfield;51.6009\nWinterberg;51.2000\nOlgiate Comasco;45.7833\nSan Miguel de Salcedo;-1.0500\nLeibnitz;46.7831\nOlagadam;11.5656\nHorndean;50.9136\nRoding;49.2000\nFulton;38.8551\nPieve di Soligo;45.8833\nOzatlán;13.3833\nFeuchtwangen;49.1667\nAït Youssef Ou Ali;31.9833\nLakeside;37.6132\nLos Santos;6.9167\nDardenne Prairie;38.7565\nWickliffe;41.6072\nArroio do Tigre;-29.3328\nBan Tom Klang;19.1961\nMoncks Corner;33.1730\nAtaléia;-18.0439\nChettipulam;10.4743\nZawiat Moulay Brahim;31.2858\nFlorence;40.0977\nLienz;46.8297\nAlampur;26.0251\nChāmarru;16.6500\nLexington Park;38.2528\nMountain Park;33.8458\nBlaubeuren;48.4119\nOrzinuovi;45.4000\nKamianka-Dniprovska;47.4922\nDarfield;53.5380\nGrenada;33.7816\nPionerskiy;54.9517\nKasaishi;37.2528\nBni Drar;34.8578\nYenipazar;37.8269\nLakri;26.2323\nSarjāpur;12.8600\nConcepción Las Minas;14.5167\nRonchi dei Legionari;45.8333\nShilka;51.8500\nCapul;12.4230\nKantang;7.4067\nCidreira;-30.1608\nChaval;-3.0339\nGreetland;53.6869\nBuenos Aires;-7.7258\nParadise Valley;33.5434\nKarrāpur;23.9489\nSahsaul;25.7024\nHeddesheim;49.5053\nEski Arab;40.3686\nAmherst;41.4022\nTarwāra;26.2007\nDrongen;51.0500\nMèze;43.4267\nShirguppi;16.6187\nNāttarampalli;12.5920\nDevāpur;19.0443\nCapitán Bado;-23.2600\nPatarrá;9.8637\nPenal;10.1667\nWinkler;49.1817\nBalpyq Bī;44.8947\nLoiyo;23.7928\nTrophy Club;33.0040\nNew Germany;-29.8000\nVerde Village;34.7119\nWinnetka;42.1064\nAntilla;20.8411\nAvigliana;45.0779\nGurramkonda;13.7833\nFlorham Park;40.7773\nWetaskiwin;52.9694\nMende;44.5183\nShchastia;48.7381\nVillafranca de los Barros;38.5667\nCambuquira;-21.8583\nEl Adjiba;36.3333\nDunkirk;42.4801\nEmiliano Zapata;19.6500\nChauny;49.6156\nFatehpur Shāhbāz;25.5698\nGalaosiyo Shahri;39.8500\nNāysar;35.3267\nErkner;52.4167\nMāndu;23.7946\nViotá;4.4381\nAnzola dell’Emilia;44.5472\nBaykalsk;51.5167\nKoyulhisar;40.3053\nPennsville;39.6266\nChudamani;21.1379\nNewington Forest;38.7370\nRielasingen-Worblingen;47.7347\nSaltcoats;55.6352\nPanj;37.2353\nUbud;-8.5069\nBishunpur;26.1561\nArtesia;32.8497\nTagoloan;8.1092\nTwistringen;52.8000\nYenkuvārigūdem;16.9989\nZaladanki;14.8843\nSanta Bárbara de Pinto;9.4333\nKawamata;37.6650\nMiranorte;-9.5289\nKalajoki;64.2667\nXiaping;33.4047\nPannaikkādu;10.2761\nPajo;-8.5167\nVirālippatti;10.1081\nBeaumont;18.4833\nKaujalgi;16.1400\nRochefort;50.1667\nJunín de los Andes;-39.9167\nLe Pont-de-Claix;45.1231\nZonnebeke;50.8667\nGoldenrod;28.6114\nGodohou;7.0333\nUlster;41.9699\nMonte Compatri;41.8081\nJaciara;-15.9650\nAdré;13.4667\nLana;46.6160\nMahavanona;-12.4500\nHullatti;11.4771\nJustice;41.7495\nWadhraf;33.9833\nAdalaj;23.1700\nCardoso Moreira;-21.4878\nCunda diá Baze;-8.9167\nMartinho Campos;-19.3319\nSarıveliler;36.6964\nEdemissen;52.3667\nÇukurçayır;40.9667\nItiquira;-17.2089\nDurmersheim;48.9383\nManpaur;26.5081\nOshikango;-17.4000\nKākalūr;13.1394\nSan Marino;34.1224\nCinisi;38.1667\nSmyrna;39.2935\nMamakating;41.5860\nSan Mauro Pascoli;44.1000\nParamanandal;12.3585\nTuzdybastaū;43.3189\nParamankurichi;8.4785\nBaikunthpur;24.7277\nWieringerwerf;52.8506\nBrandfort;-28.7000\nKayattār;8.9469\nRong Kwang;18.3392\nDuartina;-22.4144\nTundhul;23.3247\nCananéia;-25.0150\nCamposampiero;45.5667\nYuzha;56.5833\nIsla Ratón;5.1311\nSan Rafael;6.2975\nBorger;35.6598\nWietmarschen;52.5331\nBrunswick;42.7558\nTaguaí;-23.4519\nFestus;38.2194\nPhulparās;26.3549\nSpresiano;45.7833\nCentral Elgin;42.7667\nSan Pietro in Casale;44.7000\nGavardo;45.5875\nMatsukawa;35.5972\nSteenokkerzeel;50.9189\nQuimperlé;47.8728\nHinundayan;10.3500\nTiszavasvári;47.9511\nProvadia;43.1833\nCevicos;19.0000\nVălenii de Munte;45.1856\nGoražde;43.6667\nBirni;9.9892\nAnklam;53.8500\nAmbātturai;10.2603\nShamsābād;23.8149\nChaukhata;25.0247\nElland;53.6830\nBryne;58.7354\nCasciana Terme;43.5281\nMehnatobod;40.2000\nIerápetra;35.0000\nEast Islip;40.7257\nPaal;51.0392\nBalneário do Rincão;-28.8344\nCumpăna;44.1128\nKhujner;23.7860\nNorth Valley;35.1736\nQārah;34.1542\nEral;8.6258\nNeuenburg am Rhein;47.8147\nLinkenheim-Hochstetten;49.1261\nMaba;0.7000\nOttawa;38.5996\nNorwalk;41.4895\nBānk;24.9539\nByram;32.1890\nBurām;25.9725\nOngwediva;-17.7833\nAnna Regina;7.2633\nBarra do Ribeiro;-30.2908\nSanta Ana Maya;20.0000\nBuchach;49.0647\nValu lui Traian;44.1650\nNanakuli;21.3892\nTiadiaye;14.4167\nMecatlán;20.2135\nSarare;9.7839\nPyrzyce;53.1333\nIconha;-20.7928\nMattenhof;47.4870\nGeneral Acha;-37.3833\nKhānda;28.9167\nBerwick-Upon-Tweed;55.7692\nMenfi;37.6078\nBeydağ;38.0833\nPayariq Shahri;39.9892\nBranson;36.6509\nBhaur;26.2751\nHarri;26.3238\nDrouin;-38.1333\nGeneva;42.8645\nSântana;46.3500\nSan Andrés de Llevaneras;41.5733\nRussi;44.3764\nPrairie Ridge;47.1438\nBishnāh;32.6106\nPonnai;13.1276\nCurrimao;18.0203\nKataysk;56.3000\nTezoatlán de Segura y Luna;17.6500\nBandipur;27.9381\nVohindava;-22.4167\nKongnolli;16.4200\nLake Tapps;47.2307\nElkhotovo;43.3458\nGethaura;25.6879\nSheerness;51.4410\nQuirihue;-36.2833\nNeerijnen;51.8333\nKelso;46.1236\nMira;40.4333\nKurhani;25.9803\nBorgo San Dalmazzo;44.3333\nBandalli;12.1640\nRevúca;48.6831\nLindenberg im Allgäu;47.6000\nCloquet;46.7221\nTilbury;51.4606\nBrown Deer;43.1743\nReshuijie;24.4580\nLeutenbach;48.8883\nVianópolis;-16.7419\nBan Krang;16.8775\nAywaille;50.4733\nGaffney;35.0743\nCalanasan;18.2550\nSabugal;40.3500\nWindsor Locks;41.9267\nAwānkh;32.1392\nBolbec;49.5722\nBenifayó;39.2847\nNamchi;27.1700\nArmadale;55.8978\nDiamou;14.0939\nPetrov Val;50.1500\nKoriukivka;51.7753\nCorreia Pinto;-27.5850\nBou Arkoub;36.5400\nHisarcık;39.2497\nKamin-Kashyrskyi;51.6242\nPreußisch Oldendorf;52.2833\nKishanganj;25.6844\nFrohburg;51.0561\nGandorhun;7.5564\nVysoké Mýto;49.9533\nUppukkottai;9.9587\nAlkhan-Kala;43.2586\nSimrāhi;26.3135\nChichli;22.8336\nLindsay;36.2082\nLachute;45.6500\nBiddupur;25.6464\nSrīpur;25.5861\nKoluszki;51.7500\nXavantes;-23.0389\nBhaisālotan;27.4500\nSangrām;26.3141\nMettuppālaiyam;11.4503\nHuodoushancun;40.7797\nOberwil;47.5135\nOuédo-Aguéko;6.4963\nPillānallūr;11.4322\nAmmāpettai;11.6197\nWoolwich;39.7400\nLa Carlota;-33.4333\nMonte Quemado;-25.8036\nMelavāyi;13.9397\nEnumclaw;47.2018\nNanzhai;26.6299\nLila;9.6000\nLaguna Paiva;-31.3039\nPfäffikon;47.3667\nBad Windsheim;49.5000\nNihāl Singhwāla;30.5919\nIchora;19.4333\nEbersberg;48.0833\nGulshan;37.5833\nUludere;37.4460\nBickenhill;52.4390\nNorth Smithfield;41.9727\nTendūkheda;23.1708\nGobardhanpur Kanāp;25.0682\nJaidte Lbatma;31.6806\nUgento;39.9333\nCharmahīn;32.3378\nHarrai;22.6143\nTamalpais-Homestead Valley;37.8793\nMendota;36.7555\nMelvindale;42.2802\nBéjar;40.3833\nOttappārai;11.1936\nMotta Sant’Anastasia;37.5000\nMinnāl;13.0744\nFort Atkinson;42.9253\nNiel;51.1167\nShoeburyness;51.5316\nLa Motte-Servolex;45.5967\nManne Ekeli;17.7200\nWilmington;39.4362\nKameshkovo;56.3500\nMerāl;24.1876\nSamādh Bhai;30.5985\nViswanāthaperi;9.3359\nValmadrera;45.8463\nNossa Senhora do Livramento;-15.7750\nSawādah;28.0775\nEstepa;37.2917\nSan Severino Marche;43.2289\nDayālpur;26.0511\nHarsinghpur;26.0504\nWest Grey;44.1833\nDom Basílio;-13.7600\nXinyingheyan;35.3369\nBoumalne;31.3738\nParksville;49.3150\nMurukondapādu;15.9174\nCodegua;-34.0347\nTaviano;39.9833\nArumanallūr;8.3167\nSylacauga;33.1780\nDorridge;52.3720\nÁlamos;27.0275\nBoone;42.0531\nCascades;39.0464\nKamalnagar;18.2310\nSátão;40.7333\nBaūyrzhan Momyshuly;42.6189\nNandipeta;18.9622\nLodhīkheda;21.5824\nViterbo;5.0667\nVilsbiburg;48.4500\nTīkar;24.4194\nDokkum;53.3269\nRainhill;53.4157\nKoilakh;26.3358\nNobeji;40.8644\nChachagüí;1.3605\nMunnūru;12.8283\nDatoda;22.5713\nDhaula;30.2856\nLake Norman of Catawba;35.5995\nValentim Gentil;-20.4219\nBajpe;12.9803\nMassena;44.9609\nKingri;25.6326\nBrzeszcze;50.0000\nDeerlijk;50.8533\nLake Los Angeles;34.6097\nMortugaba;-15.0228\nShichuanxiang;34.5866\nKuhsān;34.6500\nMatāla;17.8244\nLa Argentina;2.1961\nHasroûn;34.2419\nEl Tambo;1.4131\nJüterbog;51.9933\nButtāyagūdem;17.2089\nChambray-lès-Tours;47.3375\nCornedo Vicentino;45.6167\nLos Bellosos;19.8333\nOulad Aïssa;30.5580\nIarinarivo;-18.9167\nCowansville;45.2000\nFeliz;-29.4508\nAnjuna;15.5833\nMöglingen;48.8883\nBad Sassendorf;51.5831\nKīrippatti;11.5357\nFinspång;58.7000\nNina Rodrigues;-3.4658\nKewanee;41.2399\nPothia;25.5413\nGamarra;8.3333\nObernai;48.4622\nShuangxianxiang;35.3300\nXiushuicun;25.1728\nLulhaul;25.8787\nFortuna;40.5862\nDoddanahalli;12.3892\nXinchangcun;26.4249\nPlan-les-Ouates;46.1667\nHessisch Lichtenau;51.2000\nDuggirāla;16.3281\nEpping;51.7004\nAraçás;-12.2200\nTsuruta;40.7588\nGeorgetown;31.9849\nUlverston;54.1930\nEyvānekey;35.3433\nKesarimangalam;11.5423\nYangiariq;41.3628\nAn Phú;10.8500\nCortês;-8.4700\nMonóvar;38.4369\nPutussibau;0.8575\nDiamniadio;14.7219\nKolanpāk;17.6942\nPecos;31.3971\nSędziszów Małopolski;50.0667\nBan Bang Yai;13.8369\nNorīa;32.5210\nZłocieniec;53.5269\nEmstek;52.8167\nRiverview;42.1723\nGladenbach;50.7681\nAcalá del Río;37.5167\nTroy;38.9708\nTharīke;30.8669\nCandolim;15.5200\nBalchik;43.4269\nRefahiye;39.9011\nDatiāna;25.4834\nNovalukoml;54.6569\nCommerce;33.9963\nVallejuelo;18.6500\nSangān;34.3986\nVaddepalli;15.9363\nHuai Yot;7.7894\nKinrooi;51.1450\nSablé-sur-Sarthe;47.8400\nAngalakurichchi;10.5282\nLakeland Village;33.6480\nKhānjahānpur;25.6055\nAl Awjām;26.5583\nHizan;38.2256\nBernalda;40.4167\nLeominster;52.2282\nSiki;10.1833\nGuamaré;-5.0950\nGaildorf;49.0000\nSever do Vouga;40.7333\nMarysville;39.1518\nXinbocun;42.3037\nMugdampalli;17.6167\nReẕvānshahr;37.5511\nDehqonobod;37.6333\nMurnau am Staffelsee;47.6833\nKika;9.3000\nTeningen;48.1269\nProfondeville;50.3769\nRomanshorn;47.5635\nOulad Fares;35.5167\nBaraboo;43.4695\nKachnār;25.9699\nMesker-Yurt;43.2514\nSusa;5.4528\nKálymnos;36.9900\nCastelnaudary;43.3181\nSanta Mariana;-23.1500\nDharmastala;12.9479\nSantañy;39.3542\nEl Carmen;13.3500\nRazlog;41.8833\nTeano;41.2500\nCahokia;38.5650\nEscanaba;45.7477\nNeosho;36.8437\nSher Muhammadpuram;18.2997\nQuinta de Tilcoco;-34.3547\nMato Verde;-15.3969\nBécancour;46.3333\nNawalpur;26.9366\nAsfarvarīn;35.9333\nEnkesen;51.5006\nTerranuova Bracciolini;43.5531\nIaciara;-14.0958\nPalmer;42.1888\nRehoboth;41.8439\nSrīrāmpuram;10.4346\nSão Luís do Curu;-3.6700\nTring;51.7962\nTeotepeque;13.5853\nEl Ayote;12.4972\nPipariya;25.2593\nMeru;24.0097\nMaqu;35.9451\nAlwa Tirunagari;8.6100\nNagykáta;47.4120\nValentigney;47.4625\nObikiik;38.1586\nCacequi;-29.8839\nMays Chapel;39.4343\nDoi Lo;18.4667\nAmbatomainty;-20.9000\nGhambiraopet;18.3000\nShamshernagar;25.0862\nSolliès-Pont;43.1900\nVelair;18.0071\nPira;8.5000\nSagon;7.1500\nSarābleh;33.7667\nIssum;51.5389\nBankya;42.7000\nSaboyá;5.7000\nChã da Alegria;-8.0008\nJosefina;8.2144\nVeurne;51.0722\nTaiynsha;53.8478\nCaapiranga;-3.3167\nQuatipuru;-0.9008\nAnndevarapeta;17.0937\nSaint Ives;50.2110\nValencia;10.6500\nHarrison;44.1935\nDingman;41.3226\nLas Parejas;-32.6833\nMeerzorg;5.8072\nCookstown;54.6470\nMoldova Nouă;44.7178\nChāltābāria;21.9996\nNevele;51.0333\nCuichapa;18.7667\nKingsburg;36.5244\nBaozhong;23.6956\nKegeyli Shahar;42.7767\nMinooka;41.4507\nHengshan;24.7100\nTucson Estates;32.1792\nJuvignac;43.6131\nBudakalász;47.6215\nLālsaraia;26.7388\nPößneck;50.7000\nAmbinanynony;-18.6000\nKamlāpur;17.5786\nSūreshjān;32.3156\nBłonie;52.2000\nHarrislee;54.7972\nHigashiagatsuma;36.5714\nEraclea;45.5833\nDhakaich;25.5835\nSão Sebastião da Grama;-21.7108\nKhvalynsk;52.4833\nIlhota;-26.9000\nLizzanello;40.3051\nGlyká Nerá;37.9917\nItaguara;-20.3919\nPulakurti;15.7502\nLas Lomitas;-24.7072\nVedène;43.9775\nVobkent Shahri;40.0333\nBad Fallingbostel;52.8675\nJadayāmpālaiyam;11.2930\nMcComb;31.2442\nCruzeiro do Sul;-29.5128\nFojnica;43.9667\nHerrin;37.7983\nGisors;49.2806\nRankweil;47.2667\nCatarama;-1.5700\nYedtare;13.9246\nNorth St. Paul;45.0137\nMāhta;31.6647\nTabontabon;11.0333\nPrieska;-29.6683\nKhonobod;40.2000\nMonte Sant’Angelo;41.7000\nSão José do Campestre;-6.3158\nEast Renton Highlands;47.4718\nPartāp Tānr;25.8897\nHuntington;53.9926\nParbata;25.3195\nBishunpur Hakīmābād;25.8453\nSânnicolau Mare;46.0636\nChâteaubriant;47.7169\nGistel;51.1561\nJhāua;25.7487\nLudwigslust;53.3244\nDerby;41.3265\nTüp;42.7300\nPaxtaobod;40.3453\nGovernador Dix-Sept Rosado;-5.4589\nCesson;48.5658\nLeeds;33.5436\nOulad Amrane el Mekki;35.2167\nRinconada de Malloa;-34.4464\nBāgewādi;16.2900\nHaddonfield;39.8955\nUpper;39.2563\nSandy;45.3988\nGranarolo del l’Emilia;44.5500\nPantepec;17.1833\nPoquoson;37.1318\nSan Antonio;10.0000\nVilla Literno;41.0096\nMangalkot;23.5213\nGharbia;35.5153\nKlazienaveen;52.7333\nNkheila;32.9572\nJork;53.5344\nTyngsborough;42.6662\nSala;59.9167\nBan;-8.2333\nBueu;42.3167\nMonteforte Irpino;40.8928\nInverell;-29.7667\nBarharia;26.3191\nMaxhütte-Haidhof;49.2000\nArbeláez;4.2725\nSabaur;25.2428\nG’oliblar Qishlog’i;40.4953\nGainza;13.6167\nAlto do Rodrigues;-5.2878\nMixtla de Altamirano;18.6000\nCardoso;-20.0819\nDoctor Phillips;28.4474\nSiruvāchchūr;11.6380\nTissa;34.2833\nSarasota Springs;27.3087\nAurāhi;25.5709\nRobertsville;40.3395\nOcchiobello;44.9216\nShamaldy-Say;41.1972\n‘Anadān;36.2936\nBad Freienwalde;52.7856\nYakouren;36.7348\nParora;25.8022\nKladanj;44.2256\nLogan;40.5263\nBind;25.3035\nSremska Kamenica;45.2206\nKhem Karan;31.1600\nHnivan;49.0833\nShady Hills;28.4042\nMakhmālpur;25.2870\nTe Awamutu;-38.0167\nMorab;15.5833\nChikni;26.0075\nBayanaūyl;50.7889\nVijayāpati;8.1913\nTitisee-Neustadt;47.9122\nEgelsbach;49.9694\nGerman Flatts;42.9868\nSaint-Avé;47.6867\nMartuni;40.1400\nBan Tap Tao;19.7280\nSindalakkundu;10.3665\nAin Kansara;34.1500\nTalen;23.5695\nSoklogbo;7.6937\nFoča;43.5000\nThogapalle;17.2603\nSaādatpur Aguāni;25.2830\nCrestwood;38.5569\nHanūr;12.0874\nSīpālakottai;9.8493\nKaradge;16.4200\nKaurihār;26.9650\nBarhi;26.5714\nMalloussa;35.7333\nMallikkundam;11.8715\nSangalbahīta;25.3295\nWołów;51.3414\nRāsingapuram;9.9448\nPalmares Paulista;-21.0828\nSengurichchi;10.3756\nMutoko;-17.4000\nJequeri;-20.4558\nRobinson;31.4501\nTega Cay;35.0390\nMeitingen;48.5333\nMelle;51.0000\nCypress Lake;26.5392\nSonāda;27.0000\nTomball;30.0951\nBukkapatnam;14.1997\nSernovodsk;43.3117\nNurhak;37.9658\nWęgrów;52.4000\nGrantsville;40.6148\nHatillo de Loba;8.9586\nNorth Castle;41.1331\nMatina;-13.9089\nFarciennes;50.4313\nSedriano;45.4833\nHagenow;53.4167\nUdawantnagar;25.5054\nLa Palma;14.3167\nTittachcheri;10.8674\nAnamã;-3.5800\nLake City;30.1901\nNordstemmen;52.1605\nAubière;45.7508\nMulug;18.1910\nUren;57.4500\nBelūr;11.7075\nFairfax Station;38.7942\nBan Huai So Nuea;20.0536\nSant’Ambrogio di Valpolicella;45.5209\nSan Pedro La Laguna;14.6918\nLaren;52.2500\nSpilimbergo;46.1281\nMirante da Serra;-11.0297\nScotts Valley;37.0555\nBibbiena;43.7000\nBodaybo;57.8667\nFalmouth;43.7476\nBarberton;-25.7861\nVellār;11.8938\nTeulada;38.7292\nKhargrām;24.0232\nQorao‘zak;43.0275\nChainpur;25.0345\nGravenhurst;44.9167\nGatumba;-3.3333\nSākib;32.2854\nTorri di Quartesolo;45.5167\nSālamedu;11.9088\nBaños;-2.9000\nAj Jourf;31.4903\nTadapurambākkam;13.3205\nDalippur;25.4222\nStaryye Atagi;43.1126\nLehre;52.3167\nBudha Thēh;31.5177\nCapdepera;39.7000\nDarauli;26.0781\nConcepción Batres;13.3500\nLahra Muhabbat;30.2421\nMandasa;19.0600\nGandara West;5.9500\nNew Mills;53.3670\nEnns;48.2167\nMarumori;37.9114\nOpmeer;52.7000\nFakirtaki;22.3815\nAgcogon;12.0667\nCórdoba;9.5867\nŽupanja;45.0700\nPargas;60.3000\nBucheya;26.3421\nTibbar;31.9697\nLaichingen;48.4897\nWeiz;47.2189\nSakawa;33.5008\nGulbahor;41.0747\nWells;51.2094\nKibungo;-2.1608\nTamarana;-23.7228\nSaint-Saulve;50.3697\nNīdāmangalam;10.7720\nEklahra;22.2036\nOuénou;9.7870\nLissegazoun;6.6167\nStradella;45.0833\nPāta Putrela;17.0173\nRānko;25.5181\nRamabitsa;-29.7625\nMoss Point;30.4241\nLagoa Dourada;-20.9139\nGrootegast;53.2167\nWasilków;53.2050\nMarquetalia;5.3333\nWebster;29.5317\nEl Campo;29.2000\nWeinfelden;47.5698\nTzintzuntzán;19.6283\nGuntupalle;16.5681\nRazua;22.0529\nZeuthen;52.3667\nTeus;25.2493\nConneaut;41.9275\nBeatrice;40.2736\nRottofreno;45.0579\nLauffen am Neckar;49.0833\nKenduadīh;23.7757\nPrattipādu;17.2333\nLeingarten;49.1500\nPort Washington;43.3846\nPinneli;16.5689\nEmboscada;-25.1233\nUpper Uwchlan;40.0817\nAmbatomasina;-18.7333\nChennūr;14.1554\nTortoreto;42.8000\nArth;47.0644\nAntardipa;24.6442\nVegarai;11.0903\nBurladingen;48.2903\nTaurisano;39.9500\nAntônio Cardoso;-12.4350\nTholey;49.4833\nOcean Pines;38.3851\nSedro-Woolley;48.5112\nEssenbach;48.6167\nVilla Unión;-29.3000\nMaida Babhangāwān;25.4793\nSathiāla;31.5833\nTetagunta;17.3140\nAmarāpuuram;14.1333\nPiripá;-14.9400\nCasièr;45.6500\nDharmasāgaram;17.9933\nPerth East;43.4700\nStrzelin;50.7833\nVecchiano;43.7833\nVelddrif;-32.7833\nCitlaltépec;21.3366\nGötzis;47.3342\nBharwelī;21.8373\nBelén;-27.6500\nKampenhout;50.9413\nAlucra;40.3167\nOberschleißheim;48.2500\nMorūr;11.4221\nBotlikh;42.6650\nJaguapitã;-23.1128\nKathu;-27.7000\nBībīpet;18.2101\nPalestina;-20.3900\nNa Wa;17.4692\nMarket Drayton;52.9044\nDarmahā;26.3663\nSonbarsa;26.8474\nKhānsāhibpuram;9.6304\nPhulgāchhi;26.3273\nWoodward;36.4247\nBoloso;2.0333\nPenne;42.4500\nMirik;26.8870\nVulcăneşti;45.6833\nAtripalda;40.9167\nSaubara;-12.7378\nTorroella de Montgrí;42.0439\nHamilton Square;40.2248\nPorto Valter;-8.2689\nMiller Place;40.9374\nAccokeek;38.6745\nLower Pottsgrove;40.2537\nSapna;44.4917\nDumri;25.6243\nNgou;5.2000\nPaulista;-6.5939\nPresidencia de la Plaza;-26.9833\nFómeque;4.4847\nSokouhoué;6.9000\nDăbuleni;43.8011\nYakoma;4.0982\nLaukāha;26.0336\nSanta Elena;14.0833\nAleksandrovsk;59.1667\nGuaraniaçu;-25.1008\nMadison;38.7581\nChâteau-Gontier;47.8286\nGopālapuram;17.1007\nDiré;16.2667\nKālipatnam;16.3904\nBampūr;27.1944\nAntônio Gonçalves;-10.5728\nPūvalūr;10.9003\nBenoy;8.9908\nKorb;48.8417\nWest Deer;40.6351\nParkes;-33.1330\nBiknūr;18.2150\nNew Kensington;40.5712\nWolgast;54.0500\nPasca;4.3075\nLewisboro;41.2697\nKrasnyy Yar;46.5331\nMulungu do Morro;-11.9658\nNova Trento;-27.2867\nPettaivāyttalai;10.9014\nAbertillery;51.7300\nPrince Rupert;54.3122\nAndrelândia;-21.7400\nEffingham;39.1205\nFourmies;50.0172\nĀrutla;17.1346\nGundrājukuppam;13.3406\nBurnham;51.5400\nJefferson Hills;40.2926\nSanta Leopoldina;-20.1006\nDinkelsbühl;49.0708\nŌsako;31.4292\nIvoamba;-21.4000\nCanóvanas;18.3693\nIelmo Marinho;-5.8239\nDendulūru;16.7606\nChinnatadāgam;11.0816\nRovinari;44.9125\nSalgado de São Félix;-7.3569\nSaint-Gaudens;43.1081\nMettlach;49.4917\nHārohalli;12.3204\nLobería;-38.1333\nPiprāhi;26.5871\nPuerto Nare;6.1917\nEbéjico;6.3333\nSanta Cruz Michapa;13.7333\nPortoferraio;42.8167\nUnguía;8.0500\nSaclepea;7.1167\nBellegarde-sur-Valserine;46.1075\nAnjanazana;-15.3833\nPinheiro Machado;-31.5778\nJitwārpur Chauth;25.8499\nSanto Domingo;12.2631\nKalaidasht;38.6333\nPacé;48.1478\nIsola del Liri;41.6794\nSuchanino;54.3566\nCuers;43.2375\nZhengdong;22.4871\nMaromiandra;-21.6833\nNeuenrade;51.2839\nAppingedam;53.3167\nNew Britain;40.3084\nIbiraci;-20.4619\nRocca Priora;41.7833\nRichland;40.2842\nLagoa do Ouro;-9.1269\nZlatograd;41.3833\nManchester;37.4902\nPedda Adsarlapalli;16.7086\nLonate Pozzolo;45.6000\nKornepādu;16.2444\nSaint-Pierre-du-Perray;48.6131\nAs Sars;36.0833\nRijkevorsel;51.3500\nHighlands;41.3601\nBrattleboro;42.8619\nTiszakécske;46.9312\nCoventry;41.7828\nTanakallu;13.9198\nHātod;22.7938\nVillamartín;36.8667\nJerome;42.7179\nArganil;40.2180\nFuensalida;40.0500\nKozloduy;43.7833\nBan Bo Luang;18.1476\nBan Noen Phoem;17.1167\nMettingen;52.3167\nIlmajoki;62.7333\nEldorado;-23.7869\nMālthone;24.3055\nZwönitz;50.6167\nBetmangala;13.0085\nAlken;50.8761\nBishunpur;24.7631\nBayyanagūdem;17.1250\nUnterföhring;48.1917\nVylgort;61.6275\nHirao;33.9379\nPilis;47.2844\nChebrolu;16.1967\nPanhar;25.0936\nChorleywood;51.6500\nNový Bor;50.7577\nQoubaiyat;34.5683\nPrévost;45.8700\nTheux;50.5349\nHōdatsushimizu;36.8627\nHoneygo;39.4055\nOyón;-10.6692\nLittle Bookham;51.2804\nWaikanae;-40.8750\nLiperi;62.5333\nSteha;35.3460\nAntanamalaza;-19.4000\nVengikkal;12.2642\nHavixbeck;51.9778\nMoparipālaiyam;11.1332\nEl Sobrante;33.8724\nSahoria Subhai;25.9028\nMalhador;-10.6578\nDora;22.1221\nGuebwiller;47.9075\nTranent;55.9450\nMitchellville;38.9358\nAlbox;37.3833\nRoda;30.6820\nAllūr;14.6800\nSisia;25.4539\nFaradābād;23.7445\nGanapavaram;16.7000\nNußloch;49.3236\nSan José El Ídolo;14.4500\nBeryslav;46.8333\nNova Gradiška;45.2500\nIwanai;42.9798\nPlanegg;48.1047\nPortales;34.1754\nPasłęk;54.0500\nSão Francisco do Maranhão;-6.2508\nNariman;40.5972\nBad Vöslau;47.9669\nEura;61.1333\nSchwieberdingen;48.8778\nNew Baltimore;42.6904\nJītpur;26.8149\nJericó;5.7833\nJardim do Seridó;-6.5839\nJusto Daract;-33.8667\nBoskovice;49.4875\nKőszeg;47.3819\nMinden;32.6187\nAjjanahalli;12.0376\nKotha Gurū;30.4419\nWyndham;37.6924\nJacinto;-16.1439\nKanhāipur;25.4542\nSontha;26.1861\nBernissart;50.4833\nMayate;32.2667\nDenkendorf;48.6958\nGulgam;34.5500\nBasaithi;26.0284\nKhamānon Kalān;30.8200\nCorbas;45.6681\nTabapuã;-20.9639\nSainte-Adèle;45.9500\nAmpasimbe;-16.8167\nCapela do Alto Alegre;-11.6678\nHalstead;51.9451\nStreator;41.1245\nNosiarina;-14.2167\nMalkā;32.6653\nPulsano;40.3833\nSorombo;-22.1000\nEdgewood;47.2309\nBabhnoul;25.3202\nBerlaar;51.1167\nTábua;40.3603\nIslamey;43.6756\nLewisburg;35.4510\nAnnappes;50.6269\nHagfors;60.0333\nBelampona;-14.6833\nSocuéllamos;39.2933\nMostardas;-31.1069\nChoctaw;35.4802\nBajiao;27.6573\nCherlak;54.1605\nRosdorf;51.5000\nAntaritarika;-25.4000\nZetel;53.4197\nLakhipur;26.3281\nBolaños de Calatrava;38.8831\nIchinomiya;35.3667\nPonte da Barca;41.8000\nMiddleburg;30.0502\nAmbohimandroso;-21.8833\nAmbalavero;-21.8000\nMontrose;56.7080\nBan Pae;18.2108\nSaint-Cyr-sur-Mer;43.1836\nPerleberg;53.0667\nPedda Vegi;16.8095\nBramhabarada;20.6683\nStamboliyski;42.1333\nSunkarevu;16.3904\nBefody;-20.7667\nKōteshwar;13.6070\nArchdale;35.9032\nPalos Heights;41.6637\nJhakhra;25.7528\nSogndal;61.2297\nCiudad-Rodrigo;40.5969\nCurití;6.6667\nBicske;47.4907\nUzyn;49.8242\nCernay;47.8067\nRudrāngi;18.6262\nIwate;39.9728\nLauria Inferiore;40.0500\nSon Servera;39.6208\nAuchel;50.5083\nBømlo;59.7794\nCedarburg;43.2990\nAcandí;8.5333\nFreeport;10.4500\nAgadi;14.8190\nSassenage;45.2050\nPhước Long;9.4194\nUnion;38.4399\nFalimāri;26.3856\nUmm ar Rizam;32.5325\nPalmácia;-4.1500\nCaimito;8.8333\nWargal;17.7751\nManorville;40.8574\nBlackfoot;43.1940\nSan Carlos Yautepec;16.5000\nArasūr;11.0866\nOiba;6.2667\nCarmiano;40.3458\nLiuba;38.1634\nGbanhi;8.4497\nUbaporanga;-19.6350\nKévé;6.4278\nOmatjete;-21.0500\nNová Dubnica;48.9331\nMargherita di Savoia;41.3667\nVosselaar;51.3167\nNonoai;-27.3619\nAnkafina Tsarafidy;-21.2000\nWarka;51.7833\nKerāi;25.7510\nSusegana;45.8500\nMadna;26.3963\nGlen Rock;40.9601\nRio do Pires;-13.1278\nOulad Daoud;34.4058\nMādhopur Hazāri;26.2623\nAbhia;25.3499\nComarnic;45.2511\nTori-Cada;6.5833\nJacala;21.0053\nPriolo Gargallo;37.1667\nMmadinare;-21.8746\nOqqo‘rg‘on;40.8764\nSeyyedān;30.0042\nMataili Khemchand;25.5612\nKentville;45.0775\nRyūō;35.0608\nSimplício Mendes;-7.8539\nBaohe;33.2033\nSöderhamn;61.3000\nBaxiangshan;23.7630\nWichelen;51.0000\nAnorombato;-22.0167\nAmpondra;-13.4167\nMacedonia;41.3147\nGóra Kalwaria;51.9733\nRied im Innkreis;48.2100\nÇüngüş;38.2128\nGambettola;44.1167\nEdlapādu;16.1686\nSam;11.0333\nGrafton;43.3204\nSendrisoa;-22.0000\nPanpuli;9.0214\nGonzales;30.2132\nAtça;37.8833\nChevigny-Saint-Sauveur;47.3017\nXincheng;36.0311\nWelver;51.6167\nWrentham;42.0513\nAnjahambe;-17.3833\nErfelek;41.8833\nTummalacheruvu;16.5246\nWang Saphung;17.2995\nPedappai;12.8854\nBitetto;41.0333\nBahādarpur;21.2922\nCottonwood;34.7195\nSaint-Martin-Boulogne;50.7258\nAl Majma‘ah;25.9039\nSnihurivka;47.0708\nTefam;5.2667\nBüdelsdorf;54.3167\nDang‘ara;40.5831\nFlores de Goiás;-14.4489\nNeustadt;51.0239\nJādopur Shukul;26.5250\nNovoīshīmskīy;53.1981\nBhānuvalli;14.4333\nOdatturai;11.4577\nRonneby;56.2000\nOestrich-Winkel;50.0000\nGoiatins;-7.7100\nAlfonsine;44.5000\nValley Falls;41.9233\nFanambana;-13.5500\nAmbohinamboarina;-21.0333\nSouq Jamaa Fdalate;33.5911\nVillepreux;48.8300\nCentralia;38.5224\nSão Miguel das Matas;-13.0478\nMainvilliers;48.4531\nDon Sak;9.3169\nTiruvādānai;9.7841\nMahazoarivo;-21.3667\nAlavus;62.5917\nFiume Veneto;45.9333\nLoano;44.1167\nGarden City;43.6526\nKissing;48.3000\nVaux-le-Pénil;48.5264\nLajia;34.6818\nToropets;56.5000\nIpaumirim;-6.7900\nBaitoa;19.3200\nDário Meira;-14.4358\nKuangfu;23.6351\nTlacolulan;19.6667\nCastelginest;43.6936\nSewāi;23.6175\nLapinig;12.3150\nKabira;25.6897\nSaharefo;-21.6667\nMoreira Sales;-24.0619\nWeeze;51.6267\nDąbrowa Tarnowska;50.1667\nBéna;12.0804\nNedelišće;46.3833\nKountouri;10.4050\nThiers;45.8564\nGhal Kalān;30.8189\nDoranāla;15.9076\nStony Brook;40.9061\nWest Plains;36.7377\nBarai;26.3717\nIalysós;36.4167\nSão Pedro da Água Branca;-5.0850\nKājhi Hridenagar;25.9320\nHuité;14.9175\nWildau;52.3167\nBenisa;38.7145\nHardia;26.6184\nBeandrarezona;-14.4833\nWhitburn;55.8621\nBeniaján;37.9833\nDarabani;48.1864\nBhangha;25.5780\nJaitwār;24.7320\nBalua Rāmpur;26.7777\nApen;53.2214\nAl Fayd;30.6167\nKinattukkadavu;10.8225\nEnniscorthy;52.5021\nAranda;26.0850\nBālupur;25.2611\nAmbaliha;-14.4667\nVilla Berthet;-27.2667\nVillefranche-de-Rouergue;44.3525\nWeatherford;35.5380\nAnjiamangirana I;-15.1667\nUpper Montclair;40.8433\nHolalu;15.0200\nSpearfish;44.4909\nAltstätten;47.3833\nBoldājī;31.9383\nFarkhâna;35.2833\nVilleneuve-Tolosane;43.5236\nComasagua;13.6333\nAndonabe;-21.4667\nArkansas City;37.0726\nMaliāl;18.7000\nOsterhofen;48.7019\nJīdigunta;16.9098\nAmbolomoty;-16.1667\nKrosūru;16.5500\nBenaguacil;39.5933\nAbergele;53.2800\nSouthwick;54.9193\nNong Bua;15.8647\nḨukūmatī Gīzāb;33.3813\nPornichet;47.2658\nViera East;28.2613\nChinna Orampādu;14.0613\nCave;41.8167\nGalvarino;-38.4000\nGuimarães;-2.1328\nGladstone;45.3864\nBuqkoosaar;4.5108\nTryavna;42.8669\nTotogalpa;13.5631\nBara Belun;23.4007\nUrakawa;42.1684\nWashington;38.6586\nMaromby;-24.3500\nRājāram;18.9870\nBilovodsk;49.2076\nQorashina;38.3394\nBissorã;12.0400\nAin Beida;31.5850\nBorgaro Torinese;45.1500\nBou Merdès;35.4500\nBekapaika;-16.7500\nAndrembesoa;-20.1500\nBetânia;-8.2767\nDakhrām;26.0542\nRiviera Beach;39.1623\nGhabāghib;33.1839\nAndranovao;-17.6167\nBasibasy;-22.1667\nLouvres;49.0439\nBeauharnois;45.3200\nLes Îles-de-la-Madeleine;47.3833\nCoussé;6.8500\nKasaji;-10.3662\nZlaté Moravce;48.3783\nKibi;6.1667\nEl Carmen;8.5128\nPrincetown;5.9049\nItondy;-19.0500\nSassenburg;52.5167\nVolosovo;59.4333\nWaltikon;47.3667\nMadina do Boé;11.7500\nUmm Badr;14.2167\nBelp;46.8914\nIssoudun;46.9481\nPoranga;-4.7450\nLargo;38.8800\nAndramy;-17.9635\nLandsmeer;52.4333\nAvesta;60.1456\nKrasnousol’skiy;53.8947\nNorth Middleton;40.2462\nNyírbátor;47.8333\nAlegría;13.5000\nDoesburg;52.0167\nPatu;-6.1100\nMikkelin Maalaiskunta;61.6776\nSabnima;25.4583\nNaini;25.8320\nCasteldaccia;38.0500\nSárbogárd;46.8878\nEl Arba Des Bir Lenni;34.3272\nHildburghausen;50.4167\nMatmata;34.1000\nLichtenstein;50.7564\nSajószentpéter;48.2169\nLonguenesse;50.7356\nAmbhua;24.5568\nRudra Nagar;24.3841\nUllūr;10.9706\nMahmūda;25.0531\nGuidel;47.7906\nAttippattu;13.2633\nArakvāz-e Malekshāhī;33.3828\nNueva Era;17.9167\nIchhāpur;21.1551\nErbaocun;42.9633\nGeisenheim;49.9844\nWallan;-37.4167\nDistracción;10.9000\nJamhor;24.8486\nGreat Wyrley;52.6593\nDiez;50.3708\nKautālam;15.7710\nAlijó;41.2761\nLower Gwynedd;40.1880\nCaldogno;45.6000\nÇamaş;40.9131\nCangas de Narcea;43.1714\nMartinsville;40.6030\nSapahi;26.6517\nSanta Flavia;38.0833\nPaispamba;2.2500\nNaīgarhi;24.7869\nHadim;36.9883\nBeladi;13.1464\nKargıpınar;36.6667\nChaumont-Gistoux;50.6839\nMykhailivka;47.2717\nNorth Lebanon;40.3668\nJanów Lubelski;50.7167\nJiajin;25.6743\nGardone Val Trompia;45.6833\nKadalādi;12.4040\nŞalpazarı;40.9422\nZārach;31.9911\nAït I’yach;32.6908\nTosashimizu;32.7833\nKāranchedu;15.8823\nRaghunāthpur;26.6418\nOswaldtwistle;53.7430\nTectitán;15.3073\nSerravalle Pistoiese;43.9000\nZumbagua;-0.9558\nTigzirt;36.8931\nSantana do Matos;-5.9578\nLevashi;42.4333\nSomersworth;43.2534\nSão Sebastião de Lagoa de Roça;-7.0828\nSpencer;42.2471\nSandy;52.1310\nSultanhanı;38.2481\nCogolin;43.2525\nPeriya Soragai;11.7394\nVillebon-sur-Yvette;48.7000\nBad Dürrenberg;51.2833\nMeghraj;23.5000\nGroß-Enzersdorf;48.2000\nPopovača;45.5697\nManchester;35.4630\nOnet Village;44.3656\nVehkalahti;60.5756\nPratāparāmpuram;10.6741\nStuarts Draft;38.0188\nSantoña;43.4414\nDrolshagen;51.0333\nTizi Nisly;32.4667\nDranesville;38.9955\nZaoqiao;24.6500\nArenzano;44.4042\nBrejetuba;-20.1458\nFenton;42.7994\nMöhnesee;51.4958\nCampobello di Mazara;37.6333\nSidi Amer El Hadi;34.7992\nSaint-Jean-de-Védas;43.5764\nNāgalāpuram;13.3889\nDalmatovo;56.2667\nPorto;-3.8928\nKunkalagunta;16.2969\nGamharia;25.8973\nHawaiian Paradise Park;19.5828\nCamp Verde;34.5690\nDaroji;15.0700\nTirupporūr;12.7259\nMudgere;13.1300\nDoddappanāyakkanūr;9.9810\nGuraahai;33.6449\nFinale Ligure;44.1714\nMayūreswar;23.9851\nNambour;-26.6269\nWootton;52.2007\nMülheim-Kärlich;50.3869\nYangiqo‘rg‘on;41.1872\nPatori;25.9665\nNārāyanavanam;13.4200\nPongode;16.9246\nMyjava;48.7492\nBhado Khara;24.9567\nMamqān;37.8431\nClermont;49.3789\nZriba-Village;36.3333\nNiles;41.8346\nNova Crixás;-14.0989\nBechloul;36.3167\nBhaurādah;26.2520\nHalsūr;17.8600\nIkkādu;13.1724\nPozharan;42.3648\nGudibanda;13.6711\nSan Michele al Tagliamento;45.7636\nNeuville-en-Ferrain;50.7467\nPoselikha;51.9833\nLa Homa;26.2796\nAndhana;25.2574\nAheqi;40.9372\nBom Princípio;-29.4889\nAthol;42.5841\nCastenedolo;45.4704\nSalem;40.9049\nLachhmīpur;25.5248\nYamamoto;37.9627\nAmelia;42.5500\nSixaola;9.5579\nBokākhāt;26.6402\nCrowley;30.2175\nDownham Market;52.6000\nMahazoarivo;-20.3833\nMiesbach;47.7833\nManiago;46.1667\nTorton;52.4522\nWellington North;43.9000\nNuvem;15.3174\nSt. Andrews;50.2700\nBakwa;26.0601\nTālsur;25.3667\nSomerville;-38.2260\nBurgthann;49.3563\nKagamino;35.0918\nNieuwpoort;51.1167\nPloufragan;48.4894\nPéonga;10.3333\nTalakād;12.1887\nLendinara;45.0850\nArkadak;51.9333\nLanggöns;50.5000\nLoran;33.8346\nTurvo;-28.9258\nIbirá;-21.0800\nLa Puebla del Río;37.2667\nEkerö;59.2833\nPunjai Kālāmangalam;11.2322\nJamsher;31.2700\nNewport East;41.5159\nRapho;40.1576\nNorth Union;39.9101\nNowe Miasto Lubawskie;53.4256\nEranāpuram;11.5581\nHöhenkirchen-Siegertsbrunn;48.0167\nCarleton Place;45.1333\nPodor;16.6167\nNellipāka;17.7679\nEijsden;50.7778\nMādhopur;25.3453\nSainte-Savine;48.2947\nVendas Novas;38.6833\nGiffoni Valle Piana;40.7167\nOlivenza;38.6858\nRandaberg;59.0017\nKać;45.3000\nKete Krachi;7.8000\nIvybridge;50.3890\nRāibāri Mahuawa;27.0980\nGbéroubouè;10.5333\nPalmilla;-34.6042\nRio Paranaíba;-19.1939\nBerilo;-16.9519\nCrossville;35.9526\nPellezzano;40.7333\nLopon;30.6715\nOjuelos de Jalisco;21.8642\nJataìzinho;-23.2539\nDammapeta;17.2667\nDudley;42.0550\nFateha;25.6073\nTiruvennanallūr;11.8589\nKongupatti;11.8593\nGreen River;41.5127\nGuatajiagua;13.6667\nCastelló de Ampurias;42.2582\nMutia;8.4176\nNallūr;14.0871\nMacerata Campania;41.0667\nBan Phan Don;17.1290\nSartana;47.1708\nNovaya Lyalya;59.0667\nRangsdorf;52.2831\nUkrainsk;48.1000\nScottburgh;-30.2833\nKabīrpur;26.2661\nMazzarino;37.3000\nKeolāri;22.3697\nRosaryville;38.7672\nToualet;32.7333\nItanhomi;-19.1719\nIacanga;-21.8900\nAndraitx;39.5746\nAgamé;6.7333\nBopfingen;48.8569\nAtmākūr;18.0712\nKushmanchi;17.2263\nZaragoza;17.9487\nOwk;15.2167\nĀzamnagar;25.5456\nRodenbach;50.1500\nMatino;40.0333\nRupenaguntla;16.3043\nSanta Cruz da Baixa Verde;-7.8208\nChintalavādi;10.9511\nHorodnia;51.8924\nAbasolo;24.0559\nOvidiopol;46.2667\nChauki Hasan Chauki Makhdum;26.2333\nDevikāpuram;12.4744\nVellavādanparappu;11.1854\nKingston;-42.9769\nAzcoitia;43.1792\nAlamedin;42.8900\nBroome;-17.9619\nSatoshō;34.5138\nBugongi;-0.6356\nIngurti;17.6695\nKurabalakota;13.6500\nGerstetten;48.6225\nCoswig;51.8833\nHàng Trạm;20.3944\nOberderdingen;49.0625\nLābhgaon;25.5062\nBaroni Khurd;25.6852\nKuruman;-27.4597\nAguasay;9.3203\nCarmo da Cachoeira;-21.4608\nNandavaram;16.0170\nShāhpur;24.0312\nRājānagaram;17.0833\nKuchinarai;16.5318\nRed Bank;35.1117\nBrookhaven;31.5803\nChikni;26.0664\nSeringueiras;-11.7981\nWhistler;50.1208\nMacajuba;-12.1358\nMương Theng;21.3869\nChilonga;-12.0244\nNarasāpuram;17.1016\nLabbaikkudikkādu;11.3922\nYakushima;30.3903\nLebon Régis;-26.9289\nRecreo;-29.2667\nMonschau;50.5600\nMartinsville;39.4149\nWorb;46.9306\nPerches;19.5167\nWolnzach;48.6000\nSantuario;5.0725\nHolešov;49.3333\nPipra Naurangiā;26.8591\nCricova;47.1333\nHauzenberg;48.6500\nZiyodin Shaharchasi;40.0342\nBrighton;44.1222\nTolcayuca;19.9500\nBan Wiang Phan;20.4128\nBocaina;-22.1361\nQâna;33.2092\nKhimlāsa;24.2058\nCasino;-28.8667\nChhātāpur;26.2197\nBhanghi;26.3612\nOlivença;-9.5186\nMonción;19.4167\nMedina Sidonia;36.4667\nIskapālem;14.5416\nRoessleville;42.6969\nScorniceşti;44.5700\nPuliyara;9.0041\nKīlkottai;10.2861\nSanta Ana;14.0667\nOpatija;45.3333\nNāranāpuram;11.0254\nGulfport;27.7463\nParaíso do Norte;-23.2808\nDolo Bay;4.1833\nKadrābād;25.5793\nKhandpara;20.2644\nTirodi;21.6852\nMömbris;50.0667\nDestrehan;29.9626\nKummarapurugupālem;16.3653\nOn Top of the World Designated Place;29.1058\nKāla Diāra;25.5092\nMoulay Driss Zerhoun;34.0542\nAl Hāmah;33.5581\nHardās Bigha;25.4994\nSenirkent;38.1081\nNeuhausen am Rheinfall;47.6833\nSeptèmes-les-Vallons;43.3983\nLommedalen;59.9500\nChaplygin;53.2333\nItaipé;-17.4019\nXuân Trùng;21.0500\nJalalaqsi;3.4000\nBefandefa;-22.1333\nHaradok;55.4667\nNandimandalam;14.4052\nSant’Ilario d’Enza;44.7667\nÜberherrn;49.2500\nRichland;40.6440\nEast Bethel;45.3557\nRaghunāthpur;26.3448\nKaniyambādi;12.8118\nVilpatti;10.2672\nWinfield;37.2740\nUmurlu;37.8500\nSanta Lucía;10.3167\nBīrpur;26.5767\nSaverne;48.7414\nRewtith;26.2853\nPorto-Vecchio;41.5908\nShāhpur Undi;25.6370\nCastano Primo;45.5500\nCodigoro;44.8333\nTifni;31.6281\nMareeba;-16.9833\nAmarchinta;16.3740\nTarrytown;41.0647\nTādepalle;16.8454\nCampagnano di Roma;42.1333\nCisneros;6.5383\nWeston;42.3589\nSarauni Kalān;25.7579\nKadwa;25.0316\nOkhargara;24.2141\nComalapa;12.2842\nOignies;50.4692\nOak Grove;33.9780\nBaranivka;50.3000\nEvanston;41.2602\nLabin;45.0833\nVenosa;40.9618\nScharbeutz;54.0214\nOlaippatti;11.7676\nKantilo;20.3615\nCafayate;-26.0833\nZayukovo;43.6119\nRostam Kolā;36.6778\nCollege;64.8694\nSan Pedro;17.9214\nLa Roche-sur-Foron;46.0669\nJagannāthpur;25.6573\nPhon;15.8084\nAmelia;39.0269\nEndwell;42.1184\nNgerengere;-6.7500\nCarnaubeira da Penha;-8.3219\nCarmen;9.2289\nIguaraci;-7.8350\nOxelösund;58.6667\nKāri;24.8368\nGuspini;39.5333\nHalf Moon Bay;37.4685\nPallipattu;13.3361\nTegueste;28.5233\nTârgu Lăpuş;47.4525\nPasadena Hills;28.2881\nPampas;-12.3989\nTiny;44.6833\nLohiān;31.3156\nIrupi;-20.3450\nPūngulam;12.5727\nAllonnes;47.9686\nKankaanpää;61.8000\nRiolândia;-19.9900\nTrofarello;44.9833\nCologno al Serio;45.5833\nLiman;38.8733\nJarābulus;36.8175\nLom Sak;16.7775\nFairview Shores;28.6021\nNirpur;25.7192\nSítio do Quinto;-10.3500\nMoldava nad Bodvou;48.6064\nVentersburg;-28.0833\nLos Alamitos;33.7971\nDarwa;25.6690\nImaculada;-7.3900\nRingwood;41.1065\nPutnam Valley;41.3980\nGänserndorf;48.3406\nPicayune;30.5322\nCourrières;50.4581\nJangy-Kyshtak;40.5500\nBilopillya;51.1474\nLieksa;63.3167\nRaesfeld;51.7667\nPlatteville;42.7280\nElgóibar;43.2142\nDarnétal;49.4447\nPonte San Pietro;45.6978\nKusugal;15.3667\nRoss on Wye;51.9140\nCampo Alegre;-26.1928\nÓbidos;39.3581\nVlašim;49.7064\nÉtaples;50.5178\nBullas;38.0497\nArataca;-15.2628\nRichmond;29.5824\nJacó;9.6200\nLansing;42.5667\nCisternino;40.7333\nAmbatofisaka II;-20.0833\nSinghāna;27.9800\nPontiac;40.8894\nKundurpi;14.2833\nBrejinho;-6.1908\nĀrambākkam;13.5258\nGhogaon;21.9100\nZero Branco;45.6000\nVasylkivka;48.2084\nGardnerville Ranchos;38.8957\nSrikrishnapur;22.9717\nWetherby;53.9276\nSulebhāvi;15.8800\nEnglefield Green;51.4301\nHollabrunn;48.5667\nGóra;51.6667\nSão João do Manhuaçu;-20.3939\nStokke;59.2400\nPuente Nacional;5.8833\nDolores;17.6490\nMaghra;25.1903\nLwakhakha;0.7967\nKrujë;41.5000\nAesch;47.4694\nRājghāt Garail;25.7618\nPachauth;25.5760\nSinzheim;48.7619\nPadiham;53.7970\nBajestān;34.5164\nBan Mae Kham Lang Wat;20.2225\nLundazi;-12.3000\nNamli;23.4612\nWolmirstedt;52.2519\nCarbonera;45.6833\nBallston;42.9542\nBordentown;40.1420\nAmbohimahasoa;-21.1064\nBriançon;44.8958\nElk City;35.3862\nKalakada;13.8167\nPeiting;47.8000\nRiver Forest;41.8950\nBāra;25.9286\nRaubling;47.7881\nKopervik;59.2801\nMagdagachi;53.4500\nColares;-0.9369\nSaint-Cyprien;42.6181\nGoasi;25.7643\nTrinidad;5.4089\nVauvert;43.6933\nIsaszeg;47.5333\nPimenteiras;-6.2450\nBonito de Santa Fé;-7.3128\nZhetibay;43.5942\nRío Colorado;-38.9908\nMarkham;41.6000\nNemyriv;48.9794\nMissões;-14.8839\nBiri;12.6667\nQuerência do Norte;-23.0839\nVelké Meziříčí;49.3553\nSonwān;25.6258\nOrchha;25.3500\nDeutschlandsberg;46.8161\nHarsum;52.2054\nGräfenhainichen;51.7167\nSint Anthonis;51.6258\nNagar Nahusa;25.3959\nRengāli;21.6460\nSalkhua;25.6677\nMatca;45.8500\nLeidschendam;52.0833\nAl M’aziz;33.6667\nYamkanmardi;16.2900\nPoggio a Caiano;43.8167\nTelwa;26.0877\nVakhrusheve;48.1667\nVaradarājampettai;11.3553\nElwood;40.8462\nPortomaggiore;44.7000\nMacusani;-14.0692\nWalldürn;49.5831\nSatyavedu;13.4370\nMierlo;51.4411\nHoeilaart;50.7667\nPike Creek Valley;39.7294\nRāyavaram;17.1830\nShanmukhasundarapuram;10.0065\nCandelaria;10.4592\nMusile di Piave;45.6178\nMountain Top;41.1353\nManabo;17.4331\nDevanakavundanūr;11.5048\nTamezmout;30.8075\nLamosina;-21.6400\nConceição do Castelo;-20.3678\nAmherst;42.8706\nDurbuy;50.3522\nSääminki;61.8675\nPacoti;-4.2250\nIsola della Scala;45.2692\nGhanpur;17.4989\nEl Ançor;35.6833\nPatera;23.9960\nMangalam;12.3298\nPlymouth;41.6642\nYāllūru;15.3063\nKasempa;-13.4550\nRichfield;43.2372\nLower Burrell;40.5818\nRavanusa;37.2678\nMasanasa;39.4083\nBistān;21.6979\nPrymorsk;46.7353\nIsaka;-21.1500\nAltdorf;48.5667\nSanta Comba Dão;40.4000\nGeisenfeld;48.6667\nTaormina;37.8518\nSirgora;22.2063\nSt. Peter;44.3295\nKamiita;34.1213\nMotegi;36.5321\nSablan;16.4967\nNorton;41.0294\nNossa Senhora dos Milagres;-12.8700\nHeerlerbaan;50.8692\nStelle;53.3667\nDérassi;10.1667\nSouth Yarmouth;41.6692\nSomerset;37.0834\nSeven Hills;41.3803\nMelsele;51.2209\nRakhwāri;26.3603\nCampos del Puerto;39.4306\nSomavārappatti;10.6779\nUbaí;-16.2850\nMena;51.5167\nDolinsk;47.3167\nGouvêa;-18.4539\nLaredo;43.4144\nBefotaka;-17.0839\nOliva;-32.0333\nAniche;50.3300\nBillerbeck;51.9792\nJiwachhpur;26.3120\nMitai;32.7117\nPāpireddippatti;11.9140\nKoori;37.8547\nFrenštát pod Radhoštěm;49.5483\nMinabe;33.7725\nBucyrus;40.8054\nMuzaffarnagar;29.4820\nSandy;41.1447\nGander;48.9569\nEast Glenville;42.8648\nBālakrishnanpatti;11.2511\nOvada;44.6392\nMūdashedde;12.9300\nHanover;40.6668\nChak Thāt;25.7347\nJigani;12.7861\nOstrhauderfehn;53.1167\nEningen unter Achalm;48.4831\nNaryn;41.1306\nSunninghill;51.4025\nSultānpur;23.1381\nĀhiro;24.9192\nCaorle;45.6000\nMendota Heights;44.8815\nHinwil;47.3033\nSchiller Park;41.9586\nDouglas;31.5065\nSanta Clara;44.1154\nBytča;49.2242\nChantilly;49.1869\nYirol;6.5600\nTāzhakudi;8.2348\nRājpur Kalān;25.6792\nUdachnyy;66.4000\nGuaiçara;-21.6219\nParvatgiri;17.7417\nBad Nenndorf;52.3369\nTulshia;26.3468\nCapela de Santana;-29.7000\nLawrenceburg;38.0332\nMurapāka;18.2282\nYercaud;11.7794\nShuinancun;23.2995\nMyrtle Grove;34.1230\nPīr Bakrān;32.4689\nLa Calamine;50.7000\nPepperell;42.6713\nLoutráki;37.9750\nGolet;19.2390\nSurinam;-20.5139\nDiao’ecun;40.7227\nXiaoba;26.7217\nTlachichilco;20.6217\nLyuban;52.7819\nSchwaigern;49.1333\nDe Pinte;51.0000\nRosario de Mora;13.5833\nPort Morant;17.9000\nTārar;25.1821\nSidi Tabet;36.9139\nYelandūr;12.0700\nSaint Helena Bay;-32.7583\nCocentaina;38.7450\nEsperanza;22.4472\nVernouillet;48.9722\nEureka;38.5004\nHuandacareo;19.9906\nAlburquerque;9.6104\nHalavāgalu;14.7083\nMilattūr;10.8576\nJódar;37.8333\nHallbergmoos;48.3333\nRudersberg;48.8856\nHidaka;42.4803\nMestrino;45.4500\nRothesay;45.3831\nMangabe;-16.9500\nRadnevo;42.3000\nElma;42.8231\nSingapperumālkovil;12.7595\nTonse West;13.3968\nIonia;42.9773\nFatehpur;25.3032\nPort Lavaca;28.6181\nFortaleza dos Nogueiras;-6.9639\nKamānpur;18.6667\nBan Mae Tuen;18.0100\nTrecastagni;37.6167\nLittle Chute;44.2906\nPoulsbo;47.7417\nKuřim;49.2985\nOulad Friha;32.6108\nFranklin;39.5538\nBonate di Sopra;45.6833\nCenter;40.6483\nLardero;42.4261\nAnnoeullin;50.5294\nSagada;17.0842\nDrawsko Pomorskie;53.5333\nMala Vyska;48.6500\nAuhar Sheikh;26.7216\nLiberty Lake;47.6686\nMistelbach;48.5667\nTudela;10.6360\nSidi Moussa Ben Ali;33.5594\nRoss-Bétio;16.2667\nBrock;44.3167\nHipperholme;53.7258\nCarver;41.8739\nKalmiuske;47.6667\nNzeto;-7.2290\nOkpo;18.1167\nSanta Cruz Itundujia;16.8667\nJamaat Shaim;32.3500\nSahuria;25.8197\nBan Bang Toei;14.0656\nVidele;44.2833\nAnatolí;39.6386\nKhair Khān;26.2727\nMotīpur;25.8159\nDautphe;50.8583\nLenvik;69.3836\nBellmawr;39.8666\nDumri;25.5263\nJaqueira;-8.7269\nMöhlin;47.5583\nQuebrangulo;-9.3189\nAsbury Lake;30.0472\nSpring Lake;35.1843\nMontegrotto Terme;45.3333\nSanto Antônio do Jacinto;-16.5339\nLunenburg;42.5897\nDodvad;15.7900\nChikkārampālaiyam;11.2416\nCalheta;32.7258\nShow Low;34.2671\nWinton;37.3854\nWarden;-27.8539\nCamisano Vicentino;45.5167\nHlaingbwe;17.1333\nStaden;50.9750\nShāhzādpur;25.6541\nOñate;43.0333\nEast Greenwich;39.7903\nSchöningen;52.1333\nChegem Vtoroy;43.5667\nFuente de Oro;3.4667\nUlricehamn;57.7833\nSidi Kasem;35.5339\nDerdara;35.1103\nQaşr-e Qand;26.2483\nGravelines;50.9864\nJames Island;32.7353\nLa Unión;8.8606\nLézignan-Corbières;43.2006\nSummerland;49.6006\nDen Chai;17.9835\nValpovo;45.6667\nIhumwa;-6.1667\nBig Lake;45.3417\nRāmbilli;17.4644\nCadale;2.7500\nHisar;26.5495\nHanover;43.7156\nSīrpanandal;11.9741\nSanta Lucía;-28.9833\nSelsey;50.7350\nKrynica;49.4117\nBatemans Bay;-35.7081\nLikhoslavl;57.1333\nFirminópolis;-16.5819\nMarktheidenfeld;49.8500\nBoscotrecase;40.7833\nGelves;37.3333\nKem;64.9500\nBan Saeo;20.2158\nAnuppampattu;13.3018\nNauheim;49.9447\nBaghānt;26.1748\nBela;24.9689\nShengping;28.4865\nIngelmunster;50.9208\nHexham;54.9710\nKurgunta;17.2000\nMortād;18.8167\nBāra Khurd;25.2599\nOkuizumo;35.1973\nKhorramābād;36.7828\nUchchangidurgam;14.5614\nSangrāmpur;25.0711\nTemamatla;19.2028\nSvidník;49.3056\nBarahbatta;25.7727\nYellayapālem;14.5378\nSursee;47.1667\n’Aïn Roua;36.3344\nDzouz;31.8900\nThanh Xuân;10.2308\nTimahdit;33.2369\nSăcueni;47.3525\nDe Panne;51.1019\nKonanūr;12.6333\nPadre Burgos;10.0333\nGhinda’e;15.4500\nLa Riche;47.3892\nCaraguatay;-25.2333\nKuppachchipālaiyam;11.0273\nNāgojanahalli;12.3570\nTadley;51.3506\nGandhāri;18.3932\nMexico;39.1625\nOuro Branco;-9.1667\nBannewitz;50.9931\nUsuppūr;11.3815\nSiniscola;40.5743\nMuroto-misakicho;33.2900\nOdugattūr;12.7679\nStollberg;50.7083\nEmmaus;40.5352\nRāmchandrapur;22.9000\nDamonojodi;18.7632\nEpazoyucan;20.0177\nRisch;47.1411\nWerther;52.0750\nĀtharga;16.9875\nBhagirathpur;24.0912\nSesto Calende;45.7333\nCranleigh;51.1363\nKonakondla;15.1053\nRutesheim;48.8097\nHuanian;24.0781\nSimri;26.3825\nSanta Genoveva de Docordó;4.2586\nMango;27.9914\nVal-des-Monts;45.6500\nKodmiāl;18.6333\nAdendorf;53.2833\nIrmo;34.1018\nRounia;25.5179\nKuttappatti;11.7939\nGympie;-26.1900\nRecke;52.3700\nÉzanville;49.0278\nKhawaspur;26.2331\nVineyard;40.3059\nComala;19.3208\nPfastatt;47.7689\nLeatherhead;51.2950\nKonganāpuram;11.5710\nSchönaich;48.6569\nMallagunta;12.6343\nTrostberg an der Alz;48.0167\nSheron;30.1582\nKoch;24.9259\nBharhopur;25.9488\nElizabethtown;40.1533\nPatterson;41.4849\nNavarro;-35.0167\nGreensburg;39.3518\nBek-Abad;40.8472\nBabhniyāwān;25.4943\nRiesi;37.2833\nTawnza;32.0944\nMasakkavundanchettipālaiyam;11.1473\nBora;23.6585\nMiddle Valley;35.1877\nYuasa;34.0294\nBouabout;31.2667\nGustavsberg;59.3333\nTaché;49.7081\nKaniyūr;11.0930\nLuathaha;26.6316\nChettimangurichchi;11.6393\nPhanat Nikhom;13.4458\nSatuek;15.3008\nGrobbendonk;51.2000\nPuerto Suárez;-18.9667\nSevernyy;67.6083\nItārhi;25.4832\nAngicos;-5.6658\nSalaya;13.8023\nBarni;25.3484\nShankarpalli;17.4523\nWhitchurch;51.4064\nPāta Ellamilli;16.8473\nMaxéville;48.7114\nEstiva Gerbi;-22.2708\nKovūrupalli;14.7772\nKirchhundem;51.1000\nKadūr Sāhib;31.4239\nLantana;33.0926\nDouar Trougout;35.1800\nChassieu;45.7444\nMelito di Porto Salvo;37.9167\nBad Schwalbach;50.1333\nCiechocinek;52.8833\nMogilno;52.6500\nFerreiros;-7.4478\nWittingen;52.7167\nValdivia;7.2890\nEsil;51.9556\nTagami;37.6988\nSevilla;9.7000\nBārīgarh;25.2325\nNarasingam;9.9658\nOskaloosa;41.2922\nMiami Shores;25.8670\nMaurilândia;-17.9708\nOmaruru;-21.4333\nNettanige;12.6101\nKin;26.4562\nRheinau;48.6678\nKenzhe;43.4911\nRiorges;46.0428\nCadolzburg;49.4500\nMalkanūr;18.0821\nDiamond Springs;38.6920\nPedro Afonso;-8.9678\nNyazepetrovsk;56.0500\nKaboua;8.2500\nCholpon-Ata;42.6500\nWambrechies;50.6853\nNembro;45.7439\nKamalāpuram;18.2925\nHasbergen;52.2167\nMasinigudi;11.5683\nMutlūru;16.1500\nHigashiizu;34.7667\nAlto Garças;-16.9439\nWakefield;38.8230\nChintakunta;14.6466\nSebastião Laranjeiras;-14.5728\nPlankstadt;49.3933\nBochaha;25.5675\nMatulji;45.3667\nBhattiprolu;16.1000\nKulgo;24.0154\nBuzhum;40.0100\nBondoufle;48.6133\nBath;42.3219\nNorfolk;42.1163\nSant Joan de Vilatorrada;41.7456\nSonbāri;24.2286\nUtiel;39.5672\nKuriyama;43.0563\nCastelvetro di Modena;44.5000\nGrosse Pointe Park;42.3794\nSaint-Hilaire-de-Riez;46.7211\nMoyamba;8.1606\nVillerupt;49.4697\nBox Elder;44.1120\nChorrochó;-8.9800\nSan Carlos de Guaroa;3.7111\nAreal;-22.2308\nMorgan City;29.7041\nFatehpur;24.6297\nPirangi;-21.0914\nYuncos;40.0833\nSan Lázaro;-22.1083\nZvenigovo;55.9833\nIlicínia;-20.9358\nCampo do Meio;-21.1069\nMontopoli in Val d’Arno;43.6667\nPanazol;45.8389\nNew Baltimore;38.7495\nLokhvytsya;50.3610\nDhorgaon;25.9545\nBelém de Maria;-8.6139\nGuayabal;4.9633\nLantana;26.5834\nKapaa;22.0910\nKarlsdorf-Neuthard;49.1364\nCherdakly;54.3594\nWelzheim;48.8747\nLakeville;41.8310\nMyronivka;49.6500\nTârgu Ocna;46.2800\nRothenburg ob der Tauber;49.3833\nCoronel Dorrego;-38.7000\nDobbs Ferry;41.0127\nHolíč;48.8122\nNewtown;52.5132\nMāshyāl;17.3226\nScalea;39.8167\nUničov;49.7709\nZierikzee;51.6497\nDammartin-en-Goële;49.0542\nBalve;51.3333\nSidéradougou;10.6876\nLençóis;-12.5628\nBeclean;47.1797\nDivinolândia;-21.6614\nYakymivka;46.6977\nMinnehaha;45.6577\nLurate Caccivio;45.7667\nGohuma Bairia;26.3938\nVermillion;42.7811\nCrikvenica;45.1833\nLutry;46.5000\nGig Harbor;47.3352\nLovington;32.9128\nPoldasht;39.3475\nLeon Valley;29.4954\nBurhia Dhanghatta;25.9004\nSociedad;13.7000\nMāli;25.1269\nPaceco;37.9833\nLenzburg;47.3833\nAmnéville;49.2608\nBuriti do Tocantins;-5.3158\nDalāwarpur;26.3466\nMānikpur;25.3129\nMuquém de São Francisco;-12.0650\nKīlrājakularāman;9.3969\nCerese;45.0500\nEl Khemis des Beni Chegdal;32.4441\nEr Regueb;34.8667\nTibau do Sul;-6.1869\nJādupatti;26.1186\nKonen Agrahār;12.8574\nAginskoye;51.1031\nBaldock;51.9900\nOchsenfurt;49.6500\nLahfayr;30.5700\nAin Legdah;34.1667\nFlorennes;50.2514\nWaupun;43.6314\nSonakhal;22.2213\nMedulla;27.9570\nDomažlice;49.4406\nMalapannanagudi;15.2800\nBom Retiro do Sul;-29.6089\nSalisbury;40.0380\nMontmagny;46.9833\nCornate d’Adda;45.6500\nTerku Valliyūr;8.3570\nKostinbrod;42.8167\nAmjhār;25.0641\nAhlaf;33.2833\nKlyetsk;53.0636\nChkalovsk;56.7667\nBátonyterenye;47.9906\nTinogasta;-28.0667\nYorktown;40.1830\nXambioá;-6.4108\nVarzobkala;38.7667\nJem’at Oulad ’Abbou;33.1156\nFort Morgan;40.2537\nNekarikallu;16.3833\nAvigliano;40.7314\nLoyalsock;41.2743\nFarmington;42.4614\nOrono;44.8867\nSenador José Porfírio;-2.5908\nAntônio Carlos;-21.3178\nPaduma;26.5766\nOrtakent;37.1035\nKuzuculu;36.8833\nDinard;48.6325\nTāmba;17.0001\nPrien am Chiemsee;47.8560\nGayāspur;25.9217\nLajosmizse;47.0264\nRidgefield;40.8313\nNaliya;23.2611\nGracemere;-23.4391\nSales Oliveira;-20.7719\nRaghunāthpur;26.0019\nRāmanāyakkanpālaiyam;11.6291\nḐurumā;24.6000\nCalatrava;12.6167\nRetie;51.2667\nStafford;41.9876\nGerasdorf bei Wien;48.2950\nByerazino;53.8333\nHerbolzheim;48.2219\nAbjīj;29.2861\nEgersund;58.4497\nPueblo Viejo;18.4000\nKyjov;49.0102\nChandreru;16.8200\nMancha Real;37.7864\nRavutulapūdi;17.3833\nMāngobandar;24.8162\nKennebunk;43.3972\nGuinagourou;9.5667\nOntario;44.0259\nNew Garden;39.8119\nAmdel;31.5617\nKomorniki;52.2667\nBaragaon;25.1348\nAxixá;-2.8369\nHartsville;36.3921\nGreat Harwood;53.7860\nPiazzola sul Brenta;45.5333\nGrafton;-29.6833\nDharmavaram;17.2100\nFulton;43.3171\nHejiaji;37.3539\nPeddapādu;16.6408\nLanham;38.9620\nLawrenceburg;35.2497\nGriswold;41.5852\nKanamadi;16.8300\nMaltby;47.8027\nTinkoni;26.8613\nResende;41.1060\nOud-Heverlee;50.8333\nÉcaussinnes-Lalaing;50.5667\nSaint-Junien;45.8872\nBūdili;13.9353\nPātrasāer;23.1968\nNelson Bay;-32.7150\nPerali;15.8860\nMoss Bluff;30.3039\nMack;39.1492\nSeneffe;50.5333\nRoma;26.4166\nTucson Mountains;32.2822\nSanta Rosa de Viterbo;5.8833\nVenafro;41.4844\nLa Maddalena;41.2167\nFagundes;-7.3550\nCanton;44.5802\nDouar Oulad Naoual;34.4936\nBelén;-23.4660\nLaqraqra;32.4333\nBotticino Sera;45.5333\nEidsberg;59.5369\nLa Libertad;12.2156\nKalavapūdi;16.4623\nVirton;49.5675\nKannūlu;12.8685\nNikel;69.4081\nPort Salerno;27.1461\nNueva Helvecia;-34.2833\nKörmend;47.0110\nTown and Country;38.6317\nLafrayta;31.9167\nCzarnków;52.9000\nHealdsburg;38.6224\nErin;43.7667\nJimaní;18.4900\nPalukudoddi;15.8610\nPedro de Toledo;-24.2750\nGloucester City;39.8924\nAratuba;-4.4178\nOraviţa;45.0403\nMărăşeşti;45.8800\nHato Corozal;3.1833\nDouar Sgarta;32.1667\nSan José de Guaribe;9.7930\nHejamādi;13.1062\nPuerto Rico;2.9383\nValley Center;33.2330\nZaō;38.0981\nFlawil;47.4053\nBoldeşti-Scăeni;45.0300\nBarbosa Ferraz;-24.0300\nDagbé;6.5667\nDhilwān Kalān;30.5718\nKall;50.5497\nDouchy-les-Mines;50.3014\nBarbadanes;42.3003\nHatwāns;22.7683\nSolymár;47.5910\nLamsabih;32.2933\nCreazzo;45.5333\nTelkap;24.7048\nGentio do Ouro;-11.4289\nPottireddippatti;11.1659\nJhundo;24.7756\nSorsk;54.0333\nYuryuzan;54.8667\nKastav;45.3750\nKochgāwān;25.0431\nTeixeiras;-20.6508\nGhatāwān;25.0968\nGararu;-9.9678\nCazzago San Martino;45.5817\nCoveñas;9.4167\nGalsi;23.3427\nKawadgaon;17.9100\nPortes-lès-Valence;44.8733\nAbaiara;-7.3589\nWaidhofen an der Ybbs;47.9596\nMusāpur;25.6821\nBridgeton;38.7673\nKhurān Milik;25.6000\nAlassio;44.0000\nPāma;25.8122\nSào Amaro das Brotas;-10.7889\nGhagga;30.0198\nDūrpalli;18.5967\nVieux-Condé;50.4594\nKattāri;11.4593\nLumaco;-38.1500\nTiruvalam;12.9825\nZirə;40.3636\nSnovsk;51.8203\nGuachetá;5.3856\nTiruppālaikudi;9.5461\nSuhr;47.3747\nCharne;26.1185\nLijiacha;37.2467\nZambrano;9.7500\nPālakollu;16.5160\nSárospatak;48.3190\nAlcântaras;-3.5889\nHeule;50.8333\nLystrup;56.2353\nLasht-e Neshā;37.3661\nYelpur;18.7651\nChekmagush;55.1411\nSidhap Kalān;26.5456\nSussex;43.1346\nBabayevo;59.3833\nTelsang;16.7200\nMaheshrām;25.2874\nCividale del Friuli;46.1000\nHandewitt;54.7667\nGrigny;45.6083\nDhanwār;24.4107\nMoorslede;50.8906\nTalaigua Nuevo;9.3069\nKingsnorth;51.1178\nLoreto;-7.0839\nStannington;53.3960\nAthy;52.9920\nKuttattuppatti;10.3759\nTilmi;31.8189\nHillsborough;37.5572\nBăcioi;46.9122\nKincardine;44.1667\nLauingen;48.5667\nKarukkalvādi;11.6714\nDrezna;55.7453\nBitritto;41.0500\nLieshout;51.5194\nOnoto;9.5958\nKhaira;24.8727\nKochkor;42.2158\nSaharbani;25.7201\nEast Grand Rapids;42.9464\nRio Novo do Sul;-20.8628\nElchūru;16.0813\nWesterkappeln;52.3153\nIchikai;36.5431\nSankt Johann im Pongau;47.3500\nEl Ghourdane;32.3400\nGornozavodsk;58.3667\nCanápolis;-18.7250\nCălan;45.7361\nKiwoko;0.8442\nCommune Sidi Youssef Ben Ahmed;33.7861\nSantiago del Teide;28.2957\nEkma;26.0541\nLang Suan;9.9500\nCatskill;42.2063\nHumahuaca;-23.2000\nOxted;51.2570\nPassy;45.9236\nSan José del Fragua;1.3286\nVila Franca do Campo;37.7167\nYangirabot;40.0253\nWoods Cross;40.8731\nCaotan;36.2501\nCepagatti;42.3667\nThevūr;11.5240\nAnguera;-12.1508\nPunjai Turaiyāmpālaiyam;11.5142\nRavenna;41.1612\nNalgora;22.0346\nSnyder;32.7133\nBurrel;41.6083\nGualcince;14.1167\nPassa e Fica;-6.4358\nKiáto;38.0102\nHerrsching am Ammersee;48.0000\nIbicuitinga;-4.9739\nArslanbob;41.3333\nSūlibele;13.1667\nHanover;41.2012\nOuaklim Oukider;31.4500\nIpaporanga;-4.9000\nMakoua;-0.0047\nRatauli;26.1861\nHormigueros;18.1437\nSidi Abdellah Ben Taazizt;34.0019\nAmatenango del Valle;16.5167\nLangarivo;-14.6000\nJeumont;50.2944\nSabana Yegua;18.7200\nTortolì;39.9333\nBardipuram;18.6431\nOstbevern;52.0389\nChampua;22.0667\nSan Giustino;43.5500\nSanta Juliana;-19.3089\nYanahuanca;-10.4914\nRostraver;40.1690\nBarāhi;25.9725\nCharouine;29.0167\nMiechów;50.3578\nPalmerston;53.3500\nBang Ban;14.4247\nTsqaltubo;42.3264\nUsmate Velate;45.6500\nYargatti;15.9667\nAramari;-12.0819\nErmenek;36.6389\nTouama;31.5339\nGurwaliā Biswās;26.8372\nCapitán Sarmiento;-34.1667\nLindon;40.3414\nFloresta Azul;-14.8600\nLe Luc;43.3947\nCampbellsville;37.3445\nBesalampy;-16.7500\nMontanhas;-6.4858\nEichenzell;50.4934\nHolbrook;42.1471\nWoodmere;29.8493\nSebba;13.4333\nPetal;31.3477\nKarebilachi;14.1449\nIuiú;-14.4139\nLa Chapelle-Saint-Mesmin;47.8897\nNandasmo;11.9247\nChirak;30.7206\nEl Quisco;-33.3913\nTirumayam;10.2449\nTarare;45.8961\nKonnūr;15.8595\nSankhavaram;17.2704\nRāmchandarpur;25.2365\nRumburk;50.9516\nSøgne;58.0942\nIchinohe;40.2129\nAmbotaka;-21.7500\nAllāhdurg;17.9667\nAcate;37.0339\nParamoti;-4.0969\nMudki;30.7800\nOkmulgee;35.6134\nMülsen;50.7447\nChiyoda;36.2178\nSatai;24.7220\nBalsa Nova;-25.5839\nCislago;45.6500\nKrosno Odrzańskie;52.0333\nKasba;25.5856\nShiloh;39.8159\nSant’Agata de’ Goti;41.0893\nLakeland Highlands;27.9572\nŪttukkuli;11.1689\nPālamedu;10.1050\nVadamugam Vellodu;11.2366\nTalupula;14.2500\nSendurai;11.2530\nLansing;39.2428\nChittārkottal;9.4276\nBurtonwood;53.4302\nParwāha;26.2336\nOllerton;53.2000\nEisenberg;50.9667\nHonmachi;43.9115\nVargaūr;11.1452\nBailin;33.4850\nCocoa Beach;28.3327\nChantepie;48.0886\nGolfito;8.6526\nRolla;13.8331\nHonwāda;16.8111\nBom Jesus;-28.6678\nAbbeville;29.9751\nGloucester Point;37.2767\nBollullos de la Mitación;37.3333\nKpandae;8.4700\nRejiche;35.4667\nMontlouis-sur-Loire;47.3883\nIllintsi;49.1000\nTyāmagondal;13.2137\nEnebakk;59.7639\nInhassoro;-21.5333\nNhandeara;-20.6939\nMpraeso;6.5800\nBarahpur;25.4192\nImbaú;-24.4450\nLe Pradet;43.1056\nDevgeri;14.8512\nSvitlodarsk;48.4358\nChāoke;30.1847\nBilldal;57.5833\nCristais;-20.8758\nGetulina;-21.7986\nThouaré-sur-Loire;47.2689\nAntsambalahy;-14.7167\nKaset Wisai;15.6556\nHullahalli;12.1000\nTysvær;59.3617\nBan Kat;18.1764\nPedersöre;63.6642\nShenfield;51.6297\nMasdi;25.2441\nPoção;-8.1858\nWālūr;19.4872\nCastle Pines;39.4625\nMonmouth;51.8100\nPattanam;11.4728\nDerecik;37.0830\nRosario;12.5167\nIazizatene;35.2544\nSpencer;43.1468\nBrooklyn;41.4349\nCabanillas del Campo;40.6383\nChota Mollakhāli;22.2177\nPareo;25.5582\nCabestany;42.6806\nEl Refugio;13.9750\nLas Charcas;18.4500\nAreiópolis;-22.6681\nSakkamapatti;9.9250\nBoguchar;49.9500\nProgress;40.2901\nUropá;-11.1406\nArvand Kenār;29.9789\nArvand Kenār;30.0617\nCleveland;33.7440\nWanaque;41.0440\nApt;43.8761\nDerbisek;41.5608\nIver;51.5210\nUraí;-23.1978\nAukštieji Paneriai;54.6000\nGarrucha;37.1842\nPiên;-26.0978\nSant’Antìoco;39.0664\nKleinblittersdorf;49.1583\nNorth Dundas;45.0833\nArouca;10.6333\nMeulebeke;50.9497\nItikalapalle;14.6013\nAulla;44.2167\nBoekel;51.6000\nEl Playón;7.4767\nMaraial;-8.8028\nTwo Rivers;44.1565\nEnfida;36.1353\nMarcali;46.5858\nSão Domingos;-13.3978\nBurley;42.5379\nEdéia;-17.3389\nKriževci;46.0258\nBelmonte Mezzagno;38.0500\nLowes Island;39.0471\nDrochtersen;53.7000\nPoko;3.1500\nNieder-Olm;49.9083\nHamilton;39.9432\nMelres;41.0667\nFiľakovo;48.2683\nSonseca;39.7000\nGanga Sāgar;21.6571\nZaouiet Says;32.7931\nDouar Ain Maatouf;34.4352\nTetyushi;54.9333\nWestwood;40.9878\nJoquicingo;19.0556\nMineral de Angangueo;19.6206\nLargs;55.7950\nCapilla del Monte;-30.8500\nPasaco;13.9789\nSanta Cruz;-0.5333\nKowdalli;12.0670\nEdd;13.9333\nCelebration;28.3102\nBānāvar;13.4167\nMadhuban;25.8948\nLaurel;27.1507\nFeldkirchen-Westerham;47.9000\nKamargani;22.5475\nErrahalli;12.3911\nMonaragala;6.8726\nDrākshārāma;16.7928\nErraguntla;15.2821\nBarton upon Humber;53.6833\nWellesley;43.5500\nMeiwa;36.2113\nLubawa;53.5000\nMoyuta;14.0381\nEngen;47.8528\nNorwell;42.1608\nEstevan;49.1392\nPūdimadaka;17.5000\nDuraiswāmipuram;9.4233\nRaibhīr;25.9978\nJeseník;50.2297\nBewdley;52.3758\nSanta Clara La Laguna;14.7167\nPotukonda;17.2708\nSanta Cruz Balanyá;14.6869\nQuintanar de la Orden;39.5906\nDouar Jwalla;31.8900\nPolistena;38.4000\nGroton;42.6137\nAlpu;39.7667\nPottipuram;9.9709\nSierra Madre;34.1687\nFort Meade;39.1061\nBeaumont-sur-Oise;49.1425\nSaddlebrooke;32.5576\nŠtúrovo;47.7992\nLorch;48.7983\nNova Laranjeiras;-25.3069\nGlückstadt;53.7917\nKirchseeon;48.0731\nMilford;38.9091\nNorth Saanich;48.6142\nKapasiāwān;25.2783\nInhangapi;-1.4300\nLinluo;22.6506\nOtar;43.5375\nSokhodewara;24.8358\nSanjiaocheng;36.8993\nMishrikot;15.2465\nSaltsjöbaden;59.2861\nPaināl;25.5900\nSahidganj;25.6627\nFriedrichsthal;49.3256\nVire;48.8386\nTherwil;47.4997\nChicholi;22.0100\nQuincy-sous-Sénart;48.6711\nKorablino;53.9167\nThạnh Phú;9.9539\nKusumha;25.1859\nLos Almácigos;19.4083\nChamestān;36.4772\nXintianfeng;24.4575\nLake Elmo;44.9944\nGoldach;47.4831\nLavandevīl;38.3089\nBataiporã;-22.2950\nBanagi;13.6100\nThepaha Rāja Rām;26.2229\nIbiraçu;-19.8319\nDois Riachos;-9.3928\nCerreto Guidi;43.7667\nGold Canyon;33.3639\nBoguchany;58.3667\nKāza;16.3887\nKranenburg;51.7897\nKursavka;44.4500\nHudson;28.3595\nJalkaura;25.5034\nĪmani;16.3302\nBayou Blue;29.6341\nTýrnavos;39.7333\nNallamada;14.2164\nFino Mornasco;45.7500\nPalsud;21.8262\nLindome;57.5667\nNueva Toltén;-39.1786\nBraunfels;50.5167\nModa;13.8246\nMapleton;40.1188\nBoujediane;35.1114\nVanj;38.3731\nJardim Alegre;-24.1789\nRāmabhadrapuram;18.5000\nBagamanoc;13.9408\nBanta;24.1025\nSan José de Aerocuar;10.6027\nPlaine Magnien;-20.4286\nSanta Croce Camerina;36.8272\nJalālpur;26.0433\nStonehaven;56.9640\nChulym;55.1167\nAroāli;23.9146\nDhamsāin;26.0938\nArmstrong;-32.7833\nSalcedo;17.1517\nShahmīrzād;35.7728\nEfatsy-Anandroza;-23.1167\nYakınca;38.3000\nKamalāpuram;18.1600\nTinchlik;40.4264\nShahrinav;38.5667\nMāruteru;16.6237\nIygli;29.5001\nOcean City;39.2681\nBalingoan;9.0000\nStaryya Darohi;53.0394\nSão Félix do Araguaia;-11.6169\nLloró;5.5000\nHardia;25.8657\nBan Wang Daeng;17.4790\nSiktiāhi;26.4812\nSanta Inês;-13.2938\nAnderson;40.4497\nSangam;14.5956\nSanta Ana Huista;15.6833\nKasavanampatti;10.3692\nKaruvelampatti;9.8448\nNādendla;16.2186\nValkeala;60.9389\nWoodbury;41.3284\nGottmadingen;47.7356\nRychnov nad Kněžnou;50.1629\nMagnolia;33.2775\nKīlminnal;12.9447\nWęgorzewo;54.2167\nKothri Kalān;23.0722\nHernando;-32.4167\nPihuamo;19.1889\nBernardino de Campos;-23.0167\nTrofaiach;47.4261\nGengenbach;48.4000\nSão João de Ver;40.9540\nFīnch’a’ā;9.9000\nBobil;25.6269\nBiganos;44.6442\nRāmpur Kalān;26.1649\nKazarman;41.4000\nAmbinanin’i Sakaleona;-20.5333\nMhangura;-16.9000\nEbreichsdorf;47.9611\nSan Nicolas Buenos Aires;19.1433\nCastalla;38.5967\nEast Windsor;41.9049\nKatālpur;26.2255\nSušice;49.2312\nRianxo;42.6500\nPipalrawān;23.1625\nTakad Sahel;30.2500\nBisaria;25.9789\nTadhwa Nandpur;26.7556\nOporapa;2.0500\nIlfracombe;51.2080\nWillistown;40.0010\nRaipur Buzurg;25.7118\nIsselburg;51.8331\nHumpolec;49.5417\nCongaz;46.1083\nNāthpur;26.3261\nMānkur;23.4312\nSwarna;15.8542\nCameri;45.5000\nKariat Ben Aouda;34.7667\nSäter;60.3500\nSannieshof;-26.5333\nSi Wilai;18.1865\nCorleone;37.8167\nFagersta;60.0042\nUchagaon;15.8800\nBan Bo Phlap;13.8439\nOgose;35.9645\nPādiyūr;10.4234\nSerris;48.8564\nBarrington;42.1515\nCastel Mella;45.5000\nImerimandroso;-17.4333\nXinyaoshang;26.8350\nPipraun;26.5990\nPotosí;11.4942\nPetua;22.4143\nSuhāgi;23.2206\nSan Valentino Torio;40.7911\nSimpelveld;50.8333\nMahādeopur;18.7316\nMangalmé;12.3547\nMiastko;54.0167\nSmithfield;35.5133\nChikha;23.8898\nRegen;48.9667\nGokinepalle;16.9228\nPine Castle;28.4651\nBurr Ridge;41.7485\nTanippādi;12.1078\nHagen im Bremischen;53.3577\nStorm Lake;42.6431\nUrbana;40.1085\nWarren;41.7282\nZakamensk;50.3833\nBuxerolles;46.5975\nLa Escala;42.1136\nTrevignano;45.7335\nInzago;45.5333\nTaylorville;39.5328\nBegogo;-23.4833\nRājagiri;10.9333\nSzprotawa;51.5667\nHârlău;47.4278\nWaggaman;29.9373\nByelaazyorsk;52.4500\nHéricourt;47.5775\nIchikawa;34.9893\nBarmstedt;53.7833\nWells;43.3267\nBaley;51.6000\nCovington;30.4810\nOsterwieck;51.9667\nIlāmi;24.6776\nKaradichittūr;11.8289\nBetzdorf;50.7856\nChicureo Abajo;-33.2833\nShepperton;51.3900\nBarros Cassal;-29.0928\nMarudūr;11.2346\nKerap;24.8332\nBairiyā;26.3392\nYamanouchi;36.7446\nLongtaixiang;34.5988\nŞā’īn Qal‘eh;36.3058\nWisła;49.6549\nBesagarahalli;12.6333\nBhadsara;25.3696\nHājīpur;25.2657\nMāraneri;9.4333\nBarahra;26.2356\nUrlāha;25.7440\nOued Amlil;34.2000\nChandūr;16.9800\nNakagawa;33.9511\nMarilândia;-19.4128\nBelzig;52.1422\nPandāravādai;10.9133\nTha Chang;9.2674\nBir Ghbalou;36.2642\nGucheng;34.4545\nAl ‘Amādīyah;37.0925\nSão Jerônimo da Serra;-23.7278\nKumbhāri;21.2088\nWulingshancun;40.4755\nNandayure;9.9014\nEkamba;25.9689\nFlöha;50.8558\nCharlton Kings;51.8877\nKirensk;57.7833\nManandroy;-21.1333\nVinaninkarena;-19.9500\nChinna Annalūru;14.8913\nBertinoro;44.1500\nHikawadai;32.5825\nDe Witt;43.0300\nJyllinge;55.7511\nTolna;46.4236\nWesttown;39.9417\nWimauma;27.6964\nLeers;50.6817\nClayton;37.9404\nTimonium;39.4459\nShōō;35.0418\nPuerto Caicedo;0.6850\nEkchāri;25.2093\nYairipok;24.6779\nFour Corners;29.6705\nTepetlán;19.6667\nFronteiras;-7.0878\nDamme;51.2500\nCampolongo Maggiore;45.3333\nWen’anyi;36.8658\nWangjiabian;38.2412\nSemuto;0.6200\nMiddle Island;40.8857\nAduku;2.0194\nAlella;41.4953\nMiānpur Dubauli;26.7381\nGachetá;4.8176\nSabana Grande;18.0832\nEast Hanover;40.8192\nLloyd;41.7286\nTournon-sur-Rhône;45.0672\nKongaralli;12.1500\nRáckeve;47.1608\nArakeri;16.9181\nAgua de Dios;4.3781\nEl Águila;4.9167\nMawu;34.4310\nAmjhera;22.5578\nWeinböhla;51.1667\nKumāravādi;10.5264\nPeru;40.7593\nItainópolis;-7.4469\nFanlu;23.4494\nParthenay;46.6486\nMātsavaram;16.5270\nAliganj;24.9365\nCampinorte;-14.3139\nHammelburg;50.1167\nAydıncık;36.1417\nKārīz;34.8128\nSigatoka;-18.1414\nGainrha;25.9916\nTiri;25.8871\nUnion City;36.4267\nAppārāopeta;16.8987\nSosnivka;50.2946\nKarapa;16.9000\nEl Trébol;-32.1833\nRío Cuarto;10.4076\nBatesville;35.7687\nAntanandava;-15.8500\nNarot Mehra;32.2673\nMoita Bonita;-10.5778\nNiémasson;10.3078\nSan Bernardo;-27.2667\nCalçado;-8.7419\nAkhnūr;32.8667\nMaryānaj;34.8311\nMyślibórz;52.9333\nPompton Lakes;41.0024\nSanto André;38.0500\nMontale;43.9333\nAlberique;39.1167\nKataha;26.7159\nBolkhov;53.4500\nAsahni;26.0079\nMerriam;39.0186\nLake Grove;40.8586\nTârgu Frumos;47.2097\nNew Port Richey East;28.2605\nMittahalli;12.4210\nGriñón;40.2167\nRāmpur;25.8864\nDolhasca;47.4303\nAlipur;18.8621\nFuller Heights;27.9227\nMahīn;34.2425\nMiyato;36.1772\nVeselí nad Moravou;48.9536\nWaasmunster;51.1097\nNazyvayevsk;55.5667\nSoamanova;-23.2833\nParapuã;-21.7681\nPanguipulli;-39.6444\nMocharim;24.6794\nHerxheim;49.1469\nVijes;3.7000\nSingoli;24.9667\nOregon;42.9253\nJanāpul;22.8615\nFao Rai;18.0175\nBarhi;26.4629\nGoldbach;49.9889\nShiloh;39.9732\nManaíra;-7.7058\nSnodland;51.3280\nGuilherand;44.9344\nKaunra;25.5231\nGorha;26.2267\nDhilwan;31.5143\nPontchâteau;47.4369\nMarly;49.0611\nPallattūr;10.1461\nVilyuysk;63.7500\nUjjini;14.9100\nKarīmpur;23.9667\nSatellite Beach;28.1782\nRoscoe;42.4256\nShahmīrpet;17.5947\nBelén de los Andaquíes;1.4161\nSão José do Jacuípe;-11.4119\nMahālgaon;26.0466\nColumbia;38.4581\nGrand Gosier;18.1833\nNarimanov;46.6833\nMotta di Livenza;45.7797\nBan Yang Hom;19.9222\nMilicz;51.5333\nKhokri Kalān;30.8456\nGreasley;53.0200\nSão Ludgero;-28.3258\nSzydłowiec;51.2333\nĀwash;8.9944\nJandaíra;-11.5639\nĀnavatti;14.5645\nAndacollo;-30.2303\nMarreddipalli;17.7989\nMahād;36.6472\nAltamira do Maranhão;-4.1650\nLeicester;42.2400\nSide;36.7667\nAvelino Lopes;-10.1369\nFotsialanana;-16.9333\nBurgstädt;50.9167\nMondeville;49.1739\nNova Ubiratã;-12.9908\nBrotas de Macaúbas;-11.9989\nOlbernhau;50.6667\nPāraippatti;10.3144\nSan Carlos Centro;-31.7333\nHulshout;51.0833\nHoek van Holland;51.9811\nTruşeni;47.0667\nStruer;56.4856\nSampona;-25.1500\nLower Saucon;40.5881\nCanyon Lake;33.6885\nAmporoforo;-22.4667\nCachoeira de Minas;-22.3550\nMaryville;40.3428\nDayr ‘Aţīyah;34.0833\nDent;39.1915\nAndranomeva;-15.8000\nVilla La Angostura;-40.7625\nBaltāra;25.5116\nHaspra;44.4361\nSturgis;41.7991\nBorna;25.4373\nManambolosy;-16.0333\nBrunete;40.4000\nDonzdorf;48.6833\nCosteşti;46.8678\nOnna;26.4833\nBeiuş;46.6500\nCidade Gaúcha;-23.3800\nBevata;-23.2833\nGemona del Friuli;46.2833\nStropkov;49.2050\nAntakotako;-15.3167\nChornomorske;45.5019\nMagny-le-Hongre;48.8631\nAmāyan;26.3205\nObuse;36.6975\nZumaia;43.2972\nWaihee-Waiehu;20.9188\nElon;36.1016\nMahazony;-21.9833\nAmbinanindovoka;-21.9167\nAntsambahara;-14.5333\nSosnovka;56.2500\nSantana do Mundaú;-9.1678\nUrdorf;47.3867\nKishunpur;25.7947\nLa Esperanza;7.6392\nPūliguntā;12.4395\nPingtouchuanxiang;35.8763\nGrand Rapids;47.2380\nTân Sơn;21.2600\nYoung;-34.3000\nDek’emhāre;15.0667\nKalafotsy;-22.2833\nAcari;-6.4358\nTorrejón de la Calzada;40.2000\nMalente;54.1667\nLavaur;43.6989\nTravilah;39.0570\nCoshocton;40.2618\nAcarlar;37.8333\nPonte Serrada;-26.8719\nAntsoha;-15.7667\nMarovantaza;-15.3833\nFairview;37.6758\nRogoźno;52.7492\nShalushka;43.5261\nBrumunddal;60.8836\nParanatama;-8.9208\nIxtacomitán;17.4167\nSanta Teresinha (2);-7.3778\nSchkopau;51.3833\nPasrāha;25.3973\nForest;37.3728\nSchleusingen;50.5167\nSaraiya;24.8012\nStephanskirchen;47.8500\nBorovsk;55.2000\nLa Palma;5.3606\nIgarapé Grande;-4.5850\nPai Bigha;25.0511\nMethil;56.1844\nSansa;25.0291\nMorafeno;-19.0833\nSabalito;8.8828\nHakone;35.1894\nOp;25.2092\nCéu Azul;-25.1469\nBotuporã;-13.3819\nJhitkahiyā;26.7860\nVera Cruz;-22.2200\nGernsheim;49.7500\nGleisdorf;47.1039\nAmbodimangavolo;-17.5167\nJhundpura;26.3473\nKhāspur;25.6466\nMartinengo;45.5704\nMaroamalona;-15.3000\nZasechnoye;53.1142\nBowral;-34.4792\nWaldkirchen;48.7305\nKoronowo;53.3167\nAl Atārib;36.1389\nMossley;53.5147\nPélissanne;43.6314\nFranklin Lakes;41.0086\nPragadavaram;17.0167\nLyndon;38.2645\nRanomafana;-24.5667\nAmbodiampana;-16.8167\nOrlu;5.7837\nHulgūr;15.0833\nAnalamitsivalana;-20.3167\nGignac-la-Nerthe;43.3932\nVellipālaiyam;11.3314\nMarotandrano;-16.1667\nTaiyūr;12.7833\nMānrar;25.8895\nAmbohidranandriana;-19.8833\nFairview;42.0261\nNowra;-34.8808\nAbbigeri;15.5862\nPanaon;8.3667\nThe Hills;40.6561\nTripurāntakam;16.0007\nAntsahabe;-14.8000\nMarolinta;-25.1000\nAndrondrona Anava;-15.7500\nItzer;32.8833\nLocate di Triulzi;45.3500\nZhydachiv;49.3833\nSummerfield;36.1973\nWyomissing;40.3317\nMaroambihy;-14.4667\nVölkermarkt;46.6622\nBelvādi;15.7900\nMarinette;45.0871\nTsararano;-16.1667\nRüthen;51.4933\nMontechiarugolo;44.6934\nQal‘at an Nakhl;29.9000\nSpringdale;39.2909\nTsinjomitondraka;-15.6667\nCacaopera;13.7667\nJafra;31.5145\nGrezzana;45.5167\nBernex;46.1784\nAmbodimanary;-15.2167\nMulungu;-4.3058\nAntsakanalabe;-15.4167\nUgrinovci;44.8783\nRuisui;23.4333\nRacale;39.9667\nWarman;52.3219\nMunagapāka;17.6390\nMiandrarivo;-18.9167\nXudat;41.6281\nKarabash;55.4833\nAntanandava;-17.4833\nDrăgăneşti-Olt;44.1697\nKiskunmajsa;46.4923\nSoham;52.3338\nCelano;42.0864\nLyakhavichy;53.0333\nAnkavandra;-18.7722\nPunacha;12.9000\nDanau Kändimarg;33.5646\nPuente de Piedra;10.0298\nAdda-Douéni;-12.3000\nKnowle;52.3881\nBelāo;25.1476\nOak Ridge;41.0323\nTotowa;40.9039\nVoloina;-15.5667\nAkyaka;40.7444\nMemphis;27.5435\nMontecchio Emilia;44.6986\nKüçük Dalyan;36.2167\nKotharpettai;12.6780\nSan Felice sul Panaro;44.8393\nBananal;-22.6839\nKalanivāsal;10.0700\nWestview;25.8825\nTranomaro;-24.6000\nAltensteig;48.5864\nAngalakudūru Malepalle;16.2392\nBithauli;26.0219\nSoaserana;-21.1167\nVerkhniy Tagil;57.3833\nRodeio;-26.9228\nSângeorz-Băi;47.3700\n‘Utaybah;33.4861\nWiener Neudorf;48.0856\nTexcatepec;20.5833\nMa’ai;34.5937\nMajhariyā;26.8696\nHarīpur;26.2580\nSoyaló;16.9333\nHemāvati;14.0232\nRaceland;29.7282\nLa Tuque;48.0652\nNorwich;42.9833\nVadakādu;10.3418\nKondakomarla;14.0678\nBocaiúva do Sul;-25.2058\nTerryville;40.9093\nHighland City;27.9633\nGuéoul;15.4833\nShagonar;51.5500\nChinnamandem;13.9419\nHosahalli;15.3140\nChenango;42.1954\nKhāpdeh;26.2706\nDeokali;25.9068\nCanandaigua;42.8608\nGoulds;25.5614\nPhibun Mangsahan;15.2482\nNariār;25.8875\nMeaford;44.5800\nSankhavaram;15.0497\nEd Dâmoûr;33.7333\nWanderlândia;-6.8489\nSiswār;26.4292\nGülbaar;40.4800\nBommārbettu;13.3390\nKhān Bebīn;37.0372\nDiedorf;48.3500\nNallippālaiyam;11.2388\nEstanzuela;14.9979\nEnumulapalle;14.1446\nMonte San Pietro;44.4578\nSan Juanito de Escobedo;20.8000\nHöllviken;55.4167\nSüßen;48.6797\nMutukūru;16.3829\nAppleton;53.3508\nGeneral Salgado;-20.6478\nMarck;50.9481\nWronki;52.7000\nPalmares do Sul;-30.2578\nParaparaumu Beach;-40.8938\nEl Tarra;8.5756\nBonthe;7.5264\nAtlit;32.6872\nNörvenich;50.8000\nKattipūdi;17.2500\nLos Corrales de Buelna;43.2617\nPrachatice;49.0130\nBroomall;39.9688\nHaigerloch;48.3647\nKalyānpur;26.4802\nLomazzo;45.7000\nKeila;59.3086\nHagondange;49.2542\nAdjala-Tosorontio;44.1333\nRokytne;49.6897\nPhrai Bueng;14.7490\nCapitão de Campos;-4.4569\nCollegedale;35.0526\nDaulatpur;25.3682\nTarrá;8.0475\nCáchira;7.7500\nMedesano;44.7500\nMinamiise;34.3521\nGranby;41.9694\nBurlington;42.6744\nGardere;30.3582\nSaint-Laurent-de-la-Salanque;42.7736\nSidi Namane;36.7581\nNewcastle;35.2401\nWest Caldwell;40.8488\nDighāwāni;22.2061\nBog’ot;41.3500\nYeşilli;37.3406\nAylesford;51.3033\nWooburn;51.5810\nSaray;40.5322\nBela;26.4989\nKaraağaç;41.3000\nMatsuda-sōryō;35.3482\nPunitaqui;-30.9000\nPerumpāndi;10.9808\nLa Palma del Condado;37.3842\nSemri;22.6833\nNeuhof;50.4333\nDesborough;52.4398\nWest Point;41.1220\nMinamisanriku;38.6806\nChambly;49.1667\nNew Albany;40.0809\nQuimilí;-27.6333\nLa Puebla de Cazalla;37.2222\nAttleborough;52.5183\nSirugudi;10.2627\nHurzuf;44.5528\nNeman;55.0333\nSalò;45.6000\nTömük;36.6667\nCanelli;44.7208\nDuas Barras;-22.0508\nCristuru Secuiesc;46.2917\nLinganore;39.4127\nShamsābād;32.2983\nShahar Telpa;25.1330\nPont-Saint-Esprit;44.2564\nCarmo da Mata;-20.5578\nErstein;48.4219\nCanton;32.5975\nBischofswerda;51.1275\nInácio Martins;-25.5708\nErtvelde;51.1783\nKetugrām;23.6957\nMetsamor;40.1428\nVelappādi;12.6499\nZwettl;48.6033\nBad Iburg;52.1592\nKoppāka;16.7494\nBoizenburg;53.3667\nGerzat;45.8258\nWijnegem;51.2333\nJerônimo Monteiro;-20.7889\nGarmeh;36.9869\nFox Lake;42.4239\nMandrem;15.6581\nCerro Corá;-6.0458\nBedford Heights;41.4041\nHamilton Township;44.0540\nBurgkirchen an der Alz;48.1667\nRājiāna;30.6923\nPatlūr;11.6000\nBassian;30.6559\nLagoa do Mato;-6.0469\nKandry;54.5667\nKanur;17.0318\nSeridó;-6.9339\nVillers-la-Ville;50.5833\nRāmgarha;25.7983\nGuantingzhan;40.2492\nSanjiangkou;24.7579\nGohi Bishunpur;25.9275\nCadelbosco di Sopra;44.7667\nMae Wang;18.6567\nVilla Nougues;-26.8578\nBarberino di Mugello;44.0014\nGrand Haven;43.0553\nGangaur;26.5666\nIlvesheim;49.4725\nKombai;10.6143\nMassa Lombarda;44.4500\nKaufering;48.0833\nKhajuri;26.0630\nResende Costa;-20.9219\nKarath;25.2010\nFeyzin;45.6728\nStar;43.7026\nCacimbinhas;-9.4000\nBargas;39.9400\nCasaluce;41.0000\nAdohoun;6.6333\nAlto Paraguai;-14.5139\nMontignoso;44.0167\nFiguig;32.1167\nNanjundāpuram;11.0857\nMadhuban Bediban;26.5062\nLincolnton;35.4748\nVillers-Cotterêts;49.2531\nMuscoy;34.1552\nEasttown;40.0281\nKowary;50.7917\nPau Brasil;-15.4639\nBueno Brandão;-22.4408\nSan Gaspar Ixchil;15.3833\nPānrepatti;25.5537\nChencha;6.2500\nKisújszállás;47.2169\nBogalusa;30.7812\nDelhi;37.4306\nGok;27.1065\nBerkley;39.8045\nCold Springs;39.6927\nChupaca;-12.0620\nGudlavalleru;16.3500\nKamen’-Rybolov;44.7667\nNyakosoba;-29.5047\nItarana;-19.8739\nFelton;51.5100\nCassá de la Selva;41.8893\nBobrovytsia;50.7424\nFortuna;38.1789\nNarmeta;17.8861\nMalibu;34.0370\nBobrynets;48.0578\nLangenzenn;49.4944\nShevington;53.5720\nJaladurgam;15.2840\nEski Yakkabog‘;38.9314\nJordbro;59.1500\nBarano d’Ischia;40.7167\nKurdi;16.0511\nPetrovka;42.8389\nChatham;40.7274\nHozin;6.5333\nDhanur Kalyānwādi;17.7700\nBodippatti;10.5642\nLe Crès;43.6472\nBüyükyoncalı;41.3833\nKhlung;12.4525\nRiverdale;41.6441\nWorth;41.6877\nYungay;-37.1194\nPaittūr;11.5356\nEnez;40.7333\nKivistö;60.3236\nCrestwood;41.6454\nGajiginhālu;15.6969\nBraine-le-Château;50.6833\nSão Bento do Sapucaí;-22.6889\nSan Maurizio Canavese;45.2171\nMadathapatti;9.1321\nRiedlingen;48.1553\nBorgloon;50.8022\nNova Vodolaha;49.7197\nMeßstetten;48.1806\nWaterloo;38.3403\nRatnahalli;12.1922\nSetubinha;-17.6000\nHānsa;26.0911\nSagarejo;41.7333\nSultānpur;29.1600\nSuhiya;25.6482\nMount Sinai;40.9372\nMount Kisco;41.2016\nYacopí;5.4667\nTettuppatti;10.3979\nKulriān;29.7994\nRamacca;37.3833\nKenzingen;48.1917\nDavos;46.8000\nDourdan;48.5289\nAsahi;36.9462\nGovernador Lindenberg;-19.2519\nCiudad Insurgentes;25.2617\nBhawānandpur;25.5400\nMunnūru;12.9000\nPua;19.1799\nCori;41.6445\nNivala;63.9250\nBofete;-23.1022\nTecoh;20.7419\nAşağı Ayıblı;40.9368\nCourt-Saint-Étienne;50.6333\nGrandview;46.2443\nYoko;6.7000\nJānpur;25.2958\nItapebi;-15.9508\nDaganzo de Arriba;40.5433\nVikrutamāla;13.6206\nSan Roque;-28.5667\nMesyagutovo;55.5322\nLágos;41.0667\nShāhpur Chaumukhi;25.7683\nHumlebæk;55.9611\nAmbohidanerana;-19.1833\nKotūr;17.1447\nCelina;40.5550\nRāmāreddi;18.4110\nGudibanda;13.9753\nEstiva;-22.4628\nPithaura;26.2620\nTekkāttūr;10.2997\nKūcheşfahān;37.2783\nYazoo City;32.8619\nHaysville;37.5648\nVashon;47.4122\nStenungsund;58.0833\nPlano;41.6757\nLe Locle;47.0532\nErlenbach am Main;49.8039\nScartho;53.5399\nKatra;32.9917\nMogotes;6.4833\nRicaurte;4.2792\nAlto Rio Doce;-21.0258\nArapgir;39.0333\nDamascus;45.4233\nSérékali;9.9186\nKomarolu;15.2667\nValaparla;15.9167\nLollar;50.6497\nAmioûn;34.3000\nLincoln Park;40.9239\nHariāna;31.6351\nSt. Clements;50.2689\nAmbato;-18.6000\nTallimarjon Shahri;38.2967\nTokkavādi;11.3702\nKhorol;44.4289\nNovgorodskoye;48.3328\nTaimali;22.6167\nBlackhawk;37.8159\nVilliersdorp;-33.9833\nYedrāmi;16.8667\nHambühren;52.6333\nWaynesboro;39.7524\nSaint-Amable;45.6500\nWeyburn;49.6611\nLauterach;47.4772\nFife;47.2329\nStrasshof an der Nordbahn;48.3194\nSorbhog;26.5000\nTriangle;38.5483\nSam Ko;14.6013\nItri;41.2833\nKarayılan;36.7167\nKrzeszowice;50.1333\nParaúna;-16.9478\nTacima;-6.4878\nRipoll;42.2011\nKeza;-2.7540\nGhattu;13.6602\nSan Pablo Huixtepec;16.8167\nFredericksburg;30.2660\nFreeport;28.9453\nDoi Saket;18.8667\nGairtganj;23.4102\nWorsley;53.5093\nBeachwood;39.9286\nGuaitarilla;1.1333\nAfonso Bezerra;-5.4978\nFürth;49.6502\nSwanage;50.6080\nGarhi;24.7904\nKara-Tash;40.2167\nManville;40.5420\nKharika;25.7173\nGrigiškės;54.6667\nMios;44.6050\nScherpenzeel;52.0833\nSarmiento;-45.6000\nShāmpur;23.4032\nTroy;38.7268\nPocono;41.0612\nKākhandiki;16.6010\nApía;5.1000\nSan Juan;17.6834\nCantillana;37.6000\nKey Largo;25.1224\nCedro;-7.7219\nSuyo;16.9839\nTosagua;-0.7800\nReguengos de Monsaraz;38.4167\nRaeren;50.6833\nNgorongoro;-3.2496\nBurkburnett;34.0746\nVembūr;10.5893\nDasai;22.7200\nChesterfield;53.2358\nLaranja da Terra;-19.8989\nArāvelli;18.7190\nAmaturá;-3.3639\nManevychi;51.2925\nNijoní;39.9667\nSharg‘un;38.4600\nIcononzo;4.1833\nKadanganeri;8.9200\nØrsta;62.2003\nChuhr Chak;30.7775\nPencoed;51.5228\nDevi Hosūr;14.7858\nNawāda;25.5037\nBorshchiv;48.8024\nGangāpur;25.8565\nCelldömölk;47.2557\nCapena;42.1403\nBurgos;18.5114\nKanhai;25.9761\nSouth Union;39.8705\nSt. Albans;38.3769\nHrebinka;50.1180\nKitee;62.1000\nPuduppatti;9.6171\nSão Tomé;-5.9728\nBestwig;51.3667\nPrimeiro de Maio;-22.8508\nKuršėnai;55.9833\nAkbarpur;24.6281\nAgouna;7.5667\nYampil;48.2450\nPattīswaram;10.9253\nWeingarten;49.0514\nMaur;47.3417\nGaohucun;28.3368\nPiraúba;-21.2758\nBaryshivka;50.3703\nUchti;25.9197\nLaćarak;45.0000\nSouth Dundas;44.9167\nSanson;9.2833\nEmiliano Zapata;16.5000\nYeghvard;40.3217\nChapeltique;13.6333\nBārah;35.6830\nNova Floresta;-6.4550\nWantage;41.2431\nXiaozui;35.6912\nRincão;-21.5869\nFiuggi;41.8000\nPipra;26.3460\nVolda;62.1468\nKaimūh;33.7197\nMunhall;40.3935\nDiavatá;40.6883\nLéognan;44.7286\nItapitanga;-14.4228\nJaipur;23.4313\nOppatavādi;12.5690\nHombal;15.5164\nMallan;30.4015\nTivim;15.6000\nAurahi;25.8263\nDibrāghani;25.8261\nOusseltia;35.8400\nEast Cocalico;40.2242\nKhrystynivka;48.8333\nSonoma;38.2902\nEuxton;53.6620\nAsālem;37.7306\nBraunsbedra;51.2833\nIsnapuram;17.5443\nPāikpāra;24.3149\nWang Sombun;13.3515\nRandazzo;37.8833\nNurmo;62.8278\nSaint-Gély-du-Fesc;43.6922\nChandera;25.0829\nTamiang Layang;-2.1160\nOgano;36.0171\nDasaut;25.8997\nAbram;53.5080\nTurmānīn;36.2333\nRush;53.5220\nAl Karak;32.6872\nKurman;45.4978\nSimarbani;26.1953\nTököl;47.3203\nLe Taillan-Médoc;44.9044\nImi Mokorn;30.1675\nJhonkar;23.2361\nWald-Michelbach;49.5724\nMontignies-le-Tilleul;50.3833\nMangrāwān;25.0929\nKāmepalle;16.5191\nHuétor-Tájar;37.1947\nArarendá;-4.7528\nSoquel;36.9978\nFoum Jam’a;31.9600\nJuripiranga;-7.3728\nLehman;41.1518\nFontaine-lès-Dijon;47.3433\nShannon;52.7137\nAntenetibe;-18.7833\nWittelsheim;47.8053\nTiszaföldvár;46.9739\nDáli;35.0211\nNarkatpalli;17.2030\nVilleneuve-lès-Maguelone;43.5322\nHochdorf;47.1664\nUzda;53.4661\nSanto Domingo;6.4708\nGounarou;10.8667\nSāngi;26.3237\nKolno;53.4106\nMontgomery;39.2496\nDouar Bouchfaa;34.1014\nTarabha;20.7325\nPoiana Mare;43.9333\nTiszafüred;47.6167\nƏliabad;41.4783\nGuaraci;-20.4986\nSisai;23.1794\nLa Trinité;43.7408\nBan Ko;13.6486\nRaitar;25.0577\nVan Wert;40.8651\nBaretha;25.5258\nZuchwil;47.2056\nGharyāla;31.2294\nTotolapan;18.9869\nMadison Heights;37.4487\nCastleton;53.5907\nDumri;26.8648\nTorpa;22.9361\nMākhar;25.7693\nNkokonjeru;0.2394\nMorro Bay;35.3682\nJoutseno;61.1230\nAntanandehibe;-19.6833\nBāsht;30.3611\nOloron-Sainte-Marie;43.1942\nPompton Plains;40.9679\nMéry-sur-Oise;49.0636\nItatuba;-7.3750\nDemmin;53.9050\nBabhantoli;26.2168\nItacurubí de la Cordillera;-25.4500\nNāgambhotlapālem;15.6804\nNowa Dęba;50.4333\nHarpur Bhindi;25.7746\nJaguari;-29.4969\nSwan Hill;-35.3333\nBorim;15.3604\nHonwād;16.8100\nBleicherode;51.4167\nChoachí;4.5297\nPlacerville;38.7308\nAlcoa;35.8076\nNāhargarh;24.1692\nYeşilköy;36.8667\nLa Londe-les-Maures;43.1381\nAstorga;42.4589\nKings Mountain;35.2349\nVigonovo;45.3852\nTakon;6.6500\nQamīnis;31.6572\nTanant;31.8667\nĀnandpur;25.6192\nParmānpur;26.1457\nPasupatikovil;10.8893\nJoaquim Távora;-23.4989\nUrlaţi;44.9911\nAtchison;39.5625\nŌtsuchi;39.3582\nBalderton;53.0549\nGateway;26.5793\nLa Farlède;43.1678\nYuzhno-Sukhokumsk;44.6667\nCentenário do Sul;-22.8208\nSabaneta de Yásica;19.6667\nGalena Park;29.7452\nBirkenfeld;48.8697\nRâs el Metn;33.8500\nWellington;40.7000\nAl Musayfirah;32.6322\nKauniainen;60.2167\nKāmthi;14.5000\nAlto Parnaíba;-9.1108\nGuthrie;35.8424\nBelsara;26.0152\nKelilalina;-21.2833\nBhargaon;26.0750\nDumra;25.5907\nLerici;44.0764\nFelsberg;51.1333\nKūhbanān;31.4103\nTisma;12.0831\nCurimatá;-10.0358\nArcola;44.1167\nKopparam;16.0841\nCoité do Nóia;-9.6319\nIwai;35.5833\nPintadas;-11.8128\nGoianápolis;-16.5108\nLakkireddipalle;14.1667\nKöngen;48.6819\nLehigh;40.7678\nNizza Monferrato;44.7747\nBāsdeopur;25.3909\nPeriyanegamam;10.7432\nNgaputaw;16.5378\nCaernarfon;53.1400\nTaouloukoult;31.2167\nAndovoranto;-18.9544\nL’Île-Perrot;45.3833\nNotre-Dame-de-l'Île-Perrot;45.3667\nBan Lueak;13.7065\nCampo Largo;-26.8000\nElattūr;11.3866\nMomanpet;17.5175\nSūlagiri;12.6645\nAntsahadinta;-19.0167\nTangerhütte;52.4333\nHasanpura;26.0751\nKhāsbalanda;22.5881\nWilliams Lake;52.1294\nNonea;26.9746\nBischofshofen;47.4172\nEstaimpuis;50.6756\nSanta Bárbara;26.8133\nTelkapalli;16.4500\nArbaa Sahel;29.5993\nSanta Catarina Ayotzingo;19.2647\nBöhl-Iggelheim;49.3714\nNadezhda;45.0448\nVanzago;45.5268\nSurazh;53.0167\nSvedala;55.5000\nSeberi;-27.4778\nAigle;46.3167\nQal‘eh Tall;31.6325\nSão Luís do Paraitinga;-23.2219\nAlberobello;40.7833\nShŭrobod;37.8403\nRichmond Heights;41.5589\nOyim;40.8242\nCoriano;43.9667\nKīramangalam;10.2859\nLeninskoe;42.9806\nEriyodu;10.5172\nOpglabbeek;51.0500\nBrandon;43.5928\nDarling;-33.3833\nChewara;25.0756\nItabirinha de Mantena;-18.5658\nNorth Branch;45.5137\nMount Evelyn;-37.7830\nLamhadi;32.3000\nKaithāhi;26.3488\nOrthez;43.4881\nSouthwater;51.0238\nElliot Lake;46.3833\nLichtenau;51.6000\nPresidente Vargas;-3.4069\nSarmera;25.2564\nPraskoveya;44.7444\nSāīnkhera;22.9589\nDarb-e Behesht;29.2417\nVillahermosa;5.0000\nRāmpur Parhat;25.5916\nBenalla;-36.5519\nMonmouth;44.8505\nTamanar;31.0000\nDharir;22.3337\nBourg-de-Péage;45.0378\nTarboro;35.9046\nPleasant View;41.3249\nČáslav;49.9117\nYādavolu;17.0619\nSão Brás de Alportel;37.1500\nFô-Bouré;10.1167\nBranquinha;-9.2458\nLohārda;22.5918\nMurtosa;40.7333\nSenjān;34.0497\nAnkarabato;-16.3500\nJackson;43.4720\nIchnia;50.8500\nDießen am Ammersee;47.9500\nZavitinsk;50.1281\nLatteri;12.9712\nClute;29.0256\nMangalpur Gudaria;26.6513\nSan Ricardo;9.9167\nUbalá;4.7439\nHarsola;22.5694\nSivrice;38.4467\nLālmunia Munhāra;26.5741\nPānchi;25.1123\nAbadou;31.5797\nMiāni;31.7092\nMudgee;-32.6125\nBolivar;37.6059\nSukhsena;25.6881\nPoirino;44.9208\nKatigang;25.4157\nParauli;26.2227\nKingsteignton;50.5458\nKiełczów;51.1406\nSidi Brahim;35.2606\nRocafuerte;-0.9200\nSütçüler;37.4944\nBondues;50.7017\nGöynücek;40.3833\nGeneseo;42.8038\nSan Rafael Obrajuelo;13.5000\nNahulingo;13.7000\nPonnāda;18.2536\nBakhariā;26.7666\nVilla Purificación;19.7858\nUrubici;-28.0150\nLake Morton-Berrydale;47.3325\nBedum;53.3000\nCorning;42.1470\nHarpur;25.6537\nTājpur;25.9022\nNakayama;38.3331\nKanteru;16.3906\nSalemi;37.8167\nNorth Logan;41.7759\nVeppattūr;11.0154\nRombas;49.2494\nMantasoa;-19.0167\nLittle Canada;45.0244\nChavusy;53.8075\nSebt Ait Ikkou;33.6690\nMáncora;-4.1056\nAngwāli;23.7317\nBrejolândia;-12.4828\nTárnok;47.3597\nBellefontaine Neighbors;38.7529\nMaynard;42.4264\nWendeburg;52.3167\nKollankulam;8.7964\nTaufkirchen;48.3439\nSidi Bousber;34.5667\nDeForest;43.2301\nBāgalūr;12.8333\nAhogbeya;7.0333\nSilea;45.6547\nCantley;45.5667\nMehdīpur;25.3902\nZapotitlán;14.1674\nTorre Santa Susanna;40.4667\nGravatal;-28.3308\nJankampet;18.7067\nAntsaravibe;-13.0500\nCollege;40.8144\nDinagat;9.9561\nVilla Jaragua;18.4800\nPeralillo;-34.4875\nInkerman;44.6142\nNewburn;54.9830\nHajeb el Aïoun;35.3900\nUrcos;-13.6861\nNova Olinda;-7.6319\nNakonde;-9.3272\nJucati;-8.7058\nTrovagunta;15.5509\nRussellville;34.5055\nNāgasamudram;15.0556\nKodūru;13.8692\nTafalla;42.5132\nBadru Khān;30.2523\nDombāchcheri;9.9604\nHämeenkyrö;61.6333\nChalco;41.1817\nMilton;44.6429\nAgdz;30.6978\nCowra;-33.8183\nPirpirituba;-6.7800\nBaetov;41.2100\nDuga Resa;45.4472\nLohariandava;-18.7833\nNeuenhaus;52.5000\nHad Laaounate;32.6128\nAkim Swedru;5.8940\nDehqonobod;40.5314\nJhabrera;29.8091\nEl Paraíso;14.0833\nAnoviara;-14.7333\nBālia;24.2433\nWepangandla;15.9359\nDuque Bacelar;-4.1558\nItaueira;-7.6028\nLake Barcroft;38.8514\nAver-o-Mar;41.4039\nFondettes;47.4042\nBetsiaka;-13.1500\nHilter;52.1357\nOrşova;44.7253\nPeschiera del Garda;45.4386\nMerchweiler;49.3603\nSzigetvár;46.0475\nJibou;47.2667\nTogamalai;10.7251\nMarkt Indersdorf;48.3667\nVienna;39.3240\nAmtar;35.2385\nAlmoloya;19.7000\nGangania;25.2395\nAtessa;42.0667\nKilibo;8.5717\nBurgau;48.4322\nPhulhara;25.8937\nGhusiya;25.1832\nRecco;44.3667\nPeñarroya-Pueblonuevo;38.3000\nCanelinha;-27.2650\nChuqung;33.3743\nKolárovo;47.9169\nArdrossan;55.6432\nRaymond;43.0322\nLonkly;7.1333\nHetane;32.8403\nZawyat Ahançal;31.8325\nMonroe;42.6030\nRoccapiemonte;40.7617\nSanta Margarita de Mombúy;41.5756\nRupāna;30.4070\nKiến Giang;17.2250\nNovotroitske;46.3544\nRuppichteroth;50.8456\nLyons;41.8119\nCastelli Calepio;45.6333\nPaimio;60.4500\nNelson;49.5000\nKnin;44.0414\nBel Air;39.5348\nWeilheim an der Teck;48.6150\nTubará;10.8667\nRincon;32.2947\nRibeirão Claro;-23.1939\nCunha Porã;-26.8939\nJandiāla;31.2157\nMel Seval;8.6722\nPeddāpuram;18.0289\nQuerfurt;51.3833\nPelāgor;25.5992\nDevanakonda;15.5333\nFaxinal dos Guedes;-26.8528\nRingkøbing;56.0897\nBovingdon;51.7231\nScaggsville;39.1416\nKuiyibagecun;38.0836\nPerumuchchi;13.0560\nBaran;54.4833\nCastrolibero;39.3167\nTokigawa;36.0086\nFlămânzi;47.5500\nPriol;15.4167\nCajobi;-20.8800\nVysokovsk;56.3167\nCorocoro;-17.1667\nLas Matas de Santa Cruz;19.6700\nLagunia Raghukanth;25.8195\nMara Rosa;-14.0169\nSosenskiy;54.0500\nİnebolu;41.9747\nShirako;35.4543\nEscaudain;50.3344\nZdzieszowice;50.4192\nMorbach;49.8167\nKrálŭv Dvŭr;49.9499\nGudofredo Viana;-1.4028\nFilipstad;59.7167\nRettanai;12.1953\nCsömör;47.5500\nCastelletto sopra Ticino;45.7167\nMarum;53.1500\nRatnagiri;13.8111\nMāchalpur;24.1277\nAltötting;48.2267\nIronton;38.5323\nDifficult Run;38.9016\nTrets;43.4469\nVittuone;45.4833\nConselve;45.2333\nPakka Kalān;30.0323\nScotchtown;41.4765\nCamden;33.5672\nOţelu Roşu;45.5186\nTadas;15.1333\nMouans-Sartoux;43.6200\nAdigappādi;12.1459\nAbay;43.2092\nKottaipatti;10.1533\nVidalia;32.2125\nPotavaram;17.0194\nMurata;38.1185\nHussepur;26.1801\nFenglin;23.7500\nSint-Lievens-Houtem;50.9167\nGrevesmühlen;53.8667\nSpa;50.4925\nArimalam;10.2550\nUrrugne;43.3622\nKhovaling;38.3386\nCortalim;15.3978\nPine Hill;39.7879\nAïn Zora;34.6600\nHarlākhi;26.6353\nKüçükkuyu;39.5500\nMadhura;25.5418\nChausa;25.5149\nMadanpur;24.6554\nBobenheim-Roxheim;49.5839\nPasil;17.3894\nVairampatti;10.5515\nLaheji;26.0957\nIndalvai;18.5403\nLambton Shores;43.1833\nSantiago Suchilquitongo;17.2500\nAl Ghizlānīyah;33.3986\nPola de Lena;43.1583\nSugarmill Woods;28.7299\nIsola Vicentina;45.6333\nIngeniero White;-38.7667\nMalvern;34.3734\nTarawān;24.7295\nCanteras;37.6122\nBegijnendijk;51.0186\nSouq Sebt Says;32.7773\nToundout;31.2667\nMokrisset;34.9100\nHöchberg;49.7831\nForest Acres;34.0323\nParczew;51.6333\nMaevka;42.9250\nMussomeli;37.5794\nLeninaul;43.0878\nSālehpur;25.6119\nRiverton;43.0421\nMotibennur;14.7150\nVouzela;40.7167\nKrishnamsettipalle;15.3695\nGölpazarı;40.2847\nCandelaria Loxicha;15.9262\nOzieri;40.5849\nBariariya Tola Rājpur;26.4567\nEkangar Sarai;25.2234\nMonnickendam;52.4667\nChandankiāri;23.5781\nPārtibanūr;9.5855\nJablanica;43.6583\nMold;53.1660\nNuriston;38.4892\nHolmen;43.9706\nPrineville;44.2985\nDoraville;33.9073\nTourza;29.4778\nKimpese;-5.5631\nVadakku Ariyanāyakipuram;8.7208\nBiskupiec;53.8667\nAerzen;52.0496\nPeschanokopskoye;46.1958\nKamikawa;35.0642\nKhilok;51.3500\nSchalksmühle;51.2403\nGommern;52.0667\nTarazona de Aragón;41.9044\nMonte San Juan;13.7667\nLudlow;52.3680\nMalaya Vishera;58.8500\nSatwār;26.2163\nMeerhout;51.1333\nKambaliyampatti;10.3671\nPāra;23.5142\nSweetwater;32.4692\nCajapió;-2.9667\nBibbiano;44.6667\nSadovoye;42.8528\nYacuanquer;1.1167\nPinto;-36.7000\nHartford;43.6644\nKonkavāripalle;13.7125\nAït Hani;31.7786\nPulpí;37.4019\nGhosrāwān;25.0910\nAlīpura;25.1753\nTnine Sidi Lyamani;35.3700\nMildenhall;52.3446\nHanson;42.0558\nSelma;29.5866\nSanta Teresinha;-12.7719\nGarden City;33.5926\nAmbohitromby;-18.4333\nAmbolotarakely;-18.2667\nRokunohe;40.6095\nWustermark;52.5497\nJurbise;50.5333\nJiménez;10.1797\nPlombières;50.7333\nImst;47.2394\nPia;42.7447\nWalker Mill;38.8758\nRignano Flaminio;42.2000\nSongo;-7.3496\nLa Ferté-sous-Jouarre;48.9492\nExcelsior Springs;39.3390\nLavínia;-21.1683\nEvander;-26.4719\nBeverly Hills;42.5220\nKanyāna;12.9000\nArmanāz;36.0833\nVillanueva de Arosa;42.5628\nBoiling Springs;35.0450\nWahlstedt;53.9500\nPatsanda;24.8580\nBorgampād;17.6500\nStrehaia;44.6222\nSuganwān;25.1176\nAtlapadu;16.7833\nKorosavāda;18.7256\nLejanías;3.5268\nČelić;44.7167\nNanticoke;41.2005\nPotunūru;16.7442\nOuando;6.5542\nMfou;3.9600\nKursaha;25.5588\nModisi;0.4517\nBan Ueam;18.4246\nAscope;-7.7138\nTiztoutine;34.9833\nBasla;33.3833\nMillington;35.3350\nNossen;51.0500\nBangshang;32.2575\nBarcs;45.9601\nScottdale;33.7950\nVejen;55.4774\nDumri;25.8605\nCastelnovo ne’ Monti;44.4333\nAgramonte;22.6761\nMohanpur;25.5507\nSawla;9.2833\nKhagaur;25.1744\nSão Tiago;-20.9128\nBom Jesus da Serra;-14.3719\nDoorn;52.0333\nTimrå;62.4869\nAlcora;40.0667\nVadapalanji;9.9266\nWestphalia;38.8356\nEl Álamo;40.2306\nBen N’Choud;36.8624\nWhitnash;52.2680\nMontividiu;-17.4439\nNaganuma;43.0102\nMādhopur;26.7474\nValpoy;15.5324\nWest Hanover;40.3635\nRāmpur;25.1826\nAmbahy;-20.7667\nForestville;38.8518\nAsārhi;25.2892\nLa Bañeza;42.2975\nRaymondville;26.4759\nEugenópolis;-21.0989\nSirsa;26.2667\nLepākshi;13.8032\nDallgow-Döberitz;52.5331\nPetmanhalli;17.7688\nRiver Grove;41.9243\nMadhopur;26.7333\nHirehadagalli;14.9267\nSanta Maria de Itabira;-19.4489\nUsmat Shaharchasi;39.7386\nBan Bang Phlap;13.9241\nUmarizal;-5.9908\nLowell;41.2917\nDouglass;40.3438\nPebble Creek;28.1583\nCottage Grove;43.7960\nRasebetsane;-29.8992\nTilougguit;32.0333\nKujri;26.2392\nBacliff;29.5085\nNanzhou;22.4789\nHōki;35.3852\nKhesht;29.5636\nBorjomi;41.8389\nKadama;1.0167\nColeford;51.7910\nNavabad;38.5278\nChitagá;7.1333\nRialma;-15.3150\nBorger;52.9236\nAugustdorf;51.9094\nRebola;3.7192\nSanta Teresa di Riva;37.9400\nLuanco;43.6100\nGonghaur;26.4346\nVermilion;41.4103\nKendall Park;40.4135\nMarotaolana;-14.0167\nSkilloúnta;37.6167\nIckenham;51.5580\nPazaryeri;40.0000\nDouar Mzoura;34.3167\nSerra do Salitre;-19.1108\nRosario;-34.3139\nDombasle-sur-Meurthe;48.6250\nKharahara;24.9142\nSujāpur;25.4815\nSinganamane;13.7167\nBelgrade;45.7789\nMallapuram;9.8280\nJesenice;49.9683\nKandulāpuram;15.5976\nMahīnāthpur;26.6554\nHaripura;34.0410\nTalugai;11.3752\nAltenholz;54.4000\nMontalegre;41.8231\nFrontera;-31.4278\nBad Orb;50.2167\nVillacarrillo;38.1000\nParicônia;-9.2539\nVeitshöchheim;49.8328\nBordj Okhriss;36.0833\nRupahi;26.4110\nBluffton;40.7424\nPartanna;37.7289\nZhatay;62.1641\nNovodnistrovsk;48.5778\nCampi Salentina;40.4000\nMount Airy;36.5083\nSumner;47.2189\nTorotoro;-18.1342\nKamifurano;43.4556\nHerīs;38.2467\nBlandford Forum;50.8560\nBan Thung Khao Phuang;19.5342\nArceburgo;-21.3639\nGalimuyod;17.1833\nLa Virgen;10.4312\nArgelès-sur-Mer;42.5461\nTrescore Balneario;45.7000\nCutro;39.0328\nZmeinogorsk;51.1667\nReiskirchen;50.6000\nBad Lauterberg;51.6317\nKilkunda;11.2569\nMagalia;39.8228\nTepperumālnallūr;10.9694\nLitomyšl;49.8719\nMartin;36.3385\nArraias;-12.9308\nAltenberge;52.0458\nKoila Belwā;26.3753\nMiribel;45.8244\nDona Inês;-6.6178\nKihō;33.7333\nKibichūō;34.8634\nWilkau-Haßlau;50.6667\nMadhurāpur;25.9456\nKarghar;25.1267\nSortland;68.6982\nAndonabe Atsimo;-19.8833\nSan Vicente de Castellet;41.6655\nMamdāpur;16.1400\nIbiassucê;-14.2589\nLighthouse Point;26.2785\nNovi Banovci;44.9500\nConcordia Sagittaria;45.7667\nPerket;18.7942\nPeravali;15.2861\nArlesheim;47.4922\nAvelgem;50.7753\nBagnara Calabra;38.2833\nAngostura;6.8667\nSotkamo;64.1333\nAlachua;29.7779\nMapleton;43.7358\nBaisa;25.3552\nDnestrovsc;46.6167\nBrahmānandapuram;16.9583\nMāldah;25.1740\nSoyaux;45.6403\nBīrpur Bārāpatti Pindraun;26.5475\nSidi Abdallah;32.5783\nFayzobod;38.5500\nShumanay;42.6333\nSangão;-28.6378\nReading;39.2242\nAppenweier;48.5397\nBāgh-e Bahādorān;32.3772\nLake Hopatcong;40.9599\nMaxaranguape;-5.5158\nWhitwick;52.7403\nAcushnet;41.7138\nEl Chol;14.9611\nTonse East;13.3963\nMatias Olímpio;-3.7158\nRhosllanerchrugog;53.0110\nCongonhal;-22.1528\nAlbert;50.0019\nGarešnica;45.5667\nHöchst im Odenwald;49.7992\nDandkhora;25.5729\nKhurmi;39.5167\nBarāgaon;24.5682\nNānan;25.0905\nGreentree;39.8989\nMaduvanalli;12.1500\nPérols;43.5650\nJessup;39.1488\nRegidor;8.6667\nVaals;50.7667\nSan Giorgio del Sannio;41.0667\nPrakhon Chai;14.6092\nSādiqpur Maraul;25.9966\nValdobbiadene;45.9000\nParavāda;17.6283\nJettihalli;12.0800\nDinnington;53.3667\nSinaia;45.3500\nSiruvalūr;11.3600\nBolekhiv;49.0669\nSusuz;40.7800\nGaunivāripalle;13.9756\nSchwaikheim;48.8714\nPhai Sali;15.6000\nPilar;9.8639\nPleasanton;28.9642\nVirginópolis;-18.8228\nKennett;36.2403\nBithlo;28.5644\nLikiškiai;54.3950\nDar El Kebdani;35.1203\nAltofonte;38.0500\nKirlampūdi;17.1919\nNajrīj;30.9667\nOld Saybrook;41.3017\nMahārājapuram;9.6588\nBarnāon;25.4809\nKirchzarten;47.9667\nLāpangā;23.6333\nNatuba;-7.6408\nMaria Enzersdorf;48.1000\nSaks;33.7118\nNova Europa;-21.7783\nInungūr;10.8507\nVaddādi;17.8474\nBan Dan Na Kham;17.7167\nThilogne;15.9239\nBom Repouso;-22.4708\nPort Wentworth;32.1951\nAyntap;40.0986\nPalestina;1.7500\nJefferson;29.9609\nFuveau;43.4522\nValley;32.8088\nFatehābād;31.3811\nLahstedt;52.2500\nSan Vendemiano;45.8914\nTopoloveni;44.8069\nNewberry;34.2813\nBad Wildbad;48.7503\nFlorestópolis;-22.8628\nPraia do Carvoeiro;37.1200\nVillamarchante;39.5678\nSidi Boushab;30.0740\nOneida;43.0769\nIramaia;-13.2858\nHuittinen;61.1750\nIvangorod;59.3667\nLanghirano;44.6167\nEspañola;36.0044\nLyngdal;58.1333\nRāparla;15.9569\nKannamangalam;12.7499\nLyuboml’;51.2158\nMarlton;39.9014\nOlëkminsk;60.3667\nBērikai;12.8056\nHeum;59.0955\nKarahallı;38.3167\nBlackwells Mills;40.4773\nChākand;24.8907\nSteinfeld;52.6000\nWildberg;48.6239\nBellmead;31.6026\nPitkyaranta;61.5750\nRishivandiyam;11.8170\nWittenbach;47.4667\nForestville;39.0711\nNorth Bellport;40.7868\nDouar Echbanat;34.2167\nCosteşti;44.6697\nEmsworth;50.8490\nRāmpur Khajuriyā;26.3923\nGossau;47.3081\nKönigsbach-Stein;48.9664\nCorzuela;-26.9333\nEtropole;42.8333\nKarkamış;36.8340\nColonia Nicolich;-34.8167\nNanfang;23.3568\nGeorgian Bluffs;44.6500\nBajwāra;31.5150\nSamalpur;25.1961\nLuís Alves;-26.7208\nSomireddipalle;14.8365\nPintuyan;9.9500\nAlcaudete;37.5833\nKlipphausen;51.0833\nAdyār;12.8756\nJomasho‘y;40.8633\nPuerto Santander;8.3636\nJaltocan;21.1333\nKangning;38.0176\nMinobu;35.4675\nHachīrūd;36.6864\nOlevsk;51.2278\nAradeo;40.1333\nPembroke Dock;51.6933\nAltusried;47.8000\nAulendorf;47.9542\nEssex Junction;44.4902\nCarmaux;44.0492\nSalanso;12.1833\nMinnāmpalli;11.6758\nNiebüll;54.7881\nSomers Point;39.3167\nAnnavāsal;10.4667\nBujari;-9.8308\nCampton Hills;41.9498\nTrumbull Center;41.2415\nTomblaine;48.6856\nNeuenhof;47.4469\nFrouzins;43.5161\nKoranampatti;11.6085\nBogen;48.9167\nCorcuera;12.8000\nRoelofarendsveen;52.2000\nManakana;-19.8167\nIrineópolis;-26.2389\nTangermünde;52.5408\nFairmont;43.6441\nShenjiaba;32.9441\nIsua;25.2330\nDobhāwān;25.3987\nTürkan;40.3639\nTakkali;8.2461\nSidi Bou Ali;35.9561\nDharmavaram;18.2164\nLe Mars;42.7810\nSantiago;-14.1892\nFelling;54.9500\nMörlenbach;49.5990\nSaint-Grégoire;48.1511\nÀrvorezinha;-28.8719\nKangaroo Flat;-36.7833\nHaikoucun;28.3237\nLoudoun Valley Estates;38.9770\nSudogda;55.9500\nNeuenstadt am Kocher;49.2333\nKothi;24.7526\nBogué;16.5904\nVellatūru;16.1209\nIsabela;18.4991\nBurtonsville;39.1166\nRāoke Kalān;30.8219\nKaror;25.6018\nZuyevka;58.4000\nSucupira do Norte;-6.4769\nPôrto Firme;-20.6728\nSūndekuppam;12.4567\nOudewater;52.0167\nKhiram;33.7320\nBrikama Ba;13.5333\nGranbury;32.4475\nSylva;57.3139\nTrabia;38.0000\nBrikcha;34.9667\nNăsăud;47.2833\nKiso;35.9363\nRoche-la-Molière;45.4339\nAlagarai;10.9826\nMungod;17.0667\nReddipalle;14.1993\nCittanova;38.3500\nAchchippatti;10.6989\nKourani;-11.8511\nPhon Charoen;18.0258\nIvankiv;50.9328\nOulad Slim;32.7775\nMawai;24.8043\nMuhammadganj;26.1506\nKottapālem;16.5787\nSovata;46.5961\nErraballa;14.3971\nSidi Rahhal;31.6667\nPierrelaye;49.0225\nDougba;8.4497\nVillasāgar;18.4736\nGages Lake;42.3519\nConceição dos Ouros;-22.4128\nFanjā’;23.4675\nGauli Palāsiya;22.5323\nCunupia;10.5500\nWarr Acres;35.5285\nSchwaig;49.4692\nFarmersville;36.3050\nLachen;47.1833\nMasindi Port;1.6983\nMāli;25.6549\nKalanak;39.0833\nSanta Fé;-23.0378\nFairview;45.5469\nFlat Rock;42.0991\nSrīrēmapuram;16.8600\nLake Monticello;37.9210\nSemmarikulan;8.4815\nSão Gonçalo do Pará;-19.9828\nGroßburgwedel;52.4933\nEdwards;39.6215\nSilvārpatti;10.4473\nBalikumbat;5.8928\nShirbadgi;16.0417\nDihri;25.3796\nTansandra;13.0554\nAwfouss;31.6833\nKrasnoilsk;48.0167\nQuinto di Treviso;45.6500\nRāmannapeta;17.2833\nRidgefield;45.8114\nNevelsk;46.6833\nBomporto;44.7333\nCoroneo;20.1333\nManalūrpettai;12.0079\nOntario;43.2408\nBaraçlândia;-7.2050\nDan;7.3167\nKragerø;58.8869\nPrestonpans;55.9597\nHeath;40.0241\nĪdupugallu;16.4609\nMolango;20.7844\nMyers Corner;41.5864\nVolpago del Montello;45.7833\nModavāndisatyamangalam;11.2635\nTiddas;33.5665\nBāghīn;30.1811\nBeni Oulid;34.5897\nDanville;39.7584\nChinchinim;15.2000\nRoseira;-22.8978\nTha Muang;13.9611\nScituate;41.7926\nBrumath;48.7319\nWaimea;20.0124\nDevarāpalle;17.9886\nAydıncık;40.1167\nEerbeek;52.1053\nBan Klang;18.5791\nLimoux;43.0569\nWerlte;52.8500\nWabash;40.8034\nAgatogba;6.4000\nVedurupāvalūru;16.5519\nCorral de Bustos;-33.2833\nAgua Blanca Iturbide;20.3500\nPortet-sur-Garonne;43.5219\nPlaridel;13.9511\nPirapetinga;-21.6558\nBasāha;26.1329\nNāgulapādu;16.3090\nMachchand;26.3241\nPlanura;-20.1378\nMerzenich;50.8262\nWaterford;39.7415\nRawdon;46.0500\nPella;41.4052\nAmurrio;43.0528\nSão José do Calçado;-21.0250\nAnröchte;51.5667\nDhāntola;26.2016\nBaldeogarh;24.7562\nPlattekill;41.6478\nPūmalakkundu;9.8871\nHalgūr;12.2500\nEmsbüren;52.3925\nLingampet;18.2383\nBordighera;43.7833\nHamilton;-37.7333\nGarden Acres;37.9637\nCampbellton;48.0050\nChong-Aryk;42.8139\nReddigūdem;16.8939\nBelaya Kholunitsa;58.8500\nVettaikkāraniruppu;10.5739\nLemmer;52.8437\nFasintsara;-20.7000\nView Royal;48.4517\nBelle Chasse;29.8558\nPiraí do Norte;-13.7619\nGilbués;-9.8319\nMajhgawān;23.4039\nLeones;-32.6617\nChiankī;24.0051\nSilverton;45.0030\nGalion;40.7385\nSanta Catarina Masahuat;13.7833\nWeil im Schönbuch;48.6214\nPuduppattanam;10.7626\nDāmu;26.5461\nJogiāra;26.4083\nTerralba;39.7197\nJacinto Machado;-28.9969\nJaguaribara;-5.6578\nGreat Missenden;51.7042\nPalatka;29.6493\nShasta Lake;40.6790\nSuthālia;23.9955\nErravaram;17.5458\nSomers;41.9949\nMercês;-21.1939\nHuachipato;-36.7481\nPavittiram;11.1406\nBad Ems;50.3381\nLajes;-5.7000\nVūtukūru;14.5778\nMillstone;40.2123\nRangamāti;26.8040\nMahem;15.5796\nSambhu Chak;26.4081\nKīlakkurichchi;10.7645\nLibanté;10.7936\nKudūru;13.1081\nPuerto Quijarro;-17.7796\nSimbach am Inn;48.2667\nPasewalk;53.5000\nDera Baba Nanak;32.0321\nIanca;45.1350\nMorsbach;50.8667\nDholbāja;26.2674\nPararia;25.6492\nTavriisk;46.7559\nCholchol;-38.6000\nKnezha;43.5000\nFelida;45.7138\nIraiyūr;11.7834\nVaprio d’Adda;45.5667\nLipova;46.0917\nChavkandak;39.9000\nBimun;34.0588\nPeixe;-12.0250\nBarhauna;25.3040\nUkkali;16.5900\nAlguazas;38.0514\nTerakanāmbi;11.8000\nEl Realejo;12.5428\nKeshwāri;24.1878\nÚmbita;5.2167\nBowen;-20.0102\nKunnūr;9.5882\nVālāntaravai;9.3390\nKapyl;53.1500\nSīlamalai;9.9621\nPirojgarh;26.2769\nKanakpur;24.4976\nVatana;-22.2167\nJaqma;33.2920\nBad Frankenhausen;51.3558\nBadia Polesine;45.1000\nNatonin;17.1089\nLima;-23.9000\nSouthborough;42.3012\nTanichchiyam;10.0412\nPedda Kotayalanka;16.1567\nGolakpur;25.1777\nVerucchio;43.9833\nFervedouro;-20.7258\nQiushanxiang;34.3562\nSatghara;26.3977\nKhariāl;30.1056\nKöflach;47.0639\nCabañaquinta;43.1000\nFrýdlant nad Ostravicí;49.5928\nValaiyāmpattu;12.6927\nSteinau an der Straße;50.3167\nInduno Olona;45.8500\nQuétigny;47.3144\nRobstown;27.7940\nMettuppālaiyam;11.1747\nSão Domingos;-10.7908\nWinchendon;42.6667\nCorumbá de Goiás;-15.9239\nSouth Lebanon;40.3058\nKudelstaart;52.2339\nWerneck;49.9833\nEssey-lès-Nancy;48.7058\nMaría Pinto;-33.5167\nChuhal;31.5950\nPernes-les-Fontaines;43.9978\nBiot;43.6286\nPont Sondé;19.1493\nShamva;-17.3167\nKemin;42.7861\nSan Diego Country Estates;33.0094\nFirou;10.9192\nNanbu;35.3403\nGłogów Małopolski;50.1667\nRājepur;25.5377\nLevanger;63.7465\nFørde;61.4522\nVaiano;43.9667\nBethanie;-26.4833\nBlairgowrie;56.5916\nKondakindi Agrahāram;14.6790\nBenedito Novo;-26.7828\nLetychiv;49.3833\nDatian;25.4379\nRāmpatti;26.3333\nLondon;39.8935\nKut Chap;17.4262\nSylva;58.0333\nMünchberg;50.2000\nVictoria;44.8634\nNideggen;50.7000\nBernay;49.0886\nBounaamane;29.5283\nKirkel;49.2833\nCapriolo;45.6373\nSan Simón;13.8333\nNallikodūr;17.5811\nNordkirchen;51.7381\nTaksimo;56.3315\nHire Megalageri;14.5440\nAlderwood Manor;47.8146\nBanga;-8.7333\nPālepalli;12.5667\nOostzaan;52.4333\nNeustadt;50.8500\nAydarken;39.9400\nKalgi;17.3500\nSão Carlos;-27.0778\nSanta María de Palautordera;41.6953\nBerwick;41.0555\nKiklah;32.0683\nBowdon;53.3760\nBuckie;57.6760\nPayerne;46.8167\nPadugaipattu;8.3642\nVenecia;5.9167\nSrīsailain;16.0833\nKorolevo;48.1500\nSobral de Monte Agraço;39.0180\nGoito;45.2500\nPortage;43.5489\nMurowana Goślina;52.5667\nMonsenhor Gil;-5.5639\nNagyatád;46.2227\nPanasapādu;17.0185\nConceição da Aparecida;-21.0939\nEl Jicaral;12.7286\nRancho Arriba;18.7147\nKīl Vālūr;10.7659\nMonte Alegre do Piauí;-9.7539\nOttendorf-Okrilla;51.1792\nExeter;36.2941\nSouth Huntington;40.8225\nKazo;-0.0528\nRoddam;14.1000\nSanta Isabel Ishuatán;13.6167\nMurfatlar;44.1736\nSandalpur;25.5639\nGagnef;60.6000\nIapu;-19.4369\nÖrkelljunga;56.2833\nTiruchchuli;9.5348\nVorsma;55.9833\nKsar Lmajaz;35.8428\nRecreio;-21.5250\nJordânia;-15.9000\nTeocuitatlán de Corona;20.0918\nKalakeri;16.6667\nBuzdyak;54.5711\nNormandia;3.8808\nKarattuppālaiyam;11.4402\nKalinagar;22.4206\nFort Madison;40.6207\nKoila;25.4550\nLaunaguet;43.6739\nMarpingen;49.4500\nWeston;41.2284\nParanã;-12.6150\nAich;48.6228\nDāra;26.1546\nRouvroy;50.3936\nGanapavaram;16.4314\nGislaved;57.3000\nCedral;-2.0000\nBen Nasseur;33.1107\nWinterville;35.5291\nWinchester;41.9218\nDarsur;25.9711\nLenguazaque;5.3069\nEngenheiro Caldas;-19.2189\nHorti;17.1700\nBiandanshan;26.0409\nUnion Park;28.5657\nSanta Maria Madalena;-21.9550\nRoca Sales;-29.2839\nFochville;-26.4833\nBilehra;23.6463\nArkadelphia;34.1253\nParis;36.2933\nTirumangalakkudi;11.0214\nPresidente Kennedy;-21.0989\nFriedeburg;53.4500\nOliveira de Frades;40.7167\nVolterra;43.4000\nCrosia;39.5667\nAl Jazīrah al Ḩamrā’;25.7089\nLolokhur;26.4136\nNāvinipatti;10.0439\nAperibé;-21.6208\nNorthampton;40.6866\nBieber;50.6000\nBangaon;26.3081\nBhatauliā;26.4771\nKottampatti;10.6705\nLondon Colney;51.7260\nCaparrapí;5.3442\nKranuan;16.7081\nDettingen an der Erms;48.5300\nVytegra;61.0000\nChavinda;20.0167\nWelkenraedt;50.6606\nAghbalou n’Kerdous;31.6767\nLexington;40.7779\nRifle;39.5362\nWood River;38.8631\nDari;23.8283\nManglūr;15.5177\nPithiviers;48.1719\nDahua;24.7742\nBinéfar;41.8500\nKafr Takhārīm;36.1164\nHipparga;17.4568\nNgọc Sơn;21.3500\nPedras de Maria da Cruz;-15.6069\nUlft;51.8908\nKampong Tunah Jambu;4.9957\nClay;33.6951\nBallina;-28.8333\nSão Geraldo;-20.9228\nDāita;24.4548\nPineville;35.0864\nCadillac;44.2493\nCordele;31.9563\nQanliko‘l;42.8333\nTyukalinsk;55.8667\nGrand-Couronne;49.3575\nMontemarciano;43.6333\nCumnock;55.4529\nCampo Redondo;-6.2428\nTanaina;61.6576\nColdstream;50.2200\nSirdala;24.6559\nKurşunlu;40.8333\nMasquefa;41.5036\nBelagola;13.3833\nUrucânia;-20.3508\nMandello del Lario;45.9167\nManteswar;23.4225\nBellamkonda;16.4923\nTerra Alta;-1.0378\nChākicherla;15.1127\nShankarampet;18.0490\nSanta Terezinha de Goiás;-14.4378\nSgamna;32.7333\nCermenate;45.7000\nChester;44.6500\nVālavandānkottai;10.7667\nĀttūrkuppam;12.6000\nArgayash;55.4889\nEllon;57.3660\nTelpur;27.0548\nSanto Stefano di Magra;44.1625\nZuidlaren;53.0942\nQueens;44.0333\nTrajano de Morais;-22.0628\nBilenke;48.7664\nPotengi;-7.0908\nKambarka;56.2667\nNewport;44.6242\nSouthampton;39.9137\nBanská Štiavnica;48.4581\nSaint-Loubès;44.9172\nRāyen;29.5978\nSoanpeta;18.9586\nArlöv;55.6333\nRio dos Cedros;-26.7378\nAjjipuram;12.1500\nPetrolina de Goiás;-16.0950\nNovi di Modena;44.8934\nGafour;36.3400\nSermoneta;41.5500\nHigashikagura;43.6966\nMiędzychód;52.6000\nCêrro Grande;-30.5900\nPilar;17.4168\nErdőkertes;47.6667\nBuenópolis;-17.8742\nDalgān;27.4753\nCentralina;-18.5839\nRoßtal;49.4000\nLontras;-27.1658\nBonham;33.5880\nSchönwalde-Siedlung;52.6500\nZaozërnyy;55.9667\nTeixeira Soares;-25.3678\nNehoiu;45.3531\nVelakkuttai;12.6519\nWorcester;40.1899\nTello;3.0667\nGroaíras;-3.9128\nVilla Elisa;-32.1667\nKāsarkod;14.2500\nHecelchakán;20.1667\nBertem;50.8500\nFairmount;43.0414\nTokunoshima;27.7266\nLaligam;12.0500\nChitrāda;17.0802\nJamhra;25.7777\nKhiriāwān;25.1120\nAmbalavao;-19.1000\nBan Bong Tai;17.4057\nAngelim;-8.8833\nAlvorada do Sul;-22.7800\nNieuw-Lekkerland;51.8833\nShelton;47.2186\nFenggeling;34.5312\nSan José de Feliciano;-30.3833\nFiumefreddo di Sicilia;37.8000\nBomareddipalli;18.7044\nMinamiaso;32.8167\nCorfe Mullen;50.7701\nSanjāt;25.6046\nJogaili;25.9096\nBāsmanpur;26.6433\nMiradouro;-20.8908\nDhānga;26.4630\nSant’Egidio alla Vibrata;42.8333\nChivhu;-19.0000\nBhirua;25.8509\nCaetanópolis;-19.2950\nOuistreham;49.2792\nEnriquillo;17.9000\nSātulūru;16.2541\nPliezhausen;48.5586\nErtil;51.8500\nPushpattūr;10.5438\nBrewster;41.7463\nHirni;25.8323\nMondaí;-27.1028\nAdvi Devalpalli;16.6631\nKarariyā;26.5249\nSão Romão;-16.3689\nBelpāra;20.5889\nKenafif;30.4167\nParanacity;-22.9300\nParnaguá;-10.2269\nSpout Springs;35.2724\nSapkyo;36.6864\nGuadalupe;-6.7869\nWaverly;42.7250\nSelkirk;50.1436\nSaint-Félicien;48.6500\nPrimavera;-0.9428\nBierbeek;50.8333\nPiranhas;-16.4269\nHeubach;48.7881\nTūlin;23.3700\nRewāhi;26.2698\nEast Bradford;39.9590\nSão Francisco;-5.1228\nLillers;50.5636\nBurgum;53.2000\nTabubil;-5.2750\nErada;-25.2833\nSihanamaro;-25.1833\nMagstadt;48.7422\nSlatina;45.7022\nKodikkulam;9.9811\nGhāriyah al Gharbīyah;32.6828\nAmparihitsokatra;-17.5167\nEnnamangalam;11.6449\nLinthicum;39.2088\nJangalapalle;14.8844\nErenler;38.8197\nVétraz-Monthoux;46.1742\nIizuna;36.7547\nMadridejos;39.4667\nSewa;24.8753\nCarice;19.3833\nOmmangi;17.2597\nManubolu;14.1833\nElkhorn;42.6713\nKapuvár;47.6000\nMālingaon;26.5467\nBan Pa Hung;19.5672\nPachchāmpālaiyam;11.5723\nRockport;28.0290\nRum;47.2872\nBusca;44.5167\nBareh;26.6786\nGarden City;32.0867\nHawkesbury;45.6000\nSteinen;47.6453\nSoverato Marina;38.6833\nOster;50.9486\nAdamankottai;12.0742\nAmritpur;28.1167\nBimāwān;25.5111\nDhanauli;26.0026\nKenār;25.2916\nCarroll;42.0699\nVīrapāndiyanpattanam;8.5200\nSão João d’Aliança;-14.7058\nKearney;39.3550\nHalfway;39.6162\nFontoura Xavier;-28.9828\nMoimenta da Beira;40.9797\nShankarpur;26.1821\nBirkenau;49.5607\nKarajgi;14.8641\nPires Ferreira;-4.2469\nTrês Cachoeiras;-29.4558\nJiji;23.8300\nMinatitlán;19.3833\nPabégou;9.8333\nSaint-Jean-le-Blanc;47.8919\nFrancisco Badaró;-16.9928\nLonquimay;-38.4333\nBhāgsar;30.4417\nLanškroun;49.9122\nKāttāgaram;12.4110\nItapé;-14.8978\nLūgovoy;42.9472\nMeuselwitz;51.0500\nAnkalgi;16.0333\nTiana;41.4831\nAlāwalpur;31.4967\nMartinópole;-3.2258\nMucugê;-13.0050\nRangasamudram;14.9852\nRājhanpur;25.7885\nLa’tamna;31.9100\nBan Kang;18.5444\nElmas;39.2667\nWere Īlu;10.6000\nKengarai;11.4144\nMarawī;18.4833\nBisignano;39.5167\nRonda Alta;-27.7669\nDivonne-les-Bains;46.3567\nPalafolls;41.6692\nColumbia;40.0347\nFanzhao;26.6615\nBandixon;37.8614\nSanta María;2.9500\nSalvatierra de Miño;42.0833\nChegūr;17.1758\nAndergrove;-21.0931\nCaspe;41.2333\nNishi;32.2011\nBoriguma;19.0468\nSenhora dos Remédios;-21.0278\nChaungtha;16.9667\nRadyvyliv;50.1286\nHadiāya;30.3413\nFountain Inn;34.6989\nIttikelakunta;16.6797\nBeverly Hills;28.9176\nViravāda;17.1194\nCharalá;6.2500\nLuza;60.6500\nCaracol;-9.2789\nHosur;15.8201\nTanggemu Nongchang;36.0750\nBalangkayan;11.4728\nXishrov;39.6383\nWingles;50.4942\nCuorgnè;45.3897\nOppeano;45.3000\nKaimāti;26.0854\nPôrto Xavier;-27.9058\nSedico;46.1167\nTarashcha;49.5500\nEumseong;36.9353\nBlumberg;47.8392\nKanchanpur;24.6096\nHonwāda;16.7333\nKamdoli;15.2048\nEkhari;26.5246\nAlgarrobo;-33.3911\nMakri;24.3860\nRedentora;-27.6639\nMariluz;-24.0019\nQovlar;40.9419\nRoberval;48.5200\nCumaru;-8.0058\nDhauni;24.9901\nKannāndahalli;12.4164\nDoiwāla;30.1760\nVelpūru;16.1775\nNorth Bend;43.4075\nSniatyn;48.4500\nCypress Gardens;28.0036\nSainte-Agathe-des-Monts;46.0500\nShyroke;47.6882\nPadbury;51.9710\nBorzna;51.2539\nSan Miguel Sigüilá;14.9000\nSpelle;52.3667\nAmmanford;51.8000\nJemaat Oulad Mhamed;33.0938\nHackettstown;40.8540\nAin Karma;34.0071\nMarāi Kalān;24.0211\nFoz;43.5694\nElambalūr;11.2669\nJocoro;13.6167\nCalasparra;38.2306\nBendrahallī;12.2642\nSyców;51.3100\nMajhariyā Sheikh;26.7356\nMsoga;-6.5667\nTeplodar;46.5036\nMangasamudram;13.2291\nMstsislaw;54.0167\nEleşkirt;39.7981\nHighland;38.7602\nNorth Dumfries;43.3200\nGöytəpə;39.1167\nTefenni;37.3111\nBeli Manastir;45.7667\nMādarpākkam;13.4439\nHooglede;50.9781\nSan Marcos;9.6703\nCarqueiranne;43.0950\nLohafary;-23.2500\nAmmanabrolu;15.5802\nMedina;4.5092\nTutzing;47.9089\nPotosí;0.8081\nAnkadindambo;-21.4667\nHouthulst;50.9783\nRehburg-Loccum;52.4508\nLagoa da Confusão;-10.7939\nChestnut Ridge;41.0829\nSmithville;39.3919\nCaudete;38.7044\nShioya;36.7776\nGovernador Archer;-5.0219\nPlymouth;41.3483\nAlpine;40.4629\nMosquera;2.4903\nAinring;47.8156\nPeryavaram;13.9317\nLovejoy;33.4426\nSão João;-25.8278\nRideau Lakes;44.6667\nTolmezzo;46.4000\nAsola;45.2167\nVernon;34.1479\nYelm;46.9398\nPechea;45.6333\nMolsheim;48.5428\nPleasant Hill;41.5867\nCastellamonte;45.3820\nNārāyanraopet;18.2114\nParis;38.2016\nTipp City;39.9644\nComstock Park;43.0438\nKushijima;32.7401\nOlovo;44.1275\nMahabo-Mananivo;-23.1833\nJāmunia;25.3676\nPatūt;25.4658\nMsila;35.2000\nAleşd;47.0572\nItamogi;-21.0778\nSechelt;49.4742\nTiruvāduturai;11.0379\nCetraro;39.5000\nSan Blas;21.5397\nGunbarrel;40.0632\nSão Pedro do Ivaí;-23.8650\nYermolino;55.2000\nSatravāda;13.3201\nNong Ki;14.6867\nKulundu;40.1069\nTovāla;8.2482\nTuminkatti;14.4131\nVersailles;38.0486\nFort Oglethorpe;34.9318\nAïn Zohra;34.1000\nPullach im Isartal;48.0500\nTissaf;33.4000\nAuterive;43.3503\nItamukkala;15.3731\nVigasio;45.3167\nKolnūr;18.5095\nValkurti;18.7171\nLint;51.1167\nFriendly;38.7601\nMikhaylov;54.2333\nAldenham;51.6723\nBasāpatna;15.4302\nSkidal’;53.5861\nCabriès;43.4411\nBeccles;52.4580\nNandamūru;16.6400\nKokiladānga;26.3452\nBerthoud;40.3071\nSātgāchia;23.2641\nVysokyi;49.8850\nCingoli;43.3667\nCheat Lake;39.6670\nSan Sebastiano al Vesuvio;40.8333\nVenkatāpuram;18.2232\nHarrison;40.6374\nZa’roura;35.2167\nTakahama;35.4903\nTocina;37.6000\nCatanduvas;-25.2028\nGobindpura;30.2805\nAntanananivo;-16.3000\nChilpur;18.2388\nStandish;43.7811\nMilford;40.4291\nSundarapāndiyam;9.6127\nSwāmimalai;10.9575\nBāsudebpur;21.8256\nPādarti;15.4690\nAlpena;45.0740\nPřelouč;50.0399\nAlmoloya del Río;19.1586\nUchtepa Qishlog’i;40.2050\nKokoszki;54.3541\nToca;5.5667\nAnnan;54.9830\nKawara;33.6680\nOelsnitz;50.4167\nJāvagallu;13.3000\nTut;37.7967\nElūrupādu;16.5167\nFort William;56.8198\nBayyavaram;17.6638\nKirkland;43.0368\nPińczów;50.5333\nSouama;36.6417\nLe Passage;44.2014\nSleepy Hollow;41.0936\nGambissara;13.2333\nCaatiba;-14.9769\nPariyāri;25.2128\nUgargol;15.7800\nRemada;32.3061\nIppagūdem;17.7668\nNovo Horizonte;-11.7100\nMālior;25.3900\nShpola;49.0333\nNaters;46.3237\nGranada;6.1470\nCovasna;45.8492\nTellār;12.4011\nYatton;51.3855\nMazamet;43.4917\nGarliava;54.8167\nBatán;-38.0078\nMuurame;62.1292\nJamunāmukh;26.1015\nChada;17.4992\nWoodburn;38.8503\nSan Pablo;-40.4000\nMoree;-29.4650\nSiechnice;51.0367\nNové Město na Moravě;49.5615\nVisbek;52.8333\nCachoeira dos Índios;-6.9269\nKingaroy;-26.5408\nEch Chaïbat;31.6000\nThāthūpur;25.9731\nAstoria;46.1856\nHillsdale;41.0074\nRacconigi;44.7667\nFouesnant;47.8933\nMālipākar;25.3567\nErquelinnes;50.3101\nLaakirchen;47.9828\nMajhaulia;25.9635\nZumárraga;43.0831\nWillstätt;48.5417\nCanápolis;-13.0700\nCalçoene;2.4978\nBucine;43.4833\nCaém;-11.1000\nPhak Hai;14.4626\nHolsbeek;50.9167\nSung Noen;14.8965\nCitrus Springs;28.9931\nGangaura Behra;25.9541\nHeeze;51.3825\nByarozawka;53.7167\nEmbrach;47.5103\nBan Bu Sung;14.9602\nKāndra;22.8517\nAvalūrpet;12.3800\nOrange Lake;41.5369\nGakuch;36.1736\nPepinster;50.5667\nBāghduma;24.8223\nMainaschaff;49.9833\nWest Vero Corridor;27.6363\nKele;6.0833\nBad Breisig;50.5092\nMangalam;11.6368\nOpochka;56.7000\nMeymand;28.8678\nJucuruçu;-16.8428\nSiddarāmpuram;15.5300\nGavirate;45.8500\nBanbhāg;25.7919\nMarlton;38.7620\nOgdensburg;44.7088\nChunakhali;22.3010\nSîngera;46.9139\nLa Misión;21.1000\nLoudonville;42.7068\nOzimek;50.6731\nLiminka;64.8083\nWhite City;42.4316\nGoldenstedt;52.7833\nYaotsu;35.4760\nWest Point;33.6064\nChoele Choel;-39.2667\nĀnjukulippatti;10.2444\nKishanpūra Kalān;30.9337\nGénova;1.6442\nLiberty;41.8132\nAtāri;31.6008\nCorte Madera;37.9238\nKodakkal;13.0685\nWald;47.2753\nDavutlar;37.7333\nReddippatti;11.2100\nBruino;45.0167\nHuldenberg;50.7833\nRinópolis;-21.7258\nMarondry;-18.4167\nManvel;29.4798\nRokkasho;40.9672\nElūrpatti;11.0234\nCarrillos;10.0369\nSteinhaus;47.1969\nNathāna;30.3155\nPyetrykaw;52.1333\nZavolzhsk;57.4667\nMatadepera;41.6036\nAlhendín;37.1167\nSanta Isabel Cholula;19.0000\nIwashita;32.6516\nSerebryansk;49.6819\nArrapalli;18.0718\nSchotten;50.5000\nMorrovalle;43.3167\nChamusca;39.3500\nMengibar;37.9683\nSugbongkogon;8.9500\nTolbazy;54.0242\nŪttumalai;8.9916\nBan Pong Yaeng Nai;18.8833\nIndūrti;18.2233\nCanton;41.8600\nArdal;31.9989\nRāsak;26.2361\nSofiivka;48.2683\nOldenburg in Holstein;54.3000\nMassi;9.9167\nProgress Village;27.8831\nTouwu;24.5833\nHermantown;46.8057\nSovicille;43.2833\nKumçatı;37.4710\nKuroshio;33.0167\nRio do Fogo;-5.2728\nAlexandria;38.9621\nShohimardon;39.9833\nKeuruu;62.2583\nHathiākān;25.6060\nMashhad Rīzeh;34.7922\nNamorona;-21.6500\nGroßhansdorf;53.6667\nIpupiara;-11.8200\nÁgua Branca;-7.5119\nTungāvi;10.6263\nHull;42.2861\nLe Beausset;43.1983\nParūr;11.5793\nSatipo;-11.2542\nChansolme;19.8833\nRüdesheim am Rhein;49.9833\nJudenburg;47.1725\nCambridge;40.0221\nTuam;53.5150\nIretama;-24.4239\nSuttamalli;8.6987\nBālgudar;25.2000\nMurungattoluvu;11.1651\nDhanwāda;16.6500\nLysá nad Labem;50.2015\nBagnolo in Piano;44.7667\nSulzbach;50.1331\nDumont;-21.2364\nRed Hook;42.0188\nKlötze;52.6263\nOrotina;9.9024\nKirchlinteln;52.9428\nSaladoblanco;2.0167\nŌnan;34.8939\nCoal;40.7873\nZaggota;34.1667\nBoucau;43.5236\nNorth Glengarry;45.3333\nHosahalli;14.6480\nMakaya;25.2242\nLedegem;50.8531\nDigora;43.1581\nNisarpur;22.1088\nFairfield;33.4747\nAirway Heights;47.6459\nGambolò;45.2586\nCavriago;44.7000\nMelendugno;40.2667\nSarız;38.4792\nPavlikeni;43.2428\nMadera Acres;37.0123\nKotli Ablu;30.3504\nPoienile de sub Munte;47.8167\nMeldola;44.1333\nCondé-sur-l’Escaut;50.4492\nMaiquinique;-15.6208\nDylym;43.0710\nParsād;26.1586\nAigali;16.7200\nMacomer;40.2667\nRoboré;-18.3333\nLescar;43.3250\nHeves;47.6000\nKrivodanovka;55.0881\nLenggries;47.6803\nKamalasai;16.3383\nSanta Teresa;-25.0519\nOberhausen-Rheinhausen;49.2606\nNogliki;51.8333\nKinhālu;15.4431\nNayāgaon;24.5622\nKurort Steinbach-Hallenberg;50.7006\nTöging am Inn;48.2500\nBela Vista de Minas;-19.8300\nTomboutou;11.8550\nSouth Huron;43.3200\nTerku Narippaiyūr;9.1167\nSakuho;36.1610\nCairo;30.8790\nPenn;40.1864\nBrembate;45.6000\nMarieville;45.4333\nMengen;48.0497\nRainbow City;33.9336\nBeilngries;49.0333\nCrigglestone;53.6440\nMori;45.8500\nWölfersheim;50.3975\nBilāspur;30.3044\nBou Nouh;36.5000\nKidira;14.4167\nBoaz;34.1985\nSnohomish;47.9276\nCedartown;34.0223\nBamora;24.0554\nHingyon;16.8522\nÇeltik;39.0244\nFrancisville;39.1068\nSinimbu;-29.5389\nUppūr;13.3945\nSan Felice Circeo;41.2353\nWaynesville;35.4854\nLevski;43.3667\nWaldwick;41.0133\nChavuttahalli;12.4202\nKösching;48.8167\nNiederhasli;47.4822\nMakale;-3.1000\nLesquin;50.5897\nRamiriquí;5.4000\nHongliuwan;39.6348\nKhathjari;24.7046\nArques;50.7356\nPasaul;26.2647\nHarewa;25.6831\nFigeac;44.6086\nBīrpur;32.6617\nChilakhāna;26.2990\nQuartz Hill;34.6527\nDharāwat;25.0592\nKümmersbruck;49.4167\nBergambacht;51.9333\nBhagatpur;25.4098\nLa Leonesa;-27.0500\nThogadūru;12.0957\nBuenavista;9.3222\nSannicandro di Bari;41.0000\nRellivalasa;17.9108\nSan Agustín de las Juntas;17.0000\nSan Isidro;9.8000\nTiruvengadam;9.2586\nBad König;49.7500\nIkryanoye;46.0903\nSendamangalam;11.7431\nKharagbani;26.4852\nHarrisonville;38.6530\nRed Bank;33.9309\nBerd;40.8808\nTsunō;32.2565\nBāg;22.3590\nHazle;40.9558\nWare;42.2806\nWoodbury;39.8379\nZoudjamé;6.8167\nAveley;51.5018\nHayle;50.1860\nLovendegem;51.1000\nChegurumomadi;18.2361\nTaghbalt;30.6200\nPortland;-38.3333\nSakhua;26.1734\nMaków Mazowiecki;52.8667\nLittleton;42.5350\nPescaria Brava;-28.3833\nPlanalto;-27.3289\nAire-sur-la-Lys;50.6386\nBanāso;23.9884\nKosh-Agach;49.9927\nFairview;33.1399\nBirch Bay;48.9243\nInverigo;45.7333\nNorth Versailles;40.3785\nKalaīkunda;22.3392\nBüyükorhan;39.7500\nLambesc;43.6539\nHaria;-3.5833\nMolalla;45.1502\nDeRidder;30.8468\nNūtakki;16.4139\nIvančice;49.1014\nSaint-Pierre-du-Mont;43.8825\nStruthers;41.0510\nMuskegon Heights;43.2023\nParadarāmi;13.0833\nCzersk Pomorski;53.7928\nKargopol;61.5000\nPachalum;14.9269\nGuaraciaba;-26.5989\nSan Pancrazio Salentino;40.4167\nBhatkhori;25.9156\nDabhaura;25.1162\nGarlasco;45.2000\nSan Ignacio de Moxo;-14.9961\nCody;44.5213\nNandiyālam;12.9237\nLa Plata;38.5352\nAhmadpur;23.8301\nBaşmakçı;37.8833\nCalimesa;33.9874\nBrowns Mills;39.9737\nBlain;47.4761\nRödinghausen;52.2550\nBarwān;23.9409\nPine Ridge;28.9330\nEast Liverpool;40.6333\nGolden Hills;35.1409\nMoba;-7.0398\nTiruvambalapuram;8.2514\nWorpswede;53.2222\nLambertville;41.7484\nMānbāzār;23.0615\nSimrol;22.5387\n’Aïn Leuh;33.2833\nSantamāgulūru;16.1303\nBarga;44.0750\nShyamnagar;22.9700\nLentvaris;54.6500\nSankt Andrä;46.7667\nFrickenhausen;48.5928\nVemulanarva;16.9660\nGeylegphug;26.8706\nBo‘z;40.6833\nBanino;54.3922\nMayfield;36.7371\nMuddāda;18.2385\nMilton;30.6286\nOsthofen;49.7078\nPuszczykowo;52.2817\nJanhapāra;21.3390\nBūdalūr;10.7861\nPiploda;23.6073\nŠurany;48.0872\nBou’nane;32.0275\nVernal;40.4517\nNohfelden;49.5867\nNallamadu;16.8802\nPullūru;16.8301\nSan Pedro Huamelula;16.0167\nSola;21.6744\nSanta María Ajoloapan;19.9692\nMadhubani;27.0001\nYorkshire;38.7882\nTay;44.7167\nSanta Margherita Ligure;44.3333\nKalladai;10.7272\nDubove;48.1781\nSuaita;6.1019\nPunjai Lakkāpuram;11.3050\nNeglūr;14.9000\nPāchhāpur;16.2900\nCoycoyan de las Flores;17.2713\nSulęcin;52.4444\nPeriyapuliyūr;11.4296\nHuejuquilla el Alto;22.5333\nValozhyn;54.0833\nGudensberg;51.1833\nKhandāich;24.8511\nMonument;39.0736\nSan Elizario;31.5793\nDiabougou;14.5431\nVolodarsk;56.2167\nUrgnano;45.5972\nGassino Torinese;45.1271\nHowell;42.6078\nCaraíbas;-14.6000\nBude;50.8240\nMoravská Třebová;49.7580\nWielsbeke;50.9089\nKoumpentoum;13.9833\nBikrampur Bānde;25.8415\nUmbrete;37.3667\nValea lui Mihai;47.5200\nOhrdruf;50.8281\nGalleh Dār;27.6594\nHickam Housing;21.3311\nPurkersdorf;48.2092\nKami-kawabe;35.4866\nIlsfeld;49.0500\nKusmaul;26.1911\nPuigcerdá;42.4317\nDevmaudaldal;24.6312\nKanangle;16.2900\nFlowood;32.3359\nTaltal;-25.4000\nSenanga;-16.1167\nDodarasinakere;12.5083\nGrosse Pointe Farms;42.4068\nFredonia;42.4407\nVuktyl;63.7000\nMaisenhausen;50.0172\nGlenwood Springs;39.5455\nMont-Saint-Martin;49.5406\nAlajärvi;63.0000\nNavani;11.3709\nAnalalava;-14.6333\nHakka;25.9163\nLakhna;25.8865\nNogent-le-Rotrou;48.3217\nRahta;25.9213\nKapelle-op-den-Bos;51.0167\nBāba Bakāla;31.5500\nŞūfīān;38.2722\nEl Cairo;4.7500\nCabo Rojo;18.0867\nPalankottai;9.1356\nMenzel Kamel;35.6333\nHiranai;40.9259\nJaisinghnagar;23.6260\nAlkhan-Yurt;43.2317\nFuente Palmera;37.7000\nVadavālam;10.4286\nParatdiha;24.1638\nHoeselt;50.8500\nUchoa;-20.9528\nSaint-Doulchard;47.0997\nGlocester;41.8934\nMuturkha;24.1044\nKanhauli;26.4815\nKittery;43.0998\nGandikunta;16.1699\nAytré;46.1342\nAizenay;46.7400\nRaipur;25.4226\nBānki;26.1497\nPathāri;23.9333\nPort Townsend;48.1220\nWarrenton;38.7176\nGhadāmis;30.1333\nSaint-Amand-Montrond;46.7228\nAl Mazyūnah;17.8486\nGar;32.1166\nBad Liebenzell;48.7742\nArauá;-11.2619\nMerville;50.6439\nKadimetla;15.7376\nBaker City;44.7749\nGūdalūr;10.7830\nSan Calixto;8.4000\nGiesen;52.2000\nKinnelon;40.9847\nRatne;51.6500\nGundi;18.6237\nVardenik;40.1331\nOudenburg;51.1833\nFernán-Núñez;37.6667\nLapinlahti;63.3667\nPagidyāla;15.9330\nHlinsko;49.7622\nLizzano;40.3919\nTarhjicht;29.0564\nPonneri;12.5972\nVelpūru;16.1496\nChinnakkavundanūr;11.4559\nOued Laou;35.4500\nUniontown;39.8993\nBundehra;25.3776\nZafargarh;17.7686\nRuffano;39.9833\nCorozal;18.3410\nTurgutalp;39.1833\nVegachí;6.7731\nFoix;42.9653\nMatias Cardoso;-14.8550\nMagny-les-Hameaux;48.7239\nTadangam;12.1056\nYenice;36.9667\nMagnago;45.5792\nHeilsbronn;49.3167\nChilanga;13.7167\nCoronel Freitas;-26.9089\nSão Sebastião do Maranhão;-18.0839\nClinton;36.0981\nCristino Castro;-8.8178\nCampobello di Licata;37.2500\nSomasamudram;15.1500\nSauk Village;41.4906\nSafford;32.8335\nLa Sierra;2.2500\nBoves;44.3333\nGreencastle;39.6432\nVlist;51.9667\nTeotitlán;18.1333\nCape Canaveral;28.3933\nMargny-lès-Compiègne;49.4261\nBastak;27.1992\nKeokuk;40.4095\nKarankot;17.2866\nGudimūlakhandrika;16.4090\nÄlmhult;56.5500\nCedar Hills;40.4135\nDuPont;47.1079\nIi;65.3167\nNaqneh;31.9336\nPunnaikkāyal;8.6322\nChinnāmpālaiyam;10.6604\nBudd Lake;40.8733\nBoudinar;35.1500\nPasian di Prato;46.0500\nVentania;-24.2458\nBudhma;25.6451\nConsuegra;39.4619\nHonge;15.8800\nMīāndasht;33.0736\nPereshchepyne;49.0179\nDaruvar;45.5929\nSaint-Lys;43.5142\nImmingham;53.6139\nWāngjing;24.3862\nSanta Cruz Atizapán;19.1756\nDongcha;34.3800\nSan Francisco la Unión;14.9167\nStrzelce Krajeńskie;52.8756\nImaruí;-28.3408\nLiesveld;51.9156\nShāhganj;22.8467\nCatunda;-4.6478\nJaisinghnagar;23.6858\nAirmont;41.0992\nCoapilla;17.1167\nḨās;35.6169\nCuicatlan;17.8000\nItatiaiuçu;-20.1969\nRibadeo;43.5336\nPloërmel;47.9317\nDessel;51.2333\nCoroaci;-18.6219\nLeppävirta;62.4917\nSorkheh;35.4633\nMareno di Piave;45.8409\nHöhr-Grenzhausen;50.4350\nSande;59.5936\nGessate;45.5500\nGenemuiden;52.6244\nMaihma Sarja;30.3110\nNovyye Atagi;43.1328\nTha Mai;12.6196\nSparta;43.9377\nManduri;-23.0033\nChintapalle;17.8667\nLenoir City;35.8111\nEstavayer-le-Lac;46.8500\nPinos Puente;37.2500\nMāmidipalli;18.7772\nFair Oaks Ranch;29.7467\nPiedras Blancas;43.5600\nMonteriggioni;43.4000\nTreillières;47.3308\nTerra de Areia;-29.5850\nHolywell;53.2740\nWadgira;16.5858\nKourimat;31.4500\nMādhavaram;16.8900\nNéa Moudaniá;40.2386\nBukowno;50.2681\nGroßröhrsdorf;51.1444\nColindres;43.3967\nGovindāpuram;16.1548\nWorth;51.1130\nTowcester;52.1300\nVidor;30.1291\nMalhārgarh;24.2829\nUmburetama;-7.6958\nHamīra;31.4589\nBellavista;6.5236\nReedsburg;43.5348\nPanjāb;34.3833\nMae Ai;20.0296\nConselice;44.5167\nNorth Lakes;61.6191\nFairmount;39.7931\nOuta Bouabane;34.2606\nZell am See;47.3233\nSaint-Rémy-de-Provence;43.7894\nGunnedah;-30.9817\nJagannādapuram;13.2745\nPokrovske;47.9853\nMajali;14.9000\nIngré;47.9206\nZaozërsk;69.3978\nLagbé;6.6833\nGidha;26.0507\nPangunattam;12.1112\nNambutalai;9.7277\nKostrzyń;52.3942\nMontescaglioso;40.5500\nTafersit;35.0167\nKeora;25.4374\nKatahra;26.2235\nDeruta;42.9833\nDināra;25.4613\nCaldas de Reyes;42.6028\nRubim;-16.3750\nRurka Kalān;31.0700\nLittle River;33.8786\nWilloughby Hills;41.5873\nBad Gandersheim;51.8719\nGeorge Mason;38.8356\nUrzhum;57.1167\nKendallville;41.4441\nMarysville;42.9084\nByalynichy;53.9956\nKattamūru;17.0800\nCastel Bolognese;44.3167\nMount Vista;45.7373\nJilotlán de los Dolores;19.3719\nBeneditinos;-5.4550\nVargem;-22.8889\nPórto Ráfti;37.8844\nHardiya;25.5301\nBrandis;51.3347\nSaarijärvi;62.7050\nWaltenhofen;47.6667\nSaidia;35.0850\nKaikaram;16.8120\nEast Setauket;40.9210\nWapakoneta;40.5664\nBee Ridge;27.2855\nCosne sur Loire;47.4103\nAnantpur;16.8890\nTemiskaming Shores;47.5167\nCarregal do Sal;40.4333\nNgaparou;14.4631\nEast Rutherford;40.8179\nMount Holly;39.9950\nIdumbāvanam;10.4224\nAltmünster;47.9000\nCoello;4.3333\nJuru;-7.5369\nArgelato;44.5758\nTalachyn;54.4167\nValtoha;31.2074\nPoggio Renatico;44.7650\nNon Sung;15.1788\nFällanden;47.3717\nTiptree;51.8100\nAranzazu;5.3000\nMirante;-14.2419\nKudowa-Zdrój;50.4383\nSan Pedro Ixtlahuaca;17.0500\nIngichka;39.7389\nRevel;43.4586\nMargarita;9.0833\nRāmpura;14.8810\nRute;37.3167\nRye Brook;41.0302\nPunnavalli;16.4062\nKonidena;16.0156\nColac;-38.3403\nMīnākshipuram;9.9908\nNew Richmond;45.1250\nEllisville;38.5897\nAgoué;6.2500\nMonticello Conte Otto;45.6000\nBrinkmann;-30.8669\nRautara;25.6630\nWorsborough;53.5200\nAdiyakkamangalam;10.7626\nSasaima;4.9650\nRotonda;26.8844\nQueensferry;55.9900\nCsorna;47.6167\nTrancoso;40.7833\nBalatonalmádi;47.0333\nRedon;47.6514\nDevanāngurichchi;11.3895\nJesup;31.5992\nLago Ranco;-40.3167\nLa Grange;38.3987\nNāgathān;16.8300\nKhutha Baijnāth;26.0268\nAlcorta;-33.5333\nDagarua;25.8000\nSan Giovanni in Marignano;43.9393\nTenente Ananias;-6.4650\nTāmganj;26.2478\nBisaul;26.6151\nKarczew;52.0833\nÅstorp;56.1347\nNong Wua So;17.2702\nQiziltepa;40.0361\nNéa Artáki;38.5167\nBellinzago Novarese;45.5833\nJāwalgeri;15.8656\nPatchūr;12.5949\nResana;45.6333\nAshukino;56.1611\nChimay;50.0500\nRothrist;47.3028\nMezőberény;46.8167\nCachipay;4.7308\nChevy Chase;38.9944\nNadimpālem;16.2123\nSiano;40.8025\nRiver Vale;41.0138\nUppalaguptam;16.5667\nVaikuntam;11.5197\nBjärred;55.7167\nSaidoke;30.5267\nKushnarënkovo;55.1049\nSundarsi;23.2688\nGangādhar;18.5883\nFranklin;36.7177\nAlukkuli;11.4458\nSanta María Jacatepec;17.8500\nMission;39.0270\nNarikombu;12.9000\nOakbrook;38.9996\nBockenem;52.0117\nHinton;53.4114\nSānampūdi;16.0860\nAlaçatı;38.2814\nKondalahalli;14.7200\nSaint-Sauveur;45.9000\nToudja;36.7586\nPowdersville;34.7826\nZinkiv;50.2081\nLuçon;46.4547\nBastrop;32.7748\nQuesnel;52.9784\nBeuvry;50.5197\nTorrinha;-22.4258\nDodworth;53.5417\nSan Bartolomé Milpas Altas;14.6046\nMuddanūru;14.6667\nRuoqiang;39.0181\nMoyogalpa;11.5403\nVarna;53.3806\nBaisuhalli;12.2064\nQahjāvarestān;32.7039\nNorosí;8.5261\nSinghāna;22.1902\nFerryhill;54.6900\nHawera;-39.5933\nHobart;44.4967\nDasso;7.0167\nTitu;44.6622\nPobiedziska;52.4833\nBaikunthapur;22.9117\nGuateque;5.0056\nPinjranwān;25.1702\nSerafimovskiy;54.4333\nFlossmoor;41.5391\nArden Hills;45.0721\nGiardini;37.8333\nNāgasamudra;14.7200\nManchenahalli;13.5007\nVillas;39.0157\nHornsby Bend;30.2388\nKobeliaky;49.1474\nGāndlapenta;14.0500\nPedavīdu;16.8558\nBueng Khong Long;17.9667\nBerezivka;47.2039\nQuilombo;-26.7258\nBeltangadi;12.9795\nSarapuí;-23.6408\nHavanūr;14.8667\nAtoka;35.4239\nBelomorsk;64.5253\nBroni;45.0619\nPeru;41.3482\nCiudad de Loreto;-28.3000\nMakariv;50.4648\nPiombino Dese;45.6067\nAulnoye-Aymeries;50.2047\nSan Vicente;-1.9000\nCroydon;40.0911\nRenaico;-37.6667\nJerissa;35.8500\nLitovel;49.7012\nKambaneri Pudukkudi;9.0685\nSeysses;43.4981\nŁobez;53.6333\nIndependent Hill;38.6404\nElizabethtown-Kitley;44.7000\nSabana Larga;18.5850\nNersingen;48.4289\nMora;39.6840\nPailón;-17.6594\nMulungu;-7.0239\nBrandywine;38.6963\nWinfield;41.8787\nMosjøen;65.8370\nPhotharam;13.6918\nVanukūru;16.4406\nChom Thong;18.4901\nRio Vista;38.1765\nIndependence;44.8547\nPlüderhausen;48.7950\nGold;33.5874\nMorinville;53.8022\nEl Roble;9.1000\nWendell;35.7819\nThe Pinery;39.4462\nBreuillet;48.5661\nDrezdenko;52.8333\nKondayampālaiyam;11.5130\nArtigues-près-Bordeaux;44.8606\nVirālimalai;10.6023\nBadagabettu;13.3335\nÇıldır;41.1289\nSaint-Barthélemy-d’Anjou;47.4675\nGangūru;16.4833\nEkalbehri;21.8933\nRadekhiv;50.2828\nStansbury Park;40.6356\nVeauche;45.5619\nTrebbin;52.2167\nJennings;30.2233\nSanta Bárbara;9.6000\nPanganiban;13.9000\nRoztoky;50.1585\nNurobod Shahri;39.6086\nKannāl;18.6938\nBan Nong Tong;18.6115\nZorneding;48.0833\nRāmasingavaram;16.8863\nSchlitz;50.6667\nLāila;12.9900\nManchi;12.9000\nNykøbing Mors;56.7953\nWłoszczowa;50.8542\nMallappādi;12.5273\nSan Sebastián;1.8439\nRaun;26.3431\nSocotá;6.0500\nBishunpur;25.5665\nPulivalam;10.7525\nRasht;39.0167\nCouzeix;45.8761\nSt. Augustine Shores;29.8039\nHaţeg;45.6075\nMurājpur;25.9506\nStøvring;56.8867\nKirangūr;12.4316\nUlipuram;11.4667\nSuntar;62.1575\nPlains;41.2657\nGuia Lopes da Laguna;-21.4578\nNinheira;-15.3208\nOsterburg;52.7833\nPerumbālai;11.9635\nImām Şāḩib;37.1844\nHalls;36.0817\nYazıkonak;38.6167\nMadhubani;26.3272\nEast Stroudsburg;41.0023\nPuraini;26.0607\nGökçeada;40.1608\nOulunsalo;64.9333\nUppugunduru;15.6730\nOosterwolde;52.9903\nAlcanar;40.5430\nGeneral Alvear;-36.0333\nUdburu;23.0333\nBerchha;23.2823\nSairé;-8.3278\nTriuggio;45.6667\nInole;17.8682\nAlmusafes;39.2903\nPizarra;36.7667\nParol;32.3460\nDolianova;39.3833\nMozzate;45.6833\nEisenberg;49.5614\nMasku;60.5708\nGorom-Gorom;14.4500\nDattapāra;22.8491\nBādanahatti;15.3176\nDorogobuzh;54.9167\nBrockworth;51.8500\nTotma;59.9667\nCobham;51.3290\nT’q’ibuli;42.3503\nLøgten;56.1643\nBrownsville;35.5890\nCalca;-13.3230\nThīkri;22.0634\nSorbolo;44.8463\nEverswinkel;51.9250\nChiang Klang;19.2930\nGrey Highlands;44.3333\nSão Gonçalo do Rio Abaixo;-19.8258\nBan Krot;14.3121\nJujhārpur;25.7514\nTišnov;49.3487\nVettweiß;50.7389\nAldona;15.5800\nNerinjippettai;11.6543\nBasse-Goulaine;47.2153\nBan Nam Dip Luang;18.4500\nWepener;-29.7333\nHarbatpur;30.4500\nConstantina;-27.7350\nGuntramsdorf;48.0483\nPiru;25.1009\nHeiligenhafen;54.3739\nThap Khlo;16.1600\nBarracão;-26.2539\nYekāmbarakuppam;13.3168\nLeeton;-34.5667\nTadla;32.4409\nAdjarra;6.5333\nWiang Sa;8.6364\nMarshall;40.6453\nBiei;43.5883\nChikkāla;16.9698\nJambukuttaippatti;12.3246\nBhogāpuram;18.0667\nTesalia;2.4833\nNyurba;63.2833\nMarlboro Village;38.8307\nHighfields;-27.4633\nOtočac;44.8667\nOstercappeln;52.3500\nSaidābād;25.5489\nAlto Piquiri;-24.0278\nMatelica;43.2566\nSalmānshahr;36.7092\nHonganur;12.6044\nIrungalūr;10.9399\nBelalcázar;5.0000\nHueyotlipan;18.9000\nNeshannock;41.0509\nEksjö;57.6669\nPalomares del Río;37.3167\nFlero;45.4835\nLa Ravoire;45.5569\nCarnaubais;-5.3408\nBarbana;26.0719\nAklim;34.9167\nSuzdal;56.4211\nPolorós;13.8108\nKemberg;51.7833\nAlfaro;42.1783\nEschenbach;47.2709\nMae Rim;18.9163\nPuerto Tirol;-27.3667\nSohta;26.2149\nCaturama;-13.3289\nHostotipaquillo;21.0603\nPettāmpālaiyam;11.3499\nScionzier;46.0572\nZāhed Shahr;28.7450\nColmenarejo;40.5608\nTweed Heads;-28.1833\nHattula;61.0556\nNordwalde;52.0833\nSanto Tomás de los Plátanos;19.1817\nMońki;53.4000\nKāliganj;23.7348\nConcordia;10.2667\nStudénka;49.7234\nÇamoluk;40.1333\nQuiculungo;-8.5167\nSarpamāri;26.3841\nBasavilbaso;-32.3667\nVardhamānkota;17.3775\nGalten;56.1533\nAlcarraz;41.5638\nJoigny;47.9822\nBūdanūr;12.5500\nNirna;17.7700\nGobindpur;24.7820\nHacarí;8.3167\nLoria;45.7333\nÓcsa;47.2934\nPlainville;42.0141\nLādhuka;30.5082\nPodu Iloaiei;47.2167\nVillarrubia de los Ojos;39.2167\nMesetas;3.3781\nWysokie Mazowieckie;52.9192\nLa Matanza de Acentejo;28.4403\nGrimmen;54.1100\nPicnic Point;47.8744\nSabangan;17.0044\nWagner;-12.2869\nWashington;35.5586\nFateh Nangal;31.9453\nEl Haouaria;37.0500\nCardeal da Silva;-11.9419\nAltlandsberg;52.5667\nGlencoe;-46.1833\nAghbalou Aqourar;33.9341\nSarkad;46.7500\nSan Fausto de Campcentellas;41.5061\nPuerto Nariño;-3.7733\nOberstdorf;47.4097\nNueva Esparta;13.7833\nSidi Ahmed El Khadir;32.5167\nArgostóli;38.1739\nSaint-Vith;50.2833\nDushanovë;42.2347\nBijeraghogarh;23.9955\nTazarka;36.5500\nFelpham;50.7905\nDouar Lehouifrat;32.2800\nSchmitten;50.2697\nNashtīfān;34.4344\nSenmanat;41.6086\nSan Juan del Puerto;37.3167\nFürstenau;52.5167\nEidson Road;28.6677\nSint Willebrord;51.5503\nLéguevin;43.5989\nKukraun;25.7647\nUssel;45.5481\nTepe-Korgon;40.6000\nIrigny;45.6731\nSivamalai;11.0319\nSomvārpet;12.5970\nCollege Place;46.0419\nSan Pedro;-33.8944\nUnāo;25.5784\nVesele;47.0189\nFuli;23.1333\nNakao;35.3307\nSevilla La Nueva;40.3475\nGorgāb;32.8658\nDāmargidda;16.8189\nAleksandrov Gay;50.1333\nPingree Grove;42.0855\nCorella;9.6833\nPunta del Este;-34.9667\nVoitsberg;47.0483\nValsequillo de Gran Canaria;27.9808\nYalagüina;13.4858\nZafferana Etnea;37.6833\nTuta;5.7000\nKadiyadda;16.8774\nPathrāha;26.4330\nSekha;30.3586\nNolinsk;57.5667\nAyas;24.2508\nSunbury;40.8616\nRājapūdi;17.1830\nKātūria;24.7476\nHuari;-9.3689\nMonmouth Junction;40.3754\nLoreto;10.3586\nHarran;36.8708\nNhân Trạch;19.0500\nTremonton;41.7187\nGarrison;39.4023\nChandwārā;24.3930\nMiddleton;42.6043\nAlsbach-Hähnlein;49.7413\nUrangānpatti;9.9984\nSaint-Sulpice-la-Pointe;43.7742\nGolbey;48.1958\nAvon Park;27.5898\nLoudéac;48.1778\nMajra;25.7131\nSedona;34.8581\nKommūru;16.0667\nIdanha-a-Nova;39.9167\nHalen;50.9481\nPaso Canoas;8.5333\nSpanish Fort;30.7254\nKottūr;9.9038\nShchuchye;55.2167\nAkabira;43.5581\nLiteni;47.5200\nImías;20.0767\nDetroit Lakes;46.8060\nKhorāgāchhi;26.3344\nBni Boufrah;35.1000\nNattakkādaiyūr;11.0882\nKasāp;25.4702\nPāppampatti;10.4446\nBeckett Ridge;39.3448\nSweet Home;44.4023\nKhem Karan Saray;25.1233\nGhorbanki;26.5697\nWehrheim;50.3033\nArenys de Munt;41.6128\nChełmek;50.1167\nLüchow;52.9667\nNové Město nad Metují;50.3446\nBardmoor;27.8574\nBerlin;44.4869\nMakaha;21.4739\nWhite Horse;40.1919\nBisingen;48.3119\nEhningen;48.6589\nEl Espinar;40.7186\nSan Marzano di San Giuseppe;40.4500\nBohechío;18.7700\nMentone;34.0609\nFort Salonga;40.9068\nSarauni;24.8613\nFultondale;33.6174\nHelena-West Helena;34.5313\nTimmapuram;17.1036\nMuppālla;16.3198\nNowy Dwór Gdański;54.2167\nStratford;46.2167\nLavis;46.1333\nFerros;-19.2319\nAlamosa;37.4752\nFoiano della Chiana;43.2500\nKhajuri;26.5216\nXinpi;22.4880\nMāmā Khēl;34.2500\nAkhuryan;40.7814\nCavriglia;43.5167\nMaserada sul Piave;45.7500\nBluefield;37.2608\nAwans;50.6669\nBarjhar;22.6012\nCoweta;35.9683\nFallston;39.5332\nGokhulāpur;26.2479\nMurrells Inlet;33.5560\nSilver City;32.7783\nAlayor;39.9342\nCervelló;41.3962\nDobre Miasto;53.9875\nValerik;43.1797\nKola;68.8833\nUlaş;39.2725\nUppinangadi;12.7700\nSolsona;41.9944\nKharī;33.3890\nHohenmölsen;51.1564\nVisselhövede;52.9667\nLindesberg;59.5833\nDassel;51.8033\nGrado;43.3881\nCastelfranco di Sopra;43.6236\nSellersburg;38.4028\nPechory;57.8167\nKuchai Kot;26.5559\nOil City;41.4281\nGopālpur;19.2586\nBāgchīni;26.4817\nSalcea;47.6500\nCébazat;45.8314\nTlagasana;-7.1786\nElne;42.6003\nCastelleone;45.2958\nNeu Bleckede;53.3000\nLaubach;50.5333\nSowān;25.5540\nJawāsa;26.6259\nSémbé;1.6481\nAlfred and Plantagenet;45.5667\nFiladelfia;5.3000\nNiederwerrn;50.0667\nIndianola;33.4492\nAranya Kalān;23.2448\nCholavaram;13.2389\nIlsenburg;51.8667\nTsrār Sharīf;33.8632\nFarsund;58.0947\nMorrisville;40.2074\nRāsol;20.6298\nVempatti;17.4488\nMonte Porzio Catone;41.8167\nSegarai;10.7300\nPorto Tolle;44.9500\nKorwār;16.9200\nTzitzio;19.4449\nAlgūn;31.2795\nKalvārpatti;10.6250\nMādepalli;12.5491\nAttnang-Puchheim;48.0167\nLa Victoria de Acentejo;28.4348\nTandarāmpattu;12.1533\nKhodoriv;49.4100\nSüdlohn;51.9436\nAndiyappanūr;12.5342\nLuís Gomes;-6.4139\nẤp Tân Ngãi;10.2369\nCountry Club;37.9687\nTrzebiatów;54.0625\nKrasnogvardeyskoye;45.1278\nThomaston;32.8907\nAnjēhalli;12.1395\nKadanādu;11.4607\nCuéllar;41.4009\nSanta Monica;10.0200\nDouar Messassa;34.2803\nWhite Marsh;39.3819\nRangāpuram;15.4092\nTālakulam;8.1824\nBarpathār;26.2871\nArmutlu;40.5194\nOlivares;37.4167\nRockcreek;45.5526\nKunnattūr;11.2727\nAdelsdorf;49.7112\nAgareb;34.7414\nKovilpatti;10.0283\nLincoln City;44.9751\nBabhangaon;25.7897\nGamail;25.7062\nHârşova;44.6833\nFairfield;41.0064\nKankanālapalle;15.9923\nParsons;37.3405\nBesozzo;45.8500\nFauske;67.2594\nPrudente de Morais;-19.4819\nOulad Imloul;32.0333\nSanta Ana;9.2444\nTirúa;-38.3414\nLake Arrowhead;34.2531\nPinhel;40.7833\nBrand-Erbisdorf;50.8689\nTraversetolo;44.6399\nMaserà di Padova;45.3167\nHockley;51.6014\nMont-Tremblant;46.1167\nRoncador;-24.6028\nJagta;26.1321\nImielin;50.1333\nMortágua;40.4333\nMartensville;52.2897\nSidi Bou Othmane;31.9033\nKākarāti;24.5639\nDurgi;16.4242\nTwist;52.6167\nKaruveppampatti;11.3983\nBarleben;52.2000\nKaglipur;12.8006\nCanonsburg;40.2643\nRunkel;50.4053\nHimmatpura;30.5271\nSzubin;53.0167\nEemnes;52.2500\nZwiesel;49.0167\nStary Sącz;49.5625\nPleasant Grove;33.4940\nZadonsk;52.4000\nChokkalingapuram;10.1930\nStriano;40.8167\nMorières-lès-Avignon;43.9417\nBan San Pong;18.9424\nLandivisiau;48.5092\nOnda;25.2452\nIzium;49.1958\nUracoa;8.9129\nDecatur;40.8286\nLowell;36.2561\nClay Cross;53.1637\nElhovo;42.1667\nLuckau;51.8500\nOststeinbek;53.5442\nCorona de Tucson;31.9503\nKensington;41.6284\nSztum;53.9217\nEl Molar;40.7336\nGatteo;44.1000\nItasca;41.9772\nMolagavalli;15.3567\nSanta Lucia di Piave;45.8500\nSarakkayhalli;12.2191\nMarathon;24.7263\nŚroda Śląska;51.1500\nMount Airy;39.3742\nBorogani;46.3667\nVallet;47.1617\nApiúna;-27.0358\nVranjska Banja;42.5556\nElsenfeld;49.8500\nSierning;48.0447\nBikkatti;11.3741\nGorē;8.1490\nSaint-Raymond;46.9000\nRāmachandrapuram;16.5689\nBellūdi;14.4500\nBilozerka;46.6317\nMaḑāyā;33.6878\nRalla;30.1200\nLevokumskoye;44.8228\nMittenwalde;52.2667\nSanta María;-31.2611\nVanavāsi;11.7523\nKanavāypudūr;11.9282\nBrugnera;45.9000\nChhapera;23.8948\nMizhhiria;48.5286\nZschopau;50.7500\nLaSalle;41.3589\nKungsängen;59.4833\nBrewer;44.7835\nEl Cacao;18.5264\nVelyka Dymerka;50.5928\nNorth College Hill;39.2175\nRafelbuñol;39.5922\nKanchanadit;9.1653\nMarano Vicentino;45.7000\nBan Wat Chan;16.8033\nIchenhausen;48.3667\nPalmeira d’Oeste;-20.4158\nEagle Point;42.4677\nUbbergen;51.8333\nSarahs;36.5333\nVoreppe;45.2978\nSebnitz;50.9667\nSuan;10.3333\nPetersberg;51.6000\nWertingen;48.5333\nLa Reina;14.1833\nWābāgai;24.5309\nIrthlingborough;52.3240\nParasbani;25.8249\nBad Bevensen;53.0792\nUppalapādu;16.3862\nGūdalūr;10.7898\nHenderson;-36.2833\nBelley;45.7592\nKāyatha;23.2370\nČepin;45.5167\nBlachownia;50.7833\nObersiggenthal;47.4869\nMokri;25.0184\nEunice;30.4904\nBelmont;39.0622\nOdobeşti;45.7667\nValréas;44.3842\nSan Pedro Nonualco;13.6000\nBuñol;39.4194\nSankt Johann in Tirol;47.5225\nTatoufet;35.0339\nLototla;20.8392\nSan Juan Bautista;14.4167\nBakaly;55.1789\nNangal Lālchand;29.9200\nManuel Urbano;-8.8389\nMiajadas;39.1500\nVareš;44.1619\nDahi;22.1122\nParay-le-Monial;46.4511\nBezliudivka;49.8694\nAschheim;48.1733\nRāni Sāgar;25.6079\nSanganakallu;15.1847\nReinfeld;53.8333\nPeriyamuttūr;12.4630\nŪnagatla;16.9611\nIngenbohl;47.0028\nLa Grande-Motte;43.5606\nBoddikūrapādu;15.6591\nLwówek Śląski;51.1167\nRodeo;38.0367\nBni Gmil;35.0833\nSarenja;25.4449\nBolívar;5.9911\nObernkirchen;52.2664\nEhringshausen;50.6000\nIngleside;27.8703\nYamakita;35.3606\nGirard;41.1665\nSanta Rosa del Peñón;12.8003\nRyki;51.6333\nSchaafheim;49.9242\nSantiponce;37.4353\nGuria;26.1633\nZawyat Sidi Ben Hamdoun;33.0450\nKayyngdy;42.8300\nOuroeste;-20.0008\nRāmgarh;25.2889\nCarlton Colville;52.4540\nĀlampur;24.8721\nSteger;41.4723\nBay St. Louis;30.3281\nSchübelbach;47.1733\nNéa Michanióna;40.4644\nChinnāyagūdem;17.0470\nCatanduvas;-27.0708\nCervera;41.6657\nPararia;26.3400\nBendapūdi;17.2673\nCunday;4.0833\nLa Paz;-33.4667\nSədərək;39.7175\nPudukkottai;10.6118\nSosale;12.2330\nBhui;25.0894\nChaplynka;46.3629\nLangnau;46.9433\nGurmaila;25.4829\nOnchan;54.1750\nAksay;43.3725\nParempuyre;44.9492\nBrandon;52.4474\nChita;6.1667\nMogadouro;41.3333\nNittendorf;49.0256\nNepi;42.2436\nRauco;-34.9167\nIpuiúna;-22.0989\nNalbach;49.3833\nLügde;51.9500\nBang Khla;13.7268\nCastel Gandolfo;41.7469\nJuprelle;50.7167\nPenaballi;17.2103\nAmherst;45.8167\nPohrebyshche;49.4869\nChahār Borj-e Qadīm;37.1231\nLegnaro;45.3500\nEl Amim;32.2067\nGhālib Kalān;30.8372\nBull Mountain;45.4125\nSankt Valentin;48.1747\nIstrana;45.6833\nFossombrone;43.7000\nMendicino;39.2628\nAmityville;40.6696\nAmbatolahy;-19.7333\nNeuried;48.0933\nIaras;-22.8667\nTadworth;51.2940\nÁguia Branca;-18.9828\nEcatzingo;18.9500\nRehau;50.2500\nSturgeon Bay;44.8228\nShanklin;50.6333\nRāmapattanam;10.7106\nMorānha;27.1874\nViagrande;37.6167\nPokotylivka;49.9139\nBurayevo;55.8425\nEurajoki;61.2000\nAragona;37.4019\nMorehead City;34.7308\nRudraprayāg;30.2800\nModra;48.3317\nSukkāmpatti;10.5267\nPagqên;33.9739\nHemau;49.0519\nBāgeshwar;29.8380\nVilla Castelli;40.5833\nLa Loggia;44.9577\nOuédémè;6.7000\nHagaribommanahalli;15.0400\nCarencro;30.3126\nBastrop;30.1113\nSuccasunna;40.8530\nHernando;28.9451\nWaltham Cross;51.6860\nWhitestown;39.9706\nPeriyapōdu;10.6099\nOrchies;50.4747\nSogām;34.5014\nGandhwāni;22.3400\nVarre-Sai;-20.9308\nGanāram;18.5275\nIkeda;36.4212\nHostivice;50.0814\nVallahbhāpuram;16.3528\nGomaringen;48.4519\nAngichettippālaiyam;11.7742\nSan José Guayabal;13.8500\nBom Jesus;-5.9839\nZacualpan de Amilpas;18.7836\nGonfreville-l’Orcher;49.5053\nTomah;43.9879\nPasivedalajimma;17.0072\nMiltenberg;49.7039\nHalgeri;14.5551\nRauenberg;49.2678\nSaßnitz;54.5164\nMonett;36.9218\nCherniakhiv;50.4550\nChechen-Aul;43.2000\nCedar Hills;45.5047\nThe Village;35.5706\nAniskino;55.9417\nJa‘farīyeh;34.7894\nMosciano Sant’Angelo;42.7500\nClaymont;39.8032\nNyzhnohirskyi;45.4464\nNakoushi;26.6825\nCajvana;47.7044\nOakville;41.5893\nTambura;5.5900\nAleksandrovsk-Sakhalinskiy;50.9000\nTriunfo;-6.5789\nHalge;15.8800\nBohemia;40.7717\nWallerfangen;49.3278\nLake Mohawk;41.0149\nMeadowbrook;33.3935\nPallippatti;11.8722\nLesnoy Gorodok;55.6417\nGovindapalle;15.3525\nSungal;32.9392\nJūraqān;34.8850\nSavignano sul Panaro;44.4833\nAn Châu;21.3333\nNelali;10.9282\nLanta;7.1000\nAndanappettai;10.7498\nAdjido;7.0333\nAnanás;-6.3658\nGreenwood;35.2134\nLouisville;40.8370\nSauzal;28.4799\nMartano;40.2000\nCarácuaro;19.0167\nRudnya;54.9500\nHerenthout;51.1500\nGaggiano;45.4048\nNorth Gates;43.1718\nMiddlesborough;36.6127\nBinfield;51.4320\nOnnaing;50.3878\nIseo;45.6586\nPérigny;46.1528\nBelvedere Marittimo;39.6167\nElgin;30.3526\nRamara;44.6333\nAadorf;47.4939\nLamarão;-11.7828\nDharhwa;26.9104\nBurela de Cabo;43.6500\nMatawan;40.4127\nSuances;43.4333\nKadlabālu;15.0400\nLititz;40.1540\nMinano;36.0708\nSíndos;40.6706\nPlanaltino;-13.2589\nGranada;4.5186\nHarvard;42.4296\nEsperantina;-5.3428\nGrinnell;41.7359\nSoubakaniédougou;10.4824\nYutsa;43.9625\nJājireddigūdem;17.3278\nDhāmnod;23.4421\nTerra Roxa;-20.7889\nSantanópolis;-12.0169\nCastellabate;40.2789\nConning Towers Nautilus Park;41.3850\nItiki;14.9510\nSusāri;22.1797\nHuedin;46.8700\nArenápolis;-14.4500\nParabita;40.0500\nRiachuelo;-10.7278\nHombrechtikon;47.2500\nVallendar;50.3971\nPerwez;50.6241\nZwenkau;51.2175\nMiddletown;38.2410\nNieuwleusen;52.5833\nMhâjâr;35.1200\nBystrzyca Kłodzka;50.3000\nDielheim;49.2825\nOpalenica;52.3078\nSidi El Hattab;32.2667\nOakwood;39.7202\nVillacañas;39.6333\nMiddletown;40.2010\nGooik;50.8000\nGrossos;-4.9800\nAblu;30.3391\nDāvulūru;16.2625\nDānesfahān;35.8108\nLeeds and the Thousand Islands;44.4500\nFilottrano;43.4333\nVárzea do Poço;-11.5289\nBethel;39.8458\nCarignan;45.4500\nBrockton;44.1667\nSão Domingos;-26.5578\nEast Brandywine;40.0364\nTārazu;34.2714\nVega Alta;18.4151\nHartland;43.1029\nFársala;39.2833\nLa Chapelle d’Armentières;50.6728\nBudenheim;50.0167\nWau;-7.3389\nKirs;59.3500\nMissaglia;45.7000\nSouth Abington;41.4900\nLa Ferté-Bernard;48.1867\nCambridge;45.5612\nLa Mujer;36.7523\nAlmagro;11.9108\nShira;54.4939\nCapbreton;43.6419\nSan Francisco Libre;12.5061\nMohelnice;49.7770\nMandalavādi;12.6073\nHegde;14.4667\nDubrovytsya;51.5667\nOlho d’Água do Casado;-9.5000\nVilla Cañás;-34.0000\nCape Elizabeth;43.5891\nMidland;47.1734\nAsolo;45.8000\nAlawandi;15.2303\nBan Tha Phra;16.3298\nLillebonne;49.5208\nGreat Dunmow;51.8730\nClarksville;35.4570\nKodigenahalli;13.7214\nMadanāncheri;12.7034\nHarqalah;36.0333\nNāgāyalanka;15.9500\nDonabagatta;13.8951\nYanchep;-31.5500\nEsanai;11.3004\nAdolfo Gonzáles Chaves;-38.0333\nPandino;45.4000\nIncline Village;39.2639\nSirāli;22.1519\nNiesky;51.3000\nPryor Creek;36.2996\nLovosice;50.5151\nRaunds;52.3450\nBraslaw;55.6391\nLes Sorinières;47.1483\nBorovskoy;53.7964\nTissint;29.9006\nPizzo;38.7333\nBārun;24.8602\nSīlaiyampatti;9.8732\nTrebisacce;39.8667\n’s-Gravendeel;51.7833\nLivron-sur-Drôme;44.7728\nKottapālem;17.4360\nVochaïkó;37.9333\nGrigoriopol;47.1503\nCross Lanes;38.4351\nKondūru;16.6780\nMaddūr;16.8667\nLedbury;52.0339\nWaiuku;-37.2490\nTeisendorf;47.8500\nSan Fructuoso de Bagés;41.7507\nKurichchi;11.7276\nMoḩammad Yār;36.9831\nHuinca Renancó;-34.8333\nMooresville;39.6022\nLaufenburg (Baden);47.5656\nLe Muy;43.4725\nTurín;13.9667\nAbra Pampa;-22.7167\nTeghra;26.4929\nWunsiedel;50.0167\nAlma;43.3799\nDunblane;56.1838\nBad Laer;52.1031\nCatral;38.1594\nSan Sebastián de la Gomera;28.0922\nCastelli;-25.9500\nCountry Club Estates;31.2113\nAlfredo Wagner;-27.7000\nSanta Maria;-24.9389\nBūdamangalam;12.3792\nMontes Altos;-5.8308\nOrivesi;61.6750\nMudhol;15.6406\nGammasa;31.4182\nVarzedo;-12.9708\nDehri;25.4252\nDiamondhead;30.3791\nGreenville;40.9986\nHavre;48.5427\nCistérniga;41.6167\nSpáta;37.9667\nNegrete;-37.5833\nKrasnoslobodsk;54.4333\nSan Ignacio;9.7997\nBethalto;38.9015\nPūttai;11.8957\nSa Pa;22.3356\nMutis;6.2167\nSavenay;47.3611\nMendig;50.3744\nAniva;46.7167\nAmtala;26.1000\nSanta Comba;43.0383\nStevenston;55.6450\nLidzbark;53.2603\nSorala;19.1492\nGouvieux;49.1878\nTreia;43.3114\nGangapatnam;14.5237\nDuvvūru;14.5507\nNārāyanpur;17.8589\nLaghzawna;33.1890\nSandy Hook;41.4128\nVelampatti;10.2311\nBridge City;30.0298\nLe Rheu;48.1019\nNandnāwān;25.0785\nAmeskroud;30.5308\nVerkhneyarkeyevo;55.4458\nYenmangandla;16.8839\nLa Bruyère;50.5000\nHallstadt;49.9333\nKandel;49.0833\nMelpanaikkādu;10.2599\nMorubāgalu;13.9702\nSchlangen;51.8167\nLower Swatara;40.2188\nMuro del Alcoy;38.7797\nPorcari;43.8415\nMadeira;39.1856\nHelsinge;56.0222\nNärpes;62.4667\nSæby;57.3294\nSt. Stephens;35.7642\nBiblis;49.6841\nSanta María de Cayón;43.3114\nLamorlaye;49.1550\nTysmenytsia;48.9008\nSibilia;15.0000\nCavalcante;-13.7978\nPfedelbach;49.1750\nLe Mont-sur-Lausanne;46.5217\nTonneins;44.3897\nSéné;47.6197\nKöse;40.2100\nKod;22.8850\nBovalino Marina;38.1500\nColumbia City;41.1612\nDenham Springs;30.4743\nTāla;24.3735\nDouar Ezzerarda;34.7667\nSompting;50.8303\nChaponost;45.7103\nGūgi;16.7292\nChesapeake Ranch Estates;38.3574\nLaurentian Valley;45.7681\nSabiñánigo;42.5186\nSavādi;15.6469\nKolkwitz;51.7496\nSan Lorenzo;14.0333\nChinna Kalaiyamputtūr;10.4714\nCountryside;39.0518\nUniversity of Virginia;38.0405\nCoccaglio;45.5633\nCurepto;-35.0833\nHirehalli;14.3200\nLempdes;45.7711\nPedda Muppāram;17.4792\nIfigha;36.6667\nRāmpatti;26.0028\nIrshava;48.3172\nIgaratá;-23.2044\nOuled Rached;36.2119\nRochelle;41.9197\nAçucena;-19.0728\nBorio;25.0344\nWest Glens Falls;43.3057\nNavappatti;11.7393\nNeginhāl;15.7900\nTettu;13.6275\nDardilly;45.8056\nAvabodji;6.4533\nMīrjāveh;29.0147\nSherborne;50.9469\nKargat;55.1956\nCurrumbin;-28.1580\nLe Petit-Couronne;49.3856\nMunagāla;17.0500\nEast St. Paul;49.9772\nEdelény;48.2967\nKurichedu;15.9026\nFolignano;42.8167\nLa Jigua;15.0333\nLa Fare-les-Oliviers;43.5517\nBelakvādi;12.2550\nGudivāda;17.3974\nSlateng Dua;-8.1324\nKruszwica;52.6772\nRiacho dos Machados;-16.0058\nManhattan;41.4274\nRisaralda;5.1667\nMound;44.9328\nNewmarket;43.0691\nAidlingen;48.6792\nWarren;41.8434\nLubuagan;17.3500\nSiteía;35.2000\nHeath;32.8439\nRichterich;50.8086\nProspect;41.4993\nSangam;17.8958\nHamsāvaram;17.2938\nHāthāpur;26.5609\nTecklenburg;52.2194\nMosrāh;18.6155\nTvrdošín;49.3343\nKibaya;-5.3014\nBābai Kalān;22.8313\nDowlatābād;35.2822\nJori Kalān;24.2045\nPesca;5.5833\nMahāgaon;17.5211\nKopong;-24.4686\nLongvic;47.2878\nIngleshwār;16.5900\nMoka;-20.2190\nFlorence;43.9916\nNová Paka;50.4945\nMonteforte d’Alpone;45.4167\nLorraine;45.6833\nIsbergues;50.6233\nGreen Cove Springs;29.9904\nVerkhneuralsk;53.8833\nPodenzano;44.9500\nCrestline;34.2486\nHirehāluhosahalli;15.0105\nHaiku-Pauwela;20.9156\nAriranha;-21.1878\nKhotyn;48.5078\nNagykálló;47.8833\nRiverside;41.8310\nQuirino;17.1383\nIpiranga do Piauí;-6.8278\nMerrill;45.1820\nGhāt Borūl;17.7700\nSegni;41.6833\nHillsborough;36.0679\nBetania;5.7500\nNārsingi;18.0446\nWerneuchen;52.6333\nFort Stewart;31.8811\nGrabels;43.6481\nKyritz;52.9500\nEvergreen;39.6349\nWillow Street;39.9810\nVila Nova de Cerveira;41.9667\nVendin-le-Vieil;50.4739\nGramsh;40.8667\nTelaprolu;16.5860\nCherasco;44.6500\nBojacá;4.7336\nSangaree;33.0327\nIneu;46.4258\nKoheda;18.1709\nDodji-Bata;6.6833\nNansio;-2.1078\nPorangaba;-23.1758\nHohenhameln;52.2600\nBanārūyeh;28.0842\nVentnor City;39.3457\nYeldūrti;17.9074\nKaleybar;38.8664\nLacchiarella;45.3250\nSainte-Julienne;45.9700\nBinisalem;39.6831\nRensselaer;42.6465\nHyrum;41.6325\nTirano;46.2164\nKot Umachigi;15.5426\nSeydunganallūr;8.6624\nMasandra;44.5167\nConcepcion;8.4167\nShimizu;43.0113\nEcorse;42.2489\nBlackfalds;52.3833\nAdaklı;39.2308\nTirumalaippatti;11.3353\nYvoir;50.3333\nBelousovo;55.0833\nReggiolo;44.9167\nVelakalnattam;12.5505\nAltınyayla;39.2725\nHatti Mattūr;14.9435\nDores de Campos;-21.1089\nNakhon Thai;17.1011\nManzanares el Real;40.7272\nBorgo a Buggiano;43.8833\nLandquart;46.9688\nSint-Martens-Lennik;50.8000\nCaluco;13.7167\nSkwierzyna;52.6000\nKirrāyach;26.6322\nSan Jorge;13.6833\nInveruno;45.5167\nPanjampatti;10.3178\nKūnimedu;12.0885\nKadganchi;17.4437\nKhetko;23.7554\nDhobipet;17.4716\nMiryal;17.5661\nHualañe;-34.9765\nMechanicsburg;40.2115\nLansdowne;39.2365\nWoodway;31.4988\nKoshanam;11.3701\nDāmal;12.8860\nBad Liebenwerda;51.5167\nMels;47.0497\nPlymouth;42.3718\nMīlājerd;34.6219\nClermont-l’Hérault;43.6272\nSan José La Arada;14.7167\nCinderford;51.8225\nIgaratinga;-19.9550\nMagdalena;-35.0833\nPaula Cândido;-20.8739\nSheffield;34.7570\nHighland Park;42.4052\nTerra Nova;-8.2300\nNittenau;49.2000\nCapilla del Señor;-34.2833\nLo Miranda;-34.1900\nTeolo;45.3500\nHeusden;51.0281\nVelykyi Bychkiv;47.9714\nSeddouk Oufella;36.6061\nVeľké Kapušany;48.5503\nSprings;41.0212\nGuryongpo;35.9833\nSrīrāmapuram;16.4071\nStăuceni;47.0875\nKiskunlacháza;47.2000\nWinchester;35.1898\nFairview;35.9815\nAugusta;37.6955\nNong Kung Si;16.6500\nMahomet;40.1888\nCorgao;15.7096\nHohenbrunn;48.0500\nAkālgarh;30.8019\nZörbig;51.6167\nChennayyanakote;12.2719\nYellanda;17.7929\nKambūr;10.1599\nBorgosatollo;45.4761\nWashington;40.9884\nMalahide;42.7928\nSaūmalköl;53.2914\nMolbergen;52.8667\nUrbach;48.8133\nBaláo;-2.9100\nMoman Barodiya;23.6042\nDidymóteicho;41.3500\nBabadag;44.8981\nTanakoub;35.1091\nMonte Rico;-24.4514\nCarignano;44.9069\nPhilippeville;50.2000\nAntônio Dias;-19.6528\nAxixá do Tocantins;-5.6169\nGonzaga;44.9500\nHünenberg;47.1761\nKirchberg;47.4000\nQuakertown;40.4398\nGerstungen;50.9625\nTlahuiltepa;20.9233\nSuwannaphum;15.6078\nPiliscsaba;47.6167\nVaratanapalli;12.5828\nPedda Pendyāla;17.9230\nKotabommāli;18.5333\nHerculândia;-22.0036\nBurscough;53.5960\nJuruaia;-21.2528\nPozo Almonte;-20.2667\nRiverdale;41.1732\nGnarrenburg;53.3864\nMomchilgrad;41.5333\nGuttikonda;16.4300\nMallāram;18.7540\nAljustrel;37.9167\nSucha Beskidzka;49.7403\nTorgelow;53.6167\nZhur;42.1639\nHorodenka;48.6675\nWesterland;54.9100\nKanavāypatti;10.1857\nChikkerūr;14.5326\nFuldabrück;51.2667\nSucre;5.9230\nZavyalovo;56.7922\nSanta María del Tule;17.0465\nOulad Cherif;31.7667\nVignate;45.5000\nTummapūdi;16.3780\nRoanoke;33.0144\nKawara;14.0706\nTillaivilāgam;10.4127\nChotěboř;49.7208\nNeustadt;50.7333\nSidi Lahsene;34.0999\nChala;-15.8519\nStansted Mountfitchet;51.8980\nGuararé;7.8200\nFrodsham;53.2950\nSalto Grande;-22.8928\nAltenbeken;51.7667\nBiberist;47.1828\nSugar Grove;41.7759\nValky;49.8386\nMaddūr;13.2397\nReshetylivka;49.5636\nParedes de Coura;41.9127\nChettiyapatti;10.4240\nTumberi;12.6986\nRio del Mar;36.9607\nDodda Siddavvanahalli;14.2200\nPalocabildo;5.1333\nGródek Nad Dunajcem;49.7333\nKaniwāra;22.2145\nPokrovsk;61.4833\nTroina;37.7833\nGuatapé;6.2333\nDirusumarru;16.4722\nRājod;22.9501\nMalalbergo;44.7167\nNizhniye Sergi;56.6667\nZabok;46.0333\nSt. Francis;42.9716\nFalan;5.1333\nSouthside;33.9007\nChillicothe;39.7953\nMelgaço;42.1167\nNato;-22.3000\nKelso;-33.4186\nLaurens;34.5022\nForestdale;33.5737\nDunn Loring;38.8945\nKalanchak;46.2581\nFort Polk South;31.0512\nAshland;39.8782\nArdooie;50.9667\nZūlakallu;16.4442\nLanivo;-22.2833\nLe Thor;43.9292\nSalzhemmendorf;52.0667\nMontoro;38.0167\nPong Nam Ron;12.9057\nZoeterwoude;52.1333\nAmbara;22.1892\nNaduvalūr;11.4800\nColorno;44.9333\nHosūru;15.3797\nAbaíra;-13.2500\nObukhivka;48.5442\nSūrak;36.5950\nRosário do Catete;-10.6958\nCarneiros;-9.4828\nOborniki Śląskie;51.2986\nUne;4.4019\nGholia Kalān;30.6726\nWaseca;44.0827\nAliquippa;40.6155\nĀdamī Tulu;7.8667\nAslanapa;39.2167\nBahābād;31.8719\nHonganūr;11.9400\nZiębice;50.6000\nDahbed;39.7636\nNangis;48.5550\nHaram;62.6665\nTummalacheruvu;17.7667\nĀgadāllanka;16.7123\nYaxley;52.5200\nSaint-Paul-Trois-Châteaux;44.3489\nSegorbe;39.8519\nSaint-Claude;46.3872\nPotangal;18.5661\nSaint-Philbert-de-Grand-Lieu;47.0350\nDharmājigūdem;16.9000\nFreystadt;49.2000\nDouar Snada;35.0667\nKovvali;16.7333\nBerndorf;47.9428\nSoresina;45.2865\nShawano;44.7748\nMontagnana;45.2333\nLuzzi;39.4500\nHirayama;33.6467\nFurth im Wald;49.3097\nBalvādi;21.4412\nMoss Vale;-34.5500\nI-n-Amenas;28.0500\nVannikkonendal;8.9959\nStryzhavka;49.3103\nPásztó;47.9202\nCharlotte;42.5662\nRoquevaire;43.3494\nAlmargem;38.8475\nBaluntaicun;42.7594\nGolbāf;29.8850\nOromocto;45.8488\nBassenge;50.7586\nPonte Buggianese;43.8408\nFlanders;40.8412\nBurlington;48.4676\nHarleysville;40.2792\nVadacheri;10.7324\nLakhanāpuram;18.7504\nSerramanna;39.4228\nNort-sur-Erdre;47.4394\nMejillones;-23.1000\nPeresecina;47.2500\nTarcento;46.2167\nChtiba;32.2000\nWashington Terrace;41.1683\nMonserrat;39.3575\nAllāhpur;26.3434\nSholaqqorghan;43.7650\nFrankfort Square;41.5219\nPerondi;40.7833\nKrompachy;48.9139\nBeauraing;50.1092\nChécy;47.8936\nWanaka;-44.7000\nSan Antonio;12.4140\nDalavāypattanam;10.6747\nNotre-Dame-de-Gravenchon;49.4892\nMaisaram;17.1329\nPadakanti;18.6942\nEduttavāynattam;11.8057\nCanal Winchester;39.8437\nGrants;35.1538\nO'Hara;40.5092\nBhelsi;24.7866\nTrittau;53.6167\nThorigné-Fouillard;48.1597\nFredensborg;55.9750\nKanchanpalli;17.7427\nBorgoricco;45.5167\nNānguneri;8.4906\nSidi Ouassay;30.0500\nBellerive-sur-Allier;46.1164\nOak Hills Place;30.3690\nL’Isle-Jourdain;43.6136\nSan Manuel Chaparrón;14.5167\nYeşilyurt;40.0000\nRockingham;34.9386\nNellutla;17.7034\nUnterägeri;47.1386\nFurtwangen im Schwarzwald;48.0503\nBir Tam Tam;33.9833\nGlanmire;51.9167\nCopceac;45.8500\nWenzenbach;49.0747\nPepillo Salcedo;19.7000\nRivesaltes;42.7689\nSanto Domingo Petapa;16.8167\nNettādahalli;12.1330\nLorgues;43.4933\nGudlūru;15.0729\nFlowery Branch;34.1712\nGretz-Armainvilliers;48.7411\nOlesno;50.8750\nPike Road;32.2939\nVinjam;13.2544\nElsfleth;53.2333\nEgg;47.3019\nBlackstone;42.0399\nRichmond Heights;38.6309\nBandamūrlanka;16.5170\nAmapá;2.0528\nTibaná;5.3167\nPlön;54.1622\nFujisawachō-niinuma;38.8585\nYel’sk;51.8167\nOggiono;45.7833\nVanduvāncheri;10.4292\nLunner;60.2528\nNeuhaus am Rennweg;50.5167\nConsacá;1.2000\nNagaoki;32.9781\nOlds;51.7928\nJerez de los Caballeros;38.3203\nKalicherla;13.8833\nPiriápolis;-34.9000\nMandurah;-32.5289\nVillamediana de Iregua;42.4264\nMaidencreek;40.4618\nMwaline al Oued;33.4467\nKilānkundal;10.7543\nTullukuttināyakkanūr;9.8149\nKożuchów;51.7500\nZarbdor Shaharchasi;40.0747\nZogno;45.7939\nWaldheim;51.0667\nMustafābād;18.2787\nAratuípe;-13.0789\nWillowbrook;41.7641\nŻychlin;52.2453\nJanglot;32.4353\nHorokhiv;50.4994\nRompicherla;13.7228\nModachchūr;11.4415\nPalm Beach;26.6945\nRāmnagar;32.8073\nNeuötting;48.2167\nBanak;27.8722\nÇardak;37.8247\nBeecher;43.0903\nBenton Harbor;42.1159\nDörverden;52.8500\nTimmendorfer Strand;53.9944\nChannubanda;17.0331\nPetilia Policastro;39.1167\nBundāla;31.1429\nBridgeport;39.3036\nMikhaylovka;43.9283\nMemmelsdorf;49.9328\nLe Teil;44.5453\nTulbagh;-33.2850\nTournan-en-Brie;48.7406\nOrtenberg;50.3558\nAbalessa;22.8900\nBorgholzhausen;52.1000\nChalgeri;14.5652\nVerdejante;-7.9256\nElze;52.1167\nJainagar;24.3756\nAviano;46.0667\nGlens Falls North;43.3350\nRain;48.6833\nCoqueiral;-21.1889\nUsakos;-22.0000\nVīrapperumānallūr;11.7763\nBingham;52.9520\nMonteroni d’Arbia;43.2333\nCarbonita;-17.5269\nKandanāti;15.6997\nSângeorgiu de Mureş;46.5500\nBruchhausen-Vilsen;52.8333\nCosta Volpino;45.8306\nBishamagiri;19.3849\nKara-Bak;40.1583\nSalisbury;42.8465\nSolita;0.8667\nCastagneto Carducci;43.1667\nḨīsh;35.5464\nAl Bardīyah;31.7600\nPā’īn Chāf;37.2294\nValasa;14.1632\nKoppunur;16.4867\nCarmen de Carupa;5.3503\nHundested;55.9667\nBoukhralfa;36.6144\nBichura;50.5864\nGundumāl;16.8939\nPine Lake Park;40.0017\nVilla Chalcatongo de Hidalgo;16.9929\nPenugolanu;16.9771\nKressbronn am Bodensee;47.5958\nLoeches;40.3833\nDuchcov;50.6039\nPedda Nindrakolanu;16.7342\nRanjal;18.7458\nDospat;41.6500\nSan Zenón;9.2450\nTiburon;37.8854\nSan Lorenzo de Descardazar;39.6090\nSt. Anthony;45.0278\nPalmeiras;-12.5289\nTrilj;43.6167\nCrvenka;45.6583\nPanthersville;33.7059\nHaddington;55.9560\nKatoomba;-33.7150\nUrânia;-20.2458\nLlagostera;41.8292\nChadan;51.2833\nIijima;35.6767\nKißlegg;47.7900\nOchsenhausen;48.0722\nEstanzuelas;13.6500\nKottadindulu;16.4830\nEast Grand Forks;47.9286\nHuron East;43.6300\nCastelnuovo Berardenga;43.3474\nHarahan;29.9374\nZeydābād;29.6000\nCampamento;6.9789\nQuéven;47.7886\nThāndewāla;30.4720\nScenic Oaks;29.7038\nOberriet;47.3164\nKeregodu;12.6333\nOakengates;52.6950\nBurgos;16.5250\nRiverside;41.0318\nLichtervelde;51.0333\nVelyki Luchky;48.4200\nMühlhausen;49.2475\nGtarna;32.9724\nKot Fatah;30.1122\nRio Acima;-20.0878\nIguidiy;30.7467\nKaeng Khro;16.1086\nCoronel Murta;-16.6189\nSmithville;39.4929\nLugoff;34.2113\nNunihāt;24.4843\nThung Sai;16.2955\nSeini;47.7478\nAnísio de Abreu;-9.1889\nCivitella in Val di Chiana;43.4167\nGuardiagrele;42.2000\nKalas;15.0981\nGarsekurti;18.5083\nCogoleto;44.3894\nOak Hills;34.3910\nSilvārpatti;10.1180\nKharsod B;23.2225\nTarusa;54.7333\nEmbalse;-32.1833\nVelden am Wörthersee;46.6125\nSini;22.7933\nSirikonda;17.1947\nNeuenkirchen;52.5167\nDoberlug-Kirchhain;51.6167\nSauce;-30.0667\nDzhalka;43.3186\nBolokhovo;54.0833\nCutrofiano;40.1167\nTerrace Heights;46.6045\nEntraigues-sur-la-Sorgue;44.0031\nTiachiv;48.0114\nTineo;43.3095\nPolakala;13.3458\nLa Florida;1.3017\nTagapul-an;12.0500\nMnichovo Hradiště;50.5273\nKodavatipūdi;17.4887\nVergiate;45.7167\nWoodbury;40.8176\nNelkattumseval;9.2400\nBernolákovo;48.1992\nNavoloki;57.4667\nFarra di Soligo;45.8833\nNimmekal;17.2372\nParanaiguana;-18.9158\nPullalacheruvu;16.1584\nKratovo;55.5911\nSomero;60.6333\nRoccastrada;43.0097\nTrissino;45.5667\nTutrakan;44.0500\nBig Rapids;43.6992\nFelino;44.6936\nKosum Phisai;16.2430\nKharovsk;59.9500\nStará Turá;48.7767\nAkat Amnuai;17.5898\nDeshnur;15.7900\nBālumāth;23.8298\nAmingaon;26.2300\nAransas Pass;27.8876\nWaldenbuch;48.6372\nWaterford;37.6429\nFort Irwin;35.2477\nHerseh Chhīna;31.7453\nRathdrum;47.7948\nOsicala;13.8000\nIgana;7.0333\nRada Tilly;-45.9333\nWasilla;61.5770\nYakakent;41.6222\nSalem;40.0539\nSäffle;59.1333\nCheste;39.4797\nBarhagarh;19.5676\nDes Peres;38.5973\nCresskill;40.9405\nLynwood;41.5235\nMadnūr;18.5000\nZalishchyky;48.6392\nPântano Grande;-30.1908\nEpanomí;40.4261\nPedrinhas;-11.1919\nRedlands;39.0886\nCalamar;1.9206\nGalbiate;45.8000\nMalangām;34.4383\nMiddleton;43.7113\nChiţcani;46.7833\nNāgaiyampatti;11.4639\nPortlethen;57.0610\nChinna Mupparam;17.6319\nBreckerfeld;51.2667\nÅmål;59.0500\nShar;49.5858\nLa Celia;5.0019\nTha Luang;15.0697\nBad Schussenried;48.0067\nPāppākudi;8.7520\nBérégadougou;10.7667\nHerzberg;51.6833\nDeodora;22.6149\nCasca;-28.5608\nPicture Rocks;32.3274\nNanzhuang;24.5699\nSilves;-2.8389\nVista Alegre do Alto;-21.1708\nHarīke;31.1661\nGrenade;43.7714\nSiklós;45.8519\nSan Francisco;14.1167\nHāta;25.0460\nLivno;43.8269\nÍquira;2.6500\nElsmere;38.9948\nKandanūr;10.1037\nAdigoppula;16.4402\nVinhais;41.8167\nCaputira;-20.1719\nSorisole;45.7375\nLançon-Provence;43.5925\nVerkhnyaya Tura;58.3594\nDhībān;35.0025\nKhānāpur;17.9004\nChitvel;14.1667\nEdgewater;38.9373\nMuhos;64.8000\nChrysoúpoli;40.9833\nWaldfeucht;51.0667\nSaline;42.1740\nRafard;-23.0117\nPa Mok;14.4921\nBellheim;49.1981\nPolička;49.7147\nNierstein;49.8694\nKings Grant;34.2664\nVilla Aberastain;-31.6500\nAcobamba;-12.8431\nTilvalli;14.6268\nBeaver Falls;40.7619\nWhite Meadow Lake;40.9241\nBni Sidel;35.1392\nPerkasie;40.3720\nFallon;39.4737\nGisborne;-37.4900\nWhippany;40.8233\nHad Dra;31.5833\nCherry Hinton;52.1849\nNoventa Vicentina;45.2833\nBorgo;42.5539\nBrownfield;33.1757\nAbcoude;52.2700\nHiramandalam;18.6708\nWollert;-37.5833\nBuriti Alegre;-18.1439\nFlekkefjord;58.2969\nDékanmé;7.1333\nGroßbeeren;52.3551\nSunset Hills;38.5310\nWestampton;40.0168\nSaudade;-26.9239\nBansko;41.8385\nLanark;55.6749\nJanuário Cicco;-6.1578\nPalazzolo Acreide;37.0617\nMiramar Beach;30.3854\nObernburg am Main;49.8400\nMonistrol-sur-Loire;45.2925\nGlenshaw;40.5391\nHirson;49.9217\nSubiaco;41.9333\nGreenville;43.1797\nBayabas;8.9678\nCeprano;41.5500\nSaint-Jean-d’Illac;44.8097\nLaveno-Mombello;45.9089\nThaon-les-Vosges;48.2505\nLinares;1.3500\nNorthwest Harborcreek;42.1494\nSão Jorge d’Oeste;-25.7058\nAmadalli;14.7667\nCrest;44.7283\nAngelópolis;6.1333\nMorlupo;42.1435\nBeldibi;36.8667\nÇayırhan;40.1000\nLittle Falls;45.9862\nDavenport;28.1587\nBernalillo;35.3127\nNewark;43.0418\nNeves Paulista;-20.8458\nSan Pablo Villa de Mitla;16.9170\nToccoa;34.5810\nZunilito;14.6167\nMāgam;34.4595\nSanta Sylvina;-27.7833\nDāla;30.7773\nPunnappatti;10.2243\nSai Ngam;16.4669\nKozova;49.4318\nBallenstedt;51.7200\nDunavarsány;47.2781\nNuevo Paysandú;-32.2667\nHemmoor;53.7025\nAbsecon;39.4229\nAyr;-19.5744\nKarlıova;39.2992\nStanley;49.1331\nÇayırlı;39.8056\nYapraklı;40.7500\nKhoni;42.3244\nBommagondanahalli;13.8984\nSan Giorgio di Piano;44.6500\nMaravilha;-9.2358\nDelta;38.7560\nRhymney;51.7590\nUspenka;48.3939\nBharno;23.2204\nCoffeyville;37.0519\nSande;53.5022\nAlbinea;44.6167\nCoronel Du Graty;-27.6667\nAbirāmam;9.4423\nCandeal;-11.8078\nFitzgerald;31.7134\nFairless Hills;40.1783\nWervershoof;52.7300\nPhopnār Kalān;21.2365\nCraig;40.5171\nMcFarland;43.0203\nThap Than;15.4570\nLibonik;40.7500\nBerching;49.1000\nSítio Novo de Goiás;-5.6008\nBolnisi;41.4500\nBargersville;39.5412\nCloverdale;38.7962\nMburucuyá;-28.0500\nDevnya;43.2167\nFlorstadt;50.3158\nPomichna;48.2500\nBersenbrück;52.5333\nNāttarasankottai;9.8690\nMānpur;22.4315\nRāgampet;18.6383\nÇatalağzı;41.5000\nMādāram;19.1653\nHope;33.6682\nKoekelare;51.0906\nAuerbach;49.6833\nHoyo de Manzanares;40.6333\nKattirippulam;10.4640\nBuşteni;45.4117\nKodaimangalam;10.4733\nPuerto Octay;-40.9667\nKarkkila;60.5333\nEngerwitzdorf;48.3397\nSarlat-la-Canéda;44.8900\nVolkach;49.8667\nNatividade;-11.7100\nḨalāwah;32.3828\nSanta Venerina;37.6833\nUrdinarrain;-32.6856\nArboledas;7.6667\nSan Francisco Ixhuatan;16.3514\nCzarna Białostocka;53.3000\nHailey;43.5141\nYelnya;54.5833\nPāta Uppāl;18.1799\nBachchannapet;17.7883\nKālkuni;14.6000\nRondon;-23.4108\nUricani;45.3364\nMarguerittes;43.8600\nMbamba Bay;-11.2833\nPyālakurti;15.7286\nOlney;38.7285\nMount Pleasant;40.9625\nIscuandé;2.4444\nRolesville;35.9223\nSzentgotthárd;46.9488\nPillutla;16.5390\nChop;48.4333\nFoum Zguid;30.0833\nDobříš;49.7811\nPerkiomen;40.2316\nFully;46.1333\nMontalto di Castro;42.3500\nMurillo;26.2642\nOspina;1.0581\nDomérat;46.3603\nTepechitlán;21.6667\nSępólno Krajeńskie;53.4500\nPark Ridge;41.0352\nCameron;39.7444\nPuerto Lleras;3.2694\nZawyat Sidi al Mekki;33.2120\nSheffield Lake;41.4883\nFehrbellin;52.8144\nPulaski;37.0528\nDivisópolis;-15.7258\nLocogahoué;6.8000\nGreat Cornard;52.0245\nBreganze;45.7000\nVeľký Meder;47.8564\nPsyzh;44.2333\nVijayapuri;11.2300\nPotiraguá;-15.5950\nHuasco;-28.4664\nTuscumbia;34.7204\nFlorânia;-6.1269\nTeranikallu;15.6392\nSiachoque;5.5000\nSăbăoani;47.0167\nAngallu;13.6287\nGarching an der Alz;48.1167\nMonastyryshche;48.9900\nCapim Branco;-19.5489\nNuquí;5.7167\nYaguará;2.6661\nTena;4.6547\nGalmaarden;50.7500\nChoceň;50.0017\n’s-Heerenberg;51.8764\nKui Buri;12.0702\nAndré Fernandes;-15.9658\nMorpará;-11.5589\nMaina;23.1712\nLake Park;26.7998\nSaint-Vallier;46.6419\nWoodfield;34.0587\nBumbeşti-Jiu;45.1786\nBhalaiana;30.3290\nFair Oaks;33.9193\nUlātu;23.2766\nPovarovo;56.0767\nInnsbrook;37.6552\nHuntertown;41.2185\nBorskoye;53.0261\nKambhampādu;16.9822\nVicopisano;43.6991\nMinerbio;44.6175\nEmirgazi;37.9022\nSt. Pete Beach;27.7235\nLuzzara;44.9667\nPenetanguishene;44.7667\nDashouping;23.6488\nAla;45.7500\nWinslow;35.0243\nSkidaway Island;31.9372\nSukand;26.6444\nKāoni;30.4000\nSchleiz;50.5833\nPallappālaiyam;11.3891\nMudhol;16.3500\nHawthorn Woods;42.2313\nRanod;25.0748\nSint-Job-in-’t-Goor;51.3000\nVelaux;43.5225\nStrijen;51.7500\nTlumach;48.8669\nItapiranga;-2.7489\nGreenville;41.8820\nNaunhof;51.2778\nOld Orchard Beach;43.5239\nVīrapalle;14.1500\nBad Lauchstädt;51.3667\nHarrodsburg;37.7654\nKusterdingen;48.5222\nArizona City;32.7506\nSekimachi;33.0598\nLadue;38.6377\nSucre;2.0333\nEslohe;51.2500\nHampstead;42.8821\nCarmo do Rio Verde;-15.3539\nKhaur;32.8229\nRaonta;30.5619\nArgelia;5.7425\nBeni Hassane;35.5700\nShahr-e Pīr;28.3106\nGroß Kreutz;52.3997\nBargaon;23.1795\nPeebles;55.6519\nFlorø;61.5996\nAhuimanu;21.4379\nQualicum Beach;49.3500\nAlmagro;38.8878\nGrünheide;52.4255\nTepetitlan;20.1842\nSanta Rita de Caldas;-22.0289\nHooper;41.1599\nDourado;-22.1000\nHanko;59.8333\nFrei Inocêncio;-18.5450\nNesārg;15.9069\nNunchía;5.6333\nSarzeau;47.5272\nHelotes;29.5687\nClusone;45.8833\nPaulo de Faria;-20.0308\nIskourane;30.8433\nBockhorn;53.4000\nDeutsch-Wagram;48.2994\nMikhaylovsk;56.4500\nKulu;39.0892\nQashyr;53.0804\nPark Forest Village;40.7996\nTonk Khurd;23.0983\nMeine;52.3833\nEceabat;40.1839\nNārona;17.5156\nCarmen de Apicalá;4.1500\nTaxkorgan;37.7728\nSan Sebastian;11.7000\nNottampatti;9.9772\nİliç;39.4536\nCockermouth;54.6613\nLequile;40.3000\nCumberland Hill;41.9736\nMannegudam;17.4601\nSan Giuseppe Iato;37.9667\nVidapanakallu;15.0667\nFlorida;-36.8167\nGonzález;8.4000\nArarat;-37.2833\nAchacachi;-16.0444\nKaruppūr;10.4918\nOrte;42.4603\nSuoyarvi;62.0833\nAraújos;-19.9478\nNerk’in Getashen;40.1467\nWestwood;42.3031\nIlarionove;48.4059\nSerafimovich;49.5833\nSrīrangāpur;16.1917\nHilzingen;47.7653\nEdgewater Park;40.0540\nMetsemotlhaba;-24.5531\nSão Sebastião do Alto;-21.9569\nSchwarzenbruck;49.3500\nAngola;41.6433\nPenig;50.9336\nNavipet;18.8022\nBemiss;30.9318\nEdgemere;39.2273\nSaint-Chamas;43.5503\nJagannāthpur;22.2211\nCharters Towers;-20.0765\nBasrūr;13.6308\nMalhada de Pedras;-14.3878\nTopchikha;52.8211\nSilleda;42.7000\nBaía da Traição;-6.6878\nCamenca;48.0167\nLapeer;43.0447\nVairichettipālaiyam;11.2872\nChapel en le Frith;53.3220\nShelawādi;15.5833\nPurcellville;39.1378\nKozlovka;55.8500\nPibrac;43.6169\nFishersville;38.1050\nTakua Pa;8.8658\nPolegate;50.8216\nMakhambet;47.6667\nNapoleon;41.3977\nWattwil;47.2957\nSan José de Gracia;22.1500\nGuntapalli;14.7385\nNueva Guadalupe;13.5333\nRāiparthi;17.7042\nBarth;54.3667\nTaftanāz;35.9969\nHalikko;60.3972\nHale Dyāmavvanahalli;14.2682\nYarmouth;43.7978\nHolagondi;15.0200\nAlvarado;4.5667\nObertraubling;48.9658\nCaister-on-Sea;52.6510\nBāgalvād;16.0528\nHunduan;16.8333\nMsemrir;31.7028\nBrejão;-9.0300\nPudozh;61.8000\nMinervino Murge;41.1000\nHürtgenwald;50.7172\nSummit;47.1694\nOuriçangas;-12.0169\nAit Ikkou;33.5667\nHighland Park;32.8311\nShoshong;-23.0333\nTeruel;2.7500\nSanta María Xadani;16.3667\nManteno;41.2470\nNorth Haledon;40.9628\nHlevakha;50.2604\nBelsh;40.9833\nPedda Penki;18.5853\nMerrydale;30.4998\nSan Martín de Valdeiglesias;40.3640\nIndian Harbour Beach;28.1529\nKoror;7.3419\nRodelas;-8.8508\nKamień Pomorski;53.9700\nImilchil;32.1550\nKolbuszowa;50.2500\nBelhatti;15.0818\nBussy;46.5500\nPalhano;-4.7450\nAnaurilândia;-22.1878\nGilgit;35.9208\nSeosaeng;35.3536\nAk’ordat;15.5500\nPlymouth;43.7447\nAudubon;40.1304\nVif;45.0553\nNova Bassano;-28.7239\nVráble;48.2408\nRignano sull’Arno;43.7237\nSan Martín Hidalgo;20.4350\nCarlosama;0.8658\nTādināda;16.5470\nDilāwarpur;19.0908\nZanica;45.6394\nGuichen;47.9675\nBrandizzo;45.1766\nLoenen;52.2419\nĀmudālapalle;15.9301\nOld Jefferson;30.3776\nAït Ouaoumana;32.7128\nLāndupdīh;23.1478\nFöritz;50.3500\nOak Grove;45.3409\nNeya;58.3000\nMaipú;-36.8667\nBuda-Kashalyova;52.7167\nNotre-Dame-des-Prairies;46.0500\nCampogalliano;44.6833\nReddiyapatti;10.1581\nBouhlou;34.1333\nWeilmünster;50.4333\nTemperance;41.7653\nErchie;40.4333\nWest Perth;43.4700\nKuvshinovo;57.0333\nMedikunda;15.9581\nPonta do Sol;32.6806\nMoe;-38.1722\nRoetgen;50.6500\nPerungulam;8.6413\nShiddāpūr;13.6635\nRoxborough Park;39.4492\nEntrerríos;6.5667\nAgadir Melloul;30.2167\nPresque Isle;46.6868\nIaboutene;35.0670\nBala Cynwyd;40.0116\nCoutras;45.0408\nTalwandi Chaudhriān;31.3000\nLajedo do Tabocal;-13.4750\nSão José da Bela Vista;-20.5928\nPa Sang;18.5261\nTaragi;32.2640\nSoeda;33.5718\nJacareacanga;-6.2239\nRice Lake;45.4864\nMaysville;38.6455\nCordeiros;-15.0389\nCullinan;-25.6728\nRrëshen;41.7667\nMangala;11.9998\nDeniliquin;-35.5331\nJolfā;38.9308\nNagykovácsi;47.5800\nTausa;5.1964\nCastelnuovo di Porto;42.1333\nClinton;38.3716\nToppenish;46.3806\nWest Donegal;40.1297\nWoodmoor;39.1063\nEfringen-Kirchen;47.6556\nAmarzgane;31.0500\nGroßbottwar;49.0014\nMarilândia do Sul;-23.7450\nSaint-Jean-de-Monts;46.7928\nPhimai;15.2229\nRudravaram;15.2660\nPianella;42.4000\nJeannette;40.3277\nNorth Londonderry;40.3227\nBan Ratchakrut;9.7571\nShopokov;42.8400\nMinyar;55.0667\nTrujillo;39.4653\nLienen;52.1461\nBainbridge;41.3855\nZavāreh;33.4489\nDornstadt;48.4692\nSonsbeck;51.6089\nSopot;42.6500\nBálsamo;-20.7350\nCastelbuono;37.9333\nŌtaki;35.2852\nFort Valley;32.5520\nCavan Monaghan;44.2000\nEl Marmouta;32.0838\nCarbondale;41.5714\nKaris;60.0708\nKolumalapalle;15.4774\nBoville Ernica;41.6500\nBertrix;49.8542\nReyes;-14.2958\nGulf Hills;30.4367\nMansfeld;51.5942\nGlencoe;42.1347\nBenahavís;36.5190\nTordesillas;41.5000\nAnantasāgaram;14.5715\nKryzhopil;48.3842\nHosuru;13.7399\nMürzzuschlag;47.6075\nYaragol;16.9047\nPol-e Sefīd;36.1178\nSerra Caiada;-6.1058\nNakaseke;0.7300\nGuajeru;-14.5469\nYacimiento Río Turbio;-51.5333\nClayton;39.6627\nBeibu;24.6639\nKappeln;54.6614\nTarīchar Kalān;25.4118\nLocust Grove;33.3446\nPerryton;36.3928\nG‘ozg‘on;40.5944\nCaimanera;19.9947\nGorodoviki;46.1353\nSoltsy;58.1333\nPadmapuram;19.2428\nNanzhangcheng;37.9108\nBayport;40.7461\nPitman;39.7335\nCedral;-20.9028\nMeshkān;29.4769\nAgnita;45.9731\nMonmouth;40.9140\nLopatcong;40.7091\nYang Talat;16.3997\nNam Som;17.7694\nSidi Dahbi;33.0500\nKuhmo;64.1250\nYellāreddi;18.5239\nRock Falls;41.7724\nTsallagundla;16.3522\nSidi el Mokhfi;34.6039\nHeek;52.1167\nHassi Berkane;34.8333\nOakland;35.2256\nIles;0.9667\nChintakommadinne;14.4267\nArico el Nuevo;28.1904\nMascoutah;38.5192\nFlieden;50.4231\nVestignè;45.3833\nAurisina;45.7333\nTiqqi;29.8667\nFairfield Glade;36.0028\nKukrahill;12.2428\nSan Ignacio;14.6500\nVohburg an der Donau;48.7667\nArnprior;45.4333\nConthey;46.2167\nSavoy;40.0600\nTudela de Duero;41.5842\nThief River Falls;48.1108\nMariinskiy Posad;56.1000\nBad Sooden-Allendorf;51.2833\nTirschenreuth;49.8833\nQorovul;41.5569\nBelozërsk;60.0333\nZapatoca;6.8167\nIvins;37.1742\nVillage St. George;30.3598\nAudenge;44.6836\nIernut;46.4536\nHūdem;14.9100\nHabo;57.9167\nSodankylä;67.4167\nOrting;47.0967\nMerksplas;51.3667\nCandiota;-31.5578\nSmiths Falls;44.9000\nStainz;46.8942\nNūlvi;15.2728\nRoznov;46.8356\nKulpsville;40.2440\nTanudan;17.2814\nĀshtīān;34.5219\nMiyada;35.7689\nPort Jervis;41.3783\nMonte San Savino;43.3333\nAzandarīān;34.5075\nSignal Mountain;35.1448\nBoonton;40.9047\nTleta Taghramt;35.7877\nTashir;41.1244\nLago Vista;30.4519\nMücheln;51.3000\nFranklin;43.4499\nMandalapalle;14.0209\nCape St. Claire;39.0433\nHajdúdorog;47.8167\nGigmoto;13.7833\nUstrzyki Dolne;49.4297\nBloomingdale;36.5793\nGroßräschen;51.5831\nCalbe;51.9033\nHausjärvi;60.7884\nTifra;36.6664\nHainichen;50.9697\nPerry Heights;40.7977\nMajhgawān;24.8000\nJondor Shaharchasi;39.7333\nPorkhov;57.7833\nValley Cottage;41.1162\nSchuylkill;40.1086\nAnthony;32.0131\nTuba City;36.1250\nSkovorodino;53.9833\nRoverbella;45.2667\nChinaur;25.9467\nIbirapuã;-17.6878\nJunín;4.7903\nHöshööt;48.9408\nSanta Lúcia;-21.6850\nTer Apel;52.8756\nVolchansk;59.9333\nVásárosnamény;48.1267\nChachersk;52.9161\nCortez;37.3503\nGremyachinsk;58.5667\nPoteau;35.0282\nLake Villa;42.4184\nStrzyżów;49.8833\nŠtětí;50.4531\nNorth Madison;41.8297\nAmalou;36.4778\nMoranbah;-22.0016\nForbes;-33.3817\nChanute;37.6695\nSokyriany;48.4500\nSan Juan de Arama;3.3736\nBrooksville;28.5404\nAtmore;31.0927\nSeneca;34.6818\nOrtaköy;40.2830\nCollier;40.3991\nRava-Rus’ka;50.2500\nBaraolt;46.0750\nGangājalghāti;23.4200\nBarntrup;51.9831\nSanger;33.3715\nTaft;35.1268\nKościelisko;49.2833\nReichelsheim;49.7149\nOgulin;45.2669\nSteinheim am Albuch;48.6922\nMonforte del Cid;38.3792\nSolotvyno;47.9597\nBarro Alto;-14.9683\nSanatoga;40.2497\nPont-Rouge;46.7500\nChamonix-Mont-Blanc;45.9222\nSan Isidro;9.9369\nRedlynch;-16.8833\nSarbīsheh;32.5756\nFürstenfeld;47.0500\nSzeghalom;47.0272\nBath;43.9346\nGraham;33.1017\nSmižany;48.9556\nFarob;39.2408\nCatuípe;-28.2500\nLe Poiré-sur-Vie;46.7686\nMaryborough;-37.0500\nTăşnad;47.4772\nInékar;15.9492\nTlanalapa;19.8167\nItapeva;-22.7678\nCasorate Primo;45.3167\nSredets;42.3500\nRakitovo;41.9833\nGyümai;33.7560\nAigues-Mortes;43.5667\nPark Hills;37.8211\nMidutūru;15.7667\nClarendon Hills;41.7981\nŻuromin;53.0667\nPiranguinho;-22.4008\nChamplain;45.5333\nUlstein;62.3564\nBriceño;7.1111\nChiusi;43.0167\nSpello;42.9889\nHernani;11.3239\nBooneville;34.6643\nOrosi;36.5433\nBorgentreich;51.5667\nHoquiam;46.9863\nRonciglione;42.2894\nMrakovo;52.7161\nGroßenlüder;50.5925\nCoaticook;45.1333\nTibro;58.4167\nSão Miguel;-5.1250\nAndriivka;49.5325\nMarāveh Tappeh;37.9042\nSan Gavino Monreale;39.5499\nUglegorsk;49.0667\nSantana do Manhuaçu;-20.1078\nPoniatowa;51.1833\nQuezalguaque;12.5078\nWyoming;39.2297\nÇamlıyayla;37.1703\nUeckermünde;53.7389\nFair Lakes;38.8530\nReserve;30.0741\nGubden;42.5658\nLamesa;32.7333\nTangará;-27.1050\nOlmsted Falls;41.3657\nGibsonville;36.0993\nPlabennec;48.5019\nChyhyryn;49.0833\nVillanueva de Córdoba;38.3167\nOrange Park;30.1706\nSollefteå;63.1667\nPerl;49.4667\nEl Espinal;16.4906\nChamba;8.7000\nCordisburgo;-19.1250\nBusk;49.9667\nBarvynkove;48.9067\nNádudvar;47.4167\nPleasant Hill;38.8059\nMinto;43.9167\nEast York;39.9687\nJalhay;50.5572\nKalaun;29.8300\nWiang Haeng;19.5500\nDemirözü;40.1639\nAd Darbāsīyah;37.0728\nDunaföldvár;46.8089\nHollymead;38.1266\nBryan;41.4706\nMorden;49.1919\nLa Libertad;16.7804\nBicaz;46.9108\nCommerce;33.2421\nHakubachō;36.6981\nCovington;35.5660\nWieruszów;51.3000\nVolvera;44.9500\nFerreira do Zêzere;39.6833\nUnterwellenborn;50.6586\nReginópolis;-21.8878\nWesley Chapel;34.9985\nLitchfield Beach;33.4773\nLakhzazra;33.0333\nZuera;41.8692\nHighland Heights;41.5518\nOxford;36.3155\nBushtyno;48.0503\nDobanovci;44.8333\nSortino;37.1667\nOuro Verde;-21.4894\nPenkridge;52.7252\nVirgínia;-22.3328\nDobrada;-21.5167\nMauléon;46.9228\nLong Hill;40.6838\nTecumseh;42.0066\nUsiacurí;10.7500\nMcKee City;39.4465\nLambarkiyine;33.2000\nAndrushivka;50.0167\nHillview;38.0562\nBösel;53.0058\nNefasīt;15.3333\nDorgali;40.3000\nSão Sebastião da Amoreira;-23.4650\nNariño;5.6092\nArealva;-22.0286\nGoundam;16.4144\nLaishevo;55.4000\nTakiéta;13.6806\nMcCordsville;39.8966\nSan Lorenzo;18.1875\nGonzales;36.5055\nUstyuzhna;58.8333\nLa Belleza;5.8614\nYasinia;48.2728\nWorplesdon;51.2720\nMeßkirch;47.9928\nLützen;51.2597\nCanford Cliffs;50.7000\nGavorrano;42.9250\nMicco;27.8683\nFort Mitchell;39.0460\nIttiri;40.6000\nOulad Khallouf;34.7167\nDunn;35.3114\nSolosuchiapa;17.4000\nLipki;53.9333\nVerkhoturye;58.8667\nKosiv;48.3150\nOgden;34.2656\nClinton;35.5069\nDruid Hills;33.7842\nTakaharu;31.9284\nOsternienburg;51.8000\nMono;44.0167\nBaía Formosa;-6.3689\nFrancisco Santos;-6.9928\nKiuruvesi;63.6500\nMuzo;5.5313\nPratápolis;-20.7450\nNa Yung;17.9142\nYalí;6.6767\nJapurá;-23.4700\nItauçu;-16.2008\nFerrandina;40.5000\nRiacho dos Cavalos;-6.4428\nWharton;29.3177\nCalvisano;45.3489\nSummit View;47.1343\nVillage Green-Green Ridge;39.8639\nTanquinho;-11.9789\nGlenwood;41.5410\nJauru;-15.3419\nTorre de Moncorvo;41.2000\nMataraca;-6.6008\nSan Fernando;13.6767\nIndependence;37.2119\nCagli;43.5500\nLöwenberg;52.8960\nKirk of Shotts;55.8230\nRio das Flores;-22.1678\nKennedy;40.4768\nVerkhniy Mamon;50.1678\nTarrafas;-6.6839\nItamari;-13.7778\nMeltham;53.5920\nPöytyä;60.7167\nMahopac;41.3688\nCloster;40.9733\nJóia;-28.6469\nKarmaskaly;54.3694\nDayton;30.0315\nGresham Park;33.7053\nSan Sebastián;18.3356\nDelavan;42.6282\nMonticello;33.6257\nSouth Kensington;39.0188\nAlfonso Castañeda;15.7933\nNovoselitskoye;44.7494\nMonona;43.0540\nQueimada Nova;-8.5789\nToro;41.5200\nIwaizumi;39.8431\nAğlasun;37.6494\nPochinok;54.4000\nLake of the Woods;38.3343\nLanco;-39.4500\nParis;39.6148\nSocorro;34.0543\nDubovskoye;47.4092\nKrupki;54.3167\nItaquara;-13.4508\nHerencia;39.3669\nPokrovka;42.7500\nBaxter;46.3426\nObluchye;49.0167\nWestwego;29.9058\nBee Cave;30.3084\nEl Dovio;4.5167\nLadysmith;48.9975\nSulakyurt;40.1575\nTuneiras do Oeste;-23.8708\nLaitila;60.8833\nAibonito;18.1398\nBridgewater;44.3700\nSanta Isabel do Ivaí;-23.0053\nGuaraçaí;-21.0283\nNova Glória;-15.1428\nGering;41.8275\nLos Altos Hills;37.3669\nLaanoussar;33.6833\nSitka;57.2401\nVyetka;52.5667\nLycksele;64.6000\nNarrabri;-30.3317\nCenter Line;42.4805\nBarre;44.1998\nLewistown;40.5964\nSmithfield;36.9755\nBlanchard;35.1524\nRichland Hills;32.8095\nHastings-on-Hudson;40.9904\nSallisaw;35.4606\nBryans Road;38.6145\nMilton;47.2524\nBiryusinsk;55.9667\nNamsos;64.4656\nChapaev;50.2000\nOrocué;4.7942\nAs Sallūm;31.5500\nOutjo;-20.1089\nBūlaevo;54.9056\nAlvorada;-12.4800\nMoengo;5.6167\nZhänibek;49.4167\nPampa del Infierno;-26.5167\nHammerfest;70.6634\nAguelhok;19.4614\nHeyin;36.0451\nQusmuryn;52.4580\nKibale;0.7911\nDilolo;-10.6833\nSan Julián;-49.3000\nErtis;53.3333\nKemijärvi;66.7167\nBairnsdale;-37.8333\nGaoual;11.7540\nKapoeta;4.7750\nPort Augusta;-32.4925\nLibrazhd;41.1833\nWick;58.4540\nKiama;-34.6708\nCoracora;-15.0170\nThames;-37.1383\nAtherton;-17.2658\nAiquile;-18.1667\nRabaul;-4.2000\nSeymour;-37.0300\nVanrhynsdorp;-31.6167\nPort Saint John’s;-31.6288\nNewman;-23.3539\nTranqueras;-31.1833\nKerikeri;-35.2244\nCooma;-36.2317\nCarnarvon;-30.9667\nTumut;-35.3039\nKieta;-6.2158\nSelfoss;63.9333\nRoma;-26.5733\nNata;-20.2106\nYamba;-29.4400\nNortham;-31.6531\nCharagua;-19.7906\nKishkeneköl;53.6394\nRinconada;-22.4333\nAwjilah;29.1081\nCliza;-17.6000\nStawell;-37.0500\nYeppoon;-23.1288\nMakarov;48.6333\nKaitaia;-35.1125\nScone;-32.0483\nSan Ramón;-13.2672\nKarasburg;-28.0167\nDalaba;10.6560\nIngeniero Guillermo N. Juárez;-23.9000\nOficina María Elena;-22.3451\nZouar;20.4500\nMelut;10.4404\nComandante Luis Piedra Buena;-49.9830\nSan Carlos;-17.4044\nGoondiwindi;-28.5461\nVerkhnevilyuysk;63.4506\nPërmet;40.2333\nCobram;-35.9667\nQueanbeyan;-35.3533\nAlbury;-36.0806\nIngeniero Jacobacci;-41.3000\nBir Anzarane;23.8918\nLithgow;-33.4833\nGyangzê;28.9203\nRichmond;-33.5983\nPolýgyros;40.3783\nVeintiocho de Noviembre;-51.6500\nDinguiraye;11.2990\nBiloela;-24.4002\nChepes;-31.3500\nMaltahöhe;-24.8333\nUncia;-18.4681\nChonchi;-42.6219\nVadsø;70.0803\nBeni Ounif;32.0500\nMali;12.0840\nDesaguadero;-16.5684\nByron Bay;-28.6483\nGeneral Conesa;-40.1000\nSan Antonio de los Cobres;-24.2178\nSingleton;-32.5667\nWonthaggi;-38.6056\nBajram Curri;42.3581\nBilibino;68.0500\nKununurra;-15.7736\nBerri;-34.2833\nOtavi;-19.6500\nJinzhong;26.3504\nMayumba;-3.4167\nVictor Harbor;-35.5500\nLismore;-28.8167\nIgarka;67.4667\nIngham;-18.6508\nMitzic;0.7833\nTurukhansk;65.7931\nSusuman;62.7833\nOranjemund;-28.5517\nBagdarin;54.4444\nSmithton;-40.8440\nSvolvær;68.2353\nWestport;-41.7581\nFinnsnes;69.2294\nPerito Moreno;-46.5886\nNarrogin;-32.9360\nManjimup;-34.2411\nCamargo;-20.6403\nGobernador Gregores;-48.7667\nTepelenë;40.2967\nPofadder;-29.1286\nVictorica;-36.2167\nManica;-18.9344\nSamaipata;-18.1794\nSokolo;14.7328\nMagdalena;-13.2606\nMerimbula;-36.8983\nDehiba;32.0167\nComandante Fontana;-25.3333\nLa Paloma;-34.6500\nPort Hedland;-20.3100\nApolo;-14.7200\nErsekë;40.3333\nLas Lajas;-38.6000\nÇorovodë;40.5000\nPevek;69.7000\nEl Maitén;-42.0500\nKarmah an Nuzul;19.6008\nNautla;20.2167\nSicasica;-17.3333\nVergara;-32.9500\nTeseney;15.1100\nWeipa;-12.6300\nTirupati;13.6500\nPukë;42.0500\nClare;-33.8333\nUlaan-Uul;44.3337\nProserpine;-20.4016\nWallaroo;-33.9167\nKatanning;-33.6908\nLavumisa;-27.3167\nPadilla;-19.3000\nPort Douglas;-16.4834\nYomou;7.5660\nTessalit;20.2011\nTurangi;-38.9889\nBaltasar Brum;-30.7167\nKirkenes;69.7269\nSrednekolymsk;67.4667\nZhigansk;66.7708\nTrancas;-26.2172\nCharleville;-26.4016\nMopipi;-21.2019\nMezen;65.8333\nRørvik;64.8619\nJuradó;7.1114\nHokitika;-42.7156\nMkokotoni;-5.8800\nTeeli;51.0086\nSinnamary;5.3800\nBordertown;-36.3118\nKarungu;-0.8496\nAiguá;-34.2000\nBuur Gaabo;-1.2175\nMangbwalu;1.9352\nTom Price;-22.6939\nI-n-Amguel;23.6936\nEsperance;-33.8611\nLongreach;-23.4422\nPuerto Villamil;-0.9568\nMerredin;-31.4820\nUrubamba;-13.3042\nDonegal;54.6540\nHlatikulu;-26.9667\nRío Mayo;-45.6869\nCochrane;-47.2547\nMount Barker;-34.6300\nSaint-Georges;3.9105\nCloncurry;-20.7047\nScottsdale;-41.1667\nRodeo;-30.2164\nÍsafjörður;66.0758\nBourke;-30.1000\nTe Anau;-45.4167\nChumbicha;-28.8667\nExmouth;-21.9331\nTasiilaq;65.6136\nNauta;-4.5083\nSevero-Kuril’sk;50.6667\nTarabuco;-19.1667\nQueenstown;-42.0667\nBaures;-13.6556\nAl ‘Alamayn;30.8333\nEl Dorado;6.7167\nHöfn;64.2540\nJaqué;7.5181\nBoffa;10.1850\nKatwe;-0.1296\nCoroico;-16.1833\nEgilsstaðir;65.2833\nSaskylakh;71.9653\nLehututu;-23.9169\nSorata;-15.7733\nRoura;4.7300\nKaikoura;-42.4000\nJosé Batlle y Ordóñez;-33.4667\nTumby Bay;-34.3667\nAlexander Bay;-28.6083\nRockhampton;-23.3781\nMaitland;-32.7167\nPenola;-37.3786\nBorgarnes;64.5333\nMazatán;29.0167\nHuinan;42.6229\nInnisfail;-17.5238\nKalyān;19.2502\nMysore;12.3086\nNovyy Port;67.6919\nNokaneng;-19.6639\nBarcaldine;-23.5555\nKingston South East;-36.8167\nGawler;-34.5981\nPeterborough;-32.9667\nStreaky Bay;-32.8000\nPuerto Williams;-54.9333\nCuevo;-20.4500\nAlto Río Senguer;-45.0167\nKalbarri;-27.7100\nArtëmovsk;54.3483\nUummannaq;70.6747\nSierra Colorada;-40.5833\nIracoubo;5.4804\nOuyen;-35.0667\nHalls Creek;-18.2300\nChibemba;-15.7355\nPort Denison;-29.2750\nWagin;-33.3167\nTajarhī;24.2622\nKatherine;-14.4667\nLokwabe;-24.0961\nQasigiannguit;68.8201\nPaamiut;61.9944\nTsau;-20.1686\nZaragoza;13.5833\nSanta Cruz de la Sierra;-17.7520\nTarutung;2.0167\nKazachye;70.7522\nNakhodka;67.7206\nHāthras;27.3600\nPort Pirie;-33.1858\nGreytown;10.9467\nSitalpur;27.6300\nPríncipe da Beira;-12.4167\nLavrentiya;65.5842\nMeningie;-35.6883\nHughenden;-20.8438\nAmbāla;30.3786\nVerkhoyansk;67.5500\nCiudad Arce;13.8333\nCowell;-33.6833\nUad Damran;27.4181\nYulara;-25.2406\nSusques;-23.4167\nUpernavik;72.7869\nChumikan;54.7000\nYélimané;15.1180\nBicheno;-41.8667\nRoebourne;-20.7667\nWinton;-22.3913\nOatlands;-42.3000\nKempsey;-31.0833\nGingin;-31.3400\nGodhavn;69.2472\nAyan;56.4583\nWilcannia;-31.5650\nHarīpur;31.5322\nNanyangcun;36.0819\nLaverton;-28.6280\nPīlibhīt;28.6333\nOnslow;-21.6333\nDudhauni;28.0300\nTamworth;-31.0833\nOmolon;65.2667\nLeonora;-28.8845\nWyndham;-15.4825\nLinxi;43.5171\nComallo;-41.0333\nEidsvold;-25.3667\nPannawonica;-21.6350\nZhilinda;70.1333\nMeekatharra;-26.5931\nPanying;33.0023\nUbombo;-27.5667\nSouthern Cross;-31.2500\nThree Springs;-29.5333\nItuni;5.5333\nAguilares;13.9500\nKimba;-33.1333\nRichmond;-20.7305\nQaanaaq;77.4667\nMālegaon;20.5500\nUelen;66.1594\nTheodore;-24.9500\nGastre;-42.2667\nCandelaria;13.7500\nNorseman;-32.1961\nMikhalkino;69.4353\nNavsāri;20.8504\nTelsen;-42.3833\nSan José Villanueva;13.5833\nKarumba;-17.4838\nIsemi-Ile;7.9700\nMorawa;-29.2111\nTonk;26.1505\nAndamooka;-30.4470\nRavensthorpe;-33.5831\nGeorgetown;-18.3000\nChengde;40.9604\nMount Magnet;-28.0600\nOymyakon;63.4629\nBoulia;-22.9000\nPorbandar;21.6425\nEspungabera;-20.4531\nHalfmoon Bay;-46.9000\nSanta María;13.3500\nSan Ignacio;14.3333\nAdelaide River;-13.2381\nKairaki;-43.3860\nBurketown;-17.7167\nScoresbysund;70.4853\nProgress;49.7504\nIvanhoe;-32.8983\nThargomindah;-28.0000\nPine Creek;-13.8231\nSanta Elena;13.3833\nIkela;-1.1833\nCazombo;-11.9058\nShoyna;67.8778\nEnurmino;66.9500\nTimbedgha;16.2447\nSanta Rosa de Lima;13.6167\nConchagua;13.3000\nEl Tránsito;13.3500\nCamooweal;-19.9167\nCarnarvon;-24.8672\nHubli;15.3619\nKorf;60.3667\nBirdsville;-25.8989\nBedourie;-24.3500\nMount Isa;-20.7261\nWindorah;-25.4206\nPunta Prieta;28.9289\nSharbaqty;52.4800\nChirilagua;13.2167\nAl ‘Uqaylah;30.2558\nVictoria;13.9500\nPasaquina;13.5844\nSesori;13.7167\nKovda;66.6919\nBhuj;23.2500\nKingoonya;-30.9000\nTiyerbes;64.3728\nUst’-Nyukzha;56.5608\nChegga;25.3733\nUst’-Olenëk;72.9855\nOlenëk;68.5000\nAmbarchik;69.6167\nLogashkino;70.8536\nCharlotte Amalie;18.3420\nVohitrafeno;-21.6667\nVinanitelo;-21.7167\nBolsward;53.0667\nGūlyam;15.3598\nAntsoantany;-19.7000\nMiadanandriana;-19.0333\nMahabako;-21.7500\nAmbahatrazo;-21.8667\nPuttige;13.0751\nVondrozo;-22.8206\nAmbatolava;-23.5667\nIsahara;-23.7167\nAntaretra;-21.0667\nTamponala;-19.3000\nAmbodivoara;-14.4000\nMorafeno;-21.2000\nZávora;-24.5167\nErraguntlakota;13.9622\nAmbohitrambo;-18.9167\nAnkirondro;-19.6333\nAmbohimahazo;-20.6667\nMataguá;22.2370\nŢālkhvoncheh;32.2631\nAndranambolava;-20.9000\nMarosakoa;-16.2333\nBelavabary;-18.8333\nAnkerana;-21.0333\nSahatona-Tamboharivo;-20.9667\nAmpitahana;-21.1333\nSoatanana;-21.3833\nAmbararatabe;-18.9900\nAboso;5.3633\nZoma-Bealoka;-18.8500\nSahanivotry-Manandona;-20.1167\nBoanamary;-15.8333\nVinanitelo;-22.0167\nBeanana;-17.3667\nAmbodimadiro;-14.6000\nAmpasimazava;-17.6667\nIfarantsa;-24.9333\nTanambao-Daoud;-13.9833\nTujg;32.0686\nMora;14.3278\nKalimala;18.0738\nAmbatomivary;-23.8333\nVohitany;-24.1333\nThị Trấn Mậu A;21.8781\nMaroharatra;-20.7333\nMiarinarivo;-22.0833\nAmbatomifanongoa;-20.2667\nAmbovonomby;-14.3667\nLos Ríos;18.5219\nDaraina;-13.2000\nAmbohimiarivo;-19.8500\nDujiashigou;37.7691\nAnosimparihy;-21.5000\nSandravinany;-24.0333\nMurgap;37.4964\nMazoe;-17.5167\nBunji;35.6422\nSoavimbahoaka;-18.6833\nAmparihy;-15.6667\nAmbatolahy;-22.5333\nFanjakana;-21.1833\nMasiaboay;-23.9000\nAmbodisikidy;-14.2333\nEbelo;-24.4833\nMboki;5.3160\nChartoûn;33.7711\nMiary-Taheza;-23.1333\nAndranomenatsa;-23.3167\nVohitsaoka;-22.0333\nEsira;-24.3333\nSoahany;-18.6667\nVodiriana;-19.1667\nBekodoka;-16.9667\nIanapera;-23.6167\nJangany;-22.8500\nNamakadu;14.0060\nBedidy;-17.4667\nAmbodimandresy;-14.7833\nTsararano;-17.3333\nGadoon;5.6897\nBeheloka;-23.9017\nAmbalanjanakomby;-16.7000\nMahabe;-17.0833\nAndranopasy;-21.2833\nTīgaon;21.6456\nAnontsibe-Sakalava;-21.3667\nKatsepy;-15.7667\nTanamarina;-21.5731\nAmborompotsy;-20.6000\nBetrandraka;-17.0333\nPuerto America;-11.5500\nSorab;14.3814\nLenīnskīy;52.2528\nYueyaquan;40.1256\nWilliston;44.4345\nColts Neck;40.2928\nBan Non Sombun;18.2983\nP’yŏngch’ang;37.3675\nPālkot;22.8748\nBirni Lafia;11.9783\nBan Phan Chali;16.6333\nNarasimharājapura;13.6108\nKodivalasa;13.2547\nAmbinanintromby;-21.6667\nGamba;-2.7250\nKouarfa;10.4833\nKarimunjawa;-5.8192\nMae O;19.6500\nNödinge-Nol;57.9000\nPenn Forest;40.9571\nMohlanapeng;-29.6975\nRangasamudram;13.7140\nImlil;31.7567\nAnkazotsifantatra;-19.9500\nAmbodiriana;-17.8861\nKrasnyy Yar;53.3239\nJixian;35.7321\nVanipenta;14.7906\nBasso;10.5000\nBan Pha Bong;19.2266\nSūknah;29.0669\nDulce Nombre de Jesús;10.0838\nDjangoa;-13.7833\nAlden;42.9114\nConway;44.0085\nPakhtaobod;38.4667\nSirka;9.5719\nAnjahamana;-18.3667\nPisac;-13.4242\nOulad ’Azzouz;32.7693\nOttappidāram;8.9127\nPiprai;24.5097\nQarabalyq;53.7506\nFandrandava;-21.5167\nBan Bueng Kok;16.6833\nPhilipstown;41.4189\nSävja;59.8167\nRepatriación;-25.5300\nAndrainjato;-21.4667\nSan Fernando;9.2797\nBan Mae Sam Laep;17.9750\nOlmos;-5.9855\nMohdra;24.1849\nSturbridge;42.1076\nPindra;24.9595\nMikun;62.3667\nPondalūru;14.2535\nBan Mae Chedi;19.1833\nBan Dong Mada;19.7237\nDangcheng;39.5161\nBavānāt;30.4667\nSouthport;42.0400\nXiba;40.1645\nWoodbury;41.5615\nSeforong;-30.1028\nTsaramasoandro;-17.9833\nShiyuan;35.7991\nTālavādi;11.7780\nRanomafana;-21.2500\nAk-Suu;42.8000\nChervyen;53.7078\nTayakou;10.5500\nZengjiaba;32.1263\nPleasant Valley;41.7697\nBan Lao Yao;18.3667\nGonikoppal;12.1830\nBarwādih;23.8478\nMallampalli;18.1105\nVenecia;10.3357\nAqadyr;48.2749\nTounfafi;14.0464\nTorihama;35.6006\nDatori;10.4017\nPueblo Viejo;19.1781\nCanoas;8.5333\nĀdivāla;13.9131\nCapitán Mauricio José Troche;-25.7500\nAweitancun;47.7251\nAlberdi;-26.1900\nAvsallar;36.5833\nLangar;39.4500\nMaizal;19.6500\nRamree;19.0833\nMarne;13.3284\nGaada;35.1594\nHerkimer;43.0610\nBan Wiang Ka Long;19.2332\nAnkadimanga;-18.9667\nXiada;24.0391\nNaurhiya;24.2069\nSultan-Yangiyurt;43.2167\nBou Zemou;32.1114\nLisbon;44.0265\nSouth Strabane;40.1756\nBougou;9.4333\nÅhus;55.9167\nIāwar;23.0094\nVəndam;40.9447\nSonsoro;11.0875\nTaisar;22.4867\nDombarovskiy;50.7550\nFitampito;-20.9667\nJianshi;24.5761\nIgrim;63.1933\nSoldato-Aleksandrovskoye;44.2659\nFalam;22.9136\nZhangping;37.6339\nCusseta;32.3470\nKesli;23.4183\nSyurte;48.5033\nSokotindji;10.8528\nButler;41.0358\nBurlington;41.7598\nUkwā;21.9710\nBenbutucun;42.0263\nPedro Luro;-39.5000\nNūlivedu;14.1002\nEsopus;41.8425\nDeh-e Shū;30.4344\nDouar Oulad Bouziane;34.2083\nBerkine;33.7665\nBan Sathan;18.2667\nKanajanahalli;14.1092\nOppicherla;16.4444\nAlakamisy Anativato;-19.8833\nBāyaram;18.0506\nPortland;41.5988\nJantho;5.3000\nMariyādau;24.2762\nKarajgi;17.2827\nTopsham;43.9614\nBan Khi Lek;19.0625\nTimmāpuram;15.4887\nKatteragandla;15.0091\nManchester;42.9921\nShendē;10.6333\nHastings;43.3215\nAnan’evo;42.7300\nGhattupal;17.0725\nAnaconda;46.0608\nMēga;4.0167\nRatangarh;24.8167\nMoisei;47.6561\nNewfane;43.2818\nBarei;9.6833\nĀltūn Kawbrī;35.7533\nBan Kham Pom;15.9653\nSutton;42.1337\nXalqobod;37.4597\nMoore;40.7798\nKondrukota;17.1717\nBoali;4.8000\nBandio;13.8888\nDouar Oulad Sidi Moussa;32.2726\nHelena Valley Southeast;46.6219\nDouar El Mellaliyine;35.6264\nPadinska Skela;44.9500\nChesterfield;40.1166\nAnalaroa;-18.4083\nRancho Mission Viejo;33.5140\nSouthwick;42.0544\nTasso;9.6737\nMikhaylovskoye;43.0997\nXiangping;24.5892\nPrabhāt Pattan;21.6407\nWalworth;43.1633\nBarrington;43.2139\nTalata-Angavo;-18.2000\nVeinticinco de Diciembre;-24.7000\nTanamarina-Sakay;-21.4667\nMonte Cristo;-31.3431\nPhagu;26.8403\nCàbras;39.9333\nPutnam;41.9093\nQorovulbozor;39.5000\nBīkē;9.5297\nMacedon;43.0792\nBorja;-25.9528\nRomang;-29.5000\nḨorr-e Rīāḩī;32.1447\nUmreth;22.1262\nIntich’o;14.2667\nLeichi;36.3351\nLa Cruz;11.0845\nJackson;40.3774\nBan Yaeng;16.8833\nBan Ngio Ngam;17.6671\nQarqaraly;49.4167\nThompson;41.9798\nPodstepki;53.5151\nCrawford;41.5685\nMarale;14.9167\nAs Sidrah;30.6294\nQahramon;40.3050\nSettivāripalle;14.7543\nCanela Baja;-31.3989\nChārakunda;16.6916\nJumlā;29.2500\nFreetown;41.7714\nKharsāwān;22.7909\nMorarano;-19.4333\nAïn el Mediour;30.4000\nDulce Nombre de María;14.1500\nBan Wang Krachae;14.2333\nUsworth;54.9400\nUst’-Nera;64.5666\nTownsend;42.6671\nDallas;41.3608\nDazhuangzi;40.2321\nVinsady;44.0817\nArgudan;43.4200\nGāzulapalle;15.4036\nMorafeno;-14.4000\nAnkarana-Miraihina;-23.0833\nVenkatādripālem;16.0506\nMendon;42.9859\nSānchi;23.4865\nTuskegee;32.4409\nHebron;41.6593\nNorth Codorus;39.8646\nAmbodivoanio;-16.1833\nAlakamisy-Ambohimahazo;-20.4000\nAndilana Avaratra;-17.3500\nNizhniy Odes;63.6500\nIxtapa Zihuatanejo;17.6367\nBazimini;-12.1833\nAnteza;-21.6667\nAntanankambano;-22.0500\nCoatetelco;18.7294\nMahamaibe;-21.7500\nVohilava;-21.7667\nPeddannavāripalle;14.2535\nSalobe;-23.5333\nBemarivo;-17.6333\nAmpary;-19.1833\nYangiobod;41.1192\nSpringfield;43.2907\nDiabugu;13.3833\nAntsahavaribe;-13.8500\nAnjialava;-14.0667\nMitanty;-21.7333\nRanopiso;-25.0500\nSarasambo;-25.1000\nWoodbridge;41.3566\nWeare;43.0813\nNew Scotland;42.6047\nBan Nikhom Phatthana;16.7242\nTsaratanana;-15.6500\nEconomy;40.6411\nFierenana;-18.4833\nKegen;43.0197\nSoamahamanina;-18.9833\nSulahpet;17.4014\nBelinta;-19.9500\nAntsatramidola;-15.6333\nBarskoon;42.1561\nAmbalaromba;-14.6667\nMandīshah;28.3515\nAmbariokorano;-15.8833\nIvandrika;-22.8667\nIara;-23.0833\nAmbodimahabibo;-15.7333\nVatananto;-23.6667\nAmbinanin’ Andravory;-13.7667\nAmbatoharanana;-16.4333\nSoanierana;-25.0000\nBenato-Toby;-23.0833\nBemaharivo;-16.1333\nAmpasimpotsy-Gara;-18.9667\nMarovatolena;-15.1833\nAmbatoria;-14.5000\nWest Manheim;39.7458\nMiddlebury;44.0043\nMaropaika;-22.7000\nSahatsiho-Ambohimanjaka;-20.2000\nAmbarimaninga;-16.5000\nAkpassi;8.4500\nMarotolana;-14.6500\nAntaly;-24.3833\nNanmucun;25.1619\nBan Noen Kum Nueng;16.5500\nAndribavontsona;-15.4000\nManampaneva;-16.0500\nAntambohobe;-22.3000\nNosibe;-13.1500\nAnkiliabo;-24.6833\nAmboronabo;-22.6667\nBekopaka;-19.0167\nStillwater;42.9701\nMahabo;-24.2833\nBeparasy;-19.1667\nManevy;-24.3833\nSoamanonga;-23.8667\nTsimafana;-19.7167\nViale;-31.8667\nSoanenga;-16.5000\nChanco;-36.2667\nAnkirihitra;-16.7667\nAntsaidoha-Bebao;-17.3667\nTandrano;-22.0833\nAmbalajia;-17.4833\nAntseza;-16.2167\nBefotaka;-20.8333\nManja;-21.4333\nJonnagiri;15.2303\nMānsong;27.1662\nLieşti;45.6193\nRutland;42.3848\nLadan Kara;40.9264\nDouglas;42.0524\nEast Haddam;41.4798\nMiyār;13.1945\nBan Muang Kham;19.5008\nBansang;13.4333\nGalela;1.8236\nMarcy;43.1731\nEast Nottingham;39.7621\nKishtwār;33.3135\nAngor;37.4639\nUpper Leacock;40.0801\nDaping;24.6501\nAustralia;22.4995\nWest Caln;40.0237\nSeneca Falls;42.9136\nDouar Ait Taleb;32.3839\nMoulay Abdelkader;34.6422\nToulou;14.1688\nEl Valle;18.9764\nIklod;26.0222\nFrancisco Caballero Álvarez;-24.1543\nTakouta;10.3000\nPendekallu;15.3753\nJabera;23.5582\nBan Si Don Chai;20.1300\nFort Knox;37.8915\nChīchkah;37.0706\nQızılhacılı;40.5808\nBan Pong Tao;18.8333\nMousoulou;7.3899\nPardanjān;32.2539\nAl Abraq;32.7867\nMālaimārpuram;14.2096\nRocas de Santo Domingo;-33.6358\nAmberomanga;-19.2500\nMahela;-19.4833\nIndūrti;17.0055\nBan Sai Yoi;16.4167\nMirdoddi;18.0786\nLenox;43.1113\nMansfield;40.0853\nRedding;41.3050\nRío Jiménez;10.2556\nPittsgrove;39.5404\nFalla;22.1704\nBuenavista;9.3333\nAşağı Quşçu;40.9533\nPacuarito;10.1093\nSalar;33.8789\nRudewa;-10.1008\nUpper Makefield;40.2941\nNayāgaon;24.8015\nHire Vadvatti;15.2235\nMarrupa;-13.1833\nHamlin;43.3213\nBrighton;40.7023\nAndalusia;31.3102\nSegaon;21.8585\nGidan Idèr;14.0131\nTilarán;10.4709\nSobhāpur;22.7737\nSèmèrè;9.6268\nVerkhniye Achaluki;43.3469\nBuved;37.5833\nEllicott;42.1330\nKaravan;40.2944\nMarlborough;41.6337\nSolebury;40.3676\nAl Quway‘īyah;24.0464\nClanton;32.8444\nKaldsletta;69.6956\nPoninguinim;14.9679\nAnkatafa;-13.6167\nNewstead;43.0196\nLondon Grove;39.8327\nPeralta;18.5167\nBan Charoen Mueang;19.6075\nHamilton;40.9334\nMarginea;47.8167\nTanmpègré;10.4800\nChāpalamadugu;16.0730\nMunnelli;14.9200\nPanfilovka;42.7917\nVostochnyy;39.9222\nNerubaiske;46.5467\nChartiers;40.2505\nFreeport;43.8556\nAnjahamarina;-18.0167\nCarneys Point;39.6967\nJackson;39.9057\nEast Donegal;40.0823\nWindsor;43.2405\nChermen;43.1486\nVícam Pueblo;27.6422\nSouth Londonderry;40.2424\nZhujiagua;38.2242\nTionk Essil;12.7856\nCorman Park No. 344;52.2291\nMontague;42.5549\nBarton;42.0812\nGuntersville;34.3671\nHongtuliang;40.9986\nSkowhegan;44.7554\nHelena Valley West Central;46.6634\nAqsū;52.4502\nOlamzé;2.2167\nOlovyannaya;50.9500\nPutina;-15.4700\nOldeani;-3.3500\nOsakarovka;50.5619\nKontcha;7.9667\nCiudad Cortés;9.0221\nCh’osan-ŭp;40.8255\nIqaluit;63.7598\nKalabo;-14.9911\nQazaly;45.7667\nBayghanīn;48.6917\nNeiafu;-18.6508\nLuân Châu;21.7400\nBossembele;5.2667\nBestöbe;52.4997\nTobyl;52.6980\nOkondja;-0.6519\nMelekeok;7.5006\nZambezi;-13.5500\nNicoadala;-17.6077\nKaribib;-21.9381\nZholymbet;51.7502\nKhandyga;62.6660\nNdendé;-2.4014\nSan Matías;-16.3611\nUmba;66.6814\nSan Javier;-16.2748\nTazovskiy;67.4833\nMundybash;53.2333\nAiyomojok;5.7504\nPiggs Peak;-25.9610\nFdérik;22.6783\nTiksi;71.6269\nVossevangen;60.6300\nOkhotsk;59.3830\nFort-Shevchenko;44.5167\nWitu;-2.3889\nTura;64.2833\nSan Quintín;30.4837\nOuadda;8.0667\nHohenau;-27.0796\nTorghay;49.6260\nChernyshevskiy;63.0128\nVilla del Rosario;-24.4167\nMcMinns Lagoon;-12.5329\nQaşr al Farāfirah;27.0583\nPuerto Casado;-22.2896\nUst’-Kamchatsk;56.2167\nMékambo;1.0167\nBetanzos;-19.5533\nBrownsweg;5.0164\nBongandanga;1.5100\nSangar;63.9241\nKhatanga;71.9797\nAl Qaşr;25.6959\nSaryshaghan;46.1167\nBekily;-24.2162\nBatagay;67.6560\nOmsukchan;62.5333\nNovyy Uoyan;56.1350\nQuime;-16.9817\nAraouane;18.9050\nP’ungsan;40.8175\nVitim;59.4515\nPalana;59.0840\nCherskiy;68.7501\nCeduna;-32.1167\nZyryanka;65.7360\nDe-Kastri;51.4666\nVilla Ygatimí;-24.0800\nLigonha;-15.1757\nUspallata;-32.5667\nDarregueira;-37.6996\nBukachacha;52.9833\nUgol’nyye Kopi;64.7333\nLukulu;-14.4083\nKrasnogorsk;48.4172\nArroyos y Esteros;-25.0500\nUst’-Maya;60.4566\nAbaí;-26.0296\nTaoudenni;22.6667\nSan Lorenzo;-21.4167\nSaranpaul;64.2600\nVillalonga;-39.8829\nEntre Ríos;-21.5264\nAl Jaghbūb;29.7425\nBîr Mogreïn;25.2167\nSauðárkrókur;65.7461\nProvideniya;64.4235\nChokurdakh;70.6183\nMarādah;29.2333\nMariscal José Félix Estigarribia;-22.0333\nSohano;-5.4297\nYpejhú;-23.9100\nToltén;-39.2166\nMwenga;-3.0382\nEgvekinot;66.3221\nEl Manteco;7.3483\nPozo Colorado;-23.4300\nOmboué;-1.5667\nKonza;-1.7496\nEvensk;61.9500\nAltata;24.6333\nAbunã;-9.6954\nTaedong;40.6171\nBeringovskiy;63.0655\nNasir;8.6000\nCapitán Pablo Lagerenza;-19.9200\nKipili;-7.4329\nOktyabr’skiy;52.6636\nUst’-Kuyga;70.0171\nEldikan;60.8000\nNyimba;-14.5495\nFulacunda;11.7730\nLubutu;-0.7431\nRegedor Quissico;-24.7257\nBala Cangamba;-13.6833\nVilla Rumipal;-32.1879\nÑacunday;-26.0200\nAğdam;40.9053\nVilla Martín Colchak;-20.7406\nBuluko;-0.7570\nÇeleken;39.4362\nPuerto Acosta;-15.5333\nLos Blancos;-23.6000\nMirbāţ;16.9886\nDikson;73.5070\nKlyuchi;56.3167\nGeneral Eugenio A. Garay;-20.5200\nDaraj;30.1500\nLuanza;-8.6996\nHoskins;-5.4746\nCharaña;-17.6000\nMuhembo;-18.2996\nDibaya;-6.5095\nYerëma;60.3808\nSatadougou;12.6170\nZhaltyr;51.6324\nManily;62.4908\nCalatrava;1.1164\nMassangena;-21.5378\nPanda;-24.0629\nVilla O’Higgins;-48.4683\nKullorsuaq;74.5792\nQuilpie;-26.6161\nChiramba;-16.8921\nSabaya;-19.0147\nMereeg;3.7667\nLlica;-19.8500\nCalenga;-11.3196\nCaluula;11.9667\nTournavista;-8.9322\nTchitado;-17.3167\nYakossi;5.6170\nPuerto Pinasco;-22.7167\nTmassah;26.3667\nWoomera;-31.1496\nSherlovaya Gora;50.5306\nTsavo;-2.9828\nNizhneyansk;71.4333\nToconao;-23.1903\nTasiusaq;73.3689\nBurubaytal;44.9350\nKanyato;-4.4565\nKulusuk;65.5753\nUmm al ‘Abīd;27.5170\nBugrino;68.7831\nPut’ Lenina;68.5166\nYaupi;-2.8379\nAmderma;69.7631\nKangersuatsiaq;72.3797\nAmau;-10.0426\nAndroka;-25.0219\nLusanga;-5.5808\nKraulshavn;74.1111\nHurdiyo;10.5667\nButon;4.2170\nNarsarsuaq;61.1458\nBafwasende;1.0103\nBan Huai Hin;12.5697\nBifoun;-0.3333\nIl’pyrskiy;59.9600\nSavissivik;76.0194\nCuya;-19.1597\nGyda;70.8814\nGüeppí;-0.1166\nChuquicamata;-22.3169\nPuerto Heath;-12.5200\nYessey;68.4652\nLemsid;26.5482\nMukhomornoye;66.4171\nVorontsovo;71.6983\nGrytviken;-54.2806\nPiso Firme;-13.6830\nRocafuerte;-0.9329\nPeregrebnoye;62.9670\nLaryak;61.1012\nLagunas;-20.9829\nAndoas;-2.9042\nPuca Urco;-2.3328\nZillah;28.5489\nBarnīs;23.9460\nSoldado Bartra;-2.5161\nUlkan;55.9004\nStrelka;61.8670\nBol’sheretsk;52.4390\nKaramken;60.2004\nDjado;21.0150\nSiglan;59.0337\nOmchak;61.6333\nShalaurova;73.2204\nKhorgo;73.4833\nKomsa;61.8680\nPakhachi;60.5816\nIndiga;67.6898\nChagda;60.1000\nTrofimovsk;72.5997\nTunguskhaya;64.9004\nPodkamennaya Tunguska;61.5995\nVarnek;69.7153\nUtkholok;57.5504\nMatochkin Shar;73.2700\nKhakhar;57.6666\nMenkerya;67.9886\nZvëzdnyy;70.9333\nStarorybnoye;72.7666\nSagastyr;73.3779\nZemlya Bunge;74.8983\nAgapa;71.4504\nTukchi;57.3670\nNumto;63.6667\nNord;81.7166\nTimmiarmiut;62.5333\nSan Rafael;-16.7795\nNordvik;74.0165\n"
  },
  {
    "path": "etc/eclipse-formatter-config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!--\n\n     Copyright 2023 The original authors\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n\n-->\n<profiles version=\"12\">\n    <profile kind=\"CodeFormatterProfile\" name=\"Debezium\" version=\"12\">\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.disabling_tag\" value=\"@formatter:off\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.use_on_off_tags\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"80\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_binary_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\" value=\"insert\" />\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"2\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n        <!-- 16: default, 20: indent by 1, 18: indent on column, effectively aligns content -->\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_binary_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.7\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.join_wrapped_lines\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"170\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.enabling_tag\" value=\"@formatter:on\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"error\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"18\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_method_declaration\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.problem.enumIdentifier\" value=\"error\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.7\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"2\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\"\n                 value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_binary_expression\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"enabled\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_label\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"200\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.wrap_before_binary_operator\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.join_lines_in_comments\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"16\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"18\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.7\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_resources_in_try\" value=\"80\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation\" value=\"0\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"49\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\"\n                 value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\" value=\"true\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources\" value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\"\n                 value=\"do not insert\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n        <setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"false\"/>\n    </profile>\n</profiles>"
  },
  {
    "path": "etc/license.txt",
    "content": " Copyright 2023 The original authors\n\n Licensed under the Apache License, Version 2.0 (the \"License\");\n you may not use this file except in compliance with the License.\n You may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\n Unless required by applicable law or agreed to in writing, software\n distributed under the License is distributed on an \"AS IS\" BASIS,\n WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n See the License for the specific language governing permissions and\n limitations under the License.\n"
  },
  {
    "path": "evaluate.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -eo pipefail\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: evaluate.sh <fork name> (<fork name 2> ...)\"\n    echo \" for each fork, there must be a 'calculate_average_<fork name>.sh' script and an optional 'prepare_<fork name>.sh'.\"\n    exit 1\nfi\n\nBOLD_WHITE='\\033[1;37m'\nCYAN='\\033[0;36m'\nGREEN='\\033[0;32m'\nPURPLE='\\033[0;35m'\nBOLD_RED='\\033[1;31m'\nRED='\\033[0;31m'\nBOLD_YELLOW='\\033[1;33m'\nRESET='\\033[0m' # No Color\n\nMEASUREMENTS_FILE=\"measurements_1B.txt\"\nRUNS=10\nDEFAULT_JAVA_VERSION=\"21.0.1-open\"\n: \"${BUILD_JAVA_VERSION:=21.0.1-open}\"\nRUN_TIME_LIMIT=300 # seconds\n\nTIMEOUT=\"\"\nif [ \"$(uname -s)\" == \"Linux\" ]; then\n  TIMEOUT=\"timeout -v $RUN_TIME_LIMIT\"\nelse # MacOs\n  if [ -x \"$(command -v gtimeout)\" ]; then\n    TIMEOUT=\"gtimeout -v $RUN_TIME_LIMIT\" # from `brew install coreutils`\n  else\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} gtimeout not available, benchmark runs may take indefinitely long.\"\n  fi\nfi\n\nfunction check_command_installed {\n  if ! [ -x \"$(command -v $1)\" ]; then\n    echo \"Error: $1 is not installed.\" >&2\n    exit 1\n  fi\n}\n\nfunction print_and_execute() {\n  echo \"+ $@\" >&2\n  \"$@\"\n}\n\ncheck_command_installed java\ncheck_command_installed hyperfine\ncheck_command_installed jq\ncheck_command_installed bc\n\n# Validate that ./calculate_average_<fork>.sh exists for each fork\nfor fork in \"$@\"; do\n  if [ ! -f \"./calculate_average_$fork.sh\" ]; then\n    echo -e \"${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist.\" >&2\n    exit 1\n  fi\ndone\n\n## SDKMAN Setup\n# 1. Custom check for sdkman installed; not sure why check_command_installed doesn't detect it properly\nif [ ! -f \"$HOME/.sdkman/bin/sdkman-init.sh\" ]; then\n     echo -e \"${BOLD_RED}ERROR${RESET}: sdkman is not installed.\" >&2\n    exit 1\nfi\n\n# 2. Init sdkman in this script\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\n\n# 3. make sure the default java version is installed\nif [ ! -d \"$HOME/.sdkman/candidates/java/$DEFAULT_JAVA_VERSION\" ]; then\n  print_and_execute sdk install java $DEFAULT_JAVA_VERSION\nfi\n\n# 4. Install missing SDK java versions in any of the prepare_*.sh scripts for the provided forks\nfor fork in \"$@\"; do\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    grep -h \"^sdk use\" \"./prepare_$fork.sh\" | cut -d' ' -f4 | while read -r version; do\n      if [ ! -d \"$HOME/.sdkman/candidates/java/$version\" ]; then\n        print_and_execute sdk install java $version\n      fi\n    done || true # grep returns exit code 1 when no match, `|| true` prevents the script from exiting early\n  fi\ndone\n## END - SDKMAN Setup\n\n# Check if SMT is enabled (we want it disabled)\nif [ -f \"/sys/devices/system/cpu/smt/active\" ]; then\n  if [ \"$(cat /sys/devices/system/cpu/smt/active)\" != \"0\" ]; then\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} SMT is enabled\"\n  fi\nfi\n\n# Check if Turbo Boost is enabled (we want it disabled)\nif [ -f \"/sys/devices/system/cpu/cpufreq/boost\" ]; then\n  if [ \"$(cat /sys/devices/system/cpu/cpufreq/boost)\" != \"0\" ]; then\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} Turbo Boost is enabled\"\n  fi\nfi\n\nprint_and_execute sdk use java $BUILD_JAVA_VERSION\nprint_and_execute java --version\nprint_and_execute ./mvnw --quiet clean verify\n\nprint_and_execute rm -f measurements.txt\nprint_and_execute ln -s $MEASUREMENTS_FILE measurements.txt\n\necho \"\"\n\n# check if measurements_xxx.out exists\nif [ ! -f \"${MEASUREMENTS_FILE%.txt}.out\" ]; then\n  echo -e \"${BOLD_RED}ERROR${RESET}: ${MEASUREMENTS_FILE%.txt}.out does not exist.\" >&2\n  echo \"Please create it with:\"\n  echo \"\"\n  echo \"  ./calculate_average_baseline.sh > ${MEASUREMENTS_FILE%.txt}.out\"\n  echo \"\"\n  exit 1\nfi\n\n# Run tests and benchmark for each fork\nfiletimestamp=$(date  +\"%Y%m%d%H%M%S\") # same for all fork.out files from this run\nfailed=()\nfor fork in \"$@\"; do\n  set +e # we don't want prepare.sh, test.sh or hyperfine failing on 1 fork to exit the script early\n\n  # Run prepare script\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    print_and_execute source \"./prepare_$fork.sh\"\n  else\n    print_and_execute sdk use java $DEFAULT_JAVA_VERSION\n  fi\n\n  # Run the test suite\n  print_and_execute $TIMEOUT ./test.sh $fork\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    echo \"\"\n    echo -e \"${BOLD_RED}FAILURE${RESET}: ./test.sh $fork failed\"\n\n    continue\n  fi\n  echo \"\"\n\n  # Run the test on $MEASUREMENTS_FILE; this serves as the warmup\n  print_and_execute $TIMEOUT ./test.sh $fork $MEASUREMENTS_FILE\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    echo \"\"\n    echo -e \"${BOLD_RED}FAILURE${RESET}: ./test.sh $fork $MEASUREMENTS_FILE failed\"\n\n    continue\n  fi\n  echo \"\"\n\n  # re-link measurements.txt since test.sh deleted it\n  print_and_execute rm -f measurements.txt\n  print_and_execute ln -s $MEASUREMENTS_FILE measurements.txt\n\n  # Use hyperfine to run the benchmark for each fork\n  HYPERFINE_OPTS=\"--warmup 0 --runs $RUNS --export-json $fork-$filetimestamp-timing.json --output ./$fork-$filetimestamp.out\"\n\n  # check if this script is running on a Linux box\n  if [ \"$(uname -s)\" == \"Linux\" ]; then\n    check_command_installed numactl\n\n    # Linux platform\n    # prepend this with numactl --physcpubind=0-7 for running it only with 8 cores\n    numactl --physcpubind=0-7 hyperfine $HYPERFINE_OPTS \"$TIMEOUT ./calculate_average_$fork.sh 2>&1\"\n  else # MacOS\n    hyperfine $HYPERFINE_OPTS \"$TIMEOUT ./calculate_average_$fork.sh 2>&1\"\n  fi\n  # Catch hyperfine command failed\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    # Hyperfine already prints the error message\n    echo \"\"\n    continue\n  fi\ndone\nset -e\n\n# Summary\necho -e \"${BOLD_WHITE}Summary${RESET}\"\nfor fork in \"$@\"; do\n  # skip reporting results for failed forks\n  if [[ \" ${failed[@]} \" =~ \" ${fork} \" ]]; then\n    echo -e \"  ${RED}$fork${RESET}: command failed or output did not match\"\n    continue\n  fi\n\n  # Trimmed mean = The slowest and the fastest runs are discarded, the\n  # mean value of the remaining three runs is the result for that contender\n  trimmed_mean=$(jq -r '.results[0].times | sort_by(.|tonumber) | .[1:-1] | add / length' $fork-$filetimestamp-timing.json)\n  raw_times=$(jq -r '.results[0].times | join(\",\")' $fork-$filetimestamp-timing.json)\n\n  if [ \"$fork\" == \"$1\" ]; then\n    color=$CYAN\n  elif [ \"$fork\" == \"$2\" ]; then\n    color=$GREEN\n  else\n    color=$PURPLE\n  fi\n\n  echo -e \"  ${color}$fork${RESET}: trimmed mean ${BOLD_WHITE}$trimmed_mean${RESET}, raw times ${BOLD_WHITE}$raw_times${RESET}\"\ndone\necho \"\"\n\n## Leaderboard - prints the leaderboard in Markdown table format\necho -e \"${BOLD_WHITE}Leaderboard${RESET}\"\n\n# 1. Create a temp file to store the leaderboard entries\nleaderboard_temp_file=$(mktemp)\n\n# 2. Process each fork and append the 1-line entry to the temp file\nfor fork in \"$@\"; do\n  # skip reporting results for failed forks\n  if [[ \" ${failed[@]} \" =~ \" ${fork} \" ]]; then\n    continue\n  fi\n\n  trimmed_mean=$(jq -r '.results[0].times | sort_by(.|tonumber) | .[1:-1] | add / length' $fork-$filetimestamp-timing.json)\n\n  # trimmed_mean is in seconds\n  # Format trimmed_mean as MM::SS.mmm\n  # using bc\n  trimmed_mean_minutes=$(echo \"$trimmed_mean / 60\" | bc)\n  trimmed_mean_seconds=$(echo \"$trimmed_mean % 60 / 1\" | bc)\n  trimmed_mean_ms=$(echo \"($trimmed_mean - $trimmed_mean_minutes * 60 - $trimmed_mean_seconds) * 1000 / 1\" | bc)\n  trimmed_mean_formatted=$(printf \"%02d:%02d.%03d\" $trimmed_mean_minutes $trimmed_mean_seconds $trimmed_mean_ms)\n\n  # Get Github user's name from public Github API (rate limited after ~50 calls, so results are cached in github_users.txt)\n  set +e\n  github_user__name=$(grep \"^$fork;\" github_users.txt | cut -d ';' -f2)\n  if [ -z \"$github_user__name\" ]; then\n    github_user__name=$(curl -s https://api.github.com/users/$fork | jq -r '.name' | tr -d '\"')\n    if [ \"$github_user__name\" != \"null\" ]; then\n      echo \"$fork;$github_user__name\" >> github_users.txt\n    else\n      github_user__name=$fork\n    fi\n  fi\n  set -e\n\n  # Read java version from prepare_$fork.sh if it exists, otherwise assume 21.0.1-open\n  java_version=\"21.0.1-open\"\n  # Hard-coding the note message for now\n  notes=\"\"\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    java_version=$(grep -F \"sdk use java\" ./prepare_$fork.sh | cut -d' ' -f4)\n\n    if grep -F \"native-image\" -q ./prepare_$fork.sh ; then\n      notes=\"GraalVM native binary\"\n    fi\n  fi\n\n  # check if Java source file uses Unsafe\n  if grep -F \"theUnsafe\" -q ./src/main/java*/dev/morling/onebrc/CalculateAverage_$fork.java ; then\n    # if notes is not empty, append a comma and space before the unsafe note\n    notes=\"${notes:+$notes, }uses Unsafe\"\n  fi\n\n  echo -n \"$trimmed_mean;\" >> $leaderboard_temp_file # for sorting\n  echo -n \"| # \" >> $leaderboard_temp_file\n  echo -n \"| $trimmed_mean_formatted \" >> $leaderboard_temp_file\n  echo -n \"| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_$fork.java)\" >> $leaderboard_temp_file\n  echo -n \"| $java_version \" >> $leaderboard_temp_file\n  echo -n \"| [$github_user__name](https://github.com/$fork) \" >> $leaderboard_temp_file\n  echo -n \"| $notes \" >> $leaderboard_temp_file\n  echo \"|\" >> $leaderboard_temp_file\ndone\n\n# 3. Sort leaderboard_temp_file by trimmed_mean and remove the sorting column\nsort -n $leaderboard_temp_file | cut -d ';' -f 2 > $leaderboard_temp_file.sorted\n\n# 4. Print the leaderboard\necho \"\"\necho \"| # | Result (m:s.ms) | Implementation     | JDK | Submitter     | Notes     |\"\necho \"|---|-----------------|--------------------|-----|---------------|-----------|\"\n# If $leaderboard_temp_file.sorted has more than 3 entires, include rankings\nif [ $(wc -l < $leaderboard_temp_file.sorted) -gt 3 ]; then\n  head -n 1 $leaderboard_temp_file.sorted | tr '#' 1\n  head -n 2 $leaderboard_temp_file.sorted | tail -n 1 | tr '#' 2\n  head -n 3 $leaderboard_temp_file.sorted | tail -n 1 | tr '#' 3\n  tail -n+4 $leaderboard_temp_file.sorted | tr '#' ' '\nelse\n  # Don't show rankings\n  cat $leaderboard_temp_file.sorted | tr '#' ' '\nfi\necho \"\"\n\n# 5. Cleanup\nrm $leaderboard_temp_file\n## END - Leaderboard\n\n# Finalize .out files\necho \"Raw results saved to file(s):\"\nfor fork in \"$@\"; do\n  if [ -f \"$fork-$filetimestamp-timing.json\" ]; then\n      cat $fork-$filetimestamp-timing.json >> $fork-$filetimestamp.out\n      rm $fork-$filetimestamp-timing.json\n  fi\n\n  if [ -f \"$fork-$filetimestamp.out\" ]; then\n    echo \"  $fork-$filetimestamp.out\"\n  fi\ndone\n"
  },
  {
    "path": "evaluate_10K.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -eo pipefail\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: evaluate.sh <fork name> (<fork name 2> ...)\"\n    echo \" for each fork, there must be a 'calculate_average_<fork name>.sh' script and an optional 'prepare_<fork name>.sh'.\"\n    exit 1\nfi\n\nBOLD_WHITE='\\033[1;37m'\nCYAN='\\033[0;36m'\nGREEN='\\033[0;32m'\nPURPLE='\\033[0;35m'\nBOLD_RED='\\033[1;31m'\nRED='\\033[0;31m'\nBOLD_YELLOW='\\033[1;33m'\nRESET='\\033[0m' # No Color\n\nMEASUREMENTS_FILE=\"measurements_10K_1B.txt\"\nRUNS=5\nDEFAULT_JAVA_VERSION=\"21.0.1-open\"\n: \"${BUILD_JAVA_VERSION:=21.0.1-open}\"\nRUN_TIME_LIMIT=300 # seconds\n\nTIMEOUT=\"\"\nif [ \"$(uname -s)\" == \"Linux\" ]; then\n  TIMEOUT=\"timeout -v $RUN_TIME_LIMIT\"\nelse # MacOs\n  if [ -x \"$(command -v gtimeout)\" ]; then\n    TIMEOUT=\"gtimeout -v $RUN_TIME_LIMIT\" # from `brew install coreutils`\n  else\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} gtimeout not available, benchmark runs may take indefinitely long.\"\n  fi\nfi\n\nfunction check_command_installed {\n  if ! [ -x \"$(command -v $1)\" ]; then\n    echo \"Error: $1 is not installed.\" >&2\n    exit 1\n  fi\n}\n\nfunction print_and_execute() {\n  echo \"+ $@\" >&2\n  \"$@\"\n}\n\ncheck_command_installed java\ncheck_command_installed hyperfine\ncheck_command_installed jq\ncheck_command_installed bc\n\n# Validate that ./calculate_average_<fork>.sh exists for each fork\nfor fork in \"$@\"; do\n  if [ ! -f \"./calculate_average_$fork.sh\" ]; then\n    echo -e \"${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist.\" >&2\n    exit 1\n  fi\ndone\n\n## SDKMAN Setup\n# 1. Custom check for sdkman installed; not sure why check_command_installed doesn't detect it properly\nif [ ! -f \"$HOME/.sdkman/bin/sdkman-init.sh\" ]; then\n     echo -e \"${BOLD_RED}ERROR${RESET}: sdkman is not installed.\" >&2\n    exit 1\nfi\n\n# 2. Init sdkman in this script\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\n\n# 3. make sure the default java version is installed\nif [ ! -d \"$HOME/.sdkman/candidates/java/$DEFAULT_JAVA_VERSION\" ]; then\n  print_and_execute sdk install java $DEFAULT_JAVA_VERSION\nfi\n\n# 4. Install missing SDK java versions in any of the prepare_*.sh scripts for the provided forks\nfor fork in \"$@\"; do\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    grep -h \"^sdk use\" \"./prepare_$fork.sh\" | cut -d' ' -f4 | while read -r version; do\n      if [ ! -d \"$HOME/.sdkman/candidates/java/$version\" ]; then\n        print_and_execute sdk install java $version\n      fi\n    done || true # grep returns exit code 1 when no match, `|| true` prevents the script from exiting early\n  fi\ndone\n## END - SDKMAN Setup\n\n# Check if SMT is enabled (we want it disabled)\nif [ -f \"/sys/devices/system/cpu/smt/active\" ]; then\n  if [ \"$(cat /sys/devices/system/cpu/smt/active)\" != \"0\" ]; then\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} SMT is enabled\"\n  fi\nfi\n\n# Check if Turbo Boost is enabled (we want it disabled)\nif [ -f \"/sys/devices/system/cpu/cpufreq/boost\" ]; then\n  if [ \"$(cat /sys/devices/system/cpu/cpufreq/boost)\" != \"0\" ]; then\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} Turbo Boost is enabled\"\n  fi\nfi\n\nprint_and_execute sdk use java $BUILD_JAVA_VERSION\nprint_and_execute java --version\n# print_and_execute ./mvnw --quiet clean verify\n\nprint_and_execute rm -f measurements.txt\nprint_and_execute ln -s $MEASUREMENTS_FILE measurements.txt\n\necho \"\"\n\n# check if measurements_xxx.out exists\nif [ ! -f \"${MEASUREMENTS_FILE%.txt}.out\" ]; then\n  echo -e \"${BOLD_RED}ERROR${RESET}: ${MEASUREMENTS_FILE%.txt}.out does not exist.\" >&2\n  echo \"Please create it with:\"\n  echo \"\"\n  echo \"  ./calculate_average_baseline.sh > ${MEASUREMENTS_FILE%.txt}.out\"\n  echo \"\"\n  exit 1\nfi\n\n# Run tests and benchmark for each fork\nfiletimestamp=$(date  +\"%Y%m%d%H%M%S\") # same for all fork.out files from this run\nfailed=()\nfor fork in \"$@\"; do\n  set +e # we don't want prepare.sh, test.sh or hyperfine failing on 1 fork to exit the script early\n\n  # Run prepare script\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    print_and_execute source \"./prepare_$fork.sh\"\n  else\n    print_and_execute sdk use java $DEFAULT_JAVA_VERSION\n  fi\n\n  # Run the test suite\n  print_and_execute $TIMEOUT ./test.sh $fork\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    echo \"\"\n    echo -e \"${BOLD_RED}FAILURE${RESET}: ./test.sh $fork failed\"\n\n    continue\n  fi\n  echo \"\"\n\n  # Run the test on $MEASUREMENTS_FILE; this serves as the warmup\n  print_and_execute $TIMEOUT ./test.sh $fork $MEASUREMENTS_FILE\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    echo \"\"\n    echo -e \"${BOLD_RED}FAILURE${RESET}: ./test.sh $fork $MEASUREMENTS_FILE failed\"\n\n    continue\n  fi\n  echo \"\"\n\n  # re-link measurements.txt since test.sh deleted it\n  print_and_execute rm -f measurements.txt\n  print_and_execute ln -s $MEASUREMENTS_FILE measurements.txt\n\n  # Use hyperfine to run the benchmark for each fork\n  HYPERFINE_OPTS=\"--warmup 0 --runs $RUNS --export-json $fork-$filetimestamp-timing.json --output ./$fork-$filetimestamp.out\"\n\n  # check if this script is running on a Linux box\n  if [ \"$(uname -s)\" == \"Linux\" ]; then\n    check_command_installed numactl\n\n    # Linux platform\n    # prepend this with numactl --physcpubind=0-7 for running it only with 8 cores\n    numactl --physcpubind=0-7 hyperfine $HYPERFINE_OPTS \"$TIMEOUT ./calculate_average_$fork.sh 2>&1\"\n  else # MacOS\n    hyperfine $HYPERFINE_OPTS \"$TIMEOUT ./calculate_average_$fork.sh 2>&1\"\n  fi\n  # Catch hyperfine command failed\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    # Hyperfine already prints the error message\n    echo \"\"\n    continue\n  fi\ndone\nset -e\n\n# Summary\necho -e \"${BOLD_WHITE}Summary${RESET}\"\nfor fork in \"$@\"; do\n  # skip reporting results for failed forks\n  if [[ \" ${failed[@]} \" =~ \" ${fork} \" ]]; then\n    echo -e \"  ${RED}$fork${RESET}: command failed or output did not match\"\n    continue\n  fi\n\n  # Trimmed mean = The slowest and the fastest runs are discarded, the\n  # mean value of the remaining three runs is the result for that contender\n  trimmed_mean=$(jq -r '.results[0].times | sort_by(.|tonumber) | .[1:-1] | add / length' $fork-$filetimestamp-timing.json)\n  raw_times=$(jq -r '.results[0].times | join(\",\")' $fork-$filetimestamp-timing.json)\n\n  if [ \"$fork\" == \"$1\" ]; then\n    color=$CYAN\n  elif [ \"$fork\" == \"$2\" ]; then\n    color=$GREEN\n  else\n    color=$PURPLE\n  fi\n\n  echo -e \"  ${color}$fork${RESET}: trimmed mean ${BOLD_WHITE}$trimmed_mean${RESET}, raw times ${BOLD_WHITE}$raw_times${RESET}\"\ndone\necho \"\"\n\n## Leaderboard - prints the leaderboard in Markdown table format\necho -e \"${BOLD_WHITE}Leaderboard${RESET}\"\n\n# 1. Create a temp file to store the leaderboard entries\nleaderboard_temp_file=$(mktemp)\n\n# 2. Process each fork and append the 1-line entry to the temp file\nfor fork in \"$@\"; do\n  # skip reporting results for failed forks\n  if [[ \" ${failed[@]} \" =~ \" ${fork} \" ]]; then\n    continue\n  fi\n\n  trimmed_mean=$(jq -r '.results[0].times | sort_by(.|tonumber) | .[1:-1] | add / length' $fork-$filetimestamp-timing.json)\n\n  # trimmed_mean is in seconds\n  # Format trimmed_mean as MM::SS.mmm\n  # using bc\n  trimmed_mean_minutes=$(echo \"$trimmed_mean / 60\" | bc)\n  trimmed_mean_seconds=$(echo \"$trimmed_mean % 60 / 1\" | bc)\n  trimmed_mean_ms=$(echo \"($trimmed_mean - $trimmed_mean_minutes * 60 - $trimmed_mean_seconds) * 1000 / 1\" | bc)\n  trimmed_mean_formatted=$(printf \"%02d:%02d.%03d\" $trimmed_mean_minutes $trimmed_mean_seconds $trimmed_mean_ms)\n\n  # Get Github user's name from public Github API (rate limited after ~50 calls, so results are cached in github_users.txt)\n  set +e\n  github_user__name=$(grep \"^$fork;\" github_users.txt | cut -d ';' -f2)\n  if [ -z \"$github_user__name\" ]; then\n    github_user__name=$(curl -s https://api.github.com/users/$fork | jq -r '.name' | tr -d '\"')\n    if [ \"$github_user__name\" != \"null\" ]; then\n      echo \"$fork;$github_user__name\" >> github_users.txt\n    else\n      github_user__name=$fork\n    fi\n  fi\n  set -e\n\n  # Read java version from prepare_$fork.sh if it exists, otherwise assume 21.0.1-open\n  java_version=\"21.0.1-open\"\n  # Hard-coding the note message for now\n  notes=\"\"\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    java_version=$(grep -F \"sdk use java\" ./prepare_$fork.sh | cut -d' ' -f4)\n\n    if grep -F \"native-image\" -q ./prepare_$fork.sh ; then\n      notes=\"GraalVM native binary\"\n    fi\n  fi\n\n  # check if Java source file uses Unsafe\n  if grep -F \"theUnsafe\" -q ./src/main/java*/dev/morling/onebrc/CalculateAverage_$fork.java ; then\n    # if notes is not empty, append a comma and space before the unsafe note\n    notes=\"${notes:+$notes, }uses Unsafe\"\n  fi\n\n  echo -n \"$trimmed_mean;\" >> $leaderboard_temp_file # for sorting\n  echo -n \"| # \" >> $leaderboard_temp_file\n  echo -n \"| $trimmed_mean_formatted \" >> $leaderboard_temp_file\n  echo -n \"| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_$fork.java)\" >> $leaderboard_temp_file\n  echo -n \"| $java_version \" >> $leaderboard_temp_file\n  echo -n \"| [$github_user__name](https://github.com/$fork) \" >> $leaderboard_temp_file\n  echo -n \"| $notes \" >> $leaderboard_temp_file\n  echo \"|\" >> $leaderboard_temp_file\ndone\n\n# 3. Sort leaderboard_temp_file by trimmed_mean and remove the sorting column\nsort -n $leaderboard_temp_file | cut -d ';' -f 2 > $leaderboard_temp_file.sorted\n\n# 4. Print the leaderboard\necho \"\"\necho \"| # | Result (m:s.ms) | Implementation     | JDK | Submitter     | Notes     |\"\necho \"|---|-----------------|--------------------|-----|---------------|-----------|\"\n# If $leaderboard_temp_file.sorted has more than 3 entires, include rankings\nif [ $(wc -l < $leaderboard_temp_file.sorted) -gt 3 ]; then\n  head -n 1 $leaderboard_temp_file.sorted | tr '#' 1\n  head -n 2 $leaderboard_temp_file.sorted | tail -n 1 | tr '#' 2\n  head -n 3 $leaderboard_temp_file.sorted | tail -n 1 | tr '#' 3\n  tail -n+4 $leaderboard_temp_file.sorted | tr '#' ' '\nelse\n  # Don't show rankings\n  cat $leaderboard_temp_file.sorted | tr '#' ' '\nfi\necho \"\"\n\n# 5. Cleanup\nrm $leaderboard_temp_file\n## END - Leaderboard\n\n# Finalize .out files\necho \"Raw results saved to file(s):\"\nfor fork in \"$@\"; do\n  if [ -f \"$fork-$filetimestamp-timing.json\" ]; then\n      cat $fork-$filetimestamp-timing.json >> $fork-$filetimestamp.out\n      rm $fork-$filetimestamp-timing.json\n  fi\n\n  if [ -f \"$fork-$filetimestamp.out\" ]; then\n    echo \"  $fork-$filetimestamp.out\"\n  fi\ndone\n"
  },
  {
    "path": "github_users.txt",
    "content": "giovannicuccu;Giovanni Cuccu\nUjjwalbharti;Ujjwal Bharti\nabfrmblr;Abhilash\nags313;ags\nanandmattikopp;twohardthings\narmandino;Arman Sharif\nartpar;Parth Mudgal\nasun;Alan Sun\nbjhara;Hampus\ncoolmineman;Cool_Mineman\ncriccomini;Chris Riccomini\ndavecom;David Kopec\ndavery22;Daniel Avery\nddimtirov;Dimitar Dimitrov\nebarlas;Elliot Barlas\nentangled90;Carlo\nfatroom;Roman Romanchuk\nfelix19350;Bruno Félix\nfiliphr;Filip Hrisafov\nflippingbits;Stefan Sprenger\nfragmede;Samson\ngabrielreid;Gabriel Reid\nhchiorean;Horia Chiorean\nimrafaelmerino;Rafael Merino García\nisolgpus;Jamie Stansfield\niziamos;John Ziamos\njgrateron;Jairo Graterón\njotschi;Johannes Schüth\nkevinmcmurtrie;Kevin McMurtrie\nkgeri;Gergely Kiss\nkhmarbaise;Karl Heinz Marbaise\nkuduwa-keshavram;Keshavram Kuduwa\nmerykitty;Quan Anh Mai\nmoysesb;Moysés Borges Furtado\nmudit-saxena;Mudit Saxena\nnstng;Nils Semmelrock\nobourgain;Olivier Bourgain\npadreati;Aurelian Tutuianu\npalmr;Nick Palmer\nrby;Ramzi Ben Yahya\nrichardstartin;Richard Startin\nspullara;Sam Pullara\nroyvanrijn;Roy van Rijn\nseijikun;Markus Ebner\nsemotpan;Serghei Motpan\nthomaswue;Thomas Wuerthinger\ntruelive;Roman Schweitzer\ntwobiers;Tobi\nyavuztas;Yavuz Tas\nyehwankim23;김예환 Ye-Hwan Kim (Sam)\nhundredwatt;Jason Nochlin\ngnmathur;Gaurav Mathur\nvemana;Subrahmanyam\njincongho;Jin Cong Ho\nyonatang;Yonatan Graber\nadriacabeza;Adrià Cabeza\nAlexanderYastrebov;Alexander Yastrebov\nelh;Eugene Huang\n"
  },
  {
    "path": "mvnw",
    "content": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements.  See the NOTICE file\n# distributed with this work for additional information\n# regarding copyright ownership.  The ASF licenses this file\n# to you under the Apache License, Version 2.0 (the\n# \"License\"); you may not use this file except in compliance\n# with the License.  You may obtain a copy of the License at\n#\n#    http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing,\n# software distributed under the License is distributed on an\n# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n# KIND, either express or implied.  See the License for the\n# specific language governing permissions and limitations\n# under the License.\n# ----------------------------------------------------------------------------\n\n# ----------------------------------------------------------------------------\n# Apache Maven Wrapper startup batch script, version 3.2.0\n#\n# Required ENV vars:\n# ------------------\n#   JAVA_HOME - location of a JDK home dir\n#\n# Optional ENV vars\n# -----------------\n#   MAVEN_OPTS - parameters passed to the Java VM when running Maven\n#     e.g. to debug Maven itself, use\n#       set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\n#   MAVEN_SKIP_RC - flag to disable loading of mavenrc files\n# ----------------------------------------------------------------------------\n\nif [ -z \"$MAVEN_SKIP_RC\" ] ; then\n\n  if [ -f /usr/local/etc/mavenrc ] ; then\n    . /usr/local/etc/mavenrc\n  fi\n\n  if [ -f /etc/mavenrc ] ; then\n    . /etc/mavenrc\n  fi\n\n  if [ -f \"$HOME/.mavenrc\" ] ; then\n    . \"$HOME/.mavenrc\"\n  fi\n\nfi\n\n# OS specific support.  $var _must_ be set to either true or false.\ncygwin=false;\ndarwin=false;\nmingw=false\ncase \"$(uname)\" in\n  CYGWIN*) cygwin=true ;;\n  MINGW*) mingw=true;;\n  Darwin*) darwin=true\n    # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home\n    # See https://developer.apple.com/library/mac/qa/qa1170/_index.html\n    if [ -z \"$JAVA_HOME\" ]; then\n      if [ -x \"/usr/libexec/java_home\" ]; then\n        JAVA_HOME=\"$(/usr/libexec/java_home)\"; export JAVA_HOME\n      else\n        JAVA_HOME=\"/Library/Java/Home\"; export JAVA_HOME\n      fi\n    fi\n    ;;\nesac\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  if [ -r /etc/gentoo-release ] ; then\n    JAVA_HOME=$(java-config --jre-home)\n  fi\nfi\n\n# For Cygwin, ensure paths are in UNIX format before anything is touched\nif $cygwin ; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=$(cygpath --unix \"$JAVA_HOME\")\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=$(cygpath --path --unix \"$CLASSPATH\")\nfi\n\n# For Mingw, ensure paths are in UNIX format before anything is touched\nif $mingw ; then\n  [ -n \"$JAVA_HOME\" ] && [ -d \"$JAVA_HOME\" ] &&\n    JAVA_HOME=\"$(cd \"$JAVA_HOME\" || (echo \"cannot cd into $JAVA_HOME.\"; exit 1); pwd)\"\nfi\n\nif [ -z \"$JAVA_HOME\" ]; then\n  javaExecutable=\"$(which javac)\"\n  if [ -n \"$javaExecutable\" ] && ! [ \"$(expr \"\\\"$javaExecutable\\\"\" : '\\([^ ]*\\)')\" = \"no\" ]; then\n    # readlink(1) is not available as standard on Solaris 10.\n    readLink=$(which readlink)\n    if [ ! \"$(expr \"$readLink\" : '\\([^ ]*\\)')\" = \"no\" ]; then\n      if $darwin ; then\n        javaHome=\"$(dirname \"\\\"$javaExecutable\\\"\")\"\n        javaExecutable=\"$(cd \"\\\"$javaHome\\\"\" && pwd -P)/javac\"\n      else\n        javaExecutable=\"$(readlink -f \"\\\"$javaExecutable\\\"\")\"\n      fi\n      javaHome=\"$(dirname \"\\\"$javaExecutable\\\"\")\"\n      javaHome=$(expr \"$javaHome\" : '\\(.*\\)/bin')\n      JAVA_HOME=\"$javaHome\"\n      export JAVA_HOME\n    fi\n  fi\nfi\n\nif [ -z \"$JAVACMD\" ] ; then\n  if [ -n \"$JAVA_HOME\"  ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n      # IBM's JDK on AIX uses strange locations for the executables\n      JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n      JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n  else\n    JAVACMD=\"$(\\unset -f command 2>/dev/null; \\command -v java)\"\n  fi\nfi\n\nif [ ! -x \"$JAVACMD\" ] ; then\n  echo \"Error: JAVA_HOME is not defined correctly.\" >&2\n  echo \"  We cannot execute $JAVACMD\" >&2\n  exit 1\nfi\n\nif [ -z \"$JAVA_HOME\" ] ; then\n  echo \"Warning: JAVA_HOME environment variable is not set.\"\nfi\n\n# traverses directory structure from process work directory to filesystem root\n# first directory with .mvn subdirectory is considered project base directory\nfind_maven_basedir() {\n  if [ -z \"$1\" ]\n  then\n    echo \"Path not specified to find_maven_basedir\"\n    return 1\n  fi\n\n  basedir=\"$1\"\n  wdir=\"$1\"\n  while [ \"$wdir\" != '/' ] ; do\n    if [ -d \"$wdir\"/.mvn ] ; then\n      basedir=$wdir\n      break\n    fi\n    # workaround for JBEAP-8937 (on Solaris 10/Sparc)\n    if [ -d \"${wdir}\" ]; then\n      wdir=$(cd \"$wdir/..\" || exit 1; pwd)\n    fi\n    # end of workaround\n  done\n  printf '%s' \"$(cd \"$basedir\" || exit 1; pwd)\"\n}\n\n# concatenates all lines of a file\nconcat_lines() {\n  if [ -f \"$1\" ]; then\n    # Remove \\r in case we run on Windows within Git Bash\n    # and check out the repository with auto CRLF management\n    # enabled. Otherwise, we may read lines that are delimited with\n    # \\r\\n and produce $'-Xarg\\r' rather than -Xarg due to word\n    # splitting rules.\n    tr -s '\\r\\n' ' ' < \"$1\"\n  fi\n}\n\nlog() {\n  if [ \"$MVNW_VERBOSE\" = true ]; then\n    printf '%s\\n' \"$1\"\n  fi\n}\n\nBASE_DIR=$(find_maven_basedir \"$(dirname \"$0\")\")\nif [ -z \"$BASE_DIR\" ]; then\n  exit 1;\nfi\n\nMAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-\"$BASE_DIR\"}; export MAVEN_PROJECTBASEDIR\nlog \"$MAVEN_PROJECTBASEDIR\"\n\n##########################################################################################\n# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\n# This allows using the maven wrapper in projects that prohibit checking in binary data.\n##########################################################################################\nwrapperJarPath=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\"\nif [ -r \"$wrapperJarPath\" ]; then\n    log \"Found $wrapperJarPath\"\nelse\n    log \"Couldn't find $wrapperJarPath, downloading it ...\"\n\n    if [ -n \"$MVNW_REPOURL\" ]; then\n      wrapperUrl=\"$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\n    else\n      wrapperUrl=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\n    fi\n    while IFS=\"=\" read -r key value; do\n      # Remove '\\r' from value to allow usage on windows as IFS does not consider '\\r' as a separator ( considers space, tab, new line ('\\n'), and custom '=' )\n      safeValue=$(echo \"$value\" | tr -d '\\r')\n      case \"$key\" in (wrapperUrl) wrapperUrl=\"$safeValue\"; break ;;\n      esac\n    done < \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties\"\n    log \"Downloading from: $wrapperUrl\"\n\n    if $cygwin; then\n      wrapperJarPath=$(cygpath --path --windows \"$wrapperJarPath\")\n    fi\n\n    if command -v wget > /dev/null; then\n        log \"Found wget ... using wget\"\n        [ \"$MVNW_VERBOSE\" = true ] && QUIET=\"\" || QUIET=\"--quiet\"\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            wget $QUIET \"$wrapperUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        else\n            wget $QUIET --http-user=\"$MVNW_USERNAME\" --http-password=\"$MVNW_PASSWORD\" \"$wrapperUrl\" -O \"$wrapperJarPath\" || rm -f \"$wrapperJarPath\"\n        fi\n    elif command -v curl > /dev/null; then\n        log \"Found curl ... using curl\"\n        [ \"$MVNW_VERBOSE\" = true ] && QUIET=\"\" || QUIET=\"--silent\"\n        if [ -z \"$MVNW_USERNAME\" ] || [ -z \"$MVNW_PASSWORD\" ]; then\n            curl $QUIET -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L || rm -f \"$wrapperJarPath\"\n        else\n            curl $QUIET --user \"$MVNW_USERNAME:$MVNW_PASSWORD\" -o \"$wrapperJarPath\" \"$wrapperUrl\" -f -L || rm -f \"$wrapperJarPath\"\n        fi\n    else\n        log \"Falling back to using Java to download\"\n        javaSource=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java\"\n        javaClass=\"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class\"\n        # For Cygwin, switch paths to Windows format before running javac\n        if $cygwin; then\n          javaSource=$(cygpath --path --windows \"$javaSource\")\n          javaClass=$(cygpath --path --windows \"$javaClass\")\n        fi\n        if [ -e \"$javaSource\" ]; then\n            if [ ! -e \"$javaClass\" ]; then\n                log \" - Compiling MavenWrapperDownloader.java ...\"\n                (\"$JAVA_HOME/bin/javac\" \"$javaSource\")\n            fi\n            if [ -e \"$javaClass\" ]; then\n                log \" - Running MavenWrapperDownloader.java ...\"\n                (\"$JAVA_HOME/bin/java\" -cp .mvn/wrapper MavenWrapperDownloader \"$wrapperUrl\" \"$wrapperJarPath\") || rm -f \"$wrapperJarPath\"\n            fi\n        fi\n    fi\nfi\n##########################################################################################\n# End of extension\n##########################################################################################\n\n# If specified, validate the SHA-256 sum of the Maven wrapper jar file\nwrapperSha256Sum=\"\"\nwhile IFS=\"=\" read -r key value; do\n  case \"$key\" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;\n  esac\ndone < \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties\"\nif [ -n \"$wrapperSha256Sum\" ]; then\n  wrapperSha256Result=false\n  if command -v sha256sum > /dev/null; then\n    if echo \"$wrapperSha256Sum  $wrapperJarPath\" | sha256sum -c > /dev/null 2>&1; then\n      wrapperSha256Result=true\n    fi\n  elif command -v shasum > /dev/null; then\n    if echo \"$wrapperSha256Sum  $wrapperJarPath\" | shasum -a 256 -c > /dev/null 2>&1; then\n      wrapperSha256Result=true\n    fi\n  else\n    echo \"Checksum validation was requested but neither 'sha256sum' or 'shasum' are available.\"\n    echo \"Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties.\"\n    exit 1\n  fi\n  if [ $wrapperSha256Result = false ]; then\n    echo \"Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.\" >&2\n    echo \"Investigate or delete $wrapperJarPath to attempt a clean download.\" >&2\n    echo \"If you updated your Maven version, you need to update the specified wrapperSha256Sum property.\" >&2\n    exit 1\n  fi\nfi\n\nMAVEN_OPTS=\"$(concat_lines \"$MAVEN_PROJECTBASEDIR/.mvn/jvm.config\") $MAVEN_OPTS\"\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin; then\n  [ -n \"$JAVA_HOME\" ] &&\n    JAVA_HOME=$(cygpath --path --windows \"$JAVA_HOME\")\n  [ -n \"$CLASSPATH\" ] &&\n    CLASSPATH=$(cygpath --path --windows \"$CLASSPATH\")\n  [ -n \"$MAVEN_PROJECTBASEDIR\" ] &&\n    MAVEN_PROJECTBASEDIR=$(cygpath --path --windows \"$MAVEN_PROJECTBASEDIR\")\nfi\n\n# Provide a \"standardized\" way to retrieve the CLI args that will\n# work with both Windows and non-Windows executions.\nMAVEN_CMD_LINE_ARGS=\"$MAVEN_CONFIG $*\"\nexport MAVEN_CMD_LINE_ARGS\n\nWRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\n\n# shellcheck disable=SC2086 # safe args\nexec \"$JAVACMD\" \\\n  $MAVEN_OPTS \\\n  $MAVEN_DEBUG_OPTS \\\n  -classpath \"$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar\" \\\n  \"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}\" \\\n  ${WRAPPER_LAUNCHER} $MAVEN_CONFIG \"$@\"\n"
  },
  {
    "path": "mvnw.cmd",
    "content": "@REM ----------------------------------------------------------------------------\r\n@REM Licensed to the Apache Software Foundation (ASF) under one\r\n@REM or more contributor license agreements.  See the NOTICE file\r\n@REM distributed with this work for additional information\r\n@REM regarding copyright ownership.  The ASF licenses this file\r\n@REM to you under the Apache License, Version 2.0 (the\r\n@REM \"License\"); you may not use this file except in compliance\r\n@REM with the License.  You may obtain a copy of the License at\r\n@REM\r\n@REM    http://www.apache.org/licenses/LICENSE-2.0\r\n@REM\r\n@REM Unless required by applicable law or agreed to in writing,\r\n@REM software distributed under the License is distributed on an\r\n@REM \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\n@REM KIND, either express or implied.  See the License for the\r\n@REM specific language governing permissions and limitations\r\n@REM under the License.\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@REM ----------------------------------------------------------------------------\r\n@REM Apache Maven Wrapper startup batch script, version 3.2.0\r\n@REM\r\n@REM Required ENV vars:\r\n@REM JAVA_HOME - location of a JDK home dir\r\n@REM\r\n@REM Optional ENV vars\r\n@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands\r\n@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending\r\n@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven\r\n@REM     e.g. to debug Maven itself, use\r\n@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000\r\n@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files\r\n@REM ----------------------------------------------------------------------------\r\n\r\n@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'\r\n@echo off\r\n@REM set title of command window\r\ntitle %0\r\n@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'\r\n@if \"%MAVEN_BATCH_ECHO%\" == \"on\"  echo %MAVEN_BATCH_ECHO%\r\n\r\n@REM set %HOME% to equivalent of $HOME\r\nif \"%HOME%\" == \"\" (set \"HOME=%HOMEDRIVE%%HOMEPATH%\")\r\n\r\n@REM Execute a user defined script before this one\r\nif not \"%MAVEN_SKIP_RC%\" == \"\" goto skipRcPre\r\n@REM check for pre script, once with legacy .bat ending and once with .cmd ending\r\nif exist \"%USERPROFILE%\\mavenrc_pre.bat\" call \"%USERPROFILE%\\mavenrc_pre.bat\" %*\r\nif exist \"%USERPROFILE%\\mavenrc_pre.cmd\" call \"%USERPROFILE%\\mavenrc_pre.cmd\" %*\r\n:skipRcPre\r\n\r\n@setlocal\r\n\r\nset ERROR_CODE=0\r\n\r\n@REM To isolate internal variables from possible post scripts, we use another setlocal\r\n@setlocal\r\n\r\n@REM ==== START VALIDATION ====\r\nif not \"%JAVA_HOME%\" == \"\" goto OkJHome\r\n\r\necho.\r\necho Error: JAVA_HOME not found in your environment. >&2\r\necho Please set the JAVA_HOME variable in your environment to match the >&2\r\necho location of your Java installation. >&2\r\necho.\r\ngoto error\r\n\r\n:OkJHome\r\nif exist \"%JAVA_HOME%\\bin\\java.exe\" goto init\r\n\r\necho.\r\necho Error: JAVA_HOME is set to an invalid directory. >&2\r\necho JAVA_HOME = \"%JAVA_HOME%\" >&2\r\necho Please set the JAVA_HOME variable in your environment to match the >&2\r\necho location of your Java installation. >&2\r\necho.\r\ngoto error\r\n\r\n@REM ==== END VALIDATION ====\r\n\r\n:init\r\n\r\n@REM Find the project base dir, i.e. the directory that contains the folder \".mvn\".\r\n@REM Fallback to current working directory if not found.\r\n\r\nset MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%\r\nIF NOT \"%MAVEN_PROJECTBASEDIR%\"==\"\" goto endDetectBaseDir\r\n\r\nset EXEC_DIR=%CD%\r\nset WDIR=%EXEC_DIR%\r\n:findBaseDir\r\nIF EXIST \"%WDIR%\"\\.mvn goto baseDirFound\r\ncd ..\r\nIF \"%WDIR%\"==\"%CD%\" goto baseDirNotFound\r\nset WDIR=%CD%\r\ngoto findBaseDir\r\n\r\n:baseDirFound\r\nset MAVEN_PROJECTBASEDIR=%WDIR%\r\ncd \"%EXEC_DIR%\"\r\ngoto endDetectBaseDir\r\n\r\n:baseDirNotFound\r\nset MAVEN_PROJECTBASEDIR=%EXEC_DIR%\r\ncd \"%EXEC_DIR%\"\r\n\r\n:endDetectBaseDir\r\n\r\nIF NOT EXIST \"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\" goto endReadAdditionalConfig\r\n\r\n@setlocal EnableExtensions EnableDelayedExpansion\r\nfor /F \"usebackq delims=\" %%a in (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\jvm.config\") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a\r\n@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%\r\n\r\n:endReadAdditionalConfig\r\n\r\nSET MAVEN_JAVA_EXE=\"%JAVA_HOME%\\bin\\java.exe\"\r\nset WRAPPER_JAR=\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.jar\"\r\nset WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain\r\n\r\nset WRAPPER_URL=\"https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\r\n\r\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\r\n    IF \"%%A\"==\"wrapperUrl\" SET WRAPPER_URL=%%B\r\n)\r\n\r\n@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central\r\n@REM This allows using the maven wrapper in projects that prohibit checking in binary data.\r\nif exist %WRAPPER_JAR% (\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Found %WRAPPER_JAR%\r\n    )\r\n) else (\r\n    if not \"%MVNW_REPOURL%\" == \"\" (\r\n        SET WRAPPER_URL=\"%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar\"\r\n    )\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Couldn't find %WRAPPER_JAR%, downloading it ...\r\n        echo Downloading from: %WRAPPER_URL%\r\n    )\r\n\r\n    powershell -Command \"&{\"^\r\n\t\t\"$webclient = new-object System.Net.WebClient;\"^\r\n\t\t\"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {\"^\r\n\t\t\"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');\"^\r\n\t\t\"}\"^\r\n\t\t\"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')\"^\r\n\t\t\"}\"\r\n    if \"%MVNW_VERBOSE%\" == \"true\" (\r\n        echo Finished downloading %WRAPPER_JAR%\r\n    )\r\n)\r\n@REM End of extension\r\n\r\n@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file\r\nSET WRAPPER_SHA_256_SUM=\"\"\r\nFOR /F \"usebackq tokens=1,2 delims==\" %%A IN (\"%MAVEN_PROJECTBASEDIR%\\.mvn\\wrapper\\maven-wrapper.properties\") DO (\r\n    IF \"%%A\"==\"wrapperSha256Sum\" SET WRAPPER_SHA_256_SUM=%%B\r\n)\r\nIF NOT %WRAPPER_SHA_256_SUM%==\"\" (\r\n    powershell -Command \"&{\"^\r\n       \"$hash = (Get-FileHash \\\"%WRAPPER_JAR%\\\" -Algorithm SHA256).Hash.ToLower();\"^\r\n       \"If('%WRAPPER_SHA_256_SUM%' -ne $hash){\"^\r\n       \"  Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';\"^\r\n       \"  Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';\"^\r\n       \"  Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';\"^\r\n       \"  exit 1;\"^\r\n       \"}\"^\r\n       \"}\"\r\n    if ERRORLEVEL 1 goto error\r\n)\r\n\r\n@REM Provide a \"standardized\" way to retrieve the CLI args that will\r\n@REM work with both Windows and non-Windows executions.\r\nset MAVEN_CMD_LINE_ARGS=%*\r\n\r\n%MAVEN_JAVA_EXE% ^\r\n  %JVM_CONFIG_MAVEN_PROPS% ^\r\n  %MAVEN_OPTS% ^\r\n  %MAVEN_DEBUG_OPTS% ^\r\n  -classpath %WRAPPER_JAR% ^\r\n  \"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%\" ^\r\n  %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*\r\nif ERRORLEVEL 1 goto error\r\ngoto end\r\n\r\n:error\r\nset ERROR_CODE=1\r\n\r\n:end\r\n@endlocal & set ERROR_CODE=%ERROR_CODE%\r\n\r\nif not \"%MAVEN_SKIP_RC%\"==\"\" goto skipRcPost\r\n@REM check for post script, once with legacy .bat ending and once with .cmd ending\r\nif exist \"%USERPROFILE%\\mavenrc_post.bat\" call \"%USERPROFILE%\\mavenrc_post.bat\"\r\nif exist \"%USERPROFILE%\\mavenrc_post.cmd\" call \"%USERPROFILE%\\mavenrc_post.cmd\"\r\n:skipRcPost\r\n\r\n@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'\r\nif \"%MAVEN_BATCH_PAUSE%\"==\"on\" pause\r\n\r\nif \"%MAVEN_TERMINATE_CMD%\"==\"on\" exit %ERROR_CODE%\r\n\r\ncmd /C exit /B %ERROR_CODE%\r\n"
  },
  {
    "path": "pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n     Copyright 2023 The original authors\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n\n-->\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd\">\n  <modelVersion>4.0.0</modelVersion>\n  \n  <groupId>dev.morling.demos</groupId>\n  <artifactId>average</artifactId>\n  <version>1.0.0-SNAPSHOT</version>\n  \n  <properties>\n    <maven.compiler.parameters>true</maven.compiler.parameters>\n    <maven.compiler.release>21</maven.compiler.release>\n    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>\n  </properties>\n\n  <name>My OSS Project</name>\n  <description>My Latest OSS Project</description>\n  <inceptionYear>2021</inceptionYear>\n  <url>tbd.</url>\n\n  <licenses>\n    <license>\n      <name>Apache-2.0</name>\n      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>\n      <distribution>repo</distribution>\n    </license>\n  </licenses>\n\n  <dependencyManagement>\n    <dependencies>\n      <dependency>\n        <groupId>org.junit</groupId>\n        <artifactId>junit-bom</artifactId>\n        <version>5.8.1</version>\n        <type>pom</type>\n        <scope>import</scope>\n      </dependency>\n    </dependencies>\n  </dependencyManagement>\n\n  <dependencies>\n    <dependency>\n      <groupId>org.junit.jupiter</groupId>\n      <artifactId>junit-jupiter</artifactId>\n      <scope>test</scope>\n    </dependency>\n    <dependency>\n      <groupId>org.assertj</groupId>\n      <artifactId>assertj-core</artifactId>\n      <version>3.21.0</version>\n      <scope>test</scope>\n    </dependency>\n  </dependencies>\n\n  <build>\n    <!-- Keep alphabetic order -->\n    <pluginManagement>\n      <plugins>\n        <plugin>\n          <groupId>com.mycila</groupId>\n          <artifactId>license-maven-plugin</artifactId>\n          <version>4.1</version>\n        </plugin>\n        <plugin>\n          <groupId>net.revelc.code.formatter</groupId>\n          <artifactId>formatter-maven-plugin</artifactId>\n          <version>2.16.0</version>\n          <configuration>\n            <configFile>etc/eclipse-formatter-config.xml</configFile>\n            <directories>\n              <directory>${project.build.sourceDirectory}</directory>\n              <directory>${project.basedir}/src/main/java-22</directory>\n            </directories>\n          </configuration>\n        </plugin>\n        <plugin>\n          <groupId>net.revelc.code</groupId>\n          <artifactId>impsort-maven-plugin</artifactId>\n          <version>1.9.0</version>\n          <configuration>\n            <groups>java.,javax.,org.,com.</groups>\n            <removeUnused>true</removeUnused>\n            <staticAfter>true</staticAfter>\n          </configuration>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-compiler-plugin</artifactId>\n          <version>3.12.1</version>\n          <configuration>\n            <parameters>true</parameters>\n            <compilerArgs>\n              <!--\n                IntelliJ does not yet support the enablePreview configuration option.\n                Therefore, we use a compiler argument.\n                See https://youtrack.jetbrains.com/issue/IDEA-296303\n              -->\n              <compilerArg>--enable-preview</compilerArg>\n              <compilerArg>--add-modules</compilerArg>\n              <compilerArg>java.base,jdk.incubator.vector</compilerArg>\n              <compilerArg>--add-opens=java.base/java.lang=ALL-UNNAMED</compilerArg>\n              <compilerArg>--add-opens=java.base/jdk.internal.util=ALL-UNNAMED</compilerArg>\n            </compilerArgs>\n          </configuration>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-clean-plugin</artifactId>\n          <version>3.1.0</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-deploy-plugin</artifactId>\n          <version>3.1.1</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-enforcer-plugin</artifactId>\n          <version>3.3.0</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-install-plugin</artifactId>\n          <version>3.1.1</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-jar-plugin</artifactId>\n          <version>3.2.0</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-resources-plugin</artifactId>\n          <version>3.2.0</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-site-plugin</artifactId>\n          <version>3.12.1</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-surefire-plugin</artifactId>\n          <version>3.2.3</version>\n        </plugin>\n        <plugin>\n          <groupId>org.apache.maven.plugins</groupId>\n          <artifactId>maven-wrapper-plugin</artifactId>\n          <version>3.2.0</version>\n        </plugin>\n      </plugins>\n    </pluginManagement>\n\n  </build>\n  <profiles>\n    <profile>\n      <id>ci</id>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>net.revelc.code.formatter</groupId>\n            <artifactId>formatter-maven-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>validate-format</id>\n                <goals>\n                  <goal>validate</goal>\n                </goals>\n                <phase>validate</phase>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n    <profile>\n      <id>qa</id>\n      <activation>\n        <property>\n          <name>!quick</name>\n        </property>\n      </activation>\n      <build>\n        <plugins>\n          <plugin>\n            <groupId>com.mycila</groupId>\n            <artifactId>license-maven-plugin</artifactId>\n            <configuration>\n              <header>etc/license.txt</header>\n              <strictCheck>true</strictCheck>\n              <aggregate>true</aggregate>\n              <excludes>\n                <exclude>LICENSE.txt</exclude>\n                <exclude>**/.dontdelete</exclude>\n                <exclude>**/measurements*.txt</exclude>\n                <exclude>**/measurements*.out</exclude>\n                <exclude>out_expected.txt</exclude>\n                <exclude>github_users.txt</exclude>\n                <!-- Cliff asked to be named as the copyright holder for his entry; -->\n                <exclude>src/main/java/dev/morling/onebrc/CalculateAverage_cliffclick.java</exclude>\n                <exclude>.sdkmanrc</exclude>\n              </excludes>\n            </configuration>\n            <executions>\n              <execution>\n                <goals>\n                  <goal>check</goal>\n                </goals>\n              </execution>\n            </executions>\n          </plugin>\n          <plugin>\n            <groupId>net.revelc.code.formatter</groupId>\n            <artifactId>formatter-maven-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>format</id>\n                <goals>\n                  <goal>format</goal>\n                </goals>\n                <phase>process-sources</phase>\n              </execution>\n            </executions>\n          </plugin>\n<!--          <plugin>-->\n<!--            <groupId>net.revelc.code</groupId>-->\n<!--            <artifactId>impsort-maven-plugin</artifactId>-->\n<!--            <executions>-->\n<!--              <execution>-->\n<!--                <id>sort-imports</id>-->\n<!--                <goals>-->\n<!--                  <goal>sort</goal>-->\n<!--                </goals>-->\n<!--                <phase>process-sources</phase>-->\n<!--              </execution>-->\n<!--            </executions>-->\n<!--          </plugin>-->\n          <plugin>\n            <groupId>org.apache.maven.plugins</groupId>\n            <artifactId>maven-enforcer-plugin</artifactId>\n            <executions>\n              <execution>\n                <id>enforce-plugin-versions</id>\n                <goals>\n                  <goal>enforce</goal>\n                </goals>\n                <configuration>\n                  <rules>\n                    <requireJavaVersion>\n                      <version>${maven.compiler.release}</version>\n                    </requireJavaVersion>\n                    <requirePluginVersions>\n                       <banLatest>true</banLatest>\n                       <banRelease>true</banRelease>\n                       <banSnapshots>true</banSnapshots>\n                       <phases>clean,deploy,site</phases>\n                    </requirePluginVersions>\n                  </rules>\n                </configuration>\n              </execution>\n            </executions>\n          </plugin>\n        </plugins>\n      </build>\n    </profile>\n    <profile>\n      <id>quick</id>\n      <activation>\n        <property>\n          <name>quick</name>\n        </property>\n      </activation>\n      <properties>\n        <skipTests>true</skipTests>\n      </properties>\n    </profile>\n    <profile>\n      <id>jdk22</id>\n      <activation>\n        <jdk>22</jdk>\n      </activation>\n      <properties>\n      </properties>\n      <build>\n        <pluginManagement>\n          <plugins>\n            <plugin>\n              <artifactId>maven-compiler-plugin</artifactId>\n              <configuration>\n                <release>22</release>\n                <compileSourceRoots>\n                  <compileSourceRoot>${project.basedir}/src/main/java-22</compileSourceRoot>\n                  <!--\n                    Uncomment the next line to build the entire project with jdk22.\n                    Currently, some classes fail to compile under jdk22.\n                  -->\n                  <!-- <compileSourceRoot>${project.build.sourceDirectory}</compileSourceRoot> -->\n                </compileSourceRoots>\n              </configuration>\n            </plugin>\n          </plugins>\n        </pluginManagement>\n      </build>\n    </profile>\n  </profiles>\n</project>\n"
  },
  {
    "path": "prepare_3j5a.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_AlexanderYastrebov.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nDOCKER_BUILDKIT=1 docker build -o target/AlexanderYastrebov src/main/go/AlexanderYastrebov\n"
  },
  {
    "path": "prepare_C5H12O5.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_EduardoSaverin.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_JaimePolidura.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_JaimePolidura_image ]; then\n\tOPTS=\"--gc=epsilon -O3 --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_JaimePolidura\"\n\tnative-image $OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_JaimePolidura_image dev.morling.onebrc.CalculateAverage_JaimePolidura\nfi\t\n"
  },
  {
    "path": "prepare_JamalMulla.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_JamalMulla_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native --enable-preview --strict-image-heap --link-at-build-time -R:MaxHeapSize=64m -da -dsa --no-fallback --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_JamalMulla\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_JamalMulla_image dev.morling.onebrc.CalculateAverage_JamalMulla\nfi"
  },
  {
    "path": "prepare_Judekeyser.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_Kidlike.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ ! -e target/image_calculateaverage_Kidlike ]; then\n  source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n  sdk use java 21.0.1-graal\n  #NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native --enable-preview\"\n  NATIVE_IMAGE_OPTS=\"-O3 -march=native --enable-preview\"\n  native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/image_calculateaverage_Kidlike dev.morling.onebrc.CalculateAverage_Kidlike\nfi"
  },
  {
    "path": "prepare_MeanderingProgrammer.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_PanagiotisDrakatos.sh",
    "content": "#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n\nif [ ! -f target/CalculateAverage_PanagiotisDrakatos_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -R:MaxHeapSize=10536m --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_PanagiotisDrakatos\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_PanagiotisDrakatos_image dev.morling.onebrc.CalculateAverage_PanagiotisDrakatos\nfi"
  },
  {
    "path": "prepare_PawelAdamski.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_SamuelYvon.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# THIS IS A DIRECT COPY OF royvanrijn's PREPARE SCRIPT; I AM NOT FAMILIAR WITH AOT STUFF ON JAVA.\n# THANKS royvanrijn!!\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_SamuelYvon_image ]; then\n\n    JAVA_OPTS=\"--enable-preview -dsa\"\n\n    # No vector API because it does not link :(\n#    JAVA_OPTS=\"--enable-preview -dsa --add-modules jdk.incubator.vector\"\n\n#     Enable the GC because I need memory :D\n    NATIVE_IMAGE_OPTS=\"--gc=G1 -O3 -march=native --strict-image-heap $JAVA_OPTS\"\n\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_SamuelYvon_image dev.morling.onebrc.CalculateAverage_SamuelYvon\nfi\n"
  },
  {
    "path": "prepare_Smoofie.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_YannMoisan.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_abeobk.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_abeobk_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native -H:InlineAllBonus=10 -H:-GenLoopSafepoints --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_abeobk\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_abeobk_image dev.morling.onebrc.CalculateAverage_abeobk\nfi\n"
  },
  {
    "path": "prepare_adriacabeza.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_agoncal.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-tem 1>&2\n"
  },
  {
    "path": "prepare_ags313.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_anitasv.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_armandino.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_armandino_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native --enable-preview -H:InlineAllBonus=10 -H:-ParseRuntimeOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_armandino\\$Scanner\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_armandino_image dev.morling.onebrc.CalculateAverage_armandino\nfi\n"
  },
  {
    "path": "prepare_artsiomkorzun.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_artsiomkorzun_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native -H:TuneInlinerExploration=1 -R:MaxHeapSize=64m -H:-GenLoopSafepoints --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_artsiomkorzun\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_artsiomkorzun_image dev.morling.onebrc.CalculateAverage_artsiomkorzun\nfi"
  },
  {
    "path": "prepare_baseline.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_breejesh.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_cb0s.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_charlibot.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_chrisbellew.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_coolmineman.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_davecom.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_ddimtirov.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# also tried: 23.ea.3-open, 21.0.1-graalce, 21.0.1-graal, 21.0.1.crac-librca (tried CRaC API to see if it preserves JIT state)\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-tem\n"
  },
  {
    "path": "prepare_dpsoft.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2"
  },
  {
    "path": "prepare_dqhieuu.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_ebarlas.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_ebarlas_image ]; then\n    NATIVE_IMAGE_OPTS=\"-H:+UnlockExperimentalVMOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_ebarlas --gc=epsilon -O3 -march=native -R:MaxHeapSize=128m -H:-GenLoopSafepoints --enable-preview\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_ebarlas_image dev.morling.onebrc.CalculateAverage_ebarlas\nfi\n"
  },
  {
    "path": "prepare_elh.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nDOCKER_BUILDKIT=1 docker build -o target/elh src/main/go/elh\n"
  },
  {
    "path": "prepare_eriklumme.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_filiphr.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_flippingbits.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_gabrielfoo.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal > /dev/null 2>&1"
  },
  {
    "path": "prepare_gnabyl.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_godofwharf.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-tem 1>&2"
  },
  {
    "path": "prepare_hundredwatt.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal\n"
  },
  {
    "path": "prepare_imrafaelmerino.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_iziamos.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_iziamos_image ]; then\n    NATIVE_IMAGE_OPTS=\"-H:+UnlockExperimentalVMOptions --gc=epsilon -O3 -march=native -R:MaxHeapSize=64m -H:-GenLoopSafepoints --enable-preview -H:InlineAllBonus=10 -H:-ParseRuntimeOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_iziamos\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_iziamos_image dev.morling.onebrc.CalculateAverage_iziamos\nfi\n"
  },
  {
    "path": "prepare_jatingala.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_jbachorik.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_jerrinot.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_jerrinot_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native --enable-preview -H:-GenLoopSafepoints -H:InlineAllBonus=10 --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_jerrinot\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_jerrinot_image dev.morling.onebrc.CalculateAverage_jerrinot\nfi\n"
  },
  {
    "path": "prepare_jonathan-aotearoa.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_jonathan-aotearoa_image ]; then\n    # Enable preview features and disable system assertions.\n    JAVA_OPTS=\"--enable-preview -dsa\"\n    # Use the no-op GC.\n    # Enable CPU features (-march=native) and level-3 optimisations (-O3)\n    NATIVE_IMAGE_OPTS=\"--initialize-at-build-time=dev.morling.onebrc.CalculateAverage_jonathanaotearoa --gc=epsilon -O3 -march=native --strict-image-heap $JAVA_OPTS\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_jonathan-aotearoa_image dev.morling.onebrc.CalculateAverage_jonathanaotearoa\nfi"
  },
  {
    "path": "prepare_justplainlaake.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n\nif [ ! -f target/CalculateAverage_justplainlaake_image ]; then\n    #disable assertions\n    #optimize code for best performance\n    #native march gives best performance for machine image is built on\n    #strict image heap allows all classes ot be used at build time\n    #native image info prints the trace of the build\n    #enable preview allows for preview features of current release\n    #epsilon garbage collector is a gc that doesn't gc... haha\n    native-image -dsa -O3 -march=native --strict-image-heap --native-image-info --enable-preview --gc=epsilon -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_justplainlaake_image dev.morling.onebrc.CalculateAverage_justplainlaake\nfi\n"
  },
  {
    "path": "prepare_kuduwa-keshavram.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_linl33.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 22.ea.32-open 1>&2\n\nCLASS_NAME=\"CalculateAverage_linl33\"\n\nJAVA_OPTS=\"-Xrs --enable-preview --add-modules jdk.incubator.vector --enable-native-access=ALL-UNNAMED\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions\"\nJAVA_OPTS=\"${JAVA_OPTS} -Xms128m -XX:+AlwaysPreTouch -XX:+AlwaysPreTouchStacks -XX:-UseTransparentHugePages\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseCompressedClassPointers -XX:+ForceUnreachable -XX:-CompactStrings\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:CodeEntryAlignment=64 -XX:OptoLoopAlignment=64 -XX:MaxLoopPad=16 -XX:ObjectAlignmentInBytes=64\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseLoopPredicate -XX:LoopStripMiningIter=0 -XX:LoopStripMiningIterShortLoop=0\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseCountedLoopSafepoints -XX:GuaranteedSafepointInterval=0 -XX:AllocatePrefetchStyle=0\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+TrustFinalNonStaticFields -XX:LockingMode=2 -XX:+UseSystemMemoryBarrier\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:-UseDynamicNumberOfCompilerThreads -XX:-UseDynamicNumberOfGCThreads\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:ArchiveRelocationMode=0 -XX:-UsePerfData -XX:-UseNotificationThread -XX:-CheckIntrinsics\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseZGC -XX:-ZProactive -XX:+ZCollectionIntervalOnly -XX:ZCollectionInterval=0 -XX:-ZUncommit -XX:-ZBufferStoreBarriers -XX:ZIndexDistributorStrategy=1\"\nJAVA_OPTS=\"${JAVA_OPTS} -XX:+UseEpsilonGC -XX:-UseCompressedOops\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseParallelGC -XX:-UseCompressedOops\"\n#JAVA_OPTS=\"${JAVA_OPTS} -XX:+UseG1GC -XX:-UseCompressedOops\"\nJAVA_OPTS=\"${JAVA_OPTS} -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0 -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.MethodHandle.DONT_INLINE_THRESHOLD=-1\"\nJAVA_OPTS=\"${JAVA_OPTS} -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8\"\nJAVA_OPTS=\"${JAVA_OPTS} -Ddev.morling.onebrc.CalculateAverage_linl33.measurementsPath=src/test/resources/samples/measurements-10000-unique-keys.txt\"\n\n# create CDS archive\njava ${JAVA_OPTS} -Xshare:off -XX:DumpLoadedClassList=target/${CLASS_NAME}.classlist --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.${CLASS_NAME}\njava ${JAVA_OPTS} -Xshare:dump -XX:SharedClassListFile=target/${CLASS_NAME}.classlist -XX:SharedArchiveFile=target/${CLASS_NAME}.jsa --class-path target/average-1.0.0-SNAPSHOT.jar\njava ${JAVA_OPTS} -Xshare:on -XX:SharedArchiveFile=target/${CLASS_NAME}.jsa -XX:ArchiveClassesAtExit=target/${CLASS_NAME}_dynamic.jsa --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.${CLASS_NAME}\n"
  },
  {
    "path": "prepare_mahadev-k.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_manishgarg90.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_martin2038.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n##\n#if [ ! -f target/CalculateAverage_martin2038 ]; then\n#    MAIN=dev.morling.onebrc.CalculateAverage_martin2038\n#    NATIVE_IMAGE_OPTS=\"-H:+UnlockExperimentalVMOptions --initialize-at-build-time=$MAIN --gc=epsilon -O3 -march=native -R:MaxHeapSize=515m -H:-GenLoopSafepoints -H:InlineAllBonus=10 -H:-ParseRuntimeOptions\"\n#    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_martin2038_image $MAIN\n#fi"
  },
  {
    "path": "prepare_maximz101.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n#sdk use java 21.0.1-amzn 1>&2"
  },
  {
    "path": "prepare_melgenek.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-open 1>&2\n"
  },
  {
    "path": "prepare_mtopolnik.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_mtopolnik_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -H:+UnlockExperimentalVMOptions -H:-GenLoopSafepoints -march=native --enable-preview -H:InlineAllBonus=10 -H:-ParseRuntimeOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_mtopolnik\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_mtopolnik_image dev.morling.onebrc.CalculateAverage_mtopolnik\nfi\n"
  },
  {
    "path": "prepare_phd3.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_plevart.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-tem 1>&2\n"
  },
  {
    "path": "prepare_rcasteltrione.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_ricardopieper.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_roman-r-m.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_roman_r_m_image ]; then\n\n    JAVA_OPTS=\"--enable-preview -dsa\"\n    NATIVE_IMAGE_OPTS=\"--initialize-at-build-time=dev.morling.onebrc.CalculateAverage_roman_r_m --gc=epsilon -Ob -O3 -march=native --strict-image-heap $JAVA_OPTS\"\n    NATIVE_IMAGE_OPTS=\"$NATIVE_IMAGE_OPTS -R:MaxHeapSize=128m\"\n    NATIVE_IMAGE_OPTS=\"$NATIVE_IMAGE_OPTS -H:+UnlockExperimentalVMOptions -H:-GenLoopSafepoints -H:InlineAllBonus=10 -H:-ParseRuntimeOptions\"\n\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_roman_r_m_image dev.morling.onebrc.CalculateAverage_roman_r_m\nfi"
  },
  {
    "path": "prepare_royvanrijn.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_royvanrijn_image ]; then\n\n    JAVA_OPTS=\"--enable-preview\"\n    NATIVE_IMAGE_OPTS=\"-H:+UnlockExperimentalVMOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_royvanrijn --gc=epsilon -O3 -march=native -R:MaxHeapSize=515m -H:-GenLoopSafepoints -H:InlineAllBonus=10 -H:-ParseRuntimeOptions $JAVA_OPTS\"\n\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_royvanrijn_image dev.morling.onebrc.CalculateAverage_royvanrijn\nfi\n"
  },
  {
    "path": "prepare_seijikun.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_serkan-ozal.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-open 1>&2\n\nJAVA_OPTS=\"--enable-preview --enable-native-access=ALL-UNNAMED --add-modules=jdk.incubator.vector \"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-TieredCompilation -XX:MaxInlineSize=10000 -XX:InlineSmallCode=10000 -XX:FreqInlineSize=10000\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:-UseCountedLoopSafepoints -XX:GuaranteedSafepointInterval=0\"\nJAVA_OPTS=\"$JAVA_OPTS -XX:+TrustFinalNonStaticFields -da -dsa -XX:+UseNUMA -XX:-EnableJVMCI\"\nJAVA_OPTS=\"$JAVA_OPTS -Djdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK=0\"\nJAVA_OPTS=\"${JAVA_OPTS} -Dfile.path=src/test/resources/samples/measurements-10000-unique-keys.txt\"\nif [[ ! \"$(uname -s)\" = \"Darwin\" ]]; then\n  JAVA_OPTS=\"$JAVA_OPTS -XX:+UseTransparentHugePages\"\nfi\n\n# Set configs\nexport USE_SHARED_ARENA=true\nexport USE_SHARED_REGION=true\nexport CLOSE_STDOUT_ON_RESULT=true\n\nCLASS_NAME=\"CalculateAverage_serkan_ozal\"\n\n# Create CDS archive\njava ${JAVA_OPTS} -Xshare:off -XX:DumpLoadedClassList=target/${CLASS_NAME}.classlist --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.${CLASS_NAME}\njava ${JAVA_OPTS} -Xshare:dump -XX:SharedClassListFile=target/${CLASS_NAME}.classlist -XX:SharedArchiveFile=target/${CLASS_NAME}.jsa --class-path target/average-1.0.0-SNAPSHOT.jar\njava ${JAVA_OPTS} -Xshare:on -XX:SharedArchiveFile=target/${CLASS_NAME}.jsa -XX:ArchiveClassesAtExit=target/${CLASS_NAME}_cds.jsa --class-path target/average-1.0.0-SNAPSHOT.jar dev.morling.onebrc.${CLASS_NAME}\n"
  },
  {
    "path": "prepare_slovdahl.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\n\nsdk use java 21.0.2-tem 1>&2 > /dev/null\n./mvnw verify\n"
  },
  {
    "path": "prepare_spullara.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_stephenvonworley.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_stephenvonworley_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -H:TuneInlinerExploration=1 -march=native --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_stephenvonworley\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_stephenvonworley_image dev.morling.onebrc.CalculateAverage_stephenvonworley\nfi\n"
  },
  {
    "path": "prepare_sudhirtumati.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-open 1>&2\n"
  },
  {
    "path": "prepare_thanhtrinity.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_thomaswue.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_thomaswue_image ]; then\n\n    # Performance tuning flags, optimization level 3, maximum inlining exploration, and compile for the architecture where the native image is generated.\n    NATIVE_IMAGE_OPTS=\"-O3 -H:TuneInlinerExploration=1 -march=native\"\n   \n    # Need to enable preview for accessing the raw address of the foreign memory access API.\n    # Initializing the Scanner to make sure the unsafe access object is known as a non-null compile time constant.\n    NATIVE_IMAGE_OPTS=\"$NATIVE_IMAGE_OPTS --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_thomaswue\\$Scanner\"\n\n    # There is no need for garbage collection and therefore also no safepoints required.\n    NATIVE_IMAGE_OPTS=\"$NATIVE_IMAGE_OPTS --gc=epsilon -H:-GenLoopSafepoints\"\n\n    # Uncomment the following line for outputting the compiler graph to the IdealGraphVisualizer\n    # NATIVE_IMAGE_OPTS=\"$NATIVE_IMAGE_OPTS -H:MethodFilter=CalculateAverage_thomaswue.* -H:Dump=:2 -H:PrintGraph=Network\"\n    \n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_thomaswue_image dev.morling.onebrc.CalculateAverage_thomaswue\nfi\n"
  },
  {
    "path": "prepare_tivrfoa.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\n# ./mvnw clean verify removes target/ and will re-trigger native image creation.\nif [ ! -f target/CalculateAverage_tivrfoa_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -H:-GenLoopSafepoints -march=native --enable-preview -H:InlineAllBonus=10 -H:-ParseRuntimeOptions --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_tivrfoa\\$Scanner\"\n    # Use -H:MethodFilter=CalculateAverage_tivrfoa.* -H:Dump=:2 -H:PrintGraph=Network for IdealGraphVisualizer graph dumping.\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_tivrfoa_image dev.morling.onebrc.CalculateAverage_tivrfoa\nfi\n"
  },
  {
    "path": "prepare_tonivade.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-tem 1>&2\n"
  },
  {
    "path": "prepare_truelive.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graalce 1>&2\n"
  },
  {
    "path": "prepare_twobiers.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-tem 1>&2\n"
  },
  {
    "path": "prepare_vaidhy.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_vemana.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\n#sdk1 use java 21.0.1-open 1>&2\nsdk use java 21.0.1-graal 1>&2\n#sdk1 use java 21.0.1-zulu 1>&2\n#sdk1 use java 21.0.1-graalce 1>&2\n\n"
  },
  {
    "path": "prepare_vemanaNonIdiomatic.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.1-graal 1>&2\n\n"
  },
  {
    "path": "prepare_yavuztas.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_yavuztas_image ]; then\n    NATIVE_IMAGE_OPTS=\"--initialize-at-build-time=dev.morling.onebrc.CalculateAverage_yavuztas --gc=epsilon -O3 -march=native -R:MaxHeapSize=128m -H:-GenLoopSafepoints --enable-preview\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_yavuztas_image dev.morling.onebrc.CalculateAverage_yavuztas\nfi\n"
  },
  {
    "path": "prepare_yonatang.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Uncomment below to use sdk\n# source \"$HOME/.sdkman/bin/sdkman-init.sh\"\n# sdk use java 21.0.1-graal 1>&2\n"
  },
  {
    "path": "prepare_zerninv.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\nsdk use java 21.0.2-graal 1>&2\n\nif [ ! -f target/CalculateAverage_zerninv_image ]; then\n    NATIVE_IMAGE_OPTS=\"--gc=epsilon -O3 -march=native -R:MaxHeapSize=512m -H:-GenLoopSafepoints --enable-preview --initialize-at-build-time=dev.morling.onebrc.CalculateAverage_zerninv\"\n    native-image $NATIVE_IMAGE_OPTS -cp target/average-1.0.0-SNAPSHOT.jar -o target/CalculateAverage_zerninv_image dev.morling.onebrc.CalculateAverage_zerninv\nfi"
  },
  {
    "path": "process.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: process_output.sh <fork name>\"\n    exit 1\nfi\n\njava --enable-preview --source=21 process_output.java out_expected.txt $1.out\n"
  },
  {
    "path": "process_output.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.stream.Collectors;\nimport java.time.Duration;\n\npublic class process_output {\n\n    public static void main(String... args) throws Exception {\n        String expectedFile = args[0];\n        String actualFile = args[1];\n\n        String expected = new String(Files.readAllBytes(Paths.get(expectedFile)));\n        List<String> times = new ArrayList<>();\n\n        var outputLines = Files.lines(Paths.get(actualFile))\n                .collect(Collectors.toList());\n\n        int matched = 0;\n\n        for (String line : outputLines) {\n            if (line.contains(\"Hamburg\")) {\n                if (!line.equals(expected)) {\n                    System.err.println(\"FAILURE Unexpected output\");\n                    System.err.println(line);\n                }\n                else {\n                    matched++;\n                }\n            }\n            else if (line.startsWith(\"real\")) {\n                times.add(line);\n            }\n        }\n\n        if (matched == 5) {\n            System.out.println(\"OK Output matched\");\n        }\n        else {\n            System.err.println(\"FAILURE Output didn't match\");\n        }\n\n        System.out.println();\n        System.out.println(actualFile);\n\n        System.out.println(times.stream()\n            .map(t -> t.substring(5))\n            .map(t -> t.replace(\"s\", \"\").replace(\"m\", \":\"))\n            .collect(Collectors.joining(System.lineSeparator())));\n\n        var asDurations = times.stream()\n            .map(t -> t.substring(5))\n            .map(t -> t.replace(\"s\", \"S\").replace(\"m\", \"M\"))\n            .map(t -> \"PT\" + t)\n            .map(Duration::parse)\n            .collect(Collectors.toList());\n\n        var min = asDurations.stream().min(Comparator.naturalOrder()).get();\n        var max = asDurations.stream().max(Comparator.naturalOrder()).get();\n\n        var evaluated = asDurations.stream()\n            .filter(d -> d != min && d != max)\n            .collect(Collectors.toList());\n\n        var mean = evaluated.get(0).plus(evaluated.get(1)).plus(evaluated.get(2)).dividedBy(3);\n        var result = String.format(\"%02d:%02d.%.0f\", mean.toMinutesPart(), mean.toSecondsPart(), (double) mean.toNanosPart() / 1_000_000);\n        var author = actualFile.replace(\".out\", \"\");\n\n        System.out.println(String.format(\"\\n|   |        %s| [link](https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_%s.java)| 21.0.1-open | [%s](https://github.com/%s)|\", result, author, author, author));\n    }\n}\n"
  },
  {
    "path": "src/main/go/AlexanderYastrebov/Dockerfile",
    "content": "#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nFROM golang AS build-stage\nCOPY . src/\nRUN cd src && go build .\n\nFROM scratch AS export-stage\nCOPY --from=build-stage /go/src/1brc /\n"
  },
  {
    "path": "src/main/go/AlexanderYastrebov/README.md",
    "content": "# 1brc in go\n\nIt uses Docker with BuildKit plugin to build and [export binary](https://docs.docker.com/engine/reference/commandline/build/#output) binary,\nsee [prepare_AlexanderYastrebov.sh](../../../../prepare_AlexanderYastrebov.sh)\nand [calculate_average_AlexanderYastrebov.sh](../../../../calculate_average_AlexanderYastrebov.sh).\n\nDemo:\n```sh\n$ ./test.sh AlexanderYastrebov\n[+] Building 0.2s (9/9) FINISHED\n => [internal] load .dockerignore                                                                                                             0.0s\n => => transferring context: 2B                                                                                                               0.0s\n => [internal] load build definition from Dockerfile                                                                                          0.0s\n => => transferring dockerfile: 172B                                                                                                          0.0s\n => [internal] load metadata for docker.io/library/golang:latest                                                                              0.0s\n => [internal] load build context                                                                                                             0.0s\n => => transferring context: 145B                                                                                                             0.0s\n => [build-stage 1/3] FROM docker.io/library/golang                                                                                           0.0s\n => CACHED [build-stage 2/3] COPY . src/                                                                                                      0.0s\n => CACHED [build-stage 3/3] RUN cd src && go build .                                                                                         0.0s\n => CACHED [export-stage 1/1] COPY --from=build-stage /go/src/1brc /                                                                          0.0s\n => exporting to client directory                                                                                                             0.1s\n => => copying files 2.03MB                                                                                                                   0.0s\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-10000-unique-keys.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-10.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-1.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-20.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-2.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-3.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-boundaries.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-complex-utf8.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-dot.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-shortest.txt\nValidating calculate_average_AlexanderYastrebov.sh -- src/test/resources/samples/measurements-short.txt\n\n# Run once to setup the benchmark\n# ./create_measurements.sh 1000000000\n# mv measurements.txt measurements_1B.txt\n# ln -s measurements_1B.txt measurements.txt\n# ./calculate_average_baseline.sh > out_expected.txt\n\n$ wc -l measurements_1B.txt\n1000000000 measurements_1B.txt\n\n$ ./evaluate2.sh AlexanderYastrebov royvanrijn\n...                                                                                                                                         0.0s\nBenchmark 1: ./calculate_average_AlexanderYastrebov.sh 2>&1\n  Time (mean ± σ):     16.786 s ±  0.545 s    [User: 56.030 s, System: 10.068 s]\n  Range (min … max):   15.918 s … 17.309 s    5 runs\n...\nBenchmark 1: ./calculate_average_royvanrijn.sh 2>&1\n  Time (mean ± σ):     16.731 s ±  0.190 s    [User: 56.485 s, System: 10.279 s]\n  Range (min … max):   16.490 s … 16.951 s    5 runs\n\nSummary\n  AlexanderYastrebov: trimmed mean 16.901712789513336, raw times 16.69836470718,17.30911065018,16.83413600418,15.91787706218,17.17263765718\n  royvanrijn: trimmed mean 16.738037123633333, raw times 16.4900939703,16.9513459953,16.5794539913,16.8297746273,16.8048827523\n```\n"
  },
  {
    "path": "src/main/go/AlexanderYastrebov/calc.go",
    "content": "package main\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"log\"\n\t\"math\"\n\t\"os\"\n\t\"runtime\"\n\t\"sort\"\n\t\"sync\"\n\t\"syscall\"\n)\n\ntype measurement struct {\n\tmin, max, sum, count int64\n}\n\nfunc main() {\n\tif len(os.Args) != 2 {\n\t\tlog.Fatalf(\"Missing measurements filename\")\n\t}\n\n\tmeasurements := processFile(os.Args[1])\n\n\tids := make([]string, 0, len(measurements))\n\tfor id := range measurements {\n\t\tids = append(ids, id)\n\t}\n\tsort.Strings(ids)\n\n\tfmt.Print(\"{\")\n\tfor i, id := range ids {\n\t\tif i > 0 {\n\t\t\tfmt.Print(\", \")\n\t\t}\n\t\tm := measurements[id]\n\t\tfmt.Printf(\"%s=%.1f/%.1f/%.1f\", id, round(float64(m.min)/10.0), round(float64(m.sum)/10.0/float64(m.count)), round(float64(m.max)/10.0))\n\t}\n\tfmt.Println(\"}\")\n}\n\nfunc processFile(filename string) map[string]*measurement {\n\tf, err := os.Open(filename)\n\tif err != nil {\n\t\tlog.Fatalf(\"Open: %v\", err)\n\t}\n\tdefer f.Close()\n\n\tfi, err := f.Stat()\n\tif err != nil {\n\t\tlog.Fatalf(\"Stat: %v\", err)\n\t}\n\n\tsize := fi.Size()\n\tif size <= 0 || size != int64(int(size)) {\n\t\tlog.Fatalf(\"Invalid file size: %d\", size)\n\t}\n\n\tdata, err := syscall.Mmap(int(f.Fd()), 0, int(size), syscall.PROT_READ, syscall.MAP_SHARED)\n\tif err != nil {\n\t\tlog.Fatalf(\"Mmap: %v\", err)\n\t}\n\n\tdefer func() {\n\t\tif err := syscall.Munmap(data); err != nil {\n\t\t\tlog.Fatalf(\"Munmap: %v\", err)\n\t\t}\n\t}()\n\n\treturn process(data)\n}\n\nfunc process(data []byte) map[string]*measurement {\n\tnChunks := runtime.NumCPU()\n\n\tchunkSize := len(data) / nChunks\n\tif chunkSize == 0 {\n\t\tchunkSize = len(data)\n\t}\n\n\tchunks := make([]int, 0, nChunks)\n\toffset := 0\n\tfor offset < len(data) {\n\t\toffset += chunkSize\n\t\tif offset >= len(data) {\n\t\t\tchunks = append(chunks, len(data))\n\t\t\tbreak\n\t\t}\n\n\t\tnlPos := bytes.IndexByte(data[offset:], '\\n')\n\t\tif nlPos == -1 {\n\t\t\tchunks = append(chunks, len(data))\n\t\t\tbreak\n\t\t} else {\n\t\t\toffset += nlPos + 1\n\t\t\tchunks = append(chunks, offset)\n\t\t}\n\t}\n\n\tvar wg sync.WaitGroup\n\twg.Add(len(chunks))\n\n\tresults := make([]map[string]*measurement, len(chunks))\n\tstart := 0\n\tfor i, chunk := range chunks {\n\t\tgo func(data []byte, i int) {\n\t\t\tresults[i] = processChunk(data)\n\t\t\twg.Done()\n\t\t}(data[start:chunk], i)\n\t\tstart = chunk\n\t}\n\twg.Wait()\n\n\tmeasurements := make(map[string]*measurement)\n\tfor _, r := range results {\n\t\tfor id, rm := range r {\n\t\t\tm := measurements[id]\n\t\t\tif m == nil {\n\t\t\t\tmeasurements[id] = rm\n\t\t\t} else {\n\t\t\t\tm.min = min(m.min, rm.min)\n\t\t\t\tm.max = max(m.max, rm.max)\n\t\t\t\tm.sum += rm.sum\n\t\t\t\tm.count += rm.count\n\t\t\t}\n\t\t}\n\t}\n\treturn measurements\n}\n\nfunc processChunk(data []byte) map[string]*measurement {\n\t// Use fixed size linear probe lookup table\n\tconst (\n\t\t// use power of 2 for fast modulo calculation,\n\t\t// should be larger than max number of keys which is 10_000\n\t\tentriesSize = 1 << 14\n\n\t\t// use FNV-1a hash\n\t\tfnv1aOffset64 = 14695981039346656037\n\t\tfnv1aPrime64  = 1099511628211\n\t)\n\n\ttype entry struct {\n\t\tm     measurement\n\t\thash  uint64\n\t\tvlen  int\n\t\tvalue [128]byte // use power of 2 > 100 for alignment\n\t}\n\tentries := make([]entry, entriesSize)\n\tentriesCount := 0\n\n\t// keep short and inlinable\n\tgetMeasurement := func(hash uint64, value []byte) *measurement {\n\t\ti := hash & uint64(entriesSize-1)\n\t\tentry := &entries[i]\n\n\t\t// bytes.Equal could be commented to speedup assuming no hash collisions\n\t\tfor entry.vlen > 0 && !(entry.hash == hash && bytes.Equal(entry.value[:entry.vlen], value)) {\n\t\t\ti = (i + 1) & uint64(entriesSize-1)\n\t\t\tentry = &entries[i]\n\t\t}\n\n\t\tif entry.vlen == 0 {\n\t\t\tentry.hash = hash\n\t\t\tentry.vlen = copy(entry.value[:], value)\n\t\t\tentriesCount++\n\t\t}\n\t\treturn &entry.m\n\t}\n\n\t// assume valid input\n\tfor len(data) > 0 {\n\n\t\tidHash := uint64(fnv1aOffset64)\n\t\tsemiPos := 0\n\t\tfor i, b := range data {\n\t\t\tif b == ';' {\n\t\t\t\tsemiPos = i\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\t// calculate FNV-1a hash\n\t\t\tidHash ^= uint64(b)\n\t\t\tidHash *= fnv1aPrime64\n\t\t}\n\n\t\tidData := data[:semiPos]\n\n\t\tdata = data[semiPos+1:]\n\n\t\tvar temp int64\n\t\t// parseNumber\n\t\t{\n\t\t\tnegative := data[0] == '-'\n\t\t\tif negative {\n\t\t\t\tdata = data[1:]\n\t\t\t}\n\n\t\t\t_ = data[3]\n\t\t\tif data[1] == '.' {\n\t\t\t\t// 1.2\\n\n\t\t\t\ttemp = int64(data[0])*10 + int64(data[2]) - '0'*(10+1)\n\t\t\t\tdata = data[4:]\n\t\t\t\t// 12.3\\n\n\t\t\t} else {\n\t\t\t\t_ = data[4]\n\t\t\t\ttemp = int64(data[0])*100 + int64(data[1])*10 + int64(data[3]) - '0'*(100+10+1)\n\t\t\t\tdata = data[5:]\n\t\t\t}\n\n\t\t\tif negative {\n\t\t\t\ttemp = -temp\n\t\t\t}\n\t\t}\n\n\t\tm := getMeasurement(idHash, idData)\n\t\tif m.count == 0 {\n\t\t\tm.min = temp\n\t\t\tm.max = temp\n\t\t\tm.sum = temp\n\t\t\tm.count = 1\n\t\t} else {\n\t\t\tm.min = min(m.min, temp)\n\t\t\tm.max = max(m.max, temp)\n\t\t\tm.sum += temp\n\t\t\tm.count++\n\t\t}\n\t}\n\n\tresult := make(map[string]*measurement, entriesCount)\n\tfor i := range entries {\n\t\tentry := &entries[i]\n\t\tif entry.m.count > 0 {\n\t\t\tresult[string(entry.value[:entry.vlen])] = &entry.m\n\t\t}\n\t}\n\treturn result\n}\n\nfunc round(x float64) float64 {\n\treturn roundJava(x*10.0) / 10.0\n}\n\n// roundJava returns the closest integer to the argument, with ties\n// rounding to positive infinity, see java's Math.round\nfunc roundJava(x float64) float64 {\n\tt := math.Trunc(x)\n\tif x < 0.0 && t-x == 0.5 {\n\t\t//return t\n\t} else if math.Abs(x-t) >= 0.5 {\n\t\tt += math.Copysign(1, x)\n\t}\n\n\tif t == 0 { // check -0\n\t\treturn 0.0\n\t}\n\treturn t\n}\n\n// parseNumber reads decimal number that matches \"^-?[0-9]{1,2}[.][0-9]\" pattern,\n// e.g.: -12.3, -3.4, 5.6, 78.9 and return the value*10, i.e. -123, -34, 56, 789.\nfunc parseNumber(data []byte) int64 {\n\tnegative := data[0] == '-'\n\tif negative {\n\t\tdata = data[1:]\n\t}\n\n\tvar result int64\n\tswitch len(data) {\n\t// 1.2\n\tcase 3:\n\t\tresult = int64(data[0])*10 + int64(data[2]) - '0'*(10+1)\n\t// 12.3\n\tcase 4:\n\t\tresult = int64(data[0])*100 + int64(data[1])*10 + int64(data[3]) - '0'*(100+10+1)\n\t}\n\n\tif negative {\n\t\treturn -result\n\t}\n\treturn result\n}\n"
  },
  {
    "path": "src/main/go/AlexanderYastrebov/calc_test.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestRoundJava(t *testing.T) {\n\tfor _, tc := range []struct {\n\t\tvalue    float64\n\t\texpected string\n\t}{\n\t\t{value: -1.5, expected: \"-1.0\"},\n\t\t{value: -1.0, expected: \"-1.0\"},\n\t\t{value: -0.7, expected: \"-1.0\"},\n\t\t{value: -0.5, expected: \"0.0\"},\n\t\t{value: -0.3, expected: \"0.0\"},\n\t\t{value: 0.0, expected: \"0.0\"},\n\t\t{value: 0.3, expected: \"0.0\"},\n\t\t{value: 0.5, expected: \"1.0\"},\n\t\t{value: 0.7, expected: \"1.0\"},\n\t\t{value: 1.0, expected: \"1.0\"},\n\t\t{value: 1.5, expected: \"2.0\"},\n\t} {\n\t\tif rounded := roundJava(tc.value); fmt.Sprintf(\"%.1f\", rounded) != tc.expected {\n\t\t\tt.Errorf(\"Wrong rounding of %v, expected: %s, got: %.1f\", tc.value, tc.expected, rounded)\n\t\t}\n\t}\n}\n\nfunc TestParseNumber(t *testing.T) {\n\tfor _, tc := range []struct {\n\t\tvalue    string\n\t\texpected string\n\t}{\n\t\t{value: \"-99.9\", expected: \"-999\"},\n\t\t{value: \"-12.3\", expected: \"-123\"},\n\t\t{value: \"-1.5\", expected: \"-15\"},\n\t\t{value: \"-1.0\", expected: \"-10\"},\n\t\t{value: \"0.0\", expected: \"0\"},\n\t\t{value: \"0.3\", expected: \"3\"},\n\t\t{value: \"12.3\", expected: \"123\"},\n\t\t{value: \"99.9\", expected: \"999\"},\n\t} {\n\t\tif number := parseNumber([]byte(tc.value)); fmt.Sprintf(\"%d\", number) != tc.expected {\n\t\t\tt.Errorf(\"Wrong parsing of %v, expected: %s, got: %d\", tc.value, tc.expected, number)\n\t\t}\n\t}\n}\n\nvar parseNumberSink int64\n\nfunc BenchmarkParseNumber(b *testing.B) {\n\tdata1 := []byte(\"1.2\")\n\tdata2 := []byte(\"-12.3\")\n\n\tfor i := 0; i < b.N; i++ {\n\t\tparseNumberSink = parseNumber(data1) + parseNumber(data2)\n\t}\n}\n\nfunc BenchmarkProcess(b *testing.B) {\n\t// $ ./create_measurements.sh 1000000 && mv measurements.txt measurements-1e6.txt\n\t// Created file with 1,000,000 measurements in 514 ms\n\tconst filename = \"../../../../measurements-1e6.txt\"\n\n\tdata, err := os.ReadFile(filename)\n\tif err != nil {\n\t\tb.Fatal(err)\n\t}\n\n\tmeasurements := process(data)\n\trows := int64(0)\n\tfor _, m := range measurements {\n\t\trows += m.count\n\t}\n\n\tb.ReportAllocs()\n\tb.ResetTimer()\n\tb.ReportMetric(float64(rows), \"rows/op\")\n\n\tfor i := 0; i < b.N; i++ {\n\t\tprocess(data)\n\t}\n}\n"
  },
  {
    "path": "src/main/go/AlexanderYastrebov/go.mod",
    "content": "module github.com/AlexanderYastrebov/1brc\n\ngo 1.21.5\n"
  },
  {
    "path": "src/main/go/elh/Dockerfile",
    "content": "#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nFROM golang AS builder\nWORKDIR /app\nCOPY . ./\nRUN go build -ldflags \"-w -s\" -o /1brc-go .\n\nFROM scratch AS runner\nWORKDIR /\nCOPY --from=builder /1brc-go /\n"
  },
  {
    "path": "src/main/go/elh/go.mod",
    "content": "module github.com/elh/1brc-go\n\ngo 1.21.5\n"
  },
  {
    "path": "src/main/go/elh/main.go",
    "content": "package main\n\nimport (\n\t\"bufio\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"runtime/pprof\"\n\t\"sort\"\n\t\"strconv\"\n\t\"strings\"\n\t\"sync\"\n\t\"time\"\n\t\"unsafe\"\n)\n\n// go run main.go [measurements_file]\n// tune env vars for performance\n//\n// Environment variables:\n// - NUM_PARSERS:         number of parsers to run concurrently. if unset, defaults\n//   \t\t\t          to runtime.NumCPU()\n// - PARSE_CHUNK_SIZE_MB: size of each chunk to parse. if unset, defaults to\n//                        defaultParseChunkSize\n// - PROFILE:             if \"true\", enables profiling\n\nvar (\n\t// others: \"heap\", \"threadcreate\", \"block\", \"mutex\"\n\tprofileTypes = []string{\"goroutine\", \"allocs\"}\n)\n\nconst (\n\tdefaultMeasurementsPath = \"measurements.txt\"\n\tmaxNameLen              = 100\n\tmaxNameNum              = 10000\n\n\t// tuned for a 2023 Macbook M2 Pro\n\tdefaultParseChunkSizeMB = 64\n\tmb                      = 1024 * 1024 // bytes\n)\n\ntype Stats struct {\n\tMin, Max, Sum float64\n\tCount         int\n}\n\n// rounding floats to 1 decimal place with 0.05 rounding up to 0.1\nfunc round(x float64) float64 {\n\treturn math.Floor((x+0.05)*10) / 10\n}\n\n// parseFloatFast is a high performance float parser using the assumption that\n// the byte slice will always have a single decimal digit.\nfunc parseFloatFast(bs []byte) float64 {\n\tvar intStartIdx int // is negative?\n\tif bs[0] == '-' {\n\t\tintStartIdx = 1\n\t}\n\n\tv := float64(bs[len(bs)-1]-'0') / 10 // single decimal digit\n\tplace := 1.0\n\tfor i := len(bs) - 3; i >= intStartIdx; i-- { // integer part\n\t\tv += float64(bs[i]-'0') * place\n\t\tplace *= 10\n\t}\n\n\tif intStartIdx == 1 {\n\t\tv *= -1\n\t}\n\treturn v\n}\n\n// size is the intended number of bytes to parse. buffer should be longer than size\n// because we need to continue reading until the end of the line in order to\n// properly segment the entire file and not miss any data.\nfunc parseAt(f *os.File, buf []byte, offset int64, size int) map[string]*Stats {\n\tstats := make(map[string]*Stats, maxNameNum)\n\tn, err := f.ReadAt(buf, offset) // load the buffer\n\tif err != nil && err != io.EOF {\n\t\tlog.Fatal(err)\n\t}\n\n\tlastName := make([]byte, maxNameLen) // last name parsed\n\tvar lastNameLen int\n\tisScanningName := true // currently scanning name or value?\n\n\t// if offset is non-zero, skip to the first new line\n\tvar idx, start int\n\tif offset != 0 {\n\t\tfor idx < n {\n\t\t\tif buf[idx] == '\\n' {\n\t\t\t\tidx++\n\t\t\t\tstart = idx\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tidx++\n\t\t}\n\t}\n\t// tick tock between parsing names and values while accummulating stats\n\tfor {\n\t\tif isScanningName {\n\t\t\tfor idx < n {\n\t\t\t\tif buf[idx] == ';' {\n\t\t\t\t\tnameBs := buf[start:idx]\n\t\t\t\t\tlastNameLen = copy(lastName, nameBs)\n\n\t\t\t\t\tidx++\n\t\t\t\t\tstart = idx\n\t\t\t\t\tisScanningName = false\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tidx++\n\t\t\t}\n\t\t} else {\n\t\t\tfor idx < n {\n\t\t\t\tif buf[idx] == '\\n' {\n\t\t\t\t\tvalueBs := buf[start:idx]\n\t\t\t\t\tvalue := parseFloatFast(valueBs)\n\n\t\t\t\t\tnameUnsafe := unsafe.String(&lastName[0], lastNameLen)\n\t\t\t\t\tif s, ok := stats[nameUnsafe]; !ok {\n\t\t\t\t\t\tname := string(lastName[:lastNameLen]) // actually allocate string\n\t\t\t\t\t\tstats[name] = &Stats{Min: value, Max: value, Sum: value, Count: 1}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tif value < s.Min {\n\t\t\t\t\t\t\ts.Min = value\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif value > s.Max {\n\t\t\t\t\t\t\ts.Max = value\n\t\t\t\t\t\t}\n\t\t\t\t\t\ts.Sum += value\n\t\t\t\t\t\ts.Count++\n\t\t\t\t\t}\n\n\t\t\t\t\tidx++\n\t\t\t\t\tstart = idx\n\t\t\t\t\tisScanningName = true\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tidx++\n\t\t\t}\n\t\t}\n\t\t// terminate when we hit the first newline after the intended size OR\n\t\t// when we hit the end of the file\n\t\tif (isScanningName && idx >= size) || idx >= n {\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn stats\n}\n\nfunc printResults(stats map[string]*Stats) { // doesn't help\n\t// sorted alphabetically for output\n\tnames := make([]string, 0, len(stats))\n\tfor name := range stats {\n\t\tnames = append(names, name)\n\t}\n\tsort.Strings(names)\n\n\tvar builder strings.Builder\n\tfor i, name := range names {\n\t\ts := stats[name]\n\t\t// gotcha: first round the sum to to remove float precision errors!\n\t\tavg := round(round(s.Sum) / float64(s.Count))\n\t\tbuilder.WriteString(fmt.Sprintf(\"%s=%.1f/%.1f/%.1f\", name, s.Min, avg, s.Max))\n\t\tif i < len(names)-1 {\n\t\t\tbuilder.WriteString(\", \")\n\t\t}\n\t}\n\n\twriter := bufio.NewWriter(os.Stdout)\n\tfmt.Fprintf(writer, \"{%s}\\n\", builder.String())\n\twriter.Flush()\n}\n\n// Read file in chunks and parse concurrently. N parsers work off of a chunk\n// offset chan and send results on an output chan. The results are merged into a\n// single map of stats and printed.\nfunc main() {\n\t// parse env vars and inputs\n\tshouldProfile := os.Getenv(\"PROFILE\") == \"true\"\n\tvar err error\n\tvar numParsers int\n\t{\n\t\tif os.Getenv(\"NUM_PARSERS\") != \"\" {\n\t\t\tnumParsers, err = strconv.Atoi(os.Getenv(\"NUM_PARSERS\"))\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatal(fmt.Errorf(\"failed to parse NUM_PARSERS: %w\", err))\n\t\t\t}\n\t\t} else {\n\t\t\tnumParsers = runtime.NumCPU()\n\t\t}\n\t}\n\tvar parseChunkSize int\n\t{\n\t\tif os.Getenv(\"PARSE_CHUNK_SIZE_MB\") != \"\" {\n\t\t\tparseChunkSizeMB, err := strconv.Atoi(os.Getenv(\"PARSE_CHUNK_SIZE_MB\"))\n\t\t\tif err != nil {\n\t\t\t\tlog.Fatal(fmt.Errorf(\"failed to parse PARSE_CHUNK_SIZE_MB: %w\", err))\n\t\t\t}\n\t\t\tparseChunkSize = parseChunkSizeMB * mb\n\t\t} else {\n\t\t\tparseChunkSize = defaultParseChunkSizeMB * mb\n\t\t}\n\t}\n\n\tmeasurementsPath := defaultMeasurementsPath\n\tif len(os.Args) > 1 {\n\t\tmeasurementsPath = os.Args[1]\n\t}\n\n\t// profile code\n\tif shouldProfile {\n\t\tnowUnix := time.Now().Unix()\n\t\tos.MkdirAll(fmt.Sprintf(\"profiles/%d\", nowUnix), 0755)\n\t\tfor _, profileType := range profileTypes {\n\t\t\tfile, _ := os.Create(fmt.Sprintf(\"profiles/%d/%s.%s.pprof\",\n\t\t\t\tnowUnix, filepath.Base(measurementsPath), profileType))\n\t\t\tdefer file.Close()\n\t\t\tdefer pprof.Lookup(profileType).WriteTo(file, 0)\n\t\t}\n\n\t\tfile, _ := os.Create(fmt.Sprintf(\"profiles/%d/%s.cpu.pprof\",\n\t\t\tnowUnix, filepath.Base(measurementsPath)))\n\t\tdefer file.Close()\n\t\tpprof.StartCPUProfile(file)\n\t\tdefer pprof.StopCPUProfile()\n\t}\n\n\t// read file\n\tf, err := os.Open(measurementsPath)\n\tif err != nil {\n\t\tlog.Fatal(fmt.Errorf(\"failed to open %s file: %w\", measurementsPath, err))\n\t}\n\tdefer f.Close()\n\n\tinfo, err := f.Stat()\n\tif err != nil {\n\t\tlog.Fatal(fmt.Errorf(\"failed to read %s file: %w\", measurementsPath, err))\n\t}\n\n\t// kick off \"parser\" workers\n\twg := sync.WaitGroup{}\n\twg.Add(numParsers)\n\n\t// buffered to not block on merging\n\tchunkOffsetCh := make(chan int64, numParsers)\n\tchunkStatsCh := make(chan map[string]*Stats, numParsers)\n\n\tgo func() {\n\t\ti := 0\n\t\tfor i < int(info.Size()) {\n\t\t\tchunkOffsetCh <- int64(i)\n\t\t\ti += parseChunkSize\n\t\t}\n\t\tclose(chunkOffsetCh)\n\t}()\n\n\tfor i := 0; i < numParsers; i++ {\n\t\t// WARN: w/ extra padding for line overflow. Each chunk should be read past\n\t\t// the intended size to the next new line. 128 bytes should be enough for\n\t\t// a max 100 byte name + the float value.\n\t\tbuf := make([]byte, parseChunkSize+128)\n\t\tgo func() {\n\t\t\tfor chunkOffset := range chunkOffsetCh {\n\t\t\t\tchunkStatsCh <- parseAt(f, buf, chunkOffset, parseChunkSize)\n\t\t\t}\n\t\t\twg.Done()\n\t\t}()\n\t}\n\n\tgo func() {\n\t\twg.Wait()\n\t\tclose(chunkStatsCh)\n\t}()\n\n\tmergedStats := make(map[string]*Stats, maxNameNum)\n\tfor chunkStats := range chunkStatsCh {\n\t\tfor name, s := range chunkStats {\n\t\t\tif ms, ok := mergedStats[name]; !ok {\n\t\t\t\tmergedStats[name] = s\n\t\t\t} else {\n\t\t\t\tif s.Min < ms.Min {\n\t\t\t\t\tms.Min = s.Min\n\t\t\t\t}\n\t\t\t\tif s.Max > ms.Max {\n\t\t\t\t\tms.Max = s.Max\n\t\t\t\t}\n\t\t\t\tms.Sum += s.Sum\n\t\t\t\tms.Count += s.Count\n\t\t\t}\n\t\t}\n\t}\n\n\tprintResults(mergedStats)\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_0xshivamagarwal.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.lang.foreign.ValueLayout.JAVA_BYTE;\nimport static java.nio.file.StandardOpenOption.READ;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_0xshivamagarwal {\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n    private static final byte COLON = ';';\n    private static final byte NEW_LINE = '\\n';\n    private static final byte HYPHEN = '-';\n    private static final byte DOT = '.';\n    private static final int NO_OF_THREADS = Runtime.getRuntime().availableProcessors();\n\n    private static long[] mergeFn(final long[] v1, final long[] v2) {\n        v1[0] = Math.min(v1[0], v2[0]);\n        v1[1] = Math.max(v1[1], v2[1]);\n        v1[2] += v2[2];\n        v1[3] += v2[3];\n        return v1;\n    }\n\n    private static String toString(final Map.Entry<String, long[]> entry) {\n        var m = entry.getValue();\n\n        return entry.getKey()\n                + '='\n                + m[0] / 10.0\n                + '/'\n                + Math.round(1.0 * m[2] / m[3]) / 10.0\n                + '/'\n                + m[1] / 10.0;\n    }\n\n    private static Map<String, long[]> parseData(\n                                                 final MemorySegment data, long offset, final long limit) {\n        var map = new HashMap<String, long[]>(10000, 1);\n        var sep = false;\n        var neg = false;\n        var key = new byte[100];\n        var len = 0;\n        var val = 0;\n\n        while (offset < limit) {\n            var b = data.get(JAVA_BYTE, offset++);\n            if (sep) {\n                if (b == NEW_LINE) {\n                    val = neg ? -val : val;\n                    map.merge(\n                            new String(key, 0, len),\n                            new long[]{ val, val, val, 1 },\n                            CalculateAverage_0xshivamagarwal::mergeFn);\n                    sep = false;\n                    neg = false;\n                    len = 0;\n                    val = 0;\n                }\n                else if (b == HYPHEN) {\n                    neg = true;\n                }\n                else if (b != DOT) {\n                    val = val * 10 + (b - 48);\n                }\n            }\n            else if (b == COLON) {\n                sep = true;\n            }\n            else {\n                key[len++] = b;\n            }\n        }\n\n        return map;\n    }\n\n    public static void main(String[] args) throws IOException {\n        final String result;\n\n        try (var channel = FileChannel.open(FILE, READ);\n                var arena = Arena.ofShared()) {\n            var data = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size(), arena);\n            var chunkSize = data.byteSize() / NO_OF_THREADS;\n            var chunks = new long[NO_OF_THREADS + 1];\n            chunks[NO_OF_THREADS] = data.byteSize();\n\n            for (int i = 1; i < NO_OF_THREADS; ++i) {\n                var chunkPos = i * chunkSize;\n\n                while (data.get(JAVA_BYTE, chunkPos++) != NEW_LINE) {\n                }\n\n                chunks[i] = chunkPos;\n            }\n\n            result = IntStream.range(0, NO_OF_THREADS)\n                    .mapToObj(i -> parseData(data, chunks[i], chunks[i + 1]))\n                    .parallel()\n                    .reduce(\n                            (m1, m2) -> {\n                                m2.forEach((k, v) -> m1.merge(k, v, CalculateAverage_0xshivamagarwal::mergeFn));\n                                return m1;\n                            })\n                    .map(\n                            map -> map.entrySet().parallelStream()\n                                    .sorted(Map.Entry.comparingByKey())\n                                    .map(CalculateAverage_0xshivamagarwal::toString)\n                                    .collect(Collectors.joining(\", \", \"{\", \"}\")))\n                    .orElse(null);\n        }\n\n        System.out.println(result);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_3j5a.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.invoke.MethodHandle;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport static java.lang.Class.forName;\nimport static java.lang.System.out;\nimport static java.lang.invoke.MethodHandles.lookup;\nimport static java.util.Comparator.comparing;\n\npublic class CalculateAverage_3j5a {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        try (RandomAccessFile measurementsFile = new RandomAccessFile(FILE, \"r\")) {\n            var slices = slice(measurementsFile);\n            var measurementsChannel = measurementsFile.getChannel();\n            slices.stream().parallel().map(slice -> {\n                MappedByteBuffer measurementsSlice = map(slice, measurementsChannel);\n                var measurementBuffer = new byte[rules.maxMeasurementLength];\n                var measurements = HashMap.<Station, StationMeasurementStatistics> newHashMap(rules.uniqueStationsCount);\n                while (measurementsSlice.hasRemaining()) {\n                    var a = nextStationMeasurement(measurementBuffer, measurementsSlice);\n                    var stats = measurements.get(a.station);\n                    if (stats == null) {\n                        a.station.detachFromMeasurementBuffer();\n                        stats = new StationMeasurementStatistics(a);\n                        measurements.put(a.station, stats);\n                    }\n                    else {\n                        stats.add(a);\n                    }\n                }\n                return measurements;\n            }).reduce((aslice, bslice) -> {\n                aslice.forEach((astation, astats) -> {\n                    var bstats = bslice.putIfAbsent(astation, astats);\n                    if (bstats != null) {\n                        bstats.merge(astats);\n                    }\n                });\n                return bslice;\n            }).ifPresent(measurements -> {\n                var results = new StringBuilder(measurements.size() * (rules.maxStationNameLength + rules.maxStationStatisticsOutputLength));\n                measurements.values().stream()\n                        .sorted(comparing(StationMeasurementStatistics::getName))\n                        .forEach(stationStats -> results.append(stationStats).append(\", \"));\n                out.println(\"{\" + results.substring(0, results.length() - 2) + \"}\");\n            });\n        }\n    }\n\n    record Rules(int minMeasurementLength, int maxStationNameLength,\n                 int maxMeasurementLength, int maxStationStatisticsOutputLength,\n                 int uniqueStationsCount) {\n        Rules() {\n            this(5, 100, 106, 18, 10_000);\n        }\n    }\n\n    private static final Rules rules = new Rules();\n\n    record MeasurementsSlice(long start, long length) {\n    }\n\n    static class Station {\n\n        private byte[] name;\n        final int length;\n        private int hash;\n\n        private static final MethodHandle vectorizedHashCode;\n        private static final int T_BYTE = 8;\n\n        static {\n            try {\n                var arraysSupport = forName(\"jdk.internal.util.ArraysSupport\");\n                Class<?>[] vectorizedHashCodeSignature = { Object.class, int.class, int.class, int.class, int.class };\n                var vectorizedHashCodeMethod = arraysSupport.getDeclaredMethod(\"vectorizedHashCode\", vectorizedHashCodeSignature);\n                vectorizedHashCode = lookup().unreflect(vectorizedHashCodeMethod);\n            }\n            catch (NoSuchMethodException | IllegalAccessException | ClassNotFoundException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        Station(byte[] name, int length) {\n            this.name = name;\n            this.length = length;\n        }\n\n        public void detachFromMeasurementBuffer() {\n            var n = new byte[length];\n            System.arraycopy(name, 0, n, 0, length);\n            this.name = n;\n        }\n\n        @Override\n        public boolean equals(Object that) {\n            return Arrays.mismatch(this.name, 0, length, ((Station) that).name, 0, length) < 0;\n        }\n\n        @Override\n        public int hashCode() {\n            if (hash == 0) {\n                try {\n                    hash = (int) vectorizedHashCode.invokeExact((Object) name, 0, length, 1, T_BYTE);\n                }\n                catch (Throwable e) {\n                    throw new RuntimeException(e);\n                }\n            }\n            return hash;\n        }\n\n    }\n\n    record StationMeasurement(Station station, int temperature) {\n    }\n\n    private static class StationMeasurementStatistics {\n\n        private final byte[] bname;\n        private String name;\n        private int min;\n        private int max;\n        private long sum;\n        private int count = 1;\n\n        StationMeasurementStatistics(StationMeasurement stationMeasurement) {\n            this.bname = stationMeasurement.station.name;\n            this.min = stationMeasurement.temperature;\n            this.max = stationMeasurement.temperature;\n            this.sum = stationMeasurement.temperature;\n        }\n\n        public String getName() {\n            if (name == null) {\n                name = new String(bname, StandardCharsets.UTF_8);\n            }\n            return name;\n        }\n\n        void add(StationMeasurement measurement) {\n            var temperature = measurement.temperature;\n            update(1, temperature, temperature, temperature);\n        }\n\n        void merge(StationMeasurementStatistics other) {\n            update(other.count, other.min, other.max, other.sum);\n        }\n\n        private void update(int count, int min, int max, long sum) {\n            this.count += count;\n            if (this.min > min) {\n                this.min = min;\n            }\n            if (this.max < max) {\n                this.max = max;\n            }\n            this.sum += sum;\n        }\n\n        @Override\n        public String toString() {\n            var name = getName();\n            var min = this.min / 10f;\n            var mean = Math.round(this.sum / (float) this.count) / 10f;\n            var max = this.max / 10f;\n            return new StringBuilder(name.length() + rules.maxStationStatisticsOutputLength)\n                    .append(name).append(\"=\").append(min).append(\"/\").append(mean).append(\"/\").append(max)\n                    .toString();\n        }\n    }\n\n    private static StationMeasurement nextStationMeasurement(byte[] measurement, MappedByteBuffer memoryMappedSlice) {\n        byte b;\n        int i = rules.minMeasurementLength;\n        memoryMappedSlice.get(measurement, 0, i);\n        while ((b = memoryMappedSlice.get()) != '\\n') {\n            measurement[i] = b;\n            i++;\n        }\n        var zeroOffset = '0';\n        int temperature = measurement[--i] - zeroOffset;\n        i--; // skipping dot\n        var base = 10;\n        while ((b = measurement[--i]) != ';') {\n            if (b == '-') {\n                temperature = -temperature;\n            }\n            else {\n                temperature = base * (b - zeroOffset) + temperature;\n                base *= base;\n            }\n        }\n        return new StationMeasurement(new Station(measurement, i), temperature);\n    }\n\n    private static MappedByteBuffer map(MeasurementsSlice slice, FileChannel measurements) {\n        try {\n            return measurements.map(FileChannel.MapMode.READ_ONLY, slice.start, slice.length);\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static List<MeasurementsSlice> slice(RandomAccessFile measurements) throws IOException {\n        int chunks = Runtime.getRuntime().availableProcessors();\n        List<MeasurementsSlice> measurementSlices;\n        while ((measurementSlices = slice(measurements, chunks)) == null) {\n            chunks++;\n        }\n        return measurementSlices;\n    }\n\n    private static List<MeasurementsSlice> slice(RandomAccessFile measurements, int chunks) throws IOException {\n        long measurementsFileLength = measurements.length();\n        long chunkLength = 0;\n        long remainder;\n        if (chunks < measurementsFileLength) {\n            chunks--;\n            do {\n                chunkLength = measurementsFileLength / ++chunks;\n                remainder = measurementsFileLength % chunkLength;\n            } while (chunkLength + remainder > Integer.MAX_VALUE);\n        }\n        if (chunkLength <= rules.maxMeasurementLength) {\n            return List.of(new MeasurementsSlice(0, measurementsFileLength));\n        }\n        var measurementSlices = new ArrayList<MeasurementsSlice>(chunks);\n        var sliceStart = 0L;\n        for (int i = 0; i < chunks - 1; i++) {\n            var sliceLength = chunkLength;\n            measurements.seek(sliceStart + sliceLength);\n            while (measurements.readByte() != '\\n') {\n                measurements.seek(sliceStart + ++sliceLength);\n            }\n            sliceLength++;\n            if (sliceLength > Integer.MAX_VALUE) {\n                return null;\n            }\n            measurementSlices.add(new MeasurementsSlice(sliceStart, sliceLength));\n            sliceStart = sliceStart + sliceLength;\n        }\n        var previousSlice = measurementSlices.getLast();\n        var lastSliceStart = previousSlice.start + previousSlice.length;\n        measurementSlices.addLast(new MeasurementsSlice(lastSliceStart, measurementsFileLength - lastSliceStart));\n        return measurementSlices;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_AbstractKamen.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\npublic class CalculateAverage_AbstractKamen {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class Measurement {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private int sum;\n        private long count;\n\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round(sum / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        try (final FileChannel fc = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ);\n                final RandomAccessFile raf = new RandomAccessFile(new File(FILE), \"r\")) {\n            final Map<String, Measurement> res = getParallelBufferStream(raf, fc)\n                    .map(CalculateAverage_AbstractKamen::getMeasurements)\n                    .flatMap(m -> m.entrySet().stream())\n                    .collect(Collectors.collectingAndThen(\n                            Collectors.toMap(Map.Entry::getKey,\n                                    Map.Entry::getValue,\n                                    CalculateAverage_AbstractKamen::aggregateMeasurements),\n                            TreeMap::new));\n            System.out.println(res);\n        }\n    }\n\n    private static Measurement aggregateMeasurements(Measurement src, Measurement target) {\n        target.min = Math.min(src.min, target.min);\n        target.max = Math.max(src.max, target.max);\n        target.sum = src.sum + target.sum;\n        target.count = src.count + target.count;\n        return target;\n    }\n\n    private static Map<String, Measurement> getMeasurements(BufferSupplier getBuffer) {\n        final Map<String, Measurement> map = new HashMap<>(50_000);\n        final ByteBuffer byteBuffer = getBuffer.get();\n        final byte[] bytes = new byte[512];\n        while (byteBuffer.hasRemaining()) {\n            int nameLen = 0;\n            String name;\n            byte b;\n            while ((b = byteBuffer.get()) != ';') {\n                bytes[nameLen++] = b;\n            }\n            name = new String(bytes, 0, nameLen, StandardCharsets.UTF_8);\n            int valueLen = 0;\n            int neg = 1;\n            while (byteBuffer.hasRemaining() && ((b = byteBuffer.get()) != '\\n')) {\n                if (b == '-') {\n                    neg = -1;\n                }\n                else if (b == '.' || b == '\\r') {\n                    // skip the dot and retart char\n                }\n                else {\n                    bytes[valueLen++] = b;\n                }\n            }\n            final int val = parseAsInt(valueLen, bytes);\n            takeMeasurement(val * neg, map, name);\n        }\n        return map;\n    }\n\n    private static int parseAsInt(int valueLen, byte[] bytes) {\n        int val;\n        switch (valueLen) {\n            case 2 -> val = (bytes[0] - 48) * 10 + (bytes[1] - 48);\n            case 3 -> val = (bytes[0] - 48) * 100 + (bytes[1] - 48) * 10 + (bytes[2] - 48);\n            default -> val = 0;\n        }\n        return val;\n    }\n\n    private static void takeMeasurement(int temperature, Map<String, Measurement> map, String name) {\n        Measurement measurement = map.get(name);\n        if (measurement != null) {\n            measurement.min = Math.min(measurement.min, temperature);\n            measurement.max = Math.max(measurement.max, temperature);\n            measurement.sum += temperature;\n            measurement.count++;\n        }\n        else {\n            measurement = new Measurement();\n            map.put(name, measurement);\n            measurement.min = temperature;\n            measurement.max = temperature;\n            measurement.sum = temperature;\n            measurement.count = 1;\n        }\n    }\n\n    private static Stream<BufferSupplier> getParallelBufferStream(RandomAccessFile raf, FileChannel fc) throws IOException {\n        final int availableProcessors = Runtime.getRuntime().availableProcessors();\n        return StreamSupport.stream(\n                StreamSupport.stream(\n                        Spliterators.spliterator(\n                                new BufferSupplierIterator(raf, fc, availableProcessors), availableProcessors,\n                                Spliterator.IMMUTABLE | Spliterator.SIZED | Spliterator.SUBSIZED),\n                        false)\n                        .spliterator(),\n                true);\n    }\n\n}\n\ninterface BufferSupplier extends Supplier<ByteBuffer> {\n}\n\nclass BufferSupplierIterator implements Iterator<BufferSupplier> {\n    private long start;\n    private final RandomAccessFile raf;\n    private final FileChannel fc;\n    private final long fileLength;\n    private final long chunkSize;\n\n    public BufferSupplierIterator(RandomAccessFile raf, FileChannel fc, int numberOfParts) throws IOException {\n        this.raf = raf;\n        this.fc = fc;\n        this.fileLength = fc.size();\n        this.chunkSize = Math.min(fileLength / numberOfParts, 1073741824);\n    }\n\n    @Override\n    public boolean hasNext() {\n        return start < fileLength;\n    }\n\n    @Override\n    public BufferSupplier next() {\n        try {\n            if (hasNext()) {\n                final long end = getEnd();\n                long s = start;\n                this.start = end;\n                return getBufferSupplier(s, end);\n            }\n            else {\n                throw new NoSuchElementException();\n            }\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private long getEnd() throws IOException {\n        long end = Math.min(start + chunkSize, fileLength);\n        while (end < fileLength) {\n            raf.seek(end++);\n            if (raf.read() == '\\n')\n                break;\n        }\n        return end;\n    }\n\n    private BufferSupplier getBufferSupplier(long position, long end) {\n        final long size = end - position;\n        return new BufferSupplier() {\n\n            private ByteBuffer bb;\n\n            @Override\n            public ByteBuffer get() {\n                try {\n                    if (bb == null) {\n                        return (bb = fc.map(MapMode.READ_ONLY, position, size));\n                    }\n                    else {\n                        return bb;\n                    }\n                }\n                catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        };\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_C5H12O5.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.AsynchronousFileChannel;\nimport java.nio.channels.CompletionHandler;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.LinkedTransferQueue;\nimport java.util.concurrent.TransferQueue;\n\n/**\n * Results on Mac mini (Apple M2 with 8-core CPU / 8GB unified memory):\n * <pre>\n *   using AIO and multiple threads:\n *     120.15s user 4.33s system 710% cpu 17.522 total\n *\n *   reduce the number of memory copies:\n *      45.87s user 2.82s system 530% cpu  9.185 total\n *\n *   processing byte array backwards and using bitwise operation to find specific byte (inspired by thomaswue):\n *      25.38s user 3.44s system 342% cpu  8.406 total\n * </pre>\n *\n * @author Xylitol\n */\n@SuppressWarnings(\"unchecked\")\npublic class CalculateAverage_C5H12O5 {\n    private static final int AVAILABLE_PROCESSOR_NUM = Runtime.getRuntime().availableProcessors();\n    private static final int TRANSFER_QUEUE_CAPACITY = 1024 / 16 / AVAILABLE_PROCESSOR_NUM; // 1GB memory max\n    private static final int BYTE_BUFFER_CAPACITY = 1024 * 1024 * 16; // 16MB one time\n    private static final int EXPECTED_MAPPINGS_NUM = 10000;\n\n    /**\n     * Fragment the file into chunks.\n     */\n    private static long[] fragment(Path path) throws IOException {\n        long size = Files.size(path);\n        long chunk = size / AVAILABLE_PROCESSOR_NUM;\n        List<Long> positions = new ArrayList<>();\n        try (RandomAccessFile file = new RandomAccessFile(path.toFile(), \"r\")) {\n            long position = chunk;\n            for (int i = 0; i < AVAILABLE_PROCESSOR_NUM - 1; i++) {\n                if (position >= size) {\n                    break;\n                }\n                file.seek(position);\n                // move the position to the next newline byte\n                while (file.read() != '\\n') {\n                    position++;\n                }\n                positions.add(++position);\n                position += chunk;\n            }\n        }\n        if (positions.isEmpty() || positions.getLast() < size) {\n            positions.add(size);\n        }\n        return positions.stream().mapToLong(Long::longValue).toArray();\n    }\n\n    public static void main(String[] args) throws Exception {\n        // fragment the input file\n        Path path = Path.of(\"./measurements.txt\");\n        long[] positions = fragment(path);\n\n        // start the calculation tasks\n        FutureTask<Map<Station, MeasurementData>>[] tasks = new FutureTask[positions.length];\n        for (int i = 0; i < positions.length; i++) {\n            tasks[i] = new FutureTask<>(new Calculator(path, (i == 0 ? 0 : positions[i - 1]), positions[i]));\n            new Thread(tasks[i]).start();\n        }\n\n        // wait for the results\n        Map<Station, MeasurementData> result = HashMap.newHashMap(EXPECTED_MAPPINGS_NUM);\n        for (FutureTask<Map<Station, MeasurementData>> task : tasks) {\n            task.get().forEach((k, v) -> result.merge(k, v, MeasurementData::merge));\n        }\n\n        // sort and print the results\n        TreeMap<String, MeasurementData> sorted = new TreeMap<>();\n        for (Map.Entry<Station, MeasurementData> entry : result.entrySet()) {\n            sorted.put(new String(entry.getKey().bytes, StandardCharsets.UTF_8), entry.getValue());\n        }\n        System.out.println(sorted);\n    }\n\n    /**\n     * The calculation task.\n     */\n    private static class Calculator implements Callable<Map<Station, MeasurementData>> {\n        private final TransferQueue<byte[]> transfer = new LinkedTransferQueue<>();\n        private final AsynchronousFileChannel asyncChannel;\n        private final long limit;\n        private long position;\n\n        public Calculator(Path file, long position, long limit) throws IOException {\n            ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();\n            this.asyncChannel = AsynchronousFileChannel.open(file, Set.of(StandardOpenOption.READ), executor);\n            this.position = position;\n            this.limit = limit;\n        }\n\n        @Override\n        public Map<Station, MeasurementData> call() throws InterruptedException {\n            ByteBuffer buffer = ByteBuffer.allocateDirect(BYTE_BUFFER_CAPACITY);\n            asyncChannel.read(buffer, position, buffer, new CompletionHandler<>() {\n                @Override\n                public void completed(Integer readSize, ByteBuffer buffer) {\n                    if (position + readSize >= limit) {\n                        buffer.limit(readSize - (int) (position + readSize - limit));\n                    }\n                    else {\n                        for (int i = buffer.position() - 1; i >= 0; i--) {\n                            if (buffer.get(i) == '\\n') {\n                                // truncate the buffer to the last newline byte\n                                buffer.limit(i + 1);\n                                break;\n                            }\n                        }\n                    }\n                    buffer.flip();\n                    byte[] bytes = new byte[buffer.limit() + 1];\n                    // add a newline byte at the beginning\n                    bytes[0] = '\\n';\n                    buffer.get(bytes, 1, buffer.limit());\n                    transfer(bytes);\n                    if ((position += buffer.limit()) < limit) {\n                        buffer.clear();\n                        asyncChannel.read(buffer, position, buffer, this);\n                    }\n                    else {\n                        // stop signal\n                        transfer(new byte[0]);\n                    }\n                }\n\n                @Override\n                public void failed(Throwable exc, ByteBuffer buffer) {\n                    transfer(new byte[0]);\n                }\n            });\n            return process();\n        }\n\n        /**\n         * Transfer or put the bytes to the queue.\n         */\n        private void transfer(byte[] bytes) {\n            try {\n                if (transfer.size() >= TRANSFER_QUEUE_CAPACITY) {\n                    transfer.transfer(bytes);\n                }\n                else {\n                    transfer.put(bytes);\n                }\n            }\n            catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        /**\n         * Take and process the bytes from the queue.\n         */\n        private Map<Station, MeasurementData> process() throws InterruptedException {\n            Map<Station, MeasurementData> result = HashMap.newHashMap(EXPECTED_MAPPINGS_NUM);\n            for (byte[] bytes = transfer.take(); bytes.length > 0; bytes = transfer.take()) {\n                Station station = new Station(bytes);\n                // read the bytes backwards\n                for (int position = bytes.length - 2; position >= 1; position--) {\n\n                    // calculate the temperature value\n                    int temperature = bytes[position] - '0' + (bytes[position -= 2] - '0') * 10;\n                    byte unknownByte = bytes[--position];\n                    int semicolon = switch (unknownByte) {\n                        case ';' -> position;\n                        case '-' -> {\n                            temperature = -temperature;\n                            yield --position;\n                        }\n                        default -> {\n                            temperature += (unknownByte - '0') * 100;\n                            if (bytes[--position] == '-') {\n                                temperature = -temperature;\n                                --position;\n                            }\n                            yield position;\n                        }\n                    };\n\n                    // calculate the station name hash\n                    int hash = 1;\n                    while (true) {\n                        long temp = LineFinder.previousLong(bytes, position);\n                        int distance = LineFinder.NATIVE.fromRight(temp);\n                        if (distance == 0) {\n                            // current byte is '\\n'\n                            break;\n                        }\n                        position -= distance;\n                        if (distance == 8) {\n                            // can't find '\\n' in previous 8 bytes\n                            hash = 31 * hash + (int) (temp ^ (temp >>> 32));\n                            continue;\n                        }\n                        // clear the redundant bytes\n                        temp = LineFinder.NATIVE.clearLeft(temp, distance);\n                        hash = 31 * hash + (int) (temp ^ (temp >>> 32));\n                    }\n\n                    // merge data to the result map\n                    MeasurementData data = result.get(station.slice(hash, position + 1, semicolon));\n                    if (data == null) {\n                        result.put(station.copy(), new MeasurementData(temperature));\n                    } else {\n                        data.merge(temperature);\n                    }\n                }\n            }\n            return result;\n        }\n    }\n\n    /**\n     * To find the nearest newline byte position in a long.\n     */\n    private interface LineFinder {\n        // choose the implementation according to the native byte order\n        LineFinder NATIVE = ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ? LELineFinder.INST : BELineFinder.INST;\n\n        Unsafe UNSAFE = initUnsafe();\n        int BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);\n        int LONG_BYTES = Long.SIZE / Byte.SIZE;\n\n        static Unsafe initUnsafe() {\n            try {\n                Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n                theUnsafe.setAccessible(true);\n                return (Unsafe) theUnsafe.get(Unsafe.class);\n            }\n            catch (NoSuchFieldException | IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        static long previousLong(byte[] bytes, long offset) {\n            return UNSAFE.getLong(bytes, BYTE_ARRAY_BASE_OFFSET + offset + 1 - LONG_BYTES);\n        }\n\n        /**\n         * Mark the highest bit of newline byte (0x0A) to 1.\n         */\n        static long markHighestBit(long longBytes) {\n            long temp = longBytes ^ 0x0A0A0A0A0A0A0A0AL;\n            return (temp - 0x0101010101010101L) & ~temp & 0x8080808080808080L;\n        }\n\n        /**\n         * Find the nearest newline byte position from right to left.\n         */\n        int fromRight(long longBytes);\n\n        /**\n         * Clear the left bytes out of the range.\n         */\n        long clearLeft(long longBytes, int keepNum);\n\n        enum LELineFinder implements LineFinder {\n            INST;\n\n            private static final long[] MASKS = new long[8];\n\n            static {\n                for (int i = 1; i <= 7; i++) {\n                    MASKS[i] = 0xFFFFFFFFFFFFFFFFL << ((8 - i) << 3);\n                }\n            }\n\n            @Override\n            public int fromRight(long longBytes) {\n                return Long.numberOfLeadingZeros(markHighestBit(longBytes)) >>> 3;\n            }\n\n            @Override\n            public long clearLeft(long longBytes, int keepNum) {\n                return longBytes & MASKS[keepNum];\n            }\n        }\n\n        enum BELineFinder implements LineFinder {\n            INST;\n\n            private static final long[] MASKS = new long[8];\n\n            static {\n                for (int i = 1; i <= 7; i++) {\n                    MASKS[i] = 0xFFFFFFFFFFFFFFFFL >>> ((8 - i) << 3);\n                }\n            }\n\n            @Override\n            public int fromRight(long longBytes) {\n                return Long.numberOfTrailingZeros(markHighestBit(longBytes)) >>> 3;\n            }\n\n            @Override\n            public long clearLeft(long longBytes, int keepNum) {\n                return longBytes & MASKS[keepNum];\n            }\n        }\n    }\n\n    /**\n     * The station name wrapper ( bytes[from, to) ).\n     */\n    private static class Station {\n        private final byte[] bytes;\n        private int from;\n        private int to;\n        private int hash;\n\n        public Station(byte[] bytes) {\n            this(bytes, 0, 0, 0);\n        }\n\n        public Station(byte[] bytes, int hash, int from, int to) {\n            this.bytes = bytes;\n            this.slice(hash, from, to);\n        }\n\n        public Station slice(int hash, int from, int to) {\n            this.hash = hash;\n            this.from = from;\n            this.to = to;\n            return this;\n        }\n\n        public Station copy() {\n            int length = to - from;\n            byte[] newBytes = new byte[length];\n            System.arraycopy(bytes, from, newBytes, 0, length);\n            return new Station(newBytes, hash, 0, length);\n        }\n\n        @Override\n        public boolean equals(Object station) {\n            Station other = (Station) station;\n            return Arrays.equals(bytes, from, to, other.bytes, other.from, other.to);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n    }\n\n    /**\n     * The measurement data wrapper ( temperature * 10 ).\n     */\n    private static class MeasurementData {\n        private int min;\n        private int max;\n        private long sum;\n        private int count;\n\n        public MeasurementData(int value) {\n            this.min = value;\n            this.max = value;\n            this.sum = value;\n            this.count = 1;\n        }\n\n        public MeasurementData merge(int value) {\n            return merge(value, value, value, 1);\n        }\n\n        public MeasurementData merge(MeasurementData other) {\n            return merge(other.min, other.max, other.sum, other.count);\n        }\n\n        public MeasurementData merge(int min, int max, long sum, int count) {\n            this.min = Math.min(this.min, min);\n            this.max = Math.max(this.max, max);\n            this.sum += sum;\n            this.count += count;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{min / 10.0}/\\{Math.round((double) sum / count) / 10.0}/\\{max / 10.0}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_EduardoSaverin.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\nimport static java.nio.file.StandardOpenOption.READ;\n\npublic class CalculateAverage_EduardoSaverin {\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n    private static final int NO_OF_THREADS = Runtime.getRuntime().availableProcessors();\n    private static final Unsafe UNSAFE = initUnsafe();\n    private static final int FNV_32_OFFSET = 0x811c9dc5;\n    private static final int FNV_32_PRIME = 0x01000193;\n    private static final Map<String, ResultRow> resultRowMap = new HashMap<>();\n    private static final Lock lock = new ReentrantLock();\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public record Chunk(long start, long length) {\n    }\n\n    record MapEntry(String key, ResultRow row) {\n    }\n\n    private static final class ResultRow {\n        private double min;\n        private double max;\n        private double sum;\n        private int count;\n\n        private ResultRow(double v) {\n            this.min = v;\n            this.max = v;\n            this.sum = v;\n            this.count = 1;\n        }\n\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n    }\n\n    /**\n     * 0xA - Represents New Line\n     *\n     * @param fileChannel\n     * @return\n     * @throws IOException\n     */\n    static List<Chunk> getChunks(FileChannel fileChannel) throws IOException {\n        int numThreads = 1;\n        if (fileChannel.size() > 64000) {\n            numThreads = NO_OF_THREADS;\n        }\n        final long fileBytes = fileChannel.size();\n        final long chunkSize = fileBytes / numThreads;\n        final List<Chunk> chunks = new ArrayList<>(numThreads);\n        final long mappedAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileBytes, Arena.global()).address();\n        long chunkStart = 0;\n        // Ensures that the chunk size does not exceed the remaining bytes in the file.\n        long chunkLength = Math.min(fileBytes - chunkStart - 1, chunkSize);\n        while (chunkStart < fileBytes) {\n            MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, chunkStart + chunkLength,\n                    Math.min(Math.min(fileBytes - chunkStart - chunkLength, chunkLength), 100));\n            // Until \\n found\n            while (mappedByteBuffer.get() != 0xA) {\n                chunkLength++;\n            }\n            chunks.add(new Chunk(mappedAddress + chunkStart, chunkLength + 1));\n            chunkStart += (chunkLength + 1);\n            chunkLength = Math.min(fileBytes - chunkStart - 1, chunkSize);\n        }\n        return chunks;\n    }\n\n    static class SimplerHashMap {\n        final int MAPSIZE = 65536;\n        final ResultRow[] slots = new ResultRow[MAPSIZE];\n        final byte[][] keys = new byte[MAPSIZE][];\n\n        public void putOrMerge(final byte[] key, final short length, final int hash, final int temp) {\n            int slot = hash;\n            ResultRow slotValue;\n\n            // Doing Linear Probing if Collision\n            while ((slotValue = slots[slot]) != null && (keys[slot].length != length || !unsafeEquals(keys[slot], key, length))) {\n                slot++;\n            }\n\n            // Existing Key\n            if (slotValue != null) {\n                slotValue.min = Math.min(slotValue.min, temp);\n                slotValue.max = Math.max(slotValue.max, temp);\n                slotValue.sum += temp;\n                slotValue.count++;\n                return;\n            }\n\n            // New Key\n            slots[slot] = new ResultRow(temp);\n            byte[] bytes = new byte[length];\n            System.arraycopy(key, 0, bytes, 0, length);\n            keys[slot] = bytes;\n        }\n\n        static boolean unsafeEquals(final byte[] a, final byte[] b, final short length) {\n            // byte by byte comparisons are slow, so do as big chunks as possible\n            final int baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;\n\n            short i = 0;\n            // Double\n            for (; i < (length & -8); i += 8) {\n                if (UNSAFE.getDouble(a, i + baseOffset) != UNSAFE.getDouble(b, i + baseOffset)) {\n                    return false;\n                }\n            }\n\n            // Long\n            for (; i < (length & -8); i += 8) {\n                if (UNSAFE.getLong(a, i + baseOffset) != UNSAFE.getLong(b, i + baseOffset)) {\n                    return false;\n                }\n            }\n            if (i == length) {\n                return true;\n            }\n            // Int\n            for (; i < (length - i & -4); i += 4) {\n                if (UNSAFE.getInt(a, i + baseOffset) != UNSAFE.getInt(b, i + baseOffset)) {\n                    return false;\n                }\n            }\n            if (i == length) {\n                return true;\n            }\n            // Short\n            for (; i < (length - i & -2); i += 2) {\n                if (UNSAFE.getShort(a, i + baseOffset) != UNSAFE.getShort(b, i + baseOffset)) {\n                    return false;\n                }\n            }\n            if (i == length) {\n                return true;\n            }\n            // Byte\n            for (; i < (length - i); i++) {\n                if (UNSAFE.getByte(a, i + baseOffset) != UNSAFE.getByte(b, i + baseOffset)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        // Get all pairs\n        public List<MapEntry> getAll() {\n            final List<MapEntry> result = new ArrayList<>(slots.length);\n            for (int i = 0; i < slots.length; i++) {\n                ResultRow slotValue = slots[i];\n                if (slotValue != null) {\n                    result.add(new MapEntry(new String(keys[i], StandardCharsets.UTF_8), slotValue));\n                }\n            }\n            return result;\n        }\n    }\n\n    private static class Task implements Runnable {\n\n        private final SimplerHashMap results;\n        private final Chunk chunk;\n\n        public Task(Chunk chunk) {\n            this.results = new SimplerHashMap();\n            this.chunk = chunk;\n        }\n\n        @Override\n        public void run() {\n            // Max length of any city name\n            final byte[] nameBytes = new byte[100];\n            short nameIndex = 0;\n            int ot;\n            int hash = FNV_32_OFFSET;\n\n            long i = chunk.start;\n            final long cl = chunk.start + chunk.length;\n            while (i < cl) {\n                byte c;\n                // 0x3B is ;\n                while ((c = UNSAFE.getByte(i++)) != 0x3B) {\n                    nameBytes[nameIndex++] = c;\n                    // FNV-1a hash : https://en.wikipedia.org/wiki/Fowler–Noll–Vo_hash_function\n                    hash ^= c;\n                    hash *= FNV_32_PRIME;\n                }\n\n                // Temperature just after Semicolon\n                c = UNSAFE.getByte(i++);\n                // 0x2D is Minus(-)\n                // Below you will see -48 which is used to convert from ASCII to Integer, 48 represents 0 in ASCII\n                if (c == 0x2D) {\n                    // X.X or XX.X\n                    if (UNSAFE.getByte(i + 3) == 0xA) {\n                        ot = (UNSAFE.getByte(i++) - 48) * 10;\n                    }\n                    else {\n                        ot = (UNSAFE.getByte(i++) - 48) * 100;\n                        ot += (UNSAFE.getByte(i++) - 48) * 10;\n                    }\n                    // Now dot\n                    i++; // Skipping Dot\n                    ot += (UNSAFE.getByte(i++) - 48);\n                    // Make Number Negative Since we detected (-) sign\n                    ot = -ot;\n                }\n                else {\n                    // X.X or XX.X\n                    if (UNSAFE.getByte(i + 2) == 0xA) {\n                        ot = (c - 48) * 10;\n                    }\n                    else {\n                        ot = (c - 48) * 100;\n                        ot += (UNSAFE.getByte(i++) - 48) * 10;\n                    }\n                    // Now dot\n                    i++; // Skipping Dot\n                    // Number after dot\n                    ot += (UNSAFE.getByte(i++) - 48);\n                }\n                // Since Parsed Line, Next thing must be newline\n                i++;\n                hash &= 65535;\n                results.putOrMerge(nameBytes, nameIndex, hash, ot);\n                // Reset\n                nameIndex = 0;\n                hash = FNV_32_OFFSET;\n            }\n            List<MapEntry> all = results.getAll();\n            lock.lock();\n            try {\n                for (MapEntry me : all) {\n                    ResultRow rr;\n                    ResultRow lr = me.row;\n                    if ((rr = resultRowMap.get(me.key)) != null) {\n                        rr.min = Math.min(rr.min, lr.min);\n                        rr.max = Math.max(rr.max, lr.max);\n                        rr.count += lr.count;\n                        rr.sum += lr.sum;\n                    }\n                    else {\n                        resultRowMap.put(me.key, lr);\n                    }\n                }\n            }\n            catch (Exception e) {\n                e.printStackTrace();\n            }\n            finally {\n                lock.unlock();\n            }\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        FileChannel fileChannel = FileChannel.open(FILE, READ);\n        List<Chunk> chunks = getChunks(fileChannel);\n        List<Thread> threads = new ArrayList<>();\n        for (Chunk chunk : chunks) {\n            Thread thread = new Thread(new Task(chunk));\n            thread.setPriority(Thread.MAX_PRIORITY); // Make this thread of highest priority\n            threads.add(thread);\n            thread.start();\n        }\n        for (Thread thread : threads) {\n            thread.join();\n        }\n        System.out.println(new TreeMap<>(resultRowMap));\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_JaimePolidura.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic final class CalculateAverage_JaimePolidura {\n    private static final String FILE = \"./measurements.txt\";\n    private static final Unsafe UNSAFE = initUnsafe();\n    private static final long SEMICOLON_PATTERN = 0X3B3B3B3B3B3B3B3BL;\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        Worker[] workers = createWorkers();\n\n        startWorkers(workers);\n        joinWorkers(workers);\n\n        Map<String, Result> results = mergeWorkersResults(workers);\n        printResults(results);\n    }\n\n    private static void joinWorkers(Worker[] workers) throws InterruptedException {\n        for (int i = 0; i < workers.length; i++) {\n            workers[i].join();\n        }\n    }\n\n    private static void startWorkers(Worker[] workers) {\n        for (int i = 0; i < workers.length; i++) {\n            workers[i].start();\n        }\n    }\n\n    private static Worker[] createWorkers() throws Exception {\n        FileChannel channel = new RandomAccessFile(FILE, \"r\").getChannel();\n        MemorySegment mmappedFile = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size(), Arena.global());\n\n        int nWorkers = channel.size() > 1024 * 1024 ? Runtime.getRuntime().availableProcessors() : 1;\n        Worker[] workers = new Worker[nWorkers];\n        long quantityPerWorker = Math.floorDiv(channel.size(), nWorkers);\n        long quantityLastWorker = quantityPerWorker + (channel.size() % nWorkers);\n\n        for (int i = 0; i < nWorkers; i++) {\n            boolean isLastWorker = i == nWorkers - 1;\n\n            long startAddr = mmappedFile.address() + quantityPerWorker * i;\n            long endAddr = startAddr + (isLastWorker ? quantityLastWorker : quantityPerWorker);\n            workers[i] = new Worker(mmappedFile, channel.size(), startAddr, endAddr);\n            workers[i].setPriority(Thread.MAX_PRIORITY);\n        }\n\n        return workers;\n    }\n\n    private static Map<String, Result> mergeWorkersResults(Worker[] workers) {\n        Map<String, Result> mergedResults = new TreeMap<>();\n\n        for (int i = 0; i < workers.length; i++) {\n            Worker worker = workers[i];\n\n            for (Result entry : worker.results.entries) {\n                if (entry != null) {\n                    String name = new String(entry.name, 0, entry.nameLength);\n                    Result alreadyExistingResult = mergedResults.get(name);\n                    if (alreadyExistingResult != null) {\n                        alreadyExistingResult.min = Math.min(alreadyExistingResult.min, entry.min);\n                        alreadyExistingResult.max = Math.max(alreadyExistingResult.max, entry.max);\n                        alreadyExistingResult.count = alreadyExistingResult.count + entry.count;\n                        alreadyExistingResult.sum = alreadyExistingResult.sum + entry.sum;\n                    }\n                    else {\n                        mergedResults.put(name, entry);\n                    }\n                }\n            }\n        }\n\n        return mergedResults;\n    }\n\n    private static void printResults(Map<String, Result> results) {\n        StringBuilder stringBuilder = new StringBuilder(results.size() * 32);\n        stringBuilder.append('{');\n\n        for (Map.Entry<String, Result> entry : results.entrySet()) {\n            if (stringBuilder.length() > 1) {\n                stringBuilder.append(\", \");\n            }\n\n            Result result = entry.getValue();\n            stringBuilder.append(entry.getKey())\n                    .append('=')\n                    .append(round(((double) result.min) / 10.0))\n                    .append('/')\n                    .append(round((double) result.sum / (result.count * 10)))\n                    .append('/')\n                    .append(round(((double) result.max) / 10.0d));\n\n        }\n\n        stringBuilder.append('}');\n\n        System.out.println(stringBuilder);\n    }\n\n    static class Worker extends Thread {\n        private final byte[] lastParsedNameBytes = new byte[100];\n        private int lastParsedNameLength;\n        private long lastParsedNameHash;\n        private int lastParsedTemperature;\n\n        private final SimpleMap results;\n        private final MemorySegment mmappedFile;\n        private final long mmappedFileSize;\n        private long currentAddr; // Will point to beginning of string\n        private long endAddr; // Will point to \\n\n\n        public Worker(MemorySegment mmappedFile, long mmappedFileSize, long startAddr, long endAddr) {\n            super(\"Worker[\" + startAddr + \", \" + endAddr + \"]\");\n\n            this.mmappedFileSize = mmappedFileSize;\n            this.mmappedFile = mmappedFile;\n            this.currentAddr = startAddr;\n            this.endAddr = endAddr;\n\n            this.results = new SimpleMap(roundUpToPowerOfTwo(1 << 16)); // 2^16\n        }\n\n        @Override\n        public void run() {\n            adjustStartAddr();\n            adjustEndAddr();\n\n            if (this.currentAddr >= endAddr) {\n                return;\n            }\n\n            while (currentAddr < endAddr) {\n                parseName();\n                parseTemperature();\n\n                this.currentAddr++; // We don't want it to point to \\n\n\n                results.put(this.lastParsedNameHash, this.lastParsedNameBytes, this.lastParsedNameLength, this.lastParsedTemperature);\n            }\n        }\n\n        // Idea from Quan Anh Mai's implementation\n        private void parseTemperature() {\n            long numberWord = UNSAFE.getLong(currentAddr);\n\n            // The 4th binary digit of the ascii (Starting from left) of a digit is 1 while '.' is 0\n            int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n            // 28 = 4 + 8 * 3 (4 bytes is the number of tail zeros in the byte of decimalPos)\n            // xxxn.nn- shift: 28 - 28 = 0\n            // xxxxxn.n shift: 28 - 12 = 16\n            // xxxxn.nn shift: 28 - 20 = 8\n            int shift = 28 - decimalSepPos;\n\n            // Negative in ASCII: 00101101 2D. In ascii every digit starts with hex digit 3\n            // So in order to know if a number is positive, we simpy need the first bit of the 2º half\n            // If signed is 0 the number is positive. If it is negative signed will be -1.\n            long signed = (~numberWord << 59) >> 63;\n\n            // If signed is 0 (positive), designMask will be 0xFFFFFFFFFFFFFFFF (-256)\n            // If signed is -1, all 1s (negative), designMask will be 0xFFFFFFFFFFFFFF00 (-1)\n            long designMask = ~(signed & 0xFF);\n\n            // Align the number to a fixed position\n            // (x represents any non-related character, _ represents 0x00, n represents the actual digit and - negative)\n            // xxxn.nn- -> xxxn.nn-\n            // xxxxxn.n -> xxxn.n__\n            // xxxxn.nn -> xxxn.nn_\n            long numberAligned = (numberWord & designMask) << shift;\n\n            // We convert ascii representation to number value\n            long numberConvertedFromAscii = numberAligned & 0x0F000F0F00L;\n\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 +\n            // 0x00UU00TTHH000000 * 10 +\n            // 0xUU00TTHH00000000 * 100\n            // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n            // This results in our value lies in the bit 32 to 41 of this product\n            // That was close :)\n            long absValue = ((numberConvertedFromAscii * 0x640a0001) >>> 32) & 0x3FF;\n\n            long signedValue = (absValue ^ signed) - signed;\n\n            this.currentAddr += (((decimalSepPos - 4) / 8) + 2);\n\n            this.lastParsedTemperature = (int) signedValue;\n        }\n\n        // I first saw this idea in Artsiom Korzun's implementation\n        private void parseName() {\n            this.lastParsedNameHash = 0;\n\n            long totalWordHash = 0;\n            int totalWordLength = 0;\n\n            for (;;) {\n                long actualWord = UNSAFE.getLong(currentAddr + totalWordLength);\n                long hasSemicolon = hasByte(actualWord, SEMICOLON_PATTERN);\n\n                if (hasSemicolon != 0) {\n                    int actualLength = Long.numberOfTrailingZeros(hasSemicolon) >> 3;\n                    if (actualLength == 0) {\n                        actualWord = 0;\n                    }\n\n                    actualWord = mask(actualWord, actualLength);\n\n                    UNSAFE.putLong(this.lastParsedNameBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET + totalWordLength, actualWord);\n\n                    totalWordHash ^= actualWord;\n                    totalWordLength += actualLength;\n\n                    this.lastParsedNameLength = totalWordLength;\n                    this.lastParsedNameHash = totalWordHash;\n                    this.currentAddr += totalWordLength + 1; // +1 Because we don't want to point to ';'\n\n                    break;\n                }\n                else {\n                    UNSAFE.putLong(this.lastParsedNameBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET + totalWordLength, actualWord);\n\n                    totalWordLength += 8;\n                    totalWordHash ^= actualWord;\n                }\n            }\n        }\n\n        // Removes \"garbage\" of a word byte\n        private long mask(long word, int length) {\n            int shift = (8 - length) * 8;\n            return (word << shift) >> shift;\n        }\n\n        private long hasByte(long word, long pattern) {\n            long patternMatch = word ^ pattern;\n            return (patternMatch - 0x0101010101010101L) & (~patternMatch & 0x8080808080808080L);\n        }\n\n        private void adjustStartAddr() {\n            if (currentAddr == this.mmappedFile.address()) {\n                return;\n            }\n\n            while (UNSAFE.getByte(currentAddr) != '\\n' && currentAddr != endAddr) {\n                currentAddr++;\n            }\n\n            currentAddr++; // We want it to point to the first character instead of \\n\n        }\n\n        private void adjustEndAddr() {\n            long endAddressMmappedFile = mmappedFile.address() + mmappedFileSize;\n            if (endAddr >= endAddressMmappedFile) {\n                return;\n            }\n\n            while (UNSAFE.getByte(endAddr) != '\\n' && endAddr != endAddressMmappedFile) {\n                endAddr++;\n            }\n        }\n    }\n\n    static class SimpleMap {\n        private final Result[] entries;\n        private final long size;\n\n        public SimpleMap(int size) {\n            this.entries = new Result[size];\n            this.size = size;\n        }\n\n        public void put(long hashToPut, byte[] nameToPut, int nameLength, int valueToPut) {\n            int index = toIndex(hashToPut);\n\n            for (;;) {\n                Result actualEntry = entries[index];\n\n                if (actualEntry == null) {\n                    byte[] nameToPutCopy = new byte[nameLength];\n                    UNSAFE.copyMemory(nameToPut, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameToPutCopy, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameLength);\n\n                    entries[index] = new Result(hashToPut, nameToPutCopy, nameLength, valueToPut,\n                            valueToPut, valueToPut, 1);\n                    return;\n                }\n                if (actualEntry.isSameName(nameToPut, nameLength)) {\n                    actualEntry.min = Math.min(actualEntry.min, valueToPut);\n                    actualEntry.max = Math.max(actualEntry.max, valueToPut);\n                    actualEntry.count++;\n                    actualEntry.sum = actualEntry.sum + valueToPut;\n                    return;\n                }\n\n                index = toIndex(index + 31);\n            }\n        }\n\n        private int toIndex(long hash) {\n            return (int) (((hash >> 32) ^ ((int) hash)) & (this.size - 1));\n        }\n    }\n\n    static class Result {\n        public byte[] name;\n        public int nameLength;\n        public int max;\n        public int min;\n        public int sum;\n        public int count;\n        public long hash;\n\n        public Result(long hash, byte[] name, int nameLength, int max, int min, int sum, int occ) {\n            this.nameLength = nameLength;\n            this.count = occ;\n            this.hash = hash;\n            this.name = name;\n            this.max = max;\n            this.min = min;\n            this.sum = sum;\n        }\n\n        public boolean isSameName(byte[] otherNameBytes, int otherNameLength) {\n            return this.nameLength == otherNameLength && isSameNameBytes(otherNameBytes);\n        }\n\n        private boolean isSameNameBytes(byte[] otherNameBytes) {\n            for (int i = 0; i < this.nameLength; i += 8) {\n                long thisNameBytesAsLong = UNSAFE.getLong(this.name, Unsafe.ARRAY_BYTE_BASE_OFFSET + i);\n                long otherNameBytesAsLong = UNSAFE.getLong(otherNameBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET + i);\n\n                int isPositiveAsInt = (((8 - nameLength + i) >> 31) & 1) ^ 0x01;\n                int shift = ((8 - nameLength + i) * isPositiveAsInt) * 8;\n                otherNameBytesAsLong = (otherNameBytesAsLong << shift) >>> shift;\n\n                if (thisNameBytesAsLong != otherNameBytesAsLong) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n    }\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static int roundUpToPowerOfTwo(int number) {\n        if (number <= 0) {\n            return 1;\n        }\n\n        number--;\n        number |= number >> 1;\n        number |= number >> 2;\n        number |= number >> 4;\n        number |= number >> 8;\n        number |= number >> 16;\n\n        return number + 1;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_JamalMulla.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\npublic class CalculateAverage_JamalMulla {\n\n    private static final long ALL_SEMIS = 0x3B3B3B3B3B3B3B3BL;\n    private static final Map<String, ResultRow> global = new TreeMap<>();\n    private static final String FILE = \"./measurements.txt\";\n    private static final Unsafe UNSAFE = initUnsafe();\n    private static final Lock lock = new ReentrantLock();\n    private static final long FXSEED = 0x517cc1b727220a95L;\n\n    private static final long[] masks = {\n            0x0,\n            0x00000000000000FFL,\n            0x000000000000FFFFL,\n            0x0000000000FFFFFFL,\n            0x00000000FFFFFFFFL,\n            0x000000FFFFFFFFFFL,\n            0x0000FFFFFFFFFFFFL,\n            0x00FFFFFFFFFFFFFFL\n    };\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final class ResultRow {\n        private int min;\n        private int max;\n        private long sum;\n        private int count;\n        private final long keyStart;\n        private final byte keyLength;\n\n        private ResultRow(int v, final long keyStart, final byte keyLength) {\n            this.min = v;\n            this.max = v;\n            this.sum = v;\n            this.count = 1;\n            this.keyStart = keyStart;\n            this.keyLength = keyLength;\n        }\n\n        public String toString() {\n            return round(min) + \"/\" + round((double) (sum) / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n    }\n\n    private record Chunk(Long start, Long length) {\n    }\n\n    static Chunk[] getChunks(int numThreads, FileChannel channel) throws IOException {\n        // get all chunk boundaries\n        final long filebytes = channel.size();\n        final long roughChunkSize = filebytes / numThreads;\n        final Chunk[] chunks = new Chunk[numThreads];\n        final long mappedAddress = channel.map(FileChannel.MapMode.READ_ONLY, 0, filebytes, Arena.global()).address();\n        long chunkStart = 0;\n        long chunkLength = Math.min(filebytes - chunkStart - 1, roughChunkSize);\n        int i = 0;\n        while (chunkStart < filebytes) {\n            while (UNSAFE.getByte(mappedAddress + chunkStart + chunkLength) != 0xA /* \\n */) {\n                chunkLength++;\n            }\n\n            chunks[i++] = new Chunk(mappedAddress + chunkStart, chunkLength + 1);\n            // to skip the nl in the next chunk\n            chunkStart += chunkLength + 1;\n            chunkLength = Math.min(filebytes - chunkStart - 1, roughChunkSize);\n        }\n\n        return chunks;\n    }\n\n    private static void run(Chunk chunk) {\n\n        // can't have more than 10000 unique keys but want to match max hash\n        final int MAPSIZE = 65536;\n        final ResultRow[] slots = new ResultRow[MAPSIZE];\n\n        byte nameLength;\n        int temp;\n        long hash;\n\n        long i = chunk.start;\n        final long cl = chunk.start + chunk.length;\n        long word;\n        long hs;\n        long start;\n        byte c;\n        int slot;\n        long n;\n        ResultRow slotValue;\n\n        while (i < cl) {\n            start = i;\n            hash = 0;\n\n            word = UNSAFE.getLong(i);\n\n            while (true) {\n                n = word ^ ALL_SEMIS;\n                hs = (n - 0x0101010101010101L) & (~n & 0x8080808080808080L);\n                if (hs != 0)\n                    break;\n                hash = (hash ^ word) * FXSEED;\n                i += 8;\n                word = UNSAFE.getLong(i);\n            }\n\n            i += Long.numberOfTrailingZeros(hs) >> 3;\n\n            // hash of what's left ((hs >>> 7) - 1) masks off the bytes from word that are before the semicolon\n            hash = (hash ^ word & (hs >>> 7) - 1) * FXSEED;\n            nameLength = (byte) (i++ - start);\n\n            // temperature value follows\n            c = UNSAFE.getByte(i++);\n            // we know the val has to be between -99.9 and 99.8\n            // always with a single fractional digit\n            // represented as a byte array of either 4 or 5 characters\n            if (c != 0x2D /* minus sign */) {\n                // could be either n.x or nn.x\n                if (UNSAFE.getByte(i + 2) == 0xA) {\n                    temp = (c - 48) * 10; // char 1\n                }\n                else {\n                    temp = (c - 48) * 100; // char 1\n                    temp += (UNSAFE.getByte(i++) - 48) * 10; // char 2\n                }\n                temp += (UNSAFE.getByte(++i) - 48); // char 3\n            }\n            else {\n                // could be either n.x or nn.x\n                if (UNSAFE.getByte(i + 3) == 0xA) {\n                    temp = (UNSAFE.getByte(i) - 48) * 10; // char 1\n                    i += 2;\n                }\n                else {\n                    temp = (UNSAFE.getByte(i) - 48) * 100; // char 1\n                    temp += (UNSAFE.getByte(i + 1) - 48) * 10; // char 2\n                    i += 3;\n                }\n                temp += (UNSAFE.getByte(i) - 48); // char 2\n                temp = -temp;\n            }\n            i += 2;\n\n            // xor folding\n            slot = (int) (hash ^ hash >> 32) & 65535;\n\n            // Linear probe for open slot\n            while ((slotValue = slots[slot]) != null && (slotValue.keyLength != nameLength || !unsafeEquals(slotValue.keyStart, start, nameLength))) {\n                slot = (slot + 1) % MAPSIZE;\n            }\n\n            // existing\n            if (slotValue != null) {\n                slotValue.sum += temp;\n                slotValue.count++;\n                if (temp > slotValue.max) {\n                    slotValue.max = temp;\n                    continue;\n                }\n                if (temp < slotValue.min)\n                    slotValue.min = temp;\n\n            }\n            else {\n                // new value\n                slots[slot] = new ResultRow(temp, start, nameLength);\n            }\n        }\n\n        // merge results with overall results\n        ResultRow rr;\n        String key;\n        byte[] bytes;\n        lock.lock();\n        try {\n            for (ResultRow resultRow : slots) {\n                if (resultRow != null) {\n                    bytes = new byte[resultRow.keyLength];\n                    // copy the name bytes\n                    UNSAFE.copyMemory(null, resultRow.keyStart, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, resultRow.keyLength);\n                    key = new String(bytes, StandardCharsets.UTF_8);\n                    if ((rr = global.get(key)) != null) {\n                        rr.min = Math.min(rr.min, resultRow.min);\n                        rr.max = Math.max(rr.max, resultRow.max);\n                        rr.count += resultRow.count;\n                        rr.sum += resultRow.sum;\n                    }\n                    else {\n                        global.put(key, resultRow);\n                    }\n                }\n            }\n        }\n        finally {\n            lock.unlock();\n        }\n\n    }\n\n    static boolean unsafeEquals(final long a_address, final long b_address, final byte b_length) {\n        // byte by byte comparisons are slow, so do as big chunks as possible\n        byte i = 0;\n        for (; i < (b_length & -8); i += 8) {\n            if (UNSAFE.getLong(a_address + i) != UNSAFE.getLong(b_address + i)) {\n                return false;\n            }\n        }\n        if (i == b_length)\n            return true;\n        return (UNSAFE.getLong(a_address + i) & masks[b_length - i]) == (UNSAFE.getLong(b_address + i) & masks[b_length - i]);\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        int numThreads = 1;\n        FileChannel channel = new RandomAccessFile(FILE, \"r\").getChannel();\n        if (channel.size() > 64000) {\n            numThreads = Runtime.getRuntime().availableProcessors();\n        }\n        Chunk[] chunks = getChunks(numThreads, channel);\n        Thread[] threads = new Thread[chunks.length];\n        for (int i = 0; i < chunks.length; i++) {\n            int finalI = i;\n            Thread thread = new Thread(() -> run(chunks[finalI]));\n            thread.setPriority(Thread.MAX_PRIORITY);\n            thread.start();\n            threads[i] = thread;\n        }\n        for (Thread t : threads) {\n            t.join();\n        }\n        System.out.println(global);\n        channel.close();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_JesseVanRooy.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.stream.IntStream;\n\n//Disclaimer: The idea from the segmentation into #core amount of chunks came from previously submitted solutions.\npublic class CalculateAverage_JesseVanRooy {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final ValueLayout.OfByte DATA_LAYOUT = ValueLayout.JAVA_BYTE;\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static class Result {\n        long nameStart;\n        long nameSize;\n        String name;\n        int min;\n        int max;\n        long sum;\n        int count;\n\n        double min() {\n            return min / 10.0;\n        }\n\n        double max() {\n            return max / 10.0;\n        }\n\n        double mean() {\n            return (sum / 10.0) / count;\n        }\n    }\n\n    public static class ThreadResult {\n        Result[] results;\n    }\n\n    static final int MAP_SIZE = 16384;\n    static final int MAP_MASK = MAP_SIZE - 1;\n    static final int VALUE_CAPACITY = 10000;\n\n    static void process(MemorySegment memorySegment, ThreadResult threadResult) {\n        // initialize hash table\n        final int[] keys = new int[MAP_SIZE];\n        Arrays.fill(keys, -1);\n        final Result[] values = new Result[MAP_SIZE];\n\n        // pre-create the result objects\n        final Result[] preCreatedResults = new Result[VALUE_CAPACITY];\n        int usedPreCreatedResults = 0;\n        for (int i = 0; i < VALUE_CAPACITY; i++)\n            preCreatedResults[i] = new Result();\n\n        // load address info\n        final long size = memorySegment.byteSize();\n        final long address = memorySegment.address();\n        final long end = address + size;\n\n        for (long index = address; index < end;) {\n            final long nameStart = index;\n\n            byte next = UNSAFE.getByte(index);\n\n            // hash the city name\n            int hash = 0;\n            while (next != ';') {\n                hash = (hash * 33) + next;\n\n                index++;\n                next = UNSAFE.getByte(index);\n            }\n\n            final long nameEnd = index;\n\n            // skip the separator\n            index++;\n            next = UNSAFE.getByte(index);\n\n            // check for negative\n            boolean negative = next == '-';\n            if (negative) {\n                index++;\n                next = UNSAFE.getByte(index);\n            }\n\n            // count the temperature\n            int temperature = next - '0';\n            index++;\n            next = UNSAFE.getByte(index);\n\n            if (next != '.') {\n                temperature = (temperature * 10) + (next - '0');\n                index++;\n            }\n\n            // skip the .\n            index++;\n            next = UNSAFE.getByte(index);\n\n            // add the last digit to temperature\n            temperature = (temperature * 10) + (next - '0');\n            index++;\n\n            // negate the temperature if needed\n            if (negative) {\n                temperature = -temperature;\n            }\n\n            // skip the newline\n            index++;\n\n            // insert into map\n            for (int i = hash; i < hash + MAP_SIZE; i++) {\n                int mapIndex = i & MAP_MASK;\n                if (keys[mapIndex] == -1) {\n                    Result result = preCreatedResults[usedPreCreatedResults++];\n                    result.nameStart = nameStart;\n                    result.nameSize = nameEnd - nameStart;\n                    result.min = temperature;\n                    result.max = temperature;\n                    result.sum = temperature;\n                    result.count = 1;\n\n                    keys[mapIndex] = hash;\n                    values[mapIndex] = result;\n                    break;\n                }\n                if (keys[mapIndex] == hash) {\n                    Result result = values[mapIndex];\n                    result.min = Math.min(result.min, temperature);\n                    result.max = Math.max(result.max, temperature);\n                    result.sum += temperature;\n                    result.count++;\n                    break;\n                }\n            }\n        }\n\n        threadResult.results = Arrays.stream(values).filter(Objects::nonNull).toArray(Result[]::new);\n\n        for (Result result : threadResult.results) {\n            result.name = new String(memorySegment.asSlice(result.nameStart - address, result.nameSize).toArray(DATA_LAYOUT));\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        int numberOfChunks = Runtime.getRuntime().availableProcessors();\n\n        try (var fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n\n            long fileSize = fileChannel.size();\n            MemorySegment allData = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n\n            long segmentSize = (fileSize + numberOfChunks - 1) / numberOfChunks;\n            long[] segmentBounds = new long[numberOfChunks + 1];\n\n            segmentBounds[0] = 0;\n            for (int i = 1; i < numberOfChunks; i++) {\n                long chunkAddress = i * segmentSize;\n                while (chunkAddress < fileSize && allData.getAtIndex(DATA_LAYOUT, chunkAddress++) != '\\n') {\n                }\n                segmentBounds[i] = Math.min(chunkAddress, fileSize);\n            }\n            segmentBounds[numberOfChunks] = fileSize;\n\n            ThreadResult[] threadResults = IntStream.range(0, numberOfChunks)\n                    .parallel()\n                    .mapToObj(i -> {\n                        long size = segmentBounds[i + 1] - segmentBounds[i];\n                        long offset = segmentBounds[i];\n                        MemorySegment segment = allData.asSlice(offset, size);\n                        ThreadResult result = new ThreadResult();\n                        process(segment, result);\n                        return result;\n                    })\n                    .toArray(ThreadResult[]::new);\n\n            HashMap<String, Result> combinedResults = new HashMap<>(1024);\n\n            for (int i = 0; i < numberOfChunks; i++) {\n                for (Result result : threadResults[i].results) {\n                    if (!combinedResults.containsKey(result.name)) {\n                        Result newResult = new Result();\n                        newResult.name = result.name;\n                        newResult.min = result.min;\n                        newResult.max = result.max;\n                        newResult.sum = result.sum;\n                        newResult.count = result.count;\n                        combinedResults.put(result.name, newResult);\n                    }\n                    else {\n                        Result existingResult = combinedResults.get(result.name);\n                        existingResult.min = Math.min(existingResult.min, result.min);\n                        existingResult.max = Math.max(existingResult.max, result.max);\n                        existingResult.sum += result.sum;\n                        existingResult.count += result.count;\n                    }\n                }\n            }\n\n            Result[] sortedResults = combinedResults.values().toArray(Result[]::new);\n            Arrays.sort(sortedResults, Comparator.comparing(result -> result.name));\n\n            System.out.print(\"{\");\n\n            for (int i = 0; i < sortedResults.length; i++) {\n                Result sortedResult = sortedResults[i];\n                if (i != 0) {\n                    System.out.print(\", \");\n                }\n                System.out.printf(Locale.US, \"%s=%.1f/%.1f/%.1f\", sortedResult.name, sortedResult.min(), sortedResult.mean(), sortedResult.max());\n            }\n\n            System.out.printf(\"}\\n\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_Judekeyser.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorSpecies;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.io.UncheckedIOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.text.DecimalFormat;\nimport java.text.DecimalFormatSymbols;\nimport java.util.*;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport static java.lang.foreign.ValueLayout.OfByte.JAVA_BYTE;\nimport static java.lang.foreign.ValueLayout.OfByte.JAVA_INT_UNALIGNED;\n\npublic class CalculateAverage_Judekeyser {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int chunkSize = (1 << 7) << 12; // This can't go beyond 2^21, because otherwise we might exceed int capacity\n\n    private static final int numberOfIOWorkers = 1 << 8; // We are going to need (numberOfIOWorkers-1) * chunkSize capacity\n    private static final int numberOfParallelWorkers = Runtime.getRuntime().availableProcessors() - 1;\n\n    private static final VectorSpecies<Byte> SPECIES = ByteVector.SPECIES_PREFERRED;\n\n    public static void main(String[] args) throws Exception {\n        class SimpleStatistics {\n            int min, max, sum, count;\n            SimpleStatistics() {\n                min = Integer.MAX_VALUE;\n                max = Integer.MIN_VALUE;\n                sum = 0;\n                count = 0;\n            }\n\n            void accept(int value) {\n                min = Math.min(min, value);\n                max = Math.max(max, value);\n                sum += value;\n                count++;\n            }\n        }\n        class Statistics {\n            double min, max, avg;\n            long count;\n            Statistics(SimpleStatistics simple) {\n                min = simple.min/10.;\n                max = simple.max/10.;\n                avg = simple.sum/10./simple.count;\n                count = simple.count;\n            }\n\n            void accept(SimpleStatistics simple) {\n                min = Math.min(min, simple.min/10.);\n                max = Math.max(max, simple.max/10.);\n                var nextCount = count + simple.count;\n                avg = (avg * count + simple.sum/10.)/nextCount;\n                count = nextCount;\n            }\n\n            static final DecimalFormat format;\n            static {\n                var decimalFormatSymbols = DecimalFormatSymbols.getInstance();\n                decimalFormatSymbols.setDecimalSeparator('.');\n                format = new DecimalFormat(\"#0.0\", decimalFormatSymbols);\n            }\n            @Override\n            public String toString() {\n                return STR.\"\\{format.format(round(min))}/\\{format.format(round(avg))}/\\{format.format(round(max))}\";\n            }\n\n            static double round(double d) {\n                return Math.round(d*10.)/10.;\n            }\n        }\n        class Name {\n            final int[] data;\n            final int hash;\n            Name(int[] data) {\n                this.data = data;\n                {\n                    var hash = 0;\n                    for (var d : data) {\n                        hash = 31 * hash + d;\n                    }\n                    this.hash = hash;\n                }\n            }\n\n            @Override\n            public int hashCode() {\n                return hash;\n            }\n\n            @Override\n            public boolean equals(Object obj) {\n                if(obj == this) return true;\n                else if(obj instanceof Name name && name.data.length == data.length) {\n                    int size  = 0;\n                    while(size < data.length) {\n                        if(data[size] != name.data[size]) {\n                            return false;\n                        } else size++;\n                    }\n                    return true;\n                } else return false;\n            }\n\n            @Override\n            public String toString() {\n                var bdata = new byte[data.length * 4];\n                int j = 0;\n                for(int i = 0;i < data.length; i++) {\n                    bdata[j++] = (byte)((data[i] >>>  0) & 255);\n                    bdata[j++] = (byte)((data[i] >>>  8) & 255);\n                    bdata[j++] = (byte)((data[i] >>> 16) & 255);\n                    bdata[j++] = (byte)((data[i] >>> 24) & 255);\n                }\n                while(bdata[--j] == 0);\n                return new String(bdata, 0, j+1, StandardCharsets.UTF_8);\n            }\n        }\n\n        record Line(Name name, int value) {}\n\n        var results = new HashMap<Name, Statistics>();\n        try(var file = new RandomAccessFile(Paths.get(FILE).toFile(), \"r\")) {\n            class Ls implements Iterator<MemorySegment> {\n                final int M = chunkSize;\n                final Arena arena = Arena.ofShared();\n                final long length;\n\n                long offset;\n\n                Ls() throws IOException {\n                    offset = 0L;\n                    length = file.length();\n                }\n\n                @Override\n                public MemorySegment next() {\n                    MemorySegment memorySegment;\n                    try {\n                        memorySegment = file.getChannel().map(\n                                FileChannel.MapMode.READ_ONLY,\n                                offset, Math.min(M + 128L, file.getChannel().size() - offset),\n                                arena\n                        );\n                    } catch (IOException e) {\n                        throw new UncheckedIOException(e);\n                    }\n\n                    var size = M;\n                    if (offset + M < length) {\n                        b:\n                        {\n                            for (int N = 0; N < 128; N++) {\n                                var b = memorySegment.get(JAVA_BYTE, size);\n                                size += 1;\n                                if (b == '\\n') {\n                                    break b;\n                                }\n                            }\n                            assert false : \"Lines are smaller than 128 bytes\";\n                        }\n                        offset += size;\n                    } else {\n                        size = (int) (length - offset);\n                        offset = length;\n                    }\n\n                    return memorySegment.asSlice(0, size);\n                }\n\n                @Override\n                public boolean hasNext() {\n                    return offset < length;\n                }\n            }\n\n            class It implements Iterator<Line> {\n                int offset;\n                final int length;\n                final MemorySegment memorySegment;\n                final ByteOrder endian;\n\n                It(MemorySegment memorySegment) {\n                    offset = 0;\n                    endian = ByteOrder.nativeOrder();\n                    this.memorySegment = memorySegment;\n                    length = (int) memorySegment.byteSize();\n                    assert '\\n' == memorySegment.get(JAVA_BYTE, length - 1);\n                }\n\n                @Override\n                public boolean hasNext() {\n                    return offset < length;\n                }\n\n                @Override\n                public Line next() {\n                    int size;\n                    b: {\n                        /*\n                         * Vectorization does not seem to bring anything interesting.\n                         * This is a bit disappointing. What am I doing wrong?\n                         */\n\n                        size = 0;\n\n                        while (offset+size+SPECIES.length() <= length) {\n                            var vector = ByteVector.fromMemorySegment(\n                                    SPECIES, memorySegment,\n                                    offset+size, endian\n                            );\n                            var j = vector.eq((byte) '\\n').firstTrue();\n                            if (j < SPECIES.length()) {\n                                assert j >= 0;\n                                size += j;\n                                assert memorySegment.get(JAVA_BYTE, offset+size) == '\\n';\n                                break b;\n                            } else {\n                                assert j == SPECIES.length();\n                                size += SPECIES.length();\n                            }\n                        }\n                        {\n                            byte b;\n                            for (; size < 128; size++) {\n                                b = memorySegment.get(JAVA_BYTE, offset+size);\n                                if (b == '\\n') break b;\n                            }\n                            assert false : \"Lines are smaller than 128 bytes\";\n                        }\n                        assert memorySegment.get(JAVA_BYTE, offset+size) == '\\n';\n                        assert size < 128;\n                    }\n\n                    Name name;\n                    int value;\n                    {\n                        long cursor = offset+size - 1L;\n                        {\n                            value = memorySegment.get(JAVA_BYTE, cursor) - '0';\n                            value += (memorySegment.get(JAVA_BYTE, cursor-2L) - '0') * 10;\n                            cursor -= 3L;\n                            if (memorySegment.get(JAVA_BYTE, cursor) == '-') {\n                                value *= -1;\n                                cursor -= 1L;\n                            } else if (memorySegment.get(JAVA_BYTE, cursor) != ';') {\n                                value += (memorySegment.get(JAVA_BYTE, cursor) - '0') * 100;\n                                cursor -= 1L;\n                                if (memorySegment.get(JAVA_BYTE, cursor) == '-') {\n                                    value *= -1;\n                                    cursor -= 1L;\n                                }\n                            }\n                        }\n                        //var data = memorySegment.asSlice(offset, cursor-offset).toArray(JAVA_BYTE);\n                        //System.arraycopy(chunk, 0, data, 0, data.length);\n                        //assert ';' != data[data.length - 1];\n                        //name = new Name(data);\n                        {\n                            int mod4StringSize = ((int)(cursor-offset+3))/4 * 4;\n                            var data = memorySegment.asSlice(offset, mod4StringSize).toArray(JAVA_INT_UNALIGNED);\n                            switch(((int)(cursor - offset)) % 4) {\n                                case 0: break;\n                                case 1: {\n                                    data[data.length - 1] &= 255;\n                                } break;\n                                case 2: {\n                                    data[data.length - 1] &= 65535;\n                                } break;\n                                case 3: {\n                                    data[data.length - 1] &= 16777215;\n                                } break;\n                            }\n                            name = new Name(data);\n                        }\n                    }\n                    offset += size + 1;\n                    return new Line(name, value);\n                }\n            }\n\n            record Pair(MemorySegment segment, Map<Name, SimpleStatistics> simple) {\n                Pair(MemorySegment segment) {\n                    this(segment, apply(segment));\n                }\n\n                private static Map<Name, SimpleStatistics> apply(MemorySegment memorySegment) {\n                    try {\n                        return call(memorySegment);\n                    } catch (IOException e) {\n                        throw new UncheckedIOException(e);\n                    }\n                }\n\n                private static Map<Name, SimpleStatistics> call(MemorySegment memorySegment) throws IOException {\n                    var it = new It(memorySegment);\n                    var simple = new HashMap<Name, SimpleStatistics>();\n                    while (it.hasNext()) {\n                        var line = it.next();\n                        var name = line.name();\n                        var value = line.value();\n\n                        var statistics = simple.get(name);\n                        if (statistics == null) {\n                            statistics = new SimpleStatistics();\n                            simple.put(name, statistics);\n                        }\n                        statistics.accept(value);\n                    }\n                    return simple;\n                }\n            }\n\n            var ls = new Ls();\n\n            try(\n                    var nioService = Executors.newVirtualThreadPerTaskExecutor();\n                    var parallelService =Executors.newFixedThreadPool(numberOfParallelWorkers)\n            ) {\n                var tasksQueue = new ArrayList<Future<Pair>>();\n                for(;;) {\n                    assert tasksQueue.size() <= numberOfIOWorkers;\n                    if(tasksQueue.size() < numberOfIOWorkers) {\n                        if(ls.hasNext()) {\n                            var memseg = ls.next();\n                            var task = CompletableFuture.supplyAsync(\n                                    () -> {\n                                        memseg.load();\n                                        return memseg;\n                                    }, nioService\n                            ).thenApplyAsync(Pair::new, parallelService);\n\n                            tasksQueue.add(task);\n                        } else if(tasksQueue.isEmpty()) break;\n                    }\n                    /*\n                     * Wait for the tasks and merge what's ready\n                     */\n                    {\n                        var copy = new ArrayList<Future<Pair>>(tasksQueue.size());\n                        for(var worker: tasksQueue) {\n                            if(worker.isDone()) {\n                                /*\n                                 * Merge the maps\n                                 */\n                                var p = worker.get();\n                                var simple = p.simple();\n                                p.segment().unload();\n                                for (var entry : simple.entrySet()) {\n                                    var name = entry.getKey();\n\n                                    var statistics = results.get(name);\n                                    if (statistics == null) {\n                                        statistics = new Statistics(entry.getValue());\n                                        results.put(name, statistics);\n                                    } else {\n                                        statistics.accept(entry.getValue());\n                                    }\n                                }\n                            } else copy.add(worker);\n                        }\n                        tasksQueue.clear();\n                        tasksQueue.addAll(copy);\n                    }\n                }\n            }\n        }\n\n        /*\n         * Print\n         */\n        {\n            var sortedMap = new TreeMap<String, Statistics>();\n            for(var entry: results.entrySet()) {\n                sortedMap.put(\n                        entry.getKey().toString(),\n                        entry.getValue()\n                );\n            }\n            var joiner = new StringJoiner(\", \", \"{\", \"}\");\n            for (var entry : sortedMap.entrySet()) {\n                joiner.add(STR. \"\\{ entry.getKey() }=\\{ entry.getValue() }\" );\n            }\n            System.out.println(joiner);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_JurenIvan.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\nimport static java.lang.Math.round;\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.file.StandardOpenOption.READ;\n\npublic class CalculateAverage_JurenIvan {\n\n    private static final String FILE_NAME = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        long[] segments = getSegments(Runtime.getRuntime().availableProcessors());\n\n        var result = IntStream.range(0, segments.length - 1)\n                .parallel()\n                .mapToObj(i -> processSegment(segments[i], segments[i + 1]))\n                .flatMap(m -> Arrays.stream(m.hashTable).filter(Objects::nonNull))\n                .collect(Collectors.toMap(m -> new String(m.city), m -> m, Measurement::merge, TreeMap::new));\n\n        System.out.println(result);\n    }\n\n    private static LinearProbingHashMap processSegment(long start, long end) {\n        var results = new LinearProbingHashMap(1 << 19);\n\n        try (var fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE_NAME), READ)) {\n            var bb = fileChannel.map(READ_ONLY, start, end - start);\n            var buffer = new byte[100];\n\n            int limit = bb.limit();\n            for (int startLine = bb.position(); startLine < limit; startLine = bb.position()) {\n                int currentPosition = startLine;\n\n                byte b;\n                int hash = 7;\n                int wordLen = 0;\n                while (currentPosition < end && (b = bb.get(currentPosition++)) != ';') {\n                    buffer[wordLen++] = b;\n                    hash = hash * 31 + b;\n                }\n\n                int temp;\n                int negative = 1;\n                if (bb.get(currentPosition) == '-') {\n                    negative = -1;\n                    currentPosition++;\n                }\n\n                if (bb.get(currentPosition + 1) == '.') {\n                    temp = negative * ((bb.get(currentPosition) - '0') * 10 + (bb.get(currentPosition + 2) - '0'));\n                    currentPosition += 3;\n                }\n                else {\n                    temp = negative * ((bb.get(currentPosition) - '0') * 100 + ((bb.get(currentPosition + 1) - '0') * 10 + (bb.get(currentPosition + 3) - '0')));\n                    currentPosition += 4;\n                }\n\n                currentPosition++;\n\n                results.put(hash, buffer, wordLen, temp);\n\n                bb.position(currentPosition);\n            }\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        return results;\n    }\n\n    private static long[] getSegments(int segmentCount) throws IOException {\n        try (var raf = new RandomAccessFile(FILE_NAME, \"r\")) {\n            long fileSize = raf.length();\n\n            if (fileSize < 100000) {\n                long[] chunks = new long[2];\n                chunks[1] = fileSize;\n                return chunks;\n            }\n\n            while (fileSize / segmentCount >= (Integer.MAX_VALUE - 150)) {\n                segmentCount *= 2;\n            }\n\n            long[] chunks = new long[segmentCount + 1];\n\n            chunks[0] = 0;\n            long segmentSize = fileSize / segmentCount;\n\n            for (int i = 1; i < segmentCount; i++) {\n                long chunkOffset = chunks[i - 1] + segmentSize;\n                raf.seek(chunkOffset);\n                while (raf.readByte() != '\\n') {\n                }\n                chunks[i] = raf.getFilePointer();\n            }\n            chunks[segmentCount] = fileSize;\n            return chunks;\n        }\n    }\n\n    public static class LinearProbingHashMap {\n        final Measurement[] hashTable;\n        int slots;\n\n        public LinearProbingHashMap(int slots) {\n            this.slots = slots;\n            this.hashTable = new Measurement[slots];\n        }\n\n        void put(int hash, byte[] key, int len, int temperature) {\n            hash = Math.abs(hash);\n            int index = hash & (slots - 1);\n\n            int i = index;\n            while (hashTable[i] != null) {\n                if (keyIsEqual(key, hashTable[i].city, len)) { // handling hash collisions\n                    hashTable[i].add(temperature);\n                    return;\n                }\n                i++;\n                if (i == slots) {\n                    i = 0;\n                }\n            }\n\n            var cityArr = new byte[len];\n            System.arraycopy(key, 0, cityArr, 0, len);\n            hashTable[i] = new Measurement(cityArr, hash, temperature, temperature, 1, temperature);\n        }\n\n        private boolean keyIsEqual(byte[] one, byte[] other, int len) {\n            if (len != other.length)\n                return false;\n            for (int i = 0; i < len; i++) {\n                if (one[i] != other[i]) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n    }\n\n    static class Measurement {\n        byte[] city;\n        int hash;\n        int min;\n        int max;\n        int count;\n        long sum;\n\n        public Measurement(byte[] city, int hash, int min, int max, int count, long sum) {\n            this.city = city;\n            this.hash = hash;\n            this.min = min;\n            this.max = max;\n            this.count = count;\n            this.sum = sum;\n        }\n\n        public void add(int temperature) {\n            min = Math.min(min, temperature);\n            max = Math.max(max, temperature);\n            count++;\n            sum += temperature;\n        }\n\n        public Measurement merge(Measurement other) {\n            min = Math.min(min, other.min);\n            max = Math.max(max, other.max);\n            count += other.count;\n            sum += other.sum;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return (min * 1.0) / 10 + \"/\" + round((sum * 1.0) / count) / 10.0 + \"/\" + (max * 1.0) / 10;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return Arrays.equals(city, ((Measurement) obj).city);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_Kidlike.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.text.DecimalFormat;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Executors;\nimport java.util.stream.Collectors;\n\n/**\n * Versions (correlate to git commits):\n * <ol>\n *     <li>2m34s: parallel file read -> load byte chunks in memory -> sequentially process bytes for result</li>\n *     <li>0m59s: process byte chunks in parallel (had to introduce smarter byte chunking so it splits only on newlines)</li>\n *     <li>0m46s: smaller numeric types for MeasurementAggregator</li>\n *     <li>0m39s: implement custom byte[] to int parsing, instead of Double.parseDouble(new String(bytes))</li>\n *     <li>0m18s: run with GraalVM native-image</li>\n *     <li>0m14s: remove ConcurrentHashMap</li>\n *     <li>0m11s: remove Map#compute</li>\n * </ol>\n *\n * <p>\n * Hardware:\n * <ul>\n *     <li>CPU: https://www.cpubenchmark.net/cpu.php?cpu=AMD+Ryzen+7+5800H&id=3907</li>\n *     <li>NVMe: https://www.harddrivebenchmark.net/hdd.php?hdd=SKHynix%20HFS001TDE9X084N&id=28560</li>\n * </ul>\n * </p>\n */\npublic class CalculateAverage_Kidlike {\n\n    public static void main(String[] args) {\n        File file = new File(\"./measurements.txt\");\n        long fileSize = file.length();\n        int processors = (fileSize < 1_000_000) ? 1 : Runtime.getRuntime().availableProcessors();\n        long chunkSize = fileSize / processors;\n\n        MappedByteBuffer[] byteBuffers = new MappedByteBuffer[processors];\n\n        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {\n            for (int i = 0; i < processors; i++) {\n                long start = i * chunkSize;\n                long length = (i == processors - 1) ? fileSize - chunkSize * (processors - 1) : chunkSize;\n                int processor = i;\n                executor.execute(() -> {\n                    long realStart = start;\n                    try (RandomAccessFile raf = new RandomAccessFile(file, \"r\")) {\n                        if (start != 0) {\n                            raf.seek(start);\n                            while (raf.readByte() != '\\n') {\n                                // move pointer to newline, so that we can process the byte chunks in parallel later.\n                            }\n                            realStart = raf.getFilePointer();\n                        }\n                        long realLength = fileSize - realStart;\n                        if (realStart + length < fileSize) {\n                            raf.seek(realStart + length);\n                            while (raf.readByte() != '\\n') {\n                                // move pointer to newline, so that we can process the byte chunks in parallel later.\n                            }\n                            realLength = raf.getFilePointer() - realStart;\n                        }\n\n                        MappedByteBuffer byteBuffer = raf.getChannel().map(MapMode.READ_ONLY, realStart, realLength);\n                        byteBuffer.load();\n                        byteBuffers[processor] = byteBuffer;\n                    }\n                    catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                });\n            }\n        }\n\n        System.out.println(new TreeMap(calculateMeasurements(byteBuffers)));\n    }\n\n    private static Map<String, MeasurementAggregator> calculateMeasurements(MappedByteBuffer[] buffers) {\n        return Arrays.stream(buffers).parallel()\n                .map(buffer -> {\n                    var results = new HashMap<String, MeasurementAggregator>();\n\n                    var state = State.NEXT_READ_CITY;\n                    var citySink = new CheapByteBuffer(100);\n                    var measurementSink = new CheapByteBuffer(10);\n\n                    while (buffer.hasRemaining()) {\n                        byte b = buffer.get();\n                        char c = (char) b;\n\n                        if (c == ';') {\n                            state = State.NEXT_READ_MEASUREMENT;\n                            continue;\n                        }\n\n                        if (c == '\\n') {\n                            String city = new String(citySink.getBytes(), UTF_8);\n                            int measurement = bytesToInt(measurementSink.getBytes());\n                            var entry = results.get(city);\n                            if (entry == null) {\n                                entry = new MeasurementAggregator();\n                                results.put(city, entry);\n                            }\n\n                            entry.count++;\n                            entry.sum += measurement;\n                            entry.min = (short) Math.min(entry.min, measurement);\n                            entry.max = (short) Math.max(entry.max, measurement);\n\n                            citySink.clear();\n                            measurementSink.clear();\n                            state = State.NEXT_READ_CITY;\n                            continue;\n                        }\n\n                        switch (state) {\n                            case NEXT_READ_CITY -> citySink.append(b);\n                            case NEXT_READ_MEASUREMENT -> measurementSink.append(b);\n                        }\n                    }\n\n                    return results;\n                })\n                .flatMap(m -> m.entrySet().stream())\n                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, MeasurementAggregator::merge));\n    }\n\n    /**\n     * Removes decimal points and returns an integer. For example -12.3 would return -123\n     */\n    static int bytesToInt(byte[] bytes) {\n        short index = (short) (bytes.length - 1);\n\n        boolean isNegative = (bytes[0] == '-');\n        int number = (bytes[index] - '0');\n        index -= 2;\n\n        number += (10 * (bytes[index--] - '0'));\n\n        if (index == 1 || (!isNegative && index == 0)) {\n            number += (100 * (bytes[index] - '0'));\n        }\n\n        if (isNegative) {\n            return -number;\n        }\n        else {\n            return number;\n        }\n    }\n\n    private enum State {\n        NEXT_READ_CITY,\n        NEXT_READ_MEASUREMENT\n    }\n\n    /**\n     * Numbers are stored as integers, because of {@link #bytesToInt}, and then divided by 10.0 to restore their decimal point.\n     */\n    private static class MeasurementAggregator {\n\n        private static final DecimalFormat rounder = new DecimalFormat(\"0.0\");\n        short min = Short.MAX_VALUE;\n        short max = Short.MIN_VALUE;\n        long sum;\n        int count;\n\n        private MeasurementAggregator merge(MeasurementAggregator other) {\n            min = (short) Math.min(min, other.min);\n            max = (short) Math.max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return rounder.format(min / 10.0)\n                    + \"/\" + rounder.format(Math.round((double) sum / count) / 10.0)\n                    + \"/\" + rounder.format(max / 10.0);\n        }\n    }\n\n    private static class CheapByteBuffer {\n\n        private final byte[] data;\n        private int length;\n\n        public CheapByteBuffer(final int startSize) {\n            this.data = new byte[startSize];\n            this.length = 0;\n        }\n\n        public void append(final byte b) {\n            data[length++] = b;\n        }\n\n        public void clear() {\n            this.length = 0;\n        }\n\n        public byte[] getBytes() {\n            return Arrays.copyOf(this.data, this.length);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_MahmoudFawzyKhalil.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.concurrent.ForkJoinPool;\n\n// Solution using project Panama and Map Reduce\npublic class CalculateAverage_MahmoudFawzyKhalil {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws Exception {\n        mapReduce();\n    }\n\n    private static void mapReduce() throws IOException {\n        var f = new File(FILE);\n        try (var raf = new RandomAccessFile(f, \"r\")) {\n            FileChannel channel = raf.getChannel();\n            long fileSize = channel.size();\n            MemorySegment ms = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n            long chunkSize = fileSize / ForkJoinPool.commonPool().getParallelism();\n            List<Chunk> chunks = getChunks(ms, chunkSize);\n            Map<String, MeasurementAggregate> result = chunks.stream()\n                    .parallel()\n                    .map(c -> readChunkToMap(c, ms))\n                    .reduce(Collections.emptyMap(), (a, b) -> combine(a, b));\n            System.out.println(new TreeMap<>(result));\n        }\n    }\n\n    private static List<Chunk> getChunks(MemorySegment ms, long chunkSize) {\n        List<Chunk> chunks = new ArrayList<>(32);\n        long start = 0;\n        long fileSize = ms.byteSize();\n        long end = chunkSize;\n\n        while (start < fileSize) {\n            byte b = ms.get(ValueLayout.JAVA_BYTE, end);\n            if (b == '\\n') {\n                chunks.add(new Chunk(start, end));\n                start = end + 1;\n                end = Math.min(end + chunkSize, fileSize - 2);\n            }\n            end++;\n        }\n        return chunks;\n    }\n\n    private static Map<String, MeasurementAggregate> readChunkToMap(Chunk chunk, MemorySegment ms) {\n        Map<String, MeasurementAggregate> map = new HashMap<>();\n\n        long start = chunk.start();\n        while (start < chunk.end()) {\n            long cityNameSize = 0;\n            while (ms.get(ValueLayout.JAVA_BYTE, start + cityNameSize) != ';') {\n                cityNameSize++;\n            }\n\n            String cityName = readString(ms, start, cityNameSize);\n            start = start + cityNameSize + 1;\n\n            long temperatureSize = 0;\n            while (ms.get(ValueLayout.JAVA_BYTE, start + temperatureSize) != '\\n') {\n                temperatureSize++;\n            }\n\n            String temperature = readString(ms, start, temperatureSize);\n            start = start + temperatureSize + 1;\n\n            // System.out.println(STR.\"\\{cityName};\\{temperature}\");\n            addMeasurement(map, cityName, temperature);\n        }\n\n        return map;\n    }\n\n    // Credit goes to imrafaelmerino for combine function\n    private static Map<String, MeasurementAggregate> combine(Map<String, MeasurementAggregate> xs, Map<String, MeasurementAggregate> ys) {\n        Map<String, MeasurementAggregate> result = new HashMap<>();\n\n        for (var key : xs.keySet()) {\n            var m1 = xs.get(key);\n            var m2 = ys.get(key);\n            var combined = (m2 == null) ? m1 : (m1 == null) ? m2 : m1.combine(m2);\n            result.put(key, combined);\n        }\n\n        for (var key : ys.keySet())\n            result.putIfAbsent(key, ys.get(key));\n        return result;\n    }\n\n    private static String readString(MemorySegment ms, long start, long size) {\n        byte[] stringBytes = ms.asSlice(start, size)\n                .toArray(ValueLayout.JAVA_BYTE);\n        return new String(stringBytes);\n    }\n\n    private static void addMeasurement(Map<String, MeasurementAggregate> measurements, String station, String reading) {\n        measurements.compute(station,\n                (_, oldMeasurements) -> oldMeasurements == null ? MeasurementAggregate.of(reading) : oldMeasurements.update(reading));\n    }\n\n    record Chunk(long start, long end) {\n    }\n\n    private static final class MeasurementAggregate {\n        private double min;\n        private double max;\n        private double sum;\n        private long count;\n\n        private MeasurementAggregate(double min, double max, double sum, long count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n\n        public static MeasurementAggregate of(String temperature) {\n            double measurement = Double.parseDouble(temperature);\n            return new MeasurementAggregate(measurement, measurement, measurement, 1);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj == this)\n                return true;\n            if (obj == null || obj.getClass() != this.getClass())\n                return false;\n            var that = (MeasurementAggregate) obj;\n            return Double.doubleToLongBits(this.min) == Double.doubleToLongBits(that.min) &&\n                    Double.doubleToLongBits(this.max) == Double.doubleToLongBits(that.max) &&\n                    Double.doubleToLongBits(this.sum) == Double.doubleToLongBits(that.sum) &&\n                    this.count == that.count;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(min, max, sum, count);\n        }\n\n        public MeasurementAggregate update(String part) {\n            double measurement = Double.parseDouble(part);\n            this.min = Math.min(this.min, measurement);\n            this.max = Math.max(this.max, measurement);\n            this.sum += measurement;\n            this.count++;\n            return this;\n        }\n\n        public String toString() {\n            return min + \"/\" + round(round(sum) / count) + \"/\" + max;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public MeasurementAggregate combine(MeasurementAggregate m2) {\n            return new MeasurementAggregate(\n                    Math.min(this.min, m2.min),\n                    Math.max(this.max, m2.max),\n                    this.sum + m2.sum,\n                    this.count + m2.count);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_MeanderingProgrammer.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.*;\nimport java.util.*;\nimport java.util.stream.*;\n\n/*\n * # Main Speed Drivers\n *\n * Changes were made in this order, each header includes the runtime before and after the change,\n * and whose implementation (if any) was used as a reference.\n *\n * ## Parallel Process Chunks [160.5 -> 18] [twobiers]\n *\n * Rather than reading data top to bottom and attempting to parallelize processing with batches\n * of the parsed data, we read chunks of data (about 1 MB) and parrallelize processing per chunk.\n *\n * Several implementations do this kind of processing using a FileChannel to map chunks to buffers,\n * the reference above gave the idea to use an iterator.\n *\n * ## Share Byte Array when Deserializing [18 -> 6.5] [Various]\n *\n * When deserializing names after going through the effort of processing one byte at a time\n * when processing a chunk of data we can re-use a single byte array to store the characters\n * that make up the name. This removes the need to allocate and de-allocate memory for the buffer.\n *\n * We can then use the new String(byte[], 0, length) constructor to create the String without\n * worrying about clearing the underlying byte array as we provide a length.\n *\n * For this one I did not use any particular implementation as a reference but have seen it in many.\n *\n * ## Store ints Compute Doubles at End [6.5 -> 6.2] [None]\n *\n * Since input has a single decimal only we can effectively ignore it, do all of our math with the\n * numbers as integers, then only when printing out divide by 10.0 to get the correct values.\n *\n * The impact of this is small, maybe even nothing in this implementation, but keeping it in place.\n *\n * ## Use graal [6.2 -> 5.3] [None]\n *\n * Change from 21.0.1-tem to 21.0.1-graal.\n *\n * ## Process ByteBuffer for Name then Value [5.3 -> 4.7] [None]\n *\n * This started as a refactor and turned out to have noticeable runtime impact, which is nice.\n *\n * Rather than processing the ByteBuffer in a single while (current != '\\n') with a condition\n * to switch from getting the name to calculating the integer value on (current == ';') the\n * logic was split into 2 separate loops.\n *\n * The first, while (current != ';') and a second, while (current != '\\n').\n *\n * # For my Own Reference\n *\n * ## Constraints\n *\n * - Station name: non null UTF-8 string of length [1, 100] bytes\n * - Temperature value: non null double [-99.9, 99.9] with one fractional digit\n * - Station names: maximum of 10,000 unique names\n *\n * ## Run Commands\n *\n * ./mvnw clean verify && ./test.sh MeanderingProgrammer\n *\n * ./mvnw clean verify && ./calculate_average_MeanderingProgrammer.sh\n *\n * ## Runtimes\n *\n * Baseline: 2:40.597\n * Current:  0:04.668\n */\npublic class CalculateAverage_MeanderingProgrammer {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class ChunkReader implements Iterator<ByteBuffer> {\n\n        private static final long CHUNK_SIZE = 1_024 * 1_024;\n\n        private final FileChannel channel;\n        private final long size;\n        private long read;\n\n        public ChunkReader(Path path) throws Exception {\n            this.channel = FileChannel.open(path, StandardOpenOption.READ);\n            this.size = this.channel.size();\n            this.read = 0;\n        }\n\n        public long estimateIterations() {\n            return this.size / CHUNK_SIZE;\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.nextChunkSize() > 0;\n        }\n\n        @Override\n        public ByteBuffer next() {\n            ByteBuffer buffer = null;\n            try {\n                buffer = this.channel.map(FileChannel.MapMode.READ_ONLY, this.read, this.nextChunkSize());\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n            // Logic to clamp buffer to last complete line\n            int bufferSize = buffer.limit();\n            while (buffer.get(bufferSize - 1) != '\\n') {\n                bufferSize--;\n            }\n            buffer.limit(bufferSize);\n            this.read += bufferSize;\n            return buffer;\n        }\n\n        private long nextChunkSize() {\n            return Math.min(CHUNK_SIZE, this.size - this.read);\n        }\n    }\n\n    private static record Row(String name, int value) {\n    }\n\n    private static class RowReader implements Iterator<Row> {\n\n        private final ByteBuffer buffer;\n        private final byte[] nameBuffer;\n\n        public RowReader(ByteBuffer buffer) {\n            this.buffer = buffer;\n            this.nameBuffer = new byte[100];\n        }\n\n        @Override\n        public boolean hasNext() {\n            return this.buffer.hasRemaining();\n        }\n\n        @Override\n        public Row next() {\n            var index = 0;\n            var current = buffer.get();\n            while (current != ';') {\n                this.nameBuffer[index] = current;\n                index++;\n                current = buffer.get();\n            }\n            var name = new String(this.nameBuffer, 0, index, StandardCharsets.UTF_8);\n\n            var negative = false;\n            var value = 0;\n            current = buffer.get();\n            while (current != '\\n') {\n                if (current == '-') {\n                    negative = true;\n                }\n                else if (current != '.') {\n                    value = (value * 10) + (current - '0');\n                }\n                current = buffer.get();\n            }\n            if (negative) {\n                value *= -1;\n            }\n\n            return new Row(name, value);\n        }\n    }\n\n    private static class Measurement {\n\n        private int min;\n        private int max;\n        private long sum;\n        private int count;\n\n        public Measurement(int value) {\n            this.min = value;\n            this.max = value;\n            this.sum = value;\n            this.count = 1;\n        }\n\n        public Measurement merge(Measurement other) {\n            if (other.min < this.min) {\n                this.min = other.min;\n            }\n            if (other.max > this.max) {\n                this.max = other.max;\n            }\n            this.sum += other.sum;\n            this.count += other.count;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\n                    \"%.1f/%.1f/%.1f\",\n                    this.min / 10.0,\n                    (this.sum / 10.0) / this.count,\n                    this.max / 10.0);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        run();\n    }\n\n    private static void run() throws Exception {\n        var reader = new ChunkReader(Paths.get(FILE));\n        var iterator = Spliterators.spliterator(reader, reader.estimateIterations(), Spliterator.IMMUTABLE);\n        var measurements = StreamSupport.stream(iterator, true)\n                .flatMap(buffer -> toMeasurements(buffer).entrySet().stream())\n                .collect(Collectors.toConcurrentMap(\n                        entry -> entry.getKey(),\n                        entry -> entry.getValue(),\n                        Measurement::merge));\n        System.out.println(new TreeMap<>(measurements));\n    }\n\n    private static Map<String, Measurement> toMeasurements(ByteBuffer buffer) {\n        var iterator = Spliterators.spliteratorUnknownSize(new RowReader(buffer), Spliterator.IMMUTABLE);\n        return StreamSupport.stream(iterator, false)\n                .collect(Collectors.toMap(\n                        row -> row.name(),\n                        row -> new Measurement(row.value()),\n                        Measurement::merge));\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_PanagiotisDrakatos.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_PanagiotisDrakatos {\n    private static final String FILE = \"./measurements.txt\";\n    private static final long MAP_SIZE = 1024 * 1024 * 12L;\n    private static TreeMap<String, MeasurementObject> sortedCities;\n\n    public static void main(String[] args) throws IOException {\n        SeekableByteRead(FILE);\n        System.out.println(sortedCities.toString());\n        boolean DEBUG = true;\n    }\n\n    private static void SeekableByteRead(String path) throws IOException {\n        FileInputStream fileInputStream = new FileInputStream(new File(FILE));\n        FileChannel fileChannel = fileInputStream.getChannel();\n        try {\n            sortedCities = getFileSegments(new File(FILE), fileChannel).stream()\n                    .map(CalculateAverage_PanagiotisDrakatos::SplitSeekableByteChannel)\n                    .parallel()\n                    .map(CalculateAverage_PanagiotisDrakatos::MappingByteBufferToData)\n                    .flatMap(MeasurementRepository::get)\n                    .collect(Collectors.toMap(e -> e.cityName, MeasurementRepository.Entry::measurement, MeasurementObject::updateWith, TreeMap::new));\n        }\n        catch (NullPointerException e) {\n        }\n        fileChannel.close();\n    }\n\n    record FileSegment(long start, long end, FileChannel fileChannel) {\n    }\n\n    private static List<FileSegment> getFileSegments(final File file, final FileChannel fileChannel) throws IOException {\n        final int numberOfSegments = Runtime.getRuntime().availableProcessors();\n        final long fileSize = file.length();\n        final long segmentSize = fileSize / numberOfSegments;\n        final List<FileSegment> segments = new ArrayList<>();\n        if (segmentSize < 1000) {\n            segments.add(new FileSegment(0, fileSize, fileChannel));\n            return segments;\n        }\n        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\")) {\n            long segStart = 0;\n            long segEnd = segmentSize;\n            while (segStart < fileSize) {\n                segEnd = findSegment(randomAccessFile, segEnd, fileSize);\n                segments.add(new FileSegment(segStart, segEnd, fileChannel));\n                segStart = segEnd; // Just re-use the end and go from there.\n                segEnd = Math.min(fileSize, segEnd + segmentSize);\n            }\n        }\n        return segments;\n    }\n\n    private static long findSegment(RandomAccessFile raf, long location, final long fileSize) throws IOException {\n        raf.seek(location);\n        while (location < fileSize) {\n            location++;\n            if (raf.read() == '\\n')\n                return location;\n        }\n        return location;\n    }\n\n    private static ByteBuffer SplitSeekableByteChannel(FileSegment segment) {\n        try {\n            MappedByteBuffer buffer = segment.fileChannel.map(FileChannel.MapMode.READ_ONLY, segment.start(), segment.end - segment.start());\n            return buffer;\n        }\n        catch (Exception ex) {\n            long start = segment.start;\n            long end = 0;\n            try {\n                end = segment.fileChannel.size();\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n            MappedByteBuffer buffer = null;\n            ArrayList<ByteBuffer> list = new ArrayList<>();\n            while (start < end) {\n                try {\n                    buffer = segment.fileChannel.map(FileChannel.MapMode.READ_ONLY, start, Math.min(MAP_SIZE, end - start));\n                    // don't split the data in the middle of lines\n                    // find the closest previous newline\n                    int realEnd = buffer.limit() - 1;\n                    while (buffer.get(realEnd) != '\\n')\n                        realEnd--;\n\n                    realEnd++;\n                    buffer.limit(realEnd);\n                    start += realEnd;\n                    list.add(buffer.slice(0, realEnd - 1));\n                }\n                catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            sortedCities = list.stream().parallel().map(CalculateAverage_PanagiotisDrakatos::MappingByteBufferToData).flatMap(MeasurementRepository::get)\n                    .collect(Collectors.toMap(e -> e.cityName, MeasurementRepository.Entry::measurement, MeasurementObject::updateWith, TreeMap::new));\n            return null;\n        }\n    }\n\n    public static ByteBuffer concat(ByteBuffer[] buffers) {\n        int overAllCapacity = 0;\n        for (int i = 0; i < buffers.length; i++)\n            overAllCapacity += buffers[i].limit() - buffers[i].position();\n        overAllCapacity += buffers[0].limit() - buffers[0].position();\n        ByteBuffer all = ByteBuffer.allocate(overAllCapacity);\n        for (int i = 0; i < buffers.length; i++) {\n            ByteBuffer curr = buffers[i];\n            all.put(curr);\n        }\n\n        all.flip();\n        return all;\n    }\n\n    private static TreeMap<String, MeasurementObject> combineMaps(Stream<MeasurementRepository.Entry> stream1, Stream<MeasurementRepository.Entry> stream2) {\n        Stream<MeasurementRepository.Entry> resultingStream = Stream.concat(stream1, stream2);\n        return resultingStream.collect(Collectors.toMap(e -> e.cityName, MeasurementRepository.Entry::measurement, MeasurementObject::updateWith, TreeMap::new));\n    }\n\n    private static int longHashStep(final int hash, final long word) {\n        return 31 * hash + (int) (word ^ (word >>> 32));\n    }\n\n    private static final long SEPARATOR_PATTERN = compilePattern((byte) ';');\n\n    private static long compilePattern(final byte value) {\n        return ((long) value << 56) | ((long) value << 48) | ((long) value << 40) | ((long) value << 32) | ((long) value << 24) | ((long) value << 16)\n                | ((long) value << 8) | (long) value;\n    }\n\n    private static MeasurementRepository MappingByteBufferToData(ByteBuffer byteBuffer) {\n        MeasurementRepository measurements = new MeasurementRepository();\n        ByteBuffer bb = byteBuffer.duplicate();\n\n        int start = 0;\n        int limit = bb.limit();\n\n        long[] cityNameAsLongArray = new long[16];\n        int[] delimiterPointerAndHash = new int[2];\n\n        bb.order(ByteOrder.nativeOrder());\n        final boolean bufferIsBigEndian = bb.order().equals(ByteOrder.BIG_ENDIAN);\n\n        while ((start = bb.position()) < limit + 1) {\n\n            int delimiterPointer;\n\n            findNextDelimiterAndCalculateHash(bb, SEPARATOR_PATTERN, start, limit, delimiterPointerAndHash, cityNameAsLongArray, bufferIsBigEndian);\n            delimiterPointer = delimiterPointerAndHash[0];\n            // Simple lookup is faster for '\\n' (just three options)\n            if (delimiterPointer >= limit) {\n                return measurements;\n            }\n            final int cityNameLength = delimiterPointer - start;\n\n            int temp_counter = 0;\n            int temp_end = delimiterPointer + 1;\n            try {\n                // bb.position(delimiterPointer++);\n                while (bb.get(temp_end) != '\\n') {\n                    temp_counter++;\n                    temp_end++;\n                }\n            }\n            catch (IndexOutOfBoundsException e) {\n                // temp_counter--;\n                // temp_end--;\n            }\n            ByteBuffer temp = bb.duplicate().slice(delimiterPointer + 1, temp_counter);\n            int tempPointer = 0;\n            int abs = 1;\n            if (temp.get(0) == '-') {\n                abs = -1;\n                tempPointer++;\n            }\n            int measuredValue;\n            if (temp.get(tempPointer + 1) == '.') {\n                measuredValue = abs * ((temp.get(tempPointer)) * 10 + (temp.get(tempPointer + 2)) - 528);\n            }\n            else {\n                measuredValue = abs * (temp.get(tempPointer) * 100 + temp.get(tempPointer + 1) * 10 + temp.get(tempPointer + 3) - 5328);\n            }\n\n            measurements.update(cityNameAsLongArray, bb, cityNameLength, delimiterPointerAndHash[1]).updateWith(measuredValue);\n\n            if (temp_end + 1 > limit)\n                return measurements;\n            bb.position(temp_end + 1);\n        }\n        return measurements;\n    }\n\n    private static void findNextDelimiterAndCalculateHash(final ByteBuffer bb, final long pattern, final int start, final int limit, final int[] output,\n                                                          final long[] asLong, final boolean bufferBigEndian) {\n        int hash = 1;\n        int i;\n        int lCnt = 0;\n        for (i = start; i <= limit - 8; i += 8) {\n            long word = bb.getLong(i);\n            if (bufferBigEndian) {\n                word = Long.reverseBytes(word); // Reversing the bytes is the cheapest way to do this\n            }\n            final long match = word ^ pattern;\n            long mask = ((match - 0x0101010101010101L) & ~match) & 0x8080808080808080L;\n\n            if (mask != 0) {\n                final int index = Long.numberOfTrailingZeros(mask) >> 3;\n                output[0] = (i + index);\n\n                final long partialHash = word & ((mask >> 7) - 1);\n                asLong[lCnt] = partialHash;\n                output[1] = longHashStep(hash, partialHash);\n                return;\n            }\n            asLong[lCnt++] = word;\n            hash = longHashStep(hash, word);\n        }\n        // Handle remaining bytes near the limit of the buffer:\n        long partialHash = 0;\n        int len = 0;\n        for (; i < limit; i++) {\n            byte read;\n            if ((read = bb.get(i)) == (byte) pattern) {\n                asLong[lCnt] = partialHash;\n                output[0] = i;\n                output[1] = longHashStep(hash, partialHash);\n                return;\n            }\n            partialHash = partialHash | ((long) read << (len << 3));\n            len++;\n        }\n        output[0] = limit; // delimiter not found\n    }\n\n    static class MeasurementRepository {\n        private int tableSize = 1 << 20; // can grow in theory, made large enough not to (this is faster)\n        private int tableMask = (tableSize - 1);\n        private int tableLimit = (int) (tableSize * LOAD_FACTOR);\n        private int tableFilled = 0;\n        private static final float LOAD_FACTOR = 0.8f;\n\n        private Entry[] table = new Entry[tableSize];\n\n        record Entry(int hash, long[] nameBytesInLong, String cityName, MeasurementObject measurement) {\n            @Override\n            public String toString() {\n                return cityName + \"=\" + measurement;\n            }\n        }\n\n        public MeasurementObject update(long[] nameBytesInLong, ByteBuffer bb, int length, int calculatedHash) {\n\n            final int nameBytesInLongLength = 1 + (length >>> 3);\n\n            int index = calculatedHash & tableMask;\n            Entry tableEntry;\n            while ((tableEntry = table[index]) != null\n                    && (tableEntry.hash != calculatedHash || !arrayEquals(tableEntry.nameBytesInLong, nameBytesInLong, nameBytesInLongLength))) { // search for the right spot\n                index = (index + 1) & tableMask;\n            }\n\n            if (tableEntry != null) {\n                return tableEntry.measurement;\n            }\n\n            // --- This is a brand new entry, insert into the hashtable and do the extra calculations (once!) do slower calculations here.\n            MeasurementObject measurement = new MeasurementObject();\n\n            // Now create a string:\n            byte[] buffer = new byte[length];\n            bb.get(buffer, 0, length);\n            String cityName = new String(buffer, 0, length);\n\n            // Store the long[] for faster equals:\n            long[] nameBytesInLongCopy = new long[nameBytesInLongLength];\n            System.arraycopy(nameBytesInLong, 0, nameBytesInLongCopy, 0, nameBytesInLongLength);\n\n            // And add entry:\n            Entry toAdd = new Entry(calculatedHash, nameBytesInLongCopy, cityName, measurement);\n            table[index] = toAdd;\n\n            // Resize the table if filled too much:\n            if (++tableFilled > tableLimit) {\n                resizeTable();\n            }\n\n            return toAdd.measurement;\n        }\n\n        private void resizeTable() {\n            // Resize the table:\n            Entry[] oldEntries = table;\n            table = new Entry[tableSize <<= 2]; // x2\n            tableMask = (tableSize - 1);\n            tableLimit = (int) (tableSize * LOAD_FACTOR);\n\n            for (Entry entry : oldEntries) {\n                if (entry != null) {\n                    int updatedTableIndex = entry.hash & tableMask;\n                    while (table[updatedTableIndex] != null) {\n                        updatedTableIndex = (updatedTableIndex + 1) & tableMask;\n                    }\n                    table[updatedTableIndex] = entry;\n                }\n            }\n        }\n\n        public Stream<Entry> get() {\n            return Arrays.stream(table).filter(Objects::nonNull);\n        }\n    }\n\n    private static boolean arrayEquals(final long[] a, final long[] b, final int length) {\n        for (int i = 0; i < length; i++) {\n            if (a[i] != b[i])\n                return false;\n        }\n        return true;\n    }\n\n    private static final class MeasurementObject {\n\n        private int MAX;\n        private int MIN;\n\n        private long SUM;\n\n        private int REPEAT;\n\n        public MeasurementObject(int MAX, int MIN, long SUM, int REPEAT) {\n            this.MAX = MAX;\n            this.MIN = MIN;\n            this.SUM = SUM;\n            this.REPEAT = REPEAT;\n        }\n\n        public MeasurementObject() {\n            this.MAX = -999;\n            this.MIN = 9999;\n            this.SUM = 0;\n            this.REPEAT = 0;\n        }\n\n        public MeasurementObject(int MAX, int MIN, long SUM) {\n            this.MAX = MAX;\n            this.MIN = MIN;\n            this.SUM = SUM;\n        }\n\n        public MeasurementObject(int MAX, int MIN) {\n            this.MAX = MAX;\n            this.MIN = MIN;\n        }\n\n        public static MeasurementObject combine(MeasurementObject m1, MeasurementObject m2) {\n            var mres = new MeasurementObject();\n            mres.MIN = MeasurementObject.min(m1.MIN, m2.MIN);\n            mres.MAX = MeasurementObject.max(m1.MAX, m2.MAX);\n            mres.SUM = m1.SUM + m2.SUM;\n            mres.REPEAT = m1.REPEAT + m2.REPEAT;\n            return mres;\n        }\n\n        public static MeasurementObject updateWith(MeasurementObject m1, MeasurementObject m2) {\n            var mres = new MeasurementObject();\n            mres.MIN = MeasurementObject.min(m1.MIN, m2.MIN);\n            mres.MAX = MeasurementObject.max(m1.MAX, m2.MAX);\n            mres.SUM = m1.SUM + m2.SUM;\n            mres.REPEAT = m1.REPEAT + m2.REPEAT;\n            return mres;\n        }\n\n        public MeasurementObject updateWith(int measurement) {\n            MIN = MeasurementObject.min(MIN, measurement);\n            MAX = MeasurementObject.max(MAX, measurement);\n            SUM += measurement;\n            REPEAT++;\n            return this;\n        }\n\n        private static int max(final int a, final int b) {\n            final int diff = a - b;\n            final int dsgn = diff >> 31;\n            return a - (diff & dsgn);\n        }\n\n        private static int min(final int a, final int b) {\n            final int diff = a - b;\n            final int dsgn = diff >> 31;\n            return b + (diff & dsgn);\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n            MeasurementObject that = (MeasurementObject) o;\n            return MAX == that.MAX && MIN == that.MIN && REPEAT == that.REPEAT;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(MAX, MIN, REPEAT);\n        }\n\n        @Override\n        public String toString() {\n            return round(MIN) + \"/\" + round((1.0 * SUM) / REPEAT) + \"/\" + round(MAX);\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_PawelAdamski.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static java.util.stream.Collectors.groupingByConcurrent;\n\npublic class CalculateAverage_PawelAdamski {\n\n    private static final long READ_SIZE = 100_000_000;\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record ResultRow(double min, double mean, double max) {\n\n        public ResultRow(MeasurementAggregator ma) {\n            this(ma.min / 10.0, ((Math.round(ma.sum * 100.0) / 100.0) / (double) ma.count) / 10.0, ma.max / 10.0);\n        }\n\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static class Station {\n        byte[] bytes;\n        int hash;\n\n        public Station(byte[] station) {\n            this.bytes = station;\n            this.hash = Arrays.hashCode(bytes);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            return Arrays.equals(bytes, ((Station) o).bytes);\n        }\n\n    }\n\n    private static class MeasurementAggregator {\n        private long min;\n        private long max;\n        private long sum;\n        private long count;\n\n        public MeasurementAggregator(long temp) {\n            min = temp;\n            max = temp;\n            sum = temp;\n            count = 1;\n        }\n\n        public MeasurementAggregator() {\n            min = Long.MAX_VALUE;\n            max = Long.MIN_VALUE;\n            sum = 0;\n            count = 0;\n        }\n\n        public MeasurementAggregator merge(MeasurementAggregator measurement) {\n            MeasurementAggregator ma = new MeasurementAggregator();\n            ma.min = Math.min(min, measurement.min);\n            ma.max = Math.max(max, measurement.max);\n            ma.sum = sum + measurement.sum;\n            ma.count = count + measurement.count;\n            return ma;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        try (RandomAccessFile raf = new RandomAccessFile(FILE, \"r\")) {\n            List<FilePart> parts = splitFileIntoParts(raf);\n            Map<Station, MeasurementAggregator> rr = calculateTemperatureStats(parts, raf);\n            Map<String, ResultRow> results = prepareResults(rr);\n            System.out.println(results);\n        }\n    }\n\n    private static Map<String, ResultRow> prepareResults(Map<Station, MeasurementAggregator> rr) {\n        Map<String, ResultRow> measurements = new TreeMap<>();\n        rr.forEach((k, v) -> measurements.put(new String(k.bytes, UTF_8), new ResultRow(v)));\n        return measurements;\n    }\n\n    private static Map<Station, MeasurementAggregator> calculateTemperatureStats(List<FilePart> parts, RandomAccessFile raf) {\n        return parts.parallelStream()\n                .map(filePart -> parse(filePart, raf))\n                .flatMap(m -> m.entrySet().stream())\n                .collect(groupingByConcurrent(\n                        Map.Entry::getKey,\n                        Collectors.reducing(\n                                new MeasurementAggregator(),\n                                Map.Entry::getValue,\n                                MeasurementAggregator::merge)));\n    }\n\n    private static ArrayList<FilePart> splitFileIntoParts(RandomAccessFile raf) throws IOException {\n        ArrayList<FilePart> parts = new ArrayList<>((int) (raf.length() / READ_SIZE));\n        long pointer = 0;\n        long nextPointer = 0;\n        long fileLength = raf.length();\n        while (pointer < fileLength) {\n            if (pointer + READ_SIZE > fileLength) {\n                nextPointer = fileLength;\n            }\n            else {\n                nextPointer = findNextLine(raf, pointer + READ_SIZE);\n            }\n            parts.add(new FilePart(pointer, nextPointer - pointer));\n            pointer = nextPointer;\n        }\n        return parts;\n    }\n\n    private static Map<Station, MeasurementAggregator> parse(FilePart filePart, RandomAccessFile raf) {\n        try {\n            byte[] bytes = readBytesFromFile(filePart, raf);\n            return parseBytesIntoStationsMap(bytes);\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static HashMap<Station, MeasurementAggregator> parseBytesIntoStationsMap(byte[] bytes) {\n        HashMap<Station, MeasurementAggregator> measurementAggregator = new HashMap<>(500);\n        int semicolonIndex = 0;\n        int newLineIndex = -1;\n        for (int i = 0; i < bytes.length; i++) {\n            if (bytes[i] == ';') {\n                semicolonIndex = i;\n            }\n            else if (bytes[i] == '\\n') {\n                byte[] station = Arrays.copyOfRange(bytes, newLineIndex + 1, semicolonIndex);\n                long temp = parseDouble(bytes, semicolonIndex + 1, i);\n                MeasurementAggregator measurement = new MeasurementAggregator(temp);\n                measurementAggregator.compute(new Station(station), (k, prevV) -> prevV == null ? measurement : prevV.merge(measurement));\n                newLineIndex = i;\n            }\n        }\n        return measurementAggregator;\n    }\n\n    private static byte[] readBytesFromFile(FilePart filePart, RandomAccessFile raf) throws IOException {\n        var bb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, filePart.start(), filePart.len());\n        byte[] bytes = new byte[bb.remaining()];\n        bb.get(bytes);\n        return bytes;\n    }\n\n    private static long parseDouble(byte[] text, int start, int end) {\n        boolean negative = false;\n        int result = 0;\n        for (int i = start; i < end; i++) {\n            byte c = text[i];\n            if (c == '-') {\n                negative = true;\n            }\n            else if (c != '.') {\n                result *= 10;\n                result += c - '0';\n            }\n        }\n        if (negative) {\n            return -result;\n        }\n        else {\n            return result;\n        }\n    }\n\n    private static long findNextLine(RandomAccessFile raf, long currentPosition) throws IOException {\n        raf.seek(currentPosition);\n        while (raf.readByte() != '\\n')\n            ;\n        return raf.getFilePointer();\n    }\n\n    record FilePart(long start, long len) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_SamuelYvon.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\n//import jdk.incubator.vector.ByteVector;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.stream.Collectors;\n\n/**\n * Samuel Yvon's entry.\n * <p>\n * Explanation behind my reasoning:\n * - I want to make it as fast as possible without it being an unreadable mess; I want to avoid bit fiddling UTF-8\n * and use the provided facilities\n * - I use the fact that we know the number of stations to optimize HashMap creation (75% rule)\n * - I stole branch-less compare from royvanrijn\n * - I assume valid ASCII encoding for the number part, which allows me to parse it manually\n * (should hold for valid UTF-8)\n * - I have not done Java in forever. Especially what the heck it's become. I've looked at the other submissions and\n * the given sample to get inspiration. I did not even know about this Stream API thing.\n * </p>\n *\n * <p>\n * Future ideas:\n * - Probably can Vector-Apirize the number parsing (but it's three to four numbers, is it worth?)\n * </p>\n *\n * <p>\n * Observations:\n * - [2024-01-09] The branch-less code from royvarijn does not have a huge impact\n * </p>\n *\n * <p>\n * Changelogs:\n * 2024-01-09: Naive multi-threaded, no floats, manual line parsing\n * </p>\n */\npublic class CalculateAverage_SamuelYvon {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int MAX_STATIONS = 10000;\n\n    private static final byte SEMICOL = 0x3B;\n\n    private static final byte DOT = '.';\n\n    private static final byte MINUS = '-';\n\n    private static final byte ZERO = '0';\n\n    private static final String SLASH_S = \"/\";\n\n    private static final byte NEWLINE = '\\n';\n\n    // The minimum line length in bytes (over-egg.)\n    private static final int MIN_LINE_LENGTH_BYTES = 200;\n\n    private static final int DJB2_INIT = 5381;\n\n    /**\n     * Branchless min (unprecise for large numbers, but good enough)\n     *\n     * @author royvanrijn\n     */\n    private static int branchlessMax(final int a, final int b) {\n        final int diff = a - b;\n        final int dsgn = diff >> 31;\n        return a - (diff & dsgn);\n    }\n\n    /**\n     * Branchless min (unprecise for large numbers, but good enough)\n     *\n     * @author royvanrijn\n     */\n    private static int branchlessMin(final int a, final int b) {\n        final int diff = a - b;\n        final int dsgn = diff >> 31;\n        return b + (diff & dsgn);\n    }\n\n    /**\n     * A magic key that contains references to the String and where it's located in memory\n     */\n    private static final class StationName {\n        private final int hash;\n\n        private final byte[] value;\n\n        private StationName(int hash, MappedByteBuffer backing, int pos, int len) {\n            this.hash = hash;\n            this.value = new byte[len];\n            backing.get(pos, this.value);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @SuppressWarnings(\"EqualsWhichDoesntCheckParameterClass\")\n        @Override\n        public boolean equals(Object obj) {\n            // Should NEVER be true\n            // if (!(obj instanceof StationName)) {\n            // return false;\n            // }\n            StationName other = (StationName) obj;\n\n            if (this.value.length != other.value.length) {\n                return false;\n            }\n\n            // Byte for byte compare. This actually is a bug! I'm assuming the input\n            // is UTF-8 normalized, which in real life would probably not be the case.\n            // TODO: SIMD?\n            return Arrays.equals(this.value, other.value);\n        }\n\n        @Override\n        public String toString() {\n            return new String(this.value, StandardCharsets.UTF_8);\n        }\n    }\n\n    private static class StationMeasureAgg {\n        private int min;\n        private int max;\n        private long sum;\n        private long count;\n\n        private final StationName station;\n\n        private String memoizedName;\n\n        public StationMeasureAgg(StationName name) {\n            // Actual numbers are between -99.9 and 99.9, but we *10 to avoid float\n            this.station = name;\n            min = 1000;\n            max = -1000;\n            sum = 0;\n            count = 0;\n        }\n\n        @Override\n        public int hashCode() {\n            return this.station.hash;\n        }\n\n        /**\n         * Get the city name, but also memoized it to avoid building it multiple times\n         *\n         * @return the city name\n         */\n        public String city() {\n            if (null == this.memoizedName) {\n                this.memoizedName = station.toString();\n            }\n            return this.memoizedName;\n        }\n\n        public StationMeasureAgg mergeWith(StationMeasureAgg other) {\n            min = branchlessMin(min, other.min);\n            max = branchlessMax(max, other.max);\n\n            sum += other.sum;\n            count += other.count;\n\n            return this;\n        }\n\n        public void accumulate(int number) {\n            min = branchlessMin(min, number);\n            max = branchlessMax(max, number);\n\n            sum += number;\n            count++;\n        }\n\n        @Override\n        public String toString() {\n            double min = Math.round((double) this.min) / 10.0;\n            double max = Math.round((double) this.max) / 10.0;\n            double mean = Math.round((((double) this.sum / this.count))) / 10.0;\n            return min + SLASH_S + mean + SLASH_S + max;\n        }\n\n        public StationName station() {\n            return this.station;\n        }\n    }\n\n    private static HashMap<StationName, StationMeasureAgg> parseChunk(MappedByteBuffer chunk) {\n        HashMap<StationName, StationMeasureAgg> m = HashMap.newHashMap(MAX_STATIONS);\n\n        int i = 0;\n        while (i < chunk.limit()) {\n            int j = i;\n\n            int hash = DJB2_INIT;\n\n            // Implement a version of djb2 while we read until the semi, we read anyways\n            for (; j < chunk.limit(); ++j) {\n                byte b = chunk.get(j);\n\n                if (b == SEMICOL) {\n                    break;\n                }\n\n                // How will this behave in java? Why do I get no control OF SIGNEDNESS FFS\n                // Can I assume int is 32 bits? What is this language! In Java 1.7 it could be 16 bits?\n                // Apparently not anymore??\n                hash = (((hash << 5) + hash) + b);\n            }\n\n            StationName name = new StationName(hash, chunk, i, j - i);\n\n            // Skip the `;`\n            j++;\n\n            // Parse the int ourselves, avoids a 'String::replace' to remove the\n            // digit.\n            int temp = 0;\n            boolean neg = chunk.get(j) == MINUS;\n            for (j = j + (neg ? 1 : 0); j < chunk.limit(); ++j) {\n                temp *= 10;\n                byte c = chunk.get(j);\n                if (c != DOT) {\n                    temp += (char) (c - ZERO);\n                }\n                else {\n                    j++;\n                    break;\n                }\n            }\n\n            // The decimal point\n            temp += (char) (chunk.get(j) - ZERO);\n\n            i = j + 1;\n\n            while (chunk.get(i++) != NEWLINE)\n                ;\n\n            if (neg)\n                temp = -temp;\n\n            m.computeIfAbsent(name, StationMeasureAgg::new).accumulate(temp);\n        }\n\n        return m;\n    }\n\n    private static int approximateChunks() {\n        // https://stackoverflow.com/a/4759606\n        // I don't remember Java :D\n        return Runtime.getRuntime().availableProcessors();\n    }\n\n    private static List<MappedByteBuffer> getFileChunks() throws IOException {\n        int approxChunkCount = approximateChunks();\n\n        List<MappedByteBuffer> fileChunks = new ArrayList<>(approxChunkCount * 2);\n\n        // Compute chunks offsets and lengths\n        try (RandomAccessFile file = new RandomAccessFile(FILE, \"r\")) {\n            long totalOffset = 0;\n            long fLength = file.length();\n            long approximateLength = Long.max(fLength / approxChunkCount, MIN_LINE_LENGTH_BYTES);\n\n            while (totalOffset < fLength) {\n                long offset = totalOffset;\n                int length = (int) approximateLength;\n\n                boolean eof = offset + length >= fLength;\n                if (eof) {\n                    length = (int) (fLength - offset);\n                }\n\n                MappedByteBuffer out = file.getChannel().map(FileChannel.MapMode.READ_ONLY, totalOffset, length);\n\n                while (out.get(length - 1) != NEWLINE) {\n                    length--;\n                }\n\n                out.position(0);\n                out.limit(length);\n\n                fileChunks.add(out);\n\n                totalOffset += length;\n            }\n        }\n\n        return fileChunks;\n    }\n\n    public static void main(String[] args) throws IOException {\n        var fileChunks = getFileChunks();\n\n        // Map per core, giving the non-overlapping memory slices\n        final Map<StationName, StationMeasureAgg> allMeasures = fileChunks.parallelStream().map(CalculateAverage_SamuelYvon::parseChunk).flatMap(x -> x.values().stream())\n                .collect(Collectors.toMap(StationMeasureAgg::station, x -> x, StationMeasureAgg::mergeWith, HashMap::new));\n\n        // Give a capacity that should never be gone past\n        StringBuilder sb = new StringBuilder(allMeasures.size() * (100 + 4 + 20));\n        sb.append('{');\n\n        allMeasures.values().stream().sorted(Comparator.comparing(StationMeasureAgg::city)).forEach(x -> {\n            sb.append(x.city());\n            sb.append('=');\n            sb.append(x);\n            sb.append(\", \");\n        });\n\n        sb.delete(sb.length() - 2, sb.length()); // delete trailing comma and space\n\n        sb.append('}');\n\n        System.out.println(sb);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_Smoofie.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.TreeMap;\nimport java.util.concurrent.Executors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_Smoofie {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final Unsafe unsafe = getUnsafe();\n\n    private static class MeasurementAggregator {\n        private int min = -1000;\n        private int max = 1000;\n        private long sum = 0;\n        private int count = 0;\n\n        @Override\n        public String toString() {\n            return ((double) min) / 10 + \"/\" + round(sum / 10.0 / count) + \"/\" + ((double) max) / 10;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static final class CountResult {\n        private final long cityHashTableAddress;\n        private final long countsAddress;\n        private int cityIdCounter;\n        private long nextCollisionAddress;\n\n        private CountResult(\n\n                            // cityId|cityLength|cityNameAddress|nextElementAddress|cityCountsAddress\n                            long cityHashTableAddress,\n                            long countsAddress,\n                            int cityIdCounter,\n                            long nextCollisionAddress) {\n            this.cityHashTableAddress = cityHashTableAddress;\n            this.countsAddress = countsAddress;\n            this.cityIdCounter = cityIdCounter;\n            this.nextCollisionAddress = nextCollisionAddress;\n        }\n\n    }\n\n    private static int hash(long cityNameAddress, short cityLength) {\n        if (cityLength < 17) {\n            long[] city = new long[2];\n            unsafe.copyMemory(null, cityNameAddress, city, Unsafe.ARRAY_LONG_BASE_OFFSET, cityLength);\n            long hash = city[0] ^ (city[1] >> 1);\n            int foldedHash = (int) (hash ^ (hash >>> 31));\n            return (foldedHash & foldedHash >>> 15) & 0xffff;\n        }\n        else {\n            long[] city = new long[cityLength >> 3 + 1];\n            unsafe.copyMemory(null, cityNameAddress, city, Unsafe.ARRAY_LONG_BASE_OFFSET, cityLength);\n\n            long hash = city[0];\n            for (int i = 1; i < city.length; i++) {\n                hash ^= city[i];\n            }\n\n            int foldedHash = (int) (hash ^ (hash >>> 30));\n            return (foldedHash & foldedHash >>> 15) & 0xffff;\n        }\n    }\n\n    private static Unsafe getUnsafe() {\n        try {\n            var field = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            field.setAccessible(true);\n            return (Unsafe) field.get(null);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static long locateSemicolon(long input) {\n        long semiXor = input ^ 0x3B3B3B3B3B3B3B3BL;\n        return (semiXor - 0x0101010101010101L) & ~semiXor & 0x8080808080808080L;\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var numberOfThreads = Runtime.getRuntime().availableProcessors();\n        var executorService = Executors.newFixedThreadPool(numberOfThreads);\n        var resultMap = new TreeMap<String, MeasurementAggregator>();\n        var subCountResults = new CountResult[numberOfThreads];\n\n        try (RandomAccessFile randomAccessFile = new RandomAccessFile(FILE, \"r\");\n                FileChannel fileChannel = randomAccessFile.getChannel()) {\n\n            long fileSize = randomAccessFile.length();\n            if (fileSize < numberOfThreads * 1024) {\n                numberOfThreads = fileSize < 1024 ? 1 : (int) (fileSize / 1024);\n            }\n            long chunkSize = fileSize / numberOfThreads;\n\n            long inputFileAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global()).address();\n            final long[] inputFileMemoryOffsets = new long[numberOfThreads + 1];\n            inputFileMemoryOffsets[0] = inputFileAddress;\n            inputFileMemoryOffsets[numberOfThreads] = inputFileAddress + fileSize;\n            for (long i = inputFileAddress + chunkSize, index = 1; index < numberOfThreads; i += chunkSize, index++) {\n                while (unsafe.getByte(i++) != '\\n')\n                    ;\n                inputFileMemoryOffsets[(int) index] = i;\n            }\n\n            for (int i = 0; i < numberOfThreads; i++) {\n                final long start = inputFileMemoryOffsets[i];\n                final long end = inputFileMemoryOffsets[i + 1];\n\n                final int threadIndex = i;\n                executorService.execute(() -> {\n                    var cityHashTableAddress = unsafe.allocateMemory(75536 * 32);\n                    unsafe.setMemory(cityHashTableAddress, 75536 * 32, (byte) 0);\n                    long nextCollisionAddress = cityHashTableAddress + (65536 << 5);\n\n                    var countsAddress = unsafe.allocateMemory(10000 * 2 * 1000 * 4);\n                    int cityId;\n                    int temperature = 0;\n                    int cityIdCounter = 0;\n                    long position = start;\n                    byte c;\n                    long input;\n                    long inputSemicolon;\n                    int cityHash;\n                    long hashAddress;\n                    short cityLength;\n                    long cityStart;\n                    long temperatureAddress;\n                    while (position < end) {\n                        cityStart = position;\n                        input = unsafe.getLong(position);\n                        inputSemicolon = locateSemicolon(input);\n                        if (inputSemicolon == 0) {\n                            position += 8;\n                            input = unsafe.getLong(position);\n                            inputSemicolon = locateSemicolon(input);\n\n                            if (inputSemicolon == 0) {\n                                // probably not gonna happen very often\n                                while (inputSemicolon == 0) {\n                                    position += 8;\n                                    input = unsafe.getLong(position);\n                                    inputSemicolon = locateSemicolon(input);\n                                }\n                            }\n                        }\n                        position += Long.numberOfTrailingZeros(inputSemicolon) >> 3;\n\n                        cityLength = (short) (position - cityStart);\n\n                        cityHash = hash(cityStart, cityLength);\n                        hashAddress = cityHashTableAddress + ((long) cityHash << 5);\n                        cityId = -1;\n                        outer: for (;;) {\n                            if (cityLength != unsafe.getShort(hashAddress + 4)) {\n                                if (unsafe.getShort(hashAddress + 4) == 0) {\n                                    // new hash slot init\n                                    cityId = cityIdCounter++;\n                                    unsafe.setMemory(countsAddress + cityId * 8000, 8000, (byte) 0);\n                                    unsafe.putInt(hashAddress, cityId);\n                                    unsafe.putShort(hashAddress + 4, cityLength);\n                                    unsafe.putLong(hashAddress + 6, cityStart);\n                                    unsafe.putLong(hashAddress + 22, countsAddress + cityId * 8000);\n                                    break;\n                                }\n                                if (unsafe.getLong(hashAddress + 14) != 0) {\n                                    hashAddress = unsafe.getLong(hashAddress + 14);\n                                    continue;\n                                }\n                                break;\n                            }\n                            long cityNameAddress = unsafe.getLong(hashAddress + 6);\n                            int j;\n                            for (j = 0; j < cityLength >> 3 << 3; j += 8) {\n                                if (unsafe.getLong(cityStart + j) != unsafe.getLong(cityNameAddress + j)) {\n                                    if (unsafe.getLong(hashAddress + 14) != 0) {\n                                        hashAddress = unsafe.getLong(hashAddress + 14);\n                                        continue outer;\n                                    }\n                                    break outer;\n                                }\n                            }\n                            if (j < cityLength) {\n                                if ((unsafe.getLong(cityStart + j) << ((0x8 - cityLength & 0x7) << 3)) != (unsafe\n                                        .getLong(cityNameAddress + j) << ((0x8 - cityLength & 0x7) << 3))) {\n                                    if (unsafe.getLong(hashAddress + 14) != 0) {\n                                        hashAddress = unsafe.getLong(hashAddress + 14);\n                                        continue;\n                                    }\n                                    break;\n                                }\n                            }\n                            cityId = unsafe.getInt(hashAddress);\n                            break;\n                        }\n\n                        if (cityId == -1) {\n                            // collision\n                            cityId = cityIdCounter++;\n                            unsafe.setMemory(countsAddress + cityId * 8000, 8000, (byte) 0);\n                            unsafe.putLong(hashAddress + 14, nextCollisionAddress);\n                            hashAddress = nextCollisionAddress;\n                            nextCollisionAddress += 32;\n                            unsafe.putInt(hashAddress, cityId);\n                            unsafe.putShort(hashAddress + 4, cityLength);\n                            unsafe.putLong(hashAddress + 6, cityStart);\n                            unsafe.putLong(hashAddress + 22, countsAddress + cityId * 8000);\n                        }\n\n                        position++; // skip semicolon\n\n                        // long inputDecimalPoint = locateDecimalPoint(unsafe.getLong(position));\n                        // position += (Long.numberOfTrailingZeros(inputDecimalPoint) >> 3) + 3;\n\n                        temperature = 0;\n                        c = unsafe.getByte(position++);\n                        if (c == '-') {\n                            while ((c = unsafe.getByte(position++)) != '\\n') {\n                                if (c != '.') {\n                                    temperature = temperature * 10 + (c ^ 0x30);\n                                }\n                            }\n                            temperatureAddress = unsafe.getLong(hashAddress + 22) + (1000 + temperature) * 4;\n                            unsafe.putInt(temperatureAddress, unsafe.getInt(temperatureAddress) + 1);\n                        }\n                        else {\n                            temperature = c - '0';\n                            while ((c = unsafe.getByte(position++)) != '\\n') {\n                                if (c != '.') {\n                                    temperature = temperature * 10 + (c ^ 0x30);\n                                }\n                            }\n\n                            temperatureAddress = unsafe.getLong(hashAddress + 22) + temperature * 4;\n                            unsafe.putInt(temperatureAddress, unsafe.getInt(temperatureAddress) + 1);\n                        }\n                    }\n                    subCountResults[threadIndex] = new CountResult(cityHashTableAddress, countsAddress, cityIdCounter, nextCollisionAddress);\n                });\n            }\n\n            executorService.shutdown();\n            executorService.awaitTermination(120, java.util.concurrent.TimeUnit.SECONDS);\n\n            // aggregate results 1..n to 0\n            var subCountA = subCountResults[0];\n            for (int r = 1; r < numberOfThreads; r++) {\n                CountResult subCountB = subCountResults[r];\n                for (int i = 0; i < 65536; i++) {\n                    long bHashAddress = subCountB.cityHashTableAddress + ((long) i << 5);\n                    if (unsafe.getShort(bHashAddress + 4) == 0) {\n                        continue;\n                    }\n                    long aHashAddress = subCountA.cityHashTableAddress + ((long) i << 5);\n                    // check if a initialized\n                    if (unsafe.getShort(aHashAddress + 4) == 0) {\n                        // new hash slot init\n                        for (long addressA = aHashAddress, addressB = bHashAddress; addressB != 0;) {\n                            unsafe.putInt(addressA, subCountA.cityIdCounter++);\n                            unsafe.putShort(addressA + 4, unsafe.getShort(addressB + 4));\n                            unsafe.putLong(addressA + 6, unsafe.getLong(addressB + 6));\n                            addressB = unsafe.getLong(addressB + 14);\n                            if (addressB != 0) {\n                                unsafe.putLong(addressA + 14, subCountA.nextCollisionAddress);\n                                addressA = subCountA.nextCollisionAddress;\n                                subCountA.nextCollisionAddress += 32;\n                            }\n                        }\n                    }\n                    else {\n                        // check to copy collision list too\n                        outerB: for (long addressB = bHashAddress; addressB != 0; addressB = unsafe.getLong(addressB + 14)) {\n                            short cityLength = unsafe.getShort(addressB + 4);\n                            long cityNameAddress = unsafe.getLong(addressB + 6);\n                            // compare to each city in A slot\n                            outerA: for (long aAddress = aHashAddress; aAddress != 0; aAddress = unsafe.getLong(aAddress + 14)) {\n                                if (unsafe.getShort(aAddress + 4) == cityLength) {\n                                    long aCityNameAddress = unsafe.getLong(aAddress + 6);\n                                    int j;\n                                    for (j = 0; j < cityLength >> 3 << 3; j += 8) {\n                                        if (unsafe.getLong(cityNameAddress + j) != unsafe.getLong(aCityNameAddress + j)) {\n                                            // nope, not the same, try next\n                                            continue outerA;\n                                        }\n                                    }\n                                    if (j == cityLength ||\n                                            (unsafe.getLong(cityNameAddress + j) << ((0x8 - cityLength & 0x7) << 3)) == (unsafe\n                                                    .getLong(aCityNameAddress + j) << ((0x8 - cityLength & 0x7) << 3))) {\n                                        // found the same city, continue with next city in B slot\n                                        continue outerB;\n                                    }\n                                }\n                            }\n                            // city not found in A slot, add it. It's a collision too\n                            long addressA = aHashAddress;\n                            while (unsafe.getLong(addressA + 14) != 0) {\n                                addressA = unsafe.getLong(addressA + 14);\n                            }\n                            unsafe.putLong(addressA + 14, subCountA.nextCollisionAddress);\n                            addressA = subCountA.nextCollisionAddress;\n                            subCountA.nextCollisionAddress += 32;\n\n                            unsafe.putInt(addressA, subCountA.cityIdCounter++);\n                            unsafe.putShort(addressA + 4, cityLength);\n                            unsafe.putLong(addressA + 6, cityNameAddress);\n                        }\n                    }\n                }\n\n                int[] cityIdMap = new int[10000];\n                for (int i = 0; i < 10000; i++) {\n                    cityIdMap[i] = -1;\n                }\n\n                for (int i = 0; i < 65536; i++) {\n                    long bHashAddress = subCountB.cityHashTableAddress + ((long) i << 5);\n                    long aHashAddress = subCountA.cityHashTableAddress + ((long) i << 5);\n                    if (unsafe.getShort(aHashAddress + 4) == 0) {\n                        continue;\n                    }\n                    // for each city in A slot\n                    outerA: for (long aAddress = aHashAddress; aAddress != 0; aAddress = unsafe.getLong(aAddress + 14)) {\n                        short cityLength = unsafe.getShort(aAddress + 4);\n                        long cityNameAddress = unsafe.getLong(aAddress + 6);\n                        int cityIdA = unsafe.getInt(aAddress);\n                        // compare to each city in B slot\n                        outer: for (long bAddress = bHashAddress; bAddress != 0; bAddress = unsafe.getLong(bAddress + 14)) {\n                            if (unsafe.getShort(bAddress + 4) == cityLength) {\n                                long bCityNameAddress = unsafe.getLong(bAddress + 6);\n                                int j;\n                                for (j = 0; j < cityLength >> 3 << 3; j += 8) {\n                                    if (unsafe.getLong(cityNameAddress + j) != unsafe.getLong(bCityNameAddress + j)) {\n                                        // nope, not the same, try next\n                                        continue outer;\n                                    }\n                                }\n                                if (j == cityLength ||\n                                        (unsafe.getLong(cityNameAddress + j) << ((0x8 - cityLength & 0x7) << 3)) == (unsafe\n                                                .getLong(bCityNameAddress + j) << ((0x8 - cityLength & 0x7) << 3))) {\n                                    cityIdMap[cityIdA] = unsafe.getInt(bAddress);\n                                    // found the same city, continue with next city in A slot\n                                    continue outerA;\n                                }\n                            }\n                        }\n                    }\n                }\n\n                for (int i = 0; i < subCountA.cityIdCounter; i++) {\n                    int cityId2 = cityIdMap[i];\n                    if (cityId2 != -1) {\n                        for (int j = 0; j < 2; j++) {\n                            for (int k = 0; k < 1000; k++) {\n                                unsafe.putInt(subCountA.countsAddress + i * 8000 + j * 4000 + k * 4,\n                                        unsafe.getInt(subCountA.countsAddress + i * 8000 + j * 4000 + k * 4) +\n                                                unsafe.getInt(subCountB.countsAddress + cityId2 * 8000 + j * 4000 + k * 4));\n                            }\n                        }\n                    }\n                }\n            }\n\n            var countResult = subCountResults[0];\n            var reverseCityIds = new String[10000];\n            for (int i = 0; i < 65536; i++) {\n                long resultHashAddress = countResult.cityHashTableAddress + ((long) i << 5);\n                if (unsafe.getShort(resultHashAddress + 4) != 0) {\n                    for (long address = resultHashAddress; address != 0; address = unsafe.getLong(address + 14)) {\n                        int cityId = unsafe.getInt(address);\n                        int cityLength = unsafe.getShort(address + 4);\n                        long cityNameAddress = unsafe.getLong(address + 6);\n                        byte[] cityBytes = new byte[cityLength];\n                        unsafe.copyMemory(null, cityNameAddress, cityBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, cityLength);\n                        reverseCityIds[cityId] = new String(cityBytes, StandardCharsets.UTF_8);\n                    }\n                }\n            }\n\n            // count result as stream\n            IntStream.range(0, 10000).parallel().forEach(cityId -> {\n                var cityName = reverseCityIds[cityId];\n                if (cityName == null) {\n                    return;\n                }\n                var cityAddress = countResult.countsAddress + cityId * 8000;\n                var cityResult = new MeasurementAggregator();\n                for (int i = 999; i > -1; i--) {\n                    if (unsafe.getInt(cityAddress + 4000 + i * 4) > 0) {\n                        cityResult.min = -i;\n                        break;\n                    }\n                }\n                if (cityResult.min == -1000) {\n                    for (int i = 0; i < 1000; i++) {\n                        if (unsafe.getInt(cityAddress + i * 4) > 0) {\n                            cityResult.min = i;\n                            break;\n                        }\n                    }\n                }\n                for (int i = 999; i > -1; i--) {\n                    if (unsafe.getInt(cityAddress + i * 4) > 0) {\n                        cityResult.max = i;\n                        break;\n                    }\n                }\n                if (cityResult.max == 1000) {\n                    for (int i = 0; i < 1000; i++) {\n                        if (unsafe.getInt(cityAddress + 4000 + i * 4) > 0) {\n                            cityResult.max = -i;\n                            break;\n                        }\n                    }\n                }\n                for (int i = 0; i < 1000; i++) {\n                    cityResult.sum += ((long) unsafe.getInt(cityAddress + i * 4)) * i;\n                    cityResult.sum -= ((long) unsafe.getInt(cityAddress + 4000 + i * 4)) * i;\n                    cityResult.count += unsafe.getInt(cityAddress + i * 4);\n                    cityResult.count += unsafe.getInt(cityAddress + 4000 + i * 4);\n                }\n                synchronized (resultMap) {\n                    resultMap.put(cityName, cityResult);\n                }\n            });\n\n            System.out.println(resultMap);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_Ujjwalbharti.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream.Collector;\n\nimport static java.util.stream.Collectors.groupingBy;\n\npublic class CalculateAverage_Ujjwalbharti {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final List<Map<String, MeasurementAggregator>> results = new CopyOnWriteArrayList<>();\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    ;\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    private static class FileReaderCallable implements Callable<Void> {\n        private final Path filePath;\n        private final long startPos;\n        private final long endPos;\n\n        public FileReaderCallable(Path filePath, long startPos, long endPos) {\n            this.filePath = filePath;\n            this.startPos = startPos;\n            this.endPos = endPos;\n        }\n\n        @Override\n        public Void call() {\n\n            try (FileChannel channel = FileChannel.open(filePath, StandardOpenOption.READ)) {\n                channel.position(startPos);\n                ByteBuffer buffer = ByteBuffer.allocate((int) (endPos - startPos + 1));\n                channel.read(buffer);\n                String chunk = new String(buffer.array());\n                String[] chunkLines = chunk.split(\"\\n\");\n\n                Collector<Measurement, ?, MeasurementAggregator> collector = Collector.of(\n                        MeasurementAggregator::new,\n                        (a, m) -> {\n                            a.min = Math.min(a.min, m.value());\n                            a.max = Math.max(a.max, m.value());\n                            a.sum += m.value();\n                            a.count++;\n                        },\n                        (agg1, agg2) -> {\n                            var res = new MeasurementAggregator();\n                            res.min = Math.min(agg1.min, agg2.min);\n                            res.max = Math.max(agg1.max, agg2.max);\n                            res.sum = agg1.sum + agg2.sum;\n                            res.count = agg1.count + agg2.count;\n\n                            return res;\n                        });\n\n                Map<String, MeasurementAggregator> result = Arrays.stream(chunkLines)\n                        .map(line -> new Measurement(line.split(\";\")))\n                        .collect(groupingBy(Measurement::station, collector));\n\n                results.add(result);\n\n            }\n            catch (IOException e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n    }\n\n    private static long calculateEndPosition(Path path, long startPos, long chunkSize) throws IOException {\n        try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {\n            if (startPos >= channel.size()) {\n                return -1;\n            }\n\n            long currentPos = startPos + chunkSize;\n            if (currentPos >= channel.size()) {\n                currentPos = channel.size() - 1;\n            }\n\n            channel.position(currentPos);\n            ByteBuffer buffer = ByteBuffer.allocate(1024);\n            int readBytes = channel.read(buffer);\n\n            if (readBytes > 0) {\n                for (int i = 0; i < readBytes; i++) {\n                    if (buffer.get(i) == '\\n') {\n                        break;\n                    }\n                    currentPos++;\n                }\n            }\n\n            return currentPos;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        Path path = Paths.get(FILE);\n        long fileSize = Files.size(path);\n        long chunkSize = 1000 * 1000;\n        int nThread = (int) (fileSize / chunkSize);\n        var database = new HashMap<String, MeasurementAggregator>();\n        try (ExecutorService customExecutor = Executors.newFixedThreadPool(275)) {\n            var futures = new ArrayList<CompletableFuture<Void>>();\n            long startPos = 0;\n            for (int i = 0; i <= nThread; i++) {\n                long endPos = calculateEndPosition(path, startPos, chunkSize);\n                if (endPos == -1) {\n                    break;\n                }\n                long finalStartPos = startPos;\n                futures.add(CompletableFuture.runAsync(() -> new FileReaderCallable(path, finalStartPos, endPos).call(), customExecutor));\n                startPos = endPos + 1;\n            }\n            CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));\n            allOfFuture.get();\n        }\n        catch (Exception e) {\n            System.out.println(e.getMessage());\n        }\n\n        for (var map : results) {\n            for (String key : map.keySet()) {\n                if (database.containsKey(key)) {\n                    MeasurementAggregator mag1 = database.get(key);\n                    MeasurementAggregator mag2 = map.get(key);\n                    mag1.min = Math.min(mag1.min, mag2.min);\n                    mag1.max = Math.max(mag1.max, mag2.max);\n                    mag1.sum = mag1.sum + mag2.sum;\n                    mag1.count = mag1.count + mag2.count;\n                    database.put(key, mag1);\n                }\n                else {\n                    database.put(key, map.get(key));\n                }\n            }\n        }\n\n        var measurements = new TreeMap<String, ResultRow>();\n\n        for (String key : database.keySet()) {\n            MeasurementAggregator mag = database.get(key);\n            measurements.put(key, new ResultRow(mag.min, mag.sum / mag.count, mag.max));\n        }\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_YannMoisan.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\n/**\n * based on imrafaelmerino\n * ./calculate_average_imrafaelmerino.sh  129.10s user 4.73s system 1395% cpu 9.591 total\n *\n * ./calculate_average_baseline.sh  193.27s user 5.81s system 100% cpu 3:17.85 total\n *\n * addition to copied implementation\n * - use a Location object as a key in the Map to avoid String instantiations.\n * ./calculate_average_YannMoisan.sh  118.36s user 5.72s system 1425% cpu 8.705 total\n *\n *  Model Name: MacBook Pro\n *  Chip: Intel Core i9\n *  Total Number of Cores: 8\n *  Memory: 64 GB\n *  */\npublic class CalculateAverage_YannMoisan {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int FIELD_SIZE = 128;\n\n    public static void main(String[] args) throws IOException {\n        var chunkSize = 1024 * 1024 * 50L; // Long.parseLong(args[0].trim());\n        var result = calculateStats(FILE, chunkSize);\n        System.out.println(result);\n    }\n\n    private static Map<String, Stat> calculateStats(String file,\n                                                    long chunkSize)\n            throws IOException {\n\n        try (var fileChannel = FileChannel.open(Paths.get(file),\n                StandardOpenOption.READ)) {\n            var stats = fileMemoryStream(fileChannel, chunkSize)\n                    .parallel()\n                    .map(p -> ManagedComputation.compute(() -> parse(p)))\n                    .reduce(Collections.emptyMap(),\n                            (stat1, stat2) -> combine(stat1, stat2));\n\n            var tm = new TreeMap<String, Stat>();\n            stats.forEach((k, v) -> tm.put(new String(k.value, 0, k.value.length), v));\n            return tm;\n        }\n\n    }\n\n    private static Map<Location, Stat> combine(Map<Location, Stat> xs,\n                                               Map<Location, Stat> ys) {\n\n        Map<Location, Stat> result = new HashMap<>();\n\n        for (var key : xs.keySet()) {\n            var m1 = xs.get(key);\n            var m2 = ys.get(key);\n            var combined = (m2 == null) ? m1 : (m1 == null) ? m2 : Stat.combine(m1, m2);\n            result.put(key, combined);\n        }\n\n        for (var key : ys.keySet())\n            result.putIfAbsent(key, ys.get(key));\n        return result;\n\n    }\n\n    private static Map<Location, Stat> parse(ByteBuffer bb) {\n        Map<Location, Stat> stats = new HashMap<>();\n        var limit = bb.limit();\n        var field = new byte[FIELD_SIZE];\n        while (bb.position() < limit) {\n            var fieldCurrentIndex = 0;\n            field[fieldCurrentIndex++] = bb.get();\n            while (bb.position() < limit) {\n                var fieldByte = bb.get();\n                if (fieldByte == ';')\n                    break;\n                field[fieldCurrentIndex++] = fieldByte;\n            }\n            var fieldStr = new Location(Arrays.copyOfRange(field, 0, fieldCurrentIndex));\n            var number = 0;\n            var sign = 1;\n            while (bb.position() < limit) {\n                var numberByte = bb.get();\n                if (numberByte == '-')\n                    sign = -1;\n                else if (numberByte == '\\n')\n                    break;\n                else if (numberByte != '.')\n                    number = number * 10 + (numberByte - '0');\n            }\n            var v = stats.get(fieldStr);\n            if (v == null) {\n                var vv = new Stat();\n                vv.update(sign * number);\n                stats.put(fieldStr, vv);\n            }\n            else {\n                v.update(sign * number);\n            }\n        }\n\n        return stats;\n    }\n\n    private static Stream<ByteBuffer> fileMemoryStream(FileChannel fileChannel,\n                                                       long chunkSize)\n            throws IOException {\n\n        var spliterator = Spliterators.spliteratorUnknownSize(fileMemoryIterator(fileChannel,\n                chunkSize),\n                Spliterator.IMMUTABLE);\n        return StreamSupport.stream(spliterator,\n                false);\n    }\n\n    private static Iterator<ByteBuffer> fileMemoryIterator(FileChannel fileChannel, long chunkSize) throws IOException {\n        return new Iterator<>() {\n\n            private final long size = fileChannel.size();\n            private long start = 0;\n\n            @Override\n            public boolean hasNext() {\n                return start < size;\n            }\n\n            @Override\n            public ByteBuffer next() {\n                try {\n                    var buffer = fileChannel.map(MapMode.READ_ONLY,\n                            start,\n                            Math.min(chunkSize,\n                                    size - start));\n                    var limmit = buffer.limit() - 1;\n                    while (buffer.get(limmit) != '\\n')\n                        limmit--;\n                    limmit++;\n                    buffer.limit(limmit);\n                    start += limmit;\n                    return buffer;\n                }\n                catch (IOException ex) {\n                    throw new UncheckedIOException(ex);\n                }\n            }\n        };\n    }\n\n    private static final class Location {\n        public final byte[] value;\n\n        public Location(byte[] value) {\n            this.value = value;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n            Location location = (Location) o;\n            return Arrays.equals(value, location.value);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(value);\n        }\n    }\n\n    private static final class Stat {\n\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum = 0L;\n        private long count = 0L;\n\n        public static Stat combine(Stat m1,\n                                   Stat m2) {\n            var stat = new Stat();\n            stat.min = Math.min(m1.min, m2.min);\n            stat.max = Math.max(m1.max, m2.max);\n            stat.sum = m1.sum + m2.sum;\n            stat.count = m1.count + m2.count;\n            return stat;\n        }\n\n        private void update(int value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum += value;\n            this.count++;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round((sum / 10.0) / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static final class ManagedComputation {\n        static <T> T compute(final Supplier<T> supplier) {\n            var managedBlocker = new ManagedSupplier<>(supplier);\n            try {\n                ForkJoinPool.managedBlock(managedBlocker);\n                return managedBlocker.getResult();\n            }\n            catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new RuntimeException(e);\n            }\n\n        }\n\n        private static class ManagedSupplier<T> implements ForkJoinPool.ManagedBlocker {\n            private final Supplier<T> task;\n            private T result;\n            private boolean isDone = false;\n\n            private ManagedSupplier(final Supplier<T> supplier) {\n                task = supplier;\n            }\n\n            @Override\n            public boolean block() {\n                result = task.get();\n                isDone = true;\n                return true;\n            }\n\n            @Override\n            public boolean isReleasable() {\n                return isDone;\n            }\n\n            T getResult() {\n                return result;\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_abeobk.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.TreeMap;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\nimport java.util.stream.IntStream;\n\nimport sun.misc.Unsafe;\n\npublic class CalculateAverage_abeobk {\n    private static final int CPU_CNT = Runtime.getRuntime().availableProcessors();\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int BUCKET_SIZE = 1 << 16;\n    private static final long BUCKET_MASK = BUCKET_SIZE - 1;\n    private static final int MAX_STR_LEN = 100;\n    private static final int MAX_STATIONS = 10000;\n    private static final long CHUNK_SZ = 1 << 22;\n    private static final Unsafe UNSAFE = initUnsafe();\n    private static final long[] HASH_MASKS = new long[]{\n            0x0L,\n            0xffL,\n            0xffffL,\n            0xffffffL,\n            0xffffffffL,\n            0xffffffffffL,\n            0xffffffffffffL,\n            0xffffffffffffffL,\n            0xffffffffffffffffL, };\n\n    private static AtomicInteger chunk_id = new AtomicInteger(0);\n    private static AtomicReference<Node[]> mapref = new AtomicReference<>(null);\n    private static int chunk_cnt;\n    private static long start_addr, end_addr;\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (Exception ex) {\n            throw new RuntimeException();\n        }\n    }\n\n    /*\n     * MAIN FUNCTION\n     */\n    public static void main(String[] args) throws InterruptedException, IOException {\n        // thomaswue trick\n        if (args.length == 0 || !(\"--worker\".equals(args[0]))) {\n            spawnWorker();\n            return;\n        }\n\n        var file = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n        long file_size = file.size();\n        start_addr = file.map(MapMode.READ_ONLY, 0, file.size(), Arena.global()).address();\n        end_addr = start_addr + file_size;\n\n        // only use all cpus on large file\n        int cpu_cnt = file_size < 1e6 ? 1 : CPU_CNT;\n        chunk_cnt = (int) Math.ceilDiv(file_size, CHUNK_SZ);\n\n        // spawn workers\n        for (var w : IntStream.range(0, cpu_cnt).mapToObj(i -> new Worker(i)).toList()) {\n            w.join();\n        }\n\n        // collect results\n        TreeMap<String, Node> ms = new TreeMap<>();\n        for (var crr : mapref.get()) {\n            if (crr == null)\n                continue;\n            var prev = ms.putIfAbsent(crr.key(), crr);\n            if (prev != null)\n                prev.merge(crr);\n        }\n        // print result\n        System.out.println(ms);\n        System.out.close();\n    }\n\n    /*\n     * HELPER FUNCTIONS\n     */\n\n    // Get semicolon pos code\n    static final long getSemiCode(final long w) {\n        long x = w ^ 0x3b3b3b3b3b3b3b3bL; // xor with ;;;;;;;;\n        return (x - 0x0101010101010101L) & (~x & 0x8080808080808080L);\n    }\n\n    // Get new line pos code\n    static final long getLFCode(final long w) {\n        long x = w ^ 0x0A0A0A0A0A0A0A0AL; // xor with \\n\\n\\n\\n\\n\\n\\n\\n\n        return (x - 0x0101010101010101L) & (~x & 0x8080808080808080L);\n    }\n\n    // Get decimal point pos code\n    static final int getDotCode(final long w) {\n        return Long.numberOfTrailingZeros(~w & 0x10101000);\n    }\n\n    // Convert semicolon pos code to position\n    static final int getSemiPos(final long spc) {\n        return Long.numberOfTrailingZeros(spc) >>> 3;\n    }\n\n    // Find next line address\n    static final long nextLF(long addr) {\n        long word = UNSAFE.getLong(addr);\n        long lfpos_code = getLFCode(word);\n        while (lfpos_code == 0) {\n            addr += 8;\n            word = UNSAFE.getLong(addr);\n            lfpos_code = getLFCode(word);\n        }\n        return addr + (Long.numberOfTrailingZeros(lfpos_code) >>> 3) + 1;\n    }\n\n    // Parse number\n    // great idea from merykitty (Quan Anh Mai)\n    static final long num(long w, int d) {\n        int shift = 28 - d;\n        long signed = (~w << 59) >> 63;\n        long dsmask = ~(signed & 0xFF);\n        long digits = ((w & dsmask) << shift) & 0x0F000F0F00L;\n        long abs_val = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        return ((abs_val ^ signed) - signed);\n    }\n\n    // Hash mixer\n    static final long mix(long hash) {\n        long h = hash * 37;\n        return (h ^ (h >>> 29));\n    }\n\n    // Spawn worker (thomaswue trick\n    private static void spawnWorker() throws IOException {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> workerCommand = new ArrayList<>();\n        info.command().ifPresent(workerCommand::add);\n        info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args)));\n        workerCommand.add(\"--worker\");\n        new ProcessBuilder()\n                .command(workerCommand)\n                .start()\n                .getInputStream()\n                .transferTo(System.out);\n    }\n\n    final static class Node {\n        long addr;\n        long hash;\n        long word0;\n        long sum;\n        long min, max;\n        int keylen;\n        int count;\n\n        public final String toString() {\n            return (min / 10.0) + \"/\"\n                    + (Math.round(((double) sum / count)) / 10.0) + \"/\"\n                    + (max / 10.0);\n        }\n\n        final String key() {\n            byte[] sbuf = new byte[MAX_STR_LEN];\n            UNSAFE.copyMemory(null, addr, sbuf, Unsafe.ARRAY_BYTE_BASE_OFFSET, keylen);\n            return new String(sbuf, 0, (int) keylen, StandardCharsets.UTF_8);\n        }\n\n        Node(long a, long h, int kl, long v) {\n            addr = a;\n            min = max = v;\n            keylen = kl;\n            hash = h;\n        }\n\n        Node(long a, long h, int kl) {\n            addr = a;\n            hash = h;\n            min = 999;\n            max = -999;\n            keylen = kl;\n        }\n\n        Node(long a, long w0, long h, int kl, long v) {\n            addr = a;\n            word0 = w0;\n            hash = h;\n            min = max = v;\n            keylen = kl;\n        }\n\n        Node(long a, long w0, long h, int kl) {\n            addr = a;\n            word0 = w0;\n            hash = h;\n            min = 999;\n            max = -999;\n            keylen = kl;\n        }\n\n        final void add(long val) {\n            sum += val;\n            count++;\n            if (val > max) {\n                max = val;\n            }\n            if (val < min) {\n                min = val;\n            }\n        }\n\n        final void merge(Node other) {\n            sum += other.sum;\n            count += other.count;\n            if (other.max > max) {\n                max = other.max;\n            }\n            if (other.min < min) {\n                min = other.min;\n            }\n        }\n\n        final boolean contentEquals(long other_addr, long other_word0, long other_hash, long kl) {\n            if (word0 != other_word0 || hash != other_hash)\n                return false;\n            // this is faster than comparision if key is short\n            long xsum = 0;\n            long n = kl & 0xF8;\n            for (long i = 8; i < n; i += 8) {\n                xsum |= (UNSAFE.getLong(addr + i) ^ UNSAFE.getLong(other_addr + i));\n            }\n            return xsum == 0;\n        }\n\n        final boolean contentEquals(Node other) {\n            if (hash != other.hash)\n                return false;\n            long n = keylen & 0xF8;\n            for (long i = 0; i < n; i += 8) {\n                if (UNSAFE.getLong(addr + i) != UNSAFE.getLong(other.addr + i))\n                    return false;\n            }\n            return true;\n        }\n    }\n\n    // Thread pool worker\n    static final class Worker extends Thread {\n        final int thread_id; // for debug use only\n\n        Worker(int i) {\n            thread_id = i;\n            this.setPriority(Thread.MAX_PRIORITY);\n            this.start();\n        }\n\n        @Override\n        public void run() {\n            var map = new Node[BUCKET_SIZE + MAX_STATIONS]; // extra space for collisions\n\n            int id;\n            // process in small chunk to maintain disk locality (artsiomkorzun trick)\n            while ((id = chunk_id.getAndIncrement()) < chunk_cnt) {\n                long addr = start_addr + id * CHUNK_SZ;\n                long end = Math.min(addr + CHUNK_SZ, end_addr);\n\n                // find start of line\n                if (id > 0) {\n                    addr = nextLF(addr);\n                }\n\n                final int num_segs = 3;\n                long seglen = (end - addr) / num_segs;\n\n                long a0 = addr;\n                long a1 = nextLF(addr + 1 * seglen);\n                long a2 = nextLF(addr + 2 * seglen);\n                ChunkParser p0 = new ChunkParser(map, a0, a1);\n                ChunkParser p1 = new ChunkParser(map, a1, a2);\n                ChunkParser p2 = new ChunkParser(map, a2, end);\n\n                while (p0.ok() && p1.ok() && p2.ok()) {\n                    long w0 = p0.word();\n                    long w1 = p1.word();\n                    long w2 = p2.word();\n                    long sc0 = getSemiCode(w0);\n                    long sc1 = getSemiCode(w1);\n                    long sc2 = getSemiCode(w2);\n                    Node n0 = p0.key(w0, sc0);\n                    Node n1 = p1.key(w1, sc1);\n                    Node n2 = p2.key(w2, sc2);\n                    long v0 = p0.val();\n                    long v1 = p1.val();\n                    long v2 = p2.val();\n                    n0.add(v0);\n                    n1.add(v1);\n                    n2.add(v2);\n                }\n\n                while (p0.ok()) {\n                    long w = p0.word();\n                    long sc = getSemiCode(w);\n                    Node n = p0.key(w, sc);\n                    long v = p0.val();\n                    n.add(v);\n                }\n                while (p1.ok()) {\n                    long w = p1.word();\n                    long sc = getSemiCode(w);\n                    Node n = p1.key(w, sc);\n                    long v = p1.val();\n                    n.add(v);\n                }\n                while (p2.ok()) {\n                    long w = p2.word();\n                    long sc = getSemiCode(w);\n                    Node n = p2.key(w, sc);\n                    long v = p2.val();\n                    n.add(v);\n                }\n            }\n\n            // merge is cheaper than string casting (artsiomkorzun)\n            while (!mapref.compareAndSet(null, map)) {\n                var other_map = mapref.getAndSet(null);\n                if (other_map != null) {\n                    for (int i = 0; i < other_map.length; i++) {\n                        var other = other_map[i];\n                        if (other == null)\n                            continue;\n                        int bucket = (int) (other.hash & BUCKET_MASK);\n                        while (true) {\n                            var node = map[bucket];\n                            if (node == null) {\n                                map[bucket] = other;\n                                break;\n                            }\n                            if (node.contentEquals(other)) {\n                                node.merge(other);\n                                break;\n                            }\n                            bucket++;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    static final class ChunkParser {\n        long addr;\n        long end;\n        Node[] map;\n\n        ChunkParser(Node[] m, long a, long e) {\n            map = m;\n            addr = a;\n            end = e;\n        }\n\n        final boolean ok() {\n            return addr < end;\n        }\n\n        final long word() {\n            return UNSAFE.getLong(addr);\n        }\n\n        final void skip(int n) {\n            addr += n;\n        }\n\n        final void skip(long n) {\n            addr += n;\n        }\n\n        final long val0() {\n            long w = word();\n            int d = getDotCode(w);\n            return num(w, d);\n        }\n\n        final long val() {\n            long w = word();\n            int d = getDotCode(w);\n            skip((d >>> 3) + 3);\n            return num(w, d);\n        }\n\n        // optimize for contest\n        // save as much slow memory access as possible\n        // about 50% key < 8chars, 25% key bettween 8-10 chars\n        // keylength histogram (%) = [0, 0, 0, 0, 4, 10, 21, 15, 13, 11, 6, 6, 4, 2...\n        final Node key(long word0, long semipos_code) {\n            long row_addr = addr;\n            // about 50% chance key < 8 chars\n            if (semipos_code != 0) {\n                int semi_pos = Long.numberOfTrailingZeros(semipos_code) >>> 3;\n                skip(semi_pos + 1);\n                long tail = word0 & HASH_MASKS[semi_pos];\n                long hash = mix(tail);\n                int bucket = (int) (hash & BUCKET_MASK);\n                while (true) {\n                    Node node = map[bucket];\n                    if (node == null) {\n                        return (map[bucket] = new Node(row_addr, hash, semi_pos));\n                    }\n                    if (node.hash == hash) {\n                        return node;\n                    }\n                    bucket++;\n                }\n            }\n\n            skip(8);\n            long word = UNSAFE.getLong(addr);\n            semipos_code = getSemiCode(word);\n            // 43% chance\n            if (semipos_code != 0) {\n                int semi_pos = Long.numberOfTrailingZeros(semipos_code) >>> 3;\n                skip(semi_pos + 1);\n                long tail = word0 ^ (word & HASH_MASKS[semi_pos]);\n                long hash = mix(tail);\n                int bucket = (int) (hash & BUCKET_MASK);\n                while (true) {\n                    Node node = map[bucket];\n                    if (node == null) {\n                        return (map[bucket] = new Node(row_addr, word0, hash, semi_pos + 8));\n                    }\n                    if (node.word0 == word0 && node.hash == hash) {\n                        return node;\n                    }\n                    bucket++;\n                }\n            }\n\n            // why not going for more? tested, slower\n            long hash = word0;\n            while (semipos_code == 0) {\n                hash ^= word;\n                skip(8);\n                word = UNSAFE.getLong(addr);\n                semipos_code = getSemiCode(word);\n            }\n\n            int semi_pos = Long.numberOfTrailingZeros(semipos_code) >>> 3;\n            skip(semi_pos);\n            long keylen = addr - row_addr;\n            skip(1);\n            long tail = hash ^ (word & HASH_MASKS[semi_pos]);\n            hash = mix(tail);\n            int bucket = (int) (hash & BUCKET_MASK);\n\n            while (true) {\n                Node node = map[bucket];\n                if (node == null) {\n                    return (map[bucket] = new Node(row_addr, word0, hash, (int) keylen));\n                }\n                if (node.contentEquals(row_addr, word0, hash, keylen)) {\n                    return node;\n                }\n                bucket++;\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_abfrmblr.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.util.concurrent.*;\nimport java.util.stream.Stream;\n\nimport static java.nio.file.Files.lines;\nimport static java.nio.file.Paths.*;\n\npublic class CalculateAverage_abfrmblr {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Stats (double min, double max, double mean, long count) {\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static record MeasurementTuple (String station, double temp) {\n        public MeasurementTuple (String[] values) {\n            this(values[0], Double.parseDouble(values[1]));\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        Stream<String> lines = lines(get(FILE));\n\n        ConcurrentMap<String, Stats> aggregatedStats = new ConcurrentSkipListMap<>();\n\n        lines.parallel().forEach(s -> {\n            MeasurementTuple tuple = new MeasurementTuple(s.split(\";\"));\n            aggregatedStats.compute(tuple.station(), (s1, stats) -> {\n                if (stats == null) {\n                    return new Stats(tuple.temp, tuple.temp, tuple.temp, 1L);\n                }\n                else {\n                    long latestCount = stats.count + 1;\n                    double min = Math.min(stats.min, tuple.temp);\n                    double max = Math.max(stats.max, tuple.temp);\n                    double mean = ((stats.mean * stats.count) + tuple.temp) / latestCount;\n                    return new Stats(min, max, mean, latestCount);\n                }\n            });\n        });\n\n        System.out.println(aggregatedStats);\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_adriacabeza.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\n/**\n * This class calculates average measurements from a file in a parallelized manner.\n */\npublic class CalculateAverage_adriacabeza {\n\n    private static final Path FILE_PATH = Paths.get(\"./measurements.txt\");\n    public static final int CITY_NAME_MAX_CHARACTERS = 128;\n    private static final int N_PROCESSORS = Runtime.getRuntime().availableProcessors();\n    private static final int DJB2_INIT = 5381;\n    private static final Map<Integer, String> cityMap = new ConcurrentHashMap<>(10_000, 1, N_PROCESSORS);\n\n    /**\n     * Represents result containing a HashMap with city as key and ResultRow as value.\n     */\n    private static class Result {\n        public void addStation(int hash, int value) {\n            resultMap.put(hash, new StationData(value));\n        }\n\n        public StationData getData(int hash) {\n            return resultMap.get(hash);\n        }\n\n        private static class StationData {\n            private int min, sum, count, max;\n\n            public StationData(int value) {\n                this.count = 1;\n                this.sum = value;\n                this.min = value;\n                this.max = value;\n            }\n\n            public void update(int value) {\n                this.count++;\n                this.sum += value;\n                this.min = Math.min(this.min, value);\n                this.max = Math.max(this.max, value);\n            }\n\n            public String toString() {\n                return \"%.1f/%.1f/%.1f\".formatted(min / 10.0, sum / 10.0 / count, max / 10.0);\n            }\n\n        }\n\n        private final Map<Integer, StationData> resultMap;\n\n        public Result() {\n            this.resultMap = new HashMap<>(10_000, 1);\n        }\n\n        public Map<Integer, StationData> getResultMap() {\n            return resultMap;\n        }\n\n        public void merge(Result other) {\n            other.getResultMap().forEach((city, resultRow) -> resultMap.merge(city, resultRow, (existing, incoming) -> {\n                existing.min = Math.min(existing.min, incoming.min);\n                existing.max = Math.max(existing.max, incoming.max);\n                existing.sum += incoming.sum;\n                existing.count += incoming.count;\n                return existing;\n            }));\n        }\n\n        public String toString() {\n            return this.resultMap.entrySet().parallelStream()\n                    .map(entry -> \"%s=%s\".formatted(cityMap.get(entry.getKey()), entry.getValue()))\n                    .sorted(Comparator.comparing(s -> s.split(\"=\")[0]))\n                    .collect(Collectors.joining(\", \", \"{\", \"}\"));\n        }\n    }\n\n    /**\n     * Finds the ending position in the file, ensuring it ends at the beginning of a line.\n     *\n     * @param channel  File channel\n     * @param position Current position in the file\n     * @return Ending position at the beginning of a line\n     * @throws IOException If an I/O error occurs\n     */\n    private static long findEndPosition(FileChannel channel, long position) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(1);\n\n        // Iterate over the file from the given position to find the next newline character\n        while (position < channel.size()) {\n            channel.read(buffer, position);\n\n            // Check if the current byte is a newline character\n            if (buffer.get(0) == '\\n') {\n                return position + 1; // Return the position immediately after the newline\n            }\n\n            position++;\n            buffer.clear();\n        }\n\n        return channel.size(); // Return the end of the file if no newline is found after the current position\n    }\n\n    /**\n     * Gets the mapped byte buffers for parallel processing.\n     *\n     * @param nProcessors Number of processors for parallelization\n     * @return List of MappedByteBuffers\n     * @throws IOException If an I/O error occurs\n     */\n    private static List<MappedByteBuffer> getMappedByteBuffers(int nProcessors) throws IOException {\n        try (FileChannel channel = FileChannel.open(FILE_PATH, StandardOpenOption.READ)) {\n            long fileSize = channel.size();\n            long chunkSize = (fileSize + nProcessors - 1) / nProcessors;\n            long pos = 0;\n\n            List<MappedByteBuffer> buffers = new ArrayList<>(nProcessors);\n            for (int i = 0; i < nProcessors; i++) {\n                long endPosition = findEndPosition(channel, pos + chunkSize);\n                long size = endPosition - pos;\n                MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, pos, size);\n                pos = pos + size;\n                buffers.add(buffer);\n            }\n            return buffers;\n        }\n    }\n\n    private static int readNumberFromBuffer(ByteBuffer buffer, int limit) {\n        var number = 0;\n        var sign = 1;\n        while (buffer.position() < limit) {\n            var numberByte = buffer.get();\n            if (numberByte == '-')\n                sign = -1;\n            else if (numberByte == '\\n')\n                break;\n            else if (numberByte != '.')\n                number = number * 10 + (numberByte - '0');\n        }\n        return sign * number;\n    }\n\n    /**\n     * Calculates average measurements from the file.\n     *\n     * @return Result containing min/mean/max values for each city\n     */\n    private static Result calculateAverageMeasurements(List<MappedByteBuffer> chunks) {\n        // Process each buffer in parallel\n        return chunks.parallelStream()\n                .map(buffer -> {\n                    Result partialResult = new Result();\n                    var limit = buffer.limit();\n                    var field = new byte[CITY_NAME_MAX_CHARACTERS];\n                    Set<Integer> seenHashes = new HashSet<>(10_000, 1);\n                    while (buffer.position() < limit) {\n                        var fieldCurrentIndex = 0;\n                        var fieldByte = buffer.get();\n                        field[fieldCurrentIndex++] = fieldByte;\n                        // implement djb2 hash: https://theartincode.stanis.me/008-djb2/\n                        int hash = DJB2_INIT;\n                        while (buffer.position() < limit) {\n                            // hash = hash * 33 + fieldByte\n                            hash = (((hash << 5) + hash) + fieldByte);\n                            fieldByte = buffer.get();\n                            if (fieldByte == ';')\n                                break;\n                            field[fieldCurrentIndex++] = fieldByte;\n                        }\n\n                        var number = readNumberFromBuffer(buffer, limit);\n                        if (!seenHashes.contains(hash)) {\n                            seenHashes.add(hash);\n                            cityMap.put(hash, new String(field, 0, fieldCurrentIndex));\n                            partialResult.addStation(hash, number);\n                        }\n                        else {\n                            partialResult.getData(hash).update(number);\n                        }\n                    }\n                    return partialResult;\n                }).reduce(new Result(), (partialResult1, partialResult2) -> {\n                    Result result = new Result();\n                    result.merge(partialResult1);\n                    result.merge(partialResult2);\n                    return result;\n                });\n    }\n\n    /**\n     * The main method to run the average measurements calculations program.\n     *\n     * @param args Command line arguments. Not utilized in this program.\n     */\n    public static void main(String[] args) {\n        try {\n            // Get the MappedByteBuffers by splitting the file evenly across available processors\n            var buffers = getMappedByteBuffers(Runtime.getRuntime().availableProcessors());\n\n            // Calculate the average measurements from the buffers obtained\n            var measurements = calculateAverageMeasurements(buffers);\n\n            // Print the measurements result to the console.\n            System.out.println(measurements);\n\n        } catch (IOException e) {\n            // Handle any potential I/O exceptions by printing the error message to the console\n            System.err.println(STR.\"Error processing file: \\{e.getMessage()}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_agoncal.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\n\n/**\n * This is the solution from GitHut Copilot Chat with the help of Antonio Goncalves (prompting and guiding, but trying not to change code directly on my own, always using Copilot).\n * <p>\n * List of prompts that has been used:\n * <p>\n * =============\n * =============\n * =============\n * v1 - 73603 ms\n * You are entering The One Billion Row Challenge (1BRC) which is an exploration of how far modern Java can be pushed for aggregating one billion rows from a text file. Grab all the (virtual) threads, reach out to SIMD, optimize the GC, or pull any other trick, and create the fastest implementation for solving this task!\n * The text file contains temperature values for a range of weather stations. Each row is one measurement in the format <string: station name>;<double: measurement>, with the measurement value having exactly one fractional digit. The following delimited with --- shows ten rows as an example:\n * ---\n * Hamburg;12.0\n * Bulawayo;8.9\n * Palembang;38.8\n * St. John's;15.2\n * Cracow;12.6\n * Bridgetown;26.9\n * Istanbul;6.2\n * Roseau;34.4\n * Conakry;31.2\n * Istanbul;23.0\n * ---\n * You have to write a Java program which reads the file, calculates the min, mean, and max temperature value per weather station, and emits the results on stdout like the result below delimited by --- (i.e. sorted alphabetically by station name, and the result values per station in the format <min>/<mean>/<max>, rounded to one fractional digit). Notice the curly braces:\n * ---\n * {Abha=-23.0/18.0/59.2, Abidjan=-16.2/26.0/67.3, Abéché=-10.0/29.4/69.0, Accra=-10.1/26.4/66.4, Addis Ababa=-23.7/16.0/67.0, Adelaide=-27.8/17.3/58.5, ...}\n * ---\n * You must use Java 21.\n * Create an algorithm in any way you see fit including parallelizing the computation, using the (incubating) Vector API, memory-mapping different sections of the file concurrently, using AppCDS, GraalVM, CRaC, etc. for speeding up the application start-up, choosing and tuning the garbage collector, and much more.\n * No external library dependencies may be used.\n * =============\n * =============\n * =============\n * (Here I had to chat with Copilot about formatting the output, there were commas missing, the curly brackets were also missed)\n * =============\n * =============\n * =============\n * v2 - 71831 ms\n * Being written in Java 21, please use records instead of classes for Measurement.\n * =============\n * =============\n * =============\n * v3 - 69333 ms\n * If the temperatures are small numbers, why use double? Can't you use another datatype ?\n * <p>\n * The profiler mentions that this line of code has very bad performance. Can you refactor it so it has better performance:\n * ---\n * String[] parts = line.split(\";\")\n * ---\n * <p>\n * There is a maximum of 10000 unique station names. Can you optimize the code taking this into account?\n * =============\n * =============\n * =============\n * v4 - 56417 ms\n * Which parameters can I pass to the JVM to make it run faster ?\n * Which GC can I use and what is the most optimized to run CalculateAverage ?\n */\npublic class CalculateAverage_agoncal {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    record Measurement(String station, double temperature) {\n    }\n\n    static class StationStats {\n        double min;\n        double max;\n        double sum;\n        int count;\n\n        public StationStats(double temperature) {\n            this.min = temperature;\n            this.max = temperature;\n            this.sum = 0;\n            this.count = 0;\n        }\n\n        synchronized void update(double temperature) {\n            min = Math.min(min, temperature);\n            max = Math.max(max, temperature);\n            sum += temperature;\n            count++;\n        }\n\n        double getAverage() {\n            return round(sum) / count;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"%.1f/%.1f/%.1f\", round(min), round(getAverage()), round(max));\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        Map<String, StationStats> stats = new ConcurrentHashMap<>(10_000);\n        try (BufferedReader reader = Files.newBufferedReader(Paths.get(FILE))) {\n            reader.lines().parallel().forEach(line -> {\n                int separatorIndex = line.indexOf(';');\n                String station = line.substring(0, separatorIndex);\n                String temperature = line.substring(separatorIndex + 1);\n                Measurement m = new Measurement(station, Double.parseDouble(temperature));\n                stats.computeIfAbsent(m.station, k -> new StationStats(m.temperature)).update(m.temperature);\n            });\n        }\n\n        TreeMap<String, StationStats> sortedStats = new TreeMap<>(stats);\n        Iterator<Map.Entry<String, StationStats>> iterator = sortedStats.entrySet().iterator();\n        System.out.print(\"{\");\n        while (iterator.hasNext()) {\n            Map.Entry<String, StationStats> entry = iterator.next();\n            StationStats s = entry.getValue();\n            if (iterator.hasNext()) {\n                System.out.printf(\"%s=%s, \", entry.getKey(), s.toString());\n            }\n            else {\n                System.out.printf(\"%s=%s\", entry.getKey(), s.toString());\n            }\n        }\n        System.out.println(\"}\");\n    }\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ags313.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Field;\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.nio.channels.FileChannel;\nimport java.util.HashMap;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_ags313 {\n\n    private static final int THREAD_COUNT = 8;\n    private static final int FUTURE_BUFFER = 1024;\n    private static final int ALLOCATION = 128 * 1024 * 1024;\n\n    // private static final String FILE = \"./measurementsCut.txt\";\n    private static final String FILE = \"./measurements.txt\";\n    // private static final String FILE = \"./src/test/resources/samples/measurements-1.txt\";\n    // private static final String FILE = \"./src/test/resources/samples/measurements-20.txt\";\n\n    private static final int NAME_LENGTH_LIMIT_BYTES = 128;\n    private static final int BUFFER_SIZE = 108;\n    private static final ExecutorService exec = Executors.newFixedThreadPool(THREAD_COUNT);\n\n    /**\n     *  1B rows\n     *  8s  multithreaded\n     *  44s single threaded\n     *\n     *  ideas:\n     *  1) replace hashmap with something faster(er)\n     *  2) play with graal\n     **/\n\n    private static class Key implements Comparable<Key> {\n        private final byte[] value = new byte[NAME_LENGTH_LIMIT_BYTES];\n        private int hashCode;\n        private int length = 0;\n\n        // https://stackoverflow.com/questions/20952739/how-would-you-convert-a-string-to-a-64-bit-integer\n        public void accept(byte b) {\n            value[length] = b;\n            length += 1;\n            hashCode = hashCode * 10191 + b;\n        }\n\n        @Override\n        public boolean equals(Object that) {\n            if (this == that)\n                return true;\n            if (that == null)\n                return false;\n            Key key = (Key) that; // not checking class, nothing else uses this\n            if (hashCode != key.hashCode)\n                return false;\n            if (length != key.length)\n                return false;\n            for (int i = 0; i < length; i++) {\n                if (UNSAFE.getByte(value, i) != UNSAFE.getByte(key.value, i)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        @Override\n        public int hashCode() {\n            return hashCode;\n        }\n\n        @Override\n        public String toString() {\n            return new String(value, 0, length);\n        }\n\n        void reset() {\n            length = 0;\n            hashCode = 0;\n        }\n\n        @Override\n        public int compareTo(Key other) {\n            return toString().compareTo(other.toString());\n        }\n    }\n\n    private static HashMap<Key, Stats> readChunk(FileChannel from, long start, int bytesToRead) throws IOException {\n        HashMap<Key, Stats> result = new HashMap<>(1024 * 16);\n\n        var bbuffer = from.map(FileChannel.MapMode.READ_ONLY, start, bytesToRead);\n\n        var key = new Key();\n        while (bbuffer.remaining() > 1) {\n            key.reset();\n            boolean negative = false;\n            var temperature = 0;\n\n            while (bbuffer.remaining() > 0) {\n                byte b = bbuffer.get();\n                if (b == ';') {\n                    break;\n                }\n                key.accept(b);\n            }\n\n            loop2: while (bbuffer.remaining() > 0) {\n                byte b = bbuffer.get();\n                switch (b) {\n                    case '-':\n                        negative = true;\n                        break;\n                    case '.':\n                        temperature = (temperature * 10) + (bbuffer.get() - '0'); // single decimal\n                        break;\n                    case '\\n':\n                        break loop2;\n                    default:\n                        temperature = (temperature * 10) + (b - '0');\n                }\n            }\n\n            int measure = negative ? -temperature : temperature;\n            Stats stats = result.computeIfAbsent(key, c -> new Stats());\n            if (stats.count == 0) {\n                key = new Key();\n            }\n\n            stats.count++;\n            stats.total += measure;\n            if (measure < stats.min) {\n                stats.min = measure;\n            }\n            if (measure > stats.max) {\n                stats.max = measure;\n            }\n        }\n\n        return result;\n    }\n\n    public static void main(String[] args) throws Exception {\n        var channel = new RandomAccessFile(FILE, \"r\").getChannel();\n        long totalToRead = channel.size();\n\n        Future<HashMap<Key, Stats>>[] futures = new Future[FUTURE_BUFFER];\n\n        long allocated = 0;\n        int chunkCounter = 0;\n        while (allocated < totalToRead) {\n            var start = allocated;\n            var bytesToReadInPass = Math.min(totalToRead - allocated, ALLOCATION);\n\n            if (bytesToReadInPass < BUFFER_SIZE) {\n                // System.out.println(\"Want to read: \" + bytesToReadInPass + \", starting buffer at: \" + startBufferAt);\n                // System.out.println(\"Total: \" + totalToRead + \", allocated: \" + allocated + \", allocating: \" + (correctedBytesToRead));\n                futures[chunkCounter++] = exec.submit(() -> readChunk(channel, start, (int) bytesToReadInPass));\n                allocated += bytesToReadInPass;\n            }\n            else {\n                var startBufferAt = Math.max(0, allocated + bytesToReadInPass - BUFFER_SIZE);\n                var buffer = channel.map(FileChannel.MapMode.READ_ONLY, startBufferAt, BUFFER_SIZE);\n\n                // System.out.println(\"Want to read: \" + bytesToReadInPass + \", starting buffer at: \" + startBufferAt);\n\n                var endOfLine = 0;\n                for (int i = 0; i < BUFFER_SIZE; i++) {\n                    if (buffer.get() == '\\n') {\n                        endOfLine = i;\n                        break;\n                    }\n                }\n                long correctedBytesToRead = bytesToReadInPass - BUFFER_SIZE + endOfLine;\n\n                // System.out.println(\"Total: \" + totalToRead + \", allocated: \" + allocated + \", allocating: \" + (correctedBytesToRead));\n                futures[chunkCounter++] = exec.submit(() -> readChunk(channel, start, (int) correctedBytesToRead));\n                allocated += correctedBytesToRead + 1;\n            }\n        }\n\n        var accumulator = new HashMap<Key, Stats>(1024 * 16);\n        for (int i = 0; i < chunkCounter; i++) {\n            var aMap = futures[i].get();\n            aMap.forEach((key, value) -> accumulator.computeIfAbsent(key, __ -> new Stats()).merge(value));\n        }\n\n        exec.shutdown();\n\n        System.out.println(new TreeMap(accumulator));\n    }\n\n    static class Stats {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long total;\n        private int count;\n\n        Stats() {\n        }\n\n        @Override\n        public String toString() {\n            return BigDecimal.valueOf(min / (10.0)).setScale(1, RoundingMode.HALF_UP) + \"/\"\n                    + BigDecimal.valueOf(total / (10.0 * count)).setScale(1, RoundingMode.HALF_UP) + '/'\n                    + BigDecimal.valueOf(max / (10.0)).setScale(1, RoundingMode.HALF_UP);\n        }\n\n        void merge(Stats that) {\n            max = Math.max(this.max, that.max);\n            min = Math.min(this.min, that.min);\n            total += that.total;\n            count += that.count;\n        }\n    }\n\n    private static final Unsafe UNSAFE = unsafe();\n\n    private static Unsafe unsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_albertoventurini.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\n/**\n * == File reading ==\n * The file is read using RandomAccessFile, and split into chunks. Each thread is assigned a chunk.\n * E.g. if the file size is 100, and we have two threads, the first thread will read from 0 to 49,\n * the second from 50 to 99.\n * Each chunk is aligned to the next end-of-line (or to the end-of-file), so that each thread\n * consumes full input lines.\n * Further, each file chunk is split into smaller pieces (byte arrays), with each piece up to 2^22 bytes.\n * This particular size seems to work best on my machine.\n * == Data structure ==\n * Each thread stores its results in a prefix tree (trie). Each node in the trie represents\n * one byte of a location's name. Non-ASCII characters are represented by multiple nodes in the trie.\n * Each leaf contains the statistics for a location.\n */\npublic class CalculateAverage_albertoventurini {\n\n    // The maximum byte that can ever appear in a UTF-8-encoded string is 11110111, i.e., 0xF7\n    private static final int MAX_UTF8_BYTE_VALUE = 0xF7;\n\n    // Define a prefix tree that is used to store results.\n    // Each node in the trie represents a byte (NOT character) from a location name.\n    // A nice side effect is, when traversing the trie to print results,\n    // the names will be printed in alphabetical order.\n    private static final class TrieNode {\n        final TrieNode[] children = new TrieNode[MAX_UTF8_BYTE_VALUE];\n        int min = Integer.MAX_VALUE;\n        int max = Integer.MIN_VALUE;\n        int sum;\n        int count;\n    }\n\n    private static final int TWO_BYTE_TO_INT = 480 + 48;\n    private static final int THREE_BYTE_TO_INT = 4800 + 480 + 48;\n\n    // Process a chunk and write results in a Trie rooted at 'root'.\n    private static void processChunk(final TrieNode root, final ChunkReader cr) {\n        while (cr.ensureHasMoreRows()) {\n            TrieNode node = root;\n\n            // Process the location name navigating through the trie\n            int b = cr.getNext();\n            do {\n                b &= 0xFF;\n                if (node.children[b] == null) {\n                    node.children[b] = new TrieNode();\n                }\n                node = node.children[b];\n                b = cr.getNext();\n            } while (b != ';');\n\n            // Process the reading value (temperature)\n            final int reading;\n\n            final byte b1 = cr.getNext();\n            final byte b2 = cr.getNext();\n            if (b2 == '.') { // value is n.n\n                reading = (b1 * 10 + cr.getNext() - TWO_BYTE_TO_INT);\n            }\n            else {\n                final byte b3 = cr.getNext();\n                final byte b4 = cr.getNext();\n                if (b4 == '.') { // value is -nn.n\n                    reading = -(b2 * 100 + b3 * 10 + cr.getNext() - THREE_BYTE_TO_INT);\n                }\n                else if (b1 == '-') { // value is -n.n\n                    reading = -(b2 * 10 + b4 - TWO_BYTE_TO_INT);\n                }\n                else { // value is nn.n\n                    reading = (b1 * 100 + b2 * 10 + b4 - THREE_BYTE_TO_INT);\n                }\n            }\n            cr.cursor++; // new line\n\n            if (reading < node.min) {\n                node.min = reading;\n            }\n            if (reading > node.max) {\n                node.max = reading;\n            }\n            node.sum += reading;\n            node.count++;\n        }\n    }\n\n    // Print results.\n    // Because there are multiple tries (one for each thread), this method\n    // aggregates results from all tries.\n    static class ResultPrinter {\n        // Contains the bytes for the current location name. 100 bytes should be enough\n        // to represent each location name encoded in UTF-8.\n        final byte[] bytes = new byte[100];\n\n        boolean firstOutput = true;\n\n        void printResults(final TrieNode[] roots) {\n            System.out.print(\"{\");\n            printResultsRec(roots, bytes, 0);\n            System.out.println(\"}\");\n        }\n\n        private static double round(long value) {\n            return Math.round(value) / 10.0;\n        }\n\n        // Find and print results recursively.\n        private void printResultsRec(final TrieNode[] nodes, final byte[] bytes, final int index) {\n            long min = Long.MAX_VALUE;\n            long max = Long.MIN_VALUE;\n            long sum = 0;\n            long count = 0;\n\n            for (final TrieNode node : nodes) {\n                if (node != null && node.count > 0) {\n                    min = Math.min(min, node.min);\n                    max = Math.max(max, node.max);\n                    sum += node.sum;\n                    count += node.count;\n                }\n            }\n\n            if (count > 0) {\n                final String location = new String(bytes, 0, index);\n                if (firstOutput) {\n                    firstOutput = false;\n                }\n                else {\n                    System.out.print(\", \");\n                }\n                double mean = Math.round((double) sum / (double) count) / 10.0;\n                System.out.print(location + \"=\" + round(min) + \"/\" + mean + \"/\" + round(max));\n            }\n\n            for (int i = 0; i < MAX_UTF8_BYTE_VALUE; i++) {\n                final TrieNode[] childNodes = new TrieNode[nodes.length];\n                boolean shouldRecurse = false;\n                for (int j = 0; j < nodes.length; j++) {\n                    if (nodes[j] != null && nodes[j].children[i] != null) {\n                        childNodes[j] = nodes[j].children[i];\n\n                        // Only recurse if there's at least one trie that has non-null child for index 'i'.\n                        shouldRecurse = true;\n                    }\n                }\n                if (shouldRecurse) {\n                    bytes[index] = (byte) i;\n                    printResultsRec(childNodes, bytes, index + 1);\n                }\n            }\n        }\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n\n    /**\n     * Read a chunk of a {@link RandomAccessFile} file.\n     * Internally, the chunk is further subdivided into \"sub-chunks\" (byte arrays).\n     */\n    private static final class ChunkReader {\n        // Byte arrays of size 2^20 seem to have the best performance on my machine.\n        private static final int BYTE_ARRAY_SIZE = 1 << 20;\n        private final byte[] bytes;\n\n        private final RandomAccessFile file;\n\n        // The initial position of this chunk.\n        private final long chunkBegin;\n\n        // The length of this chunk.\n        private final long chunkLength;\n\n        // The beginning of the current \"sub-chunk\", relative to the initial position of the chunk.\n        private long offset = 0;\n\n        // The size of the current \"sub-chunk\".\n        private int subChunkSize = 0;\n\n        // The current position within the current \"sub-chunk\".\n        private int cursor = 0;\n\n        // The maximum size of a row\n        private static final int MAX_ROW_SIZE_BYTES = 107;\n\n        ChunkReader(\n                    final RandomAccessFile file,\n                    final long chunkBegin,\n                    final long chunkLength) {\n            this.file = file;\n            this.chunkBegin = chunkBegin;\n            this.chunkLength = chunkLength;\n\n            int byteArraySize = chunkLength < BYTE_ARRAY_SIZE ? (int) chunkLength : BYTE_ARRAY_SIZE;\n            this.bytes = new byte[byteArraySize];\n\n            readSubChunk();\n        }\n\n        // Return true if this ChunkReader has more bytes available, false otherwise.\n        // If this ChunkReader needs to read a new \"sub-chunk\", it does so in this method.\n        boolean ensureHasMoreRows() {\n            if (cursor >= subChunkSize) {\n                offset += cursor;\n                if (offset >= chunkLength) {\n                    return false;\n                }\n                readSubChunk();\n            }\n\n            return true;\n        }\n\n        byte getNext() {\n            return bytes[cursor++];\n        }\n\n        private void readSubChunk() {\n            try {\n                synchronized (file) {\n                    file.seek(chunkBegin + offset);\n                    subChunkSize = file.read(bytes);\n                }\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n\n            // Always \"pretend\" that we've read a few bytes less,\n            // so that we don't stop in the middle of reading a row\n            subChunkSize -= MAX_ROW_SIZE_BYTES;\n\n            cursor = 0;\n        }\n    }\n\n    private static ChunkReader[] makeChunkReaders(\n                                                  final int count,\n                                                  final RandomAccessFile file)\n            throws Exception {\n\n        final ChunkReader[] chunkReaders = new ChunkReader[count];\n\n        // The total size of each chunk\n        final long chunkReaderSize = file.length() / count;\n\n        long previousPosition = 0;\n        long currentPosition;\n\n        for (int i = 0; i < count; i++) {\n            // Go to the end of the chunk\n            file.seek(chunkReaderSize * (i + 1));\n\n            // Align to the next end of line or end of file\n            try {\n                while (file.readByte() != '\\n')\n                    ;\n            }\n            catch (EOFException e) {\n            }\n\n            currentPosition = file.getFilePointer();\n            long chunkBegin = previousPosition;\n            long chunkLength = currentPosition - previousPosition;\n            chunkReaders[i] = new ChunkReader(file, chunkBegin, chunkLength);\n\n            previousPosition = currentPosition;\n        }\n\n        return chunkReaders;\n    }\n\n    // Spin up threads and assign a file chunk to each one.\n    // Then use the 'ResultPrinter' class to aggregate and print the results.\n    private static void processWithChunkReaders() throws Exception {\n        final var randomAccessFile = new RandomAccessFile(FILE, \"r\");\n\n        final int nThreads = randomAccessFile.length() < 1 << 20 ? 1 : Runtime.getRuntime().availableProcessors();\n\n        final CountDownLatch latch = new CountDownLatch(nThreads);\n\n        final ChunkReader[] chunkReaders = makeChunkReaders(nThreads, randomAccessFile);\n        final TrieNode[] roots = new TrieNode[nThreads];\n        for (int i = 0; i < nThreads; i++) {\n            roots[i] = new TrieNode();\n        }\n\n        final ExecutorService executorService = Executors.newFixedThreadPool(nThreads);\n        for (int i = 0; i < nThreads; i++) {\n            final int idx = i;\n            executorService.submit(() -> {\n                processChunk(roots[idx], chunkReaders[idx]);\n                latch.countDown();\n            });\n        }\n        executorService.shutdown();\n        latch.await();\n\n        new ResultPrinter().printResults(roots);\n\n        executorService.close();\n    }\n\n    public static void main(String[] args) throws Exception {\n        processWithChunkReaders();\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_alesj.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.DoubleSummaryStatistics;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_alesj {\n    public static void main(String[] args) throws Exception {\n        Map<String, DoubleSummaryStatistics> stations = new ConcurrentHashMap<>();\n        try (Stream<String> stream = Files.lines(Paths.get(\"./measurements.txt\")).parallel()) {\n            stream.forEach(line -> {\n                String[] split = line.split(\";\");\n                stations.computeIfAbsent(split[0], k -> new DoubleSummaryStatistics() {\n                    public synchronized void accept(double value) {\n                        super.accept(value);\n                    }\n\n                    public String toString() {\n                        return String.format(\"%.1f/%.1f/%.1f\", getMin(), getAverage(), getMax());\n                    }\n                })\n                        .accept(Double.parseDouble(split[1]));\n            });\n        }\n        System.out.println(new TreeMap<>(stations));\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_algirdasrascius.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorCompletionService;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class CalculateAverage_algirdasrascius {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int MAX_NAMES = 10000;\n    private static final int MAP_ENTRY_COUNT = 20011; // Prime exceeding double MAX_NAMES count\n    private static final int MAX_NAME_LENGTH_IN_CHARS = 100;\n    private static final int MAX_NAME_LENGTH_IN_BYTES = MAX_NAME_LENGTH_IN_CHARS * 4;\n    private static final int NAME_BUFFER_LENGTH = MAX_NAMES * MAX_NAME_LENGTH_IN_BYTES;\n\n    private static class AggregatorMap {\n        private final AggregatorMapEntry[] entries = new AggregatorMapEntry[MAP_ENTRY_COUNT];\n        private final byte[] nameBuffer = new byte[NAME_BUFFER_LENGTH];\n        private int nameBufferEnd = 0;\n\n        void add(byte[] buffer, int nameStart, int nameEnd, int nameHash, short value) {\n            getEntry(buffer, nameStart, nameEnd, nameHash).accumulate(value);\n        }\n\n        void combineWith(AggregatorMap other) {\n            for (int i = 0; i < MAP_ENTRY_COUNT; i++) {\n                AggregatorMapEntry entry = other.entries[i];\n                while (entry != null) {\n                    getEntry(other.nameBuffer, entry.nameStart, entry.nameEnd, entry.nameHash).combineWith(entry);\n                    entry = entry.nextEntry;\n                }\n            }\n        }\n\n        void printResult() {\n            Map<String, ResultRow> sortedMeasurements = new TreeMap<>();\n            for (int i = 0; i < MAP_ENTRY_COUNT; i++) {\n                AggregatorMapEntry entry = entries[i];\n                while (entry != null) {\n                    String name = new String(nameBuffer, entry.nameStart, entry.nameEnd - entry.nameStart, StandardCharsets.UTF_8);\n                    sortedMeasurements.put(name, entry.result());\n                    entry = entry.nextEntry;\n                }\n            }\n            System.out.println(sortedMeasurements);\n        }\n\n        private AggregatorMapEntry getEntry(byte[] buffer, int nameStart, int nameEnd, int nameHash) {\n            int index = (nameHash & 0x7FFFFFFF) % MAP_ENTRY_COUNT;\n            AggregatorMapEntry firstEntry = entries[index];\n            AggregatorMapEntry entry = firstEntry;\n            while (entry != null && (entry.nameHash != nameHash || !Arrays.equals(buffer, nameStart, nameEnd, nameBuffer, entry.nameStart, entry.nameEnd))) {\n                entry = entry.nextEntry;\n            }\n            if (entry == null) {\n                int entryNameStart = nameBufferEnd;\n                int nameLength = nameEnd - nameStart;\n                System.arraycopy(buffer, nameStart, nameBuffer, entryNameStart, nameLength);\n                nameBufferEnd += nameLength;\n                entry = new AggregatorMapEntry(entryNameStart, nameBufferEnd, nameHash, firstEntry);\n                entries[index] = entry;\n            }\n            return entry;\n        }\n\n    }\n\n    private static class AggregatorMapEntry {\n        private final int nameStart;\n        private final int nameEnd;\n        private final int nameHash;\n        private final AggregatorMapEntry nextEntry;\n        private short min = Short.MAX_VALUE;\n        private short max = Short.MIN_VALUE;\n        private long sum;\n        private int count;\n\n        public AggregatorMapEntry(int nameStart, int nameEnd, int nameHash, AggregatorMapEntry nextEntry) {\n            this.nameStart = nameStart;\n            this.nameEnd = nameEnd;\n            this.nameHash = nameHash;\n            this.nextEntry = nextEntry;\n        }\n\n        void accumulate(short value) {\n            if (min > value) {\n                min = value;\n            }\n            if (max < value) {\n                max = value;\n            }\n            sum += value;\n            count++;\n        }\n\n        void combineWith(AggregatorMapEntry other) {\n            if (min > other.min) {\n                min = other.min;\n            }\n            if (max < other.max) {\n                max = other.max;\n            }\n            sum += other.sum;\n            count += other.count;\n        }\n\n        ResultRow result() {\n            // return new ResultRow(min, (short) ((sum + count / 2) / count), max);\n            return new ResultRow(min, (short) Math.round(((double) sum) / count), max);\n        }\n    }\n\n    private record ResultRow(short min, short mean, short max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private String round(short value) {\n            return value >= 0\n                    ? ((value / 10) + \".\" + (value % 10))\n                    : (\"-\" + (-value / 10) + \".\" + (-value % 10));\n        }\n    }\n\n    private static final int READ_CHUNK_SIZE = 1024 * 1024;\n    private static final int MAX_LINE_SIZE = MAX_NAME_LENGTH_IN_BYTES + 10;\n    private static final int READ_BUFFER_SIZE = READ_CHUNK_SIZE + MAX_LINE_SIZE;\n\n    private static class ReaderTask implements Callable<AggregatorMap> {\n        private final AggregatorMap aggregatorMap = new AggregatorMap();\n        private final byte[] buffer = new byte[READ_BUFFER_SIZE];\n        private final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);\n        private final FileChannel channel;\n        private final AtomicLong nextChunkPosition;\n\n        public ReaderTask(FileChannel channel, AtomicLong nextChunkPosition) {\n            this.channel = channel;\n            this.nextChunkPosition = nextChunkPosition;\n        }\n\n        @Override\n        public AggregatorMap call() throws Exception {\n            while (processChunk()) {\n            }\n            return aggregatorMap;\n        }\n\n        private boolean processChunk() throws IOException {\n            long channelPosition = nextChunkPosition.getAndAdd(READ_CHUNK_SIZE);\n            int endIndex = 0;\n\n            byteBuffer.rewind();\n            do {\n                int bytesRead = channel.read(byteBuffer, channelPosition + endIndex);\n                if (bytesRead < 0) {\n                    break;\n                }\n                endIndex += bytesRead;\n            } while (endIndex < READ_CHUNK_SIZE);\n\n            int index = 0;\n\n            // If this is not the first chunk skip till first line end\n            if (channelPosition != 0) {\n                byte v;\n                while (index < endIndex && buffer[index] != '\\n') {\n                    index++;\n                }\n                index++;\n            }\n\n            if (endIndex > READ_CHUNK_SIZE + 1) {\n                endIndex = READ_CHUNK_SIZE + 1;\n            }\n\n            while (index < endIndex) {\n                index = processLine(index);\n            }\n\n            return endIndex > READ_CHUNK_SIZE;\n        }\n\n        private int processLine(int index) {\n            // Read station name\n            byte v;\n            int nameStart = index;\n            int nameHash = 0;\n            while ((v = buffer[index]) != ';') {\n                index++;\n                nameHash = 31 * nameHash + v;\n            }\n            int nameEnd = index;\n\n            // Skip ;\n            index++;\n\n            // Read temperature value\n            v = buffer[index++];\n            boolean negative = false;\n            if (v == '-') {\n                negative = true;\n                v = buffer[index++];\n            }\n            int value = v - '0';\n            v = buffer[index++];\n            if (v != '.') {\n                value = value * 10 + (v - '0');\n                index++;\n            }\n            v = buffer[index++];\n            value = value * 10 + (v - '0');\n            if (negative) {\n                value = -value;\n            }\n\n            // Skip line feed\n            index++;\n\n            // System.out.println(new String(buffer, nameStart, nameEnd - nameStart) + \" = \" + value);\n            aggregatorMap.add(buffer, nameStart, nameEnd, nameHash, (short) value);\n            return index;\n        }\n\n    }\n\n    public static void main(String[] args) throws Exception {\n        try (FileInputStream stream = new FileInputStream(FILE)) {\n            FileChannel channel = stream.getChannel();\n            AtomicLong nextChunkPosition = new AtomicLong(0L);\n\n            int threadCount = Runtime.getRuntime().availableProcessors() * 2;\n            ExecutorService executorService = Executors.newFixedThreadPool(threadCount);\n            ExecutorCompletionService<AggregatorMap> completionService = new ExecutorCompletionService<>(executorService);\n            for (int i = 0; i < threadCount; i++) {\n                completionService.submit(new ReaderTask(channel, nextChunkPosition));\n            }\n\n            AggregatorMap aggregatorMap = completionService.take().get();\n            for (int i = 1; i < threadCount; i++) {\n                aggregatorMap.combineWith(completionService.take().get());\n            }\n            aggregatorMap.printResult();\n            executorService.close();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_anandmattikopp.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_anandmattikopp {\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        Map<String, StationStatistics> stationStatisticsMap = Files.lines(Paths.get(FILE)).parallel()\n                .map(entry -> {\n                    String[] tokens = entry.split(\";\");\n                    return new Station(tokens[0], Double.parseDouble(tokens[1]));\n                })\n                .collect(\n                        Collectors.toConcurrentMap(\n                                station -> station.stationName,\n                                station -> new StationStatistics(station),\n                                StationStatistics::merge));\n\n        System.out.println(new TreeMap<>(stationStatisticsMap));\n    }\n\n    private record Station(String stationName, double temperature) {\n    }\n\n    private record StationStatistics(String stationName, double minTemp, double meanTemp, double maxTemp,\n                                     long totalCount) {\n        StationStatistics(Station station) {\n            //Calling canonical constructor\n            this(station.stationName, station.temperature, station.temperature, station.temperature, 1);\n        }\n\n        //Merging two stats to create new stats\n        public static StationStatistics merge(StationStatistics stats1, StationStatistics stats2) {\n            assert stats1.stationName.equals(stats2.stationName);\n            return new StationStatistics(\n                    stats1.stationName,\n                    Math.min(stats1.minTemp, stats2.minTemp), // minimum of both the temp\n                    (stats1.meanTemp * stats1.totalCount + stats2.meanTemp * stats2.totalCount) / (stats1.totalCount + stats2.totalCount), // average of both the average temps from stats\n                    Math.max(stats1.maxTemp, stats2.maxTemp), // maximum of both the temp\n                    stats1.totalCount + stats2.totalCount // increment the totalCount\n            );\n        }\n\n        @Override\n        public String toString() {\n            return round(minTemp) + \"/\" + round(meanTemp) + \"/\" + round(maxTemp);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_anestoruk.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport static java.lang.Math.ceil;\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\nimport static java.lang.Runtime.getRuntime;\nimport static java.lang.foreign.ValueLayout.JAVA_BYTE;\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static java.util.concurrent.CompletableFuture.supplyAsync;\n\npublic class CalculateAverage_anestoruk {\n\n    private static final String path = \"./measurements.txt\";\n    private static final int cpus = getRuntime().availableProcessors();\n\n    public static void main(String[] args) throws IOException {\n        List<SegmentRange> rangeList = new ArrayList<>();\n        MemorySegment segment;\n\n        try (FileChannel channel = FileChannel.open(Path.of(path))) {\n            final long fileSize = channel.size();\n            final long chunkSize = calculateChunkSize(fileSize);\n            final int chunks = (int) ceil((double) fileSize / chunkSize);\n            segment = channel.map(READ_ONLY, 0, fileSize, Arena.global());\n            long startOffset = 0;\n            long size = chunkSize;\n            for (int i = 0; i < chunks && size > 0; i++) {\n                long endOffset = startOffset + size;\n                while (endOffset < fileSize && segment.get(JAVA_BYTE, endOffset) != '\\n') {\n                    endOffset++;\n                }\n                rangeList.add(new SegmentRange(startOffset, endOffset));\n                startOffset = endOffset + 1;\n                size = min(chunkSize, fileSize - startOffset);\n            }\n        }\n\n        TreeMap<String, Record> result = new TreeMap<>();\n        try (ExecutorService executor = Executors.newFixedThreadPool(cpus)) {\n            List<CompletableFuture<Record[]>> futures = new ArrayList<>();\n            for (SegmentRange range : rangeList) {\n                futures.add(supplyAsync(() -> process(range, segment), executor));\n            }\n            for (CompletableFuture<Record[]> future : futures) {\n                try {\n                    Record[] partialResult = future.get();\n                    mergeResult(result, partialResult);\n                }\n                catch (InterruptedException | ExecutionException ex) {\n                    throw new RuntimeException(ex);\n                }\n            }\n        }\n\n        System.out.println(result);\n    }\n\n    private static long calculateChunkSize(long fileSize) {\n        int divisor = cpus;\n        long chunkSize;\n        if (fileSize > 10_000) {\n            while ((chunkSize = fileSize / divisor) > Integer.MAX_VALUE - 512) {\n                divisor *= 2;\n            }\n            return chunkSize;\n        }\n        return fileSize;\n    }\n\n    private static Record[] process(SegmentRange range, MemorySegment segment) {\n        Record[] records = new Record[1024 * 100];\n        byte[] cityBuffer = new byte[100];\n        long offset = range.startOffset;\n        byte b;\n        while (offset < range.endOffset) {\n            int cityLength = 0;\n            int hash = 0;\n            while ((b = segment.get(JAVA_BYTE, offset++)) != ';') {\n                cityBuffer[cityLength++] = b;\n                hash = hash * 31 + b;\n            }\n            hash = Math.abs(hash);\n            int value = 0;\n            boolean negative;\n            if ((b = segment.get(JAVA_BYTE, offset++)) == '-') {\n                negative = true;\n            }\n            else {\n                negative = false;\n                value = b - '0';\n            }\n            while ((b = segment.get(JAVA_BYTE, offset++)) != '\\n') {\n                if (b != '.') {\n                    value = value * 10 + (b - '0');\n                }\n            }\n            int temperature = negative ? -value : value;\n            addRecord(records, hash, cityBuffer, cityLength, temperature);\n        }\n        return records;\n    }\n\n    private static void addRecord(Record[] records, int hash, byte[] cityBuffer, int cityLength, int temperature) {\n        int idx = hash % records.length;\n        Record record;\n        while ((record = records[idx]) != null) {\n            if (record.hash == hash && Arrays.equals(record.city, 0, record.city.length, cityBuffer, 0, cityLength)) {\n                record.add(temperature);\n                return;\n            }\n            idx = (idx + 1) % records.length;\n        }\n        byte[] city = new byte[cityLength];\n        System.arraycopy(cityBuffer, 0, city, 0, cityLength);\n        records[idx] = new Record(hash, city, temperature);\n    }\n\n    private static void mergeResult(TreeMap<String, Record> result, Record[] partialResult) {\n        for (Record partialRecord : partialResult) {\n            if (partialRecord == null) {\n                continue;\n            }\n            String cityName = new String(partialRecord.city, UTF_8);\n            result.compute(cityName, (_, record) -> {\n                if (record == null) {\n                    return partialRecord;\n                }\n                record.merge(partialRecord);\n                return record;\n            });\n        }\n    }\n\n    private record SegmentRange(long startOffset, long endOffset) {\n    }\n\n    private static class Record {\n\n        private final int hash;\n        private final byte[] city;\n        private int min;\n        private int max;\n        private long sum;\n        private int count;\n\n        public Record(int hash, byte[] city, int temperature) {\n            this.hash = hash;\n            this.city = city;\n            this.min = temperature;\n            this.max = temperature;\n            this.sum = temperature;\n            this.count = 1;\n        }\n\n        public void add(int temperature) {\n            min = min(min, temperature);\n            max = max(max, temperature);\n            sum += temperature;\n            count++;\n        }\n\n        public void merge(Record other) {\n            min = min(min, other.min);\n            max = max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n        }\n\n        @Override\n        public String toString() {\n            return \"%.1f/%.1f/%.1f\".formatted(\n                    (min / 10.0),\n                    ((double) sum / count / 10.0),\n                    (max / 10.0));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_anitasv.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_anitasv {\n    private static final String FILE = \"./measurements.txt\";\n\n    private record Shard(MemorySegment mmapMemory,\n                         long chunkStart, long chunkEnd) {\n\n        byte getByte(long address) {\n            return mmapMemory.get(ValueLayout.JAVA_BYTE, address);\n        }\n\n        long indexOf(long position, byte ch) {\n            ByteBuffer buf = mmapMemory.asSlice(position,\n                            Math.min(128, mmapMemory.byteSize() - position))\n                    .asByteBuffer();\n            while (buf.hasRemaining()) {\n                if (buf.get() == ch) {\n                    return position + (buf.position() - 1);\n                }\n            }\n            return -1;\n        }\n\n        MemorySegment getRange(long start, long end) {\n            return mmapMemory.asSlice(start, end - start);\n        }\n\n        int parseDouble(long start, long end) {\n            int normalized = 0;\n            boolean sign = true;\n            long index = start;\n            if (getByte(index) == '-') {\n                index++;\n                sign = false;\n            }\n            boolean hasDot = false;\n            for (; index < end; index++) {\n                byte ch = getByte(index);\n                if (ch != '.') {\n                    normalized = normalized * 10 + (ch - '0');\n                } else {\n                    hasDot = true;\n                }\n            }\n            if (!hasDot) {\n                normalized *= 10;\n            }\n            if (!sign) {\n                normalized = -normalized;\n            }\n            return normalized;\n        }\n\n        public int computeHash(long position, long stationEnd) {\n            ByteBuffer buf2 = mmapMemory.asSlice(position, stationEnd - position)\n                    .asByteBuffer();\n            return buf2.hashCode();\n        }\n\n        public long truncate(long index) {\n            return Math.min(index, mmapMemory.byteSize());\n        }\n\n        public long getLong(long position) {\n            return mmapMemory.get(ValueLayout.JAVA_LONG_UNALIGNED, position);\n        }\n    }\n\n    private record ResultRow(IntSummaryStatistics statistics, int keyLength, int next) {\n    }\n\n    private static class FastHashMap {\n        private final byte[] keys;\n        private final ResultRow[] values;\n\n        private final int capacityMinusOne;\n\n        private final MemorySegment keySegment;\n\n        private int next = -1;\n\n        private FastHashMap(int capacity) {\n            this.capacityMinusOne = capacity - 1;\n            this.keys = new byte[capacity << 7];\n            this.keySegment = MemorySegment.ofArray(keys);\n            this.values = new ResultRow[capacity];\n        }\n\n        IntSummaryStatistics find(int hash, Shard shard, long stationStart, long stationEnd) {\n            int initialIndex = hash & capacityMinusOne;\n            int lookupLength = (int) (stationEnd - stationStart);\n            int lookupAligned = ((lookupLength + 7) & (-8));\n            int i = initialIndex;\n\n            lookupAligned = (int) (shard.truncate(stationStart + lookupAligned) - stationStart) - 7;\n\n            do {\n                int keyIndex = i << 7;\n\n                if (keys[keyIndex] != 0 && keys[keyIndex + lookupLength] == 0) {\n\n                    int mismatch = -1, j;\n                    for (j = 0; j < lookupAligned; j += 8) {\n                        long entryLong = keySegment.get(ValueLayout.JAVA_LONG_UNALIGNED, keyIndex + j);\n                        long lookupLong = shard.getLong(stationStart + j);\n                        if (entryLong != lookupLong) {\n                            int diff = Long.numberOfTrailingZeros(entryLong ^ lookupLong);\n                            mismatch = j + (diff >> 3);\n                            break;\n                        }\n                    }\n                    if (mismatch == -1) {\n                        for (; j < lookupLength; j++) {\n                            byte entryByte = keys[keyIndex + j];\n                            byte lookupByte = shard.getByte(stationStart + j);\n                            if (entryByte != lookupByte) {\n                                mismatch = j;\n                                break;\n                            }\n                        }\n                    }\n                    if (mismatch == -1 || mismatch >= lookupLength) {\n                        return this.values[i].statistics;\n                    }\n                }\n                if (keys[keyIndex] == 0) {\n                    MemorySegment fullLookup = shard.getRange(stationStart, stationEnd);\n\n                    keySegment.asSlice(keyIndex, lookupLength)\n                            .copyFrom(fullLookup);\n\n                    keys[keyIndex + lookupLength] = 0;\n                    IntSummaryStatistics stats = new IntSummaryStatistics();\n                    ResultRow resultRow = new ResultRow(stats, lookupLength, this.next);\n                    this.next = i;\n                    this.values[i] = resultRow;\n                    return stats;\n                }\n\n                if (i == capacityMinusOne) {\n                    i = 0;\n                }\n                else {\n                    i++;\n                }\n            } while (i != initialIndex);\n            throw new IllegalStateException(\"Hash size too small\");\n        }\n\n        Iterable<Map.Entry<String, IntSummaryStatistics>> values() {\n            return () -> new Iterator<>() {\n\n                int scan = FastHashMap.this.next;\n\n                @Override\n                public boolean hasNext() {\n                    return scan != -1;\n                }\n\n                @Override\n                public Map.Entry<String, IntSummaryStatistics> next() {\n                    ResultRow resultRow = values[scan];\n                    IntSummaryStatistics stats = resultRow.statistics;\n                    String key = new String(keys, scan << 7, resultRow.keyLength,\n                            StandardCharsets.UTF_8);\n                    scan = resultRow.next;\n                    return new AbstractMap.SimpleEntry<>(key, stats);\n                }\n            };\n        }\n\n    }\n\n    private static Iterable<Map.Entry<String, IntSummaryStatistics>> process(Shard shard) {\n        FastHashMap result = new FastHashMap(1 << 14);\n\n        boolean skip = shard.chunkStart != 0;\n        for (long position = shard.chunkStart; position < shard.chunkEnd; position++) {\n            if (skip) {\n                position = shard.indexOf(position, (byte) '\\n');\n                skip = false;\n            }\n            else {\n                long stationEnd = shard.indexOf(position, (byte) ';');\n                int hash = shard.computeHash(position, stationEnd);\n\n                long temperatureEnd = shard.indexOf(stationEnd + 1, (byte) '\\n');\n                int temperature = shard.parseDouble(stationEnd + 1, temperatureEnd);\n\n                IntSummaryStatistics stats = result.find(hash, shard, position, stationEnd);\n                stats.accept(temperature);\n                position = temperatureEnd;\n            }\n        }\n\n        return result.values();\n    }\n\n    private static Map<String, IntSummaryStatistics> combineResults(List<Iterable<Map.Entry<String, IntSummaryStatistics>>> list) {\n        Map<String, IntSummaryStatistics> output = HashMap.newHashMap(1024);\n        for (Iterable<Map.Entry<String, IntSummaryStatistics>> map : list) {\n            for (Map.Entry<String, IntSummaryStatistics> entry : map) {\n                output.compute(entry.getKey(), (ignore, val) -> {\n                    if (val == null) {\n                        return entry.getValue();\n                    }\n                    else {\n                        val.combine(entry.getValue());\n                        return val;\n                    }\n                });\n            }\n        }\n\n        return output;\n    }\n\n    private static Map<String, IntSummaryStatistics> master(MemorySegment mmapMemory) {\n        long totalBytes = mmapMemory.byteSize();\n        int numWorkers = Runtime.getRuntime().availableProcessors();\n        long chunkSize = Math.ceilDiv(totalBytes, numWorkers);\n        return combineResults(IntStream.range(0, numWorkers)\n                .parallel()\n                .mapToObj(workerId -> {\n                    long chunkStart = workerId * chunkSize;\n                    long chunkEnd = Math.min(chunkStart + chunkSize + 1, totalBytes);\n                    return new Shard(mmapMemory, chunkStart, chunkEnd);\n                })\n                .map(CalculateAverage_anitasv::process)\n                .toList());\n    }\n\n    public static Map<String, IntSummaryStatistics> start() throws IOException {\n        try (FileChannel fileChannel = FileChannel.open(Path.of(FILE),\n                StandardOpenOption.READ)) {\n            long fileSize = fileChannel.size();\n            MemorySegment mmapMemory = fileChannel.map(\n                    FileChannel.MapMode.READ_ONLY,\n                    0, fileSize, Arena.global());\n            return master(mmapMemory);\n        }\n    }\n\n    private static Map<String, String> toPrintMap(Map<String, IntSummaryStatistics> output) {\n        Map<String, String> outputStr = new TreeMap<>();\n        for (Map.Entry<String, IntSummaryStatistics> entry : output.entrySet()) {\n            IntSummaryStatistics stat = entry.getValue();\n            outputStr.put(entry.getKey(), statToString(stat));\n        }\n        return outputStr;\n    }\n\n    private static String statToString(IntSummaryStatistics stat) {\n        return STR.\"\\{stat.getMin() / 10.0}/\\{Math.round(stat.getAverage()) / 10.0}/\\{stat.getMax() / 10.0}\";\n    }\n\n    public static void main(String[] args) throws IOException {\n        System.out.println(toPrintMap(start()));\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_arjenvaneerde.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class CalculateAverage_arjenvaneerde {\n\n    static class Measure {\n        byte[] station;\n        int length;\n        int count;\n        int minTemp;\n        int maxTemp;\n        long sumTemp;\n\n        Measure(final byte[] station, int count, int minTemp, int maxTemp, long sumTemp) {\n            this.station = station;\n            this.length = station.length;\n            this.count = count;\n            this.minTemp = minTemp;\n            this.maxTemp = maxTemp;\n            this.sumTemp = sumTemp;\n        }\n\n        Measure(byte[] bytes, int startPos, int endPos, int temp) {\n            this.length = endPos - startPos;\n            this.station = new byte[this.length];\n            System.arraycopy(bytes, startPos, this.station, 0, this.station.length);\n            this.count = 1;\n            this.minTemp = temp;\n            this.maxTemp = temp;\n            this.sumTemp = temp;\n        }\n\n        void add(int temp) {\n            this.count++;\n            this.minTemp = Math.min(this.minTemp, temp);\n            this.maxTemp = Math.max(this.maxTemp, temp);\n            this.sumTemp += temp;\n        }\n\n        public static Measure merge(Measure m1, Measure m2) {\n            return new Measure(m1.station, m1.count + m2.count, Math.min(m1.minTemp, m2.minTemp), Math.max(m1.maxTemp, m2.maxTemp), m1.sumTemp + m2.sumTemp);\n        }\n\n        public String toString() {\n            return String.format(\"%.1f/%.1f/%.1f\", this.minTemp / 10.0, this.sumTemp / (10.0 * this.count), this.maxTemp / 10.0);\n        }\n    }\n\n    static class Measures {\n        static final int HASH_TABLE_SIZE = 8 * 1024;\n\n        Measure[][] measureHashTable;\n\n        Measures() {\n            this.measureHashTable = new Measure[HASH_TABLE_SIZE][20];\n        }\n\n        void add(byte[] bytes, int startPos, int endPos, int temp) {\n            int len = endPos - startPos;\n            int index = ((len - 2) & 0x0f | // 4 bits of the length\n                    ((bytes[startPos + 0] & 0x1f) << 4) | // 5 bits of first char\n                    ((bytes[startPos + 2] & 0x1f) << 9) // 5 bits of third char\n            // ((bytes[startPos + 1] & 0x1f) << 14) // 5 bits of second char\n            ) & (HASH_TABLE_SIZE - 1);\n            Measure[] arr = this.measureHashTable[index];\n            int i = 0;\n            boolean found = false;\n            int arrLength = arr.length;\n            while (i < arrLength) {\n                Measure m = arr[i];\n                if (m == null) {\n                    // Not found. Add new entry.\n                    arr[i] = new Measure(bytes, startPos, endPos, temp);\n                    return;\n                }\n                if (m.length == len) {\n                    switch (len) {\n                        case 0:\n                            break;\n                        case 1:\n                            if (m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 2:\n                            if (m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 3:\n                            if (m.station[2] == bytes[startPos + 2] &&\n                                    m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 4:\n                            if (m.station[3] == bytes[startPos + 3] &&\n                                    m.station[2] == bytes[startPos + 2] &&\n                                    m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 5:\n                            if (m.station[4] == bytes[startPos + 4] &&\n                                    m.station[3] == bytes[startPos + 3] &&\n                                    m.station[2] == bytes[startPos + 2] &&\n                                    m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 6:\n                            if (m.station[5] == bytes[startPos + 5] &&\n                                    m.station[4] == bytes[startPos + 4] &&\n                                    m.station[3] == bytes[startPos + 3] &&\n                                    m.station[2] == bytes[startPos + 2] &&\n                                    m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        case 7:\n                            if (m.station[6] == bytes[startPos + 6] &&\n                                    m.station[5] == bytes[startPos + 5] &&\n                                    m.station[4] == bytes[startPos + 4] &&\n                                    m.station[3] == bytes[startPos + 3] &&\n                                    m.station[2] == bytes[startPos + 2] &&\n                                    m.station[1] == bytes[startPos + 1] &&\n                                    m.station[0] == bytes[startPos]) {\n                                found = true;\n                            }\n                            break;\n                        default:\n                            found = Arrays.mismatch(m.station, 0, len, bytes, startPos, endPos) == -1;\n                            break;\n                    }\n                    if (found) {\n                        // Add info.\n                        m.add(temp);\n                        return;\n                    }\n                }\n                i++;\n            }\n            // throw new RuntimeException(\"Reached end of Measures array.\");\n            Measure[] newArr = new Measure[arr.length * 2];\n            System.arraycopy(arr, 0, newArr, 0, arr.length);\n            newArr[i] = new Measure(bytes, startPos, endPos, temp);\n            this.measureHashTable[index] = newArr;\n        }\n    }\n\n    private static class BytesProcessor implements Runnable {\n        final Measures measures;\n        final byte[] buffer;\n        long absoluteStartPos;\n        int startPos;\n        int endPos;\n\n        BytesProcessor(byte[] buffer, long absoluteStartPos, int startPos, int endPos, final Measures measures) {\n            this.buffer = buffer;\n            this.absoluteStartPos = absoluteStartPos;\n            this.startPos = startPos;\n            this.endPos = endPos;\n            this.measures = measures;\n        }\n\n        @Override\n        public void run() {\n            int startOfLinePos = startPos;\n            int endOfLinePos = startOfLinePos;\n            int sepPos;\n            // Process all lines\n            while (endOfLinePos < endPos) {\n                while (buffer[endOfLinePos] != ';') {\n                    endOfLinePos++;\n                }\n                sepPos = endOfLinePos;\n                int temperature = 0;\n                byte lineByte;\n                endOfLinePos++;\n                lineByte = buffer[endOfLinePos];\n                while (lineByte != 0x0A) {\n                    if (lineByte >= '0' && lineByte <= '9') {\n                        temperature = temperature * 10 + (lineByte - '0');\n                    }\n                    lineByte = buffer[++endOfLinePos];\n                }\n                if (buffer[sepPos + 1] == '-') {\n                    temperature = -temperature;\n                }\n                measures.add(buffer, startOfLinePos, sepPos, temperature);\n                startOfLinePos = ++endOfLinePos;\n            }\n        }\n    }\n\n    private static class MeasuresMergeProcessor implements Runnable {\n        final Measures[] measures;\n        final int startIndex;\n        final int endIndex;\n        final ConcurrentSkipListMap<String, Measure> results;\n\n        MeasuresMergeProcessor(final Measures[] measures,\n                               final int startIndex,\n                               final int endIndex,\n                               final ConcurrentSkipListMap<String, Measure> results) {\n            this.measures = measures;\n            this.startIndex = startIndex;\n            this.endIndex = endIndex;\n            this.results = results;\n        }\n\n        @Override\n        public void run() {\n            for (int mIdx = 0; mIdx < this.measures.length; mIdx++) {\n                for (int hashIdx = this.startIndex; hashIdx < this.endIndex; hashIdx++) {\n                    Measure[] mArr = this.measures[mIdx].measureHashTable[hashIdx];\n                    int i = 0;\n                    Measure measure = mArr[i];\n                    while (measure != null) {\n                        Measure finalMeasure = measure;\n                        this.results.compute(new String(measure.station, StandardCharsets.UTF_8), (k, v) -> v == null ? finalMeasure : Measure.merge(v, finalMeasure));\n                        measure = mArr[++i];\n                    }\n                }\n            }\n        }\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n    // private static final String FILE = \"./src/test/resources/samples/measurements-1.txt\";\n    // private static final String FILE = \"./src/test/resources/samples/measurements-10000-unique-keys.txt\";\n    private static final int NUM_THREADS = 8; // Runtime.getRuntime().availableProcessors();\n    private static final int BYTE_BUFFER_SIZE = 16 * 1024 * 1024;\n    private static final ExecutorService threads = Executors.newFixedThreadPool(NUM_THREADS);\n    private static final List<Future<Integer>> futures = new ArrayList<>(NUM_THREADS);\n    private static final Measures[] measures = new Measures[NUM_THREADS];\n\n    public static void main(String[] args) throws Exception {\n        long startTime = System.currentTimeMillis();\n        for (int i = 0; i < NUM_THREADS; i++) {\n            measures[i] = new Measures();\n        }\n        File file = new File(FILE);\n        try (RandomAccessFile raFile = new RandomAccessFile(file, \"r\");\n                FileChannel inChannel = raFile.getChannel()) {\n\n            ByteBuffer[] byteBuffers = new ByteBuffer[2];\n            byteBuffers[0] = ByteBuffer.allocate(BYTE_BUFFER_SIZE);\n            byteBuffers[1] = ByteBuffer.allocate(BYTE_BUFFER_SIZE);\n            int currrentByteBuffer = 0;\n            long numBytesRead = 0;\n            long numTotBytesRead = 0;\n            numBytesRead = inChannel.read(byteBuffers[currrentByteBuffer]);\n            byteBuffers[currrentByteBuffer].flip();\n            while (numBytesRead > 0 || byteBuffers[currrentByteBuffer].position() > 0) {\n                if (numBytesRead > 0) {\n                    numTotBytesRead += numBytesRead;\n                }\n                // System.out.println((double) numTotBytesRead/(1024*1024));\n                // Distribute buffer chunks across threads.\n                int bufferLimit = byteBuffers[currrentByteBuffer].limit();\n                byte[] fileBytes = byteBuffers[currrentByteBuffer].array();\n                int chunckSize = bufferLimit / NUM_THREADS;\n                int startOfChunkPos = 0;\n                int endOfChunkPos = 0;\n                for (int chunk = 0; chunk < NUM_THREADS; chunk++) {\n                    if (chunk == NUM_THREADS - 1) {\n                        endOfChunkPos = bufferLimit - 1;\n                    }\n                    else {\n                        endOfChunkPos = Math.min((chunk + 1) * chunckSize, bufferLimit - 1);\n                    }\n                    while (endOfChunkPos > startOfChunkPos &&\n                            fileBytes[endOfChunkPos] != 0x0A) {\n                        endOfChunkPos--;\n                    }\n                    if (endOfChunkPos > startOfChunkPos) {\n                        endOfChunkPos++;\n                        Future<Integer> f = threads.submit(new BytesProcessor(fileBytes, numTotBytesRead - numBytesRead, startOfChunkPos, endOfChunkPos, measures[chunk]),\n                                chunk);\n                        futures.add(f);\n                        startOfChunkPos = endOfChunkPos;\n                    }\n                }\n                int nextByteBuffer = (currrentByteBuffer + 1) % 2;\n                byteBuffers[nextByteBuffer].clear();\n                if (numBytesRead > 0) {\n                    // Copy over remaining bytes to next buffer.\n                    for (; endOfChunkPos < bufferLimit; endOfChunkPos++) {\n                        byteBuffers[nextByteBuffer].put(fileBytes[endOfChunkPos]);\n                    }\n                    // Read next set from channel.\n                    numBytesRead = inChannel.read(byteBuffers[nextByteBuffer]);\n                    byteBuffers[nextByteBuffer].flip();\n                    // Wait for all threads to finish.\n                    for (Future<Integer> future : futures) {\n                        future.get();\n                    }\n                    futures.clear();\n                }\n                currrentByteBuffer = nextByteBuffer;\n            }\n        }\n        ConcurrentSkipListMap<String, Measure> measurements = new ConcurrentSkipListMap<>();\n        int chunkSize = Measures.HASH_TABLE_SIZE / measures.length;\n        for (int i = 0; i < measures.length; i++) {\n            Future<Integer> f = threads.submit(new MeasuresMergeProcessor(measures, i * chunkSize, (i + 1) * chunkSize, measurements), i);\n            futures.add(f);\n        }\n        for (Future<Integer> future : futures) {\n            future.get();\n        }\n        futures.clear();\n        threads.shutdown();\n        threads.awaitTermination(1, TimeUnit.MILLISECONDS);\n        System.out.println(measurements);\n        // long endTime = System.currentTimeMillis();\n        // System.out.printf(\"Duration : %.3f%n\", (endTime - startTime) / 1000.0);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_arjenw.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Iterator;\nimport java.util.NoSuchElementException;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\nimport java.util.stream.IntStream;\n\n// Calculate Average\n// * baseline:                              3m7s\n// * single-threaded chunk-based reading:   0m45s\n// * multi-threaded chunk-based reading:    0m14s\n// * less branches in parsing:              0m12s\n// * list approach iso map:                 0m5.5s\n// * chunk finetuning:                      0m4.5s\n// * threadlocal result gathering:          0m4.3s (trying graalvm-ce)\n// * memory-mapped file approach:           0m3.2s (also way simpler and neater code; inspired by spullara)\n// * smarter number parsing:                0m2.95s (inspired by iziamos)\n// * switching back to 21-tem vm            0m2.6s\n// * small optimizations                    0m2.5s (skip byte-array copy, optimal StationList array size avoiding collisions)\n\npublic class CalculateAverage_arjenw {\n    private static final int TWO_BYTE_TO_INT = 480 + 48; // 48 is the ASCII code for '0'\n    private static final int THREE_BYTE_TO_INT = 4800 + 480 + 48;\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) {\n        var file = new File(args.length > 0 ? args[0] : FILE);\n        var fileSize = file.length();\n        var numberOfProcessors = fileSize > 1_000_000 ? Runtime.getRuntime().availableProcessors() : 1;\n        var segmentSize = (int) Math.min(Integer.MAX_VALUE, fileSize / numberOfProcessors); // bytebuffer position is an int, so can be max Integer.MAX_VALUE\n        var segmentCount = (int) (fileSize / segmentSize);\n        var results = IntStream.range(0, segmentCount)\n                .mapToObj(segmentNr -> parseSegment(file, fileSize, segmentSize, segmentNr))\n                .parallel()\n                .reduce(StationList::merge)\n                .orElseGet(StationList::new)\n                .toStringArray();\n        Arrays.sort(results, Comparator.comparing(o -> takeUntil(o, '=')));\n        System.out.format(\"{%s}%n\", String.join(\", \", results));\n    }\n\n    private static StationList parseSegment(File file, long fileSize, int segmentSize, int segmentNr) {\n        long segmentStart = segmentNr * (long) segmentSize;\n        long segmentEnd = Math.min(fileSize, segmentStart + segmentSize + 100);\n        try (var fileChannel = (FileChannel) Files.newByteChannel(file.toPath(), StandardOpenOption.READ)) {\n            var bb = fileChannel.map(FileChannel.MapMode.READ_ONLY, segmentStart, segmentEnd - segmentStart);\n            if (segmentStart > 0) {\n                // noinspection StatementWithEmptyBody\n                while (bb.get() != '\\n')\n                    ; // skip to first new line\n            }\n            StationList stationList = new StationList();\n            var buffer = new byte[100];\n            while (bb.position() < segmentSize) {\n                byte b;\n                var i = 0;\n                int hash = 0;\n                while ((b = bb.get()) != ';') {\n                    hash = hash * 31 + b;\n                    buffer[i++] = b;\n                }\n\n                int value;\n                byte b1 = bb.get();\n                byte b2 = bb.get();\n                byte b3 = bb.get();\n                byte b4 = bb.get();\n                if (b2 == '.') {// value is n.n\n                    value = (b1 * 10 + b3 - TWO_BYTE_TO_INT);\n                    // b4 == \\n\n                }\n                else {\n                    if (b4 == '.') { // value is -nn.n\n                        value = -(b2 * 100 + b3 * 10 + bb.get() - THREE_BYTE_TO_INT);\n                    }\n                    else if (b1 == '-') { // value is -n.n\n                        value = -(b2 * 10 + b4 - TWO_BYTE_TO_INT);\n                    }\n                    else { // value is nn.n\n                        value = (b1 * 100 + b2 * 10 + b4 - THREE_BYTE_TO_INT);\n                    }\n                    bb.get(); // new line\n                }\n\n                if (stationList.add(buffer, i, Math.abs(hash), value))\n                    buffer = new byte[100]; // station was new, create new buffer to contain the next station's name\n            }\n\n            return stationList;\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final class Station {\n        private final byte[] data;\n        private final int hash;\n        private final int length;\n\n        private int min;\n        private int max;\n        private int total;\n        private int count;\n\n        private Station(byte[] data, int length, int hash, int value) {\n            this.data = data;\n            this.hash = hash;\n            this.length = length;\n\n            min = max = total = value;\n            count = 1;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{new String(data, 0, length, StandardCharsets.UTF_8)}=\\{min / 10.0}/\\{Math.round(((double) total) / count) / 10.0}/\\{max / 10.0}\";\n        }\n\n        private void append(int min, int max, int total, int count) {\n            if (min < this.min)\n                this.min = min;\n            if (max > this.max)\n                this.max = max;\n            this.total += total;\n            this.count += count;\n        }\n\n        public void append(int value) {\n            append(value, value, value, 1);\n        }\n\n        public void merge(Station other) {\n            append(other.min, other.max, other.total, other.count);\n        }\n    }\n\n    private static class StationList implements Iterable<Station> {\n        private final static int MAX_ENTRY = 65375; // choose a value that _eliminates_ collisions on the test set.\n        private final Station[] array = new Station[MAX_ENTRY];\n        private int size = 0;\n\n        private boolean add(int hash, Supplier<Station> create, Consumer<Station> update) {\n            var position = hash % MAX_ENTRY;\n            Station existing;\n            while ((existing = array[position]) != null && existing.hash != hash) {\n                position = (position + 1) % MAX_ENTRY;\n            }\n            if (existing == null) {\n                array[position] = create.get();\n                size++;\n                return true;\n            }\n            else {\n                update.accept(existing);\n                return false;\n            }\n        }\n\n        public boolean add(byte[] data, int stationNameLength, int stationHash, int value) {\n            return add(stationHash, () -> new Station(data, stationNameLength, stationHash, value), existing -> existing.append(value));\n        }\n\n        public void add(Station station) {\n            add(station.hash, () -> station, existing -> existing.merge(station));\n        }\n\n        public String[] toStringArray() {\n            var destination = new String[size];\n\n            var i = 0;\n            for (Station station : this)\n                destination[i++] = station.toString();\n\n            return destination;\n        }\n\n        public StationList merge(StationList other) {\n            for (Station station : other)\n                add(station);\n            return this;\n        }\n\n        @Override\n        public Iterator<Station> iterator() {\n            return new Iterator<>() {\n                private int index = 0;\n\n                @Override\n                public boolean hasNext() {\n                    Station station = null;\n                    while (index < MAX_ENTRY && (station = array[index]) == null)\n                        index++;\n                    return station != null;\n                }\n\n                @Override\n                public Station next() {\n                    if (hasNext()) {\n                        return array[index++];\n                    }\n                    throw new NoSuchElementException();\n                }\n            };\n        }\n    }\n\n    private static String takeUntil(String s, char c) {\n        var pos = s.indexOf(c);\n        return pos > -1 ? s.substring(0, pos) : s;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_armandino.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Collection;\nimport java.util.Map;\nimport java.util.TreeMap;\n\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\npublic class CalculateAverage_armandino {\n\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n\n    private static final int NUM_CHUNKS = Math.max(8, Runtime.getRuntime().availableProcessors());\n    private static final int INITIAL_MAP_CAPACITY = 8192;\n    private static final byte SEMICOLON = 59;\n    private static final byte NL = 10;\n    private static final int PRIME = 1117;\n\n    private static final int KEY_OFFSET = 0, // 100b\n            HASH_OFFSET = 100, // int\n            KEY_LENGTH_OFFSET = 104, // short\n            MIN_OFFSET = 106, // short\n            MAX_OFFSET = 108, // short\n            COUNT_OFFSET = 110, // int\n            SUM_OFFSET = 114; // long\n\n    private static final long ENTRY_SIZE = 100 // key: offset=0\n            + 4 // keyHash: offset=100\n            + 2 // keyLength: offset=104\n            + 2 // min: 108; offset=106\n            + 2 // max: 110; offset=108\n            + 4 // count: 114; offset=110\n            + 8; // sum: 122; offset=118\n\n    private static final Unsafe UNSAFE = getUnsafe();\n\n    public static void main(String[] args) throws Exception {\n        var channel = FileChannel.open(FILE, StandardOpenOption.READ);\n\n        Chunk[] chunks = split(channel);\n        ChunkProcessor[] processors = new ChunkProcessor[chunks.length];\n\n        for (int i = 0; i < processors.length; i++) {\n            processors[i] = new ChunkProcessor(chunks[i].start, chunks[i].end);\n            processors[i].start();\n        }\n\n        Map<String, Stats> results = new TreeMap<>();\n\n        for (int i = 0; i < processors.length; i++) {\n            processors[i].join();\n            final long end = processors[i].map.mapEnd;\n\n            for (long addr = processors[i].map.mapStart; addr < end; addr += ENTRY_SIZE) {\n                final short keyLength = UNSAFE.getShort(addr + KEY_LENGTH_OFFSET);\n\n                if (keyLength == 0)\n                    continue;\n\n                final byte[] keyBytes = new byte[keyLength];\n                UNSAFE.copyMemory(null, addr, keyBytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, keyLength);\n                final short min = UNSAFE.getShort(addr + MIN_OFFSET);\n                final short max = UNSAFE.getShort(addr + MAX_OFFSET);\n                final int count = UNSAFE.getInt(addr + COUNT_OFFSET);\n                final long sum = UNSAFE.getLong(addr + SUM_OFFSET);\n                final Stats s = new Stats(new String(keyBytes, 0, keyLength, UTF_8), min, max, count, sum);\n                results.merge(s.key, s, CalculateAverage_armandino::mergeStats);\n            }\n        }\n\n        print(results.values());\n    }\n\n    private static Stats mergeStats(final Stats x, final Stats y) {\n        x.min = Math.min(x.min, y.min);\n        x.max = Math.max(x.max, y.max);\n        x.count += y.count;\n        x.sum += y.sum;\n        return x;\n    }\n\n    private static class ChunkProcessor extends Thread {\n        private final UnsafeMap map = new UnsafeMap(INITIAL_MAP_CAPACITY);\n\n        final long chunkStart;\n        final long chunkEnd;\n\n        private ChunkProcessor(long chunkStart, long chunkEnd) {\n            this.chunkStart = chunkStart;\n            this.chunkEnd = chunkEnd;\n        }\n\n        @Override\n        public void run() {\n            long i = chunkStart;\n            while (i < chunkEnd) {\n                final long keyAddress = i;\n                int keyHash = 0;\n                byte b;\n\n                while ((b = UNSAFE.getByte(i++)) != SEMICOLON) {\n                    keyHash = PRIME * keyHash + b;\n                }\n\n                final short keyLength = (short) (i - keyAddress - 1);\n                final long numberWord = UNSAFE.getLong(i);\n                final int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n                final short measurement = parseNumber(decimalSepPos, numberWord);\n                final int addOffset = (decimalSepPos >>> 3) + 3;\n                i += addOffset;\n\n                map.addEntry(keyHash, keyAddress, keyLength, measurement);\n            }\n        }\n\n        // credit: merykitty\n        private static short parseNumber(int decimalSepPos, long numberWord) {\n            int shift = 28 - decimalSepPos;\n            // signed is -1 if negative, 0 otherwise\n            long signed = (~numberWord << 59) >> 63;\n            long designMask = ~(signed & 0xFF);\n            // Align the number to a specific position and transform the ascii to digit value\n            long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 + 0x00UU00TTHH000000 * 10 + 0xUU00TTHH00000000 * 100\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            return (short) ((absValue ^ signed) - signed);\n        }\n    }\n\n    private static class Stats {\n        private final String key;\n        private int min;\n        private int max;\n        private int count;\n        private long sum;\n\n        Stats(final String key, final int min, final int max, final int count, final long sum) {\n            this.min = min;\n            this.max = max;\n            this.count = count;\n            this.sum = sum;\n            this.key = key;\n        }\n\n        void print(final PrintStream out) {\n            out.print(key);\n            out.print('=');\n            out.print(round(min / 10f));\n            out.print('/');\n            out.print(round((sum / 10f) / count));\n            out.print('/');\n            out.print(round(max) / 10f);\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static void print(final Collection<Stats> sorted) {\n        int size = sorted.size();\n        System.out.print('{');\n        for (Stats stats : sorted) {\n            stats.print(System.out);\n            if (--size > 0) {\n                System.out.print(\", \");\n            }\n        }\n        System.out.println('}');\n    }\n\n    private static Chunk[] split(final FileChannel channel) throws IOException {\n        final long fileSize = channel.size();\n        long start = channel.map(READ_ONLY, 0, fileSize, Arena.global()).address();\n        final long endAddress = start + fileSize;\n        if (fileSize < 10000) {\n            return new Chunk[]{ new Chunk(start, endAddress) };\n        }\n\n        final long chunkSize = fileSize / NUM_CHUNKS;\n        final var chunks = new Chunk[NUM_CHUNKS];\n        long end = start + chunkSize;\n\n        for (int i = 0; i < NUM_CHUNKS; i++) {\n            if (i > 0) {\n                start = chunks[i - 1].end;\n                end = Math.min(start + chunkSize, endAddress);\n            }\n            if (end < endAddress) {\n                while (UNSAFE.getByte(end) != NL) {\n                    end++;\n                }\n                end++;\n            }\n            chunks[i] = new Chunk(start, end);\n        }\n        return chunks;\n    }\n\n    private record Chunk(long start, long end) {\n    }\n\n    private static Unsafe getUnsafe() {\n        try {\n            Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            unsafe.setAccessible(true);\n            return (Unsafe) unsafe.get(null);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static class UnsafeMap {\n\n        long mapStart;\n        long mapEnd;\n        int capacity; // num entries\n\n        UnsafeMap(int numEntries) {\n            capacity = numEntries;\n            final long size = ENTRY_SIZE * numEntries;\n            mapStart = UNSAFE.allocateMemory(size);\n            mapEnd = mapStart + size;\n            UNSAFE.setMemory(mapStart, size, (byte) 0);\n        }\n\n        void addEntry(final int keyHash, final long keyAddress, final short keyLength, final short measurement) {\n            final int pos = (capacity - 1) & keyHash;\n\n            long addr = mapStart + pos * ENTRY_SIZE;\n            int hash = UNSAFE.getInt(addr + HASH_OFFSET);\n\n            if (hash == 0) { // new entry\n                initEntry(addr, keyAddress, keyLength, measurement, keyHash);\n                return;\n            }\n            if (hash == keyHash && keysEqual(addr, keyAddress, keyLength)) {\n                updateEntry(addr, measurement);\n                return;\n            }\n\n            // this can be improved to avoid clustering at the start.\n            // should only affect the 10k test\n            addr = mapStart;\n\n            while (addr < mapEnd) {\n                addr += ENTRY_SIZE;\n                hash = UNSAFE.getInt(addr + HASH_OFFSET);\n\n                if (hash == 0) {\n                    initEntry(addr, keyAddress, keyLength, measurement, keyHash);\n                    return;\n                }\n                if (hash == keyHash && keysEqual(addr, keyAddress, keyLength)) {\n                    updateEntry(addr, measurement);\n                    return;\n                }\n            }\n\n            resize(keyHash, keyAddress, keyLength, measurement);\n        }\n\n        private void resize(final int keyHash, final long keyAddress, final short keyLength, final short measurement) {\n            UnsafeMap newMap = new UnsafeMap(capacity * 2);\n\n            for (long addr = mapStart; addr < mapEnd; addr += ENTRY_SIZE) {\n                final short oKeyLength = UNSAFE.getShort(addr + KEY_LENGTH_OFFSET);\n                final int oKeyHsh = UNSAFE.getInt(addr + HASH_OFFSET);\n                final short oMin = UNSAFE.getShort(addr + MIN_OFFSET);\n                final short oMax = UNSAFE.getShort(addr + MAX_OFFSET);\n                final int oCount = UNSAFE.getInt(addr + COUNT_OFFSET);\n                final long oSum = UNSAFE.getLong(addr + SUM_OFFSET);\n\n                final int newPos = (newMap.capacity - 1) & oKeyHsh;\n                long newAddr = newMap.mapStart + newPos * ENTRY_SIZE;\n\n                UNSAFE.putShort(newAddr + KEY_LENGTH_OFFSET, oKeyLength);\n                UNSAFE.putInt(newAddr + HASH_OFFSET, oKeyHsh);\n                UNSAFE.putShort(newAddr + MIN_OFFSET, oMin);\n                UNSAFE.putShort(newAddr + MAX_OFFSET, oMax);\n                UNSAFE.putInt(newAddr + COUNT_OFFSET, oCount);\n                UNSAFE.putLong(newAddr + SUM_OFFSET, oSum);\n            }\n\n            newMap.addEntry(keyHash, keyAddress, keyLength, measurement);\n\n            this.mapStart = newMap.mapStart;\n            this.mapEnd = newMap.mapEnd;\n            this.capacity = newMap.capacity;\n        }\n\n        private static void initEntry(final long entry, final long keyAddress, final short keyLength, final short measurement, final int keyHash) {\n            UNSAFE.copyMemory(keyAddress, entry, keyLength);\n            UNSAFE.putInt(entry + HASH_OFFSET, keyHash);\n            UNSAFE.putShort(entry + KEY_LENGTH_OFFSET, keyLength);\n            UNSAFE.putShort(entry + MIN_OFFSET, Short.MAX_VALUE);\n            UNSAFE.putShort(entry + MAX_OFFSET, Short.MIN_VALUE);\n\n            updateEntry(entry, measurement);\n        }\n\n        private static void updateEntry(final long entry, final short measurement) {\n            UNSAFE.putShort(entry + MIN_OFFSET,\n                    (short) Math.min(UNSAFE.getShort(entry + MIN_OFFSET), measurement));\n            UNSAFE.putShort(entry + MAX_OFFSET,\n                    (short) Math.max(UNSAFE.getShort(entry + MAX_OFFSET), measurement));\n            UNSAFE.putInt(entry + COUNT_OFFSET,\n                    UNSAFE.getInt(entry + COUNT_OFFSET) + 1);\n            UNSAFE.putLong(entry + SUM_OFFSET,\n                    UNSAFE.getLong(entry + SUM_OFFSET) + measurement);\n        }\n    }\n\n    private static boolean keysEqual(long key1Address, long key2Address, final int keyLength) {\n        // credit: abeobk\n        long xsum = 0;\n        int n = keyLength & 0xF8;\n        for (int i = 0; i < n; i += 8) {\n            xsum |= (UNSAFE.getLong(key1Address + i) ^ UNSAFE.getLong(key2Address + i));\n        }\n        return xsum == 0;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_artpar.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.BufferedOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.time.Instant;\nimport java.util.*;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_artpar {\n    public static final int N_THREADS = 8;\n    private static final String FILE = \"./measurements.txt\";\n    private static final int INT_MAP_SIZE = 8192; // from calculateIntegerByteMapTest()\n    final static int[] byteHashMapToInt = calculateIntegerByteMap();\n    private static final Unsafe UNSAFE = initUnsafe();\n    // private static final VectorSpecies<Integer> SPECIES = IntVector.SPECIES_PREFERRED;\n    // final int VECTOR_SIZE = 512;\n    // final int VECTOR_SIZE_1 = VECTOR_SIZE - 1;\n    final int AVERAGE_CHUNK_SIZE = 1024 * 64;\n    final int AVERAGE_CHUNK_SIZE_1 = AVERAGE_CHUNK_SIZE - 1;\n\n    public CalculateAverage_artpar() throws IOException {\n        long start = Instant.now().toEpochMilli();\n        Path measurementFile = Paths.get(FILE);\n        long fileSize = Files.size(measurementFile);\n\n        // System.out.println(\"File size - \" + fileSize);\n        int expectedChunkSize = Math.toIntExact(Math.min(fileSize / N_THREADS, Integer.MAX_VALUE / 2));\n\n        ExecutorService threadPool = Executors.newFixedThreadPool(N_THREADS);\n\n        long chunkStartPosition = 0;\n        RandomAccessFile fis = new RandomAccessFile(measurementFile.toFile(), \"r\");\n        List<Future<Map<String, MeasurementAggregator>>> futures = new ArrayList<>();\n        long bytesReadCurrent = 0;\n\n        FileChannel fileChannel = FileChannel.open(measurementFile, StandardOpenOption.READ);\n        for (int i = 0; chunkStartPosition < fileSize; i++) {\n\n            int chunkSize = expectedChunkSize;\n            chunkSize = fis.skipBytes(chunkSize);\n\n            bytesReadCurrent += chunkSize;\n            while (((char) fis.read()) != '\\n' && bytesReadCurrent < fileSize) {\n                chunkSize++;\n                bytesReadCurrent++;\n            }\n\n            // System.out.println(\"[\" + chunkStartPosition + \"] - [\" + (chunkStartPosition + chunkSize) + \" bytes\");\n            if (chunkStartPosition + chunkSize >= fileSize) {\n                chunkSize = (int) Math.min(fileSize - chunkStartPosition, Integer.MAX_VALUE);\n            }\n            if (chunkSize < 1) {\n                break;\n            }\n            if (chunkSize >= Integer.MAX_VALUE) {\n                throw new RuntimeException();\n            }\n\n            // MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, chunkStartPosition,\n            // chunkSize);\n\n            ReaderRunnable readerRunnable = new ReaderRunnable(chunkStartPosition, chunkSize, fileChannel);\n            Future<Map<String, MeasurementAggregator>> future = threadPool.submit(readerRunnable::run);\n            // System.out.println(\"Added future [\" + chunkStartPosition + \"][\" + chunkSize + \"]\");\n            futures.add(future);\n            chunkStartPosition = chunkStartPosition + chunkSize + 1;\n        }\n\n        fis.close();\n\n        Map<String, MeasurementAggregator> globalMap = futures.parallelStream().flatMap(future -> {\n            try {\n                return future.get().entrySet().stream();\n            }\n            catch (InterruptedException | ExecutionException e) {\n                throw new RuntimeException(e);\n            }\n        }).parallel().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, MeasurementAggregator::combine));\n        fileChannel.close();\n\n        Map<String, ResultRow> results = globalMap.entrySet().stream().parallel()\n                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().finish()));\n\n        threadPool.shutdown();\n        Map<String, ResultRow> measurements = new TreeMap<>(results);\n\n        PrintStream printStream = new PrintStream(new BufferedOutputStream(System.out));\n        // PrintStream printStream = System.out;\n        printStream.print(\"{\");\n\n        boolean isFirst = true;\n        for (Map.Entry<String, ResultRow> stringResultRowEntry : measurements.entrySet()) {\n            if (!isFirst) {\n                printStream.print(\", \");\n                printStream.flush();\n            }\n            printStream.flush();\n            printStream.print(stringResultRowEntry.getKey());\n            printStream.flush();\n            printStream.print(\"=\");\n            printStream.flush();\n            stringResultRowEntry.getValue().printTo(printStream);\n            printStream.flush();\n            isFirst = false;\n        }\n\n        System.out.print(\"}\\n\");\n\n        // long end = Instant.now().toEpochMilli();\n        // System.out.println((end - start) / 1000);\n\n    }\n\n    public static int[] calculateIntegerByteMapTest() {\n        int[] intToIntMap = null;\n        for (int j = 0; j < 10000; j++) {\n            int length = 2000 + j;\n            intToIntMap = new int[length];\n            boolean hasHashClash = false;\n            Map<Integer, Integer> byteHashToInt = new HashMap<>();\n            for (int i = -999; i < 1000; i++) {\n                int hashCode = hashInteger(i);\n\n                // String s = new String(value);\n                int position = hashCode & (length - 1);\n                // System.out.printf(\"%.1f => %s length [%d] hash [%d] => %d\\n\", number, s, s.length(), hashCode, position);\n                if (byteHashToInt.containsKey(hashCode) || intToIntMap[position] != 0) {\n                    // System.err.println(\"HashClash [\" + hashCode + \"] -> \" +\n                    // byteHashToInt.get(\n                    // hashCode) + \" vs \" + number + \" == [\" + position + \"] =>\" + intToIntMap[position]);\n                    hasHashClash = true;\n                    break;\n                }\n                else {\n                    byteHashToInt.put(hashCode, i);\n                    intToIntMap[position] = i;\n                }\n            }\n            if (!hasHashClash) {\n                // 8192\n                System.out.println(\"NoHash clash at [\" + length + \"]\");\n                // throw new RuntimeException(\"clash\");\n                return intToIntMap;\n            }\n\n        }\n        System.out.println(\"Fail\");\n        return null;\n    }\n\n    private static int hashInteger(int i) {\n        float number = i / 10f;\n        String numberString = String.format(\"%.1f\", number);\n        byte[] value = numberString.getBytes();\n\n        int hashCode = 1;\n        for (int k = 0; k < value.length; k++) {\n            hashCode = hashCode * 31 + value[k];\n        }\n        return hashCode;\n    }\n\n    public static int[] calculateIntegerByteMap() {\n        long start = System.currentTimeMillis();\n        int[] intToIntMap = new int[INT_MAP_SIZE];\n        for (int i = -999; i < 1000; i++) {\n            float number = i / 10f;\n            byte[] value = String.format(\"%.1f\", number).getBytes();\n\n            int hashCode = 1;\n            for (byte b : value) {\n                hashCode = hashCode * 31 + b;\n            }\n            int position = hashCode & (INT_MAP_SIZE - 1);\n            intToIntMap[position] = i;\n        }\n        long end = System.currentTimeMillis();\n        // System.out.println(\"calculateIntegerByteMap \" + (end - start) + \" ms\");\n        return intToIntMap;\n    }\n\n    public static void main(String[] args) throws IOException {\n        new CalculateAverage_artpar();\n    }\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    static boolean unsafeEquals(long aStart, long aLength, long bStart, long bLength) {\n        if (aLength != bLength) {\n            return false;\n        }\n        for (int i = 0; i < aLength; ++i) {\n            if (UNSAFE.getByte(aStart + i) != UNSAFE.getByte(bStart + i)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min / 10) + \"/\" + round(mean / 10) + \"/\" + round(max / 10);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public void printTo(PrintStream out) {\n            out.printf(\"%.1f/%.1f/%.1f\", min / 10, mean / 10, max / 10);\n        }\n    }\n\n    private static class MeasurementAggregator {\n        private int min = 999;\n        private int max = -999;\n        private double sum;\n        private long count;\n\n        MeasurementAggregator combine(MeasurementAggregator other) {\n            min = other.min + ((min - other.min) & ((min - other.min) >> (32 * 8 - 1)));\n            max = max - ((max - other.max) & ((max - other.max) >> (32 * 8 - 1)));\n            sum += other.sum;\n            count += other.count;\n            return this;\n        }\n\n        void combine(int value) {\n            sum += value;\n            count++;\n\n            min = value + ((min - value) & ((min - value) >> (32 * 8 - 1))); // min(x, y)\n            max = max - ((max - value) & ((max - value) >> (32 * 8 - 1))); // max(x, y)\n        }\n\n        ResultRow finish() {\n            double mean = (count > 0) ? sum / count : 0;\n            return new ResultRow(min, mean, max);\n        }\n    }\n\n    static class StationName {\n        public final int hash;\n        private final ByteBuffer nameBytes;\n        private final MeasurementAggregator measurementAggregator = new MeasurementAggregator();\n        public int count = 0;\n\n        public StationName(ByteBuffer nameBytes, int hash) {\n            this.nameBytes = nameBytes;\n            this.hash = hash;\n        }\n\n    }\n\n    private class ReaderRunnable {\n        private final long startPosition;\n        private final FileChannel fileChannel;\n        private final int chunkSize;\n        StationNameMap stationNameMap = new StationNameMap();\n\n        private ReaderRunnable(long startPosition, int chunkSize, FileChannel fileChannel) throws IOException {\n            this.chunkSize = chunkSize;\n            this.startPosition = startPosition;\n            this.fileChannel = fileChannel;\n            // mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, startPosition, chunkSize);\n        }\n\n        public Map<String, MeasurementAggregator> run() throws IOException {\n            MemorySegment mappedSegment = fileChannel.map(FileChannel.MapMode.READ_ONLY,\n                    startPosition, chunkSize, Arena.global());\n\n            long rawBufferAddress = UNSAFE.allocateMemory(100);\n            int rawBufferReadIndex = 0;\n            long position = mappedSegment.address();\n            long endPosition = position + chunkSize;\n            byte b;\n            int hash;\n            int nameHash;\n\n            hash = 1;\n\n            while (position < endPosition) {\n\n                while ((position < endPosition) &&\n                        (b = UNSAFE.getByte(position++)) != ';') {\n                    UNSAFE.putByte(rawBufferAddress + rawBufferReadIndex++, b);\n                    hash = hash * 31 + b;\n                }\n\n                nameHash = hash;\n                hash = 1;\n\n                while ((position < endPosition) &&\n                        (b = UNSAFE.getByte(position++)) != '\\n') {\n                    hash = hash * 31 + b;\n                }\n                stationNameMap.getOrCreate(rawBufferAddress, rawBufferReadIndex,\n                        byteHashMapToInt[hash & (INT_MAP_SIZE - 1)], nameHash);\n                rawBufferReadIndex = 0;\n                hash = 1;\n\n            }\n            return Arrays.stream(stationNameMap.names).parallel().filter(Objects::nonNull).collect(\n                    Collectors.toMap(e -> StandardCharsets.UTF_8.decode(e.nameBytes).toString(),\n                            e -> e.measurementAggregator, MeasurementAggregator::combine));\n        }\n    }\n\n    class StationNameMap {\n        int[] indexes = new int[AVERAGE_CHUNK_SIZE];\n        StationName[] names = new StationName[AVERAGE_CHUNK_SIZE];\n        int currentIndex = 0;\n        ByteBuffer bytesForName = ByteBuffer.allocateDirect(1000 * 100);\n        int nameBufferIndex = 0;\n\n        public void getOrCreate(long stationNameBytesAddress, int length, int doubleValue, int hash) {\n            int position = hash & AVERAGE_CHUNK_SIZE_1;\n            while (indexes[position] != 0 && (names[indexes[position]].hash != hash)) {\n                position = ++position & AVERAGE_CHUNK_SIZE_1;\n            }\n            if (indexes[position] != 0) {\n                StationName stationName = names[indexes[position]];\n                stationName.measurementAggregator.combine(doubleValue);\n            }\n            else {\n                ByteBuffer nameSlice = bytesForName.slice(nameBufferIndex, length);\n                nameBufferIndex += length;\n                for (int i = 0; i < length; i++) {\n                    nameSlice.put(UNSAFE.getByte(stationNameBytesAddress + i));\n                }\n                nameSlice.flip();\n                StationName stationName = new StationName(nameSlice, hash);\n                indexes[position] = ++currentIndex;\n                names[indexes[position]] = stationName;\n                stationName.measurementAggregator.combine(doubleValue);\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_artsiomkorzun.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.TreeMap;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\npublic class CalculateAverage_artsiomkorzun {\n\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n    private static final long SEGMENT_SIZE = 2 * 1024 * 1024;\n    private static final long COMMA_PATTERN = 0x3B3B3B3B3B3B3B3BL;\n    private static final long LINE_PATTERN = 0x0A0A0A0A0A0A0A0AL;\n    private static final long DOT_BITS = 0x10101000;\n    private static final long MAGIC_MULTIPLIER = (100 * 0x1000000 + 10 * 0x10000 + 1);\n    private static final long[] WORD_MASK = { 0, 0, 0, 0, 0, 0, 0, 0, -1 };\n    private static final int[] LENGTH_MASK = { 0, 0, 0, 0, 0, 0, 0, 0, -1 };\n\n    private static final Unsafe UNSAFE;\n\n    static {\n        try {\n            Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            unsafe.setAccessible(true);\n            UNSAFE = (Unsafe) unsafe.get(Unsafe.class);\n        }\n        catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // for (int i = 0; i < 10; i++) {\n        // long start = System.currentTimeMillis();\n        // execute();\n        // long end = System.currentTimeMillis();\n        // System.err.println(\"Time: \" + (end - start));\n        // }\n\n        if (isSpawn(args)) {\n            spawn();\n            return;\n        }\n\n        execute();\n    }\n\n    private static boolean isSpawn(String[] args) {\n        for (String arg : args) {\n            if (\"--worker\".equals(arg)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static void spawn() throws Exception {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> commands = new ArrayList<>();\n        Optional<String> command = info.command();\n        Optional<String[]> arguments = info.arguments();\n\n        if (command.isPresent()) {\n            commands.add(command.get());\n        }\n\n        if (arguments.isPresent()) {\n            commands.addAll(Arrays.asList(arguments.get()));\n        }\n\n        commands.add(\"--worker\");\n\n        new ProcessBuilder()\n                .command(commands)\n                .start()\n                .getInputStream()\n                .transferTo(System.out);\n    }\n\n    private static void execute() throws Exception {\n        MemorySegment fileMemory = map(FILE);\n        long fileAddress = fileMemory.address();\n        long fileSize = fileMemory.byteSize();\n        int segmentCount = (int) ((fileSize + SEGMENT_SIZE - 1) / SEGMENT_SIZE);\n\n        AtomicInteger counter = new AtomicInteger();\n        AtomicReference<Aggregates> result = new AtomicReference<>();\n\n        int parallelism = Runtime.getRuntime().availableProcessors();\n        Aggregator[] aggregators = new Aggregator[parallelism];\n\n        for (int i = 0; i < aggregators.length; i++) {\n            aggregators[i] = new Aggregator(counter, result, fileAddress, fileSize, segmentCount);\n            aggregators[i].start();\n        }\n\n        for (int i = 0; i < aggregators.length; i++) {\n            aggregators[i].join();\n        }\n\n        Map<String, Aggregate> aggregates = result.get().build();\n        System.out.println(text(aggregates));\n        System.out.close();\n    }\n\n    private static MemorySegment map(Path file) {\n        try (FileChannel channel = FileChannel.open(file, StandardOpenOption.READ)) {\n            long size = channel.size();\n            return channel.map(FileChannel.MapMode.READ_ONLY, 0, size, Arena.global());\n        }\n        catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static long word(long address) {\n        return UNSAFE.getLong(address);\n        /*\n         * if (BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n         * value = Long.reverseBytes(value);\n         * }\n         *\n         * return value;\n         */\n    }\n\n    private static String text(Map<String, Aggregate> aggregates) {\n        StringBuilder text = new StringBuilder(aggregates.size() * 32 + 2);\n        text.append('{');\n\n        for (Map.Entry<String, Aggregate> entry : aggregates.entrySet()) {\n            if (text.length() > 1) {\n                text.append(\", \");\n            }\n\n            Aggregate aggregate = entry.getValue();\n            text.append(entry.getKey()).append('=')\n                    .append(round(aggregate.min)).append('/')\n                    .append(round(1.0 * aggregate.sum / aggregate.cnt)).append('/')\n                    .append(round(aggregate.max));\n        }\n\n        text.append('}');\n        return text.toString();\n    }\n\n    private static double round(double v) {\n        return Math.round(v) / 10.0;\n    }\n\n    private record Aggregate(int min, int max, long sum, int cnt) {\n    }\n\n    private static class Aggregates {\n\n        private static final long ENTRIES = 64 * 1024;\n        private static final long SIZE = 128 * ENTRIES;\n        private static final long MASK = (ENTRIES - 1) << 7;\n\n        private final long pointer;\n\n        public Aggregates() {\n            long address = UNSAFE.allocateMemory(SIZE + 4096);\n            pointer = (address + 4095) & (~4095);\n            UNSAFE.setMemory(pointer, SIZE, (byte) 0);\n        }\n\n        public long find(long word1, long word2, long hash) {\n            long address = pointer + offset(hash);\n            long w1 = word(address + 24);\n            long w2 = word(address + 32);\n            return (word1 == w1) && (word2 == w2) ? address : 0;\n        }\n\n        public long put(long reference, long word, long length, long hash) {\n            for (long offset = offset(hash);; offset = next(offset)) {\n                long address = pointer + offset;\n                if (equal(reference, word, address + 24, length)) {\n                    return address;\n                }\n\n                int len = UNSAFE.getInt(address);\n                if (len == 0) {\n                    alloc(reference, length, hash, address);\n                    return address;\n                }\n            }\n        }\n\n        public static void update(long address, long value) {\n            long sum = UNSAFE.getLong(address + 8) + value;\n            int cnt = UNSAFE.getInt(address + 16) + 1;\n            short min = UNSAFE.getShort(address + 20);\n            short max = UNSAFE.getShort(address + 22);\n\n            UNSAFE.putLong(address + 8, sum);\n            UNSAFE.putInt(address + 16, cnt);\n\n            if (value < min) {\n                UNSAFE.putShort(address + 20, (short) value);\n            }\n\n            if (value > max) {\n                UNSAFE.putShort(address + 22, (short) value);\n            }\n        }\n\n        public void merge(Aggregates rights) {\n            for (long rightOffset = 0; rightOffset < SIZE; rightOffset += 128) {\n                long rightAddress = rights.pointer + rightOffset;\n                int length = UNSAFE.getInt(rightAddress);\n\n                if (length == 0) {\n                    continue;\n                }\n\n                int hash = UNSAFE.getInt(rightAddress + 4);\n\n                for (long offset = offset(hash);; offset = next(offset)) {\n                    long address = pointer + offset;\n\n                    if (equal(address + 24, rightAddress + 24, length)) {\n                        long sum = UNSAFE.getLong(address + 8) + UNSAFE.getLong(rightAddress + 8);\n                        int cnt = UNSAFE.getInt(address + 16) + UNSAFE.getInt(rightAddress + 16);\n                        short min = (short) Math.min(UNSAFE.getShort(address + 20), UNSAFE.getShort(rightAddress + 20));\n                        short max = (short) Math.max(UNSAFE.getShort(address + 22), UNSAFE.getShort(rightAddress + 22));\n\n                        UNSAFE.putLong(address + 8, sum);\n                        UNSAFE.putInt(address + 16, cnt);\n                        UNSAFE.putShort(address + 20, min);\n                        UNSAFE.putShort(address + 22, max);\n                        break;\n                    }\n\n                    int len = UNSAFE.getInt(address);\n\n                    if (len == 0) {\n                        UNSAFE.copyMemory(rightAddress, address, length + 24);\n                        break;\n                    }\n                }\n            }\n        }\n\n        public Map<String, Aggregate> build() {\n            TreeMap<String, Aggregate> set = new TreeMap<>();\n\n            for (long offset = 0; offset < SIZE; offset += 128) {\n                long address = pointer + offset;\n                int length = UNSAFE.getInt(address);\n\n                if (length != 0) {\n                    byte[] array = new byte[length - 1];\n                    UNSAFE.copyMemory(null, address + 24, array, Unsafe.ARRAY_BYTE_BASE_OFFSET, array.length);\n                    String key = new String(array);\n\n                    long sum = UNSAFE.getLong(address + 8);\n                    int cnt = UNSAFE.getInt(address + 16);\n                    short min = UNSAFE.getShort(address + 20);\n                    short max = UNSAFE.getShort(address + 22);\n\n                    Aggregate aggregate = new Aggregate(min, max, sum, cnt);\n                    set.put(key, aggregate);\n                }\n            }\n\n            return set;\n        }\n\n        private static void alloc(long reference, long length, long hash, long address) {\n            UNSAFE.putInt(address, (int) length);\n            UNSAFE.putInt(address + 4, (int) hash);\n            UNSAFE.putShort(address + 20, Short.MAX_VALUE);\n            UNSAFE.putShort(address + 22, Short.MIN_VALUE);\n            UNSAFE.copyMemory(reference, address + 24, length);\n        }\n\n        private static long offset(long hash) {\n            return hash & MASK;\n        }\n\n        private static long next(long prev) {\n            return (prev + 128) & (SIZE - 1);\n        }\n\n        private static boolean equal(long leftAddress, long leftWord, long rightAddress, long length) {\n            while (length > 8) {\n                long left = UNSAFE.getLong(leftAddress);\n                long right = UNSAFE.getLong(rightAddress);\n\n                if (left != right) {\n                    return false;\n                }\n\n                leftAddress += 8;\n                rightAddress += 8;\n                length -= 8;\n            }\n\n            return leftWord == word(rightAddress);\n        }\n\n        private static boolean equal(long leftAddress, long rightAddress, long length) {\n            do {\n                long left = UNSAFE.getLong(leftAddress);\n                long right = UNSAFE.getLong(rightAddress);\n\n                if (left != right) {\n                    return false;\n                }\n\n                leftAddress += 8;\n                rightAddress += 8;\n                length -= 8;\n            } while (length > 0);\n\n            return true;\n        }\n    }\n\n    private static class Aggregator extends Thread {\n\n        private final AtomicInteger counter;\n        private final AtomicReference<Aggregates> result;\n        private final long fileAddress;\n        private final long fileSize;\n        private final int segmentCount;\n\n        public Aggregator(AtomicInteger counter, AtomicReference<Aggregates> result,\n                          long fileAddress, long fileSize, int segmentCount) {\n            super(\"aggregator\");\n            this.counter = counter;\n            this.result = result;\n            this.fileAddress = fileAddress;\n            this.fileSize = fileSize;\n            this.segmentCount = segmentCount;\n        }\n\n        @Override\n        public void run() {\n            Aggregates aggregates = new Aggregates();\n\n            for (int segment; (segment = counter.getAndIncrement()) < segmentCount;) {\n                long position = SEGMENT_SIZE * segment;\n                long size = Math.min(SEGMENT_SIZE + 1, fileSize - position);\n                long start = fileAddress + position;\n                long end = start + size;\n\n                if (segment > 0) {\n                    start = next(start);\n                }\n\n                long chunk = (end - start) / 3;\n                long left = next(start + chunk);\n                long right = next(start + chunk + chunk);\n\n                Chunk chunk1 = new Chunk(start, left);\n                Chunk chunk2 = new Chunk(left, right);\n                Chunk chunk3 = new Chunk(right, end);\n\n                while (chunk1.has() && chunk2.has() && chunk3.has()) {\n                    long word1 = word(chunk1.position);\n                    long word2 = word(chunk2.position);\n                    long word3 = word(chunk3.position);\n                    long word4 = word(chunk1.position + 8);\n                    long word5 = word(chunk2.position + 8);\n                    long word6 = word(chunk3.position + 8);\n\n                    long separator1 = separator(word1);\n                    long separator2 = separator(word2);\n                    long separator3 = separator(word3);\n                    long separator4 = separator(word4);\n                    long separator5 = separator(word5);\n                    long separator6 = separator(word6);\n\n                    long pointer1 = find(aggregates, chunk1, word1, word4, separator1, separator4);\n                    long pointer2 = find(aggregates, chunk2, word2, word5, separator2, separator5);\n                    long pointer3 = find(aggregates, chunk3, word3, word6, separator3, separator6);\n\n                    long value1 = value(chunk1);\n                    long value2 = value(chunk2);\n                    long value3 = value(chunk3);\n\n                    Aggregates.update(pointer1, value1);\n                    Aggregates.update(pointer2, value2);\n                    Aggregates.update(pointer3, value3);\n                }\n\n                while (chunk1.has()) {\n                    long word1 = word(chunk1.position);\n                    long word2 = word(chunk1.position + 8);\n\n                    long separator1 = separator(word1);\n                    long separator2 = separator(word2);\n\n                    long pointer = find(aggregates, chunk1, word1, word2, separator1, separator2);\n                    long value = value(chunk1);\n\n                    Aggregates.update(pointer, value);\n                }\n\n                while (chunk2.has()) {\n                    long word1 = word(chunk2.position);\n                    long word2 = word(chunk2.position + 8);\n\n                    long separator1 = separator(word1);\n                    long separator2 = separator(word2);\n\n                    long pointer = find(aggregates, chunk2, word1, word2, separator1, separator2);\n                    long value = value(chunk2);\n\n                    Aggregates.update(pointer, value);\n                }\n\n                while (chunk3.has()) {\n                    long word1 = word(chunk3.position);\n                    long word2 = word(chunk3.position + 8);\n\n                    long separator1 = separator(word1);\n                    long separator2 = separator(word2);\n\n                    long pointer = find(aggregates, chunk3, word1, word2, separator1, separator2);\n                    long value = value(chunk3);\n\n                    Aggregates.update(pointer, value);\n                }\n            }\n\n            while (!result.compareAndSet(null, aggregates)) {\n                Aggregates rights = result.getAndSet(null);\n\n                if (rights != null) {\n                    aggregates.merge(rights);\n                }\n            }\n        }\n\n        private static long next(long position) {\n            while (true) {\n                long word = word(position);\n                long match = word ^ LINE_PATTERN;\n                long line = (match - 0x0101010101010101L) & (~match & 0x8080808080808080L);\n\n                if (line == 0) {\n                    position += 8;\n                    continue;\n                }\n\n                return position + length(line) + 1;\n            }\n        }\n\n        private static long find(Aggregates aggregates, Chunk chunk, long word1, long word2, long separator1, long separator2) {\n            boolean small = (separator1 | separator2) != 0;\n            long start = chunk.position;\n            long hash;\n            long word;\n\n            if (small) {\n                int length1 = length(separator1);\n                int length2 = length(separator2);\n                word1 = mask(word1, separator1);\n                word2 = mask(word2 & WORD_MASK[length1], separator2);\n                hash = mix(word1 ^ word2);\n\n                chunk.position += length1 + (length2 & LENGTH_MASK[length1]) + 1;\n                long pointer = aggregates.find(word1, word2, hash);\n\n                if (pointer != 0) {\n                    return pointer;\n                }\n\n                word = (separator1 == 0) ? word2 : word1;\n            }\n            else {\n                chunk.position += 16;\n                hash = word1 ^ word2;\n\n                while (true) {\n                    word = word(chunk.position);\n                    long separator = separator(word);\n\n                    if (separator == 0) {\n                        chunk.position += 8;\n                        hash ^= word;\n                        continue;\n                    }\n\n                    word = mask(word, separator);\n                    hash = mix(hash ^ word);\n                    chunk.position += length(separator) + 1;\n                    break;\n                }\n            }\n\n            long length = chunk.position - start;\n            return aggregates.put(start, word, length, hash);\n        }\n\n        private static long value(Chunk chunk) {\n            long num = word(chunk.position);\n            long dot = dot(num);\n            long value = value(num, dot);\n            chunk.position += (dot >> 3) + 3;\n            return value;\n        }\n\n        private static long separator(long word) {\n            long match = word ^ COMMA_PATTERN;\n            return (match - 0x0101010101010101L) & (~match & 0x8080808080808080L);\n        }\n\n        private static long mask(long word, long separator) {\n            long mask = separator ^ (separator - 1);\n            return word & mask;\n        }\n\n        private static int length(long separator) {\n            return Long.numberOfTrailingZeros(separator) >>> 3;\n        }\n\n        private static long mix(long x) {\n            long h = x * -7046029254386353131L;\n            h ^= h >>> 35;\n            return h;\n            // h ^= h >>> 32;\n            // return (int) (h ^ h >>> 16);\n        }\n\n        private static long dot(long num) {\n            return Long.numberOfTrailingZeros(~num & DOT_BITS);\n        }\n\n        private static long value(long w, long dot) {\n            long signed = (~w << 59) >> 63;\n            long mask = ~(signed & 0xFF);\n            long digits = ((w & mask) << (28 - dot)) & 0x0F000F0F00L;\n            long abs = ((digits * MAGIC_MULTIPLIER) >>> 32) & 0x3FF;\n            return (abs ^ signed) - signed;\n        }\n    }\n\n    private static class Chunk {\n        final long limit;\n        long position;\n\n        public Chunk(long position, long limit) {\n            this.position = position;\n            this.limit = limit;\n        }\n\n        boolean has() {\n            return position < limit;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_as-com.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.*;\nimport sun.misc.Unsafe;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.lang.reflect.Field;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.atomic.AtomicLongArray;\n\n// based on spullara's submission\n\nclass CalculateAverage_asun {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_256;\n    private static final VectorSpecies<Integer> INT_SPECIES = IntVector.SPECIES_256;\n    private static final int VECTOR_SIZE = 32;\n\n    private static final ByteVector ASC;\n    static {\n        byte[] bytes = new byte[VECTOR_SIZE];\n        for (int i = 0; i < VECTOR_SIZE; i++) {\n            bytes[i] = (byte) i;\n        }\n\n        ASC = ByteVector.fromArray(BYTE_SPECIES, bytes, 0);\n    }\n\n    private static final Unsafe UNSAFE;\n\n    static {\n        try {\n            Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            UNSAFE = (Unsafe) f.get(null);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static AtomicLongArray segmentQueue;\n    @SuppressWarnings(\"FieldMayBeFinal\")\n    // @jdk.internal.vm.annotation.Contended\n    private static volatile int head = 0;\n    @SuppressWarnings(\"FieldMayBeFinal\")\n    // @jdk.internal.vm.annotation.Contended\n    private static volatile int tail = 0;\n    @SuppressWarnings(\"FieldMayBeFinal\")\n    // @jdk.internal.vm.annotation.Contended\n    private static volatile boolean doneQueueing = false;\n\n    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();\n    private static final VarHandle headHandle;\n    private static final VarHandle tailHandle;\n    private static final VarHandle doneHandle;\n\n    static {\n        try {\n            headHandle = LOOKUP.findStaticVarHandle(CalculateAverage_asun.class, \"head\", int.class);\n            tailHandle = LOOKUP.findStaticVarHandle(CalculateAverage_asun.class, \"tail\", int.class);\n            doneHandle = LOOKUP.findStaticVarHandle(CalculateAverage_asun.class, \"doneQueueing\", boolean.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final ArrayBlockingQueue<ByteArrayToResultMap> workerOutput = new ArrayBlockingQueue<>(Runtime.getRuntime().availableProcessors());\n\n    private static class Worker implements Runnable {\n        private long segmentStart;\n        private long segmentEnd;\n\n        private final MemorySegment ms;\n\n        private Worker(MemorySegment ms) {\n            this.ms = ms;\n        }\n\n        @Override\n        public void run() {\n            var resultMap = new ByteArrayToResultMap();\n            var ms = this.ms.asSlice(0);\n            var msAddr = ms.address();\n            var actualLimit = ms.byteSize();\n            var buffer = new byte[100 + VECTOR_SIZE];\n\n            while (pollSegment()) {\n                long startLine;\n                long pos = segmentStart;\n                long limit = segmentEnd;\n                long vectorLimit = Math.min(limit, actualLimit - VECTOR_SIZE);\n                long longLimit = Math.min(limit, actualLimit - 8);\n\n                // int[] lastHashMult = new int[]{ 7, 31, 63, 15, 255, 127, 3, 511 };\n                // IntVector lastMul = IntVector.fromArray(INT_SPECIES, lastHashMult, 0);\n\n                vector: while ((startLine = pos) < vectorLimit) {\n                    long currentPosition = startLine;\n                    ByteVector r;\n                    VectorMask<Byte> m;\n                    int offset = 0;\n\n                    IntVector h = IntVector.zero(INT_SPECIES);\n                    while (true) {\n                        if (currentPosition >= vectorLimit) {\n                            break vector;\n                        }\n\n                        r = ByteVector.fromMemorySegment(BYTE_SPECIES, ms, currentPosition, ByteOrder.LITTLE_ENDIAN);\n                        r.intoArray(buffer, offset);\n                        offset += VECTOR_SIZE;\n                        m = r.eq((byte) ';');\n                        if (m.anyTrue()) {\n                            int firstTrue = m.firstTrue();\n                            currentPosition += firstTrue;\n                            // note: target platform likely does not have AVX-512, so manipulating and using m directly is likely to be slow\n                            ByteVector lastMask = (ByteVector) ASC.lt((byte) firstTrue).toVector();\n                            h = h.mul(31);\n                            h = h.add(r.and(lastMask).reinterpretAsInts());\n                            break;\n                        }\n                        else {\n                            currentPosition += VECTOR_SIZE;\n                            h = h.mul(31);\n                            h = h.add(r.reinterpretAsInts());\n                        }\n                    }\n\n                    // h = h.mul(lastMul);\n\n                    int hash = h.reduceLanes(VectorOperators.ADD);\n\n                    // currentPosition now has index of semicolon\n                    int nameLen = (int) (currentPosition - startLine);\n                    currentPosition++;\n\n                    if (currentPosition >= longLimit) {\n                        break;\n                    }\n\n                    long g = UNSAFE.getLong(msAddr + currentPosition);\n                    // long g = ms.get(ValueLayout.JAVA_LONG_UNALIGNED, currentPosition);\n                    boolean minus = (g & 0xff) == '-';\n                    long minusL = (minus ? 1L : 0L) - 1;\n                    int negative = minus ? -1 : 1;\n\n                    // 00101101 MINUS\n                    // 00101110 PERIOD\n                    // 00001101 CR\n                    // 00001010 LF\n                    // 00110000 0\n                    // 00111001 9\n\n                    // scan for LF\n                    long lf = ~g & 0x20202020202020L;\n                    int tzc = Long.numberOfTrailingZeros(lf);\n                    long bytesToLF = tzc / 8;\n\n                    int shift = 72 - tzc & 0b111000;\n\n                    long reversedDigits = Long.reverseBytes(g & (0xFFFFFFFFFFFFFF00L | minusL)) >> shift;\n\n                    long temp = (reversedDigits & 0xf)\n                            + 10 * ((reversedDigits >> 16) & 0xf)\n                            + 100 * ((reversedDigits >> 24) & 0xf);\n\n                    temp *= negative;\n\n                    currentPosition += bytesToLF + 1;\n\n                    resultMap.putOrMerge(buffer, 0, nameLen, temp, hash);\n                    pos = currentPosition;\n\n                }\n\n                while ((startLine = pos) < limit) {\n                    long currentPosition = startLine;\n                    byte b;\n                    int offset = 0;\n\n                    while (currentPosition != segmentEnd && (b = ms.get(ValueLayout.JAVA_BYTE, currentPosition++)) != ';') {\n                        buffer[offset++] = b;\n                    }\n                    // Invariant: the remaining length is less than VECTOR_SIZE, so we can just run the last round of hashing\n                    int hash = ByteVector.fromArray(BYTE_SPECIES, buffer, 0, ASC.lt((byte) offset))\n                            .reinterpretAsInts()\n                            // .mul(lastMul)\n                            .reduceLanes(VectorOperators.ADD);\n\n                    int temp;\n                    int negative = 1;\n                    // Inspired by @yemreinci to unroll this even further\n                    if (ms.get(ValueLayout.JAVA_BYTE, currentPosition) == '-') {\n                        negative = -1;\n                        currentPosition++;\n                    }\n                    if (ms.get(ValueLayout.JAVA_BYTE, currentPosition + 1) == '.') {\n                        temp = negative * ((ms.get(ValueLayout.JAVA_BYTE, currentPosition) - '0') * 10 + (ms.get(ValueLayout.JAVA_BYTE, currentPosition + 2) - '0'));\n                        currentPosition += 3;\n                    }\n                    else {\n                        temp = negative * ((ms.get(ValueLayout.JAVA_BYTE, currentPosition) - '0') * 100\n                                + ((ms.get(ValueLayout.JAVA_BYTE, currentPosition + 1) - '0') * 10 + (ms.get(ValueLayout.JAVA_BYTE, currentPosition + 3) - '0')));\n                        currentPosition += 4;\n                    }\n                    if (ms.get(ValueLayout.JAVA_BYTE, currentPosition) == '\\r') {\n                        currentPosition++;\n                    }\n                    currentPosition++;\n                    resultMap.putOrMerge(buffer, 0, offset, temp, hash);\n                    pos = currentPosition;\n                }\n            }\n\n            workerOutput.add(resultMap);\n        }\n\n        private boolean pollSegment() {\n            int head;\n            int tail;\n\n            do {\n                head = (int) headHandle.getAcquire();\n                tail = (int) tailHandle.getAcquire();\n\n                while (head >= tail) {\n                    if ((boolean) doneHandle.getAcquire()) {\n                        return false;\n                    }\n\n                    head = (int) headHandle.getAcquire();\n                    tail = (int) tailHandle.getAcquire();\n                }\n            } while (!headHandle.compareAndSet(head, head + 1));\n\n            segmentStart = segmentQueue.getPlain(head * 2);\n            segmentEnd = segmentQueue.getPlain(head * 2 + 1);\n\n            return true;\n        }\n\n    }\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        // long start = System.currentTimeMillis();\n        var filename = args.length == 0 ? FILE : args[0];\n        var file = new File(filename);\n\n        @SuppressWarnings(\"resource\")\n        var fileChannel = (FileChannel) Files.newByteChannel(Path.of(filename), StandardOpenOption.READ);\n        var ms = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size(), Arena.global());\n\n        long fileSize = file.length();\n        long segmentSize = 10_000_000;\n        int numberOfSegments = (int) (file.length() / segmentSize + 1) * 2;\n        segmentQueue = new AtomicLongArray(numberOfSegments);\n        int tail = 0;\n\n        int processors = Runtime.getRuntime().availableProcessors();\n\n        Thread.ofPlatform().daemon().start(() -> {\n            for (int i = 0; i < processors - 1; i++) {\n                Thread.ofPlatform().daemon().start(new Worker(ms));\n            }\n\n            new Worker(ms).run();\n        });\n\n        long segStart = 0;\n        while (segStart < fileSize) {\n            long segEnd = findSegment(ms, Math.min(segStart + segmentSize, fileSize), fileSize);\n            segmentQueue.setRelease(tail * 2, segStart);\n            segmentQueue.setRelease(tail * 2 + 1, segEnd);\n            tailHandle.setRelease(++tail);\n\n            segStart = segEnd;\n        }\n\n        doneHandle.setRelease(true);\n\n        // System.out.println(System.currentTimeMillis() - start);\n\n        var resultsMap = new TreeMap<String, Result>();\n        for (int i = 0; i < processors; i++) {\n            var result = workerOutput.take();\n\n            // System.out.println(i + \" \" + (System.currentTimeMillis() - start));\n\n            for (Entry e : result.getAll()) {\n                resultsMap.merge(new String(e.key()), e.value(), CalculateAverage_asun::merge);\n            }\n\n            // System.out.println(i + \" \" + (System.currentTimeMillis() - start));\n        }\n\n        System.out.println(resultsMap);\n\n        // System.out.println(System.currentTimeMillis() - start);\n\n        Runtime.getRuntime().halt(0);\n    }\n\n    private static Result merge(Result v, Result value) {\n        return merge(v, value.min, value.max, value.sum, value.count);\n    }\n\n    private static Result merge(Result v, long value, long value1, long value2, long value3) {\n        v.min = Math.min(v.min, value);\n        v.max = Math.max(v.max, value1);\n        v.sum += value2;\n        v.count += value3;\n        return v;\n    }\n\n    private static long findSegment(MemorySegment ms, long location, long fileSize) {\n        while (location < fileSize) {\n            if (ms.get(ValueLayout.JAVA_BYTE, location) == '\\n') {\n                location++;\n                break;\n            }\n\n            location++;\n        }\n        return location;\n    }\n\n    static class Result {\n        long min, max, sum;\n        long count;\n\n        Result(long value) {\n            min = max = sum = value;\n            this.count = 1;\n        }\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round((sum / 10.0) / count) + \"/\" + round(max);\n        }\n\n        double round(double v) {\n            return Math.round(v * 10.0) / 10.0;\n        }\n\n        double round(long v) {\n            return v / 10.0;\n        }\n\n    }\n\n    record Entry(byte[] key, Result value) {\n    }\n\n    static class ByteArrayToResultMap {\n        public static final int MAPSIZE = 1024 * 128;\n        Result[] slots = new Result[MAPSIZE];\n        byte[][] keys = new byte[MAPSIZE][];\n\n        public void putOrMerge(byte[] key, int offset, int size, long temp, int hash) {\n            int slot = hash & (slots.length - 1);\n            var slotValue = slots[slot];\n            // Linear probe for open slot\n            while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n                slot = (slot + 1) & (slots.length - 1);\n                slotValue = slots[slot];\n            }\n            Result value = slotValue;\n            if (value == null) {\n                slots[slot] = new Result(temp);\n                byte[] bytes = new byte[size];\n                System.arraycopy(key, offset, bytes, 0, size);\n                keys[slot] = bytes;\n            }\n            else {\n                value.min = Math.min(value.min, temp);\n                value.max = Math.max(value.max, temp);\n                value.sum += temp;\n                value.count += 1;\n            }\n        }\n\n        // Get all pairs\n        public List<Entry> getAll() {\n            List<Entry> result = new ArrayList<>(slots.length);\n            for (int i = 0; i < slots.length; i++) {\n                Result slotValue = slots[i];\n                if (slotValue != null) {\n                    result.add(new Entry(keys[i], slotValue));\n                }\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_baseline.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collector;\n\npublic class CalculateAverage_baseline {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    public static void main(String[] args) throws IOException {\n        // Map<String, Double> measurements1 = Files.lines(Paths.get(FILE))\n        // .map(l -> l.split(\";\"))\n        // .collect(groupingBy(m -> m[0], averagingDouble(m -> Double.parseDouble(m[1]))));\n        //\n        // measurements1 = new TreeMap<>(measurements1.entrySet()\n        // .stream()\n        // .collect(toMap(e -> e.getKey(), e -> Math.round(e.getValue() * 10.0) / 10.0)));\n        // System.out.println(measurements1);\n\n        Collector<Measurement, MeasurementAggregator, ResultRow> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    a.min = Math.min(a.min, m.value);\n                    a.max = Math.max(a.max, m.value);\n                    a.sum += m.value;\n                    a.count++;\n                },\n                (agg1, agg2) -> {\n                    var res = new MeasurementAggregator();\n                    res.min = Math.min(agg1.min, agg2.min);\n                    res.max = Math.max(agg1.max, agg2.max);\n                    res.sum = agg1.sum + agg2.sum;\n                    res.count = agg1.count + agg2.count;\n\n                    return res;\n                },\n                agg -> {\n                    return new ResultRow(agg.min, (Math.round(agg.sum * 10.0) / 10.0) / agg.count, agg.max);\n                });\n\n        Map<String, ResultRow> measurements = new TreeMap<>(Files.lines(Paths.get(FILE))\n                .map(l -> new Measurement(l.split(\";\")))\n                .collect(groupingBy(m -> m.station(), collector)));\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_baseline_original_rounding.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collector;\n\n/**\n * This is the original version of the baseline implementation. It contains a\n * rounding bug, which can cause calculated mean values to be off by 0.1. See\n * {@link CalculateAverage_baseline} for the correct behavior. This version here\n * is only kept for reference, in particular for determining whether an\n * implementation is valid with the old behavior. Any new or updated entries to\n * the challenge must conform to the correct behavior as implemented by\n * {@code CalculateAverage_baseline}.\n */\npublic class CalculateAverage_baseline_original_rounding {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    public static void main(String[] args) throws IOException {\n        // Map<String, Double> measurements1 = Files.lines(Paths.get(FILE))\n        // .map(l -> l.split(\";\"))\n        // .collect(groupingBy(m -> m[0], averagingDouble(m -> Double.parseDouble(m[1]))));\n        //\n        // measurements1 = new TreeMap<>(measurements1.entrySet()\n        // .stream()\n        // .collect(toMap(e -> e.getKey(), e -> Math.round(e.getValue() * 10.0) / 10.0)));\n        // System.out.println(measurements1);\n\n        Collector<Measurement, MeasurementAggregator, ResultRow> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    a.min = Math.min(a.min, m.value);\n                    a.max = Math.max(a.max, m.value);\n                    a.sum += m.value;\n                    a.count++;\n                },\n                (agg1, agg2) -> {\n                    var res = new MeasurementAggregator();\n                    res.min = Math.min(agg1.min, agg2.min);\n                    res.max = Math.max(agg1.max, agg2.max);\n                    res.sum = agg1.sum + agg2.sum;\n                    res.count = agg1.count + agg2.count;\n\n                    return res;\n                },\n                agg -> {\n                    return new ResultRow(agg.min, agg.sum / agg.count, agg.max);\n                });\n\n        Map<String, ResultRow> measurements = new TreeMap<>(Files.lines(Paths.get(FILE))\n                .map(l -> new Measurement(l.split(\";\")))\n                .collect(groupingBy(m -> m.station(), collector)));\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_berry120.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.TreeSet;\n\npublic class CalculateAverage_berry120 {\n\n    private static final String FILE = \"./measurements.txt\";\n    // TODO: Tweak this number?\n    public static final int NUM_VIRTUAL_THREADS = 1000;\n    public static final boolean DEBUG = false;\n\n    static class TemperatureSummary implements Comparable<TemperatureSummary> {\n        byte[] name;\n        int min;\n        int max;\n        int total;\n        int sampleCount;\n\n        public TemperatureSummary(byte[] name, int min, int max, int total, int sampleCount) {\n            this.name = name;\n            this.min = min;\n            this.max = max;\n            this.total = total;\n            this.sampleCount = sampleCount;\n        }\n\n        @Override\n        public int compareTo(TemperatureSummary o) {\n            return new String(name).compareTo(new String(o.name));\n        }\n\n        @Override\n        public String toString() {\n            return \"TemperatureSummary{\" +\n                    \"name=\" + new String(name) +\n                    \", min=\" + min +\n                    \", max=\" + max +\n                    \", total=\" + total +\n                    \", sampleCount=\" + sampleCount +\n                    '}';\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        long time = System.currentTimeMillis();\n\n        Path path = Path.of(FILE);\n        RandomAccessFile file = new RandomAccessFile(path.toFile(), \"r\");\n        FileChannel channel = file.getChannel();\n        long size = Files.size(path);\n        int splitSize = size < 10_000_000 ? 1 : (NUM_VIRTUAL_THREADS - 1);\n        long inc = (int) (size / splitSize);\n\n        List<Long> positions = new ArrayList<>();\n        positions.add(0L);\n\n        MemorySegment segment = channel.map(FileChannel.MapMode.READ_ONLY, 0, Files.size(path), Arena.ofShared());\n\n        long pos = 0;\n        for (int i = 0; i < splitSize; i++) {\n            long endPos = pos + inc - 1;\n            while (segment.get(ValueLayout.JAVA_BYTE, endPos) != '\\n') {\n                endPos--;\n            }\n            pos = endPos + 1;\n            positions.add(pos);\n        }\n        positions.add(size);\n\n        if (DEBUG)\n            System.out.println(\"WORKED OUT SPLITS: \" + (System.currentTimeMillis() - time));\n\n        List<Thread> threads = new ArrayList<>(NUM_VIRTUAL_THREADS);\n\n        List<Map<?, TemperatureSummary>> maps = Collections.synchronizedList(new ArrayList<>());\n\n        for (int split = 0; split < positions.size() - 1; split++) {\n\n            long position = positions.get(split);\n            long positionEnd = positions.get(split + 1);\n\n            threads.add(Thread.ofVirtual().start(() -> {\n\n                // TODO: Custom faster map?\n                Map<Integer, TemperatureSummary> map = new HashMap<>();\n                maps.add(map);\n\n                // Care much less about this map, only used if collisions in the first\n                Map<String, TemperatureSummary> backupMap = new HashMap<>();\n                maps.add(backupMap);\n\n                boolean processingPlaceName = true;\n\n                byte[] placeName = new byte[100];\n                int placeNameIdx = 0;\n\n                byte[] digits = new byte[100];\n                int digitIdx = 0;\n\n                for (long address = position; address < positionEnd; address++) {\n                    byte b = segment.get(ValueLayout.JAVA_BYTE, address);\n\n                    if (b == 10) {\n                        int rollingHash = 5381;\n                        for (int i = 0; i < placeNameIdx; i++) {\n                            rollingHash = (((rollingHash << 5) + rollingHash) + placeName[i]) & 0xFFFFF;\n                        }\n\n                        var existingTemperatureSummary = map.get(rollingHash);\n                        int num = parse(digits, digitIdx - 1);\n\n                        if (existingTemperatureSummary == null) {\n                            byte[] thisPlace = new byte[placeNameIdx];\n                            System.arraycopy(placeName, 0, thisPlace, 0, placeNameIdx);\n                            map.put(rollingHash, new TemperatureSummary(thisPlace, num, num, num, 1));\n                        }\n                        else if (!Arrays.equals(placeName, 0, placeNameIdx, existingTemperatureSummary.name, 0, existingTemperatureSummary.name.length)) {\n\n                            /*\n                             * This block will be slow - don't really care, should be very rare\n                             */\n                            if (DEBUG)\n                                System.out.println(\"BAD: COLLISION!\");\n                            byte[] thisPlace = new byte[placeNameIdx];\n                            System.arraycopy(placeName, 0, thisPlace, 0, placeNameIdx);\n                            String backupKey = new String(thisPlace);\n                            var backupExistingTemperatureSummary = backupMap.get(backupKey);\n\n                            if (backupExistingTemperatureSummary == null) {\n                                backupMap.put(backupKey, new TemperatureSummary(thisPlace, num, num, num, 1));\n                            }\n                            else {\n                                backupExistingTemperatureSummary.max = (Math.max(num, backupExistingTemperatureSummary.max));\n                                backupExistingTemperatureSummary.min = (Math.min(num, backupExistingTemperatureSummary.min));\n                                backupExistingTemperatureSummary.total += num;\n                                backupExistingTemperatureSummary.sampleCount++;\n                            }\n                            /*\n                             * End slow block\n                             */\n                        }\n                        else {\n\n                            existingTemperatureSummary.max = (Math.max(num, existingTemperatureSummary.max));\n                            existingTemperatureSummary.min = (Math.min(num, existingTemperatureSummary.min));\n                            existingTemperatureSummary.total += num;\n                            existingTemperatureSummary.sampleCount++;\n                        }\n\n                        processingPlaceName = true;\n                        placeNameIdx = 0;\n                        digitIdx = 0;\n                    }\n                    else if (b == ';') {\n                        processingPlaceName = false;\n                    }\n                    else if (processingPlaceName) {\n                        placeName[placeNameIdx++] = b;\n                    }\n                    else {\n                        digits[digitIdx++] = b;\n                    }\n                }\n            }));\n\n        }\n\n        if (DEBUG) {\n            System.out.println(\"STARTED THREADS: \" + (System.currentTimeMillis() - time));\n        }\n\n        for (Thread thread : threads) {\n            thread.join();\n        }\n\n        TreeMap<String, TemperatureSummary> mergedMap = new TreeMap<>();\n\n        for (var map : maps) {\n            for (TemperatureSummary t1 : map.values()) {\n                if (t1 == null)\n                    continue;\n\n                var t2 = mergedMap.get(new String(t1.name));\n\n                if (t2 == null) {\n                    mergedMap.put(new String(t1.name), t1);\n                }\n                else {\n                    var merged = new TemperatureSummary(t1.name, Math.min(t1.min, t2.min), Math.max(t1.max, t2.max), t1.total + t2.total,\n                            t1.sampleCount + t2.sampleCount);\n                    mergedMap.put(new String(t1.name), merged);\n                }\n            }\n        }\n\n        boolean first = true;\n        StringBuilder output = new StringBuilder(16_000);\n        output.append(\"{\");\n        for (var value : new TreeSet<>(mergedMap.values())) {\n            if (first) {\n                first = false;\n            }\n            else {\n                output.append(\", \");\n            }\n            output.append(new String(value.name)).append(\"=\").append((double) value.min / 10).append(\"/\")\n                    .append(String.format(\"%.1f\", ((double) value.total / value.sampleCount / 10))).append(\"/\").append((double) value.max / 10);\n        }\n        output.append(\"}\");\n\n        System.out.println(output);\n        // if (DEBUG)\n        // System.out.println(\"CORRECT: \" + output.toString().equals(CORRECT));\n\n        if (DEBUG)\n            System.out.println(\"TOTAL TIME: \" + (System.currentTimeMillis() - time));\n\n    }\n\n    private static int parse(byte[] arr, int len) {\n        // TODO: SIMD?\n        int num = 0;\n        for (int mI = len, m = 1; mI >= 0; mI--) {\n            byte d = arr[mI];\n            if (d == '.') {\n            }\n            else if (d == '-') {\n                num = -num;\n                m *= 10;\n            }\n            else {\n                num += (d & 0xF) * m;\n                m *= 10;\n            }\n        }\n        return num;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_bjhara.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.*;\nimport java.nio.channels.*;\nimport java.nio.file.*;\nimport java.util.*;\nimport java.util.stream.*;\n\npublic class CalculateAverage_bjhara {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class Measurement {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public static Measurement combine(Measurement m1, Measurement m2) {\n            var mres = new Measurement();\n            mres.min = m1.min < m2.min ? m1.min : m2.min;\n            mres.max = m1.max > m2.max ? m1.max : m2.max;\n            mres.sum = m1.sum + m2.sum;\n            mres.count = m1.count + m2.count;\n            return mres;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE),\n                EnumSet.of(StandardOpenOption.READ))) {\n\n            var cities = splitFileChannel(fileChannel)\n                    .parallel()\n                    .map(CalculateAverage_bjhara::parseBuffer)\n                    .collect(Collectors.reducing(CalculateAverage_bjhara::combineMaps));\n\n            var sortedCities = new TreeMap<>(cities.orElseThrow());\n            System.out.println(sortedCities);\n        }\n    }\n\n    private static Map<String, Measurement> combineMaps(Map<String, Measurement> map1,\n                                                        Map<String, Measurement> map2) {\n        for (var entry : map2.entrySet()) {\n            map1.merge(entry.getKey(), entry.getValue(), Measurement::combine);\n        }\n\n        return map1;\n    }\n\n    private static Stream<ByteBuffer> splitFileChannel(final FileChannel fileChannel) throws IOException {\n        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(new Iterator<ByteBuffer>() {\n            private static final long CHUNK_SIZE = 1024 * 1024 * 10L;\n\n            private final long size = fileChannel.size();\n            private long start = 0;\n\n            @Override\n            public boolean hasNext() {\n                return start < size;\n            }\n\n            @Override\n            public ByteBuffer next() {\n                try {\n                    MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, start,\n                            Math.min(CHUNK_SIZE, size - start));\n\n                    // don't split the data in the middle of lines\n                    // find the closest previous newline\n                    int realEnd = mappedByteBuffer.limit() - 1;\n                    while (mappedByteBuffer.get(realEnd) != '\\n')\n                        realEnd--;\n\n                    realEnd++;\n\n                    mappedByteBuffer.limit(realEnd);\n                    start += realEnd;\n\n                    return mappedByteBuffer;\n                }\n                catch (IOException ex) {\n                    throw new UncheckedIOException(ex);\n                }\n            }\n        }, Spliterator.IMMUTABLE), false);\n    }\n\n    private static Map<String, Measurement> parseBuffer(ByteBuffer bb) {\n        Map<String, Measurement> cities = new HashMap<>();\n\n        final int limit = bb.limit();\n        final byte[] buffer = new byte[128];\n\n        while (bb.position() < limit) {\n            final int currentPosition = bb.position();\n\n            // find the ; separator\n            int separator = currentPosition;\n            while (separator != limit && bb.get(separator) != ';')\n                separator++;\n\n            // find the end of the line\n            int end = separator + 1;\n            while (end != limit && !Character.isWhitespace((char) bb.get(end)))\n                end++;\n\n            // get the name as a string\n            int nameLength = separator - currentPosition;\n            bb.get(buffer, 0, nameLength);\n            String city = new String(buffer, 0, nameLength);\n\n            // get rid of the separator\n            bb.get();\n\n            // get the double value\n            int valueLength = end - separator - 1;\n            bb.get(buffer, 0, valueLength);\n            String valueStr = new String(buffer, 0, valueLength);\n            double value = Double.parseDouble(valueStr);\n\n            // and get rid of the new line (handle both kinds)\n            byte newline = bb.get();\n            if (newline == '\\r')\n                bb.get();\n\n            // update the map with the new measurement\n            Measurement agg = cities.get(city);\n            if (agg == null) {\n                agg = new Measurement();\n                cities.put(city, agg);\n            }\n\n            agg.min = agg.min < value ? agg.min : value;\n            agg.max = agg.max > value ? agg.max : value;\n            agg.sum += value;\n            agg.count++;\n        }\n\n        return cities;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_breejesh.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class CalculateAverage_breejesh {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int TWO_BYTE_TO_INT = 480 + 48; // 48 is the ASCII code for '0'\n    private static final int THREE_BYTE_TO_INT = 4800 + 480 + 48;\n\n    private static final class Measurement {\n\n        private int min;\n        private int max;\n        private int total;\n        private int count;\n\n        public Measurement(int value) {\n            this.min = value;\n            this.max = value;\n            this.total = value;\n            this.count = 1;\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder result = new StringBuilder();\n            result.append(min / 10.0);\n            result.append(\"/\");\n            result.append(Math.round(((double) total) / count) / 10.0);\n            result.append(\"/\");\n            result.append(max / 10.0);\n            return result.toString();\n        }\n\n        private void append(int min, int max, int total, int count) {\n            if (min < this.min)\n                this.min = min;\n            if (max > this.max)\n                this.max = max;\n            this.total += total;\n            this.count += count;\n        }\n\n        public void append(int value) {\n            append(value, value, value, 1);\n        }\n\n        public void merge(Measurement other) {\n            append(other.min, other.max, other.total, other.count);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // long start = System.currentTimeMillis();\n        // Find system details to determine cores and\n        var file = new File(args.length > 0 ? args[0] : FILE);\n        long fileSize = file.length();\n        var numberOfCores = fileSize > 1_000_000 ? Runtime.getRuntime().availableProcessors() : 1;\n        var splitSectionSize = (int) Math.min(Integer.MAX_VALUE, fileSize / numberOfCores); // bytebuffer position is an int, so can be max Integer.MAX_VALUE\n        var segmentCount = (int) (fileSize / splitSectionSize);\n\n        // Divide file into segments\n        ExecutorService executor = Executors.newFixedThreadPool(segmentCount);\n        List<CompletableFuture<Map<String, Measurement>>> futures = new ArrayList<>();\n        for (int i = 0; i < segmentCount; i++) {\n            long sectionStart = i * (long) splitSectionSize;\n            long sectionEnd = Math.min(fileSize, sectionStart + splitSectionSize + 100);\n            var fileChannel = (FileChannel) Files.newByteChannel(file.toPath(), StandardOpenOption.READ);\n            CompletableFuture<Map<String, Measurement>> future = CompletableFuture.supplyAsync(() -> {\n                MappedByteBuffer currentBuffer = null;\n                try {\n                    currentBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, sectionStart, sectionEnd - sectionStart);\n                }\n                catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n                // Skip till new line for unequal segments, not to be done for first section\n                if (sectionStart > 0) {\n                    while (currentBuffer.get() != '\\n')\n                        ;\n                }\n                Map<String, Measurement> map = new HashMap<>();\n                while (currentBuffer.position() < splitSectionSize) {\n                    // Read station\n                    String str = getStationFromBuffer(currentBuffer);\n                    // Read number\n                    int value = getValueFromBuffer(currentBuffer);\n                    if (map.containsKey(str)) {\n                        map.get(str).append(value);\n                    }\n                    else {\n                        map.put(str, new Measurement(value));\n                    }\n                }\n                return map;\n            }, executor);\n            futures.add(future);\n        }\n\n        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();\n        Map<String, Measurement> finalMap = new TreeMap<>();\n        for (CompletableFuture<Map<String, Measurement>> future : futures) {\n            Map<String, Measurement> map = future.get();\n            map.keySet().stream().forEach(\n                    key -> {\n                        if (finalMap.containsKey(key)) {\n                            finalMap.get(key).merge(map.get(key));\n                        }\n                        else {\n                            finalMap.put(key, map.get(key));\n                        }\n                    });\n        }\n\n        System.out.println(finalMap);\n        // System.out.printf(\"Time %s\", System.currentTimeMillis() - start);\n        System.exit(0);\n    }\n\n    private static String getStationFromBuffer(MappedByteBuffer currentBuffer) {\n        byte currentByte;\n        var byteCounter = 0;\n        var buffer = new byte[100];\n        while ((currentByte = currentBuffer.get()) != ';') {\n            buffer[byteCounter++] = currentByte;\n        }\n        return new String(buffer, 0, byteCounter, StandardCharsets.UTF_8);\n    }\n\n    private static int getValueFromBuffer(MappedByteBuffer currentBuffer) {\n        int value;\n        byte[] nums = new byte[4];\n        currentBuffer.get(nums);\n        if (nums[1] == '.') {\n            // case of n.n\n            value = (nums[0] * 10 + nums[2] - TWO_BYTE_TO_INT);\n        }\n        else {\n            if (nums[3] == '.') {\n                // case of -nn.n\n                value = -(nums[1] * 100 + nums[2] * 10 + currentBuffer.get() - THREE_BYTE_TO_INT);\n            }\n            else if (nums[0] == '-') {\n                // case of -n.n\n                value = -(nums[1] * 10 + nums[3] - TWO_BYTE_TO_INT);\n            }\n            else {\n                // case of nn.n\n                value = (nums[0] * 100 + nums[1] * 10 + nums[3] - THREE_BYTE_TO_INT);\n            }\n            currentBuffer.get(); // new line\n        }\n        return value;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_bufistov.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport static java.lang.Math.toIntExact;\n\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.time.Instant;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.concurrent.Future;\n\nclass ByteArrayWrapper {\n    private final byte[] data;\n\n    public ByteArrayWrapper(byte[] data) {\n        this.data = data;\n    }\n\n    @Override\n    public boolean equals(Object other) {\n        return Arrays.equals(data, ((ByteArrayWrapper) other).data);\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(data);\n    }\n}\n\npublic class CalculateAverage_bufistov {\n\n    static class ResultRow {\n        byte[] station;\n\n        String stationString;\n        long min, max, count, suma;\n\n        ResultRow() {\n        }\n\n        ResultRow(byte[] station, long value) {\n            this.station = new byte[station.length];\n            System.arraycopy(station, 0, this.station, 0, station.length);\n            this.min = value;\n            this.max = value;\n            this.count = 1;\n            this.suma = value;\n        }\n\n        ResultRow(long value) {\n            this.min = value;\n            this.max = value;\n            this.count = 1;\n            this.suma = value;\n        }\n\n        void setStation(long startPosition, long endPosition) {\n            this.station = new byte[(int) (endPosition - startPosition)];\n            for (int i = 0; i < this.station.length; ++i) {\n                this.station[i] = UNSAFE.getByte(startPosition + i);\n            }\n        }\n\n        public String toString() {\n            stationString = new String(station, StandardCharsets.UTF_8);\n            return stationString + \"=\" + round(min / 10.0) + \"/\" + round(suma / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        void update(long newValue) {\n            this.count += 1;\n            this.suma += newValue;\n            if (newValue < this.min) {\n                this.min = newValue;\n            }\n            else if (newValue > this.max) {\n                this.max = newValue;\n            }\n        }\n\n        ResultRow merge(ResultRow another) {\n            this.count += another.count;\n            this.suma += another.suma;\n            this.min = Math.min(this.min, another.min);\n            this.max = Math.max(this.max, another.max);\n            return this;\n        }\n    }\n\n    static class OpenHash {\n        ResultRow[] data;\n        int dataSizeMask;\n\n        // ResultRow metrics = new ResultRow();\n\n        public OpenHash(int capacityPow2) {\n            assert capacityPow2 <= 20;\n            int dataSize = 1 << capacityPow2;\n            dataSizeMask = dataSize - 1;\n            data = new ResultRow[dataSize];\n        }\n\n        int hashByteArray(byte[] array) {\n            int result = 0;\n            long mask = 0;\n            for (int i = 0; i < array.length; ++i, mask = ((mask + 1) & 3)) {\n                result += array[i] << mask;\n            }\n            return result & dataSizeMask;\n        }\n\n        void merge(byte[] station, long value, int hashValue) {\n            while (data[hashValue] != null && !Arrays.equals(station, data[hashValue].station)) {\n                hashValue += 1;\n                hashValue &= dataSizeMask;\n            }\n            if (data[hashValue] == null) {\n                data[hashValue] = new ResultRow(station, value);\n            }\n            else {\n                data[hashValue].update(value);\n            }\n            // metrics.update(delta);\n        }\n\n        void merge(byte[] station, long value) {\n            merge(station, value, hashByteArray(station));\n        }\n\n        void merge(final long startPosition, long endPosition, int hashValue, long value) {\n            while (data[hashValue] != null && !equalsToStation(startPosition, endPosition, data[hashValue].station)) {\n                hashValue += 1;\n                hashValue &= dataSizeMask;\n            }\n            if (data[hashValue] == null) {\n                data[hashValue] = new ResultRow(value);\n                data[hashValue].setStation(startPosition, endPosition);\n            }\n            else {\n                data[hashValue].update(value);\n            }\n        }\n\n        boolean equalsToStation(long startPosition, long endPosition, byte[] station) {\n            if (endPosition - startPosition != station.length) {\n                return false;\n            }\n            for (int i = 0; i < station.length; ++i, ++startPosition) {\n                if (UNSAFE.getByte(startPosition) != station[i])\n                    return false;\n            }\n            return true;\n        }\n\n        HashMap<ByteArrayWrapper, ResultRow> toJavaHashMap() {\n            HashMap<ByteArrayWrapper, ResultRow> result = new HashMap<>(20000);\n            for (int i = 0; i < data.length; ++i) {\n                if (data[i] != null) {\n                    var key = new ByteArrayWrapper(data[i].station);\n                    result.put(key, data[i]);\n                }\n            }\n            return result;\n        }\n    }\n\n    static final Unsafe UNSAFE;\n\n    static {\n        try {\n            Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            unsafe.setAccessible(true);\n            UNSAFE = (Unsafe) unsafe.get(Unsafe.class);\n        }\n        catch (Throwable e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    static final long LINE_SEPARATOR = '\\n';\n\n    public static class FileRead implements Callable<HashMap<ByteArrayWrapper, ResultRow>> {\n\n        private final FileChannel fileChannel;\n\n        private long currentLocation;\n        private long bytesToRead;\n\n        private static final int hashCapacityPow2 = 18;\n\n        static final int hashCapacityMask = (1 << hashCapacityPow2) - 1;\n\n        public FileRead(FileChannel fileChannel, long startLocation, long bytesToRead, boolean firstSegment) {\n            this.fileChannel = fileChannel;\n            this.currentLocation = startLocation;\n            this.bytesToRead = bytesToRead;\n        }\n\n        @Override\n        public HashMap<ByteArrayWrapper, ResultRow> call() throws IOException {\n            try {\n                OpenHash openHash = new OpenHash(hashCapacityPow2);\n                log(\"Reading the channel: \" + currentLocation + \":\" + bytesToRead);\n                if (currentLocation > 0) {\n                    toLineBeginPrefix();\n                }\n                toLineBeginSuffix();\n                var memorySegment = fileChannel.map(FileChannel.MapMode.READ_ONLY, currentLocation, bytesToRead, Arena.global());\n                currentLocation = memorySegment.address();\n                processChunk(openHash);\n                log(\"Done Reading the channel: \" + currentLocation + \":\" + bytesToRead);\n                return openHash.toJavaHashMap();\n            }\n            catch (Exception e) {\n                e.printStackTrace();\n                throw e;\n            }\n        }\n\n        byte getByte(long position) throws IOException {\n            MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, position, 1);\n            return byteBuffer.get();\n        }\n\n        void toLineBeginPrefix() throws IOException {\n            while (getByte(currentLocation - 1) != LINE_SEPARATOR) {\n                ++currentLocation;\n                --bytesToRead;\n            }\n        }\n\n        void toLineBeginSuffix() throws IOException {\n            while (getByte(currentLocation + bytesToRead - 1) != LINE_SEPARATOR) {\n                ++bytesToRead;\n            }\n        }\n\n        void processChunk(OpenHash result) {\n            long nameBegin = currentLocation;\n            long nameEnd = -1;\n            long numberBegin = -1;\n            int currentHash = 0;\n            int currentMask = 0;\n            int nameHash = 0;\n            long end = currentLocation + bytesToRead;\n            byte nextByte;\n            for (; currentLocation < end; ++currentLocation) {\n                nextByte = UNSAFE.getByte(currentLocation);\n                if (nextByte == ';') {\n                    nameEnd = currentLocation;\n                    numberBegin = currentLocation + 1;\n                    nameHash = currentHash & hashCapacityMask;\n                }\n                else if (nextByte == LINE_SEPARATOR) {\n                    long value = getValue(numberBegin, currentLocation);\n                    // log(\"Station name: '\" + getStationName(nameBegin, nameEnd) + \"' value: \" + value + \" hash: \" + nameHash);\n                    result.merge(nameBegin, nameEnd, nameHash, value);\n                    nameBegin = currentLocation + 1;\n                    currentHash = 0;\n                    currentMask = 0;\n                }\n                else {\n                    currentHash += (nextByte << currentMask);\n                    currentMask = (currentMask + 1) & 3;\n                }\n            }\n        }\n\n        long getValue(long startLocation, long endLocation) {\n            byte nextByte = UNSAFE.getByte(startLocation);\n            boolean negate = nextByte == '-';\n            long result = negate ? 0 : nextByte - '0';\n            for (long i = startLocation + 1; i < endLocation; ++i) {\n                nextByte = UNSAFE.getByte(i);\n                if (nextByte != '.') {\n                    result *= 10;\n                    result += nextByte - '0';\n                }\n            }\n            return negate ? -result : result;\n        }\n\n        String getStationName(long from, long to) {\n            byte[] bytes = new byte[(int) (to - from)];\n            for (int i = 0; i < bytes.length; ++i) {\n                bytes[i] = UNSAFE.getByte(from + i);\n            }\n            return new String(bytes, StandardCharsets.UTF_8);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        String fileName = \"measurements.txt\";\n        if (args.length > 0 && args[0].length() > 0) {\n            fileName = args[0];\n        }\n        log(\"InputFile: \" + fileName);\n        FileInputStream fileInputStream = new FileInputStream(fileName);\n        int numThreads = 2 * Runtime.getRuntime().availableProcessors();\n        if (args.length > 1) {\n            numThreads = Integer.parseInt(args[1]);\n        }\n        log(\"NumThreads: \" + numThreads);\n        FileChannel channel = fileInputStream.getChannel();\n        final long fileSize = channel.size();\n        long remaining_size = fileSize;\n        long chunk_size = Math.min((fileSize + numThreads - 1) / numThreads, Integer.MAX_VALUE - 5);\n\n        ExecutorService executor = Executors.newFixedThreadPool(numThreads);\n\n        long startLocation = 0;\n        ArrayList<Future<HashMap<ByteArrayWrapper, ResultRow>>> results = new ArrayList<>(numThreads);\n        var fileChannel = FileChannel.open(Paths.get(fileName));\n        boolean firstSegment = true;\n        while (remaining_size > 0) {\n            long actualSize = Math.min(chunk_size, remaining_size);\n            results.add(executor.submit(new FileRead(fileChannel, startLocation, toIntExact(actualSize), firstSegment)));\n            firstSegment = false;\n            remaining_size -= actualSize;\n            startLocation += actualSize;\n        }\n        executor.shutdown();\n\n        // Wait for all threads to finish\n        while (!executor.isTerminated()) {\n            Thread.yield();\n        }\n        log(\"Finished all threads\");\n        fileInputStream.close();\n        HashMap<ByteArrayWrapper, ResultRow> result = new HashMap<>(20000);\n        for (var future : results) {\n            for (var entry : future.get().entrySet()) {\n                result.merge(entry.getKey(), entry.getValue(), ResultRow::merge);\n            }\n        }\n        ResultRow[] finalResult = result.values().toArray(new ResultRow[0]);\n        for (var row : finalResult) {\n            row.toString();\n        }\n        Arrays.sort(finalResult, Comparator.comparing(a -> a.stationString));\n        System.out.println(\"{\" + String.join(\", \", Arrays.stream(finalResult).map(ResultRow::toString).toList()) + \"}\");\n        log(\"All done!\");\n    }\n\n    static void log(String message) {\n        // System.err.println(Instant.now() + \"[\" + Thread.currentThread().getName() + \"]: \" + message);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_bytesfellow.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Consumer;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_bytesfellow {\n\n    public static final String CPU_CORES_1BRC_ENV_VARIABLE = \"CPU_CORES_1BRC\";\n    private static final byte Separator = ';';\n\n    private static final double SchedulerCpuRatio = 0.4;\n\n    private static final int availableCpu = System.getenv(CPU_CORES_1BRC_ENV_VARIABLE) != null ? Integer.parseInt(System.getenv(CPU_CORES_1BRC_ENV_VARIABLE))\n            : Runtime.getRuntime().availableProcessors();\n\n    private static final int SchedulerPoolSize = Math.max((int) (availableCpu * SchedulerCpuRatio), 1);\n    private static final int SchedulerQueueSize = Math.min(SchedulerPoolSize * 3, 12);\n    private static final int PartitionsNumber = Math.max((availableCpu - SchedulerPoolSize), 1);\n    private static final int PartitionExecutorQueueSize = 1000;\n\n    private static final int InputStreamBlockSize = 4096;\n    private static final int InputStreamReadBufferLen = 250 * InputStreamBlockSize;\n\n    static class Partition {\n\n        private static final AtomicInteger cntr = new AtomicInteger(-1);\n        private final Map<Station, MeasurementAggregator> partitionResult = new HashMap<>(10000); // as per requirement we have not more than 10K keys\n        private final AtomicInteger leftToExecute = new AtomicInteger(0);\n\n        private final String name = \"partition-\" + cntr.incrementAndGet();\n\n        private final Executor executor = new ThreadPoolExecutor(1, 1,\n                0L, TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(PartitionExecutorQueueSize) { // some limit to avoid OOM\n                    @Override\n                    public boolean offer(Runnable runnable) {\n                        try {\n                            put(runnable); // block if limit was exceeded\n                        }\n                        catch (InterruptedException e) {\n                            throw new RuntimeException(e);\n                        }\n                        return true;\n                    }\n                }, r -> {\n                    Thread t = new Thread(r);\n                    t.setDaemon(true);\n                    t.setName(name);\n                    return t;\n                });\n\n        public void scheduleToProcess(byte[] slice, List<LineParams> lines) {\n\n            if (!lines.isEmpty()) {\n                leftToExecute.incrementAndGet();\n                executor.execute(\n                        () -> {\n                            for (int i = 0; i < lines.size(); i++) {\n                                LineParams lineParams = lines.get(i);\n\n                                Measurement measurement = getMeasurement(slice, lineParams);\n\n                                MeasurementAggregator measurementAggregator = partitionResult.get(measurement.station);\n                                if (measurementAggregator == null) {\n                                    partitionResult.put(new Station(measurement.station), new MeasurementAggregator().withMeasurement(measurement));\n                                }\n                                else {\n                                    measurementAggregator.withMeasurement(measurement);\n                                }\n                            }\n\n                            leftToExecute.decrementAndGet();\n                        });\n            }\n\n        }\n\n        public void materializeNames() {\n            partitionResult.keySet().forEach(Station::materializeName);\n        }\n\n        public Map<Station, MeasurementAggregator> getResult() {\n            return partitionResult;\n        }\n\n        public boolean allTasksCompleted() {\n            return leftToExecute.get() == 0;\n        }\n\n    }\n\n    record LineParams(int start, int length) {\n    }\n\n    static class Partitioner {\n\n        private final List<Partition> allPartitions = new ArrayList<>();\n        private final int partitionsSize;\n\n        AtomicInteger jobsScheduled = new AtomicInteger(0);\n\n        final Executor scheduler = new ThreadPoolExecutor(SchedulerPoolSize, SchedulerPoolSize,\n                0L, TimeUnit.MILLISECONDS,\n                new LinkedBlockingQueue<>(SchedulerQueueSize) { // some limit to avoid OOM\n\n                    @Override\n                    public Runnable take() throws InterruptedException {\n                        return super.take();\n                    }\n\n                    @Override\n                    public boolean offer(Runnable runnable) {\n                        try {\n                            put(runnable); // preventing unlimited scheduling due to possible OOM\n                        }\n                        catch (InterruptedException e) {\n                            throw new RuntimeException(e);\n                        }\n                        return true;\n                    }\n                }, r -> {\n                    Thread t = new Thread(r);\n                    t.setDaemon(true);\n                    t.setName(\"scheduler\");\n                    return t;\n                });\n\n        Partitioner(int partitionsSize) {\n            IntStream.range(0, partitionsSize).forEach((i) -> allPartitions.add(new Partition()));\n            this.partitionsSize = partitionsSize;\n        }\n\n        private int partitionsSize() {\n            return partitionsSize;\n        }\n\n        void processSlice(byte[] slice) {\n\n            jobsScheduled.incrementAndGet();\n\n            scheduler.execute(() -> {\n                List<List<LineParams>> partitionedLines = new ArrayList<>(partitionsSize());\n                // allocate some capacity, assuming that on average lines are half of the max (407 bytes) length\n                IntStream.range(0, partitionsSize()).forEach((p) -> partitionedLines.add(new ArrayList<>(slice.length / 407 / 2)));\n\n                int start = 0;\n                int i = 0;\n                int startCharLen = 0;\n                while (i < slice.length) {\n\n                    if (slice[i] == '\\n' || i == (slice.length - 1)) {\n\n                        int lineLength = i - start + (i == (slice.length - 1) ? 1 : 0);\n                        LineParams lineParams = new LineParams(start, lineLength);\n\n                        int partitioningCode = getPartitioningCode(slice, start, getUtf8CharNumberOfBytes(slice[start]));\n                        int partition = computePartition(partitioningCode);\n\n                        partitionedLines.get(partition).add(lineParams);\n                        start = i + 1;\n\n                    }\n\n                    i++;\n                }\n\n                processPartitionedBatch(slice, partitionedLines);\n\n                jobsScheduled.decrementAndGet();\n            });\n\n        }\n\n        private static byte[] getLine(byte[] slice, int lineLength, int start) {\n            byte[] line = new byte[lineLength];\n            System.arraycopy(slice, start, line, 0, lineLength);\n            return line;\n        }\n\n        private void processPartitionedBatch(byte[] slice, List<List<LineParams>> partitionedLines) {\n            for (int i = 0; i < partitionedLines.size(); i++) {\n                allPartitions.get(i).scheduleToProcess(slice, partitionedLines.get(i));\n            }\n        }\n\n        private int computePartition(int code) {\n            return Math.abs(code % partitionsSize());\n        }\n\n        private static int getPartitioningCode(byte[] line, int start, int utf8CharNumberOfBytes) {\n            // seems good enough\n            if (utf8CharNumberOfBytes == 4) {\n                return line[start] + line[start + 1] + line[start + 2] + line[start + 3];\n            }\n            else if (utf8CharNumberOfBytes == 3) {\n                return line[start] + line[start + 1] + line[start + 2];\n            }\n            else if (utf8CharNumberOfBytes == 2) {\n                return line[start] + line[start + 1];\n            }\n            else {\n                return line[start];\n            }\n        }\n\n        SortedMap<Station, MeasurementAggregator> getAllResults() {\n            allPartitions.parallelStream().forEach(Partition::materializeNames);\n            SortedMap<Station, MeasurementAggregator> result = new TreeMap<>();\n            allPartitions.forEach((p) -> result.putAll(p.getResult()));\n            return result;\n        }\n\n        public boolean allTasksCompleted() {\n            return allPartitions.stream().allMatch(Partition::allTasksCompleted);\n        }\n\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static class Station implements Comparable<Station> {\n\n        private final byte[] inputSlice;\n        private final int hash;\n\n        private final int startIdx;\n        private final int len;\n\n        private volatile String nameAsString;\n\n        public Station(byte[] inputSlice, int startIdx, int len) {\n            this.inputSlice = inputSlice;\n            this.startIdx = startIdx;\n            this.len = len;\n            this.hash = hashcodeFast();\n        }\n\n        public Station(Station from) {\n            this.inputSlice = new byte[from.len];\n            System.arraycopy(from.inputSlice, from.startIdx, this.inputSlice, 0, from.len);\n            this.startIdx = 0;\n            this.len = from.len;\n            this.hash = from.hash;\n        }\n\n        private int hashcodeFast() {\n            if (len == 0) {\n                return 0;\n            }\n            else if (len == 1) {\n                return inputSlice[startIdx] * 109;\n            }\n            else if (len == 2) {\n                return inputSlice[startIdx + 1] * 109 * 109 + inputSlice[startIdx];\n            }\n            else if (len == 3) {\n                return inputSlice[startIdx + 2] * 109 * 109 * 109 + inputSlice[startIdx + 1] * 109 * 109 + inputSlice[startIdx];\n            }\n            else {\n                return inputSlice[startIdx + 3] * 109 * 109 * 109 * 109 + inputSlice[startIdx + 2] * 109 * 109 * 109 + inputSlice[startIdx + 1] * 109 * 109\n                        + inputSlice[startIdx];\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n\n            Station station = (Station) o;\n\n            if (len != station.len) {\n                return false;\n            }\n\n            return Arrays.equals(inputSlice, startIdx, startIdx + len, station.inputSlice, station.startIdx, station.startIdx + len);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public int compareTo(Station o) {\n            return materializeName().compareTo(o.materializeName()); //\n        }\n\n        public String materializeName() {\n            if (nameAsString == null) {\n                byte[] nameForMaterialization = new byte[len];\n                System.arraycopy(inputSlice, startIdx, nameForMaterialization, 0, len);\n                nameAsString = new String(nameForMaterialization, StandardCharsets.UTF_8);\n            }\n\n            return nameAsString;\n        }\n\n        @Override\n        public String toString() {\n            return materializeName();\n        }\n    }\n\n    private record Measurement(Station station, long value) {\n    }\n\n    private record ResultRow(long min, long sum, long count, long max) {\n\n        public String toString() {\n            return fakeDouble(min) + \"/\" + round((double) sum / (double) count / 10.0) + \"/\" + fakeDouble(max);\n        }\n\n        private String fakeDouble(long value) {\n            long positiveValue = value < 0 ? -value : value;\n            long wholePart = positiveValue / 10;\n            String positiveDouble = wholePart + \".\" + (positiveValue - wholePart * 10);\n\n\n            return (value < 0 ? \"-\" : \"\") + positiveDouble;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n    }\n\n    public static class MeasurementAggregator {\n        private long min = Long.MAX_VALUE;\n        private long max = Long.MIN_VALUE;\n        private long sum;\n        private long count;\n\n        MeasurementAggregator withMeasurement(Measurement m) {\n\n            min = Math.min(min, m.value);\n            max = Math.max(max, m.value);\n            sum += m.value;\n            count++;\n\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return new ResultRow(min, sum, count, max).toString();\n        }\n\n    }\n\n    private static long parseToLongIgnoringDecimalPoint(byte[] slice, int startIndex, int len) {\n        long value = 0;\n\n        int start = startIndex;\n        if (slice[startIndex] == '-') {\n            start = startIndex + 1;\n        }\n\n        for (int i = start; i < startIndex + len; i++) {\n            if (slice[i] == '.') {\n                continue;\n            }\n\n            if (i > 0) {\n                value = multipleByTen(value); // *= 10;\n            }\n            value += digitAsLong(slice, i);\n        }\n\n        return start > startIndex ? -value : value;\n    }\n\n    private static long multipleByTen(long value) {\n        return (value << 3) + (value << 1);\n    }\n\n    private static long digitAsLong(byte[] digits, int position) {\n        return (digits[position] - 48);\n    }\n\n    public static void main(String[] args) throws IOException {\n\n        Partitioner partitioner = new Partitioner(PartitionsNumber);\n\n        try (FileInputStream fileInputStream = new FileInputStream(FILE)) {\n            parseStreamWithBytes(fileInputStream, InputStreamReadBufferLen, partitioner::processSlice);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n\n        showResults(partitioner);\n\n    }\n\n    static void parseStreamWithBytes(InputStream inputStream, int bufferLen, Consumer<byte[]> sliceConsumer) throws IOException {\n\n        byte[] byteArray = new byte[bufferLen];\n        int offset = 0;\n        int lenToRead = bufferLen;\n\n        int readLen;\n\n        while ((readLen = inputStream.read(byteArray, offset, lenToRead)) > -1) {\n            if (readLen == 0) {\n                continue;\n            }\n\n            int traverseLen = Math.min(offset + readLen, bufferLen);\n            int lastLineBreakInSlicePosition = traverseLen;\n\n            for (int j = traverseLen - 1; j >= 0; j--) {\n                if (byteArray[j] == '\\n') {\n                    lastLineBreakInSlicePosition = j + 1;\n                    break;\n                }\n            }\n\n            if (lastLineBreakInSlicePosition == traverseLen) {\n                // todo: end of line was not found in a slice?\n            }\n\n            int sliceSize = lastLineBreakInSlicePosition / SchedulerPoolSize;\n\n            int s = 0;\n\n            int j = Math.min(sliceSize, lastLineBreakInSlicePosition - 1);\n            while (s < lastLineBreakInSlicePosition && j < lastLineBreakInSlicePosition) {\n                if (byteArray[j] == '\\n') {\n                    int len = j - s;\n                    byte[] slice = new byte[len];\n                    System.arraycopy(byteArray, s, slice, 0, len);\n                    sliceConsumer.accept(slice);\n\n                    s = j + 1;\n                    j = Math.min(s + sliceSize, lastLineBreakInSlicePosition - 1);\n\n                }\n                else {\n                    j++;\n                }\n            }\n\n            if (s < traverseLen && lastLineBreakInSlicePosition < traverseLen) {\n                // some tail left, carry it over to the next read\n                int len = traverseLen - s;\n                System.arraycopy(byteArray, s, byteArray, 0, len);\n                offset = len;\n                lenToRead = bufferLen - len;\n            }\n            else {\n                offset = 0;\n                lenToRead = bufferLen;\n            }\n        }\n    }\n\n    static int getUtf8CharNumberOfBytes(byte firstByteOfChar) {\n        int masked = firstByteOfChar & 0b11111000;\n        if (masked == 0b11110000) {\n            return 4;\n        }\n        else if (masked == 0b11100000) {\n            return 3;\n        }\n        else if (masked == 0b11000000) {\n            return 2;\n        }\n        else {\n            return 1;\n        }\n    }\n\n    static void showResults(Partitioner partitioner) {\n\n        CountDownLatch c = new CountDownLatch(1);\n        partitioner.scheduler.execute(() -> {\n\n            try {\n                // check if any unprocessed slices\n                while (partitioner.jobsScheduled.get() > 0) {\n                }\n\n                // check if anything left in partitions\n                while (!partitioner.allTasksCompleted()) {\n                }\n\n                SortedMap<Station, MeasurementAggregator> result = partitioner.getAllResults();\n                System.out.println(result); // output aggregated measurements according to the requirement\n            }\n            catch (Exception e) {\n                System.out.println(e);\n            }\n            c.countDown();\n        });\n\n        try {\n            c.await();\n        }\n        catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        }\n\n    }\n\n    private static Measurement getMeasurement(byte[] slice, LineParams lineParams) {\n        int idx = lastIndexOfSeparator(slice, lineParams);\n        return new Measurement(\n                new Station(slice, lineParams.start, idx - lineParams.start),\n                parseToLongIgnoringDecimalPoint(slice, idx + 1, lineParams.start + lineParams.length - (idx + 1)));\n    }\n\n    private static int lastIndexOfSeparator(byte[] slice, LineParams lineParams) {\n        // hacky - we know that from the end of the line we have only\n        // single byte characters\n        // -2 is also hacky since we expect a particular format at the end of the line\n\n        int lastIdx = lineParams.start + lineParams.length() - 1;\n        if (slice[lastIdx - 3] == Separator) {\n            return lastIdx - 3;\n        }\n        else if (slice[lastIdx - 4] == Separator) {\n            return lastIdx - 4;\n        }\n        else if (slice[lastIdx - 5] == Separator) {\n            return lastIdx - 5;\n        }\n\n        return -1;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_cb0s.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_cb0s {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int INPUT_BUFFER_SIZE = 1 << 16; // yields the best performance on my system...\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        run();\n        // benchmark();\n    }\n\n    private static void benchmark() throws IOException {\n        var startTime = System.currentTimeMillis();\n        for (int count = 0; count < 3; ++count) {\n            run();\n        }\n        var stopTime = System.currentTimeMillis();\n\n        System.out.println(STR.\"Running 3 times took: \\{stopTime - startTime}ms (1 run: \\{(stopTime - startTime) / 3}ms)\");\n    }\n\n    private static void run() throws IOException {\n        var fileSize = getFileSize();\n\n        // for consistency for smaller files (actually a mess, could be solved more elegantly in the parsing step)\n        var processors = Runtime.getRuntime().availableProcessors();\n        processors = Math.max(1, Math.min(processors, (int) fileSize / 106));\n        while (fileSize / processors < INPUT_BUFFER_SIZE && processors > 1)\n            --processors;\n\n        var chunkSize = fileSize / processors;\n\n        System.out.write('{');\n\n        // for getting a bit more out of this solution, we don't check for null\n        var mergedResults = IntStream.range(0, processors)\n                .parallel()\n                .mapToObj(i -> processChunk(i, chunkSize))\n                .reduce(TempResultStorage::merge).get();\n\n        var endResult = mergedResults.aggregatedResultsPreOrdered.stream()\n                .map(Station::toString)\n                .collect(Collectors.joining(\", \"));\n\n        System.out.write(endResult.getBytes());\n\n        System.out.write(new byte[]{ '}', '\\n' });\n    }\n\n    private static class MeasurementAggregator {\n        public MeasurementAggregator(int initialValue) {\n            min = initialValue;\n            max = initialValue;\n            count = 1;\n            sum = initialValue;\n        }\n\n        public int min, max, count;\n        // we need to long if the possible absolute sum is greater than 2^31\n        public long sum;\n    }\n\n    private record Station(\n            MeasurementAggregator results,\n            RawName rawName\n    ) implements Comparable<Station> {\n\n    @Override\n    public boolean equals(Object otherObject) {\n        if (otherObject instanceof Station otherStation) {\n            return otherStation.rawName.equals(rawName);\n        }\n        return false;\n    }\n\n    @Override\n    public int compareTo(Station otherStation) {\n        return rawName.compareTo(otherStation.rawName);\n    }\n\n    @Override\n    public String toString() {\n        return STR.\"\\{rawName}=\\{results.min/10.0}/\\{Math.round(results.sum / (float) results.count) / 10.0}/\\{results.max/10.0}\";\n    }\n\n    @Override\n    public int hashCode() {\n        return rawName.hashCode();\n    }\n\n    }\n\n    private record RawName(\n            byte[] rawName\n    ) implements Comparable<RawName> {\n\n    @Override\n    public boolean equals(Object otherObject) {\n        RawName otherRawName = (RawName) otherObject;\n        return Arrays.equals(otherRawName.rawName, this.rawName);\n\n        /*\n         * Although being safer, comparing actually is a small bottleneck\n         * if (otherObject instanceof RawName otherRawName) {\n         * return Arrays.equals(otherRawName.rawName, this.rawName);\n         * }\n         * return false;\n         */\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(rawName);\n    }\n\n    @Override\n    public String toString() {\n        return new String(rawName, 0, rawName.length, StandardCharsets.UTF_8);\n    }\n\n    @Override\n    public int compareTo(RawName otherRawName) {\n        int result = 0;\n        // Math.min is SLIGHTLY less efficient, but we don't care at this point\n        var lowerIndex = Math.min(rawName.length, otherRawName.rawName.length);\n        for (int i = 0; i < lowerIndex && result == 0; ++i) {\n            result = Byte.compareUnsigned(rawName[i], otherRawName.rawName[i]);\n        }\n\n        return result == 0 ? rawName.length - otherRawName.rawName.length : result;\n    }\n}\n\nprivate static class TempResultStorage {\n    public void insertMeasurement(byte[] dataRow, int from, int to) {\n        // 1st parse measurement\n        var sepIndex = from + 1;\n        while (dataRow[sepIndex] != ';')\n            ++sepIndex;\n\n        var parsedMeasurement = parseMeasurement(dataRow, sepIndex + 1, to);\n\n        // 2nd handle if city occurs the first time\n        var rawName = new RawName(Arrays.copyOfRange(dataRow, from, sepIndex));\n        var tempIndex = indexCache.get(rawName);\n        if (tempIndex == null) {\n            var aggregator = new MeasurementAggregator(parsedMeasurement);\n            var tempStation = new Station(aggregator, rawName);\n            aggregatedResults.add(tempStation);\n            indexCache.put(rawName, aggregatedResults.size() - 1);\n            aggregatedResultsPreOrdered.add(tempStation);\n            return;\n        }\n\n        // or update already existing station\n        var tempResults = aggregatedResults.get(tempIndex).results;\n        // TODO: compare to: add simd vector storage and process once every 8 iterations\n\n        tempResults.sum += parsedMeasurement;\n        tempResults.count++;\n\n        if (tempResults.max < parsedMeasurement) {\n            tempResults.max = parsedMeasurement;\n        }\n        else if (tempResults.min > parsedMeasurement) {\n            tempResults.min = parsedMeasurement;\n        }\n    }\n\n    public TempResultStorage() {\n        aggregatedResults = new ArrayList<>(INITIAL_RESULT_SIZE);\n        indexCache = new HashMap<>(INITIAL_RESULT_SIZE);\n        aggregatedResultsPreOrdered = new TreeSet<>();\n    }\n\n    public static TempResultStorage merge(TempResultStorage storage0, TempResultStorage storage1) {\n        // default case\n        if (storage0 == null) {\n            return storage1;\n        }\n\n        // TODO: Implementation with SIMD commands\n        for (var station1 : storage1.aggregatedResults) {\n            // System.out.println(station1.results.count + \" \" + station1.results.sum);\n            var key = storage0.indexCache.get(station1.rawName);\n            if (key == null) {\n                storage0.aggregatedResults.add(station1);\n                storage0.indexCache.put(station1.rawName, storage0.aggregatedResults.size() - 1);\n                storage0.aggregatedResultsPreOrdered.add(station1);\n                continue;\n            }\n\n            var station0 = storage0.aggregatedResults.get(key);\n            station0.results.count += station1.results.count;\n            station0.results.sum += station1.results.sum;\n\n            if (station0.results.min > station1.results.min) {\n                station0.results.min = station1.results.min;\n            }\n\n            if (station1.results.max > station0.results.max) {\n                station0.results.max = station1.results.max;\n            }\n        }\n\n        return storage0;\n    }\n\n    // the closer it is to the actual value the better -> for 10_000 stations 10_000 is obviously better\n    private static final int INITIAL_RESULT_SIZE = 420;\n\n    // we use a custom name mapping for faster access to aggregatedResults and easier sorting\n    private final List<Station> aggregatedResults;\n    private final TreeSet<Station> aggregatedResultsPreOrdered;\n    private final HashMap<RawName, Integer> indexCache;\n\n    /**\n     * Parses a char[] array to the contained number in a fixed point format.\n     * The number can be between [-99.9, 99.9] (i.e. has either 2 or 3 digits and might contain a sign)\n     * and represents a temperature measurement.\n     * Note that no checking takes place. Incorrect formats yield unexpected results.\n     *\n     * @param dataRow char array actually containing the number\n     * @param from    the start index of the number inside the array (included)\n     * @param to      the end index of the number (not included, i.e. the char after the number or the length)\n     * @return fixed point (int) representation of the contained measurement\n     */\n    private int parseMeasurement(byte[] dataRow, int from, int to) {\n        // almost branch-less solution\n        int sign = -1 + 2 * ((dataRow[from] >> 4) & 1);\n\n        int floatingPoint = dataRow[to - 1] - 48;\n        int lastIntDigit = dataRow[to - 3] - 48;\n        int firstIntDigit = to - from - 4 >= 0 ? (sign + 1) / 2 * dataRow[to - 4] - 48 : 0;\n\n        if (to - from >= 4) {\n            firstIntDigit = dataRow[to - 4] - 48;\n\n            if (to - from == 4 && sign == -1) {\n                firstIntDigit = 0;\n            }\n        }\n\n        return (firstIntDigit * 100 + lastIntDigit * 10 + floatingPoint) * sign;\n    }\n\n    }\n\n    private static TempResultStorage processChunk(int i, long chunkSize) {\n        var storage = new TempResultStorage();\n        var readBuffer = new byte[INPUT_BUFFER_SIZE];\n\n        try (var inputStream = new BufferedInputStream(new FileInputStream(FILE), INPUT_BUFFER_SIZE)) {\n            var readBytes = 0L; // we set it to one because our first loop will not register last read byte\n            var readBytesDelta = 0;\n\n            // preparation\n            if (i != 0) {\n                --readBytes;\n                inputStream.skip(i * chunkSize - 1);\n                int c;\n                while ((c = inputStream.read()) != '\\n' && c != -1)\n                    ++readBytes;\n            }\n\n            // actual parsing\n            // worst case: only \\n is missing for a whole line\n            var carryOver = new byte[107];\n            var carryOverSize = 0;\n\n            while (readBytes < chunkSize && inputStream.available() > 0) {\n                readBytes += (readBytesDelta = inputStream.read(readBuffer, 0, readBuffer.length));\n                int from = 0, to = 0;\n\n                if (carryOverSize != 0) {\n                    while (readBuffer[to] != '\\n')\n                        ++to;\n                    System.arraycopy(readBuffer, from, carryOver, carryOverSize, to - from + 1);\n\n                    storage.insertMeasurement(carryOver, 0, carryOverSize + to - from);\n                    from = ++to;\n                }\n\n                // Actually looking 5 ahead instead of 1 at each new line\n                // Minimal line consists of: [name-byte];[first_digit].[last_digit]\\n\n                while (to <= readBytesDelta && (readBytes - readBytesDelta + to) < chunkSize) {\n                    to += 5;\n\n                    while (to < readBytesDelta && readBuffer[to] != '\\n')\n                        ++to;\n\n                    if (to >= readBytesDelta) {\n                        System.arraycopy(readBuffer, from, carryOver, 0, readBytesDelta - from);\n                        carryOverSize = readBytesDelta - from;\n                        break;\n                    }\n\n                    storage.insertMeasurement(readBuffer, from, to);\n                    from = ++to;\n                }\n            }\n        }\n        catch (IOException e) {\n            return null; // shouldn't happen\n        }\n\n        return storage;\n    }\n\n    private static long getFileSize() {\n        return new File(CalculateAverage_cb0s.FILE).length();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_charlibot.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_charlibot {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static Unsafe initUnsafe() {\n        try {\n            final Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final int MAP_CAPACITY = 16384; // Need at least 10,000 so 2^14 = 16384. Might need 2^15 = 32768.\n\n    public static void main(String[] args) throws Exception {\n        memoryMap();\n    }\n\n    // Copied from Roy van Rijn's code\n    // branchless max (unprecise for large numbers, but good enough)\n    static int max(final int a, final int b) {\n        final int diff = a - b;\n        final int dsgn = diff >> 31;\n        return a - (diff & dsgn);\n    }\n\n    // branchless min (unprecise for large numbers, but good enough)\n    static int min(final int a, final int b) {\n        final int diff = a - b;\n        final int dsgn = diff >> 31;\n        return b + (diff & dsgn);\n    }\n\n    static class Measurement {\n        int min;\n        int max;\n        int sum;\n        int count;\n\n        Measurement(int value) {\n            min = value;\n            max = value;\n            sum = value;\n            count = 1;\n        }\n\n        @Override\n        public String toString() {\n            double minD = (double) min / 10;\n            double maxD = (double) max / 10;\n            double meanD = (double) sum / 10 / count;\n            return round(minD) + \"/\" + round(meanD) + \"/\" + round(maxD);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    static class MeasurementMap3 {\n\n        final Measurement[] measurements;\n        final byte[][] cities;\n\n        final int capacity = MAP_CAPACITY;\n\n        MeasurementMap3() {\n            measurements = new Measurement[capacity];\n            cities = new byte[capacity][128]; // 100 bytes for the city. Round up to nearest power of 2.\n        }\n\n        public void insert(long fromAddress, long toAddress, int hashcode, int value) {\n            int index = hashcode & (capacity - 1); // same trick as in hashmap. This is the same as (% capacity).\n            tryInsert(index, fromAddress, toAddress, value);\n        }\n\n        private void tryInsert(int mapIndex, long fromAddress, long toAddress, int value) {\n            byte length = (byte) (toAddress - fromAddress);\n            outer: while (true) {\n                byte[] cityArray = cities[mapIndex];\n                Measurement jas = measurements[mapIndex];\n                if (jas != null) {\n                    if (cityArray[0] == length) {\n                        int i = 0;\n                        while (i < length) {\n                            byte b = UNSAFE.getByte(fromAddress + i);\n                            if (b != cityArray[i + 1]) {\n                                mapIndex = (mapIndex + 1) & (capacity - 1);\n                                continue outer;\n                            }\n                            i++;\n                        }\n                        jas.min = min(value, jas.min);\n                        jas.max = max(value, jas.max);\n                        jas.sum += value;\n                        jas.count += 1;\n                        break;\n                    }\n                    else {\n                        mapIndex = (mapIndex + 1) & (capacity - 1);\n                    }\n                }\n                else {\n                    // just insert\n                    int i = 0;\n                    cityArray[0] = length;\n                    while (i < length) {\n                        byte b = UNSAFE.getByte(fromAddress + i);\n                        cityArray[i + 1] = b;\n                        i++;\n                    }\n                    measurements[mapIndex] = new Measurement(value);\n                    break;\n\n                }\n            }\n        }\n\n        public HashMap<String, Measurement> toMap() {\n            HashMap<String, Measurement> hashMap = new HashMap<>();\n            for (int mapIndex = 0; mapIndex < cities.length; mapIndex++) {\n                byte[] cityArray = cities[mapIndex];\n                Measurement measurement = measurements[mapIndex];\n                if (measurement != null) {\n                    int length = cityArray[0];\n                    String city = new String(cityArray, 1, length, StandardCharsets.UTF_8);\n                    hashMap.put(city, measurement);\n                }\n            }\n            return hashMap;\n        }\n\n        public Set<Map.Entry<String, Measurement>> entrySet() {\n            return toMap().entrySet();\n        }\n    }\n\n    public static long[] getChunks(int numChunks) throws Exception {\n        long[] chunks = new long[numChunks + 1];\n        try (FileChannel fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            long fileSize = fileChannel.size();\n            long sizeOfChunk = fileSize / numChunks;\n            var address = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global()).address();\n            chunks[0] = address;\n            for (int processIdx = 1; processIdx < numChunks; processIdx++) {\n                long chunkAddress = processIdx * sizeOfChunk + address;\n                while (UNSAFE.getByte(chunkAddress) != '\\n') {\n                    chunkAddress++;\n                }\n                chunkAddress++;\n                chunks[processIdx] = chunkAddress;\n            }\n            chunks[numChunks] = address + fileSize;\n        }\n        return chunks;\n    }\n\n    public static void memoryMap() throws Exception {\n        int numProcessors = Runtime.getRuntime().availableProcessors();\n        long[] chunks = getChunks(numProcessors);\n        try (ExecutorService executorService = Executors.newWorkStealingPool(numProcessors)) {\n            Future[] results = new Future[numProcessors];\n            for (int processIdx = 0; processIdx < numProcessors; processIdx++) {\n                int finalProcessIdx = processIdx;\n                Future<HashMap<String, Measurement>> future = executorService.submit(() -> {\n                    long chunkIdx = chunks[finalProcessIdx];\n                    long chunkEnd = chunks[finalProcessIdx + 1];\n                    MeasurementMap3 measurements = new MeasurementMap3();\n                    while (chunkIdx < chunkEnd) {\n                        long cityStart = chunkIdx;\n                        byte b;\n                        int hashcode = 0;\n                        while ((b = UNSAFE.getByte(chunkIdx)) != ';') {\n                            hashcode = 31 * hashcode + b;\n                            chunkIdx++;\n                        }\n                        long cityEnd = chunkIdx;\n                        chunkIdx++;\n                        int multiplier = 1;\n                        b = UNSAFE.getByte(chunkIdx);\n                        if (b == '-') {\n                            multiplier = -1;\n                            chunkIdx++;\n                        }\n                        int value = 0;\n                        while ((b = UNSAFE.getByte(chunkIdx)) != '\\n') {\n                            if (b != '.') {\n                                value = (value * 10) + (b - '0');\n                            }\n                            chunkIdx++;\n                        }\n                        value = value * multiplier;\n                        measurements.insert(cityStart, cityEnd, hashcode, value);\n                        chunkIdx++;\n                    }\n                    return measurements.toMap();\n                });\n                results[processIdx] = future;\n            }\n            final HashMap<String, Measurement> measurements = new HashMap<>();\n            for (Future f : results) {\n                HashMap<String, Measurement> m = (HashMap<String, Measurement>) f.get();\n                m.forEach((city, measurement) -> {\n                    measurements.merge(city, measurement, (oldValue, newValue) -> {\n                        Measurement mmm = new Measurement(0);\n                        mmm.min = Math.min(oldValue.min, newValue.min);\n                        mmm.max = Math.max(oldValue.max, newValue.max);\n                        mmm.sum = oldValue.sum + newValue.sum;\n                        mmm.count = oldValue.count + newValue.count;\n                        return mmm;\n                    });\n                });\n            }\n            System.out.print(\"{\");\n            System.out.print(\n                    measurements.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(Object::toString).collect(Collectors.joining(\", \")));\n            System.out.println(\"}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_chrisbellew.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Field;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.HashMap;\nimport java.util.TreeMap;\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorMask;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\n/**\n * This is Chris Bellew's implementation. Here are the key points:\n * \n * - The file is equally split into ranges, one range per thread.\n *   18 threads was experimentally found to be optimal.\n * \n * - Each thread memory maps the file range it is responsible for and\n *   then iterates through the range, one smaller buffer at a time.\n * \n * - The contents are parsed by using SIMD vector equality comparisons\n *   between the source data and the newline character, effectively\n *   delimiting each line. The measurement of each line is discovered\n *   by moving back from the end of the line, parsing into an integer\n *   as it goes. The integer representation is 10x the actual value\n *   but is used because integer parsing was found to be much faster\n *   than floating point parsing, and it's also immune to floating\n *   point arithmetic errors when aggregating the measurements later.\n * \n * - Once the name and the measurement is parsed for a line, the name\n *   is hashed and used a lookup into a hash table. The value of the\n *   hash table at the given slot is an index into another array, this\n *   time an array of SIMD vectors that represent that name as a series\n *   of vectors. The vectors are used to compare equality of the name of\n *   the source line with the name in the slot to confirm the slot is\n *   occupied by the same city name. The indirection of having a hash\n *   table storing lookups into another array of vectors is to allow\n *   the hash table slots to have a fixed size, while allowing the city\n *   names to be arbitrarily long. The hash table can then use open\n *   addressing to resolve collisions and remain efficient for lookups.\n * \n * - After the range has been processed, the results are collected by\n *   iterating through the hash table and looking up the corresponding\n *   integer table for each slot then collecting the min, max, count\n *   and sum of the measurements for each city. Then the results are\n *   combined from all threads, using a treemap for sorting, and printed.\n */\npublic final class CalculateAverage_chrisbellew {\n    public static final long FILE_SIZE = getFileSize();\n\n    /**\n     * The overlap is the number of bytes that is peeked into the next buffer\n     * in order to find the end of the last newline in the current buffer.\n     * Every buffer ignores the characters before the first newline character\n     * and peeks into the next buffer to find the first newline character. This\n     * way no data is lost even though the buffers are arbitrarily sliced.\n     * 100 is the maximum length of a city name, 1 is the semicolon character,\n     * 5 is the maximum length of a measurement, 1 is the newline character,\n     * 8 is one extra vector length so that we don't overflow the buffer.\n     * If we overlap to this length then we will always be able to complete the\n     * last line in the buffer.\n     */\n    public static final int OVERLAP = 100 + 1 + 5 + 1 + 8;\n\n    public static void main(String[] args) throws IOException {\n        /**\n         * The test cases use small test files. This causes issues because we\n         * are trying to open the file at different locations on 16 threads.\n         */\n        final int NUM_THREADS = FILE_SIZE < 12_000_000_000L ? 1 : 16;\n\n        /**\n         * Experimentally optimal buffer size for iterating over each\n         * memory mapped segment of the file.\n         */\n        final int BUFFER_SIZE = 1024 * 256;\n\n        /**\n         * Split the whole file into slices. One slice per thread.\n         */\n        var ranges = getThreadRanges(NUM_THREADS);\n\n        var processors = new ThreadProcessor[NUM_THREADS];\n        Thread[] threads = new Thread[NUM_THREADS];\n        for (var i = 0; i < NUM_THREADS; i++) {\n            processors[i] = new ThreadProcessor(ranges[i].start, ranges[i].end, BUFFER_SIZE);\n            threads[i] = new Thread(processors[i]);\n            threads[i].start();\n        }\n\n        var results = new TreeMap<String, CityResult>();\n        for (int i = 0; i < NUM_THREADS; i++) {\n            try {\n                threads[i].join();\n                processors[i].collectResults(results);\n            }\n            catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        printResults(results);\n    }\n\n    private static void printResults(TreeMap<String, CityResult> results) {\n        var builder = new StringBuilder();\n        builder.append(\"{\");\n        boolean first = true;\n        for (var entry : results.entrySet()) {\n            var city = entry.getKey();\n            var result = entry.getValue();\n            var average = ((float) Math.round((float) result.sum / (float) result.count)) / 10.0;\n            var min = ((float) result.min) / 10.0;\n            var max = ((float) result.max) / 10.0;\n\n            if (first) {\n                first = false;\n            }\n            else {\n                builder.append(\", \");\n            }\n            builder.append(city).append(\"=\").append(min).append(\"/\").append(average).append(\"/\").append(max);\n        }\n        builder.append(\"}\");\n        System.out.println(builder.toString());\n    }\n\n    /**\n     * Splits the measurements file into ranges for each thread, ensuring that the last\n     * range ends at the end of the file.\n     */\n    public static final FileRange[] getThreadRanges(int threads) throws IOException {\n        var chunkSize = FILE_SIZE / threads;\n        var ranges = new FileRange[threads];\n        for (var i = 0; i < threads; i++) {\n            var start = i * chunkSize;\n            var end = i == threads - 1 ? FILE_SIZE : (i + 1) * chunkSize;\n            ranges[i] = new FileRange(start, end);\n        }\n        return ranges;\n    }\n\n    private static final long getFileSize() {\n        try (var stream = new FileInputStream(\"measurements.txt\")) {\n            return stream.getChannel().size();\n        }\n        catch (IOException e) {\n            throw new RuntimeException(\"Failed to get file size\", e);\n        }\n    }\n\n    /**\n     * Processes a range of the file. The range is defined by a start and end\n     * position. The start is inclusive and the end is exclusive.\n     */\n    static final class ThreadProcessor implements Runnable {\n        /**\n         * The number of slots in the hash table. This number was found to be the\n         * minimum number to use in conjunction with the hashing function to\n         * produce no collisions on the test data. The test data is a hint, but the\n         * correctness of the implementation is not coupled to the test data because\n         * the hash table is able to handle collisions in other arbitrary source data.\n         */\n        private static final int NUM_SLOTS = 12133;\n\n        /**\n         * The size of the SIMD vector to use when striding through the source data\n         * in order to detect newlines, and when comparing equality of the source line\n         * with a given slot in the hash table.\n         */\n        private static final VectorSpecies<Byte> SPECIES = ByteVector.SPECIES_64;\n\n        /**\n         * A precomputed lookup table of vector masks to use when comparing equality of\n         * the source line and a given slot in the hash table. Each slot in the hash table\n         * has a set of vectors associated with it. The source name is split into vectors\n         * and each source vector is compared with the corresponding slot vector for equality.\n         * Unless the length of the city name is a multiple of the vector length, the last\n         * vector in the slot will be a partial vector. The masks are used to ignore the\n         * unused bytes in the last vector.\n         */\n        private static final VectorMask<Byte>[] MASKS = generateMasks(SPECIES);\n\n        /**\n         * The unsafe instance is used to allocate memory for the hash table slots\n         * and integer table slots. It skips the JVM's garbage collector and allows\n         * the memory to be accessed directly without overhead such as bounds checks.\n         */\n        private static final Unsafe unsafe = getUnsafe();\n\n        /**\n         * The start and end positions this thread will iterate through.\n         */\n        private final long start;\n        private final long end;\n\n        private final int bufferSize;\n\n        /**\n         * The main memory address at the beginning of the hash table slots.\n         */\n        private final long slotsAddress;\n\n        /**\n         * The main memory address at the beginning of the integer table slots.\n         */\n        private final long numbersAddress;\n\n        /**\n         * The main memory address at the beginning of the name length table slots.\n         */\n        private final long lengthsAddress;\n\n        /**\n         * The SIMD vectors associated with each slot in the hash table. The\n         * content of a given slot in a hash table is a lookup into this array.\n         * The intent of having this array as an extra lookup is to allow N\n         * vectors per slot while having fixed size slots.\n         */\n        private ByteVector[] vectors = new ByteVector[200000];\n        private String[] cityNames = new String[NUM_SLOTS];\n\n        /**\n         * The next available index in the vectors array.\n         */\n        private short nextVectorIndex = 8;\n\n        /**\n         * A map of city name strings to their corresponding slot index in the\n         * hash table. When the hash table slots will be sparsely populated it's\n         * not efficient to iterate through the slots when collecting the results.\n         * This map provides a way to discover the occupied slots.\n         */\n        private final HashMap<String, Integer> cityVectorLookup = new HashMap<>();\n\n        public ThreadProcessor(long start, long end, int bufferSize) {\n            this.start = start;\n            this.end = end;\n            this.bufferSize = bufferSize;\n\n            /**\n             * Allocate memory for the hash table and the integer table.\n             * Initialise the hash table slots to 0, so we can use 0 to\n             * indicate an empty slot.\n             */\n            slotsAddress = unsafe.allocateMemory(NUM_SLOTS * 2);\n            for (int i = 0; i < NUM_SLOTS; i++) {\n                unsafe.putShort(slotsAddress + i * 2, (short) 0);\n            }\n            numbersAddress = unsafe.allocateMemory(NUM_SLOTS * 16);\n            lengthsAddress = unsafe.allocateMemory(NUM_SLOTS);\n        }\n\n        public final void run() {\n            try (RandomAccessFile file = new RandomAccessFile(\"measurements.txt\", \"r\")) {\n                FileChannel fileChannel = file.getChannel();\n\n                /**\n                 * Work out whether we need to peek into the next range. If this is the last\n                 * range then the end of this range will be the end of the file, so we won't\n                 * peek. Otherwise, we'll peek just enough into the next slot to complete the\n                 * last line in this range.\n                 */\n                boolean lastRange = end == FILE_SIZE;\n                long length = lastRange ? end - start : end - start + OVERLAP;\n\n                MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, start, length);\n                processRange(buffer, lastRange);\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        /**\n         * Iterates through the entire memory mapped range, one buffer at a time.\n         * The buffers are made to overlap to allow each buffer to peek into the next\n         * range to complete the last line. \n         */\n        private final void processRange(MappedByteBuffer buffer, boolean lastRange) {\n            byte[] buf = new byte[bufferSize];\n            int remaining;\n            long globalPosition = start;\n            while ((remaining = buffer.remaining()) != 0) {\n                int numBytes = Math.min(remaining, bufferSize);\n                boolean lastBuffer = remaining == numBytes;\n\n                /**\n                 * Fill this buffer and process it.\n                 */\n                buffer.get(buf, 0, numBytes);\n                processBuffer(buf, numBytes, lastRange, lastBuffer, globalPosition);\n\n                /**\n                 * Start the next range slightly before the end of this range.\n                 */\n                if (!lastBuffer) {\n                    buffer.position(buffer.position() - OVERLAP);\n                }\n\n                globalPosition += numBytes;\n            }\n        }\n\n        /**\n         * Parses and processes each line from a buffer.\n         */\n        private final void processBuffer(byte[] buffer, int numBytes, boolean lastRange, boolean lastBuffer, long globalPosition) {\n\n            /**\n             * Skip past any characters before the first newline because the previous\n             * segment will have already processed them. That is unless this if the \n             * first buffer in the first range (global position zero), in which case\n             * we will start from the first character.\n             */\n            int index = globalPosition == 0 ? 0 : findFirstNewline(buffer) + 1;\n\n            /**\n             * Keep track of the start of the city name.\n             */\n            int nameStart = index;\n\n            while (true) {\n                /**\n                 * Take a slice of bytes and convert it into a vector so we can apply\n                 * SIMD operations to find newlines.\n                 */\n                ByteVector vector = ByteVector.fromArray(SPECIES, buffer, index);\n\n                /**\n                 * Find the newline using SIMD.\n                 */\n                VectorMask<Byte> newLineMask = vector.eq((byte) '\\n');\n                int firstTrue = newLineMask.firstTrue();\n                if (firstTrue == SPECIES.length()) {\n                    /**\n                     * We haven't found a newline in this vector, so move on to the\n                     * next vector.\n                     */\n                    index += SPECIES.length();\n                    continue;\n                }\n\n                slice(buffer, index + firstTrue, nameStart);\n\n                index = index + firstTrue + 1;\n                nameStart = index;\n\n                /**\n                 * If this is the last buffer in the last range then we want to \n                 * process every character until the very end of the file.\n                 */\n                if (lastRange && lastBuffer) {\n                    if (index == numBytes) {\n                        return;\n                    }\n\n                    /**\n                     * If we're less than one vector length away from the end\n                     * of the buffer then just take the remaining bytes as the\n                     * final line. If we tried to use a vector it would overflow.\n                     */\n                    if (index >= numBytes - SPECIES.length()) {\n                        slice(buffer, numBytes - 1, nameStart);\n                        return;\n                    }\n                    continue;\n                }\n\n                /**\n                 * If it's not the last buffer or it's not the last range then\n                 * we want to overlap into the next buffer, but only by enough\n                 * to complete the last line.\n                 */\n                if (index > numBytes - OVERLAP) {\n                    return;\n                }\n            }\n        }\n\n        /**\n         * Finds the first newline in a buffer using SIMD. Used to skip past a\n         * partial line at the beginning of a buffer.\n         */\n        private final int findFirstNewline(byte[] buffer) {\n            int index = 0;\n            while (true) {\n                ByteVector vector = ByteVector.fromArray(SPECIES, buffer, index);\n                VectorMask<Byte> newLineMask = vector.eq((byte) '\\n');\n                int firstTrue = newLineMask.firstTrue();\n                if (firstTrue == SPECIES.length()) {\n                    index += SPECIES.length();\n                    continue;\n                }\n                return index + firstTrue;\n            }\n        }\n\n        /**\n         * Given the index in the buffer of where a name starts, and the index of\n         * the next newline, creeps back from the next newline to find the structure\n         * of the measurement, parsing it into a number as it goes. It is parsed \n         * into an integer because it's faster than parsing as a float, and it's also\n         * immune to floating point arithmetic errors when aggregating the measurements\n         * later.\n         * \n         * Then proceeds to record the fully parsed name and measurement in the hash table.\n         */\n        private final void slice(byte[] buffer, int newlineIndex, int nameStart) {\n            int i = newlineIndex - 1;\n            int measurement = buffer[i] - '0';\n            i -= 2; // Skip before the decimal point\n            measurement += (buffer[i] - '0') * 10;\n            i--;\n\n            if (buffer[i] == ';') {\n                // 1.2\n                record(buffer, nameStart, i, measurement);\n            }\n            else {\n                // 12.3 or -1.2 or -12.3\n                if (buffer[i] == '-') {\n                    // -1.2\n                    record(buffer, nameStart, i - 1, -measurement);\n                }\n                else {\n                    // 12.3 or -12.3\n                    measurement += (buffer[i] - '0') * 100;\n                    i--;\n                    if (buffer[i] == '-') {\n                        // -12.3\n                        record(buffer, nameStart, i - 1, -measurement);\n                    }\n                    else {\n                        // 12.3\n                        record(buffer, nameStart, i, measurement);\n                    }\n                }\n            }\n        }\n\n        /**\n         * Given a name and measurement, looks up a slot in the hash table by hashing\n         * the city name as a key, then applies the measurement to the accumulated\n         * aggregation of that city's measurements.\n         */\n        private final void record(byte[] buffer, int nameStart, int nameEnd, int measurement) {\n            int nameLength = nameEnd - nameStart;\n\n            /**\n             * The length of most city names will not be a multiple of the SIMD\n             * vector length so there will be a remainder in the final vector\n             * of extraneous bytes. We need to mask these bytes out when comparing.\n             */\n            var remainder = nameLength % SPECIES.length();\n\n            var numVectors = nameLength / SPECIES.length() + (remainder == 0 ? 0 : 1);\n\n            /**\n             * Lookup the slot index in the hash table for the city name.\n             */\n            var slotIndex = nameToSlotIndex(buffer, nameStart, nameLength);\n\n            /**\n             * Identify if the slot is occupied, then check the equality of the\n             * slot with the city name.\n             */\n            var vectorOffset = unsafe.getShort(slotsAddress + slotIndex * 2);\n            while (vectorOffset != 0) {\n\n                /**\n                 * Check the set of vectors in the slot match the city name\n                 */\n                if (slotEquals(buffer, nameStart, vectorOffset, numVectors, remainder, slotIndex)) {\n\n                    /**\n                     * Check the length of the slot name and city name match. This\n                     * check is needed because the vector equality check can give\n                     * false positives if one city name starts with another.\n                     */\n                    byte slotNameLength = unsafe.getByte(lengthsAddress + slotIndex);\n                    if (slotNameLength == nameLength) {\n                        updateSlot(slotIndex, measurement);\n                        break;\n                    }\n                }\n\n                /**\n                 * If the slot is occupied but the city name doesn't match, then\n                 * we try the next slot in the hash table through linear probing.\n                 */\n                slotIndex = (slotIndex + 1) % NUM_SLOTS;\n                vectorOffset = unsafe.getShort(slotsAddress + slotIndex * 2);\n            }\n\n            /**\n             * If the slot was unoccupied, then we can initialise it with the\n             * city name and measurement.\n             */\n            if (vectorOffset == 0) {\n                /**\n                 * Record where the city name length is recorded for this slot.\n                 */\n                unsafe.putByte(lengthsAddress + slotIndex, (byte) nameLength);\n\n                /**\n                 * Record where the start of the set of vectors are recorded for\n                 */\n                unsafe.putShort(slotsAddress + slotIndex * 2, nextVectorIndex);\n\n                /**\n                 * Records the vectors for the city name.\n                 */\n                for (int v = 0; v < numVectors; v++) {\n                    vectors[nextVectorIndex] = ByteVector.fromArray(SPECIES, buffer, nameStart + v * SPECIES.length());\n                    nextVectorIndex++;\n                }\n\n                cityVectorLookup.put(new String(buffer, nameStart, nameLength), slotIndex);\n\n                /**\n                 * Min, max, count, sum\n                 */\n                var numbersIndex = getNumbersIndex(slotIndex);\n                unsafe.putInt(numbersIndex, measurement);\n                unsafe.putInt(numbersIndex + 4, measurement);\n                unsafe.putInt(numbersIndex + 8, 1);\n                unsafe.putInt(numbersIndex + 12, measurement);\n\n                cityNames[slotIndex] = new String(buffer, nameStart, nameLength);\n            }\n        }\n\n        /**\n         * Given the index bounds of a name in a buffer, creates a hash of the name\n         * by multiplying the first twelve characters. This was experimentally found\n         * to provide a good distribution of hash values for the test data. In\n         * combination with the number of slots in the hash table, this produces no\n         * collisions on the test data. The test data is a hint, but the correctness\n         * of the implementation is not coupled to the test data because the hash\n         * table is able to handle collisions in other arbitrary source data.\n         */\n        private final int nameToSlotIndex(byte[] buffer, int nameStart, int nameLength) {\n            var integer = 1;\n            integer *= buffer[nameStart + 0];\n            if (nameLength > 1) {\n                integer *= buffer[nameStart + 1];\n                if (nameLength > 2) {\n                    integer *= buffer[nameStart + 2];\n                    if (nameLength > 3) {\n                        integer *= buffer[nameStart + 3];\n                        if (nameLength > 4) {\n                            integer *= buffer[nameStart + 4];\n                            if (nameLength > 5) {\n                                integer *= buffer[nameStart + 5];\n                                if (nameLength > 6) {\n                                    integer *= buffer[nameStart + 6];\n                                    if (nameLength > 7) {\n                                        integer *= buffer[nameStart + 7];\n                                        if (nameLength > 8) {\n                                            integer *= buffer[nameStart + 8];\n                                            if (nameLength > 9) {\n                                                integer *= buffer[nameStart + 9];\n                                                if (nameLength > 10) {\n                                                    integer *= buffer[nameStart + 10];\n                                                    if (nameLength > 11) {\n                                                        integer *= buffer[nameStart + 11];\n                                                    }\n                                                }\n                                            }\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n            return Math.abs(integer) % NUM_SLOTS;\n        }\n\n        /**\n         * Given a slot index and a measurement, updates the aggregation of the\n         * measurements for the city in that slot.\n         */\n        private final void updateSlot(int slotIndex, int measurement) {\n            var numbersIndex = getNumbersIndex(slotIndex);\n            var min = unsafe.getInt(numbersIndex);\n            var max = unsafe.getInt(numbersIndex + 4);\n            var count = unsafe.getInt(numbersIndex + 8);\n            var sum = unsafe.getInt(numbersIndex + 12);\n\n            unsafe.putInt(numbersIndex, Math.min(min, measurement));\n            unsafe.putInt(numbersIndex + 4, Math.max(max, measurement));\n            unsafe.putInt(numbersIndex + 8, count + 1);\n            unsafe.putInt(numbersIndex + 12, sum + measurement);\n        }\n\n        /**\n         * Given a name in a buffer, a slot index, and a number of vectors, checks\n         * the equality of the name and the slot.\n         * \n         * The length of the name is not necessarily a multiple of the SIMD vector\n         * length, so the last vector in the slot will be a partial vector. The\n         * masks are used to ignore the unused bytes in the last vector.\n         */\n        private final boolean slotEquals(byte[] buffer, int nameStart, int vectorOffset, int numVectors, int remainder, int slotIndex) {\n            for (int v = 0; v < numVectors; v++) {\n                var nameVector = ByteVector.fromArray(SPECIES, buffer, nameStart + v * SPECIES.length());\n                var slotVector = vectors[vectorOffset + v];\n                if (v == numVectors - 1) {\n                    if (remainder == 0) {\n                        if (!slotVector.eq(nameVector).allTrue()) {\n                            return false;\n                        }\n                    }\n                    else {\n                        var mask = MASKS[remainder - 1];\n                        if (!slotVector.compare(VectorOperators.EQ, nameVector, mask).equals(mask)) {\n                            return false;\n                        }\n                    }\n                    break;\n                }\n                else {\n                    if (!slotVector.eq(nameVector).allTrue()) {\n                        return false;\n                    }\n                }\n            }\n\n            return true;\n        }\n\n        /**\n         * Given a slot index, returns the main memory address of the integer table\n         * where the min, max, count and sum of the measurements are stored.\n         */\n        private final long getNumbersIndex(int slotIndex) {\n            return numbersAddress + slotIndex * 16;\n        }\n\n        public void collectResults(TreeMap<String, CityResult> results) {\n            for (var entry : cityVectorLookup.entrySet()) {\n                var city = entry.getKey();\n                var slotIndex = entry.getValue();\n                var numbersIndex = getNumbersIndex(slotIndex);\n                var min = unsafe.getInt(numbersIndex);\n                var max = unsafe.getInt(numbersIndex + 4);\n                var count = unsafe.getInt(numbersIndex + 8);\n                var sum = unsafe.getInt(numbersIndex + 12);\n                results.compute(city, (k, v) -> {\n                    if (v == null) {\n                        return new CityResult(min, max, sum, count);\n                    }\n                    else {\n                        v.min = Math.min(v.min, min);\n                        v.max = Math.max(v.max, max);\n                        v.sum += sum;\n                        v.count += count;\n                        return v;\n                    }\n                });\n            }\n        }\n\n        /**\n         * Generates a lookup table of vector masks to use when comparing equality of\n         * the last vector of the source line and a given slot in the hash table.\n         */\n        private static final VectorMask<Byte>[] generateMasks(VectorSpecies<Byte> species) {\n            VectorMask<Byte>[] masks = new VectorMask[species.length() - 1];\n            masks[0] = VectorMask.fromArray(species, new boolean[]{ true, false, false, false, false, false, false, false }, 0);\n            masks[1] = VectorMask.fromArray(species, new boolean[]{ true, true, false, false, false, false, false, false }, 0);\n            masks[2] = VectorMask.fromArray(species, new boolean[]{ true, true, true, false, false, false, false, false }, 0);\n            masks[3] = VectorMask.fromArray(species, new boolean[]{ true, true, true, true, false, false, false, false }, 0);\n            masks[4] = VectorMask.fromArray(species, new boolean[]{ true, true, true, true, true, false, false, false }, 0);\n            masks[5] = VectorMask.fromArray(species, new boolean[]{ true, true, true, true, true, true, false, false }, 0);\n            masks[6] = VectorMask.fromArray(species, new boolean[]{ true, true, true, true, true, true, true, false }, 0);\n            return masks;\n        }\n\n        private static final Unsafe getUnsafe() {\n            Field field;\n            try {\n                field = Unsafe.class.getDeclaredField(\"theUnsafe\");\n                field.setAccessible(true);\n                return (Unsafe) field.get(null);\n            }\n            catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {\n                throw new RuntimeException(\"Failed to get unsafe\", e);\n            }\n        }\n    }\n\n    static final class CityResult {\n        public int min;\n        public int max;\n        public int sum;\n        public int count;\n\n        public CityResult(int min, int max, int sum, int count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n    }\n\n    static final class FileRange {\n        public final long start;\n        public final long end;\n\n        public FileRange(long start, long end) {\n            this.start = start;\n            this.end = end;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_cliffclick.java",
    "content": "/*\n *  Copyright 2024 Cliff Click\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.lang.reflect.Field;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.*;\nimport java.util.Arrays;\nimport sun.misc.Unsafe;\n\nabstract class CalculateAverage_cliffclick {\n    // abstract class CNC {\n    public static final int NCPUS = Runtime.getRuntime().availableProcessors();\n    public static final long HASSEMI = 0x3B3B3B3B3B3B3B3BL;\n\n    private static final Unsafe UNSAFE;\n    private static long MMAP_ADDRESS;\n    static {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);\n\n            Field f;\n            try {\n                f = java.nio.Buffer.class.getDeclaredField(\"address\");\n            }\n            catch (java.lang.NoSuchFieldException e) {\n                throw new RuntimeException(e);\n            }\n            MMAP_ADDRESS = UNSAFE.objectFieldOffset(f);\n\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        if (args.length < 1)\n            args = new String[]{ \"measurements.txt\" };\n\n        Work w = work(args);\n        String foo = w.toString();\n        byte[] bar = new byte[foo.length()];\n        foo.getBytes(0, foo.length(), bar, 0);\n        System.out.write(bar);\n        System.out.write('\\n');\n    }\n\n    // General work flow:\n\n    // Spawn threads. Make empty hash for sums, counts.\n    // Seek to offset. Skip till newline. Parse to end of chunk, plus rest of partial line.\n\n    // SWAR out city name into n8; both hash and uhash name.\n    // Lookup in sums; if miss: insert map uhash to 0 cnt; insert map uhash to String name also;\n    // if hit: bump count; same index in sums array, bump sums with scaled decimal\n    // At end, grab more work until done.\n\n    // At end, across all threads total sums & counts.\n    // Compute averages, lookup names and print.\n    static Work work(String[] args) throws Exception {\n        File f = new File(args[0]);\n\n        // How many threads?\n        int ncpus = (int) Math.min((f.length() >> 14) + 1, NCPUS); // Keep 1<<14 min work\n        long len = (f.length() / ncpus) + 1;\n\n        Work[] WS = new Work[ncpus];\n        Thread[] TS = new Thread[ncpus];\n\n        // Spawn work on threads\n        for (int i = 0; i < ncpus; i++) {\n            long s = i * len;\n            Work w = WS[i] = new Work();\n            Thread T = TS[i] = new Thread() {\n                public void run() {\n                    tstart(w, f, s, Math.min(len, f.length() - s));\n                }\n            };\n            T.start();\n        }\n\n        TS[0].join();\n        Work W = WS[0];\n        for (int i = 1; i < ncpus; i++) {\n            TS[i].join();\n            W.reduce(WS[i]);\n        }\n        return W;\n    }\n\n    static void tstart(Work w, File f, long start, long len) {\n        try {\n            // Thread gets a chunk of work\n            FileChannel fc = FileChannel.open(f.toPath(), StandardOpenOption.READ);\n            final int MAX_MAP = 1 << 30;\n\n            for (long s = start; s < start + len; s += MAX_MAP) {\n                int maxlen = (int) Math.min(len + 1, MAX_MAP); // Length capped at MAX_MAP\n                long rem = f.length() - s;\n                int mlen = (int) Math.min(rem, maxlen + 100); // Add a little extra so can finish out a line\n                int clen = (int) Math.min(rem, maxlen);\n                // mmap is capped at MAX_MAP (plus change), or\n                // to the end of the chosen parse length (plus change)\n                // or the end of the file in any case\n                MappedByteBuffer mmap = fc.map(FileChannel.MapMode.READ_ONLY, s, mlen);\n                // Chunk runs to min(MAX_MAP, parse length, eof), plus it runs to the end\n                // of any partial line.\n                do_chunk(w, s > 0, clen, mmap);\n            }\n        }\n        catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n    }\n\n    // Has a zero byte in a long, copied straight from Hackers Delight\n    static long has0(long x) {\n        return (x - 0x0101010101010101L) & (~x) & 0x8080808080808080L;\n    }\n\n    // Parse a chunk, from 0 to limit in mmap. Runs past limit to finish any\n    // partial line. If skip1, then skip any leading partial line.\n    static void do_chunk(Work w, boolean skip1, int limit, MappedByteBuffer mmap) {\n        assert mmap.isDirect();\n        int idx = 0;\n        int max = mmap.limit();\n        long base = UNSAFE.getLong(mmap, MMAP_ADDRESS);\n\n        // If start>0, skip until first newline\n        if (skip1)\n            idx = skipFirst(idx, base);\n\n        // The very last entry will want to fetch 8 bytes, some of which may go\n        // past the mmap max - do this entry now, before looping.\n        if (limit == max)\n            limit = skipLast(limit, w, base);\n\n        // Edges of the ~2G region taken care of. Now do the giant middle part.\n\n        // For this chunk of file do...\n        while (idx < limit) {\n            int cityx = idx; // Used if we find a new city name\n\n            // SWAR read and build n8; the long-as-a-string value. Also track start\n            // and end of the string, in case it is new and needs to be inserted into\n            // the n8->city_name map.\n            long n8 = 0;\n            // Read a misaligned long\n            long x = UNSAFE.getLong(base + idx);\n            // Found semi ?\n            long hasM = has0(x ^ HASSEMI);\n            while (hasM == 0) {\n                // Read 2nd word of city\n                n8 ^= x;\n                idx += 8;\n                // Read a misaligned long\n                x = UNSAFE.getLong(base + idx);\n                // Found semi ?\n                hasM = has0(x ^ HASSEMI);\n            }\n            // Found a semicolon this word.\n            // The high bit of the byte in question is set.\n            int shr = Long.numberOfTrailingZeros(hasM) + 1;\n            if (shr > 8) {\n                int shr2 = 72 - shr;\n                n8 ^= (x << shr2) >> shr2;\n                idx += (shr >> 3) - 1;\n            }\n\n            // Skip semicolon\n            idx++;\n\n            // Reading tempature, and add\n            idx = parseData(idx, w, cityx, n8, base);\n        }\n    }\n\n    // The very last entry will want to fetch 8 bytes, some of which may go\n    // past the mmap max - do this entry now, before looping.\n    private static int skipLast(int limit, Work w, long base) {\n        limit--;\n        while (limit > 0 && UNSAFE.getByte(base + limit - 1) != '\\n')\n            limit--;\n        long n8 = 0, mask = 0, c;\n        int i = limit;\n        while ((c = UNSAFE.getByte(base + i)) != ';') {\n            mask = (mask >> 8) | (c << 56);\n            i++;\n            if (((limit - i) & 7) == 0) {\n                n8 ^= mask;\n                mask = 0;\n            }\n        }\n        int shr = (limit - i) & 7;\n        n8 ^= (mask >> (shr << 3));\n        parseData(i + 1, w, limit, n8, base);\n        return limit;\n    }\n\n    // Parse temp data, and insert entry into hash table\n    private static int parseData(int idx, Work w, int cityx, long n8, long base) {\n        // Reading tempature:\n        int temp = 0;\n        boolean neg = false;\n        byte b = UNSAFE.getByte(base + idx++);\n        if (b == '-') {\n            neg = true;\n            b = UNSAFE.getByte(base + idx++);\n        }\n        temp = b - '0';\n        b = UNSAFE.getByte(base + idx++);\n        if (b != '.') {\n            temp = temp * 10 + b - '0';\n            idx++;\n        }\n        // Read fraction digit; scaled decimal temp\n        b = UNSAFE.getByte(base + idx++);\n        temp = temp * 10 + b - '0';\n        if (neg)\n            temp = -temp;\n        // Skip newline\n        idx++;\n        // F*KING WINDOWS.\n        // Skip CR\n        // idx++;\n        w.insert(n8, temp, base, cityx);\n        return idx;\n    }\n\n    private static int skipFirst(int idx, long base) {\n        while (UNSAFE.getByte(base + idx++) != '\\n')\n            ;\n        // WINDOWS\n        // idx++;\n        return idx;\n    }\n\n    private static class Work {\n        private static final int TAB_SIZE = 0x4000; // 512 for 413 cities\n        // Fixed size hashtable. Longs are packed to hold the data.\n        // cnt uhash\n        // 8 7 6 5 4 3 2 1\n        // min max temp sum\n        // 8 7 6 5 4 3 2 1\n        long[] table = new long[TAB_SIZE * 2]; //\n        String[] cities = new String[TAB_SIZE]; // Same index holds city names\n\n        // Gather for city bits\n        final byte[] city = new byte[256];\n        int reprobes;\n\n        void insert(long n8, int temp, long base, int cityx) {\n            // 3 bytes uniquely id city, left at 4\n            int uhash = (int) uhash_final(n8);\n            // Index in small table\n            int ihash = hash_hash(uhash);\n            long cnt_key = table[(ihash << 1)];\n            long min_max = table[(ihash << 1) + 1];\n            int key = key(cnt_key);\n            while (key != uhash) {\n                if (key == 0) {\n                    // Miss in hash table\n                    cnt_key = uhash & 0xFFFFFFFFL;\n                    min_max = min_max(0x7FFF, 0xF000, 0);\n                    // Put city name in cities\n                    new_city(ihash, base + cityx);\n                    break;\n                }\n                // Reprobe. Seeiong 53M reprobes out of 1000M rows, so a 5.3% reprobe rate\n                ihash = reprobe(ihash, uhash);\n                cnt_key = table[(ihash << 1)];\n                min_max = table[(ihash << 1) + 1];\n                key = key(cnt_key);\n            }\n            // assert cities[ihash].equals(toChar(n8)) : String.format(\"uhash=0x%08x %s %s, FAILS FOR %d\",uhash,cities[ihash],toChar(n8),X0);\n\n            // Break down parts\n            int min = min(min_max);\n            min = Math.min(min, temp);\n            int max = max(min_max);\n            max = Math.max(max, temp);\n            int sum = temp(min_max);\n            sum += temp;\n            min_max = min_max(min, max, sum);\n            // Back into table\n            table[(ihash << 1)] = cnt_key + (1L << 32);\n            table[(ihash << 1) + 1] = min_max;\n        }\n\n        // Hash the n8 value; the 3 bytes uniquely identify the city.\n        static long uhash_final(long n8) {\n            return n8 ^ (n8 >> 29);\n        }\n\n        // New city\n        void new_city(int ihash, long base_cityx) {\n            // Put city name in cities\n            int i = 0;\n            byte c;\n            while ((c = UNSAFE.getByte(base_cityx++)) != ';')\n                city[i++] = c;\n            cities[ihash] = new String(city, 0, 0, i);\n        }\n\n        private static int hash_hash(int uhash) {\n            // Index in small table\n            int ihash = uhash;\n            ihash = ihash ^ (ihash >> 17);\n            ihash = ihash + 29 * uhash;\n            ihash &= (TAB_SIZE - 1);\n            return ihash;\n        }\n\n        private static int reprobe(int ihash, int uhash) {\n            return (ihash + (uhash | 1)) & (TAB_SIZE - 1);\n        }\n\n        // Convert the large unique hash into a smaller table hash\n        int ihash(int uhash) {\n            // Index in small table\n            int ihash = hash_hash(uhash);\n            long cnt_key = table[ihash << 1];\n            int key = key(cnt_key);\n            while (key != uhash) {\n                if (key == 0)\n                    return ihash;\n                // Reprobe\n                ihash = reprobe(ihash, uhash);\n                cnt_key = table[(ihash << 1)];\n                key = key(cnt_key);\n            }\n            return ihash;\n        }\n\n        void reduce(Work w) {\n            for (int i = 0; i < w.cities.length; i++) {\n                if (w.cities[i] == null)\n                    continue;\n\n                // Break down parts\n                long cnt_key = w.table[(i << 1)];\n                long min_max = w.table[(i << 1) + 1];\n                int cnt = cnt(cnt_key);\n                int key = key(cnt_key);\n                int min = min(min_max);\n                int max = max(min_max);\n                int sum = temp(min_max);\n\n                // Find key in local table\n                int ihash = ihash(key);\n                long cnt_key0 = table[(ihash << 1)];\n                long min_max0 = table[(ihash << 1) + 1];\n                int cnt0 = cnt(cnt_key0);\n                int key0 = key(cnt_key0);\n                int min0 = min(min_max0);\n                int max0 = max(min_max0);\n                int sum0 = temp(min_max0);\n\n                cnt0 += cnt;\n                sum0 += sum;\n                min0 = Math.min(min0, min);\n                max0 = Math.max(max0, max);\n                if (key0 == 0) {\n                    key0 = key;\n                    min0 = min;\n                    cities[ihash] = w.cities[i];\n                }\n                table[(ihash << 1)] = cnt_key(cnt0, key0);\n                table[(ihash << 1) + 1] = min_max(min0, max0, sum0);\n            }\n        }\n\n        static int key(long cnt_key) {\n            return (int) cnt_key;\n        }\n\n        static int cnt(long cnt_key) {\n            return (int) (cnt_key >> 32);\n        }\n\n        static int min(long min_max) {\n            return (int) (min_max >> 48);\n        } // Signed right shift; min often negative\n\n        static int max(long min_max) {\n            return (short) ((min_max >>> 32) & 0xFFFF);\n        }// Unsigned right shift;\n\n        static int temp(long min_max) {\n            return (int) min_max;\n        }; // Low int\n\n        static long cnt_key(int cnt, int key) {\n            return ((long) cnt << 32) | (key & 0xFFFFFFFFL);\n        }\n\n        static long min_max(int min, int max, int sum) {\n            return ((long) min << 48) | ((long) (max & 0xFFFF) << 32) | (((long) sum) & 0xFFFFFFFFL);\n        }\n\n        @Override\n        public String toString() {\n            int ncitys = 0; // totals 413\n            for (int i = 0; i < TAB_SIZE; i++)\n                if (cities[i] != null)\n                    ncitys++;\n            // Index of city entries\n            Integer[] is = new Integer[ncitys];\n            for (int i = 0, j = 0; i < TAB_SIZE; i++)\n                if (cities[i] != null)\n                    is[j++] = i;\n\n            // Sort indices\n            Arrays.sort(is, (x, y) -> cities[x].compareTo(cities[y]));\n\n            StringBuilder sb = new StringBuilder().append(\"{\");\n            for (int i : is) {\n                String city = cities[i];\n                int cnt = cnt(table[(i << 1)]);\n                long min_max = table[(i << 1) + 1];\n                double min = min(min_max) / 10.0;\n                double max = max(min_max) / 10.0;\n                double temp = temp(min_max) / 10.0;\n                double mean = temp / cnt;\n                sb.append(String.format(\"%s=%.1f/%.1f/%.1f, \", city, min, mean, max));\n            }\n            if (sb.length() > 2)\n                sb.setLength(sb.length() - 2);\n            return sb.append(\"}\").toString();\n        }\n    }\n\n    // Debugging utilities\n    static String toHex(byte[] bs) {\n        StringBuilder sb = new StringBuilder().append(\"[\");\n        for (byte b : bs)\n            sb.append(String.format(\"%02X,\", b));\n        sb.setLength(sb.length() - 1);\n        return sb.append(\"]\").toString();\n    }\n\n    static String toChar(long x) {\n        StringBuilder sb = new StringBuilder();\n        for (int i = 0; i < 8; i++) {\n            char c = (char) (x & 0xFF);\n            if (c != 0)\n                sb.append(c);\n            x >>= 8;\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_coolmineman.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.nio.ByteBuffer;\nimport java.nio.channels.AsynchronousFileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Set;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_coolmineman {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        void add(double value) {\n            min = Math.min(min, value);\n            max = Math.max(max, value);\n            sum += value;\n            count++;\n        }\n\n        void merge(MeasurementAggregator o) {\n            min = Math.min(min, o.min);\n            max = Math.max(max, o.max);\n            sum += o.sum;\n            count += o.count;\n        }\n\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    static class BytesKey implements Comparable<BytesKey> {\n        byte[] value;\n        int hashcode;\n\n        BytesKey(byte[] value) {\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            return new String(value, StandardCharsets.UTF_8);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(value);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof BytesKey bk) {\n                return Arrays.equals(value, bk.value);\n            }\n            return false;\n        }\n\n        @Override\n        public int compareTo(BytesKey o) {\n            return Arrays.compare(value, o.value);\n        }\n\n    }\n\n    static void parse(ByteBuffer a, int as, ByteBuffer b, int bs, boolean isFirst, HashMap<BytesKey, MeasurementAggregator> map) {\n        var aa = a.array();\n        var ba = b.array();\n        int pos = 0;\n        int nameEnd = 0;\n        boolean parseDouble = false;\n        int doubleStart = 0;\n        int doubleEnd = 0;\n        if (!isFirst) {\n            while (aa[pos] != (byte) '\\n') {\n                pos++;\n            }\n            pos++;\n        }\n        int nameStart = pos;\n        while (pos < as) {\n            if (parseDouble) {\n                if (aa[pos] == '\\n') {\n                    doubleEnd = pos;\n\n                    BytesKey station = new BytesKey(Arrays.copyOfRange(aa, nameStart, nameEnd));\n                    double value = parseDouble(aa, doubleStart, doubleEnd);\n                    MeasurementAggregator ma = map.get(station);\n                    if (ma == null)\n                        map.put(station, ma = new MeasurementAggregator());\n                    ma.add(value);\n\n                    parseDouble = false;\n                    nameStart = pos + 1;\n                    nameEnd = 0;\n                    doubleStart = 0;\n                    doubleEnd = 0;\n                }\n            }\n            else {\n                if (aa[pos] == ';') {\n                    nameEnd = pos;\n                    parseDouble = true;\n                    doubleStart = pos + 1;\n                }\n            }\n\n            pos++;\n        }\n        if (bs <= 0)\n            return;\n        for (;;) {\n            if (parseDouble) {\n                if (ba[pos - as] == '\\n') {\n                    doubleEnd = pos;\n\n                    BytesKey station = new BytesKey(ofRange(a, as, b, bs, nameStart, nameEnd));\n                    double value = parseDouble(ofRange(a, as, b, bs, doubleStart, doubleEnd), 0, doubleEnd - doubleStart);\n                    map.computeIfAbsent(station, k -> new MeasurementAggregator()).add(value);\n\n                    return;\n                }\n            }\n            else {\n                if (ba[pos - as] == ';') {\n                    nameEnd = pos;\n                    parseDouble = true;\n                    doubleStart = pos + 1;\n                }\n            }\n\n            pos++;\n        }\n    }\n\n    static byte[] ofRange(ByteBuffer a, int as, ByteBuffer b, int bs, int start, int end) {\n        var aa = a.array();\n        var ba = b.array();\n        byte[] r = new byte[end - start];\n        for (int i = 0; i < r.length; i++) {\n            int pos = start + i;\n            if (pos < as) {\n                r[i] = aa[pos];\n            }\n            else {\n                r[i] = ba[pos - as];\n            }\n        }\n        return r;\n    }\n\n    static double parseDouble(byte[] b, int start, int end) {\n        boolean negative = false;\n        if (b[start] == (byte) '-') {\n            negative = true;\n            start += 1;\n        }\n        double result = 0;\n        for (int i = start; i < end; i++) {\n            if (b[i] != (byte) '.') {\n                result *= 10;\n                result += (b[i] & 0xFF) - '0';\n            }\n        }\n        if (negative)\n            result *= -1;\n        return result * .1;\n    }\n\n    public static void main(String[] args) throws Exception {\n        int pageSize = 1600000;\n        long pos = 0;\n        try (AsynchronousFileChannel fc = AsynchronousFileChannel.open(Paths.get(FILE), Set.of(StandardOpenOption.READ), Executors.newCachedThreadPool())) {\n            var cp = Executors.newWorkStealingPool(Runtime.getRuntime().availableProcessors());\n\n            var bbs = new ByteBuffer[Runtime.getRuntime().availableProcessors() * 8];\n            for (int i = 0; i < bbs.length; i++) {\n                bbs[i] = ByteBuffer.allocate(pageSize);\n            }\n\n            Future<Integer>[] futures = new Future[bbs.length];\n            HashMap<BytesKey, MeasurementAggregator>[] maps = new HashMap[bbs.length];\n            Future[] tasks = new Future[bbs.length];\n\n            for (int i = 0; i < futures.length; i++) {\n                futures[i] = fc.read(bbs[i], pos);\n                maps[i] = new HashMap<>();\n                pos += pageSize;\n            }\n\n            boolean first = true;\n            l: for (;;) {\n                for (int i = 0; i < bbs.length; i++) {\n                    int nextIndex = (i + 1) % bbs.length;\n                    if (tasks[nextIndex] != null) {\n                        tasks[nextIndex].get();\n                        bbs[nextIndex].position(0);\n                        futures[nextIndex] = fc.read(bbs[nextIndex], pos);\n                        pos += pageSize;\n                    }\n                    var fa = futures[i];\n                    var fb = futures[(i + 1) % futures.length];\n                    var isFirst = first;\n                    int ra = fa.get();\n                    if (ra < 0)\n                        break l;\n                    int rb = Math.max(0, fb.get());\n                    var iLol = i;\n                    tasks[i] = cp.submit(() -> {\n                        parse(bbs[iLol], ra, bbs[nextIndex], rb, isFirst, maps[iLol]);\n                    });\n\n                    first = false;\n                }\n            }\n\n            for (Future t : tasks) {\n                if (t != null)\n                    t.get();\n            }\n\n            for (int i = 1; i < maps.length; i++) {\n                merge(maps[0], maps[i]);\n            }\n\n            System.out.print('{');\n            boolean[] firstE = new boolean[]{ true };\n            maps[0].entrySet().stream().sorted((a, b) -> a.getKey().toString().compareTo(b.getKey().toString())).forEach(e -> {\n                if (!firstE[0]) {\n                    System.out.print(',');\n                    System.out.print(' ');\n                }\n                firstE[0] = false;\n                System.out.print(e.toString());\n            });\n            System.out.println('}');\n            System.exit(0);\n        }\n    }\n\n    static void merge(HashMap<BytesKey, MeasurementAggregator> a, HashMap<BytesKey, MeasurementAggregator> b) {\n        for (var e : b.entrySet()) {\n            if (a.containsKey(e.getKey())) {\n                a.get(e.getKey()).merge(e.getValue());\n            }\n            else {\n                a.put(e.getKey(), e.getValue());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_couragelee.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.*;\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class CalculateAverage_couragelee {\n    private static class Temperature {\n        private int cnt = 0;\n\n        private double sum = 0;\n\n        private double min;\n\n        private double max;\n\n        public Temperature(String tempStr) {\n            double temp = Double.parseDouble(tempStr);\n            this.min = temp;\n            this.max = temp;\n            this.sum = temp;\n            this.cnt++;\n        }\n\n        public Temperature(int cnt, double sum, double min, double max) {\n            this.cnt = cnt;\n            this.sum = sum;\n            this.min = min;\n            this.max = max;\n        }\n\n        public Temperature addRecord(String tempStr) {\n            double temp = Double.parseDouble(tempStr);\n            Temperature newTemp = new Temperature(this.cnt, this.sum, this.min, this.max);\n            newTemp.min = Math.min(temp, newTemp.min);\n            newTemp.max = Math.max(temp, newTemp.max);\n            newTemp.sum += temp;\n            newTemp.cnt++;\n            return newTemp;\n        }\n\n        public Temperature merge(Temperature newValue) {\n            Temperature oldTemp = new Temperature(this.cnt, this.sum, this.min, this.max);\n            oldTemp.min = Math.min(newValue.min, oldTemp.min);\n            oldTemp.max = Math.max(newValue.max, oldTemp.max);\n            oldTemp.sum += newValue.sum;\n            oldTemp.cnt += newValue.cnt;\n            return oldTemp;\n        }\n\n        public void update(String tempStr) {\n            double temp = parseDouble(tempStr);\n            this.min = Math.min(temp, this.min);\n            this.max = Math.max(temp, this.max);\n            this.sum += temp;\n            this.cnt++;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{min}/\\{Math.round((sum / cnt) * 10.0) / 10.0}/\\{max}\";\n        }\n    }\n\n    private static final String FILE_PATH = \"./measurements.txt\";\n\n    // 并行任务的数量\n    public static final int CONCURRENT_NUM = 20;\n\n    private static FileChannel fc;\n    private static long fcSize;\n\n    private static int segmentSize;\n\n    private static Map<String, Temperature> temperatureMap;\n\n    // 需要拼接的行信息\n    private static Map<String, byte[]> tempBytesMap = new ConcurrentHashMap<>();\n\n    // 缓存double解析数据\n    private static Map<String, Double> doubleCache;\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        // 初始化\n        File file = new File(FILE_PATH);\n        fc = new RandomAccessFile(file, \"r\").getChannel();\n        fcSize = fc.size();\n        segmentSize = (int) Math.ceil((double) fcSize / CONCURRENT_NUM);\n\n        calculate();\n\n        String resStr = temperatureMap.toString();\n        System.out.println(resStr);\n    }\n\n    private static void calculate() throws IOException, InterruptedException, ExecutionException {\n        ThreadPoolExecutor executor = new ThreadPoolExecutor(CONCURRENT_NUM, CONCURRENT_NUM, 0, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());\n\n        temperatureMap = new ConcurrentSkipListMap<>();\n        preHeatDoubleCache();\n\n        List<Future<Map<String, Temperature>>> res = new ArrayList<>();\n        long startPos = 0;\n        if (fcSize < 1000000) {\n            Future<Map<String, Temperature>> partRes = executor.submit(new Task(startPos, fcSize));\n            Map<String, Temperature> map = partRes.get();\n            temperatureMap.putAll(map);\n        }\n        else {\n            while (true) {\n                if (startPos + segmentSize >= fcSize) {\n                    Future<Map<String, Temperature>> partRes = executor.submit(new Task(startPos, fcSize - startPos));\n                    res.add(partRes);\n                    break;\n                }\n                else {\n                    Future<Map<String, Temperature>> partRes = executor.submit(new Task(startPos, segmentSize));\n                    res.add(partRes);\n                    startPos += segmentSize;\n                }\n            }\n            // 合并结果\n            for (Future<Map<String, Temperature>> future : res) {\n                Map<String, Temperature> stringTemperatureMap = future.get();\n                for (Map.Entry<String, Temperature> entry : stringTemperatureMap.entrySet()) {\n                    String station = entry.getKey();\n                    Temperature value = entry.getValue();\n                    temperatureMap.merge(station, value, (oldValue, newValue) -> oldValue.merge(newValue));\n                }\n            }\n        }\n\n        executor.shutdown();\n        executor.awaitTermination(10, TimeUnit.MINUTES);\n\n        // 处理拼接的行信息,不超过总并发数,顺序处理\n        for (Map.Entry<String, byte[]> entry : tempBytesMap.entrySet()) {\n            String key = entry.getKey();\n            if (key.startsWith(\"E\")) {\n                continue;\n            }\n            byte[] part1 = entry.getValue();\n            byte[] part2 = tempBytesMap.getOrDefault(\"E\" + key, new byte[0]);\n            byte[] bytes = new byte[part1.length + part2.length];\n            System.arraycopy(part1, 0, bytes, 0, part1.length);\n            System.arraycopy(part2, 0, bytes, part1.length, part2.length);\n            String[] lines = convertToString1(bytes, 0, bytes.length - 1);\n            for (String line : lines) {\n                try {\n                    handleRecordConcurrently(line);\n                }\n                catch (Exception e) {\n                    e.printStackTrace();\n                    System.out.println(line);\n                }\n            }\n        }\n    }\n\n    private static class Task implements Callable<Map<String, Temperature>> {\n        private long startPos;\n        private long size;\n\n        public Task(long startPos, long size) throws IOException {\n            this.startPos = startPos;\n            this.size = size;\n        }\n\n        @Override\n        public Map<String, Temperature> call() throws Exception {\n            Map<String, Temperature> map = new HashMap<>(10000);\n            try {\n                // 1亿个byte\n                boolean firstRowHandled = false;\n\n                MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, startPos, size);\n                byte[] lastLastRowBytes = null;\n                while (buffer.hasRemaining()) {\n                    byte[] bytes = new byte[10000];\n                    // 先拼上上一次的最后一行\n                    int startIndex = 0;\n                    if (lastLastRowBytes != null) {\n                        for (byte lastLastRowByte : lastLastRowBytes) {\n                            bytes[startIndex++] = lastLastRowByte;\n                        }\n                    }\n                    int readLength = Math.min(buffer.remaining(), 10000 - startIndex);\n                    lastLastRowBytes = null;\n                    buffer.get(bytes, startIndex, readLength);\n                    // 处理第一行\n                    int firstIndex = 0;\n                    if (!firstRowHandled) {\n                        firstRowHandled = true;\n                        if (startPos == 0) {\n                            // 全文第一行,不要特殊处理\n                        }\n                        else {\n                            while (bytes[firstIndex] != 10) {\n                                firstIndex++;\n                            }\n                            byte[] firstRowBytes = Arrays.copyOfRange(bytes, 0, firstIndex + 1);\n                            tempBytesMap.put(\"E\" + String.valueOf(startPos - 1), firstRowBytes);\n                            firstIndex++;\n                        }\n                    }\n                    // 分段的最后一行(可能不完整)\n                    int lastIndex = startIndex + readLength - 1;\n\n                    while (bytes[lastIndex] != 10) {\n                        lastIndex--;\n                    }\n                    if (lastIndex == startIndex + readLength - 1) {\n                        // 分段的最后一行是完整的\n                    }\n                    else {\n                        // 暂存一下\n                        lastLastRowBytes = Arrays.copyOfRange(bytes, lastIndex + 1, startIndex + readLength);\n                    }\n\n                    // [firstIndex, lastIndex] 这之间的数据是完整的多行数据\n                    String[] lines = convertToString1(bytes, firstIndex, lastIndex);\n                    handleRecord(map, lines);\n                }\n                // 处理最后一行\n                if (lastLastRowBytes != null) {\n                    tempBytesMap.put(String.valueOf(startPos + size - 1), Arrays.copyOf(lastLastRowBytes, lastLastRowBytes.length));\n                }\n                else {\n                    tempBytesMap.put(String.valueOf(startPos + size - 1), new byte[0]);\n                }\n            }\n            catch (Exception e) {\n                e.printStackTrace();\n            }\n            return map;\n        }\n    }\n\n    private static void handleRecord(Map<String, Temperature> map, String[] records) {\n        if (records == null || records.length == 0) {\n            return;\n        }\n        for (String record : records) {\n            if (\"\".equals(record)) {\n                continue;\n            }\n            int index = record.indexOf(\";\");\n            String station = record.substring(0, index);\n            String stationValue = record.substring(index + 1);\n            Temperature temperature = map.get(station);\n            if (temperature == null) {\n                temperature = new Temperature(stationValue);\n                map.put(station, temperature);\n            }\n            else {\n                temperature.update(stationValue);\n            }\n        }\n    }\n\n    private static void handleRecordConcurrently(String record) {\n        if (record.isEmpty()) {\n            return;\n        }\n        String[] split = record.split(\";\");\n        String station = split[0];\n        String stationValue = split[1];\n        // temperatureMap中只能新增值,不会删除\n        if (temperatureMap.get(station) == null) {\n            if (temperatureMap.putIfAbsent(station, new Temperature(stationValue)) != null) {\n                // 插入失败\n                temperatureMap.computeIfPresent(station, (key, oldValue) -> oldValue.addRecord(stationValue));\n            }\n        }\n        else {\n            // 已经有值了\n            temperatureMap.computeIfPresent(station, (key, oldValue) -> oldValue.addRecord(stationValue));\n        }\n    }\n\n    /**\n     *\n     * @param bytes\n     * @param start 起始索引,包含\n     * @param end 结束索引,包含\n     * @return\n     */\n    private static String[] convertToString1(byte[] bytes, int start, int end) {\n        if (bytes == null || bytes.length == 0) {\n            return new String[0];\n        }\n        String s = new String(bytes, start, (end - start + 1), StandardCharsets.UTF_8);\n        String[] split = s.split(\"\\n\");\n        return split;\n    }\n\n    // 预热-99.9到99.9之间的数,且始终包含一位小数\n    private static void preHeatDoubleCache() {\n        doubleCache = new ConcurrentHashMap<>();\n        for (int i = -99; i < 99; i++) {\n            for (int j = 0; j < 10; j++) {\n                String stand = String.valueOf(i);\n                String v = stand + \".\" + j;\n                doubleCache.put(v, Double.parseDouble(v));\n            }\n        }\n        for (int i = 0; i < 10; i++) {\n            String stand = \"-0\";\n            String v = stand + \".\" + i;\n            doubleCache.put(v, Double.parseDouble(v));\n        }\n\n    }\n\n    private static double parseDouble(String tempStr) {\n        return doubleCache.get(tempStr);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_criccomini.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class CalculateAverage_criccomini {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final long FILE_SIZE = new File(FILE).length();\n    private static final long SEGMENT_SIZE = 256_000_000;\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static Map<String, MeasurementAggregator> processSegment(MappedByteBuffer buffer, int length) {\n        Map<String, MeasurementAggregator> aggregates = new HashMap<>();\n        int lineStart = 0;\n        int doubleStart = 0;\n        String station = null;\n        for (int i = 0; i < length; ++i) {\n            byte b = buffer.get(i);\n            if (b == ';') {\n                byte[] stationBuffer = new byte[i - lineStart];\n                buffer.position(lineStart);\n                buffer.get(stationBuffer);\n                station = new String(stationBuffer, StandardCharsets.UTF_8);\n                doubleStart = i + 1;\n            }\n            else if (b == '\\n') {\n                byte[] doubleBuffer = new byte[i - doubleStart];\n                buffer.position(doubleStart);\n                buffer.get(doubleBuffer);\n                Double temperature = Double.parseDouble(new String(doubleBuffer));\n                lineStart = i + 1;\n\n                MeasurementAggregator aggregator = aggregates.computeIfAbsent(station, s -> new MeasurementAggregator());\n                aggregator.min = Math.min(aggregator.min, temperature);\n                aggregator.max = Math.max(aggregator.max, temperature);\n                aggregator.sum += temperature;\n                aggregator.count++;\n            }\n        }\n        return aggregates;\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        ExecutorService executor = Executors.newFixedThreadPool(128);\n        RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n        long position = 0;\n        List<Future<Map<String, MeasurementAggregator>>> futures = new ArrayList<>();\n        while (position < FILE_SIZE) {\n            int end = (int) Math.min(position + SEGMENT_SIZE, FILE_SIZE);\n            int length = (int) (end - position);\n            MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, position, length);\n            while (buffer.get(length - 1) != '\\n') {\n                --length;\n            }\n            position += length;\n            int finalLength = length;\n            futures.add(executor.submit(() -> processSegment(buffer, finalLength)));\n        }\n\n        executor.shutdown();\n        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);\n\n        // Merge results into a single TreeMap<String, MeasurementAggregator>\n        Map<String, MeasurementAggregator> aggregates = new TreeMap<>();\n        for (Future<Map<String, MeasurementAggregator>> future : futures) {\n            Map<String, MeasurementAggregator> segmentAggregates = future.get();\n            for (Map.Entry<String, MeasurementAggregator> entry : segmentAggregates.entrySet()) {\n                MeasurementAggregator aggregator = aggregates.computeIfAbsent(entry.getKey(), s -> new MeasurementAggregator());\n                aggregator.min = Math.min(aggregator.min, entry.getValue().min);\n                aggregator.max = Math.max(aggregator.max, entry.getValue().max);\n                aggregator.sum += entry.getValue().sum;\n                aggregator.count += entry.getValue().count;\n            }\n        }\n        System.out.println(aggregates);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_davecom.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.math.RoundingMode;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.text.DecimalFormat;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.HashMap;\nimport java.util.IntSummaryStatistics;\nimport java.util.List;\nimport java.util.ArrayList;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_davecom {\n\n    /*\n     * Original Header Could Not Be Changed to Match Checks so...\n     * Copyright 2024 David Kopec\n     * Licensed under the Apache License, Version 2.0 (the \"License\");\n     * Created by David Kopec with some inspiration from seijikun's solution\n     * and assistance from GitHub Copilot.\n     */\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final ConcurrentHashMap<ByteBuffer, Integer> mins = new ConcurrentHashMap<>();\n    private static final ConcurrentHashMap<ByteBuffer, Integer> maxs = new ConcurrentHashMap<>();\n    private static final ConcurrentHashMap<ByteBuffer, Integer> sums = new ConcurrentHashMap<>();\n    private static final ConcurrentHashMap<ByteBuffer, Integer> counts = new ConcurrentHashMap<>();\n\n    public static void processChunk(MappedByteBuffer chunk, long chunkSize) {\n        // setup\n        chunk.load();\n        HashMap<ByteBuffer, IntSummaryStatistics> values = new HashMap<>();\n\n        // do the actual processing\n        long end = chunk.position() + chunkSize;\n        // byte[] name = new byte[128];\n        int value = 0;\n        byte b = 0;\n        boolean negate = false;\n        long nameStart = 0;\n        long nameEnd = 0;\n        int nameLength = 0;\n        while (chunk.position() < end) {\n            // read name up to semicolon\n            nameStart = chunk.position();\n            b = chunk.get();\n            while (b != ';') {\n                b = chunk.get();\n            }\n            nameEnd = chunk.position() - 1;\n            nameLength = (int) (nameEnd - nameStart);\n            // generate byte array for name\n            ByteBuffer nameBuffer = ByteBuffer.allocate(nameLength);\n            chunk.get(chunk.position() - nameLength - 1, nameBuffer.array(), 0, nameLength);\n            // convert name to string\n            // read value\n            value = 0;\n            b = chunk.get();\n            negate = false;\n            while (b != '\\n') {\n                if (b == '.') {\n                    b = chunk.get();\n                    continue;\n                }\n                else if (b == '-') {\n                    negate = true;\n                    b = chunk.get();\n                    continue;\n                }\n                value = value * 10 + (b - '0');\n                b = chunk.get();\n            }\n            if (negate) {\n                value = -value;\n            }\n\n            if (values.containsKey(nameBuffer)) {\n                values.get(nameBuffer).accept(value);\n            }\n            else {\n                IntSummaryStatistics stats = new IntSummaryStatistics();\n                stats.accept(value);\n                values.put(nameBuffer, stats);\n            }\n        }\n\n        for (ByteBuffer nameBfr : values.keySet()) {\n            IntSummaryStatistics stats = values.get(nameBfr);\n            mins.compute(nameBfr, (k, v) -> v == null ? stats.getMin() : Math.min(v, stats.getMin()));\n            maxs.compute(nameBfr, (k, v) -> v == null ? stats.getMax() : Math.max(v, stats.getMax()));\n            sums.compute(nameBfr, (k, v) -> v == null ? (int) stats.getSum() : (v + (int) stats.getSum()));\n            counts.compute(nameBfr, (k, v) -> v == null ? (int) stats.getCount() : (v + (int) stats.getCount()));\n        }\n    }\n\n    public static void outputResults() {\n        // output results sorted by name with format {name}={min}/{mean}/{max} in one giant string\n        // fast string concatenation starting with { and ending with } with a comma between each (no newlines)\n        StringBuilder sb = new StringBuilder();\n        sb.append('{');\n        // var sortedNames = mins.keySet().stream().sorted().toArray(String[]::new);\n\n        DecimalFormat df = new DecimalFormat(\"0.0\");\n        df.setRoundingMode(RoundingMode.HALF_UP);\n        List<String> sortedNames = mins.keySet().stream()\n                .map(b -> new String(b.array(), 0, b.limit()))\n                .sorted()\n                .collect(Collectors.toList());\n        for (String nameStr : sortedNames) {\n            ByteBuffer name = ByteBuffer.wrap(nameStr.getBytes());\n            double min = ((double) mins.get(name)) / 10;\n            double max = ((double) maxs.get(name)) / 10;\n            double average = ((double) sums.get(name)) / ((double) counts.get(name)) / 10;\n            sb.append(nameStr);\n            sb.append('=');\n            sb.append(df.format(min));\n            sb.append('/');\n            sb.append(df.format(average));\n            sb.append('/');\n            sb.append(df.format(max));\n            sb.append(',');\n            sb.append(' ');\n        }\n        if (sb.length() > 1) {\n            sb.deleteCharAt(sb.length() - 2);\n            sb.deleteCharAt(sb.length() - 1);\n        }\n        sb.append('}');\n        System.out.println(sb.toString());\n    }\n\n    public static void main(String[] args) throws IOException {\n        // create thread pool\n        ExecutorService es = Executors.newVirtualThreadPerTaskExecutor();\n\n        // load file\n        FileChannel fc = FileChannel.open(Path.of(FILE));\n\n        // configuration information\n        long fileSize = fc.size();\n        int numProcessors = Runtime.getRuntime().availableProcessors();\n        int numChunks = numProcessors * 2000;\n        // System.out.println(\"numProcessors: \" + numProcessors);\n        // System.out.println(\"numChunks: \" + numChunks);\n\n        // create check buffer\n        ByteBuffer bb = ByteBuffer.allocateDirect(128);\n\n        // find appropriate chunks\n        // System.out.println(\"fileSize: \" + fileSize);\n        long chunkLimit = fileSize / numChunks;\n        long chunkStart = 0;\n        long chunkEnd = chunkLimit;\n        // int chunkNum = 0;\n        while (chunkEnd < fileSize) {\n            // System.out.println(\"initiated chunkNum: \" + chunkNum);\n            // find the next newline\n            fc.position(chunkEnd);\n            bb.clear();\n            fc.read(bb);\n            bb.flip();\n            while (bb.get() != '\\n' && bb.position() < bb.limit()) {\n            }\n            chunkEnd = chunkEnd + bb.position();\n            if (chunkEnd > fileSize) {\n                chunkEnd = fileSize - 1;\n            }\n            // process chunk\n            long chunkSize = chunkEnd - chunkStart;\n            if (chunkSize < 1) {\n                break;\n            }\n            // System.out.println(\"chunkStart: \" + chunkStart);\n            // System.out.println(\"chunkEnd: \" + chunkEnd);\n            // System.out.println(\"chunkSize: \" + chunkSize);\n            MappedByteBuffer chunk = fc.map(FileChannel.MapMode.READ_ONLY, chunkStart, chunkSize);\n            // final int chunkNumFinal = chunkNum;\n            es.submit(() -> {\n                // System.out.println(\"started chunkNum: \" + chunkNumFinal);\n                processChunk(chunk, chunkSize);\n                // System.out.println(\"finished chunkNum: \" + chunkNumFinal);\n            });\n            chunkStart = chunkEnd;\n            chunkEnd = chunkEnd + chunkLimit;\n            if (chunkEnd > fileSize) {\n                chunkEnd = fileSize - 1;\n            }\n            // chunkNum++;\n        }\n        es.close();\n\n        outputResults();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_davery22.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileDescriptor;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\n\npublic class CalculateAverage_davery22 {\n    static final String FILE = \"./measurements.txt\";\n    static final int MAP_SIZE = 1 << 16; // Must be a power of two > 10000\n    static final int MAP_MASK = MAP_SIZE - 1;\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        FileChannel in = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ);\n        int concurrency = Runtime.getRuntime().availableProcessors();\n        Thread[] threads = new Thread[concurrency - 1];\n        Worker[] workers = new Worker[concurrency - 1];\n        long fileSize = in.size();\n        int segmentSize = (int) (fileSize / concurrency);\n        long fileCursor = 0;\n\n        // Process each segment in its own thread\n        for (int i = 0; i < concurrency - 1; i++) {\n            MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, fileCursor, segmentSize);\n            int limit = segmentSize;\n            for (; limit > 0 && buf.get(limit - 1) != '\\n'; limit--) {\n            }\n            buf.limit(limit);\n            fileCursor += limit;\n\n            Thread t = threads[i] = new Thread(workers[i] = new Worker(buf));\n            t.start();\n        }\n\n        // Process last segment on main thread\n        MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, fileCursor, fileSize - fileCursor);\n        Worker main = new Worker(buf);\n        main.run();\n\n        for (Thread t : threads) {\n            t.join();\n        }\n\n        // Merge maps\n        for (int i = 0; i < concurrency - 1; i++) {\n            long[][] entries = workers[i].entries;\n            for (int j = 0; entries[j] != null; j++) {\n                main.mergeEntry(entries[j]);\n            }\n        }\n\n        // Estimate size of output buffer - okay to overestimate, not underestimate\n        long[][] entries = main.entries;\n        int platformCR = System.lineSeparator().length() > 1 ? 1 : 0; // May be different from file\n        int bufferLen = 3 + platformCR; // '{' and '}' and '\\n' (and '\\r' if detected)\n        int entriesLen = 0;\n        for (; entries[entriesLen] != null; entriesLen++) {\n            // Needs enough space for: '<city_name>=<min>/<mean>/<max>, ' where the stats are up to 5 bytes each\n            bufferLen += (entries[entriesLen].length - 4) * 8 + 20;\n        }\n\n        // Sort by city name\n        Arrays.sort(entries, 0, entriesLen, (a, b) -> {\n            int n = Math.min(a.length, b.length) - 4;\n            for (int i = 0; i < n; i++) {\n                int cmp = Long.compareUnsigned(a[i], b[i]);\n                if (cmp != 0) {\n                    return cmp;\n                }\n            }\n            return a.length - b.length;\n        });\n\n        // Fill the output buffer\n        byte[] toPrint = new byte[bufferLen];\n        bufferLen = 0;\n        toPrint[bufferLen++] = '{';\n        for (int i = 0; i < entriesLen; i++) {\n            if (i > 0) {\n                toPrint[bufferLen++] = ',';\n                toPrint[bufferLen++] = ' ';\n            }\n            long[] entry = entries[i];\n            int j = 0;\n            for (; j < entry.length - 5; j++) {\n                long word = entry[j];\n                for (int k = 0; k < 8; k++) {\n                    toPrint[bufferLen++] = (byte) ((word >>> (56 - k * 8)) & 0xFF);\n                }\n            }\n            long last = entry[j++];\n            int lastLen = 8 - (Long.numberOfTrailingZeros(last) >>> 3);\n            for (int k = 0; k < lastLen; k++) {\n                toPrint[bufferLen++] = (byte) ((last >>> (56 - k * 8)) & 0xFF);\n            }\n            long min = entry[j++];\n            long max = entry[j++];\n            long sum = entry[j++];\n            long count = entry[j++];\n            long mean = mean(sum, count);\n            toPrint[bufferLen++] = '=';\n            bufferLen = statToBytes(min, toPrint, bufferLen);\n            toPrint[bufferLen++] = '/';\n            bufferLen = statToBytes(mean, toPrint, bufferLen);\n            toPrint[bufferLen++] = '/';\n            bufferLen = statToBytes(max, toPrint, bufferLen);\n        }\n        toPrint[bufferLen++] = '}';\n        if (platformCR == 1) {\n            toPrint[bufferLen++] = '\\r';\n        }\n        toPrint[bufferLen++] = '\\n';\n\n        // Print\n        FileOutputStream out = new FileOutputStream(FileDescriptor.out);\n        out.write(toPrint, 0, bufferLen);\n    }\n\n    static class Worker implements Runnable {\n        final MappedByteBuffer buf;\n        final int[] indexes = new int[MAP_SIZE];\n        final long[][] entries = new long[MAP_SIZE][];\n        int lastIndex;\n\n        Worker(MappedByteBuffer buf) {\n            this.buf = buf;\n        }\n\n        @Override\n        public void run() {\n            // Big enough for max city bytes (100 bytes) + temperature value (1 long)\n            long[] item = new long[14];\n            int itemLen = 0, bufCursor = 0, bufLimit = buf.limit();\n            int lineSeparatorLen = (bufLimit > 1 && buf.get(bufLimit - 2) == '\\r') ? 2 : 1;\n            boolean isLittleEndian = buf.order().equals(ByteOrder.LITTLE_ENDIAN);\n\n            while (bufCursor < bufLimit) {\n                // Parse next long of bytes, until we see a semicolon\n                long word = 0;\n                if (bufLimit - bufCursor >= 8) {\n                    word = isLittleEndian ? Long.reverseBytes(buf.getLong(bufCursor)) : buf.getLong(bufCursor);\n                }\n                else {\n                    for (int j = 0; bufCursor + j < bufLimit; j++) {\n                        word |= ((long) buf.get(bufCursor + j) & 0xFF) << (56 - j * 8);\n                    }\n                }\n                int idx = indexOfSemicolon(word);\n                if (idx < 0) {\n                    item[itemLen++] = word;\n                    bufCursor += 8;\n                    continue;\n                }\n                // Zero-out everything after city bytes\n                if (idx > 0) {\n                    item[itemLen++] = word & (-1L << (64 - idx * 8));\n                }\n                // Parse the temperature value\n                bufCursor += idx + 1;\n                long sign = 1, magnitude;\n                byte b1, b2;\n                if ((b1 = buf.get(bufCursor)) == '-') {\n                    sign = -1;\n                    bufCursor += 1;\n                    b1 = buf.get(bufCursor);\n                }\n                if ((b2 = buf.get(bufCursor + 1)) == '.') {\n                    magnitude = 10 * (b1 - '0') + (buf.get(bufCursor + 2) - '0');\n                    bufCursor += 3 + lineSeparatorLen;\n                }\n                else {\n                    magnitude = 100 * (b1 - '0') + 10 * (b2 - '0') + (buf.get(bufCursor + 3) - '0');\n                    bufCursor += 4 + lineSeparatorLen;\n                }\n                // Merge to map\n                item[itemLen++] = sign * magnitude;\n                mergeItem(item, itemLen);\n                itemLen = 0;\n            }\n        }\n\n        static int hash(long word) {\n            return (int) (word ^ (word >>> 16) * (word >>> 32) ^ (word >>> 48)) & MAP_MASK;\n        }\n\n        void mergeItem(long[] item, int len) { // format [n longs for key, 1 long for value]\n            loop: for (int hash = hash(item[0]);; hash = hash + 1 < MAP_SIZE ? hash + 1 : 0) { // Linear probing\n                int index = indexes[hash];\n                // Check if new\n                if (index == 0) {\n                    long[] entry = new long[len + 3];\n                    System.arraycopy(item, 0, entry, 0, len);\n                    entry[len] = item[len - 1]; // initial max\n                    entry[len + 1] = item[len - 1]; // initial sum\n                    entry[len + 2] = 1; // initial count\n                    indexes[hash] = ++lastIndex;\n                    entries[lastIndex - 1] = entry;\n                    return;\n                }\n                // Check if equal or conflict\n                long[] entry = entries[index - 1];\n                if (entry.length != len + 3) {\n                    continue;\n                }\n                int i = 0;\n                for (; i < len - 1; i++) {\n                    if (entry[i] != item[i]) {\n                        continue loop;\n                    }\n                }\n                // Equal - update stats\n                entry[i] = Math.min(entry[i], item[i]); // min\n                entry[i + 1] = Math.max(entry[i + 1], item[i]); // max\n                entry[i + 2] += item[i]; // sum\n                entry[i + 3] += 1; // count\n                return;\n            }\n        }\n\n        void mergeEntry(long[] item) { // format: [n longs for key, 4 longs for min/max/sum/count]\n            loop: for (int hash = hash(item[0]);; hash = hash + 1 < MAP_SIZE ? hash + 1 : 0) { // Linear probing\n                int index = indexes[hash];\n                // Check if new\n                if (index == 0) {\n                    indexes[hash] = ++lastIndex;\n                    entries[lastIndex - 1] = item;\n                    return;\n                }\n                // Check if equal or conflict\n                long[] entry = entries[index - 1];\n                if (entry.length != item.length) {\n                    continue;\n                }\n                int i = 0;\n                for (; i < item.length - 4; i++) {\n                    if (entry[i] != item[i]) {\n                        continue loop;\n                    }\n                }\n                // Equal - update stats\n                entry[i] = Math.min(entry[i], item[i]); // min\n                entry[i + 1] = Math.max(entry[i + 1], item[i + 1]); // max\n                entry[i + 2] += item[i + 2]; // sum\n                entry[i + 3] += item[i + 3]; // count\n                return;\n            }\n        }\n    }\n\n    // SWAR search based on royvanrijn's code\n    static final long SEMICOLON_PATTERN = ((long) ';' << 56) | ((long) ';' << 48) | ((long) ';' << 40) | ((long) ';' << 32) |\n            ((long) ';' << 24) | ((long) ';' << 16) | ((long) ';' << 8) | ((long) ';');\n\n    static int indexOfSemicolon(long word) {\n        long match = word ^ SEMICOLON_PATTERN; // Only matching bytes are zero\n        long mask = ((match - 0x0101010101010101L) & ~match) & 0x8080808080808080L; // Only matching bytes are non-zero (leftmost bit is 1)\n        return mask == 0 ? -1 : Long.numberOfLeadingZeros(mask) >>> 3; // Return byte index of first 1 bit\n    }\n\n    static int statToBytes(long stat, byte[] buf, int pos) {\n        // stat is fixed point, so the original guaranteed range of [-99.9, 99.9] becomes [-999, 999]\n        if (stat < 0) {\n            stat = -stat;\n            buf[pos++] = '-';\n        }\n        int digits = stat > 99 ? 3 : 2;\n        buf[pos + digits] = (byte) ((stat % 10) + '0');\n        buf[pos + digits - 1] = '.';\n        stat /= 10;\n        for (int i = digits - 2; i >= 0; i--) {\n            buf[pos + i] = (byte) ((stat % 10) + '0');\n            stat /= 10;\n        }\n        return pos + digits + 1;\n    }\n\n    static long mean(long sum, long count) {\n        long mean = sum / count;\n        long remainder = sum % count;\n        if (remainder < 0) {\n            // Match the rounding behavior of the baseline, which uses Math.round(number * 10.0) / 10.0.\n            // For positive numbers we need to round up between [.5, 1).\n            // For negative numbers we need to round up between [-.5, 0).\n            // Interestingly this differs from the rounding behavior of String.format(\"%.1f\", number),\n            // which would round -8.55 to -8.6, rather than -8.5.\n            if (count < (-remainder << 1)) {\n                return mean - 1;\n            }\n        }\n        else if (count <= (remainder << 1)) {\n            return mean + 1;\n        }\n        return mean;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ddimtirov.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.atomic.LongAdder;\n\npublic class CalculateAverage_ddimtirov {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MAX_STATIONS = 100_000;\n    private static final int MAX_STATION_NAME_LENGTH = 100;\n    private static final int MAX_UTF8_CODEPOINT_SIZE = 3;\n\n    private static final int OFFSET_MIN = 0;\n    private static final int OFFSET_MAX = 1;\n    private static final int OFFSET_COUNT = 2;\n\n    private static final boolean assertions = CalculateAverage_ddimtirov.class.desiredAssertionStatus();\n    private static final Map<String, LongAdder> hashCollisionOccurrences = new ConcurrentHashMap<>();\n\n    @SuppressWarnings(\"RedundantSuppression\")\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var path = Path.of(args.length>0 ? args[0] : FILE);\n        Instant start = null;// Instant.now();\n\n        var desiredSegmentsCount = Runtime.getRuntime().availableProcessors();\n        var fileSegments = FileSegment.forFile(path, desiredSegmentsCount);\n\n        var loaders = new ThreadGroup(\"Loaders\");\n        var trackers = Collections.synchronizedList(new ArrayList<Tracker>());\n        var threads = fileSegments.stream().map(fileSegment -> Thread // manually start thread per segment\n                .ofPlatform()\n                .group(loaders)\n                .name(STR.\"Segment \\{fileSegment}\")\n                .start(() -> {\n                    try (var fileChannel = (FileChannel) Files.newByteChannel(path, StandardOpenOption.READ)) {\n                        var tracker = new Tracker();\n                        var memorySegment = fileChannel.map(FileChannel.MapMode.READ_ONLY, fileSegment.start(), fileSegment.size(), Arena.ofConfined());\n                        tracker.processSegment(memorySegment);\n                        trackers.add(tracker);\n                    }\n                    catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                })\n        ).toList();\n\n        for (Thread thread : threads) thread.join();\n        assert trackers.size() == threads.size();\n        assert trackers.size() <= desiredSegmentsCount;\n\n        var result = summarizeTrackers(trackers.toArray(Tracker[]::new));\n        System.out.println(result);\n\n        // noinspection ConstantValue\n        if (start != null) {\n            System.err.println(Duration.between(start, Instant.now()));\n            if (assertions) System.err.printf(\"hash clashes: %s%n\", hashCollisionOccurrences);\n        }\n        assert Files.readAllLines(Path.of(\"measurements.out\")).getFirst().equals(result);\n    }\n\n    record FileSegment(int index, long start, long size) {\n        @Override\n        public String toString() {\n            return STR.\"#\\{index} [\\{start}..\\{start + size}] \\{size} bytes\";\n        }\n\n        public static List<FileSegment> forFile(Path file, int desiredSegmentsCount) throws IOException {\n            try (var raf = new RandomAccessFile(file.toFile(), \"r\")) {\n                var segments = new ArrayList<FileSegment>();\n                var fileSize = raf.length();\n                var segmentSize = Math.max(1024 * 1024, fileSize / desiredSegmentsCount);\n\n                var i = 1;\n                var prevEnd = 0L;\n                while (prevEnd < fileSize-1) {\n                    var start = prevEnd;\n                    var end = findNewLineAfter(raf, prevEnd + segmentSize, fileSize);\n                    segments.add(new FileSegment(i, start, end - start));\n                    prevEnd = end;\n                }\n                return segments;\n            }\n        }\n\n        private static long findNewLineAfter(RandomAccessFile raf, long location, long fileSize) throws IOException {\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                int c = raf.read();\n                if (c == '\\r' || c == '\\n') break;\n            }\n            return Math.min(location, fileSize - 1);\n        }\n    }\n\n    static class Accumulator {\n        public final String name;\n        public int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE, count;\n        public long sum;\n\n        public Accumulator(String name) {\n            this.name = name;\n        }\n\n        public void accumulate(int min, int max, int count, long sum) {\n            if (this.min > min)\n                this.min = min;\n            if (this.max < max)\n                this.max = max;\n            this.count += count;\n            this.sum += sum;\n        }\n\n        @Override\n        public String toString() {\n            var mean = Math.round((double) sum / count) / 10.0;\n            return (min / 10.0) + \"/\" + mean + \"/\" + (max / 10.0);\n        }\n    }\n\n    private static String summarizeTrackers(Tracker[] trackers) {\n        var result = new TreeMap<String, Accumulator>();\n\n        for (var i = 0; i < Tracker.SIZE; i++) {\n            Accumulator acc = null;\n\n            for (Tracker tracker : trackers) {\n                var name = tracker.names[i];\n                if (name == null) {\n                    continue;\n                }\n                else if (acc == null || !name.equals(acc.name)) {\n                    acc = result.computeIfAbsent(name, Accumulator::new);\n                }\n                acc.accumulate(\n                        tracker.minMaxCount[i * 3 + OFFSET_MIN],\n                        tracker.minMaxCount[i * 3 + OFFSET_MAX],\n                        tracker.minMaxCount[i * 3 + OFFSET_COUNT],\n                        tracker.sums[i]);\n            }\n        }\n        return result.toString();\n    }\n\n    static class Tracker {\n        public static final int SIZE = MAX_STATIONS * 10;\n\n        private static final int CORRECTION_0_TO_9 = '0' * 10 + '0';\n        private static final int CORRECTION_10_TO_99 = '0' * 100 + '0' * 10 + '0';\n\n        private final byte[] tempNameBytes = new byte[MAX_STATION_NAME_LENGTH * MAX_UTF8_CODEPOINT_SIZE];\n        private final int[] minMaxCount = new int[SIZE * 3];\n        private final long[] sums = new long[SIZE];\n        private final String[] names = new String[SIZE];\n        private final byte[][] nameBytes = new byte[SIZE][];\n\n        private void processSegment(MemorySegment memory) {\n            long limit = memory.byteSize();\n\n            var pos = 0;\n\n            // skip newlines so the chunk limit check can work correctly\n            while (pos < limit) {\n                byte c = memory.get(ValueLayout.JAVA_BYTE, pos);\n                if (c != '\\r' && c != '\\n')\n                    break;\n                pos++;\n            }\n\n            while (pos < limit) {\n                byte b;\n\n                int nameLength = 0, nameHash = 0;\n                while ((b = memory.get(ValueLayout.JAVA_BYTE, pos++)) != ';') {\n                    tempNameBytes[nameLength++] = b;\n                    nameHash = nameHash * 31 + b;\n                }\n\n                int sign;\n                if (memory.get(ValueLayout.JAVA_BYTE, pos) == '-') {\n                    sign = -1;\n                    pos++;\n                }\n                else {\n                    sign = 1;\n                }\n\n                int temperature; // between [-99.9 and 99.9], mapped to fixed point int (scaled by 10)\n                if (memory.get(ValueLayout.JAVA_BYTE, pos + 1) == '.') { // between -9.99 and 9.99\n                    assert memory.get(ValueLayout.JAVA_BYTE, pos + 1) == '.';\n                    temperature = memory.get(ValueLayout.JAVA_BYTE, pos) * 10 +\n                            memory.get(ValueLayout.JAVA_BYTE, pos + 2) - CORRECTION_0_TO_9;\n                    pos += 3; // #.# - 3 chars\n                }\n                else { // between [-99.9 and -9.99] OR [9.99 and 99.9]\n                    assert memory.get(ValueLayout.JAVA_BYTE, pos + 2) == '.';\n                    temperature = memory.get(ValueLayout.JAVA_BYTE, pos) * 100 +\n                            memory.get(ValueLayout.JAVA_BYTE, pos + 1) * 10 +\n                            memory.get(ValueLayout.JAVA_BYTE, pos + 3) - CORRECTION_10_TO_99;\n                    pos += 4; // ##.# - 4 chars\n                }\n\n                processLine(nameHash, tempNameBytes, nameLength, temperature * sign);\n\n                // skip newlines so the chunk limit check can work correctly\n                while (pos < limit) {\n                    byte c = memory.get(ValueLayout.JAVA_BYTE, pos);\n                    if (c != '\\r' && c != '\\n')\n                        break;\n                    pos++;\n                }\n            }\n        }\n\n        public void processLine(int nameHash, byte[] nameBytesBuffer, int nameLength, int temperature) {\n            var i = Math.abs(nameHash) % SIZE;\n\n            while (true) {\n                if (names[i] == null) {\n                    byte[] trimmedBytes = Arrays.copyOf(nameBytesBuffer, nameLength);\n                    names[i] = new String(trimmedBytes, StandardCharsets.UTF_8);\n                    nameBytes[i] = trimmedBytes;\n                    minMaxCount[i*3 + OFFSET_MIN] = Integer.MAX_VALUE;\n                    minMaxCount[i*3 + OFFSET_MAX] = Integer.MIN_VALUE;\n                    break;\n                }\n                else if (nameBytes[i].length==nameLength && Arrays.equals(nameBytes[i], 0, nameLength, nameBytesBuffer, 0, nameLength)) {\n                    break;\n                }\n                if (assertions) {\n                    var key = new String(nameBytesBuffer, 0, nameLength, StandardCharsets.UTF_8);\n                    hashCollisionOccurrences.computeIfAbsent(key, _ -> new LongAdder()).increment();\n                }\n                i = (i + 1) % SIZE;\n            }\n            if (assertions) {\n                var key = new String(nameBytesBuffer, 0, nameLength, StandardCharsets.UTF_8);\n                if (hashCollisionOccurrences.containsKey(key)) {\n                    hashCollisionOccurrences.computeIfAbsent(STR.\"\\{key}[\\{i}]\", _ -> new LongAdder()).increment();\n                }\n            }\n\n            sums[i] += temperature;\n\n            int mmcIndex = i * 3;\n            var min = minMaxCount[mmcIndex + OFFSET_MIN];\n            var max = minMaxCount[mmcIndex + OFFSET_MAX];\n            if (temperature < min)\n                minMaxCount[mmcIndex + OFFSET_MIN] = temperature;\n            if (temperature > max)\n                minMaxCount[mmcIndex + OFFSET_MAX] = temperature;\n\n            minMaxCount[mmcIndex + OFFSET_COUNT]++;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_deemkeen.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class CalculateAverage_deemkeen {\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n\n        File file = new File(FILE);\n        long fileSize = file.length();\n        int numberOfSegments = 400;\n        long segmentSize = fileSize / numberOfSegments;\n\n        if (segmentSize < 100) {\n            numberOfSegments = 1;\n            segmentSize = fileSize;\n        }\n\n        List<SegmentPair> segments = new ArrayList<>();\n\n        try (\n                var randomAccessFile = new RandomAccessFile(file, \"r\");\n                var fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), StandardOpenOption.READ)) {\n            for (int i = 0; i < numberOfSegments; i++) {\n                long segStart = i * segmentSize;\n                long segEnd = (i == numberOfSegments - 1) ? fileSize : segStart + segmentSize;\n\n                if (i != 0) {\n                    randomAccessFile.seek(segStart);\n                    while (segStart < segEnd) {\n                        segStart++;\n                        if (randomAccessFile.read() == '\\n')\n                            break;\n                    }\n                }\n\n                if (i != numberOfSegments - 1) {\n                    randomAccessFile.seek(segEnd);\n                    while (segEnd < fileSize) {\n                        segEnd++;\n                        if (randomAccessFile.read() == '\\n')\n                            break;\n                    }\n                }\n\n                segments.add(new SegmentPair(new FileSegment(segStart, segEnd), new ByteArrayToResultMap()));\n            }\n\n            try (ExecutorService es = Executors.newVirtualThreadPerTaskExecutor()) {\n                var partitions = Collections.synchronizedList(new ArrayList<ByteArrayToResultMap>());\n                for (var segment : segments) {\n                    var segmentResultMap = segment.value;\n                    es.execute(() -> {\n                        MappedByteBuffer bb;\n                        try {\n                            bb = fileChannel.map(FileChannel.MapMode.READ_ONLY, segment.key.start, segment.key.end - segment.key.start);\n                        }\n                        catch (IOException e) {\n                            throw new RuntimeException(e);\n                        }\n                        byte[] buffer = new byte[100];\n                        int startLine;\n                        while ((startLine = bb.position()) < bb.limit()) {\n                            int currentPosition = startLine;\n                            byte b;\n                            int offset = 0;\n                            int hash = 0;\n                            while (currentPosition != segment.key.end && (b = bb.get(currentPosition++)) != ';') {\n                                buffer[offset++] = b;\n                                hash = 31 * hash + b;\n                            }\n                            int temp;\n                            int negative = 1;\n                            // Inspired by @yemreinci to unroll this even further\n                            if (bb.get(currentPosition) == '-') {\n                                negative = -1;\n                                currentPosition++;\n                            }\n                            if (bb.get(currentPosition + 1) == '.') {\n                                temp = negative * ((bb.get(currentPosition) - '0') * 10 + (bb.get(currentPosition + 2) - '0'));\n                                currentPosition += 3;\n                            }\n                            else {\n                                temp = negative\n                                        * ((bb.get(currentPosition) - '0') * 100 + ((bb.get(currentPosition + 1) - '0') * 10 + (bb.get(currentPosition + 3) - '0')));\n                                currentPosition += 4;\n                            }\n                            if (bb.get(currentPosition) == '\\r') {\n                                currentPosition++;\n                            }\n                            currentPosition++;\n                            segmentResultMap.putOrMerge(buffer, 0, offset, temp / 10.0, hash);\n                            bb.position(currentPosition);\n                        }\n\n                    });\n\n                    partitions.add(segmentResultMap);\n\n                }\n\n                try {\n                    es.shutdown();\n                    while (!es.awaitTermination(24L, TimeUnit.HOURS)) {\n                        System.out.println(\"Still waiting for termination..\");\n                    }\n                }\n                catch (InterruptedException e) {\n                    // do nothing\n                }\n\n                TreeMap<String, Result> resultMap = new TreeMap<>();\n                for (ByteArrayToResultMap partition : partitions) {\n                    for (Entry e : partition.getAll()) {\n                        resultMap.merge(new String(e.key()), e.value(), CalculateAverage_deemkeen::merge);\n                    }\n                }\n\n                System.out.println(resultMap);\n            }\n        }\n    }\n\n    private static Result merge(Result v, Result value) {\n        return merge(v, value.min, value.max, value.sum, value.count);\n    }\n\n    private static Result merge(Result v, double value, double value1, double value2, long value3) {\n        v.min = Math.min(v.min, value);\n        v.max = Math.max(v.max, value1);\n        v.sum += value2;\n        v.count += value3;\n        return v;\n    }\n\n    record Pair(int slot, Result slotValue) {\n    }\n\n    record SegmentPair(FileSegment key, ByteArrayToResultMap value) {\n    }\n\n    record Entry(byte[] key, Result value) {\n    }\n\n    record FileSegment(long start, long end) {\n    }\n\n    static class Result {\n        double min;\n        double max;\n        double sum;\n        long count;\n\n        Result(double value) {\n            this.min = value;\n            this.max = value;\n            this.sum = value;\n            this.count = 1;\n        }\n\n        @Override\n        public String toString() {\n            return round(min) +\n                    \"/\" + round(sum / count) +\n                    \"/\" + round(max);\n        }\n\n        double round(double v) {\n            return Math.round(v * 10.0) / 10.0;\n        }\n\n    }\n\n    static class ByteArrayToResultMap {\n        public static final int MAPSIZE = 1024 * 128;\n        Result[] slots = new Result[MAPSIZE];\n        byte[][] keys = new byte[MAPSIZE][];\n\n        public void putOrMerge(byte[] key, int offset, int size, double temp, int hash) {\n            int slot = hash & (slots.length - 1);\n            var slotValue = slots[slot];\n            // Linear probe for open slot\n            while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n                slot = (slot + 1) & (slots.length - 1);\n                slotValue = slots[slot];\n            }\n            Result value = slotValue;\n            if (value == null) {\n                slots[slot] = new Result(temp);\n                byte[] bytes = new byte[size];\n                System.arraycopy(key, offset, bytes, 0, size);\n                keys[slot] = bytes;\n            }\n            else {\n                value.min = Math.min(value.min, temp);\n                value.max = Math.max(value.max, temp);\n                value.sum += temp;\n                value.count += 1;\n            }\n        }\n\n        private int hashCode(byte[] a, int fromIndex, int length) {\n            int result = 0;\n            int end = fromIndex + length;\n            for (int i = fromIndex; i < end; i++) {\n                result = 31 * result + a[i];\n            }\n            return result;\n        }\n\n        private Pair getPair(byte[] key, int offset, int size) {\n            int hash = hashCode(key, offset, size);\n            int slot = hash & (slots.length - 1);\n            Result slotValue = slots[slot];\n            // Linear probe for open slot\n            while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n                slot = (slot + 1) & (slots.length - 1);\n                slotValue = slots[slot];\n            }\n            return new Pair(slot, slotValue);\n        }\n\n        public Result get(byte[] key, int offset, int size) {\n            return getPair(key, offset, size).slotValue();\n        }\n\n        // Get all pairs\n        public List<Entry> getAll() {\n            List<Entry> result = new ArrayList<>();\n            for (int i = 0; i < slots.length; i++) {\n                Result slotValue = slots[i];\n                if (slotValue != null) {\n                    result.add(new Entry(keys[i], slotValue));\n                }\n            }\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_dkarampi.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\n\npublic class CalculateAverage_dkarampi {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int BUFFER_SIZE = (1 << 29); // 500mb\n    private static final int HT_SIZE = nextPowerOfTwo(10000);\n    private static final int NUM_THREADS = 8;\n    private final List<Station[]> stationHashTables = new ArrayList<>();\n\n    public static void main(String[] args) throws Exception {\n        new CalculateAverage_dkarampi().runFast();\n    }\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static boolean areEqual(byte[] a, int aLen, byte[] b, int bLen) {\n        if (aLen != bLen) {\n            return false;\n        }\n        for (byte i = 0; i < aLen; i++) {\n            if (a[i] != b[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static int nextPowerOfTwo(int n) {\n        for (int i = 1; i < 32; i <<= 1) {\n            n |= n >> i;\n        }\n        return n + 1;\n    }\n\n    private void runFast() throws Exception {\n        createStationHashTables();\n        FileChannel channel = FileChannel.open(Path.of(FILE));\n\n        List<List<Buffer>> buffersList = new ArrayList<>();\n        for (int i = 0; i < NUM_THREADS; i++) {\n            buffersList.add(new ArrayList<>());\n        }\n\n        List<Buffer> buffers = createBuffers(channel);\n        for (int i = 0; i < buffers.size(); i++) {\n            buffersList.get(i % NUM_THREADS).add(buffers.get(i));\n        }\n\n        List<Task> tasks = new ArrayList<>();\n        for (int i = 0; i < NUM_THREADS; i++) {\n            tasks.add(new Task(stationHashTables.get(i), buffersList.get(i)));\n        }\n\n        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);\n        Future<?>[] futures = new Future<?>[NUM_THREADS];\n        for (int i = 0; i < NUM_THREADS; i++) {\n            futures[i] = executorService.submit(tasks.get(i));\n        }\n\n        for (Future<?> future : futures) {\n            future.get();\n        }\n\n        sortAndPrint();\n\n        executorService.shutdown();\n        channel.close();\n    }\n\n    private void createStationHashTables() {\n        for (int i = 0; i < NUM_THREADS; i++) {\n            Station[] stationsHashTable = new Station[HT_SIZE];\n            for (int j = 0; j < HT_SIZE; j++) {\n                stationsHashTable[j] = new Station();\n            }\n            stationHashTables.add(stationsHashTable);\n        }\n    }\n\n    private List<Buffer> createBuffers(FileChannel channel) throws Exception {\n        List<Buffer> buffers = new ArrayList<>();\n        long size = channel.size();\n        int lastByte;\n        for (long offset = 0; offset < size; offset += lastByte + 1) {\n            long sizeToMap = Math.min(size - offset, BUFFER_SIZE);\n            MappedByteBuffer buffer = channel.map(READ_ONLY, offset, sizeToMap);\n            lastByte = (int) sizeToMap - 1;\n            while (buffer.get(lastByte) != '\\n')\n                --lastByte;\n            buffers.add(new Buffer(buffer, lastByte + 1));\n        }\n        return buffers;\n    }\n\n    private void sortAndPrint() {\n        TreeMap<String, Station> sortedStations = new TreeMap<>();\n\n        for (Station[] stationHashTable : stationHashTables) {\n            for (Station station : stationHashTable) {\n                if (station.freq == 0) {\n                    continue;\n                }\n                String key = new String(station.name, 0, station.nameLen);\n                Station st = sortedStations.get(key);\n                if (st == null) {\n                    sortedStations.put(key, station);\n                }\n                else {\n                    st.min = Math.min(st.min, station.min);\n                    st.max = Math.max(st.max, station.max);\n                    st.sum += station.sum;\n                    st.freq += station.freq;\n                }\n            }\n        }\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"{\");\n        for (Map.Entry<String, Station> entry : sortedStations.entrySet()) {\n            String name = entry.getKey();\n            Station station = entry.getValue();\n            sb.append(name);\n            sb.append(\"=\");\n            sb.append(round(station.min));\n            sb.append(\"/\");\n            sb.append(round(round(station.sum) / station.freq));\n            sb.append(\"/\");\n            sb.append(round(station.max));\n            sb.append(\", \");\n        }\n        sb.delete(sb.length() - 2, sb.length());\n        sb.append(\"}\");\n        System.out.println(sb);\n    }\n\n    private record Buffer(ByteBuffer byteBuffer, int length) {\n    }\n\n    private static class Station {\n        double sum;\n        double min = 100;\n        double max = -100;\n        int freq;\n        short nameLen;\n        byte[] name = new byte[nextPowerOfTwo(100)];\n    }\n\n    private record Task(Station[] stations, List<Buffer> buffers) implements Runnable {\n\n    @Override\n    public void run() {\n        for (Buffer buffer : buffers) {\n            process(buffer);\n        }\n    }\n\n    private void process(Buffer buffer) {\n        short nameLen = 0;\n        int hash = 5381;\n        int temperature;\n        byte[] name = new byte[100];\n\n        for (int i = 0; i < buffer.length; i++) {\n            byte c = buffer.byteBuffer.get(i);\n            if (c == ';') {\n                int sign = 1;\n                c = buffer.byteBuffer.get(++i);\n                if (c == '-') {\n                    sign = -1;\n                    c = buffer.byteBuffer.get(++i);\n                    temperature = (c - '0') * 10;\n                    c = buffer.byteBuffer.get(++i);\n                    if (c == '.') {\n                        c = buffer.byteBuffer.get(++i);\n                        temperature = temperature + c - '0';\n                    }\n                    else {\n                        temperature = temperature + c - '0';\n                        ++i; // dot\n                        c = buffer.byteBuffer.get(++i);\n                        temperature = temperature * 10 + c - '0';\n                    }\n                }\n                else {\n                    temperature = (c - '0') * 10;\n                    c = buffer.byteBuffer.get(++i);\n                    if (c == '.') {\n                        c = buffer.byteBuffer.get(++i);\n                        temperature = temperature + c - '0';\n                    }\n                    else {\n                        temperature = temperature + c - '0';\n                        ++i; // dot\n                        c = buffer.byteBuffer.get(++i);\n                        temperature = temperature * 10 + c - '0';\n                    }\n                }\n                hash = hash & 0x7FFFFFFF;\n                updateStations(hash, name, nameLen, sign * (double) temperature / 10);\n                ++i; // For '\\n'\n                nameLen = 0;\n                hash = 5383;\n            }\n            else {\n                name[nameLen++] = c;\n                hash = ((hash << 5) + hash) + c;\n            }\n        }\n    }\n\n    private void updateStations(int hash, byte[] name, short nameLen, double temperature) {\n        int idx;\n        for (idx = hash % HT_SIZE; stations[idx].freq != 0; idx = (idx + 1) % HT_SIZE) {\n            if (areEqual(stations[idx].name, stations[idx].nameLen, name, nameLen)) {\n                stations[idx].sum += temperature;\n                stations[idx].min = Math.min(stations[idx].min, temperature);\n                stations[idx].max = Math.max(stations[idx].max, temperature);\n                ++stations[idx].freq;\n                return;\n            }\n        }\n        stations[idx].sum = temperature;\n        stations[idx].min = temperature;\n        stations[idx].max = temperature;\n        stations[idx].nameLen = nameLen;\n        System.arraycopy(name, 0, stations[idx].name, 0, nameLen);\n        stations[idx].freq = 1;\n    }\n}}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_dpsoft.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.Phaser;\n\npublic class CalculateAverage_dpsoft {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MAX_ROWS = 1 << 15;\n    private static final int ROWS_MASK = MAX_ROWS - 1;\n\n    public static void main(String[] args) throws IOException {\n        final var cpus = Runtime.getRuntime().availableProcessors();\n        final var segments = getMemorySegments(cpus);\n        final var tasks = new MeasurementExtractor[segments.size()];\n        final var phaser = new Phaser(segments.size());\n\n        for (int i = 0; i < segments.size(); i++) {\n            tasks[i] = new MeasurementExtractor(segments.get(i), phaser);\n        }\n\n        phaser.awaitAdvance(phaser.getPhase());\n\n        final var allMeasurements = Arrays.stream(tasks)\n                .parallel()\n                .map(MeasurementExtractor::getMeasurements)\n                .reduce(MeasurementMap::merge)\n                .orElseThrow();\n\n        System.out.println(sortSequentially(allMeasurements));\n\n        System.exit(0);\n    }\n\n    private static Map<String, Measurement> sortSequentially(MeasurementMap allMeasurements) {\n        final Map<String, Measurement> sorted = new TreeMap<>();\n        for (Measurement m : allMeasurements.measurements) {\n            if (m != null) {\n                sorted.put(new String(m.name, StandardCharsets.UTF_8), m);\n            }\n        }\n        return sorted;\n    }\n\n    // Inspired by @spullara\n    private static List<FileSegment> getMemorySegments(int numberOfSegments) throws IOException {\n        var file = new File(FILE);\n        long fileSize = file.length();\n        long segmentSize = fileSize / numberOfSegments;\n        List<FileSegment> segments = new ArrayList<>(numberOfSegments);\n\n        if (fileSize < 1_000_000) {\n            segments.add(new FileSegment(0, fileSize));\n            return segments;\n        }\n\n        while (segmentSize >= Integer.MAX_VALUE) {\n            numberOfSegments += 1;\n            segmentSize = fileSize / numberOfSegments;\n        }\n\n        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\")) {\n            for (int i = 0; i < numberOfSegments; i++) {\n                long segStart = i * segmentSize;\n                long segEnd = (i == numberOfSegments - 1) ? fileSize : segStart + segmentSize;\n                segStart = findSegment(i, 0, randomAccessFile, segStart, segEnd);\n                segEnd = findSegment(i, numberOfSegments - 1, randomAccessFile, segEnd, fileSize);\n\n                segments.add(new FileSegment(segStart, segEnd));\n            }\n        }\n        return segments;\n    }\n\n    private static long findSegment(int i, int skipSegment, RandomAccessFile raf, long location, long fileSize) throws IOException {\n        if (i != skipSegment) {\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                if (raf.read() == '\\n')\n                    break;\n            }\n        }\n        return location;\n    }\n\n    record FileSegment(long start, long end) {\n    }\n\n    static final class MeasurementExtractor implements Runnable {\n        private final FileSegment segment;\n        private final Phaser phaser;\n        private final MeasurementMap measurements = new MeasurementMap();\n\n        MeasurementExtractor(FileSegment memorySegment, Phaser phaser) {\n            this.segment = memorySegment;\n            this.phaser = phaser;\n            (new Thread(this)).start();\n        }\n\n        @Override\n        public void run() {\n            long segmentEnd = segment.end();\n            try (var fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n                var mbb = fileChannel.map(FileChannel.MapMode.READ_ONLY, segment.start(), segmentEnd - segment.start());\n                mbb.order(ByteOrder.nativeOrder());\n\n                if (segment.start() > 0) {\n                    skipToFirstLine(mbb);\n                }\n\n                while (mbb.remaining() > 0 && mbb.position() <= segmentEnd) {\n                    int pos = mbb.position();\n                    int nameHash = hashAndRewind(mbb);\n                    var m = measurements.getOrCompute(nameHash, mbb, pos);\n                    int temp = readTemperatureFromBuffer(mbb);\n\n                    m.sample(temp);\n                }\n            }\n            catch (IOException e) {\n                throw new RuntimeException(\"Error reading file\", e);\n            }\n            finally {\n                phaser.arriveAndAwaitAdvance();\n            }\n        }\n\n        // inspired by @lawrey\n        private static int hashAndRewind(MappedByteBuffer mbb) {\n            int hash = 0;\n            int idx = mbb.position();\n            outer: while (true) {\n                int name = mbb.getInt();\n                for (int c = 0; c < 4; c++) {\n                    int b = (name >> (c << 3)) & 0xFF;\n                    if (b == ';') {\n                        idx += c + 1;\n                        break outer;\n                    }\n                    hash ^= b * 82805;\n                }\n                idx += 4;\n            }\n\n            var rewind = mbb.position() - idx;\n            mbb.position(mbb.position() - rewind);\n            return hash;\n        }\n\n        private static int readTemperatureFromBuffer(MappedByteBuffer mbb) {\n            int temp = 0;\n            boolean negative = false;\n\n            outer: while (mbb.remaining() > 0) {\n                int b = mbb.get();\n                switch (b) {\n                    case '-':\n                        negative = true;\n                        break;\n                    default:\n                        temp = 10 * temp + (b - '0');\n                        break;\n                    case '.':\n                        b = mbb.get();\n                        temp = 10 * temp + (b - '0');\n                    case '\\r':\n                        mbb.get();\n                    case '\\n':\n                        break outer;\n                }\n            }\n            if (negative)\n                temp = -temp;\n            return temp;\n        }\n\n        public MeasurementMap getMeasurements() {\n            return measurements;\n        }\n\n        // Skips to the first line in the buffer, used for chunk processing.\n        private static void skipToFirstLine(MappedByteBuffer mbb) {\n            while ((mbb.get() & 0xFF) >= ' ') {\n                // Skip bytes until reaching the start of a line.\n            }\n        }\n    }\n\n    // credits to @shipilev\n    static class MeasurementMap {\n        private final Measurement[] measurements = new Measurement[MAX_ROWS];\n\n        public Measurement getOrCompute(int hash, MappedByteBuffer mbb, int position) {\n            int index = hash & ROWS_MASK;\n            var measurement = measurements[index];\n            if (measurement != null && hash == measurement.nameHash && Measurement.equalsTo(measurement.name, mbb, position)) {\n                return measurement;\n            }\n            else {\n                return compute(hash, mbb, position);\n            }\n        }\n\n        private Measurement compute(int hash, MappedByteBuffer mbb, int position) {\n            var index = hash & ROWS_MASK;\n            Measurement m;\n\n            while (true) {\n                m = measurements[index];\n                if (m == null || (hash == m.nameHash && Measurement.equalsTo(m.name, mbb, position))) {\n                    break;\n                }\n                index = (index + 1) & ROWS_MASK;\n            }\n\n            if (m == null) {\n                int len = mbb.position() - position - 1;\n                byte[] bytes = new byte[len];\n                mbb.position(position);\n                mbb.get(bytes, 0, len);\n                mbb.get();\n                measurements[index] = m = new Measurement(bytes, hash);\n            }\n\n            return m;\n        }\n\n        public MeasurementMap merge(MeasurementMap otherMap) {\n            for (Measurement other : otherMap.measurements) {\n                if (other == null)\n                    continue;\n                int index = other.nameHash & ROWS_MASK;\n                while (true) {\n                    Measurement m = measurements[index];\n                    if (m == null) {\n                        measurements[index] = other;\n                        break;\n                    }\n                    else if (Arrays.equals(m.name, other.name)) {\n                        m.merge(other);\n                        break;\n                    }\n                    else {\n                        index = (index + 1) & ROWS_MASK;\n                    }\n                }\n            }\n            return this;\n        }\n    }\n\n    static final class Measurement {\n        public final int nameHash;\n        public final byte[] name;\n\n        public long sum;\n        public int count = 0;\n        public int min = Integer.MAX_VALUE;\n        public int max = Integer.MIN_VALUE;\n\n        public Measurement(byte[] name, int nameHash) {\n            this.name = name;\n            this.nameHash = nameHash;\n        }\n\n        public static boolean equalsTo(byte[] name, MappedByteBuffer mbb, int position) {\n            int len = mbb.position() - position - 1;\n            if (len != name.length)\n                return false;\n            for (int i = 0; i < len; i++) {\n                if (name[i] != mbb.get(position + i))\n                    return false;\n            }\n            return true;\n        }\n\n        public void sample(int temp) {\n            min = Math.min(min, temp);\n            max = Math.max(max, temp);\n            sum += temp;\n            count++;\n        }\n\n        public Measurement merge(Measurement m2) {\n            min = Math.min(min, m2.min);\n            max = Math.max(max, m2.max);\n            sum += m2.sum;\n            count += m2.count;\n            return this;\n        }\n\n        public String toString() {\n            return round(((double) min) / 10.0) + \"/\" + round((((double) sum) / 10.0) / count) + \"/\" + round(((double) max) / 10.0);\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_dqhieuu.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\npublic class CalculateAverage_dqhieuu {\n    private static final String FILE = \"measurements.txt\";\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static class MeasurementAggregator {\n        private Lock lock = new ReentrantLock();\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum = 0;\n        private int count = 0;\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(round(sum) / count) + \"/\" + round(max);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        var lineStream = Files.lines(Paths.get(FILE)).parallel();\n\n        Map<String, MeasurementAggregator> measurements = new ConcurrentHashMap<>(10_000);\n\n        lineStream.forEach(\n                l -> {\n                    var sepIdx = 0;\n                    while (l.charAt(sepIdx) != ';') {\n                        sepIdx++;\n                    }\n\n                    var station = l.substring(0, sepIdx);\n\n                    int valueInt = 0;\n                    int sign = l.charAt(sepIdx + 1) == '-' ? -1 : 1;\n\n                    var lineLength = l.length();\n                    for (var i = sepIdx + 1; i < lineLength; i++) {\n                        var c = l.charAt(i);\n                        if (c == '-' || c == '.') {\n                            continue;\n                        }\n                        valueInt = valueInt * 10 + (c - '0');\n                    }\n\n                    var value = ((double) valueInt / 10.0) * sign;\n\n                    var agg = measurements.computeIfAbsent(station, k -> new MeasurementAggregator());\n\n                    agg.lock.lock();\n\n                    if (value < agg.min) {\n                        agg.min = value;\n                    }\n                    if (value > agg.max) {\n                        agg.max = value;\n                    }\n                    agg.sum += value;\n                    agg.count++;\n\n                    agg.lock.unlock();\n                });\n\n        Map<String, MeasurementAggregator> sortedEntries = new TreeMap<>(measurements);\n\n        var res = new StringBuilder();\n        res.append(\"{\");\n\n        var first = true;\n        for (var entry : sortedEntries.entrySet()) {\n            if (first) {\n                first = false;\n            }\n            else {\n                res.append(\", \");\n            }\n\n            var k = entry.getKey();\n            var v = entry.getValue();\n\n            res.append(k);\n            res.append('=');\n            res.append(v);\n        }\n\n        res.append(\"}\");\n\n        System.out.println(res);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ebarlas.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.List;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_ebarlas {\n\n    private static final Arena ARENA = Arena.global();\n\n    private static final int MAX_KEY_SIZE = 104; // 4 additional bytes to allow for single-int overflow due to padding\n    private static final int MAX_VAL_SIZE = 5; // -dd.d\n    private static final int MAX_LINE_SIZE = MAX_KEY_SIZE + MAX_VAL_SIZE + 2; // key, semicolon, val, newline\n    private static final int HASH_TBL_SIZE = 131_071; // range of allowed hash values, inclusive\n\n    private static final Unsafe UNSAFE = makeUnsafe();\n\n    private static Unsafe makeUnsafe() {\n        try {\n            var f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            return (Unsafe) f.get(null);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var path = Paths.get(\"measurements.txt\");\n        var channel = FileChannel.open(path, StandardOpenOption.READ);\n        var numPartitions = Runtime.getRuntime().availableProcessors();\n        var partitionSize = channel.size() / numPartitions;\n        var partitions = new Partition[numPartitions];\n        var threads = new Thread[numPartitions];\n        for (int i = 0; i < numPartitions; i++) {\n            var pIdx = i;\n            var pStart = pIdx * partitionSize;\n            var pEnd = pIdx == numPartitions - 1\n                    ? channel.size() // last partition might be slightly larger\n                    : pStart + partitionSize;\n            var pSize = pEnd - pStart;\n            Runnable r = () -> {\n                try {\n                    var ms = channel.map(FileChannel.MapMode.READ_ONLY, pStart, pSize, ARENA);\n                    partitions[pIdx] = processSegment(ms, pIdx == 0, pIdx == numPartitions - 1);\n                }\n                catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            };\n            threads[i] = new Thread(r);\n            threads[i].start();\n        }\n        for (var thread : threads) {\n            thread.join();\n        }\n        var partitionList = List.of(partitions);\n        foldFootersAndHeaders(partitionList);\n        printResults(foldStats(partitionList));\n    }\n\n    private static void printResults(Stats[] stats) { // adheres to Gunnar's reference code\n        var result = new TreeMap<String, String>();\n        for (var st : stats) {\n            if (st != null) {\n                var key = new String(convert(st.keyAddr, st.keyLen, st.lastBytes), StandardCharsets.UTF_8);\n                result.put(key, format(st));\n            }\n        }\n        System.out.println(result);\n    }\n\n    private static byte[] convert(long keyAddr, int keyLen, int keyLastBytes) {\n        var len = keyLastBytes == 4\n                ? keyLen * 4 // fully packed\n                : (keyLen - 1) * 4 + keyLastBytes; // last int partially packed\n        var bytes = new byte[len];\n        var idx = 0;\n        for (long i = 0; i < keyLen; i++) {\n            var offset = i << 2;\n            var n = UNSAFE.getInt(keyAddr + offset);\n            var bound = i == keyLen - 1 ? keyLastBytes : 4;\n            for (int j = 0; j < bound; j++) {\n                bytes[idx++] = (byte) (n & 0xFF);\n                n >>>= 8;\n            }\n        }\n        return bytes;\n    }\n\n    private static String format(Stats st) { // adheres to expected output format\n        return round(st.min / 10.0) + \"/\" + round((st.sum / 10.0) / st.count) + \"/\" + round(st.max / 10.0);\n    }\n\n    private static double round(double value) { // Gunnar's round function\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static Stats[] foldStats(List<Partition> partitions) { // fold stats from all partitions into first partition\n        var target = partitions.getFirst().stats;\n        for (int i = 1; i < partitions.size(); i++) {\n            var current = partitions.get(i).stats;\n            for (int j = 0; j < current.length; j++) {\n                if (current[j] != null) {\n                    var t = findInTable(target, current[j].hash, current[j].keyAddr, current[j].keyLen, current[j].lastBytes);\n                    t.min = Math.min(t.min, current[j].min);\n                    t.max = Math.max(t.max, current[j].max);\n                    t.sum += current[j].sum;\n                    t.count += current[j].count;\n                }\n            }\n        }\n        return target;\n    }\n\n    private static void foldFootersAndHeaders(List<Partition> partitions) { // fold footers and headers into prev partition\n        for (int i = 1; i < partitions.size(); i++) {\n            var pNext = partitions.get(i);\n            var pPrev = partitions.get(i - 1);\n            var merged = mergeFooterAndHeader(pPrev.footer, pNext.header);\n            if (merged != null && merged.length != 0) {\n                if (merged[merged.length - 1] == '\\n') { // fold into prev partition\n                    doProcessSegment(ARENA.allocateArray(ValueLayout.JAVA_BYTE, merged), 0, pPrev.stats, true);\n                }\n                else { // no newline appeared in partition, carry forward\n                    pNext.footer = merged;\n                }\n            }\n        }\n    }\n\n    private static byte[] mergeFooterAndHeader(byte[] footer, byte[] header) {\n        if (footer == null) {\n            return header;\n        }\n        if (header == null) {\n            return footer;\n        }\n        var merged = new byte[footer.length + header.length];\n        System.arraycopy(footer, 0, merged, 0, footer.length);\n        System.arraycopy(header, 0, merged, footer.length, header.length);\n        return merged;\n    }\n\n    private static Partition processSegment(MemorySegment ms, boolean first, boolean last) {\n        var stats = new Stats[HASH_TBL_SIZE + 1]; // vals range from [0, size] inclusive\n        var header = first ? null : readHeader(ms);\n        var keyStart = doProcessSegment(ms, header == null ? 0 : header.offset, stats, last); // last segment is complete\n        var footer = keyStart < ms.byteSize() ? readFooter(ms, keyStart) : null;\n        return new Partition(header == null ? null : header.data, footer, stats);\n    }\n\n    private static long doProcessSegment(MemorySegment ms, long offset, Stats[] stats, boolean complete) {\n        long cursor = ms.address() + offset;\n        long keyBaseAddr = UNSAFE.allocateMemory(MAX_KEY_SIZE); // reusable target for current key data\n        long lineStart = cursor; // start of key in segment used for footer calc\n        long limit = ms.address() + (complete ? ms.byteSize() : ms.byteSize() - MAX_LINE_SIZE); // stop short of longest line, sweep up at the end\n        while (cursor < limit) { // one line per iteration\n            int keyHash = 0; // key hash code\n            long keyAddr = keyBaseAddr; // address for next int\n            int keyArrLen = 0; // number of key 4-byte ints\n            int keyLastBytes; // occupancy in last byte (1, 2, 3, or 4)\n            int val;\n            while (true) {\n                int n = UNSAFE.getInt(cursor);\n                cursor += 4;\n                if ((n & 0xFF) == ';') { // ;vvv\n                    UNSAFE.putInt(keyAddr, 0); // always pad with extra int to facilitate 8-byte aligned comparisons\n                    keyLastBytes = 4;\n                    byte b0 = (byte) ((n >> 8) & 0xFF);\n                    byte b1 = (byte) ((n >> 16) & 0xFF);\n                    byte b2 = (byte) ((n >> 24) & 0xFF);\n                    if (b0 == '-') {\n                        if (b2 != '.') { // 6 bytes: -dd.dn\n                            cursor++; // decimal point\n                            byte b4 = UNSAFE.getByte(cursor);\n                            cursor += 2; // adv beyond digit and newline\n                            val = -(((b1 - '0') * 10 + (b2 - '0')) * 10 + (b4 - '0'));\n                        }\n                        else { // 5 bytes: -d.dn\n                            byte b3 = UNSAFE.getByte(cursor);\n                            cursor += 2; // digit and newline\n                            val = -((b1 - '0') * 10 + (b3 - '0'));\n                        }\n                    }\n                    else {\n                        if (b1 != '.') { // 5 bytes: dd.dn\n                            var b3 = UNSAFE.getByte(cursor);\n                            cursor += 2; // digit and newline\n                            val = ((b0 - '0') * 10 + (b1 - '0')) * 10 + (b3 - '0');\n                        }\n                        else { // 4 bytes: d.dn\n                            cursor++; // newline\n                            val = (b0 - '0') * 10 + (b2 - '0');\n                        }\n                    }\n                    break;\n                }\n                else if ((n & 0xFF00) == 0x3b00) { // k;vv\n                    int k = n & 0xFF;\n                    UNSAFE.putLong(keyAddr, k); // pad with extra int for comparison alignment\n                    keyLastBytes = 1;\n                    keyArrLen++;\n                    keyHash += k;\n                    byte b0 = (byte) ((n >> 16) & 0xFF);\n                    byte b1 = (byte) ((n >> 24) & 0xFF);\n                    byte b2 = UNSAFE.getByte(cursor++);\n                    if (b0 == '-') {\n                        if (b2 != '.') { // 6 bytes: -dd.dn\n                            cursor++; // decimal point\n                            byte b4 = UNSAFE.getByte(cursor);\n                            cursor += 2; // adv beyond digit and newline\n                            val = -(((b1 - '0') * 10 + (b2 - '0')) * 10 + (b4 - '0'));\n                        }\n                        else { // 5 bytes: -d.dn\n                            byte b3 = UNSAFE.getByte(cursor);\n                            cursor += 2; // digit newline\n                            val = -((b1 - '0') * 10 + (b3 - '0'));\n                        }\n                    }\n                    else {\n                        if (b1 != '.') { // 5 bytes: dd.dn\n                            byte b3 = UNSAFE.getByte(cursor);\n                            cursor += 2; // newline\n                            val = ((b0 - '0') * 10 + (b1 - '0')) * 10 + (b3 - '0');\n                        }\n                        else { // 4 bytes: d.dn\n                            cursor++;\n                            val = (b0 - '0') * 10 + (b2 - '0');\n                        }\n                    }\n                    break;\n                }\n                else if ((n & 0xFF0000) == 0x3b0000) { // kk;v\n                    int k = n & 0xFFFF;\n                    UNSAFE.putLong(keyAddr, k); // pad with extra int for comparison alignment\n                    keyLastBytes = 2;\n                    keyArrLen++;\n                    keyHash += k;\n                    byte b0 = (byte) ((n >> 24) & 0xFF);\n                    if (b0 == '-') {\n                        n = UNSAFE.getInt(cursor);\n                        cursor += 4;\n                        byte b1 = (byte) (n & 0xFF);\n                        byte b2 = (byte) ((n >> 8) & 0xFF);\n                        byte b3 = (byte) ((n >> 16) & 0xFF);\n                        if (b2 != '.') { // 6 bytes: -dd.dn\n                            byte b4 = (byte) ((n >> 24) & 0xFF);\n                            cursor++; // newline\n                            val = -(((b1 - '0') * 10 + (b2 - '0')) * 10 + (b4 - '0'));\n                        }\n                        else { // 5 bytes: -d.dn\n                            val = -((b1 - '0') * 10 + (b3 - '0'));\n                        }\n                    }\n                    else {\n                        byte b1 = UNSAFE.getByte(cursor++);\n                        byte b2 = UNSAFE.getByte(cursor++);\n                        byte b3 = UNSAFE.getByte(cursor++);\n                        if (b1 != '.') { // 5 bytes: dd.dn\n                            cursor++; // newline\n                            val = ((b0 - '0') * 10 + (b1 - '0')) * 10 + (b3 - '0');\n                        }\n                        else { // 4 bytes: d.dn\n                            val = (b0 - '0') * 10 + (b2 - '0');\n                        }\n                    }\n                    break;\n                }\n                else if ((n & 0xFF000000) == 0x3b000000) { // kkk;\n                    int k = n & 0xFFFFFF;\n                    UNSAFE.putLong(keyAddr, k); // pad with extra int for comparison alignment\n                    keyLastBytes = 3;\n                    keyArrLen++;\n                    keyHash += k;\n                    n = UNSAFE.getInt(cursor);\n                    cursor += 4;\n                    byte b0 = (byte) (n & 0xFF);\n                    byte b1 = (byte) ((n >> 8) & 0xFF);\n                    byte b2 = (byte) ((n >> 16) & 0xFF);\n                    byte b3 = (byte) ((n >> 24) & 0xFF);\n                    if (b0 == '-') {\n                        if (b2 != '.') { // 6 bytes: -dd.dn\n                            byte b4 = UNSAFE.getByte(cursor);\n                            cursor += 2; // adv beyond digit and newline\n                            val = -(((b1 - '0') * 10 + (b2 - '0')) * 10 + (b4 - '0'));\n                        }\n                        else { // 5 bytes: -d.dn\n                            cursor++; // newline\n                            val = -((b1 - '0') * 10 + (b3 - '0'));\n                        }\n                    }\n                    else {\n                        if (b1 != '.') { // 5 bytes: dd.dn\n                            cursor++; // newline\n                            val = ((b0 - '0') * 10 + (b1 - '0')) * 10 + (b3 - '0');\n                        }\n                        else { // 4 bytes: d.dn\n                            val = (b0 - '0') * 10 + (b2 - '0');\n                        }\n                    }\n                    break;\n                }\n                else { // kkkk\n                    UNSAFE.putInt(keyAddr, n);\n                    keyArrLen++;\n                    keyAddr += 4;\n                    keyHash += n;\n                }\n            }\n            keyHash ^= keyHash >>> 13;\n            var idx = keyHash & HASH_TBL_SIZE;\n            var st = stats[idx];\n            if (st == null) { // nothing in table, eagerly claim spot\n                st = stats[idx] = newStats(keyBaseAddr, keyArrLen, keyLastBytes, keyHash);\n            }\n            else if (!equals(st.keyAddr, st.keyLen, keyBaseAddr, keyArrLen)) {\n                st = findInTable(stats, keyHash, keyBaseAddr, keyArrLen, keyLastBytes);\n            }\n            st.min = Math.min(st.min, val);\n            st.max = Math.max(st.max, val);\n            st.sum += val;\n            st.count++;\n            lineStart = cursor; // preserve line start\n        }\n        return lineStart - ms.address();\n    }\n\n    private static boolean equals(long key1, int len1, long key2, int len2) {\n        if (len1 != len2) {\n            return false;\n        }\n        if (len1 <= 2) {\n            return UNSAFE.getLong(key1) == UNSAFE.getLong(key2);\n        }\n        if (len1 <= 4) {\n            return UNSAFE.getLong(key1) == UNSAFE.getLong(key2) && UNSAFE.getLong(key1 + 8) == UNSAFE.getLong(key2 + 8);\n        }\n        for (int i = 0; i < len1; i += 2) {\n            var offset = i << 2;\n            if (UNSAFE.getLong(key1 + offset) != UNSAFE.getLong(key2 + offset)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static Stats findInTable(Stats[] stats, int hash, long keyAddr, int keyLen, int keyLastBytes) { // open-addressing scan\n        var idx = hash & HASH_TBL_SIZE;\n        var st = stats[idx];\n        while (st != null && !equals(st.keyAddr, st.keyLen, keyAddr, keyLen)) {\n            idx = (idx + 1) % (HASH_TBL_SIZE + 1);\n            st = stats[idx];\n        }\n        if (st != null) {\n            return st;\n        }\n        return stats[idx] = newStats(keyAddr, keyLen, keyLastBytes, hash);\n    }\n\n    private static Stats newStats(long keyAddr, int keyLen, int keyLastBytes, int hash) {\n        var bytes = (keyLen + 1) << 2; // include overflow chunk\n        long k = UNSAFE.allocateMemory(bytes);\n        UNSAFE.copyMemory(keyAddr, k, bytes);\n        return new Stats(k, keyLen, keyLastBytes, hash);\n    }\n\n    private static byte[] readFooter(MemorySegment ms, long offset) { // read from line start to current pos (end-of-input)\n        var footer = new byte[(int) (ms.byteSize() - offset)];\n        for (int i = 0; i < footer.length; i++) {\n            footer[i] = ms.get(ValueLayout.JAVA_BYTE, offset + i);\n        }\n        return footer;\n    }\n\n    private static ByteArrayOffset readHeader(MemorySegment ms) { // read up to and including first newline (or end-of-input)\n        long offset = 0;\n        while (offset < ms.byteSize() && ms.get(ValueLayout.JAVA_BYTE, offset++) != '\\n')\n            ;\n        var header = new byte[(int) offset];\n        for (int i = 0; i < offset; i++) {\n            header[i] = ms.get(ValueLayout.JAVA_BYTE, i);\n        }\n        return new ByteArrayOffset(header, offset);\n    }\n\n    record ByteArrayOffset(byte[] data, long offset) {\n    }\n\n    private static class Partition {\n        byte[] header;\n        byte[] footer;\n        Stats[] stats;\n\n        Partition(byte[] header, byte[] footer, Stats[] stats) {\n            this.header = header;\n            this.footer = footer;\n            this.stats = stats;\n        }\n    }\n\n    private static class Stats { // min, max, and sum values are modeled with integral types that represent tenths of a unit\n        final long keyAddr; // address of 4-byte integer array\n        final int keyLen; // number of 4-byte integers starting at address\n        final int lastBytes; // number of bytes packed into last key int (1, 2, 3 or 4)\n        final int hash;\n        int min = Integer.MAX_VALUE;\n        int max = Integer.MIN_VALUE;\n        long sum;\n        long count;\n\n        Stats(long keyAddr, int keyLen, int lastBytes, int hash) {\n            this.keyAddr = keyAddr;\n            this.keyLen = keyLen;\n            this.lastBytes = lastBytes;\n            this.hash = hash;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_entangled90.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\n\nimport static java.lang.Math.round;\n\npublic class CalculateAverage_entangled90 {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static final boolean DEBUG = false;\n\n    public static void main(String[] args) throws IOException {\n        Scanner scanner = new Scanner();\n        long start = System.currentTimeMillis();\n        PooledChunkProcessor chunkProcessor = new PooledChunkProcessor(Runtime.getRuntime().availableProcessors());\n        scanner.scan(FILE, chunkProcessor, 0L, -1);\n        long finish = System.currentTimeMillis();\n        var map = chunkProcessor.result();\n        map.printResults();\n        if (DEBUG) {\n            System.out.println(\"Took: \" + TimeUnit.MILLISECONDS.toSeconds(finish - start) + \"seconds\");\n        }\n    }\n}\n\nclass AggregatedProcessor {\n    public double max = Double.NEGATIVE_INFINITY;\n    public double min = Double.POSITIVE_INFINITY;\n    private double sum = 0L;\n    public long count = 0L;\n\n    public void addMeasure(double value) {\n        max = Math.max(max, value);\n        min = Math.min(min, value);\n        sum += value;\n        count++;\n    }\n\n    public void combine(AggregatedProcessor processor) {\n        max = Math.max(max, processor.max);\n        min = Math.min(min, processor.min);\n        sum += processor.sum;\n        count += processor.count;\n    }\n\n    public double mean() {\n        return sum / count;\n    }\n\n    private static double round(double d) {\n        return Math.round(d * 10.0) / 10.0;\n    }\n\n    @Override\n    public String toString() {\n        return String.format(Locale.US, \"%.1f/%.1f/%.1f\", round(min), round(mean()), round(max));\n    }\n}\n\nclass ProcessorMap {\n    Map<BytesWrapper, AggregatedProcessor> processors = new HashMap<>(1024);\n\n    public void printResults() {\n        // System.out.println(\"Processed: \" + processors.entrySet().stream().mapToLong(e -> e.getValue().count).sum());\n        System.out.print(\"{\");\n        System.out.print(\n                processors.entrySet().stream()\n                        .sorted(Map.Entry.comparingByKey()).map(Object::toString).collect(Collectors.joining(\", \")));\n        System.out.println(\"}\");\n    }\n\n    public void addMeasure(BytesWrapper city, double value) {\n        var processor = processors.get(city);\n        if (processor == null) {\n            processor = new AggregatedProcessor();\n            processors.put(city, processor);\n        }\n        processor.addMeasure(value);\n    }\n\n    private void combine(BytesWrapper city, AggregatedProcessor processor) {\n        var thisProcessor = processors.get(city);\n        if (thisProcessor == null) {\n            processors.put(city, processor);\n        }\n        else {\n            thisProcessor.combine(processor);\n        }\n    }\n\n    public static ProcessorMap combineAll(ProcessorMap... processors) {\n        var result = new ProcessorMap();\n        for (var p : processors) {\n            for (var entry : p.processors.entrySet()) {\n                result.combine(entry.getKey(), entry.getValue());\n            }\n        }\n        return result;\n    }\n}\n\nclass PooledChunkProcessor implements Consumer<ByteBuffer> {\n    private final ArrayBlockingQueue<ByteBuffer> queue;\n    private final ProcessorMap[] results;\n    private final CountDownLatch latch;\n\n    private volatile boolean queueClosed = false;\n\n    public PooledChunkProcessor(int n) {\n        queue = new ArrayBlockingQueue<>(4 * 1024);\n        results = new ProcessorMap[n];\n        latch = new CountDownLatch(n);\n        for (int i = 0; i < n; i++) {\n            int finalI = i;\n            var t = new Thread(() -> {\n                var processor = new ChunkProcessor();\n                while (!Thread.interrupted()) {\n                    try {\n                        var element = queue.poll(1, TimeUnit.MILLISECONDS);\n                        if (element != null)\n                            processor.processChunk(element);\n                        else if (queueClosed) {\n                            if (CalculateAverage_entangled90.DEBUG) {\n                                System.out.println(\"Queue closed, thread #\" + finalI + \" stopping\");\n                            }\n                            break;\n                        }\n                    }\n                    catch (InterruptedException e) {\n                        break;\n                    }\n                }\n                results[finalI] = processor.processors;\n                latch.countDown();\n            });\n            t.start();\n        }\n    }\n\n    @Override\n    public void accept(ByteBuffer byteBuffer) {\n        try {\n            queue.put(byteBuffer);\n        }\n        catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public ProcessorMap result() {\n        try {\n            queueClosed = true;\n            latch.await();\n        }\n        catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        return ProcessorMap.combineAll(results);\n    }\n}\n\nclass ChunkProcessor implements Consumer<ByteBuffer> {\n    ProcessorMap processors = new ProcessorMap();\n\n    public void processChunk(ByteBuffer bb) {\n        while (processRow(bb)) {\n        }\n    }\n\n    @Override\n    public void accept(ByteBuffer byteBuffer) {\n        processChunk(byteBuffer);\n    }\n\n    // true if you can continue\n    // false if input is missing\n    public boolean processRow(ByteBuffer bb) {\n        int colonIdx = findSemiColon(bb);\n        if (colonIdx < 0) {\n            return false;\n        }\n        while (bb.get(bb.position()) == '\\n') {\n            bb.get();\n        }\n        var wrapper = wrapperFromBB(bb, colonIdx - bb.position());\n        bb.position(colonIdx + 1);\n        double value = parseDoubleNewLine(bb);\n        processors.addMeasure(wrapper, value);\n        return true;\n    }\n\n    private static BytesWrapper wrapperFromBB(ByteBuffer bb, int length) {\n        var bytes = new byte[length];\n        bb.get(bytes);\n        return new BytesWrapper(bytes);\n    }\n\n    // don't advance bb\n    private int findSemiColon(ByteBuffer bb) {\n        for (int i = bb.position(); i < bb.limit(); i++) {\n            if (bb.get(i) == (byte) ';')\n                return i;\n        }\n        return -1;\n    }\n\n    // parses double until new line and advances buffer\n    private static double parseDoubleNewLine(ByteBuffer bb) {\n        int result = 0;\n        int sign = 1;\n        byte c;\n        do {\n            c = bb.get();\n            switch (c) {\n                case '-':\n                    sign = -1;\n                    break;\n                case '.', ',', '\\r', '\\n':\n                    break;\n                default:\n                    result = result * 10 + (c - '0');\n            }\n        } while (c != '\\n' && bb.position() < bb.limit());\n        return result * sign / 10.0;\n    }\n}\n\nclass Scanner {\n    private static final int MAX_MAPPED_MEMORY = 32 * 1024 * 1024;\n\n    public void scan(String fileName, Consumer<ByteBuffer> consumer, long offset, long len) throws IOException {\n        try (var file = new RandomAccessFile(fileName, \"r\"); FileChannel channel = file.getChannel()) {\n            int chunkId = 0;\n            if (len < 0) {\n                len = file.length();\n            }\n\n            while (true) {\n                if (offset > 0) {\n                    file.seek(offset);\n                }\n                MappedByteBuffer bb = channel.map(FileChannel.MapMode.READ_ONLY, offset, Math.min(MAX_MAPPED_MEMORY, len - offset));\n                var limitIdx = findLastNewLine(bb);\n                bb.limit(limitIdx);\n                // get last newline from the end\n                consumer.accept(bb);\n                chunkId++;\n                offset += limitIdx;\n                if (CalculateAverage_entangled90.DEBUG && chunkId % 10 == 0) {\n                    System.out.println(\" read chunk \" + chunkId + \" at pointer \" + offset + \"(\" + ((int) (offset * 100 / len)) + \"%)\");\n                }\n\n                if (offset >= len - 1) {\n                    break;\n                }\n            }\n        }\n    }\n\n    public int findLastNewLine(ByteBuffer bb) {\n        for (int i = bb.limit() - 1; i > bb.position(); i--) {\n            if (bb.get(i) == '\\n') {\n                return i;\n            }\n        }\n        return -1;\n    }\n}\n\nclass BytesWrapper implements Comparable<BytesWrapper> {\n    private final byte[] bytes;\n\n    public BytesWrapper(byte[] bytes) {\n        this.bytes = bytes;\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        if (obj instanceof BytesWrapper) {\n            return Arrays.equals(bytes, ((BytesWrapper) obj).bytes);\n        }\n        else {\n            return false;\n        }\n    }\n\n    @Override\n    public int hashCode() {\n        return Arrays.hashCode(bytes);\n    }\n\n    @Override\n    public String toString() {\n        return new String(bytes);\n    }\n\n    @Override\n    public int compareTo(BytesWrapper bytesWrapper) {\n        return this.toString().compareTo(bytesWrapper.toString());\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_eriklumme.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_eriklumme {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int NUM_CPUS = Runtime.getRuntime().availableProcessors();\n    private static final int LINE_OVERHEAD = 208;\n    private static final int NUM_TASKS = NUM_CPUS * 6;\n\n    private final CountDownLatch countDownLatch = new CountDownLatch(NUM_TASKS);\n\n    private final FileInputStream fileInputStream = new FileInputStream(FILE);\n    private final FileChannel fileChannel = fileInputStream.getChannel();\n    private final long fileSize = fileChannel.size();\n    private final int fileSizePerThread = (int) Math.max(Math.ceil(fileSize / (float) NUM_TASKS), 1000);\n\n    private CalculateAverage_eriklumme() throws Exception {\n        Map<ByteArrayWrapper, StationMeasurement> map = new HashMap<>();\n\n        try (ExecutorService executorService = Executors.newFixedThreadPool(NUM_CPUS); fileInputStream; fileChannel) {\n            long sizeAccountedFor = 0;\n\n            List<Future<Map<ByteArrayWrapper, StationMeasurement>>> futures = new ArrayList<>(NUM_TASKS);\n            for (int i = 0; i < NUM_TASKS; i++) {\n                if (sizeAccountedFor >= fileSize) {\n                    // The file is so small that because of the minimum file size per thread, we've covered it in less\n                    // threads than expected\n                    countDownLatch.countDown();\n                    continue;\n                }\n                futures.add(executorService.submit(new DataProcessor(i)));\n                sizeAccountedFor += fileSizePerThread;\n            }\n            countDownLatch.await();\n\n            for (Future<Map<ByteArrayWrapper, StationMeasurement>> future : futures) {\n                Map<ByteArrayWrapper, StationMeasurement> futureMap = future.get();\n                futureMap.forEach((key, value) -> map.merge(key, value,\n                        (st1, st2) -> {\n                            st1.sum += st2.sum;\n                            st1.count += st2.count;\n                            st1.min = Math.min(st1.min, st2.min);\n                            st1.max = Math.max(st1.max, st2.max);\n                            return st1;\n                        }));\n            }\n        }\n\n        StringBuilder result = new StringBuilder(\"{\");\n        boolean first = true;\n        List<StationMeasurement> values = new ArrayList<>(map.values());\n        values.sort(Comparator.comparing(StationMeasurement::stringName));\n\n        for (StationMeasurement stationMeasurement : values) {\n            if (!first) {\n                result.append(\", \");\n            }\n            first = false;\n            result.append(new String(stationMeasurement.stationName.value, StandardCharsets.UTF_8)).append(\"=\");\n            result.append(DECIMAL_LOOKUP[stationMeasurement.min + 1000]);\n            result.append(String.format(\"/%.1f/\", (stationMeasurement.sum / (stationMeasurement.count * 10.0))));\n            result.append(DECIMAL_LOOKUP[stationMeasurement.max + 1000]);\n        }\n        result.append(\"}\");\n\n        System.out.println(result);\n    }\n\n    private static class StationMeasurement {\n        private final ByteArrayWrapper stationName;\n\n        private StationMeasurement(ByteArrayWrapper stationName) {\n            this.stationName = stationName;\n        }\n\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum = 0;\n        private int count = 0;\n\n        public String stringName() {\n            return new String(stationName.value, StandardCharsets.UTF_8);\n        }\n    }\n\n    private enum Mode {\n        UNINITIALIZED,\n        READ_STATION,\n        READ_VALUE\n    }\n\n    private record ByteArrayWrapper(byte[] value) {\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o instanceof ByteArrayWrapper that) {\n                return Arrays.equals(value, that.value);\n            }\n            return false;\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(value);\n        }\n    }\n\n    public class DataProcessor implements Callable<Map<ByteArrayWrapper, StationMeasurement>> {\n\n        private final int processorIndex;\n\n        public DataProcessor(int processorIndex) {\n            this.processorIndex = processorIndex;\n        }\n\n        @Override\n        public Map<ByteArrayWrapper, StationMeasurement> call() throws Exception {\n            Map<ByteArrayWrapper, StationMeasurement> map = new HashMap<>();\n\n            byte[] stationBuffer = new byte[200];\n            int stationIndex = 0;\n\n            byte[] valueBuffer = new byte[10];\n            int valueIndex = 0;\n\n            Mode mode = processorIndex == 0 ? Mode.READ_STATION : Mode.UNINITIALIZED;\n            byte b;\n\n            long offset = ((long) fileSizePerThread) * processorIndex;\n            long sizeWithOverhead = Math.min(((long) fileSizePerThread) + LINE_OVERHEAD, fileSize - offset);\n\n            try {\n                MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, offset, sizeWithOverhead);\n                // Read from buffer in chunks for improved performance\n                byte[] bytes = new byte[(int) (sizeWithOverhead / 6) + 1];\n\n                while (buffer.hasRemaining()) {\n                    long bytesRemaining = sizeWithOverhead - buffer.position();\n                    int bytesOffset, bytesLength;\n                    if (bytesRemaining >= bytes.length) {\n                        bytesOffset = 0;\n                        bytesLength = bytes.length;\n                    }\n                    else {\n                        bytesOffset = (int) (bytes.length - bytesRemaining);\n                        bytesLength = (int) bytesRemaining;\n                    }\n                    buffer.get(bytes, bytesOffset, bytesLength);\n\n                    for (int i = bytesOffset; i < bytes.length; i++) {\n                        b = bytes[i];\n                        if (b == '\\n') {\n                            // We have a station to store\n                            if (mode == Mode.READ_VALUE) {\n                                storeStation(map, stationBuffer, stationIndex, valueBuffer, valueIndex);\n                                stationIndex = 0;\n                                valueIndex = 0;\n                            }\n                            mode = Mode.READ_STATION;\n\n                            // We've run past our size, can happen\n                            if (buffer.position() - bytes.length + i >= fileSizePerThread) {\n                                return map;\n                            }\n                        }\n                        else if (mode == Mode.UNINITIALIZED) {\n                            // Do-nothing, read more\n                        }\n                        else if (b == ';') {\n                            mode = Mode.READ_VALUE;\n                        }\n                        else if (mode == Mode.READ_STATION) {\n                            stationBuffer[stationIndex++] = b;\n                        }\n                        else {\n                            valueBuffer[valueIndex++] = b;\n                        }\n                    }\n                }\n                if (mode == Mode.READ_VALUE && valueIndex > 0) {\n                    // One value left to store\n                    storeStation(map, stationBuffer, stationIndex, valueBuffer, valueIndex);\n                }\n            }\n            finally {\n                countDownLatch.countDown();\n            }\n            return map;\n        }\n\n        private void storeStation(Map<ByteArrayWrapper, StationMeasurement> map, byte[] stationBuffer, int stationIndex, byte[] valueBuffer, int valueIndex) {\n            ByteArrayWrapper stationName = new ByteArrayWrapper(Arrays.copyOfRange(stationBuffer, 0, stationIndex));\n\n            int value = 0;\n            for (int i = 0; i < valueIndex; i++) {\n                byte b = valueBuffer[valueIndex - i - 1];\n                if (i == 1) {\n                    // Skip the decimal point\n                }\n                else if (b == '-') {\n                    // Number is negative\n                    value = (-value);\n                }\n                else {\n                    int valueAtIndex = b - 48;\n                    if (i == 0) {\n                        value += valueAtIndex;\n                    }\n                    else {\n                        value += valueAtIndex * (i == 2 ? 10 : 100);\n                    }\n                }\n            }\n            StationMeasurement stationMeasurement = map.computeIfAbsent(stationName, StationMeasurement::new);\n            stationMeasurement.count++;\n            stationMeasurement.min = Math.min(value, stationMeasurement.min);\n            stationMeasurement.max = Math.max(value, stationMeasurement.max);\n            stationMeasurement.sum += value;\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        Locale.setDefault(Locale.US);\n        new CalculateAverage_eriklumme();\n    }\n\n    private static final String[] DECIMAL_LOOKUP = new String[]{\n            \"-100.0\", \"-99.9\", \"-99.8\", \"-99.7\", \"-99.6\", \"-99.5\", \"-99.4\", \"-99.3\", \"-99.2\", \"-99.1\", \"-99.0\", \"-98.9\", \"-98.8\", \"-98.7\", \"-98.6\", \"-98.5\", \"-98.4\",\n            \"-98.3\", \"-98.2\", \"-98.1\", \"-98.0\", \"-97.9\", \"-97.8\", \"-97.7\", \"-97.6\", \"-97.5\", \"-97.4\", \"-97.3\", \"-97.2\", \"-97.1\", \"-97.0\", \"-96.9\", \"-96.8\", \"-96.7\",\n            \"-96.6\", \"-96.5\", \"-96.4\", \"-96.3\", \"-96.2\", \"-96.1\", \"-96.0\", \"-95.9\", \"-95.8\", \"-95.7\", \"-95.6\", \"-95.5\", \"-95.4\", \"-95.3\", \"-95.2\", \"-95.1\", \"-95.0\",\n            \"-94.9\", \"-94.8\", \"-94.7\", \"-94.6\", \"-94.5\", \"-94.4\", \"-94.3\", \"-94.2\", \"-94.1\", \"-94.0\", \"-93.9\", \"-93.8\", \"-93.7\", \"-93.6\", \"-93.5\", \"-93.4\", \"-93.3\",\n            \"-93.2\", \"-93.1\", \"-93.0\", \"-92.9\", \"-92.8\", \"-92.7\", \"-92.6\", \"-92.5\", \"-92.4\", \"-92.3\", \"-92.2\", \"-92.1\", \"-92.0\", \"-91.9\", \"-91.8\", \"-91.7\", \"-91.6\",\n            \"-91.5\", \"-91.4\", \"-91.3\", \"-91.2\", \"-91.1\", \"-91.0\", \"-90.9\", \"-90.8\", \"-90.7\", \"-90.6\", \"-90.5\", \"-90.4\", \"-90.3\", \"-90.2\", \"-90.1\", \"-90.0\", \"-89.9\",\n            \"-89.8\", \"-89.7\", \"-89.6\", \"-89.5\", \"-89.4\", \"-89.3\", \"-89.2\", \"-89.1\", \"-89.0\", \"-88.9\", \"-88.8\", \"-88.7\", \"-88.6\", \"-88.5\", \"-88.4\", \"-88.3\", \"-88.2\",\n            \"-88.1\", \"-88.0\", \"-87.9\", \"-87.8\", \"-87.7\", \"-87.6\", \"-87.5\", \"-87.4\", \"-87.3\", \"-87.2\", \"-87.1\", \"-87.0\", \"-86.9\", \"-86.8\", \"-86.7\", \"-86.6\", \"-86.5\",\n            \"-86.4\", \"-86.3\", \"-86.2\", \"-86.1\", \"-86.0\", \"-85.9\", \"-85.8\", \"-85.7\", \"-85.6\", \"-85.5\", \"-85.4\", \"-85.3\", \"-85.2\", \"-85.1\", \"-85.0\", \"-84.9\", \"-84.8\",\n            \"-84.7\", \"-84.6\", \"-84.5\", \"-84.4\", \"-84.3\", \"-84.2\", \"-84.1\", \"-84.0\", \"-83.9\", \"-83.8\", \"-83.7\", \"-83.6\", \"-83.5\", \"-83.4\", \"-83.3\", \"-83.2\", \"-83.1\",\n            \"-83.0\", \"-82.9\", \"-82.8\", \"-82.7\", \"-82.6\", \"-82.5\", \"-82.4\", \"-82.3\", \"-82.2\", \"-82.1\", \"-82.0\", \"-81.9\", \"-81.8\", \"-81.7\", \"-81.6\", \"-81.5\", \"-81.4\",\n            \"-81.3\", \"-81.2\", \"-81.1\", \"-81.0\", \"-80.9\", \"-80.8\", \"-80.7\", \"-80.6\", \"-80.5\", \"-80.4\", \"-80.3\", \"-80.2\", \"-80.1\", \"-80.0\", \"-79.9\", \"-79.8\", \"-79.7\",\n            \"-79.6\", \"-79.5\", \"-79.4\", \"-79.3\", \"-79.2\", \"-79.1\", \"-79.0\", \"-78.9\", \"-78.8\", \"-78.7\", \"-78.6\", \"-78.5\", \"-78.4\", \"-78.3\", \"-78.2\", \"-78.1\", \"-78.0\",\n            \"-77.9\", \"-77.8\", \"-77.7\", \"-77.6\", \"-77.5\", \"-77.4\", \"-77.3\", \"-77.2\", \"-77.1\", \"-77.0\", \"-76.9\", \"-76.8\", \"-76.7\", \"-76.6\", \"-76.5\", \"-76.4\", \"-76.3\",\n            \"-76.2\", \"-76.1\", \"-76.0\", \"-75.9\", \"-75.8\", \"-75.7\", \"-75.6\", \"-75.5\", \"-75.4\", \"-75.3\", \"-75.2\", \"-75.1\", \"-75.0\", \"-74.9\", \"-74.8\", \"-74.7\", \"-74.6\",\n            \"-74.5\", \"-74.4\", \"-74.3\", \"-74.2\", \"-74.1\", \"-74.0\", \"-73.9\", \"-73.8\", \"-73.7\", \"-73.6\", \"-73.5\", \"-73.4\", \"-73.3\", \"-73.2\", \"-73.1\", \"-73.0\", \"-72.9\",\n            \"-72.8\", \"-72.7\", \"-72.6\", \"-72.5\", \"-72.4\", \"-72.3\", \"-72.2\", \"-72.1\", \"-72.0\", \"-71.9\", \"-71.8\", \"-71.7\", \"-71.6\", \"-71.5\", \"-71.4\", \"-71.3\", \"-71.2\",\n            \"-71.1\", \"-71.0\", \"-70.9\", \"-70.8\", \"-70.7\", \"-70.6\", \"-70.5\", \"-70.4\", \"-70.3\", \"-70.2\", \"-70.1\", \"-70.0\", \"-69.9\", \"-69.8\", \"-69.7\", \"-69.6\", \"-69.5\",\n            \"-69.4\", \"-69.3\", \"-69.2\", \"-69.1\", \"-69.0\", \"-68.9\", \"-68.8\", \"-68.7\", \"-68.6\", \"-68.5\", \"-68.4\", \"-68.3\", \"-68.2\", \"-68.1\", \"-68.0\", \"-67.9\", \"-67.8\",\n            \"-67.7\", \"-67.6\", \"-67.5\", \"-67.4\", \"-67.3\", \"-67.2\", \"-67.1\", \"-67.0\", \"-66.9\", \"-66.8\", \"-66.7\", \"-66.6\", \"-66.5\", \"-66.4\", \"-66.3\", \"-66.2\", \"-66.1\",\n            \"-66.0\", \"-65.9\", \"-65.8\", \"-65.7\", \"-65.6\", \"-65.5\", \"-65.4\", \"-65.3\", \"-65.2\", \"-65.1\", \"-65.0\", \"-64.9\", \"-64.8\", \"-64.7\", \"-64.6\", \"-64.5\", \"-64.4\",\n            \"-64.3\", \"-64.2\", \"-64.1\", \"-64.0\", \"-63.9\", \"-63.8\", \"-63.7\", \"-63.6\", \"-63.5\", \"-63.4\", \"-63.3\", \"-63.2\", \"-63.1\", \"-63.0\", \"-62.9\", \"-62.8\", \"-62.7\",\n            \"-62.6\", \"-62.5\", \"-62.4\", \"-62.3\", \"-62.2\", \"-62.1\", \"-62.0\", \"-61.9\", \"-61.8\", \"-61.7\", \"-61.6\", \"-61.5\", \"-61.4\", \"-61.3\", \"-61.2\", \"-61.1\", \"-61.0\",\n            \"-60.9\", \"-60.8\", \"-60.7\", \"-60.6\", \"-60.5\", \"-60.4\", \"-60.3\", \"-60.2\", \"-60.1\", \"-60.0\", \"-59.9\", \"-59.8\", \"-59.7\", \"-59.6\", \"-59.5\", \"-59.4\", \"-59.3\",\n            \"-59.2\", \"-59.1\", \"-59.0\", \"-58.9\", \"-58.8\", \"-58.7\", \"-58.6\", \"-58.5\", \"-58.4\", \"-58.3\", \"-58.2\", \"-58.1\", \"-58.0\", \"-57.9\", \"-57.8\", \"-57.7\", \"-57.6\",\n            \"-57.5\", \"-57.4\", \"-57.3\", \"-57.2\", \"-57.1\", \"-57.0\", \"-56.9\", \"-56.8\", \"-56.7\", \"-56.6\", \"-56.5\", \"-56.4\", \"-56.3\", \"-56.2\", \"-56.1\", \"-56.0\", \"-55.9\",\n            \"-55.8\", \"-55.7\", \"-55.6\", \"-55.5\", \"-55.4\", \"-55.3\", \"-55.2\", \"-55.1\", \"-55.0\", \"-54.9\", \"-54.8\", \"-54.7\", \"-54.6\", \"-54.5\", \"-54.4\", \"-54.3\", \"-54.2\",\n            \"-54.1\", \"-54.0\", \"-53.9\", \"-53.8\", \"-53.7\", \"-53.6\", \"-53.5\", \"-53.4\", \"-53.3\", \"-53.2\", \"-53.1\", \"-53.0\", \"-52.9\", \"-52.8\", \"-52.7\", \"-52.6\", \"-52.5\",\n            \"-52.4\", \"-52.3\", \"-52.2\", \"-52.1\", \"-52.0\", \"-51.9\", \"-51.8\", \"-51.7\", \"-51.6\", \"-51.5\", \"-51.4\", \"-51.3\", \"-51.2\", \"-51.1\", \"-51.0\", \"-50.9\", \"-50.8\",\n            \"-50.7\", \"-50.6\", \"-50.5\", \"-50.4\", \"-50.3\", \"-50.2\", \"-50.1\", \"-50.0\", \"-49.9\", \"-49.8\", \"-49.7\", \"-49.6\", \"-49.5\", \"-49.4\", \"-49.3\", \"-49.2\", \"-49.1\",\n            \"-49.0\", \"-48.9\", \"-48.8\", \"-48.7\", \"-48.6\", \"-48.5\", \"-48.4\", \"-48.3\", \"-48.2\", \"-48.1\", \"-48.0\", \"-47.9\", \"-47.8\", \"-47.7\", \"-47.6\", \"-47.5\", \"-47.4\",\n            \"-47.3\", \"-47.2\", \"-47.1\", \"-47.0\", \"-46.9\", \"-46.8\", \"-46.7\", \"-46.6\", \"-46.5\", \"-46.4\", \"-46.3\", \"-46.2\", \"-46.1\", \"-46.0\", \"-45.9\", \"-45.8\", \"-45.7\",\n            \"-45.6\", \"-45.5\", \"-45.4\", \"-45.3\", \"-45.2\", \"-45.1\", \"-45.0\", \"-44.9\", \"-44.8\", \"-44.7\", \"-44.6\", \"-44.5\", \"-44.4\", \"-44.3\", \"-44.2\", \"-44.1\", \"-44.0\",\n            \"-43.9\", \"-43.8\", \"-43.7\", \"-43.6\", \"-43.5\", \"-43.4\", \"-43.3\", \"-43.2\", \"-43.1\", \"-43.0\", \"-42.9\", \"-42.8\", \"-42.7\", \"-42.6\", \"-42.5\", \"-42.4\", \"-42.3\",\n            \"-42.2\", \"-42.1\", \"-42.0\", \"-41.9\", \"-41.8\", \"-41.7\", \"-41.6\", \"-41.5\", \"-41.4\", \"-41.3\", \"-41.2\", \"-41.1\", \"-41.0\", \"-40.9\", \"-40.8\", \"-40.7\", \"-40.6\",\n            \"-40.5\", \"-40.4\", \"-40.3\", \"-40.2\", \"-40.1\", \"-40.0\", \"-39.9\", \"-39.8\", \"-39.7\", \"-39.6\", \"-39.5\", \"-39.4\", \"-39.3\", \"-39.2\", \"-39.1\", \"-39.0\", \"-38.9\",\n            \"-38.8\", \"-38.7\", \"-38.6\", \"-38.5\", \"-38.4\", \"-38.3\", \"-38.2\", \"-38.1\", \"-38.0\", \"-37.9\", \"-37.8\", \"-37.7\", \"-37.6\", \"-37.5\", \"-37.4\", \"-37.3\", \"-37.2\",\n            \"-37.1\", \"-37.0\", \"-36.9\", \"-36.8\", \"-36.7\", \"-36.6\", \"-36.5\", \"-36.4\", \"-36.3\", \"-36.2\", \"-36.1\", \"-36.0\", \"-35.9\", \"-35.8\", \"-35.7\", \"-35.6\", \"-35.5\",\n            \"-35.4\", \"-35.3\", \"-35.2\", \"-35.1\", \"-35.0\", \"-34.9\", \"-34.8\", \"-34.7\", \"-34.6\", \"-34.5\", \"-34.4\", \"-34.3\", \"-34.2\", \"-34.1\", \"-34.0\", \"-33.9\", \"-33.8\",\n            \"-33.7\", \"-33.6\", \"-33.5\", \"-33.4\", \"-33.3\", \"-33.2\", \"-33.1\", \"-33.0\", \"-32.9\", \"-32.8\", \"-32.7\", \"-32.6\", \"-32.5\", \"-32.4\", \"-32.3\", \"-32.2\", \"-32.1\",\n            \"-32.0\", \"-31.9\", \"-31.8\", \"-31.7\", \"-31.6\", \"-31.5\", \"-31.4\", \"-31.3\", \"-31.2\", \"-31.1\", \"-31.0\", \"-30.9\", \"-30.8\", \"-30.7\", \"-30.6\", \"-30.5\", \"-30.4\",\n            \"-30.3\", \"-30.2\", \"-30.1\", \"-30.0\", \"-29.9\", \"-29.8\", \"-29.7\", \"-29.6\", \"-29.5\", \"-29.4\", \"-29.3\", \"-29.2\", \"-29.1\", \"-29.0\", \"-28.9\", \"-28.8\", \"-28.7\",\n            \"-28.6\", \"-28.5\", \"-28.4\", \"-28.3\", \"-28.2\", \"-28.1\", \"-28.0\", \"-27.9\", \"-27.8\", \"-27.7\", \"-27.6\", \"-27.5\", \"-27.4\", \"-27.3\", \"-27.2\", \"-27.1\", \"-27.0\",\n            \"-26.9\", \"-26.8\", \"-26.7\", \"-26.6\", \"-26.5\", \"-26.4\", \"-26.3\", \"-26.2\", \"-26.1\", \"-26.0\", \"-25.9\", \"-25.8\", \"-25.7\", \"-25.6\", \"-25.5\", \"-25.4\", \"-25.3\",\n            \"-25.2\", \"-25.1\", \"-25.0\", \"-24.9\", \"-24.8\", \"-24.7\", \"-24.6\", \"-24.5\", \"-24.4\", \"-24.3\", \"-24.2\", \"-24.1\", \"-24.0\", \"-23.9\", \"-23.8\", \"-23.7\", \"-23.6\",\n            \"-23.5\", \"-23.4\", \"-23.3\", \"-23.2\", \"-23.1\", \"-23.0\", \"-22.9\", \"-22.8\", \"-22.7\", \"-22.6\", \"-22.5\", \"-22.4\", \"-22.3\", \"-22.2\", \"-22.1\", \"-22.0\", \"-21.9\",\n            \"-21.8\", \"-21.7\", \"-21.6\", \"-21.5\", \"-21.4\", \"-21.3\", \"-21.2\", \"-21.1\", \"-21.0\", \"-20.9\", \"-20.8\", \"-20.7\", \"-20.6\", \"-20.5\", \"-20.4\", \"-20.3\", \"-20.2\",\n            \"-20.1\", \"-20.0\", \"-19.9\", \"-19.8\", \"-19.7\", \"-19.6\", \"-19.5\", \"-19.4\", \"-19.3\", \"-19.2\", \"-19.1\", \"-19.0\", \"-18.9\", \"-18.8\", \"-18.7\", \"-18.6\", \"-18.5\",\n            \"-18.4\", \"-18.3\", \"-18.2\", \"-18.1\", \"-18.0\", \"-17.9\", \"-17.8\", \"-17.7\", \"-17.6\", \"-17.5\", \"-17.4\", \"-17.3\", \"-17.2\", \"-17.1\", \"-17.0\", \"-16.9\", \"-16.8\",\n            \"-16.7\", \"-16.6\", \"-16.5\", \"-16.4\", \"-16.3\", \"-16.2\", \"-16.1\", \"-16.0\", \"-15.9\", \"-15.8\", \"-15.7\", \"-15.6\", \"-15.5\", \"-15.4\", \"-15.3\", \"-15.2\", \"-15.1\",\n            \"-15.0\", \"-14.9\", \"-14.8\", \"-14.7\", \"-14.6\", \"-14.5\", \"-14.4\", \"-14.3\", \"-14.2\", \"-14.1\", \"-14.0\", \"-13.9\", \"-13.8\", \"-13.7\", \"-13.6\", \"-13.5\", \"-13.4\",\n            \"-13.3\", \"-13.2\", \"-13.1\", \"-13.0\", \"-12.9\", \"-12.8\", \"-12.7\", \"-12.6\", \"-12.5\", \"-12.4\", \"-12.3\", \"-12.2\", \"-12.1\", \"-12.0\", \"-11.9\", \"-11.8\", \"-11.7\",\n            \"-11.6\", \"-11.5\", \"-11.4\", \"-11.3\", \"-11.2\", \"-11.1\", \"-11.0\", \"-10.9\", \"-10.8\", \"-10.7\", \"-10.6\", \"-10.5\", \"-10.4\", \"-10.3\", \"-10.2\", \"-10.1\", \"-10.0\",\n            \"-9.9\", \"-9.8\", \"-9.7\", \"-9.6\", \"-9.5\", \"-9.4\", \"-9.3\", \"-9.2\", \"-9.1\", \"-9.0\", \"-8.9\", \"-8.8\", \"-8.7\", \"-8.6\", \"-8.5\", \"-8.4\", \"-8.3\", \"-8.2\", \"-8.1\",\n            \"-8.0\", \"-7.9\", \"-7.8\", \"-7.7\", \"-7.6\", \"-7.5\", \"-7.4\", \"-7.3\", \"-7.2\", \"-7.1\", \"-7.0\", \"-6.9\", \"-6.8\", \"-6.7\", \"-6.6\", \"-6.5\", \"-6.4\", \"-6.3\", \"-6.2\",\n            \"-6.1\", \"-6.0\", \"-5.9\", \"-5.8\", \"-5.7\", \"-5.6\", \"-5.5\", \"-5.4\", \"-5.3\", \"-5.2\", \"-5.1\", \"-5.0\", \"-4.9\", \"-4.8\", \"-4.7\", \"-4.6\", \"-4.5\", \"-4.4\", \"-4.3\",\n            \"-4.2\", \"-4.1\", \"-4.0\", \"-3.9\", \"-3.8\", \"-3.7\", \"-3.6\", \"-3.5\", \"-3.4\", \"-3.3\", \"-3.2\", \"-3.1\", \"-3.0\", \"-2.9\", \"-2.8\", \"-2.7\", \"-2.6\", \"-2.5\", \"-2.4\",\n            \"-2.3\", \"-2.2\", \"-2.1\", \"-2.0\", \"-1.9\", \"-1.8\", \"-1.7\", \"-1.6\", \"-1.5\", \"-1.4\", \"-1.3\", \"-1.2\", \"-1.1\", \"-1.0\", \"-0.9\", \"-0.8\", \"-0.7\", \"-0.6\", \"-0.5\",\n            \"-0.4\", \"-0.3\", \"-0.2\", \"-0.1\", \"0.0\", \"0.1\", \"0.2\", \"0.3\", \"0.4\", \"0.5\", \"0.6\", \"0.7\", \"0.8\", \"0.9\", \"1.0\", \"1.1\", \"1.2\", \"1.3\", \"1.4\", \"1.5\", \"1.6\", \"1.7\",\n            \"1.8\", \"1.9\", \"2.0\", \"2.1\", \"2.2\", \"2.3\", \"2.4\", \"2.5\", \"2.6\", \"2.7\", \"2.8\", \"2.9\", \"3.0\", \"3.1\", \"3.2\", \"3.3\", \"3.4\", \"3.5\", \"3.6\", \"3.7\", \"3.8\", \"3.9\",\n            \"4.0\", \"4.1\", \"4.2\", \"4.3\", \"4.4\", \"4.5\", \"4.6\", \"4.7\", \"4.8\", \"4.9\", \"5.0\", \"5.1\", \"5.2\", \"5.3\", \"5.4\", \"5.5\", \"5.6\", \"5.7\", \"5.8\", \"5.9\", \"6.0\", \"6.1\",\n            \"6.2\", \"6.3\", \"6.4\", \"6.5\", \"6.6\", \"6.7\", \"6.8\", \"6.9\", \"7.0\", \"7.1\", \"7.2\", \"7.3\", \"7.4\", \"7.5\", \"7.6\", \"7.7\", \"7.8\", \"7.9\", \"8.0\", \"8.1\", \"8.2\", \"8.3\",\n            \"8.4\", \"8.5\", \"8.6\", \"8.7\", \"8.8\", \"8.9\", \"9.0\", \"9.1\", \"9.2\", \"9.3\", \"9.4\", \"9.5\", \"9.6\", \"9.7\", \"9.8\", \"9.9\", \"10.0\", \"10.1\", \"10.2\", \"10.3\", \"10.4\",\n            \"10.5\", \"10.6\", \"10.7\", \"10.8\", \"10.9\", \"11.0\", \"11.1\", \"11.2\", \"11.3\", \"11.4\", \"11.5\", \"11.6\", \"11.7\", \"11.8\", \"11.9\", \"12.0\", \"12.1\", \"12.2\", \"12.3\",\n            \"12.4\", \"12.5\", \"12.6\", \"12.7\", \"12.8\", \"12.9\", \"13.0\", \"13.1\", \"13.2\", \"13.3\", \"13.4\", \"13.5\", \"13.6\", \"13.7\", \"13.8\", \"13.9\", \"14.0\", \"14.1\", \"14.2\",\n            \"14.3\", \"14.4\", \"14.5\", \"14.6\", \"14.7\", \"14.8\", \"14.9\", \"15.0\", \"15.1\", \"15.2\", \"15.3\", \"15.4\", \"15.5\", \"15.6\", \"15.7\", \"15.8\", \"15.9\", \"16.0\", \"16.1\",\n            \"16.2\", \"16.3\", \"16.4\", \"16.5\", \"16.6\", \"16.7\", \"16.8\", \"16.9\", \"17.0\", \"17.1\", \"17.2\", \"17.3\", \"17.4\", \"17.5\", \"17.6\", \"17.7\", \"17.8\", \"17.9\", \"18.0\",\n            \"18.1\", \"18.2\", \"18.3\", \"18.4\", \"18.5\", \"18.6\", \"18.7\", \"18.8\", \"18.9\", \"19.0\", \"19.1\", \"19.2\", \"19.3\", \"19.4\", \"19.5\", \"19.6\", \"19.7\", \"19.8\", \"19.9\",\n            \"20.0\", \"20.1\", \"20.2\", \"20.3\", \"20.4\", \"20.5\", \"20.6\", \"20.7\", \"20.8\", \"20.9\", \"21.0\", \"21.1\", \"21.2\", \"21.3\", \"21.4\", \"21.5\", \"21.6\", \"21.7\", \"21.8\",\n            \"21.9\", \"22.0\", \"22.1\", \"22.2\", \"22.3\", \"22.4\", \"22.5\", \"22.6\", \"22.7\", \"22.8\", \"22.9\", \"23.0\", \"23.1\", \"23.2\", \"23.3\", \"23.4\", \"23.5\", \"23.6\", \"23.7\",\n            \"23.8\", \"23.9\", \"24.0\", \"24.1\", \"24.2\", \"24.3\", \"24.4\", \"24.5\", \"24.6\", \"24.7\", \"24.8\", \"24.9\", \"25.0\", \"25.1\", \"25.2\", \"25.3\", \"25.4\", \"25.5\", \"25.6\",\n            \"25.7\", \"25.8\", \"25.9\", \"26.0\", \"26.1\", \"26.2\", \"26.3\", \"26.4\", \"26.5\", \"26.6\", \"26.7\", \"26.8\", \"26.9\", \"27.0\", \"27.1\", \"27.2\", \"27.3\", \"27.4\", \"27.5\",\n            \"27.6\", \"27.7\", \"27.8\", \"27.9\", \"28.0\", \"28.1\", \"28.2\", \"28.3\", \"28.4\", \"28.5\", \"28.6\", \"28.7\", \"28.8\", \"28.9\", \"29.0\", \"29.1\", \"29.2\", \"29.3\", \"29.4\",\n            \"29.5\", \"29.6\", \"29.7\", \"29.8\", \"29.9\", \"30.0\", \"30.1\", \"30.2\", \"30.3\", \"30.4\", \"30.5\", \"30.6\", \"30.7\", \"30.8\", \"30.9\", \"31.0\", \"31.1\", \"31.2\", \"31.3\",\n            \"31.4\", \"31.5\", \"31.6\", \"31.7\", \"31.8\", \"31.9\", \"32.0\", \"32.1\", \"32.2\", \"32.3\", \"32.4\", \"32.5\", \"32.6\", \"32.7\", \"32.8\", \"32.9\", \"33.0\", \"33.1\", \"33.2\",\n            \"33.3\", \"33.4\", \"33.5\", \"33.6\", \"33.7\", \"33.8\", \"33.9\", \"34.0\", \"34.1\", \"34.2\", \"34.3\", \"34.4\", \"34.5\", \"34.6\", \"34.7\", \"34.8\", \"34.9\", \"35.0\", \"35.1\",\n            \"35.2\", \"35.3\", \"35.4\", \"35.5\", \"35.6\", \"35.7\", \"35.8\", \"35.9\", \"36.0\", \"36.1\", \"36.2\", \"36.3\", \"36.4\", \"36.5\", \"36.6\", \"36.7\", \"36.8\", \"36.9\", \"37.0\",\n            \"37.1\", \"37.2\", \"37.3\", \"37.4\", \"37.5\", \"37.6\", \"37.7\", \"37.8\", \"37.9\", \"38.0\", \"38.1\", \"38.2\", \"38.3\", \"38.4\", \"38.5\", \"38.6\", \"38.7\", \"38.8\", \"38.9\",\n            \"39.0\", \"39.1\", \"39.2\", \"39.3\", \"39.4\", \"39.5\", \"39.6\", \"39.7\", \"39.8\", \"39.9\", \"40.0\", \"40.1\", \"40.2\", \"40.3\", \"40.4\", \"40.5\", \"40.6\", \"40.7\", \"40.8\",\n            \"40.9\", \"41.0\", \"41.1\", \"41.2\", \"41.3\", \"41.4\", \"41.5\", \"41.6\", \"41.7\", \"41.8\", \"41.9\", \"42.0\", \"42.1\", \"42.2\", \"42.3\", \"42.4\", \"42.5\", \"42.6\", \"42.7\",\n            \"42.8\", \"42.9\", \"43.0\", \"43.1\", \"43.2\", \"43.3\", \"43.4\", \"43.5\", \"43.6\", \"43.7\", \"43.8\", \"43.9\", \"44.0\", \"44.1\", \"44.2\", \"44.3\", \"44.4\", \"44.5\", \"44.6\",\n            \"44.7\", \"44.8\", \"44.9\", \"45.0\", \"45.1\", \"45.2\", \"45.3\", \"45.4\", \"45.5\", \"45.6\", \"45.7\", \"45.8\", \"45.9\", \"46.0\", \"46.1\", \"46.2\", \"46.3\", \"46.4\", \"46.5\",\n            \"46.6\", \"46.7\", \"46.8\", \"46.9\", \"47.0\", \"47.1\", \"47.2\", \"47.3\", \"47.4\", \"47.5\", \"47.6\", \"47.7\", \"47.8\", \"47.9\", \"48.0\", \"48.1\", \"48.2\", \"48.3\", \"48.4\",\n            \"48.5\", \"48.6\", \"48.7\", \"48.8\", \"48.9\", \"49.0\", \"49.1\", \"49.2\", \"49.3\", \"49.4\", \"49.5\", \"49.6\", \"49.7\", \"49.8\", \"49.9\", \"50.0\", \"50.1\", \"50.2\", \"50.3\",\n            \"50.4\", \"50.5\", \"50.6\", \"50.7\", \"50.8\", \"50.9\", \"51.0\", \"51.1\", \"51.2\", \"51.3\", \"51.4\", \"51.5\", \"51.6\", \"51.7\", \"51.8\", \"51.9\", \"52.0\", \"52.1\", \"52.2\",\n            \"52.3\", \"52.4\", \"52.5\", \"52.6\", \"52.7\", \"52.8\", \"52.9\", \"53.0\", \"53.1\", \"53.2\", \"53.3\", \"53.4\", \"53.5\", \"53.6\", \"53.7\", \"53.8\", \"53.9\", \"54.0\", \"54.1\",\n            \"54.2\", \"54.3\", \"54.4\", \"54.5\", \"54.6\", \"54.7\", \"54.8\", \"54.9\", \"55.0\", \"55.1\", \"55.2\", \"55.3\", \"55.4\", \"55.5\", \"55.6\", \"55.7\", \"55.8\", \"55.9\", \"56.0\",\n            \"56.1\", \"56.2\", \"56.3\", \"56.4\", \"56.5\", \"56.6\", \"56.7\", \"56.8\", \"56.9\", \"57.0\", \"57.1\", \"57.2\", \"57.3\", \"57.4\", \"57.5\", \"57.6\", \"57.7\", \"57.8\", \"57.9\",\n            \"58.0\", \"58.1\", \"58.2\", \"58.3\", \"58.4\", \"58.5\", \"58.6\", \"58.7\", \"58.8\", \"58.9\", \"59.0\", \"59.1\", \"59.2\", \"59.3\", \"59.4\", \"59.5\", \"59.6\", \"59.7\", \"59.8\",\n            \"59.9\", \"60.0\", \"60.1\", \"60.2\", \"60.3\", \"60.4\", \"60.5\", \"60.6\", \"60.7\", \"60.8\", \"60.9\", \"61.0\", \"61.1\", \"61.2\", \"61.3\", \"61.4\", \"61.5\", \"61.6\", \"61.7\",\n            \"61.8\", \"61.9\", \"62.0\", \"62.1\", \"62.2\", \"62.3\", \"62.4\", \"62.5\", \"62.6\", \"62.7\", \"62.8\", \"62.9\", \"63.0\", \"63.1\", \"63.2\", \"63.3\", \"63.4\", \"63.5\", \"63.6\",\n            \"63.7\", \"63.8\", \"63.9\", \"64.0\", \"64.1\", \"64.2\", \"64.3\", \"64.4\", \"64.5\", \"64.6\", \"64.7\", \"64.8\", \"64.9\", \"65.0\", \"65.1\", \"65.2\", \"65.3\", \"65.4\", \"65.5\",\n            \"65.6\", \"65.7\", \"65.8\", \"65.9\", \"66.0\", \"66.1\", \"66.2\", \"66.3\", \"66.4\", \"66.5\", \"66.6\", \"66.7\", \"66.8\", \"66.9\", \"67.0\", \"67.1\", \"67.2\", \"67.3\", \"67.4\",\n            \"67.5\", \"67.6\", \"67.7\", \"67.8\", \"67.9\", \"68.0\", \"68.1\", \"68.2\", \"68.3\", \"68.4\", \"68.5\", \"68.6\", \"68.7\", \"68.8\", \"68.9\", \"69.0\", \"69.1\", \"69.2\", \"69.3\",\n            \"69.4\", \"69.5\", \"69.6\", \"69.7\", \"69.8\", \"69.9\", \"70.0\", \"70.1\", \"70.2\", \"70.3\", \"70.4\", \"70.5\", \"70.6\", \"70.7\", \"70.8\", \"70.9\", \"71.0\", \"71.1\", \"71.2\",\n            \"71.3\", \"71.4\", \"71.5\", \"71.6\", \"71.7\", \"71.8\", \"71.9\", \"72.0\", \"72.1\", \"72.2\", \"72.3\", \"72.4\", \"72.5\", \"72.6\", \"72.7\", \"72.8\", \"72.9\", \"73.0\", \"73.1\",\n            \"73.2\", \"73.3\", \"73.4\", \"73.5\", \"73.6\", \"73.7\", \"73.8\", \"73.9\", \"74.0\", \"74.1\", \"74.2\", \"74.3\", \"74.4\", \"74.5\", \"74.6\", \"74.7\", \"74.8\", \"74.9\", \"75.0\",\n            \"75.1\", \"75.2\", \"75.3\", \"75.4\", \"75.5\", \"75.6\", \"75.7\", \"75.8\", \"75.9\", \"76.0\", \"76.1\", \"76.2\", \"76.3\", \"76.4\", \"76.5\", \"76.6\", \"76.7\", \"76.8\", \"76.9\",\n            \"77.0\", \"77.1\", \"77.2\", \"77.3\", \"77.4\", \"77.5\", \"77.6\", \"77.7\", \"77.8\", \"77.9\", \"78.0\", \"78.1\", \"78.2\", \"78.3\", \"78.4\", \"78.5\", \"78.6\", \"78.7\", \"78.8\",\n            \"78.9\", \"79.0\", \"79.1\", \"79.2\", \"79.3\", \"79.4\", \"79.5\", \"79.6\", \"79.7\", \"79.8\", \"79.9\", \"80.0\", \"80.1\", \"80.2\", \"80.3\", \"80.4\", \"80.5\", \"80.6\", \"80.7\",\n            \"80.8\", \"80.9\", \"81.0\", \"81.1\", \"81.2\", \"81.3\", \"81.4\", \"81.5\", \"81.6\", \"81.7\", \"81.8\", \"81.9\", \"82.0\", \"82.1\", \"82.2\", \"82.3\", \"82.4\", \"82.5\", \"82.6\",\n            \"82.7\", \"82.8\", \"82.9\", \"83.0\", \"83.1\", \"83.2\", \"83.3\", \"83.4\", \"83.5\", \"83.6\", \"83.7\", \"83.8\", \"83.9\", \"84.0\", \"84.1\", \"84.2\", \"84.3\", \"84.4\", \"84.5\",\n            \"84.6\", \"84.7\", \"84.8\", \"84.9\", \"85.0\", \"85.1\", \"85.2\", \"85.3\", \"85.4\", \"85.5\", \"85.6\", \"85.7\", \"85.8\", \"85.9\", \"86.0\", \"86.1\", \"86.2\", \"86.3\", \"86.4\",\n            \"86.5\", \"86.6\", \"86.7\", \"86.8\", \"86.9\", \"87.0\", \"87.1\", \"87.2\", \"87.3\", \"87.4\", \"87.5\", \"87.6\", \"87.7\", \"87.8\", \"87.9\", \"88.0\", \"88.1\", \"88.2\", \"88.3\",\n            \"88.4\", \"88.5\", \"88.6\", \"88.7\", \"88.8\", \"88.9\", \"89.0\", \"89.1\", \"89.2\", \"89.3\", \"89.4\", \"89.5\", \"89.6\", \"89.7\", \"89.8\", \"89.9\", \"90.0\", \"90.1\", \"90.2\",\n            \"90.3\", \"90.4\", \"90.5\", \"90.6\", \"90.7\", \"90.8\", \"90.9\", \"91.0\", \"91.1\", \"91.2\", \"91.3\", \"91.4\", \"91.5\", \"91.6\", \"91.7\", \"91.8\", \"91.9\", \"92.0\", \"92.1\",\n            \"92.2\", \"92.3\", \"92.4\", \"92.5\", \"92.6\", \"92.7\", \"92.8\", \"92.9\", \"93.0\", \"93.1\", \"93.2\", \"93.3\", \"93.4\", \"93.5\", \"93.6\", \"93.7\", \"93.8\", \"93.9\", \"94.0\",\n            \"94.1\", \"94.2\", \"94.3\", \"94.4\", \"94.5\", \"94.6\", \"94.7\", \"94.8\", \"94.9\", \"95.0\", \"95.1\", \"95.2\", \"95.3\", \"95.4\", \"95.5\", \"95.6\", \"95.7\", \"95.8\", \"95.9\",\n            \"96.0\", \"96.1\", \"96.2\", \"96.3\", \"96.4\", \"96.5\", \"96.6\", \"96.7\", \"96.8\", \"96.9\", \"97.0\", \"97.1\", \"97.2\", \"97.3\", \"97.4\", \"97.5\", \"97.6\", \"97.7\", \"97.8\",\n            \"97.9\", \"98.0\", \"98.1\", \"98.2\", \"98.3\", \"98.4\", \"98.5\", \"98.6\", \"98.7\", \"98.8\", \"98.9\", \"99.0\", \"99.1\", \"99.2\", \"99.3\", \"99.4\", \"99.5\", \"99.6\", \"99.7\",\n            \"99.8\", \"99.9\" };\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_faridtmammadov.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_faridtmammadov {\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        int availableProcessors = Runtime.getRuntime().availableProcessors();\n\n        var map = getSegments(availableProcessors).stream()\n                .map(CalculateAverage_faridtmammadov::aggregate).parallel()\n                .flatMap(f -> f.entrySet().stream())\n                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Aggregate::update, TreeMap::new));\n\n        printFormatted(map);\n    }\n\n    private static List<MemorySegment> getSegments(int numberOfChunks) throws IOException {\n        try (var fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            var fileSize = fileChannel.size();\n            var segmentSize = fileSize / numberOfChunks;\n            var segment = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n            var baseAddress = segment.address();\n            var endAddress = baseAddress + fileSize;\n            var segments = new ArrayList<MemorySegment>();\n            var startAddress = baseAddress;\n\n            for (var i = 0; i < numberOfChunks; i++) {\n                var pointer = startAddress + segmentSize;\n                while (pointer < endAddress) {\n                    long offset = pointer - baseAddress;\n                    byte b = segment.get(ValueLayout.JAVA_BYTE, offset);\n                    if (b == '\\n') {\n                        break;\n                    }\n                    pointer++;\n                }\n                if (pointer >= endAddress) {\n                    var offsetStart = startAddress - baseAddress;\n                    var offsetEnd = endAddress - baseAddress - offsetStart;\n                    segments.add(segment.asSlice(offsetStart, offsetEnd));\n                    break;\n                }\n                var offsetStart = startAddress - baseAddress;\n                var offsetEnd = pointer - baseAddress - offsetStart;\n                segments.add(segment.asSlice(offsetStart, offsetEnd));\n                startAddress = pointer + 1;\n            }\n\n            return segments;\n        }\n    }\n\n    private static Map<String, Aggregate> aggregate(MemorySegment segment) {\n        var map = new HashMap<String, Aggregate>();\n        var iterator = new MemorySegmentIterator(segment);\n\n        while (iterator.hasNext()) {\n            String city = parseCity(iterator);\n            long temperature = parseTemperature(iterator);\n\n            map.compute(city, (key, value) -> {\n                if (value == null) {\n                    return new Aggregate(temperature);\n                }\n                else {\n                    return value.update(temperature);\n                }\n            });\n        }\n\n        return map;\n    }\n\n    private static String parseCity(MemorySegmentIterator iterator) {\n        var byteStream = new ByteArrayOutputStream();\n        while (iterator.hasNext()) {\n            var b = iterator.getNextByte();\n            if (b == ';') {\n                return byteStream.toString(StandardCharsets.UTF_8);\n            }\n            byteStream.write(b);\n        }\n\n        return null;\n    }\n\n    public static long parseTemperature(MemorySegmentIterator iterator) {\n        long value = 0L;\n        int sign = 1;\n        while (iterator.hasNext()) {\n            byte b = iterator.getNextByte();\n            if (b >= '0' && b <= '9') {\n                value = value * 10 + b - '0';\n            }\n            else if (b == '\\n') {\n                return value * sign;\n            }\n            else if (b == '-') {\n                sign = -1;\n            }\n        }\n\n        return value * sign;\n    }\n\n    private static void printFormatted(Map<String, Aggregate> map) {\n        var iterator = map.entrySet().iterator();\n        var length = map.entrySet().size();\n        System.out.print(\"{\");\n        for (int i = 0; i < length - 1; i++) {\n            var entry = iterator.next();\n            System.out.printf(\"%s=%s, \", entry.getKey(), entry.getValue().toString());\n        }\n        var lastEntry = iterator.next();\n        System.out.printf(\"%s=%s}\\n\", lastEntry.getKey(), lastEntry.getValue().toString());\n    }\n\n    static class Aggregate {\n        long min;\n        long max;\n        long sum;\n        int count;\n\n        public Aggregate(long temperature) {\n            min = temperature;\n            max = temperature;\n            sum = temperature;\n            count = 1;\n        }\n\n        public Aggregate update(long temp) {\n            min = Math.min(min, temp);\n            max = Math.max(max, temp);\n            sum += temp;\n            count++;\n            return this;\n        }\n\n        public Aggregate update(Aggregate agg) {\n            min = Math.min(min, agg.min);\n            max = Math.max(max, agg.max);\n            sum += agg.sum;\n            count += agg.count;\n            return this;\n        }\n\n        public String toString() {\n            return String.format(\"%s/%s/%s\", min / 10.0f, Math.round(sum * 1.0f / count) / 10.0f, max / 10.0f);\n        }\n    }\n\n    static class MemorySegmentIterator {\n        private long offset;\n        private final MemorySegment segment;\n        private final long segmentSize;\n\n        public MemorySegmentIterator(MemorySegment segment) {\n            this.segment = segment;\n            this.segmentSize = segment.byteSize();\n        }\n\n        public boolean hasNext() {\n            return offset < segmentSize;\n        }\n\n        public byte getNextByte() {\n            var b = segment.get(ValueLayout.JAVA_BYTE, offset);\n            offset++;\n            return b;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_fatroom.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\n\npublic class CalculateAverage_fatroom {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class MeasurementAggregator {\n        private double min;\n        private double max;\n        private double sum;\n        private long count;\n\n        public MeasurementAggregator() {\n            this.min = 1000;\n            this.max = -1000;\n            this.sum = 0;\n            this.count = 0;\n        }\n\n        public void consume(double value) {\n            this.min = value > this.min ? this.min : value;\n            this.max = this.max > value ? this.max : value;\n            this.sum += value;\n            this.count++;\n        }\n\n        public MeasurementAggregator combineWith(MeasurementAggregator that) {\n            this.min = that.min > this.min ? this.min : that.min;\n            this.max = this.max > that.max ? this.max : that.max;\n            this.sum += that.sum;\n            this.count += that.count;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            StringBuilder sb = new StringBuilder();\n            sb.append(min / 10.0).append(\"/\").append(Math.round(sum / count) / 10.0).append(\"/\").append(max / 10.0);\n            return sb.toString();\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        int SEGMENT_LENGTH = 256_000_000; // 256 MB\n\n        RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n        long fileSize = file.length();\n        long position = 0;\n\n        List<Callable<StationMap>> tasks = new LinkedList<>();\n        while (position < fileSize) {\n            long end = Math.min(position + SEGMENT_LENGTH, fileSize);\n            int length = (int) (end - position);\n            MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, position, length);\n            while (buffer.get(length - 1) != '\\n') {\n                length--;\n            }\n            final int finalLength = length;\n            tasks.add(() -> processBuffer(buffer, finalLength));\n            position += length;\n        }\n\n        var executor = Executors.newFixedThreadPool(tasks.size());\n\n        Map<String, MeasurementAggregator> aggregates = new TreeMap<>();\n        for (var future : executor.invokeAll(tasks)) {\n            var segmentAggregates = future.get();\n            for (var entry : segmentAggregates.entrySet()) {\n                aggregates.merge(entry.getKey(), entry.value, MeasurementAggregator::combineWith);\n            }\n        }\n        executor.shutdown();\n\n        // no sense to wait longer than base case\n        executor.awaitTermination(5, TimeUnit.MINUTES);\n\n        System.out.println(aggregates);\n    }\n\n    private static StationMap processBuffer(MappedByteBuffer source, int length) {\n        StationMap aggregates = new StationMap();\n        byte[] buffer = new byte[200];\n        byte[] measurement = new byte[5];\n        int measurementLength;\n        int idx = 0;\n        int hash = 1;\n        for (int i = 0; i < length; ++i) {\n            byte b = source.get(i);\n            hash = 31 * hash + b;\n            buffer[idx++] = b;\n            if (b == ';') {\n                measurementLength = 3;\n                measurement[0] = source.get(++i);\n                measurement[1] = source.get(++i);\n                measurement[2] = source.get(++i);\n                measurement[3] = source.get(++i);\n                if (measurement[3] != '\\n') {\n                    measurementLength++;\n                    measurement[4] = source.get(++i);\n                    if (measurement[4] != '\\n') {\n                        i++;\n                        measurementLength++;\n                    }\n                }\n                aggregates.get(hash, buffer, idx - 1).consume(parseMeasurement(measurement, measurementLength));\n                idx = 0;\n                hash = 1;\n            }\n        }\n        return aggregates;\n    }\n\n    static double parseMeasurement(byte[] source, int size) {\n        int isNegativeSignPresent = ~(source[0] >> 4) & 1;\n        int firstDigit = source[isNegativeSignPresent] - '0';\n        int secondDigit = source[size - 3];\n        int thirdDigit = source[size - 1];\n        int has4 = (size - isNegativeSignPresent) >> 2;\n        int value = has4 * firstDigit * 100 + secondDigit * 10 + thirdDigit - 528;\n        return -isNegativeSignPresent ^ value - isNegativeSignPresent;\n    }\n\n    static class Station {\n        private byte[] bytes;\n        private int hash;\n        private MeasurementAggregator value;\n        private Station next;\n\n        public Station(int hash, byte[] bytes, int length, Station next) {\n            this.hash = hash;\n            this.bytes = new byte[length];\n            System.arraycopy(bytes, 0, this.bytes, 0, length);\n            this.value = new MeasurementAggregator();\n            this.next = next;\n        }\n\n        public String getKey() {\n            return new String(bytes, 0, bytes.length, StandardCharsets.UTF_8);\n        }\n    }\n\n    static class StationMap {\n        private Station[] stations = new Station[16384];\n\n        MeasurementAggregator get(int hash, byte[] buffer, int length) {\n            int bucketId = hash & 0x3fff;\n            Station entry = stations[bucketId];\n            while (entry != null) {\n                if (entry.hash == hash && Arrays.equals(entry.bytes, 0, entry.bytes.length, buffer, 0, length)) {\n                    return entry.value;\n                }\n                entry = entry.next;\n            }\n            stations[bucketId] = new Station(hash, buffer, length, stations[bucketId]);\n            return stations[bucketId].value;\n        }\n\n        private List<Station> entrySet() {\n            List<Station> result = new LinkedList<>();\n            for (var station : stations) {\n                while (station != null) {\n                    result.add(station);\n                    station = station.next;\n                }\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_felix19350.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executors;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_felix19350 {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int NEW_LINE_SEEK_BUFFER_LEN = 128;\n\n    private static final int EXPECTED_MAX_NUM_CITIES = 15_000; // 10K cities + a buffer no to trigger the load factor\n\n    private static class CityRef {\n\n        final int length;\n        final int fingerprint;\n        final byte[] stringBytes;\n\n        public CityRef(ByteBuffer byteBuffer, int startIdx, int length, int fingerprint) {\n            this.length = length;\n            this.stringBytes = new byte[length];\n            byteBuffer.get(startIdx, this.stringBytes, 0, this.stringBytes.length);\n            this.fingerprint = fingerprint;\n        }\n\n        public String cityName() {\n            return new String(stringBytes, StandardCharsets.UTF_8);\n        }\n\n        @Override\n        public int hashCode() {\n            return fingerprint;\n        }\n\n        @Override\n        public boolean equals(Object other) {\n            if (other instanceof CityRef otherRef) {\n                if (fingerprint != otherRef.fingerprint) {\n                    return false;\n                }\n\n                if (this.length != otherRef.length) {\n                    return false;\n                }\n\n                for (var i = 0; i < this.length; i++) {\n                    if (this.stringBytes[i] != otherRef.stringBytes[i]) {\n                        return false;\n                    }\n                }\n                return true;\n            }\n            else {\n                return false;\n            }\n        }\n\n    }\n\n    private static class ResultRow {\n\n        private int min;\n        private int max;\n        private int sum;\n        private int count;\n\n        public ResultRow(int initialValue) {\n            this.min = initialValue;\n            this.max = initialValue;\n            this.sum = initialValue;\n            this.count = 1;\n        }\n\n        public void mergeValue(int value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum += value;\n            this.count += 1;\n        }\n\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round(sum / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public void mergeResult(ResultRow value) {\n            min = Math.min(min, value.min);\n            max = Math.max(max, value.max);\n            sum += value.sum;\n            count += value.count;\n        }\n    }\n\n  private record AverageAggregatorTask(ByteBuffer byteBuffer) {\n    private static final int HASH_FACTOR = 31; // Mersenne prime\n\n\n    public static Stream<AverageAggregatorTask> createStreamOf(List<ByteBuffer> byteBuffers) {\n      return byteBuffers.stream().map(AverageAggregatorTask::new);\n    }\n\n    public Map<CityRef, ResultRow> processChunk() {\n      final var measurements = new HashMap<CityRef, ResultRow>(EXPECTED_MAX_NUM_CITIES);\n      var lineStart = 0;\n      // process line by line playing with the fact that a line is no longer than 106 bytes\n      // 100 bytes for city name + 1 byte for separator + 1 bytes for negative sign + 4 bytes for number\n      while (lineStart < byteBuffer.limit()) {\n        lineStart = this.processLine(measurements, byteBuffer, lineStart);\n      }\n      return measurements;\n    }\n\n    private int processLine(Map<CityRef, ResultRow> measurements, ByteBuffer byteBuffer, int start) {\n      var fingerPrint = 0;\n      var separatorIdx = -1;\n      var sign = 1;\n      var value = 0;\n      var lineEnd = -1;\n      // Lines are processed in two stages:\n      // 1 - prior do the city name separator\n      // 2 - after the separator\n      // this ensures less if clauses\n\n      // stage 1 loop\n      {\n        for (int i = 0; i < NEW_LINE_SEEK_BUFFER_LEN; i++) {\n          final var currentByte = byteBuffer.get(start + i);\n          if (currentByte == ';') {\n            separatorIdx = i;\n            break;\n          } else {\n            fingerPrint = HASH_FACTOR * fingerPrint + currentByte;\n          }\n        }\n      }\n\n      // stage 2 loop:\n      {\n        for (int i = separatorIdx + 1; i < NEW_LINE_SEEK_BUFFER_LEN; i++) {\n          final var currentByte = byteBuffer.get(start + i);\n          switch (currentByte) {\n            case '-':\n              sign = -1;\n              break;\n            case '.':\n              break;\n            case '\\n':\n              lineEnd = start + i + 1;\n              break;\n            default:\n              // only digits are expected here\n              value = value * 10 + (currentByte - '0');\n          }\n\n          if (lineEnd != -1) {\n            break;\n          }\n        }\n      }\n\n      assert (separatorIdx > 0);\n      final var cityRef = new CityRef(byteBuffer, start, separatorIdx,fingerPrint);\n      value = sign * value;\n\n      final var existingMeasurement = measurements.get(cityRef);\n      if (existingMeasurement == null) {\n        measurements.put(cityRef, new ResultRow(value));\n      } else {\n        existingMeasurement.mergeValue(value);\n      }\n\n      return lineEnd; //to account for the line end\n    }\n  }\n\n    public static void main(String[] args) throws IOException {\n        // memory map the files and divide by number of cores\n        final var numProcessors = Runtime.getRuntime().availableProcessors();\n        final var byteBuffers = calculateMemorySegments(numProcessors);\n        final var tasks = AverageAggregatorTask.createStreamOf(byteBuffers);\n        assert (byteBuffers.size() <= numProcessors);\n        assert (!byteBuffers.isEmpty());\n\n        try (var pool = Executors.newFixedThreadPool(numProcessors)) {\n            final Map<CityRef, ResultRow> aggregatedCities = tasks\n                    .parallel()\n                    .map(task -> CompletableFuture.supplyAsync(task::processChunk, pool))\n                    .map(CompletableFuture::join)\n                    .reduce(new HashMap<>(EXPECTED_MAX_NUM_CITIES), (currentMap, accumulator) -> {\n                        currentMap.forEach((key, value) -> {\n                            final var prev = accumulator.get(key);\n                            if (prev == null) {\n                                accumulator.put(key, value);\n                            }\n                            else {\n                                prev.mergeResult(value);\n                            }\n                        });\n                        return accumulator;\n                    });\n\n            var results = new HashMap<String, ResultRow>(EXPECTED_MAX_NUM_CITIES);\n            aggregatedCities.forEach((key, value) -> results.put(key.cityName(), value));\n\n            System.out.print(\"{\");\n            String output = results.keySet()\n                    .stream()\n                    .sorted()\n                    .map(key -> key + \"=\" + results.get(key).toString())\n                    .collect(Collectors.joining(\", \"));\n            System.out.print(output);\n            System.out.println(\"}\");\n        }\n    }\n\n    private static List<ByteBuffer> calculateMemorySegments(int numChunks) throws IOException {\n        try (FileChannel fc = FileChannel.open(Paths.get(FILE))) {\n            var memMappedFile = fc.map(FileChannel.MapMode.READ_ONLY, 0L, fc.size(), Arena.ofAuto());\n            var result = new ArrayList<ByteBuffer>(numChunks);\n\n            var fileSize = fc.size();\n            var chunkSize = fileSize / numChunks; // TODO: if chunksize > MAX INT we will need to adjust\n            var previousChunkEnd = 0L;\n\n            for (int i = 0; i < numChunks; i++) {\n                if (previousChunkEnd >= fileSize) {\n                    // There is a scenario for very small files where the number of chunks may be greater than\n                    // the number of lines.\n                    break;\n                }\n                var chunk = new long[]{ previousChunkEnd, 0 };\n                if (i == (numChunks - 1)) {\n                    // ensure the last chunk covers the full file\n                    chunk[1] = fileSize;\n                }\n                else {\n                    // all other chunks are end at a new line (\\n)\n                    var theoreticalEnd = Math.min(previousChunkEnd + chunkSize, fileSize);\n                    var newLineOffset = 0;\n                    for (int j = 0; j < NEW_LINE_SEEK_BUFFER_LEN; j++) {\n                        var candidateOffset = theoreticalEnd + j;\n                        if (candidateOffset >= fileSize) {\n                            break;\n                        }\n                        byte b = memMappedFile.get(ValueLayout.OfByte.JAVA_BYTE, candidateOffset);\n                        newLineOffset += 1;\n                        if ((char) b == '\\n') {\n                            break;\n                        }\n                    }\n                    chunk[1] = Math.min(fileSize, theoreticalEnd + newLineOffset);\n                    previousChunkEnd = chunk[1];\n                }\n\n                assert (chunk[1] > chunk[0]);\n                assert (chunk[1] <= fileSize);\n\n                result.add(memMappedFile.asSlice(chunk[0], (chunk[1] - chunk[0])).asByteBuffer());\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_filiphr.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.TreeMap;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\n/**\n * Initial submission:                                 1m 35s\n * Adding memory mapped files:                         0m 55s (based on bjhara's submission)\n * Using big decimal and iterating the buffer once:    0m 20s\n * Using long parse:                                   0m 11s\n * Using array hash code for city key:                 0m 7.1s (this is invalid since it can lead to hash collisions)\n * Manually compute the value:                         0m 6.8s\n * Revert array hash code for city key:                0m 10s\n * Use array hash and Arrays#equals for city key:      0m 7.2s\n * <p>\n * Using 21.0.1 Temurin with ShenandoahGC on Macbook (Intel) Pro\n * `sdk use java 21.0.1-tem`\n *\n * When using Oracle GraalVM 21.0.1+12.1\n * `sdk use java 21.0.1-graal`\n * It takes 0m 15s on my machine\n * `sdk use java 21.0.1-graalce`\n * It takes 0m 20s on my machine\n *\n * @author Filip Hrisafov\n */\npublic class CalculateAverage_filiphr {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final long CHUNK_SIZE = 1024 * 1024 * 10L; // 1KB * 10KB ~ 10MB\n\n    private static final class Measurement {\n\n        private long min = Long.MAX_VALUE;\n        private long max = Long.MIN_VALUE;\n        private long sum = 0L;\n        private long count = 0L;\n\n        private void add(long value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum += value;\n            this.count++;\n        }\n\n        public static Measurement combine(Measurement m1, Measurement m2) {\n            Measurement measurement = new Measurement();\n            measurement.min = Math.min(m1.min, m2.min);\n            measurement.max = Math.max(m1.max, m2.max);\n            measurement.sum = m1.sum + m2.sum;\n            measurement.count = m1.count + m2.count;\n            return measurement;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round((sum / 10.0) / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        // long start = System.nanoTime();\n\n        Map<Key, Measurement> measurements;\n        try (FileChannel fileChannel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            measurements = fineChannelStream(fileChannel)\n                    .parallel()\n                    .map(CalculateAverage_filiphr::parseBuffer)\n                    .reduce(Collections.emptyMap(), CalculateAverage_filiphr::mergeMaps);\n        }\n\n        Map<String, Measurement> finalMeasurements = new TreeMap<>();\n        for (Map.Entry<Key, Measurement> entry : measurements.entrySet()) {\n            StoredKey key = (StoredKey) entry.getKey();\n            Measurement measurement = entry.getValue();\n            finalMeasurements.put(new String(key.keyBytes), measurement);\n        }\n\n        System.out.println(finalMeasurements);\n        // System.out.println(\"Done in \" + (System.nanoTime() - start) / 1000000 + \" ms\");\n    }\n\n    private static Map<Key, Measurement> mergeMaps(Map<Key, Measurement> map1, Map<Key, Measurement> map2) {\n        if (map1.isEmpty()) {\n            return map2;\n        }\n        else {\n            Set<Key> cities = new HashSet<>(map1.keySet());\n            cities.addAll(map2.keySet());\n            Map<Key, Measurement> result = HashMap.newHashMap(cities.size());\n\n            for (Key city : cities) {\n                Measurement m1 = map1.get(city);\n                Measurement m2 = map2.get(city);\n                if (m2 == null) {\n                    // When m2 is null then it is not possible for m1 to be null as well,\n                    // since cities is a union of the map key sets\n                    result.put(city, m1);\n                }\n                else if (m1 == null) {\n                    // When m1 is null then it is not possible for m2 to be null as well,\n                    // since cities is a union of the map key sets\n                    result.put(city, m2);\n                }\n                else {\n                    result.put(city, Measurement.combine(m1, m2));\n                }\n            }\n\n            return result;\n        }\n    }\n\n    /**\n     * This is an adapted implementation of the bjhara parseBuffer.\n     * We are using {@code Map<Integer, Measurement>} because creating the string key on every single line is obsolete.\n     * Instead, we create a hash key from the string, and we use that as a key in the map.\n     */\n    private static Map<Key, Measurement> parseBuffer(ByteBuffer bb) {\n        Map<Key, Measurement> measurements = HashMap.newHashMap(415);\n        int limit = bb.limit();\n        byte[] cityBuffer = new byte[128];\n\n        while (bb.position() < limit) {\n            int cityBufferIndex = 0;\n\n            // Iterate through the byte buffer and fill the buffer until we find the separator (;)\n            // While iterating we are also going to compute the city hash key\n            int cityHash = 1;\n            while (bb.position() < limit) {\n                byte positionByte = bb.get();\n                if (positionByte == ';') {\n                    break;\n                }\n                cityBuffer[cityBufferIndex++] = positionByte;\n                cityHash = 31 * cityHash + positionByte;\n            }\n\n            SearchKey searchKey = new SearchKey(cityBuffer, cityHash, cityBufferIndex);\n\n            byte lastPositionByte = '\\n';\n            boolean negative = false;\n            long value = 0;\n            while (bb.position() < limit) {\n                byte positionByte = bb.get();\n                if (positionByte == '\\r' || positionByte == '\\n') {\n                    lastPositionByte = positionByte;\n                    break;\n                }\n                else if (positionByte == '-') {\n                    negative = true;\n                }\n                else if (positionByte != '.') {\n                    // The 0 to 9 characters have an int value of 48 (for 0) to 57 (for 9)\n                    // Therefore, in order to compute the digit we subtract with 48\n                    int digit = positionByte - 48;\n                    // We are computing the value by hand (in order to avoid iterating the index twice)\n                    value = value * 10 + digit;\n                }\n            }\n\n            if (negative) {\n                value = -value;\n            }\n\n            Measurement measurement = measurements.get(searchKey);\n            if (measurement == null) {\n                byte[] keyBytes = new byte[cityBufferIndex];\n                System.arraycopy(cityBuffer, 0, keyBytes, 0, cityBufferIndex);\n                StoredKey storedKey = new StoredKey(keyBytes, cityHash);\n                measurement = new Measurement();\n                measurements.put(storedKey, measurement);\n            }\n            measurement.add(value);\n\n            // and get rid of the new line (handle both kinds)\n            if (lastPositionByte == '\\r') {\n                bb.get();\n            }\n        }\n\n        return measurements;\n    }\n\n    /**\n     * Thanks to bjhara and royvanrijn for the idea of using (and learning about) memory mapped files.\n     */\n    private static Stream<ByteBuffer> fineChannelStream(FileChannel fileChannel) throws IOException {\n        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(fileChannelIterator(fileChannel), Spliterator.IMMUTABLE), false);\n    }\n\n    private static Iterator<ByteBuffer> fileChannelIterator(FileChannel fileChannel) throws IOException {\n        return new Iterator<>() {\n\n            private final long size = fileChannel.size();\n            private long start = 0;\n\n            @Override\n            public boolean hasNext() {\n                return start < size;\n            }\n\n            @Override\n            public ByteBuffer next() {\n                try {\n                    MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, start,\n                            Math.min(CHUNK_SIZE, size - start));\n\n                    // don't split the data in the middle of lines\n                    // find the closest previous newline\n                    int realEnd = mappedByteBuffer.limit() - 1;\n                    while (mappedByteBuffer.get(realEnd) != '\\n')\n                        realEnd--;\n\n                    realEnd++;\n\n                    mappedByteBuffer.limit(realEnd);\n                    start += realEnd;\n\n                    return mappedByteBuffer;\n                }\n                catch (IOException ex) {\n                    throw new UncheckedIOException(ex);\n                }\n            }\n        };\n    }\n\n    /**\n     * This is a class that is used to reference a city key using its bytes only.\n     * It has the hash precomputed, and it is equal to a {@link SearchKey} when the key bytes are equal to the {@link SearchKey#buffer} up to the {@link SearchKey#limit}.\n     */\n    private static final class StoredKey implements Key {\n\n        private final byte[] keyBytes;\n        private final int hash;\n\n        private StoredKey(byte[] keyBytes, int hash) {\n            this.keyBytes = keyBytes;\n            this.hash = hash;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) {\n                return true;\n            }\n            if (o == null) {\n                return false;\n            }\n            if (o instanceof SearchKey key) {\n                return Arrays.equals(keyBytes, 0, keyBytes.length, key.buffer, 0, key.limit);\n            }\n            else if (o instanceof StoredKey key) {\n                return Arrays.equals(keyBytes, key.keyBytes);\n            }\n            return false;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n    }\n\n    /**\n     * A class that is used to lookup for a value in a map.\n     * This key is equal to {@link StoredKey} when the buffer has the same contents as the {@link StoredKey#keyBytes}.\n     */\n    private static final class SearchKey implements Key {\n\n        private final byte[] buffer;\n        private final int hash;\n        private final int limit;\n\n        private SearchKey(byte[] buffer, int hash, int limit) {\n            this.buffer = buffer;\n            this.hash = hash;\n            this.limit = limit;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) {\n                return true;\n            }\n            if (o == null) {\n                return false;\n            }\n\n            if (o instanceof StoredKey key) {\n                return Arrays.equals(buffer, 0, limit, key.keyBytes, 0, limit);\n            }\n            else if (o instanceof SearchKey key) {\n                return Arrays.equals(buffer, 0, limit, key.buffer, 0, key.limit);\n            }\n            return false;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n    }\n\n    private interface Key {\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_flippingbits.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ShortVector;\nimport jdk.incubator.vector.VectorOperators;\n\nimport sun.misc.Unsafe;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\n\n/**\n * Approach:\n * - Use memory-mapped file to speed up loading data into memory\n * - Partition data, compute aggregates for partitions in parallel, and finally combine results from all partitions\n * - Apply SIMD instructions for computing min/max/sum aggregates\n * - Use Shorts for storing aggregates of partitions, so we maximize the SIMD parallelism\n */\npublic class CalculateAverage_flippingbits {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final long MINIMUM_FILE_SIZE_PARTITIONING = 10 * 1024 * 1024; // 10 MB\n\n    private static final int SIMD_LANE_LENGTH = ShortVector.SPECIES_MAX.length();\n\n    private static final int NUM_STATIONS = 10_000;\n\n    private static final int HASH_MAP_OFFSET_CAPACITY = 200_000;\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static int HASH_PRIME_NUMBER = 31;\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        var result = Arrays.asList(getSegments()).parallelStream()\n                .map(segment -> {\n                    try {\n                        return processSegment(segment[0], segment[1]);\n                    }\n                    catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                })\n                .reduce(FasterHashMap::mergeWith)\n                .get();\n\n        var sortedMap = new TreeMap<String, Station>();\n        for (Station station : result.getEntries()) {\n            sortedMap.put(station.getName(), station);\n        }\n\n        System.out.println(sortedMap);\n    }\n\n    private static long[][] getSegments() throws IOException {\n        try (var file = new RandomAccessFile(FILE, \"r\")) {\n            var channel = file.getChannel();\n\n            var fileSize = channel.size();\n            var startAddress = channel\n                    .map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global())\n                    .address();\n\n            // Split file into segments, so we can work around the size limitation of channels\n            var numSegments = (fileSize > MINIMUM_FILE_SIZE_PARTITIONING)\n                    ? Runtime.getRuntime().availableProcessors()\n                    : 1;\n            var segmentSize = fileSize / numSegments;\n\n            var boundaries = new long[numSegments][2];\n            var endPointer = startAddress;\n\n            for (var i = 0; i < numSegments - 1; i++) {\n                // Start of segment\n                boundaries[i][0] = endPointer;\n\n                // Extend segment until end of line or file\n                endPointer = endPointer + segmentSize;\n                while (UNSAFE.getByte(endPointer) != '\\n') {\n                    endPointer++;\n                }\n\n                // End of segment\n                boundaries[i][1] = endPointer++;\n            }\n\n            boundaries[numSegments - 1][0] = endPointer;\n            boundaries[numSegments - 1][1] = startAddress + fileSize;\n\n            return boundaries;\n        }\n    }\n\n    private static FasterHashMap processSegment(long startOfSegment, long endOfSegment) throws IOException {\n        var fasterHashMap = new FasterHashMap();\n        for (var i = startOfSegment; i < endOfSegment; i += 3) {\n            // Read station name\n            int nameHash = UNSAFE.getByte(i);\n            final var nameStartAddress = i++;\n            var character = UNSAFE.getByte(i);\n            while (character != ';') {\n                nameHash = nameHash * HASH_PRIME_NUMBER + character;\n                i++;\n                character = UNSAFE.getByte(i);\n            }\n            var nameLength = (int) (i - nameStartAddress);\n            i++;\n\n            // Read measurement\n            var isNegative = UNSAFE.getByte(i) == '-';\n            var measurement = 0;\n            if (isNegative) {\n                i++;\n                character = UNSAFE.getByte(i);\n                while (character != '.') {\n                    measurement = measurement * 10 + character - '0';\n                    i++;\n                    character = UNSAFE.getByte(i);\n                }\n                measurement = (measurement * 10 + UNSAFE.getByte(i + 1) - '0') * -1;\n            }\n            else {\n                character = UNSAFE.getByte(i);\n                while (character != '.') {\n                    measurement = measurement * 10 + character - '0';\n                    i++;\n                    character = UNSAFE.getByte(i);\n                }\n                measurement = measurement * 10 + UNSAFE.getByte(i + 1) - '0';\n            }\n\n            fasterHashMap.addEntry(nameHash, nameLength, nameStartAddress, (short) measurement);\n        }\n\n        for (Station station : fasterHashMap.getEntries()) {\n            station.aggregateRemainingMeasurements();\n        }\n\n        return fasterHashMap;\n    }\n\n    private static class Station {\n        final short[] measurements = new short[SIMD_LANE_LENGTH * 2];\n        // Assume that we do not have more than Integer.MAX_VALUE measurements for the same station per partition\n        int count = 1;\n        long sum = 0;\n        short min = Short.MAX_VALUE;\n        short max = Short.MIN_VALUE;\n        final long nameAddress;\n        final int nameLength;\n        final int nameHash;\n\n        public Station(int nameHash, int nameLength, long nameAddress, short measurement) {\n            this.nameHash = nameHash;\n            this.nameLength = nameLength;\n            this.nameAddress = nameAddress;\n            measurements[0] = measurement;\n        }\n\n        public String getName() {\n            byte[] name = new byte[nameLength];\n            UNSAFE.copyMemory(null, nameAddress, name, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameLength);\n            return new String(name, StandardCharsets.UTF_8);\n        }\n\n        public void addMeasurementAndComputeAggregate(short measurement) {\n            // Add measurement to buffer, which is later processed by SIMD instructions\n            measurements[count % measurements.length] = measurement;\n            count++;\n\n            // Once lane is full, use SIMD instructions to calculate aggregates\n            if (count % measurements.length == 0) {\n                var firstVector = ShortVector.fromArray(ShortVector.SPECIES_MAX, measurements, 0);\n                var secondVector = ShortVector.fromArray(ShortVector.SPECIES_MAX, measurements, SIMD_LANE_LENGTH);\n\n                var simdMin = firstVector.min(secondVector).reduceLanes(VectorOperators.MIN);\n                min = (short) Math.min(min, simdMin);\n\n                var simdMax = firstVector.max(secondVector).reduceLanes(VectorOperators.MAX);\n                max = (short) Math.max(max, simdMax);\n\n                sum += firstVector.add(secondVector).reduceLanes(VectorOperators.ADD);\n            }\n        }\n\n        public void aggregateRemainingMeasurements() {\n            for (var i = 0; i < count % measurements.length; i++) {\n                var measurement = measurements[i];\n                min = (short) Math.min(min, measurement);\n                max = (short) Math.max(max, measurement);\n                sum += measurement;\n            }\n        }\n\n        public void mergeWith(Station otherStation) {\n            min = (short) Math.min(min, otherStation.min);\n            max = (short) Math.max(max, otherStation.max);\n            count = count + otherStation.count;\n            sum = sum + otherStation.sum;\n        }\n\n        public boolean nameEquals(long otherNameAddress) {\n            var swarLimit = (nameLength / Long.BYTES) * Long.BYTES;\n            var i = 0;\n            for (; i < swarLimit; i += Long.BYTES) {\n                if (UNSAFE.getLong(nameAddress + i) != UNSAFE.getLong(otherNameAddress + i)) {\n                    return false;\n                }\n            }\n            for (; i < nameLength; i++) {\n                if (UNSAFE.getByte(nameAddress + i) != UNSAFE.getByte(otherNameAddress + i)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        public String toString() {\n            return String.format(\n                    Locale.US,\n                    \"%.1f/%.1f/%.1f\",\n                    (min / 10.0),\n                    ((sum / 10.0) / count),\n                    (max / 10.0));\n        }\n    }\n\n    /**\n     * Use two arrays for implementing the hash map:\n     * - The array `entries` holds the map values, in our case instances of the class Station.\n     * - The array `offsets` maps hashes of the keys to indexes in the `entries` array.\n     *\n     * We create `offsets` with a much larger capacity than `entries`, so we minimize collisions.\n     */\n    private static class FasterHashMap {\n        // Using 16-bit integers (shorts) for offsets supports up to 2^15 (=32,767) entries\n        // If you need to store more entries, consider replacing short with int\n        short[] offsets = new short[HASH_MAP_OFFSET_CAPACITY];\n        Station[] entries = new Station[NUM_STATIONS + 1];\n        int slotsInUse = 0;\n\n        private int getOffsetIdx(int nameHash, int nameLength, long nameAddress) {\n            var offsetIdx = nameHash & (offsets.length - 1);\n            var offset = offsets[offsetIdx];\n\n            while (offset != 0 &&\n                    (nameLength != entries[offset].nameLength || !entries[offset].nameEquals(nameAddress))) {\n                offsetIdx = (offsetIdx + 1) % offsets.length;\n                offset = offsets[offsetIdx];\n            }\n\n            return offsetIdx;\n        }\n\n        public void addEntry(int nameHash, int nameLength, long nameAddress, short measurement) {\n            var offsetIdx = getOffsetIdx(nameHash, nameLength, nameAddress);\n            var offset = offsets[offsetIdx];\n\n            if (offset == 0) {\n                slotsInUse++;\n                entries[slotsInUse] = new Station(nameHash, nameLength, nameAddress, measurement);\n                offsets[offsetIdx] = (short) slotsInUse;\n            }\n            else {\n                entries[offset].addMeasurementAndComputeAggregate(measurement);\n            }\n        }\n\n        public FasterHashMap mergeWith(FasterHashMap otherMap) {\n            for (Station station : otherMap.getEntries()) {\n                var offsetIdx = getOffsetIdx(station.nameHash, station.nameLength, station.nameAddress);\n                var offset = offsets[offsetIdx];\n\n                if (offset == 0) {\n                    slotsInUse++;\n                    entries[slotsInUse] = station;\n                    offsets[offsetIdx] = (short) slotsInUse;\n                }\n                else {\n                    entries[offset].mergeWith(station);\n                }\n            }\n            return this;\n        }\n\n        public List<Station> getEntries() {\n            return Arrays.asList(entries).subList(1, slotsInUse + 1);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_fragmede.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collector;\n\npublic class CalculateAverage_fragmede {\n\n    private static final String FILE = \"./measurements.txt\";\n    // private static final String FILE = \"./yaku.txt\";// \"./measurements.txt\";\n\n    private static record Measurement(String station, int value) {\n\t\tpublic static Measurement of(String[] parts) {\n\t\t\t//System.out.printf(\"string: %s!\\n\", parts[1]);\n\t\t\tboolean negative = false;\n\t\t\tint idx = 0;\n\t\t\tif (parts[1].charAt(0) == '-') {\n\t\t\t\tnegative = true;\n\t\t\t\tidx = 1;\n\t\t\t}\n\t\t\tint digit = (parts[1].charAt(idx)-48) * 10;\n\t\t\tint digit2 = 0;\n\t\t\tif (parts[1].charAt(idx+1) != '.') {\n\t\t\t\t// two digit temperature\n\t\t\t\tdigit = (digit) * 10;\n\t\t\t\t//System.out.println(parts[1].charAt(idx+1));\n\t\t\t\tdigit2 = (parts[1].charAt(idx+1)-48)*10;\n\t\t\t\tidx++;\n\t\t\t}\n\t\t\t// if (parts[1].charAt(idx+2) != \".\") {\n\t\t\t// \tabort();\n\t\t\t// }\n\t\t\tint frac = parts[1].charAt(idx+2)-48;\n\t\t\t//System.out.printf(\"parts, %d:%d:%d\\n\", digit, digit2, frac);\n\t\t\tint value = digit + digit2 + frac;\n\t\t\tif (negative) {\n\t\t\t\tvalue = -value;\n\t\t\t}\n\t\t\t//System.out.printf(\"end value: %d\\n\", value);\n\t\t\treturn new Measurement(parts[0], value);\n\t\t}\n\t}\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return min + \"/\" + round(mean) + \"/\" + max;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    public static void main(String[] args) throws IOException {\n        Collector<Measurement, MeasurementAggregator, ResultRow> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    a.min = Math.min(a.min, m.value);\n                    a.max = Math.max(a.max, m.value);\n                    a.sum += m.value;\n                    a.count++;\n                },\n                (agg1, agg2) -> {\n                    var res = new MeasurementAggregator();\n                    res.min = Math.min(agg1.min, agg2.min);\n                    res.max = Math.max(agg1.max, agg2.max);\n                    res.sum = agg1.sum + agg2.sum;\n                    res.count = agg1.count + agg2.count;\n\n                    return res;\n                },\n                agg -> {\n                    return new ResultRow(agg.min / 10.0, agg.sum / 10.0 / agg.count, agg.max / 10.0);\n                });\n\n        Map<String, ResultRow> measurements = new TreeMap<>(Files.lines(Paths.get(args[0]))\n                .map(l -> Measurement.of(l.split(\";\")))\n                .collect(groupingBy(Measurement::station, collector)));\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gabrielfoo.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ThreadFactory;\n\npublic class CalculateAverage_gabrielfoo {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int UTF8_MAX_LEN_100_BYTES = 400;\n    private static final int DOUBLE_DIGITS_MAX = 3;\n    private static final int UNIQUE_STATION_NAMES = 10000;\n\n    private static class ResultRow {\n        private double min = Double.POSITIVE_INFINITY;\n        private double sum = 0.0;\n        private double max = Double.NEGATIVE_INFINITY;\n        private int count = 0;\n\n        public String toString() {\n            return min + \"/\" + (Math.round(sum / count) / 10.0) + \"/\" + max;\n        }\n\n        public void updateMinMax(double incoming) {\n            min = Math.min(min, incoming);\n            max = Math.max(max, incoming);\n            sum += incoming * 10.0;\n            count += 1;\n        }\n\n        public void combine(ResultRow other) {\n            min = Math.min(min, other.min);\n            max = Math.max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n        }\n    }\n\n    public static MappedByteBuffer[] mapFileToMemory(final RandomAccessFile file, final int chunkCount) throws Exception {\n        FileChannel channel = file.getChannel();\n        final long chunkSize = Math.ceilDiv(file.length(), chunkCount);\n\n        MappedByteBuffer buffers[] = new MappedByteBuffer[chunkCount];\n\n        long position = 0;\n        for (int i = 0; i < chunkCount - 1; ++i) {\n            file.seek(position + chunkSize);\n            long ptr = file.getFilePointer();\n\n            while (file.readByte() != '\\n') {\n                file.seek(++ptr);\n            }\n\n            buffers[i] = channel.map(FileChannel.MapMode.READ_ONLY, position, ptr - position + 1);\n\n            position = ptr + 1;\n        }\n\n        buffers[buffers.length - 1] = channel.map(FileChannel.MapMode.READ_ONLY, position, file.length() - position);\n\n        return buffers;\n    }\n\n    public static void main(String[] args) throws Exception {\n        final RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n        final int coreCount = file.length() < 2147483647 ? 1 : Runtime.getRuntime().availableProcessors();\n        ArrayList<HashMap<String, ResultRow>> maps = new ArrayList<>();\n\n        final ThreadFactory threadFactory = new ThreadFactory() {\n            public Thread newThread(Runnable r) {\n                Thread t = new Thread(r);\n                t.setPriority(Thread.MAX_PRIORITY);\n                return t;\n            }\n        };\n        ExecutorService executor = Executors.newFixedThreadPool(coreCount, threadFactory);\n\n        Future<?> initFuture = executor.submit(() -> {\n            for (int i = 0; i < coreCount; ++i) {\n                maps.add(new HashMap<>(UNIQUE_STATION_NAMES, 0.9f));\n            }\n        });\n\n        MappedByteBuffer[] buffers = mapFileToMemory(file, coreCount);\n        initFuture.get();\n\n        Future<?>[] futures = new Future<?>[buffers.length];\n\n        for (int k = 0; k < buffers.length; ++k) {\n            final MappedByteBuffer buffer = buffers[k];\n            final var map = maps.get(k);\n            futures[k] = executor.submit(() -> {\n                int start = 0;\n                byte[] stationArr = new byte[UTF8_MAX_LEN_100_BYTES];\n                double[] floatArr = new double[DOUBLE_DIGITS_MAX];\n                byte currentByte;\n\n                while (buffer.hasRemaining()) {\n                    currentByte = buffer.get();\n                    stationArr[buffer.position() - start - 1] = currentByte;\n\n                    if (currentByte == ';') {\n                        final int stationEnd = buffer.position() - 1;\n                        // convert to double now\n                        currentByte = buffer.get();\n                        boolean neg = currentByte == '-';\n                        if (neg)\n                            currentByte = buffer.get();\n                        floatArr[0] = currentByte - '0';\n                        currentByte = buffer.get();\n                        if (currentByte == '.') {\n                            floatArr[1] = (buffer.get() - '0') / 10.0;\n                            floatArr[2] = 0.0;\n                        }\n                        else {\n                            floatArr[0] *= 10.0;\n                            floatArr[1] = (currentByte - '0');\n                            buffer.get();\n                            floatArr[2] = (buffer.get() - '0') / 10.0;\n                        }\n                        final double f = (neg ? -1 : 1) * (floatArr[0] + floatArr[1] + floatArr[2]);\n\n                        buffer.get(); // discard \\n\n\n                        String station = new String(stationArr, 0, stationEnd - start);\n\n                        map.compute(station, (key, existingRow) -> {\n                            ResultRow row = (existingRow == null) ? new ResultRow() : existingRow;\n                            row.updateMinMax(f);\n                            return row;\n                        });\n\n                        start = buffer.position();\n                    }\n                }\n\n            });\n        }\n\n        for (Future<?> future : futures) {\n            future.get();\n        }\n\n        HashMap<String, ResultRow> resultHashMap = maps.get(0);\n\n        maps.stream().skip(1).flatMap(map -> map.entrySet().stream()).forEach(entry -> {\n            resultHashMap.merge(entry.getKey(), entry.getValue(), (oldVal, newVal) -> {\n                oldVal.combine(newVal);\n                return oldVal;\n            });\n        });\n\n        TreeMap<String, ResultRow> res = new TreeMap<>(resultHashMap);\n\n        executor.shutdown();\n\n        System.out.println(res);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gabrielreid.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorSpecies;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.LinkedBlockingDeque;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\n\n/**\n * An attempt at using the \"new\" Vector API for determining where newline and semicolons are.\n */\npublic class CalculateAverage_gabrielreid {\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED;\n    private static final int BYTE_SPECIES_LEN = BYTE_SPECIES.length();\n    private static final byte SEMICOLON_BYTE = (byte) ';';\n    private static final byte NEWLINE_BYTE = (byte) '\\n';\n    private static final byte NEG_BYTE = (byte) '-';\n\n    private static final int BLOCK_READ_SIZE = 1024 * 1024 * 16;\n    private static final int SUMMARY_TABLE_SIZE = 2048;\n    private static final int MAP_INITIAL_SIZE = 450;\n\n    /**\n     * State with the full summary table, as well as leftover bytes between processed blocks that need to\n     * be handled afterward.\n     */\n    record State(Map<String, CitySummary> map, byte[] remainderBytes) {\n    }\n\n    public static void main(String[] args) throws IOException {\n        int numCores = Runtime.getRuntime().availableProcessors();\n        int numReadBuffers = numCores + 2;\n\n        var blockBuilderQueue = new LinkedBlockingDeque<BlockBuilder>(numReadBuffers);\n        for (int i = 0; i < numReadBuffers; i++) {\n            blockBuilderQueue.add(new BlockBuilder(BLOCK_READ_SIZE));\n        }\n        try (var fjp = new ForkJoinPool(numCores)) {\n\n            CompletableFuture<State> stateFuture = CompletableFuture.completedFuture(new State(new HashMap<>(MAP_INITIAL_SIZE), new byte[0]));\n\n            try (var fis = new FileInputStream(\"./measurements.txt\")) {\n                var blockBuilder = Objects.requireNonNull(blockBuilderQueue.poll());\n                boolean skipToNewline = false;\n                int cnt;\n                while ((cnt = fis.read(blockBuilder.readBuffer)) != -1) {\n\n                    var localBlockBuilder = blockBuilder;\n                    var localCnt = cnt;\n                    var localSkipToNewline = skipToNewline;\n                    skipToNewline = true;\n                    stateFuture = stateFuture.thenCombine(\n                            CompletableFuture.supplyAsync(() -> {\n                                var summaryMap = localBlockBuilder.buildSummaryTable(localCnt, localSkipToNewline);\n\n                                int unprocessedRemainderSize = localBlockBuilder.firstLineStart + (localCnt - localBlockBuilder.lastLineEnd);\n                                var unprocessedBytes = new byte[unprocessedRemainderSize];\n                                System.arraycopy(localBlockBuilder.readBuffer, 0, unprocessedBytes, 0, localBlockBuilder.firstLineStart);\n                                System.arraycopy(localBlockBuilder.readBuffer, localBlockBuilder.lastLineEnd, unprocessedBytes, localBlockBuilder.firstLineStart,\n                                        (localCnt - localBlockBuilder.lastLineEnd));\n\n                                localBlockBuilder.reset();\n                                blockBuilderQueue.add(localBlockBuilder);\n                                return new State(summaryMap, unprocessedBytes);\n                            }, fjp), (state, newState) -> {\n                                newState.map.forEach(\n                                        (k, v) -> state.map.merge(k, v, CitySummary::add));\n\n                                var newRemainderBytes = new byte[state.remainderBytes.length + newState.remainderBytes.length];\n                                System.arraycopy(state.remainderBytes, 0, newRemainderBytes, 0, state.remainderBytes.length);\n                                System.arraycopy(newState.remainderBytes, 0, newRemainderBytes, state.remainderBytes.length, newState.remainderBytes.length);\n                                return new State(state.map, newRemainderBytes);\n                            });\n\n                    try {\n                        blockBuilder = blockBuilderQueue.poll(1, TimeUnit.HOURS);\n                    } catch (InterruptedException e) {\n                        Thread.currentThread().interrupt();\n                        throw new RuntimeException(e);\n                    }\n                }\n\n            }\n\n            stateFuture = stateFuture.thenApply(state -> {\n                BlockBuilder blockBuilder;\n                try {\n                    blockBuilder = blockBuilderQueue.poll(1, TimeUnit.HOURS);\n                } catch (InterruptedException e) {\n                    Thread.currentThread().interrupt();\n                    throw new RuntimeException(e);\n                }\n                System.arraycopy(state.remainderBytes, 0, blockBuilder.readBuffer, 0, state.remainderBytes.length);\n\n                var m = blockBuilder.buildSummaryTable(state.remainderBytes.length, false);\n                m.forEach(\n                        (k, v) -> state.map.merge(k, v, CitySummary::add));\n                return new State(state.map, new byte[0]);\n            });\n\n            var state = stateFuture.join();\n            System.out.println(STR.\"{\\{state.map.entrySet().stream().sorted(Map.Entry.comparingByKey())\n                    .map(e -> String.format(Locale.US, \"%s=%.1f/%.1f/%.1f\", e.getKey(), e.getValue().min / 10f,\n                            (e.getValue().sum / (float) e.getValue().count) / 10f, e.getValue().max / 10f))\n                    .collect(Collectors.joining(\", \"))}}\");\n\n    }}\n\n    /**\n     * Parses number values as integers from the byte array.\n     * <p>\n     * The multiplier is 1 if positive and -1 if negative.\n     */\n    static short parseNumFromLine(byte[] buf, int offset, int len) {\n        return switch (len) {\n            case 3 -> (short) ((((buf[offset] - '0') * 10) + buf[offset + 2] - '0'));\n            case 4 -> (short) ((((buf[offset] - '0') * 100) + (buf[offset + 1] - '0') * 10 + buf[offset + 3] - '0'));\n            default -> throw new IllegalStateException(\"Unexpected number length %d\".formatted(len));\n        };\n    }\n\n    /**\n     * Aggregator of temperature values. All values are stored as integers internally (i.e. multiplied by 10).\n     */\n    static class CitySummary {\n        int max;\n        int min;\n        long sum;\n        int count;\n\n        public CitySummary(int value) {\n            this.max = value;\n            this.min = value;\n            this.sum = value;\n            this.count = 1;\n        }\n\n        void add(int value) {\n            this.max = Math.max(value, this.max);\n            this.min = Math.min(value, this.min);\n            this.sum += value;\n            this.count++;\n        }\n\n        CitySummary add(CitySummary other) {\n            this.max = Math.max(other.max, this.max);\n            this.min = Math.min(other.min, this.min);\n            this.sum += other.sum;\n            this.count += other.count;\n            return this;\n        }\n\n    }\n\n    /**\n     * A wrapper around a city name.\n     * <p>\n     * Provides a view of a large read buffer, but can also be cloned and detached from the read buffer.\n     */\n    static final class ByteSlice {\n\n        private final byte[] buf;\n        private final int offset;\n        private final int len;\n\n        public ByteSlice(byte[] buf, int offset, int len) {\n            this.buf = buf;\n            this.offset = offset;\n            this.len = len;\n        }\n\n        public String valueAsString() {\n            return new String(this.buf, this.offset, this.len, StandardCharsets.UTF_8);\n        }\n\n        public int hashCode() {\n            return hashCode(this.buf, this.offset, this.len);\n        }\n\n        public static int hashCode(byte[] buf, int offset, int len) {\n            int result = 1;\n            int i = 0;\n            for (; i + 3 < len; i += 4) {\n                result = 31 * 31 * 31 * 31 * result\n                        + 31 * 31 * 31 * buf[offset + i]\n                        + 31 * 31 * buf[offset + i + 1]\n                        + 31 * buf[offset + i + 2]\n                        + buf[offset + i + 3];\n            }\n            for (; i < len; i++) {\n                result = 31 * result + buf[offset + i];\n            }\n            return result;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof ByteSlice otherByteSlice) {\n                return ByteSlice.equal(this, otherByteSlice);\n            }\n            return false;\n        }\n\n        public static boolean equal(ByteSlice a, ByteSlice b) {\n            return Arrays.equals(a.buf, a.offset, a.offset + a.len, b.buf, b.offset, b.offset + b.len);\n        }\n\n        public static boolean equal(ByteSlice a, byte[] buf, int offset, int len) {\n            return Arrays.equals(a.buf, a.offset, a.offset + a.len, buf, offset, offset + len);\n        }\n\n    }\n\n    record ValueNode(ByteSlice byteSlice, CitySummary citySummary) {\n\n    }\n\n    static final class SummaryTable {\n\n        private static final int LOAD_FACTOR = 4;\n\n        private int size;\n        private ValueNode[] values;\n        private int valueCount;\n        private int resizeThreshold;\n\n        private byte[] localBufferBytes = new byte[MAP_INITIAL_SIZE * 100];\n        private int localBufferPtr = 0;\n\n        SummaryTable(int size) {\n            this.size = size;\n            this.values = new ValueNode[size];\n            this.resizeThreshold = size / LOAD_FACTOR;\n        }\n\n        void reset() {\n            for (int i = 0; i < size; i++) {\n                this.values[i] = null;\n            }\n            localBufferPtr = 0;\n        }\n\n        public void addAll(SummaryTable other) {\n            for (int i = 0; i < other.size; i++) {\n                var otherSlice = other.values[i];\n                if (otherSlice != null) {\n                    putValueNode(otherSlice);\n                }\n            }\n        }\n\n        private void putValueNode(ValueNode valueNode) {\n            int hashCode = valueNode.byteSlice.hashCode();\n            int index = (hashCode & 0x7FFFFFFF) % size;\n            while (values[index] != null) {\n                if (ByteSlice.equal(values[index].byteSlice, valueNode.byteSlice)) {\n                    values[index].citySummary.add(valueNode.citySummary);\n                    return;\n                }\n                index = (index + (hashCode & 0xFF) + 1) % size;\n            }\n            values[index] = valueNode;\n            valueCount++;\n            resizeIfNecessary();\n        }\n\n        public void putTemperatureValue(byte[] buf, int offset, int len, int value) {\n\n            int hashCode = ByteSlice.hashCode(buf, offset, len);\n            int index = (hashCode & 0x7FFFFFFF) % size;\n            while (values[index] != null) {\n                if (ByteSlice.equal(values[index].byteSlice, buf, offset, len)) {\n                    values[index].citySummary.add(value);\n                    return;\n                }\n                index = (index + (hashCode & 0xFF) + 1) % size;\n            }\n\n            System.arraycopy(buf, offset, this.localBufferBytes, this.localBufferPtr, len);\n            var byteSlice = new ByteSlice(this.localBufferBytes, this.localBufferPtr, len);\n            var valueNode = new ValueNode(byteSlice, new CitySummary(value));\n            localBufferPtr += len;\n\n            values[index] = valueNode;\n            valueCount++;\n            resizeIfNecessary();\n        }\n\n        private void resizeIfNecessary() {\n            if (valueCount >= resizeThreshold) {\n                int newSize = size * 2;\n                var resized = new SummaryTable(newSize);\n                for (int i = 0; i < this.size; i++) {\n                    if (this.values[i] != null) {\n                        resized.putValueNode(this.values[i]);\n                    }\n                }\n                resized.addAll(this);\n                byte[] localBufferBytes = new byte[this.localBufferBytes.length * 2];\n                System.arraycopy(this.localBufferBytes, 0, localBufferBytes, 0, this.localBufferPtr);\n                this.values = resized.values;\n                this.size = newSize;\n                this.valueCount = resized.valueCount;\n                this.resizeThreshold = newSize / LOAD_FACTOR;\n                this.localBufferBytes = localBufferBytes;\n            }\n        }\n\n        public Map<String, CitySummary> toMap() {\n            HashMap<String, CitySummary> m = HashMap.newHashMap(valueCount);\n            for (int i = 0; i < size; i++) {\n                var valueNode = this.values[i];\n                if (valueNode != null) {\n                    m.put(valueNode.byteSlice.valueAsString(), valueNode.citySummary);\n                }\n            }\n            return m;\n        }\n    }\n\n    /**\n     * Performs actual building of a SummaryTable from a read buffer.\n     */\n    static class BlockBuilder {\n        final byte[] readBuffer;\n        private final SummaryTable summaryTable;\n\n        private int firstLineStart;\n        private int lastLineEnd;\n\n        public BlockBuilder(int readBufferSize) {\n            this.readBuffer = new byte[readBufferSize];\n            this.summaryTable = new SummaryTable(SUMMARY_TABLE_SIZE);\n        }\n\n        void reset() {\n            firstLineStart = -1;\n            lastLineEnd = -1;\n            this.summaryTable.reset();\n\n        }\n\n        public Map<String, CitySummary> buildSummaryTable(int readByteCount, boolean skipToNewline) {\n            parseLineSegments(readByteCount, skipToNewline);\n            return summaryTable.toMap();\n        }\n\n        private void parseLineSegments(int byteCount, boolean skipToNewline) {\n            var upperBound = BYTE_SPECIES.loopBound(byteCount) - BYTE_SPECIES_LEN;\n            int idx = 0;\n\n            if (skipToNewline) {\n                while (this.readBuffer[idx] != NEWLINE_BYTE) {\n                    idx++;\n                }\n                idx++;\n            }\n\n            this.firstLineStart = idx;\n            int lineStart = idx;\n\n            while (idx < upperBound) {\n                var byteVector = ByteVector.fromArray(BYTE_SPECIES, readBuffer, idx);\n                var newlineIdx = byteVector.eq(NEWLINE_BYTE).firstTrue();\n                if (newlineIdx < BYTE_SPECIES_LEN) {\n                    var semicolonByteMask = byteVector.eq(SEMICOLON_BYTE);\n                    var semicolonIdx = semicolonByteMask.firstTrue();\n\n                    int semicolonOffset = idx + semicolonIdx;\n                    int lineEnd = idx + newlineIdx;\n                    short negative = (short) ((readBuffer[idx + semicolonIdx + 1] == NEG_BYTE) ? 1 : 0);\n                    int numLength = (byte) ((lineEnd - (semicolonOffset + 1)));\n                    var num = parseNumFromLine(this.readBuffer, semicolonOffset + 1 + negative, numLength - negative);\n                    num = negative == 1 ? (short) -num : num;\n                    int nameLen = semicolonOffset - lineStart;\n                    summaryTable.putTemperatureValue(this.readBuffer, lineStart, nameLen, num);\n                    idx = lineEnd + 1;\n                    lastLineEnd = idx;\n                    lineStart = idx;\n                }\n                else {\n                    // TODO This is mostly just out of laziness so that we process a full line on every step\n                    idx += BYTE_SPECIES_LEN - 7; // Max length of semicolon, negative temp, and newline is 7\n                }\n            }\n\n            int semicolonIdx = -1;\n            while (idx < byteCount) {\n                if (readBuffer[idx] == SEMICOLON_BYTE) {\n                    semicolonIdx = idx;\n                }\n                if (readBuffer[idx] == NEWLINE_BYTE) {\n                    int lineEnd = idx;\n\n                    short negative = (short) ((readBuffer[semicolonIdx + 1] == NEG_BYTE) ? 1 : 0);\n                    int numLength = (byte) ((lineEnd - (semicolonIdx + 1)));\n                    var num = parseNumFromLine(this.readBuffer, semicolonIdx + 1 + negative, numLength - negative);\n                    num = negative == 1 ? (short) -num : num;\n                    int nameLen = semicolonIdx - lineStart;\n                    summaryTable.putTemperatureValue(this.readBuffer, lineStart, nameLen, num);\n                    idx = lineEnd + 1;\n                    lastLineEnd = idx;\n                    lineStart = idx;\n                }\n                idx++;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gamlerhart.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.*;\n\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.TreeMap;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\n\nimport static java.lang.Double.doubleToRawLongBits;\nimport static java.lang.Double.longBitsToDouble;\nimport static java.lang.foreign.ValueLayout.*;\n\n/**\n * Broad experiments in this implementation:\n * - Memory-Map the file with new MemorySegments\n * - Use SIMD/vectorized search for the semicolon and new line feeds\n * - Use SIMD/vectorized comparison for the 'key'\n * <p>\n * Absolute stupid things / performance left on the table\n * - Single Threaded! Multi threading planned.\n * - The hash map/table is super basic.\n * - Hash table implementation / hashing has no resizing and is quite basic\n * - Zero time spend on profiling =)\n * <p>\n * <p>\n * Cheats used:\n * - Only works with Unix line feed \\n\n * - double parsing is only accepting XX.X and X.X\n * - HashMap has no resizing, check, horrible hash etc.\n * - Used the double parsing from yemreinci\n */\npublic class CalculateAverage_gamlerhart {\n\n    private static final String FILE = \"./measurements.txt\";\n    final static VectorSpecies<Byte> byteVec = ByteVector.SPECIES_PREFERRED;\n    final static Vector<Byte> zero = byteVec.zero();\n    final static int vecLen = byteVec.length();\n    final static Vector<Byte> semiColon = byteVec.broadcast(';');\n    final static VectorMask<Byte> allTrue = byteVec.maskAll(true);\n    final static ValueLayout.OfInt INT_UNALIGNED_BIG_ENDIAN = ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);\n\n    public static void main(String[] args) throws Exception {\n        try (var arena = Arena.ofShared();\n                FileChannel fc = FileChannel.open(Path.of(FILE))) {\n            long fileSize = fc.size();\n            MemorySegment fileContent = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, arena);\n\n            ArrayList<Section> sections = splitFileIntoSections(fileSize, fileContent);\n\n            var loopBound = byteVec.loopBound(fileSize) - vecLen;\n            var result = sections.stream()\n                    .parallel()\n                    .map(s -> {\n                        return parseSection(s.start, s.end, loopBound, fileContent);\n                    });\n\n            var measurements = new TreeMap<String, ResultRow>();\n            result.forEachOrdered(m -> {\n                m.fillMerge(fileContent, measurements);\n            });\n            System.out.println(measurements);\n        }\n    }\n\n    private static PrivateHashMap parseSection(long start, long end, long loopBound, MemorySegment fileContent) {\n        var map = new PrivateHashMap();\n        for (long i = start; i < end;) {\n            long nameStart = i;\n            int simdSearchEnd = 0;\n            int nameLen = 0;\n            // Vectorized Search\n            if (i < loopBound) {\n                do {\n                    var vec = byteVec.fromMemorySegment(fileContent, i, ByteOrder.BIG_ENDIAN);\n                    var hasSemi = vec.eq(semiColon);\n                    simdSearchEnd = hasSemi.firstTrue();\n                    i += simdSearchEnd;\n                    nameLen += simdSearchEnd;\n                } while (simdSearchEnd == vecLen && i < loopBound);\n            }\n            // Left-over search\n            while (loopBound <= i && fileContent.get(JAVA_BYTE, i) != ';') {\n                nameLen++;\n                i++;\n            }\n            i++; // Consume ;\n            // Copied from yemreinci. I mostly wanted to experiment the vector math, not with parsing =)\n            double val;\n            {\n                boolean negative = false;\n                if ((fileContent.get(JAVA_BYTE, i)) == '-') {\n                    negative = true;\n                    i++;\n                }\n                byte b;\n                double temp;\n                if ((b = fileContent.get(JAVA_BYTE, i + 1)) == '.') { // temperature is in either XX.X or X.X form\n                    temp = (fileContent.get(JAVA_BYTE, i) - '0') + (fileContent.get(JAVA_BYTE, i + 2) - '0') / 10.0;\n                    i += 3;\n                }\n                else {\n                    temp = (fileContent.get(JAVA_BYTE, i) - '0') * 10 + (b - '0')\n                            + (fileContent.get(JAVA_BYTE, i + 3) - '0') / 10.0;\n                    i += 4;\n                }\n                val = (negative ? -temp : temp);\n            }\n            i++; // Consume \\n\n            map.add(fileContent, nameStart, nameLen, val);\n        }\n        return map;\n    }\n\n    private static ArrayList<Section> splitFileIntoSections(long fileSize, MemorySegment fileContent) {\n        var cpuCount = Runtime.getRuntime().availableProcessors();\n        var roughChunkSize = fileSize / cpuCount;\n        ArrayList<Section> sections = new ArrayList<>(cpuCount);\n        for (long sStart = 0; sStart < fileSize;) {\n            var endGuess = Math.min(sStart + roughChunkSize, fileSize);\n            for (; endGuess < fileSize && fileContent.get(JAVA_BYTE, endGuess) != '\\n'; endGuess++) {\n            }\n            sections.add(new Section(sStart, endGuess));\n            sStart = endGuess + 1;\n        }\n        return sections;\n    }\n\n    private static class PrivateHashMap {\n        private static final int SIZE_SHIFT = 14;\n        public static final int SIZE = 1 << SIZE_SHIFT;\n        public static int MASK = 0xFFFFFFFF >>> (32 - SIZE_SHIFT);\n\n        public static long SHIFT_POS = 16;\n        public static long MASK_POS = 0xFFFFFFFFFFFF0000L;\n        public static long MASK_LEN = 0x000000000000FFFFL;\n        // Encoding:\n        // - Key: long\n        // - 48 bits index, 16 bits length\n        final long[] keys = new long[SIZE];\n        final Value[] values = new Value[SIZE];\n\n        private class Value {\n            public Value(double min, double max, double sum, long count) {\n                this.min = min;\n                this.max = max;\n                this.sum = sum;\n                this.count = count;\n            }\n\n            public double min;\n            public double max;\n            public double sum;\n            public long count;\n        }\n\n        // int debug_size = 0;\n\n        // int debug_reprobeMax = 0;\n        public PrivateHashMap() {\n\n        }\n\n        public void add(MemorySegment file, long pos, int len, double val) {\n            int hashCode = calculateHash(file, pos, len);\n            doAdd(file, hashCode, pos, len, val);\n        }\n\n        private static int calculateHash(MemorySegment file, long pos, int len) {\n            if (len > 4) {\n                return file.get(INT_UNALIGNED_BIG_ENDIAN, pos) + 31 * len;\n            }\n            else {\n                int hashCode = len;\n                int i = 0;\n                for (; i < len; i++) {\n                    int v = file.get(JAVA_BYTE, pos + i);\n                    hashCode = 31 * hashCode + v;\n                }\n                return hashCode;\n            }\n        }\n\n        private void doAdd(MemorySegment file, int hash, long pos, int len, double val) {\n            int slot = hash & MASK;\n            for (var probe = 0; probe < 20000; probe++) {\n                var iSl = ((slot + probe) & MASK);\n                var slotEntry = keys[iSl];\n\n                var emtpy = slotEntry == 0;\n                if (emtpy) {\n                    long keyInfo = pos << SHIFT_POS | len;\n                    keys[iSl] = keyInfo;\n                    values[iSl] = new Value(val, val, val, 1);\n                    // debug_size++;\n                    return;\n                }\n                else if (isSameEntry(file, slotEntry, pos, len)) {\n                    var vE = values[iSl];\n                    vE.min = Math.min(vE.min, val);\n                    vE.max = Math.max(vE.max, val);\n                    vE.sum = vE.sum + val;\n                    vE.count++;\n                    return;\n                }\n                else {\n                    // long keyPos = (slotEntry & MASK_POS) >> SHIFT_POS;\n                    // int keyLen = (int) (slotEntry & MASK_LEN);\n                    // System.out.println(\"Colliding \" + new String(file.asSlice(pos,len).toArray(ValueLayout.JAVA_BYTE)) +\n                    // \" with key\" + new String(file.asSlice(keyPos,keyLen).toArray(ValueLayout.JAVA_BYTE)) +\n                    // \" hash \" + hash + \" slot \" + slot + \"+\" + probe + \" at \" + iSl);\n                    // debug_reprobeMax = Math.max(debug_reprobeMax, probe);\n                }\n            }\n            throw new IllegalStateException(\"More than 20000 reprobes\");\n            // throw new IllegalStateException(\"More than 100 reprobes: At \" + debug_size + \"\");\n        }\n\n        private boolean isSameEntry(MemorySegment file, long slotEntry, long pos, int len) {\n            long keyPos = (slotEntry & MASK_POS) >> SHIFT_POS;\n            int keyLen = (int) (slotEntry & MASK_LEN);\n            var isSame = len == keyLen && isSame(file, keyPos, pos, len);\n            return isSame;\n        }\n\n        private static boolean isSame(MemorySegment file, long i1, long i2, int len) {\n            int i = 0;\n            var i1len = i1 + vecLen;\n            var i2len = i2 + vecLen;\n            if (len < vecLen && i1len <= file.byteSize() && i2len <= file.byteSize()) {\n                var v1 = byteVec.fromMemorySegment(file, i1, ByteOrder.nativeOrder());\n                var v2 = byteVec.fromMemorySegment(file, i2, ByteOrder.nativeOrder());\n                var isTrue = v1.compare(VectorOperators.EQ, v2, allTrue.indexInRange(0, len));\n                return isTrue.trueCount() == len;\n            }\n            while (8 < (len - i)) {\n                var v1 = file.get(JAVA_LONG_UNALIGNED, i1 + i);\n                var v2 = file.get(JAVA_LONG_UNALIGNED, i2 + i);\n                if (v1 != v2) {\n                    return false;\n                }\n                i += 8;\n            }\n            while (i < len) {\n                var v1 = file.get(JAVA_BYTE, i1 + i);\n                var v2 = file.get(JAVA_BYTE, i2 + i);\n\n                if (v1 != v2) {\n                    return false;\n                }\n                i++;\n            }\n            return true;\n        }\n\n        public void fillMerge(MemorySegment file, TreeMap<String, ResultRow> treeMap) {\n            for (int i = 0; i < keys.length; i++) {\n                var ji = i;\n                long keyE = keys[ji];\n                if (keyE != 0) {\n                    long keyPos = (keyE & MASK_POS) >> SHIFT_POS;\n                    int keyLen = (int) (keyE & MASK_LEN);\n                    byte[] keyBytes = new byte[keyLen];\n                    MemorySegment.copy(file, JAVA_BYTE, keyPos, keyBytes, 0, keyLen);\n                    var key = new String(keyBytes);\n                    var vE = values[ji];\n                    var min = vE.min;\n                    var max = vE.max;\n                    var sum = vE.sum;\n                    var count = vE.count;\n                    treeMap.compute(key, (k, e) -> {\n                        if (e == null) {\n                            return new ResultRow(min, max, sum, count);\n                        }\n                        else {\n                            return new ResultRow(Math.min(e.min, min), Math.max(e.max, max), e.sum + sum, e.count + count);\n                        }\n                    });\n                }\n            }\n        }\n\n        // public String debugPrint(MemorySegment file) {\n        // StringBuilder b = new StringBuilder();\n        // for (int i = 0; i < keyValues.length / 5; i++) {\n        // var ji = i * 5;\n        // long keyE = keyValues[ji];\n        // if (keyE != 0) {\n        // long keyPos = (keyE & MASK_POS) >> SHIFT_POS;\n        // int keyLen = (int) (keyE & MASK_LEN);\n        // byte[] keyBytes = new byte[keyLen];\n        // MemorySegment.copy(file, JAVA_BYTE, keyPos, keyBytes, 0, keyLen);\n        // var key = new String(keyBytes);\n        // var min = longBitsToDouble(keyValues[ji + 1]);\n        // var max = longBitsToDouble(keyValues[ji + 2]);\n        // var sum = longBitsToDouble(keyValues[ji + 3]);\n        // var count = keyValues[ji + 4];\n        // b.append(\"{\").append(key).append(\"@\").append(ji)\n        // .append(\",\").append(min)\n        // .append(\",\").append(max)\n        // .append(\",\").append(sum)\n        // .append(\",\").append(count).append(\"},\");\n        // }\n        // }\n        // return b.toString();\n        // }\n    }\n\n    record Section(long start, long end) {\n    }\n\n    private static record ResultRow(double min, double max, double sum, long count) {\n        public String toString() {\n            return round(min) + \"/\" + round(((Math.round(sum * 10.0) / 10.0) / count)) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    ;\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gauravdeshmukh.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_gauravdeshmukh {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final byte NEGATIVE_SIGN_BYTE = 0x2D;\n    private static final byte DOT_BYTE = 0x2E;\n    private static final int SEARCH_SPACE_BUFFER_SIZE = 140;\n\n    private static final long SEMI_COLON_MASK = 0x3B3B3B3B3B3B3B3BL;\n    private static final long EOL_MASK = 0x0A0A0A0A0A0A0A0AL;\n\n    private static class ByteString {\n        final private String string;\n        final private int staticHashCode;\n\n        public ByteString(byte[] bytes) {\n            this.string = new String(bytes, StandardCharsets.UTF_8);\n            this.staticHashCode = this.string.hashCode();\n        }\n\n        public byte[] getBytes() {\n            return string.getBytes(StandardCharsets.UTF_8);\n        }\n\n        @Override\n        public boolean equals(Object bs) {\n            return this.string.equals(bs.toString());\n        }\n\n        @Override\n        public int hashCode() {\n            return staticHashCode;\n        }\n\n        @Override\n        public String toString() {\n            return this.string;\n        }\n    }\n\n    private static class Measurement {\n        public ByteString station;\n        public int value;\n\n        public Measurement(ByteString station, int value) {\n            this.station = station;\n            this.value = value;\n        }\n\n        @Override\n        public String toString() {\n            StringBuffer sb = new StringBuffer();\n            sb.append(station.toString());\n            sb.append(\";\");\n            sb.append(value);\n            return sb.toString();\n        }\n    }\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private int sum;\n        private long count;\n\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round(sum * 1.0 / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // long st = System.currentTimeMillis();\n        int cores = 1;\n\n        File file = new File(FILE);\n        long fileSize = file.length();\n        if (fileSize > 1048576) {\n            cores = Runtime.getRuntime().availableProcessors();\n        }\n        long chunkSize = fileSize / cores;\n\n        ExecutorService executorService = Executors.newFixedThreadPool(cores);\n        List<ParallelFileReaderTask> callableTasks = new ArrayList<>(cores);\n        RandomAccessFile raf = new RandomAccessFile(file, \"r\");\n        long end = chunkSize, start = 0;\n        for (int i = 0; i < cores; i++) {\n            if (i < cores - 1) {\n                MappedByteBuffer mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, end, Math.min(SEARCH_SPACE_BUFFER_SIZE, fileSize - end));\n                int eolIndex = -1;\n                int extraBytes = 0;\n                while (true) {\n                    long word;\n                    try {\n                        word = mbb.getLong();\n                    }\n                    catch (java.nio.BufferUnderflowException ex) {\n                        byte[] remainingBytes = ByteBuffer.allocate(8).putLong(0).array();\n                        mbb.get(mbb.position(), remainingBytes, 0, mbb.remaining());\n                        word = ByteBuffer.wrap(remainingBytes).getLong();\n                    }\n                    eolIndex = findEolInLong(word);\n                    if (eolIndex > -1) {\n                        extraBytes = extraBytes + eolIndex + 1;\n                        break;\n                    }\n                    extraBytes += 8;\n                }\n                end = end + extraBytes;\n            }\n\n            callableTasks.add(new ParallelFileReaderTask(start, (end - start),\n                    raf.getChannel().map(FileChannel.MapMode.READ_ONLY, start, (end - start))));\n            start = end;\n            end = Math.min(end + chunkSize, fileSize - 1);\n        }\n        List<Future<Map<ByteString, MeasurementAggregator>>> futures = executorService.invokeAll(callableTasks);\n        List<Map<ByteString, MeasurementAggregator>> resultList = new ArrayList<>(futures.size());\n        for (Future<Map<ByteString, MeasurementAggregator>> future : futures) {\n            resultList.add(future.get());\n        }\n\n        Map<String, MeasurementAggregator> resultMap = new TreeMap<>();\n        for (Map<ByteString, MeasurementAggregator> map : resultList) {\n            for (Map.Entry<ByteString, MeasurementAggregator> entry : map.entrySet()) {\n                MeasurementAggregator agg = resultMap.get(entry.getKey().toString());\n                if (agg == null) {\n                    agg = new MeasurementAggregator();\n                    resultMap.put(entry.getKey().toString(), agg);\n                }\n                agg.min = Math.min(agg.min, entry.getValue().min);\n                agg.max = Math.max(agg.max, entry.getValue().max);\n                agg.sum = agg.sum + entry.getValue().sum;\n                agg.count = agg.count + entry.getValue().count;\n            }\n        }\n        System.out.println(resultMap);\n        executorService.shutdown();\n        // System.out.println(\"Time taken: \" + (System.currentTimeMillis() - st));\n    }\n\n    private static int findEolInLong(long word) {\n        return findPositionInLong(word, EOL_MASK);\n    }\n\n    private static int findSemiColonInLong(long word) {\n        return findPositionInLong(word, SEMI_COLON_MASK);\n    }\n\n    private static int findPositionInLong(long word, long searchMask) {\n        long maskedWord = word ^ searchMask;\n        long tmp = (maskedWord - 0x0101010101010101L) & ~maskedWord & 0x8080808080808080L;\n        return tmp == 0 ? -1 : (Long.numberOfLeadingZeros(tmp) >>> 3);\n    }\n\n    private static class ParallelFileReaderTask implements Callable<Map<ByteString, MeasurementAggregator>> {\n        private long start;\n        private int size;\n        private MappedByteBuffer mbf;\n        byte[] bytes;\n        private static final int BATCH_READ_SIZE = 64;\n        Map<ByteString, MeasurementAggregator> map;\n\n        public ParallelFileReaderTask(long start, long size, MappedByteBuffer mbf) {\n            this.start = start;\n            this.size = (int) size;\n            this.mbf = mbf;\n            this.bytes = new byte[BATCH_READ_SIZE];\n            this.map = new HashMap<>(10000);\n        }\n\n        @Override\n        public Map<ByteString, MeasurementAggregator> call() throws Exception {\n            int bytesReadTillNow = 0;\n            int startOfStation = 0, startOfNumber = -1, endOfStation = -1, endOfNumber = -1;\n            boolean isLastRead = false;\n            try {\n                while (bytesReadTillNow < this.size) {\n                    int semiColonIndex = -1;\n                    while (semiColonIndex == -1 && bytesReadTillNow < this.size) {\n                        long currentWord;\n                        try {\n                            currentWord = mbf.getLong();\n                        }\n                        catch (java.nio.BufferUnderflowException ex) {\n                            int remainingBytesCount = this.size - bytesReadTillNow;\n                            byte[] remainingBytes = ByteBuffer.allocate(8).putLong(0).array();\n                            mbf.get(bytesReadTillNow, remainingBytes, 0, remainingBytesCount);\n                            currentWord = ByteBuffer.wrap(remainingBytes).getLong();\n                        }\n                        semiColonIndex = findSemiColonInLong(currentWord);\n                        if (semiColonIndex > -1) {\n                            endOfStation = bytesReadTillNow + semiColonIndex;\n                            startOfNumber = bytesReadTillNow + semiColonIndex + 1;\n                            mbf.position(startOfNumber);\n                            bytesReadTillNow += semiColonIndex + 1;\n                        }\n                        else {\n                            bytesReadTillNow += 8;\n                        }\n                    }\n\n                    int stationLength = endOfStation - startOfStation;\n                    byte[] stationBytes = new byte[stationLength];\n                    mbf.get(startOfStation, stationBytes, 0, stationLength);\n\n                    int eolIndex = -1;\n                    while (eolIndex == -1 && bytesReadTillNow < this.size) {\n                        long currentWord;\n                        try {\n                            currentWord = mbf.getLong();\n                        }\n                        catch (java.nio.BufferUnderflowException ex) {\n                            int remainingBytesCount = this.size - bytesReadTillNow;\n                            byte[] remainingBytes = ByteBuffer.allocate(8).putLong(0).array();\n                            mbf.get(bytesReadTillNow, remainingBytes, 0, remainingBytesCount);\n                            currentWord = ByteBuffer.wrap(remainingBytes).getLong();\n                            isLastRead = true;\n                        }\n                        eolIndex = findEolInLong(currentWord);\n                        if (eolIndex > -1) {\n                            endOfNumber = bytesReadTillNow + eolIndex;\n                            startOfStation = bytesReadTillNow + eolIndex + 1;\n                            mbf.position(startOfStation);\n                            bytesReadTillNow += eolIndex + 1;\n                        }\n                        else {\n                            bytesReadTillNow += 8;\n                        }\n                        if (isLastRead) {\n                            bytesReadTillNow = this.size;\n                            if (eolIndex == -1) {\n                                endOfNumber = this.size;\n                            }\n                        }\n                    }\n\n                    int numberLength = endOfNumber - startOfNumber;\n                    byte[] numberBytes = new byte[numberLength];\n                    mbf.get(startOfNumber, numberBytes, 0, numberLength);\n\n                    Measurement measurement = new Measurement(new ByteString(stationBytes),\n                            getIntegerFromTemperatureBytes(numberBytes));\n                    MeasurementAggregator aggregator = this.map.get(measurement.station);\n                    if (aggregator == null) {\n                        aggregator = new MeasurementAggregator();\n                        this.map.put(measurement.station, aggregator);\n                    }\n                    aggregator.min = Math.min(aggregator.min, measurement.value);\n                    aggregator.max = Math.max(aggregator.max, measurement.value);\n                    aggregator.sum += measurement.value;\n                    aggregator.count++;\n                }\n            }\n            catch (Exception ex) {\n                throw ex;\n            }\n\n            return this.map;\n        }\n\n        private int getIntegerFromTemperatureBytes(byte[] numberBytes) {\n            int firstDigitIndex = (numberBytes[0] ^ NEGATIVE_SIGN_BYTE) == 0 ? 1 : 0;\n            int ret = 0;\n            for (int i = firstDigitIndex; i < numberBytes.length; i++) {\n                if ((numberBytes[i] ^ DOT_BYTE) != 0) {\n                    ret = (ret << 3) + (ret << 1) + ((int) numberBytes[i] - 48);\n                }\n            }\n            return (firstDigitIndex > 0) ? -ret : ret;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gigiblender.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_gigiblender {\n    private static final int AVAIL_CORES = Runtime.getRuntime().availableProcessors();\n    private static final HashTable[] tables = new HashTable[AVAIL_CORES];\n\n    private static Unsafe unsafe;\n    static {\n        Field theUnsafe = null;\n        try {\n            theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            unsafe = (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (IllegalAccessException | NoSuchFieldException ignored) {\n        }\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n\n    static class HashTable {\n\n        // 10_000 unique hashes ->\n        private static final int ENTRY_SIZE = 32;\n        private static final int NUM_ENTRIES = 16384;\n        private static final int DATA_SIZE = NUM_ENTRIES * ENTRY_SIZE;\n\n        /*\n         * data[i -> i + 7] = 8 bytes hash\n         * data[i + 8 -> i + 15] = 7 bytes masked address of the string in the file. 1 byte for the length of the string\n         * data[i + 16 -> i + 19] = 4 bytes count\n         * data[i + 20 -> i + 21] = 2 bytes max\n         * data[i + 22 -> i + 23] = 2 bytes min -- sign preserved\n         * data[i + 24 -> i + 31] = 8 bytes sum\n         */\n        byte[] data;\n\n        private static final int HASH_OFFSET = 0;\n\n        private static final int ADDR_OFFSET = 8;\n        private static final long ADDR_MASK = 0x00FFFFFFFFFFFFFFL;\n        private static final int STRING_LENGTH_SHIFT = 56;\n\n        private static final int COUNT_OFFSET = 16;\n\n        private static final int SUM_OFFSET = 24;\n\n        private int reprobe_count;\n\n        public HashTable() {\n            data = new byte[DATA_SIZE];\n            // reprobe_count = 0;\n        }\n\n        private long string_addr_and_length(long hash) {\n            return unsafe.getLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + hash + ADDR_OFFSET);\n        }\n\n        private static long string_addr(long encoded_str_addr) {\n            return (encoded_str_addr & ADDR_MASK);\n        }\n\n        private static long string_length(long encoded_str_addr) {\n            return encoded_str_addr >>> STRING_LENGTH_SHIFT;\n        }\n\n        private long count_max_min(long hash) {\n            return unsafe.getLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + hash + COUNT_OFFSET);\n        }\n\n        private static short mask_min(long count_max_min) {\n            // Preserve the sign\n            return (short) (count_max_min >> 6 * Byte.SIZE);\n        }\n\n        private static short mask_max(long count_max_min) {\n            return (short) (count_max_min >>> 4 * Byte.SIZE);\n        }\n\n        private static int mask_count(long count_max_min) {\n            return (int) count_max_min;\n        }\n\n        private static long encode_count_max_min(int count, short max, short min) {\n            return ((long) count) | ((((long) max) & 0xFFFF) << 4 * Byte.SIZE) | (((long) min) << 6 * Byte.SIZE);\n        }\n\n        private long sum(long hash) {\n            return unsafe.getLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + hash + SUM_OFFSET);\n        }\n\n        private static boolean string_equals(long string_addr, long entry_string_addr, int size_bytes) {\n            int remaining_bytes = size_bytes % 8;\n            int i = 0;\n            for (; i < size_bytes - remaining_bytes; i += 8) {\n                long entry_bytes = unsafe.getLong(entry_string_addr + i);\n                long string_bytes = unsafe.getLong(string_addr + i);\n                if (entry_bytes != string_bytes) {\n                    return false;\n                }\n            }\n            // The hash function is not great, so I end up in this case a lot, so I take some risks.\n            // This never caused a SIGSEGV even though it might :) If it does, fall back to the commented version below.\n            // I will try to improve on the hash function\n            if (remaining_bytes != 0) {\n                long entry_bytes = unsafe.getLong(entry_string_addr + i);\n                long string_bytes = unsafe.getLong(string_addr + i);\n                // mask the bytes we care about\n                long mask = (1L << (remaining_bytes * Byte.SIZE)) - 1;\n                entry_bytes &= mask;\n                string_bytes &= mask;\n                return entry_bytes == string_bytes;\n            }\n            // for (; i < size_bytes; i++) {\n            // byte entry_byte = unsafe.getByte(entry_string_addr + i);\n            // byte string_byte = unsafe.getByte(string_addr + i);\n            // if (entry_byte != string_byte) {\n            // return false;\n            // }\n            // }\n            return true;\n        }\n\n        public void insert(long hash, long string_addr, byte string_size, long final_number) {\n            assert string_addr >>> 56 == 0 : String.format(\"Expected final 8 bytes to be 0, got %s\", Long.toBinaryString(string_addr));\n\n            long encoded_string_addr_and_length = string_addr | ((long) string_size << STRING_LENGTH_SHIFT);\n            assert string_addr(encoded_string_addr_and_length) == string_addr : String.format(\"Expected string addr to be %s, got %s\", Long.toHexString(string_addr),\n                    Long.toHexString(string_addr(encoded_string_addr_and_length)));\n            assert string_length(encoded_string_addr_and_length) == string_size\n                    : String.format(\"Expected string length to be %s, got %s\", string_size, string_length(encoded_string_addr_and_length));\n\n            long map_entry = apply_mask(hash * ENTRY_SIZE);\n            while (true) {\n                int entry_count0 = unsafe.getInt(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + COUNT_OFFSET);\n                if (entry_count0 == 0) {\n                    // dump_insert(map_entry, hash, string_addr, string_size, final_number);\n                    // Found an empty slot. Insert the entry here\n                    unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + HASH_OFFSET, hash);\n                    unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + ADDR_OFFSET, encoded_string_addr_and_length);\n                    unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + COUNT_OFFSET, encode_count_max_min(1, (short) final_number, (short) final_number));\n                    unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + SUM_OFFSET, final_number);\n\n                    assert mask_count(encode_count_max_min(1, (short) final_number, (short) final_number)) == 1 : String.format(\"Expected count to be 1, got %s\",\n                            Integer.toBinaryString(mask_count(encode_count_max_min(1, (short) final_number, (short) final_number))));\n                    assert mask_max(encode_count_max_min(1, (short) final_number, (short) final_number)) == (short) final_number\n                            : String.format(\"Expected max to be %s, got %s\", final_number,\n                                    Integer.toBinaryString(mask_max(encode_count_max_min(1, (short) final_number, (short) final_number))));\n                    assert mask_min(encode_count_max_min(1, (short) final_number, (short) final_number)) == (short) final_number\n                            : String.format(\"Expected min to be %s, got %s\", final_number,\n                                    Integer.toBinaryString(mask_min(encode_count_max_min(1, (short) final_number, (short) final_number))));\n                    return;\n                }\n                else {\n                    // Check if strings match. If yes, update. Otherwise, look for the next available slot\n                    long entry_string_addr_and_length = string_addr_and_length(map_entry);\n                    long entry_str_size = string_length(entry_string_addr_and_length);\n\n                    if (string_size != entry_str_size) {\n                        // Strings are not the same size. Continue looking for the next slot\n                        map_entry = apply_mask(map_entry + ENTRY_SIZE);\n                        // reprobe_count++;\n                    }\n                    else {\n                        long entry_string_addr = string_addr(entry_string_addr_and_length);\n                        if (string_equals(string_addr, entry_string_addr, string_size)) {\n                            // Strings are the same. Update the entry\n                            long entry_count_max_min = count_max_min(map_entry);\n                            int entry_count = mask_count(entry_count_max_min);\n                            short entry_max = mask_max(entry_count_max_min);\n                            short entry_min = mask_min(entry_count_max_min);\n\n                            entry_count++;\n                            assert (int) final_number == final_number : String.format(\"Expected final number to be an int, got %s\", final_number);\n                            entry_max = (short) Math.max(entry_max, (int) final_number);\n                            entry_min = (short) Math.min(entry_min, (int) final_number);\n\n                            long entry_sum = sum(map_entry);\n                            entry_sum += final_number;\n\n                            unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + COUNT_OFFSET, encode_count_max_min(entry_count, entry_max, entry_min));\n                            unsafe.putLong(data, Unsafe.ARRAY_BYTE_BASE_OFFSET + map_entry + SUM_OFFSET, entry_sum);\n                            return;\n                        }\n                        else {\n                            // Strings are not the same. Continue looking for the next slot\n                            map_entry = apply_mask(map_entry + ENTRY_SIZE);\n                            // reprobe_count++;\n                        }\n                    }\n                }\n            }\n        }\n\n        private static long apply_mask(long hash) {\n            return hash & (DATA_SIZE - 1);\n        }\n\n        public void update_res(TreeMap<String, Result> result_map) {\n            // System.err.println(\"Reprobe count: \" + reprobe_count);\n            Result r = new Result();\n\n            for (int i = 0; i < NUM_ENTRIES; i++) {\n                long entry_addr_offset = (long) i * ENTRY_SIZE;\n                long entry_count_max_min = count_max_min(entry_addr_offset);\n                int entry_count = mask_count(entry_count_max_min);\n                if (entry_count == 0) {\n                    continue;\n                }\n                long entry_string_addr_and_length = string_addr_and_length(entry_addr_offset);\n                long entry_string_addr = string_addr(entry_string_addr_and_length);\n                long entry_string_length = string_length(entry_string_addr_and_length);\n\n                // no reason to copy the byte array twice here but what can you do...\n                byte[] bytes = new byte[(int) entry_string_length];\n                unsafe.copyMemory(null, entry_string_addr, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, entry_string_length);\n                String s = new String(bytes, StandardCharsets.UTF_8);\n\n                short entry_max = mask_max(entry_count_max_min);\n                short entry_min = mask_min(entry_count_max_min);\n\n                long entry_sum = sum(entry_addr_offset);\n\n                Result ret = result_map.putIfAbsent(s, r);\n                if (ret == null) {\n                    r.count = entry_count;\n                    r.max = entry_max;\n                    r.min = entry_min;\n                    r.sum = entry_sum;\n                    r = new Result();\n                }\n                else {\n                    ret.count += entry_count;\n                    ret.max = (short) Math.max(ret.max, entry_max);\n                    ret.min = (short) Math.min(ret.min, entry_min);\n                    ret.sum += entry_sum;\n                }\n            }\n        }\n\n        public void dump_insert(long map_entry, long hash, long string_addr, byte string_size, long final_number) {\n            System.out.println(\"START dump_insert\");\n            System.out.println(\"Inserting \" + final_number + \" with hash \" + hash);\n            System.out.println(\"Map entry: \" + map_entry);\n            System.out.println(\"String addr: \" + string_addr + \" with length \" + string_size);\n            dump(string_addr, string_addr + string_size);\n            System.out.println(\"END dump_insert\");\n        }\n    }\n\n    static class Result {\n        public int count;\n        public short max;\n        public short min;\n        public long sum;\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.) + \"/\" + round(sum / (double) (10 * count)) + \"/\" + round(max / 10.);\n        }\n    }\n\n    private static void compute_slice(final long base_addr, final long slice_size, final long file_size, final int thread_index) {\n        HashTable my_table;\n        if (!SINGLE_CORE) {\n            my_table = new HashTable();\n            tables[thread_index] = my_table;\n        }\n        else {\n            if (tables[0] == null) {\n                tables[0] = new HashTable();\n            }\n            my_table = tables[0];\n        }\n\n        long cur_addr = base_addr + (long) thread_index * slice_size;\n        // Lookup the next newline. If thread_index == 0 then start right away\n        if (thread_index != 0) {\n            while (unsafe.getByte(cur_addr) != '\\n') {\n                cur_addr++;\n            }\n            cur_addr++;\n        }\n\n        long end_addr = base_addr + (long) (thread_index + 1) * slice_size;\n        if (thread_index == (AVAIL_CORES - 1)) {\n            // Last thread. We need to read until the end of the file\n            end_addr = base_addr + file_size;\n        }\n        else {\n            // look ahead for the next newline\n            while (unsafe.getByte(end_addr) != '\\n') {\n                end_addr++;\n            }\n            end_addr++;\n        }\n\n        // We now have a well-defined interval [cur_addr, end_addr) to work on\n        long hash = -2346162244362633811L;\n        byte string_size = 0;\n        long string_addr = cur_addr;\n        while (cur_addr < end_addr) {\n            long value_mem = unsafe.getLong(cur_addr);\n            int semicolon_byte_index = get_semicolon_index(value_mem);\n\n            string_size += (byte) semicolon_byte_index;\n\n            // dump(cur_addr, cur_addr + semicolon_byte_index);\n\n            if (semicolon_byte_index != 8) {\n                long value_mem_up_to_semicolon = value_mem & ((1L << (semicolon_byte_index * Byte.SIZE)) - 1);\n\n                // We have a semicolon, so the hash is complete now. We can construct the number\n                // and insert it into the hash table\n                long start_num_addr = cur_addr + semicolon_byte_index + 1;\n\n                // Always read the next 8 bytes for the number. It seems that this is faster than\n                // checking if the whole number is in the current 8 bytes and only reading if it is not\n                long number_mem_value = unsafe.getLong(start_num_addr);\n                long number_len_bytes = get_newline_index(number_mem_value);\n\n                long final_number = extract_number(number_mem_value, number_len_bytes);\n\n                // 0.2421196 % reprobe rate\n                hash = compute_hash(hash ^ value_mem_up_to_semicolon);\n\n                // We have the final number now. We can insert it into the hash table\n                my_table.insert(hash, string_addr, string_size, final_number);\n                // Now we can move on to the next line\n                hash = -2346162244362633811L;\n                string_size = 0;\n                cur_addr = start_num_addr + number_len_bytes + 1;\n                string_addr = cur_addr;\n            }\n            else {\n                // No semicolon in the 8 bytes read. Continue reading\n                hash = hash ^ value_mem;\n                cur_addr += 8;\n            }\n        }\n        assert cur_addr == end_addr : String.format(\"Expected cur_addr to be %s, got %s\", end_addr, cur_addr);\n    }\n\n    private static long extract_number(long number_mem_value, long number_len_bytes) {\n        // Pray for GVN/CSE and Sea of Nodes moving the mess below in the proper places because\n        // I don't want to spend the time to do it properly :)\n        long number_mem_dot_index = get_dot_index(number_mem_value);\n\n        int fractional_part = get_fractional_part(number_mem_value, number_len_bytes);\n        int sign = get_sign(number_mem_value);\n        int skip_sign = skip_sign(number_mem_value);\n\n        long number_mem_value_no_sign = number_mem_value >>> (skip_sign << 3);\n        // Two cases: either there's a single digit before the dot, or there's two\n        // Start from the dot index and go backwards\n        long new_number_mem_dot_index = number_mem_dot_index - skip_sign;\n        long read_byte_mask = 0xFFL << ((new_number_mem_dot_index - 1) * Byte.SIZE);\n        long ones = ((number_mem_value_no_sign & read_byte_mask) >>> ((new_number_mem_dot_index - 1) * Byte.SIZE)) - 0x30;\n        // Should be 0 due to the multiplication if there's only one digit before the dot\n        long tens = ((number_mem_value_no_sign & 0xFFL) - 0x30) * (new_number_mem_dot_index - 1);\n\n        long final_number = (tens * 100 + ones * 10 + fractional_part) * sign;\n        return final_number;\n    }\n\n    private static int get_fractional_part(long number_mem_value, long number_len_bytes) {\n        return (int) ((number_mem_value >>> ((number_len_bytes - 1) * Byte.SIZE)) & 0xFF) - 0x30;\n    }\n\n    private static int skip_sign(long number_mem_value) {\n        // return 1 if char is '-', 0 if it is not\n        long diff = (number_mem_value & 0xFF) - 0x2D;\n        long sign = (diff | -diff) >>> 63;\n        return (int) ((sign - 1) * -1);\n    }\n\n    private static int get_sign(long number_mem_value) {\n        // return 1 if char is not '-', -1 if it is\n        long diff = (number_mem_value & 0xFF) - 0x2D;\n        long sign = (diff | -diff) >>> 63;\n        return (int) (-2 * sign + 1) * -1;\n    }\n\n    private static long compute_hash(long x) { // Hash burrowed from artsiomkorzun and slightly changed\n        long h = x * -7046029254386353131L;\n        long h1 = h ^ (h >>> 32);\n        h = h ^ (h << 32);\n        return h1 ^ h;\n    }\n\n    private static void dump(long startAddr, long endAddr) {\n        byte[] bytes = new byte[(int) (endAddr - startAddr)];\n        unsafe.copyMemory(null, startAddr, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, bytes.length);\n        String s = new String(bytes, StandardCharsets.UTF_8);\n        System.out.println(s);\n        // Dump the bytes to binary form\n        for (byte b : bytes) {\n            System.out.print(Integer.toBinaryString(b & 0xFF));\n            System.out.print(\" \");\n        }\n        System.out.println();\n        // Dump the bytes to hex form\n        for (byte b : bytes) {\n            System.out.print(Integer.toHexString(b & 0xFF));\n            System.out.print(\" \");\n        }\n        System.out.println();\n    }\n\n    private static int get_byte_0_index(long value) {\n        long res = (value - 0x0101010101010101L) & (~value & 0x8080808080808080L);\n        res = Long.numberOfTrailingZeros(res) >> 3;\n        return (int) res;\n    }\n\n    private static int get_dot_index(long value) {\n        long temp = value ^ 0x2E2E2E2E2E2E2E2EL;\n        return get_byte_0_index(temp);\n    }\n\n    private static int get_newline_index(long value) {\n        long temp = value ^ 0x0A0A0A0A0A0A0A0AL;\n        return get_byte_0_index(temp);\n    }\n\n    private static int get_semicolon_index(long value) {\n        long temp = value ^ 0x3B3B3B3B3B3B3B3BL;\n        return get_byte_0_index(temp);\n    }\n\n    private static final boolean SINGLE_CORE = false;\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        FileChannel file_channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ);\n        long file_size = file_channel.size();\n        long base_addr = file_channel.map(FileChannel.MapMode.READ_ONLY, 0, file_size, Arena.global()).address();\n\n        if (!SINGLE_CORE) {\n            int num_threads = AVAIL_CORES;\n            Thread[] threads = new Thread[num_threads];\n            for (int i = 0; i < num_threads; i++) {\n                int finalI = i;\n                threads[i] = new Thread(() -> {\n                    long slice_size = file_size / AVAIL_CORES;\n                    compute_slice(base_addr, slice_size, file_size, finalI);\n                });\n                threads[i].start();\n            }\n\n            TreeMap<String, Result> result_map = new TreeMap<>();\n            for (int i = 0; i < num_threads; i++) {\n                threads[i].join();\n                tables[i].update_res(result_map);\n            }\n\n            System.out.println(result_map);\n        }\n        else {\n            for (int i = 0; i < AVAIL_CORES; i++) {\n                int finalI = i;\n                long slice_size = file_size / AVAIL_CORES;\n                compute_slice(base_addr, slice_size, file_size, finalI);\n            }\n\n            TreeMap<String, Result> result_map = new TreeMap<>();\n            tables[0].update_res(result_map);\n\n            System.out.println(result_map);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_giovannicuccu.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.IntVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.*;\n\n/*\n Solution without unsafe that borrows the ideas of splullara, thomasvue, royvanrijn and merykitty\n */\n\npublic class CalculateAverage_giovannicuccu {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_256;\n    private static final int BYTE_SPECIES_LANES = BYTE_SPECIES.length();\n    private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder();\n    public static final VectorSpecies<Integer> INT_SPECIES = IntVector.SPECIES_256;\n    public static final int INT_SPECIES_LANES = INT_SPECIES.length();\n\n    public static final int KEY_SIZE = 128;\n\n    public static record PartitionBoundary(Path path, long start, long end) {\n    }\n\n    public static interface PartitionCalculator {\n        List<PartitionBoundary> computePartitionsBoundaries(Path path);\n    }\n\n    public static class ProcessorPartitionCalculator implements PartitionCalculator {\n\n        public List<PartitionBoundary> computePartitionsBoundaries(Path path) {\n            try {\n                int numberOfSegments = Runtime.getRuntime().availableProcessors();\n                long fileSize = path.toFile().length();\n                long segmentSize = fileSize / numberOfSegments;\n                List<PartitionBoundary> segmentBoundaries = new ArrayList<>(numberOfSegments);\n                try (RandomAccessFile randomAccessFile = new RandomAccessFile(path.toFile(), \"r\")) {\n                    long segStart = 0;\n                    long segEnd = segmentSize;\n                    for (int i = 0; i < numberOfSegments; i++) {\n                        segEnd = findEndSegment(randomAccessFile, segEnd, fileSize);\n                        segmentBoundaries.add(new PartitionBoundary(path, segStart, segEnd));\n                        segStart = segEnd;\n                        segEnd = Math.min(segEnd + segmentSize, fileSize);\n                    }\n                }\n                return segmentBoundaries;\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        private long findEndSegment(RandomAccessFile raf, long location, long fileSize) throws IOException {\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                if (raf.read() == 10)\n                    break;\n            }\n            return location;\n        }\n    }\n\n    private static class MeasurementAggregatorVectorized {\n\n        private int min;\n        private int max;\n        private double sum;\n        private long count;\n        private final int len;\n        private final int hash;\n\n        private final int offset;\n        private byte[] data;\n\n        public MeasurementAggregatorVectorized(byte[] data, int offset, int len, int hash, int initialValue) {\n            min = initialValue;\n            max = initialValue;\n            sum = initialValue;\n            count = 1;\n            this.len = len;\n            this.hash = hash;\n            this.offset = offset;\n            this.data = data;\n        }\n\n        public void add(int value) {\n            if (value < min) {\n                min = value;\n            }\n            if (value > max) {\n                max = value;\n            }\n            sum += value;\n            count++;\n        }\n\n        public void merge(MeasurementAggregatorVectorized other) {\n            min = Math.min(min, other.min);\n            max = Math.max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.) + \"/\" + round(sum / (double) (10 * count)) + \"/\" + round(max / 10.);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public int getMin() {\n            return min;\n        }\n\n        public int getHash() {\n            return hash;\n        }\n\n        public int getLen() {\n            return len;\n        }\n\n        public boolean dataEquals(byte[] data, int offset) {\n            return Arrays.equals(this.data, this.offset, this.offset + len, data, offset, offset + len);\n\n        }\n\n        public String getName() {\n            return new String(data, offset, len, StandardCharsets.UTF_8);\n        }\n\n        public int getOffset() {\n            return offset;\n        }\n\n        public byte[] getData() {\n            return data;\n        }\n    }\n\n    private static class MeasurementListVectorized {\n        private static final int SIZE = 1024 * 64;\n        private final MeasurementAggregatorVectorized[] measurements = new MeasurementAggregatorVectorized[SIZE];\n        private final byte[] keyData = new byte[SIZE * KEY_SIZE];\n\n        private final MemorySegment dataSegment = MemorySegment.ofArray(keyData);\n\n        private final byte[] lineData = new byte[SIZE];\n\n        private final MemorySegment lineSegment = MemorySegment.ofArray(lineData);\n\n        public void add(int len, int hash, int value, MemorySegment memorySegment, long offset) {\n            MemorySegment.copy(memorySegment, offset, lineSegment, 0, len);\n            int index = hash & (SIZE - 1);\n            while (measurements[index] != null) {\n                if (measurements[index].getHash() == hash && measurements[index].getLen() == len) {\n                    if (Arrays.equals(keyData, index * KEY_SIZE, index * KEY_SIZE + len, lineData, 0, len)) {\n                        measurements[index].add(value);\n                        return;\n                    }\n                }\n                index = (index + 1) & (SIZE - 1);\n            }\n            MemorySegment.copy(memorySegment, offset, dataSegment, (long) index * KEY_SIZE, len);\n            measurements[index] = new MeasurementAggregatorVectorized(keyData, index * KEY_SIZE, len, hash, value);\n        }\n\n        public void addWithByteVector(ByteVector chunk1, int len, int hash, int value, MemorySegment memorySegment, long offset) {\n            int index = hash & (SIZE - 1);\n            while (measurements[index] != null) {\n                if (measurements[index].getLen() == len && measurements[index].getHash() == hash) {\n                    var nodeKey = ByteVector.fromArray(BYTE_SPECIES, keyData, index * KEY_SIZE);\n                    long eqMask = chunk1.compare(VectorOperators.EQ, nodeKey).toLong();\n                    long validMask = -1L >>> (64 - len);\n                    if ((eqMask & validMask) == validMask) {\n                        measurements[index].add(value);\n                        return;\n                    }\n                }\n                index = (index + 1) & (SIZE - 1);\n            }\n            MemorySegment.copy(memorySegment, offset, dataSegment, (long) index * KEY_SIZE, len);\n            measurements[index] = new MeasurementAggregatorVectorized(keyData, index * KEY_SIZE, len, hash, value);\n        }\n\n        public void merge(MeasurementAggregatorVectorized measurementAggregator) {\n            int index = measurementAggregator.getHash() & (SIZE - 1);\n            while (measurements[index] != null) {\n                if (measurements[index].getLen() == measurementAggregator.getLen() && measurements[index].getHash() == measurementAggregator.getHash()) {\n                    if (measurementAggregator.dataEquals(measurements[index].getData(), measurements[index].getOffset())) {\n                        measurements[index].merge(measurementAggregator);\n                        return;\n                    }\n                }\n                index = (index + 1) & (SIZE - 1);\n            }\n            measurements[index] = measurementAggregator;\n        }\n\n        public MeasurementAggregatorVectorized[] getMeasurements() {\n            return measurements;\n        }\n\n    }\n\n    private static class MMapReaderMemorySegment {\n\n        private final Path path;\n        private final List<PartitionBoundary> boundaries;\n        private final boolean serial;\n        private static final ValueLayout.OfLong JAVA_LONG_LT = ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN);\n\n        public MMapReaderMemorySegment(Path path, PartitionCalculator partitionCalculator, boolean serial) {\n            this.path = path;\n            this.serial = serial;\n            boundaries = partitionCalculator.computePartitionsBoundaries(path);\n        }\n\n        public TreeMap<String, MeasurementAggregatorVectorized> elaborate() throws IOException {\n            try (ExecutorService executor = Executors.newFixedThreadPool(boundaries.size());\n                    FileChannel fileChannel = (FileChannel) Files.newByteChannel((path), StandardOpenOption.READ);\n                    var arena = Arena.ofShared()) {\n\n                List<Future<MeasurementListVectorized>> futures = new ArrayList<>();\n                for (PartitionBoundary boundary : boundaries) {\n                    if (serial) {\n                        FutureTask<MeasurementListVectorized> future = new FutureTask<>(() -> computeListForPartition(\n                                fileChannel, boundary));\n                        future.run();\n                        futures.add(future);\n                    }\n                    else {\n                        Future<MeasurementListVectorized> future = executor.submit(() -> computeListForPartition(\n                                fileChannel, boundary));\n                        futures.add(future);\n                    }\n                }\n                TreeMap<String, MeasurementAggregatorVectorized> ris = reduce(futures);\n                return ris;\n            }\n        }\n\n        private TreeMap<String, MeasurementAggregatorVectorized> reduce(List<Future<MeasurementListVectorized>> futures) {\n            try {\n                TreeMap<String, MeasurementAggregatorVectorized> risMap = new TreeMap<>();\n                MeasurementListVectorized ris = new MeasurementListVectorized();\n                for (Future<MeasurementListVectorized> future : futures) {\n                    MeasurementListVectorized results = future.get();\n                    merge(ris, results);\n                }\n                for (MeasurementAggregatorVectorized m : ris.getMeasurements()) {\n                    if (m != null) {\n                        risMap.put(m.getName(), m);\n                    }\n                }\n                return risMap;\n            }\n            catch (InterruptedException | ExecutionException ie) {\n                System.err.println(ie);\n                throw new RuntimeException(ie);\n            }\n        }\n\n        private void merge(MeasurementListVectorized result, MeasurementListVectorized partial) {\n            for (MeasurementAggregatorVectorized m : partial.getMeasurements()) {\n                if (m != null) {\n                    result.merge(m);\n                }\n            }\n        }\n\n        private final long ALL_ONE = -1L;\n        private static final long DELIMITER_MASK = 0x3B3B3B3B3B3B3B3BL;\n\n        private static final byte SEPARATOR = ';';\n        private final static ByteVector SEPARATORS = ByteVector.broadcast(BYTE_SPECIES, SEPARATOR);\n\n        private MeasurementListVectorized computeListForPartition(FileChannel fileChannel, PartitionBoundary boundary) {\n            try (var arena = Arena.ofConfined()) {\n                var memorySegment = fileChannel.map(FileChannel.MapMode.READ_ONLY, boundary.start(), boundary.end() - boundary.start(), arena);\n                MeasurementListVectorized list = new MeasurementListVectorized();\n                long size = memorySegment.byteSize();\n                long offset = 0;\n                long safe = size - KEY_SIZE;\n                while (offset < safe) {\n                    int len = 0;\n                    var line = ByteVector.fromMemorySegment(BYTE_SPECIES, memorySegment, offset, NATIVE_ORDER);\n                    len = line.compare(VectorOperators.EQ, SEPARATORS).firstTrue();\n                    if (len == BYTE_SPECIES_LANES) {\n                        int position1 = -1;\n                        int incr = BYTE_SPECIES_LANES;\n                        while (position1 == -1) {\n                            long readBuffer = memorySegment.get(JAVA_LONG_LT, offset + incr);\n                            long comparisonResult1 = (readBuffer ^ DELIMITER_MASK);\n                            long highBitMask1 = (comparisonResult1 - 0x0101010101010101L) & (~comparisonResult1 & 0x8080808080808080L);\n\n                            boolean noContent1 = highBitMask1 == 0;\n                            position1 = noContent1 ? -1 : Long.numberOfTrailingZeros(highBitMask1) >> 3;\n                            len += noContent1 ? 8 : position1;\n                            incr += 8;\n                        }\n                        int hash = hash(memorySegment, offset, len);\n                        long prevOffset = offset;\n                        offset += len + 1;\n\n                        long numberWord = memorySegment.get(JAVA_LONG_LT, offset);\n                        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n                        int value = convertIntoNumber(decimalSepPos, numberWord);\n                        offset += (decimalSepPos >>> 3) + 3;\n                        list.add(len, hash, value, memorySegment, prevOffset);\n                    }\n                    else {\n                        int hash = hash(memorySegment, offset, len);\n                        long prevOffset = offset;\n                        offset += len + 1;\n\n                        long numberWord = memorySegment.get(JAVA_LONG_LT, offset);\n                        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n                        int value = convertIntoNumber(decimalSepPos, numberWord);\n                        offset += (decimalSepPos >>> 3) + 3;\n                        list.addWithByteVector(line, len, hash, value, memorySegment, prevOffset);\n                    }\n                }\n\n                while (offset < size) {\n                    int len = 0;\n                    while (memorySegment.get(ValueLayout.JAVA_BYTE, offset + len) != ';') {\n                        len++;\n                    }\n                    int hash = hash(memorySegment, offset, len);\n                    long prevOffset = offset;\n                    offset += len + 1;\n\n                    int value = 0;\n                    if (offset < size - 8) {\n                        long numberWord = memorySegment.get(JAVA_LONG_LT, offset);\n                        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n                        value = convertIntoNumber(decimalSepPos, numberWord);\n                        offset += (decimalSepPos >>> 3) + 3;\n                    }\n                    else {\n                        long currentPosition = offset;\n                        int sign = 1;\n                        byte b = memorySegment.get(ValueLayout.JAVA_BYTE, currentPosition++);\n                        if (b == '-') {\n                            sign = -1;\n                        }\n                        else {\n                            value = b - '0';\n                        }\n                        while ((b = memorySegment.get(ValueLayout.JAVA_BYTE, currentPosition++)) != '.') {\n                            value = value * 10 + (b - '0');\n                        }\n                        b = memorySegment.get(ValueLayout.JAVA_BYTE, currentPosition);\n                        value = value * 10 + (b - '0');\n                        if (sign == -1) {\n                            value = -value;\n                        }\n                        offset = currentPosition + 2;\n                    }\n                    list.add(len, hash, value, memorySegment, prevOffset);\n                }\n                return list;\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        private static final int GOLDEN_RATIO = 0x9E3779B9;\n        private static final int HASH_LROTATE = 5;\n\n        private static int hash(MemorySegment memorySegment, long start, int len) {\n            int x;\n            int y;\n            if (len >= Integer.BYTES) {\n                x = memorySegment.get(ValueLayout.JAVA_INT_UNALIGNED, start);\n                y = memorySegment.get(ValueLayout.JAVA_INT_UNALIGNED, start + len - Integer.BYTES);\n            }\n            else {\n                x = memorySegment.get(ValueLayout.JAVA_BYTE, start);\n                y = memorySegment.get(ValueLayout.JAVA_BYTE, start + len - Byte.BYTES);\n            }\n            return (Integer.rotateLeft(x * GOLDEN_RATIO, HASH_LROTATE) ^ y) * GOLDEN_RATIO;\n        }\n\n        private static int convertIntoNumber(int decimalSepPos, long numberWord) {\n            int shift = 28 - decimalSepPos;\n            // signed is -1 if negative, 0 otherwise\n            long signed = (~numberWord << 59) >> 63;\n            long designMask = ~(signed & 0xFF);\n            // Align the number to a specific position and transform the ascii code\n            // to actual digit value in each byte\n            long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 +\n            // 0x00UU00TTHH000000 * 10 +\n            // 0xUU00TTHH00000000 * 100\n            // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n            // This results in our value lies in the bit 32 to 41 of this product\n            // That was close :)\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            long value = (absValue ^ signed) - signed;\n            return (int) value;\n        }\n\n    }\n\n    public static void main(String[] args) throws IOException {\n        MMapReaderMemorySegment reader = new MMapReaderMemorySegment(Paths.get(FILE), new ProcessorPartitionCalculator(), false);\n        Map<String, MeasurementAggregatorVectorized> measurements = reader.elaborate();\n        System.out.println(measurements);\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gnabyl.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_gnabyl {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int NB_CHUNKS = Runtime.getRuntime().availableProcessors();\n\n    private static Map<Integer, String> stationNameMap = new ConcurrentHashMap<>(10000, 0.9f, NB_CHUNKS);\n\n    private static record Chunk(int bytesCount, MappedByteBuffer mappedByteBuffer) {\n    }\n\n    private static int reduceSizeToFitLineBreak(FileChannel channel, long startPosition, int startSize)\n            throws IOException {\n        long currentPosition = startPosition + startSize - 1;\n        int realSize = startSize;\n\n        if (currentPosition >= channel.size()) {\n            currentPosition = channel.size() - 1;\n            realSize = (int) (currentPosition - startPosition);\n        }\n\n        while (currentPosition >= startPosition) {\n            channel.position(currentPosition);\n            byte byteValue = channel.map(FileChannel.MapMode.READ_ONLY, currentPosition, 1).get();\n            if (byteValue == '\\n') {\n                // found line break\n                break;\n            }\n\n            realSize--;\n            currentPosition--;\n        }\n        return realSize;\n    }\n\n    private static List<Chunk> readChunks(int nbChunks) throws IOException {\n        RandomAccessFile file = new RandomAccessFile(FILE, \"rw\");\n        List<Chunk> res = new ArrayList<>(nbChunks);\n        FileChannel channel = file.getChannel();\n        long bytesCount = channel.size();\n        long bytesPerChunk = bytesCount / nbChunks;\n\n        // Memory map the file in read-only mode\n        // TODO: Optimize using threads\n        long currentPosition = 0;\n        int startSize;\n        int realSize;\n        for (int i = 0; i < nbChunks; i++) {\n            startSize = (int) bytesPerChunk;\n            realSize = startSize;\n\n            if (i == nbChunks - 1) {\n                realSize = (int) (bytesCount - currentPosition);\n                MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, currentPosition,\n                        realSize);\n\n                res.add(new Chunk(realSize, mappedByteBuffer));\n                break;\n            }\n\n            // Adjust size so that it ends on a newline\n            realSize = reduceSizeToFitLineBreak(channel, currentPosition, startSize);\n\n            MappedByteBuffer mappedByteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, currentPosition,\n                    realSize);\n\n            res.add(new Chunk(realSize, mappedByteBuffer));\n            currentPosition += realSize;\n        }\n\n        channel.close();\n        file.close();\n\n        return res;\n    }\n\n    private static class StationData {\n        private float sum, min, max;\n        private int count;\n\n        public StationData(float value) {\n            this.count = 1;\n            this.sum = value;\n            this.min = value;\n            this.max = value;\n        }\n\n        public void update(float value) {\n            this.count++;\n            this.sum += value;\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n        }\n\n        public float getMean() {\n            return sum / count;\n        }\n\n        public float getMin() {\n            return min;\n        }\n\n        public float getMax() {\n            return max;\n        }\n\n        public void mergeWith(StationData other) {\n            this.sum += other.sum;\n            this.count += other.count;\n            this.min = Math.min(this.min, other.min);\n            this.max = Math.max(this.max, other.max);\n        }\n\n    }\n\n    static float round(float value) {\n        return Math.round(value * 10.0f) * 0.1f;\n    }\n\n    private static class ChunkResult {\n        private Map<Integer, StationData> data;\n\n        public ChunkResult() {\n            data = new HashMap<>();\n        }\n\n        public StationData getData(int hash) {\n            return data.get(hash);\n        }\n\n        public void addStation(int hash, float value) {\n            this.data.put(hash, new StationData(value));\n        }\n\n        public void print() {\n            PrintWriter out = new PrintWriter(System.out);\n            out.println(\n                    this.data.keySet().parallelStream()\n                            .map(hash -> {\n                                var stationData = data.get(hash);\n                                var name = stationNameMap.get(hash);\n                                return String.format(\"%s=%.1f/%.1f/%.1f\", name, round(stationData.getMin()),\n                                        round(stationData.getMean()),\n                                        round(stationData.getMax()));\n                            })\n                            .sorted((a, b) -> a.split(\"=\")[0].compareTo(b.split(\"=\")[0]))\n                            .collect(Collectors.joining(\", \", \"{\", \"}\")));\n            out.flush();\n        }\n\n        public void mergeWith(ChunkResult other) {\n            for (Map.Entry<Integer, StationData> entry : other.data.entrySet()) {\n                int stationName = entry.getKey();\n                StationData otherStationData = entry.getValue();\n                StationData thisStationData = this.data.get(stationName);\n\n                if (thisStationData == null) {\n                    this.data.put(stationName, otherStationData);\n                }\n                else {\n                    thisStationData.mergeWith(otherStationData);\n                }\n            }\n        }\n    }\n\n    private static ChunkResult processChunk(Chunk chunk) {\n        ChunkResult result = new ChunkResult();\n\n        // Perform processing on the chunk data\n        byte[] data = new byte[chunk.bytesCount()];\n        chunk.mappedByteBuffer().get(data);\n\n        // Process each line\n        float value;\n        int iSplit, iEol;\n        StationData stationData;\n        int negative;\n        int hash, prime = 31;\n        Set<Integer> seenHashes = new HashSet<>(10000, 0.9f);\n        for (int offset = 0; offset < data.length; offset++) {\n            // Find station name\n            hash = 0;\n            for (iSplit = offset; data[iSplit] != ';'; iSplit++) {\n                hash = (hash << 5) - hash + (data[iSplit] & 0xFF);\n            }\n            if (!seenHashes.contains(hash)) {\n                seenHashes.add(hash);\n                stationNameMap.put(hash, new String(data, offset, iSplit - offset, StandardCharsets.UTF_8));\n            }\n\n            // Find value\n            iSplit++;\n            negative = 1;\n            value = 0;\n            for (iEol = iSplit; data[iEol] != '\\n'; iEol++) {\n                if (data[iEol] == '-') {\n                    negative = -1;\n                    continue;\n                }\n                if (data[iEol] == '.') {\n                    value = value + (data[iEol + 1] - 48) * 0.1f;\n                    iEol += 2;\n                    break;\n                }\n                value = value * 10 + data[iEol] - 48;\n            }\n            value *= negative;\n\n            // Init & count\n            stationData = result.getData(hash);\n\n            if (stationData == null) {\n                result.addStation(hash, value);\n            }\n            else {\n                stationData.update(value);\n            }\n\n            offset = iEol;\n        }\n\n        return result;\n    }\n\n    private static ChunkResult processAllChunks(List<Chunk> chunks) throws InterruptedException, ExecutionException {\n        return chunks.parallelStream().map(CalculateAverage_gnabyl::processChunk).collect(ChunkResult::new,\n                ChunkResult::mergeWith, ChunkResult::mergeWith);\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        var chunks = readChunks(NB_CHUNKS);\n        var result = processAllChunks(chunks);\n        result.print();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gnmathur.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\n\nimport static java.util.concurrent.Executors.newFixedThreadPool;\n\n/**\n * This solution uses an imperative approach. There's essentially two elements to performance tuning attempted in this\n * solution:\n * 1. Use a thread pool to process the file in chunks, setting it to the number of available processors\n * 2. Use a memory mapped file to read the file\n *\n * On an Intel(R) Core(TM) i9-10920X CPU @ 3.50GHz its taking around 38 seconds to aggregate the measurements.\n */\npublic class CalculateAverage_gnmathur {\n    private static final ExecutorService es = newFixedThreadPool(Runtime.getRuntime().availableProcessors());\n    private static final Map<String, Measurement> result = new ConcurrentHashMap<>();\n    private static final String FILE_NAME = \"measurements.txt\";\n    private static final long CHUNK_SIZE = 1024 * 1024 * 1024; // 1 GB\n\n    public static final class Measurement {\n        private double max = -5000; // impossibly low\n        private double min = 5000; // impossibly high\n        private double sum = 0;\n        private double count = 0;\n\n        public Measurement() {\n        }\n\n        public synchronized void addReading(double reading) {\n            this.min = Math.min(this.min, reading);\n            this.max = Math.max(this.max, reading);\n            this.sum += reading;\n            this.count++;\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        @Override\n        public String toString() {\n            double mean = sum / count;\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n    }\n\n    private static void updateMeasurement(String line) {\n        String[] parts = line.split(\";\");\n        String station = parts[0];\n        double measurement = Double.parseDouble(parts[1]);\n        Measurement m = null;\n        if (result.containsKey(station)) {\n            m = result.get(station);\n        }\n        else {\n            m = new Measurement();\n            result.put(station, m);\n        }\n        m.addReading(measurement);\n    }\n\n    private record FileChunkProcessor(String fileName, ExecutorService es, long start, long end) implements Runnable {\n\n    @Override\n    public void run() {\n        // Process a chunk of the file\n        try (RandomAccessFile fp = new RandomAccessFile(FILE_NAME, \"r\");\n                FileChannel fpChannel = fp.getChannel()) {\n            final MappedByteBuffer mappedByteBuffer = fpChannel.map(FileChannel.MapMode.READ_ONLY, start, end - start);\n            final ByteBuffer bb = ByteBuffer.allocate(1024);\n\n            while (mappedByteBuffer.hasRemaining()) {\n                byte b = mappedByteBuffer.get();\n                if (b == '\\n') {\n                    // We have read a line. Convert the tempBuffer to a string and process it\n                    bb.flip();\n                    String line = StandardCharsets.UTF_8.decode(bb).toString();\n                    updateMeasurement(line);\n                    bb.clear();\n                }\n                else {\n                    bb.put(b);\n                }\n            }\n            // There should be nothing in the byte buffer at this point\n            if (bb.position() > 0) {\n                throw new RuntimeException(\"byte buffer not empty\");\n            }\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    }\n\n    // We want to make sure that we don't split the data in the middle of a line. So we find the closest next\n    // newline character and adjust the end to that.\n    public static long adjustEnd(final String fileName, long end) throws IOException {\n        try (RandomAccessFile raf = new RandomAccessFile(fileName, \"r\")) {\n            raf.seek(end);\n            while (true) {\n                int read = raf.read();\n                if (read == -1 || read == '\\n') {\n                    break;\n                }\n                end++;\n            }\n        }\n        return end;\n    }\n\n    // Read the file in chunks and submit each chunk to a thread for processing\n    public static void readChunked(final String fileName, final long chunkSize) {\n        try (RandomAccessFile fp = new RandomAccessFile(fileName, \"r\")) {\n            long fileSize = fp.length();\n            long start = 0;\n\n            while (start < fileSize) {\n                long end = Math.min(start + chunkSize, fileSize);\n                end = adjustEnd(fileName, end);\n                es.submit(new FileChunkProcessor(fileName, es, start, end));\n                start = end + 1;\n            }\n            es.shutdown();\n            // Wait for all the threads to finish processing\n            es.awaitTermination(4, java.util.concurrent.TimeUnit.MINUTES);\n        }\n        catch (IOException | InterruptedException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) {\n        readChunked(FILE_NAME, CHUNK_SIZE);\n        // Print the results\n        System.out.println(new TreeMap<>(result));\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_godofwharf.java",
    "content": "package dev.morling.onebrc;\n\n/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.Vector;\nimport jdk.incubator.vector.VectorSpecies;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.management.ManagementFactory;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.function.BiConsumer;\nimport java.util.stream.IntStream;\n\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\npublic class CalculateAverage_godofwharf {\n    private static final String FILE = \"./measurements.txt\";\n    private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty(\"debug\", \"false\"));\n    private static final int NCPU = Runtime.getRuntime().availableProcessors();\n\n    private static final VectorSpecies<Byte> PREFERRED_SPECIES = VectorSpecies.ofPreferred(byte.class);\n\n    private static final Vector<Byte> NEW_LINE_VEC = PREFERRED_SPECIES.broadcast('\\n');\n    // This array is used for quick conversion of fractional part\n    private static final double[] DOUBLES = new double[]{ 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 };\n    // This array is used for quick conversion from ASCII to digit\n    private static final int[] DIGIT_LOOKUP = new int[]{\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, -1, -1, -1, -1, -1, -1, 0, 1,\n            2, 3, 4, 5, 6, 7, 8, 9, -1, -1 };\n    private static final int MAX_STR_LEN = 108;\n    private static final int DEFAULT_HASH_TBL_SIZE = 4096;\n    private static final int DEFAULT_PAGE_SIZE = 8_388_608; // 8 MB\n    private static final int PAGE_SIZE = Integer.parseInt(System.getProperty(\"pageSize\", STR.\"\\{DEFAULT_PAGE_SIZE}\"));\n\n    public static void main(String[] args) throws Exception {\n        long startTimeMs = System.currentTimeMillis();\n        Map<String, MeasurementAggregator> measurements = compute();\n        long time1 = System.nanoTime();\n        System.out.println(measurements);\n        printDebugMessage(\"Print took %d ns%n\", (System.nanoTime() - time1));\n        printDebugMessage(\"Took %d ms%n\", System.currentTimeMillis() - startTimeMs);\n        printDebugMessage(\"Time spent on GC=%d ms%n\", ManagementFactory.getGarbageCollectorMXBeans().get(0).getCollectionTime());\n        System.exit(0);\n    }\n\n    private static Map<String, MeasurementAggregator> compute() throws Exception {\n        int nThreads = Integer.parseInt(\n                System.getProperty(\"threads\", STR.\"\\{NCPU}\"));\n        printDebugMessage(\"Running program with %d threads %n\", nThreads);\n        Job job = new Job(nThreads - 1);\n        job.compute(FILE);\n        return job.sort();\n    }\n\n    public static class Job {\n        private final int nThreads;\n        private final State[] threadLocalStates;\n        private final Map<String, MeasurementAggregator> globalMap = new ConcurrentHashMap<>(DEFAULT_HASH_TBL_SIZE);\n        private final ExecutorService executorService;\n\n        public Job(final int nThreads) {\n            this.threadLocalStates = new State[(nThreads << 4)];\n            IntStream.range(0, nThreads << 4)\n                    .forEach(i -> threadLocalStates[i] = new State());\n            this.nThreads = nThreads;\n            this.executorService = Executors.newFixedThreadPool(nThreads);\n        }\n\n        public void compute(final String path) throws Exception {\n            // Create a random access file so that we can map the contents of the file into native memory for faster access\n            try (RandomAccessFile file = new RandomAccessFile(path, \"r\")) {\n                // Create a memory segment for the entire file\n                MemorySegment globalSegment = file.getChannel().map(\n                        FileChannel.MapMode.READ_ONLY, 0, file.length(), Arena.global());\n                long fileLength = file.length();\n                // Ensure that the split length never exceeds Integer.MAX_VALUE. This is because ByteBuffers cannot\n                // be larger than 2 GiB.\n                int splitLength = (int) Math.min(Integer.MAX_VALUE, Math.max(PAGE_SIZE, Math.rint(fileLength * 1.0 / nThreads)));\n                printDebugMessage(\"fileLength = %d, splitLength = %d%n\", file.length(), splitLength);\n                long time1 = System.nanoTime();\n                // Break the file into multiple splits. One thread would process one split.\n                // This routine makes sure that the splits are uniformly sized to the best extent possible.\n                // Each split would either end with a '\\n' character or EOF\n                List<Split> splits = breakFileIntoSplits(file, splitLength, PAGE_SIZE, globalSegment, false);\n                printDebugMessage(\"Number of splits = %d, splits = [%s]%n\", splits.size(), splits);\n                printDebugMessage(\"Splits calculation took %d ns%n\", System.nanoTime() - time1);\n                // consume splits in parallel using the common fork join pool\n                long time = System.nanoTime();\n                List<Future<?>> futures = new ArrayList<>(splits.size() * 2);\n                splits\n                        .forEach(split -> {\n                            // process splits concurrently using a thread pool\n                            futures.add(executorService.submit(() -> {\n                                MemorySegment splitSegment = globalSegment.asSlice(split.offset, split.length);\n                                splitSegment.load();\n                                int tid = (int) Thread.currentThread().threadId();\n                                byte[] currentPage = new byte[PAGE_SIZE + MAX_STR_LEN];\n                                // iterate over each page in split\n                                for (Page page : split.pages) {\n                                    // this byte buffer should end with '\\n' or EOF\n                                    MemorySegment segment = globalSegment.asSlice(page.offset, page.length);\n                                    MemorySegment.copy(segment, ValueLayout.JAVA_BYTE, 0L, currentPage, 0, (int) page.length);\n                                    SearchResult searchResult = findNewLinesVectorized(currentPage, (int) page.length);\n                                    int prevOffset = 0;\n                                    int j = 0;\n                                    // iterate over search results\n                                    while (j < searchResult.len) {\n                                        int curOffset = searchResult.offsets[j];\n                                        byte ch1 = currentPage[curOffset - 4];\n                                        byte ch2 = currentPage[curOffset - 5];\n                                        int temperatureLen = 5;\n                                        if (ch1 == ';') {\n                                            temperatureLen = 3;\n                                        }\n                                        else if (ch2 == ';') {\n                                            temperatureLen = 4;\n                                        }\n                                        int lineLength = curOffset - prevOffset;\n                                        int stationLen = lineLength - temperatureLen - 1;\n                                        byte[] station = new byte[stationLen];\n                                        System.arraycopy(currentPage, prevOffset, station, 0, stationLen);\n                                        int hashcode = Arrays.hashCode(station);\n                                        double temperature = NumberUtils.parseDouble2(currentPage, prevOffset + stationLen + 1, temperatureLen);\n                                        Measurement m = new Measurement(station, temperature, hashcode);\n                                        threadLocalStates[tid].update(m);\n                                        prevOffset = curOffset + 1;\n                                        j++;\n                                    }\n                                    // Explicitly commented out because unload seems to take a lot of time\n                                    // segment.unload();\n                                }\n                                mergeInternal(threadLocalStates[tid]);\n                            }));\n                        });\n                for (Future<?> future : futures) {\n                    future.get();\n                }\n                printDebugMessage(\"Aggregate took %d ns%n\", (System.nanoTime() - time));\n            }\n        }\n\n        private void mergeInternal(final State state) {\n            state.state.forEach((k, v) -> {\n                globalMap.compute(k.toString(), (ignored, agg) -> {\n                    if (agg == null) {\n                        agg = v;\n                    }\n                    else {\n                        agg.merge(v);\n                    }\n                    return agg;\n                });\n            });\n        }\n\n        public Map<String, MeasurementAggregator> sort() {\n            long time = System.nanoTime();\n            Map<String, MeasurementAggregator> sortedMap = new TreeMap<>(globalMap);\n            printDebugMessage(\"Tree map construction took %d ns%n\", (System.nanoTime() - time));\n            return sortedMap;\n        }\n\n        private static LineMetadata findNextOccurrenceOfNewLine(final ByteBuffer buffer,\n                                                                final int capacity,\n                                                                final int offset) {\n            int maxLen = capacity - offset;\n            byte[] src = new byte[Math.min(MAX_STR_LEN, maxLen)];\n            byte[] station = new byte[src.length];\n            byte[] temperature = new byte[5];\n            buffer.position(offset);\n            buffer.get(src);\n            int i = 0;\n            int j = 0;\n            int k = 0;\n            boolean isAscii = true;\n            boolean afterDelim = false;\n            int hashCode = 0;\n            for (; i < src.length; i++) {\n                byte b = src[i];\n                if (b < 0) {\n                    isAscii = false;\n                }\n                if (!afterDelim && b != '\\n') {\n                    if (b == ';') {\n                        afterDelim = true;\n                    }\n                    else {\n                        hashCode = hashCode * 31 + b;\n                        station[j++] = b;\n                    }\n                }\n                else if (b != '\\n') {\n                    temperature[k++] = b;\n                }\n                else {\n                    return new LineMetadata(\n                            station, temperature, j, k, offset + i + 1, hashCode, isAscii);\n                }\n            }\n            if (i == 0 & j == 0 && k == 0) {\n                hashCode = -1;\n            }\n            return new LineMetadata(\n                    station, temperature, j, k, offset + i, hashCode, isAscii);\n        }\n\n        private static SearchResult findNewLinesVectorized(final byte[] page,\n                                                           final int pageLen) {\n            SearchResult ret = new SearchResult(new int[pageLen / 5], 0);\n            VectorSpecies<Byte> species = PREFERRED_SPECIES;\n            int loopBound = pageLen - species.length() * 4;\n            int i = 0;\n            int j = 0;\n            while (j < loopBound) {\n                Vector<Byte> v1 = ByteVector.fromArray(species, page, j);\n                Vector<Byte> v2 = ByteVector.fromArray(species, page, j + species.length());\n                Vector<Byte> v3 = ByteVector.fromArray(species, page, j + species.length() * 2);\n                Vector<Byte> v4 = ByteVector.fromArray(species, page, j + species.length() * 3);\n                long l1 = NEW_LINE_VEC.eq(v1).toLong();\n                long l2 = NEW_LINE_VEC.eq(v2).toLong();\n                long l3 = NEW_LINE_VEC.eq(v3).toLong();\n                long l4 = NEW_LINE_VEC.eq(v4).toLong();\n                long r1 = l1 & 0xFFFFFFFFL | (l2 << species.length());\n                long r2 = l3 & 0xFFFFFFFFL | (l4 << (species.length()));\n                int b1 = Long.bitCount(r1);\n                int b2 = Long.bitCount(r2);\n                int k = i;\n                int it = b1;\n                while (it > 0) {\n                    int idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r1);\n                    ret.offsets[k++] = j + idx;\n                    r1 &= (r1 - 1);\n                    it--;\n                }\n                i += b1;\n                j += species.length() * 2;\n                k = i;\n                it = b2;\n                while (it > 0) {\n                    int idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                    idx = Long.numberOfTrailingZeros(r2);\n                    ret.offsets[k++] = j + idx;\n                    r2 &= (r2 - 1);\n                    it--;\n                }\n                i += b2;\n                j += species.length() * 2;\n            }\n\n            // tail loop\n            while (j < pageLen) {\n                byte b = page[j];\n                if (b == '\\n') {\n                    ret.offsets[i++] = j;\n                }\n                j++;\n            }\n            ret.len = i;\n            return ret;\n        }\n\n        private static List<Split> breakFileIntoSplits(final RandomAccessFile file,\n                                                       final int splitLength,\n                                                       final int pageLength,\n                                                       final MemorySegment memorySegment,\n                                                       final boolean enableChecks)\n                throws IOException {\n            final List<Split> splits = new ArrayList<>();\n            // Try to break the file into multiple splits while ensuring that each split has at least splitLength bytes\n            // and ends with '\\n' or EOF\n            for (long i = 0; i < file.length();) {\n                long splitStartOffset = i;\n                long splitEndOffset = Math.min(file.length(), splitStartOffset + splitLength); // not inclusive\n                if (splitEndOffset == file.length()) { // reached EOF\n                    List<Page> pages = breakSplitIntoPages(splitStartOffset, splitEndOffset, pageLength, memorySegment, enableChecks);\n                    splits.add(new Split(splitStartOffset, splitEndOffset - splitStartOffset, pages));\n                    break;\n                }\n                // Look past the end offset to find next '\\n' or EOF\n                long segmentLength = Math.min(MAX_STR_LEN, file.length() - i);\n                // Create a new memory segment for reading contents beyond splitEndOffset\n                MemorySegment lookahead = memorySegment.asSlice(splitEndOffset, segmentLength);\n                ByteBuffer bb = lookahead.asByteBuffer();\n                // Find the next offset which has either '\\n' or EOF\n                LineMetadata lineMetadata = findNextOccurrenceOfNewLine(bb, (int) segmentLength, 0);\n                splitEndOffset += lineMetadata.offset;\n                if (enableChecks &&\n                        memorySegment.asSlice(splitEndOffset - 1, 1).asByteBuffer().get(0) != '\\n') {\n                    throw new IllegalStateException(\"Page doesn't end with NL char\");\n                }\n                // Break the split further into multiple pages based on pageLength\n                List<Page> pages = breakSplitIntoPages(splitStartOffset, splitEndOffset, pageLength, memorySegment, enableChecks);\n                splits.add(new Split(splitStartOffset, splitEndOffset - splitStartOffset, pages));\n                i = splitEndOffset;\n                lookahead.unload();\n            }\n            return splits;\n        }\n\n        private static List<Page> breakSplitIntoPages(final long splitStartOffset,\n                                                      final long splitEndOffset,\n                                                      final int pageLength,\n                                                      final MemorySegment memorySegment,\n                                                      final boolean enableChecks) {\n            List<Page> pages = new ArrayList<>();\n            for (long i = splitStartOffset; i < splitEndOffset;) {\n                long pageStartOffset = i;\n                long pageEndOffset = Math.min(splitEndOffset, pageStartOffset + pageLength); // not inclusive\n                if (pageEndOffset == splitEndOffset) {\n                    pages.add(new Page(pageStartOffset, pageEndOffset - pageStartOffset));\n                    break;\n                }\n                // Look past the end offset to find next '\\n' till we reach the end of split\n                long lookaheadLength = Math.min(MAX_STR_LEN, splitEndOffset - i);\n                MemorySegment lookahead = memorySegment.asSlice(pageEndOffset, lookaheadLength);\n                ByteBuffer bb = lookahead.asByteBuffer();\n                // Find next offset which has either '\\n' or the end of split\n                LineMetadata lineMetadata = findNextOccurrenceOfNewLine(bb, (int) lookaheadLength, 0);\n                pageEndOffset += lineMetadata.offset;\n                if (enableChecks &&\n                        memorySegment.asSlice(pageEndOffset - 1, 1).asByteBuffer().get(0) != '\\n') {\n                    throw new IllegalStateException(\"Page doesn't end with NL char\");\n                }\n                pages.add(new Page(pageStartOffset, pageEndOffset - pageStartOffset));\n                i = pageEndOffset;\n                lookahead.unload();\n            }\n            return pages;\n        }\n    }\n\n    public static class State {\n        private final Map<AggregationKey, MeasurementAggregator> state;\n\n        public State() {\n            this.state = new HashMap<>(DEFAULT_HASH_TBL_SIZE);\n            // insert a DUMMY key to prime the hashmap for usage\n            AggregationKey dummy = new AggregationKey(\"DUMMY\".getBytes(UTF_8), -1);\n            this.state.put(dummy, null);\n            this.state.remove(dummy);\n        }\n\n        public void update(final Measurement m) {\n            MeasurementAggregator agg = state.get(m.aggregationKey);\n            if (agg == null) {\n                state.put(m.aggregationKey, new MeasurementAggregator(m.temperature, m.temperature, m.temperature, 1L));\n                return;\n            }\n            agg.count++;\n            agg.min = m.temperature <= agg.min ? m.temperature : agg.min;\n            agg.max = m.temperature >= agg.max ? m.temperature : agg.max;\n            agg.sum += m.temperature;\n        }\n\n        public static class AggregationKey {\n            private final byte[] station;\n            private final int hashCode;\n\n            public AggregationKey(final byte[] station,\n                                  final int hashCode) {\n                this.station = station;\n                this.hashCode = hashCode;\n            }\n\n            @Override\n            public String toString() {\n                return new String(station, UTF_8);\n            }\n\n            @Override\n            public int hashCode() {\n                return hashCode;\n            }\n\n            @Override\n            public boolean equals(Object other) {\n                if (!(other instanceof AggregationKey)) {\n                    return false;\n                }\n                AggregationKey sk = (AggregationKey) other;\n                return station.length == sk.station.length && Arrays.mismatch(station, sk.station) < 0;\n            }\n        }\n    }\n\n    public static class MeasurementAggregator {\n        private double min;\n        private double max;\n        private double sum;\n        private long count;\n\n        public MeasurementAggregator(final double min,\n                                     final double max,\n                                     final double sum,\n                                     final long count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n\n        public String toString() {\n            double min1 = round(min);\n            double max1 = round(max);\n            double mean = round(round(sum) / count);\n            return min1 + \"/\" + mean + \"/\" + max1;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        private void merge(final MeasurementAggregator m2) {\n            count += m2.count;\n            min = Math.min(min, m2.min);\n            max = Math.max(max, m2.max);\n            sum += m2.sum;\n        }\n    }\n\n    public static class NumberUtils {\n        public static int toDigit(final char c) {\n            return DIGIT_LOOKUP[c];\n        }\n\n        public static int fastMul10(final int i) {\n            return (i << 1) + (i << 3);\n        }\n\n        public static double parseDouble2(final byte[] b,\n                                          final int offset,\n                                          final int len) {\n            try {\n                char ch0 = (char) b[offset];\n                char ch1 = (char) b[offset + 1];\n                char ch2 = (char) b[offset + 2];\n                char ch3 = len > 3 ? (char) b[offset + 3] : ' ';\n                char ch4 = len > 4 ? (char) b[offset + 4] : ' ';\n                if (len == 3) {\n                    int decimal = toDigit(ch0);\n                    double fractional = DOUBLES[toDigit(ch2)];\n                    return decimal + fractional;\n                }\n                else if (len == 4) {\n                    // -1.2 or 11.2\n                    int decimal = (ch0 == '-' ? toDigit(ch1) : (fastMul10(toDigit(ch0)) + toDigit(ch1)));\n                    double fractional = DOUBLES[toDigit(ch3)];\n                    if (ch0 == '-') {\n                        return Math.negateExact(decimal) - fractional;\n                    }\n                    else {\n                        return decimal + fractional;\n                    }\n                }\n                else {\n                    int decimal = fastMul10(toDigit(ch1)) + toDigit(ch2);\n                    double fractional = DOUBLES[toDigit(ch4)];\n                    return Math.negateExact(decimal) - fractional;\n                }\n            }\n            catch (ArrayIndexOutOfBoundsException e) {\n                printDebugMessage(\"Array index out of bounds for string: %s%n\", new String(b, 0, len));\n                throw new RuntimeException(e);\n            }\n            catch (StringIndexOutOfBoundsException e) {\n                printDebugMessage(\"String index out of bounds for string: %s%n\", new String(b, 0, len));\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    // record classes\n    record Measurement(byte[] station,\n                       double temperature,\n                       int hash,\n                       State.AggregationKey aggregationKey) {\n\n    public Measurement(byte[] station,\n                       double temperature,\n                       int hashCode) {\n            this(station,\n                    temperature,\n                    hashCode,\n                    new State.AggregationKey(station, hashCode));\n        }\n\n    }\n\n    record LineMetadata(byte[] station,\n                        byte[] temperature,\n                        int stationLen,\n                        int temperatureLen,\n                        int offset,\n                        int precomputedHashCode, boolean isAscii) {\n    }\n\n    record Split(long offset, long length, List<Page> pages) {\n    }\n\n    record Page(long offset, long length) {\n    }\n\n    public static class SearchResult {\n        private int[] offsets;\n        private int len;\n\n        public SearchResult(final int[] offsets,\n                            final int len) {\n            this.offsets = offsets;\n            this.len = len;\n        }\n    }\n\n    private static void printDebugMessage(final String message,\n                                          final Object... args) {\n        if (DEBUG) {\n            System.err.printf(message, args);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gonix.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_gonix {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n\n        var file = new RandomAccessFile(FILE, \"r\");\n\n        var res = buildChunks(file).stream().parallel()\n                .flatMap(chunk -> new Aggregator().processChunk(chunk).stream())\n                .collect(Collectors.toMap(\n                        Aggregator.Entry::getKey,\n                        Aggregator.Entry::getValue,\n                        Aggregator.Entry::add,\n                        TreeMap::new));\n\n        System.out.println(res);\n        System.out.close();\n    }\n\n    private static List<MappedByteBuffer> buildChunks(RandomAccessFile file) throws IOException {\n        var fileSize = file.length();\n        var chunkSize = Math.min(Integer.MAX_VALUE - 512, fileSize / Runtime.getRuntime().availableProcessors());\n        if (chunkSize <= 0) {\n            chunkSize = fileSize;\n        }\n        var chunks = new ArrayList<MappedByteBuffer>((int) (fileSize / chunkSize) + 1);\n        var start = 0L;\n        while (start < fileSize) {\n            var pos = start + chunkSize;\n            if (pos < fileSize) {\n                file.seek(pos);\n                while (file.read() != '\\n') {\n                    pos += 1;\n                }\n                pos += 1;\n            }\n            else {\n                pos = fileSize;\n            }\n            var buf = file.getChannel().map(FileChannel.MapMode.READ_ONLY, start, pos - start);\n            buf.order(ByteOrder.nativeOrder());\n            chunks.add(buf);\n            start = pos;\n        }\n        return chunks;\n    }\n\n    private static class Aggregator {\n        private static final int MAX_STATIONS = 10_000;\n        private static final int MAX_STATION_SIZE = Math.ceilDiv(100, 8) + 5;\n        private static final int INDEX_SIZE = 1024 * 1024;\n        private static final int INDEX_MASK = INDEX_SIZE - 1;\n        private static final int FLD_COUNT = 0;\n        private static final int FLD_SUM = 1;\n        private static final int FLD_MIN = 2;\n        private static final int FLD_MAX = 3;\n\n        // Poor man's hash map: hash code to offset in `mem`.\n        private final int[] index;\n\n        // Contiguous storage of key (station name) and stats fields of all\n        // unique stations.\n        // The idea here is to improve locality so that stats fields would\n        // possibly be already in the CPU cache after we are done comparing\n        // the key.\n        private final long[] mem;\n        private int memUsed;\n\n        Aggregator() {\n            assert ((INDEX_SIZE & (INDEX_SIZE - 1)) == 0) : \"INDEX_SIZE must be power of 2\";\n            assert (INDEX_SIZE > MAX_STATIONS) : \"INDEX_SIZE must be greater than MAX_STATIONS\";\n\n            index = new int[INDEX_SIZE];\n            mem = new long[1 + (MAX_STATIONS * MAX_STATION_SIZE)];\n            memUsed = 1;\n        }\n\n        Aggregator processChunk(MappedByteBuffer buf) {\n            // To avoid checking if it is safe to read a whole long near the\n            // end of a chunk, we copy last couple of lines to a padded buffer\n            // and process that part separately.\n            int limit = buf.limit();\n            int pos = Math.max(limit - 16, -1);\n            while (pos >= 0 && buf.get(pos) != '\\n') {\n                pos--;\n            }\n            pos++;\n            if (pos > 0) {\n                processChunkLongs(buf, pos);\n            }\n            int tailLen = limit - pos;\n            var tailBuf = ByteBuffer.allocate(tailLen + 8).order(ByteOrder.nativeOrder());\n            buf.get(pos, tailBuf.array(), 0, tailLen);\n            processChunkLongs(tailBuf, tailLen);\n            return this;\n        }\n\n        Aggregator processChunkLongs(ByteBuffer buf, int limit) {\n            int pos = 0;\n            while (pos < limit) {\n\n                int start = pos;\n                long keyLong = buf.getLong(pos);\n                long valueSepMark = valueSepMark(keyLong);\n                if (valueSepMark != 0) {\n                    int tailBits = tailBits(valueSepMark);\n                    pos += valueOffset(tailBits);\n                    // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (1), pos=\" + (pos - startAddr);\n                    long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n\n                    long valueLong = buf.getLong(pos);\n                    int decimalSepMark = decimalSepMark(valueLong);\n                    pos += nextKeyOffset(decimalSepMark);\n                    // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (1), pos=\" + (pos - startAddr);\n                    int measurement = decimalValue(decimalSepMark, valueLong);\n\n                    add1(buf, start, tailAndLen, hash(hash1(tailAndLen)), measurement);\n                    continue;\n                }\n\n                pos += 8;\n                long keyLong1 = keyLong;\n                keyLong = buf.getLong(pos);\n                valueSepMark = valueSepMark(keyLong);\n                if (valueSepMark != 0) {\n                    int tailBits = tailBits(valueSepMark);\n                    pos += valueOffset(tailBits);\n                    // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (2), pos=\" + (pos - startAddr);\n                    long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n\n                    long valueLong = buf.getLong(pos);\n                    int decimalSepMark = decimalSepMark(valueLong);\n                    pos += nextKeyOffset(decimalSepMark);\n                    // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (2), pos=\" + (pos - startAddr);\n                    int measurement = decimalValue(decimalSepMark, valueLong);\n\n                    add2(buf, start, keyLong1, tailAndLen, hash(hash(hash1(keyLong1), tailAndLen)), measurement);\n                    continue;\n                }\n\n                long hash = hash1(keyLong1);\n                do {\n                    pos += 8;\n                    hash = hash(hash, keyLong);\n                    keyLong = buf.getLong(pos);\n                    valueSepMark = valueSepMark(keyLong);\n                } while (valueSepMark == 0);\n                int tailBits = tailBits(valueSepMark);\n                pos += valueOffset(tailBits);\n                // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (N), pos=\" + (pos - startAddr);\n                long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n                hash = hash(hash, tailAndLen);\n\n                long valueLong = buf.getLong(pos);\n                int decimalSepMark = decimalSepMark(valueLong);\n                pos += nextKeyOffset(decimalSepMark);\n                // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (N), pos=\" + (pos - startAddr);\n                int measurement = decimalValue(decimalSepMark, valueLong);\n\n                addN(buf, start, tailAndLen, hash(hash), measurement);\n            }\n\n            return this;\n        }\n\n        public Stream<Entry> stream() {\n            return Arrays.stream(index)\n                    .filter(offset -> offset != 0)\n                    .mapToObj(offset -> new Entry(mem, offset));\n        }\n\n        private static long hash1(long value) {\n            return value;\n        }\n\n        private static long hash(long hash, long value) {\n            return hash ^ value;\n        }\n\n        private static int hash(long hash) {\n            hash *= 0x9E3779B97F4A7C15L; // Fibonacci hashing multiplier\n            return (int) (hash >>> 39);\n        }\n\n        private static long valueSepMark(long keyLong) {\n            // Seen this trick used in multiple other solutions.\n            // Nice breakdown here: https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord\n            long match = keyLong ^ 0x3B3B3B3B_3B3B3B3BL; // 3B == ';'\n            match = (match - 0x01010101_01010101L) & (~match & 0x80808080_80808080L);\n            return match;\n        }\n\n        private static int tailBits(long valueSepMark) {\n            return Long.numberOfTrailingZeros(valueSepMark >>> 7);\n        }\n\n        private static int valueOffset(int tailBits) {\n            return (int) (tailBits >>> 3) + 1;\n        }\n\n        private static long tailAndLen(int tailBits, long keyLong, long keyLen) {\n            long tailMask = ~(-1L << tailBits);\n            long tail = keyLong & tailMask;\n            return (tail << 8) | ((keyLen >> 3) & 0xFF);\n        }\n\n        private static int decimalSepMark(long value) {\n            // Seen this trick used in multiple other solutions.\n            // Looks like the original author is @merykitty.\n\n            // The 4th binary digit of the ascii of a digit is 1 while\n            // that of the '.' is 0. This finds the decimal separator\n            // The value can be 12, 20, 28\n            return Long.numberOfTrailingZeros(~value & 0x10101000);\n        }\n\n        private static int decimalValue(int decimalSepMark, long value) {\n            // Seen this trick used in multiple other solutions.\n            // Looks like the original author is @merykitty.\n\n            int shift = 28 - decimalSepMark;\n            // signed is -1 if negative, 0 otherwise\n            long signed = (~value << 59) >> 63;\n            long designMask = ~(signed & 0xFF);\n            // Align the number to a specific position and transform the ascii code\n            // to actual digit value in each byte\n            long digits = ((value & designMask) << shift) & 0x0F000F0F00L;\n\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 +\n            // 0x00UU00TTHH000000 * 10 +\n            // 0xUU00TTHH00000000 * 100\n            // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n            // This results in our value lies in the bit 32 to 41 of this product\n            // That was close :)\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            return (int) ((absValue ^ signed) - signed);\n        }\n\n        private static int nextKeyOffset(int decimalSepMark) {\n            return (decimalSepMark >>> 3) + 3;\n        }\n\n        private void add1(ByteBuffer buf, int start, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (; index[idx] != 0; idx = (idx + 1) & INDEX_MASK) {\n                if (update1(index[idx], tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            index[idx] = create(buf, start, tailAndLen, measurement);\n        }\n\n        private void add2(ByteBuffer buf, int start, long keyLong, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (; index[idx] != 0; idx = (idx + 1) & INDEX_MASK) {\n                if (update2(index[idx], keyLong, tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            index[idx] = create(buf, start, tailAndLen, measurement);\n        }\n\n        private void addN(ByteBuffer buf, int start, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (; index[idx] != 0; idx = (idx + 1) & INDEX_MASK) {\n                if (updateN(index[idx], buf, start, tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            index[idx] = create(buf, start, tailAndLen, measurement);\n        }\n\n        private int create(ByteBuffer buf, int start, long tailAndLen, int measurement) {\n            int offset = memUsed;\n\n            mem[offset] = tailAndLen;\n\n            int memPos = offset + 1;\n            int memEnd = memPos + (int) (tailAndLen & 0xFF);\n            int bufPos = start;\n            while (memPos < memEnd) {\n                mem[memPos] = buf.getLong(bufPos);\n                memPos += 1;\n                bufPos += 8;\n            }\n\n            mem[memPos + FLD_MIN] = measurement;\n            mem[memPos + FLD_MAX] = measurement;\n            mem[memPos + FLD_SUM] = measurement;\n            mem[memPos + FLD_COUNT] = 1;\n            memUsed = memPos + 4;\n\n            return offset;\n        }\n\n        private boolean update1(int offset, long tailAndLen, int measurement) {\n            if (mem[offset] != tailAndLen) {\n                return false;\n            }\n            updateStats(offset + 1, measurement);\n            return true;\n        }\n\n        private boolean update2(int offset, long keyLong, long tailAndLen, int measurement) {\n            if (mem[offset] != tailAndLen || mem[offset + 1] != keyLong) {\n                return false;\n            }\n            updateStats(offset + 2, measurement);\n            return true;\n        }\n\n        private boolean updateN(int offset, ByteBuffer buf, int start, long tailAndLen, int measurement) {\n            var mem = this.mem;\n            if (mem[offset] != tailAndLen) {\n                return false;\n            }\n            int memPos = offset + 1;\n            int memEnd = memPos + (int) (tailAndLen & 0xFF);\n            int bufPos = start;\n            while (memPos < memEnd) {\n                if (mem[memPos] != buf.getLong(bufPos)) {\n                    return false;\n                }\n                memPos += 1;\n                bufPos += 8;\n            }\n            updateStats(memPos, measurement);\n            return true;\n        }\n\n        private void updateStats(int memPos, int measurement) {\n            mem[memPos + FLD_COUNT] += 1;\n            mem[memPos + FLD_SUM] += measurement;\n            if (measurement < mem[memPos + FLD_MIN]) {\n                mem[memPos + FLD_MIN] = measurement;\n            }\n            if (measurement > mem[memPos + FLD_MAX]) {\n                mem[memPos + FLD_MAX] = measurement;\n            }\n        }\n\n        public static class Entry {\n            private final long[] mem;\n            private final int offset;\n            private String key;\n\n            Entry(long[] mem, int offset) {\n                this.mem = mem;\n                this.offset = offset;\n            }\n\n            public String getKey() {\n                if (key == null) {\n                    int pos = this.offset;\n                    long tailAndLen = mem[pos++];\n                    int keyLen = (int) (tailAndLen & 0xFF);\n                    var tmpBuf = ByteBuffer.allocate((keyLen << 3) + 8).order(ByteOrder.nativeOrder());\n                    for (int i = 0; i < keyLen; i++) {\n                        tmpBuf.putLong(mem[pos++]);\n                    }\n                    long tail = tailAndLen >>> 8;\n                    tmpBuf.putLong(tail);\n                    int keyLenBytes = (keyLen << 3) + 8 - (Long.numberOfLeadingZeros(tail) >> 3);\n                    key = new String(tmpBuf.array(), 0, keyLenBytes, StandardCharsets.UTF_8);\n                }\n                return key;\n            }\n\n            public Entry add(Entry other) {\n                int fldOffset = (int) (mem[offset] & 0xFF) + 1;\n                int pos = offset + fldOffset;\n                int otherPos = other.offset + fldOffset;\n                long[] otherMem = other.mem;\n                mem[pos + FLD_MIN] = Math.min((int) mem[pos + FLD_MIN], (int) otherMem[otherPos + FLD_MIN]);\n                mem[pos + FLD_MAX] = Math.max((int) mem[pos + FLD_MAX], (int) otherMem[otherPos + FLD_MAX]);\n                mem[pos + FLD_SUM] += otherMem[otherPos + FLD_SUM];\n                mem[pos + FLD_COUNT] += otherMem[otherPos + FLD_COUNT];\n                return this;\n            }\n\n            public Entry getValue() {\n                return this;\n            }\n\n            @Override\n            public String toString() {\n                int pos = offset + (int) (mem[offset] & 0xFF) + 1;\n                return round(mem[pos + FLD_MIN])\n                        + \"/\" + round(((double) mem[pos + FLD_SUM]) / mem[pos + FLD_COUNT])\n                        + \"/\" + round(mem[pos + FLD_MAX]);\n            }\n\n            private static double round(double value) {\n                return Math.round(value) / 10.0;\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_gonixunsafe.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport sun.misc.Unsafe;\n\npublic class CalculateAverage_gonixunsafe {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MAX_THREADS = Runtime.getRuntime().availableProcessors();\n\n    public static void main(String[] args) throws Exception {\n\n        var file = new RandomAccessFile(FILE, \"r\");\n\n        var chunks = Aggregator.buildChunks(file, MAX_THREADS);\n        var chunksCount = chunks.size();\n        var threads = new Thread[chunksCount];\n        var result = new AtomicReference<Aggregator>();\n        for (int i = 0; i < chunksCount; ++i) {\n            var agg = new Aggregator();\n            var chunk = chunks.get(i);\n            var thread = new Thread(() -> {\n                agg.processChunk(chunk);\n                while (!result.compareAndSet(null, agg)) {\n                    Aggregator other = result.getAndSet(null);\n                    if (other != null) {\n                        agg.merge(other);\n                    }\n                }\n            });\n            thread.start();\n            threads[i] = thread;\n        }\n        for (int i = 0; i < chunksCount; ++i) {\n            threads[i].join();\n        }\n        System.out.println(result.get().toString());\n        System.out.close();\n    }\n\n    private static class Aggregator {\n        private static final int MAX_STATIONS = 10_000;\n        private static final int INDEX_SIZE = 256 * 1024 * 8;\n        private static final int INDEX_MASK = (INDEX_SIZE - 1) & ~7;\n\n        private static final int HEADER_SIZE = 8;\n        private static final int MAX_KEY_SIZE = 100;\n        private static final int FLD_COUNT = 0; // long\n        private static final int FLD_SUM = 8; // long\n        private static final int FLD_MIN = 16; // int\n        private static final int FLD_MAX = 20; // int\n        private static final int FLD_HASH = 24; // int\n        private static final int FIELDS_SIZE = 28 + 4; // +padding to align to 8 bytes\n        private static final int MAX_STATION_SIZE = HEADER_SIZE + MAX_KEY_SIZE + FIELDS_SIZE;\n\n        private static final Unsafe UNSAFE;\n\n        static {\n            try {\n                Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n                unsafe.setAccessible(true);\n                UNSAFE = (Unsafe) unsafe.get(Unsafe.class);\n            }\n            catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        private static long alloc(long size) {\n            long addr = UNSAFE.allocateMemory(size);\n            UNSAFE.setMemory(addr, size, (byte) 0);\n            return addr;\n        }\n\n        // Poor man's hash map: hash code to offset in `mem`.\n        private final long indexAddr = alloc(INDEX_SIZE);\n\n        // Contiguous storage of key (station name) and stats fields of all\n        // unique stations.\n        // The idea here is to improve locality so that stats fields would\n        // possibly be already in the CPU cache after we are done comparing\n        // the key.\n        private final long memAddr = alloc(MAX_STATIONS * MAX_STATION_SIZE);\n        private long memUsed = memAddr;\n        private int count = 0;\n\n        static List<Chunk> buildChunks(RandomAccessFile file, int count) throws IOException {\n            var fileSize = file.length();\n            var chunkSize = Math.min(Integer.MAX_VALUE - 512, fileSize / count);\n            if (chunkSize <= 0) {\n                chunkSize = fileSize;\n            }\n            var chunks = new ArrayList<Chunk>((int) (fileSize / chunkSize) + 1);\n            var mmap = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n            var fileStartAddr = mmap.address();\n            var fileEndAddr = mmap.address() + mmap.byteSize();\n            var chunkStartAddr = fileStartAddr;\n            while (chunkStartAddr < fileEndAddr) {\n                var pos = chunkStartAddr + chunkSize;\n                if (pos < fileEndAddr) {\n                    while (UNSAFE.getByte(pos) != '\\n') {\n                        pos += 1;\n                    }\n                    pos += 1;\n                }\n                else {\n                    pos = fileEndAddr;\n                }\n                chunks.add(new Chunk(mmap, chunkStartAddr, pos, fileStartAddr, fileEndAddr));\n                chunkStartAddr = pos;\n            }\n            return chunks;\n        }\n\n        Aggregator processChunk(Chunk chunk) {\n            // As an optimization, we assume that we can read past the end\n            // of file size if as we don't cross page boundary.\n            final int WANT_PADDING = 8;\n            final int PAGE_SIZE = UNSAFE.pageSize();\n            if (((chunk.chunkEndAddr + WANT_PADDING) / PAGE_SIZE) <= (chunk.fileEndAddr / PAGE_SIZE)) {\n                return processChunk(chunk.chunkStartAddr, chunk.chunkEndAddr);\n            }\n\n            // Otherwise, to avoid checking if it is safe to read a whole long\n            // near the end of a chunk, we copy the last couple of lines to a\n            // padded buffer and process that part separately.\n            long pos = Math.max(-1, chunk.chunkEndAddr - WANT_PADDING - 1);\n            while (pos >= 0 && UNSAFE.getByte(pos) != '\\n') {\n                pos--;\n            }\n            pos++;\n            if (pos > 0) {\n                processChunk(chunk.chunkStartAddr, pos);\n            }\n            long tailLen = chunk.chunkEndAddr - pos;\n            var tailAddr = alloc(tailLen + WANT_PADDING);\n            UNSAFE.copyMemory(pos, tailAddr, tailLen);\n            processChunk(tailAddr, tailAddr + tailLen);\n            return this;\n        }\n\n        private Aggregator processChunk(long startAddr, long endAddr) {\n            long pos = startAddr;\n            while (pos < endAddr) {\n\n                long start = pos;\n                long keyLong = UNSAFE.getLong(pos);\n                long valueSepMark = valueSepMark(keyLong);\n                if (valueSepMark != 0) {\n                    int tailBits = tailBits(valueSepMark);\n                    pos += valueOffset(tailBits);\n                    // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (1), pos=\" + (pos - startAddr);\n                    long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n\n                    long valueLong = UNSAFE.getLong(pos);\n                    int decimalSepMark = decimalSepMark(valueLong);\n                    pos += nextKeyOffset(decimalSepMark);\n                    // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (1), pos=\" + (pos - startAddr);\n                    int measurement = decimalValue(decimalSepMark, valueLong);\n\n                    add1(start, tailAndLen, hash(hash1(tailAndLen)), measurement);\n                    continue;\n                }\n\n                pos += 8;\n                long keyLong1 = keyLong;\n                keyLong = UNSAFE.getLong(pos);\n                valueSepMark = valueSepMark(keyLong);\n                if (valueSepMark != 0) {\n                    int tailBits = tailBits(valueSepMark);\n                    pos += valueOffset(tailBits);\n                    // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (2), pos=\" + (pos - startAddr);\n                    long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n\n                    long valueLong = UNSAFE.getLong(pos);\n                    int decimalSepMark = decimalSepMark(valueLong);\n                    pos += nextKeyOffset(decimalSepMark);\n                    // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (2), pos=\" + (pos - startAddr);\n                    int measurement = decimalValue(decimalSepMark, valueLong);\n\n                    add2(start, keyLong1, tailAndLen, hash(hash(hash1(keyLong1), tailAndLen)), measurement);\n                    continue;\n                }\n\n                long hash = hash1(keyLong1);\n                do {\n                    pos += 8;\n                    hash = hash(hash, keyLong);\n                    keyLong = UNSAFE.getLong(pos);\n                    valueSepMark = valueSepMark(keyLong);\n                } while (valueSepMark == 0);\n                int tailBits = tailBits(valueSepMark);\n                pos += valueOffset(tailBits);\n                // assert (UNSAFE.getByte(pos - 1) == ';') : \"Expected ';' (N), pos=\" + (pos - startAddr);\n                long tailAndLen = tailAndLen(tailBits, keyLong, pos - start - 1);\n                hash = hash(hash, tailAndLen);\n\n                long valueLong = UNSAFE.getLong(pos);\n                int decimalSepMark = decimalSepMark(valueLong);\n                pos += nextKeyOffset(decimalSepMark);\n                // assert (UNSAFE.getByte(pos - 1) == '\\n') : \"Expected '\\\\n' (N), pos=\" + (pos - startAddr);\n                int measurement = decimalValue(decimalSepMark, valueLong);\n\n                addN(start, tailAndLen, hash(hash), measurement);\n            }\n\n            return this;\n        }\n\n        private static long hash1(long value) {\n            return value;\n        }\n\n        private static long hash(long hash, long value) {\n            return hash ^ value;\n        }\n\n        private static int hash(long hash) {\n            hash *= 0x9E3779B97F4A7C15L; // Fibonacci hashing multiplier\n            return (int) (hash >>> 39);\n        }\n\n        private static long valueSepMark(long keyLong) {\n            // Seen this trick used in multiple other solutions.\n            // Nice breakdown here: https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord\n            long match = keyLong ^ 0x3B3B3B3B_3B3B3B3BL; // 3B == ';'\n            match = (match - 0x01010101_01010101L) & (~match & 0x80808080_80808080L);\n            return match;\n        }\n\n        private static int tailBits(long valueSepMark) {\n            return Long.numberOfTrailingZeros(valueSepMark >>> 7);\n        }\n\n        private static int valueOffset(int tailBits) {\n            return (int) (tailBits >>> 3) + 1;\n        }\n\n        private static long tailAndLen(int tailBits, long keyLong, long keyLen) {\n            long tailMask = ~(-1L << tailBits);\n            long tail = keyLong & tailMask;\n            return (tail << 8) | (keyLen & 0xFF);\n        }\n\n        private static int decimalSepMark(long value) {\n            // Seen this trick used in multiple other solutions.\n            // Looks like the original author is @merykitty.\n\n            // The 4th binary digit of the ascii of a digit is 1 while\n            // that of the '.' is 0. This finds the decimal separator\n            // The value can be 12, 20, 28\n            return Long.numberOfTrailingZeros(~value & 0x10101000);\n        }\n\n        private static int decimalValue(int decimalSepMark, long value) {\n            // Seen this trick used in multiple other solutions.\n            // Looks like the original author is @merykitty.\n\n            int shift = 28 - decimalSepMark;\n            // signed is -1 if negative, 0 otherwise\n            long signed = (~value << 59) >> 63;\n            long designMask = ~(signed & 0xFF);\n            // Align the number to a specific position and transform the ascii code\n            // to actual digit value in each byte\n            long digits = ((value & designMask) << shift) & 0x0F000F0F00L;\n\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 +\n            // 0x00UU00TTHH000000 * 10 +\n            // 0xUU00TTHH00000000 * 100\n            // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n            // This results in our value lies in the bit 32 to 41 of this product\n            // That was close :)\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            return (int) ((absValue ^ signed) - signed);\n        }\n\n        private static int nextKeyOffset(int decimalSepMark) {\n            return (decimalSepMark >>> 3) + 3;\n        }\n\n        private void add1(long keyStartAddr, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (long entryAddr; (entryAddr = UNSAFE.getLong(indexAddr + idx)) != 0; idx = (idx + 8) & INDEX_MASK) {\n                if (update1(entryAddr, tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            UNSAFE.putLong(indexAddr + idx, create(keyStartAddr, tailAndLen, hash, measurement, '1'));\n        }\n\n        private void add2(long keyStartAddr, long keyLong, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (long entryAddr; (entryAddr = UNSAFE.getLong(indexAddr + idx)) != 0; idx = (idx + 8) & INDEX_MASK) {\n                if (update2(entryAddr, keyLong, tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            UNSAFE.putLong(indexAddr + idx, create(keyStartAddr, tailAndLen, hash, measurement, '2'));\n        }\n\n        private void addN(long keyStartAddr, long tailAndLen, int hash, int measurement) {\n            int idx = hash & INDEX_MASK;\n            for (long entryAddr; (entryAddr = UNSAFE.getLong(indexAddr + idx)) != 0; idx = (idx + 8) & INDEX_MASK) {\n                if (updateN(entryAddr, keyStartAddr, tailAndLen, measurement)) {\n                    return;\n                }\n            }\n            UNSAFE.putLong(indexAddr + idx, create(keyStartAddr, tailAndLen, hash, measurement, 'N'));\n        }\n\n        private long create(long keyStartAddr, long tailAndLen, int hash, int measurement, char _origin) {\n            // assert (memUsed + MAX_STATION_SIZE < memAddr + MAX_STATION_SIZE * MAX_STATIONS) : \"Too many stations\";\n\n            final long entryAddr = memUsed;\n\n            int keySize = (int) (tailAndLen & 0xF8);\n            long fieldsAddr = entryAddr + HEADER_SIZE + keySize;\n            memUsed += HEADER_SIZE + keySize + FIELDS_SIZE;\n            count++;\n\n            UNSAFE.putLong(entryAddr, tailAndLen);\n            UNSAFE.copyMemory(keyStartAddr, entryAddr + HEADER_SIZE, keySize);\n            UNSAFE.putLong(fieldsAddr + FLD_COUNT, 1);\n            UNSAFE.putLong(fieldsAddr + FLD_SUM, measurement);\n            UNSAFE.putInt(fieldsAddr + FLD_MIN, measurement);\n            UNSAFE.putInt(fieldsAddr + FLD_MAX, measurement);\n            UNSAFE.putInt(fieldsAddr + FLD_HASH, hash);\n\n            return entryAddr;\n        }\n\n        private static boolean update1(long entryAddr, long tailAndLen, int measurement) {\n            if (UNSAFE.getLong(entryAddr) != tailAndLen) {\n                return false;\n            }\n\n            updateStats(entryAddr + HEADER_SIZE, measurement);\n            return true;\n        }\n\n        private static boolean update2(long entryAddr, long keyLong, long tailAndLen, int measurement) {\n            if (UNSAFE.getLong(entryAddr) != tailAndLen) {\n                return false;\n            }\n            if (UNSAFE.getLong(entryAddr + 8) != keyLong) {\n                return false;\n            }\n\n            updateStats(entryAddr + HEADER_SIZE + 8, measurement);\n            return true;\n        }\n\n        private static boolean updateN(long entryAddr, long keyStartAddr, long tailAndLen, int measurement) {\n            if (UNSAFE.getLong(entryAddr) != tailAndLen) {\n                return false;\n            }\n            long memPos = entryAddr + HEADER_SIZE;\n            long memEnd = memPos + ((int) (tailAndLen & 0xF8));\n            long bufPos = keyStartAddr;\n            while (memPos != memEnd) {\n                if (UNSAFE.getLong(memPos) != UNSAFE.getLong(bufPos)) {\n                    return false;\n                }\n                memPos += 8;\n                bufPos += 8;\n            }\n\n            updateStats(memPos, measurement);\n            return true;\n        }\n\n        private static void updateStats(long addr, int measurement) {\n            long oldCount = UNSAFE.getLong(addr + FLD_COUNT);\n            long oldSum = UNSAFE.getLong(addr + FLD_SUM);\n            long oldMin = UNSAFE.getInt(addr + FLD_MIN);\n            long oldMax = UNSAFE.getInt(addr + FLD_MAX);\n\n            UNSAFE.putLong(addr + FLD_COUNT, oldCount + 1);\n            UNSAFE.putLong(addr + FLD_SUM, oldSum + measurement);\n            if (measurement < oldMin) {\n                UNSAFE.putInt(addr + FLD_MIN, measurement);\n            }\n            if (measurement > oldMax) {\n                UNSAFE.putInt(addr + FLD_MAX, measurement);\n            }\n        }\n\n        private static void updateStats(long addr, long count, long sum, int min, int max) {\n            long oldCount = UNSAFE.getLong(addr + FLD_COUNT);\n            long oldSum = UNSAFE.getLong(addr + FLD_SUM);\n            long oldMin = UNSAFE.getInt(addr + FLD_MIN);\n            long oldMax = UNSAFE.getInt(addr + FLD_MAX);\n\n            UNSAFE.putLong(addr + FLD_COUNT, oldCount + count);\n            UNSAFE.putLong(addr + FLD_SUM, oldSum + sum);\n            if (min < oldMin) {\n                UNSAFE.putInt(addr + FLD_MIN, min);\n            }\n            if (max > oldMax) {\n                UNSAFE.putInt(addr + FLD_MAX, max);\n            }\n        }\n\n        public Aggregator merge(Aggregator other) {\n            var otherMemPos = other.memAddr;\n            var otherMemEnd = other.memUsed;\n            merge: for (long entrySize; otherMemPos < otherMemEnd; otherMemPos += entrySize) {\n                int keySize = (int) (UNSAFE.getLong(otherMemPos) & 0xF8);\n                long otherKeyEnd = otherMemPos + HEADER_SIZE + keySize;\n                entrySize = HEADER_SIZE + keySize + FIELDS_SIZE;\n                int hash = UNSAFE.getInt(otherKeyEnd + FLD_HASH);\n                int idx = hash & INDEX_MASK;\n                search: for (long entryAddr; (entryAddr = UNSAFE.getLong(indexAddr + idx)) != 0; idx = (idx + 8) & INDEX_MASK) {\n                    var thisPos = entryAddr;\n                    var otherPos = otherMemPos;\n                    while (otherPos < otherKeyEnd) {\n                        if (UNSAFE.getLong(thisPos) != UNSAFE.getLong(otherPos)) {\n                            continue search;\n                        }\n                        thisPos += 8;\n                        otherPos += 8;\n                    }\n                    updateStats(\n                            thisPos,\n                            UNSAFE.getLong(otherPos + FLD_COUNT),\n                            UNSAFE.getLong(otherPos + FLD_SUM),\n                            UNSAFE.getInt(otherPos + FLD_MIN),\n                            UNSAFE.getInt(otherPos + FLD_MAX));\n                    continue merge;\n                }\n\n                // create\n                // assert (memUsed + MAX_STATION_SIZE < memAddr + MAX_STATION_SIZE * MAX_STATIONS) : \"Too many stations (merge)\";\n                long entryAddr = memUsed;\n                memUsed += entrySize;\n                count++;\n                UNSAFE.copyMemory(otherMemPos, entryAddr, entrySize);\n                UNSAFE.putLong(indexAddr + idx, entryAddr);\n            }\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            if (count == 0) {\n                return \"{}\";\n            }\n            var entries = new Entry[count];\n            int i = 0;\n            for (long pos = memAddr; pos < memUsed; pos += (int) (UNSAFE.getLong(pos) & 0xF8) + HEADER_SIZE + FIELDS_SIZE) {\n                entries[i++] = new Entry(pos);\n            }\n            Arrays.sort(entries);\n            var sb = new StringBuilder(count * 50);\n            sb.append('{');\n            entries[0].appendTo(sb);\n            for (int j = 1; j < entries.length; ++j) {\n                sb.append(\", \");\n                entries[j].appendTo(sb);\n            }\n            sb.append('}');\n            return sb.toString();\n        }\n\n        static class Chunk {\n            final MemorySegment file;\n            final long chunkStartAddr;\n            final long chunkEndAddr;\n            final long fileStartAddr;\n            final long fileEndAddr;\n\n            Chunk(MemorySegment file, long chunkStartAddr, long chunkEndAddr, long fileStartAddr, long fileEndAddr) {\n                this.file = file;\n                this.chunkStartAddr = chunkStartAddr;\n                this.chunkEndAddr = chunkEndAddr;\n                this.fileStartAddr = fileStartAddr;\n                this.fileEndAddr = fileEndAddr;\n            }\n        }\n\n        static class Entry implements Comparable<Entry> {\n            private final long entryAddr;\n            private final int keySize;\n            private final String key;\n\n            Entry(long entryAddr) {\n                this.entryAddr = entryAddr;\n                this.keySize = (int) UNSAFE.getLong(entryAddr) & 0xF8;\n                try (var arena = Arena.ofConfined()) {\n                    var ms = arena.allocate(keySize + 8);\n                    UNSAFE.copyMemory(entryAddr + HEADER_SIZE, ms.address(), keySize);\n                    UNSAFE.copyMemory(entryAddr + 1, ms.address() + keySize, 7);\n                    this.key = ms.getUtf8String(0);\n                }\n            }\n\n            @Override\n            public int compareTo(Entry other) {\n                return key.compareTo(other.key);\n            }\n\n            @Override\n            public String toString() {\n                long pos = entryAddr + HEADER_SIZE + keySize;\n                return round(UNSAFE.getInt(pos + FLD_MIN))\n                        + \"/\" + round(((double) UNSAFE.getLong(pos + FLD_SUM)) / UNSAFE.getLong(pos + FLD_COUNT))\n                        + \"/\" + round(UNSAFE.getInt(pos + FLD_MAX));\n            }\n\n            void appendTo(StringBuilder sb) {\n                long pos = entryAddr + HEADER_SIZE + keySize;\n                sb.append(key);\n                sb.append('=');\n                sb.append(round(UNSAFE.getInt(pos + FLD_MIN)));\n                sb.append('/');\n                sb.append(round(((double) UNSAFE.getLong(pos + FLD_SUM)) / UNSAFE.getLong(pos + FLD_COUNT)));\n                sb.append('/');\n                sb.append(round(UNSAFE.getInt(pos + FLD_MAX)));\n            }\n\n            private static double round(double value) {\n                return Math.round(value) / 10.0;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_hallvard.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.function.Consumer;\nimport java.util.function.Function;\n\npublic class CalculateAverage_hallvard {\n\n    private static class ResultRow {\n\n        private String name;\n        private int min, max, sum;\n        private int count;\n\n        public ResultRow(String name) {\n            this.name = name;\n            this.min = Integer.MAX_VALUE;\n            this.max = Integer.MIN_VALUE;\n            this.sum = 0;\n            this.count = 0;\n        }\n\n        public ResultRow(String name, int value) {\n            this.name = name;\n            this.sum = this.max = this.min = value;\n            this.count = 1;\n        }\n\n        @Override\n        public String toString() {\n            return (min / 10.0d) + \"/\" + (Math.round((double) sum / count) / 10.0d) + \"/\" + (max / 10.0d);\n        }\n\n        void update(int value) {\n            if (value < min) {\n                min = value;\n            }\n            if (value > max) {\n                max = value;\n            }\n            sum += value;\n            count++;\n        }\n\n        void update(ResultRow row) {\n            if (row.min < min) {\n                min = row.min;\n            }\n            if (row.max > max) {\n                max = row.max;\n            }\n            sum += row.sum;\n            count += row.count;\n        }\n    };\n\n    private static class Trie<T> {\n\n        private final Node<T> root = new Node();\n\n        String toString(String prefix, String separator, String suffix, Function<T, String> formatter, Comparator<T> comparator) {\n            StringBuilder builder = new StringBuilder();\n            List<T> payloads = new ArrayList<>();\n            forEach(payloads::add);\n            if (comparator != null) {\n                Collections.sort(payloads, comparator);\n            }\n            for (var item : payloads) {\n                if (builder.isEmpty()) {\n                    if (prefix != null) {\n                        builder.append(prefix);\n                    }\n                }\n                else {\n                    if (separator != null) {\n                        builder.append(separator);\n                    }\n                }\n                builder.append(formatter != null ? formatter.apply(item) : item.toString());\n            }\n            if (suffix != null) {\n                builder.append(suffix);\n            }\n            return builder.toString();\n        }\n\n        void forEach(Consumer<T> consumer) {\n            forEach(root, consumer);\n        }\n\n        private void forEach(Node<T> node, Consumer<T> consumer) {\n            if (node.payload != null) {\n                consumer.accept(node.payload);\n            }\n            for (int nodeIdx = 0; nodeIdx < node.rests.length; nodeIdx++) {\n                Node<T> rest = node.rests[nodeIdx];\n                if (rest != null) {\n                    forEach(rest, consumer);\n                }\n            }\n        }\n\n        Node<T> getNode(ByteBuffer byteBuffer, int start, int end) {\n            Node<T> node = root;\n            next: for (int byteIdx = start; byteIdx < end; byteIdx++) {\n                byte b = byteBuffer.get(byteIdx);\n                if (node.nexts != null) {\n                    for (int nodeIdx = 0; nodeIdx < node.nexts.length; nodeIdx++) {\n                        byte next = node.nexts[nodeIdx];\n                        if (next == b) {\n                            // if found byte value, use corresponding node\n                            node = node.rests[nodeIdx];\n                            continue next;\n                        }\n                        else if (next == 0) {\n                            // if empty slot add new node\n                            node.nexts[nodeIdx] = b;\n                            node = (node.rests[nodeIdx] = createDefaultNode());\n                            continue next;\n                        }\n                    }\n                    // convert to full node\n                    Node<T>[] newRests = new Node[Byte.MAX_VALUE - Byte.MIN_VALUE];\n                    for (int i = 0; i < node.nexts.length; i++) {\n                        newRests[Node.idx(node.nexts[i])] = node.rests[i];\n                    }\n                    // new entry\n                    Node<T> newNode = createDefaultNode();\n                    newRests[Node.idx(b)] = newNode;\n                    node.nexts = null;\n                    node.rests = newRests;\n                    node = newNode;\n                }\n                else {\n                    int idx = Node.idx(b);\n                    Node<T> rest = node.rests[idx];\n                    node = (rest != null ? rest : (node.rests[idx] = createDefaultNode()));\n                }\n            }\n            return node;\n        }\n\n        final Node<T> createDefaultNode() {\n            return new Node(4);\n        }\n\n        private static class Node<T> {\n            private T payload;\n            private byte[] nexts;\n            private Node<T>[] rests;\n\n            // full node that covers all byte values, with byte as index\n            Node() {\n                nexts = null;\n                rests = new Node[Byte.MAX_VALUE - Byte.MIN_VALUE];\n            }\n\n            // sparse node that covers some byte values, index of value (in nexts) gives index of node (in rests)\n            Node(int length) {\n                nexts = new byte[length];\n                rests = new Node[length];\n            }\n\n            static final int idx(byte b) {\n                return b - Byte.MIN_VALUE;\n            }\n        }\n    }\n\n    private static boolean computeAverages(ByteBuffer byteBuffer, int start, Trie<ResultRow> results) {\n        // search backwards to first newline\n        int startPos = start;\n        while (startPos > 0 && byteBuffer.get(startPos - 1) != '\\n') {\n            startPos--;\n        }\n        byteBuffer.position(startPos);\n        while (byteBuffer.hasRemaining()) {\n            // find name range\n            int nameStart = byteBuffer.position(), limit = byteBuffer.limit(), pos = nameStart;\n            while (pos < limit && byteBuffer.get(pos) != ';') {\n                pos++;\n            }\n            // is there room for ; a digit, decimal point, a decimal and the final newline\n            if (pos + 4 >= limit) {\n                return false;\n            }\n            int nameEnd = pos++;\n\n            // parse value\n            byte next = byteBuffer.get(pos++);\n            boolean negative = false;\n            if (next == '-') {\n                negative = true;\n                next = byteBuffer.get(pos++);\n            }\n            int value = next - '0';\n            int decimalPos = -1;\n            while (pos < limit && (next = byteBuffer.get(pos)) != '\\n') {\n                if (next == '.') {\n                    if (decimalPos >= 0) {\n                        return false;\n                    }\n                    decimalPos = pos;\n                }\n                else {\n                    value = value * 10 + (next - '0');\n                }\n                pos++;\n            }\n            if (next != '\\n') {\n                return false;\n            }\n            if (negative) {\n                value = -value;\n            }\n            // skip newline\n            byteBuffer.position(pos + 1);\n            Trie.Node<ResultRow> node = results.getNode(byteBuffer, nameStart, nameEnd);\n            ResultRow result = node.payload;\n            if (result == null) {\n                byte[] bytes = new byte[nameEnd - nameStart];\n                byteBuffer.get(nameStart, bytes);\n                result = new ResultRow(new String(bytes), value);\n                node.payload = result;\n            }\n            else {\n                result.update(value);\n            }\n        }\n        return true;\n    }\n\n    private record TaskInfo(long chunkStart, int chunkSize, int start) {\n        Trie<ResultRow> doTask(FileChannel channel) {\n            Trie<ResultRow> results = new Trie<>();\n            try {\n                //System.err.println(\"Mapping bytes \" + chunkStart + \" - \" + (chunkStart + chunkSize));\n                //System.err.flush();\n                MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, chunkStart, chunkSize);\n                //System.err.println(\"Computing averages from \" + (chunkStart + start) + \" (\" + start + \")\");\n                //System.err.flush();\n                computeAverages(buffer, start, results);\n                //System.err.println(\"Read upto \" + (chunkStart + buffer.position()));\n                //System.err.flush();\n            } catch (IOException e) {\n                throw new RuntimeException(\"Exception while doing \" + this + \": \" + e);\n            }\n            return results;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        Path measurementsPath = Paths.get(\"./measurements.txt\");\n        try (FileChannel channel = FileChannel.open(measurementsPath)) {\n            int ROW_SIZE = 50, CHUNK_SIZE = 100_000_000;\n            long size = channel.size(), pos = 0;\n            List<TaskInfo> tasks = new ArrayList<>();\n            while (pos >= 0 && pos < size) {\n                long chunkStart = Math.max(pos - ROW_SIZE, 0);\n                int chunkSize = (int) Math.min(size - chunkStart, CHUNK_SIZE + (pos - chunkStart));\n                tasks.add(new TaskInfo(chunkStart, chunkSize, (int) (pos - chunkStart)));\n                pos = chunkStart + chunkSize;\n            }\n            Map<String, ResultRow> results = new TreeMap<>();\n            tasks.parallelStream()\n                    .map(task -> task.doTask(channel))\n                    .forEach(result -> {\n                        result.forEach(resultRow -> {\n                            synchronized (results) {\n                                ResultRow existing = results.get(resultRow.name);\n                                if (existing != null) {\n                                    existing.update(resultRow);\n                                }\n                                else {\n                                    results.put(resultRow.name, resultRow);\n                                }\n                            }\n                        });\n                    });\n            System.out.println(results);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_hchiorean.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetDecoder;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_hchiorean {\n\n    private static Map<String, double[]> parseLines(Integer key, CharBuffer chars, ConcurrentMap<Integer, String> leftoversMap) {\n        Map<String, double[]> data = new HashMap<>();\n\n        int startIdx = 0;\n        int endIdx = chars.length() - 1;\n        while (chars.charAt(startIdx) != '\\n') {\n            ++startIdx;\n        }\n        while (chars.charAt(endIdx) != '\\n') {\n            --endIdx;\n        }\n        if (startIdx < endIdx) {\n            parseSanitizedCharBuffer(chars, data, startIdx, endIdx);\n        }\n        String firstPartBeforeDelim = chars.subSequence(0, startIdx + 1).toString();\n        String lastPartBeforeDelim = chars.subSequence(endIdx + 1, chars.length()).toString();\n        leftoversMap.put(key, firstPartBeforeDelim + lastPartBeforeDelim);\n        chars = null;\n        return data;\n    }\n\n    private static void parseSanitizedCharBuffer(CharSequence sequence, Map<String, double[]> data, int startIdx, int endIdx) {\n        StringBuilder parseBuffer = new StringBuilder();\n        String name = null;\n        for (int i = startIdx; i < endIdx; ++i) {\n            char c = sequence.charAt(i);\n            if (c == '\\r') {\n                continue;\n            }\n            if (c == '\\n') {\n                if (parseBuffer.isEmpty()) {\n                    continue;\n                }\n                addParsedDataToMap(data, parseBuffer, name);\n                parseBuffer.setLength(0);\n                continue;\n            }\n            if (c == ';') {\n                name = parseBuffer.toString();\n                parseBuffer.setLength(0);\n                continue;\n            }\n            parseBuffer.append(c);\n        }\n        if (!parseBuffer.isEmpty()) {\n            assert name != null;\n            addParsedDataToMap(data, parseBuffer, name);\n        }\n    }\n\n    private static void addParsedDataToMap(Map<String, double[]> data, StringBuilder parseBuffer, String name) {\n        String value = parseBuffer.toString();\n        double valueNum = Double.parseDouble(value);\n        double[] existingMeasurements = data.putIfAbsent(name, new double[]{ valueNum, valueNum, 1, valueNum });\n        if (existingMeasurements != null) {\n            existingMeasurements[0] = Math.min(existingMeasurements[0], valueNum);\n            existingMeasurements[1] = Math.max(existingMeasurements[1], valueNum);\n            ++existingMeasurements[2];\n            existingMeasurements[3] += valueNum;\n        }\n    }\n\n    static Map<String, double[]> readFile(File file) throws Exception {\n\n        Map<String, double[]> aggregate = new TreeMap<>(Comparator.naturalOrder());\n        List<Future<Map<String, double[]>>> futures = new ArrayList<>();\n        ConcurrentMap<Integer, String> leftoversMap = new ConcurrentSkipListMap<>();\n\n        Charset defaultCharset = Charset.defaultCharset();\n        CharsetDecoder decoder = defaultCharset.newDecoder();\n\n        int bufferCapacity = 10 * 1024 * 1024;\n\n        long len = file.length();\n        int idCounter = 0;\n        try (\n                ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();\n                FileChannel chan = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {\n\n            ByteBuffer mainBuffer = ByteBuffer.allocate(bufferCapacity);\n            int totalRead = 0;\n            while (totalRead < len) {\n                mainBuffer.clear();\n                long read = chan.read(mainBuffer);\n                if (read == -1) {\n                    break;\n                }\n                totalRead += read;\n                mainBuffer.flip();\n                CharBuffer chars = null;\n                for (;;) {\n                    try {\n                        chars = decoder.decode(mainBuffer);\n                        break;\n                    }\n                    catch (CharacterCodingException e) {\n                        // keep reading byte by byte until a valid sequence is decoded\n                        mainBuffer.rewind();\n                        ByteBuffer nextByte = ByteBuffer.allocate(1);\n                        chan.read(nextByte);\n                        nextByte.flip();\n                        mainBuffer = ByteBuffer.allocate(mainBuffer.capacity() + 1).put(mainBuffer).put(nextByte);\n                        mainBuffer.flip();\n                    }\n                }\n                int nextId = idCounter++;\n                CharBuffer finalChars = chars;\n                futures.add(\n                        executor.submit(() -> parseLines(Integer.valueOf(nextId), finalChars, leftoversMap)));\n            }\n        }\n        for (Future<Map<String, double[]>> future : futures) {\n            Map<String, double[]> chunk = future.get();\n            aggregate(chunk, aggregate);\n        }\n        String leftovers = String.join(\"\", leftoversMap.values());\n        parseSanitizedCharBuffer(leftovers, aggregate, 0, leftovers.length());\n\n        return aggregate;\n    }\n\n    private static void aggregate(Map<String, double[]> chunks, Map<String, double[]> aggregate) {\n        for (Map.Entry<String, double[]> chunk : chunks.entrySet()) {\n            String name = chunk.getKey();\n            double[] chunkData = chunk.getValue();\n            double[] aggregateData = aggregate.putIfAbsent(name, chunkData);\n            if (aggregateData != null) {\n                aggregateData[0] = Math.min(aggregateData[0], chunkData[0]);\n                aggregateData[1] = Math.max(aggregateData[1], chunkData[1]);\n                aggregateData[2] += chunkData[2];\n                aggregateData[3] += chunkData[3];\n            }\n        }\n    }\n\n    static void print(Map<String, double[]> dataMap) {\n        System.out.print(\"{\");\n        for (Iterator<Map.Entry<String, double[]>> dataEntryIt = dataMap.entrySet().iterator(); dataEntryIt.hasNext();) {\n            String entryOutput = format(dataEntryIt.next());\n            System.out.print(entryOutput);\n            if (dataEntryIt.hasNext()) {\n                System.out.print(\", \");\n            }\n        }\n        System.out.println(\"}\");\n    }\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static String format(Map.Entry<String, double[]> entry) {\n        double[] dataPoints = entry.getValue();\n        double min = round(dataPoints[0]);\n        double max = round(dataPoints[1]);\n        double mean = round(dataPoints[3] / dataPoints[2]);\n        return entry.getKey() + \"=\" + min + \"/\" + mean + \"/\" + max;\n    }\n\n    public static void main(String[] args) throws Exception {\n        File file = new File(\"./measurements.txt\");\n        Map<String, double[]> data = readFile(file);\n        print(data);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_hundredwatt.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_hundredwatt {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MAX_ROW_SIZE = 100 + 1 + 5 + 1; // 100 for city name, 1 for ;, 5 for temperature, 1 for \\n\n    private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();\n    private static final long BUFFER_SIZE = 128 * 1024 * 1024; // 128MB\n    private static final long CHUNK_SIZE = BUFFER_SIZE / THREAD_COUNT;\n    private static final long FILE_CHUNK_SIZE = CHUNK_SIZE - MAX_ROW_SIZE;\n    public static final int TEMPERATURE_SLOTS = 5003; // prime number\n    private static final short[] TEMPERATURES = new short[TEMPERATURE_SLOTS];\n    private static final long PERFECT_HASH_SEED = -1982870890352534081L;\n\n    // Construct a perfect hash function mapping temperatures encoded as longs (e.g., 0x2d342e3000000000 for -4.3) to\n    // the corresponding short integer (e.g., -43).\n    static {\n        // Figure out encoding for all possible temperature values (1999 total)\n        long start = System.currentTimeMillis();\n        Map<Long, Short> decodeTemperatureMap = new HashMap<>();\n        for (short i = -999; i <= 999; i++) {\n            long word = 0;\n            int shift = 0;\n            if (i < 0) {\n                word |= ((long) '-') << shift;\n                shift += 8;\n            }\n            if (Math.abs(i) >= 100) {\n                int hh = Math.abs(i) / 100;\n                int tt = (Math.abs(i) - hh * 100) / 10;\n\n                word |= ((long) (hh + '0')) << shift;\n                shift += 8;\n                word |= ((long) (tt + '0')) << shift;\n            }\n            else {\n                int tt = Math.abs(i) / 10;\n                // convert to ascii\n                word |= ((long) (tt + '0')) << shift;\n            }\n            shift += 8;\n            word |= ((long) '.') << shift;\n            shift += 8;\n            int uu = Math.abs(i) % 10;\n            word |= ((long) (uu + '0')) << shift;\n\n            // 31302e3000000000\n            decodeTemperatureMap.put(word, i);\n        }\n\n        decodeTemperatureMap.entrySet().stream().forEach(e -> {\n            var word = e.getKey();\n            var h = (word * PERFECT_HASH_SEED) & ~(1L << 63);\n            var pos = (int) (h % TEMPERATURE_SLOTS);\n            if (TEMPERATURES[pos] != 0)\n                throw new RuntimeException(\"collision at \" + pos);\n            TEMPERATURES[pos] = e.getValue();\n        });\n        // System.out.println(\"Building table took \" + (System.currentTimeMillis() - start) + \"ms\");\n    }\n\n    static class Record {\n        short min;\n        short max;\n        int sum;\n        int count;\n\n        public Record() {\n            this.min = Short.MAX_VALUE;\n            this.max = Short.MIN_VALUE;\n            this.sum = 0;\n            this.count = 0;\n        }\n\n        public void updateWith(short value) {\n            min = (short) Math.min(min, value);\n            max = (short) Math.max(max, value);\n            sum += value;\n            count++;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round(sum / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        double round(double v) {\n            return Math.round(v * 10.0) / 10.0;\n        }\n    }\n\n    record Entry(long[] key, Record value) {\n    }\n\n    static class HashTable {\n        private static final int INITIAL_SIZE = 16 * 1024;\n        private static final float LOAD_FACTOR = 0.75f;\n        private static final int GROW_FACTOR = 4;\n        private final long[][] KEYS = new long[INITIAL_SIZE][];\n        private final Record[] VALUES = new Record[INITIAL_SIZE];\n        private final long[] HASHES = new long[INITIAL_SIZE];\n        private int size = INITIAL_SIZE;\n\n        public HashTable() {\n            for (int i = 0; i < INITIAL_SIZE; i++) {\n                VALUES[i] = new Record();\n            }\n        }\n\n        public void putOrMerge(int hash, int length, long[] key, short value) {\n            int idx = hash & (size - 1);\n\n            // linear probing\n            int i = 0;\n            while (KEYS[idx] != null && (HASHES[idx] != hash) && (0 != Arrays.compareUnsigned(KEYS[idx], 0, KEYS[idx].length, key, 0, length))) {\n                i++;\n                idx = (idx + 1) & (size - 1);\n            }\n\n            if (KEYS[idx] == null) {\n                KEYS[idx] = Arrays.copyOf(key, length);\n                HASHES[idx] = hash;\n            }\n\n            VALUES[idx].updateWith(value);\n        }\n\n        public List<Entry> getAll() {\n            List<Entry> result = new ArrayList<>(size);\n            for (int i = 0; i < size; i++) {\n                if (KEYS[i] != null) {\n                    result.add(new Entry(KEYS[i], VALUES[i]));\n                }\n            }\n            return result;\n        }\n    }\n\n    private static String keyToString(long[] key) {\n        ByteBuffer kb = ByteBuffer.allocate(8 * key.length).order(ByteOrder.LITTLE_ENDIAN);\n        Arrays.stream(key).forEach(kb::putLong);\n\n        // remove trailing '\\0' bytes from kb and\n        // fix two ';' in word issue here (rather than in hot path)\n        byte b;\n        int limit = kb.position() - 8;\n        kb.position(limit);\n        while ((b = kb.get()) != 0 && b != ';' && limit < kb.capacity() - 1) {\n            limit++;\n        }\n\n        kb.flip();\n        byte[] bytes = new byte[limit];\n        kb.get(bytes);\n\n        return new String(bytes);\n    }\n\n    private static Record merge(Record v, Record value) {\n        var record = new Record();\n        record.min = (short) Math.min(v.min, value.min);\n        record.max = (short) Math.max(v.max, value.max);\n        record.sum = v.sum + value.sum;\n        record.count = v.count + value.count;\n        return record;\n    }\n\n    private static int processChunk(ByteBuffer bb, HashTable hashTable, long start, long size) {\n        bb.order(ByteOrder.LITTLE_ENDIAN);\n        // Find first entry\n        while (start != 0 && bb.get() != '\\n') {\n        }\n\n        long word;\n        long[] key = new long[13];\n        int offset;\n        long arg, hasvalue, op1, op2;\n        int position = bb.position();\n        long hash;\n        long temperature_hash;\n        int temperature_pos;\n        short temperature_value;\n        int hashInt;\n\n        int rc = 0;\n        int end = (int) (size - MAX_ROW_SIZE);\n        while (position <= end) {\n            // rc++;\n            offset = -1;\n\n            // Parse city name\n            // First word\n            hash = key[++offset] = bb.getLong(position + offset * 8);\n\n            // From \"Determine if a word has a byte equal to n\"\n            // https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord\n            arg = (key[offset]) ^ (0x0101010101010101L * (';'));\n            op1 = (arg - 0x0101010101010101L);\n            op2 = ~(arg);\n            hasvalue = (op1 & op2 & 0x8080808080808080L);\n\n            // Remaining words (if present)\n            while (hasvalue == 0) {\n                ++offset;\n                key[offset] = bb.getLong(position + offset * 8);\n                hash ^= key[offset];\n\n                arg = (key[offset]) ^ (0x0101010101010101L * (';'));\n                op1 = (arg - 0x0101010101010101L);\n                op2 = ~(arg);\n                hasvalue = (op1 & op2 & 0x8080808080808080L);\n            }\n            hash ^= key[offset]; // unset last word since it will be updated\n            key[offset] = key[offset] & ~(-(hasvalue >> 7));\n            hash ^= key[offset];\n\n            position = position + offset * 8 + Long.numberOfTrailingZeros(hasvalue) / 8 + 1; // +1 for \\n\n\n            // Parse temperature\n            word = bb.getLong(position);\n            hasvalue = (word - 0x0B0B0B0B0B0B0B0BL) & 0x8080808080808080L;\n            int newlinePos = Long.numberOfTrailingZeros(hasvalue) - 8;\n\n            word = word & (~(-(1L << newlinePos)));\n\n            // Perfect hash lookup for temperature\n            temperature_hash = (word * PERFECT_HASH_SEED) & ~(1L << 63);\n            temperature_pos = (int) (temperature_hash % TEMPERATURE_SLOTS);\n            temperature_value = TEMPERATURES[temperature_pos];\n\n            position = position + newlinePos / 8 + 2; // +1 for \\n\n\n            hashInt = (int) (hash ^ (hash >> 32) ^ (hash >> 17));\n\n            hashTable.putOrMerge(hashInt, offset + 1, key, temperature_value);\n        }\n        return rc;\n    }\n\n    public static void main(String[] args) throws IOException {\n        final long fileSize = Files.size(Path.of(FILE));\n        // System.out.println(\"File size: \" + fileSize);\n\n        // AtomicLong rowCount = new AtomicLong();\n\n        // Read file in chunks using striping\n        try (var fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), StandardOpenOption.READ)) {\n            var r = IntStream.range(0, THREAD_COUNT + 1).mapToObj(stripe -> {\n                long start = stripe * FILE_CHUNK_SIZE;\n                var hashTable = new HashTable();\n\n                if (stripe == THREAD_COUNT) { // last thread\n                    try {\n                        // handle trailing bytes in file in jankiest way possible (for now hopefully :) )\n                        byte[] trailing = new byte[MAX_ROW_SIZE * 2];\n                        fileChannel.read(ByteBuffer.wrap(trailing), Math.max(0, fileSize - MAX_ROW_SIZE));\n                        var rc = processChunk(ByteBuffer.wrap(trailing), hashTable, Math.max(0, fileSize - MAX_ROW_SIZE),\n                                MAX_ROW_SIZE + Math.min(fileSize, MAX_ROW_SIZE) - 1);\n                        // rowCount.addAndGet(rc);\n                        return hashTable;\n\n                    }\n                    catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n\n                // if file is smaller than max row size, we're done b/c the trailing bytes handler processed the whole file\n                if (fileSize <= MAX_ROW_SIZE) {\n                    return hashTable;\n                }\n\n                while (start < fileSize) {\n                    long end = Math.min(start + CHUNK_SIZE, fileSize);\n                    MappedByteBuffer bb = null;\n                    try {\n                        bb = fileChannel.map(FileChannel.MapMode.READ_ONLY, start, Math.min(end - start + 8, fileSize - start));\n                    }\n                    catch (IOException e) {\n                        throw new RuntimeException(e);\n                    }\n                    var rc = processChunk(bb, hashTable, start, end - start);\n\n                    // rowCount.addAndGet(rc);\n                    start += FILE_CHUNK_SIZE * THREAD_COUNT;\n                }\n\n                return hashTable;\n            }).parallel().flatMap(partition -> partition.getAll().stream())\n                    .collect(Collectors.toMap(e -> keyToString(e.key()), Entry::value, CalculateAverage_hundredwatt::merge, TreeMap::new));\n\n            System.out.println(r);\n            // System.out.println(rowCount.get());\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ianopolous.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.*;\nimport java.nio.channels.*;\nimport java.util.concurrent.*;\nimport java.util.stream.*;\nimport java.util.*;\n\n/* A simple implementation aiming for readability.\n * Features:\n * * memory mapped file\n * * read chunks in parallel\n * * minimise allocation\n * * no unsafe\n *\n * Timings on 4 core i7-7500U CPU @ 2.70GHz:\n * average_baseline: 4m48s\n * ianopolous:         36s\n*/\npublic class CalculateAverage_ianopolous {\n\n    public static final int MAX_LINE_LENGTH = 107;\n    public static final int MAX_STATIONS = 10_000;\n\n    public static void main(String[] args) throws Exception {\n        File input = new File(\"./measurements.txt\");\n        long filesize = input.length();\n        // keep chunk size between 256 MB and 1G (1 chunk for files < 256MB)\n        long chunkSize = Math.min(Math.max(filesize / 32, 256 * 1024 * 1024), 1024 * 1024 * 1024L);\n        int nChunks = (int) ((filesize + chunkSize - 1) / chunkSize);\n        ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor();\n        List<Future<List<List<Stat>>>> allResults = IntStream.range(0, nChunks)\n                .mapToObj(i -> pool.submit(() -> parseStats(i * chunkSize, Math.min((i + 1) * chunkSize, filesize))))\n                .toList();\n\n        TreeMap<String, Stat> merged = allResults.stream()\n                .parallel()\n                .flatMap(f -> {\n                    try {\n                        return f.get().stream().filter(Objects::nonNull).flatMap(Collection::stream);\n                    }\n                    catch (Exception e) {\n                        return Stream.empty();\n                    }\n                })\n                .collect(Collectors.toMap(s -> s.name(), s -> s, (a, b) -> a.merge(b), TreeMap::new));\n        System.out.println(merged);\n    }\n\n    public static boolean matchingStationBytes(int start, int end, MappedByteBuffer buffer, Stat existing) {\n        for (int i = start; i < end; i++) {\n            if (existing.name[i - start] != buffer.get(i))\n                return false;\n        }\n        return true;\n    }\n\n    public static Stat parseStation(int start, int end, int hash, MappedByteBuffer buffer, List<List<Stat>> stations) {\n        int index = Math.floorMod(hash, MAX_STATIONS);\n        List<Stat> matches = stations.get(index);\n        if (matches == null) {\n            List<Stat> value = new ArrayList<>();\n            byte[] stationBuffer = new byte[end - start];\n            buffer.position(start);\n            buffer.get(stationBuffer);\n            Stat res = new Stat(stationBuffer);\n            value.add(res);\n            stations.set(index, value);\n            return res;\n        }\n        else {\n            for (int i = 0; i < matches.size(); i++) {\n                Stat s = matches.get(i);\n                if (matchingStationBytes(start, end, buffer, s))\n                    return s;\n            }\n            byte[] stationBuffer = new byte[end - start];\n            buffer.position(start);\n            buffer.get(stationBuffer);\n            Stat res = new Stat(stationBuffer);\n            matches.add(res);\n            return res;\n        }\n    }\n\n    public static List<List<Stat>> parseStats(long startByte, long endByte) {\n        try {\n            RandomAccessFile file = new RandomAccessFile(\"./measurements.txt\", \"r\");\n            long maxEnd = Math.min(file.length(), endByte + MAX_LINE_LENGTH);\n            long len = maxEnd - startByte;\n            if (len > Integer.MAX_VALUE)\n                throw new RuntimeException(\"Segment size must fit into an int\");\n            int maxDone = (int) (endByte - startByte);\n            MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, startByte, len);\n            int done = 0;\n            // read first partial line\n            if (startByte > 0) {\n                for (int i = 0; i < MAX_LINE_LENGTH; i++) {\n                    byte b = buffer.get(i);\n                    if (b == '\\n') {\n                        done = i + 1;\n                        break;\n                    }\n                }\n            }\n\n            List<List<Stat>> stations = new ArrayList<>(MAX_STATIONS);\n            for (int i = 0; i < MAX_STATIONS; i++)\n                stations.add(null);\n            int lineStart = done;\n            int lineSplit = 0;\n            short temperature = 0;\n            int hash = 1;\n            boolean negative = false;\n            while (done < maxDone) {\n                Stat station = null;\n                for (int i = done; i < done + MAX_LINE_LENGTH && i < maxEnd; i++) {\n                    byte b = buffer.get(i);\n                    if (b == '\\n') {\n                        done = i + 1;\n                        temperature = negative ? (short) -temperature : temperature;\n                        station.add(temperature);\n                        lineStart = done;\n                        station = null;\n                        hash = 1;\n                        break;\n                    }\n                    else if (b == ';') {\n                        lineSplit = i;\n                        station = parseStation(lineStart, lineSplit, hash, buffer, stations);\n                        temperature = 0;\n                        negative = false;\n                    }\n                    else if (station == null) {\n                        hash = 31 * hash + b;\n                    }\n                    else if (b == '-') {\n                        negative = true;\n                    }\n                    else if (b != '.') {\n                        temperature = (short) (temperature * 10 + (b - 0x30));\n                    }\n                }\n            }\n            return stations;\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static class Stat {\n        final byte[] name;\n        int count = 0;\n        short min = Short.MAX_VALUE, max = Short.MIN_VALUE;\n        long total = 0;\n\n        public Stat(byte[] name) {\n            this.name = name;\n        }\n\n        public void add(short value) {\n            if (value < min)\n                min = value;\n            if (value > max)\n                max = value;\n            total += value;\n            count++;\n        }\n\n        public Stat merge(Stat value) {\n            if (value.min < min)\n                min = value.min;\n            if (value.max > max)\n                max = value.max;\n            total += value.total;\n            count += value.count;\n            return this;\n        }\n\n        private static double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n        public String name() {\n            return new String(name);\n        }\n\n        public String toString() {\n            return round((double) min) + \"/\" + round(((double) total) / count) + \"/\" + round((double) max);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ianopolousfast.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\n\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.ByteOrder;\nimport java.nio.channels.*;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.stream.*;\nimport java.util.*;\n\nimport static java.lang.foreign.ValueLayout.*;\n\n/* A fast implementation with no unsafe.\n * Features:\n * * memory mapped file using preview Arena FFI\n * * semicolon finding and name comparison using incubator vector api\n * * read chunks in parallel\n * * minimise allocation\n * * no unsafe\n * * process multiple lines in each thread for better ILP\n*/\npublic class CalculateAverage_ianopolousfast {\n\n    public static final int MAX_LINE_LENGTH = 107;\n    public static final int MAX_STATIONS = 1 << 14;\n    private static final OfLong LONG_LAYOUT = JAVA_LONG_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED.length() >= 16\n            ? ByteVector.SPECIES_128\n            : ByteVector.SPECIES_64;\n\n    public static void main(String[] args) throws Exception {\n        Arena arena = Arena.global();\n        Path input = Path.of(\"measurements.txt\");\n        FileChannel channel = (FileChannel) Files.newByteChannel(input, StandardOpenOption.READ);\n        long filesize = Files.size(input);\n        MemorySegment mmap = channel.map(FileChannel.MapMode.READ_ONLY, 0, filesize, arena);\n        int nChunks = filesize < 4 * 1024 * 1024 ? 1 : Runtime.getRuntime().availableProcessors();\n        long chunkSize = (filesize + nChunks - 1) / nChunks;\n        List<Stat[]> allResults = IntStream.range(0, nChunks)\n                .parallel()\n                .mapToObj(i -> parseStats(i * chunkSize, Math.min((i + 1) * chunkSize, filesize), mmap))\n                .toList();\n\n        TreeMap<String, Stat> merged = allResults.stream()\n                .parallel()\n                .flatMap(f -> {\n                    try {\n                        return Arrays.stream(f).filter(Objects::nonNull);\n                    }\n                    catch (Exception e) {\n                        e.printStackTrace();\n                        return Stream.empty();\n                    }\n                })\n                .collect(Collectors.toMap(s -> s.name(), s -> s, (a, b) -> a.merge(b), TreeMap::new));\n        System.out.println(merged);\n    }\n\n    public static boolean matchingStationBytes(long start, long end, MemorySegment buffer, Stat existing) {\n        for (int index = 0; index < end - start; index += BYTE_SPECIES.vectorByteSize()) {\n            ByteVector line = ByteVector.fromMemorySegment(BYTE_SPECIES, buffer, start + index, ByteOrder.nativeOrder(), BYTE_SPECIES.indexInRange(start + index, end));\n            ByteVector found = ByteVector.fromArray(BYTE_SPECIES, existing.name, index);\n            if (!found.eq(line).allTrue())\n                return false;\n        }\n        return true;\n    }\n\n    private static final int GOLDEN_RATIO = 0x9E3779B9;\n    private static final int HASH_LROTATE = 5;\n\n    // hash from giovannicuccu\n    private static int hash(MemorySegment memorySegment, long start, int len) {\n        int x;\n        int y;\n        if (len >= Integer.BYTES) {\n            x = memorySegment.get(JAVA_INT_UNALIGNED, start);\n            y = memorySegment.get(JAVA_INT_UNALIGNED, start + len - Integer.BYTES);\n        }\n        else {\n            x = memorySegment.get(JAVA_BYTE, start);\n            y = memorySegment.get(JAVA_BYTE, start + len - Byte.BYTES);\n        }\n        return (Integer.rotateLeft(x * GOLDEN_RATIO, HASH_LROTATE) ^ y) * GOLDEN_RATIO;\n    }\n\n    public static Stat createStation(long start, long end, MemorySegment buffer) {\n        byte[] stationBuffer = new byte[(int) (end - start)];\n        for (long off = start; off < end; off++)\n            stationBuffer[(int) (off - start)] = buffer.get(JAVA_BYTE, off);\n        return new Stat(stationBuffer);\n    }\n\n    public static Stat dedupeStation(long start, long end, MemorySegment buffer, Stat[] stations) {\n        int hash = hash(buffer, start, (int) (end - start));\n        int index = hash & (MAX_STATIONS - 1);\n        Stat match = stations[index];\n        while (match != null) {\n            if (matchingStationBytes(start, end, buffer, match))\n                return match;\n            index = (index + 1) % stations.length;\n            match = stations[index];\n        }\n        Stat res = createStation(start, end, buffer);\n        stations[index] = res;\n        return res;\n    }\n\n    public static short getMinus(long d) {\n        return ((d & 0xff00000000000000L) ^ 0x2d00000000000000L) != 0 ? 0 : (short) -1;\n    }\n\n    public static void processTemperature(long lineSplit, int size, MemorySegment buffer, Stat station) {\n        long d = buffer.get(LONG_LAYOUT, lineSplit);\n        // negative is either 0 or -1\n        short negative = getMinus(d);\n        d = d << (negative * -8);\n        int dotIndex = size - 2 + negative;\n        d = (d >> 8) | 0x30000000_00000000L; // add a leading 0 digit\n        d = d >> 8 * (5 - dotIndex);\n        short temperature = (short) ((byte) d - '0' +\n                10 * (((byte) (d >> 16)) - '0') +\n                100 * (((byte) (d >> 24)) - '0'));\n        temperature = (short) ((temperature ^ negative) - negative); // negative treatment inspired by merkitty\n        station.add(temperature);\n    }\n\n    private static int lineSize(long lineStart, MemorySegment buffer) {\n        ByteVector line = ByteVector.fromMemorySegment(BYTE_SPECIES, buffer, lineStart, ByteOrder.nativeOrder());\n        int lineSize = line.compare(VectorOperators.EQ, '\\n').firstTrue();\n        int index = lineSize;\n        while (index == BYTE_SPECIES.vectorByteSize()) {\n            index = ByteVector.fromMemorySegment(BYTE_SPECIES, buffer, lineStart + lineSize,\n                    ByteOrder.nativeOrder()).compare(VectorOperators.EQ, '\\n').firstTrue();\n            lineSize += index;\n        }\n        return lineSize;\n    }\n\n    private static int keySize(int lineSize, long lineStart, MemorySegment buffer) {\n        return lineSize - 6 + ByteVector.fromMemorySegment(BYTE_SPECIES, buffer, lineStart + lineSize - 6,\n                ByteOrder.nativeOrder()).compare(VectorOperators.EQ, ';').firstTrue();\n    }\n\n    public static Stat[] parseStats(long start1, long end2, MemorySegment buffer) {\n        // read first partial line\n        if (start1 > 0) {\n            for (int i = 0; i < MAX_LINE_LENGTH; i++) {\n                byte b = buffer.get(JAVA_BYTE, start1++);\n                if (b == '\\n') {\n                    break;\n                }\n            }\n        }\n\n        Stat[] stations = new Stat[MAX_STATIONS];\n\n        // Handle reading the very last few lines in the file\n        // this allows us to not worry about reading beyond the end\n        // in the inner loop (reducing branches)\n        // We need at least the vector lane size bytes back\n        if (end2 == buffer.byteSize()) {\n            // reverse at least vector lane width\n            end2 = Math.max(buffer.byteSize() - 2 * BYTE_SPECIES.vectorByteSize(), 0);\n            while (end2 > 0 && buffer.get(JAVA_BYTE, end2) != '\\n')\n                end2--;\n\n            if (end2 > 0)\n                end2++;\n            // copy into a larger buffer to avoid reading off end\n            MemorySegment end = Arena.global().allocate(MAX_LINE_LENGTH + 2 * BYTE_SPECIES.vectorByteSize());\n            for (long i = end2; i < buffer.byteSize(); i++)\n                end.set(JAVA_BYTE, i - end2, buffer.get(JAVA_BYTE, i));\n            int index = 0;\n            while (end2 + index < buffer.byteSize()) {\n                int lineSize1 = lineSize(index, end);\n                int semiSearchStart = index + Math.max(0, lineSize1 - 6);\n                int keySize1 = semiSearchStart - index + ByteVector.fromMemorySegment(BYTE_SPECIES, end, semiSearchStart,\n                        ByteOrder.nativeOrder()).compare(VectorOperators.EQ, ';').firstTrue();\n                Stat station1 = dedupeStation(index, index + keySize1, end, stations);\n                processTemperature(index + keySize1 + 1, lineSize1 - keySize1 - 1, end, station1);\n                index += lineSize1 + 1;\n            }\n        }\n\n        while (start1 < end2) {\n            int lineSize1 = lineSize(start1, buffer);\n            long start2 = start1 + lineSize1 + 1;\n            int lineSize2 = start2 < end2 ? lineSize(start2, buffer) : 0;\n            int keySize1 = keySize(lineSize1, start1, buffer);\n            int keySize2 = keySize(lineSize2, start2, buffer);\n            Stat station1 = dedupeStation(start1, start1 + keySize1, buffer, stations);\n            processTemperature(start1 + keySize1 + 1, lineSize1 - keySize1 - 1, buffer, station1);\n            if (start2 < end2) {\n                Stat station2 = dedupeStation(start2, start2 + keySize2, buffer, stations);\n                processTemperature(start2 + keySize2 + 1, lineSize2 - keySize2 - 1, buffer, station2);\n                start1 = start2 + lineSize2 + 1;\n            }\n            else\n                start1 += lineSize1 + 1;\n        }\n        return stations;\n    }\n\n    public static class Stat {\n        final byte[] name;\n        final int namelen;\n        int count = 0;\n        short min = Short.MAX_VALUE, max = Short.MIN_VALUE;\n        long total = 0;\n\n        public Stat(byte[] name) {\n            int vecSize = BYTE_SPECIES.vectorByteSize();\n            int arrayLen = (name.length + vecSize - 1) / vecSize * vecSize;\n            this.name = Arrays.copyOfRange(name, 0, arrayLen);\n            this.namelen = name.length;\n        }\n\n        public void add(short value) {\n            if (value < min)\n                min = value;\n            if (value > max)\n                max = value;\n            total += value;\n            count++;\n        }\n\n        public Stat merge(Stat value) {\n            if (value.min < min)\n                min = value.min;\n            if (value.max > max)\n                max = value.max;\n            total += value.total;\n            count += value.count;\n            return this;\n        }\n\n        private static double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n        public String name() {\n            return new String(Arrays.copyOfRange(name, 0, namelen));\n        }\n\n        public String toString() {\n            return round((double) min) + \"/\" + round(((double) total) / count) + \"/\" + round((double) max);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_imrafaelmerino.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.function.Supplier;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\n/**\n * @author Rafael Merino García\n *\n * <pre>\n *\n *  Model Name: MacBook Pro\n *  Model Identifier: MacBookPro17,1\n *  Chip: Apple M1\n *  Total Number of Cores: 8 (4 performance and 4 efficiency)\n *  Memory: 16 GB\n *\n *  Executed 10 times in my machine with a chunk size of 20MB\n *\n *     21.0.1-graal\n *     avg: 15,366 sg | min: 14,878 sg | max: 15,937 sg | acc: 153,657 sg | times: 10\n *\n *     21-oracle\n *     avg: 17,032 sg | min: 16,448 sg | max: 17,424 sg | acc: 170,325 sg | times: 10\n *\n *\n *\n *  Credits:\n *      . bjhara: Really nice splitearator to be able to use the Stream API.\n *      . ebarlas: working with integers since we only have to consider one decimal\n *        (I don't think this makes a big difference though)\n *      . filiphr: It was my starting point, since it's the most natural way of approaching\n *        the problem using the nice spliterartor from bjhara. This solution has the potential\n *        for substantial improvement by actively pursuing a <br>higher level of parallelization<br>.\n *  </pre>\n *\n *\n * <pre>\n * Generalization Note:\n *\n * - This solution is designed to be applicable to any CSV file under the following assumptions:\n *\n * - The line schema follows the pattern: name;value\\n\n *\n * - The name is up to 128 characters (can be changed to hold any other size and irrelevant for the result)\n *\n * - The value is a decimal number with only one decimal digit.\n *\n * - The focus is on maintaining code simplicity without extreme optimization efforts,\n *   as achieving meaningful conclusions often requires substantial time and dedication,\n *   particularly with tools like JMH.\n *\n * - Emphasis on utilizing idiomatic Java and common data structures, following a pragmatic approach.\n *\n * - Addressing the question of whether the workload is CPU-bound or IO-bound is key; indications suggest\n *    both aspects are relevant. It's difficult to make the cores sweat! The observed trend in many solutions\n *    suggests the potential for increased parallelization to fully utilize multiple cores effectively.\n *    This solution brings to the table the Java class ManagedBlock, aiming to enhance parallelism in scenarios\n *    where threads from the Fork Join Pool are blocked.\n *\n *  - Commong guys! stop rolling the dice with fancy optimizations and reiventing hash maps structures and\n *   hash algorithms. This should be <a href=\"https://dailypapert.com/hard-fun/\">hard fun</a>\n *   and not tedious. Dont get me wrong! just an opinion :)\n *\n * - Last but not least, Gunnar Morling, you rock man! Thanks for your time and effort.\n *\n * -\n *\n * </pre>\n */\npublic class CalculateAverage_imrafaelmerino {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int FIELD_SIZE = 128;\n\n    public static void main(String[] args) throws IOException {\n        var chunkSize = Long.parseLong(args[0].trim());\n        var result = calculateStats(FILE, chunkSize);\n        System.out.println(result);\n    }\n\n    private static Map<String, Stat> calculateStats(String file,\n                                                    long chunkSize)\n            throws IOException {\n\n        try (var fileChannel = FileChannel.open(Paths.get(file),\n                StandardOpenOption.READ)) {\n            var stats = fileMemoryStream(fileChannel, chunkSize)\n                    .parallel()\n                    .map(p -> ManagedComputation.compute(() -> parse(p)))\n                    .reduce(Collections.emptyMap(),\n                            (stat1, stat2) -> combine(stat1, stat2));\n\n            return new TreeMap<>(stats);\n        }\n\n    }\n\n    private static Map<String, Stat> combine(Map<String, Stat> xs,\n                                             Map<String, Stat> ys) {\n\n        Map<String, Stat> result = new HashMap<>();\n\n        for (var key : xs.keySet()) {\n            var m1 = xs.get(key);\n            var m2 = ys.get(key);\n            var combined = (m2 == null) ? m1 : (m1 == null) ? m2 : Stat.combine(m1, m2);\n            result.put(key, combined);\n        }\n\n        for (var key : ys.keySet())\n            result.putIfAbsent(key, ys.get(key));\n        return result;\n\n    }\n\n    private static Map<String, Stat> parse(ByteBuffer bb) {\n        Map<String, Stat> stats = new HashMap<>();\n        var limit = bb.limit();\n        var field = new byte[FIELD_SIZE];\n        while (bb.position() < limit) {\n            var fieldCurrentIndex = 0;\n            field[fieldCurrentIndex++] = bb.get();\n            while (bb.position() < limit) {\n                var fieldByte = bb.get();\n                if (fieldByte == ';')\n                    break;\n                field[fieldCurrentIndex++] = fieldByte;\n            }\n            var fieldStr = new String(field, 0, fieldCurrentIndex);\n            var number = 0;\n            var sign = 1;\n            while (bb.position() < limit) {\n                var numberByte = bb.get();\n                if (numberByte == '-')\n                    sign = -1;\n                else if (numberByte == '\\n')\n                    break;\n                else if (numberByte != '.')\n                    number = number * 10 + (numberByte - '0');\n            }\n            stats.computeIfAbsent(fieldStr,\n                    k -> new Stat())\n                    .update(sign * number);\n        }\n\n        return stats;\n    }\n\n    private static Stream<ByteBuffer> fileMemoryStream(FileChannel fileChannel,\n                                                       long chunkSize)\n            throws IOException {\n\n        var spliterator = Spliterators.spliteratorUnknownSize(fileMemoryIterator(fileChannel,\n                chunkSize),\n                Spliterator.IMMUTABLE);\n        return StreamSupport.stream(spliterator,\n                false);\n    }\n\n    private static Iterator<ByteBuffer> fileMemoryIterator(FileChannel fileChannel, long chunkSize) throws IOException {\n        return new Iterator<>() {\n\n            private final long size = fileChannel.size();\n            private long start = 0;\n\n            @Override\n            public boolean hasNext() {\n                return start < size;\n            }\n\n            @Override\n            public ByteBuffer next() {\n                try {\n                    var buffer = fileChannel.map(MapMode.READ_ONLY,\n                            start,\n                            Math.min(chunkSize,\n                                    size - start));\n                    var limmit = buffer.limit() - 1;\n                    while (buffer.get(limmit) != '\\n')\n                        limmit--;\n                    limmit++;\n                    buffer.limit(limmit);\n                    start += limmit;\n                    return buffer;\n                }\n                catch (IOException ex) {\n                    throw new UncheckedIOException(ex);\n                }\n            }\n        };\n    }\n\n    private static final class Stat {\n\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum = 0L;\n        private long count = 0L;\n\n        public static Stat combine(Stat m1,\n                                   Stat m2) {\n            var stat = new Stat();\n            stat.min = Math.min(m1.min, m2.min);\n            stat.max = Math.max(m1.max, m2.max);\n            stat.sum = m1.sum + m2.sum;\n            stat.count = m1.count + m2.count;\n            return stat;\n        }\n\n        private void update(int value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum += value;\n            this.count++;\n        }\n\n        @Override\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round((sum / 10.0) / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static final class ManagedComputation {\n        static <T> T compute(final Supplier<T> supplier) {\n            var managedBlocker = new ManagedSupplier<>(supplier);\n            try {\n                ForkJoinPool.managedBlock(managedBlocker);\n                return managedBlocker.getResult();\n            }\n            catch (InterruptedException e) {\n                Thread.currentThread().interrupt();\n                throw new RuntimeException(e);\n            }\n\n        }\n\n        private static class ManagedSupplier<T> implements ForkJoinPool.ManagedBlocker {\n            private final Supplier<T> task;\n            private T result;\n            private boolean isDone = false;\n\n            private ManagedSupplier(final Supplier<T> supplier) {\n                task = supplier;\n            }\n\n            @Override\n            public boolean block() {\n                result = task.get();\n                isDone = true;\n                return true;\n            }\n\n            @Override\n            public boolean isReleasable() {\n                return isDone;\n            }\n\n            T getResult() {\n                return result;\n            }\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_isolgpus.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.math.BigDecimal;\nimport java.math.RoundingMode;\nimport java.nio.BufferUnderflowException;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_isolgpus {\n\n    public static final int HISTOGRAMS_LENGTH = 1024 * 32;\n    public static final int HISTOGRAMS_MASK = HISTOGRAMS_LENGTH - 1;\n    public static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();\n    private static final String FILE = \"./measurements.txt\";\n    public static final byte SEPERATOR = 59;\n    public static final byte OFFSET = 48;\n    public static final byte NEGATIVE = 45;\n    public static final byte DECIMAL_POINT = 46;\n    public static final int MAX_CHUNK_SIZE = Integer.MAX_VALUE - 100; // bit of wiggle room\n    public static final byte NEW_LINE = 10;\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);\n\n        File file = Paths.get(FILE).toFile();\n        long length = file.length();\n        long chunksCount = length < 8_000_000 ? 1 : Math.max(THREAD_COUNT, (int) Math.ceil(length / (double) MAX_CHUNK_SIZE));\n\n        long estimatedChunkSize = length / chunksCount;\n\n        FileChannel channel = new RandomAccessFile(file, \"r\").getChannel();\n\n        List<Future<MeasurementCollector[]>> futures = new ArrayList<>();\n        for (int i = 0; i < chunksCount; i++) {\n            int finalI = i;\n            futures.add(executorService.submit(() -> handleChunk(channel, estimatedChunkSize * finalI, estimatedChunkSize, length)));\n        }\n\n        List<MeasurementCollector[]> measurementCollectors = new ArrayList<>();\n        for (Future<MeasurementCollector[]> result : futures) {\n            measurementCollectors.add(result.get());\n        }\n        executorService.shutdown();\n\n        Map<String, MeasurementCollector> measurementCollectorsByCity = mergeMeasurements(measurementCollectors);\n        List<MeasurementResult> results = measurementCollectorsByCity.values().stream().map(MeasurementResult::from).toList();\n\n        System.out.println(\"{\" + results.stream().map(MeasurementResult::toString).collect(Collectors.joining(\", \")) + \"}\");\n\n    }\n\n    private static Map<String, MeasurementCollector> mergeMeasurements(List<MeasurementCollector[]> resultsFromAllChunk) {\n        Map<String, MeasurementCollector> mergedResults = new TreeMap<>(Comparator.naturalOrder());\n\n        for (int i = 0; i < HISTOGRAMS_LENGTH; i++) {\n            for (MeasurementCollector[] resultFromSpecificChunk : resultsFromAllChunk) {\n                MeasurementCollector measurementCollectorFromChunk = resultFromSpecificChunk[i];\n                while (measurementCollectorFromChunk != null) {\n                    MeasurementCollector currentMergedResult = mergedResults.get(new String(measurementCollectorFromChunk.name));\n                    if (currentMergedResult == null) {\n                        currentMergedResult = new MeasurementCollector(measurementCollectorFromChunk.name, measurementCollectorFromChunk.nameSum);\n                        mergedResults.put(new String(currentMergedResult.name), currentMergedResult);\n                    }\n                    currentMergedResult.merge(measurementCollectorFromChunk);\n                    measurementCollectorFromChunk = measurementCollectorFromChunk.link;\n                }\n            }\n        }\n\n        return mergedResults;\n    }\n\n    // ----n---\n    private static MeasurementCollector[] handleChunk(FileChannel channel, long estimatedStart, long lengthOfChunk, long maxLengthOfFile) throws IOException {\n        // -1 to see if we're starting on a brand new message\n        // +200 for wiggle room to finish the final message\n\n        long seekStart = Math.max(estimatedStart - 1, 0);\n        long length = Math.min(lengthOfChunk + 200, maxLengthOfFile - seekStart);\n\n        MappedByteBuffer r = channel.map(FileChannel.MapMode.READ_ONLY, seekStart, length);\n\n        boolean isNegative;\n        byte[] valueBuffer = new byte[3];\n        MeasurementCollector[] measurementCollectors = new MeasurementCollector[HISTOGRAMS_LENGTH];\n        int i = 0;\n\n        // seek to the start of the next message\n        if (estimatedStart != 0) {\n            while (r.get() != NEW_LINE) {\n                i++;\n            }\n            i++;\n        }\n\n        try {\n\n            while (i <= lengthOfChunk) {\n                int nameSum = 0;\n                int hashResult = 0;\n                int nameStart;\n                byte aChar;\n                nameStart = i;\n                int nameBufferIndex = 0;\n                int valueIndex = 0;\n\n                // optimistically assume that the name is at least 4 bytes\n                int firstInt = r.getInt();\n                nameBufferIndex = 4;\n                nameSum = firstInt;\n                hashResult = 31 * firstInt;\n\n                while ((aChar = r.get()) != SEPERATOR) {\n                    nameSum += aChar;\n                    // hash as we go, stolen after a discussion with palmr\n                    hashResult = 31 * hashResult + aChar;\n                    nameBufferIndex++;\n\n                    // oh no we read too much, do it the byte for byte way instead\n                    if (aChar == NEW_LINE) {\n                        r.position(i);\n                        nameBufferIndex = 0;\n                        nameSum = 0;\n                        hashResult = 0;\n                    }\n                }\n\n                i += nameBufferIndex + 1;\n\n                isNegative = (aChar = r.get()) == NEGATIVE;\n                valueIndex = readNumber(isNegative, valueBuffer, valueIndex, aChar, r);\n\n                int decimalValue = r.getShort() >> 8;\n\n                int value = resolveValue(valueIndex, valueBuffer, decimalValue, isNegative);\n\n                MeasurementCollector measurementCollector = resolveMeasurementCollector(measurementCollectors, hashResult, nameStart, nameBufferIndex, nameSum, r);\n\n                measurementCollector.feed(value);\n                i += valueIndex + (isNegative ? 4 : 3);\n            }\n\n        }\n        catch (BufferUnderflowException e) {\n            if (i != maxLengthOfFile - seekStart) {\n                e.printStackTrace();\n                throw new RuntimeException(e);\n            }\n        }\n\n        return measurementCollectors;\n    }\n\n    private static MeasurementCollector resolveMeasurementCollector(MeasurementCollector[] measurementCollectors, int hash, int nameStart, int nameBufferLength,\n                                                                    int nameSum, MappedByteBuffer r) {\n        MeasurementCollector measurementCollector = measurementCollectors[hash & HISTOGRAMS_MASK];\n        if (measurementCollector == null) {\n            byte[] nameBuffer = new byte[nameBufferLength];\n            r.get(nameStart, nameBuffer, 0, nameBufferLength);\n            measurementCollector = new MeasurementCollector(nameBuffer, nameSum);\n            measurementCollectors[hash & HISTOGRAMS_MASK] = measurementCollector;\n        }\n        else {\n            // collision unhappy path, try to avoid\n            while (!nameEquals(measurementCollector.name, measurementCollector.nameSum, nameSum, nameBufferLength)) {\n                if (measurementCollector.link == null) {\n                    byte[] nameBuffer = new byte[nameBufferLength];\n                    r.get(nameStart, nameBuffer, 0, nameBufferLength);\n                    measurementCollector.link = new MeasurementCollector(nameBuffer, nameSum);\n                    measurementCollector = measurementCollector.link;\n                    break;\n                }\n                else {\n                    measurementCollector = measurementCollector.link;\n                }\n            }\n\n        }\n        return measurementCollector;\n    }\n\n    private static boolean nameEquals(byte[] existingName, int existingNameSum, int incomingNameSum, int nameBufferIndex) {\n\n        if (existingName.length != nameBufferIndex) {\n            return false;\n        }\n\n        return incomingNameSum == existingNameSum;\n    }\n\n    private static int resolveValue(int valueIndex, byte[] valueBuffer, int decimalValue, boolean isNegative) {\n        int value;\n        if (valueIndex == 1) {\n            value = ((valueBuffer[0] - OFFSET) * 10) + (decimalValue - OFFSET);\n        }\n        else // it's 2 digits\n        {\n            value = ((valueBuffer[0] - OFFSET) * 100) + ((valueBuffer[1] - OFFSET) * 10) + (decimalValue - OFFSET);\n        }\n\n        if (isNegative) {\n            value = Math.negateExact(value);\n        }\n        return value;\n    }\n\n    private static int readNumber(boolean isNegative, byte[] valueBuffer, int valueIndex, byte aChar, MappedByteBuffer r) {\n        if (!isNegative) {\n            valueBuffer[valueIndex++] = aChar;\n        }\n\n        // maybe one or two more\n        while ((aChar = r.get()) != DECIMAL_POINT) {\n            valueBuffer[valueIndex++] = aChar;\n        }\n        return valueIndex;\n    }\n\n    private static class MeasurementCollector {\n        private final byte[] name;\n        private final int nameSum;\n        public MeasurementCollector link;\n        private long sum;\n        private int count;\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n\n        public MeasurementCollector(byte[] name, int nameSum) {\n\n            this.name = name;\n            this.nameSum = nameSum;\n        }\n\n        public void feed(int value) {\n            sum += value;\n            count++;\n            min = Math.min(value, min);\n            max = Math.max(value, max);\n        }\n\n        public void merge(MeasurementCollector measurementCollector) {\n            this.sum += measurementCollector.sum;\n            this.count += measurementCollector.count;\n            this.min = Math.min(measurementCollector.min, this.min);\n            this.max = Math.max(measurementCollector.max, this.max);\n        }\n    }\n\n    private static class MeasurementResult {\n        private final String name;\n        private final double mean;\n        private final BigDecimal max;\n        private final BigDecimal min;\n\n        public MeasurementResult(String name, double mean, BigDecimal max, BigDecimal min) {\n\n            this.name = name;\n            this.mean = mean;\n            this.max = max;\n            this.min = min;\n        }\n\n        @Override\n        public String toString() {\n            return name + \"=\" + min + \"/\" + mean + \"/\" + max;\n        }\n\n        public static MeasurementResult from(MeasurementCollector mc) {\n            double mean = Math.round((double) mc.sum / (double) mc.count) / 10d;\n            BigDecimal max = BigDecimal.valueOf(mc.max).divide(BigDecimal.TEN, 1, RoundingMode.HALF_UP);\n            BigDecimal min = BigDecimal.valueOf(mc.min).divide(BigDecimal.TEN, 1, RoundingMode.HALF_UP);\n            return new MeasurementResult(new String(mc.name), mean, max, min);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_itaske.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.AbstractMap;\nimport java.util.Comparator;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_itaske {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private record Measurement(long count, double sum, double min, double max) {\n\n        Measurement(double value) {\n            this(1, value, value, value);\n        }\n\n\n        public String toString() {\n            StringBuilder builder = new StringBuilder();\n            builder.append(round(min));\n            builder.append(\"/\");\n            builder.append(round(sum/count));\n            builder.append(\"/\");\n            builder.append(round(max));\n\n            return builder.toString();\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n\n        Map<String, Measurement> resultMap = Files.lines(Path.of(FILE)).parallel()\n                .map(line -> {\n                    int separatorIndex = line.indexOf(\";\");\n                    String key = line.substring(0, separatorIndex);\n                    double value = Double.parseDouble(line.substring(separatorIndex + 1));\n                    return new AbstractMap.SimpleEntry<>(key, value);\n                })\n                .collect(Collectors.toConcurrentMap(\n                        entry -> entry.getKey(),\n                        entry -> new Measurement(entry.getValue()),\n                        ((measurement1, measurement2) -> new Measurement(\n                                measurement1.count + measurement2.count,\n                                measurement1.sum + measurement2.sum,\n                                Math.min(measurement1.min, measurement2.min),\n                                Math.max(measurement1.max, measurement2.max)))));\n\n        System.out.println(\n                resultMap.entrySet().stream().sorted(Map.Entry.comparingByKey()).map(Object::toString).collect(Collectors.joining(\", \", \"{\", \"}\")));\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ivanklaric.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_ivanklaric {\n    private static final String FILE = \"measurements.txt\";\n\n    record CityTemps (double min, double max, double sum, long count) {\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double num) {\n            return Math.round(num * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        Stream<String> lines = Files.lines(Paths.get(FILE));\n        ConcurrentMap<String, CityTemps> cityStats = new ConcurrentSkipListMap<>();\n\n        lines.parallel().forEach(line -> {\n            int splitterLoc = line.indexOf(';');\n            double temp = Double.parseDouble(line.substring(splitterLoc + 1, line.length()));\n\n            cityStats.merge(line.substring(0, splitterLoc), new CityTemps(temp, temp, temp, 1),\n                    (oldValue, defaultValue) -> {\n                        return new CityTemps(Math.min(oldValue.min, temp), Math.max(oldValue.max, temp), oldValue.sum + temp, oldValue.count + 1);\n                    });\n        });\n        System.out.println(cityStats);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_iziamos.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.UncheckedIOException;\nimport java.lang.foreign.Arena;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.CompletableFuture;\n\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static java.nio.file.StandardOpenOption.READ;\n\npublic class CalculateAverage_iziamos {\n    private static final sun.misc.Unsafe UNSAFE = initUnsafe();\n\n    private static sun.misc.Unsafe initUnsafe() {\n        try {\n            java.lang.reflect.Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (sun.misc.Unsafe) theUnsafe.get(sun.misc.Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final Arena GLOBAL_ARENA = Arena.global();\n\n    public static void main(String[] args) throws Exception {\n        // final long chunkSize = Long.MAX_VALUE;\n        final long chunkSize = 64 * 1024 * 1024;\n\n        final FileChannel fileChannel;\n        try {\n            fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), READ);\n        }\n        catch (final IOException e) {\n            throw new UncheckedIOException(e);\n        }\n\n        final var seg = fileChannel.map(READ_ONLY, 0, fileChannel.size(), GLOBAL_ARENA);\n\n        final long fileSize = seg.byteSize();\n        final long threadCount = 1 + fileSize / chunkSize;\n\n        final var processingFutures = new CompletableFuture[(int) threadCount];\n        for (int i = 0; i < threadCount; ++i) {\n            processingFutures[i] = processSegment(seg.address(), seg.address() + fileSize, i, chunkSize);\n        }\n\n        final long aggregate = (long) processingFutures[0].get();\n        for (int i = 1; i < processingFutures.length; i++) {\n            final long r = (long) processingFutures[i].get();\n            ByteBackedResultSet.merge(aggregate, r);\n        }\n\n        final Map<String, ResultRow> output = new TreeMap<>();\n        ByteBackedResultSet.forEach(aggregate,\n                (name, min, max, sum, count) -> output.put(name, new ResultRow(min, (double) sum / count, max)));\n\n        System.out.println(output);\n    }\n\n    private record ResultRow(long min, double mean, long max) {\n        public String toString() {\n            return STR.\"\\{formatLong(min)}/\\{round(mean)}/\\{formatLong(max)}\";\n        }\n\n        private double formatLong(final long value) {\n            return value / 10.0;\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n    }\n\n    private static CompletableFuture<Long> processSegment(final long basePointer,\n                                                          final long endPointer,\n                                                          final long chunkNumber,\n                                                          final long chunkSize) {\n        final var ret = new CompletableFuture<Long>();\n\n        Thread.ofVirtual().start(() -> {\n            final long relativeStart = chunkNumber * chunkSize;\n            final long absoluteStart = basePointer + relativeStart;\n\n            final long absoluteEnd = computeAbsoluteEndWithSlack(absoluteStart + chunkSize, endPointer);\n            final long startOffsetAfterSkipping = skipIncomplete(basePointer, absoluteStart);\n\n            final long result = processEvents(startOffsetAfterSkipping, absoluteEnd);\n            ret.complete(result);\n        });\n\n        return ret;\n    }\n\n    private static long computeAbsoluteEndWithSlack(final long chunk, final long endPointer) {\n        return Long.compareUnsigned(endPointer, chunk) > 0 ? chunk : endPointer;\n    }\n\n    private static long skipIncomplete(final long basePointer, final long start) {\n        if (start == basePointer) {\n            return start;\n        }\n        for (long i = 0;; ++i) {\n            final byte b = UNSAFE.getByte(start + i);\n            if (b == '\\n') {\n                return start + i + 1;\n            }\n        }\n    }\n\n    private static long processEvents(final long start, final long limit) {\n        final long result = ByteBackedResultSet.createResultSet();\n        scalarLoop(start, limit, result);\n        return result;\n    }\n\n    private static void scalarLoop(final long start, final long limit, final long result) {\n        final LoopCursor cursor = new LoopCursor(start, limit);\n        while (cursor.hasMore()) {\n            final long address = cursor.getCurrentAddress();\n            final int length = cursor.getStringLength();\n            final int hash = cursor.getHash();\n            final int value = cursor.getCurrentValue();\n            ByteBackedResultSet.put(result, address, length, hash, value);\n        }\n    }\n\n    public static class LoopCursor {\n        private long pointer;\n        private final long limit;\n\n        private int hash = 0;\n\n        public LoopCursor(final long pointer, final long limit) {\n            this.pointer = pointer;\n            this.limit = limit;\n        }\n\n        public long getCurrentAddress() {\n            return pointer;\n        }\n\n        public int getStringLength() {\n            int strLen = 0;\n            hash = 0;\n\n            byte b = UNSAFE.getByte(pointer);\n            for (; b != ';'; ++strLen, b = UNSAFE.getByte(pointer + strLen)) {\n                hash = 31 * hash + b;\n            }\n            pointer += strLen + 1;\n\n            return strLen;\n        }\n\n        public int getHash() {\n            return hash;\n        }\n\n        public int getCurrentValue() {\n            return getCurrentValueMeryKitty();\n        }\n\n        /**\n         * No point rewriting what would essentially be the same code <3.\n         */\n        public int getCurrentValueMeryKitty() {\n            long word = UNSAFE.getLong(pointer);\n            if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {\n                word = Long.reverseBytes(word);\n            }\n\n            int decimalSepPos = Long.numberOfTrailingZeros(~word & 0x10101000);\n            int shift = 28 - decimalSepPos;\n\n            long signed = (~word << 59) >> 63;\n            long designMask = ~(signed & 0xFF);\n\n            long digits = ((word & designMask) << shift) & 0x0F000F0F00L;\n\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            int increment = (decimalSepPos >>> 3) + 3;\n\n            pointer += increment;\n            return (int) ((absValue ^ signed) - signed);\n        }\n\n        public boolean hasMore() {\n            return pointer < limit;\n        }\n    }\n\n    public interface ResultConsumer {\n        void consume(final String name, final int min, final int max, final long sum, final long count);\n    }\n\n    static class ByteBackedResultSet {\n        private static final int MAP_SIZE = 16384 * 4;\n        private static final int MASK = MAP_SIZE - 1;\n        private static final long STRUCT_SIZE = 64;\n        private static final long BYTE_SIZE = MAP_SIZE * STRUCT_SIZE;\n        private static final long STRING_OFFSET = 0;\n        private static final long STRING_LEN_OFFSET = 8;\n        private static final long HASH_OFFSET = 12;\n        private static final long MIN_OFFSET = 16;\n        private static final long MAX_OFFSET = 20;\n        private static final long SUM_OFFSET = 24;\n        private static final long COUNT_OFFSET = 32;\n\n        public static long createResultSet() {\n            final long baseAddress = UNSAFE.allocateMemory(BYTE_SIZE);\n            UNSAFE.setMemory(baseAddress, BYTE_SIZE, (byte) 0);\n            return baseAddress;\n        }\n\n        public static void put(final long baseAddress, final long address, final int length, final int hash, final int value) {\n            final long slot = findSlot(baseAddress, hash, address, length);\n            final long structBase = baseAddress + (slot * STRUCT_SIZE);\n\n            final int min = UNSAFE.getInt(structBase + MIN_OFFSET);\n            final int max = UNSAFE.getInt(structBase + MAX_OFFSET);\n            final long sum = UNSAFE.getLong(structBase + SUM_OFFSET);\n            final long count = UNSAFE.getLong(structBase + COUNT_OFFSET);\n\n            UNSAFE.putLong(structBase, address);\n            UNSAFE.putInt(structBase + STRING_LEN_OFFSET, length);\n            UNSAFE.putInt(structBase + HASH_OFFSET, hash);\n\n            UNSAFE.putInt(structBase + MIN_OFFSET, Math.min(value, min));\n            UNSAFE.putInt(structBase + MAX_OFFSET, Math.max(value, max));\n            UNSAFE.putLong(structBase + SUM_OFFSET, sum + value);\n            UNSAFE.putLong(structBase + COUNT_OFFSET, count + 1);\n        }\n\n        public static void forEach(final long baseAddress, final ResultConsumer resultConsumer) {\n            for (long i = 0; i < BYTE_SIZE; i += STRUCT_SIZE) {\n                final long structBase = baseAddress + i;\n                final long stringBase = UNSAFE.getLong(structBase);\n                if (stringBase == 0) {\n                    continue;\n                }\n\n                final int min = UNSAFE.getInt(structBase + MIN_OFFSET);\n                final int max = UNSAFE.getInt(structBase + MAX_OFFSET);\n                final long sum = UNSAFE.getLong(structBase + SUM_OFFSET);\n                final long count = UNSAFE.getLong(structBase + COUNT_OFFSET);\n\n                final int strLen = UNSAFE.getInt(structBase + STRING_LEN_OFFSET);\n                final byte[] bytes = new byte[strLen];\n                for (int j = 0; j < strLen; ++j) {\n                    bytes[j] = UNSAFE.getByte(stringBase + j);\n                }\n\n                resultConsumer.consume(new String(bytes, UTF_8), min, max, sum, count);\n            }\n        }\n\n        public static void merge(final long baseAddress, final long other) {\n            for (long i = 0; i < BYTE_SIZE; i += STRUCT_SIZE) {\n                final long otherStructBase = other + i;\n                if (UNSAFE.getLong(otherStructBase) == 0) {\n                    continue;\n                }\n\n                final long otherStringStart = UNSAFE.getLong(otherStructBase);\n                final int otherStringLength = UNSAFE.getInt(otherStructBase + STRING_LEN_OFFSET);\n                final int otherStringHash = UNSAFE.getInt(otherStructBase + HASH_OFFSET);\n\n                final long slot = findSlot(baseAddress, otherStringHash, otherStringStart, otherStringLength);\n\n                final long thisStructBase = baseAddress + (slot * STRUCT_SIZE);\n\n                final int min = UNSAFE.getInt(thisStructBase + MIN_OFFSET);\n                final int max = UNSAFE.getInt(thisStructBase + MAX_OFFSET);\n                final long sum = UNSAFE.getLong(thisStructBase + SUM_OFFSET);\n                final long count = UNSAFE.getLong(thisStructBase + COUNT_OFFSET);\n\n                final int otherMin = UNSAFE.getInt(otherStructBase + MIN_OFFSET);\n                final int otherMax = UNSAFE.getInt(otherStructBase + MAX_OFFSET);\n                final long otherSum = UNSAFE.getLong(otherStructBase + SUM_OFFSET);\n                final long otherCount = UNSAFE.getLong(otherStructBase + COUNT_OFFSET);\n\n                UNSAFE.putLong(thisStructBase, otherStringStart);\n                UNSAFE.putInt(thisStructBase + STRING_LEN_OFFSET, otherStringLength);\n                UNSAFE.putInt(thisStructBase + HASH_OFFSET, otherStringHash);\n\n                UNSAFE.putInt(thisStructBase + MIN_OFFSET, Math.min(otherMin, min));\n                UNSAFE.putInt(thisStructBase + MAX_OFFSET, Math.max(otherMax, max));\n                UNSAFE.putLong(thisStructBase + SUM_OFFSET, sum + otherSum);\n                UNSAFE.putLong(thisStructBase + COUNT_OFFSET, count + otherCount);\n            }\n        }\n\n        private static int findSlot(final long baseAddress,\n                                    final int hash,\n                                    final long otherStringAddress,\n                                    final int otherStringLength) {\n\n            for (int slot = mask(hash);; slot = mask(++slot)) {\n                final long structBase = baseAddress + ((long) slot * STRUCT_SIZE);\n                final long nameStart = UNSAFE.getLong(structBase);\n                if (nameStart == 0) {\n                    UNSAFE.putInt(structBase + MIN_OFFSET, Integer.MAX_VALUE);\n                    UNSAFE.putInt(structBase + MAX_OFFSET, Integer.MIN_VALUE);\n                    return slot;\n                }\n\n                final int nameLength = UNSAFE.getInt(structBase + STRING_LEN_OFFSET);\n                if (stringEquals(nameStart, nameLength, otherStringAddress, otherStringLength)) {\n                    return slot;\n                }\n            }\n        }\n\n        private static boolean stringEquals(final long thisNameAddress,\n                                            final int thisStringLength,\n                                            final long otherNameAddress,\n                                            final long otherNameLength) {\n            if (thisStringLength != otherNameLength) {\n                return false;\n            }\n\n            int i = 0;\n            for (; i < thisStringLength - 7; i += 8) {\n                if (UNSAFE.getLong(thisNameAddress + i) != UNSAFE.getLong(otherNameAddress + i)) {\n                    return false;\n                }\n            }\n\n            final long remainingToCheck = thisStringLength - i;\n            final long finalBytesMask = ((1L << remainingToCheck * 8)) - 1;\n            final long thisLastWord = UNSAFE.getLong(thisNameAddress + i);\n            final long otherLastWord = UNSAFE.getLong(otherNameAddress + i);\n\n            return 0 == ((thisLastWord ^ otherLastWord) & finalBytesMask);\n        }\n\n        public static int mask(final int value) {\n            return MASK & value;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_japplis.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\n\n/**\n * Maybe not the fastest but trying to get the most readable code for the performance.\n *\n * It allows:\n *  - pass another file as argument\n *  - the first lines can start with comments lines using '#'\n *  - the temperatures can have more than one fraction digit but it needs to be constant in the file\n *  - it does not require much RAM\n *  - Java 8 as minimal Java version\n * Assumptions\n *  - No temperatures are above 100 or below -100\n *  - the last character of the file is \\n\n *\n * Changelog:\n * - First local attempt with FileReader and TreeMap: Way too long\n * - Switched to InputStream and ConcurrentHashMap: 23\"\n * - Added Semaphore to avoid OOMException: 23\"\n * - Replaced String with my own ByteText class: a bit slower (~10%)\n * - Replaced compute lambda call with synchronized(city.intern()): 43\" (due to intern())\n * - Removed BufferedInputStream and replaced Measurement with IntSummaryStatistics (thanks davecom): still 23\" but cleaner code\n * - Execute same code on 1BRC server: 41\"\n * - One HashMap per thread: 17\" locally (12\" on 1BRC server)\n * - Read file in multiple threads if available and\n * - Changed String to (byte[]) Text with cache: 18\" locally (but 8\" -> 5\" on laptop)\n *\n * @author Anthony Goubard - Japplis\n */\npublic class CalculateAverage_japplis {\n\n    private static final String DEFAULT_MEASUREMENT_FILE = \"measurements.txt\";\n    private static final int BUFFER_SIZE = 5 * 1024 * 1024; // 5 MB\n    private static final int MAX_COMPUTE_THREADS = Runtime.getRuntime().availableProcessors();\n\n    private int precision = -1;\n    private int precisionLimitTenth;\n    private long fileSize;\n    private Map<Text, IntSummaryStatistics> cityMeasurementMap = new ConcurrentHashMap<>(10_000);\n    private List<Byte> previousBlockLastLine = new ArrayList<>();\n    private Semaphore readFileLock = new Semaphore(MAX_COMPUTE_THREADS);\n    private Queue<ByteArray> bufferPool = new ConcurrentLinkedQueue<>();\n\n    private void parseTemperatures(File measurementsFile) throws Exception {\n        fileSize = measurementsFile.length();\n        int blockIndex = 0;\n        int totalBlocks = (int) (fileSize / BUFFER_SIZE) + 1;\n        ExecutorService threadPool = Executors.newFixedThreadPool(MAX_COMPUTE_THREADS);\n        List<Future> parseBlockTasks = new ArrayList<>();\n\n        while (blockIndex < totalBlocks) {\n            int availableReadThreads = Math.min(readFileLock.availablePermits(), totalBlocks - blockIndex);\n            if (availableReadThreads == 0) {\n                readFileLock.acquire(); // No need to loop in the 'while' if all threads are busy\n                readFileLock.release();\n            }\n            List<Future<ByteArray>> readBlockTasks = new ArrayList<>();\n            for (int i = 0; i < availableReadThreads; i++) {\n                readFileLock.acquire(); // Wait if all threads are busy\n                Callable<ByteArray> blockReader = readBlock(measurementsFile, blockIndex);\n                Future<ByteArray> readBlockTask = threadPool.submit(blockReader);\n                readBlockTasks.add(readBlockTask);\n                blockIndex++;\n            }\n            for (Future<ByteArray> readBlockTask : readBlockTasks) {\n                ByteArray buffer = readBlockTask.get();\n                if (buffer.array().length > 0) {\n                    int startIndex = handleSplitLine(buffer.array());\n                    readFileLock.acquire(); // Wait if all threads are busy\n                    Runnable blockParser = parseTemperaturesBlock(buffer, startIndex);\n                    Future parseBlockTask = threadPool.submit(blockParser);\n                    parseBlockTasks.add(parseBlockTask);\n                }\n            }\n        }\n        for (Future parseBlockTask : parseBlockTasks) { // Wait for all tasks to finish\n            parseBlockTask.get();\n        }\n        threadPool.shutdownNow();\n    }\n\n    private Callable<ByteArray> readBlock(File measurementsFile, long blockIndex) {\n        return () -> {\n            long fileIndex = blockIndex * BUFFER_SIZE;\n            if (fileIndex >= fileSize) {\n                readFileLock.release();\n                return new ByteArray(0);\n            }\n            try (InputStream measurementsFileIS = new FileInputStream(measurementsFile)) {\n                if (fileIndex > 0) {\n                    long skipped = measurementsFileIS.skip(fileIndex);\n                    while (skipped != fileIndex) {\n                        skipped += measurementsFileIS.skip(fileIndex - skipped);\n                    }\n                }\n                long bufferSize = Math.min(BUFFER_SIZE, fileSize - fileIndex);\n                ByteArray buffer = bufferSize == BUFFER_SIZE ? bufferPool.poll() : new ByteArray((int) bufferSize);\n                if (buffer == null) {\n                    buffer = new ByteArray(BUFFER_SIZE);\n                }\n                int totalRead = measurementsFileIS.read(buffer.array(), 0, (int) bufferSize);\n                while (totalRead < bufferSize) {\n                    byte[] extraBuffer = new byte[(int) (bufferSize - totalRead)];\n                    int readCount = measurementsFileIS.read(extraBuffer);\n                    System.arraycopy(extraBuffer, 0, buffer.array(), totalRead, readCount);\n                    totalRead += readCount;\n                }\n                readFileLock.release();\n                return buffer;\n            }\n        };\n    }\n\n    private Runnable parseTemperaturesBlock(ByteArray buffer, int startIndex) {\n        Runnable countAverageRun = () -> {\n            int bufferIndex = startIndex;\n            Map<Text, IntSummaryStatistics> blockCityMeasurementMap = new HashMap<>(10_000);\n            Map<Integer, Text> textPool = new HashMap<>(10_000);\n            byte[] bufferArray = buffer.array();\n            try {\n                while (bufferIndex < bufferArray.length) {\n                    bufferIndex = readNextLine(bufferIndex, bufferArray, blockCityMeasurementMap, textPool);\n                }\n            }\n            catch (ArrayIndexOutOfBoundsException ex) {\n                // Done reading and parsing the buffer\n            }\n            if (bufferArray.length == BUFFER_SIZE)\n                bufferPool.add(buffer);\n            mergeBlockResults(blockCityMeasurementMap);\n            readFileLock.release();\n        };\n        return countAverageRun;\n    }\n\n    private int handleSplitLine(byte[] buffer) {\n        int bufferIndex = readFirstLines(buffer);\n        List<Byte> lastLine = new ArrayList<>(100); // Store the last (partial) line of the block\n        int tailIndex = buffer.length;\n        byte car = buffer[--tailIndex];\n        while (car != '\\n') {\n            lastLine.add(0, car);\n            car = buffer[--tailIndex];\n        }\n        if (previousBlockLastLine.isEmpty()) {\n            previousBlockLastLine = lastLine;\n            return bufferIndex;\n        }\n        bufferIndex = readSplitLine(buffer);\n        previousBlockLastLine = lastLine;\n        return bufferIndex;\n    }\n\n    private int readSplitLine(byte[] buffer) {\n        int bufferIndex = 0;\n        byte car = buffer[bufferIndex++];\n        while (car != '\\n') {\n            previousBlockLastLine.add(car);\n            car = buffer[bufferIndex++];\n        }\n        previousBlockLastLine.add((byte) '\\n');\n        byte[] splitLineBytes = new byte[previousBlockLastLine.size()];\n        for (int i = 0; i < splitLineBytes.length; i++) {\n            splitLineBytes[i] = previousBlockLastLine.get(i);\n        }\n        readNextLine(0, splitLineBytes, cityMeasurementMap, new HashMap<>());\n        return bufferIndex;\n    }\n\n    private int readFirstLines(byte[] buffer) {\n        if (precision >= 0)\n            return 0; // not the first lines of the file\n        int bufferIndex = 0;\n        while (buffer[bufferIndex] == '#') { // read comments (like in weather_stations.csv)\n            while (buffer[bufferIndex++] != '\\n') {\n            }\n        }\n        int startIndex = bufferIndex;\n        int dotPos = bufferIndex;\n        byte car = buffer[bufferIndex++];\n        while (car != '\\n') {\n            if (car == '.') {\n                dotPos = bufferIndex;\n            }\n            car = buffer[bufferIndex++];\n        }\n        precision = bufferIndex - dotPos - 1;\n        int precisionLimit = (int) Math.pow(10, precision);\n        precisionLimitTenth = precisionLimit * 10;\n        return startIndex;\n    }\n\n    private int readNextLine(int bufferIndex, byte[] buffer, Map<Text, IntSummaryStatistics> blockCityMeasurementMap, Map<Integer, Text> textPool) {\n        int startLineIndex = bufferIndex;\n        while (buffer[bufferIndex] != (byte) ';') {\n            bufferIndex++;\n        }\n        // String city = new String(buffer, startLineIndex, bufferIndex - startLineIndex, StandardCharsets.UTF_8);\n        Text city = Text.getByteText(buffer, startLineIndex, bufferIndex - startLineIndex, textPool);\n        bufferIndex++; // skip ';'\n        int temperature = readTemperature(buffer, bufferIndex);\n        bufferIndex += precision + 3; // digit, dot and CR\n        if (temperature < 0) {\n            bufferIndex++;\n        }\n        if (temperature <= -precisionLimitTenth || temperature >= precisionLimitTenth) {\n            bufferIndex++;\n        }\n        addTemperature(city, temperature, blockCityMeasurementMap);\n        return bufferIndex;\n    }\n\n    private int readTemperature(byte[] buffer, int bufferIndex) {\n        boolean negative = buffer[bufferIndex] == (byte) '-';\n        if (negative) {\n            bufferIndex++;\n        }\n        byte digit = buffer[bufferIndex++];\n        int temperature = 0;\n        while (digit != (byte) '\\n') {\n            temperature = temperature * 10 + (digit - (byte) '0');\n            digit = buffer[bufferIndex++];\n            if (digit == (byte) '.') { // Skip '.'\n                digit = buffer[bufferIndex++];\n            }\n        }\n        if (negative) {\n            temperature = -temperature;\n        }\n        return temperature;\n    }\n\n    private void addTemperature(Text city, int temperature, Map<Text, IntSummaryStatistics> blockCityMeasurementMap) {\n        IntSummaryStatistics measurement = blockCityMeasurementMap.get(city);\n        if (measurement == null) {\n            measurement = new IntSummaryStatistics();\n            blockCityMeasurementMap.put(city, measurement);\n        }\n        measurement.accept(temperature);\n    }\n\n    private void mergeBlockResults(Map<Text, IntSummaryStatistics> blockCityMeasurementMap) {\n        blockCityMeasurementMap.forEach((city, measurement) -> {\n            cityMeasurementMap.compute(city, (town, currentMeasurement) -> {\n                if (currentMeasurement == null) {\n                    return measurement;\n                }\n                currentMeasurement.combine(measurement);\n                return currentMeasurement;\n            });\n        });\n    }\n\n    private void printTemperatureStatsByCity() {\n        Set<Text> sortedCities = new TreeSet<>(cityMeasurementMap.keySet());\n        StringBuilder result = new StringBuilder(cityMeasurementMap.size() * 40);\n        result.append('{');\n        sortedCities.forEach(city -> {\n            IntSummaryStatistics measurement = cityMeasurementMap.get(city);\n            result.append(city);\n            result.append(getTemperatureStats(measurement));\n        });\n        if (!sortedCities.isEmpty()) {\n            result.delete(result.length() - 2, result.length());\n        }\n        result.append('}');\n        String temperaturesByCity = result.toString();\n        System.out.println(temperaturesByCity);\n    }\n\n    private String getTemperatureStats(IntSummaryStatistics measurement) {\n        StringBuilder stats = new StringBuilder(19);\n        stats.append('=');\n        appendTemperature(stats, measurement.getMin());\n        stats.append('/');\n        int average = (int) Math.round(measurement.getAverage());\n        appendTemperature(stats, average);\n        stats.append('/');\n        appendTemperature(stats, measurement.getMax());\n        stats.append(\", \");\n        return stats.toString();\n    }\n\n    private void appendTemperature(StringBuilder resultBuilder, int temperature) {\n        String temperatureAsText = String.valueOf(temperature);\n        int minCharacters = precision + (temperature < 0 ? 2 : 1);\n        for (int i = temperatureAsText.length(); i < minCharacters; i++) {\n            temperatureAsText = temperature < 0 ? \"-0\" + temperatureAsText.substring(1) : \"0\" + temperatureAsText;\n        }\n        int dotPosition = temperatureAsText.length() - precision;\n        resultBuilder.append(temperatureAsText.substring(0, dotPosition));\n        resultBuilder.append('.');\n        resultBuilder.append(temperatureAsText.substring(dotPosition));\n    }\n\n    public static final void main(String... args) throws Exception {\n        CalculateAverage_japplis cityTemperaturesCalculator = new CalculateAverage_japplis();\n        String measurementFile = args.length == 1 ? args[0] : DEFAULT_MEASUREMENT_FILE;\n        cityTemperaturesCalculator.parseTemperatures(new File(measurementFile));\n        cityTemperaturesCalculator.printTemperatureStatsByCity();\n    }\n\n    private class ByteArray {\n\n        private byte[] array;\n\n        private ByteArray(int size) {\n            array = new byte[size];\n        }\n\n        private byte[] array() {\n            return array;\n        }\n    }\n\n    private static class Text implements Comparable<Text> {\n\n        private final byte[] textBytes;\n        private final int hash;\n        private String text;\n\n        private Text(byte[] buffer, int startIndex, int length, int hash) {\n            textBytes = new byte[length];\n            this.hash = hash;\n            System.arraycopy(buffer, startIndex, textBytes, 0, length);\n        }\n\n        private static Text getByteText(byte[] buffer, int startIndex, int length, Map<Integer, Text> textPool) {\n            int hash = hashCode(buffer, startIndex, length);\n            Text textFromPool = textPool.get(hash);\n            if (textFromPool == null || !Arrays.equals(buffer, startIndex, startIndex + length, textFromPool.textBytes, 0, length)) {\n                Text newText = new Text(buffer, startIndex, length, hash);\n                textPool.put(hash, newText);\n                return newText;\n            }\n            return textFromPool;\n        }\n\n        private static int hashCode(byte[] buffer, int startIndex, int length) {\n            int hash = 31;\n            int endIndex = startIndex + length;\n            for (int i = startIndex; i < endIndex; i++) {\n                hash = 31 * hash + buffer[i];\n            }\n            return hash;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public boolean equals(Object other) {\n            return other != null &&\n                    hashCode() == other.hashCode() &&\n                    other instanceof Text &&\n                    Arrays.equals(textBytes, ((Text) other).textBytes);\n        }\n\n        @Override\n        public int compareTo(Text other) {\n            return toString().compareTo(other.toString());\n        }\n\n        @Override\n        public String toString() {\n            if (text == null) {\n                text = new String(textBytes, StandardCharsets.UTF_8);\n            }\n            return text;\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jatingala.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\n\npublic class CalculateAverage_jatingala {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(final String[] args) throws IOException {\n        final int processorCount = Math.max(Runtime.getRuntime().availableProcessors(), 8);\n\n        try (final RandomAccessFile randomAccessFile = new RandomAccessFile(FILE, \"r\")) {\n            final long[][] chunks = getChunkPositions(randomAccessFile, processorCount);\n            final Map<String, Statistics> result = Arrays.stream(chunks)\n                    .parallel()\n                    .map(chunk -> {\n                        try {\n                            final MappedByteBuffer mappedByteBuffer = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, chunk[0], chunk[1]);\n                            return consumeChunk(mappedByteBuffer);\n                        }\n                        catch (final Exception e) {\n                            System.out.println(e.getMessage());\n                            return new HashMap<String, Statistics>();\n                        }\n                    })\n                    .reduce((a, b) -> {\n                        a.forEach((k, v) -> {\n                            final Statistics s = b.get(k);\n                            if (s != null)\n                                v.merge(s);\n                        });\n                        b.forEach(a::putIfAbsent);\n                        return a;\n                    })\n                    .orElseGet(Collections::emptyMap);\n\n            System.out.println(new TreeMap<>(result));\n        }\n    }\n\n    private static long[][] getChunkPositions(final RandomAccessFile file, final int chunks) throws IOException {\n        final long[][] result = new long[chunks][];\n\n        final long fileSize = file.length();\n        final long chunkSize = Math.ceilDiv(fileSize, chunks);\n        long chunkStartPosition = 0;\n        for (int i = 0; i < chunks; i++) {\n            file.seek(Math.min(chunkStartPosition + chunkSize, fileSize));\n\n            while (file.getFilePointer() < fileSize && file.readByte() != '\\n') {\n                // find next newline, noop\n            }\n\n            // startPointer & length\n            result[i] = new long[]{ chunkStartPosition, file.getFilePointer() - chunkStartPosition };\n            chunkStartPosition = file.getFilePointer();\n        }\n\n        return result;\n    }\n\n    private static Map<String, Statistics> consumeChunk(final MappedByteBuffer mappedByteBuffer) {\n        final Map<String, Statistics> statisticsMap = new HashMap<>();\n\n        while (mappedByteBuffer.hasRemaining()) {\n            final String key = parseKey(mappedByteBuffer);\n            final double value = parseNumber(mappedByteBuffer);\n            statisticsMap.computeIfAbsent(key, _ -> new Statistics()).update(value);\n        }\n\n        return statisticsMap;\n    }\n\n    private static String parseKey(final MappedByteBuffer mappedByteBuffer) {\n        final ByteArrayOutputStream keyBytes = new ByteArrayOutputStream();\n        while (mappedByteBuffer.hasRemaining()) {\n            final byte val = mappedByteBuffer.get();\n            if (val == ';')\n                break;\n            keyBytes.write(val);\n        }\n        return keyBytes.toString();\n    }\n\n    private static double parseNumber(final MappedByteBuffer mappedByteBuffer) {\n        boolean negate = false;\n        int temp = 0;\n        while (mappedByteBuffer.hasRemaining()) {\n            final byte val = mappedByteBuffer.get();\n\n            if (val == '\\n')\n                break;\n            if (val == '-') {\n                negate = true;\n                continue;\n            }\n            if (val == '.')\n                continue;\n\n            temp = 10 * temp + (val - '0');\n        }\n        return (negate ? -1 : 1) * (temp / 10.0);\n    }\n\n    private static class Statistics {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        private static double round(final double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public void update(final double reading) {\n            this.min = Math.min(min, reading);\n            this.max = Math.max(max, reading);\n            this.sum += reading;\n            ++count;\n        }\n\n        public void merge(final Statistics other) {\n            this.min = Math.min(min, other.min);\n            this.max = Math.max(max, other.max);\n            this.sum += other.sum;\n            this.count += other.count;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round(sum / count)}/\\{round(max)}\";\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_javamak.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collector;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_javamak {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    ;\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    public static void main(String[] args) throws IOException {\n        // Map<String, Double> measurements1 = Files.lines(Paths.get(FILE))\n        // .map(l -> l.split(\";\"))\n        // .collect(groupingBy(m -> m[0], averagingDouble(m -> Double.parseDouble(m[1]))));\n        //\n        // measurements1 = new TreeMap<>(measurements1.entrySet()\n        // .stream()\n        // .collect(toMap(e -> e.getKey(), e -> Math.round(e.getValue() * 10.0) / 10.0)));\n        // System.out.println(measurements1);\n\n        Collector<Measurement, MeasurementAggregator, ResultRow> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    a.min = Math.min(a.min, m.value);\n                    a.max = Math.max(a.max, m.value);\n                    a.sum += m.value;\n                    a.count++;\n                },\n                (agg1, agg2) -> {\n                    var res = new MeasurementAggregator();\n                    res.min = Math.min(agg1.min, agg2.min);\n                    res.max = Math.max(agg1.max, agg2.max);\n                    res.sum = agg1.sum + agg2.sum;\n                    res.count = agg1.count + agg2.count;\n\n                    return res;\n                },\n                agg -> new ResultRow(agg.min, agg.sum / agg.count, agg.max));\n\n        var path = Paths.get(FILE);\n\n        var a = calcChunks(path).entrySet().parallelStream()\n                .flatMap(entry -> getLinesFromFile(path, entry)) // read file for each chunk and get the lines\n                .map(l -> new Measurement(l.split(\";\")))// convert each line to measurement object\n                .collect(groupingBy(Measurement::station, collector));\n        Map<String, ResultRow> measurements = new TreeMap<>(a);\n\n        System.out.println(measurements);\n    }\n\n    private static Stream<String> getLinesFromFile(Path path, Map.Entry<Long, Long> entry) {\n        try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {\n            channel.position(entry.getKey());\n            ByteBuffer buffer = ByteBuffer.allocate((int) (entry.getValue() - entry.getKey() + 1));\n            channel.read(buffer);\n            String chunk = new String(buffer.array());\n            return Arrays.stream(chunk.split(\"\\n\"));\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static Map<Long, Long> calcChunks(Path path) throws IOException {\n        long startPos = 0;\n        Map<Long, Long> retMap = new HashMap<>();\n        while (true) {\n            long endPos = calculateEndPosition(path, startPos, 1000 * 5000);\n            if (endPos == -1) {\n                break;\n            }\n            long finalStartPos = startPos;\n            retMap.put(finalStartPos, endPos);\n            startPos = endPos + 1;\n        }\n        return retMap;\n    }\n\n    private static long calculateEndPosition(Path path, long startPos, long chunkSize) throws IOException {\n        try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ)) {\n            if (startPos >= channel.size()) {\n                return -1;\n            }\n\n            long currentPos = startPos + chunkSize;\n            if (currentPos >= channel.size()) {\n                currentPos = channel.size() - 1;\n            }\n\n            channel.position(currentPos);\n            ByteBuffer buffer = ByteBuffer.allocate(1024);\n            int readBytes = channel.read(buffer);\n\n            if (readBytes > 0) {\n                for (int i = 0; i < readBytes; i++) {\n                    if (buffer.get(i) == '\\n') {\n                        break;\n                    }\n                    currentPos++;\n                }\n            }\n\n            return currentPos;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jbachorik.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.function.BiConsumer;\n\npublic class CalculateAverage_jbachorik {\n    private static final class Key {\n        final ByteBuffer bb;\n        final int offset;\n        final int len;\n        final long v0, v1;\n        final int hash;\n\n        Key(ByteBuffer bb, int offset, int len, long v0, long v1, int hash) {\n            this.bb = bb;\n            this.offset = offset;\n            this.len = len;\n            this.v0 = v0;\n            this.v1 = v1;\n            this.hash = hash;\n        }\n\n        public boolean equals(int offset, int len, long v0, long v1) {\n            // byte[] bytes = new byte[len];\n            // bb.get(offset, bytes);\n            // String str = new String(bytes);\n\n            if (((this.len ^ len) | (this.v0 ^ v0) | (this.v1 ^ v1)) != 0) {\n                return false;\n            }\n            for (int i = 0; i < len - 8; i += 8) {\n                if (bb.getLong(this.offset + i) != bb.getLong(offset + i)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @Override\n        public String toString() {\n            byte[] bytes = new byte[len];\n            bb.get(offset, bytes);\n            return new String(bytes);\n        }\n    }\n\n    private static final class Stats {\n        long min;\n        long max;\n        long count;\n        long sum;\n\n        Stats() {\n            min = Integer.MAX_VALUE;\n            max = Integer.MIN_VALUE;\n            count = 0;\n            sum = 0;\n        }\n\n        Stats add(long value) {\n            min = Math.min(min, value);\n            max = Math.max(max, value);\n            count++;\n            sum += value;\n            return this;\n        }\n\n        Stats merge(Stats other) {\n            synchronized (this) {\n                min = Math.min(min, other.min);\n                max = Math.max(max, other.max);\n                count += other.count;\n                sum += other.sum;\n            }\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"%.1f/%.1f/%.1f\", min / 10.0d, sum / (double) count / 10.0d, max / 10.0d);\n        }\n    }\n\n    private static final class StatsMap {\n        private static class StatsHolder {\n            private final Key key;\n            private final Stats stats;\n\n            StatsHolder(Key slice, Stats stats) {\n                this.key = slice;\n                this.stats = stats;\n            }\n\n            @Override\n            public String toString() {\n                return \"StatsHolder{\" +\n                        \"key=\" + key +\n                        \", stats=\" + stats +\n                        '}';\n            }\n        }\n\n        private static final int BUCKETS = 65536;\n        private static final int BUCKET_SIZE = 16;\n        private final StatsHolder[][] map = new StatsHolder[BUCKETS][BUCKET_SIZE];\n\n        public Stats getOrInsert(ByteBuffer buffer, int offset, int len, int idx, long v0, long v1) {\n            StatsHolder[] bucket = map[idx];\n            int bucketOffset = 0;\n            do {\n                StatsHolder statsHolder = bucket[bucketOffset];\n                if (statsHolder == null) {\n                    Stats stats = new Stats();\n                    bucket[bucketOffset] = new StatsHolder(new Key(buffer, offset, len, v0, v1, idx), stats);\n                    return stats;\n                }\n                if (statsHolder.key.equals(offset, len, v0, v1)) {\n                    return statsHolder.stats;\n                }\n                bucketOffset++;\n            } while (bucketOffset < BUCKET_SIZE - 1);\n            throw new Error(\"Bucket overflow\");\n        }\n\n        public void forEach(BiConsumer<Key, Stats> consumer) {\n            for (StatsHolder[] bucket : map) {\n                for (StatsHolder statsHolder : bucket) {\n                    if (statsHolder != null) {\n                        consumer.accept(statsHolder.key, statsHolder.stats);\n                    }\n                }\n            }\n        }\n    }\n\n    private static final long newLinePattern = compilePattern((byte) '\\n');\n    private static final long semiPattern = compilePattern((byte) ';');\n\n    public static void main(String[] args) throws Exception {\n        int workers = Runtime.getRuntime().availableProcessors();\n        if (args.length == 1) {\n            workers = Integer.parseInt(args[0]);\n        }\n        Map<String, Stats> map = new TreeMap<>();\n        File f = new File(\"measurements.txt\");\n\n        try (FileInputStream fis = new FileInputStream(f)) {\n            FileChannel fc = fis.getChannel();\n            int granularity = 32 * 1024 * 1024;\n            int targetWorkers = Math.min(Math.max(1, (int) (fc.size() / granularity)), workers);\n            long chunkSize = fc.size() / targetWorkers;\n            ExecutorService workerPool = Executors.newFixedThreadPool(workers);\n            // System.out.println(\"Chunk size: \" + chunkSize + \", workers: \" + targetWorkers);\n            for (ByteBuffer bb : mmap(fc, (int) chunkSize)) {\n                workerPool.submit(() -> {\n                    try {\n                        StatsMap data = processChunk(bb);\n                        synchronized (map) {\n                            data.forEach((k, v) -> {\n                                String str = k.toString();\n                                map.merge(str, v, Stats::merge);\n                            });\n                        }\n                    }\n                    catch (Throwable t) {\n                        t.printStackTrace();\n                    }\n                });\n            }\n            workerPool.shutdown();\n            workerPool.awaitTermination(1, TimeUnit.HOURS);\n        }\n        finally {\n            // System.out.println(\"Keys: \" + map.size());\n            System.out.println(map);\n        }\n    }\n\n    // unrolled FNV-1a 64 bit hash\n    private static final long fnv64OffsetBasis = 0xCBF29CE484222325L;\n    private static final long fnv64Prime = 0x100000001B3L;\n\n    private static StatsMap processChunk(ByteBuffer bb) {\n        StatsMap map = new StatsMap();\n\n        int offset = 0;\n        int limit = bb.limit();\n        int readLimit = limit - 8;\n        long v0 = 0;\n        long v1 = 0;\n        long hashCode = fnv64OffsetBasis;\n        int lastNewLine = -1;\n\n        while (offset < limit) {\n            if (offset > readLimit) {\n                int over = offset - readLimit;\n                v1 = bb.getLong(limit - 8);\n                v1 = v1 << (over * 8);\n            }\n            else {\n                v1 = bb.getLong(offset);\n            }\n            long x = preprocess(v1, newLinePattern);\n            if (x != 0) {\n                long value = 0;\n                int valueLen = 0;\n                int pos = Long.numberOfLeadingZeros(x) >>> 3;\n                int yoffset = offset;\n                int semiPos = firstInstance(v1, semiPattern);\n                if (semiPos >= pos) {\n                    yoffset -= 8;\n                    semiPos = firstInstance(v0, semiPattern);\n                    // semiPos will be at least 3 (new line is in the upper word and the value has at most 5 bytes)\n                    // a 64 bit value can not be rotated by 64 bits to 'clear' the bits\n                    // instead, it must be rotated by at most 56 bits and then, if 64 bit rotation was requested, by 8 bits more\n                    int rot2 = (8 - semiPos) >>> 3;\n                    int rot1 = (7 - semiPos) + (~rot2 & 0x1);\n                    long mask = ((0xFFFFFFFFFFFFFFFFL << (rot1 * 8)) << (rot2 * 8));\n                    rot2 = (8 - pos) >>> 3;\n                    rot1 = (7 - pos) + (~rot2 & 0x1);\n                    long newlineMask = ((0xFFFFFFFFFFFFFFFFL << (rot1 * 8)) << (rot2 * 8));\n                    value = semiPos == 7 ? 0L : (v0 << (semiPos + 1) * 8);\n                    value |= ((v1 & newlineMask) >> (7 - semiPos) * 8);\n                    // right-align the value bytes\n                    // getting the number of trailing zeros is the easiest way to figure out the shift\n                    // should be sufficiently fast but ...\n                    int zeros = (Long.numberOfTrailingZeros(value) >>> 3);\n                    value = value >>> zeros * 8;\n                    valueLen = 8 - zeros;\n                    v0 = v0 & mask;\n                }\n                else {\n                    hashCode ^= v0;\n                    hashCode *= fnv64Prime;\n                    long valMask = (0xFFFFFFFFFFFFFFFFL << (7 - semiPos) * 8);\n                    v0 = v1 & valMask;\n                    value = v1 & ~valMask;\n                    value = value >> (8 - pos) * 8;\n                    valueLen = pos - semiPos - 1;\n                }\n                v1 = 0;\n                hashCode ^= v0;\n                hashCode *= fnv64Prime;\n\n                int len = (yoffset + semiPos - 1) - lastNewLine;\n                hashCode ^= len;\n                hashCode *= fnv64Prime;\n\n                // byte[] strBuf = new byte[len];\n                // bb.get(lastNewLine + 1, strBuf);\n                // String str = new String(strBuf);\n                // System.out.println(\"===> \" + str + \": \" + Long.toHexString(value) + \" :: \" + fastParse(value, valueLen));\n                // projection of the hash code to 32 bits -> 65k buckets\n                long idx = ((hashCode & 0xFFFFFFFF00000000L) >> 32) ^ (hashCode & 0x00000000FFFFFFFFL);\n                idx = ((idx & 0x00000000FFFF0000L) >> 16) ^ (idx & 0x000000000000FFFFL);\n                map.getOrInsert(bb, lastNewLine + 1, len, (int) idx, v0, v1).add(fastParse(value, valueLen));\n\n                offset += pos + 1;\n                lastNewLine = offset - 1;\n                // reset the previous value\n                v0 = 0;\n                // reset the hash\n                hashCode = fnv64OffsetBasis;\n            }\n            else {\n                offset += 8;\n                hashCode ^= v0;\n                hashCode *= fnv64Prime;\n                v0 = v1;\n            }\n        }\n        return map;\n    }\n\n    private static final long fastParserMask = 0x3030303030303030L;\n\n    private static int fastParse(long word, int len) {\n        assert (len <= 5);\n\n        int signChar = (int) (word >> ((len - 1) * 8)) & 0xFF;\n        int sign = signChar ^ 0x2d;\n        int base = ~(sign | -sign);\n        int offset = (base >> 7) & 0x01;\n        int multiplier = -(~((sign - 1) >> 31) | 0x1);\n        int shift = (8 - len + offset) * 8;\n        long mask = (0xFFFFFFFFFFFFFFFFL >>> shift);\n        word = (word ^ fastParserMask) & mask;\n\n        int v1 = (int) word & 0xff;\n        // skip decimal point\n        // int v2 = 10 * ((int) (word >> 8) & 0xff);\n        int v3 = 10 * ((int) (word >> 16) & 0xff);\n        int v4 = 100 * ((int) (word >> 24) & 0xff);\n        // v5 is either the sign or not used\n\n        return ((v1 + v3 + v4) * multiplier);\n    }\n\n    private static ByteBuffer[] mmap(FileChannel fc, int splitSize) throws Exception {\n        if (fc.size() > splitSize && splitSize < 128) {\n            throw new IllegalArgumentException(\"Split size must be at least 128 bytes\");\n        }\n\n        byte[] byteBuffer = new byte[128];\n        int chunks = (int) (fc.size() / splitSize) + 1;\n        ByteBuffer[] buffers = new ByteBuffer[chunks];\n        long remaining = fc.size();\n        int count = 0;\n        for (int j = 0; j < chunks; j++) {\n            if (remaining > splitSize) {\n                ByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, fc.size() - remaining, splitSize);\n                buffer.get(splitSize - 128, byteBuffer, 0, 128);\n                int adjust = -1;\n                for (int i = 0; i < 128; i++) {\n                    if (byteBuffer[127 - i] == '\\n') {\n                        adjust = i;\n                        break;\n                    }\n                }\n                assert (adjust != -1);\n                int size = splitSize - adjust;\n                buffers[j] = fc.map(FileChannel.MapMode.READ_ONLY, fc.size() - remaining, size);\n                remaining -= size;\n                count = j + 1;\n            }\n            else {\n                count = j + 1;\n                if (fc.size() < 8) {\n                    // slow-path\n                    ByteBuffer bb = ByteBuffer.allocate(8);\n                    fc.read(bb, 0);\n                    buffers[j] = bb;\n                    break;\n                }\n                buffers[j] = fc.map(FileChannel.MapMode.READ_ONLY, fc.size() - remaining, remaining);\n                break;\n            }\n        }\n        // System.out.println(\"Chunks: \" + count);\n        return count < chunks ? Arrays.copyOf(buffers, count) : buffers;\n    }\n\n    private static long compilePattern(byte byteToFind) {\n        long pattern = byteToFind & 0xFFL;\n        return pattern\n                | (pattern << 8)\n                | (pattern << 16)\n                | (pattern << 24)\n                | (pattern << 32)\n                | (pattern << 40)\n                | (pattern << 48)\n                | (pattern << 56);\n    }\n\n    private static int firstInstance(long word, long pattern) {\n        long input = word ^ pattern;\n        long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;\n        tmp = ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);\n        return Long.numberOfLeadingZeros(tmp) >>> 3;\n    }\n\n    private static long preprocess(long word, long pattern) {\n        long input = word ^ pattern;\n        long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;\n        tmp = ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);\n        return tmp;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jeevjyot.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.lang.Math.round;\nimport static java.util.stream.Collectors.*;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collector;\n\npublic class CalculateAverage_jeevjyot {\n\n    public static final String MEAUREMENT_FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        Map<String, tempMeasurement> result = new ConcurrentHashMap<>();\n        Files.lines(Path.of(MEAUREMENT_FILE))\n                .parallel()\n                .forEach(s -> {\n                    var separatorIndex = s.indexOf(\";\");\n                    var stationName = s.substring(0, separatorIndex);\n                    var temp = s.substring(separatorIndex + 1);\n                    result.computeIfAbsent(stationName, d -> new tempMeasurement(parseDoubleFast(temp)))\n                            .recordTemp(parseDoubleFast(temp));\n                });\n\n        TreeMap<String, tempMeasurement> sortedStats = new TreeMap<>(result);\n        System.out.println(sortedStats);\n    }\n\n    public static double parseDoubleFast(String str) {\n        // Simple implementation - can be improved with more error checking and support for different formats\n        boolean negative = false;\n        double result = 0;\n        int length = str.length();\n        int i = 0;\n        if (str.charAt(0) == '-') {\n            negative = true;\n            i++;\n        }\n        for (; i < length; i++) {\n            char c = str.charAt(i);\n            if (c == '.') {\n                int divisor = 1;\n                for (i++; i < length; i++) {\n                    result += (double) (str.charAt(i) - '0') / (divisor *= 10);\n                }\n                break;\n            }\n            result = result * 10 + (c - '0');\n        }\n        return negative ? -result : result;\n    }\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    public static class tempMeasurement {\n        double minTemp;\n        double maxTemp;\n        double sum;\n        int count;\n\n        public tempMeasurement(double temString) {\n            this.minTemp = temString;\n            this.maxTemp = temString;\n            this.sum = 0.0;\n            this.count = 0;\n        }\n\n        public synchronized void recordTemp(Double temp) {\n            this.minTemp = Math.min(minTemp, temp);\n            this.maxTemp = Math.max(maxTemp, temp);\n            sum += temp;\n            count++;\n        }\n\n        double getAverage() {\n            return round(sum) / count;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\"%.1f/%.1f/%.1f\", round(minTemp), round(getAverage()), round(maxTemp));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jerrinot.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * I figured out it would be very hard to win the main competition of the One Billion Rows Challenge.\n * but I think this code has a good chance to win a special prize for the Ugliest Solution ever! :)\n *\n * Anyway, if you can make sense out of not exactly idiomatic Java code, and you enjoy pushing performance limits\n * then QuestDB - the fastest open-source time-series database - is hiring: https://questdb.io/careers/core-database-engineer/\n * <p>\n * <b>Credit</b>\n * <p>\n * I stand on shoulders of giants. I wouldn't be able to code this without analyzing and borrowing from solutions of others.\n * People who helped me the most:\n * <ul>\n * <li>Thomas Wuerthinger (thomaswue): The munmap() trick and work-stealing. In both cases, I shameless copy-pasted their code.\n *     Including SWAR for detecting new lines. Thomas also gave me helpful hints on how to detect register spilling issues.</li>\n * <li>Quan Anh Mai (merykitty): I borrowed their phenomenal branch-free parser.</li>\n * <li>Marko Topolnik (mtopolnik): I use a hashing function I saw in his code. It seems the produce good quality hashes\n *     and it's next-level in speed. Marko joined the challenge before me and our discussions made me to join too!</li>\n * <li>Van Phu DO (abeobk): I saw the idea with simple lookup tables instead of complicated bit-twiddling in their code first.</li>\n * <li>Roy van Rijn (royvanrijn): I borrowed their SWAR code and initially their hash code impl</li>\n * <li>Francesco Nigro (franz1981): For our online discussions about performance. Both before and during this challenge.\n *     Francesco gave me the idea to check register spilling.</li>\n * </ul>\n */\npublic class CalculateAverage_jerrinot {\n    private static final Unsafe UNSAFE = unsafe();\n    private static final String MEASUREMENTS_TXT = \"measurements.txt\";\n    // todo: with hyper-threading enable we would be better of with availableProcessors / 2;\n    // todo: validate the testing env. params.\n    private static final int EXTRA_THREAD_COUNT = Runtime.getRuntime().availableProcessors() - 1;\n    // private static final int THREAD_COUNT = 1;\n\n    private static final long SEPARATOR_PATTERN = 0x3B3B3B3B3B3B3B3BL;\n    private static final long NEW_LINE_PATTERN = 0x0A0A0A0A0A0A0A0AL;\n    private static final int SEGMENT_SIZE = 4 * 1024 * 1024;\n\n    // credits for the idea with lookup tables instead of bit-shifting: abeobk\n    private static final long[] HASH_MASKS = new long[]{\n            0x0000000000000000L, // semicolon is the first char\n            0x00000000000000ffL,\n            0x000000000000ffffL,\n            0x0000000000ffffffL,\n            0x00000000ffffffffL,\n            0x000000ffffffffffL,\n            0x0000ffffffffffffL,\n            0x00ffffffffffffffL, // semicolon is the last char\n            0xffffffffffffffffL // there is no semicolon at all\n    };\n\n    private static final long[] ADVANCE_MASKS = new long[]{\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0x0000000000000000L,\n            0xffffffffffffffffL,\n    };\n\n    private static Unsafe unsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // credits for spawning new workers: thomaswue\n        if (args.length == 0 || !(\"--worker\".equals(args[0]))) {\n            spawnWorker();\n            return;\n        }\n        calculate();\n    }\n\n    private static void spawnWorker() throws IOException {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> workerCommand = new ArrayList<>();\n        info.command().ifPresent(workerCommand::add);\n        info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args)));\n        workerCommand.add(\"--worker\");\n        new ProcessBuilder()\n                .command(workerCommand)\n                .inheritIO()\n                .redirectOutput(ProcessBuilder.Redirect.PIPE)\n                .start()\n                .getInputStream()\n                .transferTo(System.out);\n    }\n\n    static void calculate() throws Exception {\n        final File file = new File(MEASUREMENTS_TXT);\n        final long length = file.length();\n        try (var raf = new RandomAccessFile(file, \"r\")) {\n            long fileStart = raf.getChannel().map(MapMode.READ_ONLY, 0, length, Arena.global()).address();\n            long fileEnd = fileStart + length;\n            var globalCursor = new AtomicLong(fileStart);\n\n            Processor[] processors = new Processor[EXTRA_THREAD_COUNT];\n            Thread[] threads = new Thread[EXTRA_THREAD_COUNT];\n\n            for (int i = 0; i < EXTRA_THREAD_COUNT; i++) {\n                Processor processor = new Processor(fileStart, fileEnd, globalCursor);\n                Thread thread = new Thread(processor);\n                processors[i] = processor;\n                threads[i] = thread;\n                thread.start();\n            }\n\n            Processor processor = new Processor(fileStart, fileEnd, globalCursor);\n            processor.run();\n\n            var accumulator = new TreeMap<String, StationStats>();\n            processor.accumulateStatus(accumulator);\n\n            for (int i = 0; i < EXTRA_THREAD_COUNT; i++) {\n                Thread t = threads[i];\n                t.join();\n                processors[i].accumulateStatus(accumulator);\n            }\n\n            printResults(accumulator);\n        }\n    }\n\n    private static void printResults(TreeMap<String, StationStats> accumulator) {\n        var sb = new StringBuilder(10000);\n        boolean first = true;\n        for (Map.Entry<String, StationStats> statsEntry : accumulator.entrySet()) {\n            if (first) {\n                sb.append(\"{\");\n                first = false;\n            }\n            else {\n                sb.append(\", \");\n            }\n            var value = statsEntry.getValue();\n            var name = statsEntry.getKey();\n            int min = value.min;\n            int max = value.max;\n            int count = value.count;\n            long sum2 = value.sum;\n            sb.append(String.format(\"%s=%.1f/%.1f/%.1f\", name, min / 10.0, Math.round((double) sum2 / count) / 10.0, max / 10.0));\n        }\n        sb.append('}');\n        System.out.println(sb);\n        System.out.close();\n    }\n\n    public static int ceilPow2(int i) {\n        i--;\n        i |= i >> 1;\n        i |= i >> 2;\n        i |= i >> 4;\n        i |= i >> 8;\n        i |= i >> 16;\n        return i + 1;\n    }\n\n    private static class Processor implements Runnable {\n        private static final int MAX_UNIQUE_KEYS = 10000;\n        private static final int MAPS_SLOT_COUNT = ceilPow2(MAX_UNIQUE_KEYS);\n        private static final int STATION_MAX_NAME_BYTES = 104;\n\n        private static final long MAP_COUNT_OFFSET = 0;\n        private static final long MAP_MIN_OFFSET = 4;\n        private static final long MAP_MAX_OFFSET = 8;\n        private static final long MAP_SUM_OFFSET = 12;\n        private static final long MAP_LEN_OFFSET = 20;\n        private static final long SLOW_MAP_NAME_OFFSET = 24;\n\n        // private int longestChain = 0;\n\n        private static final int SLOW_MAP_ENTRY_SIZE_BYTES = Integer.BYTES // count // 0\n                + Integer.BYTES // min // +4\n                + Integer.BYTES // max // +8\n                + Long.BYTES // sum // +12\n                + Integer.BYTES // station name len // +20\n                + Long.BYTES; // station name ptr // 24\n\n        private static final long FAST_MAP_NAME_PART1 = 24;\n        private static final long FAST_MAP_NAME_PART2 = 32;\n\n        private static final int FAST_MAP_ENTRY_SIZE_BYTES = Integer.BYTES // count // 0\n                + Integer.BYTES // min // +4\n                + Integer.BYTES // max // +8\n                + Long.BYTES // sum // +12\n                + Integer.BYTES // station name len // +20\n                + Long.BYTES // station name part 1 // 24\n                + Long.BYTES; // station name part 2 // 32\n\n        private static final int SLOW_MAP_SIZE_BYTES = MAPS_SLOT_COUNT * SLOW_MAP_ENTRY_SIZE_BYTES;\n        private static final int FAST_MAP_SIZE_BYTES = MAPS_SLOT_COUNT * FAST_MAP_ENTRY_SIZE_BYTES;\n        private static final int SLOW_MAP_MAP_NAMES_BYTES = MAX_UNIQUE_KEYS * STATION_MAX_NAME_BYTES;\n        private static final int MAP_MASK = MAPS_SLOT_COUNT - 1;\n        private final AtomicLong globalCursor;\n\n        private long slowMap;\n        private long slowMapNamesPtr;\n        private long cursorA;\n        private long endA;\n        private long cursorB;\n        private long endB;\n        private HashMap<String, CalculateAverage_jerrinot.StationStats> stats = new HashMap<>(1000);\n        private final long fileEnd;\n        private final long fileStart;\n\n        // credit: merykitty\n        private long parseAndStoreTemperature(long startCursor, long baseEntryPtr, long word) {\n            long countPtr = baseEntryPtr + MAP_COUNT_OFFSET;\n            int cnt = UNSAFE.getInt(countPtr);\n            UNSAFE.putInt(countPtr, cnt + 1);\n\n            long minPtr = baseEntryPtr + MAP_MIN_OFFSET;\n            long maxPtr = baseEntryPtr + MAP_MAX_OFFSET;\n            long sumPtr = baseEntryPtr + MAP_SUM_OFFSET;\n\n            int min = UNSAFE.getInt(minPtr);\n            int max = UNSAFE.getInt(maxPtr);\n            long sum = UNSAFE.getLong(sumPtr);\n\n            final long negateda = ~word;\n            final int dotPos = Long.numberOfTrailingZeros(negateda & 0x10101000);\n            final long signed = (negateda << 59) >> 63;\n            final long removeSignMask = ~(signed & 0xFF);\n            final long digits = ((word & removeSignMask) << (28 - dotPos)) & 0x0F000F0F00L;\n            final long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            final int temperature = (int) ((absValue ^ signed) - signed);\n            sum += temperature;\n            UNSAFE.putLong(sumPtr, sum);\n\n            if (temperature > max) {\n                UNSAFE.putInt(maxPtr, temperature);\n            }\n            if (temperature < min) {\n                UNSAFE.putInt(minPtr, temperature);\n            }\n            return startCursor + (dotPos / 8) + 3;\n        }\n\n        private static long getDelimiterMask(final long word) {\n            // credit royvanrijn\n            final long match = word ^ SEPARATOR_PATTERN;\n            return (match - 0x0101010101010101L) & (~match & 0x8080808080808080L);\n        }\n\n        void accumulateStatus(TreeMap<String, CalculateAverage_jerrinot.StationStats> accumulator) {\n            for (Map.Entry<String, CalculateAverage_jerrinot.StationStats> entry : stats.entrySet()) {\n                String name = entry.getKey();\n                CalculateAverage_jerrinot.StationStats localStats = entry.getValue();\n\n                CalculateAverage_jerrinot.StationStats globalStats = accumulator.get(name);\n                if (globalStats == null) {\n                    accumulator.put(name, localStats);\n                }\n                else {\n                    accumulator.put(name, globalStats.mergeWith(localStats));\n                }\n            }\n        }\n\n        Processor(long fileStart, long fileEnd, AtomicLong globalCursor) {\n            this.globalCursor = globalCursor;\n            this.fileEnd = fileEnd;\n            this.fileStart = fileStart;\n        }\n\n        private void transferToHeap(long fastMap) {\n            for (long baseAddress = slowMap; baseAddress < slowMap + SLOW_MAP_SIZE_BYTES; baseAddress += SLOW_MAP_ENTRY_SIZE_BYTES) {\n                long len = UNSAFE.getInt(baseAddress + MAP_LEN_OFFSET);\n                if (len == 0) {\n                    continue;\n                }\n                byte[] nameArr = new byte[(int) len];\n                long baseNameAddr = UNSAFE.getLong(baseAddress + SLOW_MAP_NAME_OFFSET);\n                for (int i = 0; i < len; i++) {\n                    nameArr[i] = UNSAFE.getByte(baseNameAddr + i);\n                }\n                String name = new String(nameArr);\n                int min = UNSAFE.getInt(baseAddress + MAP_MIN_OFFSET);\n                int max = UNSAFE.getInt(baseAddress + MAP_MAX_OFFSET);\n                int count = UNSAFE.getInt(baseAddress + MAP_COUNT_OFFSET);\n                long sum = UNSAFE.getLong(baseAddress + MAP_SUM_OFFSET);\n\n                stats.put(name, new CalculateAverage_jerrinot.StationStats(min, max, count, sum));\n            }\n\n            for (long baseAddress = fastMap; baseAddress < fastMap + FAST_MAP_SIZE_BYTES; baseAddress += FAST_MAP_ENTRY_SIZE_BYTES) {\n                long len = UNSAFE.getInt(baseAddress + MAP_LEN_OFFSET);\n                if (len == 0) {\n                    continue;\n                }\n                byte[] nameArr = new byte[(int) len];\n                long baseNameAddr = baseAddress + FAST_MAP_NAME_PART1;\n                for (int i = 0; i < len; i++) {\n                    nameArr[i] = UNSAFE.getByte(baseNameAddr + i);\n                }\n                String name = new String(nameArr);\n                int min = UNSAFE.getInt(baseAddress + MAP_MIN_OFFSET);\n                int max = UNSAFE.getInt(baseAddress + MAP_MAX_OFFSET);\n                int count = UNSAFE.getInt(baseAddress + MAP_COUNT_OFFSET);\n                long sum = UNSAFE.getLong(baseAddress + MAP_SUM_OFFSET);\n\n                var v = stats.get(name);\n                if (v == null) {\n                    stats.put(name, new CalculateAverage_jerrinot.StationStats(min, max, count, sum));\n                }\n                else {\n                    stats.put(name, new CalculateAverage_jerrinot.StationStats(Math.min(v.min, min), Math.max(v.max, max), v.count + count, v.sum + sum));\n                }\n            }\n        }\n\n        private void doOne(long cursor, long end, long fastMap) {\n            while (cursor < end) {\n                // it seems that when pulling just from a single chunk\n                // then bit-twiddling is faster than lookup tables\n                // hypothesis: when processing multiple things at once then LOAD latency is partially hidden\n                // but when processing just one thing then it's better to keep things local as much as possible? maybe:)\n\n                long start = cursor;\n                long currentWord = UNSAFE.getLong(cursor);\n                long mask = getDelimiterMask(currentWord);\n                long firstWordMask = ((mask - 1) ^ mask) >>> 8;\n                final long isMaskZeroA = ((mask | -mask) >>> 63) ^ 1;\n                long ext = -isMaskZeroA;\n                firstWordMask |= ext;\n\n                long maskedFirstWord = currentWord & firstWordMask;\n                int hash = hash(maskedFirstWord);\n                int mapIndex = hash & MAP_MASK;\n                while (mask == 0) {\n                    cursor += 8;\n                    currentWord = UNSAFE.getLong(cursor);\n                    mask = getDelimiterMask(currentWord);\n                }\n                final int delimiterByte = Long.numberOfTrailingZeros(mask);\n                final long semicolon = cursor + (delimiterByte >> 3);\n                final long maskedWord = currentWord & ((mask - 1) ^ mask) >>> 8;\n\n                int len = (int) (semicolon - start);\n                if (len > 15) {\n                    long baseEntryPtr = getOrCreateEntryBaseOffsetSlow(len, start, hash, maskedWord);\n                    long temperatureWord = UNSAFE.getLong(semicolon + 1);\n                    cursor = parseAndStoreTemperature(semicolon + 1, baseEntryPtr, temperatureWord);\n                }\n                else {\n                    long baseEntryPtr = getOrCreateEntryBaseOffsetFast(mapIndex, len, maskedWord, maskedFirstWord, fastMap);\n                    long temperatureWord = UNSAFE.getLong(semicolon + 1);\n                    cursor = parseAndStoreTemperature(semicolon + 1, baseEntryPtr, temperatureWord);\n                }\n            }\n        }\n\n        private static int hash(long word) {\n            // credit: mtopolnik\n            long seed = 0x51_7c_c1_b7_27_22_0a_95L;\n            int rotDist = 17;\n            //\n            long hash = word;\n            hash *= seed;\n            hash = Long.rotateLeft(hash, rotDist);\n            return (int) hash;\n        }\n\n        private static long nextNewLine(long prev) {\n            // again: credits to @thomaswue for this code, literally copy'n'paste\n            while (true) {\n                long currentWord = UNSAFE.getLong(prev);\n                long input = currentWord ^ NEW_LINE_PATTERN;\n                long pos = (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;\n                if (pos != 0) {\n                    prev += Long.numberOfTrailingZeros(pos) >>> 3;\n                    break;\n                }\n                else {\n                    prev += 8;\n                }\n            }\n            return prev;\n        }\n\n        @Override\n        public void run() {\n            long fastMap = allocateMem();\n            for (;;) {\n                long startingPtr = globalCursor.addAndGet(SEGMENT_SIZE) - SEGMENT_SIZE;\n                if (startingPtr >= fileEnd) {\n                    break;\n                }\n                setCursors(startingPtr);\n                mainLoop(fastMap);\n                doOne(cursorA, endA, fastMap);\n                doOne(cursorB, endB, fastMap);\n            }\n            transferToHeap(fastMap);\n        }\n\n        private long allocateMem() {\n            this.slowMap = UNSAFE.allocateMemory(SLOW_MAP_SIZE_BYTES);\n            this.slowMapNamesPtr = UNSAFE.allocateMemory(SLOW_MAP_MAP_NAMES_BYTES);\n            long fastMap = UNSAFE.allocateMemory(FAST_MAP_SIZE_BYTES);\n            UNSAFE.setMemory(slowMap, SLOW_MAP_SIZE_BYTES, (byte) 0);\n            UNSAFE.setMemory(fastMap, FAST_MAP_SIZE_BYTES, (byte) 0);\n            UNSAFE.setMemory(slowMapNamesPtr, SLOW_MAP_MAP_NAMES_BYTES, (byte) 0);\n            return fastMap;\n        }\n\n        private void mainLoop(long fastMap) {\n            while (cursorA < endA && cursorB < endB) {\n                long currentWordA = UNSAFE.getLong(cursorA);\n                long currentWordB = UNSAFE.getLong(cursorB);\n\n                long delimiterMaskA = getDelimiterMask(currentWordA);\n                long delimiterMaskB = getDelimiterMask(currentWordB);\n\n                long candidateWordA = UNSAFE.getLong(cursorA + 8);\n                long candidateWordB = UNSAFE.getLong(cursorB + 8);\n\n                long startA = cursorA;\n                long startB = cursorB;\n\n                int trailingZerosA = Long.numberOfTrailingZeros(delimiterMaskA) >> 3;\n                int trailingZerosB = Long.numberOfTrailingZeros(delimiterMaskB) >> 3;\n\n                long advanceMaskA = ADVANCE_MASKS[trailingZerosA];\n                long advanceMaskB = ADVANCE_MASKS[trailingZerosB];\n\n                long wordMaskA = HASH_MASKS[trailingZerosA];\n                long wordMaskB = HASH_MASKS[trailingZerosB];\n\n                long maskedMaskA = advanceMaskA & 8;\n                long maskedMaskB = advanceMaskB & 8;\n\n                long negAdvanceMaskA = ~advanceMaskA;\n                long negAdvanceMaskB = ~advanceMaskB;\n\n                cursorA += maskedMaskA;\n                cursorB += maskedMaskB;\n\n                long nextWordA = (advanceMaskA & candidateWordA) | (negAdvanceMaskA & currentWordA);\n                long nextWordB = (advanceMaskB & candidateWordB) | (negAdvanceMaskB & currentWordB);\n\n                delimiterMaskA = getDelimiterMask(nextWordA);\n                delimiterMaskB = getDelimiterMask(nextWordB);\n\n                boolean slowA = delimiterMaskA == 0;\n                boolean slowB = delimiterMaskB == 0;\n                trailingZerosA = Long.numberOfTrailingZeros(delimiterMaskA) >> 3;\n                trailingZerosB = Long.numberOfTrailingZeros(delimiterMaskB) >> 3;\n                boolean slowSome = (slowA || slowB);\n\n                long maskedFirstWordA = wordMaskA & currentWordA;\n                long maskedFirstWordB = wordMaskB & currentWordB;\n\n                int hashA = hash(maskedFirstWordA);\n                int hashB = hash(maskedFirstWordB);\n\n                currentWordA = nextWordA;\n                currentWordB = nextWordB;\n\n                if (slowSome) {\n                    doSlow(fastMap, delimiterMaskA, currentWordA, delimiterMaskB, currentWordB, startA, startB, hashA, hashB, slowA, maskedFirstWordA, slowB,\n                            maskedFirstWordB);\n                }\n                else {\n                    final long semicolonA = cursorA + trailingZerosA;\n                    final long semicolonB = cursorB + trailingZerosB;\n\n                    long digitStartA = semicolonA + 1;\n                    long digitStartB = semicolonB + 1;\n\n                    long lastWordMaskA = HASH_MASKS[trailingZerosA];\n                    long lastWordMaskB = HASH_MASKS[trailingZerosB];\n\n                    long temperatureWordA = UNSAFE.getLong(digitStartA);\n                    long temperatureWordB = UNSAFE.getLong(digitStartB);\n\n                    final long maskedLastWordA = currentWordA & lastWordMaskA;\n                    final long maskedLastWordB = currentWordB & lastWordMaskB;\n\n                    int lenA = (int) (semicolonA - startA);\n                    int lenB = (int) (semicolonB - startB);\n\n                    int mapIndexA = hashA & MAP_MASK;\n                    int mapIndexB = hashB & MAP_MASK;\n\n                    long baseEntryPtrA;\n                    long baseEntryPtrB;\n\n                    baseEntryPtrA = getOrCreateEntryBaseOffsetFast(mapIndexA, lenA, maskedLastWordA, maskedFirstWordA, fastMap);\n                    baseEntryPtrB = getOrCreateEntryBaseOffsetFast(mapIndexB, lenB, maskedLastWordB, maskedFirstWordB, fastMap);\n\n                    cursorA = parseAndStoreTemperature(digitStartA, baseEntryPtrA, temperatureWordA);\n                    cursorB = parseAndStoreTemperature(digitStartB, baseEntryPtrB, temperatureWordB);\n                }\n            }\n        }\n\n        private void doSlow(long fastMap, long delimiterMaskA, long currentWordA, long delimiterMaskB, long currentWordB, long startA, long startB, int hashA, int hashB,\n                            boolean slowA, long maskedFirstWordA, boolean slowB, long maskedFirstWordB) {\n            int trailingZerosB;\n            int trailingZerosA;\n            while (delimiterMaskA == 0) {\n                cursorA += 8;\n                currentWordA = UNSAFE.getLong(cursorA);\n                delimiterMaskA = getDelimiterMask(currentWordA);\n            }\n\n            while (delimiterMaskB == 0) {\n                cursorB += 8;\n                currentWordB = UNSAFE.getLong(cursorB);\n                delimiterMaskB = getDelimiterMask(currentWordB);\n            }\n            trailingZerosA = Long.numberOfTrailingZeros(delimiterMaskA) >> 3;\n            trailingZerosB = Long.numberOfTrailingZeros(delimiterMaskB) >> 3;\n\n            final long semicolonA = cursorA + trailingZerosA;\n            final long semicolonB = cursorB + trailingZerosB;\n\n            long digitStartA = semicolonA + 1;\n            long digitStartB = semicolonB + 1;\n\n            long lastWordMaskA = HASH_MASKS[trailingZerosA];\n            long lastWordMaskB = HASH_MASKS[trailingZerosB];\n\n            long temperatureWordA = UNSAFE.getLong(digitStartA);\n            long temperatureWordB = UNSAFE.getLong(digitStartB);\n\n            final long maskedLastWordA = currentWordA & lastWordMaskA;\n            final long maskedLastWordB = currentWordB & lastWordMaskB;\n\n            int lenA = (int) (semicolonA - startA);\n            int lenB = (int) (semicolonB - startB);\n\n            int mapIndexA = hashA & MAP_MASK;\n            int mapIndexB = hashB & MAP_MASK;\n\n            long baseEntryPtrA;\n            long baseEntryPtrB;\n\n            if (slowA) {\n                baseEntryPtrA = getOrCreateEntryBaseOffsetSlow(lenA, startA, hashA, maskedLastWordA);\n            }\n            else {\n                baseEntryPtrA = getOrCreateEntryBaseOffsetFast(mapIndexA, lenA, maskedLastWordA, maskedFirstWordA, fastMap);\n            }\n\n            if (slowB) {\n                baseEntryPtrB = getOrCreateEntryBaseOffsetSlow(lenB, startB, hashB, maskedLastWordB);\n            }\n            else {\n                baseEntryPtrB = getOrCreateEntryBaseOffsetFast(mapIndexB, lenB, maskedLastWordB, maskedFirstWordB, fastMap);\n            }\n            cursorA = parseAndStoreTemperature(digitStartA, baseEntryPtrA, temperatureWordA);\n            cursorB = parseAndStoreTemperature(digitStartB, baseEntryPtrB, temperatureWordB);\n        }\n\n        private void setCursors(long current) {\n            // Credit for the whole work-stealing scheme: @thomaswue\n            // I have totally stolen it from him. I changed the order a bit to suite my taste better,\n            // but it's his code\n            long segmentStart;\n            if (current == fileStart) {\n                segmentStart = current;\n            }\n            else {\n                segmentStart = nextNewLine(current) + 1;\n            }\n            long segmentEnd = nextNewLine(Math.min(fileEnd - 1, current + SEGMENT_SIZE));\n\n            long size = (segmentEnd - segmentStart) / 2;\n            long mid = nextNewLine(segmentStart + size);\n\n            cursorA = segmentStart;\n            endA = mid;\n            cursorB = mid + 1;\n            endB = segmentEnd;\n        }\n\n        private static long getOrCreateEntryBaseOffsetFast(int mapIndexA, int lenA, long maskedLastWord, long maskedFirstWord, long fastMap) {\n            for (;;) {\n                long basePtr = mapIndexA * FAST_MAP_ENTRY_SIZE_BYTES + fastMap;\n                long namePart1 = UNSAFE.getLong(basePtr + FAST_MAP_NAME_PART1);\n                long namePart2 = UNSAFE.getLong(basePtr + FAST_MAP_NAME_PART2);\n                if (namePart1 == maskedFirstWord && namePart2 == maskedLastWord) {\n                    return basePtr;\n                }\n                long lenPtr = basePtr + MAP_LEN_OFFSET;\n                int len = UNSAFE.getInt(lenPtr);\n                if (len == 0) {\n                    return newEntryFast(lenA, maskedLastWord, maskedFirstWord, lenPtr, basePtr);\n                }\n                mapIndexA = ++mapIndexA & MAP_MASK;\n            }\n        }\n\n        private static long newEntryFast(int lenA, long maskedLastWord, long maskedFirstWord, long lenPtr, long basePtr) {\n            UNSAFE.putInt(lenPtr, lenA);\n            // todo: this could be a single putLong()\n            UNSAFE.putInt(basePtr + MAP_MAX_OFFSET, Integer.MIN_VALUE);\n            UNSAFE.putInt(basePtr + MAP_MIN_OFFSET, Integer.MAX_VALUE);\n            UNSAFE.putLong(basePtr + FAST_MAP_NAME_PART1, maskedFirstWord);\n            UNSAFE.putLong(basePtr + FAST_MAP_NAME_PART2, maskedLastWord);\n            return basePtr;\n        }\n\n        private long getOrCreateEntryBaseOffsetSlow(int lenA, long startPtr, int hash, long maskedLastWord) {\n            long fullLen = lenA & ~7L;\n            long mapIndexA = hash & MAP_MASK;\n            for (;;) {\n                long basePtr = mapIndexA * SLOW_MAP_ENTRY_SIZE_BYTES + slowMap;\n                long lenPtr = basePtr + MAP_LEN_OFFSET;\n                long namePtr = basePtr + SLOW_MAP_NAME_OFFSET;\n                int len = UNSAFE.getInt(lenPtr);\n                if (len == lenA) {\n                    namePtr = UNSAFE.getLong(basePtr + SLOW_MAP_NAME_OFFSET);\n                    if (nameMatchSlow(startPtr, namePtr, fullLen, maskedLastWord)) {\n                        return basePtr;\n                    }\n                }\n                else if (len == 0) {\n                    UNSAFE.putLong(namePtr, slowMapNamesPtr);\n                    UNSAFE.putInt(lenPtr, lenA);\n                    UNSAFE.putInt(basePtr + MAP_MAX_OFFSET, Integer.MIN_VALUE);\n                    UNSAFE.putInt(basePtr + MAP_MIN_OFFSET, Integer.MAX_VALUE);\n                    UNSAFE.copyMemory(startPtr, slowMapNamesPtr, lenA);\n                    long alignedLen = (lenA & ~7L) + 8;\n                    slowMapNamesPtr += alignedLen;\n                    return basePtr;\n                }\n                mapIndexA = ++mapIndexA & MAP_MASK;\n            }\n        }\n\n        private static boolean nameMatchSlow(long start, long namePtr, long fullLen, long maskedLastWord) {\n            long offset;\n            for (offset = 0; offset < fullLen; offset += 8) {\n                if (UNSAFE.getLong(start + offset) != UNSAFE.getLong(namePtr + offset)) {\n                    return false;\n                }\n            }\n            long maskedWordInMap = UNSAFE.getLong(namePtr + fullLen);\n            return (maskedWordInMap == maskedLastWord);\n        }\n    }\n\n    record StationStats(int min, int max, int count, long sum) {\n        StationStats mergeWith(StationStats other) {\n            return new StationStats(Math.min(min, other.min), Math.max(max, other.max), count + other.count, sum + other.sum);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jgrateron.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\n\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_jgrateron {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MAX_LENGTH_LINE = 255;\n    private static final int MAX_BUFFER = 1024 * 8;\n    private static boolean DEBUG = false;\n    public static int DECENAS[] = { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 };\n    public static int CENTENAS[] = { 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 };\n\n    public record Particion(long offset, long size) {\n    }\n\n    /*\n     * Divide el archivo segun el nro de cores de la PC\n     * La division se debe recalcular hasta encontrar un \\n o \\r (enter o return)\n     */\n    public static List<Particion> dividirArchivo(File archivo) throws IOException {\n        var particiones = new ArrayList<Particion>();\n        var buffer = new byte[MAX_LENGTH_LINE];\n        var length = archivo.length();\n        int cores = Runtime.getRuntime().availableProcessors();\n        var sizeParticion = length / cores;\n        if (sizeParticion > MAX_BUFFER) {\n            var ini = 0l;\n            try (var rfile = new RandomAccessFile(archivo, \"r\")) {\n                for (;;) {\n                    var size = sizeParticion;\n                    var pos = ini + size;\n                    if (pos > length) {\n                        pos = length - 1;\n                        size = length - ini;\n                    }\n                    rfile.seek(pos);\n                    int count = rfile.read(buffer);\n                    if (count == -1) {\n                        break;\n                    }\n                    for (int i = 0; i < count; i++) {\n                        size++;\n                        if (buffer[i] == '\\n' || buffer[i] == '\\r') {\n                            break;\n                        }\n                    }\n                    var particion = new Particion(ini, size);\n                    particiones.add(particion);\n                    if (count != buffer.length) {\n                        break;\n                    }\n                    ini += size;\n                }\n            }\n        }\n        else {\n            particiones.add(new Particion(0, length));\n        }\n        return particiones;\n    }\n\n    /*\n     * cambiar el locale para que el separador decimal sea punto y no coma\n     * crear un hilo por cada particion\n     * totalizar las mediciones por cada hilo\n     * ordenar y mostrar\n     */\n    public static void main(String[] args) throws InterruptedException, IOException {\n        Locale.setDefault(Locale.US);\n        var startTime = System.nanoTime();\n        var archivo = new File(FILE);\n        var tareas = new ArrayList<Thread>();\n        var totalMediciones = new HashMap<Index, Medicion>();\n        var particiones = dividirArchivo(archivo);\n\n        for (var p : particiones) {\n            var hilo = Thread.ofVirtual().start(() -> {\n                try (var miTarea = new MiTarea(archivo, p)) {\n                    var mediciones = miTarea.calcularMediciones();\n                    for (var entry : mediciones.entrySet()) {\n                        Medicion medicion;\n                        synchronized (totalMediciones) {\n                            medicion = totalMediciones.get(entry.getKey());\n                            if (medicion == null) {\n                                totalMediciones.put(entry.getKey(), entry.getValue());\n                                medicion = entry.getValue();\n                            }\n                        }\n                        synchronized (medicion) {\n                            if (!medicion.equals(entry.getValue())) {\n                                var otraMed = entry.getValue();\n                                medicion.update(otraMed.count, otraMed.tempMin, otraMed.tempMax, otraMed.tempSum);\n                            }\n                        }\n                    }\n                }\n                catch (IOException e) {\n                    System.exit(-1);\n                }\n            });\n            tareas.add(hilo);\n        }\n\n        Comparator<Map.Entry<Index, Medicion>> comparar = (a, b) -> {\n            return a.getValue().getNombreEstacion().compareTo(b.getValue().getNombreEstacion());\n        };\n\n        for (var hilo : tareas) {\n            hilo.join();\n        }\n\n        var result = totalMediciones.entrySet().stream()//\n                .sorted(comparar)\n                .map(e -> e.getValue().toString())//\n                .collect(Collectors.joining(\", \"));\n\n        System.out.println(\"{\" + result + \"}\");\n        if (DEBUG) {\n            System.out.println(\"Total: \" + (System.nanoTime() - startTime) / 1000000 + \"ms\");\n        }\n    }\n\n    /*\n     * Clase Index para reutilizar al realizar un get en el Map\n     */\n    static class Index {\n        private int hash;\n        private byte[] data;\n        private int fromIndex;\n        private int length;\n\n        public Index() {\n            this.hash = 0;\n        }\n\n        public Index(byte data[], int fromIndex, int length) {\n            this.data = data;\n            this.fromIndex = fromIndex;\n            this.length = length;\n            this.hash = calcHashCode(length, data, fromIndex, length);\n        }\n\n        public void setData(byte data[], int fromIndex, int length) {\n            this.data = data;\n            this.fromIndex = fromIndex;\n            this.length = length;\n            this.hash = calcHashCode(length, data, fromIndex, length);\n        }\n\n        /*\n         * Calcula el hash de cada estacion,\n         * variation of Daniel J Bernstein's algorithm\n         */\n        private int calcHashCode(int result, byte[] a, int fromIndex, int length) {\n            int end = fromIndex + length;\n            for (int i = fromIndex; i < end; i++) {\n                result = ((result << 5) + result) ^ a[i];\n            }\n            return result;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (this == obj) {\n                return true;\n            }\n            var otro = (Index) obj;\n            return Arrays.equals(this.data, this.fromIndex, this.fromIndex + this.length, otro.data, otro.fromIndex,\n                    otro.fromIndex + otro.length);\n        }\n    }\n\n    /*\n     * Clase para procesar el archivo a la particion que corresponde\n     * RandomAccessFile permite dezplazar el puntero de lectura del archivo\n     * Tenemos un Map para guardar las estadisticas y un map para guardar los\n     * nombres de las estaciones\n     */\n    static class MiTarea implements AutoCloseable {\n        private final RandomAccessFile rFile;\n        private long maxRead;\n        private Index index = new Index();\n        private Map<Index, Medicion> mediciones = new HashMap<>();\n\n        public MiTarea(File file, Particion particion) throws IOException {\n            rFile = new RandomAccessFile(file, \"r\");\n            maxRead = particion.size;\n            rFile.seek(particion.offset);\n        }\n\n        @Override\n        public void close() throws IOException {\n            rFile.close();\n        }\n\n        /*\n         * Lee solo su particion\n         * Divide el buffer por lineas usando los separadores \\n o \\r (enter o return)\n         * obtiene la posicion de separacion \";\" de la estacion y su temperatura\n         * calcula el hash, convierte a double y actualiza las estadisticas\n         */\n        public Map<Index, Medicion> calcularMediciones() throws IOException {\n            var buffer = new byte[MAX_BUFFER];// buffer para lectura en el archivo\n            var rest = new byte[MAX_LENGTH_LINE];// Resto que sobra en cada lectura del buffer\n            var lenRest = 0;// Longitud que sobró en cada lectura del buffer\n            var totalRead = 0l; // Total bytes leidos\n\n            for (;;) {\n                if (totalRead == maxRead) {\n                    break;\n                }\n                long numBytes = rFile.read(buffer);\n                if (numBytes == -1) {\n                    break;\n                }\n                numBytes = totalRead + numBytes > maxRead ? maxRead - totalRead : numBytes;\n                totalRead += numBytes;\n                int pos = 0;\n                int len = 0;\n                int idx = 0;\n                int semicolon = 0;\n                while (pos < numBytes) {\n                    var b = buffer[pos];\n                    if (b == '\\n' || b == '\\r') {\n                        if (lenRest > 0) {\n                            // concatenamos el sobrante anterior con la nueva linea\n                            System.arraycopy(buffer, idx, rest, lenRest, len);\n                            len += lenRest;\n                            semicolon = buscarSemicolon(rest, len);\n                            lenRest = 0;\n                            updateMediciones(rest, 0, semicolon);\n                        }\n                        else {\n                            updateMediciones(buffer, idx, semicolon);\n                        }\n                        idx = pos + 1;\n                        len = 0;\n                        semicolon = 0;\n                    }\n                    else {\n                        if (b == ';') {\n                            semicolon = len;\n                        }\n                        len++;\n                    }\n                    pos++;\n                }\n                if (len > 0) {\n                    System.arraycopy(buffer, idx, rest, 0, len);\n                    lenRest = len;\n                }\n            }\n            return mediciones;\n        }\n\n        /*\n         * Buscamos en reverso ya que el ; esta mas cerca de numero que la estacion\n         * ademas el minimo numero 0.0 asi que quitamos tres mas\n         */\n        public int buscarSemicolon(byte data[], int len) {\n            for (int i = len - 4; i >= 0; i--) {\n                if (data[i] == ';') {\n                    return i;\n                }\n            }\n            return 0;\n        }\n\n        /*\n         * Busca una medicion por su hash y crea o actualiza la temperatura\n         */\n        public void updateMediciones(byte data[], int pos, int semicolon) {\n            var temp = strToInt(data, pos, semicolon);\n            index.setData(data, pos, semicolon);\n            var medicion = mediciones.get(index);\n            if (medicion == null) {\n                var estacion = new byte[semicolon];\n                System.arraycopy(data, pos, estacion, 0, semicolon);\n                medicion = new Medicion(estacion, 1, temp, temp, temp);\n                mediciones.put(new Index(estacion, 0, semicolon), medicion);\n            }\n            else {\n                medicion.update(1, temp, temp, temp);\n            }\n        }\n\n        /*\n         * convierte de un arreglo de bytes a integer\n         */\n\n        public int strToInt(byte linea[], int idx, int posSeparator) {\n            int pos = idx + posSeparator + 1;\n            boolean esNegativo = linea[pos] == '-';\n            pos = esNegativo ? pos + 1 : pos;\n            int number = linea[pos + 1] == '.' ? DECENAS[(linea[pos] - 48)] + linea[pos + 2] - 48\n                    : CENTENAS[(linea[pos] - 48)] + DECENAS[(linea[pos + 1] - 48)] + (linea[pos + 3] - 48);\n            return esNegativo ? -number : number;\n        }\n    }\n\n    /*\n     * Clase para reservar las estadisticas por estacion\n     */\n    static class Medicion {\n        private int count;\n        private int tempMin;\n        private int tempMax;\n        private int tempSum;\n        private byte estacion[];\n        private String nombreEstacion;\n\n        public Medicion(byte estacion[], int count, int tempMin, int tempMax, int tempSum) {\n            super();\n            this.estacion = estacion;\n            this.count = count;\n            this.tempMin = tempMin;\n            this.tempMax = tempMax;\n            this.tempSum = tempSum;\n        }\n\n        public void update(int count, int tempMin, int tempMax, int tempSum) {\n            this.count += count;\n            this.tempMin = Math.min(tempMin, this.tempMin);\n            this.tempMax = Math.max(tempMax, this.tempMax);\n            this.tempSum += tempSum;\n        }\n\n        public double round(double number) {\n            return Math.round(number) / 10.0;\n        }\n\n        public String getNombreEstacion() {\n            if (nombreEstacion == null) {\n                nombreEstacion = new String(estacion);\n            }\n            return nombreEstacion;\n        }\n\n        @Override\n        public String toString() {\n            var min = round(tempMin);\n            var mid = round(1.0 * tempSum / count);\n            var max = round(tempMax);\n            var nombre = getNombreEstacion();\n            return \"%s=%.1f/%.1f/%.1f\".formatted(nombre, min, mid, max);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jincongho.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\n\n/**\n * Changelog (based on Macbook Pro Intel i7 6-cores 2.6GHz):\n *\n * Initial                          40000 ms\n * Parse key as byte vs string      30000 ms\n * Parse temp as fixed vs double    15000 ms\n * HashMap optimization             10000 ms\n * Simd + reduce memory copy         8000 ms\n *\n */\npublic class CalculateAverage_jincongho {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Vectorization utilities with 1BRC-specific optimizations\n     */\n    protected static class VectorUtils {\n\n        // key length is usually less than 32 bytes, having more is just expensive\n        public static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_256;\n\n        /** Vectorized field delimiter search **/\n\n        public static int findDelimiter(MemorySegment data, long offset) {\n            return ByteVector.fromMemorySegment(VectorUtils.BYTE_SPECIES, data, offset, ByteOrder.nativeOrder())\n                    .compare(VectorOperators.EQ, ';')\n                    .firstTrue();\n        }\n\n        /** Vectorized Hashing (explicit vectorization seems slower, overkill?) **/\n\n        // private static int[] HASH_ARRAY = initHashArray();\n        // private static final IntVector HASH_VECTOR = IntVector.fromArray(IntVector.SPECIES_256, HASH_ARRAY, 0);\n        // private static final int HASH_ACCUM = HASH_ARRAY[0] * 31;\n        //\n        // private static int[] initHashArray() {\n        // int[] x = new int[IntVector.SPECIES_256.length()];\n        // x[x.length - 1] = 1;\n        // for (int i = x.length - 2; i >= 0; i--)\n        // x[i] = x[i + 1] * 31;\n        //\n        // return x;\n        // }\n\n        /**\n         * Ref: https://github.com/PaulSandoz/vector-api-dev-live-10-2021/blob/main/src/main/java/jmh/BytesHashcode.java\n         *\n         * Essentially we are doing this calculation:\n         * h = h * 31 * 31 * 31 * 31 * 31 * 31 * 31 * 31 +\n         *         a[i + 0] * 31 * 31 * 31 * 31 * 31 * 31 * 31 +\n         *         a[i + 1] * 31 * 31 * 31 * 31 * 31 * 31 +\n         *         a[i + 2] * 31 * 31 * 31 * 31 * 31 +\n         *         a[i + 3] * 31 * 31 * 31 * 31 +\n         *         a[i + 4] * 31 * 31 * 31 +\n         *         a[i + 5] * 31 * 31 +\n         *         a[i + 6] * 31 +\n         *         a[i + 7];\n         */\n        // public static int hashCode(MemorySegment array, long offset, short length) {\n        // int h = 1;\n        // long i = offset, loopBound = offset + ByteVector.SPECIES_64.loopBound(length), tailBound = offset + length;\n        // for (; i < loopBound; i += ByteVector.SPECIES_64.length()) {\n        // // load 8 bytes, into a 64-bit vector\n        // ByteVector b = ByteVector.fromMemorySegment(ByteVector.SPECIES_64, array, i, ByteOrder.nativeOrder());\n        // // convert 8 bytes into 8 ints (hashing calculation needs int!)\n        // IntVector x = (IntVector) b.castShape(IntVector.SPECIES_256, 0);\n        // h = h * HASH_ACCUM + x.mul(HASH_VECTOR).reduceLanes(VectorOperators.ADD);\n        // }\n        //\n        // for (; i < tailBound; i++) {\n        // h = 31 * h + array.get(ValueLayout.JAVA_BYTE, i);\n        // }\n        // return h;\n        // }\n\n        // scalar implementation\n        // public static int hashCode(final MemorySegment array, final long offset, final short length) {\n        // final long limit = offset + length;\n        // int h = 1;\n        // for (long i = offset; i < limit; i++) {\n        // h = 31 * h + UNSAFE.getByte(array.address() + i);\n        // }\n        // return h;\n        // }\n\n        // fxhash\n        public static int hashCode(final MemorySegment array, final long offset, final short length) {\n            final int seed = 0x9E3779B9;\n            final int rotate = 5;\n\n            int x, y;\n            if (length >= Integer.BYTES) {\n                x = UNSAFE.getInt(array.address() + offset);\n                y = UNSAFE.getInt(array.address() + offset + length - Integer.BYTES);\n            }\n            else {\n                x = UNSAFE.getByte(array.address() + offset);\n                y = UNSAFE.getByte(array.address() + offset + length - Byte.BYTES);\n            }\n\n            return (Integer.rotateLeft(x * seed, rotate) ^ y) * seed;\n        }\n\n        /** Vectorized Key Comparison **/\n\n        private static boolean notEquals(MemorySegment a, long aOffset, MemorySegment b, long bOffset, short length, VectorSpecies BYTE_SPECIES) {\n            final long aLimit = aOffset + length, bLimit = bOffset + length;\n\n            // main loop\n            long loopBound = bOffset + BYTE_SPECIES.loopBound(length);\n            for (; bOffset < loopBound; aOffset += BYTE_SPECIES.length(), bOffset += BYTE_SPECIES.length()) {\n                ByteVector av = ByteVector.fromMemorySegment(BYTE_SPECIES, a,\n                        aOffset, ByteOrder.nativeOrder() /* , BYTE_SPECIES.indexInRange(aOffset, Math.min(aOffset + BYTE_SPECIES.length(), aLimit)) */);\n                ByteVector bv = ByteVector.fromMemorySegment(BYTE_SPECIES, b,\n                        bOffset, ByteOrder.nativeOrder() /* , BYTE_SPECIES.indexInRange(bOffset, Math.min(bOffset + BYTE_SPECIES.length(), bLimit)) */);\n                if (av.compare(VectorOperators.NE, bv).anyTrue())\n                    return true;\n            }\n\n            // tail cleanup - load last N bytes with mask\n            if (bOffset < bLimit) {\n                ByteVector av = ByteVector.fromMemorySegment(BYTE_SPECIES, a, aOffset, ByteOrder.nativeOrder(), BYTE_SPECIES.indexInRange(aOffset, aLimit));\n                ByteVector bv = ByteVector.fromMemorySegment(BYTE_SPECIES, b, bOffset, ByteOrder.nativeOrder(), BYTE_SPECIES.indexInRange(bOffset, bLimit));\n                if (av.compare(VectorOperators.NE, bv).anyTrue())\n                    return true;\n            }\n\n            return false;\n        }\n\n        // scalar implementation\n        // private static boolean equals(byte[] a, int aOffset, byte[] b, int bOffset, int len) {\n        // while (bOffset < len)\n        // if (a[aOffset++] != b[bOffset++])\n        // return false;\n        // return true;\n        // }\n\n    }\n\n    /**\n     * Measurement Hash Table (for each partition)\n     * Uses contiguous byte array to optimize for cache-line (hopefully)\n     *\n     * Each entry:\n     * - KEYS: keyLength (2 bytes) + key (100 bytes)\n     * - VALUES: min (2 bytes) + max (2 bytes) + count (4 bytes) + sum ( 8 bytes)\n     */\n    protected static class PartitionAggr {\n\n        private static int MAP_SIZE = 1 << 14; // 2^14 = 16384, closes to 10000\n        private static int KEY_SIZE = 128; // key length (2 bytes) + key (100 bytes)\n        private static int KEY_MASK = (MAP_SIZE - 1);\n        private static int VALUE_SIZE = 16; // min (2 bytes) + max ( 2 bytes) + count (4 bytes) + sum (8 bytes)\n\n        private MemorySegment KEYS = Arena.ofShared().allocate(MAP_SIZE * KEY_SIZE, 64);\n        private MemorySegment VALUES = Arena.ofShared().allocate(MAP_SIZE * VALUE_SIZE, 16);\n\n        public PartitionAggr() {\n            // init min and max\n            final long limit = VALUES.address() + (MAP_SIZE * VALUE_SIZE);\n            for (long offset = VALUES.address(); offset < limit; offset += VALUE_SIZE) {\n                UNSAFE.putShort(offset, Short.MAX_VALUE);\n                UNSAFE.putShort(offset + 2, Short.MIN_VALUE);\n            }\n        }\n\n        public void update(MemorySegment key, long keyStart, short keyLength, int keyHash, short value) {\n            int index = keyHash & KEY_MASK;\n            long keyOffset = KEYS.address() + (index * KEY_SIZE);\n            while (((UNSAFE.getShort(keyOffset) != keyLength) ||\n                    VectorUtils.notEquals(KEYS, ((index * KEY_SIZE) + 2), key, keyStart, keyLength, VectorUtils.BYTE_SPECIES))) {\n                if (UNSAFE.getShort(keyOffset) == 0) {\n                    // put key\n                    UNSAFE.putShort(keyOffset, keyLength);\n                    MemorySegment.copy(key, keyStart, KEYS, (index * KEY_SIZE) + 2, keyLength);\n                    break;\n                }\n                else {\n                    index = (index + 1) & KEY_MASK;\n                    keyOffset = KEYS.address() + (index * KEY_SIZE);\n                }\n            }\n\n            long valueOffset = VALUES.address() + (index * VALUE_SIZE);\n            UNSAFE.putShort(valueOffset, (short) Math.min(UNSAFE.getShort(valueOffset), value));\n            valueOffset += 2;\n            UNSAFE.putShort(valueOffset, (short) Math.max(UNSAFE.getShort(valueOffset), value));\n            valueOffset += 2;\n            UNSAFE.putInt(valueOffset, UNSAFE.getInt(valueOffset) + 1);\n            valueOffset += 4;\n            UNSAFE.putLong(valueOffset, UNSAFE.getLong(valueOffset) + value);\n        }\n\n        public void mergeTo(ResultAggr result) {\n            long keyOffset;\n            short keyLength;\n            for (int i = 0; i < MAP_SIZE; i++) {\n                // extract key\n                keyOffset = KEYS.address() + (i * KEY_SIZE);\n                if ((keyLength = UNSAFE.getShort(keyOffset)) == 0)\n                    continue;\n\n                // extract values (if key is not null)\n                final long valueOffset = VALUES.address() + (i * VALUE_SIZE);\n                result.compute(new ResultAggr.ByteKey(KEYS, (i * KEY_SIZE) + 2, keyLength), (k, v) -> {\n                    if (v == null) {\n                        v = new ResultAggr.Measurement();\n                    }\n                    v.min = (short) Math.min(UNSAFE.getShort(valueOffset), v.min);\n                    v.max = (short) Math.max(UNSAFE.getShort(valueOffset + 2), v.max);\n                    v.count += UNSAFE.getInt(valueOffset + 4);\n                    v.sum += UNSAFE.getLong(valueOffset + 8);\n\n                    return v;\n                });\n            }\n        }\n\n    }\n\n    /**\n     * Measurement Aggregation (for all partitions)\n     * Simple Concurrent Hash Table so all partitions can merge concurrently\n     */\n    protected static class ResultAggr extends HashMap<ResultAggr.ByteKey, ResultAggr.Measurement> {\n\n        public static class ByteKey implements Comparable<ByteKey> {\n            private final MemorySegment data;\n            private final long offset;\n            private final short length;\n            private String str;\n\n            public ByteKey(MemorySegment data, long offset, short length) {\n                this.data = data;\n                this.offset = offset;\n                this.length = length;\n            }\n\n            @Override\n            public boolean equals(Object other) {\n                return (length == ((ByteKey) other).length)\n                        && !VectorUtils.notEquals(data, offset, ((ByteKey) other).data, ((ByteKey) other).offset, length, VectorUtils.BYTE_SPECIES);\n            }\n\n            @Override\n            public int hashCode() {\n                return VectorUtils.hashCode(data, offset, length);\n            }\n\n            @Override\n            public String toString() {\n                if (str == null) {\n                    // finally has to do a copy!\n                    byte[] copy = new byte[length];\n                    MemorySegment.copy(data, offset, MemorySegment.ofArray(copy), 0, length);\n                    str = new String(copy, StandardCharsets.UTF_8);\n                }\n                return str;\n            }\n\n            @Override\n            public int compareTo(ByteKey o) {\n                return toString().compareTo(o.toString());\n            }\n        }\n\n        protected static class Measurement {\n            public short min = Short.MAX_VALUE;\n            public short max = Short.MIN_VALUE;\n            public int count = 0;\n            public long sum = 0;\n\n            @Override\n            public String toString() {\n                return ((double) min / 10) + \"/\" + (Math.round((1.0 * sum) / count) / 10.0) + \"/\" + ((double) max / 10);\n            }\n\n        }\n\n        public ResultAggr(int initialCapacity, float loadFactor) {\n            super(initialCapacity, loadFactor);\n        }\n\n        public Map toSorted() {\n            return new TreeMap(this);\n        }\n\n    }\n\n    protected static class Partition implements Runnable {\n\n        private final MemorySegment data;\n        private long offset;\n        private final long limit;\n        private final PartitionAggr result;\n\n        public Partition(MemorySegment data, long offset, long limit, PartitionAggr result) {\n            this.data = data;\n            this.offset = offset;\n            this.limit = limit;\n            this.result = result;\n        }\n\n        @Override\n        public void run() {\n            // measurement parsing\n            final PartitionAggr aggr = this.result;\n\n            // main loop (vectorized)\n            final long loopLimit = limit - (VectorUtils.BYTE_SPECIES.length() * Math.ceilDiv(100, VectorUtils.BYTE_SPECIES.length()) + Long.BYTES);\n            while (offset < loopLimit) {\n                long offsetStart = offset;\n\n                // find station name upto \";\"\n                int found;\n                do {\n                    found = VectorUtils.findDelimiter(data, offset);\n                    offset += found;\n                } while (found == VectorUtils.BYTE_SPECIES.length());\n                short stationLength = (short) (offset - offsetStart);\n                int stationHash = VectorUtils.hashCode(data, offsetStart, stationLength);\n\n                // find measurement upto \"\\n\" (credit: merykitty)\n                long numberBits = UNSAFE.getLong(data.address() + ++offset);\n                final long invNumberBits = ~numberBits;\n                final int decimalSepPos = Long.numberOfTrailingZeros(invNumberBits & 0x10101000);\n\n                int shift = 28 - decimalSepPos;\n                long signed = (invNumberBits << 59) >> 63;\n                long designMask = ~(signed & 0xFF);\n                long digits = ((numberBits & designMask) << shift) & 0x0F000F0F00L;\n                long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n\n                short fixed = (short) ((absValue ^ signed) - signed);\n                offset += (decimalSepPos >>> 3) + 3;\n\n                // update measurement\n                aggr.update(data, offsetStart, stationLength, stationHash, fixed);\n            }\n\n            // tail loop (simple)\n            while (offset < limit) {\n                long offsetStart = offset;\n\n                // find station name upto \";\"\n                short stationLength = 0;\n                while (UNSAFE.getByte(data.address() + offset++) != ';')\n                    stationLength++;\n                int stationHash = VectorUtils.hashCode(data, offsetStart, stationLength);\n\n                // find measurement upto \"\\n\"\n                byte tempBuffer = UNSAFE.getByte(data.address() + offset++);\n                boolean isNegative = (tempBuffer == '-');\n                short fixed = (short) (isNegative ? 0 : (tempBuffer - '0'));\n                while (true) {\n                    tempBuffer = UNSAFE.getByte(data.address() + offset++);\n                    if (tempBuffer == '.') {\n                        fixed = (short) (fixed * 10 + (UNSAFE.getByte(data.address() + offset) - '0'));\n                        offset += 2;\n                        break;\n                    }\n                    fixed = (short) (fixed * 10 + (tempBuffer - '0'));\n                }\n                fixed = isNegative ? (short) -fixed : fixed;\n\n                // update measurement\n                aggr.update(data, offsetStart, stationLength, stationHash, fixed);\n            }\n\n            // measurement result collection\n            // aggr.mergeTo(result);\n        }\n\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n\n        // long startTime = System.currentTimeMillis();\n\n        try (FileChannel fileChannel = (FileChannel) Files.newByteChannel(Path.of(FILE), EnumSet.of(StandardOpenOption.READ));\n                Arena arena = Arena.ofShared()) {\n\n            // scan data\n            MemorySegment data = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size(), arena);\n            final int processors = Runtime.getRuntime().availableProcessors();\n\n            // partition split\n            long[] partition = new long[processors + 1];\n            long partitionSize = Math.ceilDiv(data.byteSize(), processors);\n            for (int i = 0; i < processors; i++) {\n                partition[i + 1] = partition[i] + partitionSize;\n                if (partition[i + 1] >= data.byteSize()) {\n                    partition[i + 1] = data.byteSize();\n                    break;\n                }\n\n                // note: vectorize this made performance worse :(\n                while (UNSAFE.getByte(data.address() + partition[i + 1]++) != '\\n')\n                    ;\n            }\n\n            // partition aggregation\n            var threadList = new Thread[processors];\n            PartitionAggr[] partAggrs = new PartitionAggr[processors];\n            for (int i = 0; i < processors; i++) {\n                if (partition[i] == data.byteSize())\n                    break;\n\n                partAggrs[i] = new PartitionAggr();\n                threadList[i] = new Thread(new Partition(data, partition[i], partition[i + 1], partAggrs[i]));\n                threadList[i].start();\n            }\n\n            // result\n            ResultAggr result = new ResultAggr(1 << 14, 1);\n            for (int i = 0; i < processors; i++) {\n                if (partition[i] == data.byteSize())\n                    break;\n\n                threadList[i].join();\n                partAggrs[i].mergeTo(result);\n            }\n            System.out.println(result.toSorted());\n        }\n\n        // long elapsed = System.currentTimeMillis() - startTime;\n        // System.out.println(\"Elapsed: \" + ((double) elapsed / 1000.0));\n\n    }\n\n    /** Unit Tests **/\n\n    public static void testMain(String[] args) {\n        testHashCode();\n        testNotEquals();\n    }\n\n    private static void testHashCode() {\n        // test key length from 1 to 100\n        for (int i = 1; i <= 100; i++) {\n            byte[] array = new byte[i];\n            for (int j = 0; j < i; j++)\n                array[j] = (byte) j;\n\n            // compare with java default implementation\n            assertTrue(VectorUtils.hashCode(MemorySegment.ofArray(array), 0, (short) i) == Arrays.hashCode(array));\n        }\n    }\n\n    private static void testNotEquals() {\n        byte[] a = new byte[128];\n        byte[] b = new byte[128];\n\n        // all equals\n        for (int i = 1; i < 100; i++) {\n            a[(i + 2) - 1] = 0;\n            b[i - 1] = 0;\n            a[(i + 2)] = 10;\n            b[i] = 10;\n            assertTrue(!VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_64));\n            assertTrue(!VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_128));\n            assertTrue(!VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_256));\n            assertTrue(!VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_512));\n        }\n\n        // one el not equals\n        for (int i = 1; i < 100; i++) {\n            a[(i + 2) - 1] = 0;\n            b[i - 1] = 0;\n            a[(i + 2)] = 20;\n            b[i] = 10;\n            assertTrue(VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_64));\n            assertTrue(VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_128));\n            assertTrue(VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_256));\n            assertTrue(VectorUtils.notEquals(MemorySegment.ofArray(a), 2, MemorySegment.ofArray(b), 0, (short) 100, ByteVector.SPECIES_512));\n        }\n    }\n\n    private static void assertTrue(boolean condition) {\n        if (!condition) {\n            throw new RuntimeException(\"Failed test\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jonathanaotearoa.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.DirectoryStream;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_jonathanaotearoa {\n\n    public static final Unsafe UNSAFE;\n\n    static {\n        try {\n            final Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            UNSAFE = (Unsafe) theUnsafe.get(null);\n        } catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(STR.\"Error getting instance of \\{Unsafe.class.getName()}\");\n        }\n    }\n\n    private static final int WORD_BYTES = Long.BYTES;\n    private static final Path FILE_PATH = Path.of(\"./measurements.txt\");\n    private static final Path SAMPLE_DIR_PATH = Path.of(\"./src/test/resources/samples\");\n    private static final byte MAX_LINE_BYTES = 107;\n    private static final byte NEW_LINE_BYTE = '\\n';\n    private static final long SEPARATOR_XOR_MASK = 0x3b3b3b3b3b3b3b3bL;\n\n    // A mask where the 4th bit of the 5th, 6th and 7th bytes is set to 1.\n    // Leverages the fact that the 4th bit of a digit byte will 1.\n    // Whereas the 4th bit of the decimal point byte will be 0.\n    // Assumes little endianness.\n    private static final long DECIMAL_POINT_MASK = 0x10101000L;\n\n    // This mask performs two tasks:\n    // Sets the right-most and 3 left-most bytes to zero.\n    // Given a temp value be at most 5 bytes in length, .e.g -99.9, we can safely ignore the last 3 bytes.\n    // Subtracts 48, i.e. the UFT-8 value offset, from the digits bytes.\n    // As a result, '0' (48) becomes 0, '1' (49) becomes 1, and so on.\n    private static final long TEMP_DIGITS_MASK = 0x0f000f0f00L;\n\n    public static void main(final String[] args) throws IOException {\n        assert ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN : \"Big endian byte order is not supported\";\n        System.out.println(resultsToString(processFile(FILE_PATH)));\n    }\n\n    /**\n     * A custom version of AbstractMap's toString() method.\n     * <p>\n     * This should be more performant as we can:\n     * <ul>\n     *     <li>Set the initial capacity of the string builder</li>\n     *     <li>Append double values directly, which avoids string creation</li>\n     * </ul>\n     * </p>\n     *\n     * @param results the results.\n     * @return a string representation of the results.\n     */\n    private static String resultsToString(final Map<String, TemperatureData> results) {\n        final Iterator<Map.Entry<String, TemperatureData>> i = results.entrySet().iterator();\n        if (!i.hasNext()) {\n            System.out.println(\"{}\");\n        }\n        // Capacity based the output for measurements.txt.\n        final StringBuilder sb = new StringBuilder(1100).append('{');\n        while (i.hasNext()) {\n            Map.Entry<String, TemperatureData> e = i.next();\n            sb.append(e.getKey())\n                    .append('=')\n                    .append(e.getValue().getMin())\n                    .append('/')\n                    .append(e.getValue().getMean())\n                    .append('/')\n                    .append(e.getValue().getMax());\n            if (i.hasNext()) {\n                sb.append(',').append(' ');\n            }\n        }\n        sb.append('}');\n        return sb.toString();\n    }\n\n    /**\n     * Processes the specified file.\n     * <p>\n     * Extracted from the main method for testability.\n     * </p>\n     *\n     * @param filePath the path of the file we want to process.\n     * @return a sorted map of station data keyed by station name.\n     * @throws IOException if an error occurs.\n     */\n    private static SortedMap<String, TemperatureData> processFile(final Path filePath) throws IOException {\n        assert filePath != null : \"filePath cannot be null\";\n        assert Files.isRegularFile(filePath) : STR.\"\\{filePath.toAbsolutePath()} is not a valid file\";\n\n        try (final FileChannel fc = FileChannel.open(filePath, StandardOpenOption.READ)) {\n            final long fileSize = fc.size();\n            if (fileSize < WORD_BYTES) {\n                // The file size is less than our word size.\n                // Keep it simple and fall back to non-performant processing.\n                return processTinyFile(fc, fileSize);\n            }\n            return processFile(fc, fileSize);\n        }\n    }\n\n    /**\n     * An unoptimised method for processing a tiny file.\n     * <p>\n     * Handling tiny files in a separate method reduces the complexity of {@link #processFile(FileChannel, long)}.\n     * </p>\n     *\n     * @param fc       the file channel to read from.\n     * @param fileSize the file size in bytes.\n     * @return a sorted map of station data keyed by station name.\n     * @throws IOException if an error occurs reading from the file channel.\n     */\n    private static SortedMap<String, TemperatureData> processTinyFile(final FileChannel fc, final long fileSize) throws IOException {\n        final ByteBuffer byteBuffer = ByteBuffer.allocate((int) fileSize);\n        fc.read(byteBuffer);\n        return new String(byteBuffer.array(), StandardCharsets.UTF_8)\n                .lines()\n                .map(line -> line.trim().split(\";\"))\n                .map(tokens -> {\n                    final String stationName = tokens[0];\n                    final short temp = Short.parseShort(tokens[1].replace(\".\", \"\"));\n                    return new SimpleStationData(stationName, temp);\n                })\n                .collect(Collectors.toMap(\n                        sd -> sd.name,\n                        sd -> sd,\n                        TemperatureData::merge,\n                        TreeMap::new));\n    }\n\n    /**\n     * An optimised method for processing files > {@link Long#BYTES} in size.\n     *\n     * @param fc       the file channel to map into memory.\n     * @param fileSize the file size in bytes.\n     * @return a sorted map of station data keyed by station name.\n     * @throws IOException if an error occurs mapping the file channel into memory.\n     */\n    private static SortedMap<String, TemperatureData> processFile(final FileChannel fc, final long fileSize) throws IOException {\n        assert fileSize >= WORD_BYTES : STR.\"File size cannot be less than word size \\{WORD_BYTES}, but was \\{fileSize}\";\n\n        try (final Arena arena = Arena.ofConfined()) {\n            final long fileAddress = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, arena).address();\n            return createChunks(fileAddress, fileSize)\n                    .parallel()\n                    .map(CalculateAverage_jonathanaotearoa::processChunk)\n                    .flatMap(Repository::entries)\n                    .collect(Collectors.toMap(\n                            StationData::getName,\n                            sd -> sd,\n                            TemperatureData::merge,\n                            TreeMap::new));\n        }\n    }\n\n    /**\n     * Divides the file into chunks that can be processed in parallel.\n     * <p>\n     * If dividing the file into {@link ForkJoinPool#getCommonPoolParallelism() parallelism} chunks would result in a\n     * chunk size less than the maximum line size in bytes, then a single chunk is returned for the entire file.\n     * </p>\n     *\n     * @param fileAddress the address of the file.\n     * @param fileSize    the size of the file in bytes.\n     * @return a stream of chunks.\n     */\n    private static Stream<Chunk> createChunks(final long fileAddress, final long fileSize) {\n        // The number of cores - 1.\n        final int parallelism = ForkJoinPool.getCommonPoolParallelism();\n        final long chunkStep = fileSize / parallelism;\n        final long lastFileByteAddress = fileAddress + fileSize - 1;\n        if (chunkStep < MAX_LINE_BYTES) {\n            // We're dealing with a small file, return a single chunk.\n            return Stream.of(new Chunk(fileAddress, lastFileByteAddress, true));\n        }\n        final Chunk[] chunks = new Chunk[parallelism];\n        long startAddress = fileAddress;\n        for (int i = 0, n = parallelism - 1; i < n; i++) {\n            // Find end of the *previous* line.\n            // We know there's a previous line in this chunk because chunkStep >= MAX_LINE_BYTES.\n            // The last chunk may be slightly bigger than the others.\n            // For a 1 billion line file, this has zero impact.\n            long lastByteAddress = startAddress + chunkStep;\n            while (UNSAFE.getByte(lastByteAddress) != NEW_LINE_BYTE) {\n                lastByteAddress--;\n            }\n            // We've found the end of the previous line.\n            chunks[i] = new Chunk(startAddress, lastByteAddress, false);\n            startAddress = ++lastByteAddress;\n        }\n        // The remaining bytes are assigned to the last chunk.\n        chunks[chunks.length - 1] = (new Chunk(startAddress, lastFileByteAddress, true));\n        return Stream.of(chunks);\n    }\n\n    /**\n     * Does the work of processing a chunk.\n     *\n     * @param chunk the chunk to process.\n     * @return a repository containing the chunk's station data.\n     */\n    private static Repository processChunk(final Chunk chunk) {\n        final Repository repo = new Repository();\n        long address = chunk.startAddress;\n\n        while (address <= chunk.lastByteAddress) {\n            // Read station name.\n            long nameAddress = address;\n            long nameWord;\n            long separatorMask;\n            int nameHash = 1;\n\n            while (true) {\n                nameWord = chunk.getWord(address);\n\n                // Based on the Hacker's Delight \"Find First 0-Byte\" branch-free, 5-instruction, algorithm.\n                // See also https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord\n                final long separatorXorResult = nameWord ^ SEPARATOR_XOR_MASK;\n                // If the separator is not present, all bits in the mask will be zero.\n                // If the separator is present, the first bit of the corresponding byte in the mask will be 1.\n                separatorMask = (separatorXorResult - 0x0101010101010101L) & (~separatorXorResult & 0x8080808080808080L);\n                if (separatorMask == 0) {\n                    address += Long.BYTES;\n                    // Multiplicative hashing, as per Arrays.hashCode().\n                    // We could use XOR here, but it \"might\" produce more collisions.\n                    nameHash = 31 * nameHash + Long.hashCode(nameWord);\n                }\n                else {\n                    break;\n                }\n            }\n\n            // We've found the separator.\n            // We only support little endian, so we use the *trailing* number of zeros to get the number of name bits.\n            final int numberOfNameBits = Long.numberOfTrailingZeros(separatorMask) & ~7;\n            final int numberOfNameBytes = numberOfNameBits >> 3;\n            final long separatorAddress = address + numberOfNameBytes;\n\n            if (numberOfNameBytes > 0) {\n                // Truncate the word, so we only have the portion before the separator, i.e. the name bytes.\n                final int bitsToDiscard = Long.SIZE - numberOfNameBits;\n                // Little endian.\n                final long truncatedNameWord = (nameWord << bitsToDiscard) >>> bitsToDiscard;\n                nameHash = 31 * nameHash + Long.hashCode(truncatedNameWord);\n            }\n\n            final long tempAddress = separatorAddress + 1;\n            final long tempWord = chunk.getWord(tempAddress);\n\n            // \"0\" in UTF-8 is 48, which is 00110000 in binary.\n            // The first 4 bits of any UTF-8 digit byte are therefore 0011.\n\n            // Get the position of the decimal point...\n            // \".\" in UTF-8 is 46, which is 00101110 in binary.\n            // We can therefore use the 4th bit to check which byte is the decimal point.\n            final int decimalPointIndex = Long.numberOfTrailingZeros(~tempWord & DECIMAL_POINT_MASK) >> 3;\n\n            // Check if we've got a negative or positive number...\n            // \"-\" in UTF-8 is 45, which is 00101101 in binary.\n            // As per above, we use the 4th bit to check if the word contains a positive, or negative, temperature.\n            // If the temperature is negative, the value of \"sign\" will be -1. If it's positive, it'll be 0.\n            final long sign = (~tempWord << 59) >> 63;\n\n            // Create a mask that zeros out the minus-sign byte, if present.\n            // Little endian, i.e. the minus sign is the right-most byte.\n            final long signMask = ~(sign & 0xFF);\n\n            // To get the temperature value, we left-shift the digit bytes into the following, known, positions.\n            // 0x00 0x00 0x00 <fractional-digit> 0x00 <integer-part-digit> <integer-part-digit> 0x00\n            // Because we're ANDing with the sign mask, if the value only has a single integer-part digit, the right-most one will be zero.\n            final int leftShift = (3 - decimalPointIndex) * Byte.SIZE;\n            final long digitsWord = ((tempWord & signMask) << leftShift) & TEMP_DIGITS_MASK;\n\n            // Get the unsigned int value.\n            final byte b100 = (byte) (digitsWord >> 8);\n            final byte b10 = (byte) (digitsWord >> 16);\n            final byte b1 = (byte) (digitsWord >> 32);\n            final short unsignedTemp = (short) (b100 * 100 + b10 * 10 + b1);\n            final short temp = (short) ((unsignedTemp + sign) ^ sign);\n\n            final byte nameSize = (byte) (separatorAddress - nameAddress);\n            repo.addTemp(nameHash, nameAddress, nameSize, temp);\n\n            // Calculate the address of the next line.\n            address = tempAddress + decimalPointIndex + 3;\n        }\n\n        return repo;\n    }\n\n    /**\n     * Represents a portion of a file containing 1 or more whole lines.\n     *\n     * @param startAddress    the memory address of the first byte.\n     * @param lastByteAddress the memory address of the last byte.\n     * @param lastWordAddress the memory address of the last whole word.\n     * @param isLast          whether this is the last chunk.\n     */\n    private record Chunk(long startAddress, long lastByteAddress, long lastWordAddress, boolean isLast) {\n\n        public Chunk(final long startAddress, final long lastByteAddress, final boolean isLast) {\n            this(startAddress, lastByteAddress, lastByteAddress - (Long.BYTES - 1), isLast);\n\n            assert lastByteAddress > startAddress : STR.\"lastByteAddress \\{lastByteAddress} must be > startAddress \\{startAddress}\";\n            assert lastWordAddress >= startAddress : STR.\"lastWordAddress \\{lastWordAddress} must be >= startAddress \\{startAddress}\";\n        }\n\n        /**\n         * Gets an 8 byte word from this chunk.\n         * <p>\n         * If the specified address is greater than {@link Chunk#lastWordAddress} and {@link Chunk#isLast}, the word\n         * will be truncated. This ensures we never read beyond the end of the file.\n         * </p>\n         *\n         * @param address the address of the word we want.\n         * @return the word at the specified address.\n         */\n        public long getWord(final long address) {\n            assert address >= startAddress : STR.\"address must be >= startAddress \\{startAddress}, but was \\{address}\";\n            assert address < lastByteAddress : STR.\"address must be < lastByteAddress \\{lastByteAddress}, but was \\{address}\";\n\n            if (isLast && address > lastWordAddress) {\n                // Make sure we don't read beyond the end of the file and potentially crash the JVM.\n                final long word = UNSAFE.getLong(lastWordAddress);\n                final int bytesToDiscard = (int) (address - lastWordAddress);\n                // As with elsewhere, this assumes little endianness.\n                return word >>> (bytesToDiscard << 3);\n            }\n            return UNSAFE.getLong(address);\n        }\n    }\n\n    /**\n     * Abstract class encapsulating temperature data.\n     */\n    private static abstract class TemperatureData {\n\n        private short min;\n        private short max;\n        private long sum;\n        private int count;\n\n        protected TemperatureData(final short temp) {\n            min = max = temp;\n            sum = temp;\n            count = 1;\n        }\n\n        void addTemp(final short temp) {\n            if (temp < min) {\n                min = temp;\n            }\n            else if (temp > max) {\n                max = temp;\n            }\n            sum += temp;\n            count++;\n        }\n\n        TemperatureData merge(final TemperatureData other) {\n            if (other.min < min) {\n                min = other.min;\n            }\n            if (other.max > max) {\n                max = other.max;\n            }\n            sum += other.sum;\n            count += other.count;\n            return this;\n        }\n\n        double getMin() {\n            return round(((double) min) / 10.0);\n        }\n\n        double getMax() {\n            return round(((double) max) / 10.0);\n        }\n\n        double getMean() {\n            return round((((double) sum) / 10.0) / count);\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    /**\n     * For use with tiny files.\n     *\n     * @see CalculateAverage_jonathanaotearoa#processTinyFile(FileChannel, long).\n     */\n    private static final class SimpleStationData extends TemperatureData implements Comparable<SimpleStationData> {\n\n        private final String name;\n\n        SimpleStationData(final String name, final short temp) {\n            super(temp);\n            this.name = name;\n        }\n\n        @Override\n        public int compareTo(final SimpleStationData other) {\n            return name.compareTo(other.name);\n        }\n    }\n\n    private static final class StationData extends TemperatureData implements Comparable<StationData> {\n\n        private final int nameHash;\n        private final long nameAddress;\n        private final byte nameSize;\n        private String name;\n\n        StationData(final int nameHash, final long nameAddress, final byte nameSize, final short temp) {\n            super(temp);\n            this.nameAddress = nameAddress;\n            this.nameSize = nameSize;\n            this.nameHash = nameHash;\n        }\n\n        @Override\n        public int compareTo(final StationData other) {\n            return getName().compareTo(other.getName());\n        }\n\n        String getName() {\n            if (name == null) {\n                final byte[] nameBytes = new byte[nameSize];\n                UNSAFE.copyMemory(null, nameAddress, nameBytes, UNSAFE.arrayBaseOffset(nameBytes.getClass()), nameSize);\n                name = new String(nameBytes, StandardCharsets.UTF_8);\n            }\n            return name;\n        }\n    }\n\n    /**\n     * Open addressing, linear probing, hash map repository.\n     */\n    private static final class Repository {\n\n        private static final int CAPACITY = 100_003;\n        private static final int LAST_INDEX = CAPACITY - 1;\n\n        private final StationData[] table;\n\n        public Repository() {\n            this.table = new StationData[CAPACITY];\n        }\n\n        /**\n         * Adds a station temperature value to this repository.\n         *\n         * @param nameHash    the station name hash.\n         * @param nameAddress the station name address in memory.\n         * @param nameSize    the station name size in bytes.\n         * @param temp        the temperature value.\n         */\n        public void addTemp(final int nameHash, final long nameAddress, final byte nameSize, short temp) {\n            final int index = findIndex(nameHash, nameAddress, nameSize);\n            if (table[index] == null) {\n                table[index] = new StationData(nameHash, nameAddress, nameSize, temp);\n            }\n            else {\n                table[index].addTemp(temp);\n            }\n        }\n\n        public Stream<StationData> entries() {\n            return Arrays.stream(table).filter(Objects::nonNull);\n        }\n\n        private int findIndex(int nameHash, final long nameAddress, final byte nameSize) {\n            // Think about replacing modulo.\n            // https://lemire.me/blog/2018/08/20/performance-of-ranged-accesses-into-arrays-modulo-multiply-shift-and-masks/\n            int index = (nameHash & 0x7FFFFFFF) % CAPACITY;\n            while (isCollision(index, nameHash, nameAddress, nameSize)) {\n                index = index == LAST_INDEX ? 0 : index + 1;\n            }\n            return index;\n        }\n\n        private boolean isCollision(final int index, final long nameHash, final long nameAddress, final byte nameSize) {\n            final StationData existing = table[index];\n            if (existing == null) {\n                return false;\n            }\n            if (nameHash != existing.nameHash) {\n                return true;\n            }\n            if (nameSize != existing.nameSize) {\n                return true;\n            }\n            // Last resort; check if the names are the same.\n            // This is real performance hit :(\n            return !isMemoryEqual(nameAddress, existing.nameAddress, nameSize);\n        }\n\n        /**\n         * Checks if two locations in memory have the same value.\n         *\n         * @param address1 the address of the first location.\n         * @param address2 the address of the second locations.\n         * @param size     the number of bytes to check for equality.\n         * @return true if both addresses contain the same bytes.\n         */\n        private static boolean isMemoryEqual(final long address1, final long address2, final byte size) {\n            // Checking 1 byte at a time, so we can bail as early as possible.\n            for (int offset = 0; offset < size; offset++) {\n                final byte b1 = UNSAFE.getByte(address1 + offset);\n                final byte b2 = UNSAFE.getByte(address2 + offset);\n                if (b1 != b2) {\n                    return false;\n                }\n            }\n            return true;\n        }\n    }\n\n    /**\n     * Helper for running tests without blowing away the main measurements.txt file.\n     * Saves regenerating the 1 billion line file after each test run.\n     * Enable assertions in the IDE run config.\n     */\n    public static final class TestRunner {\n        public static void main(String[] args) throws IOException {\n            final StringBuilder testResults = new StringBuilder();\n            try (DirectoryStream<Path> dirStream = Files.newDirectoryStream(SAMPLE_DIR_PATH, \"*.txt\")) {\n                dirStream.forEach(filePath -> {\n                    testResults.append(STR.\"Testing '\\{filePath.getFileName()}'... \");\n                    final String expectedResultFileName = filePath.getFileName().toString().replace(\".txt\", \".out\");\n                    try {\n                        final String expected = Files.readString(SAMPLE_DIR_PATH.resolve(expectedResultFileName));\n                        final SortedMap<String, TemperatureData> results = processFile(filePath);\n                        // Appending \\n to the results string to mimic println().\n                        final String actual = STR.\"\\{resultsToString(results)}\\n\";\n                        if (actual.equals(expected)) {\n                            testResults.append(\"Passed\\n\");\n                        } else {\n                            testResults.append(\"Failed. Actual output does not match expected\\n\");\n                        }\n                    } catch (IOException e) {\n                        throw new RuntimeException(STR.\"Error testing '\\{filePath.getFileName()}\");\n                    }\n                });\n            } finally {\n                System.out.println(testResults);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jotschi.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout.OfByte;\nimport java.lang.foreign.ValueLayout.OfChar;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_jotschi {\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException {\n        var filename = args.length == 0 ? FILE : args[0];\n        parseFile(filename);\n    }\n\n    @SuppressWarnings(\"preview\")\n    private static void parseFile(String filename) throws IOException {\n        var file = new File(filename);\n        RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\");\n        FileChannel fileChannel = randomAccessFile.getChannel();\n        MemorySegment memSeg = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size(), Arena.global());\n        var results = getFileSegments(memSeg).stream().map(segment -> {\n            var resultMap = new ByteArrayToResultMap2();\n            long segmentEnd = segment.end();\n            MemorySegment slice = memSeg.asSlice(segment.start(), segmentEnd - segment.start());\n\n            // Up to 100 characters for a city name\n            var buffer = new byte[100];\n            int startLine;\n            int pos = 0;\n            long limit = slice.byteSize();\n            while ((startLine = pos) < limit) {\n                int currentPosition = startLine;\n                byte b;\n                int offset = 0;\n                int hash = 0;\n                while (currentPosition != segmentEnd && (b = slice.get(OfByte.JAVA_BYTE, currentPosition++)) != ';') {\n                    buffer[offset++] = b;\n                    hash = 31 * hash + b;\n                }\n                int temp;\n                int negative = 1;\n                // Inspired by @yemreinci to unroll this even further\n                if (slice.get(OfByte.JAVA_BYTE, currentPosition) == '-') {\n                    negative = -1;\n                    currentPosition++;\n                }\n                if (slice.get(OfByte.JAVA_BYTE, currentPosition + 1) == '.') {\n                    temp = negative * ((slice.get(OfByte.JAVA_BYTE, currentPosition) - '0') * 10 + (slice.get(OfByte.JAVA_BYTE, currentPosition + 2) - '0'));\n                    currentPosition += 3;\n                }\n                else {\n                    temp = negative\n                            * ((slice.get(OfByte.JAVA_BYTE, currentPosition) - '0') * 100\n                                    + ((slice.get(OfByte.JAVA_BYTE, currentPosition + 1) - '0') * 10 + (slice.get(OfByte.JAVA_BYTE, currentPosition + 3) - '0')));\n                    currentPosition += 4;\n                }\n                if (slice.get(OfByte.JAVA_BYTE, currentPosition) == '\\r') {\n                    currentPosition++;\n                }\n                currentPosition++;\n                resultMap.putOrMerge(buffer, 0, offset, temp / 10.0, hash);\n                pos = currentPosition;\n            }\n            return resultMap;\n        }).parallel().flatMap(partition -> partition.getAll().stream())\n                .collect(Collectors.toMap(e -> new String(e.key()), Entry2::value, CalculateAverage_jotschi::merge, TreeMap::new));\n        System.out.println(results);\n    }\n\n    private static List<FileSegment2> getFileSegments(MemorySegment memSeg) throws IOException {\n        int numberOfSegments = Runtime.getRuntime().availableProcessors();\n        long fileSize = memSeg.byteSize();\n        long segmentSize = fileSize / numberOfSegments;\n        List<FileSegment2> segments = new ArrayList<>(numberOfSegments);\n\n        // Pointless to split small files\n        if (segmentSize < 1_000_000) {\n            segments.add(new FileSegment2(0, fileSize));\n            return segments;\n        }\n\n        // Split the file up into even segments that match up with the CPU core count\n        // so that each core can process a segment of the file.\n        // The findSegment call ensures that the segment terminates with a newline.\n        for (int i = 0; i < numberOfSegments; i++) {\n            long segStart = i * segmentSize;\n            long segEnd = (i == numberOfSegments - 1) ? fileSize : segStart + segmentSize;\n            segStart = findSegment(i, 0, memSeg, segStart, segEnd);\n            segEnd = findSegment(i, numberOfSegments - 1, memSeg, segEnd, fileSize);\n            segments.add(new FileSegment2(segStart, segEnd));\n        }\n        return segments;\n    }\n\n    private static Result2 merge(Result2 v, Result2 value) {\n        return merge(v, value.min, value.max, value.sum, value.count);\n    }\n\n    private static Result2 merge(Result2 v, double value, double value1, double value2, long value3) {\n        v.min = Math.min(v.min, value);\n        v.max = Math.max(v.max, value1);\n        v.sum += value2;\n        v.count += value3;\n        return v;\n    }\n\n    private static long findSegment(int i, int skipSegment, MemorySegment memSeg, long location, long fileSize) throws IOException {\n        if (i != skipSegment) {\n            long remaining = fileSize - location;\n            int bufferSize = remaining < 64 ? (int) remaining : 64;\n            MemorySegment slice = memSeg.asSlice(location, bufferSize);\n            for (int offset = 0; offset < slice.byteSize(); offset++) {\n                if (slice.get(OfChar.JAVA_BYTE, offset) == '\\n') {\n                    return location + offset + 1;\n                }\n            }\n        }\n        return location;\n    }\n}\n\nclass Result2 {\n    double min, max, sum;\n    long count;\n\n    Result2(double value) {\n        min = max = sum = value;\n        this.count = 1;\n    }\n\n    @Override\n    public String toString() {\n        return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n    }\n\n    double round(double v) {\n        return Math.round(v * 10.0) / 10.0;\n    }\n\n}\n\n    record Pair2(int slot, Result2 slotValue) {\n    }\n\n    record Entry2(byte[] key, Result2 value) {\n    }\n\n    record FileSegment2(long start, long end) {\n    }\n\nclass ByteArrayToResultMap2 {\n  public static final int MAPSIZE = 1024 * 128;\n  Result2[] slots = new Result2[MAPSIZE];\n  byte[][] keys = new byte[MAPSIZE][];\n\n  public void putOrMerge(byte[] key, int offset, int size, double temp, int hash) {\n    int slot = hash & (slots.length - 1);\n    var slotValue = slots[slot];\n    // Linear probe for open slot\n    while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n      slot = (slot + 1) & (slots.length - 1);\n      slotValue = slots[slot];\n    }\n    Result2 value = slotValue;\n    if (value == null) {\n      slots[slot] = new Result2(temp);\n      byte[] bytes = new byte[size];\n      System.arraycopy(key, offset, bytes, 0, size);\n      keys[slot] = bytes;\n    } else {\n      value.min = Math.min(value.min, temp);\n      value.max = Math.max(value.max, temp);\n      value.sum += temp;\n      value.count += 1;\n    }\n  }\n\n  // Get all pairs\n  public List<Entry2> getAll() {\n    List<Entry2> result = new ArrayList<>(slots.length);\n    for (int i = 0; i < slots.length; i++) {\n      Result2 slotValue = slots[i];\n      if (slotValue != null) {\n        result.add(new Entry2(keys[i], slotValue));\n      }\n    }\n    return result;\n  }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_jparera.java",
    "content": "//COMPILE_OPTIONS -source 21 --enable-preview --add-modules jdk.incubator.vector\n//RUNTIME_OPTIONS --enable-preview --add-modules jdk.incubator.vector\n/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorSpecies;\nimport jdk.incubator.vector.VectorOperators;\n\npublic class CalculateAverage_jparera {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final VarHandle BYTE_HANDLE = MethodHandles\n            .memorySegmentViewVarHandle(ValueLayout.JAVA_BYTE);\n\n    private static final VarHandle INT_HANDLE = MethodHandles\n            .memorySegmentViewVarHandle(ValueLayout.JAVA_INT_UNALIGNED);\n\n    private static final VarHandle LONG_LE_HANDLE = MethodHandles\n            .memorySegmentViewVarHandle(ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN));\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED;\n\n    private static final int BYTE_SPECIES_LANES = BYTE_SPECIES.length();\n\n    private static final ByteOrder NATIVE_ORDER = ByteOrder.nativeOrder();\n\n    private static final byte LF = '\\n';\n\n    private static final byte SEPARATOR = ';';\n\n    private static final byte DECIMAL_SEPARATOR = '.';\n\n    private static final byte NEG = '-';\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        try (var fc = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            try (var arena = Arena.ofShared()) {\n                var fs = fc.map(MapMode.READ_ONLY, 0, fc.size(), arena);\n                var cpus = Runtime.getRuntime().availableProcessors();\n                var output = chunks(fs, cpus).stream()\n                        .parallel()\n                        .map(Chunk::parse)\n                        .flatMap(List::stream)\n                        .collect(Collectors.toMap(\n                                Entry::key,\n                                Function.identity(),\n                                Entry::merge,\n                                TreeMap::new));\n                System.out.println(output);\n            }\n        }\n    }\n\n    private static List<Chunk> chunks(MemorySegment ms, int splits) {\n        long fileSize = ms.byteSize();\n        long expectedChunkSize = Math.ceilDiv(fileSize, splits);\n        var chunks = new ArrayList<Chunk>();\n        long offset = 0;\n        while (offset < fileSize) {\n            var end = Math.min(offset + expectedChunkSize, fileSize);\n            while (end < fileSize && (byte) BYTE_HANDLE.get(ms, end++) != LF) {\n            }\n            long len = end - offset;\n            chunks.add(new Chunk(ms.asSlice(offset, len)));\n            offset = end;\n        }\n        return chunks;\n    }\n\n    private static final class Chunk {\n        private static final int KEY_LOG2_BYTES = 7;\n\n        private static final int KEY_BYTES = 1 << KEY_LOG2_BYTES;\n\n        private static final int ENTRIES_LOG2_CAPACITY = 16;\n\n        private static final int ENTRIES_CAPACITY = 1 << ENTRIES_LOG2_CAPACITY;\n\n        private static final int ENTRIES_MASK = ENTRIES_CAPACITY - 1;\n\n        private final MemorySegment segment;\n\n        private final long size;\n\n        private final Entry[] entries = new Entry[ENTRIES_CAPACITY];\n\n        private final byte[] keys = new byte[ENTRIES_CAPACITY * KEY_BYTES];\n\n        private final MemorySegment kms = MemorySegment.ofArray(this.keys);\n\n        private static final int KEYS_MASK = (ENTRIES_CAPACITY * KEY_BYTES) - 1;\n\n        private long offset;\n\n        private byte current;\n\n        private boolean hasCurrent = true;\n\n        Chunk(MemorySegment segment) {\n            this.segment = segment;\n            this.size = segment.byteSize();\n        }\n\n        public List<Entry> parse() {\n            long safe = size - KEY_BYTES;\n            while (offset < safe) {\n                vectorizedEntry().add(vectorizedValue());\n            }\n            next();\n            while (hasCurrent()) {\n                entry().add(value());\n            }\n            var output = new ArrayList<Entry>(entries.length);\n            for (int i = 0, o = 0; i < entries.length; i++, o += KEY_BYTES) {\n                var e = entries[i];\n                if (e != null) {\n                    e.setkey(keys, o);\n                    output.add(e);\n                }\n            }\n            return output;\n        }\n\n        private Entry vectorizedEntry() {\n            var separators = ByteVector.broadcast(BYTE_SPECIES, SEPARATOR);\n            int len = 0;\n            for (int i = 0;; i += BYTE_SPECIES_LANES) {\n                var block = ByteVector.fromMemorySegment(BYTE_SPECIES, this.segment, offset + i, NATIVE_ORDER);\n                int equals = block.compare(VectorOperators.EQ, separators).firstTrue();\n                len += equals;\n                if (equals != BYTE_SPECIES_LANES) {\n                    break;\n                }\n            }\n            var start = this.offset;\n            this.offset = start + len + 1;\n            int hash = hash(segment, start, len);\n            int index = (hash - (hash >>> -ENTRIES_LOG2_CAPACITY)) & ENTRIES_MASK;\n            int keyOffset = index << KEY_LOG2_BYTES;\n            int count = 0;\n            while (count < ENTRIES_MASK) {\n                index = index & ENTRIES_MASK;\n                keyOffset = keyOffset & KEYS_MASK;\n                var e = this.entries[index];\n                if (e == null) {\n                    MemorySegment.copy(this.segment, start, kms, keyOffset, len);\n                    return this.entries[index] = new Entry(len, hash);\n                }\n                else if (e.hash == hash && e.keyLength == len) {\n                    int total = 0;\n                    for (int i = 0; i < KEY_BYTES; i += BYTE_SPECIES_LANES) {\n                        var ekey = ByteVector.fromArray(BYTE_SPECIES, keys, keyOffset + i);\n                        var okey = ByteVector.fromMemorySegment(BYTE_SPECIES, this.segment, start + i, NATIVE_ORDER);\n                        int equals = ekey.compare(VectorOperators.NE, okey).firstTrue();\n                        total += equals;\n                        if (equals != BYTE_SPECIES_LANES) {\n                            break;\n                        }\n                    }\n                    if (total >= len) {\n                        return e;\n                    }\n                }\n                count++;\n                index++;\n                keyOffset += KEY_BYTES;\n            }\n            throw new IllegalStateException(\"Map is full!\");\n        }\n\n        private Entry entry() {\n            long start = this.offset - 1;\n            int len = 0;\n            while (hasCurrent() && current != SEPARATOR) {\n                len++;\n                next();\n            }\n            expect(SEPARATOR);\n            int hash = hash(segment, start, len);\n            int index = (hash - (hash >>> -ENTRIES_LOG2_CAPACITY)) & ENTRIES_MASK;\n            int keyOffset = index << KEY_LOG2_BYTES;\n            int count = 0;\n            while (count < ENTRIES_MASK) {\n                index = index & ENTRIES_MASK;\n                keyOffset = keyOffset & KEYS_MASK;\n                var e = this.entries[index];\n                if (e == null) {\n                    MemorySegment.copy(this.segment, start, kms, keyOffset, len);\n                    return this.entries[index] = new Entry(len, hash);\n                }\n                else if (e.hash == hash && e.keyLength == len) {\n                    int total = 0;\n                    for (int i = 0; i < len; i++) {\n                        if (((byte) BYTE_HANDLE.get(this.segment, start + i)) != this.keys[keyOffset + i]) {\n                            break;\n                        }\n                        total++;\n                    }\n                    if (total >= len) {\n                        return e;\n                    }\n                }\n                count++;\n                index++;\n                keyOffset += KEY_BYTES;\n            }\n            throw new IllegalStateException(\"Map is full!\");\n        }\n\n        private static final long MULTIPLY_ADD_DIGITS = 100 * (1L << 24) + 10 * (1L << 16) + 1;\n\n        private int vectorizedValue() {\n            long dw = (long) LONG_LE_HANDLE.get(this.segment, this.offset);\n            int zeros = Long.numberOfTrailingZeros(~dw & 0x10101000L);\n            boolean negative = ((dw & 0xFF) ^ NEG) == 0;\n            dw = ((negative ? (dw & ~0xFF) : dw) << (28 - zeros)) & 0x0F000F0F00L;\n            int value = (int) (((dw * MULTIPLY_ADD_DIGITS) >>> 32) & 0x3FF);\n            this.offset += (zeros >>> 3) + 3;\n            return negative ? -value : value;\n        }\n\n        private int value() {\n            int value = 0;\n            var negative = false;\n            if (consume(NEG)) {\n                negative = true;\n            }\n            while (hasCurrent()) {\n                if ((current & 0xF0) == 0x30) {\n                    value *= 10;\n                    value += current - '0';\n                }\n                else if (current != DECIMAL_SEPARATOR) {\n                    break;\n                }\n                next();\n            }\n            if (hasCurrent()) {\n                expect(LF);\n            }\n            return negative ? -value : value;\n        }\n\n        private static final int GOLDEN_RATIO = 0x9E3779B9;\n        private static final int HASH_LROTATE = 5;\n\n        private static int hash(MemorySegment ms, long start, int len) {\n            int x, y;\n            if (len >= Integer.BYTES) {\n                x = (int) INT_HANDLE.get(ms, start);\n                y = (int) INT_HANDLE.get(ms, start + len - Integer.BYTES);\n            }\n            else {\n                x = (byte) BYTE_HANDLE.get(ms, start) & 0xFF;\n                y = (byte) BYTE_HANDLE.get(ms, start + len - Byte.BYTES) & 0xFF;\n            }\n            return (Integer.rotateLeft(x * GOLDEN_RATIO, HASH_LROTATE) ^ y) * GOLDEN_RATIO;\n        }\n\n        private void expect(byte b) {\n            if (!consume(b)) {\n                throw new IllegalStateException(\"Unexpected token!\");\n            }\n        }\n\n        private boolean consume(byte b) {\n            if (current == b) {\n                next();\n                return true;\n            }\n            return false;\n        }\n\n        private boolean hasCurrent() {\n            return hasCurrent;\n        }\n\n        private void next() {\n            if (offset < size) {\n                this.current = (byte) BYTE_HANDLE.get(segment, offset++);\n            }\n            else {\n                this.hasCurrent = false;\n            }\n        }\n    }\n\n    private static final class Entry {\n        final int keyLength;\n\n        final int hash;\n\n        private int min = Integer.MAX_VALUE;\n\n        private int max = Integer.MIN_VALUE;\n\n        private long sum;\n\n        private int count;\n\n        private String key;\n\n        Entry(int keyLength, int hash) {\n            this.keyLength = keyLength;\n            this.hash = hash;\n        }\n\n        public String key() {\n            return key;\n        }\n\n        void setkey(byte[] keys, int offset) {\n            this.key = new String(keys, offset, keyLength, StandardCharsets.UTF_8);\n        }\n\n        public void add(int value) {\n            min = Math.min(min, value);\n            max = Math.max(max, value);\n            sum += value;\n            count++;\n        }\n\n        public Entry merge(Entry o) {\n            min = Math.min(min, o.min);\n            max = Math.max(max, o.max);\n            sum += o.sum;\n            count += o.count;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            var average = Math.round(((sum / 10.0) / count) * 10.0);\n            return decimal(min) + '/' + decimal(average) + '/' + decimal(max);\n        }\n\n        private static String decimal(long value) {\n            var builder = new StringBuilder();\n            if (value < 0) {\n                builder.append((char) NEG);\n            }\n            value = Math.abs(value);\n            builder.append(value / 10);\n            builder.append((char) DECIMAL_SEPARATOR);\n            builder.append(value % 10);\n            return builder.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_justplainlaake.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport sun.misc.Unsafe;\n\n/*\n    Possibilities to improve:\n        * Reduce Standard Memory Reads and/or Swaps for threading \n            - For the read file; using Unsafe or MemorySegment to map the file to an existing register instead of keeping the bytes local\n            - For normal variables; Most of the time reading a value performs a load from memory and registers it for faster lookups, but with multithreading causes each thread to re read and register each get [volatile] keyword\n        * Add multithreading to process multiple segments at once (When you have 1,000,000,000 cars driving might as well open as many lanes as possible)\n        * Improve Mapping of entries (More O(1) lookups the better, i.e. hashed key maps, preferebly open maps to skip needing linked lists or trees, also simplifies since we don't need to delete anything)\n        * Remove use of java streams (They can be much slower than expected, good for developer readability but not for performance 90% of the time)\n        * Reduce amount of bytecode instructions (Usually just a micro-optimization, but since we are reading 1,000,000,000 lines, then this is really helpful in the processing code)\n        * Never use division in processing code, division is 2x+ slower than multiplication (Easy fix is multiplying by decimal 2/2 vs 2*0.5)\n\n    My System:\n        Device:\n            Processor(16)\t11th Gen Intel(R) Core(TM) i7-11700K @ 3.60GHz   3.60 GHz\n            Installed RAM\t32.0 GB (31.8 GB usable)\n            System type\t64-bit operating system, x64-based processor\n            Pen and touch\tNo pen or touch input is available for this display\n        Windows Specification:\n            Edition\tWindows 11 Home\n            Version\t23H2\n            OS build\t22635.3061\n            Experience\tWindows Feature Experience Pack 1000.22684.1000.0\n\n\n    Runs (Only IDE open, just after complete shutdown, measured using System.nanoTime around main method):\n        - Baseline\n            * 144,403.3814ms\n        - merrykittyunsafe (#1 on LB)\n            * 2,757.8295ms\n        - royvanrijn (#2 on LB)\n            * 1,643.9123ms ??? Assuming this is because of my system specs compared to specs on testing system\n        //Obviously there were more runs than this, but these were the significant jumps\n        - Me run 1 (Initial attempt;multithreading, file mapped to global Unsafe, long hash of name, read byte by byte, store in hashmap and merge from threads)\n            * 5,423.4432ms\n        - Me run 2 (Read longs instead of bytes to determine name hash)\n            * 3,937.3234ms\n        - Me run 3 (Swap to using a rolling long hash with murmur3 hashing function, change hashmap to be an openmap with unboxed long as the key)\n            * 2,951.6891ms\n        - Me run 4 (Change entire line reading to be long based with bit operations to determine number)\n            * 2,684.9823ms\n        - Me run 5 (Use main thread as one of the processing threads)\n            * 2,307.3038ms\n        - Me run 6 (Remove use of math.min and math.max in favor of ternary operator (Reduces getStatic operation))\n            * 2,265.3521ms\n */\n\npublic class CalculateAverage_justplainlaake {\n\n    // Constants\n    private static final String FILE = \"./measurements.txt\";\n    private static final byte SEPERATOR_BYTE = ';';\n    private static final byte NEW_LINE_BYTE = '\\n';\n    private static final DecimalFormat STATION_FORMAT = new DecimalFormat(\"#,##0.0\");\n\n    private static final long[] OFFSET_CLEARS = {\n            0x0000000000000000L, // 8 Offset (Clear whole thing)\n            0x00000000000000FFL,\n            0x000000000000FFFFL,\n            0x0000000000FFFFFFL,\n            0x00000000FFFFFFFFL,\n            0x000000FFFFFFFFFFL,\n            0x0000FFFFFFFFFFFFL,\n            0x00FFFFFFFFFFFFFFL,\n            0xFFFFFFFFFFFFFFFFL,// 0 Offset (Clear nothing)\n    };\n\n    private static final Unsafe UNSAFE;\n    static {\n        Unsafe _unsafe = null;\n        try {\n            Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            unsafe.setAccessible(true);\n            _unsafe = (Unsafe) unsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {\n            e.printStackTrace();\n            System.exit(1);\n        }\n        UNSAFE = _unsafe;// Just to get around \"The blank final field UNSAFE may not have been initialized\"\n    }\n\n    public static void main(String[] args) throws IOException {\n        int processors = Runtime.getRuntime().availableProcessors();\n\n        ExecutorService e = null;\n\n        List<Future<OpenMap>> futures = new ArrayList<>();\n        OpenMap mainMap = null;\n        try (FileChannel channel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            long fileSize = channel.size();\n\n            if (fileSize < 10_000) {// File is smaller than 10,000 bytes, we will lose performance trying to multithread so just set processors to 1 which will skip the futures and only use main thread\n                processors = 1;\n            }\n            else {\n                e = Executors.newFixedThreadPool(processors);// Create a ThreadPool based executor using the count of processors available\n            }\n\n            long chunkSize = fileSize / processors;// Determine approximate size of each chunk based on amount of processors available\n\n            long startAddress = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global())// Map the file channel into memory using the global arena (accessible by all threads)\n                    .address();// And get the starting address of mapped section\n\n            long endAddress = startAddress + fileSize;\n            long currentAddress = startAddress + chunkSize;\n            long chunkStart = startAddress;\n\n            for (int i = 0; i < processors; i++) {// We need to chunk the file for each processor/thread\n\n                while (currentAddress < endAddress) {// While loop to locate the next new line character from the chunk we are in\n                    long match = UNSAFE.getLong(currentAddress);// Read the next 8 bytes as a long from the memory address\n                    short offset = getMaskOffset(match, NEW_LINE_BYTE);// find the byte in the long which equals 10 aka '\\n', if it is not found this returns -1\n                    if (offset != -1) {// We found the offset, so add it to the current adress and break the while loop\n                        currentAddress += offset;\n                        break;\n                    }\n                    currentAddress += 8;// No offset was found so advance 8 bytes, aka 1 long\n                }\n\n                long finalChunkStart = chunkStart, finalChunkEnd = Math.min(endAddress, currentAddress - 1);// Create final fields to pass to the thread call below,\n                // Also Math.min doesn't matter here since its called x times where x = count of processors\n\n                if (i == processors - 1) {// if on last processor use main thread to optimize threading, doing on last processor means the others are already processing while this runs\n                    mainMap = process(finalChunkStart, finalChunkEnd);\n                }\n                else {\n                    futures.add(e.submit(() -> process(finalChunkStart, finalChunkEnd)));\n                }\n                chunkStart = currentAddress + 1;// Advance the start of the next chunk to be the end of this chunk + 1 to move past the new line character\n                currentAddress = Math.min(currentAddress + chunkSize, endAddress);// Advance the next chunks end to be the end of the mapped file or the end of the approximated chunk\n            }\n        }\n\n        OpenMap merged = mainMap;// Set the main map created with the process called on main thread to make it effectively final\n\n        if (processors > 1) {// If there is only one processor then we only used the main thread so no point in merging the futures\n            // The merging of processing takes ~10ms\n            for (Future<OpenMap> f : futures) {\n                try {\n\n                    OpenMap processed = f.get();// Waits until the process task is done but then returns the callable value from the process method\n\n                    // Simple way to merge both lists, tried doing it more inline inside the map and ended up taking a 10ms longer\n                    processed.forEach((i, s) -> {\n                        merged.merge(i, s);\n                    });\n                }\n                catch (InterruptedException | ExecutionException e1) {\n                    e1.printStackTrace();\n                }\n            }\n            // Mark threadpool to be shutdown, call it here to let the threadpool finish out while the rest of the processing occurs\n            e.shutdown();\n        }\n\n        // Ordering and printing takes 50ms\n        Station[] nameOrdered = merged.toArray();// Turn the merged map into an array to quickly sort it\n\n        Arrays.sort(nameOrdered, (n1, n2) -> n1.name.compareTo(n2.name));// Sort based on name, this might be optimizable based on the longs of the name, but would likely only gain some ms??\n\n        // Print results to the sys out\n        System.out.print(\"{\");\n        for (int i = 0; i < nameOrdered.length; i++) {\n            if (i != 0) {\n                System.out.print(\", \");\n            }\n            System.out.print(nameOrdered[i]);\n        }\n        System.out.print(\"}\\n\");// Need newline character to meet specs\n    }\n\n    // Core processing functionality, processes a chunk of memory\n    private static OpenMap process(long fromAddress, long toAddress) {\n\n        OpenMap stationsLookup = new OpenMap();// Create a new map for this specific chunk, this is also the returned value for the callable\n\n        long blockStart = fromAddress;\n        long currentAddress = fromAddress;\n\n        while (currentAddress < toAddress) {// Just keep looping until we exhaust the chunk\n\n            long read = 0l;\n            short offset = -1;\n            // The hash is a long hash based on the murmur3 algorithm. Look at the getMurmurHash3 method to find link\n            long hash = 1;\n\n            while ((offset = getMaskOffset(read = UNSAFE.getLong(currentAddress), SEPERATOR_BYTE)) == -1) {// Read and compute the hash until we locate the seperator byte 59 or ';'\n                currentAddress += 8;// forwardscan\n                hash = (997 * hash) ^ getMurmurHash3(991 * read);\n            }\n\n            // Compute the final hash based using the last read long but only the effective bits (anything before the byte 59 or ';').\n            // Using the OFFSET_CLEARS masks that are defined statically we can essentially segregate the important bits of the name based on the offset read above\n            hash = (997 * hash) ^ getMurmurHash3(991 * (read & OFFSET_CLEARS[offset]));\n\n            // Advance the current address/pointer to be 1 character past the end of the name Example: BillyJoel;29 would make the current address start at the '2' character\n            currentAddress += offset + 1;\n\n            Station station = stationsLookup.getOrCreate(hash, currentAddress, blockStart);\n\n            /*\n             * Possible combinations (x = number) -99.9 -> 99.9; ex: 54.4, -31.7, -4.5, 1.9\n             * x.x\n             * xx.x\n             * -x.x\n             * -xx.x\n             */\n\n            // Encoding is UTF8 however, since numbers in UTF8 are all single byte characters we can do some byte math to determin the number; 0=48 and 9=57, so character - 48 = number\n            // And since - and . are also single byte characters we can make some assumptions, leading us with the primary one that no matter what the number will be 3 to 5 bytes (see above combinations)\n            // Unfortunately since an integer is only 4 bytes we must read the long; Something to test would be to see if we could read an integer and then read an extra byte if it is the 5 character edge case\n            read = UNSAFE.getLong(currentAddress);\n\n            offset = 0;// reinitiate the offset to reuse the local address\n\n            byte sign = (byte) ((read >> offset) ^ 45);// Check the first byte of the new long to see if it is 45 aka '-', if it is this byte will be 0\n\n            // The logic below is based on the fact that we are reading\n            int num = sign == 0 ? (((byte) (read >> (offset += 8))) - 48) : (((byte) read) - 48);// Start the number reading, if it is a negative advance 8 bits in the long (8 bits = 1 byte)\n            currentAddress += 4;// There will always be at least 3 digits to read and the newline digit (4 total)\n            if ((byte) ((read >> (offset + 8)) ^ 46) != 0) {// There can only be one more possible number for cases of (XY.X | -XY.X) where Y is that other number\n                num *= 10;\n                num += ((byte) (read >> (offset += 8))) - 48;\n                currentAddress++;// Add one digit read if temp is 3 digits\n            }\n            num *= 10;\n            num += ((byte) (read >> (offset + 16))) - 48;// Read the decimal character (no matter what it is 16 bits past the offset here, since 8 bits is the last number and 8 bits is the decimal)\n            if (sign == 0) {\n                num *= -1;\n                currentAddress++;// Add another digit read for the negative sign\n            }\n\n            // Assign the values, don't use Math.min or any special bit manipulation. Faster to just use ternary\n            station.min = station.min < num ? station.min : num;\n            station.max = station.max > num ? station.max : num;\n            station.count++;\n            station.sum += num;\n            // And now set the next block to start at the current address\n            blockStart = currentAddress;\n        }\n        return stationsLookup;\n    }\n\n    // Avalanche hashing function for longs: https://github.com/aappleby/smhasher/blob/master/README.md\n    public final static long getMurmurHash3(long x) {\n        x ^= x >>> 33;\n        x *= 0xff51afd7ed558ccdL;\n        x ^= x >>> 33;\n        x *= 0xc4ceb9fe1a85ec53L;\n        x ^= x >>> 33;\n        return x;\n    }\n\n    // Simple way to identify if a byte is set in a long at any of the 8 spots, and also to get the offset of that byte.\n    // On average this is fast but certain cases could make it slow (checking 500,000,000,000 longs that don't have the test byte at all...)\n    private static short getMaskOffset(long value, byte test) {\n        for (short i = 0; i < 8; i++) {\n            if (((byte) value & 0xFF) == test) {\n                return i;\n            }\n            value = value >> 8;\n        }\n        return -1;\n    }\n\n    private static class Station {\n        private final long nameStart, nameEnd;// Store the starting and ending address of the name, to fill it later\n        private final int nameLength;\n        private int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE, count;\n        private long sum;\n        private String name;\n\n        Station(long nameStart, long nameEnd) {\n            this.nameStart = nameStart;\n            this.nameEnd = nameEnd;\n            this.nameLength = (int) (nameEnd - nameStart) + 1;// Add 1 to include seperator\n        }\n\n        protected void fillName() {\n            byte[] nameBuffer = new byte[(int) (nameEnd - nameStart)];\n            UNSAFE.copyMemory(null, this.nameStart, nameBuffer, Unsafe.ARRAY_BYTE_BASE_OFFSET, nameBuffer.length);// Quick memory copy, using null as src copies from the file we mapped earlier\n            name = new String(nameBuffer, StandardCharsets.UTF_8);\n        }\n\n        @Override\n        public String toString() {// Use decimal format to print numbers\n            return name + \"=\" + STATION_FORMAT.format(Math.round(min) * 0.1) + \"/\" + STATION_FORMAT.format(Math.round(((double) sum) / count) * 0.1) + \"/\"\n                    + STATION_FORMAT.format(Math.round(max) * 0.1);\n        }\n\n    }\n\n    public static class OpenMap {\n        public static final float LOAD_FACTOR = 0.75f;\n        public static final int EXPECTED_INITIAL_SIZE = 100_000;\n\n        protected transient long[] keys;// Use unboxed long values as a key, faster than a doing new HashMap<Long,X>() as with generics it will box/unbox every action (can be costly in large quantities)\n        protected transient Station[] values;\n        protected transient int capacity;\n        protected transient int maxFill;\n        protected transient int mask;\n        protected int size;\n\n        public OpenMap() {\n            // capacity = (int) getNextPowerOfTwo((long) Math.ceil(EXPECTED_INITIAL_SIZE / LOAD_FACTOR));// need to base the capacity on the next power of two for the mask to work properly\n            // initial size of 100k gives 262,144 Capacity, since we know this and its way oversized for a max of 10k keys theres no need to recalculate\n            capacity = 262_144;\n            mask = capacity - 1;\n            maxFill = (int) Math.ceil(capacity * 0.75f);// Only allow 75% of capacity before resizing\n            keys = new long[capacity];\n            values = new Station[capacity];\n        }\n\n        public void merge(long key, Station toMerge) {\n            // Simple compute function, if exists pass existing, if it doesn't pass null\n            int pos = (int) key & mask;// Key has already been hashed as we read, but cap it by mask\n            while (values[pos] != null) {\n                if (keys[pos] == key) {\n                    final Station oldValue = values[pos];\n\n                    // If names are different size but key was same, then continue to next step as hash collided\n                    // Compare memory values to see if the name is same as well, prevents hash collision\n                    if (oldValue.nameLength == toMerge.nameLength && compareMemory(toMerge.nameStart, oldValue.nameStart, oldValue.nameLength)) {\n                        // Memory was the same, making these the same station\n                        oldValue.count += toMerge.count;\n                        oldValue.sum += toMerge.sum;\n                        oldValue.min = oldValue.min < toMerge.min ? oldValue.min : toMerge.min;\n                        oldValue.max = oldValue.max > toMerge.max ? oldValue.max : toMerge.max;\n                        return;\n                    }\n                }\n                pos = (pos + 1) & mask;\n            }\n            keys[pos] = key;\n            values[pos] = toMerge;\n            size++;\n        }\n\n        public Station getOrCreate(final long key, long currentAddress, long blockStart) {\n            int pos = (int) key & mask;// Key has already been hashed as we read, but cap it by mask\n            while (values[pos] != null) {// While position is set\n                if (keys[pos] == key) {// Check if key is correct\n\n                    // If names are different size but key was same, then continue to next step as hash collided\n                    // Compare memory values to see if the name is same as well, prevents hash collision\n                    if (values[pos].nameLength == currentAddress - blockStart && compareMemory(blockStart, values[pos].nameStart, values[pos].nameLength)) {\n                        return values[pos];\n                    }\n                }\n                pos = (pos + 1) & mask;// Since this is an open map we keep checking next masked key for an open spot (Faster than tree or linked list on a specific node)\n            }\n            keys[pos] = key;\n            size++;\n            return values[pos] = new Station(blockStart, currentAddress - 1);// Since current address contains the splitter (we will subtract by 1 here, better to do here since this is only called when it doesn't exist less math = performance)\n        }\n\n        // Simple iterator for each set value\n        public void forEach(OpenConsumer consumer) {\n            for (int i = 0; i < this.capacity; i++) {\n                if (values[i] != null) {\n                    consumer.accept(keys[i], values[i]);\n                }\n            }\n        }\n\n        public Station[] toArray() {\n            Station[] array = new Station[size];\n            int setter = 0;\n            for (int i = 0; i < capacity; i++) {\n                if (values[i] != null) {\n                    array[setter++] = values[i];\n                    values[i].fillName();\n                }\n            }\n            return array;\n        }\n\n        // Bit function to get the next power of two on some number, used to determine best capacity based on initial size\n        public long getNextPowerOfTwo(long length) {\n            if (length-- == 0)\n                return 1;\n            length |= length >> 1;\n            length |= length >> 2;\n            length |= length >> 4;\n            length |= length >> 8;\n            length |= length >> 16;\n            return (length | length >> 32) + 1;\n        }\n\n        private boolean compareMemory(long start1, long start2, int length) {\n            while (length > 0) {\n                if (length >= 8) {\n                    if (UNSAFE.getLong(start1) != UNSAFE.getLong(start2)) {\n                        return false;\n                    }\n                }\n                else {\n                    if ((UNSAFE.getLong(start1) & OFFSET_CLEARS[length]) != (UNSAFE.getLong(start2) & OFFSET_CLEARS[length])) {\n                        System.out.println(\"Found collision: \" + start1 + \": \" + start2);\n                        System.out.println(\"Found collision: \" + UNSAFE.getLong(start1) + \": \" + UNSAFE.getLong(start2));\n                        System.out.println(\"Length: \" + length);\n                        return false;\n                    }\n                }\n                length -= 8;\n                start1 += 8;\n                start2 += 8;\n            }\n            return true;\n        }\n\n        @FunctionalInterface\n        public static interface OpenConsumer {\n            void accept(long key, Station value);\n        }\n\n        @FunctionalInterface\n        public static interface OpenFunction {\n            Station action(long key, Station value);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_karthikeyan97.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.FileInputStream;\n\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Scanner;\nimport java.util.Set;\nimport java.util.TreeMap;\nimport java.util.function.BiConsumer;\nimport java.util.function.BinaryOperator;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_karthikeyan97 {\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private record Measurement(modifiedbytearray station, double value) {\n    }\n\n    private record customPair(String stationName, MeasurementAggregator agg) {\n    }\n\n    private static class MeasurementAggregator {\n        private long min = Long.MAX_VALUE;\n        private long max = Long.MIN_VALUE;\n        private long sum;\n        private long count;\n\n        public String toString() {\n            return new StringBuffer(14)\n                    .append(round((1.0 * min)))\n                    .append(\"/\")\n                    .append(round((1.0 * sum) / count))\n                    .append(\"/\")\n                    .append(round((1.0 * max))).toString();\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // long start = System.nanoTime();\n        // System.setSecurityManager(null);\n        Collector<Map.Entry<modifiedbytearray, MeasurementAggregator>, MeasurementAggregator, MeasurementAggregator> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    MeasurementAggregator agg = m.getValue();\n                    if (a.min >= agg.min) {\n                        a.min = agg.min;\n                    }\n                    if (a.max <= agg.max) {\n                        a.max = agg.max;\n                    }\n                    a.max = Math.max(a.max, m.getValue().max);\n                    a.sum += m.getValue().sum;\n                    a.count += m.getValue().count;\n                },\n                (agg1, agg2) -> {\n                    if (agg1.min <= agg2.min) {\n                        agg2.min = agg1.min;\n                    }\n                    if (agg1.max >= agg2.max) {\n                        agg2.max = agg1.max;\n                    }\n                    agg2.sum = agg1.sum + agg2.sum;\n                    agg2.count = agg1.count + agg2.count;\n\n                    return agg2;\n                },\n                agg -> agg);\n\n        RandomAccessFile raf = new RandomAccessFile(FILE, \"r\");\n        FileChannel fileChannel = raf.getChannel();\n        final long mappedAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, raf.length(), Arena.global()).address();\n        long length = raf.length();\n        final long endAddress = mappedAddress + length - 1;\n        int cores = length > 1000 ? Runtime.getRuntime().availableProcessors() : 1;\n        long boundary[][] = new long[cores][2];\n        long segments = length / (cores);\n        long before = -1;\n        for (int i = 0; i < cores - 1; i++) {\n            boundary[i][0] = before + 1;\n            if (before + segments - 107 > 0) {\n                raf.seek(before + segments - 107);\n            }\n            else {\n                raf.seek(0);\n            }\n            while (raf.read() != '\\n') {\n            }\n            boundary[i][1] = raf.getChannel().position() - 1;\n            before = boundary[i][1];\n        }\n        boundary[cores - 1][0] = before + 1;\n        boundary[cores - 1][1] = length - 1;\n\n        int l3Size = (12 * 1024 * 1024);// unsafe.l3Size();\n\n        System.out.println(new TreeMap((Arrays.stream(boundary).parallel().map(i -> {\n            try {\n                int seglen = (int) (i[1] - i[0] + 1);\n                HashMap<modifiedbytearray, MeasurementAggregator> resultmap = new HashMap<>(4000);\n                long segstart = mappedAddress + i[0];\n                int bytesRemaining = seglen;\n                long num = 0;\n                boolean isNumber = false;\n                byte bi;\n                int sign = 1;\n                modifiedbytearray stationName = null;\n                int hascode = 5381;\n                // System.out.println(\"start:\" + System.nanoTime() / 1000000);\n                while (bytesRemaining > 0) {\n                    int bytesptr = 0;\n                    // int bytesread = buffer.remaining() > l3Size ? l3Size : buffer.remaining();\n                    // byte[] bufferArr = new byte[bytesread];\n                    // buffer.get(bufferArr);\n                    int bbstart = 0;\n                    int readSize = bytesRemaining > l3Size ? l3Size : bytesRemaining;\n                    int actualReadSize = (segstart + readSize + 110 > endAddress || readSize + 110 > i[1]) ? readSize : readSize + 110;\n                    byte[] readArr = new byte[actualReadSize];\n\n                    UNSAFE.copyMemory(null, segstart, readArr, UNSAFE.ARRAY_BYTE_BASE_OFFSET, actualReadSize);\n                    while (bytesptr < actualReadSize) {\n                        bi = readArr[bytesptr++];// UNSAFE.getByte(segstart + bytesReading++);\n                        if (!isNumber) {\n                            while (bi != 59) {\n                                hascode = (hascode << 5) + hascode ^ bi;\n                                bi = readArr[bytesptr++];\n                            }\n                            isNumber = true;\n                            stationName = new modifiedbytearray(readArr, bbstart, bytesptr - 2, hascode & 0xFFFFFFFF);\n                            bbstart = 0;\n                            hascode = 5381;\n                        }\n                        else {\n                            while (bi != 10) {\n                                if (bi == 0x2D) {\n                                    sign = -1;\n                                }\n                                else if (bi != 0x2E) {\n                                    num = num * 10 + (bi - 0x30);\n                                }\n                                bi = readArr[bytesptr++];\n                            }\n                            hascode = 5381;\n                            isNumber = false;\n                            bbstart = bytesptr;\n                            num *= sign;\n                            MeasurementAggregator agg = resultmap.get(stationName);\n                            if (agg == null) {\n                                agg = new MeasurementAggregator();\n                                agg.min = num;\n                                agg.max = num;\n                                agg.sum = (long) (num);\n                                agg.count = 1;\n                                resultmap.put(stationName, agg);\n                            }\n                            else {\n                                if (agg.min >= num) {\n                                    agg.min = num;\n                                }\n                                if (agg.max <= num) {\n                                    agg.max = num;\n                                }\n                                agg.sum += (long) (num);\n                                agg.count++;\n                            }\n                            num = 0;\n                            sign = 1;\n                            if (bytesptr >= readSize) {\n                                break;\n                            }\n                        }\n                    }\n                    bytesRemaining -= bytesptr;\n                    segstart += bytesptr;\n                }\n                // System.out.println(\"end:\" + System.nanoTime() / 1000000);\n                /*\n                 * while (bytesReading < (i[1] - i[0] + 1) && buffer.position() < buffer.limit()) {\n                 * buffer.clear();\n                 * bytesRead = fileChannel.read(buffer);\n                 * buffer.flip();\n                 * while (bytesReading <= (i[1] - i[0]) && buffer.position() < buffer.limit()) {\n                 * bytesReading += 1;\n                 * bi = buffer.get();\n                 * String s;\n                 * if (ctr > 0) {\n                 * hascode = 31 * hascode + bi;\n                 * ctr--;\n                 * }\n                 * else {\n                 * if (bi >= 240) {\n                 * ctr = 3;\n                 * }\n                 * else if (bi >= 224) {\n                 * ctr = 2;\n                 * }\n                 * else if (bi >= 192) {\n                 * ctr = 1;\n                 * }\n                 * else if (bi == 59) {\n                 * isNumber = true;\n                 * System.out.println(buffer);\n                 * stationName = new modifiedbytearray(bbstart, buffer.position() - 1, hascode, buffer);\n                 * hascode = 1;\n                 * bbstart = buffer.position();\n                 * }\n                 * else if (bi == 10) {\n                 * hascode = 1;\n                 * isNumber = false;\n                 * MeasurementAggregator agg = resultmap.get(stationName);\n                 * if (agg == null) {\n                 * agg = new MeasurementAggregator();\n                 * agg.min = num * sign;\n                 * agg.max = num * sign;\n                 * agg.sum = (long) (num * sign);\n                 * agg.count = 1;\n                 * resultmap.put(stationName, agg);\n                 * }\n                 * else {\n                 * agg.min = Math.min(agg.min, num * sign);\n                 * agg.max = Math.max(agg.max, num * sign);\n                 * agg.sum += (long) (num * sign);\n                 * agg.count++;\n                 * }\n                 * num = 1;\n                 * bbstart = buffer.position();\n                 * }\n                 * else {\n                 * hascode = 31 * hascode + bi;\n                 * if (isNumber) {\n                 * switch (bi) {\n                 * case 0x2E:\n                 * break;\n                 * case 0x2D:\n                 * num = num * -1;\n                 * break;\n                 * default:\n                 * num = num * 10 + (bi - 0x30);\n                 * }\n                 * }\n                 * }\n                 * }\n                 * }\n                 * }\n                 */\n                return resultmap;\n            }\n            catch (Exception e) {\n                e.printStackTrace();\n            }\n            return null;\n        }).flatMap(e -> e.entrySet().stream()).collect(groupingBy(e -> e.getKey(), collector)))) {\n            @Override\n            public Object put(Object key, Object value) {\n                return super.put(((modifiedbytearray) key).getStationName(), value);\n            }\n        });\n\n        /*\n         * .map(a -> {\n         * return a.stream().parallel().collect(groupingBy(m -> m.station(), collector));\n         * }).flatMap(m -> m.entrySet()\n         * .stream()\n         */\n        // Get the FileChannel from the FileInputStream\n\n        // System.out.println(\"time taken1:\" + (System.nanoTime() - start) / 1000000);\n        // System.out.println(measurements);\n    }\n\n}\n\nclass modifiedbytearray {\n    private int length;\n    private int start;\n    private int end;\n    private byte[] arr;\n    public int hashcode;\n\n    modifiedbytearray(byte[] arr, int start, int end, int hashcode) {\n        this.arr = arr;\n        this.length = end - start + 1;\n        this.end = end;\n        this.start = start;\n        this.hashcode = hashcode;\n    }\n\n    public String getStationName() {\n        return new String(this.getArr(), start, length, StandardCharsets.UTF_8);\n    }\n\n    public byte[] getArr() {\n        return this.arr;\n    }\n\n    @Override\n    public String toString() {\n        return getStationName();\n    }\n\n    @Override\n    public boolean equals(Object obj) {\n        modifiedbytearray b = (modifiedbytearray) obj;\n        return Arrays.equals(this.getArr(), start, end, b.arr, b.start, b.end);\n    }\n\n    public int getHashcode() {\n        return hashcode;\n    }\n\n    @Override\n    public int hashCode() {\n        return hashcode;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_kevinmcmurtrie.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.Spliterator;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.Future;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\n\n/**\n * Kevin McMurtrie https://github.com/kevinmcmurtrie\n * <p>\n * Code challenge submission for https://github.com/gunnarmorling/1brc\n */\npublic class CalculateAverage_kevinmcmurtrie implements AutoCloseable {\n    private static final String FILE = \"./measurements.txt\";\n    private static final Charset CHARSET = StandardCharsets.UTF_8;\n    private static final int THREADS = Runtime.getRuntime().availableProcessors() + 2;\n\n    // This is used for push-back when fitting buffers to the last line break\n    private static final int MAX_LINE_LENGTH = 1024;\n\n    private static final int READ_CHUNK_SIZE = 4 * 1024 * 1024;\n    private static final int CHAR_CHUNK_SIZE = Math.max(MAX_LINE_LENGTH, 64 * 1024);\n\n    // Internal array size for hashing cities\n    private static final int HASH_BUCKETS = 1039;\n\n    // Fixed-point number parameters\n    private static final int DIGITS_AFTER_DECIMAL_POINT_INPUT = 1;\n    private static final int DIGITS_AFTER_DECIMAL_POINT_OUTPUT = 1;\n\n    // City and Temperature delimiter\n    private static final char DELIMITER = ';';\n\n    private final LineAlignedInput in; // Must synchronize on this when multiple threads are reading. Use fillFromFile().\n\n    public static class Accumulator {\n        private static final Comparator<Element> cityComparator = new Comparator<>() {\n            @Override\n            public int compare(Element a, Element b) {\n                return Arrays.compare(a.line, b.line);\n            }\n        };\n\n        private final Element buckets[];\n\n        public Accumulator(final int bucketCount) {\n            buckets = new Element[bucketCount];\n        }\n\n        /**\n         * Custom hash element.\n         * <ul>\n         * <li>Can avoid many expensive substring operations while parsing\n         * <li>Combines the key and values into a single object\n         * </ul>\n         */\n        public static class Element {\n            private final char[] line;\n            private final int hashCode;\n            private final Element collision;\n            private long min = 0;\n            private long max = 0;\n            private long sum = 0;\n            private long count = 0;\n\n            public Element(final Element collision, final char[] line, final int hashCode, final long value) {\n                this.collision = collision;\n                this.line = line;\n                this.hashCode = hashCode;\n                min = value;\n                max = value;\n                sum = value;\n                count = 1;\n            }\n\n            public Element(final Element collision, final Element src) {\n                this.collision = collision;\n                this.line = src.line;\n                this.hashCode = src.hashCode;\n                min = src.min;\n                max = src.max;\n                sum = src.sum;\n                count = src.count;\n            }\n\n            void accumulate(final long value) {\n                min = Math.min(value, min);\n                max = Math.max(value, max);\n                sum = Math.addExact(sum, value);\n                count++;\n            }\n\n            private void merge(final Element a) {\n                min = Math.min(a.min, min);\n                max = Math.max(a.max, max);\n                sum = Math.addExact(sum, a.sum);\n                count += a.count;\n            }\n\n            @Override\n            /**\n             * City=min/avg/max\n             */\n            public String toString() {\n                return new String(line) + '=' + fixedToString(min) + \"/\" + fixedToString((double) sum / count) + \"/\" + fixedToString(max);\n            }\n        }\n\n        /**\n         * Hasher that operates on a buffer without generating a substring\n         */\n        static private final int hasher(final char[] buf, final int start, final int end) {\n            int hc = buf[start];\n            for (int i = start + 1; i < end; ++i) {\n                hc = hc * 31 + buf[i];\n            }\n            return hc & Integer.MAX_VALUE;\n        }\n\n        /**\n         * Tests if a pre-calculated hash and buffer area match an Element\n         */\n        static boolean matches(final Element o, final char[] str, final int start, final int end, final int hashCode) {\n            return (hashCode == o.hashCode) && Arrays.equals(o.line, 0, o.line.length, str, start, end);\n        }\n\n        static boolean matches(final Element a, final Element b) {\n            return (a.hashCode == b.hashCode) && Arrays.equals(a.line, b.line);\n        }\n\n        /**\n         * Merge another Accumulator into this one\n         *\n         * @param src\n         */\n        void merge(final Accumulator src) {\n            for (final Element srcElementHead : src.buckets) {\n                for (Element srcElem = srcElementHead; srcElem != null; srcElem = srcElem.collision) {\n                    final int idx = srcElem.hashCode % buckets.length;\n\n                    final Element elementHead = buckets[idx];\n                    boolean found = false;\n                    for (Element e = elementHead; e != null; e = e.collision) {\n                        if (matches(e, srcElem)) {\n                            e.merge(srcElem);\n                            found = true;\n                            break;\n                        }\n                    }\n                    if (!found) {\n                        buckets[idx] = new Element(elementHead, srcElem);\n                    }\n                }\n            }\n        }\n\n        /**\n         * Accumulate a weather string\n         *\n         * @param str City;temperature\n         */\n        void accumulate(final char[] buf, final int delimiterPos, final int start, final int end) {\n            final long value = readFixed(buf, delimiterPos + 1, end);\n\n            final int hc = hasher(buf, start, delimiterPos);\n            final int idx = hc % buckets.length;\n            final Element elementHead = buckets[idx];\n\n            for (Element e = elementHead; e != null; e = e.collision) {\n                if (matches(e, buf, start, delimiterPos, hc)) {\n                    e.accumulate(value);\n                    return;\n                }\n            }\n\n            buckets[idx] = new Element(elementHead, Arrays.copyOfRange(buf, start, delimiterPos), hc, value);\n        }\n\n        /**\n         * @return A stream of Element.toString() values.\n         */\n        public Stream<Element> toStream() {\n            final Spliterator<Element> sp = new Spliterator<>() {\n                int idx = 0;\n                Element elem = null;\n\n                @Override\n                public boolean tryAdvance(final Consumer<? super Element> action) {\n                    while ((elem == null) && (idx < buckets.length)) {\n                        elem = buckets[idx++];\n                    }\n\n                    if (elem != null) {\n                        final Element result = elem;\n                        elem = result.collision;\n                        action.accept(result);\n                        return true;\n                    }\n                    return false;\n                }\n\n                @Override\n                public Spliterator<Element> trySplit() {\n                    return null;\n                }\n\n                @Override\n                public long estimateSize() {\n                    return buckets.length;\n                }\n\n                @Override\n                public int characteristics() {\n                    return DISTINCT | NONNULL;\n                }\n\n            };\n            return StreamSupport.stream(sp, false);\n        }\n\n        /**\n         * Converts rounds a higher precision fixed-point to a string. Not optimized.\n         */\n        static String fixedToString(final double d) {\n            return String.valueOf(\n                    Math.round(d / Math.pow(10, DIGITS_AFTER_DECIMAL_POINT_INPUT - DIGITS_AFTER_DECIMAL_POINT_OUTPUT)) / Math.pow(10, DIGITS_AFTER_DECIMAL_POINT_OUTPUT));\n        }\n\n        /**\n         * Read the suffix of a string as a fixed point number.\n         * Doesn't allocate memory except for exceptions.\n         */\n        static long readFixed(final char[] str, final int offset, final int end) {\n            char c;\n            int pos = offset;\n            while ((c = str[pos]) == ' ') {\n                pos++;\n            }\n\n            final boolean negate = c == '-';\n            if (negate) {\n                pos++;\n            }\n\n            c = str[pos++];\n            if ((c < '0') || (c > '9')) {\n                throw new IllegalArgumentException(new String(str, offset, end - offset));\n            }\n\n            long v = c - '0';\n\n            for (; pos < end; ++pos) {\n                c = str[pos];\n                if (c == '.') {\n                    pos++;\n                    break;\n                }\n                if ((c < '0') || (c > '9')) {\n                    throw new IllegalArgumentException(new String(str, offset, end - offset));\n                }\n                v = v * 10 + c - '0';\n            }\n\n            final int fractLimit = pos + DIGITS_AFTER_DECIMAL_POINT_INPUT;\n            for (; (pos < end) && (pos < fractLimit); ++pos) {\n                c = str[pos];\n                if ((c < '0') || (c > '9')) {\n                    throw new IllegalArgumentException(new String(str, offset, end - offset));\n                }\n                v = v * 10 + c - '0';\n            }\n\n            for (; (pos < fractLimit); ++pos) {\n                v = v * 10;\n            }\n\n            return negate ? -v : v;\n        }\n    }\n\n    public CalculateAverage_kevinmcmurtrie(final String path) throws IOException {\n        in = new LineAlignedInput(new FileInputStream(path), MAX_LINE_LENGTH);\n    }\n\n    @Override\n    public void close() throws IOException {\n        in.close();\n    }\n\n    /**\n     * Fill a byte buffer with the end aligned to a CR or LF.\n     *\n     * @param b A byte array at least large enough to hold one full line.\n     * @return Number of bytes filled, or zero for EOF\n     * @throws IOException\n     */\n    static class LineAlignedInput implements AutoCloseable {\n        private final InputStream in;\n        private final byte[] pushbackStack;\n        private int pushedBackLen = 0;\n\n        public LineAlignedInput(final InputStream in, final int maxLineLength) {\n            this.in = in;\n            pushbackStack = new byte[maxLineLength];\n        }\n\n        public int fillChunk(final byte buf[]) throws IOException {\n            int offset = 0;\n            // Recover last pushback\n            while ((pushedBackLen > 0) && (offset < buf.length)) {\n                buf[offset++] = pushbackStack[--pushedBackLen];\n            }\n\n            final int readSize = in.read(buf, offset, buf.length - offset);\n            if (readSize <= 0) {\n                return offset;\n            }\n            final int size = readSize + offset;\n\n            // Roll back end of buffer to a line break so it's not truncated\n            int rollbackPos = size - 1;\n            if (rollbackPos > 0) {\n                byte b;\n                while (((b = buf[rollbackPos]) != '\\n') && (b != '\\r')) {\n                    pushbackStack[pushedBackLen++] = b;\n                    rollbackPos--;\n                    if (rollbackPos == 0) {\n                        return size; // Last entry. Return as-as.\n                    }\n                }\n            }\n\n            return rollbackPos + 1;\n        }\n\n        @Override\n        public void close() throws IOException {\n            in.close();\n        }\n    }\n\n    /**\n     * Fill a char buffer with the end aligned to a CR or LF.\n     *\n     * @param b A char array at least large enough to hold one full line.\n     * @return Number of bytes filled, or zero for EOF\n     * @throws IOException\n     */\n    static class LineAlignedReader implements AutoCloseable {\n        private final Reader in;\n        private final char[] pushbackStack;\n        private int pushedBackLen = 0;\n\n        public LineAlignedReader(final Reader in, final int maxLineLength) {\n            this.in = in;\n            pushbackStack = new char[maxLineLength];\n        }\n\n        public int fillChunk(final char buf[]) throws IOException {\n            int offset = 0;\n            // Recover last pushback\n            while ((pushedBackLen > 0) && (offset < buf.length)) {\n                buf[offset++] = pushbackStack[--pushedBackLen];\n            }\n\n            final int readSize = in.read(buf, offset, buf.length - offset);\n            if (readSize <= 0) {\n                return offset;\n            }\n            final int size = readSize + offset;\n\n            // Roll back end of buffer to a line break so it's not truncated\n            int rollbackPos = size - 1;\n            if (rollbackPos > 0) {\n                char b;\n                while (((b = buf[rollbackPos]) != '\\n') && (b != '\\r')) {\n                    pushbackStack[pushedBackLen++] = b;\n                    rollbackPos--;\n                    if (rollbackPos == 0) {\n                        return size; // Last entry. Return as-as.\n                    }\n                }\n            }\n\n            return rollbackPos + 1;\n        }\n\n        @Override\n        public void close() throws IOException {\n            in.close();\n        }\n    }\n\n    private int fillFromFile(final byte buf[]) throws IOException {\n        synchronized (in) {\n            return in.fillChunk(buf);\n        }\n    }\n\n    /**\n     * Read as fast as possible and collect values.\n     * There's some expensive charset and String work here so many of these may run in parallel.\n     */\n    public Accumulator collect() throws IOException {\n        final Accumulator accumulation = new Accumulator(HASH_BUCKETS);\n        final byte buf[] = new byte[READ_CHUNK_SIZE];\n        final char cbuf[] = new char[CHAR_CHUNK_SIZE];\n\n        int blen;\n        while ((blen = fillFromFile(buf)) > 0) {\n            try (LineAlignedReader reader = new LineAlignedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, blen), CHARSET), CHAR_CHUNK_SIZE)) {\n                int length;\n                while ((length = reader.fillChunk(cbuf)) > 0) {\n                    int pos = 0;\n                    do {\n                        // Skip whitespace\n                        while ((pos < length) && Character.isWhitespace(cbuf[pos])) {\n                            pos++;\n                        }\n                        final int start = pos;\n                        if (start < length) {\n                            int lastDelimiterPos = -1;\n                            int c;\n                            while ((pos < length) && ((c = cbuf[pos]) != '\\n') && (c != '\\r')) {\n                                if (c == DELIMITER) {\n                                    lastDelimiterPos = pos;\n                                }\n                                pos++;\n                            }\n\n                            if (pos > start) {\n                                if (lastDelimiterPos < 1) {\n                                    throw new IllegalArgumentException(\"Malformed input: \" + new String(cbuf, start, pos - start));\n                                }\n                                accumulation.accumulate(cbuf, lastDelimiterPos, start, pos);\n                            }\n                        }\n                    } while (pos < length);\n                }\n            }\n        }\n        return accumulation;\n    }\n\n    /**\n     * Run multiple collectors and merge the results. Performance\n     * is optimized for reading many values but not for merging many results.\n     *\n     * @param threads How many threads to allocate\n     * @return Accumulator\n     * @throws InterruptedException\n     * @throws ExecutionException\n     */\n    public Accumulator collectParallel(final int threads) throws InterruptedException, ExecutionException {\n        final Accumulator acc;\n        // ForkJoinPool is somehow faster even without major work stealing. Class loading?\n        try (final ExecutorService pool = new ForkJoinPool(threads)) {\n            @SuppressWarnings(\"unchecked\")\n            final Future<Accumulator> tasks[] = new Future[threads];\n\n            for (int i = 0; i < threads; ++i) {\n                tasks[i] = pool.submit(this::collect);\n            }\n            acc = tasks[0].get();\n            for (int i = 1; i < threads; ++i) {\n                acc.merge(tasks[i].get());\n            }\n        }\n        return acc;\n    }\n\n    public static void main(final String args[]) throws IOException, InterruptedException, ExecutionException {\n        // final long startMillis = System.currentTimeMillis();\n\n        final String path = args.length > 0 ? args[0] : FILE;\n\n        final Accumulator acc;\n        try (CalculateAverage_kevinmcmurtrie c = new CalculateAverage_kevinmcmurtrie(path)) {\n            acc = c.collectParallel(THREADS);\n        }\n\n        System.out.println(acc.toStream().sorted(Accumulator.cityComparator).map(String::valueOf).collect(Collectors.joining(\", \", \"{\", \"}\")));\n        // System.out.println((System.currentTimeMillis() - startMillis) / 1000f);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_kgeri.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.io.UncheckedIOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.channels.FileChannel;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.stream.LongStream;\n\nimport static java.lang.foreign.ValueLayout.JAVA_BYTE;\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.charset.StandardCharsets.UTF_8;\n\npublic class CalculateAverage_kgeri {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class MeasurementAggregate {\n        private double min = Double.POSITIVE_INFINITY;\n        private double sum = 0d;\n        private double max = Double.NEGATIVE_INFINITY;\n        private long count;\n\n        public void append(double measurement) {\n            min = Math.min(min, measurement);\n            max = Math.max(max, measurement);\n            sum += measurement;\n            count++;\n        }\n\n        public void merge(MeasurementAggregate other) {\n            min = Math.min(min, other.min);\n            max = Math.max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n        }\n\n        @Override\n\t\tpublic String toString() {\n\t\t\treturn STR.\"\\{round(min)}/\\{round(sum / count)}/\\{round(max)}\";\n\t\t}\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    /**\n     * This is to avoid instantiating `String`s during processing as much as possible.\n     */\n    private static class StringSlice {\n        protected final byte[] buf;\n        protected int len;\n        protected int hash;\n\n        public StringSlice(StringSlice other) {\n            buf = Arrays.copyOfRange(other.buf, 0, other.len);\n            len = other.len;\n            hash = other.hash;\n        }\n\n        public StringSlice(byte[] buf, int len) {\n            this.buf = buf;\n            this.len = len;\n            calculateHash();\n        }\n\n        public int length() {\n            return len;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return obj instanceof StringSlice other && Arrays.equals(buf, 0, len, other.buf, 0, other.len);\n        }\n\n        @Override\n        public String toString() {\n            return new String(buf, 0, len, UTF_8);\n        }\n\n        protected void calculateHash() {\n            hash = 1;\n            for (int i = 0; i < len; i++) {\n                hash = 31 * hash + buf[i];\n            }\n        }\n    }\n\n    /**\n     * A flyweight of {@link StringSlice}, to avoid instantiating that as well.\n     */\n    private static class MutableStringSlice extends StringSlice {\n\n        public MutableStringSlice(byte[] buf) {\n            super(buf, 0);\n        }\n\n        public void updateLength(int length) {\n            len = length;\n            calculateHash();\n        }\n\n        public void clear() {\n            len = 0;\n            hash = 0;\n        }\n    }\n\n    private static Map<StringSlice, MeasurementAggregate> readChunk(FileChannel channel, long from, long chunkSize) {\n        MemorySegment data;\n        long remaining;\n        try {\n            long offset = Math.max(0, from - 1);\n            remaining = channel.size() - offset;\n            data = channel.map(READ_ONLY, offset, Math.min(remaining, chunkSize + 256), Arena.ofConfined()); // +256 to allow for reading records that are split by the chunk\n        }\n        catch (IOException e) {\n            throw new UncheckedIOException(e);\n        }\n\n        long start = 0;\n        if (from > 0) {\n            while (data.get(JAVA_BYTE, start++) != '\\n') {\n            }\n        }\n\n        Map<StringSlice, MeasurementAggregate> results = new HashMap<>(1000);\n        byte[] buf = new byte[256];\n        MutableStringSlice name = new MutableStringSlice(buf);\n\n        long until = Math.min(remaining, chunkSize); // Records may end (slightly) after the chunk boundary, but must not start after it\n        for (long pos = start; pos < until;) {\n            name.clear();\n            int i = 0;\n            for (;; i++) {\n                if (pos + i >= data.byteSize()) { // Guard against malformed data (typically a missing newline at the end of the input)\n                    pos = chunkSize;\n                    break;\n                }\n                byte b = data.get(JAVA_BYTE, pos + i);\n                buf[i] = b;\n                if (b == ';') {\n                    name.updateLength(i);\n                }\n                else if (b == '\\n') {\n                    pos = pos + i + 1;\n                    break;\n                }\n            }\n\n            double measurement = parseDoubleFrom(buf, name.length() + 1, i - name.length() - 1);\n            MeasurementAggregate aggr = results.get(name);\n            if (aggr == null) {\n                aggr = new MeasurementAggregate();\n                results.put(new StringSlice(name), aggr);\n            }\n            aggr.append(measurement);\n        }\n\n        return results;\n    }\n\n    // Note: based on java.lang.Integer.parseInt, surely missing some edge cases but avoids allocation\n    private static double parseDoubleFrom(byte[] buf, int offset, int length) {\n        boolean negative = false;\n        int integer = 0;\n        for (int i = 0; i < length; i++) {\n            byte c = buf[offset + i];\n            if (c == '-') {\n                negative = true;\n            }\n            else if (c != '.') {\n                integer *= 10;\n                integer -= c - '0';\n            }\n        }\n        return (negative ? integer : -integer) / 10.0;\n    }\n\n    public static void main(String[] args) throws IOException {\n        Map<String, MeasurementAggregate> measurements = new TreeMap<>();\n\n        try (RandomAccessFile raf = new RandomAccessFile(FILE, \"r\")) {\n            long size = raf.length();\n            long threads = Math.min(ForkJoinPool.getCommonPoolParallelism(), Math.max(size / 1000000, 1));\n            long chunkSize = Math.ceilDiv(size, threads);\n            System.err.printf(\"Processing size=%d, threads=%d, chunkSize=%d%n\", size, threads, chunkSize);\n\n            List<Map<StringSlice, MeasurementAggregate>> chunks = LongStream.range(0, threads)\n                    .parallel()\n                    .mapToObj(i -> readChunk(raf.getChannel(), i * chunkSize, chunkSize))\n                    .toList();\n\n            for (Map<StringSlice, MeasurementAggregate> chunk : chunks) {\n                chunk.forEach((n, m) -> measurements.computeIfAbsent(n.toString(), x -> new MeasurementAggregate()).merge(m));\n            }\n        }\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_khmarbaise.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.DoubleSummaryStatistics;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\nimport static java.util.stream.Collectors.groupingBy;\n\npublic class CalculateAverage_khmarbaise {\n\n    private static final Path MEASUREMENT_FILES = Path.of(\"./measurements.txt\");\n\n    private record MeasurementRecord(String city, Double measuredValue) {\n    }\n\n    private static final Function<String, MeasurementRecord> toMeasurementRecord = line -> {\n        var posOf = line.indexOf(\";\");\n        var city = line.substring(0, posOf);\n        var measuredValue = line.substring(posOf + 1);\n        return new MeasurementRecord(city, Double.parseDouble(measuredValue));\n    };\n\n    private static final Function<Map.Entry<String, DoubleSummaryStatistics>, String> MIN_AVG_MAX = s -> String.format(\"%s=%.1f/%.1f/%.1f\", s.getKey(),\n            s.getValue().getMin(), s.getValue().getAverage(), s.getValue().getMax());\n\n    public static void main(String[] args) throws IOException {\n        try (Stream<String> lines = Files.lines(MEASUREMENT_FILES)) {\n            var collect = lines\n                    .parallel()\n                    .map(toMeasurementRecord)\n                    .collect(groupingBy(MeasurementRecord::city, Collectors.summarizingDouble(MeasurementRecord::measuredValue)))\n                    .entrySet()\n                    .stream()\n                    .sorted(Map.Entry.comparingByKey())\n                    .map(MIN_AVG_MAX)\n                    .collect(Collectors.joining(\", \"));\n\n            System.out.println(\"{\" + collect + \"}\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_kuduwa_keshavram.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Iterator;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.TreeMap;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\nimport java.util.stream.Stream;\nimport java.util.stream.StreamSupport;\nimport sun.misc.Unsafe;\n\npublic class CalculateAverage_kuduwa_keshavram {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static Unsafe initUnsafe() {\n        try {\n            final Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        TreeMap<String, Measurement> resultMap = getFileSegments(new File(FILE))\n                .flatMap(\n                        segment -> {\n                            Result result = new Result();\n                            while (segment.start < segment.end) {\n                                byte[] city = new byte[100];\n                                byte b;\n                                int hash = 0;\n                                int i = 0;\n                                while ((b = UNSAFE.getByte(segment.start++)) != 59) {\n                                    hash = 31 * hash + b;\n                                    city[i++] = b;\n                                }\n\n                                byte[] newCity = new byte[i];\n                                System.arraycopy(city, 0, newCity, 0, i);\n                                int measurement = 0;\n                                boolean negative = false;\n                                while ((b = UNSAFE.getByte(segment.start++)) != 10) {\n                                    if (b == 45) {\n                                        negative = true;\n                                    }\n                                    else if (b == 46) {\n                                        // skip\n                                    }\n                                    else {\n                                        final int n = b - '0';\n                                        measurement = measurement * 10 + n;\n                                    }\n                                }\n                                putOrMerge(\n                                        result,\n                                        new Measurement(hash, newCity, negative ? measurement * -1 : measurement));\n                            }\n                            Iterator<Measurement> iterator = getMeasurementIterator(result);\n                            return StreamSupport.stream(\n                                    Spliterators.spliteratorUnknownSize(iterator, Spliterator.NONNULL), true);\n                        })\n                .collect(\n                        Collectors.toMap(\n                                measurement -> new String(measurement.city),\n                                Function.identity(),\n                                (m1, m2) -> {\n                                    m1.merge(m2);\n                                    return m1;\n                                },\n                                TreeMap::new));\n\n        System.out.println(resultMap);\n    }\n\n    private static Iterator<Measurement> getMeasurementIterator(Result result) {\n        return new Iterator<>() {\n            final int uniqueIndex = result.uniqueIndex;\n            final int[] indexArray = result.indexArray;\n            final Measurement[][] measurements = result.measurements;\n\n            int i = 0;\n            int j = 0;\n\n            @Override\n            public boolean hasNext() {\n                return i < uniqueIndex;\n            }\n\n            @Override\n            public Measurement next() {\n                Measurement measurement = measurements[indexArray[i]][j++];\n                if (measurements[indexArray[i]][j] == null) {\n                    i++;\n                    j = 0;\n                }\n                return measurement;\n            }\n        };\n    }\n\n    static class Result {\n        final Measurement[][] measurements = new Measurement[1024 * 128][3];\n        final int[] indexArray = new int[10_000];\n        int uniqueIndex = 0;\n    }\n\n    private static void putOrMerge(Result result, Measurement measurement) {\n        int index = measurement.hash & (result.measurements.length - 1);\n        Measurement[] existing = result.measurements[index];\n        for (int i = 0; i < existing.length; i++) {\n            Measurement existingMeasurement = existing[i];\n            if (existingMeasurement == null) {\n                result.measurements[index][i] = measurement;\n                if (i == 0) {\n                    result.indexArray[result.uniqueIndex++] = index;\n                }\n                return;\n            }\n            if (equals(existingMeasurement.city, measurement.city)) {\n                existingMeasurement.merge(measurement);\n                return;\n            }\n        }\n    }\n\n    private static boolean equals(byte[] city1, byte[] city2) {\n        for (int i = 0; i < city1.length; i++) {\n            if (city1[i] != city2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static final class FileSegment {\n        long start;\n        long end;\n\n        private FileSegment(long start, long end) {\n            this.start = start;\n            this.end = end;\n        }\n    }\n\n    private static final class Measurement {\n\n        private final int hash;\n        private final byte[] city;\n\n        int min;\n        int max;\n        int sum;\n        int count;\n\n        private Measurement(int hash, byte[] city, int temp) {\n            this.hash = hash;\n            this.city = city;\n            this.min = this.max = this.sum = temp;\n            this.count = 1;\n        }\n\n        private void merge(Measurement m2) {\n            this.min = this.min < m2.min ? this.min : m2.min;\n            this.max = this.max > m2.max ? this.max : m2.max;\n            this.sum = this.sum + m2.sum;\n            this.count = this.count + m2.count;\n        }\n\n        @Override\n        public String toString() {\n            return String.format(\n                    \"%.1f/%.1f/%.1f\", this.min / 10f, (this.sum / 10f) / this.count, this.max / 10f);\n        }\n    }\n\n    private static Stream<FileSegment> getFileSegments(final File file) throws IOException {\n        final int numberOfSegments = Runtime.getRuntime().availableProcessors() * 4;\n        final long[] chunks = new long[numberOfSegments + 1];\n        try (var fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.READ)) {\n            final long fileSize = fileChannel.size();\n            final long segmentSize = (fileSize + numberOfSegments - 1) / numberOfSegments;\n            final long mappedAddress = fileChannel.map(MapMode.READ_ONLY, 0, fileSize, Arena.global()).address();\n            chunks[0] = mappedAddress;\n            final long endAddress = mappedAddress + fileSize;\n            for (int i = 1; i < numberOfSegments; ++i) {\n                long chunkAddress = mappedAddress + i * segmentSize;\n                // Align to first row start.\n                while (chunkAddress < endAddress && UNSAFE.getByte(chunkAddress++) != '\\n') {\n                    // nop\n                }\n                chunks[i] = Math.min(chunkAddress, endAddress);\n            }\n            chunks[numberOfSegments] = endAddress;\n        }\n        return IntStream.range(0, chunks.length - 1)\n                .mapToObj(chunkIndex -> new FileSegment(chunks[chunkIndex], chunks[chunkIndex + 1]))\n                .parallel();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_kumarsaurav123.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\n\nimport static java.util.stream.Collectors.groupingBy;\n\npublic class CalculateAverage_kumarsaurav123 {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static AtomicInteger indexCount = new AtomicInteger(0);\n    private static final ReentrantLock lock = new ReentrantLock();\n    private static final int MAX_UNIQUE_KEYS = 11000;\n    private static Map<StringHolder, Integer> indexMap;\n\n    private static record Store(double[] min, double[] max, double[] sum,\n                                int[] count) {\n\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        @Override\n        public String toString() {\n            return new TreeMap<>(indexMap.entrySet()\n                    .stream()\n                    .map(e -> Map.entry(e.getKey().toString(),\n                            round(min[e.getValue()]) + \"/\" + round((Math.round(sum[e.getValue()] * 10.0) / 10.0) / count[e.getValue()]) + \"/\" + round(max[e.getValue()])\n                    ))\n                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue))).toString();\n        }\n    }\n\n    private static record Pair(long start, int size) {\n    }\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        long start = System.currentTimeMillis();\n        System.out.println(run(FILE));\n    }\n\n    public static String run(String filePath) throws IOException, InterruptedException, ExecutionException {\n        indexCount = new AtomicInteger(0);\n        indexMap = new HashMap<>(MAX_UNIQUE_KEYS);\n        ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);\n        CompletionService<Store> completionService = new ExecutorCompletionService<>(executorService);\n        Map<Integer, List<byte[]>> leftOutsMap = new ConcurrentSkipListMap<>();\n        RandomAccessFile file = new RandomAccessFile(filePath, \"r\");\n        long filelength = file.length();\n        AtomicInteger kk = new AtomicInteger();\n        MemorySegment memorySegment = file.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, filelength, Arena.ofShared());\n        int nChunks = 1000;\n\n        int pChunkSize = Math.min(Integer.MAX_VALUE, (int) (memorySegment.byteSize() / (1000)));\n        if (pChunkSize < 100) {\n            pChunkSize = (int) memorySegment.byteSize();\n            nChunks = 1;\n        }\n        ArrayList<Pair> chunks = createStartAndEnd(pChunkSize, nChunks, memorySegment);\n        chunks.stream()\n                .parallel()\n                .map(p -> {\n\n                    return createRunnable(memorySegment, p);\n                })\n                .forEach(completionService::submit);\n        executorService.shutdown();\n        int i = 0;\n        double[] min = new double[MAX_UNIQUE_KEYS];\n        double[] max = new double[MAX_UNIQUE_KEYS];\n        double[] sum = new double[MAX_UNIQUE_KEYS];\n        int[] count = new int[MAX_UNIQUE_KEYS];\n        initArray(i, count, min, max, sum);\n        i = 0;\n        final Store cureentStore = new Store(min, max, sum, count);\n        while (i < chunks.size()) {\n            Store newStore = completionService.take().get();\n            Map<Integer, StringHolder> reverseMap = indexMap.entrySet()\n                    .stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));\n            reverseMap.forEach((key, value) -> {\n                cureentStore.sum[key] += newStore.sum[key];\n                cureentStore.count[key] += newStore.count[key];\n                cureentStore.min[key] = Math.min(cureentStore.min[key],\n                        newStore.min[key]);\n                cureentStore.max[key] = Math.max(cureentStore.max[key],\n                        newStore.max[key]);\n            });\n            i++;\n        }\n\n        return cureentStore.toString();\n    }\n\n    private static void initArray(int i, int[] count, double[] min, double[] max, double[] sum) {\n        for (; i < count.length; i++) {\n            min[i] = Double.POSITIVE_INFINITY;\n            max[i] = Double.NEGATIVE_INFINITY;\n            sum[i] = 0.0d;\n            count[i] = 0;\n        }\n    }\n\n    private static ArrayList<Pair> createStartAndEnd(int chunksize, int nChunks, MemorySegment memorySegment) {\n        ArrayList<Pair> startSizePairs = new ArrayList<>();\n        byte eol = \"\\n\".getBytes(StandardCharsets.UTF_8)[0];\n        long start = 0;\n        long end = -1;\n        if (nChunks == 1) {\n            startSizePairs.add(new Pair(0, chunksize));\n            return startSizePairs;\n        }\n        else {\n            while (start < memorySegment.byteSize()) {\n                start = end + 1;\n                end = Math.min(memorySegment.byteSize() - 1, start + chunksize - 1);\n                while (memorySegment.get(ValueLayout.JAVA_BYTE, end) != eol) {\n                    end--;\n\n                }\n                startSizePairs.add(new Pair(start, (int) (end - start + 1)));\n            }\n        }\n        return startSizePairs;\n    }\n\n    public static Callable<Store> createRunnable(MemorySegment memorySegment, Pair p) {\n        return new Callable<Store>() {\n            @Override\n            public Store call() {\n                try {\n                    double[] min = new double[MAX_UNIQUE_KEYS];\n                    double[] max = new double[MAX_UNIQUE_KEYS];\n                    double[] sum = new double[MAX_UNIQUE_KEYS];\n                    int[] count = new int[MAX_UNIQUE_KEYS];\n                    for (int i = 0; i < count.length; i++) {\n                        min[i] = Double.POSITIVE_INFINITY;\n                        max[i] = Double.NEGATIVE_INFINITY;\n                        sum[i] = 0.0d;\n                        count[i] = 0;\n                    }\n\n                    byte[] allBytes2 = memorySegment.asSlice(p.start, p.size).toArray(ValueLayout.JAVA_BYTE);\n                    byte[] eol = \"\\n\".getBytes(StandardCharsets.UTF_8);\n                    byte[] sep = \";\".getBytes(StandardCharsets.UTF_8);\n\n                    int st = 0;\n                    for (int i = 0; i < allBytes2.length; i++) {\n                        if (allBytes2[i] == eol[0]) {\n                            ;\n                            byte[] s2 = new byte[i - st];\n                            System.arraycopy(allBytes2, st, s2, 0, s2.length);\n                            for (int j = 0; j < s2.length; j++) {\n                                if (s2[j] == sep[0]) {\n                                    byte[] city = new byte[j];\n                                    byte[] value = new byte[s2.length - j - 1];\n                                    System.arraycopy(s2, 0, city, 0, city.length);\n                                    System.arraycopy(s2, city.length + 1, value, 0, value.length);\n                                    double d = getaDouble(value);\n                                    StringHolder citys = new StringHolder(city);\n                                    Integer index = indexMap.get(citys);\n                                    if (Objects.isNull(index)) {\n                                        lock.lock();\n                                        if (Objects.isNull(indexMap.get(citys))) {\n                                            index = indexCount.getAndIncrement();\n                                            indexMap.putIfAbsent(citys, index);\n\n                                        }\n                                        index = indexMap.get(citys);\n                                        lock.unlock();\n                                    }\n\n                                    count[index] = count[index] + 1;\n                                    max[index] = Math.max(max[index], d);\n                                    min[index] = Math.min(min[index], d);\n                                    sum[index] = Double.sum(sum[index], d);\n                                    break;\n                                }\n                            }\n                            st = i + 1;\n                        }\n                    }\n                    // System.out.println(\"Task \" + kk + \"Completed in \" + (System.nanoTime() - start));\n                    return new Store(min, max, sum, count);\n                }\n                catch (Exception e) {\n                    // throw new RuntimeException(e);\n                    throw e;\n                }\n            }\n        };\n    }\n\n    private static double getaDouble(byte[] value) {\n        double d = 0.0;\n        int s = -1;\n        for (int k = value.length - 1; k >= 0; k--) {\n            if (value[k] == 45) {\n                d = d * -1;\n            }\n            else if (value[k] == 46) {\n            }\n            else {\n                d = d + (((int) value[k]) - 48) * Math.pow(10, s);\n                s++;\n            }\n        }\n        return d;\n    }\n\n    static class StringHolder implements Comparable<StringHolder> {\n        byte[] bytes;\n\n        public StringHolder(byte[] bytes) {\n            this.bytes = bytes;\n        }\n\n        @Override\n        public String toString() {\n            return new String(this.bytes);\n        }\n\n        @Override\n        public int hashCode() {\n            return Arrays.hashCode(this.bytes);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return Arrays.equals(this.bytes, ((StringHolder) obj).bytes);\n        }\n\n        @Override\n        public int compareTo(StringHolder o) {\n            return new String(this.bytes).compareTo(new String(o.bytes));\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_lawrey.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.stream.LongStream;\n\npublic class CalculateAverage_lawrey {\n\n    // Path to the file containing temperature measurements.\n    private static final String FILE = \"./measurements.txt\";\n\n    // Inner class representing a measurement with min, max, and average calculations.\n    static class Measurement {\n        double min = Double.POSITIVE_INFINITY;\n        double max = Double.NEGATIVE_INFINITY;\n        double sum = 0.0;\n        long count = 0;\n\n        // Default constructor for Measurement.\n        public Measurement() {\n        }\n\n        // Adds a new temperature sample and updates min, max, and average.\n        public void sample(double temp) {\n            min = Math.min(min, temp);\n            max = Math.max(max, temp);\n            sum += temp;\n            count++;\n        }\n\n        // Returns a formatted string representing min, average, and max.\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        // Helper method to round a double value to one decimal place.\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        // Merges this Measurement with another Measurement.\n        public Measurement merge(Measurement m2) {\n            min = Math.min(min, m2.min);\n            max = Math.max(max, m2.max);\n            sum += m2.sum;\n            count += m2.count;\n            return this;\n        }\n    }\n\n    // Inner class representing a key for measurements.\n    static class Key {\n        final byte[] data = new byte[32];\n        int hash = 0, length = 0;\n\n        // Override of hashCode using the hash field.\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        // Custom equals method to compare two Key objects.\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof Key k) {\n                if (length != k.length || hash != k.hash)\n                    return false;\n                return Arrays.equals(data, 0, length, k.data, 0, length);\n            }\n            return false;\n        }\n\n        // Converts the key's data to a String.\n        @Override\n        public String toString() {\n            return new String(data, 0, length, StandardCharsets.UTF_8);\n        }\n\n        // Appends a byte to the key and updates its hash.\n        public void append(byte b) {\n            data[length++] = b;\n            hash = hash * 10191 + b;\n        }\n\n        // Resets the key to its initial state.\n        public void clear() {\n            length = hash = 0;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        // Open the file for reading.\n        File file = new File(FILE);\n        long length = file.length();\n        long chunk = 1 << 28; // Size of the chunk to be processed.\n        RandomAccessFile raf = new RandomAccessFile(file, \"r\");\n\n        // Process the file in chunks and merge the results.\n        Map<Key, Measurement> allMeasurementsMap = LongStream.range(0, length / chunk + 1)\n                .parallel()\n                .mapToObj(i -> extractMeasurementsFromChunk(i, chunk, length, raf))\n                .reduce((a, b) -> mergeMeasurementMaps(a, b))\n                .orElseGet(Collections::emptyMap);\n\n        // Sort the measurements and print them.\n        Map<String, Measurement> sortedMeasurementsMap = new TreeMap<>();\n        allMeasurementsMap.forEach((k, m) -> sortedMeasurementsMap.put(k.toString(), m));\n        System.out.println(sortedMeasurementsMap);\n    }\n\n    // Merges two measurement maps.\n    private static Map<Key, Measurement> mergeMeasurementMaps(Map<Key, Measurement> a, Map<Key, Measurement> b) {\n        a.forEach((k, m) -> {\n            Measurement m2 = b.get(k);\n            if (m2 != null)\n                m.merge(m2);\n        });\n        b.forEach(a::putIfAbsent);\n        return a;\n    }\n\n    // Extracts measurements from a chunk of the file.\n    private static Map<Key, Measurement> extractMeasurementsFromChunk(long i, long chunk, long length, RandomAccessFile raf) {\n        long start = i * chunk;\n        long size = Math.min(length, start + chunk + 64 * 1024) - start;\n        Map<Key, Measurement> map = new HashMap<>(1024);\n        try {\n            MappedByteBuffer mbb = raf.getChannel().map(FileChannel.MapMode.READ_ONLY, start, size);\n            if (i > 0)\n                skipToFirstLine(mbb);\n            Key key = new Key();\n            while (mbb.remaining() > 0 && mbb.position() <= chunk) {\n                key.clear();\n                readKey(mbb, key);\n                int temp = readTemperatureFromBuffer(mbb);\n                Measurement m = map.computeIfAbsent(key, n -> new Measurement());\n                if (m.count == 0)\n                    key = new Key();\n                m.sample(temp / 10.0);\n            }\n\n        }\n        catch (IOException ioe) {\n            throw new RuntimeException(ioe);\n        }\n        return map;\n    }\n\n    // Reads a temperature value from the buffer.\n    private static int readTemperatureFromBuffer(MappedByteBuffer mbb) {\n        int temp = 0;\n        boolean negative = false;\n        outer: while (mbb.remaining() > 0) {\n            byte b = mbb.get();\n            switch (b) {\n                case '-':\n                    negative = true;\n                    break;\n                case '.':\n                    break;\n                case '\\r':\n                case '\\n':\n                    break outer;\n                default:\n                    temp = 10 * temp + (b - '0');\n                    break;\n            }\n        }\n        if (mbb.remaining() > 0) {\n            byte b = mbb.get(mbb.position());\n            if (b == '\\n')\n                mbb.get();\n        }\n        if (negative)\n            temp = -temp;\n        return temp;\n    }\n\n    // Reads a key from the buffer.\n    private static void readKey(MappedByteBuffer mbb, Key key) {\n        while (mbb.remaining() > 0) {\n            byte b = mbb.get();\n            if (b == ';' || b == '\\r' || b == '\\n')\n                break;\n            key.append(b);\n        }\n    }\n\n    // Skips to the first line in the buffer, used for chunk processing.\n    private static void skipToFirstLine(MappedByteBuffer mbb) {\n        while ((mbb.get() & 0xFF) >= ' ') {\n            // Skip bytes until reaching the start of a line.\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_maeda6uiui.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.*;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_maeda6uiui {\n    record RecordCollectorResult(\n                                 Map<String, Double> mins,\n                                 Map<String, Double> maxes,\n                                 Map<String, Double> sums,\n                                 Map<String, Integer> counts) {\n\n    }\n\n    static class RecordCollector implements Callable<RecordCollectorResult> {\n        private String inputFilepath;\n        private long startByteIndex;\n        private long numBytesToRead;\n        private char delimiter;\n        private int byteBufferSize;\n        private int bisBufferSize;\n\n        private Map<String, Double> mins;\n        private Map<String, Double> maxes;\n        private Map<String, Double> sums;\n        private Map<String, Integer> counts;\n\n        public RecordCollector(\n                               String inputFilepath,\n                               long startByteIndex,\n                               long numBytesToRead,\n                               char delimiter,\n                               int byteBufferSize,\n                               int bisBufferSize) {\n            this.inputFilepath = inputFilepath;\n            this.startByteIndex = startByteIndex;\n            this.numBytesToRead = numBytesToRead;\n            this.delimiter = delimiter;\n            this.byteBufferSize = byteBufferSize;\n            this.bisBufferSize = bisBufferSize;\n\n            mins = new HashMap<>();\n            maxes = new HashMap<>();\n            sums = new HashMap<>();\n            counts = new HashMap<>();\n        }\n\n        private int byteToInt(byte b) {\n            return switch (b) {\n                case '0' -> 0;\n                case '1' -> 1;\n                case '2' -> 2;\n                case '3' -> 3;\n                case '4' -> 4;\n                case '5' -> 5;\n                case '6' -> 6;\n                case '7' -> 7;\n                case '8' -> 8;\n                case '9' -> 9;\n                default -> -1;\n            };\n        }\n\n        private double parseDouble(byte[] bs) {\n            // Get the sign\n            int valSign;\n            if (bs[0] == '-') {\n                valSign = -1;\n            }\n            else {\n                valSign = 1;\n            }\n\n            // Get the dot position\n            int dotPos = -1;\n            for (int i = 0; i < bs.length; i++) {\n                if (bs[i] == '.') {\n                    dotPos = i;\n                    break;\n                }\n            }\n            if (dotPos == -1) {\n                return Double.NaN;\n            }\n\n            // Get the integer part\n            int valIntPart;\n            int intPartStartIndex = (valSign == -1) ? 1 : 0;\n            int intPartLength = dotPos - intPartStartIndex;\n\n            // One-digit value\n            if (intPartLength == 1) {\n                valIntPart = this.byteToInt(bs[dotPos - 1]);\n            }\n            // Two-digit value\n            else if (intPartLength == 2) {\n                int valTens = this.byteToInt(bs[dotPos - 2]);\n                int valOnes = this.byteToInt(bs[dotPos - 1]);\n                valIntPart = valTens * 10 + valOnes;\n            }\n            else {\n                return Double.NaN;\n            }\n\n            // Get the decimal part\n            double valDecPart = this.byteToInt(bs[dotPos + 1]) * 0.1;\n\n            return valSign * (valIntPart + valDecPart);\n        }\n\n        @Override\n        public RecordCollectorResult call() {\n            // Start and end indices are most likely pointing to the middle of a line\n            // Therefore, actual start and end indices should be determined\n            // before proceeding to actual reading of the file\n            long actualStartByteIndex = -1;\n            long actualEndByteIndex = -1;\n\n            try (var bis = new BufferedInputStream(new FileInputStream(inputFilepath))) {\n                int b;\n                int readCount = 0;\n                long firstLFPos;\n\n                // If start index specified is 0, actual start index is also 0\n                if (startByteIndex == 0) {\n                    actualStartByteIndex = 0;\n                }\n                else {\n                    // Skip until the preceding byte of the start index specified\n                    bis.skipNBytes(startByteIndex - 1);\n\n                    // Get the preceding byte\n                    b = bis.read();\n\n                    // If the preceding byte is LF,\n                    // actual start index is the start index specified\n                    // because it is the start of a new line\n                    if (b == '\\n') {\n                        actualStartByteIndex = startByteIndex;\n                    }\n                }\n\n                if (actualStartByteIndex != -1) {\n                    // Skip until the end byte specified\n                    bis.skipNBytes(numBytesToRead);\n                }\n                // Start index specified is pointing to the middle of a line\n                // In that case, actual start index is the one following the LF of that line\n                // (Start index of the next line)\n                else {\n                    firstLFPos = startByteIndex;\n                    while ((b = bis.read()) != -1) {\n                        readCount++;\n                        if (b == '\\n') {\n                            break;\n                        }\n\n                        firstLFPos++;\n                    }\n                    actualStartByteIndex = firstLFPos + 1;\n\n                    // Skip until the end byte specified\n                    bis.skipNBytes(numBytesToRead - readCount);\n                }\n\n                // Actual end index is the first LF encountered\n                readCount = 0;\n                firstLFPos = startByteIndex + numBytesToRead;\n                while ((b = bis.read()) != -1) {\n                    readCount++;\n                    if (b == '\\n') {\n                        break;\n                    }\n\n                    firstLFPos++;\n                }\n                actualEndByteIndex = firstLFPos;\n            }\n            catch (IOException e) {\n                System.err.println(e);\n                return null;\n            }\n\n            // Get actual number of bytes to read\n            long actualNumBytesToRead = actualEndByteIndex - actualStartByteIndex + 1;\n\n            // Read bytes from the range obtained above\n            try (var bis = new BufferedInputStream(new FileInputStream(inputFilepath), bisBufferSize)) {\n                // Skip until the start byte\n                bis.skipNBytes(actualStartByteIndex);\n\n                final int EXTENSION_SIZE = 64;\n                var buffer = new byte[byteBufferSize];\n                var extendedBuffer = new byte[byteBufferSize + EXTENSION_SIZE];\n\n                // Read bytes in chunk\n                long numTotalBytesRead = 0;\n                while (true) {\n                    int chunkSize;\n                    if (actualNumBytesToRead - numTotalBytesRead < byteBufferSize) {\n                        chunkSize = (int) (actualNumBytesToRead - numTotalBytesRead);\n                    }\n                    else {\n                        chunkSize = byteBufferSize;\n                    }\n\n                    if (chunkSize <= 0) {\n                        break;\n                    }\n\n                    Arrays.fill(buffer, (byte) 0);\n                    bis.read(buffer, 0, chunkSize);\n                    numTotalBytesRead += chunkSize;\n\n                    // Copy read content to another buffer\n                    Arrays.fill(extendedBuffer, (byte) 0);\n                    System.arraycopy(buffer, 0, extendedBuffer, 0, chunkSize);\n\n                    // Read until next LF is found\n                    // if end of buffer read above does not correspond to end of line\n                    for (int i = 0; i < EXTENSION_SIZE; i++) {\n                        int b = bis.read();\n                        if (b == -1) {\n                            break;\n                        }\n                        else if (b == '\\n') {\n                            extendedBuffer[chunkSize + i] = '\\n';\n                            numTotalBytesRead++;\n                            break;\n                        }\n\n                        extendedBuffer[chunkSize + i] = (byte) b;\n                        numTotalBytesRead++;\n                    }\n\n                    int currentDelimPos = -1;\n                    int currentLFPos = -1;\n                    int nextLineStartPos = 0;\n\n                    for (int i = 0; i < extendedBuffer.length; i++) {\n                        if (extendedBuffer[i] == 0) {\n                            break;\n                        }\n\n                        if (extendedBuffer[i] == delimiter) {\n                            currentDelimPos = i;\n                        }\n                        else if (extendedBuffer[i] == '\\n') {\n                            currentLFPos = i;\n                        }\n\n                        if (currentLFPos != -1) {\n                            // Error\n                            if (currentDelimPos == -1) {\n                                System.err.printf(\n                                        \"Error near byte index %d\\n\",\n                                        actualStartByteIndex + numTotalBytesRead);\n                            }\n                            else {\n                                String stationName = new String(\n                                        Arrays.copyOfRange(extendedBuffer, nextLineStartPos, currentDelimPos));\n\n                                // Parse string to double by myself\n                                // because Double.parseDouble() is slow...\n                                double temperature = this.parseDouble(\n                                        Arrays.copyOfRange(extendedBuffer, currentDelimPos + 1, currentLFPos));\n\n                                // Populate the maps\n                                if (!mins.containsKey(stationName)) {\n                                    mins.put(stationName, temperature);\n                                    maxes.put(stationName, temperature);\n                                    sums.put(stationName, temperature);\n                                    counts.put(stationName, 1);\n                                }\n                                else {\n                                    double currentMin = mins.get(stationName);\n                                    double currentMax = maxes.get(stationName);\n                                    double currentSum = sums.get(stationName);\n                                    int currentCount = counts.get(stationName);\n\n                                    if (temperature < currentMin) {\n                                        mins.put(stationName, temperature);\n                                    }\n                                    else if (temperature > currentMax) {\n                                        maxes.put(stationName, temperature);\n                                    }\n\n                                    sums.put(stationName, currentSum + temperature);\n                                    counts.put(stationName, currentCount + 1);\n                                }\n                            }\n\n                            nextLineStartPos = currentLFPos + 1;\n                            currentDelimPos = -1;\n                            currentLFPos = -1;\n                        }\n                    }\n                }\n            }\n            catch (IOException e) {\n                System.err.println(e);\n                return null;\n            }\n\n            return new RecordCollectorResult(mins, maxes, sums, counts);\n        }\n    }\n\n    private static double round(double d) {\n        return Math.round(d * 10.0) / 10.0;\n    }\n\n    public static void main(String[] args) {\n        final String INPUT_FILEPATH = \"./measurements.txt\";\n        final int DESIRED_NUM_THREADS = 20;\n        final char DELIMITER = ';';\n        final int BIS_BUFFER_SIZE = 1024 * 1024;\n        final int BYTE_BUFFER_SIZE = 1024;\n        final int MULTI_THREAD_NUM_LINES_THRESHOLD = DESIRED_NUM_THREADS * 10;\n\n        // First get the number of total bytes in the input file\n        long numTotalBytes;\n        try {\n            numTotalBytes = Files.size(Paths.get(INPUT_FILEPATH));\n        }\n        catch (IOException e) {\n            e.printStackTrace();\n            return;\n        }\n\n        // Make sure the input file has enough lines\n        // for this multithreading approach to work efficiently\n        int actualNumThreads = 1;\n        try (var br = new BufferedReader(new FileReader(INPUT_FILEPATH))) {\n            int lineCount = 0;\n            while (br.readLine() != null) {\n                lineCount++;\n                if (lineCount >= MULTI_THREAD_NUM_LINES_THRESHOLD) {\n                    actualNumThreads = DESIRED_NUM_THREADS;\n                    break;\n                }\n            }\n        }\n        catch (IOException e) {\n            e.printStackTrace();\n            return;\n        }\n\n        // Calculate the number of bytes each thread has to process\n        long numBytesToProcessPerThread = numTotalBytes / actualNumThreads;\n        long remainingNumBytesToProcess = numTotalBytes % actualNumThreads;\n\n        var exec = Executors.newFixedThreadPool(actualNumThreads);\n\n        var futures = new ArrayList<Future<RecordCollectorResult>>();\n        for (int i = 0; i < actualNumThreads; i++) {\n            RecordCollector recordCollector;\n            if (i == actualNumThreads - 1) {\n                recordCollector = new RecordCollector(\n                        INPUT_FILEPATH,\n                        i * numBytesToProcessPerThread,\n                        numBytesToProcessPerThread + remainingNumBytesToProcess,\n                        DELIMITER,\n                        BYTE_BUFFER_SIZE,\n                        BIS_BUFFER_SIZE);\n            }\n            else {\n                recordCollector = new RecordCollector(\n                        INPUT_FILEPATH,\n                        i * numBytesToProcessPerThread,\n                        numBytesToProcessPerThread,\n                        DELIMITER,\n                        BYTE_BUFFER_SIZE,\n                        BIS_BUFFER_SIZE);\n            }\n\n            Future<RecordCollectorResult> future = exec.submit(recordCollector);\n            futures.add(future);\n        }\n\n        // Consolidate results of each thread\n        var mins = new HashMap<String, Double>();\n        var maxes = new HashMap<String, Double>();\n        var sums = new HashMap<String, Double>();\n        var counts = new HashMap<String, Integer>();\n        try {\n            for (var future : futures) {\n                RecordCollectorResult result = future.get();\n\n                result.mins.forEach((k, v) -> {\n                    if (!mins.containsKey(k)) {\n                        mins.put(k, v);\n                    }\n                    else {\n                        mins.put(k, Double.min(v, mins.get(k)));\n                    }\n                });\n                result.maxes.forEach((k, v) -> {\n                    if (!maxes.containsKey(k)) {\n                        maxes.put(k, v);\n                    }\n                    else {\n                        maxes.put(k, Double.max(v, maxes.get(k)));\n                    }\n                });\n                result.sums.forEach((k, v) -> {\n                    if (!sums.containsKey(k)) {\n                        sums.put(k, v);\n                    }\n                    else {\n                        sums.put(k, Double.sum(v, sums.get(k)));\n                    }\n                });\n                result.counts.forEach((k, v) -> {\n                    if (!counts.containsKey(k)) {\n                        counts.put(k, v);\n                    }\n                    else {\n                        counts.put(k, Integer.sum(v, counts.get(k)));\n                    }\n                });\n            }\n        }\n        catch (InterruptedException | ExecutionException e) {\n            e.printStackTrace();\n            return;\n        }\n        finally {\n            exec.shutdown();\n        }\n\n        // Calculate means\n        var means = new HashMap<String, Double>();\n        sums.forEach((k, v) -> means.put(k, v / counts.get(k)));\n\n        // Sort station names\n        List<String> sortedStationNames = means\n                .keySet()\n                .stream()\n                .sorted()\n                .toList();\n\n        // Create output string\n        var sb = new StringBuilder();\n\n        sb.append(\"{\");\n        sortedStationNames.forEach(stationName -> {\n            sb\n                    .append(stationName)\n                    .append(\"=\")\n                    .append(round(mins.get(stationName)))\n                    .append(\"/\")\n                    .append(round(means.get(stationName)))\n                    .append(\"/\")\n                    .append(round(maxes.get(stationName)))\n                    .append(\", \");\n        });\n        sb.delete(sb.length() - 2, sb.length());\n        sb.append(\"}\");\n\n        // Print result string\n        System.out.println(sb);\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_mahadev_k.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileDescriptor;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.io.RandomAccessFile;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.StringTokenizer;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadFactory;\n\npublic class CalculateAverage_mahadev_k {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static Map<String, MeasurementAggregator> stationMap = new ConcurrentSkipListMap<>();\n\n    private static double round(double value) {\n        return Math.round(value * 10.0) / 10.0;\n    }\n\n    private static class MeasurementAggregator {\n        double minima = Double.POSITIVE_INFINITY, maxima = Double.NEGATIVE_INFINITY, total = 0, count = 0;\n\n        public synchronized void accept(double value) {\n            if (minima > value)\n                minima = value;\n            if (maxima < value)\n                maxima = value;\n            total += value;\n            count++;\n        }\n\n        public double min() {\n            return round(minima);\n        }\n\n        public double max() {\n            return round(maxima);\n        }\n\n        public double avg() {\n            return round((Math.round(total * 10.0) / 10.0) / count);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        int chunkSize = args.length == 1 ? Integer.parseInt(args[0]) : 1_000_000;\n        readAndProcess(chunkSize);\n        print();\n    }\n\n    public static void readAndProcess(int chunkSize) {\n        final ThreadFactory factory = Thread.ofVirtual().name(\"routine-\", 0).factory();\n\n        try (RandomAccessFile file = new RandomAccessFile(FILE, \"r\")) {\n            try (var executor = Executors.newThreadPerTaskExecutor(factory)) {\n\n                var channel = file.getChannel();\n                var size = channel.size();\n                long start = 0;\n                while (start <= size) {\n                    long end = start + chunkSize;\n                    String letter = \"\";\n                    do {\n                        end--;\n                        ByteBuffer buffer = ByteBuffer.allocate(1);\n                        channel.read(buffer, end);\n                        buffer.flip();\n                        letter = StandardCharsets.UTF_8.decode(buffer).toString();\n                    } while (!letter.equals(\"\\n\"));\n\n                    if (end < start)\n                        end = start + chunkSize;\n\n                    final long currentStart = start;\n                    final long currentEnd = end;\n                    executor.submit(() -> {\n                        ByteBuffer buffer = ByteBuffer.allocate((int) (currentEnd - currentStart + 1));\n                        try {\n                            channel.read(buffer, currentStart);\n                        }\n                        catch (IOException e) {\n                            e.printStackTrace();\n                        }\n                        buffer.flip();\n                        String data = StandardCharsets.UTF_8.decode(buffer).toString();\n                        processData(data);\n                    });\n                    start = end + 1;\n                }\n            }\n\n        }\n        catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void processData(String dataBlock) {\n        StringTokenizer tokenizer = new StringTokenizer(dataBlock, \"\\n\");\n        while (tokenizer.hasMoreElements()) {\n            StringTokenizer tokens = new StringTokenizer(tokenizer.nextToken(), \";\");\n            String station = tokens.nextToken();\n            double value = Double.parseDouble(tokens.nextToken());\n            processMinMaxMean(station, value);\n        }\n    }\n\n    private static void processMinMaxMean(String station, double temp) {\n        var values = stationMap.get(station);\n        if (values == null) {\n            values = new MeasurementAggregator();\n            stationMap.putIfAbsent(station, values);\n        }\n        values = stationMap.get(station);\n        values.accept(temp);\n    }\n\n    public static void print() throws UnsupportedEncodingException {\n        System.setOut(new PrintStream(new FileOutputStream(FileDescriptor.out), true, StandardCharsets.UTF_8));\n        System.out.print(\"{\");\n        int i = stationMap.size();\n        for (var kv : stationMap.entrySet()) {\n            System.out.printf(\"%s=%s/%s/%s\", kv.getKey(), kv.getValue().min(), kv.getValue().avg(), kv.getValue().max());\n            if (i > 1)\n                System.out.print(\", \");\n            i--;\n        }\n        System.out.println(\"}\");\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_makohn.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.stream.Collectors;\n\n//\n// This implementation is partially inspired by\n//\n// - GavinRay97: 1BRC in Kotlin (memory mapping, chunking) | https://github.com/gunnarmorling/1brc/discussions/154\n// - dannyvankooten: 1BRC in C (integer parsing, linear probing) | https://github.com/gunnarmorling/1brc/discussions/46\n//\npublic class CalculateAverage_makohn {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class Measurement implements Comparable<Measurement> {\n        final String city;\n        int min;\n        int max;\n        int count = 1;\n        int sum;\n\n        Measurement(String city, int val) {\n            this.city = city;\n            this.min = val;\n            this.max = val;\n            this.sum = val;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{city}=\\{round(min)}/\\{round((1.0 * sum) / count)}/\\{round(max)}\";\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n        @Override\n        public int compareTo(Measurement other) {\n            return this.city.compareTo(other.city);\n        }\n    }\n\n    // Convert a given byte array of temperature data to an int value\n    // Since the temperate values only have one decimal, we can use integer arithmetic until the end\n    //\n    // buffer: [..., '-', '1', '9', '.', '7', ...]\n    // -------------> offset\n    // ............ = s\n    //\n    // We initialize a \"pointer\" s with the offset. Depending on whether the first char is a '-' or not, we set the\n    // sign and increment the pointer.\n    //\n    // Then we only have to distinguish between one-digit and two-digit numbers.\n    // Depending on that, we set an index for the respective parts of the number.\n    //\n    private static int toInt(byte[] in, int offset) {\n        int sign = 1;\n        int s = offset;\n        if (in[s] == '-') {\n            sign = -1;\n            s++;\n        }\n\n        if (in[s + 1] == '.')\n            return sign * ((in[s] - '0') * 10 + (in[s + 2] - '0'));\n\n        return sign * ((in[s] - '0') * 100 + (in[s + 1] - '0') * 10 + (in[s + 3] - '0'));\n    }\n\n    // 10_000 distinct station names as per specification\n    // We use the next power of two (2^14 = 16384) to allow for bit-masking our hash (instead of using modulo)\n    private static final int MAX_STATIONS = 2 << 14;\n\n    // Twice as big as the maximum number of stations\n    private static final int MAP_CAPACITY = MAX_STATIONS * 2;\n\n    // We start at 1 to allow for checking our hash-index map for > 0\n    private static final int RES_FIRST_INDEX = 1;\n\n    private static class ResultMap {\n        final int[] map = new int[MAP_CAPACITY]; // hash -> index\n        final Measurement[] measurements = new Measurement[MAX_STATIONS]; // index -> measurement\n        private int lastIndex = 0;\n\n        private void put(int hash, Measurement measurement) {\n            lastIndex++;\n            measurements[lastIndex] = measurement;\n            map[hash] = lastIndex;\n        }\n\n        private boolean contains(int hash) {\n            return map[hash] > 0;\n        }\n\n        private Measurement get(int hash) {\n            return measurements[map[hash]];\n        }\n    }\n\n    // We use linear probing as our hash-collision strategy\n    //\n    // We use MAP_CAPACITY - 1 as a bitmask to force the hash to be lower than our capacity\n    // Let's consider a hash 16390. If our capacity is 2^14 = 16384, the hash is out of bounds.\n    //\n    // 16390 : 100000000000110\n    // 16383 : 011111111111111\n    // ....... 000000000000110 = 3\n    private static int linearProbe(ResultMap res, String key) {\n        var hash = key.hashCode() & (MAP_CAPACITY - 1);\n        while (res.map[hash] > 0 && !(res.measurements[res.map[hash]].city.equals(key))) {\n            hash = (hash + 1) & (MAP_CAPACITY - 1);\n        }\n        return hash;\n    }\n\n    // Custom Quicksort implementation, seems to be slightly faster than Arrays.sort\n    private static void quickSort(Measurement[] arr, int begin, int end) {\n        if (begin < end) {\n            final var partitionIndex = partition(arr, begin, end);\n\n            quickSort(arr, begin, partitionIndex - 1);\n            quickSort(arr, partitionIndex + 1, end);\n        }\n    }\n\n    private static int partition(Measurement[] arr, int begin, int end) {\n        final var pivot = arr[end];\n        int i = (begin - 1);\n\n        for (int j = begin; j < end; j++) {\n            if (arr[j].compareTo(pivot) <= 0) {\n                i++;\n                final var tmp = arr[i];\n                arr[i] = arr[j];\n                arr[j] = tmp;\n            }\n        }\n\n        final var tmp = arr[i + 1];\n        arr[i + 1] = arr[end];\n        arr[end] = tmp;\n\n        return i + 1;\n    }\n\n    private static Collection<ByteBuffer> getChunks(MemorySegment memory, long chunkSize, long fileSize) {\n        final var chunks = new ArrayList<ByteBuffer>();\n        var chunkStart = 0L;\n        var chunkEnd = 0L;\n        while (chunkStart < fileSize) {\n            chunkEnd = Math.min((chunkStart + chunkSize), fileSize);\n            // starting from the calculated chunkEnd, seek the next newline to get the real chunkEnd\n            while (chunkEnd < fileSize && (memory.getAtIndex(ValueLayout.JAVA_BYTE, chunkEnd) & 0xFF) != '\\n')\n                chunkEnd++;\n            // we have found our chunk boundaries, add a slice of memory with these boundaries to our list of chunks\n            if (chunkEnd < fileSize)\n                chunks.add(memory.asSlice(chunkStart, chunkEnd - chunkStart + 1).asByteBuffer());\n            else\n                // special case: we are at the end of the file\n                chunks.add(memory.asSlice(chunkStart, chunkEnd - chunkStart).asByteBuffer());\n\n            // next chunk\n            chunkStart = chunkEnd + 1;\n        }\n        return chunks;\n    }\n\n    // Station name: <= 100 bytes\n    // Temperature: <= 5 bytes\n    //\n    // Semicolon and new line are ignored\n    private static final int MAX_BYTES_PER_ROW = 105;\n\n    private static ResultMap processChunk(ByteBuffer chunk) {\n        final var map = new ResultMap();\n        final var buffer = new byte[MAX_BYTES_PER_ROW];\n        var i = 0;\n        var delimiter = 0;\n        // Process the chunk byte by byte and store each line in buffer\n        while (chunk.hasRemaining()) {\n            final var c = chunk.get();\n            // System.out.println((char) (c & 0xFF));\n            switch (c & 0xFF) {\n                // Memorize the position of the semicolon, such that we can divide the buffer afterward\n                case ';' -> delimiter = i;\n                // If we encounter newline, we can do the actual calculations for the current line\n                case '\\n' -> {\n                    final var key = new String(buffer, 0, delimiter, StandardCharsets.UTF_8);\n                    final var value = toInt(buffer, delimiter);\n                    final var hash = linearProbe(map, key);\n                    if (map.contains(hash)) {\n                        final var current = map.get(hash);\n                        current.min = Math.min(current.min, value);\n                        current.max = Math.max(current.max, value);\n                        current.count++;\n                        current.sum += value;\n                    }\n                    else {\n                        map.put(hash, new Measurement(key, value));\n                    }\n                    i = 0;\n                    delimiter = 0;\n                }\n                default -> {\n                    buffer[i] = c;\n                    i++;\n                }\n            }\n        }\n        return map;\n    }\n\n    // File size is approximately 13 GB, ByteBuffer has a 2 GB limit\n    // Chunks should have a maximum size of approximately 13 GB / 8 = 1.625 GB\n    private static final int MIN_NUMBER_THREADS = 8;\n\n    public static void main(String[] args) throws Exception {\n        final var numProcessors = Math.max(Runtime.getRuntime().availableProcessors(), MIN_NUMBER_THREADS);\n        // memory-map the input file\n        try (final var channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            final var fileSize = channel.size();\n            final var chunkSize = (fileSize / numProcessors);\n            final var mappedMemory = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n            // process the mapped data concurrently in chunks. Each chunk is processed on a dedicated thread\n            final var chunks = getChunks(mappedMemory, chunkSize, fileSize);\n            final var processed = chunks\n                    .parallelStream()\n                    .map(CalculateAverage_makohn::processChunk)\n                    .collect(Collectors.toList()); // materialize and thus synchronize\n            // merge the results, we can initialize with the first result, to avoid redundant probing\n            final var first = processed.removeFirst();\n            final var res = processed\n                    .stream()\n                    .reduce(first, (acc, partial) -> {\n                        for (int i = RES_FIRST_INDEX; i <= partial.lastIndex; i++) {\n                            final var value = partial.measurements[i];\n                            final var hash = linearProbe(acc, value.city);\n                            if (acc.contains(hash)) {\n                                final var cur = acc.get(hash);\n                                cur.min = Math.min(cur.min, value.min);\n                                cur.max = Math.max(cur.max, value.max);\n                                cur.count += value.count;\n                                cur.sum += value.sum;\n                            }\n                            else {\n                                acc.put(hash, value);\n                            }\n                        }\n                        return acc;\n                    });\n\n            quickSort(res.measurements, RES_FIRST_INDEX, res.lastIndex);\n            final var sb = new StringBuilder(\"{\");\n            for (int i = RES_FIRST_INDEX; i < res.lastIndex; i++) {\n                sb.append(res.measurements[i]).append(',').append(' ');\n            }\n            sb.append(res.measurements[res.lastIndex]).append('}');\n            System.out.println(sb);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_manishgarg90.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_manishgarg90 {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static int nProcessors = Runtime.getRuntime().availableProcessors();\n\n    public static void main(String[] args) throws IOException {\n        try (FileChannel channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            long fileSize = channel.size();\n            long chunkSize = (fileSize + nProcessors - 1) / nProcessors;\n            long pos = 0;\n\n            List<MappedByteBuffer> buffers = new ArrayList<>(nProcessors);\n\n            for (int i = 0; i < nProcessors; i++) {\n                long endPosition = getEndPosition(channel, pos + chunkSize);\n                long size = endPosition - pos;\n                MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, pos, size);\n                pos = pos + size;\n                buffers.add(buffer);\n            }\n\n            Map<String, Stat> s = readBufferAndCalculateMeauremenst(buffers);\n            Map<String, Stat> tm = new TreeMap<String, Stat>(s);\n            System.out.println(tm);\n        }\n        catch (IOException e) {\n            e.printStackTrace();\n        }\n\n    }\n\n    private static Map<String, Stat> readBufferAndCalculateMeauremenst(List<MappedByteBuffer> chunks) {\n        return chunks.parallelStream().map(buffer -> {\n            Map<String, Stat> map = new HashMap<>(10_000, 1);\n            int lineStart = 0;\n            int doubleStart = 0;\n            int length = buffer.limit();\n            String station = null;\n            for (int i = 0; i < length; ++i) {\n                byte b = buffer.get(i);\n                if (b == ';') {\n                    byte[] stationBuffer = new byte[i - lineStart];\n                    buffer.position(lineStart);\n                    buffer.get(stationBuffer);\n                    station = new String(stationBuffer, StandardCharsets.UTF_8);\n                    doubleStart = i + 1;\n                }\n                else if (b == '\\n') {\n                    byte[] doubleBuffer = new byte[i - doubleStart];\n                    buffer.position(doubleStart);\n                    buffer.get(doubleBuffer);\n                    Double temperature = Double.parseDouble(new String(doubleBuffer));\n                    lineStart = i + 1;\n\n                    // I have station name and temp\n                    Stat s = map.get(station);\n                    if (s == null) {\n                        map.put(station, new Stat(temperature));\n                    }\n                    else {\n                        s.update(temperature);\n                    }\n                }\n            }\n            return map;\n        }).reduce(new HashMap<>(), (map1, map2) -> {\n            Stat s = new Stat();\n            s.merge(map1);\n            s.merge(map2);\n            return s.getResultMap();\n        });\n\n    }\n\n    private static long getEndPosition(FileChannel channel, long position) throws IOException {\n        ByteBuffer buffer = ByteBuffer.allocate(1);\n        while (position < channel.size()) {\n            channel.read(buffer, position);\n\n            if (buffer.get(0) == '\\n') {\n                return position + 1;\n            }\n            position++;\n            buffer.clear();\n        }\n        return channel.size();\n    }\n\n    private static final class Stat {\n\n        private Double min = Double.MAX_VALUE;\n        private Double max = Double.MIN_VALUE;\n        private Double sum = 0d;\n        private long count = 0L;\n\n        private Map<String, Stat> resultMap = null;\n\n        public Stat() {\n            this.resultMap = new HashMap<>(10_000, 1);\n        }\n\n        public Stat(Double value) {\n            this.min = value;\n            this.max = value;\n            this.sum += value;\n            this.count++;\n        }\n\n        private void update(Double value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum = round(this.sum + value);\n            this.count++;\n        }\n\n        private void merge(Map<String, Stat> result) {\n            result.forEach((city, resultRow) -> resultMap.merge(city, resultRow, (existing, incoming) -> {\n                existing.min = Math.min(existing.min, incoming.min);\n                existing.max = Math.max(existing.max, incoming.max);\n                existing.sum += incoming.sum;\n                existing.count += incoming.count;\n                return existing;\n            }));\n        }\n\n        public Map<String, Stat> getResultMap() {\n            return resultMap;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_martin2038.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\npublic class CalculateAverage_martin2038 {\n\n    // private static final String FILE = \"/Users/martin/Garden/blog/1BRC/1brc/./measurements.txt\";\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class MeasurementAggregator {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum;\n        private int count;\n\n        void update(int temp) {\n            update(1, temp, temp, temp);\n        }\n\n        void update(int cnt, long sm, int min, int max) {\n            sum += sm;\n            count += cnt;\n            if (this.min > min) {\n                this.min = min;\n            }\n            if (this.max < max) {\n                this.max = max;\n            }\n        }\n\n        void merge(MeasurementAggregator it) {\n            update(it.count, it.sum, it.min, it.max);\n        }\n\n        public String toString() {\n            var mean = this.sum / 10.0 / this.count;\n            return (min / 10f) + \"/\" + Math.round(mean * 10) / 10f + \"/\" + (max / 10f);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n\n        var file = new RandomAccessFile(FILE, \"r\");\n        final int maxNameLength = 110;\n        var fc = file.getChannel();\n        split(file).stream().parallel().map(ck -> {\n            // StrFastHashKey 比string快500ms\n            var map = new HashMap<StrFastHashKey, MeasurementAggregator>(200);\n            // var pb = System.currentTimeMillis();\n            try {\n                var mb = fc.map(MapMode.READ_ONLY, ck.start, ck.length);\n                var buff = new byte[maxNameLength];\n                while (mb.hasRemaining()) {\n                    var name = readNextHashKey(buff, mb);\n                    // var name = readNextString(buff, mb);// .intern();\n                    var temp = readNextInt10Times(buff, mb);\n                    add2map(map, name, temp);\n                }\n                // long end = ck.start + ck.length;\n                // do {\n                // var name = readNext(file, ';', 30).intern();\n                // var temp = Double.parseDouble(readNext(file, '\\n', 6));\n                // var agg = map.computeIfAbsent(name,it->new MeasurementAggregator());\n                // agg.update(temp);\n                // }while (file.getFilePointer()<end);\n            }\n            catch (IOException | NumberFormatException e) {\n                throw new RuntimeException(e);\n            }\n            // System.out.println(\"chunk end , cost : \" + (System.currentTimeMillis() - pb));\n            return map;\n        }).reduce(CalculateAverage_martin2038::reduceMap).ifPresent(map -> {\n\n            var sb = new StringBuilder(map.size() * 100);\n            sb.append('{');\n            map.entrySet().stream().sorted(Map.Entry.comparingByKey())\n                    .forEachOrdered(kv -> sb.append(kv.getKey()).append('=').append(kv.getValue()).append(\", \"));\n            sb.deleteCharAt(sb.length() - 1);\n            sb.setCharAt(sb.length() - 1, '}');\n            var resultStr = sb.toString();\n            System.out.println(resultStr);\n            // System.out.println(resultStr.hashCode());\n        });\n\n    }\n\n    static <Key> HashMap<Key, MeasurementAggregator> reduceMap(HashMap<Key, MeasurementAggregator> aMap, HashMap<Key, MeasurementAggregator> bMap) {\n        aMap.forEach((k, v) -> {\n            var b = bMap.get(k);\n            if (null == b) {\n                bMap.put(k, v);\n            }\n            else {\n                b.merge(v);\n            }\n        });\n        return bMap;\n    }\n\n    static <Key> void add2map(Map<Key, MeasurementAggregator> map, Key name, int temp) {\n        // 比computeIfAbsent 节约1秒\n        var agg = map.get(name);\n        if (null == agg) {\n            agg = new MeasurementAggregator();\n            map.put(name, agg);\n        }\n        // var agg = map.computeIfAbsent(name,it->new MeasurementAggregator());\n        agg.update(temp);\n    }\n\n    record FileChunk(long start, long length) {\n    }\n\n    static List<FileChunk> split(RandomAccessFile file) throws IOException {\n        long total = file.length();\n        var threadNum = Math.max((int) (total / Integer.MAX_VALUE + 1), Runtime.getRuntime().availableProcessors());\n        long avgChunkSize = total / threadNum;\n        // System.out.println(avgChunkSize +\" \\t avgChunkSize : INT/MAX \\t\"+Integer.MAX_VALUE);\n        // Exception in thread \"main\" java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE\n        // at java.base/sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:1183)\n        long lastStart = 0;\n        var list = new ArrayList<FileChunk>(threadNum);\n        for (var i = 0; i < threadNum - 1; i++) {\n            var length = avgChunkSize;\n            file.seek(lastStart + length);\n            while (file.readByte() != '\\n') {\n                // file.seek(lastStart+ ++length);\n                ++length;\n            }\n            // include the '\\n'\n            length++;\n            list.add(new FileChunk(lastStart, length));\n            lastStart += length;\n            if (lastStart >= total) {\n                return list;\n            }\n        }\n        list.add(new FileChunk(lastStart, total - lastStart));\n        return list;\n    }\n\n    static StrFastHashKey readNextHashKey(byte[] buf, MappedByteBuffer mb) {\n        int i = 1;\n        mb.get(buf, 0, i);\n        byte b;\n        while ((b = mb.get()) != ';') {\n            buf[i++] = b;\n        }\n        return new StrFastHashKey(buf, i);\n    }\n\n    static String readNextString(byte[] buf, MappedByteBuffer mb) {\n        int i = 1;\n        mb.get(buf, 0, i);\n        byte b;\n        while ((b = mb.get()) != ';') {\n            buf[i++] = b;\n        }\n        return new String(buf, 0, i);\n    }\n\n    // copy from CalculateAverage_3j5a\n    // 替换 Double.parse\n    // 时间 38秒 -> 5418 ms\n    static int readNextInt10Times(byte[] buf, MappedByteBuffer mb) {\n        final int min_number_len = 3;\n        int i = min_number_len;\n        mb.get(buf, 0, i);\n        byte b;\n        while ((b = mb.get()) != '\\n') {\n            buf[i++] = b;\n        }\n        // -3.2\n        var zeroAscii = '0';\n        int temperature = buf[--i] - zeroAscii;\n        i--; // skipping dot\n        var base = 10;\n        while (i > 0) {\n            b = buf[--i];\n            if (b == '-') {\n                temperature = -temperature;\n            }\n            else {\n                temperature = base * (b - zeroAscii) + temperature;\n                base *= base;\n            }\n        }\n        return temperature;\n    }\n\n    // static String readNext(RandomAccessFile file, char endFlag,int initLength) throws IOException {\n    // StringBuilder input = new StringBuilder(initLength);\n    // int c = -1;\n    // //boolean eol = false;\n    //\n    // while (true) {\n    // c = file.read();\n    // if( c == endFlag || c == -1) {\n    // break;\n    // }\n    // input.append((char)c);\n    // }\n    //\n    // //if ((c == -1) && (input.length() == 0)) {\n    // // return null;\n    // //}\n    // return input.toString();\n    // }\n\n    static class StrFastHashKey implements Comparable<StrFastHashKey> {\n        final byte[] name;\n        final int hash;\n\n        String nameStr;\n\n        StrFastHashKey(byte[] buf, int size) {\n            name = new byte[size];\n            System.arraycopy(buf, 0, name, 0, size);\n            // hash = calculateHash(name, 0, size - 1);\n            // FNV1a save 100+ms than calculateHash\n            hash = hashFNV1a(name, size);\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            // if (this == o) {return true;}\n            // if (o == null || getClass() != o.getClass()) {return false;}\n            StrFastHashKey that = (StrFastHashKey) o;\n            return hash == that.hash && Arrays.equals(name, that.name);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public String toString() {\n            if (null == nameStr) {\n                nameStr = new String(name);\n            }\n            return nameStr;\n        }\n\n        @Override\n        public int compareTo(StrFastHashKey o) {\n            return toString().compareTo(o.toString());\n        }\n    }\n\n    private static final VarHandle LONG_VIEW = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.nativeOrder())\n            .withInvokeExactBehavior();\n    private static final VarHandle INT_VIEW = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.nativeOrder())\n            .withInvokeExactBehavior();\n\n    /**\n     * This is a prime number that gives pretty\n     * <a href=\"https://vanilla-java.github.io/2018/08/15/Looking-at-randomness-and-performance-for-hash-codes.html\">good hash distributions</a>\n     * on the data in this challenge.\n     */\n    private static final long RANDOM_PRIME = 0x7A646E4D;\n\n    /**\n     * The hash calculation is inspired by\n     * <a href=\"https://questdb.io/blog/building-faster-hash-table-high-performance-sql-joins/#fastmap-internals\">QuestDB FastMap</a>\n     */\n    private static int calculateHash(byte[] buffer, int startPosition, int endPosition) {\n        long hash = 0;\n\n        int position = startPosition;\n        for (; position + Long.BYTES <= endPosition; position += Long.BYTES) {\n            long value = (long) LONG_VIEW.get(buffer, position);\n            hash = hash * RANDOM_PRIME + value;\n        }\n\n        if (position + Integer.BYTES <= endPosition) {\n            int value = (int) INT_VIEW.get(buffer, position);\n            hash = hash * RANDOM_PRIME + value;\n            position += Integer.BYTES;\n        }\n\n        for (; position <= endPosition; position++) {\n            hash = hash * RANDOM_PRIME + buffer[position];\n        }\n        hash = hash * RANDOM_PRIME;\n        return (int) hash ^ (int) (hash >>> 32);\n    }\n\n    private static final int FNV1_32_INIT = 0x811c9dc5;\n    private static final int FNV1_PRIME_32 = 16777619;\n\n    /**\n     * https://github.com/prasanthj/hasher/blob/master/src/main/java/hasher/FNV1a.java\n     *\n     * FNV1a 32 bit variant.\n     *\n     * @param data   - input byte array\n     * @param length - length of array\n     * @return - hashcode\n     */\n    public static int hashFNV1a(byte[] data, int length) {\n        int hash = FNV1_32_INIT;\n        for (int i = 0; i < length; i++) {\n            hash ^= (data[i] & 0xff);\n            hash *= FNV1_PRIME_32;\n        }\n\n        return hash;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_mattiz.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\n\npublic class CalculateAverage_mattiz {\n    private static final int TWO_BYTE_TO_INT = 480 + 48; // 48 is the ASCII code for '0'\n    private static final int THREE_BYTE_TO_INT = 4800 + 480 + 48;\n    private static final String FILE = \"./measurements.txt\";\n    public static final int PARTS = 8;\n\n    public static void main(String[] args) throws Exception {\n        var result = new CalculateAverage_mattiz().calculate(FILE, PARTS);\n        System.out.println(result);\n    }\n\n    StationList calculate(String file, int numParts) throws Exception {\n        var buffers = createBuffers(Paths.get(file), numParts);\n\n        return buffers\n                .parallelStream()\n                .map(this::aggregate)\n                .reduce(StationList::merge)\n                .orElseThrow();\n    }\n\n    record BufferAndSize(ByteBuffer buffer, long size) {\n    }\n\n    List<ByteBuffer> createBuffers(Path file, int numParts) throws IOException {\n        FileChannel fileChannel = FileChannel.open(file, StandardOpenOption.READ);\n\n        var fileSize = fileChannel.size();\n\n        if (fileSize < (1024 * 1024)) { // Only one core for small files\n            numParts = 1;\n        }\n\n        var chunkSize = fileSize / numParts;\n        var buffers = new ArrayList<ByteBuffer>();\n        long filePointer = 0;\n\n        for (int i = 0; i < numParts; i++) {\n            if (i != numParts - 1) { // not last element\n                var adjustedChunkSize = getBuffer(fileChannel, filePointer, chunkSize, true);\n                buffers.add(adjustedChunkSize.buffer());\n                filePointer += adjustedChunkSize.size();\n            }\n            else {\n                var adjustedChunkSize = getBuffer(fileChannel, filePointer, fileSize - filePointer, false);\n                buffers.add(adjustedChunkSize.buffer());\n            }\n        }\n\n        return buffers;\n    }\n\n    BufferAndSize getBuffer(FileChannel fileChannel, long start, long size, boolean adjust) throws IOException {\n        MappedByteBuffer buffer = fileChannel.map(READ_ONLY, start, size);\n\n        var actualSize = ((int) size);\n\n        if (adjust) {\n            while (buffer.get(actualSize - 1) != '\\n') {\n                actualSize--;\n            }\n        }\n\n        buffer.limit(actualSize);\n\n        return new BufferAndSize(buffer, actualSize);\n    }\n\n    private StationList aggregate(ByteBuffer buffer) {\n        var measurements = new StationList();\n\n        while (buffer.hasRemaining()) {\n            int startPos = buffer.position();\n\n            byte b;\n            int hash = 0;\n            while ((b = buffer.get()) != ';') {\n                hash = ((hash << 5) - hash) + b;\n            }\n\n            if (hash < 0) {\n                hash = -hash;\n            }\n\n            int length = buffer.position() - startPos - 1;\n            byte[] station = new byte[length];\n            buffer.get(startPos, station);\n\n            int value = readValue(buffer);\n\n            measurements.update(station, length, hash, value);\n        }\n\n        return measurements;\n    }\n\n    /*\n     * Read decimal number from ascii characters (copied from arjenw)\n     *\n     * Example:\n     * If you have the decimal number 1.4,\n     * then byte 1 contain 49 (ascii code for '1')\n     * and byte 3 contain 52 (ascii code for '4')\n     * Subtract 480 + 48 (48 is the ASCII code for '0')\n     * to move number from ascii number to int\n     *\n     * 49 * 10 + 52 - 528 = 14\n     */\n    private static int readValue(ByteBuffer buffer) {\n        int value;\n        byte b1 = buffer.get();\n        byte b2 = buffer.get();\n        byte b3 = buffer.get();\n        byte b4 = buffer.get();\n\n        if (b2 == '.') {// value is n.n\n            value = (b1 * 10 + b3 - TWO_BYTE_TO_INT);\n        }\n        else {\n            if (b4 == '.') { // value is -nn.n\n                value = -(b2 * 100 + b3 * 10 + buffer.get() - THREE_BYTE_TO_INT);\n            }\n            else if (b1 == '-') { // value is -n.n\n                value = -(b2 * 10 + b4 - TWO_BYTE_TO_INT);\n            }\n            else { // value is nn.n\n                value = (b1 * 100 + b2 * 10 + b4 - THREE_BYTE_TO_INT);\n            }\n            buffer.get(); // new line\n        }\n        return value;\n    }\n}\n\nclass CustomMap {\n    private static final int SIZE = 1024 * 64;\n    private final Station[] stationList = new Station[SIZE];\n\n    public void addOrUpdate(byte[] stationName, int length, int hash, int value) {\n        int slot = hash & (SIZE - 1);\n        var station = stationList[slot];\n\n        while (station != null\n                && station.getHash() != hash\n                && !Arrays.equals(\n                        station.getName(), 0, station.getName().length,\n                        stationName, 0, length)) {\n\n            slot = (slot + 1) & (SIZE - 1);\n            station = stationList[slot];\n        }\n\n        if (station == null) {\n            stationList[slot] = new Station(stationName, hash);\n        }\n\n        stationList[slot].add(value);\n    }\n\n    public Station get(byte[] stationName) {\n        return stationList[findSlot(stationName)];\n    }\n\n    public void put(byte[] stationName, Station newStation) {\n        stationList[findSlot(stationName)] = newStation;\n    }\n\n    private int findSlot(byte[] stationName) {\n        int hash = getHash(stationName);\n        int slot = hash & (SIZE - 1);\n        var station = stationList[slot];\n\n        while (station != null\n                && station.getHash() != hash\n                && !Arrays.equals(station.getName(), stationName)) {\n\n            slot = (slot + 1) & (SIZE - 1);\n            station = stationList[slot];\n        }\n\n        return slot;\n    }\n\n    private int getHash(byte[] key) {\n        int hash = 0;\n\n        for (byte b : key) {\n            hash = hash * 31 + b;\n        }\n\n        if (hash < 0) {\n            hash = -hash;\n        }\n\n        return hash;\n    }\n\n    public Set<Map.Entry<byte[], Station>> entrySet() {\n        var sorted = new HashMap<byte[], Station>();\n\n        for (var s : stationList) {\n            if (s != null) {\n                sorted.put(s.getName(), s);\n            }\n        }\n\n        return sorted.entrySet();\n    }\n\n    public Map<String, Station> sorted() {\n        var sorted = new TreeMap<String, Station>();\n\n        for (var s : stationList) {\n            if (s != null) {\n                sorted.put(new String(s.getName(), StandardCharsets.UTF_8), s);\n            }\n        }\n\n        return sorted;\n    }\n}\n\nclass StationList {\n    private final CustomMap stations = new CustomMap();\n\n    public void update(byte[] stationName, int length, int hash, int value) {\n        stations.addOrUpdate(stationName, length, hash, value);\n    }\n\n    public StationList merge(StationList other) {\n        for (var aggregator : other.stations.entrySet()) {\n            var agg = stations.get(aggregator.getKey());\n\n            if (agg == null) {\n                stations.put(aggregator.getKey(), aggregator.getValue());\n            }\n            else {\n                agg.merge(aggregator.getValue());\n            }\n        }\n\n        return this;\n    }\n\n    @Override\n    public String toString() {\n        return stations.sorted().toString();\n    }\n}\n\nclass Station {\n    private final byte[] name;\n    private final int hash;\n    private int min = Integer.MAX_VALUE;\n    private int max = Integer.MIN_VALUE;\n    private int sum;\n    private int count;\n\n    public Station(byte[] name, int hash) {\n        this.name = name;\n        this.hash = hash;\n    }\n\n    public void add(int max, int min, int sum, int count) {\n        this.max = Math.max(this.max, max);\n        this.min = Math.min(this.min, min);\n        this.sum += sum;\n        this.count += count;\n    }\n\n    public void add(int value) {\n        this.max = Math.max(this.max, value);\n        this.min = Math.min(this.min, value);\n        this.sum += value;\n        this.count++;\n    }\n\n    public void merge(Station other) {\n        this.max = Math.max(this.max, other.max);\n        this.min = Math.min(this.min, other.min);\n        this.sum += other.sum;\n        this.count += other.count;\n    }\n\n    public String toString() {\n        return (min / 10.0) + \"/\" + (Math.round(((double) sum) / count)) / 10.0 + \"/\" + (max / 10.0);\n    }\n\n    public byte[] getName() {\n        return name;\n    }\n\n    public int getHash() {\n        return hash;\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_maximz101.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\npublic class CalculateAverage_maximz101 {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private record Measurement(String station, double value) {\n    }\n\n    private record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round(mean)}/\\{round(max)}\";\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private static class MeasurementAggregator {\n        private double min;\n        private double max;\n        private double sum;\n        private long count;\n\n        public MeasurementAggregator(double min, double max, double sum, long count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n    }\n\n    record FileChunkRange(long start, long end) {\n    }\n\n    public static void main(String[] args) throws IOException {\n        int parallelism = args.length == 1 ? Integer.parseInt(args[0]) : Runtime.getRuntime().availableProcessors();\n\n        Map<String, ResultRow> measurements = new ConcurrentHashMap<>();\n        try (ExecutorService executor = Executors.newWorkStealingPool(parallelism)) {\n            List<FileChunkRange> chunks = getChunks(new File(FILE), parallelism, 1_048_576);\n            List<CompletableFuture<Void>> completableFutureList = new ArrayList<>();\n            for (FileChunkRange chunk : chunks) {\n                completableFutureList\n                        .add(CompletableFuture\n                                .supplyAsync(() -> computePartialAggregations(chunk), executor)\n                                .thenAccept(map -> updateResultMap(map, measurements)));\n            }\n            CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[0]))\n                    .thenAccept(_ -> System.out.println(new TreeMap<>(measurements)))\n                    .join();\n        }\n    }\n\n    private static void updateResultMap(Map<String, MeasurementAggregator> map, Map<String, ResultRow> measurements) {\n        map.forEach((station, agg) -> measurements.merge(station,\n                new ResultRow(agg.min, agg.sum / agg.count, agg.max),\n                (r1, r2) -> new ResultRow(Math.min(r1.min, r2.min), (r1.mean + r2.mean) / 2, Math.max(r1.max, r2.max))));\n    }\n\n    private static Map<String, MeasurementAggregator> computePartialAggregations(FileChunkRange chunk) {\n        try (FileChannel channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            MappedByteBuffer buffer = channel.map(MapMode.READ_ONLY, chunk.start(), chunk.end() - chunk.start());\n            return process(buffer);\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static List<FileChunkRange> getChunks(File file, int chunksCount, int minChunkSize) {\n        long fileSize = file.length();\n        long chunkSize = fileSize / chunksCount;\n\n        if (chunkSize < minChunkSize || chunksCount == 1) {\n            return List.of(new FileChunkRange(0, fileSize));\n        }\n\n        int currentChunk = 1;\n        long currentChunkStart = 0;\n        long currentChunkEnd = chunkSize;\n        var list = new ArrayList<FileChunkRange>(chunksCount);\n        try (RandomAccessFile raf = new RandomAccessFile(file, \"r\")) {\n            while (currentChunk <= chunksCount) {\n                currentChunkEnd = findNextEOLFrom(raf, currentChunkEnd);\n                list.add(new FileChunkRange(currentChunkStart, currentChunkEnd));\n                // next\n                currentChunkStart = currentChunkEnd + 1;\n                currentChunkEnd = currentChunkStart + chunkSize;\n                if (currentChunkEnd >= fileSize) {\n                    list.add(new FileChunkRange(currentChunkStart, fileSize));\n                    break;\n                }\n                currentChunk++;\n            }\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n        return list;\n    }\n\n    private static long findNextEOLFrom(RandomAccessFile raf, long currentChunkEnd) throws IOException {\n        raf.seek(currentChunkEnd);\n        while (currentChunkEnd < raf.length() && raf.read() != '\\n') {\n            currentChunkEnd++;\n        }\n        return currentChunkEnd;\n    }\n\n    private static Map<String, MeasurementAggregator> process(MappedByteBuffer buffer) {\n        var map = new HashMap<String, MeasurementAggregator>();\n        byte[] lineBytes = new byte[107];\n        while (buffer.hasRemaining()) {\n            int i = 0;\n            lineBytes[i] = buffer.get();\n            int separatorIdx = -1;\n            while (lineBytes[i] != '\\n' && buffer.hasRemaining()) {\n                lineBytes[++i] = buffer.get();\n                if (lineBytes[i] == ';') {\n                    separatorIdx = i;\n                }\n            }\n            Measurement measurement = parseLine(lineBytes, separatorIdx, i);\n            map.merge(measurement.station,\n                    new MeasurementAggregator(measurement.value, measurement.value, measurement.value, 1),\n                    (agg, m) -> {\n                        agg.min = Math.min(agg.min, m.min);\n                        agg.max = Math.max(agg.max, m.max);\n                        agg.sum += m.sum;\n                        agg.count++;\n                        return agg;\n                    });\n        }\n        return map;\n    }\n\n    private static Measurement parseLine(byte[] lineBytes, int separatorIdx, int eolIdx) {\n        return new Measurement(\n                new String(lineBytes, 0, separatorIdx, StandardCharsets.UTF_8),\n                bytesToDouble(lineBytes, separatorIdx + 1, eolIdx));\n    }\n\n    private static double bytesToDouble(byte[] bytes, int startIdx, int endIdx) {\n        double d = 0d;\n        boolean negative = bytes[startIdx] == '-';\n        int numberStartIdx = negative ? 1 + startIdx : startIdx;\n        boolean afterDot = false;\n        int dots = 1;\n        for (int i = numberStartIdx; i < endIdx; i++) {\n            if (bytes[i] == '.') {\n                afterDot = true;\n                continue;\n            }\n            double n = bytes[i] - '0';\n            if (afterDot) {\n                d = d + n / Math.pow(10, dots++);\n            }\n            else {\n                d = d * Math.pow(10, i - numberStartIdx) + n;\n            }\n        }\n        return negative ? -d : d;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_melgenek.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.*;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.VarHandle;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.TreeMap;\nimport java.util.concurrent.*;\n\n/**\n * The implementation:\n * - reads a file with buffered IO\n * - uses VarHandles to get longs/ints from a byte array\n * - delimiter search is vectorized\n * - there is a custom hash function, that provides a low collision rate and short probe distances in hash tables\n * - has 2 custom open addressing hash tables: one for strings <=8 bytes in length, and one more for strings of any length\n */\npublic class CalculateAverage_melgenek {\n\n    private static final VarHandle LONG_VIEW = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.nativeOrder()).withInvokeExactBehavior();\n    private static final VarHandle INT_VIEW = MethodHandles.byteArrayViewVarHandle(int[].class, ByteOrder.nativeOrder()).withInvokeExactBehavior();\n    private static final int CORES_COUNT = Runtime.getRuntime().availableProcessors();\n\n    private static final String FILE = \"./measurements.txt\";\n    /**\n     * This is a prime number that gives pretty\n     * <a href=\"https://vanilla-java.github.io/2018/08/15/Looking-at-randomness-and-performance-for-hash-codes.html\">good hash distributions</a>\n     * on the data in this challenge.\n     */\n    private static final long RANDOM_PRIME = 0x7A646E4D;\n    private static final int ZERO_CHAR_3_SUM = 100 * '0' + 10 * '0' + '0';\n    private static final int ZERO_CHAR_2_SUM = 10 * '0' + '0';\n    private static final byte NEWLINE = '\\n';\n    private static final byte SEMICOLON = ';';\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED;\n    private static final int BYTE_SPECIES_BYTE_SIZE = BYTE_SPECIES.vectorByteSize();\n    private static final Vector<Byte> NEWLINE_VECTOR = BYTE_SPECIES.broadcast(NEWLINE);\n    private static final Vector<Byte> SEMICOLON_VECTOR = BYTE_SPECIES.broadcast(SEMICOLON);\n    private static final int MAX_LINE_LENGTH = 107; // 100 + len(\";-11.1\\n\") = 100+7\n\n    public static void main(String[] args) throws Throwable {\n        long totalSize = Files.size(Path.of(FILE));\n        long chunkSize = Math.max(MAX_LINE_LENGTH, totalSize / CORES_COUNT);\n        var result = new TreeMap<String, ResultRow>();\n        try (var executor = Executors.newFixedThreadPool(CORES_COUNT)) {\n            var service = new ExecutorCompletionService<CompositeTable>(executor);\n            int i = 0;\n            for (; i * chunkSize < totalSize; i++) {\n                long currentOffset = Math.max(0, i * chunkSize - 1);\n                long maxOffset = Math.min((i + 1) * chunkSize, totalSize);\n                service.submit(() -> processRange(currentOffset, maxOffset));\n            }\n            for (; i > 0; i--) {\n                service.take().get().addRows(result);\n            }\n        }\n        System.out.println(printTree(result));\n    }\n\n    private static String printTree(TreeMap<String, ResultRow> result) {\n        var sb = new StringBuilder(50 * result.size());\n        sb.append(\"{\");\n        boolean first = true;\n        for (var entry : result.entrySet()) {\n            if (first) {\n                first = false;\n            }\n            else {\n                sb.append(\", \");\n            }\n            sb.append(entry.getKey());\n            sb.append('=');\n            entry.getValue().appendToStringBuffer(sb);\n        }\n        sb.append(\"}\");\n        return sb.toString();\n    }\n\n    private static CompositeTable processRange(long startOffset, long maxOffset) {\n        final var table = new CompositeTable();\n        try (var file = new BufferedFile(startOffset, maxOffset)) {\n            processChunk(file, table);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n        return table;\n    }\n\n    private static void processChunk(BufferedFile file, CompositeTable table) throws IOException {\n        if (file.offset != 0) {\n            file.refillBuffer();\n            int newlinePosition = findDelimiter(file, 0, NEWLINE_VECTOR, NEWLINE);\n            file.bufferPosition = newlinePosition + 1;\n            file.offset += file.bufferPosition;\n        }\n        while (file.offset < file.maxOffset) {\n            file.refillBuffer();\n            int bytesProcessed = processOneRow(file, table);\n            file.offset += bytesProcessed;\n        }\n    }\n\n    private static int processOneRow(BufferedFile file, CompositeTable table) {\n        int stringStart = file.bufferPosition;\n        int stringEnd = findDelimiter(file, stringStart, SEMICOLON_VECTOR, SEMICOLON);\n\n        file.bufferPosition = stringEnd + 1;\n        short value = parseValue(file);\n\n        table.add(file.buffer, stringStart, stringEnd, value);\n\n        return file.bufferPosition - stringStart;\n    }\n\n    private static short parseValue(BufferedFile file) {\n        byte firstDigit = file.buffer[file.bufferPosition];\n        int sign = 1;\n        if (firstDigit == '-') {\n            sign = -1;\n            file.bufferPosition++;\n            firstDigit = file.buffer[file.bufferPosition];\n        }\n\n        byte secondDigit = file.buffer[file.bufferPosition + 1];\n        int result;\n        if (secondDigit == '.') {\n            result = firstDigit * 10 + file.buffer[file.bufferPosition + 2] - ZERO_CHAR_2_SUM;\n            file.bufferPosition += 4;\n        }\n        else {\n            result = firstDigit * 100 + secondDigit * 10 + file.buffer[file.bufferPosition + 3] - ZERO_CHAR_3_SUM;\n            file.bufferPosition += 5;\n        }\n        return (short) (result * sign);\n    }\n\n    /**\n     * <a href=\"https://gms.tf/stdfind-and-memchr-optimizations.html#do-more-faster\">Finds a delimiter in a byte array using vectorized comparisons.</a>\n     */\n    private static int findDelimiter(BufferedFile file, int startPosition, Vector<Byte> repeatedDelimiter, byte delimiter) {\n        int position = startPosition;\n        int vectorLoopBound = startPosition + BYTE_SPECIES.loopBound(file.bufferLimit - startPosition);\n        for (; position < vectorLoopBound; position += BYTE_SPECIES_BYTE_SIZE) {\n            var vector = ByteVector.fromArray(BYTE_SPECIES, file.buffer, position);\n            var comparisonResult = vector.compare(VectorOperators.EQ, repeatedDelimiter);\n            if (comparisonResult.anyTrue()) {\n                return position + comparisonResult.firstTrue();\n            }\n        }\n\n        while (file.buffer[position] != delimiter) {\n            position++;\n        }\n\n        return position;\n    }\n\n    private static long keepLastBytes(long value, int numBytesToKeep) {\n        // Number of bits to shift, so that the mask covers only `numBytesToKeep` least significant bits\n        int bitShift = (Long.BYTES - numBytesToKeep) * Byte.SIZE;\n        // Mask with the specified number of the least significant bits set to 1\n        long mask = -1L >>> bitShift;\n        return value & mask;\n    }\n\n    /**\n     * The function transforms a string with the length <=8 bytes to a java String.\n     * The function assumes that the string is 0 terminated.\n     */\n    private static String longToString(long value) {\n        int strLength = Long.BYTES - Long.numberOfLeadingZeros(value) / Byte.SIZE;\n        var bytes = new byte[strLength];\n        for (int i = 0; i < strLength; i++) {\n            bytes[i] = (byte) (value >> (i * Byte.SIZE));\n        }\n        return new String(bytes, StandardCharsets.UTF_8);\n    }\n\n    /**\n     * Store measurements based on string lengths.\n     * Stores strings of length <= 8 and other strings separately.\n     * This table is a simplified implementation of strings hash table in <a href=\"https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/HashTable/StringHashMap.h\">ClickHouse</a>.\n     * The original parer that describes benefits of the approach is <a href=\"https://www.mdpi.com/2076-3417/10/6/1915\">SAHA: A String Adaptive Hash Table for Analytical Databases</a>.\n     */\n    private static final class CompositeTable {\n        private final LongTable longTable = new LongTable();\n        private final RegularTable regularTable = new RegularTable();\n\n        private void add(byte[] buffer, int stringStart, int stringEnd, short value) {\n            int stringLength = stringEnd - stringStart;\n            if (stringLength <= Long.BYTES) {\n                long str = keepLastBytes((long) LONG_VIEW.get(buffer, stringStart), stringLength);\n                this.longTable.add(str, value);\n            }\n            else {\n                int hash = calculateHash(buffer, stringStart, stringEnd);\n                this.regularTable.add(buffer, stringStart, stringLength, hash, value);\n            }\n        }\n\n        public void addRows(TreeMap<String, ResultRow> result) {\n            this.longTable.addRows(result);\n            this.regularTable.addRows(result);\n        }\n    }\n\n    /**\n     * The hash calculation is inspired by\n     * <a href=\"https://questdb.io/blog/building-faster-hash-table-high-performance-sql-joins/#fastmap-internals\">QuestDB FastMap</a>\n     */\n    private static int calculateHash(byte[] buffer, int startPosition, int endPosition) {\n        long hash = 0;\n\n        int position = startPosition;\n        for (; position + Long.BYTES < endPosition; position += Long.BYTES) {\n            long value = (long) LONG_VIEW.get(buffer, position);\n            hash = hash * RANDOM_PRIME + value;\n        }\n\n        if (position + Integer.BYTES < endPosition) {\n            int value = (int) INT_VIEW.get(buffer, position);\n            hash = hash * RANDOM_PRIME + value;\n            position += Integer.BYTES;\n        }\n\n        for (; position < endPosition; position++) {\n            hash = hash * RANDOM_PRIME + buffer[position];\n        }\n        hash = hash * RANDOM_PRIME;\n        return (int) hash ^ (int) (hash >>> 32);\n    }\n\n    private static int calculateLongHash(long str) {\n        long hash = str * RANDOM_PRIME;\n        return (int) hash ^ (int) (hash >>> 32);\n    }\n\n    /**\n     * This tables stores strings of length <= 8 bytes.\n     * Does not store hashes.\n     */\n    private static final class LongTable {\n        private static final int TABLE_CAPACITY = 32768;\n        private static final int TABLE_CAPACITY_MASK = TABLE_CAPACITY - 1;\n        /**\n         * The buckets use 3 longs to store strings and measurements:\n         * long 1) station name\n         * long 2) sum of measurements\n         * long 3) count (int) | min (short) | max (short) <-- packed into one long\n         */\n        private final long[] buckets = new long[TABLE_CAPACITY * 3];\n\n        public void add(long str, short value) {\n            int hash = calculateLongHash(str);\n            int bucketIdx = hash & TABLE_CAPACITY_MASK;\n\n            long bucketStr = buckets[bucketIdx * 3];\n            if (bucketStr == str) {\n                updateBucket(bucketIdx, value);\n            }\n            else if (bucketStr == 0L) {\n                createBucket(bucketIdx, str, value);\n            }\n            else {\n                addWithProbing(str, value, (bucketIdx + 1) & TABLE_CAPACITY_MASK);\n            }\n        }\n\n        private void addWithProbing(long str, short value, int bucketIdx) {\n            int distance = 1;\n            while (true) {\n                long bucketStr = buckets[bucketIdx * 3];\n                if (bucketStr == str) {\n                    updateBucket(bucketIdx, value);\n                    break;\n                }\n                else if (bucketStr == 0L) {\n                    createBucket(bucketIdx, str, value);\n                    break;\n                }\n                else {\n                    distance++;\n                    // A new bucket index is calculated based on quadratic probing https://thenumb.at/Hashtables/#quadratic-probing\n                    // Quadratic probing decreases the number of collisions and max probing distance.\n                    // Linear:\n                    // - capacity 16k, 28.6M collisions, 14-17 max distance\n                    // - capacity 32k, 9.5M collisions, 5-7 max distance\n                    // Quadratic:\n                    // - capacity 16k 25M collisions, 8-10 max distance\n                    // - capacity 32k, 9.3M collisions, 4-7 max distance\n                    bucketIdx = (bucketIdx + distance) & TABLE_CAPACITY_MASK;\n                }\n            }\n        }\n\n        public void addRows(TreeMap<String, ResultRow> result) {\n            for (int bucketIdx = 0; bucketIdx < TABLE_CAPACITY; bucketIdx++) {\n                int bucketOffset = bucketIdx * 3;\n                long str = buckets[bucketOffset];\n                if (str != 0L) {\n                    long sum = buckets[bucketOffset + 1];\n                    long countMinMax = buckets[bucketOffset + 2];\n                    int count = (int) ((countMinMax >> 32));\n                    short min = (short) ((countMinMax >> 16) & 0xFFFF);\n                    short max = (short) (countMinMax & 0xFFFF);\n\n                    result.compute(longToString(str), (k, resultRow) -> {\n                        if (resultRow == null) {\n                            return new ResultRow(sum, count, min, max);\n                        }\n                        else {\n                            resultRow.add(sum, count, min, max);\n                            return resultRow;\n                        }\n                    });\n                }\n            }\n        }\n\n        private void createBucket(int bucketIdx, long str, short value) {\n            int offset = bucketIdx * 3;\n            buckets[offset] = str;\n            buckets[offset + 1] = value;\n            buckets[offset + 2] = (1L << 32) | ((long) (value & 0xFFFF) << 16) | (long) (value & 0xFFFF);\n        }\n\n        private void updateBucket(int bucketIdx, short value) {\n            int offset = bucketIdx * 3;\n            long sum = buckets[offset + 1];\n            buckets[offset + 1] = sum + value;\n\n            long countMinMax = buckets[offset + 2];\n            int count = (int) ((countMinMax >> 32));\n            short min = (short) ((countMinMax >> 16) & 0xFFFF);\n            short max = (short) (countMinMax & 0xFFFF);\n            if (value < min) {\n                min = value;\n            }\n            if (value > max) {\n                max = value;\n            }\n            buckets[offset + 2] = ((long) (count + 1) << 32) | ((long) (min & 0xFFFF) << 16) | (long) (max & 0xFFFF);\n        }\n    }\n\n    /**\n     * An open addressing hash table that stores strings as byte arrays.\n     * Stores hashes.\n     */\n    private static final class RegularTable {\n        private static final int TABLE_CAPACITY = 16384;\n        private static final int TABLE_CAPACITY_MASK = TABLE_CAPACITY - 1;\n        private final Bucket[] buckets = new Bucket[TABLE_CAPACITY];\n\n        public void add(byte[] data, int start, int stringLength, int hash, short value) {\n            int bucketIdx = hash & TABLE_CAPACITY_MASK;\n\n            var bucket = buckets[bucketIdx];\n            if (bucket == null) {\n                buckets[bucketIdx] = new Bucket(data, start, stringLength, hash, value);\n            }\n            else if (hash == bucket.hash && bucket.isEqual(data, start, stringLength)) {\n                bucket.update(value);\n            }\n            else {\n                addWithProbing(data, start, stringLength, hash, value, (bucketIdx + 1) & TABLE_CAPACITY_MASK);\n            }\n        }\n\n        private void addWithProbing(byte[] data, int start, int stringLength, int hash, short value, int bucketIdx) {\n            int distance = 1;\n            while (true) {\n                var bucket = buckets[bucketIdx];\n                if (bucket == null) {\n                    buckets[bucketIdx] = new Bucket(data, start, stringLength, hash, value);\n                    break;\n                }\n                else if (hash == bucket.hash && bucket.isEqual(data, start, stringLength)) {\n                    bucket.update(value);\n                    break;\n                }\n                else {\n                    distance++;\n                    bucketIdx = (bucketIdx + distance) & TABLE_CAPACITY_MASK;\n                }\n            }\n        }\n\n        public void addRows(TreeMap<String, ResultRow> result) {\n            for (var bucket : buckets) {\n                if (bucket != null) {\n                    result.compute(new String(bucket.str, StandardCharsets.UTF_8), (k, resultRow) -> {\n                        if (resultRow == null) {\n                            return new ResultRow(bucket.sum, bucket.count, bucket.min, bucket.max);\n                        }\n                        else {\n                            resultRow.add(bucket.sum, bucket.count, bucket.min, bucket.max);\n                            return resultRow;\n                        }\n                    });\n                }\n            }\n        }\n\n        private static final class Bucket {\n            int hash;\n            byte[] str;\n            long sum;\n            int count;\n            short max = Short.MIN_VALUE;\n            short min = Short.MAX_VALUE;\n\n            Bucket(byte[] data, int start, int stringLength, int hash, short value) {\n                this.str = new byte[stringLength];\n                System.arraycopy(data, start, this.str, 0, stringLength);\n                this.hash = hash;\n                update(value);\n            }\n\n            public void update(short value) {\n                this.sum += value;\n                this.count++;\n                if (max < value)\n                    max = value;\n                if (min > value)\n                    min = value;\n            }\n\n            public boolean isEqual(byte[] data, int start, int length) {\n                if (str.length != length)\n                    return false;\n                int i = 0;\n                int vectorLoopBound = BYTE_SPECIES.loopBound(str.length);\n                for (; i < vectorLoopBound; i += BYTE_SPECIES_BYTE_SIZE) {\n                    var vector1 = ByteVector.fromArray(BYTE_SPECIES, str, i);\n                    var vector2 = ByteVector.fromArray(BYTE_SPECIES, data, start + i);\n                    var comparisonResult = vector1.compare(VectorOperators.NE, vector2);\n                    if (comparisonResult.anyTrue())\n                        return false;\n                }\n                for (; i + Long.BYTES < str.length; i += Long.BYTES) {\n                    long value1 = (long) LONG_VIEW.get(str, i);\n                    long value2 = (long) LONG_VIEW.get(data, start + i);\n                    if (value1 != value2)\n                        return false;\n                }\n                if (i + Integer.BYTES < str.length) {\n                    int value1 = (int) INT_VIEW.get(str, i);\n                    int value2 = (int) INT_VIEW.get(data, start + i);\n                    if (value1 != value2)\n                        return false;\n                    i += Integer.BYTES;\n                }\n                for (; i < str.length; i++) {\n                    if (data[start + i] != str[i])\n                        return false;\n                }\n                return true;\n            }\n        }\n    }\n\n    private static class ResultRow {\n        long sum;\n        int count;\n        short min;\n        short max;\n\n        public ResultRow(long sum, int count, short min, short max) {\n            this.sum = sum;\n            this.count = count;\n            this.min = min;\n            this.max = max;\n        }\n\n        public void add(long anotherSum, int anotherCount, short anotherMin, short anotherMax) {\n            sum += anotherSum;\n            count += anotherCount;\n            if (max < anotherMax)\n                max = anotherMax;\n            if (min > anotherMin)\n                min = anotherMin;\n        }\n\n        public void appendToStringBuffer(StringBuilder sb) {\n            sb.append(Math.round((double) min) / 10.0);\n            sb.append('/');\n            sb.append(Math.round((double) sum / count) / 10.0);\n            sb.append('/');\n            sb.append(Math.round((double) max) / 10.0);\n        }\n    }\n\n    /**\n     * A utility class that uses the RandomAccessFile to read at offset.\n     * Keeps the in-memory buffer, as well as current offsets in the buffer and the file.\n     */\n    private static final class BufferedFile implements AutoCloseable {\n        private static final int BUFFER_SIZE = 512 * 1024;\n        private final byte[] buffer = new byte[BUFFER_SIZE];\n        private int bufferLimit = 0;\n        private int bufferPosition = 0;\n        private final long maxOffset;\n        private final RandomAccessFile file;\n        private long offset;\n\n        private BufferedFile(long startOffset, long maxOffset) throws IOException {\n            this.offset = startOffset;\n            this.maxOffset = maxOffset;\n            this.file = new RandomAccessFile(FILE, \"r\");\n        }\n\n        private void refillBuffer() throws IOException {\n            int remainingBytes = bufferLimit - bufferPosition;\n            if (remainingBytes < MAX_LINE_LENGTH) {\n                bufferPosition = 0;\n                file.seek(offset);\n                int bytesRead = file.read(buffer, 0, BUFFER_SIZE);\n                bufferLimit = Math.max(bytesRead, 0);\n            }\n        }\n\n        @Override\n        public void close() throws Exception {\n            file.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_merykitty.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\n\npublic class CalculateAverage_merykitty {\n    private static final String FILE = \"./measurements.txt\";\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED.length() >= 32\n            ? ByteVector.SPECIES_256\n            : ByteVector.SPECIES_128;\n    private static final ValueLayout.OfLong JAVA_LONG_LT = ValueLayout.JAVA_LONG_UNALIGNED.withOrder(ByteOrder.LITTLE_ENDIAN);\n    private static final long KEY_MAX_SIZE = 100;\n\n    private static class Aggregator {\n        private int keySize;\n        private long min = Integer.MAX_VALUE;\n        private long max = Integer.MIN_VALUE;\n        private long sum;\n        private long count;\n\n        public String toString() {\n            return round(min / 10.) + \"/\" + round(sum / (double) (10 * count)) + \"/\" + round(max / 10.);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    // An open-address map that is specialized for this task\n    private static class PoorManMap {\n\n        // 100-byte key + 4-byte hash + 4-byte size +\n        // 2-byte min + 2-byte max + 8-byte sum + 8-byte count\n        private static final int KEY_SIZE = 128;\n\n        // There is an assumption that map size <= 10000;\n        private static final int CAPACITY = 1 << 17;\n        private static final int BUCKET_MASK = CAPACITY - 1;\n\n        byte[] keyData;\n        Aggregator[] nodes;\n\n        PoorManMap() {\n            this.keyData = new byte[CAPACITY * KEY_SIZE];\n            this.nodes = new Aggregator[CAPACITY];\n        }\n\n        void observe(Aggregator node, long value) {\n            if (node.min > value) {\n                node.min = value;\n            }\n            if (node.max < value) {\n                node.max = value;\n            }\n            node.sum += value;\n            node.count++;\n        }\n\n        Aggregator indexSimple(MemorySegment data, long offset, int size) {\n            int x;\n            int y;\n            if (size >= Integer.BYTES) {\n                x = data.get(ValueLayout.JAVA_INT_UNALIGNED, offset);\n                y = data.get(ValueLayout.JAVA_INT_UNALIGNED, offset + size - Integer.BYTES);\n            }\n            else {\n                x = data.get(ValueLayout.JAVA_BYTE, offset);\n                y = data.get(ValueLayout.JAVA_BYTE, offset + size - Byte.BYTES);\n            }\n            int hash = hash(x, y);\n            int bucket = hash & BUCKET_MASK;\n            for (;; bucket = (bucket + 1) & BUCKET_MASK) {\n                var node = this.nodes[bucket];\n                if (node == null) {\n                    return insertInto(bucket, data, offset, size);\n                }\n                else if (keyEqualScalar(bucket, data, offset, size)) {\n                    return node;\n                }\n            }\n        }\n\n        Aggregator insertInto(int bucket, MemorySegment data, long offset, int size) {\n            var node = new Aggregator();\n            node.keySize = size;\n            this.nodes[bucket] = node;\n            MemorySegment.copy(data, offset, MemorySegment.ofArray(this.keyData), (long) bucket * KEY_SIZE, size + 1);\n            return node;\n        }\n\n        void mergeInto(Map<String, Aggregator> target) {\n            for (int i = 0; i < CAPACITY; i++) {\n                var node = this.nodes[i];\n                if (node == null) {\n                    continue;\n                }\n\n                String key = new String(this.keyData, i * KEY_SIZE, node.keySize, StandardCharsets.UTF_8);\n                target.compute(key, (k, v) -> {\n                    if (v == null) {\n                        v = new Aggregator();\n                    }\n\n                    v.min = Math.min(v.min, node.min);\n                    v.max = Math.max(v.max, node.max);\n                    v.sum += node.sum;\n                    v.count += node.count;\n                    return v;\n                });\n            }\n        }\n\n        static int hash(int x, int y) {\n            int seed = 0x9E3779B9;\n            int rotate = 5;\n            return (Integer.rotateLeft(x * seed, rotate) ^ y) * seed; // FxHash\n        }\n\n        private boolean keyEqualScalar(int bucket, MemorySegment data, long offset, int size) {\n            if (this.nodes[bucket].keySize != size) {\n                return false;\n            }\n\n            // Be simple\n            for (int i = 0; i < size; i++) {\n                int c1 = this.keyData[bucket * KEY_SIZE + i];\n                int c2 = data.get(ValueLayout.JAVA_BYTE, offset + i);\n                if (c1 != c2) {\n                    return false;\n                }\n            }\n            return true;\n        }\n    }\n\n    // Parse a number that may/may not contain a minus sign followed by a decimal with\n    // 1 - 2 digits to the left and 1 digits to the right of the separator to a\n    // fix-precision format. It returns the offset of the next line (presumably followed\n    // the final digit and a '\\n')\n    private static long parseDataPoint(PoorManMap aggrMap, Aggregator node, MemorySegment data, long offset) {\n        long word = data.get(JAVA_LONG_LT, offset);\n        // The 4th binary digit of the ascii of a digit is 1 while\n        // that of the '.' is 0. This finds the decimal separator\n        // The value can be 12, 20, 28\n        int decimalSepPos = Long.numberOfTrailingZeros(~word & 0x10101000);\n        int shift = 28 - decimalSepPos;\n        // signed is -1 if negative, 0 otherwise\n        long signed = (~word << 59) >> 63;\n        long designMask = ~(signed & 0xFF);\n        // Align the number to a specific position and transform the ascii code\n        // to actual digit value in each byte\n        long digits = ((word & designMask) << shift) & 0x0F000F0F00L;\n\n        // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n        // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n        // 0x000000UU00TTHH00 +\n        // 0x00UU00TTHH000000 * 10 +\n        // 0xUU00TTHH00000000 * 100\n        // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n        // This results in our value lies in the bit 32 to 41 of this product\n        // That was close :)\n        long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        long value = (absValue ^ signed) - signed;\n        aggrMap.observe(node, value);\n        return offset + (decimalSepPos >>> 3) + 3;\n    }\n\n    // Tail processing version of the above, do not over-fetch and be simple\n    private static long parseDataPointSimple(PoorManMap aggrMap, Aggregator node, MemorySegment data, long offset) {\n        int value = 0;\n        boolean negative = false;\n        if (data.get(ValueLayout.JAVA_BYTE, offset) == '-') {\n            negative = true;\n            offset++;\n        }\n        for (;; offset++) {\n            int c = data.get(ValueLayout.JAVA_BYTE, offset);\n            if (c == '.') {\n                c = data.get(ValueLayout.JAVA_BYTE, offset + 1);\n                value = value * 10 + (c - '0');\n                offset += 3;\n                break;\n            }\n\n            value = value * 10 + (c - '0');\n        }\n        value = negative ? -value : value;\n        aggrMap.observe(node, value);\n        return offset;\n    }\n\n    // An iteration of the main parse loop, parse a line starting from offset.\n    // This requires offset to be the start of the line and there is spare space so\n    // that we have relative freedom in processing\n    // It returns the offset of the next line that it needs processing\n    private static long iterate(PoorManMap aggrMap, MemorySegment data, long offset) {\n        var line = ByteVector.fromMemorySegment(BYTE_SPECIES, data, offset, ByteOrder.nativeOrder());\n\n        // Find the delimiter ';'\n        long semicolons = line.compare(VectorOperators.EQ, ';').toLong();\n\n        // If we cannot find the delimiter in the vector, that means the key is\n        // longer than the vector, fall back to scalar processing\n        if (semicolons == 0) {\n            int keySize = BYTE_SPECIES.length();\n            while (data.get(ValueLayout.JAVA_BYTE, offset + keySize) != ';') {\n                keySize++;\n            }\n            var node = aggrMap.indexSimple(data, offset, keySize);\n            return parseDataPoint(aggrMap, node, data, offset + 1 + keySize);\n        }\n\n        // We inline the searching of the value in the hash map\n        int keySize = Long.numberOfTrailingZeros(semicolons);\n        int x;\n        int y;\n        if (keySize >= Integer.BYTES) {\n            x = data.get(ValueLayout.JAVA_INT_UNALIGNED, offset);\n            y = data.get(ValueLayout.JAVA_INT_UNALIGNED, offset + keySize - Integer.BYTES);\n        }\n        else {\n            x = data.get(ValueLayout.JAVA_BYTE, offset);\n            y = data.get(ValueLayout.JAVA_BYTE, offset + keySize - Byte.BYTES);\n        }\n        int hash = PoorManMap.hash(x, y);\n        int bucket = hash & PoorManMap.BUCKET_MASK;\n        Aggregator node;\n        for (;; bucket = (bucket + 1) & PoorManMap.BUCKET_MASK) {\n            node = aggrMap.nodes[bucket];\n            if (node == null) {\n                node = aggrMap.insertInto(bucket, data, offset, keySize);\n                break;\n            }\n            if (node.keySize != keySize) {\n                continue;\n            }\n\n            var nodeKey = ByteVector.fromArray(BYTE_SPECIES, aggrMap.keyData, bucket * PoorManMap.KEY_SIZE);\n            long eqMask = line.compare(VectorOperators.EQ, nodeKey).toLong();\n            long validMask = semicolons ^ (semicolons - 1);\n            if ((eqMask & validMask) == validMask) {\n                break;\n            }\n        }\n\n        return parseDataPoint(aggrMap, node, data, offset + keySize + 1);\n    }\n\n    private static long findOffset(MemorySegment data, long offset, long limit) {\n        if (offset == 0) {\n            return offset;\n        }\n\n        offset--;\n        while (offset < limit) {\n            if (data.get(ValueLayout.JAVA_BYTE, offset++) == '\\n') {\n                break;\n            }\n        }\n        return offset;\n    }\n\n    // Process all lines that start in [offset, limit)\n    private static PoorManMap processFile(MemorySegment data, long offset, long limit) {\n        var aggrMap = new PoorManMap();\n        if (offset == limit) {\n            return aggrMap;\n        }\n        int batches = 2;\n        long batchSize = Math.ceilDiv(limit - offset, batches);\n        long offset0 = offset;\n        long offset1 = offset + batchSize;\n        long limit0 = Math.min(offset1, limit);\n        long limit1 = limit;\n\n        // Find the start of a new line\n        offset0 = findOffset(data, offset0, limit0);\n        offset1 = findOffset(data, offset1, limit1);\n\n        long mainLoopMinWidth = Math.max(BYTE_SPECIES.vectorByteSize(), KEY_MAX_SIZE + 1 + Long.BYTES);\n        if (limit1 - offset1 < mainLoopMinWidth) {\n            offset = findOffset(data, offset, limit);\n            while (offset < limit - mainLoopMinWidth) {\n                offset = iterate(aggrMap, data, offset);\n            }\n        }\n        else {\n            while (true) {\n                boolean finish = false;\n                if (offset0 < limit0) {\n                    offset0 = iterate(aggrMap, data, offset0);\n                }\n                else {\n                    finish = true;\n                }\n                if (offset1 < limit1 - mainLoopMinWidth) {\n                    offset1 = iterate(aggrMap, data, offset1);\n                }\n                else {\n                    if (finish) {\n                        break;\n                    }\n                }\n            }\n            offset = offset1;\n        }\n\n        // Now we are at the tail, just be simple\n        while (offset < limit) {\n            int keySize = 0;\n            while (data.get(ValueLayout.JAVA_BYTE, offset + keySize) != ';') {\n                keySize++;\n            }\n            var node = aggrMap.indexSimple(data, offset, keySize);\n            offset = parseDataPointSimple(aggrMap, node, data, offset + 1 + keySize);\n        }\n\n        return aggrMap;\n    }\n\n    public static void main(String[] args) throws InterruptedException, IOException {\n        int processorCnt = Runtime.getRuntime().availableProcessors();\n        var res = new TreeMap<String, Aggregator>();\n        try (var file = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n                var arena = Arena.ofShared()) {\n            var data = file.map(MapMode.READ_ONLY, 0, file.size(), arena);\n            long chunkSize = Math.ceilDiv(data.byteSize(), processorCnt);\n            var threadList = new Thread[processorCnt];\n            var resultList = new PoorManMap[processorCnt];\n            for (int i = 0; i < processorCnt; i++) {\n                int index = i;\n                long offset = i * chunkSize;\n                long limit = Math.min((i + 1) * chunkSize, data.byteSize());\n                var thread = new Thread(() -> resultList[index] = processFile(data, offset, limit));\n                threadList[index] = thread;\n                thread.start();\n            }\n            for (var thread : threadList) {\n                thread.join();\n            }\n\n            // Collect the results\n            for (var aggrMap : resultList) {\n                aggrMap.mergeInto(res);\n            }\n        }\n\n        System.out.println(res);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_merykittyunsafe.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_merykittyunsafe {\n    private static final String FILE = \"./measurements.txt\";\n    private static final Unsafe UNSAFE;\n    static {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            UNSAFE = (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED.length() >= 32\n            ? ByteVector.SPECIES_256\n            : ByteVector.SPECIES_128;\n    private static final long KEY_MAX_SIZE = 100;\n\n    private static class Aggregator {\n        private long min = Integer.MAX_VALUE;\n        private long max = Integer.MIN_VALUE;\n        private long sum;\n        private long count;\n\n        public String toString() {\n            return round(min / 10.) + \"/\" + round(sum / (double) (10 * count)) + \"/\" + round(max / 10.);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    // An open-address map that is specialized for this task\n    private static class PoorManMap {\n        // 100-byte key + 4-byte hash + 4-byte size +\n        // 2-byte min + 2-byte max + 8-byte sum + 8-byte count\n        private static final int ENTRY_SIZE = 128;\n        private static final int SIZE_OFFSET = 0;\n        private static final int MIN_OFFSET = 4;\n        private static final int MAX_OFFSET = 6;\n        private static final int SUM_OFFSET = 8;\n        private static final int COUNT_OFFSET = 16;\n        private static final int KEY_OFFSET = 24;\n\n        // There is an assumption that map size <= 10000;\n        private static final int CAPACITY = 1 << 17;\n        private static final int ENTRY_MASK = ENTRY_SIZE * CAPACITY - 1;\n\n        final byte[] data;\n\n        PoorManMap() {\n            this.data = new byte[CAPACITY * ENTRY_SIZE];\n        }\n\n        void observe(long entryOffset, long value) {\n            long baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + entryOffset;\n            if (UNSAFE.getShort(this.data, baseOffset + MIN_OFFSET) > value) {\n                UNSAFE.putShort(this.data, baseOffset + MIN_OFFSET, (short) value);\n            }\n            if (UNSAFE.getShort(this.data, baseOffset + MAX_OFFSET) < value) {\n                UNSAFE.putShort(this.data, baseOffset + MAX_OFFSET, (short) value);\n            }\n            UNSAFE.putLong(this.data, baseOffset + SUM_OFFSET,\n                    value + UNSAFE.getLong(this.data, baseOffset + SUM_OFFSET));\n            UNSAFE.putLong(this.data, baseOffset + COUNT_OFFSET,\n                    1 + UNSAFE.getLong(this.data, baseOffset + COUNT_OFFSET));\n        }\n\n        long indexSimple(long address, int size) {\n            int x;\n            int y;\n            if (size >= Integer.BYTES) {\n                x = UNSAFE.getInt(address);\n                y = UNSAFE.getInt(address + size - Integer.BYTES);\n            }\n            else {\n                x = UNSAFE.getByte(address);\n                y = UNSAFE.getByte(address + size - Byte.BYTES);\n            }\n            int hash = hash(x, y);\n            long entryOffset = (hash * ENTRY_SIZE) & ENTRY_MASK;\n            for (;; entryOffset = (entryOffset + ENTRY_SIZE) & ENTRY_MASK) {\n                int nodeSize = UNSAFE.getInt(this.data, Unsafe.ARRAY_BYTE_BASE_OFFSET + entryOffset + SIZE_OFFSET);\n                if (nodeSize == 0) {\n                    insertInto(entryOffset, address, size);\n                    return entryOffset;\n                }\n                else if (keyEqualScalar(entryOffset, address, size)) {\n                    return entryOffset;\n                }\n            }\n        }\n\n        void insertInto(long entryOffset, long address, int size) {\n            long baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + entryOffset;\n            UNSAFE.putInt(this.data, baseOffset + SIZE_OFFSET, size);\n            UNSAFE.putShort(this.data, baseOffset + MIN_OFFSET, Short.MAX_VALUE);\n            UNSAFE.putShort(this.data, baseOffset + MAX_OFFSET, Short.MIN_VALUE);\n            try (var arena = Arena.ofConfined()) {\n                var segment = MemorySegment.ofAddress(address)\n                        .reinterpret(size + 1, arena, null);\n                MemorySegment.copy(segment, 0, MemorySegment.ofArray(this.data), entryOffset + KEY_OFFSET, size + 1);\n            }\n        }\n\n        void mergeInto(Map<String, Aggregator> target) {\n            for (int entryOffset = 0; entryOffset < data.length; entryOffset += ENTRY_SIZE) {\n                long baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + entryOffset;\n                int size = UNSAFE.getInt(this.data, baseOffset + SIZE_OFFSET);\n                if (size == 0) {\n                    continue;\n                }\n\n                String key = new String(this.data, entryOffset + KEY_OFFSET, size, StandardCharsets.UTF_8);\n                target.compute(key, (k, v) -> {\n                    if (v == null) {\n                        v = new Aggregator();\n                    }\n\n                    v.min = Math.min(v.min, UNSAFE.getShort(this.data, baseOffset + MIN_OFFSET));\n                    v.max = Math.max(v.max, UNSAFE.getShort(this.data, baseOffset + MAX_OFFSET));\n                    v.sum += UNSAFE.getLong(this.data, baseOffset + SUM_OFFSET);\n                    v.count += UNSAFE.getLong(this.data, baseOffset + COUNT_OFFSET);\n                    return v;\n                });\n            }\n        }\n\n        static int hash(int x, int y) {\n            int seed = 0x9E3779B9;\n            int rotate = 5;\n            return (Integer.rotateLeft(x * seed, rotate) ^ y) * seed; // FxHash\n        }\n\n        private boolean keyEqualScalar(long entryOffset, long address, int size) {\n            long baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + entryOffset;\n            if (UNSAFE.getInt(this.data, baseOffset + SIZE_OFFSET) != size) {\n                return false;\n            }\n\n            // Be simple\n            for (long i = 0; i < size; i++) {\n                int c1 = UNSAFE.getByte(this.data, baseOffset + KEY_OFFSET + i);\n                int c2 = UNSAFE.getByte(address + i);\n                if (c1 != c2) {\n                    return false;\n                }\n            }\n            return true;\n        }\n    }\n\n    // Parse a number that may/may not contain a minus sign followed by a decimal with\n    // 1 - 2 digits to the left and 1 digits to the right of the separator to a\n    // fix-precision format. It returns the offset of the next line (presumably followed\n    // the final digit and a '\\n')\n    private static long parseDataPoint(PoorManMap aggrMap, long entryOffset, long address) {\n        long word = UNSAFE.getLong(address);\n        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {\n            word = Long.reverseBytes(word);\n        }\n        // The 4th binary digit of the ascii of a digit is 1 while\n        // that of the '.' is 0. This finds the decimal separator\n        // The value can be 12, 20, 28\n        int decimalSepPos = Long.numberOfTrailingZeros(~word & 0x10101000);\n        int shift = 28 - decimalSepPos;\n        // signed is -1 if negative, 0 otherwise\n        long signed = (~word << 59) >> 63;\n        long designMask = ~(signed & 0xFF);\n        // Align the number to a specific position and transform the ascii code\n        // to actual digit value in each byte\n        long digits = ((word & designMask) << shift) & 0x0F000F0F00L;\n\n        // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n        // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n        // 0x000000UU00TTHH00 +\n        // 0x00UU00TTHH000000 * 10 +\n        // 0xUU00TTHH00000000 * 100\n        // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n        // This results in our value lies in the bit 32 to 41 of this product\n        // That was close :)\n        long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        long value = (absValue ^ signed) - signed;\n        aggrMap.observe(entryOffset, value);\n        return address + (decimalSepPos >>> 3) + 3;\n    }\n\n    // Tail processing version of the above, do not over-fetch and be simple\n    private static long parseDataPointSimple(PoorManMap aggrMap, long entryOffset, long address) {\n        int value = 0;\n        boolean negative = false;\n        if (UNSAFE.getByte(address) == '-') {\n            negative = true;\n            address++;\n        }\n        for (;; address++) {\n            int c = UNSAFE.getByte(address);\n            if (c == '.') {\n                c = UNSAFE.getByte(address + 1);\n                value = value * 10 + (c - '0');\n                address += 3;\n                break;\n            }\n\n            value = value * 10 + (c - '0');\n        }\n        value = negative ? -value : value;\n        aggrMap.observe(entryOffset, value);\n        return address;\n    }\n\n    // An iteration of the main parse loop, parse a line starting from offset.\n    // This requires offset to be the start of the line and there is spare space so\n    // that we have relative freedom in processing\n    // It returns the offset of the next line that it needs processing\n    private static long iterate(PoorManMap aggrMap, long address) {\n        ByteVector line;\n        try (var arena = Arena.ofConfined()) {\n            var segment = MemorySegment.ofAddress(address)\n                    .reinterpret(BYTE_SPECIES.vectorByteSize(), arena, null);\n            line = ByteVector.fromMemorySegment(BYTE_SPECIES, segment, 0, ByteOrder.nativeOrder());\n        }\n\n        // Find the delimiter ';'\n        long semicolons = line.compare(VectorOperators.EQ, ';').toLong();\n\n        // If we cannot find the delimiter in the vector, that means the key is\n        // longer than the vector, fall back to scalar processing\n        if (semicolons == 0) {\n            int keySize = BYTE_SPECIES.length();\n            while (UNSAFE.getByte(address + keySize) != ';') {\n                keySize++;\n            }\n            var node = aggrMap.indexSimple(address, keySize);\n            return parseDataPoint(aggrMap, node, address + 1 + keySize);\n        }\n\n        // We inline the searching of the value in the hash map\n        int keySize = Long.numberOfTrailingZeros(semicolons);\n        int x;\n        int y;\n        if (keySize >= Integer.BYTES) {\n            x = UNSAFE.getInt(address);\n            y = UNSAFE.getInt(address + keySize - Integer.BYTES);\n        }\n        else {\n            x = UNSAFE.getByte(address);\n            y = UNSAFE.getByte(address + keySize - Byte.BYTES);\n        }\n        int hash = PoorManMap.hash(x, y);\n        long entryOffset = (hash * PoorManMap.ENTRY_SIZE) & PoorManMap.ENTRY_MASK;\n        for (;; entryOffset = (entryOffset + PoorManMap.ENTRY_SIZE) & PoorManMap.ENTRY_MASK) {\n            var nodeSize = UNSAFE.getInt(aggrMap.data, Unsafe.ARRAY_BYTE_BASE_OFFSET\n                    + entryOffset + PoorManMap.SIZE_OFFSET);\n            if (nodeSize == 0) {\n                aggrMap.insertInto(entryOffset, address, keySize);\n                break;\n            }\n\n            if (nodeSize != keySize) {\n                continue;\n            }\n\n            var nodeKey = ByteVector.fromArray(BYTE_SPECIES, aggrMap.data, (int) (entryOffset + PoorManMap.KEY_OFFSET));\n            long eqMask = line.compare(VectorOperators.EQ, nodeKey).toLong();\n            long validMask = semicolons ^ (semicolons - 1);\n            if ((eqMask & validMask) == validMask) {\n                break;\n            }\n        }\n\n        return parseDataPoint(aggrMap, entryOffset, address + keySize + 1);\n    }\n\n    private static long findOffset(long base, long offset, long limit) {\n        if (offset == 0) {\n            return offset;\n        }\n\n        offset--;\n        while (offset < limit) {\n            if (UNSAFE.getByte(base + (offset++)) == '\\n') {\n                break;\n            }\n        }\n        return offset;\n    }\n\n    // Process all lines that start in [offset, limit)\n    private static PoorManMap processFile(MemorySegment data, long offset, long limit) {\n        var aggrMap = new PoorManMap();\n        if (offset == limit) {\n            return aggrMap;\n        }\n        long base = data.address();\n        int batches = 2;\n        long batchSize = Math.ceilDiv(limit - offset, batches);\n        long offset0 = offset;\n        long offset1 = offset + batchSize;\n        long limit0 = Math.min(offset1, limit);\n        long limit1 = limit;\n\n        // Find the start of a new line\n        offset0 = findOffset(base, offset0, limit0);\n        offset1 = findOffset(base, offset1, limit1);\n\n        long begin;\n        long end = base + limit;\n        long mainLoopMinWidth = Math.max(BYTE_SPECIES.vectorByteSize(), KEY_MAX_SIZE + 1 + Long.BYTES);\n        if (limit1 - offset1 < mainLoopMinWidth) {\n            begin = base + findOffset(base, offset, limit);\n            while (begin < end - mainLoopMinWidth) {\n                begin = iterate(aggrMap, begin);\n            }\n        }\n        else {\n            long begin0 = base + offset0;\n            long begin1 = base + offset1;\n            long end0 = base + limit0;\n            long end1 = base + limit1;\n            while (true) {\n                boolean finish = false;\n                if (begin0 < end0) {\n                    begin0 = iterate(aggrMap, begin0);\n                }\n                else {\n                    finish = true;\n                }\n                if (begin1 < end1 - mainLoopMinWidth) {\n                    begin1 = iterate(aggrMap, begin1);\n                }\n                else {\n                    if (finish) {\n                        break;\n                    }\n                }\n            }\n            begin = begin1;\n        }\n\n        // Now we are at the tail, just be simple\n        while (begin < end) {\n            int keySize = 0;\n            while (UNSAFE.getByte(begin + keySize) != ';') {\n                keySize++;\n            }\n            long entryOffset = aggrMap.indexSimple(begin, keySize);\n            begin = parseDataPointSimple(aggrMap, entryOffset, begin + 1 + keySize);\n        }\n\n        return aggrMap;\n    }\n\n    public static void main(String[] args) throws InterruptedException, IOException {\n        int processorCnt = Runtime.getRuntime().availableProcessors();\n        var res = new TreeMap<String, Aggregator>();\n        try (var file = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n                var arena = Arena.ofShared()) {\n            var data = file.map(MapMode.READ_ONLY, 0, file.size(), arena);\n            long chunkSize = Math.ceilDiv(data.byteSize(), processorCnt);\n            var threadList = new Thread[processorCnt];\n            var resultList = new PoorManMap[processorCnt];\n            for (int i = 0; i < processorCnt; i++) {\n                int index = i;\n                long offset = i * chunkSize;\n                long limit = Math.min((i + 1) * chunkSize, data.byteSize());\n                var thread = new Thread(() -> resultList[index] = processFile(data, offset, limit));\n                threadList[index] = thread;\n                thread.start();\n            }\n            for (var thread : threadList) {\n                thread.join();\n            }\n\n            // Collect the results\n            for (var aggrMap : resultList) {\n                aggrMap.mergeInto(res);\n            }\n        }\n\n        System.out.println(res);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_moysesb.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.BufferUnderflowException;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorCompletionService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_moysesb {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    static class ByteArray {\n        final byte[] value;\n        final int hashCode;\n\n        private ByteArray(byte[] val, int hashCode) {\n            this.value = val;\n            this.hashCode = hashCode;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (o instanceof ByteArray other) {\n                return this == other || hashCode == other.hashCode && Arrays.equals(value, other.value);\n            }\n            return false;\n        }\n\n        @Override\n        public int hashCode() {\n            return hashCode;\n        }\n    }\n\n    static final Map<ByteArray, double[]> allResults = new HashMap<>(512);\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        int ncpus = Runtime.getRuntime().availableProcessors();\n        ExecutorCompletionService<Map<ByteArray, double[]>> exec = new ExecutorCompletionService<>(Executors.newFixedThreadPool(ncpus));\n        var file = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n        File f = new File(FILE);\n        long fileSize = f.length();\n        long split = 0;\n        long chunkSize = Math.min(1 << 28,  fileSize < 1 << 28 ? fileSize : (fileSize / ncpus));\n        List<Future<Map<ByteArray, double[]>>> tasks = new ArrayList<>();\n\n        while (split < fileSize) {\n            final long[] offset = {split};\n            var task = exec.submit(() -> {\n                try {\n                    final Map<ByteArray, double[]> results = new HashMap<>(512);\n                    file:\n                    for (; ; ) {\n                        long chunk = Math.min(fileSize - offset[0], chunkSize);\n                        if (chunk == 0) {\n                            return results;\n                        }\n                        MemorySegment mm = file.map(FileChannel.MapMode.READ_ONLY, offset[0], chunk, Arena.ofConfined());\n\n                        int i = 0;\n                        if (offset[0] > 0) {\n                            while (mm.get(ValueLayout.JAVA_BYTE, i) != '\\n') {\n                                i++;\n                            }\n                            i++;\n                        }\n                        while (i < chunk) {\n                            try {\n                                byte[] city = new byte[32];\n                                byte[] valb = new byte[16];\n                                byte[] target = city;\n                                double val = 0d;\n                                int dotOffset = 0;\n                                int l = 0;\n                                int nameHash = 0;\n                                for (; ; ) {\n                                    byte b = mm.get(ValueLayout.OfByte.JAVA_BYTE, i++);\n                                    if (b == ';') {\n                                        target = valb;\n                                        l = 0;\n                                    } else if (b == '\\n') {\n                                        int integral = 0;\n                                        int mult = 1;\n                                        int frac = 0;\n                                        for (int ii = 0; ii < dotOffset; ii++) {\n                                            if (valb[ii] == '-') {\n                                                mult = -1;\n                                            } else {\n                                                integral = integral * 10 + (valb[ii] - '0');\n                                            }\n                                        }\n\n                                        for (int ii = dotOffset+1; ii < l; ii++) {\n                                            frac = frac * 10 + (valb[ii] - '0');\n                                        }\n                                        val = integral;\n                                        if (frac > 0)\n                                            val += (frac/10d);\n\n                                        val *= mult;\n                                        var ba = new ByteArray(city, nameHash);\n\n                                        var r = results.computeIfAbsent(ba, _s -> new double[]{1000, -1000, 0, 0});\n                                        r[0] = Math.min(r[0], val);\n                                        r[1] = Math.max(r[1], val);\n                                        r[2]++;\n                                        r[3] += val;\n                                        break;\n                                    } else {\n                                        if (target == city) {\n                                            nameHash = nameHash * 31 + b;\n                                        } else if (b == '.') {\n                                            dotOffset = l;\n                                        }\n                                        target[l++] = b;\n\n                                    }\n                                }\n                            } catch (BufferUnderflowException | IndexOutOfBoundsException e) {\n                                //happens on the last segment after EOF\n                                break file;\n                            }\n                        }\n                        offset[0] += i;\n                    }\n                    return results;\n                } catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            });\n            tasks.add(task);\n            split += chunkSize;\n        }\n\n        int taken = 0;\n        while (taken < tasks.size()) {\n            Future<Map<ByteArray, double[]>> fut = exec.take();\n            var map = fut.get();\n            taken++;\n            if (map == null) {\n                continue;\n            }\n            for (Map.Entry<ByteArray, double[]> e : map.entrySet()) {\n                var ba = e.getKey();\n                var val = e.getValue();\n                allResults.merge(ba, val, (old, _new) -> {\n                    old[0] = Math.min(old[0], _new[0]);\n                    old[1] = Math.max(old[1], _new[1]);\n                    old[2] += _new[2];\n                    old[3] += _new[3];\n                    return old;\n                });\n            }\n        }\n\n        SortedMap<String, String> sorted = new TreeMap<>();\n        for (Map.Entry<ByteArray, double[]> e : allResults.entrySet()) {\n            byte[] utf8 = e.getKey().value;\n            int strlen = 0;\n            while (utf8[strlen] != '\\0') strlen++;\n            String city = new String(utf8, 0,  strlen, StandardCharsets.UTF_8);\n            double[] r = e.getValue();\n            String fmt = FormatProcessor.FMT.\"%.1f\\{round(r[0])}/%.1f\\{round(r[3]/r[2])}/%.1f\\{round(r[1])}\";\n            sorted.put(city, fmt);\n        }\n\n        System.out.println(sorted);\n\n        System.exit(0);\n    }\n\n    private static double round(double d) {\n        return Math.round(d * 10.0) / 10.0;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_mtopolnik.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\nimport static java.lang.ProcessBuilder.Redirect.PIPE;\nimport static java.util.Arrays.asList;\n\npublic class CalculateAverage_mtopolnik {\n    private static final Unsafe UNSAFE = unsafe();\n    private static final int MAX_NAME_LEN = 100;\n    private static final int STATS_TABLE_SIZE = 1 << 16;\n    private static final int TABLE_INDEX_MASK = STATS_TABLE_SIZE - 1;\n    private static final String MEASUREMENTS_TXT = \"measurements.txt\";\n\n    private static Unsafe unsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        if (args.length >= 1 && args[0].equals(\"--worker\")) {\n            calculate();\n            System.out.close();\n            return;\n        }\n        var curProcInfo = ProcessHandle.current().info();\n        var cmdLine = new ArrayList<String>();\n        cmdLine.add(curProcInfo.command().get());\n        cmdLine.addAll(asList(curProcInfo.arguments().get()));\n        cmdLine.add(\"--worker\");\n        var process = new ProcessBuilder()\n                .command(cmdLine)\n                .inheritIO().redirectOutput(PIPE)\n                .start()\n                .getInputStream().transferTo(System.out);\n\n    }\n\n    static void calculate() throws Exception {\n        final File file = new File(MEASUREMENTS_TXT);\n        final long length = file.length();\n        final int chunkCount = Runtime.getRuntime().availableProcessors();\n        final var results = new StationStats[chunkCount][];\n        final var chunkStartOffsets = new long[chunkCount];\n        try (var raf = new RandomAccessFile(file, \"r\")) {\n            final var inputBase = raf.getChannel().map(MapMode.READ_ONLY, 0, length, Arena.global()).address();\n            for (int i = 1; i < chunkStartOffsets.length; i++) {\n                var start = length * i / chunkStartOffsets.length;\n                raf.seek(start);\n                while (raf.read() != (byte) '\\n') {\n                }\n                start = raf.getFilePointer();\n                chunkStartOffsets[i] = start;\n            }\n            var threads = new Thread[chunkCount];\n            for (int i = 0; i < chunkCount; i++) {\n                final long chunkStart = chunkStartOffsets[i];\n                final long chunkLimit = (i + 1 < chunkCount) ? chunkStartOffsets[i + 1] : length;\n                threads[i] = new Thread(new ChunkProcessor(inputBase + chunkStart, inputBase + chunkLimit, results, i));\n            }\n            for (var thread : threads) {\n                thread.start();\n            }\n            for (var thread : threads) {\n                thread.join();\n            }\n        }\n        mergeSortAndPrint(results);\n    }\n\n    private static class ChunkProcessor implements Runnable {\n        private static final int CACHELINE_SIZE = 64;\n\n        private final long inputBase;\n        private final long inputSize;\n        private final StationStats[][] results;\n        private final int myIndex;\n\n        private StatsAccessor stats;\n\n        ChunkProcessor(long chunkStart, long chunkLimit, StationStats[][] results, int myIndex) {\n            this.inputBase = chunkStart;\n            this.inputSize = chunkLimit - chunkStart;\n            this.results = results;\n            this.myIndex = myIndex;\n        }\n\n        @Override\n        public void run() {\n            try (Arena confinedArena = Arena.ofConfined()) {\n                long totalAllocated = 0;\n                String threadName = Thread.currentThread().getName();\n                long statsByteSize = STATS_TABLE_SIZE * StatsAccessor.SIZEOF;\n                var diagnosticString = String.format(\"Thread %s needs %,d bytes\", threadName, statsByteSize);\n                try {\n                    stats = new StatsAccessor(confinedArena.allocate(statsByteSize, CACHELINE_SIZE));\n                }\n                catch (OutOfMemoryError e) {\n                    System.err.print(diagnosticString);\n                    throw e;\n                }\n                processChunk();\n                exportResults();\n            }\n        }\n\n        private void processChunk() {\n            final long inputSize = this.inputSize;\n            final long inputBase = this.inputBase;\n            long cursor = 0;\n            long lastNameWord;\n            while (cursor < inputSize) {\n                long nameStartAddress = inputBase + cursor;\n                long nameWord0 = UNSAFE.getLong(nameStartAddress);\n                long nameWord1 = 0;\n                long matchBits = semicolonMatchBits(nameWord0);\n                long hash;\n                int nameLen;\n                int temperature;\n                if (matchBits != 0) {\n                    nameLen = nameLen(matchBits);\n                    nameWord0 = maskWord(nameWord0, matchBits);\n                    cursor += nameLen;\n                    long tempWord = UNSAFE.getLong(inputBase + cursor);\n                    int dotPos = dotPos(tempWord);\n                    temperature = parseTemperature(tempWord, dotPos);\n                    cursor += (dotPos >> 3) + 3;\n                    hash = hash(nameWord0);\n                    if (stats.gotoName0(hash, nameWord0)) {\n                        stats.observe(temperature);\n                        continue;\n                    }\n                    lastNameWord = nameWord0;\n                }\n                else { // nameLen > 8\n                    hash = hash(nameWord0);\n                    nameWord1 = UNSAFE.getLong(nameStartAddress + Long.BYTES);\n                    matchBits = semicolonMatchBits(nameWord1);\n                    if (matchBits != 0) {\n                        nameLen = Long.BYTES + nameLen(matchBits);\n                        nameWord1 = maskWord(nameWord1, matchBits);\n                        cursor += nameLen;\n                        long tempWord = UNSAFE.getLong(inputBase + cursor);\n                        int dotPos = dotPos(tempWord);\n                        temperature = parseTemperature(tempWord, dotPos);\n                        cursor += (dotPos >> 3) + 3;\n                        if (stats.gotoName1(hash, nameWord0, nameWord1)) {\n                            stats.observe(temperature);\n                            continue;\n                        }\n                        lastNameWord = nameWord1;\n                    }\n                    else { // nameLen > 16\n                        nameLen = 2 * Long.BYTES;\n                        while (true) {\n                            lastNameWord = UNSAFE.getLong(nameStartAddress + nameLen);\n                            matchBits = semicolonMatchBits(lastNameWord);\n                            if (matchBits != 0) {\n                                nameLen += nameLen(matchBits);\n                                lastNameWord = maskWord(lastNameWord, matchBits);\n                                cursor += nameLen;\n                                long tempWord = UNSAFE.getLong(inputBase + cursor);\n                                int dotPos = dotPos(tempWord);\n                                temperature = parseTemperature(tempWord, dotPos);\n                                cursor += (dotPos >> 3) + 3;\n                                break;\n                            }\n                            nameLen += Long.BYTES;\n                        }\n                    }\n                }\n                stats.gotoAndObserve(hash, nameStartAddress, nameLen, nameWord0, nameWord1, lastNameWord, temperature);\n            }\n        }\n\n        private static final long BROADCAST_SEMICOLON = 0x3B3B3B3B3B3B3B3BL;\n        private static final long BROADCAST_0x01 = 0x0101010101010101L;\n        private static final long BROADCAST_0x80 = 0x8080808080808080L;\n\n        private static long semicolonMatchBits(long word) {\n            long diff = word ^ BROADCAST_SEMICOLON;\n            return (diff - BROADCAST_0x01) & (~diff & BROADCAST_0x80);\n        }\n\n        // credit: artsiomkorzun\n        private static long maskWord(long word, long matchBits) {\n            long mask = matchBits ^ (matchBits - 1);\n            return word & mask;\n        }\n\n        // credit: merykitty\n        private static int dotPos(long word) {\n            return Long.numberOfTrailingZeros(~word & 0x10101000);\n        }\n\n        // credit: merykitty\n        private static int parseTemperature(long word, int dotPos) {\n            final long signed = (~word << 59) >> 63;\n            final long removeSignMask = ~(signed & 0xFF);\n            final long digits = ((word & removeSignMask) << (28 - dotPos)) & 0x0F000F0F00L;\n            final long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            return (int) ((absValue ^ signed) - signed);\n        }\n\n        private static int nameLen(long separator) {\n            return (Long.numberOfTrailingZeros(separator) >>> 3) + 1;\n        }\n\n        private static long hash(long word) {\n            return Long.rotateLeft(word * 0x51_7c_c1_b7_27_22_0a_95L, 17);\n        }\n\n        // Copies the results from native memory to Java heap and puts them into the results array.\n        private void exportResults() {\n            var exportedStats = new ArrayList<StationStats>(10_000);\n            for (int i = 0; i < STATS_TABLE_SIZE; i++) {\n                stats.gotoIndex(i);\n                if (stats.nameLen() == 0) {\n                    continue;\n                }\n                var sum = stats.sum();\n                var count = stats.count();\n                var min = stats.min();\n                var max = stats.max();\n                var name = stats.exportNameString();\n                var stationStats = new StationStats();\n                stationStats.name = name;\n                stationStats.sum = sum;\n                stationStats.count = count;\n                stationStats.min = min;\n                stationStats.max = max;\n                exportedStats.add(stationStats);\n            }\n            StationStats[] exported = exportedStats.toArray(new StationStats[0]);\n            Arrays.sort(exported);\n            results[myIndex] = exported;\n        }\n    }\n\n    static class StatsAccessor {\n        static final int NAME_SLOT_SIZE = 104;\n        static final long HASH_OFFSET = 0;\n        static final long NAMELEN_OFFSET = HASH_OFFSET + Long.BYTES;\n        static final long SUM_OFFSET = NAMELEN_OFFSET + Integer.BYTES;\n        static final long COUNT_OFFSET = SUM_OFFSET + Integer.BYTES;\n        static final long MIN_OFFSET = COUNT_OFFSET + Integer.BYTES;\n        static final long MAX_OFFSET = MIN_OFFSET + Short.BYTES;\n        static final long NAME_OFFSET = MAX_OFFSET + Short.BYTES;\n        static final long SIZEOF = (NAME_OFFSET + NAME_SLOT_SIZE - 1) / 8 * 8 + 8;\n\n        static final int ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);\n\n        private final long address;\n        private long slotBase;\n\n        StatsAccessor(MemorySegment memSeg) {\n            memSeg.fill((byte) 0);\n            this.address = memSeg.address();\n        }\n\n        void gotoIndex(int index) {\n            slotBase = address + index * SIZEOF;\n        }\n\n        private boolean gotoName0(long hash, long nameWord0) {\n            gotoIndex((int) (hash & TABLE_INDEX_MASK));\n            return hash() == hash && nameWord0() == nameWord0;\n        }\n\n        private boolean gotoName1(long hash, long nameWord0, long nameWord1) {\n            gotoIndex((int) (hash & TABLE_INDEX_MASK));\n            return hash() == hash && nameWord0() == nameWord0 && nameWord1() == nameWord1;\n        }\n\n        long hash() {\n            return UNSAFE.getLong(slotBase + HASH_OFFSET);\n        }\n\n        int nameLen() {\n            return UNSAFE.getInt(slotBase + NAMELEN_OFFSET);\n        }\n\n        int sum() {\n            return UNSAFE.getInt(slotBase + SUM_OFFSET);\n        }\n\n        int count() {\n            return UNSAFE.getInt(slotBase + COUNT_OFFSET);\n        }\n\n        short min() {\n            return UNSAFE.getShort(slotBase + MIN_OFFSET);\n        }\n\n        short max() {\n            return UNSAFE.getShort(slotBase + MAX_OFFSET);\n        }\n\n        long nameAddress() {\n            return slotBase + NAME_OFFSET;\n        }\n\n        long nameWord0() {\n            return UNSAFE.getLong(nameAddress());\n        }\n\n        long nameWord1() {\n            return UNSAFE.getLong(nameAddress() + Long.BYTES);\n        }\n\n        String exportNameString() {\n            final var bytes = new byte[nameLen() - 1];\n            UNSAFE.copyMemory(null, nameAddress(), bytes, ARRAY_BASE_OFFSET, bytes.length);\n            return new String(bytes, StandardCharsets.UTF_8);\n        }\n\n        void setHash(long hash) {\n            UNSAFE.putLong(slotBase + HASH_OFFSET, hash);\n        }\n\n        void setNameLen(int nameLen) {\n            UNSAFE.putInt(slotBase + NAMELEN_OFFSET, nameLen);\n        }\n\n        void setSum(int sum) {\n            UNSAFE.putInt(slotBase + SUM_OFFSET, sum);\n        }\n\n        void setCount(int count) {\n            UNSAFE.putInt(slotBase + COUNT_OFFSET, count);\n        }\n\n        void setMin(short min) {\n            UNSAFE.putShort(slotBase + MIN_OFFSET, min);\n        }\n\n        void setMax(short max) {\n            UNSAFE.putShort(slotBase + MAX_OFFSET, max);\n        }\n\n        void gotoAndObserve(\n                            long hash, long nameStartAddress, int nameLen, long nameWord0, long nameWord1, long lastNameWord,\n                            int temperature) {\n            int tableIndex = (int) (hash & TABLE_INDEX_MASK);\n            while (true) {\n                gotoIndex(tableIndex);\n                if (hash() == hash && nameLen() == nameLen && nameEquals(\n                        nameAddress(), nameStartAddress, nameLen, nameWord0, nameWord1, lastNameWord)) {\n                    observe(temperature);\n                    break;\n                }\n                if (nameLen() != 0) {\n                    tableIndex = (tableIndex + 1) & TABLE_INDEX_MASK;\n                    continue;\n                }\n                initialize(hash, nameLen, nameStartAddress, temperature);\n                break;\n            }\n        }\n\n        void initialize(long hash, long nameLen, long nameStartAddress, int temperature) {\n            setHash(hash);\n            setNameLen((int) nameLen);\n            setSum(temperature);\n            setCount(1);\n            setMin((short) temperature);\n            setMax((short) temperature);\n            UNSAFE.copyMemory(nameStartAddress, nameAddress(), nameLen);\n        }\n\n        void observe(int temperature) {\n            setSum(sum() + temperature);\n            setCount(count() + 1);\n            setMin((short) Integer.min(min(), temperature));\n            setMax((short) Integer.max(max(), temperature));\n        }\n\n        private static boolean nameEquals(\n                                          long statsAddr, long inputAddr, long len, long inputWord1, long inputWord2, long lastInputWord) {\n            boolean mismatch1 = inputWord1 != UNSAFE.getLong(statsAddr);\n            boolean mismatch2 = inputWord2 != UNSAFE.getLong(statsAddr + Long.BYTES);\n            if (len <= 2 * Long.BYTES) {\n                return !(mismatch1 | mismatch2);\n            }\n            int i = 2 * Long.BYTES;\n            for (; i <= len - Long.BYTES; i += Long.BYTES) {\n                if (UNSAFE.getLong(inputAddr + i) != UNSAFE.getLong(statsAddr + i)) {\n                    return false;\n                }\n            }\n            return i == len || lastInputWord == UNSAFE.getLong(statsAddr + i);\n        }\n    }\n\n    private static void mergeSortAndPrint(StationStats[][] results) {\n        var onFirst = true;\n        System.out.print('{');\n        var cursors = new int[results.length];\n        var indexOfMin = 0;\n        StationStats curr = null;\n        int exhaustedCount;\n        while (true) {\n            exhaustedCount = 0;\n            StationStats min = null;\n            for (int i = 0; i < cursors.length; i++) {\n                if (cursors[i] == results[i].length) {\n                    exhaustedCount++;\n                    continue;\n                }\n                StationStats candidate = results[i][cursors[i]];\n                if (min == null || min.compareTo(candidate) > 0) {\n                    indexOfMin = i;\n                    min = candidate;\n                }\n            }\n            if (exhaustedCount == cursors.length) {\n                if (!onFirst) {\n                    System.out.print(\", \");\n                }\n                System.out.print(curr);\n                break;\n            }\n            cursors[indexOfMin]++;\n            if (curr == null) {\n                curr = min;\n            }\n            else if (min.equals(curr)) {\n                curr.sum += min.sum;\n                curr.count += min.count;\n                curr.min = Integer.min(curr.min, min.min);\n                curr.max = Integer.max(curr.max, min.max);\n            }\n            else {\n                if (onFirst) {\n                    onFirst = false;\n                }\n                else {\n                    System.out.print(\", \");\n                }\n                System.out.print(curr);\n                curr = min;\n            }\n        }\n        System.out.println('}');\n    }\n\n    static class StationStats implements Comparable<StationStats> {\n        String name;\n        long sum;\n        int count;\n        int min;\n        int max;\n\n        @Override\n        public String toString() {\n            return String.format(\"%s=%.1f/%.1f/%.1f\", name, min / 10.0, Math.round((double) sum / count) / 10.0, max / 10.0);\n        }\n\n        @Override\n        public boolean equals(Object that) {\n            return that.getClass() == StationStats.class && ((StationStats) that).name.equals(this.name);\n        }\n\n        @Override\n        public int compareTo(StationStats that) {\n            return name.compareTo(that.name);\n        }\n    }\n\n    private static String longToString(long word) {\n        final ByteBuffer buf = ByteBuffer.allocate(8).order(ByteOrder.nativeOrder());\n        buf.clear();\n        buf.putLong(word);\n        return new String(buf.array(), StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_muditsaxena.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.FutureTask;\n\npublic class CalculateAverage_muditsaxena {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    static class TaskRunner<V> implements Callable<V> {\n\n        List<String> inputList;\n        String input;\n\n        TaskRunner(List<String> taskList) {\n            this.inputList = taskList;\n        }\n\n        TaskRunner(String input) {\n            this.input = input;\n        }\n\n        String[] readInput(String inputTask) {\n            StringBuilder stationName = new StringBuilder();\n            String[] values = new String[2];\n            int index = 0;\n            char ch = inputTask.charAt(index);\n            while (ch != ';') {\n                stationName.append(ch);\n                ch = inputTask.charAt(++index);\n            }\n            index++;\n\n            values[0] = stationName.toString();\n            values[1] = inputTask.substring(index);\n\n            return values;\n        }\n\n        @Override\n        public V call() {\n            for (String inputTask : inputList) {\n\n                if (inputTask.isEmpty()) {\n                    continue;\n                }\n\n                String[] values = readInput(inputTask);\n                double value = Double.parseDouble(values[1]);\n                MeasurementAggregator measurementAggregator = map.getOrDefault(values[0], new MeasurementAggregator());\n                measurementAggregator.count += 1;\n                measurementAggregator.sum += value;\n                measurementAggregator.max = Math.max(measurementAggregator.max, value);\n                measurementAggregator.min = Math.min(measurementAggregator.min, value);\n                map.put(values[0], measurementAggregator);\n            }\n            inputList = null;\n            return null;\n        }\n    }\n\n    static ConcurrentMap<String, MeasurementAggregator> map = new ConcurrentHashMap<>();\n    static final int TASK_LIST_CAPACITY = 10000;\n    // 100000 - 1:23\n    // 10000 - 1:10\n    // 1000 - 1:21\n\n    // Optimising split\n    // 10000 - 1:15, 1:12, 1:11\n    // 1000 - 1:18, 1:23\n\n    public static void main(String[] args) throws IOException {\n        try (ExecutorService virtualThreadExecutors = Executors.newVirtualThreadPerTaskExecutor()) {\n\n            List<String> taskList = new ArrayList<>(TASK_LIST_CAPACITY);\n            List<CompletableFuture<Void>> tasks = new ArrayList<>();\n\n            try (BufferedReader br = Files.newBufferedReader(Paths.get(FILE))) {\n                String line = br.readLine();\n                while (line != null) {\n                    taskList.add(line);\n                    if (taskList.size() >= TASK_LIST_CAPACITY) {\n                        tasks.add(CompletableFuture.runAsync(new FutureTask<>(new TaskRunner<>(taskList)), virtualThreadExecutors));\n                        taskList = null;\n                        taskList = new ArrayList<>(TASK_LIST_CAPACITY);\n                    }\n                    line = br.readLine();\n                }\n            }\n\n            if (!taskList.isEmpty()) {\n                tasks.add(CompletableFuture.runAsync(new FutureTask<>(new TaskRunner<>(taskList)), virtualThreadExecutors));\n            }\n\n            for (CompletableFuture<Void> task : tasks) {\n                if (task != null) {\n                    task.join();\n                }\n            }\n\n            Map<String, ResultRow> resultRowMap = new TreeMap<>();\n            map.forEach((key, value) -> resultRowMap.put(key, new ResultRow(value.min, value.sum / value.count, value.max)));\n            System.out.println(resultRowMap);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_naive.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedReader;\nimport java.io.FileNotFoundException;\nimport java.io.FileReader;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_naive {\n\n    record Result(double min, double max, double sum, long count) {\n    }\n\n    public static void main(String[] args) throws FileNotFoundException {\n        long start = System.currentTimeMillis();\n        var results = new BufferedReader(new FileReader(\"./measurements.txt\"))\n                .lines()\n                .map(l -> l.split(\";\"))\n                .collect(Collectors.toMap(\n                        parts -> parts[0],\n                        parts -> {\n                            double temperature = Double.parseDouble(parts[1]);\n                            return new Result(temperature, temperature, temperature, 1);\n                        },\n                        (oldResult, newResult) -> {\n                            double min = Math.min(oldResult.min, newResult.min);\n                            double max = Math.max(oldResult.max, newResult.max);\n                            double sum = oldResult.sum + newResult.sum;\n                            long count = oldResult.count + newResult.count;\n                            return new Result(min, max, sum, count);\n                        }, ConcurrentSkipListMap::new));\n        System.out.println(System.currentTimeMillis() - start);\n        System.out.println(results);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_netrunnereve.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.CountDownLatch;\nimport java.lang.Math;\n\npublic class CalculateAverage_netrunnereve {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int NUM_THREADS = 8; // test machine\n    private static final int LEN_EXTEND = 200; // guarantees a newline\n    private static final int HASHT_SIZE = 16384; // size of hash table, adjust tradeoff between colisions and cache utilization\n    private static final int DJB2_INIT = 5831;\n\n    private static class MeasurementAggregator { // min, max, sum stored as 0.1/unit\n        private MeasurementAggregator next = null; // linked list of entries for handling hash colisions\n        private byte[] station = null;\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum = 0;\n        private int count = 0;\n    }\n\n    private static class ThreadCalcs {\n        private MeasurementAggregator[] hashSpace = null;\n        private String[] staArr = null;\n        private int numStations = 0;\n    }\n\n    // djb2 hash\n    private static int calc_hash(byte[] input, int len) {\n        int hash = DJB2_INIT;\n        for (int i = 0; i < len; i++) {\n            hash = ((hash << 5) + hash) + Byte.toUnsignedInt(input[i]);\n        }\n        return Math.abs(hash % HASHT_SIZE);\n    }\n\n    private static class ThreadedParser extends Thread {\n        private MappedByteBuffer mbuf;\n        private int mbs;\n        private ThreadCalcs[] threadOut;\n        private int threadID;\n        private CountDownLatch tpLatch;\n\n        private ThreadedParser(MappedByteBuffer mbuf, int mbs, ThreadCalcs[] threadOut, int threadID, CountDownLatch tpLatch) {\n            this.mbuf = mbuf;\n            this.mbs = mbs;\n            this.threadOut = threadOut;\n            this.threadID = threadID;\n            this.tpLatch = tpLatch;\n        }\n\n        public void run() {\n            MeasurementAggregator[] hashSpace = new MeasurementAggregator[HASHT_SIZE]; // hash table\n            byte[] scratch = new byte[100]; // <= 100 characters in station name\n            String[] staArr = new String[10000]; // max 10000 station names\n            MeasurementAggregator ma = null;\n\n            int numStations = 0;\n            int negMul = 1;\n            int head = 0;\n            int tempCnt = -1; // 0 if 1 digit measurement, 1 if 2 digit\n            int hash = DJB2_INIT; // do calc_hash manually in loop\n\n            int i = 0; // byte by byte iterator\n            while (true) {\n                byte cur = mbuf.get(i);\n                if (cur == 59) { // ;\n                    hash = Math.abs(hash % HASHT_SIZE);\n\n                    // this is faster than filling scratch immediately after each byte is read\n                    int len = i - head;\n                    mbuf.position(head);\n                    mbuf.get(scratch, 0, len);\n\n                    ma = hashSpace[hash];\n                    MeasurementAggregator prev = null;\n\n                    while (true) {\n                        if (ma == null) {\n                            ma = new MeasurementAggregator();\n                            ma.station = Arrays.copyOfRange(scratch, 0, len);\n                            staArr[numStations] = new String(scratch, 0, len, StandardCharsets.UTF_8);\n\n                            if (prev != null) {\n                                prev.next = ma;\n                            }\n                            else {\n                                hashSpace[hash] = ma;\n                            }\n\n                            numStations++;\n                            break;\n                        }\n                        else if ((len != ma.station.length) || (Arrays.compare(scratch, 0, len, ma.station, 0, len) != 0)) { // hash collision\n                            prev = ma;\n                            ma = ma.next;\n                        }\n                        else { // hit\n                            break;\n                        }\n                    }\n\n                    i++;\n                    while (true) {\n                        cur = mbuf.get(i);\n                        if (cur == 46) { // .\n                            int tempa = (negMul) * ((10 + 90 * tempCnt) * (scratch[0] - 48) + (10 * tempCnt) * (scratch[1] - 48) + (mbuf.get(i + 1) - 48)); // branchless\n\n                            if (tempa < ma.min) {\n                                ma.min = tempa;\n                            }\n                            if (tempa > ma.max) {\n                                ma.max = tempa;\n                            }\n                            ma.sum += tempa;\n                            ma.count++;\n\n                            // this line is finished!\n                            i += 2; // newline char\n                            hash = DJB2_INIT;\n                            negMul = 1;\n                            head = i + 1; // start of next line\n                            tempCnt = -1;\n                            break;\n                        }\n                        else if (cur == 45) { // ascii -\n                            negMul = -1;\n                        }\n                        else {\n                            scratch[tempCnt + 1] = cur;\n                            tempCnt++;\n                        }\n                        i++;\n                    }\n                    if (head >= mbs) {\n                        break;\n                    }\n                }\n                else {\n                    hash = ((hash << 5) + hash) + Byte.toUnsignedInt(cur);\n                }\n                i++;\n            }\n            threadOut[threadID] = new ThreadCalcs();\n            threadOut[threadID].hashSpace = hashSpace;\n            threadOut[threadID].staArr = staArr;\n            threadOut[threadID].numStations = numStations;\n            tpLatch.countDown();\n        }\n    }\n\n    public static void main(String[] args) {\n        try {\n            RandomAccessFile mraf = new RandomAccessFile(FILE, \"r\");\n            long fileSize = mraf.getChannel().size();\n            long threadNum = NUM_THREADS;\n\n            long minThreads = (fileSize / Integer.MAX_VALUE) + 1; // minimum # of threads required due to MappedByteBuffer size limit\n            if (threadNum < minThreads) {\n                threadNum = minThreads;\n            }\n            long bufSize = fileSize / threadNum;\n\n            // don't bother multithreading for small files\n            if (bufSize < 1000000) {\n                threadNum = 1;\n                bufSize = Integer.MAX_VALUE;\n            }\n\n            ThreadCalcs[] threadOut = new ThreadCalcs[(int) threadNum];\n            CountDownLatch tpLatch = new CountDownLatch((int) threadNum);\n            int threadID = 0;\n\n            long h = 0;\n            while (h < fileSize) {\n                long length = bufSize;\n                boolean finished = false;\n\n                if ((h == 0) && (length + LEN_EXTEND < Integer.MAX_VALUE)) { // add a bit of extra bytes to first thread to avoid generating new thread for the remainder\n                    length += LEN_EXTEND; // arbitary bytes to guarantee a newline somewhere\n                }\n                if (h + length > fileSize) { // past the end\n                    length = fileSize - h;\n                    finished = true;\n                }\n\n                MappedByteBuffer mbuf = mraf.getChannel().map(FileChannel.MapMode.READ_ONLY, h, length);\n                int mbs = mbuf.capacity();\n\n                // check for last newline and split there, anything after goes to next buffer\n                if (!finished) {\n                    for (int i = mbs - 1; true; i--) {\n                        byte cur = mbuf.get(i - 1);\n                        if (cur == 10) { // \\n\n                            mbs = i;\n                            break;\n                        }\n                    }\n                }\n\n                ThreadedParser tpThr = new ThreadedParser(mbuf, mbs, threadOut, threadID, tpLatch);\n                tpThr.start();\n\n                h += mbs;\n                threadID++;\n            }\n\n            try {\n                tpLatch.await();\n            }\n            catch (InterruptedException ex) {\n                System.exit(1);\n            }\n\n            // use treemap to sort and uniquify\n            Map<String, Boolean> staMap = new TreeMap<>();\n            for (int i = 0; i < threadID; i++) {\n                for (int j = 0; j < threadOut[i].numStations; j++) {\n                    staMap.put(threadOut[i].staArr[j], false);\n                }\n            }\n\n            boolean started = false;\n            String out = \"{\";\n            for (String i : staMap.keySet()) {\n                if (started) {\n                    out += \", \";\n                }\n                else {\n                    started = true;\n                }\n\n                byte[] strBuf = i.getBytes(StandardCharsets.UTF_8);\n\n                int hash = calc_hash(strBuf, strBuf.length);\n                MeasurementAggregator mSum = new MeasurementAggregator();\n                for (int j = 0; j < threadID; j++) {\n                    MeasurementAggregator ma = threadOut[j].hashSpace[hash];\n\n                    while (true) {\n                        if ((strBuf.length != ma.station.length) || (Arrays.compare(strBuf, ma.station) != 0)) { // hash collision\n                            ma = ma.next;\n                            continue;\n                        }\n                        else { // hit\n                            if (ma.min < mSum.min) {\n                                mSum.min = ma.min;\n                            }\n                            if (ma.max > mSum.max) {\n                                mSum.max = ma.max;\n                            }\n                            mSum.sum += ma.sum;\n                            mSum.count += ma.count;\n                            break;\n                        }\n                    }\n                }\n                double min = Math.round(Double.valueOf(mSum.min)) / 10.0;\n                double avg = Math.round(Double.valueOf(mSum.sum) / Double.valueOf(mSum.count)) / 10.0;\n                double max = Math.round(Double.valueOf(mSum.max)) / 10.0;\n                out += i + \"=\" + min + \"/\" + avg + \"/\" + max;\n            }\n            out += \"}\\n\";\n            System.out.print(out);\n\n            mraf.getChannel().close();\n            mraf.close();\n        }\n        catch (IOException ex) {\n            System.exit(1);\n        }\n        System.exit(0);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_obourgain.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.function.BiConsumer;\nimport java.util.function.Consumer;\n\npublic class CalculateAverage_obourgain {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final boolean USE_UNSAFE = true;\n\n    static class ThreadLocalState {\n        private final OpenAddressingMap resultMap = new OpenAddressingMap();\n        private final byte[] cityNameBuffer = new byte[128];\n    }\n\n    private static final ThreadLocal<ThreadLocalState> THREAD_LOCAL_STATE = ThreadLocal.withInitial(ThreadLocalState::new);\n    public static final int PER_THREAD_MAP_CAPACITY = 65536;\n    public static final int MASK = PER_THREAD_MAP_CAPACITY - 1;\n\n    // needed ony without unsafe\n    // public static final int MOST_SIGNIFICANT_BIT_SET = 0x80808080;\n    // public static final int SUBTRACT_0_FROM_EACH_BYTE_IN_INT = 0x30303030;\n    // private static final ValueLayout.OfInt BIG_ENDIAN_INTEGER_UNALIGNED = ValueLayout.JAVA_INT_UNALIGNED.withOrder(ByteOrder.BIG_ENDIAN);\n\n    private static final Unsafe UNSAFE;\n    private static final int BYTE_ARRAY_OFFSET_BASE;\n    // TODO support big endian archis\n    public static final int MASK_3_BYTES = Integer.reverseBytes(16777215);\n    public static final int MASK_2_BYTES = Integer.reverseBytes(65535);\n\n    static {\n        if (USE_UNSAFE) {\n            try {\n                Field field = Unsafe.class.getDeclaredField(\"theUnsafe\");\n                field.setAccessible(true);\n                UNSAFE = (Unsafe) field.get(null);\n                BYTE_ARRAY_OFFSET_BASE = UNSAFE.arrayBaseOffset(byte[].class);\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n        else {\n            UNSAFE = null;\n            BYTE_ARRAY_OFFSET_BASE = -1;\n        }\n    }\n\n    static class MeasurementAggregator {\n        // deci-Celcius values\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum;\n        private int count;\n\n        public void appendTo(StringBuilder stringBuilder) {\n            // micro optim, never saw the toString on a profile\n            stringBuilder.append(round(min)).append(\"/\").append(round(((double) sum) / count)).append(\"/\").append(round(max));\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n\n        public void reset() {\n            min = Integer.MAX_VALUE;\n            max = Integer.MIN_VALUE;\n            sum = 0;\n            count = 0;\n        }\n\n        void add(int measurementInDeciCelsius) {\n            max = Math.max(max, measurementInDeciCelsius);\n            min = Math.min(min, measurementInDeciCelsius);\n            sum += measurementInDeciCelsius;\n            count++;\n        }\n    }\n\n    record PrintableMeasurement(String key, MeasurementAggregator measurementAggregator) {\n    }\n\n    public static void main(String[] args) throws Exception {\n        // no close, leak everything and let the OS cleanup!\n        var randomAccessFile = new RandomAccessFile(FILE, \"r\");\n        MemorySegment segment = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length(), Arena.global());\n\n        // can we do better to balance across cpu cores?\n        int chunkSize = 20 * 1024 * 1024;\n\n        var mergedResults = new ConcurrentHashMap<KeyWrapper, MeasurementAggregator>(1024);\n\n        // Fork join pool as a lock free queue, it should help putting all threads to work faster\n        try (ExecutorService executor = Executors.newWorkStealingPool()) {\n            // start processing chunks asap, no need for an intermediate list. Finding chunks limits takes about 5ms. Using ForkJoinPool would be fun, but unlikely to yield any measurable gain\n            createChunks(segment, chunkSize, chunk -> {\n                executor.execute(() -> {\n                    ThreadLocalState threadLocalState = THREAD_LOCAL_STATE.get();\n                    processChunk(chunk, threadLocalState);\n                    merge(mergedResults, threadLocalState.resultMap);\n                });\n            });\n            executor.shutdown();\n            boolean shutdownProperly = executor.awaitTermination(1, TimeUnit.MINUTES);\n            if (!shutdownProperly) {\n                throw new RuntimeException(\"did not complete on time\");\n            }\n        }\n\n        // making it over complicated here for the sake of gaining a few milliseconds. In fact, it doesn't matter much and the stupid code would be enough here\n        List<PrintableMeasurement> entries = mergedResults.entrySet().stream()\n                // we have to convert to String to have proper UTF-8 support for the sort\n                .map(entry -> new PrintableMeasurement(new String(entry.getKey().key, StandardCharsets.UTF_8), entry.getValue()))\n                .sorted(Comparator.comparing(PrintableMeasurement::key))\n                .toList();\n\n        // presize the StringBuilder to avoid any copy. With the worst case dataset (10k keys each 100 bytes long etc) it would resize, but I don't care much\n        var sb = new StringBuilder(64 * 1024);\n        sb.append('{');\n        for (int i = 0; i < entries.size(); i++) {\n            printEntry(entries, i, sb);\n        }\n        sb.append('}');\n        System.out.println(sb);\n        // System.out.println(COLLISIONS.get());\n    }\n\n    private static void printEntry(List<PrintableMeasurement> entries, int i, StringBuilder sb) {\n        var entry = entries.get(i);\n        sb.append(entry.key());\n        sb.append('=');\n        entry.measurementAggregator().appendTo(sb);\n        if (i != entries.size() - 1) {\n            sb.append(',').append(' ');\n        }\n    }\n\n    private static void processChunk(MemorySegment segment, ThreadLocalState threadLocalState) {\n        // safe as our segments are in the tens of MB range\n        int size = (int) segment.byteSize();\n        long position = 0;\n\n        while (position < size - 1) {\n            position = processLineInChunk(segment, position, threadLocalState);\n        }\n    }\n\n    private static long processLineInChunk(MemorySegment segment, long position, ThreadLocalState threadLocalState) {\n        // compute hashCode for the city name, copy the bytes to a buffer and search for the semicolon all at once, so we don' t visit the same byte twice\n        // the packing is used to return two ints. The alternative is to return an int and add a mutable field to ThreadLocalState, but that's a bit slower\n        long packed_cityNameLength_hashCode = getCityNameLength(segment, position, threadLocalState);\n        int cityNameLength = (int) (packed_cityNameLength_hashCode >> 32);\n        int hashCode = (int) packed_cityNameLength_hashCode;\n\n        MeasurementAggregator perCityStats = threadLocalState.resultMap.getOrCreate(threadLocalState, cityNameLength, hashCode);\n\n        // I tried packing for decodeDouble, but here it is slower than passing the MeasurementAggregator\n        // + 1 for the semicolon\n        position = decodeDouble(segment, position + cityNameLength + 1, perCityStats);\n        return position;\n    }\n\n    static long getCityNameLength(MemorySegment segment, long position, ThreadLocalState threadLocalState) {\n        long cityNameLength = 0;\n        int cityNameHashCode = 0;\n        byte[] cityNameBuffer = threadLocalState.cityNameBuffer;\n\n        while (true) {\n            // trick: we know that we will have a value after the semicolon which is at least 3 bytes, so we can unroll the loop\n            // adding one for the semicolon, we know we can always read 4 bytes without worrying about reading out of bounds\n            int i = readBigEndianInt(segment, position + cityNameLength);\n\n            // if (USE_UNSAFE) {\n            // put all four bytes at once, we'll use cityNameLength to not read past the actual end of the buffer\n            UNSAFE.putInt(cityNameBuffer, BYTE_ARRAY_OFFSET_BASE + cityNameLength, Integer.reverseBytes(i));\n            // }\n\n            byte b0 = (byte) (i >>> 24);\n            if (b0 == ';') {\n                break;\n            }\n            // if (!USE_UNSAFE) {\n            // cityNameBuffer[cityNameLength] = b0;\n            // }\n\n            byte b1 = (byte) (i >>> 16);\n            if (b1 == ';') {\n                cityNameHashCode = cityNameHashCode * 31 + b0;\n                cityNameLength += 1;\n                break;\n            }\n            // if (!USE_UNSAFE) {\n            // cityNameBuffer[cityNameLength + 1] = b1;\n            // }\n\n            byte b2 = (byte) (i >>> 8);\n            if (b2 == ';') {\n                int masked = i & MASK_2_BYTES;\n                cityNameHashCode = cityNameHashCode * 31 + masked;\n                cityNameLength += 2;\n                break;\n            }\n            // if (!USE_UNSAFE) {\n            // cityNameBuffer[cityNameLength + 2] = b2;\n            // }\n\n            byte b3 = (byte) i;\n            if (b3 == ';') {\n                int masked = i & MASK_3_BYTES;\n                cityNameHashCode = cityNameHashCode * 31 + masked;\n                cityNameLength += 3;\n                break;\n            }\n            // if (!USE_UNSAFE) {\n            // cityNameBuffer[cityNameLength + 3] = b3;\n            // }\n            cityNameHashCode = cityNameHashCode * 31 + i;\n            cityNameLength += 4;\n        }\n        return (cityNameLength << 32) | (cityNameHashCode & 0xffffffffL);\n    }\n\n    private static long decodeDouble(MemorySegment segment, long position, MeasurementAggregator perCityStats) {\n        // values are assumed to be:\n        // * maybe with a minus sign\n        // * an integer part in the range of 0 to 99 included, single digit possible\n        // * always with a single decimal\n        // that's between 3 and 5 bytes\n\n        long offsetFromSign = 0;\n        long offsetFromValue = 0;\n        int signum = 1;\n        // peak at the first byte to see if we have a minus sign\n        byte maybeSign = readByte(segment, position);\n        if (maybeSign == '-') {\n            offsetFromSign++;\n            signum = -1;\n        }\n\n        // as the value is at least 3 bytes then we have a line feed, we can safely read 4 bytes\n        int i = readBigEndianInt(segment, position + offsetFromSign);\n        // keep in deci-Celcius, so we avoid a division for each line, and keep it for the end\n        int tempInDeciCelcius = (byte) (i >>> 24) - '0';\n\n        byte secondDigitOrDot = (byte) (i >>> 16);\n        byte decimalDigit;\n        if (secondDigitOrDot == '.') {\n            decimalDigit = (byte) (i >>> 8);\n            // +1 for the line feed\n            offsetFromValue += 3 + 1;\n        }\n        else {\n            tempInDeciCelcius = 10 * tempInDeciCelcius + (secondDigitOrDot - '0');\n            decimalDigit = (byte) i;\n            // +1 for the line feed\n            offsetFromValue += 4 + 1;\n        }\n        tempInDeciCelcius = 10 * tempInDeciCelcius + (decimalDigit - '0');\n        tempInDeciCelcius *= signum;\n        perCityStats.add(tempInDeciCelcius);\n        return position + offsetFromSign + offsetFromValue;\n    }\n\n    private static int readBigEndianInt(MemorySegment segment, long position) {\n        // I had to comment the code as a static flag isn't enough for max perf, maybe because until the code is JIT-ed it is a lot slower to do the check in a hot loop\n        // if (USE_UNSAFE) {\n        // sadly, Unsafe is faster than reading via the MemorySegment API. For real production code, I would go with the safety of the bound checks, but here I need the boost\n        // Actually, the MemorySegment is a great improvement over unsafe for the developer experience, kudos\n        return Integer.reverseBytes(UNSAFE.getInt(segment.address() + position));\n        // } else {\n        // return segment.get(BIG_ENDIAN_INTEGER_UNALIGNED, position);\n        // }\n    }\n\n    private static byte readByte(MemorySegment segment, long position) {\n        // if (USE_UNSAFE) {\n        return UNSAFE.getByte(segment.address() + position);\n        // } else {\n        // return segment.get(ValueLayout.JAVA_BYTE, position);\n        // }\n    }\n\n    static final class KeyWrapper implements Comparable<KeyWrapper> {\n        private final byte[] key;\n        private final int keyHashCode;\n\n        KeyWrapper(byte[] key, int keyHashCode) {\n            this.key = key;\n            this.keyHashCode = keyHashCode;\n        }\n\n        @Override\n        public int hashCode() {\n            return keyHashCode;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            // I tried making the key field mutable and interning, but that only made performance more variable. Sometime faster, sometime slower\n            var that = (KeyWrapper) obj;\n            return Arrays.equals(this.key, that.key);\n        }\n\n        @Override\n        public int compareTo(KeyWrapper o) {\n            return Arrays.compare(this.key, o.key);\n        }\n\n        @Override\n        public String toString() {\n            return new String(key, StandardCharsets.UTF_8);\n        }\n    }\n\n    private static void merge(ConcurrentHashMap<KeyWrapper, MeasurementAggregator> mergedResults, OpenAddressingMap chunkResult) {\n        chunkResult.forEach((k1, v1) -> {\n            var keyWrapper = new KeyWrapper(k1, Arrays.hashCode(k1));\n            // compute is atomic, so we don't need to synchronize\n            mergedResults.compute(keyWrapper, (k2, v2) -> {\n                if (v2 == null) {\n                    v2 = new MeasurementAggregator();\n                }\n                v2.min = Math.min(v2.min, v1.min);\n                v2.max = Math.max(v2.max, v1.max);\n                v2.sum += v1.sum;\n                v2.count += v1.count;\n                v1.reset();\n                return v2;\n            });\n        });\n    }\n\n    static void createChunks(MemorySegment segment, int chunkSize, Consumer<MemorySegment> onChunkCreated) {\n        long endOfPreviousChunk = 0;\n        while (endOfPreviousChunk < segment.byteSize()) {\n            long chunkStart = endOfPreviousChunk;\n\n            long tmpChunkEnd = Math.min(segment.byteSize() - 1, endOfPreviousChunk + chunkSize);\n            long chunkEnd;\n            if (segment.get(ValueLayout.JAVA_BYTE, tmpChunkEnd) == '\\n') {\n                // we got lucky and our chunk ends on a line break\n                chunkEnd = tmpChunkEnd + 1;\n            }\n            else {\n                // round the chunk to the next line break, included\n                chunkEnd = findNextLineBreak(segment, tmpChunkEnd) + 1;\n            }\n            MemorySegment slice = segment.asSlice(chunkStart, chunkEnd - chunkStart);\n            onChunkCreated.accept(slice);\n            endOfPreviousChunk = chunkEnd;\n        }\n    }\n\n    static long findNextLineBreak(MemorySegment segment, long start) {\n\n        long limit = segment.byteSize();\n        for (long i = start; i < limit; i++) {\n            byte b = segment.get(ValueLayout.JAVA_BYTE, i);\n            if (b == '\\n') {\n                return i;\n            }\n        }\n        return segment.byteSize();\n    }\n\n    static class OpenAddressingMap {\n        private final byte[][] keys;\n        private final MeasurementAggregator[] values;\n        private int size = 0;\n\n        public OpenAddressingMap() {\n            // must be power of 2\n            this.keys = new byte[PER_THREAD_MAP_CAPACITY][];\n            this.values = new MeasurementAggregator[PER_THREAD_MAP_CAPACITY];\n        }\n\n        public void forEach(final BiConsumer<byte[], MeasurementAggregator> consumer) {\n            int remaining = size;\n            for (int i = 1, length = values.length; remaining > 0 && i < length; i++) {\n                MeasurementAggregator value = values[i];\n                if (null != value) {\n                    consumer.accept(keys[i], value);\n                    remaining--;\n                }\n            }\n        }\n\n        public MeasurementAggregator getOrCreate(ThreadLocalState threadLocalState, int cityNameLength, int cityNameHashCode) {\n            // as I mask I lose some bits. Reinject those bit to avoid too many collisions. Maybe expert in hashing can help?\n            cityNameHashCode = (cityNameHashCode >> 16) ^ cityNameHashCode;\n\n            byte[] cityNameBuffer = threadLocalState.cityNameBuffer;\n            int keyIndex = cityNameHashCode & MASK;\n\n            MeasurementAggregator value;\n            while (null != (value = values[keyIndex])) {\n                byte[] existingKey = keys[keyIndex];\n                if (existingKey.length == cityNameLength && arrayEquals(existingKey, cityNameBuffer, (byte) cityNameLength)) {\n                    return value;\n                }\n                // }\n                // COLLISIONS.incrementAndGet();\n                // go to next slot\n                keyIndex = (keyIndex + 1) & MASK;\n            }\n            return create(cityNameLength, cityNameBuffer, keyIndex);\n        }\n\n        private MeasurementAggregator create(int cityNameLength, byte[] cityNameBuffer, int keyIndex) {\n            byte[] key = Arrays.copyOf(cityNameBuffer, cityNameLength);\n            keys[keyIndex] = key;\n            MeasurementAggregator value = new MeasurementAggregator();\n            values[keyIndex] = value;\n            size++;\n            return value;\n        }\n    }\n\n    static final AtomicLong COLLISIONS = new AtomicLong();\n\n    static boolean arrayEquals(byte[] existingKey, byte[] cityNameBuffer, byte length) {\n        int i = 0;\n        while (i != length) {\n            if (length >= 8) {\n                if (UNSAFE.getLong(existingKey, BYTE_ARRAY_OFFSET_BASE + i) != UNSAFE.getLong(cityNameBuffer, BYTE_ARRAY_OFFSET_BASE + i)) {\n                    return false;\n                }\n                else {\n                    i += 8;\n                }\n            }\n            else if (length >= 4) {\n                if (UNSAFE.getInt(existingKey, BYTE_ARRAY_OFFSET_BASE + i) != UNSAFE.getInt(cityNameBuffer, BYTE_ARRAY_OFFSET_BASE + i)) {\n                    return false;\n                }\n                else {\n                    i += 4;\n                }\n            }\n            for (; i < (long) length; ++i) {\n                if (UNSAFE.getByte(existingKey, BYTE_ARRAY_OFFSET_BASE + i) != UNSAFE.getByte(cityNameBuffer, BYTE_ARRAY_OFFSET_BASE + i)) {\n                    return false;\n                }\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_omarchenko4j.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.Executors;\n\npublic class CalculateAverage_omarchenko4j {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();\n    private static final int MAX_LINE_SIZE = 128;\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        try (var file = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            var fileSize = file.size();\n            try (var arena = Arena.ofShared()) {\n                var segment = file.map(MapMode.READ_ONLY, 0, fileSize, arena);\n\n                var tasks = sliceIntoTasks(segment);\n                try (var executor = Executors.newFixedThreadPool(Math.min(tasks.size(), NUMBER_OF_CORES))) {\n                    var futures = executor.invokeAll(tasks);\n\n                    var measurements = new TreeMap<String, Aggregator>(String::compareTo);\n                    for (var future : futures) {\n                        var result = future.get();\n                        for (var entry : result.entrySet()) {\n                            var station = entry.getKey();\n                            var a1 = entry.getValue();\n                            var a2 = measurements.get(station);\n                            if (a2 != null) {\n                                a1.merge(a2);\n                            }\n                            measurements.put(station, a1);\n                        }\n                    }\n                    System.out.println(measurements);\n                }\n            }\n        }\n    }\n\n    private static List<Task> sliceIntoTasks(MemorySegment segment) {\n        var tasks = new ArrayList<Task>(NUMBER_OF_CORES);\n\n        var segmentSize = segment.byteSize();\n        var chunkSize = segmentSize / NUMBER_OF_CORES;\n        if (chunkSize < (long) NUMBER_OF_CORES * MAX_LINE_SIZE) {\n            return List.of(new Task(segment, 0, segmentSize));\n        }\n\n        long offsetStart = 0;\n        for (int coreNumber = 1; coreNumber <= NUMBER_OF_CORES; coreNumber++) {\n            long offsetEnd = chunkSize * coreNumber;\n            while (offsetEnd < segmentSize) {\n                var b = segment.get(ValueLayout.JAVA_BYTE, offsetEnd);\n                offsetEnd++;\n                if (b == '\\n') {\n                    break;\n                }\n            }\n\n            tasks.add(new Task(segment, offsetStart, offsetEnd));\n\n            offsetStart = offsetEnd;\n        }\n\n        return tasks;\n    }\n\n    private static class Task implements Callable<Map<String, Aggregator>> {\n        private static final byte SEPARATOR = ';';\n        private static final byte END_LINE = '\\n';\n\n        private final MemorySegment segment;\n        private final long startOffset;\n        private final long endOffset;\n\n        private Task(MemorySegment segment, long startOffset, long endOffset) {\n            this.segment = segment;\n            this.startOffset = startOffset;\n            this.endOffset = endOffset;\n        }\n\n        @Override\n        public Map<String, Aggregator> call() {\n            var measurements = new HashMap<String, Aggregator>(512);\n\n            int startIndex = 0;\n            int separatorIndex = 0;\n            int endIndex = 0;\n\n            var buffer = new byte[MAX_LINE_SIZE];\n            int bufferIndex = 0;\n\n            for (long offset = startOffset; offset < endOffset; offset++) {\n                var b = segment.get(ValueLayout.JAVA_BYTE, offset);\n                buffer[bufferIndex] = b;\n                bufferIndex++;\n\n                if (b == SEPARATOR) {\n                    separatorIndex = bufferIndex - 1;\n                    continue;\n                }\n                if (b == END_LINE) {\n                    endIndex = bufferIndex - 1;\n\n                    var station = new String(buffer, startIndex, separatorIndex);\n                    var value = getDouble(buffer, separatorIndex + 1, endIndex - separatorIndex - 1);\n                    measurements.computeIfAbsent(station, ignored -> new Aggregator()).addValue(value);\n\n                    bufferIndex = 0;\n                }\n            }\n\n            return measurements;\n        }\n\n        private static final byte MINUS = '-';\n        private static final byte ZERO = '0';\n\n        private double getDouble(byte[] buffer, int offset, int length) {\n            if (length == 4) {\n                if (buffer[offset] == MINUS) {\n                    int value;\n                    value = buffer[offset + 1] - ZERO;\n                    value = (value * 10) + (buffer[offset + 3] - ZERO);\n                    value = -value;\n                    return value * .1D;\n                }\n\n                int value;\n                value = buffer[offset] - ZERO;\n                value = (value * 10) + (buffer[offset + 1] - ZERO);\n                value = (value * 10) + (buffer[offset + 3] - ZERO);\n                return value * .1D;\n            }\n            if (length == 3) {\n                int value;\n                value = buffer[offset] - ZERO;\n                value = (value * 10) + (buffer[offset + 2] - ZERO);\n                return value * .1D;\n            }\n\n            int value;\n            value = buffer[offset + 1] - ZERO;\n            value = (value * 10) + (buffer[offset + 2] - ZERO);\n            value = (value * 10) + (buffer[offset + 4] - ZERO);\n            value = -value;\n            return value * .1D;\n        }\n    }\n\n    public static class Aggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        public void addValue(double value) {\n            min = Math.min(min, value);\n            max = Math.max(max, value);\n            sum += value;\n            count++;\n        }\n\n        public void merge(Aggregator aggregator) {\n            if (aggregator.min < min) {\n                min = aggregator.min;\n            }\n            if (aggregator.max > max) {\n                max = aggregator.max;\n            }\n            sum += aggregator.sum;\n            count += aggregator.count;\n        }\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_padreati.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.StructuredTaskScope;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\n\npublic class CalculateAverage_padreati {\n\n    private static final VectorSpecies<Byte> species = ByteVector.SPECIES_PREFERRED;\n    private static final String FILE = \"./measurements.txt\";\n    private static final int CHUNK_SIZE = 1024 * 1024;\n\n    private record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    private record MeasurementAggregator(double min, double max, double sum, long count) {\n\n        public MeasurementAggregator(double seed) {\n            this(seed, seed, seed, 1);\n        }\n\n        public MeasurementAggregator merge(MeasurementAggregator b) {\n            return new MeasurementAggregator(\n                    Math.min(min, b.min),\n                    Math.max(max, b.max),\n                    sum + b.sum,\n                    count + b.count\n            );\n        }\n\n        public ResultRow toResultRow() {\n            return new ResultRow(min, sum / count, max);\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        new CalculateAverage_padreati().run();\n    }\n\n    private void run() throws IOException {\n        File file = new File(FILE);\n        var splits = findFileSplits();\n        List<StructuredTaskScope.Subtask<Map<String, MeasurementAggregator>>> subtasks = new ArrayList<>();\n        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {\n            for (int i = 0; i < splits.size(); i++) {\n                long splitStart = splits.get(i);\n                long splitEnd = i < splits.size() - 1 ? splits.get(i + 1) : file.length() + 1;\n                subtasks.add(scope.fork(() -> chunkProcessor(file, splitStart, splitEnd)));\n            }\n            scope.join();\n            scope.throwIfFailed();\n\n            var resultList = subtasks.stream().map(StructuredTaskScope.Subtask::get).toList();\n            TreeMap<String, ResultRow> measurements = collapseResults(resultList);\n            System.out.println(measurements);\n\n        }\n        catch (InterruptedException | ExecutionException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private List<Long> findFileSplits() throws IOException {\n        var splits = new ArrayList<Long>();\n        splits.add(0L);\n\n        File file = new File(FILE);\n        long next = CHUNK_SIZE;\n        while (true) {\n            if (next >= file.length()) {\n                break;\n            }\n            try (FileInputStream fis = new FileInputStream(file)) {\n                long skip = fis.skip(next);\n                if (skip != next) {\n                    throw new RuntimeException();\n                }\n                // find first new line\n                while (true) {\n                    int ch = fis.read();\n                    if (ch != '\\n') {\n                        next++;\n                        continue;\n                    }\n                    break;\n                }\n                // skip eventual \\\\r\n                if (fis.read() == '\\r') {\n                    next++;\n                }\n                splits.add(next + 1);\n                next += CHUNK_SIZE;\n            }\n        }\n        return splits;\n    }\n\n    public Map<String, MeasurementAggregator> chunkProcessor(File source, long start, long end) throws IOException {\n        var map = new HashMap<String, MeasurementAggregator>();\n        byte[] buffer = new byte[(int) (end - start)];\n        int len;\n        try (FileInputStream bis = new FileInputStream(source)) {\n            bis.skip(start);\n            len = bis.read(buffer, 0, buffer.length);\n        }\n\n        List<Integer> nlIndexes = new ArrayList<>();\n        List<Integer> commaIndexes = new ArrayList<>();\n\n        int loopBound = species.loopBound(len);\n        int i = 0;\n\n        for (; i < loopBound; i += species.length()) {\n            ByteVector v = ByteVector.fromArray(species, buffer, i);\n            var mask = v.compare(VectorOperators.EQ, '\\n');\n            for (int j = 0; j < species.length(); j++) {\n                if (mask.laneIsSet(j)) {\n                    nlIndexes.add(i + j);\n                }\n            }\n            mask = v.compare(VectorOperators.EQ, ';');\n            for (int j = 0; j < species.length(); j++) {\n                if (mask.laneIsSet(j)) {\n                    commaIndexes.add(i + j);\n                }\n            }\n        }\n        for (; i < len; i++) {\n            if (buffer[i] == '\\n') {\n                nlIndexes.add(i);\n            }\n            if (buffer[i] == ';') {\n                commaIndexes.add(i);\n            }\n        }\n\n        int startLine = 0;\n        for (int j = 0; j < nlIndexes.size(); j++) {\n            int endLine = nlIndexes.get(j);\n            int commaIndex = commaIndexes.get(j);\n            String key = new String(buffer, startLine, commaIndex - startLine);\n            double value = Double.parseDouble(new String(buffer, commaIndex + 1, endLine - commaIndex - 1));\n            map.merge(key, new MeasurementAggregator(value), MeasurementAggregator::merge);\n            startLine = endLine + 1;\n        }\n        return map;\n    }\n\n    private TreeMap<String, ResultRow> collapseResults(List<Map<String, MeasurementAggregator>> resultList) {\n        HashMap<String, MeasurementAggregator> aggregate = new HashMap<>();\n        for (var map : resultList) {\n            for (var entry : map.entrySet()) {\n                aggregate.merge(entry.getKey(), entry.getValue(), MeasurementAggregator::merge);\n            }\n        }\n        TreeMap<String, ResultRow> measurements = new TreeMap<>();\n        for (var entry : aggregate.entrySet()) {\n            measurements.put(entry.getKey(), entry.getValue().toResultRow());\n        }\n        return measurements;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_palmr.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.*;\nimport java.util.stream.Collectors;\nimport java.util.stream.StreamSupport;\n\npublic class CalculateAverage_palmr {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int CHUNK_SIZE = 1024 * 1024 * 10; // Trial and error showed ~10MB to be a good size on our machine\n    private static final int STATION_NAME_BUFFER_SIZE = 128;\n    private static final int THREAD_COUNT = Math.min(8, Runtime.getRuntime().availableProcessors());\n    private static final char SEPARATOR_CHAR = ';';\n    private static final char END_OF_RECORD = '\\n';\n    private static final char MINUS_CHAR = '-';\n    private static final char DECIMAL_POINT_CHAR = '.';\n\n    public static void main(String[] args) throws IOException {\n\n        final var file = new RandomAccessFile(FILE, \"r\");\n        final var channel = file.getChannel();\n\n        final TreeMap<String, MeasurementAggregator> results = StreamSupport.stream(ThreadChunk.chunk(file, THREAD_COUNT), true)\n                .map(chunk -> parseChunk(chunk, channel))\n                .flatMap(bakm -> bakm.getAsUnorderedList().stream())\n                .collect(Collectors.toMap(m -> new String(m.stationNameBytes, StandardCharsets.UTF_8), m -> m, MeasurementAggregator::merge, TreeMap::new));\n        System.out.println(results);\n    }\n\n    private record ThreadChunk(long startPoint, long endPoint, long size) {\n        public static Spliterator<CalculateAverage_palmr.ThreadChunk> chunk(final RandomAccessFile file, final int chunkCount) throws IOException {\n            final var fileSize = file.length();\n            final var idealChunkSize = Math.max(CHUNK_SIZE, fileSize / THREAD_COUNT);\n            final var chunks = new CalculateAverage_palmr.ThreadChunk[chunkCount];\n\n            var validChunks = 0;\n            var startPoint = 0L;\n            for (int i = 0; i < chunkCount; i++) {\n                var endPoint = Math.min(startPoint + idealChunkSize, fileSize);\n                if (startPoint + idealChunkSize < fileSize)\n                {\n                    file.seek(endPoint);\n                    while (endPoint++ < fileSize && file.readByte() != END_OF_RECORD) {\n                        Thread.onSpinWait();\n                    }\n                }\n\n                final var actualSize = endPoint - startPoint;\n                if (actualSize > 1) {\n                    chunks[i] = new CalculateAverage_palmr.ThreadChunk(startPoint, endPoint, actualSize);\n                    startPoint += actualSize;\n                    validChunks++;\n                }\n                else {\n                    break;\n                }\n            }\n\n            return Spliterators.spliterator(chunks, 0, validChunks,\n                    Spliterator.ORDERED |\n                            Spliterator.DISTINCT |\n                            Spliterator.SORTED |\n                            Spliterator.NONNULL |\n                            Spliterator.IMMUTABLE |\n                            Spliterator.CONCURRENT\n            );\n        }\n    }\n\n    private static ByteArrayKeyedMap parseChunk(ThreadChunk chunk, FileChannel channel) {\n        final var state = new State();\n\n        var offset = chunk.startPoint;\n        while (offset < chunk.endPoint) {\n            parseData(channel, state, offset, Math.min(CHUNK_SIZE, chunk.endPoint - offset));\n            offset += CHUNK_SIZE;\n        }\n\n        return state.aggregators;\n    }\n\n    private static void parseData(final FileChannel channel,\n                                  final State state,\n                                  final long offset,\n                                  final long bufferSize) {\n        final ByteBuffer byteBuffer;\n        try {\n            byteBuffer = channel.map(FileChannel.MapMode.READ_ONLY, offset, bufferSize);\n\n            while (byteBuffer.hasRemaining()) {\n                final var currentChar = byteBuffer.get();\n\n                if (currentChar == SEPARATOR_CHAR) {\n                    state.parsingValue = true;\n                }\n                else if (currentChar == END_OF_RECORD) {\n                    if (state.stationPointerEnd != 0) {\n                        final var value = state.measurementValue * state.exponent;\n\n                        MeasurementAggregator aggregator = state.aggregators.computeIfAbsent(state.stationBuffer, state.stationPointerEnd, state.signedHashCode);\n                        aggregator.count++;\n                        aggregator.min = Math.min(aggregator.min, value);\n                        aggregator.max = Math.max(aggregator.max, value);\n                        aggregator.sum += value;\n                    }\n\n                    // reset\n                    state.reset();\n                }\n                else {\n                    if (!state.parsingValue) {\n                        state.stationBuffer[state.stationPointerEnd++] = currentChar;\n                        state.signedHashCode = 31 * state.signedHashCode + (currentChar & 0xff);\n                    }\n                    else {\n                        if (currentChar == MINUS_CHAR) {\n                            state.exponent = -0.1;\n                        }\n                        else if (currentChar != DECIMAL_POINT_CHAR) {\n                            state.measurementValue = state.measurementValue * 10 + (currentChar - '0');\n                        }\n                    }\n                }\n            }\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final class State {\n        ByteArrayKeyedMap aggregators = new ByteArrayKeyedMap();\n        boolean parsingValue = false;\n        byte[] stationBuffer = new byte[STATION_NAME_BUFFER_SIZE];\n        int signedHashCode = 0;\n        int stationPointerEnd = 0;\n        double measurementValue = 0;\n        double exponent = 0.1;\n\n        public void reset() {\n            parsingValue = false;\n            signedHashCode = 0;\n            stationPointerEnd = 0;\n            measurementValue = 0;\n            exponent = 0.1;\n        }\n    }\n\n    private static class MeasurementAggregator {\n        final byte[] stationNameBytes;\n        final int stationNameHashCode;\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        public MeasurementAggregator(final byte[] stationNameBytes, final int stationNameHashCode) {\n            this.stationNameBytes = stationNameBytes;\n            this.stationNameHashCode = stationNameHashCode;\n        }\n\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round(sum / count)}/\\{round(max)}\";\n        }\n\n        private double round(final double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        private MeasurementAggregator merge(final MeasurementAggregator b) {\n            this.count += b.count;\n            this.min = Math.min(this.min, b.min);\n            this.max = Math.max(this.max, b.max);\n            this.sum += b.sum;\n            return this;\n        }\n    }\n\n    /**\n     * Very basic hash table implementation, only implementing computeIfAbsent since that's all the code needs.\n     * It's sized to give minimal collisions with the example test set. this may not hold true if the stations list\n     * changes, but it should still perform fairly well.\n     * It uses Open Addressing, meaning it's just one array, rather Separate Chaining which is what the default java HashMap uses.\n     * IT also uses Linear probing for collision resolution, which given the minimal collision count should hold up well.\n     */\n    private static class ByteArrayKeyedMap {\n        private final int BUCKET_COUNT = 0xFFFF;\n        private final MeasurementAggregator[] buckets = new MeasurementAggregator[BUCKET_COUNT + 1];\n        private final List<MeasurementAggregator> compactUnorderedBuckets = new ArrayList<>(413);\n\n        public MeasurementAggregator computeIfAbsent(final byte[] key, final int keyLength, final int keyHashCode) {\n            var index = keyHashCode & BUCKET_COUNT;\n\n            while (true) {\n                MeasurementAggregator maybe = buckets[index];\n                if (maybe != null) {\n                    if (Arrays.equals(key, 0, keyLength, maybe.stationNameBytes, 0, maybe.stationNameBytes.length)) {\n                        return maybe;\n                    }\n                    index++;\n                    index &= BUCKET_COUNT;\n                }\n                else {\n                    final var copiedKey = Arrays.copyOf(key, keyLength);\n                    MeasurementAggregator measurementAggregator = new MeasurementAggregator(copiedKey, keyHashCode);\n                    buckets[index] = measurementAggregator;\n                    compactUnorderedBuckets.add(measurementAggregator);\n                    return measurementAggregator;\n                }\n            }\n        }\n\n        public List<MeasurementAggregator> getAsUnorderedList() {\n            return compactUnorderedBuckets;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_parkertimmins.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\n\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\n\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\npublic class CalculateAverage_parkertimmins {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    static class OpenHashTable {\n        static class Entry {\n\n            // key always stored as multiple of 32 bytes\n            byte[] key;\n            byte keyLen;\n            short min = Short.MAX_VALUE;\n            short max = Short.MIN_VALUE;\n            long sum = 0;\n            long count = 0;\n\n            void merge(Entry other) {\n                min = (short) Math.min(min, other.min);\n                max = (short) Math.max(max, other.max);\n                sum += other.sum;\n                count += other.count;\n            }\n        }\n\n        static final int bits = 14;\n        static final int tableSize = 1 << bits; // 16k\n        static final int mask = tableSize - 1;\n        final Entry[] entries = new Entry[tableSize];\n\n        void add(byte[] buf, int sLen, short val, int hash) {\n            int idx = hash & mask;\n\n            while (true) {\n                Entry entry = entries[idx];\n\n                // key not present, so add it\n                if (entry == null) {\n                    entry = entries[idx] = new Entry();\n\n                    int rem = sLen % 32;\n                    int arrayLen = rem == 0 ? sLen : sLen + 32 - rem;\n                    entry.key = Arrays.copyOf(buf, arrayLen);\n                    Arrays.fill(entry.key, sLen, arrayLen, (byte) 0);\n                    entry.keyLen = (byte) sLen;\n\n                    entry.min = entry.max = val;\n                    entry.sum += val;\n                    entry.count++;\n                    break;\n                }\n                else {\n                    if (entry.keyLen == sLen && eq(buf, entry.key, entry.keyLen)) {\n                        entry.min = (short) Math.min(entry.min, val);\n                        entry.max = (short) Math.max(entry.max, val);\n                        entry.sum += val;\n                        entry.count++;\n                        break;\n                    }\n                    else {\n                        idx = (idx + 1) & mask;\n                    }\n                }\n            }\n        }\n    }\n\n    static boolean eq(byte[] buf, byte[] entryKey, int sLen) {\n        int needed = sLen;\n        for (int offset = 0; offset <= 96; offset += 32) {\n            var a = ByteVector.fromArray(ByteVector.SPECIES_256, buf, offset);\n            var b = ByteVector.fromArray(ByteVector.SPECIES_256, entryKey, offset);\n            int matches = a.eq(b).not().firstTrue();\n            if (needed <= 32) {\n                return matches >= needed;\n            }\n            else if (matches < 32) {\n                return false;\n            }\n            needed -= 32;\n        }\n        return false;\n    }\n\n    static long findNextEntryStart(MemorySegment ms, long offset) {\n        long curr = offset;\n        while (ms.get(ValueLayout.JAVA_BYTE, curr) != '\\n') {\n            curr++;\n        }\n        curr++;\n        return curr;\n    }\n\n    static short[] digits2s = new short[256];\n    static short[] digits1s = new short[256];\n    static short[] digits0s = new short[256];\n\n    static {\n        for (int i = 0; i < 10; ++i) {\n            digits2s[i + ((int) '0')] = (short) (i * 100);\n            digits1s[i + ((int) '0')] = (short) (i * 10);\n            digits0s[i + ((int) '0')] = (short) i;\n        }\n    }\n\n    static void processRangeScalar(MemorySegment ms, long start, long end, final OpenHashTable localAgg) {\n        byte[] buf = new byte[128];\n\n        long curr = start;\n        long limit = end;\n\n        while (curr < limit) {\n            int i = 0;\n            byte val = ms.get(ValueLayout.JAVA_BYTE, curr);\n            while (val != ';') {\n                buf[i++] = val;\n                curr++;\n                val = ms.get(ValueLayout.JAVA_BYTE, curr);\n            }\n\n            int sLen = i;\n            int hash = hash(buf, sLen);\n\n            curr++; // skip semicolon\n\n            long tempIdx = curr;\n            boolean neg = ms.get(ValueLayout.JAVA_BYTE, tempIdx) == '-';\n            boolean twoDig = ms.get(ValueLayout.JAVA_BYTE, tempIdx + 1 + (neg ? 1 : 0)) == '.';\n            int len = 3 + (neg ? 1 : 0) + (twoDig ? 0 : 1);\n            int d0 = ((char) ms.get(ValueLayout.JAVA_BYTE, tempIdx + len - 1));\n            int d1 = ((char) ms.get(ValueLayout.JAVA_BYTE, tempIdx + len - 3));\n            int d2 = ((char) ms.get(ValueLayout.JAVA_BYTE, tempIdx + len - 4)); // could be - or \\n\n            int base = digits0s[d0] + digits1s[d1] + digits2s[d2];\n            short temp = (short) (neg ? -base : base);\n\n            localAgg.add(buf, sLen, temp, hash);\n            curr = tempIdx + len + 1;\n        }\n    }\n\n    static int hash(byte[] buf, int sLen) {\n        int shift = Math.max(0, 8 - sLen) << 3;\n        long mask = (~0L) >>> shift;\n        long val = ((buf[7] & 0xffL) << 56) | ((buf[6] & 0xffL) << 48) | ((buf[5] & 0xffL) << 40) | ((buf[4] & 0xffL) << 32) | ((buf[3] & 0xffL) << 24)\n                | ((buf[2] & 0xffL) << 16) | ((buf[1] & 0xFFL) << 8) | (buf[0] & 0xffL);\n        val &= mask;\n        // lemire: https://lemire.me/blog/2023/07/14/recognizing-string-prefixes-with-simd-instructions/\n        int hash = (int) (((((val >> 32) ^ val) & 0xffffffffL) * 3523216699L) >> 32);\n        return hash;\n    }\n\n    static void processRangeSIMD(MemorySegment ms, boolean isFirst, boolean isLast, long start, long end, final OpenHashTable localAgg) {\n        byte[] buf = new byte[128];\n\n        long curr = isFirst ? start : findNextEntryStart(ms, start);\n        long limit = isLast ? end - padding : end;\n\n        while (curr < limit) {\n            int nl = 0;\n            for (int offset = 0; offset < 128; offset += 32) {\n                ByteVector section = ByteVector.fromMemorySegment(ByteVector.SPECIES_256, ms, curr + offset, ByteOrder.LITTLE_ENDIAN);\n                section.intoArray(buf, offset);\n                var idx = section.eq((byte) '\\n').firstTrue();\n                if (idx != 32) {\n                    nl = offset + idx;\n                    break;\n                }\n            }\n\n            int nl1 = buf[nl - 1];\n            int nl3 = buf[nl - 3];\n            int nl4 = buf[nl - 4];\n            int nl5 = buf[nl - 5];\n            int base = (nl1 - '0') + 10 * (nl3 - '0') + digits2s[nl4];\n            boolean neg = nl4 == '-' || (nl4 != ';' && nl5 == '-');\n            short temp = (short) (neg ? -base : base);\n            int tempLen = 4 + (neg ? 1 : 0) + (base >= 100 ? 1 : 0);\n            int semi = nl - tempLen;\n\n            int hash = hash(buf, semi);\n            localAgg.add(buf, semi, temp, hash);\n            curr += (nl + 1);\n        }\n\n        // last batch is near end of file, process without SIMD to avoid out-of-bounds\n        if (isLast) {\n            processRangeScalar(ms, curr, end, localAgg);\n        }\n    }\n\n    /**\n     * Combine thread local values\n     */\n    static HashMap<String, OpenHashTable.Entry> mergeAggregations(ArrayList<OpenHashTable> localAggs) {\n        HashMap<String, OpenHashTable.Entry> global = new HashMap<>();\n        for (var agg : localAggs) {\n            for (OpenHashTable.Entry entry : agg.entries) {\n                if (entry == null) {\n                    continue;\n                }\n                String station = new String(entry.key, 0, entry.keyLen, StandardCharsets.UTF_8); // for UTF-8 encoding\n                var currentVal = global.get(station);\n                if (currentVal != null) {\n                    currentVal.merge(entry);\n                }\n                else {\n                    global.put(station, entry);\n                }\n            }\n        }\n        return global;\n    }\n\n    static final int padding = 200; // max entry size is 107ish == 100 (station) + 1 (semicolon) + 5 (temp, eg -99.9) + 1 (newline)\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n        FileChannel channel = file.getChannel();\n\n        int numThreads = Runtime.getRuntime().availableProcessors();\n\n        final long batchSize = 10_000_000;\n\n        final long fileSize = channel.size();\n        // final long batchSize = fileSize / numThreads + 1;\n        final MemorySegment ms = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n        final ArrayList<OpenHashTable> localAggs = new ArrayList<>(numThreads);\n        Thread[] threads = new Thread[numThreads];\n        final AtomicLong progress = new AtomicLong(0);\n\n        class Task implements Runnable {\n            final int threadId;\n\n            Task(int threadId) {\n                this.threadId = threadId;\n            }\n\n            @Override\n            public void run() {\n                var localAgg = localAggs.get(threadId);\n                while (true) {\n                    final long startBatch = progress.getAndAdd(batchSize);\n                    if (startBatch >= fileSize) {\n                        break;\n                    }\n                    final long endBatch = Math.min(startBatch + batchSize, fileSize);\n                    final boolean isFirstBatch = startBatch == 0;\n                    final boolean isLastBatch = endBatch == fileSize;\n                    processRangeSIMD(ms, isFirstBatch, isLastBatch, startBatch, endBatch, localAgg);\n                }\n            }\n        }\n\n        for (int t = 0; t < numThreads; t++) {\n            localAggs.add(new OpenHashTable());\n            threads[t] = new Thread(new Task(t), \"Thread-\" + t);\n            threads[t].start();\n        }\n\n        for (var thread : threads) {\n            thread.join();\n        }\n\n        var globalAggs = mergeAggregations(localAggs);\n\n        Map<String, ResultRow> res = new TreeMap<>();\n        for (Map.Entry<String, OpenHashTable.Entry> entry : globalAggs.entrySet()) {\n            final var ma = entry.getValue();\n            res.put(entry.getKey(), new ResultRow(ma.min / 10.0, (ma.sum / 10.0) / ma.count, ma.max / 10.0));\n        }\n        System.out.println(res);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_pedestrianlove.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentSkipListMap;\nimport java.util.stream.Collector;\n\npublic class CalculateAverage_pedestrianlove {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    public static void main(String[] args) throws IOException {\n\n        Collector<Measurement, MeasurementAggregator, ResultRow> collector = Collector.of(\n                MeasurementAggregator::new,\n                (a, m) -> {\n                    a.min = Math.min(a.min, m.value);\n                    a.max = Math.max(a.max, m.value);\n                    a.sum += m.value;\n                    a.count++;\n                },\n                (agg1, agg2) -> {\n                    var res = new MeasurementAggregator();\n                    res.min = Math.min(agg1.min, agg2.min);\n                    res.max = Math.max(agg1.max, agg2.max);\n                    res.sum = agg1.sum + agg2.sum;\n                    res.count = agg1.count + agg2.count;\n\n                    return res;\n                },\n                agg -> {\n                    return new ResultRow(agg.min, agg.sum / agg.count, agg.max);\n                });\n\n        BufferedReader br = new BufferedReader(new FileReader(FILE));\n\n        Map<String, ResultRow> measurements = new ConcurrentSkipListMap<>(\n                br.lines().parallel()\n                        .map(l -> new Measurement(l.split(\";\")))\n                        .collect(groupingBy(m -> m.station(), collector)));\n\n        br.close();\n\n        System.out.println(measurements);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_phd3.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.*;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_phd3 {\n\n    private static final int NUM_THREADS = Runtime.getRuntime().availableProcessors() * 2;\n    private static final String FILE = \"./measurements.txt\";\n    private static final long FILE_SIZE = new File(FILE).length();\n    // A chunk is a unit for processing, the file will be divided in chunks of the following size\n    private static final int CHUNK_SIZE = 65536 * 1024;\n    // Read a little more data into the buffer to finish processing current line\n    private static final int PADDING = 512;\n    // Minor : Precompute powers to avoid recalculating while parsing doubles (temperatures)\n    private static final double[] POWERS_OF_10 = IntStream.range(0, 6).mapToDouble(x -> Math.pow(10.0, x)).toArray();\n\n    /**\n     * A Utility to print aggregated information in the desired format\n     */\n    private record ResultRow(double min, double mean, double max) {\n\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    public static ResultRow resultRow(AggregationInfo aggregationInfo) {\n        return new ResultRow(aggregationInfo.min, (Math.round(aggregationInfo.sum * 10.0) / 10.0) / (aggregationInfo.count), aggregationInfo.max);\n    }\n\n    public static void main(String[] args) throws Exception {\n        long fileLength = new File(FILE).length();\n        int numChunks = (int) Math.ceil(fileLength * 1.0 / CHUNK_SIZE);\n        ExecutorService executorService = Executors.newFixedThreadPool(NUM_THREADS);\n        BufferDataProvider provider = new RandomAccessBasedProvider(FILE, FILE_SIZE);\n        List<Future<LinearProbingHashMap>> futures = new ArrayList<>();\n        // Process chunks in parallel\n        for (int chunkIndex = 0; chunkIndex < numChunks; chunkIndex++) {\n            futures.add(executorService.submit(new Aggregator(chunkIndex, provider)));\n        }\n\n        executorService.shutdown();\n        executorService.awaitTermination(10, TimeUnit.MINUTES);\n\n        Map<String, AggregationInfo> info = futures.stream().map(f -> {\n            try {\n                return f.get();\n            }\n            catch (ExecutionException | InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        })\n                .map(LinearProbingHashMap::toMap)\n                .flatMap(map -> map.entrySet().stream())\n                .sequential()\n                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, AggregationInfo::update));\n\n        Map<String, ResultRow> measurements = new TreeMap<>(info.entrySet().stream()\n                .collect(toMap(Map.Entry::getKey, e -> resultRow(e.getValue()))));\n\n        System.out.println(measurements);\n    }\n\n    /**\n     * Stores required running aggregation information to be able to compute min/max/average at the end\n     */\n    private static class AggregationInfo {\n        double min = Double.POSITIVE_INFINITY;\n        double max = Double.NEGATIVE_INFINITY;\n        double sum;\n        long count;\n\n        public AggregationInfo update(AggregationInfo update) {\n            this.count += update.count;\n            this.sum += update.sum;\n            if (this.max < update.max) {\n                this.max = update.max;\n            }\n            if (this.min > update.min) {\n                this.min = update.min;\n            }\n            return this;\n        }\n\n        public AggregationInfo update(double value) {\n            this.count++;\n            this.sum += value;\n            if (this.max < value) {\n                this.max = value;\n            }\n            if (this.min > value) {\n                this.min = value;\n            }\n            return this;\n        }\n    }\n\n    private interface BufferDataProvider {\n        int read(byte[] buffer, long offset) throws Exception;\n    }\n\n    /**\n     * uses RandomAccessFile seek and read APIs to load data into a buffer.\n     */\n    private static class RandomAccessBasedProvider implements BufferDataProvider {\n        private final String filePath;\n\n        RandomAccessBasedProvider(String filePath, long fileSize) {\n            this.filePath = filePath;\n        }\n\n        @Override\n        public int read(byte[] buffer, long offset) throws Exception {\n            RandomAccessFile file = null;\n            try {\n                file = new RandomAccessFile(filePath, \"r\");\n                file.seek(offset);\n                return file.read(buffer);\n            }\n            finally {\n                if (file != null) {\n                    file.close();\n                }\n            }\n        }\n    }\n\n    /**\n     * Task to processes a chunk of file and return a custom linear probing hashmap for performance\n     */\n    private static class Aggregator implements Callable<LinearProbingHashMap> {\n        private final long startByte;\n        private final BufferDataProvider dataProvider;\n\n        public Aggregator(long chunkIndex, BufferDataProvider dataProvider) {\n            this.startByte = chunkIndex * CHUNK_SIZE;\n            this.dataProvider = dataProvider;\n        }\n\n        @Override\n        public LinearProbingHashMap call() {\n            try {\n                // offset for the last byte to be processed (excluded)\n                long endByte = Math.min(startByte + CHUNK_SIZE, FILE_SIZE);\n                // read a little more than needed to cover next entry if needed\n                long bufferSize = endByte - startByte + ((endByte == FILE_SIZE) ? 0 : PADDING);\n                byte[] buffer = new byte[(int) bufferSize];\n                int bytes = dataProvider.read(buffer, startByte);\n                // Partial aggregation in a hashmap\n                return processBuffer(buffer, startByte == 0, endByte - startByte);\n            }\n            catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        private static LinearProbingHashMap processBuffer(byte[] buffer, boolean isFileStart, long nextChunkStart) {\n            int start = 0;\n            // Move to the next entry after '\\n'. Don't do this if we're at the start of\n            // the file to avoid missing first entry.\n            if (!isFileStart) {\n                while (buffer[start] != '\\n') {\n                    start++;\n                }\n                start += 1;\n            }\n\n            LinearProbingHashMap chunkLocalMap = new LinearProbingHashMap();\n            while (true) {\n                LineInfo lineInfo = getNextLine(buffer, start);\n                byte[] keyBytes = new byte[lineInfo.semicolonIndex - start];\n                System.arraycopy(buffer, start, keyBytes, 0, keyBytes.length);\n                double value = parseDouble(buffer, lineInfo.semicolonIndex + 1, lineInfo.nextStart - 1);\n                // Update aggregated value for the given key with the new line\n                AggregationInfo info = chunkLocalMap.get(keyBytes, lineInfo.keyHash);\n                info.update(value);\n\n                if ((lineInfo.nextStart > nextChunkStart) || (lineInfo.nextStart >= buffer.length)) {\n                    // we are already at a point where the next line will be processed in the next chunk,\n                    // so the job is done here\n                    break;\n                }\n\n                start = lineInfo.nextStart();\n            }\n            return chunkLocalMap;\n        }\n\n        /**\n         * Converts bytes to double value without intermediate string conversion, faster than Double.parseDouble.\n         */\n        private static double parseDouble(byte[] bytes, int offset, int end) {\n            boolean negative = (bytes[offset] == '-');\n            int current = negative ? offset + 1 : offset;\n            int preFloat = 0;\n            while (current < end && bytes[current] != '.') {\n                preFloat = (preFloat * 10) + (bytes[current++] - '0');\n            }\n            current++;\n            int postFloatStart = current;\n            int postFloat = 0;\n            while (current < end) {\n                postFloat = (postFloat * 10) + (bytes[current++] - '0');\n            }\n\n            return (preFloat + ((postFloat) / POWERS_OF_10[end - postFloatStart])) * (negative ? -1 : 1);\n        }\n\n        /**\n         * Identifies indexes of the next ';' and '\\n', which will be used to get entry key and value from line. Also\n         * computes the hash value for the key while iterating.\n         */\n        private static LineInfo getNextLine(byte[] buffer, int start) {\n            // caller guarantees that the access is in bounds, so no index check\n            int hash = 0;\n            while (buffer[start] != ';') {\n                start++;\n                hash = hash * 31 + buffer[start];\n            }\n            // The following is just to further reduce the probability of collisions\n            hash = hash ^ (hash << 16);\n            int semicolonIndex = start;\n            // caller guarantees that the access is in bounds, so no index check\n            while (buffer[start] != '\\n') {\n                start++;\n            }\n            return new LineInfo(semicolonIndex, start + 1, hash);\n        }\n    }\n\n    private record LineInfo(int semicolonIndex, int nextStart, int keyHash) {\n    }\n\n    /**\n     * A simple map with pre-configured fixed bucket count. With 2^13 buckets and current hash function, seeing 4\n     * collisions which is not too bad. Every bucket is implemented with a linked list. The map is NOT thread safe.\n     */\n    private static class LinearProbingHashMap {\n        private final static int BUCKET_COUNT = 8191;\n        private final Node[] buckets;\n\n        LinearProbingHashMap() {\n            this.buckets = new Node[BUCKET_COUNT];\n        }\n\n        /**\n         * Given a key, returns the current value of AggregationInfo. If not present, creates a new empty node at the\n         * front of the bucket\n         */\n        public AggregationInfo get(byte[] key, int keyHash) {\n            // find bucket index through bitwise AND, works for bucketCount = (2^p - 1)\n            int bucketIndex = BUCKET_COUNT & keyHash;\n            Node current = buckets[bucketIndex];\n            while (current != null) {\n                if (Arrays.equals(current.entry.key(), key)) {\n                    return current.entry.aggregationInfo();\n                }\n                current = current.next;\n            }\n\n            // Entry does not exist, so add a new node in the linked list\n            AggregationInfo newInfo = new AggregationInfo();\n            KeyValuePair pair = new KeyValuePair(key, keyHash, newInfo);\n            Node newNode = new Node(pair, buckets[bucketIndex]);\n            buckets[bucketIndex] = newNode;\n            return newNode.entry.aggregationInfo();\n        }\n\n        /**\n         * A helper to convert to Java's hash map to build the final aggregation after partial aggregations\n         */\n        private Map<String, AggregationInfo> toMap() {\n            Map<String, AggregationInfo> map = new HashMap<>();\n            for (Node bucket : buckets) {\n                while (bucket != null) {\n                    map.put(new String(bucket.entry.key, StandardCharsets.UTF_8), bucket.entry.aggregationInfo());\n                    bucket = bucket.next;\n                }\n            }\n            return map;\n        }\n    }\n\n    /**\n     * Linked List node to implement a bucket of custom hash map\n     */\n    private static class Node {\n        KeyValuePair entry;\n        Node next;\n\n        public Node(KeyValuePair entry, Node next) {\n            this.entry = entry;\n            this.next = next;\n        }\n    }\n\n    /**\n     * a wrapper class to store information needed for storing a measurement information in the hashmap\n     */\n    private record KeyValuePair(byte[] key, int keyHash, AggregationInfo aggregationInfo) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_plbpietrz.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedOutputStream;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.RandomAccessFile;\nimport java.io.UncheckedIOException;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.Charset;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_plbpietrz {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int READ_SIZE = 1024;\n    private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();\n\n    private static class TemperatureStats {\n        double min = 999, max = -999d;\n        double accumulated;\n        int count;\n\n        public void update(double temp) {\n            this.min = Math.min(this.min, temp);\n            this.max = Math.max(this.max, temp);\n            this.accumulated += temp;\n            this.count++;\n        }\n    }\n\n    private record FilePart(long pos, long size) {\n    }\n\n    private static class WeatherStation {\n        private int length;\n        private int nameHash;\n        private byte[] nameBytes;\n        private String string;\n\n        public WeatherStation() {\n            nameBytes = new byte[128];\n        }\n\n        public WeatherStation(WeatherStation station) {\n            this.nameBytes = Arrays.copyOf(station.nameBytes, station.length);\n            this.length = station.length;\n            this.nameHash = station.nameHash;\n        }\n\n        @Override\n        public int hashCode() {\n            return nameHash;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o instanceof WeatherStation s) {\n                return this.nameHash == s.nameHash && Arrays.equals(this.nameBytes, 0, this.length, s.nameBytes, 0, s.length);\n            }\n            return false;\n        }\n\n        @Override\n        public String toString() {\n            if (string == null)\n                string = new String(nameBytes, 0, length, Charset.defaultCharset());\n            return string;\n        }\n\n        public void appendByte(byte b) {\n            string = null;\n            nameBytes[length++] = b;\n            nameHash = nameHash * 31 + b;\n        }\n\n        public void clear() {\n            this.length = 0;\n            this.nameHash = 0;\n            this.string = null;\n        }\n\n    }\n\n    public static void main(String[] args) throws IOException {\n        Path inputFilePath = Path.of(FILE);\n        Map<WeatherStation, TemperatureStats> results;\n        try (RandomAccessFile inputFile = new RandomAccessFile(inputFilePath.toFile(), \"r\")) {\n            var parsedBuffers = partitionInput(inputFile)\n                    .stream()\n                    .parallel()\n                    .map(fp -> getMappedByteBuffer(fp, inputFile))\n                    .map(CalculateAverage_plbpietrz::parseBuffer);\n            results = parsedBuffers.flatMap(m -> m.entrySet().stream())\n                    .collect(\n                            Collectors.groupingBy(\n                                    Map.Entry::getKey,\n                                    Collectors.reducing(\n                                            new TemperatureStats(),\n                                            Map.Entry::getValue,\n                                            CalculateAverage_plbpietrz::mergeTemperatureStats)));\n            try (PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out))) {\n                formatResults(pw, results);\n            }\n        }\n    }\n\n    private static List<FilePart> partitionInput(RandomAccessFile inputFile) throws IOException {\n        List<FilePart> fileParts = new ArrayList<>();\n        long fileLength = inputFile.length();\n\n        long blockSize = Math.min(fileLength, Math.max(READ_SIZE, fileLength / CPU_COUNT));\n\n        for (long start = 0, end; start < fileLength; start = end) {\n            end = findMinBlockOffset(inputFile, start, blockSize);\n            fileParts.add(new FilePart(start, end - start));\n        }\n        return fileParts;\n    }\n\n    private static long findMinBlockOffset(RandomAccessFile file, long startPosition, long minBlockSize) throws IOException {\n        long length = file.length();\n        if (startPosition + minBlockSize < length) {\n            file.seek(startPosition + minBlockSize);\n            while (file.readByte() != '\\n') {\n            }\n            return file.getFilePointer();\n        }\n        else {\n            return length;\n        }\n    }\n\n    private static MappedByteBuffer getMappedByteBuffer(FilePart fp, RandomAccessFile inputFile) {\n        try {\n            return inputFile.getChannel().map(FileChannel.MapMode.READ_ONLY, fp.pos, fp.size);\n        }\n        catch (IOException e) {\n            throw new UncheckedIOException(e);\n        }\n    }\n\n    private static Map<WeatherStation, TemperatureStats> parseBuffer(MappedByteBuffer buffer) {\n        byte[] readLong = new byte[READ_SIZE];\n        byte[] temperature = new byte[32];\n        int temperatureLineLenght = 0;\n\n        int limit = buffer.limit();\n        boolean readingName = true;\n        Map<WeatherStation, TemperatureStats> temperatures = new HashMap<>();\n        WeatherStation station = new WeatherStation();\n\n        int bytesToRead = Math.min(READ_SIZE, limit - buffer.position());\n        while (bytesToRead > 0) {\n            if (bytesToRead == READ_SIZE) {\n                buffer.get(readLong);\n            }\n            else {\n                for (int j = 0; j < bytesToRead; ++j)\n                    readLong[j] = buffer.get();\n            }\n\n            for (int i = 0; i < bytesToRead; ++i) {\n                byte aChar = readLong[i];\n                if (readingName) {\n                    if (aChar != ';') {\n                        if (aChar != '\\n') {\n                            station.appendByte(aChar);\n                        }\n                    }\n                    else {\n                        readingName = false;\n                    }\n                }\n                else {\n                    if (aChar != '\\n') {\n                        temperature[temperatureLineLenght++] = aChar;\n                    }\n                    else {\n                        double temp = parseTemperature(temperature, temperatureLineLenght);\n\n                        if (!temperatures.containsKey(station)) {\n                            temperatures.put(new WeatherStation(station), new TemperatureStats());\n                        }\n                        TemperatureStats weatherStats = temperatures.get(station);\n                        weatherStats.update(temp);\n\n                        station.clear();\n                        temperatureLineLenght = 0;\n                        readingName = true;\n                    }\n                }\n            }\n\n            bytesToRead = Math.min(READ_SIZE, limit - buffer.position());\n        }\n        return temperatures;\n    }\n\n    private static double parseTemperature(byte[] temperature, int temperatureSize) {\n        double sign = 1;\n        double manitssa = 0;\n        double exponent = 1;\n        for (int i = 0; i < temperatureSize; ++i) {\n            byte c = temperature[i];\n            switch (c) {\n                case '-':\n                    sign = -1;\n                    break;\n                case '.':\n                    for (int j = i; j < temperatureSize - 1; ++j)\n                        exponent *= 0.1;\n                    break;\n                default:\n                    manitssa = manitssa * 10 + (c - 48);\n            }\n        }\n        return sign * manitssa * exponent;\n    }\n\n    private static TemperatureStats mergeTemperatureStats(TemperatureStats v1, TemperatureStats v2) {\n        TemperatureStats acc = new TemperatureStats();\n        acc.min = Math.min(v1.min, v2.min);\n        acc.max = Math.max(v1.max, v2.max);\n        acc.accumulated = v1.accumulated + v2.accumulated;\n        acc.count = v1.count + v2.count;\n        return acc;\n    }\n\n    private static void formatResults(PrintWriter pw, Map<WeatherStation, TemperatureStats> resultsMap) {\n        pw.print('{');\n        var results = new ArrayList<>(resultsMap.entrySet());\n        results.sort(Comparator.comparing(e -> e.getKey().toString()));\n        var iterator = results.iterator();\n        while (iterator.hasNext()) {\n            var entry = iterator.next();\n            TemperatureStats stats = entry.getValue();\n            pw.printf(\"%s=%.1f/%.1f/%.1f\",\n                    entry.getKey(),\n                    stats.min,\n                    stats.accumulated / stats.count,\n                    stats.max);\n            if ((iterator.hasNext()))\n                pw.print(\", \");\n        }\n        pw.println('}');\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_plevart.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Comparator;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\nimport java.util.stream.Stream;\n\npublic class CalculateAverage_plevart {\n    private static final Path FILE = Path.of(\"measurements.txt\");\n\n    private static final int MAX_CITY_LEN = 100;\n    // 100 (city name) + 1 (;) + 5 (-99.9) + 1 (NL)\n    private static final int MAX_LINE_LEN = MAX_CITY_LEN + 7;\n\n    private static final int INITIAL_TABLE_CAPACITY = 8192;\n\n    public static void main(String[] args) throws IOException {\n        System.setProperty(\"jdk.incubator.vector.VECTOR_ACCESS_OOB_CHECK\", \"0\");\n        try (\n                var channel = (FileChannel) Files.newByteChannel(FILE, StandardOpenOption.READ);\n                var arena = Arena.ofShared()) {\n            var segment = channel.map(FileChannel.MapMode.READ_ONLY, 0, Files.size(FILE), arena);\n            int regions = Runtime.getRuntime().availableProcessors();\n            IntStream\n                    .range(0, regions)\n                    .parallel()\n                    .mapToObj(r -> calculateRegion(segment, regions, r))\n                    .reduce(StatsTable::reduce)\n                    .ifPresent(System.out::println);\n        }\n    }\n\n    private static StatsTable calculateRegion(MemorySegment segment, int regions, int r) {\n        long start = (segment.byteSize() * r) / regions;\n        long end = (segment.byteSize() * (r + 1)) / regions;\n        if (r > 0) {\n            start = skipPastNl(segment, start);\n        }\n        if (r + 1 < regions) {\n            end = skipPastNl(segment, end);\n        }\n\n        return calculateAdjustedRegion(segment, start, end);\n    }\n\n    private static long skipPastNl(MemorySegment segment, long i) {\n        int skipped = 0;\n        while (skipped++ < MAX_LINE_LEN && segment.get(ValueLayout.JAVA_BYTE, i++) != '\\n') {\n        }\n        if (skipped > MAX_LINE_LEN) {\n            throw new IllegalArgumentException(\n                    \"Encountered line that exceeds \" + MAX_LINE_LEN + \" bytes at offset: \" + i);\n        }\n        return i;\n    }\n\n    private static StatsTable calculateAdjustedRegion(MemorySegment segment, long start, long end) {\n        var stats = new StatsTable(segment, INITIAL_TABLE_CAPACITY);\n\n        var species = ByteVector.SPECIES_PREFERRED;\n\n        long cityStart = start, numberStart = 0;\n        int cityLen = 0;\n\n        for (long i = start, j = i; i < end; j = i) {\n            long semiNlSet;\n            if (end - i >= species.vectorByteSize()) {\n                var vec = ByteVector.fromMemorySegment(species, segment, i, ByteOrder.nativeOrder());\n                semiNlSet = vec.compare(VectorOperators.EQ, (byte) ';')\n                        .or(vec.compare(VectorOperators.EQ, (byte) '\\n'))\n                        .toLong();\n                i += species.vectorByteSize();\n            }\n            else { // tail, smaller than speciesByteSize\n                semiNlSet = 0;\n                long mask = 1;\n                while (i < end && mask != 0) {\n                    int c = segment.get(ValueLayout.JAVA_BYTE, i++);\n                    if (c == '\\n' || c == ';') {\n                        semiNlSet |= mask;\n                    }\n                    mask <<= 1;\n                }\n            }\n\n            for (int step = Long.numberOfTrailingZeros(semiNlSet); step < 64; semiNlSet >>>= (step + 1), step = Long.numberOfTrailingZeros(semiNlSet)) {\n                j += step;\n                if (numberStart == 0) { // semi\n                    cityLen = (int) (j - cityStart);\n                    numberStart = ++j;\n                }\n                else { // nl\n                    int numberLen = (int) (j - numberStart);\n                    stats.calculateEntry(cityStart, cityLen, numberStart, numberLen);\n                    cityStart = ++j;\n                    numberStart = 0;\n                }\n            }\n        }\n\n        return stats;\n    }\n\n    final static class StatsTable {\n        private static final int LOAD_FACTOR = 16;\n        // offsets of fields\n        private static final int _lenHash = 0,\n                _off = 1,\n                _count = 2,\n                _sum = 3,\n                _min = 4,\n                _max = 5;\n        private final MemorySegment segment;\n        private int pow2cap, loadedSize;\n        private long[] table;\n\n        StatsTable(MemorySegment segment, int capacity) {\n            this.segment = Objects.requireNonNull(segment);\n            int pow2cap = Integer.highestOneBit(capacity);\n            if (pow2cap < capacity) {\n                pow2cap <<= 1;\n            }\n            this.pow2cap = pow2cap;\n            this.table = new long[idx(pow2cap)];\n        }\n\n        private StatsTable(StatsTable st) {\n            this.segment = st.segment;\n            this.pow2cap = st.pow2cap;\n            this.loadedSize = st.loadedSize;\n            this.table = st.table;\n        }\n\n        private static int idx(int i) {\n            return i << 3;\n        }\n\n        private static long lenHash(int len, int hash) {\n            return ((long) len << 32) | ((long) hash & 0x00000000FFFFFFFFL);\n        }\n\n        private static int len(long lenHash) {\n            return (int) (lenHash >>> 32);\n        }\n\n        private static int hash(long lenHash) {\n            return (int) (lenHash & 0x00000000FFFFFFFFL);\n        }\n\n        private static final long[] LEN_LONG_MASK;\n        private static final int[] LEN_INT_MASK;\n\n        static {\n            LEN_LONG_MASK = new long[Long.BYTES + 1];\n            for (int len = 0; len <= Long.BYTES; len++) {\n                LEN_LONG_MASK[len] = len == 0\n                        ? 0L\n                        : ValueLayout.JAVA_LONG_UNALIGNED.order() == ByteOrder.LITTLE_ENDIAN\n                                ? -1L >>> ((Long.BYTES - len) * Byte.SIZE)\n                                : -1L << ((Long.BYTES - len) * Byte.SIZE);\n            }\n            LEN_INT_MASK = new int[Integer.BYTES + 1];\n            for (int len = 0; len <= Integer.BYTES; len++) {\n                LEN_INT_MASK[len] = len == 0\n                        ? 0\n                        : ValueLayout.JAVA_LONG_UNALIGNED.order() == ByteOrder.LITTLE_ENDIAN\n                                ? -1 >>> ((Integer.BYTES - len) * Byte.SIZE)\n                                : -1 << ((Integer.BYTES - len) * Byte.SIZE);\n            }\n        }\n\n        void calculateEntry(long cityStart, int cityLen, long numberStart, int numberLen) {\n            int hash = hash(cityStart, cityLen);\n            int number = parseNumber(numberStart, numberLen);\n            aggregate(cityStart, cityLen, hash, 1, number, number, number);\n        }\n\n        int parseNumber(long off, int len) {\n            int c0 = segment.get(ValueLayout.JAVA_BYTE, off);\n            int d0;\n            int sign;\n            if (c0 == '-') {\n                off++;\n                len--;\n                d0 = segment.get(ValueLayout.JAVA_BYTE, off) - '0';\n                sign = -1;\n            } else {\n                d0 = c0 - '0';\n                sign = 1;\n            }\n            return sign * switch (len) {\n                case 1 -> d0 * 10;                  // 9\n                case 2 -> {\n                    int d1 = segment.get(ValueLayout.JAVA_BYTE, off + 1) - '0';\n                    yield d0 * 100 + d1 * 10;       // 99\n                }\n                case 3 -> {\n                    int d2 = segment.get(ValueLayout.JAVA_BYTE, off + 2) - '0';\n                    yield d0 * 10 + d2;             // 9.9\n                }\n                case 4 -> {\n                    int d1 = segment.get(ValueLayout.JAVA_BYTE, off + 1) - '0';\n                    int d3 = segment.get(ValueLayout.JAVA_BYTE, off + 3) - '0';\n                    yield d0 * 100 + d1 * 10 + d3;  // 99.9\n                }\n                default ->\n                    throw new IllegalArgumentException(\n                        \"Invalid number: \" +\n                        new String(segment.asSlice(off, len).toArray(ValueLayout.JAVA_BYTE), StandardCharsets.UTF_8)\n                    );\n            };\n        }\n\n        int hash(long off, int len) {\n            if (len > Integer.BYTES) {\n                int head = segment.get(ValueLayout.JAVA_INT_UNALIGNED, off);\n                int tail = segment.get(ValueLayout.JAVA_INT_UNALIGNED, off + len - Integer.BYTES);\n                return (head * 31) ^ tail;\n            }\n            else {\n                // assert len >= 0 && len <= 4;\n                // each city name starts at least 4 bytes before segment end\n                // assert off + Integer.BYTES <= segment.byteSize();\n                return segment.get(ValueLayout.JAVA_INT_UNALIGNED, off) & LEN_INT_MASK[len];\n            }\n        }\n\n        private static boolean bothLessThan(long a, long b, long threshold) {\n            return (a < threshold) && (b < threshold);\n        }\n\n        boolean equals(long off1, long off2, int len) {\n            while (len >= Long.BYTES) {\n                if (segment.get(ValueLayout.JAVA_LONG_UNALIGNED, off1) != segment.get(ValueLayout.JAVA_LONG_UNALIGNED, off2)) {\n                    return false;\n                }\n                off1 += Long.BYTES;\n                off2 += Long.BYTES;\n                len -= Long.BYTES;\n            }\n            // still enough memory to compare two longs, but masked?\n            if (bothLessThan(off1, off2, segment.byteSize() - Long.BYTES + 1)) {\n                long mask = LEN_LONG_MASK[len];\n                return (segment.get(ValueLayout.JAVA_LONG_UNALIGNED, off1) & mask) == (segment.get(ValueLayout.JAVA_LONG_UNALIGNED, off2) & mask);\n            }\n            else {\n                return equalsAtBorder(off1, off2, len);\n            }\n        }\n\n        private boolean equalsAtBorder(long off1, long off2, int len) {\n            if (len > Integer.BYTES) {\n                if (segment.get(ValueLayout.JAVA_INT_UNALIGNED, off1) != segment.get(ValueLayout.JAVA_INT_UNALIGNED, off2)) {\n                    return false;\n                }\n                len -= Integer.BYTES;\n                off1 += Integer.BYTES;\n                off2 += Integer.BYTES;\n            }\n            // assert len >= 0 && len <= 4;\n            // each city name starts at least 4 bytes before segment end\n            // assert Math.max(off1, off2) + Integer.BYTES <= segment.byteSize();\n            int mask = LEN_INT_MASK[len];\n            return (segment.get(ValueLayout.JAVA_INT_UNALIGNED, off1) & mask) == (segment.get(ValueLayout.JAVA_INT_UNALIGNED, off2) & mask);\n        }\n\n        void aggregate(\n                       // key\n                       long off, int len, int hash,\n                       // value\n                       long count, long sum, int min, int max) {\n            long lenHash = lenHash(len, hash);\n            int mask = pow2cap - 1;\n            for (int i = hash & mask, probe = 0; probe < pow2cap; i = (i + 1) & mask, probe++) {\n                int idx = idx(i);\n                long lenHash_i = table[idx + _lenHash];\n                if (lenHash_i == 0) {\n                    table[idx + _lenHash] = lenHash;\n                    table[idx + _off] = off;\n                    table[idx + _count] = count;\n                    table[idx + _sum] = sum;\n                    table[idx + _min] = min;\n                    table[idx + _max] = max;\n                    loadedSize += LOAD_FACTOR;\n                    if (loadedSize >= pow2cap) {\n                        grow();\n                    }\n                    return;\n                }\n                if (lenHash_i == lenHash && equals(off, table[idx + _off], len)) {\n                    table[idx + _count] += count;\n                    table[idx + _sum] += sum;\n                    table[idx + _min] = Math.min(min, (int) table[idx + _min]);\n                    table[idx + _max] = Math.max(max, (int) table[idx + _max]);\n                    return;\n                }\n            }\n            throw new OutOfMemoryError(\"StatsTable capacity exceeded due to poor hash\");\n        }\n\n        private void grow() {\n            if (idx(pow2cap) >= 0x4000_0000) {\n                throw new OutOfMemoryError(\"StatsTable capacity exceeded\");\n            }\n            else {\n                var oldStats = new StatsTable(this);\n                pow2cap <<= 1;\n                table = new long[idx(pow2cap)];\n                loadedSize = 0;\n                reduce(oldStats);\n            }\n        }\n\n        StatsTable reduce(StatsTable other) {\n            other\n                    .idxStream()\n                    .forEach(\n                            idx -> aggregate(\n                                    other.table[idx + _off],\n                                    len(other.table[idx + _lenHash]),\n                                    hash(other.table[idx + _lenHash]),\n                                    other.table[idx + _count],\n                                    other.table[idx + _sum],\n                                    (int) other.table[idx + _min],\n                                    (int) other.table[idx + _max]));\n            return this;\n        }\n\n        IntStream idxStream() {\n            return IntStream\n                    .range(0, pow2cap)\n                    .map(StatsTable::idx)\n                    .filter(idx -> table[idx + _lenHash] != 0);\n        }\n\n        Stream<Entry> stream() {\n            return idxStream()\n                    .mapToObj(\n                            idx -> new Entry(\n                                    new String(\n                                            segment\n                                                    .asSlice(table[idx + _off], len(table[idx + _lenHash]))\n                                                    .toArray(ValueLayout.JAVA_BYTE),\n                                            StandardCharsets.UTF_8),\n                                    table[idx + _count],\n                                    table[idx + _sum],\n                                    table[idx + _min],\n                                    table[idx + _max]));\n        }\n\n        @Override\n        public String toString() {\n            return stream()\n                    .sorted(Comparator.comparing(StatsTable.Entry::city))\n                    .map(Entry::toString)\n                    .collect(Collectors.joining(\", \", \"{\", \"}\"));\n        }\n\n        record Entry(String city, long count, long sum, long min, long max) {\n            double average() {\n                return count > 0L ? (double) sum / (double) count : 0d;\n            }\n\n            @Override\n            public String toString() {\n                return String.format(\n                    \"%s=%.1f/%.1f/%.1f\",\n                    city(), (double) min() / 10d, average() / 10d, (double) max() / 10d\n                );\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_raipc.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.lang.invoke.MethodHandle;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.invoke.MethodType;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Comparator;\nimport java.util.concurrent.RecursiveTask;\n\npublic class CalculateAverage_raipc {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int BUFFER_SIZE = 16 * 1024;\n\n    private static final class AggregatedMeasurement {\n        final ByteArrayWrapper station;\n        private String stationStringCached;\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private int count;\n        private long sum;\n\n        private AggregatedMeasurement(ByteArrayWrapper station) {\n            this.station = station;\n        }\n\n        public String station() {\n            String s = this.stationStringCached;\n            if (s == null) {\n                this.stationStringCached = s = station.toString();\n            }\n            return s;\n        }\n\n        public AggregatedMeasurement merge(AggregatedMeasurement other) {\n            this.min = Math.min(this.min, other.min);\n            this.max = Math.max(this.max, other.max);\n            this.sum += other.sum;\n            this.count += other.count;\n            return this;\n        }\n\n        public void add(int value) {\n            this.min = Math.min(this.min, value);\n            this.max = Math.max(this.max, value);\n            this.sum += value;\n            this.count++;\n        }\n\n        public void format(StringBuilder out) {\n            out.append(station()).append('=')\n                    .append(min / 10.0).append('/')\n                    .append(Math.round(1.0 * sum / count) / 10.0).append('/')\n                    .append(max / 10.0);\n        }\n    }\n\n    public static void main(String[] args) throws InterruptedException {\n        File inputFile = new File(FILE);\n        ParsingTask parsingTask = new ParsingTask(inputFile, 0, inputFile.length());\n        AggregatedMeasurement[] results = parsingTask.fork().join().toArray();\n        System.out.println(formatResult(results));\n    }\n\n    private static String formatResult(AggregatedMeasurement[] result) {\n        Arrays.sort(result, Comparator.comparing(AggregatedMeasurement::station));\n        StringBuilder out = new StringBuilder().append('{');\n        for (AggregatedMeasurement item : result) {\n            item.format(out);\n            out.append(\", \");\n        }\n        if (out.length() > 2) {\n            out.setLength(out.length() - 2);\n        }\n        return out.append('}').toString();\n    }\n\n    private static class ParsingTask extends RecursiveTask<MyHashMap> {\n        private static final int SPLIT_FACTOR = 4;\n        private static final int MIN_TASK_SIZE = 256 * 1024;\n        private final File file;\n        private final long startPosition;\n        private final long endPosition;\n\n        private ParsingTask(File file, long startPosition, long endPosition) {\n            this.file = file;\n            this.startPosition = startPosition;\n            this.endPosition = endPosition;\n        }\n\n        @Override\n        protected MyHashMap compute() {\n            long size = endPosition - startPosition;\n            if (size <= MIN_TASK_SIZE || size < file.length() / Runtime.getRuntime().availableProcessors() / SPLIT_FACTOR) {\n                return doCompute();\n            }\n            var firstHalf = new ParsingTask(file, startPosition, (startPosition + endPosition) / 2).fork();\n            var secondHalf = new ParsingTask(file, (startPosition + endPosition) / 2, endPosition).fork();\n            var firstHalfResults = firstHalf.join();\n            var secondHalfResults = secondHalf.join();\n            firstHalfResults.merge(secondHalfResults);\n            return firstHalfResults;\n        }\n\n        private MyHashMap doCompute() {\n            try (RandomAccessFile raf = new RandomAccessFile(file, \"r\")) {\n                return new ParsingRoutine(startPosition, endPosition).parse(raf);\n            }\n            catch (IOException e) {\n                throw new UncheckedIOException(e);\n            }\n        }\n    }\n\n    private static class ParsingRoutine {\n        private final MyHashMap result = new MyHashMap(2048);\n        private final byte[] partialContentBuff = new byte[128];\n        private final ByteArrayWrapper reusableWrapper = new ByteArrayWrapper(partialContentBuff, 0, 0, 0);\n        private int partialSize;\n        private final long startPosition;\n        private final long endPosition;\n\n        private ParsingRoutine(long startPosition, long endPosition) {\n            this.startPosition = startPosition;\n            this.endPosition = endPosition;\n        }\n\n        private boolean hasPartialContent() {\n            return partialSize > 0;\n        }\n\n        MyHashMap parse(RandomAccessFile raf) throws IOException {\n            byte[] buffer = new byte[BUFFER_SIZE];\n            long offset = findStartOffset(raf, buffer);\n            boolean readMore = offset <= endPosition;\n            while (readMore) {\n                raf.seek(offset);\n                int length = raf.read(buffer);\n                if (length == -1) {\n                    break;\n                }\n                int bufStart = 0;\n                if (hasPartialContent()) {\n                    int idxOfLf = indexOf(buffer, '\\n', 0, length);\n                    if (idxOfLf >= 0) {\n                        bufStart = idxOfLf + 1;\n                        System.arraycopy(buffer, 0, partialContentBuff, partialSize, bufStart);\n                        int toProcess = partialSize + bufStart;\n                        partialSize = 0;\n                        processPart(offset - toProcess, partialContentBuff, 0, toProcess);\n                    }\n                    else {\n                        System.arraycopy(buffer, 0, partialContentBuff, partialSize, bufStart);\n                        offset += length;\n                        continue;\n                    }\n                }\n                readMore = processPart(offset, buffer, bufStart, length);\n                offset += length;\n            }\n            return result;\n        }\n\n        long findStartOffset(RandomAccessFile raf, byte[] buffer) throws IOException {\n            if (startPosition == 0) {\n                return 0;\n            }\n            long offset = startPosition - 1;\n            int length = 0;\n            int idxOfLf = -1;\n            while (offset < endPosition) {\n                raf.seek(offset);\n                length = raf.read(buffer);\n                if (length == -1) {\n                    throw new IllegalStateException(\"No content read on position \" + offset);\n                }\n                offset += length;\n                idxOfLf = indexOf(buffer, '\\n', 0, length);\n                if (idxOfLf >= 0) {\n                    break;\n                }\n            }\n            if (offset > startPosition) {\n                int start = idxOfLf + 1;\n                processPart(offset + start - length, buffer, start, length);\n            }\n            return offset;\n        }\n\n        boolean processPart(long position, byte[] buf, int start, int end) {\n            ByteArrayWrapper key = reusableWrapper;\n            key.content = buf;\n            while (position <= endPosition) {\n                int idxOfSemicolon = indexOf(buf, ';', start, end);\n                if (idxOfSemicolon >= 0) {\n                    int idxOfLf = indexOf(buf, '\\n', idxOfSemicolon + 2, Math.max(idxOfSemicolon + 2, end));\n                    if (idxOfLf >= 0) {\n                        key.start = start;\n                        key.length = idxOfSemicolon - start;\n                        var aggregatedMeasurement = result.getOrCreate(key);\n                        aggregatedMeasurement.add(parseInt(buf, idxOfSemicolon + 1, idxOfLf - 1));\n                        int prevStart = start;\n                        start = idxOfLf + 1;\n                        position += start - prevStart;\n                        continue;\n                    }\n                }\n                partialSize = end - start;\n                if (partialSize > 0) {\n                    System.arraycopy(buf, start, partialContentBuff, 0, partialSize);\n                }\n                break;\n            }\n            return hasPartialContent() || position < endPosition;\n        }\n\n        private int parseInt(byte[] buf, int from, int toIncl) {\n            int mul = 1;\n            if (buf[from] == '-') {\n                mul = -1;\n                ++from;\n            }\n            int res = buf[toIncl] - '0';\n            int dec = 10;\n            for (int i = toIncl - 2; i >= from; --i) {\n                res += (buf[i] - '0') * dec;\n                dec *= 10;\n            }\n            return mul * res;\n        }\n    }\n\n    private static final MethodHandle indexOfMH;\n    private static final MethodHandle vectorizedHashCodeMH;\n    private static final MethodHandle mismatchMH;\n\n    static {\n        try {\n            Class<?> stringLatin1 = Class.forName(\"java.lang.StringLatin1\");\n            var lookup = MethodHandles.privateLookupIn(stringLatin1, MethodHandles.lookup());\n            // int indexOf(byte[] value, int ch, int fromIndex, int toIndex)\n            indexOfMH = lookup.findStatic(stringLatin1, \"indexOf\",\n                    MethodType.methodType(int.class, byte[].class, int.class, int.class, int.class));\n\n            Class<?> arraysSupport = Class.forName(\"jdk.internal.util.ArraysSupport\");\n            lookup = MethodHandles.privateLookupIn(arraysSupport, MethodHandles.lookup());\n            // int vectorizedHashCode(Object array, int fromIndex, int length, int initialValue, int basicType)\n            vectorizedHashCodeMH = lookup.findStatic(arraysSupport, \"vectorizedHashCode\",\n                    MethodType.methodType(int.class, Object.class, int.class, int.class, int.class, int.class));\n            lookup = MethodHandles.privateLookupIn(arraysSupport, MethodHandles.lookup());\n            // int mismatch(byte[] a, int aFromIndex, byte[] b, int bFromIndex, int length)\n            mismatchMH = lookup.findStatic(arraysSupport, \"mismatch\",\n                    MethodType.methodType(int.class, byte[].class, int.class, byte[].class, int.class, int.class));\n        }\n        catch (Exception e) {\n            throw new Error(e);\n        }\n    }\n\n    static int indexOf(byte[] src, int ch, int fromIndex, int toIndex) {\n        try {\n            return (int) indexOfMH.invoke(src, ch, fromIndex, toIndex);\n        }\n        catch (Throwable e) {\n            throw new Error(e);\n        }\n    }\n\n    static int vectorizedHashCode(byte[] array, int fromIndex, int length) {\n        try {\n            return (int) vectorizedHashCodeMH.invoke((Object) array, fromIndex, length, 0, 8);\n        }\n        catch (Throwable e) {\n            throw new Error(e);\n        }\n    }\n\n    static boolean arraysEqual(byte[] a, int aFromIndex, byte[] b, int bFromIndex, int length) {\n        try {\n            return ((int) mismatchMH.invoke(a, aFromIndex, b, bFromIndex, length)) < 0;\n        }\n        catch (Throwable e) {\n            throw new Error(e);\n        }\n    }\n\n    private static class ByteArrayWrapper {\n        private byte[] content;\n        private int start;\n        private int length;\n        int hashCodeCached;\n\n        ByteArrayWrapper(byte[] content, int start, int length, int hashCodeCached) {\n            this.content = content;\n            this.start = start;\n            this.length = length;\n            this.hashCodeCached = hashCodeCached;\n        }\n\n        int calculateHashCode() {\n            return this.hashCodeCached = vectorizedHashCode(content, start, length);\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            return obj instanceof ByteArrayWrapper bw && isEqualTo(bw);\n        }\n\n        boolean isEqualTo(ByteArrayWrapper other) {\n            return length == other.length && arraysEqual(content, start, other.content, other.start, length);\n        }\n\n        @Override\n        public int hashCode() {\n            return hashCodeCached;\n        }\n\n        @Override\n        public String toString() {\n            return new String(content, start, length, StandardCharsets.UTF_8);\n        }\n\n        ByteArrayWrapper copy() {\n            byte[] copy = Arrays.copyOfRange(content, start, start + length);\n            return new ByteArrayWrapper(copy, 0, copy.length, hashCodeCached);\n        }\n\n    }\n\n    private static class MyHashMap {\n        private static final int INVERSE_LOAD_FACTOR = 2;\n        private AggregatedMeasurement[] data;\n        private int size;\n\n        MyHashMap(int initialCapacity) {\n            this.data = new AggregatedMeasurement[initialCapacity];\n        }\n\n        private void grow() {\n            AggregatedMeasurement[] oldData = data;\n            AggregatedMeasurement[] newData = new AggregatedMeasurement[oldData.length * 2];\n            for (AggregatedMeasurement measurement : oldData) {\n                if (measurement != null) {\n                    put(measurement, newData);\n                }\n            }\n            this.data = newData;\n        }\n\n        private void put(AggregatedMeasurement value, AggregatedMeasurement[] data) {\n            int length = data.length;\n            int hashCode = value.hashCode();\n            int idx = length & (hashCode ^ (hashCode >> 16));\n            for (int i = idx; i < length; ++i) {\n                if (data[i] == null) {\n                    data[i] = value;\n                    return;\n                }\n            }\n            for (int i = 0; i < idx; ++i) {\n                if (data[i] == null) {\n                    data[i] = value;\n                    return;\n                }\n            }\n        }\n\n        AggregatedMeasurement getOrCreate(ByteArrayWrapper key) {\n            AggregatedMeasurement[] data = this.data;\n            int length = data.length;\n            int hashCode = key.calculateHashCode();\n            int idx = (length - 1) & (hashCode ^ (hashCode >> 16));\n            AggregatedMeasurement result = doGetOrCreate(key, idx, length, data);\n            return result != null ? result : doGetOrCreate(key, 0, idx, data);\n        }\n\n        private AggregatedMeasurement doGetOrCreate(ByteArrayWrapper key, int from, int to, AggregatedMeasurement[] data) {\n            for (int i = from; i < to; ++i) {\n                AggregatedMeasurement item = data[i];\n                if (item != null) {\n                    if (item.station.isEqualTo(key)) {\n                        return item;\n                    }\n                }\n                else {\n                    AggregatedMeasurement result = new AggregatedMeasurement(key.copy());\n                    ++size;\n                    if (size * INVERSE_LOAD_FACTOR >= data.length) {\n                        grow();\n                        put(result, this.data);\n                    }\n                    else {\n                        data[i] = result;\n                    }\n                    return result;\n                }\n            }\n            return null;\n        }\n\n        void merge(MyHashMap other) {\n            for (AggregatedMeasurement measurement : other.data) {\n                if (measurement != null) {\n                    merge(measurement);\n                }\n            }\n        }\n\n        private boolean merge(AggregatedMeasurement value) {\n            AggregatedMeasurement[] data = this.data;\n            int length = data.length;\n            ByteArrayWrapper key = value.station;\n            int hashCode = key.hashCode();\n            int idx = (length - 1) & (hashCode ^ (hashCode >> 16));\n            return doMerge(key, value, idx, length, data) || doMerge(key, value, 0, idx, data);\n        }\n\n        private boolean doMerge(ByteArrayWrapper key, AggregatedMeasurement value, int from, int to, AggregatedMeasurement[] data) {\n            for (int i = from; i < to; ++i) {\n                AggregatedMeasurement item = data[i];\n                if (item != null) {\n                    if (item.station.isEqualTo(key)) {\n                        item.merge(value);\n                        return true;\n                    }\n                }\n                else {\n                    ++size;\n                    if (size * INVERSE_LOAD_FACTOR >= data.length) {\n                        grow();\n                        put(value, this.data);\n                    }\n                    else {\n                        data[i] = value;\n                    }\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        AggregatedMeasurement[] toArray() {\n            AggregatedMeasurement[] result = new AggregatedMeasurement[size];\n            int i = 0;\n            for (AggregatedMeasurement measurement : data) {\n                if (measurement != null) {\n                    result[i++] = measurement;\n                }\n            }\n            return result;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_rby.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.nio.*;\nimport java.nio.channels.*;\nimport java.nio.file.*;\nimport java.util.*;\nimport java.util.stream.*;\n\npublic class CalculateAverage_rby {\n\n    private static final String FILE = \"./measurements.txt\";\n    // private static final int CHUNK_SIZE = 8 * 1024 * 1024;\n    private static final int CHUNK_SIZE = 32 << 20;\n\n    /**\n     * Computes good enough partitions which end on a newline\n     */\n    static long[] cuts(Path p, int workers) throws IOException {\n        var channel = (FileChannel) Files.newByteChannel(p, EnumSet.of(StandardOpenOption.READ));\n        final long size = channel.size();\n\n        if (size < 10000l) {\n            return new long[]{ 0l, size };\n        }\n        long chunk = size / workers;\n        long position = size - chunk;\n\n        long[] cuts = new long[workers + 1];\n        cuts[workers] = size;\n        // 1024 should cover enough to catch a newline\n        var buf = ByteBuffer.allocateDirect(1024);\n        byte[] bytes = new byte[1024];\n\n        while (workers-- > 0) {\n            var read = channel.read(buf, position);\n            buf.flip();\n            buf.get(bytes, 0, read);\n            var nextNL = position;\n            while (read-- > 0) {\n                if (bytes[read] == '\\n') {\n                    nextNL += read;\n                    cuts[workers] = nextNL;\n                    break;\n                }\n            }\n            position -= chunk;\n            buf.rewind();\n        }\n        cuts[0] = 0L;\n        return cuts;\n\n    }\n\n    public static void main(String[] args) throws IOException {\n        var p = Paths.get(FILE);\n        var cpus = Runtime.getRuntime().availableProcessors();\n        final long[] cuts = cuts(p, cpus);\n\n        var stats = IntStream.range(0, cuts.length - 1)\n                .parallel()\n                .mapToObj((i) -> stats(p, cuts[i], cuts[i + 1]))\n                .reduce(Stats.IDENTITY, Stats::combine);\n\n        stats.print();\n\n    }\n\n    static record Stats(Map<String, Integer> indexes, int nextIx, int[] stats) {\n        private final static Stats IDENTITY = new Stats(new HashMap(), 0, new int[0]);\n        // not much optimization needed here\n        Stats combine(Stats other) {\n            if (this == IDENTITY) return other;\n            if (other == IDENTITY) return this;\n            var myNextIx = nextIx; \n            for(var e : other.indexes.entrySet()) {\n                int ix;\n                var ixi = indexes.get(e.getKey());\n                if ( ixi == null) {\n                    ix = myNextIx++ * 4;\n                } else {\n                     ix = ixi.intValue() * 4;\n                }\n                var oix = e.getValue() * 4;\n                stats[ix] = Math.min(stats[ix], other.stats[oix]);\n                stats[ix + 1] = Math.max(stats[ix + 1], other.stats[oix + 1]);\n                stats[ix + 2] += other.stats[oix + 2];\n                stats[ix + 3] += other.stats[oix + 3];\n            }\n            return new Stats(indexes, myNextIx, stats);\n        }\n        // or here\n        void print() {\n            var iter = new TreeMap<>(indexes).entrySet().iterator();\n            System.out.print(\"{\");\n            if (iter.hasNext()) {\n                var e = iter.next();\n                var ix = e.getValue().intValue() * 4;\n                var avg = Math.round(stats[ix + 2]/((double)stats[ix+3]))/10.0;\n                System.out.print(e.getKey() + \"=\"\n                        + (stats[ix]/10.0) + \"/\"\n                        + avg + \"/\"\n                        + (stats[ix + 1]/10.0));\n            }\n            while(iter.hasNext()) {\n                var e = iter.next();\n                var ix = e.getValue().intValue() * 4;\n                var avg = Math.round(stats[ix + 2]/((double)stats[ix+3]))/10.0;\n                System.out.print(\", \" + e.getKey() + \"=\"\n                        + (stats[ix]/10.0) + \"/\"\n                        + avg + \"/\"\n                        + (stats[ix + 1]/10.0)) ;\n            }\n            System.out.println(\"}\");\n        }\n    }\n\n    static final int MAX_CITIES = 1000;\n    static final int ARRAY_SIZE = 1 << 20;\n\n    static Stats stats(Path p, long start, long end) {\n        int nextCityIx = 0;\n        var cityIndexes = new HashMap<String, Integer>(MAX_CITIES, 1.0f);\n        int[] stats = new int[MAX_CITIES * 4];\n        for (int i = 0; i < MAX_CITIES; i++) {\n            stats[i * 4] = Integer.MAX_VALUE;\n            stats[i * 4 + 1] = Integer.MIN_VALUE;\n        }\n\n        try {\n            final var channel = (FileChannel) Files.newByteChannel(p, EnumSet.of(StandardOpenOption.READ));\n            channel.position(start);\n            var offset = start;\n            final byte[] array = new byte[ARRAY_SIZE];\n            // the next expected char, the most simple stateMachine\n            char nextChar = ';';\n            // good enough for a city name, or a double\n            byte[] strbuff = new byte[128];\n            int strbuffIx = 0;\n            int cityIndex = 0;\n            final var buffer = ByteBuffer.allocateDirect(CHUNK_SIZE);\n\n            while (offset < end) {\n                final int limit = channel.read(buffer);\n                if (limit <= 0)\n                    break;\n                offset += limit;\n                int totalRead = 0;\n                buffer.flip();\n                while (totalRead < limit) {\n                    int read = Math.min(array.length, limit - totalRead);\n                    buffer.get(array, 0, read);\n                    totalRead += read;\n\n                    for (int i = 0; i < read; i++) {\n                        if (nextChar == '\\n' && array[i] == '.')\n                            continue;\n                        strbuff[strbuffIx++] = array[i];\n                        if (array[i] == nextChar) {\n                            var str = new String(strbuff, 0, strbuffIx - 1, \"utf8\");\n                            strbuffIx = 0;\n                            switch (nextChar) {\n                                case ';':\n                                    nextChar = '\\n';\n                                    var mbCityIx = cityIndexes.get(str);\n                                    if (mbCityIx == null) {\n                                        cityIndex = nextCityIx;\n                                        cityIndexes.put(str, nextCityIx++);\n                                        if (nextCityIx * 4 >= stats.length) {\n                                            var newStats = Arrays.copyOf(stats, stats.length * 2);\n                                            for (int j = stats.length; j < newStats.length; j += 4) {\n                                                newStats[j] = Integer.MAX_VALUE;\n                                                newStats[j + 1] = Integer.MIN_VALUE;\n                                            }\n                                            stats = newStats;\n                                        }\n                                    }\n                                    else {\n                                        cityIndex = mbCityIx.intValue();\n                                    }\n                                    break;\n                                case '\\n':\n                                    nextChar = ';';\n                                    int temp = Integer.parseInt(str);\n                                    var ix = cityIndex * 4;\n                                    if (temp < stats[ix])\n                                        stats[ix] = temp;\n                                    if (temp > stats[ix + 1])\n                                        stats[ix + 1] = temp;\n                                    stats[ix + 2] += temp;\n                                    stats[ix + 3]++;\n\n                                    break;\n                                default:\n                            }\n\n                        }\n                    }\n                }\n                buffer.rewind();\n            }\n            return new Stats(cityIndexes, nextCityIx, stats);\n        }\n        catch (IOException err) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_rcasteltrione.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.time.Duration;\nimport java.time.Instant;\nimport java.util.*;\n\nimport static java.util.stream.Collectors.toMap;\n\n//baseline: 266s\n\npublic class CalculateAverage_rcasteltrione {\n    private static final String FILE = \"./measurements.txt\";\n    // private static final String FILE = \"./backup/measurements.txt\";\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        Path path = Paths.get(FILE);\n        Instant start = Instant.now();\n\n        var segList = FileSegment.forFile(path, Runtime.getRuntime().availableProcessors());\n        var results = new ByteArrayToMeasurementMap[segList.size()];\n        var threads = new Thread[segList.size()];\n        try (var channel = FileChannel.open(path, StandardOpenOption.READ)) {\n            for (int i = 0; i < segList.size(); i++) {\n                int finalI = i;\n                FileSegment fileSegment = segList.get(finalI);\n                var t = Thread.ofPlatform().start(() -> results[finalI] = processSegment(channel, fileSegment));\n                threads[i] = t;\n            }\n            for (Thread thread : threads) {\n                thread.join();\n            }\n        }\n\n        Map<String, Measurement> aggregatedMap = Arrays.stream(results)\n                .flatMap(m -> m.entries().stream())\n                .collect(toMap(\n                        ByteArrayToMeasurementMap.Entry::key,\n                        ByteArrayToMeasurementMap.Entry::value,\n                        Measurement::merge,\n                        TreeMap::new));\n\n        System.out.println(aggregatedMap);\n        // System.out.println(Duration.between(start, Instant.now()).toMillis());\n    }\n\n    private static ByteArrayToMeasurementMap processSegment(FileChannel channel, FileSegment seg) {\n        try {\n            MappedByteBuffer mbb = channel.map(FileChannel.MapMode.READ_ONLY, seg.start(), seg.size());\n            byte b;\n            var result = new ByteArrayToMeasurementMap();\n            var lineBuffer = new byte[1 << 13];\n            var segmentPosition = mbb.position();\n            var limit = mbb.limit();\n            var lastLineOffset = 0;\n\n            while (segmentPosition < mbb.limit()) {\n\n                int remaining = limit - segmentPosition;\n                int chunk = Math.min(remaining, lineBuffer.length);\n                mbb.get(segmentPosition, lineBuffer, 0, chunk);\n                for (int i = chunk - 1; i >= 0; i--) {\n                    if (lineBuffer[i] == '\\n') {\n                        lastLineOffset = i;\n                        break;\n                    }\n                }\n                for (int lineBufferOffset = 0; lineBufferOffset < lastLineOffset;) {\n                    int nameHash = 0;\n                    int nameLength = 0;\n                    int nameStart = lineBufferOffset;\n                    while ((b = lineBuffer[lineBufferOffset++]) != ';') {\n                        nameHash = 31 * nameHash + b;\n                        nameLength++;\n                    }\n\n                    int temp;\n                    int negative = 1;\n                    // var s = new String(Arrays.copyOfRange(lineBuffer, nameStart, lineOffset - 1), StandardCharsets.UTF_8);\n                    if (lineBuffer[lineBufferOffset] == '-') {\n                        lineBufferOffset++;\n                        negative = -1;\n                    }\n\n                    // Temperature value: non-null double between -99.9 (inclusive) and 99.9 (inclusive), always with one fractional digit\n                    if (lineBuffer[lineBufferOffset + 1] == '.') {\n                        temp = (lineBuffer[lineBufferOffset] - '0') * 10 + (lineBuffer[lineBufferOffset + 2] - '0');\n                        lineBufferOffset += 3;\n                    }\n                    else {\n                        temp = (lineBuffer[lineBufferOffset] - '0') * 100\n                                + (lineBuffer[lineBufferOffset + 1] - '0') * 10\n                                + (lineBuffer[lineBufferOffset + 3] - '0');\n                        lineBufferOffset += 4;\n                    }\n                    if (lineBuffer[lineBufferOffset] == '\\r') {\n                        lineBufferOffset++;\n                    }\n                    lineBufferOffset++;\n\n                    temp *= negative;\n                    result.mergeOrCreate(lineBuffer, nameStart, nameLength, nameHash, temp);\n                    // segmentPosition += lineOffset;\n                    // i += lineoffset;\n                }\n\n                segmentPosition += lastLineOffset + 1;\n\n            }\n\n            return result;\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    record FileSegment(long start, long size) {\n        public static List<FileSegment> forFile(Path file, int desiredSegmentsCount) throws IOException {\n            try (var raf = new RandomAccessFile(file.toFile(), \"r\")) {\n                var segments = new ArrayList<FileSegment>();\n                var fileSize = raf.length();\n                if (fileSize < 1000000) {\n                    return Collections.singletonList(new FileSegment(0, fileSize));\n                }\n                var segmentSize = fileSize / desiredSegmentsCount;\n                for (int segmentIdx = 0; segmentIdx < desiredSegmentsCount; segmentIdx++) {\n                    var segStart = segmentIdx * segmentSize;\n                    var segEnd = (segmentIdx == desiredSegmentsCount - 1) ? fileSize : segStart + segmentSize;\n                    segStart = findSegmentBoundary(raf, segmentIdx, 0, segStart, segEnd);\n                    segEnd = findSegmentBoundary(raf, segmentIdx, desiredSegmentsCount - 1, segEnd, fileSize);\n\n                    var segSize = segEnd - segStart;\n\n                    segments.add(new FileSegment(segStart, segSize));\n                }\n                return segments;\n            }\n        }\n\n        private static long findSegmentBoundary(RandomAccessFile raf, int i, int skipForSegment, long location, long fileSize) throws IOException {\n            if (i == skipForSegment) return location;\n\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                if (raf.read() == '\\n') break;\n            }\n            return location;\n        }\n    }\n\n    static class Measurement {\n        int min, max, n;\n        long sum;\n\n        private Measurement(int min, int max, long sum, int n) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.n = n;\n        }\n\n        public Measurement(int temp) {\n            this(temp, temp, temp, 1);\n        }\n\n        final Measurement merge(Measurement other) {\n            this.min = Math.min(other.min, this.min);\n            this.max = Math.max(other.max, this.max);\n            this.sum += other.sum;\n            this.n += other.n;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round(((double) sum / n))}/\\{round(max)}\";\n        }\n\n        double round(double v) {\n            return Math.round(v) / 10.0;\n        }\n    }\n\n    static class ByteArrayToMeasurementMap {\n\n        public static final int DEFAULT_CAPACITY = 1024;\n        public static final float LOAD_FACTOR = 0.75f;\n        MeasurementSlot[] slots = new MeasurementSlot[DEFAULT_CAPACITY];\n        int threshold = (int) (DEFAULT_CAPACITY * LOAD_FACTOR);\n        int size = 0;\n\n        private record MeasurementSlot(int hash, byte[] key, String city, Measurement measurement) {\n        }\n\n        public final void mergeOrCreate(byte[] line, int nameStart, int nameLength, int hash, int temperature) {\n            int hashMask = slots.length - 1;\n\n            for (int idx = hash & hashMask;; idx = (idx + 1) & hashMask) {\n                MeasurementSlot slot = slots[idx];\n                if (slot == null) {\n                    size++;\n                    if (size > threshold) {\n                        idx = resize(hash);\n                    }\n                    byte[] nameBuffer = new byte[nameLength];\n                    System.arraycopy(line, nameStart, nameBuffer, 0, nameLength);\n                    slots[idx] = new MeasurementSlot(\n                            hash,\n                            nameBuffer,\n                            new String(nameBuffer, StandardCharsets.UTF_8),\n                            new Measurement(temperature));\n                    return;\n                }\n\n                if (slot.hash == hash && arrayEquals(slot.key, line, nameStart, nameLength)) {\n                    Measurement value = slots[idx].measurement;\n                    value.min = Math.min(value.min, temperature);\n                    value.max = Math.max(value.max, temperature);\n                    value.sum += temperature;\n                    value.n++;\n                    return;\n                }\n            }\n        }\n\n        private int resize(int hash) {\n            var oldSlots = slots;\n            var newSlots = new MeasurementSlot[oldSlots.length << 1];\n            var mask = newSlots.length - 1;\n            for (MeasurementSlot oldSlot : oldSlots) {\n                if (oldSlot == null) {\n                    continue;\n                }\n                int idx = oldSlot.hash & mask;\n                while (newSlots[idx] != null) {\n                    idx = (idx + 1) & mask;\n                }\n                newSlots[idx] = oldSlot;\n            }\n\n            slots = newSlots;\n            threshold = (int) (newSlots.length * LOAD_FACTOR);\n            int hashMask = slots.length - 1;\n            int idx;\n            for (idx = hash & hashMask; slots[idx] != null; idx = (idx + 1) & hashMask) {\n            }\n            return idx;\n        }\n\n        private boolean arrayEquals(byte[] storedKey, byte[] line, int nameStart, int nameLength) {\n            if (storedKey.length != nameLength) {\n                return false;\n            }\n\n            for (int i = 0; i < storedKey.length; i++) {\n                if (storedKey[i] != line[nameStart + i]) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        private static int hashCode(int h) {\n            h ^= (h >>> 20) ^ (h >>> 12);\n            h ^= (h >>> 7) ^ (h >>> 4);\n            h += h << 7;\n            return h;\n        }\n\n        public final List<Entry> entries() {\n            var result = new ArrayList<Entry>(slots.length);\n            for (MeasurementSlot slot : slots) {\n                if (slot != null) {\n                    result.add(new Entry(slot.city, slot.measurement));\n                }\n            }\n            return result;\n        }\n\n        public record Entry(String key, Measurement value) {\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_ricardopieper.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\n\n/*\n If I had to submit something without looking what others did, I am fairly certain I would\n be under 500MB/s on my machine on the dataset created by ./create_measurement.sh.\n\n Maybe it's cheating? But I learned stuff.\n\n Credits:\n  - @royvanrijn for the idea of using bit twiddling without java.incubator.vector\n  - @royvanrijn again for the parse int only and /10 in the very end\n  - @flippingbits for the idea of not calling getLong on mmaped file directly, get a big chunk into memory instead\n        - Maybe on linux it's actually faster?\n  - OpenAI / ChatGPT for the actual bit twiddling idea for finding a character, it couldn't explain it so I did my best\n    (Turns out @royvanrijn had the same idea)\n\n Note:\n  - If someone needs maybe a new trick: in the hashmap, if you read a station name as a long and it\n  fits under 8 bytes, use it directly on equality comparisons. Saves a lot of looping and gives a nice\n  ~5% boost for me.\n\n\n Todo:\n  - The final aggregation of results is taking around 1 whole second to complete. Improve it.\n\n */\n@SuppressWarnings(\"unchecked\")\npublic class CalculateAverage_ricardopieper {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static final class StationMeasurements {\n        public long min;\n        public long max;\n        public long sum;\n        public int count;\n\n        public StationMeasurements(\n                                   long min,\n                                   long max,\n                                   long sum,\n                                   int count\n\n        ) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n\n        @Override\n        public String toString() {\n            var min = String.format(\"%.1f\", (double) this.min / 10.0);\n            var avg = String.format(\"%.1f\", ((double) this.sum / (double) this.count) / 10.0);\n            var max = String.format(\"%.1f\", (double) this.max / 10.0);\n\n            return STR.\"\\{min}/\\{avg}/\\{max}\";\n        }\n    }\n\n    public static record FileChunk(Path path, long start, int size) {\n    }\n\n    public static List<FileChunk> splitFile(Path path, int numChunks) throws IOException {\n        try (var fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {\n            var chunks = new ArrayList<FileChunk>();\n            long size = fileChannel.size();\n\n            if (numChunks == 1 && size <= Integer.MAX_VALUE) {\n                chunks.add(new FileChunk(path, 0, (int) size));\n                return chunks;\n            }\n            long approxSizePerChunk = size / numChunks;\n            var buffer = ByteBuffer.allocate(1024); // in practice records are max 20 chars long\n\n            long curOffset = 0;\n            for (int i = 0; i < numChunks; i++) {\n                long targetOffset = curOffset + approxSizePerChunk;\n                // advance to the target offset\n                fileChannel.position(targetOffset);\n                // advance until we find a newline\n                buffer.clear();\n                fileChannel.read(buffer);\n                int extraAdvance = 0;\n                while (buffer.get(extraAdvance) != '\\n') {\n                    extraAdvance++;\n                }\n                // +1 because we want to include the \\n in the current chunk\n                var end = Math.min(curOffset + approxSizePerChunk + extraAdvance + 1, size);\n                long sizeOfChunk = end - curOffset;\n\n                chunks.add(new FileChunk(path,\n                        curOffset, (int) sizeOfChunk));\n                curOffset = end; // because we found the \\n but we want to leave at the next character\n                if (curOffset >= size) {\n                    break;\n                }\n            }\n\n            return chunks;\n        }\n    }\n\n    // Ignores the dots because we do a division in the end\n    public static int longBytesToInt(long vector, int len) {\n        byte b0 = (byte) (vector >> 64 - 8),\n                b1 = (byte) (vector >> 64 - 16),\n                b2 = (byte) (vector >> 64 - 24),\n                b3 = (byte) (vector >> 64 - 32),\n                b4 = (byte) (vector >> 64 - 40);\n\n        // check for windows newline\n        byte newlineByte = (byte) (vector >> (64 - (len * 8)));\n        if (newlineByte == '\\r') {\n            len--;\n        }\n\n        // len can be 3 4 or 5\n        // in this case we get bytes 0 and 2\n        if (len == 3) {\n            return (b0 - '0') * 10 + (b2 - '0');\n        }\n        boolean isNegative = b0 == '-';\n        // a number like -1.0\n        if (len == 4 && isNegative) {\n            return -((b1 - '0') * 10 + (b3 - '0'));\n        }\n        // a number like 99.1\n        if (len == 4) {\n            return (b0 - '0') * 100 + (b1 - '0') * 10 + (b3 - '0');\n        }\n        // a number like -99.1\n        if (len == 5 && isNegative) {\n            return -((b1 - '0') * 100 + (b2 - '0') * 10 + (b4 - '0'));\n        }\n\n        throw new RuntimeException(\"Shouldn't reach here: non-negative number with >5 characters\");\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var debugMode = false;\n        var path = Paths.get(FILE);\n\n        var averageSizePerChunk = 16 * 1024 * 1024;\n        var fileSize = Files.size(path);\n        var numChunks = Math.max(1, fileSize / averageSizePerChunk);\n        var chunks = splitFile(path, (int) numChunks);\n        TreeMap<String, StationMeasurements> result = null;\n        if (debugMode) {\n            for (var chunk : chunks) {\n                result = processFileChunk(chunk).asTreeMap();\n                System.out.println(\"Processed chunk \" + chunk.start);\n            }\n        }\n        else {\n            result = chunks.parallelStream()\n                    .map(chunk -> {\n                        try {\n                            return processFileChunk(chunk);\n                        }\n                        catch (IOException e) {\n                            throw new RuntimeException(e);\n                        }\n                    })\n                    // .peek(x -> x.printStats())\n                    .map(MeasureMap::asTreeMap)\n                    .reduce((map1, map2) -> {\n                        for (var kv : map1.entrySet()) {\n                            var mergedEntry = map2.get(kv.getKey());\n                            if (mergedEntry == null) {\n                                map2.put(kv.getKey(), kv.getValue());\n                            }\n                            else {\n                                mergedEntry.min = Math.min(mergedEntry.min, kv.getValue().min);\n                                mergedEntry.max = Math.max(mergedEntry.max, kv.getValue().max);\n                                mergedEntry.count += kv.getValue().count;\n                                mergedEntry.sum += kv.getValue().sum;\n                            }\n                        }\n                        return map2;\n                    }).get();\n        }\n\n        System.out.println(result);\n    }\n\n    private static final int findFirstOccurrence(long bytes, long pattern) {\n        // This masked value will have a 00000000 at the byte where we have the separator,\n        // and crucially, only at those places.\n        long masked = bytes ^ pattern;\n\n        // Now those 00000000 can be turned into a 11111111 (underflow). Why?\n        // It will become apparent later.\n        long underflowed = masked - 0x0101010101010101L;\n\n        long clearHighBits = underflowed & ~masked;\n        /*\n         * A lot happened in that line of code above. Suppose this comment starts before the line executes.\n         * To understand this, it's best if you take some actual values during runtime and plug them onto\n         * bitwisecmd.com and see these things happening.\n         *\n         * Now that we have that full 0xFF byte at the position of the separators (or not,\n         * maybe we didn't find a separator. Don't worry it still works the same), we can do a trick\n         * where we look for the highest bit on each byte being set and isolating them. Unfortunately\n         * it's possible that our masked value (and underflowed value) still have some unrelated\n         * bytes with the high bit still set.\n         *\n         * When we negate the masked value, those high bits become 0. The AND will make those high bits in\n         * underflowed switch to 0, because the negated mask high bit is zero. Notice that this is specific to our\n         * mask value.\n         *\n         * How about our 0xFF? the ~masked turns the 0x00 at the byte position into 0xFF, so the AND\n         * still leaves them 0xFF.\n         *\n         * Well, what if our mask has a high 1 though? like 0xBB? And the input had a mix of high bits\n         * set and unset?\n         *\n         * In that case, masked would be 0x000000 at the byte position and would keep its high bits everywhere else,\n         * and every input byte with high MSB the XOR would turn into a 0. In the next operations\n         * it forwards a 0 into the calculations, and it doesn't matter what is in the other side of the AND,\n         * it will result in zero.\n         *\n         * What if our mask is 0x3B as always but we have some bytes with MSB 1?\n         * The XORed value will contain the high bits, but this same XORed value will be negated\n         * later, making its high bits 0. When they get ANDed, the high bit 0 in the negated value\n         * will clear that 1.\n         *\n         *\n         * If the search finds nothing, the final value of clearHighBits will be zero at every MSB on every byte.\n         */\n\n        // this 0x808080 is just 0b100000000|100000000, it selects the highest bit of every byte.\n        long highBitOfSeparator = clearHighBits & 0x8080808080808080L;\n\n        // If nothing is found, highBitOfSeparator will be zero, and this call returns 64, /8 becomes 8 which means\n        // we can advance 8 positions forward.\n\n        return Long.numberOfLeadingZeros(highBitOfSeparator) / 8;\n    }\n\n    private static MeasureMap processFileChunk(FileChunk chunk) throws IOException {\n        var map = new MeasureMap();\n\n        long newlineMask = 0x0A0A0A0A0A0A0A0AL;\n        long separatorMask = 0x3B3B3B3B3B3B3B3BL;\n\n        // the state machine goes like this:\n        // 1 - looking for the next ; to get name\n\n        int nameStart = 0, nameEnd = 0;\n        int tempStart = 0, tempEnd = 0;\n\n        // this +8 helps to remove a conditional check when calling getLong when there's less than 8 bytes remaining\n        ByteBuffer byteBuffer = ByteBuffer.allocate(chunk.size + 8);\n        try (var channel = new RandomAccessFile(chunk.path.toString(), \"r\")) {\n            channel.seek(chunk.start);\n            channel.read(byteBuffer.array(), 0, chunk.size);\n        }\n        byteBuffer.position(0);\n        while (byteBuffer.hasRemaining()) {\n\n            long nameVector = byteBuffer.getLong();\n\n            int idx = findFirstOccurrence(nameVector, separatorMask);\n\n            boolean foundSeparator = idx != 8;\n            nameEnd += idx;\n            if (foundSeparator) {\n                // skip the separator\n                tempStart = nameEnd + 1;\n            }\n            else {\n                continue;\n            }\n\n            byteBuffer.position(tempStart);\n            var tempVector = byteBuffer.getLong();\n\n            // looking for temperature\n            // this one is guaranteed to run in one go because\n            // the temperature is max 5 characters, 6 with the newline,\n            // and we start at the number already.\n\n            int newlineIdx = findFirstOccurrence(tempVector, newlineMask);\n            tempEnd = tempStart + newlineIdx;\n\n            // var tempStr = new String(tempBytes, 0, tempEnd - tempStart);\n            var temp = longBytesToInt(tempVector, tempEnd - tempStart);// Float.parseFloat(tempStr);\n\n            var measurements = map.getOrAdd(byteBuffer.array(), nameVector, nameStart, nameEnd - nameStart);\n\n            measurements.min = Math.min(measurements.min, temp);\n            measurements.max = Math.max(measurements.max, temp);\n            measurements.sum += temp;\n            measurements.count += 1;\n\n            // System.out.println(STR.\"\\{name} -> \\{tempStr}\");\n\n            nameStart = tempEnd + 1;\n            nameEnd = nameStart;\n            byteBuffer.position(nameStart);\n        }\n\n        return map;\n    }\n\n    // I tried using a trie but it wasn't cache efficient enough.\n    // THe problem with a HashMap is that it doesnt allow passing a byte and length,\n    // I also tried using a wrapper object that, when added, I called a .consolidate() method\n    // to actually copy the underlying buffer, but the profiler showed it allocated\n    // way too much memory. Performance was kind of the same though...\n    public static class MeasureMap {\n        public record Entry(byte[] bytes, long nameVector, StationMeasurements measurements) {\n        }\n\n        // Useful for debugging\n        public static byte[] longToBytes(long vector) {\n            byte b0 = (byte) (vector >> 64 - 8),\n                    b1 = (byte) (vector >> 64 - 16),\n                    b2 = (byte) (vector >> 64 - 24),\n                    b3 = (byte) (vector >> 64 - 32),\n                    b4 = (byte) (vector >> 64 - 40),\n                    b5 = (byte) (vector >> 64 - 48),\n                    b6 = (byte) (vector >> 64 - 56),\n                    b7 = (byte) (vector);\n\n            return new byte[]{\n                    b0, b1, b2, b3, b4, b5, b6, b7\n            };\n        }\n\n        ArrayList<Entry>[] buckets;\n\n        public MeasureMap() {\n            buckets = new ArrayList[32 * 1024];\n            for (int i = 0; i < 32 * 1024; i++) {\n                var bucket = new ArrayList<Entry>();\n                buckets[i] = bucket;\n            }\n        }\n\n        // I tried using a vectorized hashCode using ByteVector,\n        // but I think this gets vectorized anyway because the performance is\n        // either better or the same.\n        public static int hashCode(byte[] array, int offset, int length) {\n            int result = 1;\n            for (int i = offset; i < offset + length; i++) {\n                result = 31 * result + array[i];\n            }\n            return result;\n        }\n\n        public boolean equals(byte[] a1, int a1offset, int a1len, byte[] a2) {\n            if (a1len != a2.length) {\n                return false;\n            }\n            // I tried all sorts of trickery here,\n            // like comparing first and last before the loop.\n            // It's useless. Maybe slower. Because when strings are the same length\n            // it's a pretty high chance they are the same...\n            for (int i = 0; i < a1len; i++) {\n                if (a1[a1offset + i] != a2[i]) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        public StationMeasurements getOrAdd(byte[] bytes, long nameVector, int offset, int length) {\n            long shift = (64 - (length * 8L));\n            long actualNameVector = nameVector >> shift << shift;\n\n            var hash = hashCode(bytes, offset, length);\n\n            // This is a modulo operation because:\n            // buckets.length is a power of 2 (like 01000000, only 1 bit is set)\n            // -1 makes all the bits right to that 1 become 1 (like 00111111)\n            // the & will select only those 1s, and due to math, it is the remainder\n            // this has also the benefit of not needing a positive hash\n            int bucketIndex = (buckets.length - 1) & hash;\n\n            var bucket = buckets[bucketIndex];\n            for (int i = 0; i < bucket.size(); i++) {\n\n                var item = bucket.get(i);\n                // <= 7 means we found the name and separator in one read so it's\n                // guaranteed the actualNameVector holds all the data\n                boolean found = length <= 7 ? (actualNameVector == item.nameVector) : equals(bytes, offset, length, item.bytes);\n\n                if (found) {\n                    return item.measurements;\n                }\n\n            }\n\n            // new item, consolidate\n            var newItemKey = Arrays.copyOfRange(bytes, offset, offset + length);\n            var measurements = new StationMeasurements(\n                    Integer.MAX_VALUE,\n                    Integer.MIN_VALUE,\n                    0,\n                    0);\n\n            bucket.add(new Entry(\n                    newItemKey, actualNameVector, measurements));\n            return measurements;\n        }\n\n        // Convenience method to merge maps later\n        public TreeMap<String, StationMeasurements> asTreeMap() {\n            var result = new TreeMap<String, StationMeasurements>();\n            for (var bucket : this.buckets) {\n                for (var item : bucket) {\n                    var str = new String(item.bytes);\n                    result.put(str, item.measurements);\n                }\n            }\n            return result;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_richardstartin.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.ForkJoinPool;\nimport java.util.concurrent.RecursiveAction;\nimport java.util.concurrent.atomic.AtomicIntegerFieldUpdater;\nimport java.util.concurrent.atomic.AtomicReferenceFieldUpdater;\nimport java.util.function.Consumer;\n\npublic class CalculateAverage_richardstartin {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    record Slot(byte[] key, int[] aggregates) {\n        private static final int WIDTH = 8;\n        private static int[] newAggregates(int stripes) {\n            var aggregates = new int[stripes * WIDTH];\n            for (int i = 0; i < aggregates.length; i += WIDTH) {\n                aggregates[i] = Integer.MAX_VALUE;\n                aggregates[i + 1] = Integer.MIN_VALUE;\n            }\n            return aggregates;\n        }\n        Slot(byte[] key, int stripes) {\n            this(key, newAggregates(stripes));\n        }\n\n        void update(int stripe, int value) {\n            int i = stripe * WIDTH;\n            aggregates[i] = Math.min(value, aggregates[i]);\n            aggregates[i + 1] = Math.max(value, aggregates[i + 1]);\n            aggregates[i + 2] += value;\n            aggregates[i + 3]++;\n        }\n\n        public ResultRow toResultRow() {\n            int min = Integer.MAX_VALUE;\n            int max = Integer.MIN_VALUE;\n            int sum = 0;\n            int count = 0;\n            for (int i = 0; i < aggregates.length; i += WIDTH) {\n                min = Math.min(min, aggregates[i]);\n                max = Math.max(max, aggregates[i + 1]);\n                sum += aggregates[i + 2];\n                count += aggregates[i + 3];\n            }\n            return new ResultRow(min * 0.1, 0.1 * sum / count, max * 0.1);\n        }\n\n        public String toKey() {\n            return new String(key, StandardCharsets.UTF_8);\n        }\n    }\n\n    /** Maps text to an integer encoding. Adapted from async-profiler. */\n    public static class Dictionary {\n\n        private static final int ROW_BITS = 11;\n        private static final int ROWS = (1 << ROW_BITS);\n        private static final int TABLE_CAPACITY = ROWS;\n\n        private final Table table = new Table(this, nextBaseIndex());\n\n        private static final AtomicIntegerFieldUpdater<Dictionary> BASE_INDEX_UPDATER = AtomicIntegerFieldUpdater.newUpdater(Dictionary.class, \"baseIndex\");\n        volatile int baseIndex;\n\n        private void forEach(Table table, Consumer<Slot> consumer) {\n            for (var row : table.rows) {\n                var slot = row.slot;\n                if (slot != null) {\n                    consumer.accept(slot);\n                }\n                if (row.next != null) {\n                    forEach(row.next, consumer);\n                }\n            }\n        }\n\n        public void forEach(Consumer<Slot> consumer) {\n            forEach(this.table, consumer);\n        }\n\n        public Slot lookup(int hash, byte[] key, int length, int stripes) {\n            Table table = this.table;\n            while (true) {\n                int rowIndex = Math.abs(hash) % ROWS;\n                Row row = table.rows[rowIndex];\n                var storedSlot = row.slot;\n                if (storedSlot == null) {\n                    Slot slot = new Slot(Arrays.copyOf(key, length), stripes);\n                    if (row.compareAndSet(null, slot)) {\n                        return slot;\n                    }\n                    else {\n                        storedSlot = row.slot;\n                        if (Arrays.equals(key, 0, length, storedSlot.key, 0, storedSlot.key.length)) {\n                            return storedSlot;\n                        }\n                    }\n                }\n                else if (Arrays.equals(key, 0, length, storedSlot.key, 0, storedSlot.key.length)) {\n                    return storedSlot;\n                }\n                table = row.getOrCreateNextTable();\n                hash = Integer.rotateRight(hash, ROW_BITS);\n            }\n        }\n\n        private int nextBaseIndex() {\n            return BASE_INDEX_UPDATER.addAndGet(this, TABLE_CAPACITY);\n        }\n\n        private static final class Row {\n\n            private static final AtomicReferenceFieldUpdater<Row, Table> NEXT_TABLE_UPDATER = AtomicReferenceFieldUpdater.newUpdater(Row.class, Table.class, \"next\");\n            private static final AtomicReferenceFieldUpdater<Row, Slot> SLOT_UPDATER = AtomicReferenceFieldUpdater.newUpdater(Row.class, Slot.class, \"slot\");\n            private volatile Slot slot = null;\n            private final Dictionary dictionary;\n            volatile Table next;\n\n            private Row(Dictionary dictionary) {\n                this.dictionary = dictionary;\n            }\n\n            public Table getOrCreateNextTable() {\n                Table next = this.next;\n                if (next == null) {\n                    Table newTable = new Table(dictionary, dictionary.nextBaseIndex());\n                    if (NEXT_TABLE_UPDATER.compareAndSet(this, null, newTable)) {\n                        next = newTable;\n                    }\n                    else {\n                        next = this.next;\n                    }\n                }\n                return next;\n            }\n\n            public boolean compareAndSet(Slot expected, Slot newSlot) {\n                return SLOT_UPDATER.compareAndSet(this, expected, newSlot);\n            }\n        }\n\n        private static final class Table {\n\n            final Row[] rows;\n            final int baseIndex;\n\n            private Table(Dictionary dictionary, int baseIndex) {\n                this.baseIndex = baseIndex;\n                this.rows = new Row[ROWS];\n                Arrays.setAll(rows, i -> new Row(dictionary));\n            }\n        }\n    }\n\n    private static long compilePattern(long repeat) {\n        return 0x101010101010101L * repeat;\n    }\n\n    private static long compilePattern(byte delimiter) {\n        return compilePattern(delimiter & 0xFFL);\n    }\n\n    private static final long DELIMITER = compilePattern((byte) ';');\n\n    private static int findLastNewLine(ByteBuffer buffer) {\n        return findLastNewLine(buffer, buffer.limit() - 1);\n    }\n\n    private static int findLastNewLine(ByteBuffer buffer, int offset) {\n        for (int i = offset; i >= 0; i--) {\n            if (buffer.get(i) == '\\n') {\n                return i;\n            }\n        }\n        return 0;\n    }\n\n    private static int findIndexOf(ByteBuffer buffer, int limit, int offset, long pattern) {\n        int i = offset;\n        for (; i < limit - Long.BYTES + 1; i += Long.BYTES) {\n            long word = buffer.getLong(i);\n            long input = word ^ pattern;\n            long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;\n            tmp |= input | 0x7F7F7F7F7F7F7F7FL;\n            if (tmp != -1L) {\n                return i + (Long.numberOfTrailingZeros(~tmp) >>> 3);\n            }\n        }\n        byte b = (byte) (pattern & 0xFF);\n        for (; i < limit; i++) {\n            if (buffer.get(i) == b) {\n                return i;\n            }\n        }\n        return buffer.limit();\n    }\n\n    private static int hash(byte[] bytes, int limit) {\n        int hash = 1;\n        for (int i = 0; i < limit; i++) {\n            hash += hash * 129 + bytes[i];\n        }\n        return hash;\n    }\n\n    private static class AggregationTask extends RecursiveAction {\n\n        private final Dictionary dictionary;\n        private final List<ByteBuffer> slices;\n        private final int min;\n        private final int max;\n\n        private AggregationTask(Dictionary dictionary, List<ByteBuffer> slices) {\n            this(dictionary, slices, 0, slices.size() - 1);\n        }\n\n        private AggregationTask(Dictionary dictionary, List<ByteBuffer> slices, int min, int max) {\n            this.dictionary = dictionary;\n            this.slices = slices;\n            this.min = min;\n            this.max = max;\n        }\n\n        private void computeSlice(int stripe) {\n            var slice = slices.get(stripe);\n            int end = slice.limit();\n            byte[] tmp = new byte[128];\n            for (int offset = 0; offset < end;) {\n                int delimiter = findIndexOf(slice, end, offset, DELIMITER);\n                int value = 0;\n                int sign = 1;\n                byte b;\n                int i = delimiter + 1;\n                while (i != end && (b = slice.get(i++)) != '\\n') {\n                    if (b != '.') {\n                        if (b == '-') {\n                            sign = -1;\n                        }\n                        else {\n                            value = 10 * value + (b - '0');\n                        }\n                    }\n                }\n                value *= sign;\n                int length = delimiter - offset;\n                slice.get(offset, tmp, 0, length);\n                dictionary.lookup(hash(tmp, length), tmp, length, slices.size()).update(stripe, value);\n                offset = i;\n            }\n        }\n\n        @Override\n        protected void compute() {\n            if (min == max) {\n                computeSlice(min);\n            }\n            else {\n                int mid = (min + max) / 2;\n                var low = new AggregationTask(dictionary, slices, min, mid);\n                var high = new AggregationTask(dictionary, slices, mid + 1, max);\n                var fork = high.fork();\n                low.compute();\n                fork.join();\n            }\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        int maxChunkSize = 10 << 20; // 10MiB\n        try (var raf = new RandomAccessFile(FILE, \"r\");\n                var channel = raf.getChannel()) {\n            long size = channel.size();\n            // make as few mmap calls as possible subject to the 2GiB limit per buffer\n            List<ByteBuffer> rawBuffers = new ArrayList<>();\n            for (long offset = 0; offset < size - 1;) {\n                long end = Math.min(Integer.MAX_VALUE, size - offset);\n                ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, offset, end)\n                        .order(ByteOrder.LITTLE_ENDIAN);\n                boolean lastSlice = end != Integer.MAX_VALUE;\n                int limit = lastSlice\n                        ? (int) end\n                        : findLastNewLine(buffer);\n                rawBuffers.add(buffer.limit(limit));\n                offset += limit;\n            }\n\n            // now slice them up for parallel processing\n            var slices = new ArrayList<ByteBuffer>();\n            for (ByteBuffer rawBuffer : rawBuffers) {\n                for (int offset = 0; offset < rawBuffer.limit();) {\n                    int chunkSize = Math.min(rawBuffer.limit() - offset, maxChunkSize);\n                    int target = offset + chunkSize;\n                    int limit = target >= rawBuffer.limit()\n                            ? rawBuffer.limit()\n                            : findLastNewLine(rawBuffer, target);\n                    int adjustment = rawBuffer.get(offset) == '\\n' ? 1 : 0;\n                    var slice = rawBuffer.slice(offset + adjustment, limit - offset - adjustment).order(ByteOrder.LITTLE_ENDIAN);\n                    slices.add(slice);\n                    offset = limit;\n                }\n            }\n\n            try (var fjp = new ForkJoinPool(Runtime.getRuntime().availableProcessors())) {\n                Dictionary dictionary = new Dictionary();\n                fjp.submit(new AggregationTask(dictionary, slices)).join();\n                var map = new TreeMap<String, ResultRow>();\n                dictionary.forEach(slot -> map.put(slot.toKey(), slot.toResultRow()));\n                System.out.println(map);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_roman_r_m.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.File;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.util.TreeMap;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_roman_r_m {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static Unsafe UNSAFE;\n\n    private static long broadcast(byte b) {\n        return 0x101010101010101L * b;\n    }\n\n    private static final long SEMICOLON_MASK = broadcast((byte) ';');\n    private static final long LINE_END_MASK = broadcast((byte) '\\n');\n    private static final long DOT_MASK = broadcast((byte) '.');\n    private static final long ZEROES_MASK = broadcast((byte) '0');\n\n    // from netty\n\n    /**\n     * Applies a compiled pattern to given word.\n     * Returns a word where each byte that matches the pattern has the highest bit set.\n     */\n    private static long applyPattern(final long word, final long pattern) {\n        long input = word ^ pattern;\n        long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;\n        return ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);\n    }\n\n    static long nextNewline(long from, MemorySegment ms) {\n        long start = from;\n        long i;\n        long next = ms.get(ValueLayout.JAVA_LONG_UNALIGNED, start);\n        while ((i = applyPattern(next, LINE_END_MASK)) == 0) {\n            start += 8;\n            next = ms.get(ValueLayout.JAVA_LONG_UNALIGNED, start);\n        }\n        return start + Long.numberOfTrailingZeros(i) / 8;\n    }\n\n    static int hashFull(long word) {\n        return (int) (word ^ (word >>> 32));\n    }\n\n    static int hashPartial(long word, int bytes) {\n        long h = Long.reverseBytes(word) >>> (8 * (8 - bytes));\n        return (int) (h ^ (h >>> 32));\n    }\n\n    public static void main(String[] args) throws Exception {\n        Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n        f.setAccessible(true);\n        UNSAFE = (Unsafe) f.get(null);\n\n        long fileSize = new File(FILE).length();\n\n        var channel = FileChannel.open(Paths.get(FILE));\n        MemorySegment ms = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.ofConfined());\n\n        int numThreads = fileSize > Integer.MAX_VALUE ? Runtime.getRuntime().availableProcessors() : 1;\n        long chunk = fileSize / numThreads;\n\n        var bounds = IntStream.range(0, numThreads).mapToLong(i -> {\n            boolean lastChunk = i == numThreads - 1;\n            return lastChunk ? fileSize : nextNewline((i + 1) * chunk, ms);\n        }).toArray();\n\n        ms.unload();\n\n        var result = IntStream.range(0, numThreads)\n                .parallel()\n                .mapToObj(i -> {\n                    try {\n                        long segmentStart = i == 0 ? 0 : bounds[i - 1] + 1;\n                        long segmentEnd = bounds[i];\n                        var segment = channel.map(FileChannel.MapMode.READ_ONLY, segmentStart, segmentEnd - segmentStart, Arena.ofConfined());\n\n                        var resultStore = new ResultStore();\n                        var station = new ByteString(segment);\n                        long offset = segment.address();\n                        long end = offset + segment.byteSize();\n                        long tailMask;\n                        while (offset < end) {\n                            // parsing station name\n                            long start = offset;\n                            long next = UNSAFE.getLong(offset);\n                            long pattern = applyPattern(next, SEMICOLON_MASK);\n                            int bytes;\n                            if (pattern == 0) {\n                                station.hash = hashFull(next);\n                                do {\n                                    offset += 8;\n                                    next = UNSAFE.getLong(offset);\n                                    pattern = applyPattern(next, SEMICOLON_MASK);\n                                } while (pattern == 0);\n\n                                bytes = Long.numberOfTrailingZeros(pattern) / 8;\n                                offset += bytes;\n                                tailMask = ((1L << (8 * bytes)) - 1);\n                            }\n                            else {\n                                bytes = Long.numberOfTrailingZeros(pattern) / 8;\n                                offset += bytes;\n                                tailMask = ((1L << (8 * bytes)) - 1);\n\n                                station.hash = hashPartial(next, bytes);\n                            }\n\n                            int len = (int) (offset - start);\n                            station.offset = start;\n                            station.len = len;\n                            station.tail = next & tailMask;\n\n                            offset++;\n\n                            // parsing temperature\n                            // TODO next may contain temperature as well, maybe try using it if we know the full number is there\n                            // 8 - bytes >= 5 -> bytes <= 3\n                            long val;\n                            if (end - offset >= 8) {\n                                long encodedVal = UNSAFE.getLong(offset);\n\n                                int neg = 1 - Integer.bitCount((int) (encodedVal & 0x10));\n                                encodedVal >>>= 8 * neg;\n\n                                long numLen = applyPattern(encodedVal, DOT_MASK);\n                                numLen = Long.numberOfTrailingZeros(numLen) / 8;\n\n                                encodedVal ^= ZEROES_MASK;\n\n                                int intPart = (int) (encodedVal & ((1 << (8 * numLen)) - 1));\n                                intPart <<= 8 * (2 - numLen);\n                                intPart *= (100 * 256 + 10);\n                                intPart = (intPart & 0x3FF80) >>> 8;\n\n                                int frac = (int) ((encodedVal >>> (8 * (numLen + 1))) & 0xFF);\n\n                                offset += neg + numLen + 3; // 1 for . + 1 for fractional part + 1 for new line char\n                                int sign = 1 - 2 * neg;\n                                val = sign * (intPart + frac);\n                            }\n                            else {\n                                int neg = 1 - Integer.bitCount(UNSAFE.getByte(offset) & 0x10);\n                                offset += neg;\n\n                                val = UNSAFE.getByte(offset++) - '0';\n                                byte b;\n                                while ((b = UNSAFE.getByte(offset++)) != '.') {\n                                    val = val * 10 + (b - '0');\n                                }\n                                b = UNSAFE.getByte(offset);\n                                val = val * 10 + (b - '0');\n                                offset += 2;\n                                val *= 1 - (2L * neg);\n                            }\n\n                            resultStore.update(station, (int) val);\n                        }\n\n                        segment.unload();\n\n                        return resultStore.toMap();\n                    }\n                    catch (Exception e) {\n                        throw new RuntimeException(e);\n                    }\n                }).reduce((m1, m2) -> {\n                    m2.forEach((k, v) -> m1.merge(k, v, ResultRow::merge));\n                    return m1;\n                });\n\n        System.out.println(result.get());\n    }\n\n    static final class ByteString {\n\n        private final MemorySegment ms;\n        private long offset;\n        private int len = 0;\n        private int hash = 0;\n        private long tail = 0L;\n\n        ByteString(MemorySegment ms) {\n            this.ms = ms;\n        }\n\n        public String asString(byte[] reusable) {\n            UNSAFE.copyMemory(null, offset, reusable, Unsafe.ARRAY_BYTE_BASE_OFFSET, len);\n            return new String(reusable, 0, len);\n        }\n\n        public ByteString copy() {\n            var copy = new ByteString(ms);\n            copy.offset = this.offset;\n            copy.len = this.len;\n            copy.hash = this.hash;\n            copy.tail = this.tail;\n            return copy;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n\n            ByteString that = (ByteString) o;\n\n            if (len != that.len)\n                return false;\n\n            for (int i = 0; i + 7 < len; i += 8) {\n                long l1 = UNSAFE.getLong(offset + i);\n                long l2 = UNSAFE.getLong(that.offset + i);\n                if (l1 != l2) {\n                    return false;\n                }\n            }\n            return this.tail == that.tail;\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public String toString() {\n            byte[] buf = new byte[100];\n            return asString(buf);\n        }\n    }\n\n    private static final class ResultRow {\n        long min;\n        long sum;\n        long max;\n        int count;\n\n        public ResultRow(int[] values) {\n            min = values[0];\n            max = values[1];\n            sum = values[2];\n            count = values[3];\n        }\n\n        public String toString() {\n            return round(min / 10.0) + \"/\" + round(sum / 10.0 / count) + \"/\" + round(max / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public ResultRow merge(ResultRow other) {\n            this.min = Math.min(this.min, other.min);\n            this.max = Math.max(this.max, other.max);\n            this.sum += other.sum;\n            this.count += other.count;\n            return this;\n        }\n    }\n\n    static class ResultStore {\n        private static final int SIZE = 16384;\n        private final ByteString[] keys = new ByteString[SIZE];\n        private final int[][] values = new int[SIZE][];\n\n        void update(ByteString s, int value) {\n            int h = s.hashCode();\n            int idx = (SIZE - 1) & h;\n\n            var keys = this.keys;\n\n            int idx0 = idx;\n            int i = 0;\n            while (true) {\n                if (keys[idx] != null && keys[idx].equals(s)) {\n                    values[idx][0] = Math.min(values[idx][0], value);\n                    values[idx][1] = Math.max(values[idx][1], value);\n                    values[idx][2] += value;\n                    values[idx][3] += 1;\n                    return;\n                }\n                else if (keys[idx] == null) {\n                    keys[idx] = s.copy();\n                    values[idx] = new int[4];\n                    values[idx][0] = value;\n                    values[idx][1] = value;\n                    values[idx][2] = value;\n                    values[idx][3] = 1;\n                    return;\n                }\n                else {\n                    i++;\n                    idx = (idx0 + i * i) % SIZE;\n                }\n            }\n        }\n\n        TreeMap<String, ResultRow> toMap() {\n            byte[] buf = new byte[100];\n            var result = new TreeMap<String, ResultRow>();\n            for (int i = 0; i < SIZE; i++) {\n                if (keys[i] != null) {\n                    result.put(keys[i].asString(buf), new ResultRow(values[i]));\n                }\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_royvanrijn.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.stream.Collectors;\n\nimport sun.misc.Unsafe;\n\n/**\n * Changelog:\n *\n * Initial submission:               62000 ms\n * Chunked reader:                   16000 ms\n * Optimized parser:                 13000 ms\n * Branchless methods:               11000 ms\n * Adding memory mapped files:       6500 ms (based on bjhara's submission)\n * Skipping string creation:         4700 ms\n * Custom hashmap...                 4200 ms\n * Added SWAR token checks:          3900 ms\n * Skipped String creation:          3500 ms (idea from kgonia)\n * Improved String skip:             3250 ms\n * Segmenting files:                 3150 ms (based on spullara's code)\n * Not using SWAR for EOL:           2850 ms\n * Inlining hash calculation:        2450 ms\n * Replacing branchless code:        2200 ms (sometimes we need to kill the things we love)\n * Added unsafe memory access:       1900 ms (keeping the long[] small and local)\n * Fixed bug, UNSAFE bytes String:   1850 ms\n * Separate hash from entries:       1550 ms\n * Various tweaks for Linux/cache    1550 ms (should/could make a difference on target machine)\n * Improved layout/predictability:   1400 ms\n * Delayed String creation again:    1350 ms\n * Remove writing to buffer:         1335 ms\n * Optimized collecting at the end:  1310 ms\n * Adding a lot of comments:         priceless\n * Changed to flyweight byte[]:      1290 ms (adds even more Unsafe, was initially slower, now faster)\n * More LOC now parallel:            1260 ms (moved more to processMemoryArea, recombining in ConcurrentHashMap)\n * Storing only the address:         1240 ms (this is now faster, tried before, was slower)\n * Unrolling scan-loop:              1200 ms (seems to help, perhaps even more on target machine)\n * Adding more readable reader:      1300 ms (scores got worse on target machine anyway)\n *\n * Using old x86 MacBook and perf:   3500 ms (different machine for testing)\n * Decided to rewrite loop for 16 b: 3050 ms\n * Small changes, limited heap:      2950 ms\n *\n * I have some instructions that could be removed, but faster with...\n *\n * Big thanks to Francesco Nigro, Thomas Wuerthinger, Quan Anh Mai and many others for ideas.\n *\n * Follow me at: @royvanrijn\n */\npublic class CalculateAverage_royvanrijn {\n\n    private static final String FILE = \"./measurements.txt\";\n    // private static final String FILE = \"src/test/resources/samples/measurements-1.txt\";\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    // Twice the processors, smoothens things out.\n    private static final int PROCESSORS = Runtime.getRuntime().availableProcessors();\n\n    /**\n     * Flyweight entry in a byte[], max 128 bytes.\n     * <p>\n     * long: sum\n     * int:  min\n     * int:  max\n     * int:  count\n     * byte: length\n     * byte[]: cityname\n     */\n    // ------------------------------------------------------------------------\n    private static final int ENTRY_LENGTH = (Unsafe.ARRAY_BYTE_BASE_OFFSET);\n    private static final int ENTRY_SUM = (ENTRY_LENGTH + Byte.BYTES);\n    private static final int ENTRY_MIN = (ENTRY_SUM + Long.BYTES);\n    private static final int ENTRY_MAX = (ENTRY_MIN + Integer.BYTES);\n    private static final int ENTRY_COUNT = (ENTRY_MAX + Integer.BYTES);\n    private static final int ENTRY_NAME = (ENTRY_COUNT + Integer.BYTES);\n    private static final int ENTRY_NAME_8 = ENTRY_NAME + 8;\n    private static final int ENTRY_NAME_16 = ENTRY_NAME + 16;\n\n    private static final int ENTRY_BASESIZE_WHITESPACE = ENTRY_NAME + 7; // with enough empty bytes to fill a long\n    // ------------------------------------------------------------------------\n    private static final int PREMADE_MAX_SIZE = 1 << 5; // pre-initialize some entries in memory, keep them close\n    private static final int PREMADE_ENTRIES = 512; // amount of pre-created entries we should use\n    private static final int TABLE_SIZE = 1 << 19; // large enough for the contest.\n    private static final int TABLE_MASK = (TABLE_SIZE - 1);\n\n    // Idea of thomaswue, don't wait for slow unmap:\n    private static void spawnWorker() throws IOException {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> workerCommand = new ArrayList<>();\n        info.command().ifPresent(workerCommand::add);\n        info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args)));\n        workerCommand.add(\"--worker\");\n        new ProcessBuilder()\n                .command(workerCommand)\n                .inheritIO()\n                .redirectOutput(ProcessBuilder.Redirect.PIPE)\n                .start()\n                .getInputStream()\n                .transferTo(System.out);\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        if (args.length == 0 || !(\"--worker\".equals(args[0]))) {\n            spawnWorker();\n            return;\n        }\n\n        // Calculate input segments.\n        final FileChannel fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n        final long fileSize = fileChannel.size();\n        final long segmentSize = (fileSize + PROCESSORS - 1) / PROCESSORS;\n        final long mapAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global()).address();\n\n        final Thread[] parallelThreads = new Thread[PROCESSORS - 1];\n\n        // This is where the entries will land:\n        final ConcurrentHashMap<String, byte[]> measurements = new ConcurrentHashMap(1 << 10);\n\n        // We create separate threads for twice the amount of processors.\n        long lastAddress = mapAddress;\n        final long endOfFile = mapAddress + fileSize;\n        for (int i = 0; i < PROCESSORS - 1; ++i) {\n\n            final long fromAddress = lastAddress;\n            final long toAddress = Math.min(endOfFile, fromAddress + segmentSize);\n\n            final Thread thread = new Thread(() -> {\n                // The actual work is done here:\n                final byte[][] table = processMemoryArea(fromAddress, toAddress, fromAddress == mapAddress);\n\n                for (byte[] entry : table) {\n                    if (entry != null) {\n                        measurements.merge(entryToName(entry), entry, CalculateAverage_royvanrijn::mergeEntry);\n                    }\n                }\n            });\n            thread.start(); // start a.s.a.p.\n            parallelThreads[i] = thread;\n            lastAddress = toAddress;\n        }\n\n        // Use the current thread for the part of memory:\n        final byte[][] table = processMemoryArea(lastAddress, mapAddress + fileSize, false);\n\n        for (byte[] entry : table) {\n            if (entry != null) {\n                measurements.merge(entryToName(entry), entry, CalculateAverage_royvanrijn::mergeEntry);\n            }\n        }\n        // Wait for all threads to finish:\n        for (Thread thread : parallelThreads) {\n            // Can we implement work-stealing? Not sure how...\n            thread.join();\n        }\n\n        // If we don't reach start of file,\n        System.out.print(\"{\" +\n                measurements.entrySet().stream().sorted(Map.Entry.comparingByKey())\n                        .map(entry -> entry.getKey() + '=' + entryValuesToString(entry.getValue()))\n                        .collect(Collectors.joining(\", \")));\n        System.out.println(\"}\");\n\n        System.out.close(); // close the stream to stop\n    }\n\n    private static byte[] fillEntry(final byte[] entry, final long fromAddress, final int entryLength, final int temp, final long readBuffer1, final long readBuffer2) {\n        UNSAFE.putLong(entry, ENTRY_SUM, temp);\n        UNSAFE.putInt(entry, ENTRY_MIN, temp);\n        UNSAFE.putInt(entry, ENTRY_MAX, temp);\n        UNSAFE.putInt(entry, ENTRY_COUNT, 1);\n        UNSAFE.putByte(entry, ENTRY_LENGTH, (byte) entryLength);\n        UNSAFE.copyMemory(null, fromAddress, entry, ENTRY_NAME, entryLength - 16);\n        UNSAFE.putLong(entry, ENTRY_NAME + entryLength - 16, readBuffer1);\n        UNSAFE.putLong(entry, ENTRY_NAME + entryLength - 8, readBuffer2);\n        return entry;\n    }\n\n    private static byte[] fillEntry16(final byte[] entry, final int entryLength, final int temp, final long readBuffer1, final long readBuffer2) {\n        UNSAFE.putLong(entry, ENTRY_SUM, temp);\n        UNSAFE.putInt(entry, ENTRY_MIN, temp);\n        UNSAFE.putInt(entry, ENTRY_MAX, temp);\n        UNSAFE.putInt(entry, ENTRY_COUNT, 1);\n        UNSAFE.putByte(entry, ENTRY_LENGTH, (byte) entryLength);\n        UNSAFE.putLong(entry, ENTRY_NAME + entryLength - 16, readBuffer1);\n        UNSAFE.putLong(entry, ENTRY_NAME + entryLength - 8, readBuffer2);\n        return entry;\n    }\n\n    public static void updateEntry(final byte[] entry, final int temp) {\n\n        int entryMin = UNSAFE.getInt(entry, ENTRY_MIN);\n        int entryMax = UNSAFE.getInt(entry, ENTRY_MAX);\n        long entrySum = UNSAFE.getLong(entry, ENTRY_SUM) + temp;\n        int entryCount = UNSAFE.getInt(entry, ENTRY_COUNT) + 1;\n\n        if (temp < entryMin) {\n            UNSAFE.putInt(entry, ENTRY_MIN, temp);\n        }\n        else if (temp > entryMax) {\n            UNSAFE.putInt(entry, ENTRY_MAX, temp);\n        }\n        UNSAFE.putInt(entry, ENTRY_COUNT, entryCount);\n        UNSAFE.putLong(entry, ENTRY_SUM, entrySum);\n    }\n\n    public static byte[] mergeEntry(final byte[] entry, final byte[] merge) {\n\n        long sum = UNSAFE.getLong(merge, ENTRY_SUM);\n        final int mergeMin = UNSAFE.getInt(merge, ENTRY_MIN);\n        final int mergeMax = UNSAFE.getInt(merge, ENTRY_MAX);\n        int count = UNSAFE.getInt(merge, ENTRY_COUNT);\n\n        sum += UNSAFE.getLong(entry, ENTRY_SUM);\n        count += UNSAFE.getInt(entry, ENTRY_COUNT);\n\n        int entryMin = UNSAFE.getInt(entry, ENTRY_MIN);\n        int entryMax = UNSAFE.getInt(entry, ENTRY_MAX);\n        entryMin = Math.min(entryMin, mergeMin);\n        entryMax = Math.max(entryMax, mergeMax);\n        UNSAFE.putInt(entry, ENTRY_MIN, entryMin);\n        UNSAFE.putInt(entry, ENTRY_MAX, entryMax);\n\n        UNSAFE.putLong(entry, ENTRY_SUM, sum);\n        UNSAFE.putInt(entry, ENTRY_COUNT, count);\n        return entry;\n    }\n\n    private static String entryToName(final byte[] entry) {\n        // Get the length from memory:\n        int length = UNSAFE.getByte(entry, ENTRY_LENGTH);\n\n        byte[] name = new byte[length];\n        UNSAFE.copyMemory(entry, ENTRY_NAME, name, Unsafe.ARRAY_BYTE_BASE_OFFSET, length);\n\n        // Create a new String with the existing byte[]:\n        return new String(name, StandardCharsets.UTF_8).trim();\n    }\n\n    private static String entryValuesToString(final byte[] entry) {\n        return (round(UNSAFE.getInt(entry, ENTRY_MIN))\n                + \"/\" +\n                round((1.0 * UNSAFE.getLong(entry, ENTRY_SUM)) /\n                        UNSAFE.getInt(entry, ENTRY_COUNT))\n                + \"/\" +\n                round(UNSAFE.getInt(entry, ENTRY_MAX)));\n    }\n\n    // Print a piece of memory:\n    // For debug.\n    private static String printMemory(final Object target, final long address, int length) {\n        String result = \"\";\n        for (int i = 0; i < length; i++) {\n            result += (char) UNSAFE.getByte(target, address + i);\n        }\n        return result;\n    }\n\n    // Print a piece of memory:\n    // For debug.\n    private static String printMemory(final long value, int length) {\n        String result = \"\";\n        for (int i = 0; i < length; i++) {\n            result += (char) ((value >> (i << 3)) & 0xFF);\n        }\n        return result;\n    }\n\n    private static double round(final double value) {\n        return Math.round(value) / 10.0;\n    }\n\n    private static final class Reader {\n\n        private long ptr;\n        private long readBuffer1;\n        private long readBuffer2;\n\n        private long hash;\n        private long entryStart;\n        private int entryLength; // in bytes rounded to nearest 16\n\n        private final long endAddress;\n\n        Reader(final long startAddress, final long endAddress, final boolean isFileStart) {\n\n            this.ptr = startAddress;\n            this.endAddress = endAddress;\n\n            // Adjust start to next delimiter:\n            if (!isFileStart) {\n                ptr--;\n                while (ptr < endAddress) {\n                    if (UNSAFE.getByte(ptr++) == '\\n') {\n                        break;\n                    }\n                }\n            }\n        }\n\n        private void processStart() {\n            hash = 0;\n            entryStart = ptr;\n            entryLength = 0;\n        }\n\n        private boolean hasNext() {\n            return (ptr < endAddress);\n        }\n\n        private static final long DELIMITER_MASK = 0x3B3B3B3B3B3B3B3BL;\n\n        private boolean readNext() {\n\n            long lastRead = UNSAFE.getLong(ptr);\n\n            entryLength += 16;\n\n            // Find delimiter and create mask for long1\n            long comparisonResult1 = (lastRead ^ DELIMITER_MASK);\n            long highBitMask1 = (comparisonResult1 - 0x0101010101010101L) & (~comparisonResult1 & 0x8080808080808080L);\n\n            boolean noContent1 = highBitMask1 == 0;\n            long mask1 = noContent1 ? 0 : ~((highBitMask1 >>> 7) - 1);\n            int position1 = noContent1 ? 0 : 1 + (Long.numberOfTrailingZeros(highBitMask1) >> 3);\n\n            readBuffer1 = lastRead & ~mask1;\n            hash ^= readBuffer1;\n\n            int delimiter1 = position1 == 0 ? 0 : position1; // not nnecessary, but faster?\n\n            if (delimiter1 != 0) {\n                hash ^= hash >> 32;\n                readBuffer2 = 0;\n                ptr += delimiter1;\n                return false;\n            }\n\n            lastRead = UNSAFE.getLong(ptr + 8);\n\n            // Repeat for long2\n            long comparisonResult2 = (lastRead ^ DELIMITER_MASK);\n            long highBitMask2 = (comparisonResult2 - 0x0101010101010101L) & (~comparisonResult2 & 0x8080808080808080L);\n            boolean noContent2 = highBitMask2 == 0;\n            long mask2 = noContent2 ? 0 : ~((highBitMask2 >>> 7) - 1);\n            int position2 = noContent2 ? 0 : 1 + (Long.numberOfTrailingZeros(highBitMask2) >> 3);\n\n            // Apply masks\n            readBuffer2 = lastRead & ~mask2;\n            hash ^= readBuffer2;\n\n            int delimiter2 = position2 == 0 ? 0 : position2 + 8; // not necessary, but faster?\n\n            hash ^= hash >> 32;\n\n            if (delimiter2 != 0) {\n                ptr += delimiter2;\n                return false;\n            }\n            ptr += 16;\n            return true;\n        }\n\n        private int processEndAndGetTemperature() {\n            finalizeHash();\n            return readTemperature();\n        }\n\n        private void finalizeHash() {\n            hash ^= hash >> 17; // extra entropy\n        }\n\n        private static final long DOT_BITS = 0x10101000;\n        private static final long MAGIC_MULTIPLIER = (100 * 0x1000000 + 10 * 0x10000 + 1);\n\n        // Awesome idea of merykitty:\n        private int readTemperature() {\n            // This is the number part: X.X, -X.X, XX.x or -XX.X\n            final long numberBytes = UNSAFE.getLong(ptr);\n            final long invNumberBytes = ~numberBytes;\n\n            final int dotPosition = Long.numberOfTrailingZeros(invNumberBytes & DOT_BITS);\n\n            // Calculates the sign\n            final long signed = (invNumberBytes << 59) >> 63;\n            final int min28 = (dotPosition ^ 0b11100);\n            final long minusFilter = ~(signed & 0xFF);\n            // Use the pre-calculated decimal position to adjust the values\n            final long digits = ((numberBytes & minusFilter) << min28) & 0x0F000F0F00L;\n\n            // Update the pointer here, bit awkward, but we have all the data\n            ptr += (dotPosition >> 3) + 3;\n\n            // Multiply by a magic (100 * 0x1000000 + 10 * 0x10000 + 1), to get the result\n            final long absValue = ((digits * MAGIC_MULTIPLIER) >>> 32) & 0x3FF;\n            // And perform abs()\n            return (int) ((absValue + signed) ^ signed); // non-patented method of doing the same trick\n        }\n\n        private boolean matches(final byte[] entry) {\n            int step = 0;\n            for (; step < entryLength - 16;) {\n                if (compare(null, entryStart + step, entry, ENTRY_NAME + step)) {\n                    return false;\n                }\n                step += 8;\n            }\n            if (compare(readBuffer1, entry, ENTRY_NAME + step)) {\n                return false;\n            }\n            step += 8;\n            if (compare(readBuffer2, entry, ENTRY_NAME + step)) {\n                return false;\n            }\n            return true;\n        }\n\n        private boolean matches16(final byte[] entry) {\n            if (compare(readBuffer1, entry, ENTRY_NAME)) {\n                return false;\n            }\n            if (compare(readBuffer2, entry, ENTRY_NAME + 8)) {\n                return false;\n            }\n            return true;\n        }\n    }\n\n    private static byte[][] processMemoryArea(final long startAddress, final long endAddress, boolean isFileStart) {\n\n        final byte[][] table = new byte[TABLE_SIZE][];\n        final byte[][] preConstructedEntries = new byte[PREMADE_ENTRIES][ENTRY_BASESIZE_WHITESPACE + PREMADE_MAX_SIZE];\n\n        final Reader reader = new Reader(startAddress, endAddress, isFileStart);\n\n        byte[] entry;\n        int entryCount = 0;\n\n        // Find the correct starting position\n        while (reader.hasNext()) {\n\n            reader.processStart();\n\n            if (!reader.readNext()) {\n                // First 16 bytes:\n\n                int temperature = reader.processEndAndGetTemperature();\n\n                // Find or insert the entry:\n                int index = (int) (reader.hash & TABLE_MASK);\n                while (true) {\n                    entry = table[index];\n                    if (entry == null) {\n                        byte[] entryBytes = (entryCount < PREMADE_ENTRIES) ? preConstructedEntries[entryCount++]\n                                : new byte[ENTRY_BASESIZE_WHITESPACE + 16]; // with enough room\n                        table[index] = fillEntry16(entryBytes, 16, temperature, reader.readBuffer1, reader.readBuffer2);\n                        break;\n                    }\n                    else if (reader.matches16(entry)) {\n                        updateEntry(entry, temperature);\n                        break;\n                    }\n                    else {\n                        // Move to the next index\n                        index = (index + 1) & TABLE_MASK;\n                    }\n                }\n                continue;\n            }\n            while (reader.readNext())\n                ;\n\n            int temperature = reader.processEndAndGetTemperature();\n\n            // Find or insert the entry:\n            int index = (int) (reader.hash & TABLE_MASK);\n            while (true) {\n                entry = table[index];\n                if (entry == null) {\n                    int length = reader.entryLength;\n                    byte[] entryBytes = (length < PREMADE_MAX_SIZE && entryCount < PREMADE_ENTRIES) ? preConstructedEntries[entryCount++]\n                            : new byte[ENTRY_BASESIZE_WHITESPACE + length]; // with enough room\n                    table[index] = fillEntry(entryBytes, reader.entryStart, length, temperature, reader.readBuffer1, reader.readBuffer2);\n                    break;\n                }\n                else if (reader.matches(entry)) {\n                    updateEntry(entry, temperature);\n                    break;\n                }\n                else {\n                    // Move to the next index\n                    index = (index + 1) & TABLE_MASK;\n                }\n            }\n        }\n        return table;\n    }\n\n    private static boolean compare(final Object object1, final long address1, final Object object2, final long address2) {\n        return UNSAFE.getLong(object1, address1) != UNSAFE.getLong(object2, address2);\n    }\n\n    private static boolean compare(final long value1, final Object object2, final long address2) {\n        return value1 != UNSAFE.getLong(object2, address2);\n    }\n\n    /*\n     * `___` ___ ___ _ ___` ` ___ ` _ ` _ ` _` ___\n     * / ` \\| _ \\ __| \\| \\ \\ / /_\\ | | | | | | __|\n     * | () | _ / __|| . |\\ V / _ \\| |_| |_| | ._|\n     * \\___/|_| |___|_|\\_| \\_/_/ \\_\\___|\\___/|___|\n     * ---------------- BETTER SOFTWARE, FASTER --\n     *\n     * https://www.openvalue.eu/\n     */\n\n    private static Unsafe initUnsafe() {\n        try {\n            final Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_rprabhu.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\npublic class CalculateAverage_rprabhu {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static record Measurement(String station, double value) {\n        private Measurement(String[] parts) {\n            this(parts[0], Double.parseDouble(parts[1]));\n        }\n    }\n\n    private static record ResultRow(double min, double mean, double max) {\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    };\n\n    private static class MeasurementAggregator {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n    }\n\n    private static ConcurrentHashMap<String, MeasurementAggregator> map = new ConcurrentHashMap<>();\n\n    private static final int TASK_CHUNK = 50000;\n\n    private static class TaskExecutor implements Runnable {\n        List<String> list;\n\n        TaskExecutor(List<String> list) {\n            this.list = list;\n        }\n\n        @Override\n        public void run() {\n            for (String str : list) {\n                // System.out.println(str);\n                // String[] values = str.split(\";\");\n                int index = str.indexOf(';');\n                String station = str.substring(0, index);\n                double val = Double.parseDouble(str.substring(index + 1));\n                // double val = Double.parseDouble(values[1]);\n                MeasurementAggregator aggr = map.getOrDefault(station, new MeasurementAggregator());\n                aggr.count += 1;\n                aggr.sum += val;\n                aggr.max = (val >= aggr.max) ? val : aggr.max; // Math.max(aggr.max, val);\n                aggr.min = (val <= aggr.min) ? val : aggr.min; // Math.min(aggr.min, val);\n                map.put(station, aggr);\n            }\n\n        }\n\n    }\n\n    private static class TaskScheduler {\n        ExecutorService executor;\n        List<String> list = new ArrayList<>(TASK_CHUNK);\n\n        TaskScheduler(ExecutorService executor) {\n            this.executor = executor;\n        }\n\n        void push(String line) {\n            // System.out.println(\"adding: \" + line);\n            list.add(line);\n            if (list.size() >= TASK_CHUNK) {\n                executor.submit(new TaskExecutor(list));\n                list = new ArrayList<>(TASK_CHUNK);\n            }\n        }\n\n        void completeRemaining() {\n            // System.out.println(\"Completing remaining: \" + list.size());\n            if (!list.isEmpty()) {\n                // System.out.println(\"Scheduling remaining\");\n                executor.submit(new TaskExecutor(list));\n            }\n        }\n\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n\n        // ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();\n        // ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());\n        ExecutorService executor = Executors.newCachedThreadPool();\n        TaskScheduler scheduler = new TaskScheduler(executor);\n        Files.lines(Paths.get(FILE), StandardCharsets.UTF_8).forEach(line -> {\n            scheduler.push(line);\n        });\n        scheduler.completeRemaining();\n        executor.shutdown();\n        executor.awaitTermination(600, TimeUnit.SECONDS);\n\n        Map<String, ResultRow> sortedResult = new TreeMap<>();\n        map.forEach(\n                (key, value) -> sortedResult.put(key, new ResultRow(value.min, value.sum / value.count, value.max)));\n        System.out.println(sortedResult);\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_santanu.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.DoubleSummaryStatistics;\nimport java.util.Map;\nimport java.util.function.Function;\nimport java.util.stream.Collectors;\n\nimport static java.lang.Double.parseDouble;\nimport static java.lang.String.format;\nimport static java.util.stream.Collectors.summarizingDouble;\n\npublic class CalculateAverage_santanu {\n    private static final String DATA_FILE = \"./measurements.txt\";\n    private static final String PRINT_FORMAT = \"%s=%.1f/%.1f/%.1f\";\n\n    public static void main(String[] args) throws IOException {\n\n        Map<String, DoubleSummaryStatistics> summaryStatisticsMap = processMeasurements();\n\n        printResults(summaryStatisticsMap);\n    }\n\n    private static final Function<String, StationMeasurementPair> stationMeasurements = row -> {\n        int splitPosition = row.indexOf(\";\");\n        return new StationMeasurementPair(row.substring(0, splitPosition), parseDouble(row.substring(splitPosition + 1)));\n    };\n\n    private static Map<String, DoubleSummaryStatistics> processMeasurements() throws IOException {\n        return Files.lines(Path.of(DATA_FILE)).map(stationMeasurements).parallel()\n                .collect(Collectors.groupingBy(\n                        StationMeasurementPair::station, summarizingDouble(StationMeasurementPair::measurement)));\n    }\n\n    private static void printResults(Map<String, DoubleSummaryStatistics> collect) {\n\n        String result = collect.entrySet().parallelStream().sorted(Map.Entry.comparingByKey()).map(s -> format(PRINT_FORMAT, s.getKey(),\n                s.getValue().getMin(), s.getValue().getAverage(), s.getValue().getMax())).collect(Collectors.joining(\", \"));\n\n        System.out.println(\"{\" + result + \"}\");\n    }\n\n    private record StationMeasurementPair(String station, Double measurement) {\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_seijikun.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\n\nimport java.io.IOException;\nimport java.io.PrintStream;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.TreeMap;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\n\npublic class CalculateAverage_seijikun {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static class MeasurementAggregator {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        // final long startTs = System.currentTimeMillis();\n        private long sum = 0;\n        private long count = 0;\n\n        private double mean = 0;\n\n        public void finish() {\n            double sum = this.sum / 10.0;\n            mean = sum / (double) count;\n        }\n\n        public void printInto(PrintStream out) {\n            double min = (double) this.min / 10.0;\n            double max = (double) this.max / 10.0;\n            out.printf(\"%.1f/%.1f/%.1f\", min, mean, max);\n        }\n    }\n\n    public static class StationIdent {\n        private final byte[] name;\n        private final int nameHash;\n\n        public StationIdent(byte[] name, int nameHash) {\n            this.name = name;\n            this.nameHash = nameHash;\n        }\n\n        @Override\n        public int hashCode() {\n            return nameHash;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            var other = (StationIdent) obj;\n            if (other.name.length != name.length) {\n                return false;\n            }\n            return Arrays.equals(name, other.name);\n        }\n    }\n\n    public static class ChunkReader implements Runnable {\n        RandomAccessFile file;\n\n        // Start offset of this chunk\n        private final long startOffset;\n        // end offset of this chunk\n        private final long endOffset;\n\n        // state\n        private int chunkSize = 0;\n        private MappedByteBuffer buffer = null;\n        private MemorySegment memorySegment = null;\n        private int ptr = 0;\n        private HashMap<StationIdent, MeasurementAggregator> workSet;\n\n        public ChunkReader(RandomAccessFile file, long startOffset, long endOffset) {\n            this.file = file;\n            this.startOffset = startOffset;\n            this.endOffset = endOffset;\n        }\n\n        // private StationIdent readStationName() {\n        // int startPtr = ptr;\n        // int hashCode = 0;\n        // int hashBytePtr = 0;\n        // byte c;\n        // while ((c = buffer.get(ptr++)) != ';') {\n        // hashCode ^= ((int) c) << (hashBytePtr * 8);\n        // hashBytePtr = (hashBytePtr + 1) % 4;\n        // }\n        // byte[] stationNameBfr = new byte[ptr - startPtr - 1];\n        // buffer.get(startPtr, stationNameBfr);\n        // return new StationIdent(stationNameBfr, hashCode);\n        // }\n\n        private StationIdent readStationName() {\n            final var VECTOR_SPECIES = ByteVector.SPECIES_256;\n\n            if (chunkSize - ptr - 100 < VECTOR_SPECIES.length()) { // fallback\n                int startPtr = ptr;\n                while (buffer.get(ptr++) != ';') {\n                }\n                byte[] stationNameBfr = new byte[ptr - startPtr - 1];\n                buffer.get(startPtr, stationNameBfr);\n                return new StationIdent(stationNameBfr, Arrays.hashCode(stationNameBfr) ^ stationNameBfr.length);\n            }\n            else { // SIMD\n                int sepIdx = 0;\n\n                while (true) {\n                    ByteVector tmp = ByteVector.fromMemorySegment(VECTOR_SPECIES, memorySegment, ptr + sepIdx, ByteOrder.LITTLE_ENDIAN);\n                    final var cmpResult = tmp.compare(VectorOperators.EQ, ';');\n                    if (cmpResult.anyTrue()) {\n                        sepIdx += cmpResult.firstTrue();\n                        break;\n                    }\n                    else {\n                        sepIdx += tmp.length();\n                    }\n                }\n\n                int endPtr = ptr + sepIdx;\n                byte[] stationNameBfr = new byte[endPtr - ptr];\n                buffer.get(ptr, stationNameBfr);\n                ptr = endPtr + 1;\n                return new StationIdent(stationNameBfr, Arrays.hashCode(stationNameBfr) ^ stationNameBfr.length);\n            }\n        }\n\n        private int readTemperature() {\n            int ret = 0;\n            byte c = buffer.get(ptr++);\n            final boolean neg = (c == '-');\n            if (neg) {\n                c = buffer.get(ptr++);\n            }\n\n            do {\n                if (c != '.') {\n                    ret = ret * 10 + c - '0';\n                }\n            } while ((c = buffer.get(ptr++)) != '\\n');\n\n            if (neg)\n                return -ret;\n            return ret;\n        }\n\n        @Override\n        public void run() {\n            workSet = new HashMap<>();\n            if (endOffset - startOffset > Integer.MAX_VALUE) {\n                throw new RuntimeException(\"Mapping a block larger than 2GB is not possible with Java! Welcome to 2024 :)\");\n            }\n            chunkSize = (int) (endOffset - startOffset);\n            try {\n                buffer = file.getChannel().map(FileChannel.MapMode.READ_ONLY, startOffset, chunkSize);\n                memorySegment = MemorySegment.ofBuffer(buffer);\n\n                while (ptr < chunkSize) {\n                    var station = readStationName();\n                    int temp = readTemperature();\n                    var stationWorkSet = workSet.get(station);\n                    if (stationWorkSet == null) {\n                        stationWorkSet = new MeasurementAggregator();\n                        workSet.put(station, stationWorkSet);\n                    }\n                    stationWorkSet.min = Math.min(temp, stationWorkSet.min);\n                    stationWorkSet.max = Math.max(temp, stationWorkSet.max);\n                    stationWorkSet.sum += temp;\n                    stationWorkSet.count += 1;\n                }\n            }\n            catch (Throwable e) {\n                e.printStackTrace();\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private static void printWorkSet(TreeMap<String, MeasurementAggregator> result, PrintStream out) {\n        out.write('{');\n        final var iterator = result.entrySet().iterator();\n        while (iterator.hasNext()) {\n            var entry = iterator.next();\n            out.print(entry.getKey());\n            out.write('=');\n            entry.getValue().printInto(out);\n            if (iterator.hasNext()) {\n                out.print(\", \");\n            }\n        }\n        out.println('}');\n    }\n\n    private static int createChunks(final RandomAccessFile file, final ChunkReader[] chunks) throws IOException {\n        final long fileEndPtr = file.length();\n        final long chunkSize = Math.max(1, fileEndPtr / chunks.length);\n\n        int jobCnt = 0;\n        long chunkStartPtr = 0;\n        final byte[] tmpBuffer = new byte[128];\n        while (chunkStartPtr < fileEndPtr) {\n            long chunkEndPtr = Math.min(chunkStartPtr + chunkSize, fileEndPtr);\n\n            // Seek into file at the calculated chunk end ptr, then extend it until the next\n            // new-line or EOF\n            if (chunkEndPtr < fileEndPtr) {\n                file.seek(Math.max(0, chunkEndPtr - 1));\n                file.read(tmpBuffer);\n                int offset = 0;\n                while (tmpBuffer[offset] != '\\n') {\n                    offset += 1;\n                }\n                chunkEndPtr += offset;\n            }\n\n            chunks[jobCnt] = new ChunkReader(file, chunkStartPtr, chunkEndPtr);\n            jobCnt += 1;\n            chunkStartPtr = chunkEndPtr;\n        }\n        return jobCnt;\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        final RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n\n        int jobCnt = Runtime.getRuntime().availableProcessors();\n\n        final var chunks = new ChunkReader[jobCnt];\n        jobCnt = createChunks(file, chunks);\n\n        try (final var executor = Executors.newFixedThreadPool(jobCnt)) {\n            for (int i = 0; i < jobCnt; ++i) {\n                executor.submit(chunks[i]);\n            }\n            executor.shutdown();\n            final var ignored = executor.awaitTermination(1, TimeUnit.DAYS);\n        }\n\n        // merge chunks\n        final var result = new TreeMap<String, MeasurementAggregator>();\n        for (int i = 0; i < jobCnt; ++i) {\n            chunks[i].workSet.forEach((ident, otherStationWorkSet) -> {\n                final var identStr = new String(ident.name);\n                final var stationWorkSet = result.get(identStr);\n                if (stationWorkSet == null) {\n                    result.put(identStr, otherStationWorkSet);\n                }\n                else {\n                    stationWorkSet.min = Math.min(stationWorkSet.min, otherStationWorkSet.min);\n                    stationWorkSet.max = Math.max(stationWorkSet.max, otherStationWorkSet.max);\n                    stationWorkSet.sum += otherStationWorkSet.sum;\n                    stationWorkSet.count += otherStationWorkSet.count;\n                }\n            });\n        }\n        result.forEach((ignored, meas) -> meas.finish());\n\n        // print in required format\n        printWorkSet(result, System.out);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_semotpan.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.file.StandardOpenOption.READ;\n\npublic class CalculateAverage_semotpan {\n\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var spliterator = new SegmentSpliterator(FILE);\n        var summaryStations = IntStream.range(0, spliterator.segments)\n                .parallel()\n                .mapToObj(segment -> {\n                    var buff = spliterator.buffSegment(segment);\n                    return new SegmentReader(buff);\n                })\n                .flatMap(segmentReader -> segmentReader.values().stream())\n                .collect(Collectors.groupingByConcurrent(StationSummary::station));\n\n        // Complexity: O(stations * segments)\n        var output = new TreeMap<String, StationSummary>();\n        summaryStations.forEach((station, summaries) -> {\n            var summary = summaries.stream()\n                    .reduce(new StationSummary(), (identity, acc) -> {\n                        identity.min = Integer.min(identity.min, acc.min);\n                        identity.max = Integer.max(identity.max, acc.max);\n                        identity.sum += acc.sum;\n                        identity.count += acc.count;\n                        return identity;\n                    });\n            output.put(station, summary);\n        });\n\n        System.out.println(output);\n    }\n\n    private static class StationSummary {\n\n        public String station;\n        public int min, max, sum, count;\n\n        StationSummary() {\n            min = Integer.MAX_VALUE;\n            max = Integer.MIN_VALUE;\n        }\n\n        StationSummary(String station, int temperature) {\n            this.station = station;\n            this.min = this.max = this.sum = temperature;\n            this.count = 1;\n        }\n\n        String station() {\n            return station;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        @Override\n        public String toString() {\n            return new StringBuilder()\n                    .append(round((double) min * 0.1)).append('/')\n                    .append(round((double) sum * 0.1 / count))\n                    .append('/').append(round((double) max * 0.1))\n                    .toString();\n        }\n    }\n\n    static class SegmentSpliterator {\n\n        private int segments;\n        private final ByteBuffer[] buffSegments;\n\n        SegmentSpliterator(Path file) throws IOException {\n            this.segments = Runtime.getRuntime().availableProcessors();\n            var fileSize = Files.size(file);\n            var segmentSize = fileSize / segments;\n\n            if (segmentSize <= (1 << 8)) { // small segment: 1 is enough\n                segments = 1;\n            }\n\n            buffSegments = new ByteBuffer[segments];\n\n            var pos = 0L;\n            for (var s = 0; s < segments - 1; s++) {\n                try (var channel = (FileChannel) Files.newByteChannel(FILE, READ)) {\n                    var buff = channel.map(READ_ONLY, pos, segmentSize);\n                    pos = normalize(buff, (int) segmentSize - 1, pos);\n                    buffSegments[s] = buff;\n                }\n            }\n\n            // handle last segment\n            try (var channel = (FileChannel) Files.newByteChannel(FILE, READ)) {\n                var buff = channel.map(READ_ONLY, pos, fileSize - pos);\n                buffSegments[segments - 1] = buff;\n            }\n        }\n\n        private long normalize(ByteBuffer buff, int relativePos, long pos) {\n            while (buff.get(relativePos) != '\\n') {\n                relativePos--;\n            }\n\n            buff.limit(relativePos + 1);\n            return pos + (relativePos + 1);\n        }\n\n        ByteBuffer buffSegment(int index) {\n            return buffSegments[index];\n        }\n    }\n\n    static class SegmentReader {\n\n        private final Map<String, StationSummary> accumulator;\n        private final byte[] keyBuff = new byte[256];\n\n        SegmentReader(ByteBuffer byteBuffer) {\n            accumulator = new HashMap<>();\n            read(byteBuffer);\n        }\n\n        private void read(ByteBuffer buff) {\n            byte b;\n            for (int pos = 0, limit = buff.limit(); buff.hasRemaining(); buff.position(pos)) {\n                // parse station (key)\n                int offset = 0;\n                while ((b = buff.get(pos++)) != ';') {\n                    keyBuff[offset++] = b;\n                }\n\n                // parse temperature (value) as int (1.1 * 10 = 11)\n                int temp = 0;\n                int negative = 1;\n                while (pos != limit && (b = buff.get(pos++)) != '\\n') {\n                    switch (b) {\n                        case '-':\n                            negative = -1;\n                        case '.':\n                            continue;\n                        default:\n                            temp = 10 * temp + (b - '0');\n                    }\n                }\n                temp *= negative;\n\n                // compute station\n                var station = new String(keyBuff, 0, offset);\n                var finalTemp = temp;\n                accumulator.compute(station, (key, summary) -> {\n                    if (summary == null) {\n                        return new StationSummary(station, finalTemp);\n                    }\n                    summary.min = Integer.min(summary.min, finalTemp);\n                    summary.max = Integer.max(summary.max, finalTemp);\n                    summary.sum += finalTemp;\n                    summary.count += 1;\n                    return summary;\n                });\n            }\n        }\n\n        Collection<StationSummary> values() {\n            return accumulator.values();\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_serkan_ozal.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Queue;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.ThreadFactory;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\n\n/**\n * @author serkan-ozal\n */\npublic class CalculateAverage_serkan_ozal {\n\n    private static final String FILE = System.getProperty(\"file.path\", \"./measurements.txt\");\n\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED.length() >= 16\n            // Since majority (99%) of the city names <= 16 bytes, according to my experiments,\n            // 128 bit (16 byte) vectors perform better than 256 bit (32 byte) or 512 bit (64 byte) vectors\n            // even though supported by platform.\n            ? ByteVector.SPECIES_128\n            : ByteVector.SPECIES_64;\n    private static final int BYTE_SPECIES_SIZE = BYTE_SPECIES.vectorByteSize();\n    private static final MemorySegment NULL = MemorySegment.NULL.reinterpret(Long.MAX_VALUE);\n    private static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();\n\n    private static final char NEW_LINE_SEPARATOR = '\\n';\n    private static final char KEY_VALUE_SEPARATOR = ';';\n    private static final int MAX_LINE_LENGTH = 128;\n\n    // Get configurations\n    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n    private static final boolean VERBOSE = false; // getBooleanConfig(\"VERBOSE\", false);\n    private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors(); // getIntegerConfig(\"THREAD_COUNT\", Runtime.getRuntime().availableProcessors());\n    private static final boolean USE_VTHREADS = false; // getBooleanConfig(\"USE_VTHREADS\", false);\n    private static final int VTHREAD_COUNT = 1024; // getIntegerConfig(\"VTHREAD_COUNT\", 1024);\n    private static final int REGION_COUNT = 256; // getIntegerConfig(\"REGION_COUNT\", -1);\n    private static final boolean USE_SHARED_ARENA = true; // getBooleanConfig(\"USE_SHARED_ARENA\", true);\n    private static final boolean USE_SHARED_REGION = true; // getBooleanConfig(\"USE_SHARED_REGION\", true);\n    private static final int MAP_CAPACITY = 1 << 17; // getIntegerConfig(\"MAP_CAPACITY\", 1 << 17);\n    private static final boolean CLOSE_STDOUT_ON_RESULT = true; // getBooleanConfig(\"CLOSE_STDOUT_ON_RESULT\", true);\n    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n    // My dear old friend Unsafe\n    private static final Unsafe U;\n\n    static {\n        try {\n            Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            U = (Unsafe) f.get(null);\n        }\n        catch (Exception e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        long start = System.currentTimeMillis();\n        if (VERBOSE) {\n            System.out.println(\"Processing started at \" + start);\n            System.out.println(\"Vector byte size: \" + BYTE_SPECIES.vectorByteSize());\n            System.out.println(\"Use shared memory arena: \" + USE_SHARED_ARENA);\n            if (USE_VTHREADS) {\n                System.out.println(\"Virtual thread count: \" + VTHREAD_COUNT);\n            }\n            else {\n                System.out.println(\"Thread count: \" + THREAD_COUNT);\n            }\n            System.out.println(\"Map capacity: \" + MAP_CAPACITY);\n        }\n\n        int concurrency = USE_VTHREADS ? VTHREAD_COUNT : THREAD_COUNT;\n        int regionCount = REGION_COUNT > 0 ? REGION_COUNT : concurrency;\n        ByteBuffer lineBuffer = getByteBuffer(MAX_LINE_LENGTH);\n        Result result = new Result();\n\n        RandomAccessFile file = new RandomAccessFile(FILE, \"r\");\n        FileChannel fc = file.getChannel();\n        Arena arena = USE_SHARED_ARENA ? Arena.ofShared() : null;\n        try {\n            long fileSize = fc.size();\n            long regionSize = fileSize / regionCount;\n            long startPos = 0;\n            ExecutorService executor = USE_VTHREADS\n                    ? Executors.newVirtualThreadPerTaskExecutor()\n                    : Executors.newFixedThreadPool(concurrency, new RegionProcessorThreadFactory());\n            MemorySegment region = null;\n            if (USE_SHARED_REGION) {\n                arena = Arena.ofShared();\n                region = fc.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, arena);\n            }\n\n            List<Task> tasks = new ArrayList<>(regionCount);\n            // Split whole file into regions and create tasks for each region\n            List<Future<Response>> futures = new ArrayList<>(regionCount);\n            for (int i = 0; i < regionCount; i++) {\n                long endPos = Math.min(fileSize, startPos + regionSize);\n                // Lines might split into different regions.\n                // If so, move back to the line starting at the end of previous region\n                long closestLineEndPos = (i < regionCount - 1)\n                        ? findClosestLineEnd(fc, endPos, lineBuffer)\n                        : fileSize;\n                Task task = new Task(fc, region, startPos, closestLineEndPos);\n                tasks.add(task);\n                startPos = closestLineEndPos;\n            }\n\n            Queue<Task> sharedTasks = new ConcurrentLinkedQueue<>(tasks);\n\n            // Start region processors to process tasks for each region\n            for (int i = 0; i < concurrency; i++) {\n                Request request = new Request(arena, sharedTasks, result);\n                RegionProcessor regionProcessor = createRegionProcessor(request);\n                Future<Response> future = executor.submit(regionProcessor);\n                futures.add(future);\n            }\n\n            // Wait processors to complete\n            for (Future<Response> future : futures) {\n                future.get();\n            }\n\n            long finish = System.currentTimeMillis();\n            if (VERBOSE) {\n                System.out.println(\"Processing completed at \" + finish);\n                System.out.println(\"Processing completed in \" + (finish - start) + \" milliseconds\");\n            }\n\n            // Print result to stdout\n            result.print();\n\n            if (CLOSE_STDOUT_ON_RESULT) {\n                // After printing result, close stdout.\n                // So parent process can complete without waiting this process completed.\n                // Saves a few hundred milliseconds caused by unmap.\n                System.out.close();\n            }\n        }\n        finally {\n            // Close memory arena if it is managed globally here (shared arena)\n            if (arena != null) {\n                arena.close();\n            }\n            fc.close();\n            if (VERBOSE) {\n                long finish = System.currentTimeMillis();\n                System.out.println(\"All completed at \" + finish);\n                System.out.println(\"All Completed in \" + ((finish - start)) + \" milliseconds\");\n            }\n        }\n    }\n\n    private static boolean getBooleanConfig(String envVarName, boolean defaultValue) {\n        String envVarValue = System.getenv(envVarName);\n        if (envVarValue == null) {\n            return defaultValue;\n        }\n        else {\n            return Boolean.parseBoolean(envVarValue);\n        }\n    }\n\n    private static int getIntegerConfig(String envVarName, int defaultValue) {\n        String envVarValue = System.getenv(envVarName);\n        if (envVarValue == null) {\n            return defaultValue;\n        }\n        else {\n            return Integer.parseInt(envVarValue);\n        }\n    }\n\n    private static ByteBuffer getByteBuffer(int size) {\n        ByteBuffer bb = ByteBuffer.allocateDirect(size);\n        bb.order(NATIVE_BYTE_ORDER);\n        return bb;\n    }\n\n    private static long findClosestLineEnd(FileChannel fc, long endPos, ByteBuffer lineBuffer) throws IOException {\n        long lineCheckStartPos = Math.max(0, endPos - MAX_LINE_LENGTH);\n        lineBuffer.rewind();\n        fc.read(lineBuffer, lineCheckStartPos);\n        int i = MAX_LINE_LENGTH;\n        while (lineBuffer.get(i - 1) != NEW_LINE_SEPARATOR) {\n            i--;\n        }\n        return lineCheckStartPos + i;\n    }\n\n    private static RegionProcessor createRegionProcessor(Request request) {\n        return new RegionProcessor(request);\n    }\n\n    private static class RegionProcessorThreadFactory implements ThreadFactory {\n\n        @Override\n        public Thread newThread(Runnable r) {\n            Thread t = new Thread(r);\n            t.setDaemon(true);\n            t.setPriority(Thread.MAX_PRIORITY);\n            return t;\n        }\n\n    }\n\n    /**\n     * Region processor\n     */\n    private static class RegionProcessor implements Callable<Response> {\n\n        private final Arena arena;\n        private final Queue<Task> sharedTasks;\n        private final Result result;\n        private OpenMap map;\n\n        private RegionProcessor(Request request) {\n            this.arena = request.arena;\n            this.sharedTasks = request.sharedTasks;\n            this.result = request.result;\n        }\n\n        @Override\n        public Response call() throws Exception {\n            if (VERBOSE) {\n                System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Processing started at \" + System.currentTimeMillis());\n            }\n            try {\n                processRegion();\n                return new Response(map);\n            }\n            finally {\n                if (VERBOSE) {\n                    System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Processing finished at \" + System.currentTimeMillis());\n                }\n            }\n        }\n\n        private void processRegion() throws Exception {\n            // Create map in its own thread\n            this.map = new OpenMap();\n\n            boolean arenaGiven = arena != null;\n            // If no shared global memory arena is used, create and use its own local memory arena\n            Arena a = arenaGiven ? arena : Arena.ofConfined();\n            try {\n                for (Task task = sharedTasks.poll(); task != null; task = sharedTasks.poll()) {\n                    boolean regionGiven = task.region != null;\n                    MemorySegment r = regionGiven\n                            ? task.region\n                            : task.fileChannel.map(FileChannel.MapMode.READ_ONLY, task.start, task.size, a);\n                    long regionStart = regionGiven ? (r.address() + task.start) : r.address();\n                    long regionEnd = regionStart + task.size;\n\n                    doProcessRegion(regionStart, regionEnd);\n                }\n\n                if (VERBOSE) {\n                    System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Region processed at \" + System.currentTimeMillis());\n                }\n\n                // Some threads/processors might finish slightly before others.\n                // So, instead of releasing their cores idle, merge their own results here.\n\n                // If there is no another processor merging its results now, merge now.\n                // Otherwise (there is already another thread/processor got the lock of merging),\n                // Close current processor's own local memory arena (if no shared global memory arena is used) now\n                // and merge its own results after then.\n\n                boolean merged = result.tryMergeInto(map);\n                if (VERBOSE && merged) {\n                    System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Result merged at \" + System.currentTimeMillis());\n                }\n                if (!merged) {\n                    if (!arenaGiven) {\n                        a.close();\n                        a = null;\n                        if (VERBOSE) {\n                            System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Arena closed at \" + System.currentTimeMillis());\n                        }\n                    }\n                    result.mergeInto(map);\n                    if (VERBOSE) {\n                        System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Result merged at \" + System.currentTimeMillis());\n                    }\n                }\n            }\n            finally {\n                // If local memory arena is managed here and not closed yet, close it here\n                if (!arenaGiven && a != null) {\n                    a.close();\n                    if (VERBOSE) {\n                        System.out.println(\"[Processor-\" + Thread.currentThread().getName() + \"] Arena closed at \" + System.currentTimeMillis());\n                    }\n                }\n            }\n        }\n\n        private long findClosestLineEnd(long endPos, long minPos) {\n            int i = 0;\n            int maxI = Math.min(MAX_LINE_LENGTH, (int) (endPos - minPos));\n            while (i <= maxI && U.getByte(endPos - i) != NEW_LINE_SEPARATOR) {\n                i++;\n            }\n            return endPos - i + 1;\n        }\n\n        // Credits: merykitty\n        private long extractValue(long regionPtr, long word, OpenMap map, int entryOffset) {\n            // Parse and extract value\n\n            // 1. level instruction set (no dependency between each other so can be run in parallel)\n            long signed = (~word << 59) >> 63;\n            int decimalSepPos = Long.numberOfTrailingZeros(~word & 0x10101000);\n\n            // 2. level instruction set (no dependency between each other so can be run in parallel)\n            long nextPtr = regionPtr + (decimalSepPos >>> 3) + 3;\n            int shift = 28 - decimalSepPos;\n            long designMask = ~(signed & 0xFF);\n\n            long digits = ((word & designMask) << shift) & 0x0F000F0F00L;\n            long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            int value = (int) ((absValue ^ signed) - signed);\n\n            // Put extracted value into map\n            map.putValue(entryOffset, value);\n\n            // Return new position\n            return nextPtr;\n        }\n\n        private void doProcessRegion(long regionStart, long regionEnd) {\n            final long size = regionEnd - regionStart;\n            final long segmentSize = size / 2;\n\n            final long regionStart1 = regionStart;\n            final long regionEnd1 = Math.max(regionStart1, findClosestLineEnd(regionStart1 + segmentSize, regionStart));\n\n            final long regionStart2 = regionEnd1;\n            final long regionEnd2 = regionEnd;\n\n            long regionPtr1, regionPtr2;\n\n            // Read and process region - main\n            // Inspired by: @jerrinot\n            // - two lines at a time (according to my experiment, this is optimum value in terms of register spilling)\n            // - most of the implementation is inlined\n            // - so get the benefit of ILP (Instruction Level Parallelism) better\n            for (regionPtr1 = regionStart1, regionPtr2 = regionStart2; regionPtr1 < regionEnd1 && regionPtr2 < regionEnd2;) {\n                // Search key/value separators and find keys' start and end positions\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n                long keyStartPtr1 = regionPtr1;\n                long keyStartPtr2 = regionPtr2;\n\n                ByteVector keyVector1 = ByteVector.fromMemorySegment(BYTE_SPECIES, NULL, regionPtr1, NATIVE_BYTE_ORDER);\n                ByteVector keyVector2 = ByteVector.fromMemorySegment(BYTE_SPECIES, NULL, regionPtr2, NATIVE_BYTE_ORDER);\n\n                int keyLength1 = keyVector1.compare(VectorOperators.EQ, KEY_VALUE_SEPARATOR).firstTrue();\n                int keyLength2 = keyVector2.compare(VectorOperators.EQ, KEY_VALUE_SEPARATOR).firstTrue();\n\n                if (keyLength1 != BYTE_SPECIES_SIZE && keyLength2 != BYTE_SPECIES_SIZE) {\n                    regionPtr1 += (keyLength1 + 1);\n                    regionPtr2 += (keyLength2 + 1);\n                }\n                else {\n                    if (keyLength1 != BYTE_SPECIES_SIZE) {\n                        regionPtr1 += (keyLength1 + 1);\n                    }\n                    else {\n                        regionPtr1 += BYTE_SPECIES_SIZE;\n                        for (; U.getByte(regionPtr1) != KEY_VALUE_SEPARATOR; regionPtr1++)\n                            ;\n                        keyLength1 = (int) (regionPtr1 - keyStartPtr1);\n                        regionPtr1++;\n                    }\n                    if (keyLength2 != BYTE_SPECIES_SIZE) {\n                        regionPtr2 += (keyLength2 + 1);\n                    }\n                    else {\n                        regionPtr2 += BYTE_SPECIES_SIZE;\n                        for (; U.getByte(regionPtr2) != KEY_VALUE_SEPARATOR; regionPtr2++)\n                            ;\n                        keyLength2 = (int) (regionPtr2 - keyStartPtr2);\n                        regionPtr2++;\n                    }\n                }\n\n                // Read first words as they will be used while extracting values later\n                long word1 = U.getLong(regionPtr1);\n                long word2 = U.getLong(regionPtr2);\n                if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                    word1 = Long.reverseBytes(word1);\n                    word2 = Long.reverseBytes(word2);\n                }\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n                // Calculate key hashes and find entry indexes\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n                int x1, y1, x2, y2;\n                if (keyLength1 > 3 && keyLength2 > 3) {\n                    x1 = U.getInt(keyStartPtr1);\n                    y1 = U.getInt(regionPtr1 - 5);\n                    x2 = U.getInt(keyStartPtr2);\n                    y2 = U.getInt(regionPtr2 - 5);\n                }\n                else {\n                    if (keyLength1 > 3) {\n                        x1 = U.getInt(keyStartPtr1);\n                        y1 = U.getInt(regionPtr1 - 5);\n                    }\n                    else {\n                        x1 = U.getByte(keyStartPtr1);\n                        y1 = U.getByte(regionPtr1 - 2);\n                    }\n                    if (keyLength2 > 3) {\n                        x2 = U.getInt(keyStartPtr2);\n                        y2 = U.getInt(regionPtr2 - 5);\n                    }\n                    else {\n                        x2 = U.getByte(keyStartPtr2);\n                        y2 = U.getByte(regionPtr2 - 2);\n                    }\n                }\n\n                int keyHash1 = (Integer.rotateLeft(x1 * OpenMap.HASH_SEED, OpenMap.HASH_ROTATE) ^ y1) * OpenMap.HASH_SEED;\n                int keyHash2 = (Integer.rotateLeft(x2 * OpenMap.HASH_SEED, OpenMap.HASH_ROTATE) ^ y2) * OpenMap.HASH_SEED;\n\n                int entryIdx1 = (keyHash1 & OpenMap.ENTRY_HASH_MASK) << OpenMap.ENTRY_SIZE_SHIFT;\n                int entryIdx2 = (keyHash2 & OpenMap.ENTRY_HASH_MASK) << OpenMap.ENTRY_SIZE_SHIFT;\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n                // Put keys and calculate entry offsets to put values\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n                int entryOffset1 = map.putKey(keyVector1, keyStartPtr1, keyLength1, entryIdx1);\n                int entryOffset2 = map.putKey(keyVector2, keyStartPtr2, keyLength2, entryIdx2);\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n\n                // Extract values by parsing and put them into map\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n                regionPtr1 = extractValue(regionPtr1, word1, map, entryOffset1);\n                regionPtr2 = extractValue(regionPtr2, word2, map, entryOffset2);\n                ////////////////////////////////////////////////////////////////////////////////////////////////////////\n            }\n\n            // Read and process region - tail\n            doProcessTail(regionPtr1, regionEnd1, regionPtr2, regionEnd2);\n        }\n\n        private void doProcessTail(long regionPtr1, long regionEnd1, long regionPtr2, long regionEnd2) {\n            while (regionPtr1 < regionEnd1) {\n                long keyStartPtr1 = regionPtr1;\n                ByteVector keyVector1 = ByteVector.fromMemorySegment(BYTE_SPECIES, NULL, regionPtr1, NATIVE_BYTE_ORDER);\n                int keyLength1 = keyVector1.compare(VectorOperators.EQ, KEY_VALUE_SEPARATOR).firstTrue();\n                if (keyLength1 != BYTE_SPECIES_SIZE) {\n                    regionPtr1 += (keyLength1 + 1);\n                }\n                else {\n                    regionPtr1 += BYTE_SPECIES_SIZE;\n                    for (; U.getByte(regionPtr1) != KEY_VALUE_SEPARATOR; regionPtr1++)\n                        ;\n                    keyLength1 = (int) (regionPtr1 - keyStartPtr1);\n                    regionPtr1++;\n                }\n                int entryIdx1 = map.calculateEntryIndex(keyStartPtr1, keyLength1);\n                int entryOffset1 = map.putKey(keyVector1, keyStartPtr1, keyLength1, entryIdx1);\n                long word1 = U.getLong(regionPtr1);\n                if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                    word1 = Long.reverseBytes(word1);\n                }\n                regionPtr1 = extractValue(regionPtr1, word1, map, entryOffset1);\n            }\n            while (regionPtr2 < regionEnd2) {\n                long keyStartPtr2 = regionPtr2;\n                ByteVector keyVector2 = ByteVector.fromMemorySegment(BYTE_SPECIES, NULL, regionPtr2, NATIVE_BYTE_ORDER);\n                int keyLength2 = keyVector2.compare(VectorOperators.EQ, KEY_VALUE_SEPARATOR).firstTrue();\n                if (keyLength2 != BYTE_SPECIES_SIZE) {\n                    regionPtr2 += (keyLength2 + 1);\n                }\n                else {\n                    regionPtr2 += BYTE_SPECIES_SIZE;\n                    for (; U.getByte(regionPtr2) != KEY_VALUE_SEPARATOR; regionPtr2++)\n                        ;\n                    keyLength2 = (int) (regionPtr2 - keyStartPtr2);\n                    regionPtr2++;\n                }\n                int entryIdx2 = map.calculateEntryIndex(keyStartPtr2, keyLength2);\n                int entryOffset2 = map.putKey(keyVector2, keyStartPtr2, keyLength2, entryIdx2);\n                long word2 = U.getLong(regionPtr2);\n                if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                    word2 = Long.reverseBytes(word2);\n                }\n                regionPtr2 = extractValue(regionPtr2, word2, map, entryOffset2);\n            }\n        }\n\n    }\n\n    /**\n     * Region processor task\n     */\n    private static final class Task {\n\n        private final FileChannel fileChannel;\n        private final MemorySegment region;\n        private final long start;\n        private final long end;\n        private final long size;\n\n        private Task(FileChannel fileChannel, MemorySegment region, long start, long end) {\n            this.fileChannel = fileChannel;\n            this.region = region;\n            this.start = start;\n            this.end = end;\n            this.size = end - start;\n        }\n\n    }\n\n    /**\n     * Region processor request\n     */\n    private static final class Request {\n\n        private final Arena arena;\n        private final Queue<Task> sharedTasks;\n        private final Result result;\n\n        private Request(Arena arena, Queue<Task> sharedTasks, Result result) {\n            this.arena = arena;\n            this.sharedTasks = sharedTasks;\n            this.result = result;\n        }\n\n    }\n\n    /**\n     * Region processor response\n     */\n    private static final class Response {\n\n        private final OpenMap map;\n\n        private Response(OpenMap map) {\n            this.map = map;\n        }\n\n    }\n\n    /**\n     * Result of each key (city)\n     */\n    private static final class KeyResult {\n\n        private int count;\n        private int minValue;\n        private int maxValue;\n        private long sum;\n\n        private KeyResult(int count, int minValue, int maxValue, long sum) {\n            this.count = count;\n            this.minValue = minValue;\n            this.maxValue = maxValue;\n            this.sum = sum;\n        }\n\n        private void merge(KeyResult result) {\n            count += result.count;\n            minValue = Math.min(minValue, result.minValue);\n            maxValue = Math.max(maxValue, result.maxValue);\n            sum += result.sum;\n        }\n\n        @Override\n        public String toString() {\n            return (minValue / 10.0) + \"/\" + round(sum / (double) (count * 10)) + \"/\" + (maxValue / 10.0);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n    }\n\n    /**\n     * Global result\n     */\n    private static final class Result {\n\n        private final Lock lock = new ReentrantLock();\n        private final Map<String, KeyResult> resultMap;\n\n        private Result() {\n            this.resultMap = new TreeMap<>();\n        }\n\n        private boolean tryMergeInto(OpenMap map) {\n            // Use lock (not \"synchronized\" block) to be virtual threads friendly\n            if (!lock.tryLock()) {\n                return false;\n            }\n            try {\n                map.merge(this.resultMap);\n                return true;\n            }\n            finally {\n                lock.unlock();\n            }\n        }\n\n        private void mergeInto(OpenMap map) {\n            // Use lock (not \"synchronized\" block) to be virtual threads friendly\n            lock.lock();\n            try {\n                map.merge(this.resultMap);\n            }\n            finally {\n                lock.unlock();\n            }\n        }\n\n        private void print() {\n            StringBuilder sb = new StringBuilder(1 << 14);\n            boolean firstEntryAppended = false;\n            sb.append(\"{\");\n            for (Map.Entry<String, KeyResult> e : resultMap.entrySet()) {\n                if (firstEntryAppended) {\n                    sb.append(\", \");\n                }\n                String key = e.getKey();\n                KeyResult value = e.getValue();\n                sb.append(key).append(\"=\").append(value);\n                firstEntryAppended = true;\n            }\n            sb.append('}');\n            System.out.println(sb);\n        }\n\n    }\n\n    /**\n     * Custom map implementation to store results\n     */\n    private static final class OpenMap {\n\n        // Layout\n        // ================================\n        // 0 : 4 bytes - count\n        // 4 : 2 bytes - min value\n        // 6 : 2 bytes - max value\n        // 8 : 8 bytes - value sum\n        // 16 : 4 bytes - key size\n        // 20 : 4 bytes - padding\n        // 24 : 100 bytes - key\n        // 124 : 4 bytes - padding\n        // ================================\n        // 128 bytes - total\n\n        private static final int ENTRY_SIZE = 128;\n        private static final int ENTRY_SIZE_SHIFT = 7;\n\n        private static final int COUNT_OFFSET = 0;\n        private static final int MIN_VALUE_OFFSET = 4;\n        private static final int MAX_VALUE_OFFSET = 6;\n        private static final int VALUE_SUM_OFFSET = 8;\n        private static final int KEY_SIZE_OFFSET = 16;\n        private static final int KEY_OFFSET = 24;\n\n        private static final int ENTRY_HASH_MASK = MAP_CAPACITY - 1;\n        private static final int MAP_SIZE = ENTRY_SIZE * MAP_CAPACITY;\n        private static final int ENTRY_MASK = MAP_SIZE - 1;\n        private static final int KEY_ARRAY_OFFSET = KEY_OFFSET - Unsafe.ARRAY_BYTE_BASE_OFFSET;\n\n        private static final int HASH_SEED = 0x9E3779B9;\n        private static final int HASH_ROTATE = 5;\n\n        private final byte[] data;\n        private final int[] entryOffsets;\n        private int entryOffsetIdx;\n\n        private OpenMap() {\n            this.data = new byte[MAP_SIZE];\n            // Max number of unique keys are 10K, so 1 << 14 (16384) is long enough to hold offsets for all of them\n            this.entryOffsets = new int[1 << 14];\n            this.entryOffsetIdx = 0;\n        }\n\n        // Credits: merykitty\n        private int calculateEntryIndex(long address, int keyLength) {\n            int x, y;\n            if (keyLength >= Integer.BYTES) {\n                x = U.getInt(address);\n                y = U.getInt(address + keyLength - Integer.BYTES);\n            }\n            else {\n                x = U.getByte(address);\n                y = U.getByte(address + keyLength - Byte.BYTES);\n            }\n            // Calculate key hash\n            int keyHash = (Integer.rotateLeft(x * HASH_SEED, HASH_ROTATE) ^ y) * HASH_SEED;\n            // Get the position of the entry in the linear map based on calculated hash\n            return (keyHash & ENTRY_HASH_MASK) << ENTRY_SIZE_SHIFT;\n        }\n\n        private int putKey(ByteVector keyVector, long keyStartAddress, int keyLength, int entryIdx) {\n            // Start searching from the calculated position\n            // and continue until find an available slot in case of hash collision\n            // TODO Prevent infinite loop if all the slots are in use for other keys\n            for (int entryOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + entryIdx;; entryOffset = (entryOffset + ENTRY_SIZE) & ENTRY_MASK) {\n                int keySize = U.getInt(data, entryOffset + KEY_SIZE_OFFSET);\n                // Check whether current index is empty (no another key is inserted yet)\n                if (keySize == 0) {\n                    // Initialize entry slot for new key\n                    U.putShort(data, entryOffset + MIN_VALUE_OFFSET, Short.MAX_VALUE);\n                    U.putShort(data, entryOffset + MAX_VALUE_OFFSET, Short.MIN_VALUE);\n                    U.putInt(data, entryOffset + KEY_SIZE_OFFSET, keyLength);\n                    U.copyMemory(null, keyStartAddress, data, entryOffset + KEY_OFFSET, keyLength);\n                    entryOffsets[entryOffsetIdx++] = entryOffset;\n                    return entryOffset;\n                }\n                // Check for hash collision (hashes are same, but keys are different).\n                // If there is no collision (both hashes and keys are equals), return current slot's offset.\n                // Otherwise, continue iterating until find an available slot.\n                if (keySize == keyLength && keysEqual(keyVector, keyStartAddress, keyLength, entryOffset + KEY_ARRAY_OFFSET)) {\n                    return entryOffset;\n                }\n            }\n        }\n\n        private boolean keysEqual(ByteVector keyVector, long keyStartAddress, int keyLength, int keyStartArrayOffset) {\n            // Use vectorized search for the comparison of keys.\n            // Since majority of the city names >= 8 bytes and <= 16 bytes,\n            // this way is more efficient (according to my experiments) than any other comparisons (byte by byte or 2 longs).\n            ByteVector entryKeyVector = ByteVector.fromArray(BYTE_SPECIES, data, keyStartArrayOffset);\n            int eqCount = keyVector.compare(VectorOperators.EQ, entryKeyVector).trueCount();\n            if (eqCount == keyLength) {\n                return true;\n            }\n            else if (keyLength <= BYTE_SPECIES_SIZE) {\n                return false;\n            }\n\n            // Compare remaining parts of the keys\n\n            int normalizedKeyLength = keyLength;\n            if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                normalizedKeyLength = Integer.reverseBytes(normalizedKeyLength);\n            }\n\n            long keyStartOffset = keyStartArrayOffset + Unsafe.ARRAY_BYTE_BASE_OFFSET;\n            int alignedKeyLength = normalizedKeyLength & 0xFFFFFFF8;\n            int i;\n            for (i = BYTE_SPECIES_SIZE; i < alignedKeyLength; i += Long.BYTES) {\n                if (U.getLong(keyStartAddress + i) != U.getLong(data, keyStartOffset + i)) {\n                    return false;\n                }\n            }\n\n            long wordA = U.getLong(keyStartAddress + i);\n            long wordB = U.getLong(data, keyStartOffset + i);\n            if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                wordA = Long.reverseBytes(wordA);\n                wordB = Long.reverseBytes(wordB);\n            }\n            int halfShift = (Long.BYTES - (normalizedKeyLength & 0x00000007)) << 2;\n            long mask = (0xFFFFFFFFFFFFFFFFL >>> halfShift) >> halfShift;\n            wordA = wordA & mask;\n            // No need to mask \"wordB\" (word from key in the map), because it is already padded with 0s\n            return wordA == wordB;\n        }\n\n        private void putValue(int entryOffset, int value) {\n            int countOffset = entryOffset + COUNT_OFFSET;\n            int minValueOffset = entryOffset + MIN_VALUE_OFFSET;\n            int maxValueOffset = entryOffset + MAX_VALUE_OFFSET;\n            int sumOffset = entryOffset + VALUE_SUM_OFFSET;\n\n            U.putInt(data, countOffset, U.getInt(data, countOffset) + 1);\n            if (value < U.getShort(data, minValueOffset)) {\n                U.putShort(data, minValueOffset, (short) value);\n            }\n            if (value > U.getShort(data, maxValueOffset)) {\n                U.putShort(data, maxValueOffset, (short) value);\n            }\n            U.putLong(data, sumOffset, U.getLong(data, sumOffset) + value);\n        }\n\n        private void merge(Map<String, KeyResult> resultMap) {\n            // Merge this local map into global result map\n            Arrays.sort(entryOffsets, 0, entryOffsetIdx);\n            for (int i = 0; i < entryOffsetIdx; i++) {\n                int entryOffset = entryOffsets[i];\n                int keyLength = U.getInt(data, entryOffset + KEY_SIZE_OFFSET);\n                if (keyLength == 0) {\n                    // No entry is available for this index, so continue iterating\n                    continue;\n                }\n                int entryArrayIdx = entryOffset + KEY_OFFSET - Unsafe.ARRAY_BYTE_BASE_OFFSET;\n                String key = new String(data, entryArrayIdx, keyLength, StandardCharsets.UTF_8);\n                int count = U.getInt(data, entryOffset + COUNT_OFFSET);\n                short minValue = U.getShort(data, entryOffset + MIN_VALUE_OFFSET);\n                short maxValue = U.getShort(data, entryOffset + MAX_VALUE_OFFSET);\n                long sum = U.getLong(data, entryOffset + VALUE_SUM_OFFSET);\n                KeyResult result = new KeyResult(count, minValue, maxValue, sum);\n                KeyResult existingResult = resultMap.get(key);\n                if (existingResult == null) {\n                    resultMap.put(key, result);\n                }\n                else {\n                    existingResult.merge(result);\n                }\n            }\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_shipilev.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.reflect.InaccessibleObjectException;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Arrays;\nimport java.util.concurrent.*;\nimport java.util.function.Supplier;\n\npublic class CalculateAverage_shipilev {\n\n    // Detour: This implementation tries to balance the speed and readability.\n    //\n    // While the original contest suggests we pull off every trick in the\n    // book to get the peak performance, here we set a more pragmatic goal:\n    // how fast we can get without going too far into hacks. Or, putting it\n    // in another way, what would be the reasonably fast implementation that\n    // would *also* pass a code review in a reasonable project, would be usable\n    // in production without waking people up in the middle of the night, and\n    // would work through JDK updates, upgrades, and migrations.\n    //\n    // To that end, this implementation uses vanilla and standard Java as much\n    // as possible, without relying on Unsafe tricks and preview features.\n    // When any non-standard things are used, they are guarded by a feature flag,\n    // which allows to cleanly turn them off when anything goes off the rails.\n    //\n    // For performance reasons, the implementation takes more care to be reliably\n    // parallel to survive I/O stalls and scheduling oddities. This would not\n    // show up in laboratory conditions, but it is a necessary thing for a reliable\n    // code in production. It also tries not to miss simple optimizations without\n    // going too far into the woods.\n    //\n    // Note that some of the magic to run this workload fast in evaluation\n    // conditions is done separately in the invocation script. Most of that\n    // is only needed for the short-running scenarios. In real life, this code\n    // would likely run well without any of that.\n    //\n\n    // ========================= Tunables =========================\n\n    // Workload data file.\n    private static final String FILE = \"./measurements.txt\";\n\n    // Max distance to search for line separator when scanning for line\n    // boundaries. 100 bytes name should fit into this power-of-two buffer.\n    // Should probably never change.\n    private static final int MAX_LINE_LENGTH = 128;\n\n    // Fixed size of the measurements map. Must be the power of two. Should\n    // be large enough to accomodate all the station names. Rules say there are\n    // 10K station names max, so anything more than 16K works well.\n    private static final int MAP_SIZE = 1 << 15;\n\n    // The largest mmap-ed chunk. This can be be Integer.MAX_VALUE, but\n    // it is normally tuned down to seed the workers with smaller mmap regions\n    // more efficiently. This also allows to incrementally unmap chunks as we\n    // complete working on them.\n    private static final int MMAP_CHUNK_SIZE = Integer.MAX_VALUE / 32;\n\n    // The largest slice as unit of work, processed serially by a worker.\n    // Set it too low and there would be more tasks and less batching, but\n    // more parallelism. Set it too high, and the reverse would be true.\n    // Something around a large page would likely hit the right balance.\n    private static final int UNIT_SLICE_SIZE = 4 * 1024 * 1024;\n\n    // Employ direct unmapping techniques to alleviate the cost of system\n    // unmmapping on process termination. This matters for very short runs\n    // on highly parallel machines. This unfortunately calls into private\n    // methods of buffers themselves. If not available on target JVM, the\n    // feature would automatically turn off.\n    private static final boolean DIRECT_UNMMAPS = true;\n\n    // ========================= Storage =========================\n\n    // Thread-local measurement maps, each thread gets one.\n    // This allows workers to work nearly unimpeded without synchronization.\n    // Even though crude, avoid lambdas here to alleviate startup costs.\n    private static final ThreadLocal<MeasurementsMap> MAPS = ThreadLocal.withInitial(new Supplier<>() {\n        @Override\n        public MeasurementsMap get() {\n            MeasurementsMap m = new MeasurementsMap();\n            ALL_MAPS.add(m);\n            return m;\n        }\n    });\n\n    // After worker threads finish, the data is available here. The reporting\n    // code would pull the maps from here, once all workers finish.\n    private static final ConcurrentLinkedQueue<MeasurementsMap> ALL_MAPS = new ConcurrentLinkedQueue<>();\n\n    // Releasable mmaped buffers that workers are done with. These can be un-mapped\n    // in background. Main thread would wait on this queue, until it gets the poison\n    // pill from the root task.\n    private static final LinkedBlockingQueue<ByteBuffer> RELEASABLE_BUFFERS = new LinkedBlockingQueue<>();\n    private static final ByteBuffer RELEASABLE_BUFFER_POISON_PILL = ByteBuffer.allocate(1);\n\n    // ========================= MEATY GRITTY PARTS: PARSE AND AGGREGATE =========================\n\n    public static final class Bucket {\n        // Raw station name, encoded as two prefixes and the name tail,\n        // its total length, and hash.\n        public final byte[] nameTail;\n        public final int len;\n        public final int hash;\n        public final int prefix1, prefix2;\n\n        // Temperature values, in 10x scale.\n        public long sum;\n        public int count;\n        public int min;\n        public int max;\n\n        public Bucket(ByteBuffer slice, int begin, int end, int hash, int temp) {\n            len = end - begin;\n\n            // Decode the station name. It is handy to have a few prefixes\n            // available to simplify matches later.\n            int tailStart = 0;\n            if (len >= 8) {\n                prefix1 = slice.getInt(begin + 0);\n                prefix2 = slice.getInt(begin + 4);\n                tailStart += 8;\n            }\n            else if (len >= 4) {\n                prefix1 = slice.getInt(begin + 0);\n                prefix2 = 0;\n                tailStart += 4;\n            }\n            else {\n                prefix1 = 0;\n                prefix2 = 0;\n            }\n\n            // The rest goes to tail byte array. We are checking reading it on hot-path.\n            // Therefore, it is convenient to keep allocation for names near the buckets.\n            // One can avoid this by carefully recording the tail in a separate field,\n            // like the prefixes above, but this is simple enough to gain enough perf.\n            int tailLen = len - tailStart;\n            nameTail = new byte[tailLen];\n            slice.get(begin + tailStart, nameTail, 0, tailLen);\n\n            // Seed the bucket with initial value.\n            this.hash = hash;\n            this.sum = temp;\n            this.count = 1;\n            this.min = temp;\n            this.max = temp;\n        }\n\n        // Little helper method to compare the array with given ByteBuffer range.\n        public boolean matches(ByteBuffer cand, int begin, int end) {\n            int origLen = len;\n            int candLen = end - begin;\n            if (origLen != candLen) {\n                return false;\n            }\n\n            // Check the prefixes first, if we can.\n            int tailStart = 0;\n            if (origLen >= 8) {\n                if (prefix1 != cand.getInt(begin)) {\n                    return false;\n                }\n                if (prefix2 != cand.getInt(begin + 4)) {\n                    return false;\n                }\n                tailStart += 8;\n            }\n            else if (origLen >= 4) {\n                if (prefix1 != cand.getInt(begin)) {\n                    return false;\n                }\n                tailStart += 4;\n            }\n\n            // Check the rest.\n            for (int i = 0; i < origLen - tailStart; i++) {\n                if (nameTail[i] != cand.get(begin + tailStart + i)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        // Check if current Bucket matches another.\n        public boolean matches(Bucket other) {\n            return len == other.len &&\n                    prefix1 == other.prefix1 &&\n                    prefix2 == other.prefix2 &&\n                    Arrays.equals(nameTail, other.nameTail);\n        }\n\n        // Merge the temp value. Hot-path, should be fairly efficient.\n        public void merge(int value) {\n            sum += value;\n            count++;\n\n            // We rarely do the updates, so these branches are almost\n            // never taken. Writing them as explicit branches instead of\n            // Math.{min,max} improves performance a bit.\n            if (value < min) {\n                min = value;\n            }\n            if (value > max) {\n                max = value;\n            }\n        }\n\n        // Merge the buckets. Called during reporting, not a hot path.\n        public void merge(Bucket s) {\n            sum += s.sum;\n            count += s.count;\n            min = Math.min(min, s.min);\n            max = Math.max(max, s.max);\n        }\n\n        public Row toRow() {\n            // Reconstruct the name first. The prefixes and the tail were copied\n            // from the little-endian slice, so we need to match the endianness here.\n            ByteBuffer bb = ByteBuffer.allocate(len);\n            bb.order(ByteOrder.LITTLE_ENDIAN);\n            if (len >= 4) {\n                bb.putInt(prefix1);\n            }\n            if (len >= 8) {\n                bb.putInt(prefix2);\n            }\n            bb.put(nameTail);\n\n            return new Row(\n                    new String(Arrays.copyOf(bb.array(), len)),\n                    Math.round((double) min) / 10.0,\n                    Math.round((double) sum / count) / 10.0,\n                    Math.round((double) max) / 10.0);\n        }\n    }\n\n    // Quick and dirty linear-probing hash map. YOLO.\n    public static final class MeasurementsMap {\n        // Individual map buckets. Inlining these straight into map complicates\n        // the implementation without much of the performance improvement.\n        // The map is likely sparse, so whatever footprint loss we have due to\n        // Bucket headers we gain by allocating the buckets lazily. The memory\n        // dereference costs are still high in both cases. The additional benefit\n        // for explicit fields in Bucket is that we only need to pay for a single\n        // null-check on bucket instead of multiple range-checks on inlined array.\n        private final Bucket[] buckets = new Bucket[MAP_SIZE];\n\n        // Fast path is inlined in seqCompute. This is a slow-path that is taken\n        // rarely, usually when there is a hash collision. We normally do not enter here.\n        private void updateSlow(ByteBuffer name, int begin, int end, int hash, int temp) {\n            int idx = hash & (MAP_SIZE - 1);\n\n            while (true) {\n                Bucket cur = buckets[idx];\n                if (cur == null) {\n                    // No bucket yet, lucky us. Create the bucket and be done.\n                    buckets[idx] = new Bucket(name, begin, end, hash, temp);\n                    return;\n                }\n                else if ((cur.hash == hash) && cur.matches(name, begin, end)) {\n                    // Same as bucket fastpath. Check for collision by checking the full hash\n                    // first (since the index is truncated by map size), and then the exact name.\n                    cur.merge(temp);\n                    return;\n                }\n                else {\n                    // No dice. Keep searching.\n                    idx = (idx + 1) & (MAP_SIZE - 1);\n                }\n            }\n        }\n\n        // Same as update(), really, but for merging maps. See the comments there.\n        public void merge(MeasurementsMap otherMap) {\n            for (Bucket other : otherMap.buckets) {\n                if (other == null)\n                    continue;\n                int idx = other.hash & (MAP_SIZE - 1);\n                while (true) {\n                    Bucket cur = buckets[idx];\n                    if (cur == null) {\n                        buckets[idx] = other;\n                        break;\n                    }\n                    else if ((cur.hash == other.hash) && cur.matches(other)) {\n                        cur.merge(other);\n                        break;\n                    }\n                    else {\n                        idx = (idx + 1) & (MAP_SIZE - 1);\n                    }\n                }\n            }\n        }\n\n        // Convert from internal representation to the rows. This does several\n        // major things: filters away null-s, instantates full Strings, and\n        // computes the final rows.\n        public int fill(Row[] rows) {\n            int idx = 0;\n            for (Bucket bucket : buckets) {\n                if (bucket == null)\n                    continue;\n                rows[idx++] = bucket.toRow();\n            }\n            return idx;\n        }\n    }\n\n    // The heavy-weight, where most of the magic happens. This is not a usual\n    // RecursiveAction, but rather a CountedCompleter in order to be more robust\n    // in presence of I/O stalls and other scheduling irregularities.\n    public static final class ParsingTask extends CountedCompleter<Void> {\n        private final MappedByteBuffer mappedBuf;\n        private final ByteBuffer buf;\n\n        // Entered from the root task, records the original mmap-ed slice\n        // for later cleanup.\n        public ParsingTask(CountedCompleter<Void> p, MappedByteBuffer mappedBuf) {\n            super(p);\n            this.mappedBuf = mappedBuf;\n            this.buf = mappedBuf;\n        }\n\n        // Entered from the other parsing tasks.\n        public ParsingTask(CountedCompleter<Void> p, ByteBuffer buf) {\n            super(p);\n            this.mappedBuf = null;\n            this.buf = buf;\n        }\n\n        @Override\n        public void compute() {\n            try {\n                internalCompute();\n            }\n            catch (Exception e) {\n                // Meh, YOLO.\n                e.printStackTrace();\n                throw new IllegalStateException(\"Internal error\", e);\n            }\n        }\n\n        @Override\n        public void onCompletion(CountedCompleter<?> caller) {\n            // FJP API: Would be called when this task completes. At that point,\n            // we know the mmap-ed slice is not needed anymore, and can give it\n            // out for unmmaps. We do not do unmmap here, let the main thread\n            // handle it for us, as we go on doing other hot work.\n            if (DIRECT_UNMMAPS && (mappedBuf != null)) {\n                RELEASABLE_BUFFERS.offer(mappedBuf);\n            }\n        }\n\n        private void internalCompute() throws Exception {\n            int len = buf.limit();\n            if (len > UNIT_SLICE_SIZE) {\n                // Still a large chunk, let's split it in half.\n                int mid = len / 2;\n\n                // Figure out the boundary that does not split the line.\n                int w = mid + MAX_LINE_LENGTH;\n                while (buf.get(w - 1) != '\\n') {\n                    w--;\n                }\n                mid = w;\n\n                // Fork out! The stack depth would be shallow enough for us to\n                // execute one of the computations directly.\n                // FJP API: Tell there is a pending task.\n                setPendingCount(1);\n                new ParsingTask(this, buf.slice(0, mid)).fork();\n\n                // The stack depth would be shallow enough for us to\n                // execute one of the computations directly.\n                new ParsingTask(this, buf.slice(mid, len - mid)).compute();\n            }\n            else {\n                // Small enough chunk, time to process it.\n                // The call to seqCompute would normally be non-inlined.\n                // Do setup stuff here to save inlining budget.\n                MeasurementsMap map = MAPS.get();\n\n                // Force the order we need for bit extraction to work. This fits\n                // most of the hardware very well without introducing platform\n                // dependencies. Note that it would be wrong to use nativeOrder()\n                // here, because we _need_ a particular byte ordering for our\n                // computations to work. It just so happens that most hardware\n                // we have is LE.\n                buf.order(ByteOrder.LITTLE_ENDIAN);\n\n                // Go!\n                seqCompute(map, buf, len);\n\n                // FJP API: Notify that this task have completed.\n                tryComplete();\n            }\n        }\n\n        private void seqCompute(MeasurementsMap map, ByteBuffer origSlice, int length) throws IOException {\n            Bucket[] buckets = map.buckets;\n\n            // Slice up our slice! Pecular note here: this instantiates a full new buffer\n            // object, which allows compiler to trust its fields more thoroughly.\n            ByteBuffer slice = origSlice.slice();\n\n            // New slice lost the endianness setting, set it up as the original slice.\n            slice.order(ByteOrder.LITTLE_ENDIAN);\n\n            // Touch the buffer once to let the compiler eject the common checks\n            // for this slice from the loop here. This is an odd, flaky, and sometimes\n            // desperate, but a safe thing to do.\n            slice.get(0);\n\n            int idx = 0;\n            while (idx < length) {\n                // Parse out the name, computing the hash on the fly.\n                // Reading with ints allows us to guarantee that read would always\n                // be in bounds, since the temperature+EOL is at least 4 bytes\n                // long themselves. This implementation prefers simplicity over\n                // advanced tricks like SWAR.\n                int nameBegin = idx;\n                int nameHash = 0;\n\n                outer: while (true) {\n                    int intName = slice.getInt(idx);\n                    for (int c = 0; c < 4; c++) {\n                        int b = (intName >> (c << 3)) & 0xFF;\n                        if (b == ';') {\n                            idx += c + 1;\n                            break outer;\n                        }\n                        nameHash ^= b * 82805;\n                    }\n                    idx += 4;\n                }\n                int nameEnd = idx - 1;\n\n                // Parse out the temperature. The rules specify temperatures\n                // are within -99.9..99.9. This means even in the shortest case of\n                // \"0.0<EOL>\", we are not out of bounds for the int-sized read.\n                int intTemp = slice.getInt(idx);\n\n                int neg = 1;\n                if ((intTemp & 0xFF) == '-') {\n                    // Unlucky, there is a sign. Record it, shift one byte and read\n                    // the remaining digit again. Surprisingly, doing a second read\n                    // is not significantly worse than reading into long and trying\n                    // to do bit shifts on it. But it is significantly simpler.\n                    neg = -1;\n                    intTemp >>>= 8;\n                    intTemp |= slice.get(idx + 4) << 24;\n                    idx++;\n                }\n\n                // Since the sign is consumed, we are only left with two cases,\n                // which means we can trivially extract the number from int.\n                int temp = 0;\n                if ((intTemp >>> 24) == '\\n') {\n                    // Case 1: EOL-digitL-point-digitH\n                    temp = (((intTemp & 0xFF)) - '0') * 10 +\n                            ((intTemp >> 16) & 0xFF) - '0';\n                    idx += 4;\n                }\n                else {\n                    // Case 2: digitL-point-digitH-digitHH\n                    temp = (((intTemp & 0xFF)) - '0') * 100 +\n                            (((intTemp >> 8) & 0xFF) - '0') * 10 +\n                            (((intTemp >>> 24)) - '0');\n                    idx += 5;\n                }\n\n                // All done, just flip the sign, if needed.\n                temp *= neg;\n\n                // Time to update!\n                Bucket bucket = buckets[nameHash & (MAP_SIZE - 1)];\n                if ((bucket != null) && (nameHash == bucket.hash) && bucket.matches(slice, nameBegin, nameEnd)) {\n                    // Lucky fast path: matching bucket hit. Most of the time we complete here.\n                    bucket.merge(temp);\n                }\n                else {\n                    // Unlucky, slow path. The method would not be inlined, it is useful\n                    // to give it the original slice, so that we keep current hot slice\n                    // metadata provably unmodified.\n                    map.updateSlow(origSlice, nameBegin, nameEnd, nameHash, temp);\n                }\n            }\n        }\n    }\n\n    // Fork out the initial tasks. We would normally just fork out one large\n    // task and let it split, but unfortunately buffer API does not allow us\n    // \"long\" start-s and length-s. So we have to chunk at least by mmap-ed\n    // size first. It is a CountedCompleter for the same reason ParsingTask is.\n    // This also gives us a very nice opportunity to process mmap-ed chunks\n    // one by one, thus allowing incremental unmmaps.\n    public static final class RootTask extends CountedCompleter<Void> {\n        public RootTask() {\n            super(null);\n        }\n\n        @Override\n        public void compute() {\n            try {\n                internalCompute();\n            }\n            catch (Exception e) {\n                // Meh, YOLO.\n                e.printStackTrace();\n                throw new IllegalStateException(\"Internal error\", e);\n            }\n        }\n\n        private void internalCompute() throws Exception {\n            ByteBuffer buf = ByteBuffer.allocateDirect(MAX_LINE_LENGTH);\n            FileChannel fc = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n\n            long start = 0;\n            long size = fc.size();\n            while (start < size) {\n                long end = Math.min(size, start + MMAP_CHUNK_SIZE);\n\n                // Read a little chunk into a little buffer.\n                long minEnd = Math.max(0, end - MAX_LINE_LENGTH);\n                buf.rewind();\n                fc.read(buf, minEnd);\n\n                // Figure out the boundary that does not split the line.\n                int w = MAX_LINE_LENGTH;\n                while (buf.get(w - 1) != '\\n') {\n                    w--;\n                }\n                end = minEnd + w;\n\n                // Fork out the large slice.\n                long len = end - start;\n                MappedByteBuffer slice = fc.map(FileChannel.MapMode.READ_ONLY, start, len);\n                start += len;\n\n                // FJP API: Announce we have a pending task before forking.\n                addToPendingCount(1);\n\n                // ...and fork it!\n                new ParsingTask(this, slice).fork();\n            }\n\n            // All mappings are up, can close the channel now.\n            fc.close();\n\n            // FJP API: We have finished, try to complete the whole task tree.\n            propagateCompletion();\n        }\n\n        @Override\n        public void onCompletion(CountedCompleter<?> caller) {\n            // FJP API: This would be called when root task completes along with\n            // all subtasks. This means the processing is done, we can go and\n            // tell main thread about that.\n            try {\n                RELEASABLE_BUFFERS.put(RELEASABLE_BUFFER_POISON_PILL);\n            }\n            catch (Exception e) {\n                throw new IllegalStateException(e);\n            }\n        }\n    }\n\n    // ========================= Invocation =========================\n\n    public static void main(String[] args) throws Exception {\n        // Instantiate a separate FJP to match the parallelism accurately, without\n        // relying on common pool defaults.\n        ForkJoinPool pool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());\n\n        // This little line carries the whole world\n        pool.submit(new RootTask());\n\n        // While the root task is working, prepare what we need for the\n        // end of the run. Go and try to report something to prepare the\n        // reporting code for execution. This prepares classes, storage,\n        // and some profiles for eventual execution.\n        MeasurementsMap map = new MeasurementsMap();\n        Row[] rows = new Row[MAP_SIZE];\n        StringBuilder sb = new StringBuilder(16384);\n\n        report(map, rows, sb);\n        sb.setLength(0);\n\n        // Nothing else is left to do preparation-wise. Now see if we can clean up\n        // buffers that tasks do not need anymore. The root task would communicate\n        // that it is done by giving us a poison pill.\n        ByteBuffer buf;\n        while ((buf = RELEASABLE_BUFFERS.take()) != RELEASABLE_BUFFER_POISON_PILL) {\n            DirectUnmaps.invokeCleaner(buf);\n        }\n\n        // All done. Merge results from thread-local maps...\n        for (MeasurementsMap m : ALL_MAPS) {\n            map.merge(m);\n        }\n\n        // ...and truly report them\n        System.out.println(report(map, rows, sb));\n    }\n\n    private static String report(MeasurementsMap map, Row[] rows, StringBuilder sb) {\n        int rowCount = map.fill(rows);\n        Arrays.sort(rows, 0, rowCount);\n\n        sb.append(\"{\");\n        boolean first = true;\n        for (int c = 0; c < rowCount; c++) {\n            if (c != 0) {\n                sb.append(\", \");\n            }\n            rows[c].printTo(sb);\n        }\n        sb.append(\"}\");\n        return sb.toString();\n    }\n\n    // ========================= Reporting =========================\n\n    private static final class Row implements Comparable<Row> {\n        private final String name;\n        private final double min;\n        private final double max;\n        private final double avg;\n\n        public Row(String name, double min, double avg, double max) {\n            this.name = name;\n            this.min = min;\n            this.max = max;\n            this.avg = avg;\n        }\n\n        @Override\n        public int compareTo(Row o) {\n            return name.compareTo(o.name);\n        }\n\n        public void printTo(StringBuilder sb) {\n            sb.append(name);\n            sb.append(\"=\");\n            sb.append(min);\n            sb.append(\"/\");\n            sb.append(avg);\n            sb.append(\"/\");\n            sb.append(max);\n        }\n    }\n\n    // ========================= Utils =========================\n\n    // Tries to figure out if calling Cleaner directly on the DirectByteBuffer\n    // is possible. If this fails, we still go on.\n    public static class DirectUnmaps {\n        private static final Method METHOD_GET_CLEANER;\n        private static final Method METHOD_CLEANER_CLEAN;\n\n        static Method getCleaner() {\n            try {\n                ByteBuffer dbb = ByteBuffer.allocateDirect(1);\n                Method m = dbb.getClass().getMethod(\"cleaner\");\n                m.setAccessible(true);\n                return m;\n            }\n            catch (NoSuchMethodException | InaccessibleObjectException e) {\n                return null;\n            }\n        }\n\n        static Method getCleanerClean(Method methodGetCleaner) {\n            try {\n                ByteBuffer dbb = ByteBuffer.allocateDirect(1);\n                Object cleaner = methodGetCleaner.invoke(dbb);\n                Method m = cleaner.getClass().getMethod(\"clean\");\n                m.setAccessible(true);\n                m.invoke(cleaner);\n                return m;\n            }\n            catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InaccessibleObjectException e) {\n                return null;\n            }\n        }\n\n        static {\n            METHOD_GET_CLEANER = getCleaner();\n            METHOD_CLEANER_CLEAN = (METHOD_GET_CLEANER != null) ? getCleanerClean(METHOD_GET_CLEANER) : null;\n        }\n\n        public static void invokeCleaner(ByteBuffer bb) {\n            if (METHOD_GET_CLEANER == null || METHOD_CLEANER_CLEAN == null) {\n                return;\n            }\n            try {\n                METHOD_CLEANER_CLEAN.invoke(METHOD_GET_CLEANER.invoke(bb));\n            }\n            catch (InvocationTargetException | IllegalAccessException e) {\n                throw new IllegalStateException(\"Cannot happen at this point\", e);\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_slovdahl.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.foreign.ValueLayout;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.StringJoiner;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\nimport static java.util.stream.Collectors.collectingAndThen;\nimport static java.util.stream.Collectors.groupingBy;\nimport static java.util.stream.Collectors.reducing;\n\npublic class CalculateAverage_slovdahl {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int SLICE_SIZE = 1_048_576;\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        int segments = Runtime.getRuntime().availableProcessors() - 1;\n\n        try (Arena arena = Arena.ofShared();\n                FileChannel channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ);\n                ExecutorService executor = Executors.newThreadPerTaskExecutor(Executors.defaultThreadFactory())) {\n\n            long size = channel.size();\n            if (size < SLICE_SIZE) {\n                segments = 1;\n            }\n\n            long idealSegmentSize = size / segments;\n\n            MemorySegment mappedFile = channel.map(FileChannel.MapMode.READ_ONLY, 0, size, arena);\n            var futures = new ArrayList<Future<Map<Station, MeasurementAggregator>>>(segments);\n\n            long segmentStart = 0;\n            for (int i = 1; i <= segments; i++) {\n                long actualSegmentOffset = idealSegmentSize * i;\n\n                while (actualSegmentOffset < size && mappedFile.get(ValueLayout.JAVA_BYTE, actualSegmentOffset) != (byte) '\\n') {\n                    actualSegmentOffset++;\n                }\n\n                long end = actualSegmentOffset - segmentStart;\n                if (segmentStart + actualSegmentOffset - segmentStart + 1 < size) {\n                    end += 1;\n                }\n\n                MemorySegment segment = mappedFile.asSlice(segmentStart, end);\n                segmentStart = actualSegmentOffset + 1;\n\n                futures.add(executor.submit(() -> {\n                    byte[] array = new byte[SLICE_SIZE];\n                    MemorySegment bufferSegment = MemorySegment.ofArray(array);\n\n                    long position = 0;\n                    long segmentSize = segment.byteSize();\n                    Map<Station, MeasurementAggregator> map = HashMap.newHashMap(10_000);\n\n                    while (position < segmentSize) {\n                        long thisSliceSize = Math.min(SLICE_SIZE, segmentSize - position);\n\n                        MemorySegment.copy(\n                                segment,\n                                ValueLayout.JAVA_BYTE,\n                                position,\n                                bufferSegment,\n                                ValueLayout.JAVA_BYTE,\n                                0,\n                                thisSliceSize);\n\n                        if (thisSliceSize % 8 != 0) {\n                            bufferSegment\n                                    .asSlice(thisSliceSize)\n                                    .fill((byte) 0);\n                        }\n\n                        int newlinePosition = 0;\n                        int startOffset = 0;\n                        while (true) {\n                            int semicolonPosition = nextOccurrence(array, (byte) ';', startOffset);\n                            if (semicolonPosition < 0) {\n                                break;\n                            }\n\n                            int eolPosition = nextOccurrence(array, (byte) '\\n', startOffset);\n                            if (eolPosition < 0) {\n                                if (semicolonPosition < segmentSize - 4) {\n                                    break;\n                                }\n                                else {\n                                    newlinePosition = (int) segmentSize;\n                                }\n                            }\n                            else {\n                                newlinePosition = eolPosition;\n                            }\n\n                            byte[] nameArray = new byte[semicolonPosition - startOffset];\n                            System.arraycopy(array, startOffset, nameArray, 0, semicolonPosition - startOffset);\n                            Station station = new Station(nameArray);\n\n                            int temperatureStart = semicolonPosition + 1;\n                            int temperatureLength = newlinePosition - semicolonPosition - 1;\n\n                            int temperatureIntValue;\n                            if (array[temperatureStart] == '-') {\n                                if (temperatureLength == 4) {\n                                    temperatureIntValue = -1 * ((array[temperatureStart + 1] - 48) * 10 +\n                                            (array[temperatureStart + 3] - 48));\n                                }\n                                else {\n                                    temperatureIntValue = -1 * ((array[temperatureStart + 1] - 48) * 100 +\n                                            (array[temperatureStart + 2] - 48) * 10 +\n                                            (array[temperatureStart + 4] - 48));\n                                }\n                            }\n                            else {\n                                if (temperatureLength == 3) {\n                                    temperatureIntValue = (array[temperatureStart] - 48) * 10 +\n                                            (array[temperatureStart + 2] - 48);\n                                }\n                                else {\n                                    temperatureIntValue = (array[temperatureStart] - 48) * 100 +\n                                            (array[temperatureStart + 1] - 48) * 10 +\n                                            (array[temperatureStart + 3] - 48);\n                                }\n                            }\n\n                            MeasurementAggregator agg = map.get(station);\n                            if (agg == null) {\n                                agg = new MeasurementAggregator();\n                                map.put(station, agg);\n                            }\n\n                            agg.min = Math.min(agg.min, temperatureIntValue);\n                            agg.max = Math.max(agg.max, temperatureIntValue);\n                            agg.sum += temperatureIntValue;\n                            agg.count++;\n\n                            // Make sure the next iteration won't find the same delimiters.\n                            array[semicolonPosition] = (byte) 0;\n                            array[newlinePosition] = (byte) 0;\n\n                            startOffset = newlinePosition + 1;\n                        }\n\n                        position += newlinePosition + 1;\n                    }\n\n                    return map;\n                }));\n            }\n\n            TreeMap<String, ResultRow> result = futures.stream()\n                    .map(f -> {\n                        try {\n                            return f.get();\n                        }\n                        catch (InterruptedException | ExecutionException e) {\n                            throw new RuntimeException(e);\n                        }\n                    })\n                    .flatMap(m -> m.entrySet().stream())\n                    .collect(groupingBy(\n                            e -> new String(e.getKey().name()),\n                            TreeMap::new,\n                            collectingAndThen(\n                                    reducing(\n                                            new MeasurementAggregator(),\n                                            Map.Entry::getValue,\n                                            (agg1, agg2) -> {\n                                                MeasurementAggregator res = new MeasurementAggregator();\n                                                res.min = Math.min(agg1.min, agg2.min);\n                                                res.max = Math.max(agg1.max, agg2.max);\n                                                res.sum = agg1.sum + agg2.sum;\n                                                res.count = agg1.count + agg2.count;\n\n                                                return res;\n                                            }),\n                                    agg -> new ResultRow(\n                                            agg.min / 10.0,\n                                            (Math.round((agg.sum / 10.0) * 10.0) / 10.0) / agg.count,\n                                            agg.max / 10.0))));\n\n            System.out.println(result);\n\n            executor.shutdownNow();\n        }\n    }\n\n    private static int nextOccurrence(byte[] data, byte needle, int offset) {\n        while (offset < data.length) {\n            if (data[offset] == needle) {\n                return offset;\n            }\n            offset++;\n        }\n        return -1;\n    }\n\n    private record Station(byte[] name, int hash) {\n        private Station(byte[] name) {\n            this(name, Arrays.hashCode(name));\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) {\n                return true;\n            }\n            if (o == null || getClass() != o.getClass()) {\n                return false;\n            }\n            Station station = (Station) o;\n            return Arrays.equals(name, station.name);\n        }\n\n        @Override\n        public int hashCode() {\n            return hash;\n        }\n\n        @Override\n        public String toString() {\n            return new StringJoiner(\", \", Station.class.getSimpleName() + \"[\", \"]\")\n                    .add(\"name=\" + new String(name))\n                    .add(\"hash=\" + hash)\n                    .toString();\n        }\n    }\n\n    private static class MeasurementAggregator {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum;\n        private long count;\n    }\n\n    private record ResultRow(double min, double mean, double max) {\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_spullara.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_spullara {\n    private static final String FILE = \"./measurements.txt\";\n\n    /*\n     * My results on this computer:\n     *\n     * CalculateAverage: 2m37.788s\n     * CalculateAverage_royvanrijn: 0m29.639s\n     * CalculateAverage_spullara: 0m2.013s\n     *\n     */\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        long start = System.currentTimeMillis();\n        var filename = args.length == 0 ? FILE : args[0];\n        var file = new File(filename);\n\n        var resultsMap = getFileSegments(file).stream().map(segment -> {\n            var resultMap = new ByteArrayToResultMap();\n            long segmentEnd = segment.end();\n            try (var fileChannel = (FileChannel) Files.newByteChannel(Path.of(filename), StandardOpenOption.READ)) {\n                var bb = fileChannel.map(FileChannel.MapMode.READ_ONLY, segment.start(), segmentEnd - segment.start());\n                // Up to 100 characters for a city name\n                var buffer = new byte[100];\n                int startLine;\n                int limit = bb.limit();\n                while ((startLine = bb.position()) < limit) {\n                    int currentPosition = startLine;\n                    byte b;\n                    int offset = 0;\n                    int hash = 0;\n                    while (currentPosition != segmentEnd && (b = bb.get(currentPosition++)) != ';') {\n                        buffer[offset++] = b;\n                        hash = 31 * hash + b;\n                    }\n                    int temp;\n                    int negative = 1;\n                    // Inspired by @yemreinci to unroll this even further\n                    if (bb.get(currentPosition) == '-') {\n                        negative = -1;\n                        currentPosition++;\n                    }\n                    if (bb.get(currentPosition + 1) == '.') {\n                        temp = negative * ((bb.get(currentPosition) - '0') * 10 + (bb.get(currentPosition + 2) - '0'));\n                        currentPosition += 3;\n                    }\n                    else {\n                        temp = negative * ((bb.get(currentPosition) - '0') * 100 + ((bb.get(currentPosition + 1) - '0') * 10 + (bb.get(currentPosition + 3) - '0')));\n                        currentPosition += 4;\n                    }\n                    if (bb.get(currentPosition) == '\\r') {\n                        currentPosition++;\n                    }\n                    currentPosition++;\n                    resultMap.putOrMerge(buffer, 0, offset, temp / 10.0, hash);\n                    bb.position(currentPosition);\n                }\n                return resultMap;\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }).parallel().flatMap(partition -> partition.getAll().stream())\n                .collect(Collectors.toMap(e -> new String(e.key()), Entry::value, CalculateAverage_spullara::merge, TreeMap::new));\n\n        System.out.println(resultsMap);\n    }\n\n    private static List<FileSegment> getFileSegments(File file) throws IOException {\n        int numberOfSegments = Runtime.getRuntime().availableProcessors();\n        long fileSize = file.length();\n        long segmentSize = fileSize / numberOfSegments;\n        List<FileSegment> segments = new ArrayList<>(numberOfSegments);\n        // Pointless to split small files\n        if (segmentSize < 1_000_000) {\n            segments.add(new FileSegment(0, fileSize));\n            return segments;\n        }\n        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\")) {\n            for (int i = 0; i < numberOfSegments; i++) {\n                long segStart = i * segmentSize;\n                long segEnd = (i == numberOfSegments - 1) ? fileSize : segStart + segmentSize;\n                segStart = findSegment(i, 0, randomAccessFile, segStart, segEnd);\n                segEnd = findSegment(i, numberOfSegments - 1, randomAccessFile, segEnd, fileSize);\n\n                segments.add(new FileSegment(segStart, segEnd));\n            }\n        }\n        return segments;\n    }\n\n    private static Result merge(Result v, Result value) {\n        return merge(v, value.min, value.max, value.sum, value.count);\n    }\n\n    private static Result merge(Result v, double value, double value1, double value2, long value3) {\n        v.min = Math.min(v.min, value);\n        v.max = Math.max(v.max, value1);\n        v.sum += value2;\n        v.count += value3;\n        return v;\n    }\n\n    private static long findSegment(int i, int skipSegment, RandomAccessFile raf, long location, long fileSize) throws IOException {\n        if (i != skipSegment) {\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                if (raf.read() == '\\n')\n                    break;\n            }\n        }\n        return location;\n    }\n}\n\nclass Result {\n    double min, max, sum;\n    long count;\n\n    Result(double value) {\n        min = max = sum = value;\n        this.count = 1;\n    }\n\n    @Override\n    public String toString() {\n        return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n    }\n\n    double round(double v) {\n        return Math.round(v * 10.0) / 10.0;\n    }\n\n}\n\n    record Entry(byte[] key, Result value) {\n    }\n\n    record FileSegment(long start, long end) {\n    }\n\nclass ByteArrayToResultMap {\n    public static final int MAPSIZE = 1024 * 128;\n    Result[] slots = new Result[MAPSIZE];\n    byte[][] keys = new byte[MAPSIZE][];\n\n    public void putOrMerge(byte[] key, int offset, int size, double temp, int hash) {\n        int slot = hash & (slots.length - 1);\n        var slotValue = slots[slot];\n        // Linear probe for open slot\n        while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n            slot = (slot + 1) & (slots.length - 1);\n            slotValue = slots[slot];\n        }\n        Result value = slotValue;\n        if (value == null) {\n            slots[slot] = new Result(temp);\n            byte[] bytes = new byte[size];\n            System.arraycopy(key, offset, bytes, 0, size);\n            keys[slot] = bytes;\n        } else {\n            value.min = Math.min(value.min, temp);\n            value.max = Math.max(value.max, temp);\n            value.sum += temp;\n            value.count += 1;\n        }\n    }\n\n    // Get all pairs\n    public List<Entry> getAll() {\n        List<Entry> result = new ArrayList<>(slots.length);\n        for (int i = 0; i < slots.length; i++) {\n            Result slotValue = slots[i];\n            if (slotValue != null) {\n                result.add(new Entry(keys[i], slotValue));\n            }\n        }\n        return result;\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_stephenvonworley.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.*;\nimport java.lang.foreign.*;\nimport java.lang.reflect.Field;\nimport java.nio.*;\nimport java.nio.channels.*;\nimport java.nio.file.*;\nimport java.nio.charset.*;\nimport java.util.*;\nimport java.util.concurrent.*;\nimport java.util.stream.*;\nimport sun.misc.Unsafe;\n\n/*\n * Stephen Von Worley's (von@von.io) entry to Gunnar Morling's \"One Billion Row Challenge\":\n * https://www.morling.dev/blog/one-billion-row-challenge/\n *\n * To compute the desired result, this program:\n * 1. Memory maps the input file.\n * 2. Partitions the file into a queue of Chunks, which delimit sections of the file.\n * 3. Spawns one thread per processor. Each thread:\n *    a. Allocates a Table, which will accumulate names and tallies (min/max/total/count).\n *    b. Get a Chunk from the queue.\n *    c. Processes the Chunk using a parser that reads the Chunk simultaneously at three\n *       different, evenly-spaced locations, using heavily-optimized scalar code.\n *    d. Repeats steps b and c until there are no more Chunks.\n * 4. Aggregates the resulting Tables into a treemap of names to Tallies.\n * 5. Outputs the names and Tallies in ascending name order.\n *\n * Runs fastest as a natively-compiled, standalone binary, as might be produced by Graal's\n * `native-image` utility.  Tested with Oracle Graal 21.0.2.\n * \n * Incorporates code authored by a number of submitters, including Thomas Wue, Quan Anh\n * Mai, and others.\n *\n * Thanks y'all, and Happy Rowing!\n * Steve\n * von@von.io\n * www.von.io\n */\n\npublic class CalculateAverage_stephenvonworley {\n\n    private static final int NAME_LIMIT = 10000;\n\n    private static final long CHUNK_SIZE = 5000000;\n    private static final long CHUNK_PAD = 200;\n    private static final long CHUNK_PARSE3_LIMIT = 1000;\n\n    private static final long GOLDEN_LONG = 0x9e3779b97f4a7c15L;\n    private static final long TALLY_BITS = 7;\n    private static final long TALLY_SIZE = 1L << TALLY_BITS;\n    private static final long HASH_BITS = 16;\n    private static final long HASH_MASK = ((1L << HASH_BITS) - 1) << TALLY_BITS;\n    private static final long TABLE_SIZE = 1L << (HASH_BITS + TALLY_BITS);\n\n    private static final long OFFSET_MIN = 0;\n    private static final long OFFSET_MAX = 2;\n    private static final long OFFSET_COUNT = 4;\n    private static final long OFFSET_TOTAL = 8;\n    private static final long OFFSET_LEN = 16;\n    private static final long OFFSET_NAME = 17;\n\n    private static final Unsafe unsafe;\n    static {\n        try {\n            Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            unsafe = (Unsafe) f.get(null);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(\"Exception initializing unsafe\", e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        if (!List.of(args).contains(\"--worker\")) {\n            spawnWorker();\n            return;\n        }\n\n        MemorySegment in = map(\"./measurements.txt\");\n        Queue<Chunk> chunks = partition(in);\n        List<Table> tables = process(chunks, processorCount());\n        Map<String, Tally> nameToTally = aggregate(tables);\n\n        System.out.println(nameToTally);\n        System.out.close();\n    }\n\n    // credit: \"Spawn worker\" code by Thomas Wue\n    private static void spawnWorker() throws IOException {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> workerCommand = new ArrayList<>();\n        info.command().ifPresent(workerCommand::add);\n        info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args)));\n        workerCommand.add(\"--worker\");\n        new ProcessBuilder().command(workerCommand).inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE)\n                .start().getInputStream().transferTo(System.out);\n    }\n\n    private static int processorCount() {\n        return Runtime.getRuntime().availableProcessors();\n    }\n\n    private static MemorySegment map(String path) throws IOException {\n        FileChannel file = FileChannel.open(Path.of(path), StandardOpenOption.READ);\n        return file.map(FileChannel.MapMode.READ_ONLY, 0, file.size(), Arena.global());\n    }\n\n    private static MemorySegment allocate(long len) {\n        return Arena.global().allocate(len, 4096);\n    }\n\n    private static Queue<Chunk> partition(MemorySegment in) throws IOException {\n        Queue<Chunk> chunks = new ConcurrentLinkedDeque<>();\n        long address = in.address();\n        long len = in.byteSize();\n        long start = address;\n        while (start < address + len) {\n            long end = start + CHUNK_SIZE;\n            if (end >= address + len) {\n                end = address + len;\n            }\n            else {\n                end = afterNewline(end);\n            }\n            Chunk chunk;\n            if (end + CHUNK_PAD < address + len) {\n                chunk = new Chunk(start, end);\n            }\n            else {\n                MemorySegment padded = allocate(end - start + CHUNK_PAD);\n                MemorySegment.copy(in, start - address, padded, 0, end - start);\n                chunk = new Chunk(padded.address(), padded.address() + (end - start));\n            }\n            chunks.offer(chunk);\n            start = end;\n        }\n        return chunks;\n    }\n\n    private static List<Table> process(Queue<Chunk> chunks, int threadCount) throws InterruptedException {\n        List<Table> tables = Collections.synchronizedList(new ArrayList<>(threadCount));\n        List<Thread> threads = new ArrayList<>(threadCount);\n        for (int i = 0; i < threadCount; i++) {\n            Thread thread = new Thread(() -> {\n                Table t = new Table();\n                tables.add(t);\n                Chunk chunk;\n                while ((chunk = chunks.poll()) != null) {\n                    parse3(chunk.start(), chunk.end(), t);\n                }\n            });\n            threads.add(thread);\n            thread.start();\n        }\n        for (Thread thread : threads) {\n            thread.join();\n        }\n        return tables;\n    }\n\n    private static Map<String, Tally> aggregate(List<Table> tables) {\n        Map<String, Tally> nameToTally = new TreeMap<>();\n        tables.forEach(table -> aggregate(nameToTally, table));\n        return nameToTally;\n    }\n\n    private static void aggregate(Map<String, Tally> nameToTally, Table table) {\n        table.process((name, min, max, total, count) -> nameToTally.computeIfAbsent(name, _ -> new Tally()).add(min, max, total, count));\n    }\n\n    private static void parse3(long start, long end, Table table) {\n\n        if (end - start < CHUNK_PARSE3_LIMIT) {\n            parse1(start, end, table);\n            return;\n        }\n\n        final long tallies = table.tallies;\n\n        long part = (end - start) / 3;\n        long startA = start;\n        long startB = afterNewline(start + part);\n        long startC = afterNewline(start + 2 * part);\n        long endA = startB;\n        long endB = startC;\n        long endC = end;\n\n        while (true) {\n            long N = min(\n                    remaining(startA, endA),\n                    remaining(startB, endB),\n                    remaining(startC, endC));\n\n            if (N <= 1) {\n                break;\n            }\n\n            while (N > 0) {\n                long semicolonA = semicolon(startA);\n                long semicolonB = semicolon(startB);\n                long semicolonC = semicolon(startC);\n\n                long tallyA = locate(startA, semicolonA, tallies, table);\n                long tallyB = locate(startB, semicolonB, tallies, table);\n                long tallyC = locate(startC, semicolonC, tallies, table);\n\n                long numberA = number(semicolonA);\n                tally(tallyA, numberA);\n                long numberB = number(semicolonB);\n                tally(tallyB, numberB);\n                long numberC = number(semicolonC);\n                tally(tallyC, numberC);\n\n                startA = next(semicolonA);\n                startB = next(semicolonB);\n                startC = next(semicolonC);\n                N--;\n            }\n        }\n\n        parse1(startA, endA, table);\n        parse1(startB, endB, table);\n        parse1(startC, endC, table);\n    }\n\n    private static void parse1(long start, long end, Table table) {\n        final long tallies = table.tallies;\n\n        while (start < end) {\n            long semicolon = semicolon(start);\n            long tally = locate(start, semicolon, tallies, table);\n            long number = number(semicolon);\n            tally(tally, number);\n            start = next(semicolon);\n        }\n    }\n\n    private static long remaining(long start, long end) {\n        return (end - start) >> 7;\n    }\n\n    // credit: Adapted from code by Thomas Wue\n    private static long semicolon(long start) {\n        start++;\n        long word = getLong(start);\n        long input = word ^ 0x3B3B3B3B3B3B3B3BL;\n        long tmp = (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;\n        if (tmp != 0) {\n            return start + (Long.numberOfTrailingZeros(tmp) >>> 3);\n        }\n        while (true) {\n            start += 8;\n            long word2 = getLong(start);\n            long input2 = word2 ^ 0x3B3B3B3B3B3B3B3BL;\n            long tmp2 = (input2 - 0x0101010101010101L) & ~input2 & 0x8080808080808080L;\n            if (tmp2 != 0) {\n                return start + (Long.numberOfTrailingZeros(tmp2) >>> 3);\n            }\n        }\n    }\n\n    private static long trim(long value, long remove) {\n        long shift = remove << 3;\n        return ((value << shift) >>> shift);\n    }\n\n    // https://softwareengineering.stackexchange.com/questions/402542/where-do-magic-hashing-constants-like-0x9e3779b9-and-0x9e3779b1-come-from\n    private static long locate(long start, long semicolon, long tallies, Table table) {\n        long len = semicolon - start;\n        long word = getLong(start);\n        if (len <= 8) {\n            word = trim(word, 8 - len);\n            long hash = word * GOLDEN_LONG;\n            long offset = (hash >>> (64 - HASH_BITS)) << TALLY_BITS;\n            while (true) {\n                long tally = tallies + offset;\n                long tlen = getByte(tally + OFFSET_LEN);\n                long tword = getLong(tally + OFFSET_NAME);\n                if (len == tlen && word == tword) {\n                    return tally;\n                }\n                if (tword == 0) {\n                    init(tally, start, len, table);\n                    return tally;\n                }\n                offset = (offset + TALLY_SIZE) & HASH_MASK;\n            }\n        }\n        else {\n            long word2 = getLong(semicolon - 8);\n            long hash = (word + word2) * GOLDEN_LONG;\n            long offset = (hash >>> (64 - HASH_BITS)) << TALLY_BITS;\n            while (true) {\n                long tally = tallies + offset;\n                long tword = getLong(tally + OFFSET_NAME);\n                if (len <= 16) {\n                    long tlen = getByte(tally + OFFSET_LEN);\n                    long tword2 = getLong(tally + OFFSET_NAME + len - 8);\n                    if (len == tlen && word == tword && word2 == tword2) {\n                        return tally;\n                    }\n                }\n                else {\n                    if (match(tally, start, len)) {\n                        return tally;\n                    }\n                }\n                if (tword == 0) {\n                    init(tally, start, len, table);\n                    return tally;\n                }\n                offset = (offset + TALLY_SIZE) & HASH_MASK;\n            }\n        }\n    }\n\n    private static void init(long tally, long start, long len, Table t) {\n        setShort(tally + OFFSET_MIN, Short.MAX_VALUE);\n        setShort(tally + OFFSET_MAX, Short.MIN_VALUE);\n        setByte(tally + OFFSET_LEN, (byte) len);\n        copyMemory(start, tally + OFFSET_NAME, len);\n        t.addresses[t.count++] = tally;\n    }\n\n    private static boolean match(long tally, long name, long len) {\n        if (getByte(tally + OFFSET_LEN) != len) {\n            return false;\n        }\n        long a = name;\n        long b = tally + OFFSET_NAME;\n        while (len > 7) {\n            if (getLong(a) != getLong(b)) {\n                return false;\n            }\n            a += 8;\n            b += 8;\n            len -= 8;\n        }\n        if (len > 0) {\n            return (trim(getLong(a), 8 - len) == getLong(b));\n        }\n        return true;\n    }\n\n    // credit: Wonderfully-fast number parsing implementation by Quan Anh Mai\n    private static long number(long semicolon) {\n        long numberWord = getLong(semicolon + 1);\n        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n        int shift = 28 - decimalSepPos;\n        // signed is -1 if negative, 0 otherwise\n        long signed = (~numberWord << 59) >> 63;\n        long designMask = ~(signed & 0xFF);\n        // Align the number to a specific position and transform the ascii to digit value\n        long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n        // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n        // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n        // 0x000000UU00TTHH00 + 0x00UU00TTHH000000 * 10 + 0xUU00TTHH00000000 * 100\n        long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        return (absValue ^ signed) - signed;\n    }\n\n    private static void tally(long tally, long number) {\n        short min = getShort(tally + OFFSET_MIN);\n        short max = getShort(tally + OFFSET_MAX);\n        int count = getInt(tally + OFFSET_COUNT);\n        long total = getLong(tally + OFFSET_TOTAL);\n        if (number < min) {\n            setShort(tally + OFFSET_MIN, (short) number);\n        }\n        if (number > max) {\n            setShort(tally + OFFSET_MAX, (short) number);\n        }\n        setInt(tally + OFFSET_COUNT, count + 1);\n        setLong(tally + OFFSET_TOTAL, total + number);\n    }\n\n    private static long next(long semicolon) {\n        long word = getLong(semicolon);\n        semicolon += 7;\n        semicolon -= (~word >>> (24 + 4)) & 1;\n        semicolon -= (~word >>> (16 + 4 - 1)) & 2;\n        return semicolon;\n    }\n\n    private static long afterNewline(long start) {\n        while (getByte(start) != '\\n')\n            start++;\n        return start + 1;\n    }\n\n    private static long min(long a, long b, long c) {\n        return Math.min(a, Math.min(b, c));\n    }\n\n    private static byte getByte(long addr) {\n        return unsafe.getByte(addr);\n    }\n\n    private static short getShort(long addr) {\n        return unsafe.getShort(addr);\n    }\n\n    private static int getInt(long addr) {\n        return unsafe.getInt(addr);\n    }\n\n    private static long getLong(long addr) {\n        return unsafe.getLong(addr);\n    }\n\n    private static void setByte(long addr, byte value) {\n        unsafe.putByte(addr, value);\n    }\n\n    private static void setShort(long addr, short value) {\n        unsafe.putShort(addr, value);\n    }\n\n    private static void setInt(long addr, int value) {\n        unsafe.putInt(addr, value);\n    }\n\n    private static void setLong(long addr, long value) {\n        unsafe.putLong(addr, value);\n    }\n\n    private static void copyMemory(long srcAddr, long dstAddr, long count) {\n        unsafe.copyMemory(srcAddr, dstAddr, count);\n    }\n\n    private static record Chunk(long start, long end) {\n    }\n\n    private static class Table {\n        public final long tallies;\n        public final long[] addresses;\n        public int count;\n\n        public Table() {\n            tallies = allocate(TABLE_SIZE).address();\n            addresses = new long[NAME_LIMIT];\n            count = 0;\n        }\n\n        public void process(Consumer consumer) {\n            for (int i = 0; i < count; i++) {\n                long address = addresses[i];\n                int len = getByte(address + OFFSET_LEN);\n                byte[] bytes = new byte[len];\n                for (int j = 0; j < len; j++) {\n                    bytes[j] = getByte(address + OFFSET_NAME + j);\n                }\n                String name = new String(bytes, StandardCharsets.UTF_8);\n                long min = getShort(address + OFFSET_MIN);\n                long max = getShort(address + OFFSET_MAX);\n                long total = getLong(address + OFFSET_TOTAL);\n                long count = getInt(address + OFFSET_COUNT);\n                consumer.consume(name, min, max, total, count);\n            }\n        }\n    }\n\n    private static interface Consumer {\n        public void consume(String name, long min, long max, long total, long count);\n    }\n\n    private static class Tally {\n\n        private long min;\n        private long max;\n        private long total;\n        private long count;\n\n        public Tally() {\n            this.min = Short.MAX_VALUE;\n            this.max = Short.MIN_VALUE;\n            this.total = 0;\n            this.count = 0;\n        }\n\n        public void add(long addMin, long addMax, long addTotal, long addCount) {\n            min = Math.min(min, addMin);\n            max = Math.max(max, addMax);\n            total += addTotal;\n            count += addCount;\n        }\n\n        public long getMin() {\n            return min;\n        }\n\n        public long getMax() {\n            return max;\n        }\n\n        public long getTotal() {\n            return total;\n        }\n\n        public long getCount() {\n            return count;\n        }\n\n        public String toString() {\n            return String.format(\"%.1f/%.1f/%.1f\",\n                    getMin() / 10.0,\n                    getTotal() / (10.0 * getCount()),\n                    getMax() / 10.0);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_sudhirtumati.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.Semaphore;\n\npublic class CalculateAverage_sudhirtumati {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int bufferSize = 8192;\n    private static final byte SEMICOLON = (byte) ';';\n    private static final byte NEW_LINE = (byte) '\\n';\n    private static final int THREAD_COUNT = Runtime.getRuntime().availableProcessors();\n    private static final Semaphore PERMITS = new Semaphore(THREAD_COUNT);\n    private static final MeasurementAggregator globalAggregator = new MeasurementAggregator();\n    private static final Semaphore AGGREGATOR_PERMITS = new Semaphore(1);\n    private static final Map<Integer, String> LOCATION_STORE = new ConcurrentHashMap<>();\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        CalculateAverage_sudhirtumati instance = new CalculateAverage_sudhirtumati();\n        instance.chunkProcess();\n    }\n\n    private void chunkProcess() throws IOException, InterruptedException {\n        try (FileInputStream is = new FileInputStream(FILE);\n             FileChannel fc = is.getChannel()) {\n            for (int i = 0; i < THREAD_COUNT; i++) {\n                PERMITS.acquire();\n                Thread t = new ChunkProcessingThread(i, fc);\n                t.setName(STR.\"T\\{i}\");\n                t.start();\n            }\n            do {\n                Thread.sleep(100);\n            } while (PERMITS.availablePermits() != THREAD_COUNT);\n        }\n        System.out.println(globalAggregator.getResult());\n    }\n\n    static class ChunkProcessingThread extends Thread {\n\n        private int index;\n        private final FileChannel fc;\n        private final MeasurementAggregator aggregator;\n\n        ChunkProcessingThread(int index, FileChannel fc) {\n            this.index = index;\n            this.fc = fc;\n            aggregator = new MeasurementAggregator();\n        }\n\n        @Override\n        public void run() {\n            ByteBuffer buffer = ByteBuffer.allocate(index == 0 ? bufferSize : bufferSize + 50);\n            long fcPosition = index == 0 ? 0 : (((long) index * bufferSize) - 50);\n            try {\n                while (fc.read(buffer, fcPosition) != -1) {\n                    buffer.flip();\n                    if (index != 0 /* && fc.position() != bufferSize */) {\n                        seekStartPos(buffer);\n                    }\n                    processBuffer(buffer);\n                    index += THREAD_COUNT;\n                    fcPosition = ((long) index * bufferSize) - 50L;\n                    if (buffer.capacity() == 8192) {\n                        buffer = ByteBuffer.allocate(bufferSize + 50);\n                    }\n                    buffer.position(0);\n                }\n                AGGREGATOR_PERMITS.acquire();\n                globalAggregator.process(aggregator);\n                AGGREGATOR_PERMITS.release();\n            }\n            catch (IOException | InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n            PERMITS.release();\n        }\n\n        private void processBuffer(ByteBuffer buffer) throws IOException {\n            int mStartMark = buffer.position();\n            int tStartMark = -1;\n            int count = buffer.position();\n            do {\n                byte b = buffer.get(count);\n                if (b == SEMICOLON) {\n                    tStartMark = count;\n                }\n                else if (b == NEW_LINE) {\n                    byte[] locArr = new byte[tStartMark - mStartMark];\n                    byte[] tempArr = new byte[count - tStartMark];\n                    buffer.get(mStartMark, locArr);\n                    buffer.get(mStartMark + locArr.length + 1, tempArr);\n                    aggregator.process(locArr, tempArr);\n                    mStartMark = count + 1;\n                }\n                count++;\n            } while (count < buffer.limit());\n        }\n\n        private void seekStartPos(ByteBuffer buffer) {\n            int i = buffer.limit() > 50 ? 49 : buffer.limit() - 2;\n            for (; i >= 0; i--) {\n                if (buffer.get(i) == NEW_LINE) {\n                    buffer.position(i + 1);\n                    break;\n                }\n            }\n        }\n    }\n\n    static final class MeasurementAggregator {\n        private static final long MAX_VALUE_DIVIDE_10 = Long.MAX_VALUE / 10;\n        private final Map<Integer, Measurement> store = new HashMap<>();\n\n        public void process(MeasurementAggregator other) {\n            other.store.forEach((k, v) -> {\n                Measurement m = store.get(k);\n                if (m == null) {\n                    m = new Measurement();\n                    store.put(k, m);\n                }\n                m.process(v);\n            });\n        }\n\n        public void process(byte[] location, byte[] temperature) throws IOException {\n            Integer hashCode = Arrays.hashCode(location);\n            LOCATION_STORE.computeIfAbsent(hashCode, _ -> new String(location));\n            // String loc = new String(location);\n            Measurement measurement = store.get(hashCode);\n            if (measurement == null) {\n                measurement = new Measurement();\n                store.put(hashCode, measurement);\n            }\n            double tempD = parseDouble(temperature);\n            measurement.process(tempD);\n        }\n\n        public double parseDouble(byte[] bytes) {\n            long value = 0;\n            int exp = 0;\n            boolean negative = false;\n            int decimalPlaces = Integer.MIN_VALUE;\n            int index = 0;\n            int ch = bytes[index];\n            if (ch == '-') {\n                negative = true;\n                ch = bytes[++index];\n            }\n            while (index < bytes.length) {\n                if (ch >= '0' && ch <= '9') {\n                    while (value >= MAX_VALUE_DIVIDE_10) {\n                        value >>>= 1;\n                        exp++;\n                    }\n                    value = value * 10 + (ch - '0');\n                    decimalPlaces++;\n\n                }\n                else if (ch == '.') {\n                    decimalPlaces = 0;\n                }\n                if (index == bytes.length - 1) {\n                    break;\n                }\n                else {\n                    ch = bytes[++index];\n                }\n            }\n            return asDouble(value, exp, negative, decimalPlaces);\n        }\n\n        private static double asDouble(long value, int exp, boolean negative, int decimalPlaces) {\n            if (decimalPlaces > 0 && value < Long.MAX_VALUE / 2) {\n                if (value < Long.MAX_VALUE / (1L << 32)) {\n                    exp -= 32;\n                    value <<= 32;\n                }\n                if (value < Long.MAX_VALUE / (1L << 16)) {\n                    exp -= 16;\n                    value <<= 16;\n                }\n                if (value < Long.MAX_VALUE / (1L << 8)) {\n                    exp -= 8;\n                    value <<= 8;\n                }\n                if (value < Long.MAX_VALUE / (1L << 4)) {\n                    exp -= 4;\n                    value <<= 4;\n                }\n                if (value < Long.MAX_VALUE / (1L << 2)) {\n                    exp -= 2;\n                    value <<= 2;\n                }\n                if (value < Long.MAX_VALUE / (1L << 1)) {\n                    exp -= 1;\n                    value <<= 1;\n                }\n            }\n            for (; decimalPlaces > 0; decimalPlaces--) {\n                exp--;\n                long mod = value % 5;\n                value /= 5;\n                int modDiv = 1;\n                if (value < Long.MAX_VALUE / (1L << 4)) {\n                    exp -= 4;\n                    value <<= 4;\n                    modDiv <<= 4;\n                }\n                if (value < Long.MAX_VALUE / (1L << 2)) {\n                    exp -= 2;\n                    value <<= 2;\n                    modDiv <<= 2;\n                }\n                if (value < Long.MAX_VALUE / (1L << 1)) {\n                    exp -= 1;\n                    value <<= 1;\n                    modDiv <<= 1;\n                }\n                if (decimalPlaces > 1)\n                    value += modDiv * mod / 5;\n                else\n                    value += (modDiv * mod + 4) / 5;\n            }\n            final double d = Math.scalb((double) value, exp);\n            return negative ? -d : d;\n        }\n\n        public String getResult() {\n            Map<String, Measurement> sortedMap = new TreeMap<>();\n            store.forEach((k, v) -> sortedMap.put(LOCATION_STORE.get(k), v));\n            return sortedMap.toString();\n        }\n    }\n\n    static final class Measurement {\n        private double min = Double.POSITIVE_INFINITY;\n        private double max = Double.NEGATIVE_INFINITY;\n        private double sum;\n        private long count;\n\n        public void process(double value) {\n            if (value < min) {\n                min = value;\n            }\n            if (value > max) {\n                max = value;\n            }\n            sum += value;\n            count++;\n        }\n\n        public void process(Measurement other) {\n            if (other.min < min) {\n                this.min = other.min;\n            }\n            if (other.max > max) {\n                this.max = other.max;\n            }\n            this.sum += other.sum;\n            this.count += other.count;\n        }\n\n        public String toString() {\n            ResultRow result = new ResultRow(min, sum, count, max);\n            return result.toString();\n        }\n    }\n\n    private record ResultRow(double min, double sum, double count, double max) {\n\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round((Math.round(sum * 10.0) / 10.0) / count)}/\\{round(max)}\";\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_thanhtrinity.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\nimport static java.lang.Math.round;\nimport static java.nio.channels.FileChannel.MapMode.READ_ONLY;\nimport static java.nio.charset.StandardCharsets.UTF_8;\nimport static java.nio.file.StandardOpenOption.READ;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_thanhtrinity {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final int TOTAL_PROCESSOR = Runtime.getRuntime().availableProcessors();\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n\n        // System.out.println(\"Num Of Processor:\" + TOTAL_PROCESSOR);\n        var threads = new ArrayList<Thread>();\n\n        var fileChannel = FileChannel.open(Path.of(FILE), READ);\n        long fullSize = fileChannel.size();\n        // System.out.println(\"FullSize:\" + fullSize);\n\n        var standardChunkSize = fullSize / TOTAL_PROCESSOR;\n        // System.out.println(\"StandardChunkSize:\" + standardChunkSize);\n        var chunkDataList = new ChunkData[TOTAL_PROCESSOR];\n\n        var start = 0L;\n        var end = standardChunkSize;\n        for (int index = 0; index < TOTAL_PROCESSOR; index++) {\n            long newStart = start;\n            end = adjustBreakLinePosition(start + standardChunkSize) + 1;\n            end = end >= fullSize ? fullSize : end;\n            var chunkSize = end - start;\n\n            // Have checked with virtual thread but it slower than normal thread\n            int taskIdx = index;\n            var thread = new Thread(() -> {\n                try (var file = new RandomAccessFile(FILE, \"r\");\n                        var fc = file.getChannel()) {\n                    var buffer = fc.map(READ_ONLY, newStart, chunkSize);\n                    chunkDataList[taskIdx] = processBufferData(buffer, taskIdx + 1);\n                }\n                catch (IOException e) {\n                    e.printStackTrace();\n                }\n            });\n            thread.start();\n            threads.add(thread);\n            if (end == fullSize) {\n                break;\n            }\n            start = end;\n        }\n\n        for (var thread : threads) {\n            thread.join();\n        }\n        consolidateData(chunkDataList);\n    }\n\n    private static long adjustBreakLinePosition(long position) throws IOException {\n        try (var file = new RandomAccessFile(FILE, \"r\")) {\n            file.seek(position);\n            while (file.read() != '\\n' && position < file.length()) {\n                position++;\n            }\n        }\n        return position;\n\n    }\n\n    private static ChunkData processBufferData(MappedByteBuffer buffer, long taskIdx) {\n\n        int currentIdx = 0;\n        int breakLineIndex = 0;\n\n        final int capacity = 100000;\n        var cities = new City[capacity];\n        var isProcessKey = true;\n        var hashKey = 0;\n        double result = 0;\n        int integerPart = 0;\n        double fractionalPart = 0;\n        boolean isFractional = false;\n        double divisorForFraction = 1;\n        boolean isNegative = false;\n        for (int i = 0; i < buffer.limit(); i++) {\n            var b = buffer.get();\n            var position = i + 1;\n            if (isProcessKey) {\n                if (b == ';') {\n                    hashKey = hashKey % capacity;\n                    currentIdx = hashKey;\n                    var name = new byte[position - breakLineIndex];\n                    buffer.get(breakLineIndex, name, 0, position - breakLineIndex - 1);\n                    if (cities[currentIdx] == null) {\n                        cities[currentIdx] = new City(name);\n                    }\n                    else if (!Arrays.equals(cities[currentIdx].getName(), name)) {\n                        while (cities[currentIdx] != null) { // Continue probing until empty slot\n                            currentIdx = (currentIdx + 1) % capacity;\n                        }\n                        cities[currentIdx] = new City(name);\n                    }\n                    hashKey = 0;\n                    isProcessKey = false;\n                }\n                else {\n                    hashKey = (31 * hashKey + b) & 0x7FFFFFFF;\n                }\n            }\n            else {\n                if (b == '\\n') {\n                    fractionalPart /= divisorForFraction;\n                    result = integerPart + fractionalPart;\n                    if (isNegative) {\n                        result *= -1;\n                    }\n                    cities[currentIdx].updateTemp(result);\n\n                    breakLineIndex = position;\n                    // reset parameter\n                    hashKey = 0;\n                    result = 0;\n                    integerPart = 0;\n                    fractionalPart = 0;\n                    isFractional = false;\n                    divisorForFraction = 1;\n                    isNegative = false;\n                    isProcessKey = true;\n                }\n                else {\n                    switch (b) {\n                        case '-':\n                            isNegative = true;\n                            break;\n                        case '.':\n                            isFractional = true;\n                            break;\n                        default:\n                            if (!isFractional) {\n                                integerPart = integerPart * 10 + (b - '0');\n                            }\n                            else {\n                                divisorForFraction *= 10;\n                                fractionalPart = fractionalPart * 10 + (b - '0');\n                            }\n                            break;\n                    }\n                }\n            }\n\n        }\n        buffer = null;\n        System.gc();\n        var citiesList = Arrays.stream(cities).filter(Objects::nonNull).toList();\n        return new ChunkData(citiesList);\n    }\n\n    private static void consolidateData(ChunkData[] citiesTempChunk) {\n\n        var cities = Arrays.stream(citiesTempChunk).filter(Objects::nonNull)\n                .flatMap(chunkData -> chunkData.cities().stream())\n                .collect(\n                        Collectors.toMap(\n                                City::getKey,\n                                city -> city,\n                                City::combine));\n        System.out.println(new TreeMap<>(cities));\n    }\n\n    record ChunkData(List<City> cities) {\n    }\n}\n\nclass City {\n    private byte[] name;\n    private String key;\n    private double min = Double.MAX_VALUE;\n    private double max = -Double.MAX_VALUE;\n    private double sum = 0L;\n    private int count = 0;\n\n    public City() {\n    }\n\n    public City(byte[] name) {\n        this.name = name;\n    }\n\n    public void updateTemp(double temp) {\n        min = min(min, temp);\n        max = max(max, temp);\n        sum += temp;\n        count++;\n    }\n\n    public String getKey() {\n        int i = 0;\n        while (i < name.length && name[i] != 0) {\n            i++;\n        }\n        key = new String(name, 0, i, UTF_8);\n        return key;\n    }\n\n    public static City combine(City t1, City t2) {\n        City result = new City();\n        result.min = min(t1.min, t2.min);\n        result.max = max(t1.max, t2.max);\n        result.sum = t1.sum + t2.sum;\n        result.count = t1.count + t2.count;\n        return result;\n    }\n\n    @Override\n    public String toString() {\n        return roundNumber(min) + \"/\" + roundNumber(sum / count) + \"/\" + roundNumber(max);\n    }\n\n    public void setName(byte[] name) {\n        this.name = name;\n    }\n\n    public byte[] getName() {\n        return this.name;\n    }\n\n    private static double roundNumber(double value) {\n        return round(value * 10.0) / 10.0;\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicLong;\n\n/**\n * The solution starts a child worker process for the actual work such that clean up of the memory mapping can occur\n * while the main process already returns with the result. The worker then memory maps the input file, creates a worker\n * thread per available core, and then processes segments of size {@link #SEGMENT_SIZE} at a time. The segments are\n * split into 3 parts and cursors for each of those parts are processing the segment simultaneously in the same thread.\n * Results are accumulated into {@link Result} objects and a tree map is used to sequentially accumulate the results in\n * the end.\n * Runs in 0.31 on an Intel i9-13900K while the reference implementation takes 120.37s.\n * Credit:\n *  Quan Anh Mai for branchless number parsing code\n *  Alfonso² Peterssen for suggesting memory mapping with unsafe and the subprocess idea\n *  Artsiom Korzun for showing the benefits of work stealing at 2MB segments instead of equal split between workers\n *  Jaromir Hamala for showing that avoiding the branch misprediction between <8 and 8-16 cases is a big win even if\n *  more work is performed\n *  Van Phu DO for demonstrating the lookup tables based on masks instead of bit shifting\n */\npublic class CalculateAverage_thomaswue {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int MIN_TEMP = -999;\n    private static final int MAX_TEMP = 999;\n    private static final int MAX_NAME_LENGTH = 100;\n    private static final int MAX_CITIES = 10000;\n    private static final int SEGMENT_SIZE = 1 << 21;\n    private static final int HASH_TABLE_SIZE = 1 << 17;\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        // Start worker subprocess if this process is not the worker.\n        if (args.length == 0 || !(\"--worker\".equals(args[0]))) {\n            spawnWorker();\n            return;\n        }\n\n        int numberOfWorkers = Runtime.getRuntime().availableProcessors();\n        try (var fileChannel = FileChannel.open(java.nio.file.Path.of(FILE), java.nio.file.StandardOpenOption.READ)) {\n            long fileSize = fileChannel.size();\n            final long fileStart = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, java.lang.foreign.Arena.global()).address();\n            final long fileEnd = fileStart + fileSize;\n            final AtomicLong cursor = new AtomicLong(fileStart);\n\n            // Parallel processing of segments.\n            Thread[] threads = new Thread[numberOfWorkers];\n            List<Result>[] allResults = new List[numberOfWorkers];\n            for (int i = 0; i < threads.length; ++i) {\n                final int index = i;\n                threads[i] = new Thread(() -> {\n                    List<Result> results = new ArrayList<>(MAX_CITIES);\n                    parseLoop(cursor, fileEnd, fileStart, results);\n                    allResults[index] = results;\n                });\n                threads[i].start();\n            }\n            for (Thread thread : threads) {\n                thread.join();\n            }\n\n            // Final output.\n            System.out.println(accumulateResults(allResults));\n            System.out.close();\n        }\n    }\n\n    private static void spawnWorker() throws IOException {\n        ProcessHandle.Info info = ProcessHandle.current().info();\n        ArrayList<String> workerCommand = new ArrayList<>();\n        info.command().ifPresent(workerCommand::add);\n        info.arguments().ifPresent(args -> workerCommand.addAll(Arrays.asList(args)));\n        workerCommand.add(\"--worker\");\n        new ProcessBuilder().command(workerCommand).inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE)\n                .start().getInputStream().transferTo(System.out);\n    }\n\n    private static TreeMap<String, Result> accumulateResults(List<Result>[] allResults) {\n        TreeMap<String, Result> result = new TreeMap<>();\n        for (List<Result> resultArr : allResults) {\n            for (Result r : resultArr) {\n                Result current = result.putIfAbsent(r.calcName(), r);\n                if (current != null) {\n                    current.accumulate(r);\n                }\n            }\n        }\n        return result;\n    }\n\n    private static void parseLoop(AtomicLong counter, long fileEnd, long fileStart, List<Result> collectedResults) {\n        Result[] results = new Result[HASH_TABLE_SIZE];\n        while (true) {\n            long current = counter.addAndGet(SEGMENT_SIZE) - SEGMENT_SIZE;\n            if (current >= fileEnd) {\n                return;\n            }\n\n            long segmentEnd = nextNewLine(Math.min(fileEnd - 1, current + SEGMENT_SIZE));\n            long segmentStart;\n            if (current == fileStart) {\n                segmentStart = current;\n            }\n            else {\n                segmentStart = nextNewLine(current) + 1;\n            }\n\n            long dist = (segmentEnd - segmentStart) / 3;\n            long midPoint1 = nextNewLine(segmentStart + dist);\n            long midPoint2 = nextNewLine(segmentStart + dist + dist);\n\n            Scanner scanner1 = new Scanner(segmentStart, midPoint1);\n            Scanner scanner2 = new Scanner(midPoint1 + 1, midPoint2);\n            Scanner scanner3 = new Scanner(midPoint2 + 1, segmentEnd);\n            while (true) {\n                if (!scanner1.hasNext()) {\n                    break;\n                }\n                if (!scanner2.hasNext()) {\n                    break;\n                }\n                if (!scanner3.hasNext()) {\n                    break;\n                }\n                long word1 = scanner1.getLong();\n                long word2 = scanner2.getLong();\n                long word3 = scanner3.getLong();\n                long delimiterMask1 = findDelimiter(word1);\n                long delimiterMask2 = findDelimiter(word2);\n                long delimiterMask3 = findDelimiter(word3);\n                long word1b = scanner1.getLongAt(scanner1.pos() + 8);\n                long word2b = scanner2.getLongAt(scanner2.pos() + 8);\n                long word3b = scanner3.getLongAt(scanner3.pos() + 8);\n                long delimiterMask1b = findDelimiter(word1b);\n                long delimiterMask2b = findDelimiter(word2b);\n                long delimiterMask3b = findDelimiter(word3b);\n                Result existingResult1 = findResult(word1, delimiterMask1, word1b, delimiterMask1b, scanner1, results, collectedResults);\n                Result existingResult2 = findResult(word2, delimiterMask2, word2b, delimiterMask2b, scanner2, results, collectedResults);\n                Result existingResult3 = findResult(word3, delimiterMask3, word3b, delimiterMask3b, scanner3, results, collectedResults);\n                long number1 = scanNumber(scanner1);\n                long number2 = scanNumber(scanner2);\n                long number3 = scanNumber(scanner3);\n                record(existingResult1, number1);\n                record(existingResult2, number2);\n                record(existingResult3, number3);\n            }\n\n            while (scanner1.hasNext()) {\n                long word = scanner1.getLong();\n                long pos = findDelimiter(word);\n                long wordB = scanner1.getLongAt(scanner1.pos() + 8);\n                long posB = findDelimiter(wordB);\n                record(findResult(word, pos, wordB, posB, scanner1, results, collectedResults), scanNumber(scanner1));\n            }\n            while (scanner2.hasNext()) {\n                long word = scanner2.getLong();\n                long pos = findDelimiter(word);\n                long wordB = scanner2.getLongAt(scanner2.pos() + 8);\n                long posB = findDelimiter(wordB);\n                record(findResult(word, pos, wordB, posB, scanner2, results, collectedResults), scanNumber(scanner2));\n            }\n            while (scanner3.hasNext()) {\n                long word = scanner3.getLong();\n                long pos = findDelimiter(word);\n                long wordB = scanner3.getLongAt(scanner3.pos() + 8);\n                long posB = findDelimiter(wordB);\n                record(findResult(word, pos, wordB, posB, scanner3, results, collectedResults), scanNumber(scanner3));\n            }\n        }\n    }\n\n    private static final long[] MASK1 = new long[]{ 0xFFL, 0xFFFFL, 0xFFFFFFL, 0xFFFFFFFFL, 0xFFFFFFFFFFL, 0xFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFFFL,\n            0xFFFFFFFFFFFFFFFFL };\n    private static final long[] MASK2 = new long[]{ 0x00L, 0x00L, 0x00L, 0x00L, 0x00L, 0x00L, 0x00L, 0x00L, 0xFFFFFFFFFFFFFFFFL };\n\n    private static Result findResult(long initialWord, long initialDelimiterMask, long wordB, long delimiterMaskB, Scanner scanner, Result[] results,\n                                     List<Result> collectedResults) {\n        Result existingResult;\n        long word = initialWord;\n        long delimiterMask = initialDelimiterMask;\n        long hash;\n        long nameAddress = scanner.pos();\n        long word2 = wordB;\n        long delimiterMask2 = delimiterMaskB;\n        if ((delimiterMask | delimiterMask2) != 0) {\n            int letterCount1 = Long.numberOfTrailingZeros(delimiterMask) >>> 3; // value between 1 and 8\n            int letterCount2 = Long.numberOfTrailingZeros(delimiterMask2) >>> 3; // value between 0 and 8\n            long mask = MASK2[letterCount1];\n            word = word & MASK1[letterCount1];\n            word2 = mask & word2 & MASK1[letterCount2];\n            hash = word ^ word2;\n            existingResult = results[hashToIndex(hash, results)];\n            scanner.add(letterCount1 + (letterCount2 & mask));\n            if (existingResult != null && existingResult.firstNameWord == word && existingResult.secondNameWord == word2) {\n                return existingResult;\n            }\n        }\n        else {\n            // Slow-path for when the ';' could not be found in the first 16 bytes.\n            hash = word ^ word2;\n            scanner.add(16);\n            while (true) {\n                word = scanner.getLong();\n                delimiterMask = findDelimiter(word);\n                if (delimiterMask != 0) {\n                    int trailingZeros = Long.numberOfTrailingZeros(delimiterMask);\n                    word = (word << (63 - trailingZeros));\n                    scanner.add(trailingZeros >>> 3);\n                    hash ^= word;\n                    break;\n                }\n                else {\n                    scanner.add(8);\n                    hash ^= word;\n                }\n            }\n        }\n\n        // Save length of name for later.\n        int nameLength = (int) (scanner.pos() - nameAddress);\n\n        // Final calculation for index into hash table.\n        int tableIndex = hashToIndex(hash, results);\n        outer: while (true) {\n            existingResult = results[tableIndex];\n            if (existingResult == null) {\n                existingResult = newEntry(results, nameAddress, tableIndex, nameLength, scanner, collectedResults);\n            }\n            // Check for collision.\n            int i = 0;\n            for (; i < nameLength + 1 - 8; i += 8) {\n                if (scanner.getLongAt(existingResult.nameAddress + i) != scanner.getLongAt(nameAddress + i)) {\n                    // Collision error, try next.\n                    tableIndex = (tableIndex + 31) & (results.length - 1);\n                    continue outer;\n                }\n            }\n\n            int remainingShift = (64 - ((nameLength + 1 - i) << 3));\n            if (((scanner.getLongAt(existingResult.nameAddress + i) ^ (scanner.getLongAt(nameAddress + i))) << remainingShift) == 0) {\n                break;\n            }\n            else {\n                // Collision error, try next.\n                tableIndex = (tableIndex + 31) & (results.length - 1);\n            }\n        }\n        return existingResult;\n    }\n\n    private static long nextNewLine(long prev) {\n        while (true) {\n            long currentWord = Scanner.UNSAFE.getLong(prev);\n            long input = currentWord ^ 0x0A0A0A0A0A0A0A0AL;\n            long pos = (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;\n            if (pos != 0) {\n                prev += Long.numberOfTrailingZeros(pos) >>> 3;\n                break;\n            }\n            else {\n                prev += 8;\n            }\n        }\n        return prev;\n    }\n\n    private static long scanNumber(Scanner scanPtr) {\n        long numberWord = scanPtr.getLongAt(scanPtr.pos() + 1);\n        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000L);\n        long number = convertIntoNumber(decimalSepPos, numberWord);\n        scanPtr.add((decimalSepPos >>> 3) + 4);\n        return number;\n    }\n\n    private static void record(Result existingResult, long number) {\n        if (number < existingResult.min) {\n            existingResult.min = (short) number;\n        }\n        if (number > existingResult.max) {\n            existingResult.max = (short) number;\n        }\n        existingResult.sum += number;\n        existingResult.count++;\n    }\n\n    private static int hashToIndex(long hash, Result[] results) {\n        long hashAsInt = hash ^ (hash >>> 33) ^ (hash >>> 15);\n        return (int) (hashAsInt & (results.length - 1));\n    }\n\n    // Special method to convert a number in the ascii number into an int without branches created by Quan Anh Mai.\n    private static long convertIntoNumber(int decimalSepPos, long numberWord) {\n        int shift = 28 - decimalSepPos;\n        // signed is -1 if negative, 0 otherwise\n        long signed = (~numberWord << 59) >> 63;\n        long designMask = ~(signed & 0xFF);\n        // Align the number to a specific position and transform the ascii to digit value\n        long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n        // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n        // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n        // 0x000000UU00TTHH00 + 0x00UU00TTHH000000 * 10 + 0xUU00TTHH00000000 * 100\n        long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        return (absValue ^ signed) - signed;\n    }\n\n    private static long findDelimiter(long word) {\n        long input = word ^ 0x3B3B3B3B3B3B3B3BL;\n        return (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;\n    }\n\n    private static Result newEntry(Result[] results, long nameAddress, int hash, int nameLength, Scanner scanner, List<Result> collectedResults) {\n        Result r = new Result();\n        results[hash] = r;\n        int totalLength = nameLength + 1;\n        r.firstNameWord = scanner.getLongAt(nameAddress);\n        r.secondNameWord = scanner.getLongAt(nameAddress + 8);\n        if (totalLength <= 8) {\n            r.firstNameWord = r.firstNameWord & MASK1[totalLength - 1];\n            r.secondNameWord = 0;\n        }\n        else if (totalLength < 16) {\n            r.secondNameWord = r.secondNameWord & MASK1[totalLength - 9];\n        }\n        r.nameAddress = nameAddress;\n        collectedResults.add(r);\n        return r;\n    }\n\n    private static final class Result {\n        long firstNameWord, secondNameWord;\n        short min, max;\n        int count;\n        long sum;\n        long nameAddress;\n\n        private Result() {\n            this.min = MAX_TEMP;\n            this.max = MIN_TEMP;\n        }\n\n        public String toString() {\n            return round(((double) min) / 10.0) + \"/\" + round((((double) sum) / 10.0) / count) + \"/\" + round(((double) max) / 10.0);\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        private void accumulate(Result other) {\n            if (other.min < min) {\n                min = other.min;\n            }\n            if (other.max > max) {\n                max = other.max;\n            }\n            sum += other.sum;\n            count += other.count;\n        }\n\n        public String calcName() {\n            Scanner scanner = new Scanner(nameAddress, nameAddress + MAX_NAME_LENGTH + 1);\n            int nameLength = 0;\n            while (scanner.getByteAt(nameAddress + nameLength) != ';') {\n                nameLength++;\n            }\n            byte[] array = new byte[nameLength];\n            for (int i = 0; i < nameLength; ++i) {\n                array[i] = scanner.getByteAt(nameAddress + i);\n            }\n            return new String(array, java.nio.charset.StandardCharsets.UTF_8);\n        }\n    }\n\n    private static final class Scanner {\n        private static final sun.misc.Unsafe UNSAFE = initUnsafe();\n        private long pos;\n        private final long end;\n\n        private static sun.misc.Unsafe initUnsafe() {\n            try {\n                java.lang.reflect.Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField(\"theUnsafe\");\n                theUnsafe.setAccessible(true);\n                return (sun.misc.Unsafe) theUnsafe.get(sun.misc.Unsafe.class);\n            }\n            catch (NoSuchFieldException | IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        public Scanner(long start, long end) {\n            this.pos = start;\n            this.end = end;\n        }\n\n        boolean hasNext() {\n            return pos < end;\n        }\n\n        long pos() {\n            return pos;\n        }\n\n        void add(long delta) {\n            pos += delta;\n        }\n\n        long getLong() {\n            return UNSAFE.getLong(pos);\n        }\n\n        long getLongAt(long pos) {\n            return UNSAFE.getLong(pos);\n        }\n\n        byte getByteAt(long pos) {\n            return UNSAFE.getByte(pos);\n        }\n    }\n}"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_tivrfoa.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * Solution based on thomaswue solution, commit:\n * commit d0a28599c293d3afe3291fc3cf169a7b25ae9ae6\n * Author: Thomas Wuerthinger\n * Date:   Sun Jan 21 20:13:48 2024 +0100\n *\n * The goal here was to try to improve the runtime of his 10k\n * solution of: 00:04.516\n * \n * With Thomas latest changes, his time is probably much better\n * already, and maybe even 1st place for the 10k too.\n * See: https://github.com/gunnarmorling/1brc/pull/606\n * \n * As I was not able to make it faster ... so I'll make it slower,\n * because my current solution should *not* stay at the top, as it added\n * basically nothing.\n */\npublic class CalculateAverage_tivrfoa {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int MAX_CITIES = 10_000;\n    private static final int BUCKETS_LEN = 1 << 17;\n    private static final int LAST_BUCKET_ENTRY = BUCKETS_LEN - 1;\n    private static final int NUM_CPUS = Runtime.getRuntime().availableProcessors();\n    private static final AtomicInteger chunkIdx = new AtomicInteger();\n    private static long[] chunks;\n    private static int numChunks;\n\n    // Holding the current result for a single city.\n    private static class Result {\n        long lastNameLong;\n        long[] name;\n        int count;\n        short min, max;\n        long sum;\n\n        private Result(short number, long nameAddress, byte nameLength, Scanner scanner) {\n            this.min = number;\n            this.max = number;\n            this.sum = number;\n            this.count = 1;\n\n            name = new long[(nameLength / Long.BYTES) + 1];\n            int pos = 0, i = 0;\n            for (; i < nameLength + 1 - Long.BYTES; i += Long.BYTES) {\n                name[pos++] = scanner.getLongAt(nameAddress + i);\n            }\n\n            int remainingShift = (64 - (nameLength + 1 - i) << 3);\n            lastNameLong = (scanner.getLongAt(nameAddress + i) << remainingShift);\n            name[pos] = lastNameLong >> remainingShift;\n        }\n\n        public String toString() {\n            return round(((double) min) / 10.0) + \"/\" + round((((double) sum) / 10.0) / count) + \"/\" + round(((double) max) / 10.0);\n        }\n\n        private static double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        // Accumulate another result into this one.\n        private void add(Result other) {\n            if (other.min < min) {\n                min = other.min;\n            }\n            if (other.max > max) {\n                max = other.max;\n            }\n            sum += other.sum;\n            count += other.count;\n        }\n\n        private void add(short number) {\n            if (number < min) {\n                min = number;\n            }\n            if (number > max) {\n                max = number;\n            }\n            sum += number;\n            count++;\n        }\n\n        public String calcName() {\n            ByteBuffer bb = ByteBuffer.allocate(name.length * Long.BYTES).order(ByteOrder.nativeOrder());\n            bb.asLongBuffer().put(name);\n            byte[] array = bb.array();\n            int i = 0;\n            while (array[i++] != ';')\n                ;\n            return new String(array, 0, i - 1, StandardCharsets.UTF_8);\n        }\n    }\n\n    /**\n     * From:\n     * https://github.com/OpenHFT/Zero-Allocation-Hashing/blob/ea/src/main/java/net/openhft/hashing/XXH3.java\n     * \n     * Less collisions, but it will make the code slower. xD\n     * \n     * One interesting thing about Thomas' solution that I\n     * started to work with (d0a28599), is that it basically does not have\n     * any collision for the small data set (sometimes none!), but it\n     * has lots of collisions for the 10k, hence its poor performance.\n     * \n     */\n    private static long XXH3_avalanche(long h64) {\n        h64 ^= h64 >>> 37;\n        h64 *= 0x165667919E3779F9L;\n        return h64 ^ (h64 >>> 32);\n    }\n\n    private static final class SolveChunk extends Thread {\n        private int chunkStartIdx;\n        private Result[] results = new Result[MAX_CITIES];\n        private Result[] buckets = new Result[BUCKETS_LEN];\n        private int resIdx = 0;\n\n        public SolveChunk(int chunkStartIdx) {\n            this.chunkStartIdx = chunkStartIdx;\n        }\n\n        @Override\n        public void run() {\n            for (; chunkStartIdx < numChunks; chunkStartIdx = chunkIdx.getAndIncrement()) {\n                Scanner scanner = new Scanner(chunks[chunkStartIdx], chunks[chunkStartIdx + 1]);\n                long word = scanner.getLong();\n                long pos = findDelimiter(word);\n                while (scanner.hasNext()) {\n                    long nameAddress = scanner.pos();\n                    long hash = 0;\n\n                    while (true) {\n                        if (pos != 0) {\n                            pos = Long.numberOfTrailingZeros(pos) >>> 3;\n                            scanner.add(pos);\n                            word = mask(word, pos);\n                            hash ^= XXH3_avalanche(word);\n                            break;\n                        }\n                        else {\n                            scanner.add(8);\n                            hash ^= XXH3_avalanche(word);\n                        }\n\n                        word = scanner.getLong();\n                        pos = findDelimiter(word);\n                    }\n\n                    byte nameLength = (byte) (scanner.pos() - nameAddress);\n                    short number = scanNumber(scanner);\n\n                    int tableIndex = hashToIndex(hash);\n                    outer: while (true) {\n                        Result existingResult = buckets[tableIndex];\n                        if (existingResult == null) {\n                            var newResult = new Result(number, nameAddress, nameLength, scanner);\n                            buckets[tableIndex] = newResult;\n                            results[resIdx++] = newResult;\n                            break;\n                        }\n                        int i = 0;\n                        int namePos = 0;\n                        for (; i < nameLength + 1 - 8; i += 8) {\n                            if (namePos >= existingResult.name.length || existingResult.name[namePos++] != scanner.getLongAt(nameAddress + i)) {\n                                tableIndex = (tableIndex + 31) & (LAST_BUCKET_ENTRY);\n                                continue outer;\n                            }\n                        }\n\n                        int remainingShift = (64 - (nameLength + 1 - i) << 3);\n                        if (((existingResult.lastNameLong ^ (scanner.getLongAt(nameAddress + i) << remainingShift)) == 0)) {\n                            existingResult.add(number);\n                            break;\n                        }\n                        else {\n                            tableIndex = (tableIndex + 31) & (LAST_BUCKET_ENTRY);\n                        }\n                    }\n\n                    word = scanner.getLong();\n                    pos = findDelimiter(word);\n                }\n            }\n        }\n    }\n\n    private static void mergeIntoFinalMap(TreeMap<String, Result> map, Result[] newResults) {\n        for (var r : newResults) {\n            if (r == null)\n                return;\n            Result current = map.putIfAbsent(r.calcName(), r);\n            if (current != null) {\n                current.add(r);\n            }\n        }\n    }\n\n    public static void main(String[] args) throws InterruptedException, IOException {\n        chunks = getSegments(NUM_CPUS);\n        numChunks = chunks.length - 1;\n        final SolveChunk[] threads = new SolveChunk[NUM_CPUS];\n        chunkIdx.set(NUM_CPUS);\n        for (int i = 0; i < NUM_CPUS; i++) {\n            threads[i] = new SolveChunk(i);\n            threads[i].start();\n        }\n\n        System.out.println(getMap(threads));\n        System.out.close();\n    }\n\n    private static TreeMap<String, Result> getMap(SolveChunk[] threads) throws InterruptedException {\n        TreeMap<String, Result> map = new TreeMap<>();\n        threads[0].join();\n        for (var r : threads[0].results) {\n            if (r == null)\n                break;\n            map.put(r.calcName(), r);\n        }\n        for (int i = 1; i < NUM_CPUS; ++i) {\n            threads[i].join();\n            mergeIntoFinalMap(map, threads[i].results);\n        }\n\n        return map;\n    }\n\n    private static short scanNumber(Scanner scanPtr) {\n        scanPtr.add(1);\n        long numberWord = scanPtr.getLong();\n        int decimalSepPos = Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n        int number = convertIntoNumber(decimalSepPos, numberWord);\n        scanPtr.add((decimalSepPos >>> 3) + 3);\n        return (short) number;\n    }\n\n    private static int hashToIndex(long hash) {\n        int hashAsInt = (int) (hash ^ (hash >>> 28));\n        int finalHash = (hashAsInt ^ (hashAsInt >>> 17));\n        return (finalHash & LAST_BUCKET_ENTRY);\n    }\n\n    private static long mask(long word, long pos) {\n        return (word << ((7 - pos) << 3));\n    }\n\n    // Special method to convert a number in the ascii number into an int without branches created by Quan Anh Mai.\n    private static int convertIntoNumber(int decimalSepPos, long numberWord) {\n        int shift = 28 - decimalSepPos;\n        // signed is -1 if negative, 0 otherwise\n        long signed = (~numberWord << 59) >> 63;\n        long designMask = ~(signed & 0xFF);\n        // Align the number to a specific position and transform the ascii to digit value\n        long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n        // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n        // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n        // 0x000000UU00TTHH00 + 0x00UU00TTHH000000 * 10 + 0xUU00TTHH00000000 * 100\n        long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n        long value = (absValue ^ signed) - signed;\n        return (int) value;\n    }\n\n    private static long findDelimiter(long word) {\n        long input = word ^ 0x3B3B3B3B3B3B3B3BL;\n        long tmp = (input - 0x0101010101010101L) & ~input & 0x8080808080808080L;\n        return tmp;\n    }\n\n    /**\n     *  - Split 70% of the file in even chunks for all cpus;\n     *  - Create smaller chunks for the remainder of the file.  \n     */\n    private static long[] getSegments(int cpus) throws IOException {\n        try (var fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            final long fileSize = fileChannel.size();\n            final long part1 = (long) (fileSize * 0.7);\n            final long part2 = (long) (fileSize * 0.2);\n            final long part3 = fileSize - part1 - part2;\n            final long bigChunkSize = (part1 - 1) / cpus;\n            final long smallChunkSize1 = (part2 - 1) / (cpus * 3);\n            final long smallChunkSize2 = (part3 - 1) / (cpus * 3);\n            final int numChunks = cpus + cpus * 3 + cpus * 3;\n            final long[] sizes = new long[numChunks];\n            int l = 0, r = cpus;\n            Arrays.fill(sizes, l, r, bigChunkSize);\n            l = r;\n            r = l + cpus * 3;\n            Arrays.fill(sizes, l, r, smallChunkSize1);\n            l = r;\n            r = l + cpus * 3;\n            Arrays.fill(sizes, l, r, smallChunkSize2);\n            final long[] chunks = new long[sizes.length + 1];\n            final long mappedAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, java.lang.foreign.Arena.global()).address();\n            chunks[0] = mappedAddress;\n            final long endAddress = mappedAddress + fileSize;\n            final Scanner s = new Scanner(mappedAddress, mappedAddress + fileSize);\n            for (int i = 1, sizeIdx = 0; i < chunks.length - 1; ++i, sizeIdx = (sizeIdx + 1) % sizes.length) {\n                long chunkAddress = chunks[i - 1] + sizes[sizeIdx];\n                // Align to first row start.\n                while (chunkAddress < endAddress && (s.getLongAt(chunkAddress++) & 0xFF) != '\\n')\n                    ;\n                chunks[i] = Math.min(chunkAddress, endAddress);\n                // System.err.printf(\"Chunk size %d\\n\", chunks[i] - chunks[i - 1]);\n            }\n            chunks[chunks.length - 1] = endAddress;\n            // System.err.printf(\"Chunk size %d\\n\", chunks[chunks.length - 1] - chunks[chunks.length - 2]);\n            return chunks;\n        }\n    }\n\n    private static class Scanner {\n\n        private static final sun.misc.Unsafe UNSAFE = initUnsafe();\n\n        private static sun.misc.Unsafe initUnsafe() {\n            try {\n                java.lang.reflect.Field theUnsafe = sun.misc.Unsafe.class.getDeclaredField(\"theUnsafe\");\n                theUnsafe.setAccessible(true);\n                return (sun.misc.Unsafe) theUnsafe.get(sun.misc.Unsafe.class);\n            }\n            catch (NoSuchFieldException | IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        long pos, end;\n\n        public Scanner(long start, long end) {\n            this.pos = start;\n            this.end = end;\n        }\n\n        boolean hasNext() {\n            return pos < end;\n        }\n\n        long pos() {\n            return pos;\n        }\n\n        void add(long delta) {\n            pos += delta;\n        }\n\n        long getLong() {\n            return UNSAFE.getLong(pos);\n        }\n\n        long getLongAt(long pos) {\n            return UNSAFE.getLong(pos);\n        }\n\n        void setPos(long l) {\n            this.pos = l;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_tkosachev.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.Paths;\nimport java.util.*;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\n\npublic class CalculateAverage_tkosachev {\n\n    private static final String FILE = \"./measurements.txt\";\n    public static int numThreads = Math.min(Runtime.getRuntime().availableProcessors(), 8);\n\n    private record ResultRow(int min, double mean, int max) {\n        public String toString() {\n            return STR.\"\\{round(min)}/\\{round(mean)}/\\{round(max)}\";\n        }\n\n        private double round(double value) {\n            return Math.round(value) / 10.0;\n        }\n    }\n\n    private static class MeasurementAggregator {\n        private int min = Integer.MAX_VALUE;\n        private int max = Integer.MIN_VALUE;\n        private long sum = 0;\n        private long count = 0;\n\n        public void newValue(int m) {\n            if (m < min) {\n                min = m;\n            }\n            if (m > max) {\n                max = m;\n            }\n            sum += m;\n            count++;\n        }\n\n        public void mergeIn(MeasurementAggregator add) {\n            if (add.min < min) {\n                min = add.min;\n            }\n            if (add.max > max) {\n                max = add.max;\n            }\n            sum += add.sum;\n            count += add.count;\n        }\n    }\n\n    public static void main(String[] args) {\n        Path path = Paths.get(args.length == 0 ? FILE : args[0]);\n\n        Map<String, MeasurementAggregator> total;\n        try (RandomAccessFile aFile = new RandomAccessFile(path.toFile(), \"r\");\n                ExecutorService executorService = Executors.newFixedThreadPool(numThreads)) {\n            FileChannel inChannel = aFile.getChannel();\n            int numChunks = args.length > 1 ? Integer.parseInt(args[1]) : 100;\n\n            if (inChannel.size() < 1024 * 1024 * 1024) {\n                numThreads = 1;\n                numChunks = 1;\n            }\n\n            List<Future<Map<String, MeasurementAggregator>>> futures = new ArrayList<>(numThreads);\n            int bufferSize = (int) (inChannel.size() / numChunks) + 100;\n            for (int i = 0; i < numChunks; i++) {\n                final int finalI = i;\n                futures.add(executorService.submit(() -> processBuffer(inChannel, bufferSize, finalI)));\n            }\n            executorService.shutdown();\n            total = new HashMap<>();\n            for (Future<Map<String, MeasurementAggregator>> future : futures) {\n                mergeIn(total, future.get());\n            }\n        }\n        catch (IOException | InterruptedException | ExecutionException e) {\n            throw new RuntimeException(e);\n        }\n        printResults(total);\n    }\n\n    private static void mergeIn(Map<String, MeasurementAggregator> total, Map<String, MeasurementAggregator> result) {\n        for (String name : result.keySet()) {\n            MeasurementAggregator totalAggregator = total.computeIfAbsent(name, _ -> new MeasurementAggregator());\n            totalAggregator.mergeIn(result.get(name));\n        }\n    }\n\n    private static Map<String, MeasurementAggregator> processBuffer(FileChannel channel, int bufferSize, int nr) throws IOException {\n        HashMap<String, MeasurementAggregator> aggregatorMap = new HashMap<>();\n        long start = ((long) nr) * bufferSize;\n        long length = Math.min(bufferSize, channel.size() - start);\n        ByteBuffer byteBuffer = channel.map(\n                FileChannel.MapMode.READ_ONLY,\n                start,\n                length);\n        int i = 0;\n        int smcIndex = -1;\n        byte[] buf = new byte[1024];\n        int count = 0;\n        if (nr > 0) {\n            do {\n                i++;\n            } while (byteBuffer.get() != '\\n');\n        }\n        while (i < length) {\n            byte b = byteBuffer.get();\n            buf[count] = b;\n            if (b == ';') {\n                smcIndex = count;\n            }\n            count++;\n            if (b == '\\n') {\n                String name = new String(buf, 0, smcIndex);\n                int value = fastParse(buf, smcIndex + 1, count - smcIndex - 2);\n                aggregatorMap.computeIfAbsent(name, _ -> new MeasurementAggregator()).newValue(value);\n                count = 0;\n            }\n            i++;\n        }\n\n        return aggregatorMap;\n    }\n\n    private static void printResults(Map<String, MeasurementAggregator> result) {\n        Map<String, ResultRow> measurements = new TreeMap<>();\n        for (Map.Entry<String, MeasurementAggregator> entry : result.entrySet()) {\n            MeasurementAggregator value = entry.getValue();\n            measurements.put(entry.getKey(), new ResultRow(value.min, ((double) value.sum / value.count), value.max));\n        }\n        System.out.println(measurements);\n    }\n\n    public static int fastParse(byte[] buf, int start, int len) {\n        int i = 0;\n        int sign = 1;\n        for (int index = start; index < start + len; index++) {\n            byte b = buf[index];\n            if (b == '-') {\n                sign = -1;\n            }\n            if (b >= '0' && b <= '9') {\n                i = i * 10 + (b - '0');\n            }\n        }\n        return i * sign;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_tonivade.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.StructuredTaskScope;\nimport java.util.concurrent.StructuredTaskScope.Subtask;\n\npublic class CalculateAverage_tonivade {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int MIN_CHUNK_SIZE = 1024;\n    private static final int MAX_NAME_LENGTH = 128;\n    private static final int MAX_TEMP_LENGTH = 8;\n\n    public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {\n        System.out.println(readFile());\n    }\n\n    private static Map<String, Station> readFile() throws IOException, InterruptedException, ExecutionException {\n        Map<String, Station> result = new TreeMap<>();\n        try (var channel = FileChannel.open(Paths.get(FILE), StandardOpenOption.READ)) {\n            long consumed = 0;\n            long remaining = channel.size();\n            while (remaining > 0) {\n                var buffer = channel.map(\n                        MapMode.READ_ONLY, consumed, Math.min(remaining, Integer.MAX_VALUE));\n\n                int chunks = Runtime.getRuntime().availableProcessors();\n                int chunkSize = buffer.remaining() / chunks;\n                int leftover = buffer.remaining() % chunks;\n                if (chunkSize < MIN_CHUNK_SIZE) {\n                    var partialResult = new Chunk(buffer, 0, buffer.remaining()).read();\n\n                    consumed += partialResult.end();\n                    remaining -= partialResult.end();\n\n                    partialResult.merge(result);\n                }\n                else {\n                    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {\n                        var tasks = new ArrayList<Subtask<PartialResult>>(chunks);\n                        for (int i = 0; i < chunks; i++) {\n                            int start = i * chunkSize;\n                            int length = chunkSize + (i < chunks ? leftover : 0);\n                            tasks.add(scope.fork(new Chunk(buffer, start, length)::read));\n                        }\n                        scope.join();\n                        scope.throwIfFailed();\n\n                        for (var subtask : tasks) {\n                            subtask.get().merge(result);\n                        }\n                        consumed += tasks.getLast().get().end();\n                        remaining -= tasks.getLast().get().end();\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    static final class Chunk {\n\n        private static final int EOL = 10;\n        private static final int MINUS = 45;\n        private static final int SEMICOLON = 59;\n\n        final ByteBuffer buffer;\n        final int start;\n        final int end;\n\n        final byte[] name = new byte[MAX_NAME_LENGTH];\n        final byte[] temp = new byte[MAX_TEMP_LENGTH];\n        final Stations stations = new Stations();\n\n        int hash;\n\n        Chunk(ByteBuffer buffer, int start, int length) {\n            this.buffer = buffer;\n            this.start = findStart(buffer, start);\n            this.end = start + length;\n        }\n\n        private static int findStart(ByteBuffer buffer, int start) {\n            if (start > 0 && buffer.get(start - 1) != EOL) {\n                for (int i = start - 2; i > 0; i--) {\n                    byte b = buffer.get(i);\n                    if (b == EOL) {\n                        return i + 1;\n                    }\n                }\n            }\n            return start;\n        }\n\n        PartialResult read() {\n            int position = start;\n            while (position < end) {\n                int semicolon = readName(position, end - position);\n                if (semicolon < 0) {\n                    break;\n                }\n\n                int endOfLine = readTemp(semicolon + 1, end - semicolon - 1);\n                if (endOfLine < 0) {\n                    break;\n                }\n\n                stations.find(name, semicolon - position, hash)\n                        .add(parseTemp(temp, endOfLine - semicolon - 1));\n\n                // skip end of line\n                position = endOfLine + 1;\n            }\n            return new PartialResult(position, stations.buckets);\n        }\n\n        private int readName(int offset, int length) {\n            hash = 1;\n            for (int i = 0; i < length; i++) {\n                byte b = buffer.get(i + offset);\n                if (b == SEMICOLON) {\n                    return i + offset;\n                }\n                name[i] = b;\n                hash = 31 * hash + b;\n            }\n            return -1;\n        }\n\n        private int readTemp(int offset, int length) {\n            for (int i = 0; i < length; i++) {\n                byte b = buffer.get(i + offset);\n                if (b == EOL) {\n                    return i + offset;\n                }\n                temp[i] = b;\n            }\n            return -1;\n        }\n\n        // non null double between -99.9 (inclusive) and 99.9 (inclusive), always with one fractional digit\n        private static int parseTemp(byte[] value, int length) {\n            int period = length - 2;\n            if (value[0] == MINUS) {\n                int left = parseLeft(value, 1, period - 1);\n                int right = toInt(value[period + 1]);\n                return -(left + right);\n            }\n            int left = parseLeft(value, 0, period);\n            int right = toInt(value[period + 1]);\n            return left + right;\n        }\n\n        private static int parseLeft(byte[] value, int start, int length) {\n            if (length == 1) {\n                return toInt(value[start]) * 10;\n            }\n            // two chars\n            int a = toInt(value[start]) * 100;\n            int b = toInt(value[start + 1]) * 10;\n            return a + b;\n        }\n\n        private static int toInt(byte c) {\n            return c - 48;\n        }\n    }\n\n    static final class Stations {\n\n        private static final int NUMBER_OF_BUCKETS = 1000;\n        private static final int BUCKET_SIZE = 50;\n\n        final Station[][] buckets = new Station[NUMBER_OF_BUCKETS][BUCKET_SIZE];\n\n        Station find(byte[] name, int length, int hash) {\n            var bucket = buckets[Math.abs(hash % NUMBER_OF_BUCKETS)];\n            for (int i = 0; i < BUCKET_SIZE; i++) {\n                if (bucket[i] == null) {\n                    bucket[i] = new Station(name, length, hash);\n                    return bucket[i];\n                }\n                else if (bucket[i].sameName(length, hash)) {\n                    return bucket[i];\n                }\n            }\n            throw new IllegalStateException(\"no more space left\");\n        }\n    }\n\n    static final class Station {\n\n        private final byte[] name;\n        private final int hash;\n\n        private int min = 1000;\n        private int max = -1000;\n        private int sum;\n        private long count;\n\n        Station(byte[] source, int length, int hash) {\n            name = new byte[length];\n            System.arraycopy(source, 0, name, 0, length);\n            this.hash = hash;\n        }\n\n        String getName() {\n            return new String(name, StandardCharsets.UTF_8);\n        }\n\n        void add(int value) {\n            min = Math.min(min, value);\n            max = Math.max(max, value);\n            sum += value;\n            count++;\n        }\n\n        Station merge(Station other) {\n            min = Math.min(min, other.min);\n            max = Math.max(max, other.max);\n            sum += other.sum;\n            count += other.count;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return toDouble(min) + \"/\" + round(mean()) + \"/\" + toDouble(max);\n        }\n\n        boolean sameName(int length, int hash) {\n            return name.length == length && this.hash == hash;\n        }\n\n        private double mean() {\n            return toDouble(sum) / count;\n        }\n\n        private double toDouble(int value) {\n            return value / 10.;\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.) / 10.;\n        }\n    }\n\n    static record PartialResult(int end, Station[][] stations) {\n\n        void merge(Map<String, Station> result) {\n            for (Station[] bucket : stations) {\n                for (Station station : bucket) {\n                    if (station != null) {\n                        result.merge(station.getName(), station, Station::merge);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_truelive.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.*;\nimport java.util.concurrent.atomic.DoubleAccumulator;\nimport java.util.concurrent.atomic.LongAdder;\nimport java.util.stream.Collector;\nimport java.util.stream.Collectors;\nimport java.util.stream.StreamSupport;\n\npublic class CalculateAverage_truelive {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final long CHUNK_SIZE = 1024 * 1024 * 10L;\n\n    private static double getDouble(final byte[] arr, int pos) {\n        final int negative = ~(arr[pos] >> 4) & 1;\n        int sig = 1;\n        sig -= 2 * negative;\n        pos += negative;\n        final int digit1 = arr[pos] - '0';\n        pos++;\n        if (arr[pos] == '.') {\n            return sig * (digit1 + (arr[pos + 1] - '0') / 10.0);\n        }\n        else {\n            return sig * (digit1 * 10 + (arr[pos] - '0') + (arr[pos + 2] - '0') / 10.0);\n        }\n    }\n\n    private record Measurement(DoubleAccumulator min, DoubleAccumulator max, DoubleAccumulator sum, LongAdder count) {\n        public static Measurement of(final Double initialMeasurement) {\n            final Measurement measurement = new Measurement(\n                    new DoubleAccumulator(Math::min, initialMeasurement),\n                    new DoubleAccumulator(Math::max, initialMeasurement),\n                    new DoubleAccumulator(Double::sum, initialMeasurement),\n                    new LongAdder()\n            );\n            measurement.count.increment();\n            return measurement;\n        }\n\n        public Measurement add(final double measurment) {\n            min.accumulate(measurment);\n            max.accumulate(measurment);\n            sum.accumulate(measurment);\n            count.increment();\n            return this;\n        }\n\n        public String toString() {\n            return round(min.doubleValue()) +\n                   \"/\" +\n                   round(sum.doubleValue() / count.sum()) +\n                   \"/\" +\n                   round(max.doubleValue());\n        }\n\n        private double round(final double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n\n        public static Measurement combineWith(final Measurement m1, final Measurement m2) {\n            m1.min.accumulate(m2.min.doubleValue());\n            m1.max.accumulate(m2.max.doubleValue());\n            m1.sum.accumulate(m2.sum.doubleValue());\n            m1.count.add(m2.count.sum());\n            return new Measurement(\n                    m1.min,\n                    m1.max,\n                    m1.sum,\n                    m1.count\n            );\n        }\n    }\n\n    public static void main(final String[] args) throws IOException {\n        // long before = System.currentTimeMillis();\n        /**\n         * Shoutout to bjhara\n         */\n        final Iterator<ByteBuffer> iterator = new Iterator<>() {\n            final FileChannel in = new FileInputStream(FILE).getChannel();\n            final long total = in.size();\n            long start;\n\n            @Override\n            public boolean hasNext() {\n                return start < total;\n            }\n\n            @Override\n            public ByteBuffer next() {\n                try {\n                    final MappedByteBuffer mbb = in.map(\n                            FileChannel.MapMode.READ_ONLY,\n                            start,\n                            Math.min(CHUNK_SIZE, total - start));\n                    int realEnd = mbb.limit() - 1;\n                    while (mbb.get(realEnd) != '\\n') {\n                        realEnd--;\n                    }\n\n                    realEnd++;\n                    mbb.limit(realEnd);\n                    start += realEnd;\n\n                    return mbb;\n                }\n                catch (final IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        };\n\n        final Map<String, Measurement> reduce = StreamSupport.stream(Spliterators.spliteratorUnknownSize(\n                iterator, Spliterator.IMMUTABLE), true)\n                .map(CalculateAverage_truelive::parseBuffer)\n                .flatMap(map -> map.entrySet().stream())\n                .collect(Collectors.toMap(\n                        Map.Entry::getKey,\n                        Map.Entry::getValue,\n                        Measurement::combineWith,\n                        TreeMap::new));\n        System.out.println(reduce);\n\n    }\n\n    private static Map<String, Measurement> parseBuffer(final ByteBuffer bug) {\n\n        final Map<String, Measurement> resultMap = new HashMap<>();\n        bug.mark();\n        String name = null;\n        final byte[] arr = new byte[128];\n        int cur = 0;\n        while (bug.hasRemaining()) {\n            char c = (char) bug.get();\n            arr[cur++] = (byte) c;\n            while (c != ';') {\n                c = (char) bug.get();\n                arr[cur++] = (byte) c;\n            }\n            name = new String(arr, 0, cur - 1);\n            cur = 0;\n            while (c != '\\n') {\n                c = (char) bug.get();\n                arr[cur++] = (byte) c;\n            }\n            final double temp = getDouble(arr, 0);\n            resultMap.compute(name, (k, v) -> (v == null) ? Measurement.of(temp) : v.add(temp));\n            cur = 0;\n        }\n        return resultMap;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_twobiers.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport static java.util.stream.Collectors.groupingBy;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.Spliterator;\nimport java.util.Spliterators;\nimport java.util.TreeMap;\nimport java.util.function.BiConsumer;\nimport java.util.function.BinaryOperator;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\nimport java.util.stream.Collector;\nimport java.util.stream.StreamSupport;\n\npublic class CalculateAverage_twobiers {\n\n    private static final String FILE = \"./measurements.txt\";\n    private static final FastAveragingCollector FAST_AVERAGING_COLLECTOR = new FastAveragingCollector();\n    // private static final VectorSpecies<Integer> SPECIES = IntVector.SPECIES_256;\n\n    private static class FastAveragingCollector implements Collector<Measurement, double[], String> {\n        @Override\n        public Supplier<double[]> supplier() {\n            // 0: current sum\n            // 1: count\n            // 2: current max\n            // 3: current min\n            return () -> new double[4];\n        }\n\n        @Override\n        public BiConsumer<double[], Measurement> accumulator() {\n            return (a, t) -> {\n                double val = t.value();\n\n                a[0] += val;\n                a[1]++;\n\n                if (val > a[2] || a[1] == 1) {\n                    a[2] = val;\n                }\n                if (val < a[3] || a[1] == 1) {\n                    a[3] = val;\n                }\n            };\n        }\n\n        @Override\n        public BinaryOperator<double[]> combiner() {\n            return (a, b) -> {\n                a[0] += b[0];\n                a[1] += b[1];\n                if (b[2] > a[2]) {\n                    a[2] = b[2];\n                }\n                if (b[3] < a[3]) {\n                    a[3] = b[3];\n                }\n                return a;\n            };\n        }\n\n        @Override\n        public Function<double[], String> finisher() {\n            return a -> {\n                var mean = (a[1] == 0) ? 0.0d : Math.round((a[0] / a[1]) * 10.0) / 10.0;\n                var max = a[2];\n                var min = a[3];\n                return min + \"/\" + mean + \"/\" + max;\n            };\n        }\n\n        @Override\n        public Set<Characteristics> characteristics() {\n            return Collections.emptySet();\n        }\n    }\n\n    private static class FileChannelIterator implements Iterator<ByteBuffer> {\n        // File Size will be approx. 14G, 1MB Chunks sound kinda reasonable\n        private static final long CHUNK_SIZE = (long) Math.pow(2, 20);\n\n        private final FileChannel fileChannel;\n        private final long size;\n        private long bytesRead = 0;\n\n        public FileChannelIterator(FileChannel fileChannel) {\n            this.fileChannel = fileChannel;\n            try {\n                this.size = fileChannel.size();\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        public boolean hasNext() {\n            return bytesRead < size;\n        }\n\n        @Override\n        public ByteBuffer next() {\n            try {\n                MappedByteBuffer mappedByteBuffer = fileChannel.map(MapMode.READ_ONLY, bytesRead, Math.min(CHUNK_SIZE, size - bytesRead));\n\n                // Ensure the chunks will end on a newline\n                int realEnd = mappedByteBuffer.limit() - 1;\n                while (mappedByteBuffer.get(realEnd) != '\\n') {\n                    realEnd--;\n                }\n                mappedByteBuffer.limit(++realEnd);\n                bytesRead += realEnd;\n\n                return mappedByteBuffer;\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private record Measurement(String station, double value) {\n    }\n\n    public static void main(String[] args) throws IOException {\n        try (\n                var file = new RandomAccessFile(FILE, \"r\");\n                var channel = file.getChannel();) {\n            TreeMap<String, String> measurements = StreamSupport.stream(\n                    Spliterators.spliteratorUnknownSize(new FileChannelIterator(channel),\n                            Spliterator.IMMUTABLE),\n                    true)\n                    .flatMap(a -> parseMeasurements(a).stream())\n                    .collect(\n                            groupingBy(\n                                    Measurement::station,\n                                    TreeMap::new,\n                                    FAST_AVERAGING_COLLECTOR));\n\n            System.out.println(measurements);\n\n            // Simple test for my generated file\n            assert measurements.toString().equals(\n                    \"{Abha=-30.1/18.0/72.2, Abidjan=-23.4/26.0/79.9, Abéché=-17.3/29.4/80.5, Accra=-24.3/26.4/77.9, Addis Ababa=-33.6/16.0/65.9, Adelaide=-33.7/17.3/71.1, Aden=-21.2/29.1/81.2, Ahvaz=-30.2/25.4/80.2, Albuquerque=-39.1/14.0/60.9, Alexandra=-36.6/11.0/62.9, Alexandria=-30.4/20.0/69.8, Algiers=-33.1/18.2/68.4, Alice Springs=-27.2/21.0/72.1, Almaty=-40.5/10.0/58.5, Amsterdam=-38.9/10.2/58.9, Anadyr=-58.2/-6.9/39.9, Anchorage=-45.3/2.8/54.3, Andorra la Vella=-42.9/9.8/60.6, Ankara=-36.7/12.0/63.7, Antananarivo=-30.9/17.9/70.8, Antsiranana=-23.0/25.2/75.4, Arkhangelsk=-48.2/1.3/51.4, Ashgabat=-30.4/17.1/64.9, Asmara=-32.6/15.6/65.4, Assab=-21.2/30.5/78.7, Astana=-45.5/3.5/49.3, Athens=-28.5/19.2/68.0, Atlanta=-33.3/17.0/69.7, Auckland=-33.6/15.2/65.0, Austin=-32.1/20.7/68.5, Baghdad=-29.6/22.8/71.6, Baguio=-29.9/19.5/68.7, Baku=-32.1/15.1/66.8, Baltimore=-36.4/13.1/62.8, Bamako=-27.0/27.8/82.0, Bangkok=-20.5/28.6/79.0, Bangui=-24.2/26.0/73.8, Banjul=-27.0/26.0/75.4, Barcelona=-36.1/18.2/74.0, Bata=-25.9/25.1/73.7, Batumi=-36.8/14.0/65.7, Beijing=-34.2/12.9/65.9, Beirut=-28.9/20.9/68.5, Belgrade=-35.7/12.5/65.5, Belize City=-24.8/26.7/75.3, Benghazi=-28.6/19.9/68.9, Bergen=-48.8/7.7/58.5, Berlin=-48.1/10.3/62.5, Bilbao=-34.5/14.7/65.2, Birao=-22.7/26.5/77.9, Bishkek=-37.2/11.3/62.1, Bissau=-24.1/27.0/82.6, Blantyre=-29.2/22.2/68.9, Bloemfontein=-32.1/15.6/66.1, Boise=-36.6/11.4/62.2, Bordeaux=-34.2/14.2/63.0, Bosaso=-20.8/30.0/77.2, Boston=-39.8/10.9/58.4, Bouaké=-24.8/26.0/76.8, Bratislava=-40.5/10.5/62.6, Brazzaville=-29.3/25.0/74.6, Bridgetown=-25.0/27.0/78.4, Brisbane=-27.2/21.4/69.7, Brussels=-37.0/10.5/56.6, Bucharest=-48.7/10.8/60.8, Budapest=-39.6/11.3/61.6, Bujumbura=-26.3/23.8/73.8, Bulawayo=-32.8/18.9/68.5, Burnie=-35.3/13.1/64.4, Busan=-34.8/15.0/62.8, Cabo San Lucas=-25.0/23.9/71.6, Cairns=-23.1/25.0/74.3, Cairo=-27.6/21.4/68.6, Calgary=-46.9/4.4/56.2, Canberra=-36.9/13.1/63.4, Cape Town=-33.1/16.2/63.5, Changsha=-33.3/17.4/64.8, Charlotte=-33.7/16.1/63.5, Chiang Mai=-26.4/25.8/76.2, Chicago=-39.7/9.8/60.6, Chihuahua=-33.0/18.6/72.4, Chittagong=-20.8/25.9/76.1, Chișinău=-39.5/10.2/59.2, Chongqing=-30.8/18.6/71.4, Christchurch=-37.9/12.2/62.1, City of San Marino=-40.0/11.8/64.1, Colombo=-27.2/27.4/78.0, Columbus=-39.6/11.7/63.3, Conakry=-29.0/26.4/77.7, Copenhagen=-41.2/9.1/59.8, Cotonou=-24.6/27.2/80.1, Cracow=-39.9/9.3/63.2, Da Lat=-29.9/17.9/66.6, Da Nang=-23.4/25.8/74.5, Dakar=-27.8/24.0/74.8, Dallas=-33.8/19.0/69.2, Damascus=-33.5/17.0/68.5, Dampier=-25.0/26.4/75.8, Dar es Salaam=-22.6/25.8/78.6, Darwin=-22.0/27.6/75.4, Denpasar=-24.0/23.7/76.5, Denver=-38.2/10.4/60.4, Detroit=-38.0/10.0/60.0, Dhaka=-24.9/25.9/75.7, Dikson=-59.6/-11.1/39.0, Dili=-23.6/26.6/76.5, Djibouti=-18.9/29.9/77.8, Dodoma=-26.5/22.7/73.5, Dolisie=-24.4/24.0/71.9, Douala=-23.0/26.7/77.2, Dubai=-20.8/26.9/79.8, Dublin=-38.2/9.8/62.2, Dunedin=-39.3/11.1/61.3, Durban=-26.3/20.6/73.5, Dushanbe=-33.2/14.7/66.6, Edinburgh=-45.9/9.3/58.6, Edmonton=-41.7/4.2/56.0, El Paso=-29.6/18.1/66.5, Entebbe=-27.0/21.0/72.7, Erbil=-31.8/19.5/71.9, Erzurum=-47.0/5.1/55.4, Fairbanks=-48.9/-2.3/47.3, Fianarantsoa=-33.2/17.9/68.1, Flores,  Petén=-20.9/26.4/74.6, Frankfurt=-39.5/10.6/58.5, Fresno=-31.8/17.9/65.9, Fukuoka=-33.1/17.0/70.7, Gaborone=-29.0/21.0/73.1, Gabès=-34.3/19.5/70.3, Gagnoa=-24.6/26.0/80.8, Gangtok=-36.3/15.2/67.1, Garissa=-21.1/29.3/80.8, Garoua=-23.0/28.3/79.0, George Town=-23.4/27.9/78.1, Ghanzi=-33.3/21.4/73.2, Gjoa Haven=-64.9/-14.4/36.4, Guadalajara=-27.8/20.9/72.2, Guangzhou=-27.1/22.4/71.1, Guatemala City=-28.9/20.4/77.1, Halifax=-43.4/7.5/57.7, Hamburg=-41.5/9.7/65.0, Hamilton=-35.1/13.8/69.3, Hanga Roa=-29.1/20.5/70.8, Hanoi=-25.8/23.6/75.2, Harare=-33.2/18.4/69.1, Harbin=-45.1/5.0/55.0, Hargeisa=-33.4/21.7/71.1, Hat Yai=-22.5/27.0/74.3, Havana=-24.9/25.2/74.1, Helsinki=-42.3/5.9/55.2, Heraklion=-30.4/18.9/67.2, Hiroshima=-34.0/16.3/67.0, Ho Chi Minh City=-18.5/27.4/77.0, Hobart=-36.9/12.7/59.6, Hong Kong=-25.9/23.3/79.9, Honiara=-21.5/26.5/75.6, Honolulu=-22.9/25.4/73.7, Houston=-29.9/20.8/69.7, Ifrane=-36.8/11.4/59.3, Indianapolis=-39.8/11.8/58.4, Iqaluit=-58.2/-9.3/40.9, Irkutsk=-46.4/1.0/52.9, Istanbul=-35.2/13.9/61.9, Jacksonville=-29.4/20.3/72.0, Jakarta=-25.8/26.7/78.1, Jayapura=-21.2/27.0/74.9, Jerusalem=-31.8/18.3/66.8, Johannesburg=-32.2/15.5/63.9, Jos=-28.2/22.8/71.2, Juba=-21.4/27.8/76.2, Kabul=-37.5/12.1/61.9, Kampala=-33.6/20.0/70.1, Kandi=-23.3/27.7/77.6, Kankan=-24.6/26.5/82.7, Kano=-25.7/26.4/78.4, Kansas City=-38.7/12.5/60.9, Karachi=-24.5/26.0/74.4, Karonga=-22.5/24.4/77.5, Kathmandu=-37.5/18.3/67.3, Khartoum=-19.5/29.9/83.9, Kingston=-30.9/27.4/76.1, Kinshasa=-26.0/25.3/78.9, Kolkata=-23.0/26.7/76.4, Kuala Lumpur=-22.1/27.3/78.0, Kumasi=-22.4/26.0/80.3, Kunming=-33.1/15.7/66.1, Kuopio=-50.4/3.4/53.6, Kuwait City=-27.0/25.7/78.7, Kyiv=-43.4/8.4/57.5, Kyoto=-33.9/15.8/65.8, La Ceiba=-24.1/26.2/77.2, La Paz=-26.5/23.7/76.0, Lagos=-24.4/26.8/75.9, Lahore=-25.8/24.3/71.6, Lake Havasu City=-25.3/23.7/72.4, Lake Tekapo=-41.3/8.7/58.3, Las Palmas de Gran Canaria=-39.1/21.2/71.0, Las Vegas=-28.4/20.3/76.1, Launceston=-34.4/13.1/66.0, Lhasa=-41.2/7.6/57.5, Libreville=-24.0/25.9/73.8, Lisbon=-36.4/17.5/74.4, Livingstone=-27.5/21.8/77.2, Ljubljana=-36.4/10.9/61.4, Lodwar=-21.2/29.3/77.3, Lomé=-24.0/26.9/78.7, London=-38.3/11.3/63.4, Los Angeles=-29.8/18.6/67.1, Louisville=-40.0/13.9/61.7, Luanda=-22.7/25.8/75.3, Lubumbashi=-28.9/20.8/72.4, Lusaka=-29.1/19.9/75.4, Luxembourg City=-42.5/9.3/61.9, Lviv=-42.0/7.8/57.5, Lyon=-36.6/12.5/61.3, Madrid=-41.5/15.0/65.8, Mahajanga=-21.3/26.3/76.7, Makassar=-24.0/26.7/78.5, Makurdi=-21.6/26.0/76.9, Malabo=-20.1/26.3/73.1, Malé=-24.4/28.0/79.3, Managua=-26.7/27.3/78.7, Manama=-27.2/26.5/82.0, Mandalay=-22.3/28.0/76.9, Mango=-19.7/28.1/77.3, Manila=-27.7/28.4/76.9, Maputo=-31.7/22.8/71.0, Marrakesh=-28.0/19.6/74.1, Marseille=-39.0/15.8/66.1, Maun=-28.2/22.4/69.5, Medan=-24.4/26.5/78.9, Mek'ele=-28.4/22.7/73.7, Melbourne=-32.9/15.1/71.6, Memphis=-34.9/17.2/70.0, Mexicali=-31.9/23.1/71.6, Mexico City=-31.1/17.5/69.5, Miami=-24.6/24.9/75.0, Milan=-37.9/13.0/64.9, Milwaukee=-42.9/8.9/58.9, Minneapolis=-46.9/7.8/58.7, Minsk=-46.3/6.7/56.7, Mogadishu=-20.7/27.1/80.1, Mombasa=-21.4/26.3/77.4, Monaco=-34.1/16.4/66.0, Moncton=-42.7/6.1/53.7, Monterrey=-25.2/22.3/72.4, Montreal=-43.2/6.8/56.2, Moscow=-43.0/5.8/58.1, Mumbai=-22.5/27.1/78.4, Murmansk=-49.8/0.6/49.2, Muscat=-23.5/28.0/79.8, Mzuzu=-34.0/17.7/71.2, N'Djamena=-22.5/28.3/81.0, Naha=-24.9/23.1/71.0, Nairobi=-31.3/17.8/68.2, Nakhon Ratchasima=-29.4/27.3/75.4, Napier=-37.5/14.6/66.0, Napoli=-30.2/15.9/66.8, Nashville=-33.2/15.4/61.3, Nassau=-23.5/24.6/73.9, Ndola=-29.0/20.3/72.7, New Delhi=-23.4/25.0/73.4, New Orleans=-27.6/20.7/72.3, New York City=-36.1/12.9/63.9, Ngaoundéré=-25.2/22.0/73.8, Niamey=-20.5/29.3/79.3, Nicosia=-34.4/19.7/68.1, Niigata=-40.0/13.9/70.6, Nouadhibou=-27.3/21.3/76.0, Nouakchott=-23.3/25.7/84.5, Novosibirsk=-49.9/1.7/53.6, Nuuk=-52.0/-1.4/48.4, Odesa=-38.3/10.7/60.8, Odienné=-25.6/26.0/77.7, Oklahoma City=-31.5/15.9/64.4, Omaha=-38.6/10.6/57.4, Oranjestad=-24.7/28.1/78.5, Oslo=-43.8/5.7/56.2, Ottawa=-46.2/6.6/60.6, Ouagadougou=-22.3/28.3/76.2, Ouahigouya=-28.9/28.6/76.5, Ouarzazate=-32.1/18.9/66.6, Oulu=-51.5/2.7/53.0, Palembang=-20.6/27.3/76.1, Palermo=-33.8/18.5/68.3, Palm Springs=-25.4/24.5/71.9, Palmerston North=-38.8/13.2/60.8, Panama City=-22.3/28.0/76.3, Parakou=-26.4/26.8/76.6, Paris=-37.9/12.3/62.5, Perth=-29.8/18.7/67.9, Petropavlovsk-Kamchatsky=-47.7/1.9/56.0, Philadelphia=-34.1/13.2/60.1, Phnom Penh=-23.1/28.3/79.2, Phoenix=-26.8/23.9/72.6, Pittsburgh=-41.3/10.8/61.2, Podgorica=-32.4/15.3/65.3, Pointe-Noire=-24.8/26.1/74.1, Pontianak=-22.9/27.7/76.3, Port Moresby=-23.2/26.9/77.7, Port Sudan=-20.3/28.4/84.2, Port Vila=-23.2/24.3/74.7, Port-Gentil=-22.9/26.0/77.3, Portland (OR)=-36.2/12.4/61.0, Porto=-30.6/15.7/69.7, Prague=-46.5/8.4/57.3, Praia=-22.2/24.4/80.3, Pretoria=-34.0/18.2/66.9, Pyongyang=-41.5/10.8/59.6, Rabat=-34.9/17.2/68.1, Rangpur=-27.2/24.4/74.9, Reggane=-22.9/28.3/77.8, Reykjavík=-45.4/4.3/55.7, Riga=-39.8/6.2/61.3, Riyadh=-23.5/26.0/74.9, Rome=-35.5/15.2/64.5, Roseau=-22.3/26.2/81.4, Rostov-on-Don=-36.8/9.9/61.2, Sacramento=-30.9/16.3/65.1, Saint Petersburg=-43.9/5.8/54.5, Saint-Pierre=-45.1/5.7/53.5, Salt Lake City=-40.6/11.6/67.5, San Antonio=-29.7/20.8/72.8, San Diego=-31.6/17.8/69.0, San Francisco=-36.6/14.6/66.4, San Jose=-30.3/16.4/64.0, San José=-32.8/22.6/73.9, San Juan=-24.9/27.2/76.5, San Salvador=-27.9/23.1/74.4, Sana'a=-31.2/20.0/71.0, Santo Domingo=-26.5/25.9/76.4, Sapporo=-41.4/8.9/60.3, Sarajevo=-43.1/10.1/61.1, Saskatoon=-46.7/3.3/55.8, Seattle=-40.2/11.3/60.1, Seoul=-40.7/12.5/62.3, Seville=-35.5/19.2/68.8, Shanghai=-34.9/16.7/64.6, Singapore=-21.8/27.0/76.5, Skopje=-40.1/12.4/62.3, Sochi=-33.6/14.2/62.6, Sofia=-36.6/10.6/63.1, Sokoto=-21.7/28.0/76.1, Split=-33.9/16.1/63.2, St. John's=-47.5/5.0/57.9, St. Louis=-35.4/13.9/64.0, Stockholm=-43.6/6.6/57.6, Surabaya=-25.2/27.1/77.0, Suva=-26.2/25.6/74.0, Suwałki=-46.4/7.2/57.1, Sydney=-33.9/17.7/71.3, Ségou=-21.3/28.0/75.1, Tabora=-23.8/23.0/73.8, Tabriz=-40.5/12.6/63.5, Taipei=-23.5/23.0/72.8, Tallinn=-48.3/6.4/54.1, Tamale=-24.6/27.9/80.0, Tamanrasset=-26.1/21.7/70.3, Tampa=-28.4/22.9/74.7, Tashkent=-33.6/14.8/64.1, Tauranga=-37.1/14.8/69.5, Tbilisi=-40.9/12.9/63.9, Tegucigalpa=-28.9/21.7/69.4, Tehran=-36.2/17.0/70.8, Tel Aviv=-34.0/20.0/70.2, Thessaloniki=-35.1/16.0/66.3, Thiès=-23.8/24.0/70.9, Tijuana=-32.8/17.8/71.3, Timbuktu=-19.7/28.0/83.9, Tirana=-39.9/15.2/64.4, Toamasina=-30.3/23.4/72.8, Tokyo=-32.7/15.4/65.4, Toliara=-26.2/24.1/75.0, Toluca=-37.1/12.4/59.1, Toronto=-41.2/9.4/59.0, Tripoli=-32.2/20.0/66.5, Tromsø=-47.6/2.9/60.0, Tucson=-33.5/20.9/69.9, Tunis=-30.9/18.4/68.2, Ulaanbaatar=-54.1/-0.4/49.7, Upington=-27.2/20.4/78.8, Vaduz=-41.9/10.1/60.8, Valencia=-31.7/18.3/65.8, Valletta=-32.4/18.8/71.4, Vancouver=-41.1/10.4/60.9, Veracruz=-25.9/25.4/74.6, Vienna=-44.2/10.4/63.4, Vientiane=-23.2/25.9/83.4, Villahermosa=-20.0/27.1/76.7, Vilnius=-44.9/6.0/56.9, Virginia Beach=-35.9/15.8/64.7, Vladivostok=-46.3/4.9/60.2, Warsaw=-41.0/8.5/59.9, Washington, D.C.=-36.3/14.6/65.5, Wau=-20.5/27.8/79.2, Wellington=-33.0/12.9/64.0, Whitehorse=-47.5/-0.1/50.1, Wichita=-35.2/13.9/60.6, Willemstad=-21.7/28.0/77.8, Winnipeg=-51.2/3.0/53.5, Wrocław=-41.4/9.6/60.5, Xi'an=-39.7/14.1/73.7, Yakutsk=-57.8/-8.8/46.7, Yangon=-24.3/27.5/78.7, Yaoundé=-24.8/23.8/71.4, Yellowknife=-51.9/-4.3/50.0, Yerevan=-45.6/12.4/60.0, Yinchuan=-39.0/9.0/63.5, Zagreb=-41.6/10.7/58.5, Zanzibar City=-25.4/26.0/75.7, Zürich=-40.6/9.3/55.4, Ürümqi=-43.5/7.4/58.3, İzmir=-34.7/17.9/68.3}\");\n        }\n    }\n\n    private static List<Measurement> parseMeasurements(ByteBuffer byteBuffer) {\n        // Most of the code here is derived from @bjhara's implementation\n        // https://github.com/gunnarmorling/1brc/pull/10\n        var measurements = new ArrayList<Measurement>(100_000);\n\n        final int limit = byteBuffer.limit();\n        final byte[] buffer = new byte[128];\n\n        while (byteBuffer.position() < limit) {\n            final int start = byteBuffer.position();\n\n            int separatorPosition = start;\n            while (separatorPosition != limit &&\n                    byteBuffer.get(separatorPosition) != ';') {\n                separatorPosition++;\n            }\n\n            int endOfLinePosition = separatorPosition; // must be after the separator\n            while (endOfLinePosition != limit &&\n                    byteBuffer.get(endOfLinePosition) != '\\n') {\n                endOfLinePosition++;\n            }\n\n            int nameOffset = separatorPosition - start;\n            byteBuffer.get(buffer, 0, nameOffset);\n            String key = new String(buffer, 0, nameOffset);\n\n            byteBuffer.get(); // Skip separator\n\n            int valueLength = endOfLinePosition - separatorPosition - 1;\n            byteBuffer.get(buffer, 0, valueLength);\n            double value = fastParseDouble(buffer, valueLength);\n\n            byteBuffer.get(); // Skip newline\n\n            measurements.add(new Measurement(key, value));\n        }\n\n        return measurements;\n    }\n\n    private static double fastParseDouble(byte[] bytes, int length) {\n        long value = 0;\n        int exp = 0;\n        boolean negative = false;\n        int decimalPlaces = Integer.MIN_VALUE;\n        for (int i = 0; i < length; i++) {\n            byte ch = bytes[i];\n            if (ch >= '0' && ch <= '9') {\n                value = value * 10 + (ch - '0');\n                decimalPlaces++;\n            }\n            else if (ch == '-') {\n                negative = true;\n            }\n            else if (ch == '.') {\n                decimalPlaces = 0;\n            }\n        }\n\n        return asDouble(value, exp, negative, decimalPlaces);\n    }\n\n    private static double asDouble(long value, int exp, boolean negative, int decimalPlaces) {\n        if (decimalPlaces > 0 && value < Long.MAX_VALUE / 2) {\n            if (value < Long.MAX_VALUE / (1L << 32)) {\n                exp -= 32;\n                value <<= 32;\n            }\n            if (value < Long.MAX_VALUE / (1L << 16)) {\n                exp -= 16;\n                value <<= 16;\n            }\n            if (value < Long.MAX_VALUE / (1L << 8)) {\n                exp -= 8;\n                value <<= 8;\n            }\n            if (value < Long.MAX_VALUE / (1L << 4)) {\n                exp -= 4;\n                value <<= 4;\n            }\n            if (value < Long.MAX_VALUE / (1L << 2)) {\n                exp -= 2;\n                value <<= 2;\n            }\n            if (value < Long.MAX_VALUE / (1L << 1)) {\n                exp -= 1;\n                value <<= 1;\n            }\n        }\n        for (; decimalPlaces > 0; decimalPlaces--) {\n            exp--;\n            long mod = value % 5;\n            value /= 5;\n            int modDiv = 1;\n            if (value < Long.MAX_VALUE / (1L << 4)) {\n                exp -= 4;\n                value <<= 4;\n                modDiv <<= 4;\n            }\n            if (value < Long.MAX_VALUE / (1L << 2)) {\n                exp -= 2;\n                value <<= 2;\n                modDiv <<= 2;\n            }\n            if (value < Long.MAX_VALUE / (1L << 1)) {\n                exp -= 1;\n                value <<= 1;\n                modDiv <<= 1;\n            }\n            if (decimalPlaces > 1) {\n                value += modDiv * mod / 5;\n            }\n            else {\n                value += (modDiv * mod + 4) / 5;\n            }\n        }\n        final double d = Math.scalb((double) value, exp);\n        return negative ? -d : d;\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_unbounded.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.*;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.function.Consumer;\nimport java.util.stream.Collectors;\nimport java.util.stream.IntStream;\n\nimport static java.lang.foreign.ValueLayout.*;\nimport static java.nio.ByteOrder.BIG_ENDIAN;\n\npublic class CalculateAverage_unbounded {\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n    private static final int MAX_STATION_NAME_LEN = 100;\n    private static final int MAX_UNIQUE_STATIONS = 10000;\n\n    // this is *really* expensive\n    private static final OfInt BIG_ENDIAN_INT = JAVA_INT_UNALIGNED.withOrder(BIG_ENDIAN);\n    private static final VectorSpecies<Byte> LINE_SCAN_SPECIES = ByteVector.SPECIES_256;\n    private static final int LINE_SCAN_LEN = LINE_SCAN_SPECIES.length();\n    private static final VectorSpecies<Integer> NAME_HASH_SPECIES = IntVector.SPECIES_256;\n    private static final VectorSpecies<Short> HASH_LOOKUP_SPECIES = ShortVector.SPECIES_256;\n    private static final VectorSpecies<Long> ACCUMULATOR_SPECIES = LongVector.SPECIES_256;\n\n    private static final int CHUNK_SIZE = 16 * 1024 * 1024;\n\n    // Arbitrarily chosen primes\n    private static final int[] HASH_PRIMES = { 661, 1663, 2293, 3581, 5449, 5953, 6311, 6841, 7573, 7669, 7703, 7789, 7901, 8887, 8581, 8831 };\n    private static final byte[] PREFIX_MASK = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,\n            -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };\n    private static final int[] DIGIT_MULTIPLIERS = {\n            0, 10, 1, 1,\n            100, 10, 1, 1,\n            0, -10, 1, -1,\n            -100, -10, 1, -1,\n    };\n    private static final int[] DIGIT_MASK = {\n            0x000fff0f,\n            0x0f0fff0f,\n            0x000fff0f,\n            0x0f0fff0f,\n    };\n    private static final int[] DIGIT_FLIPS = { 0, 0, -1, -1 };\n\n    record Segment(long start, int len) {\n    }\n\n    static class StationStat {\n        long count;\n        long totalTemp;\n        int min;\n        int max;\n\n        StationStat(long count, long totalTemp, int min, int max) {\n            this.count = count;\n            this.totalTemp = totalTemp;\n            this.min = min;\n            this.max = max;\n        }\n\n        StationStat merge(StationStat other) {\n            this.count += other.count;\n            this.totalTemp += other.totalTemp;\n            this.min = Math.min(this.min, other.min);\n            this.max = Math.max(this.max, other.max);\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"\\{min/10.0}/\\{Math.round(1.0 * totalTemp / count)/10.0}/\\{max/10.0}\";\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        long fileSize = Files.size(FILE);\n        int lastChunkSize = (int) Math.min(200, fileSize);\n        int numSegments = (int) (fileSize / CHUNK_SIZE + 10);\n\n        var segments = new ArrayBlockingQueue<Segment>((int) (fileSize / CHUNK_SIZE + 10));\n        for (long i = 0; i < fileSize - lastChunkSize; i += CHUNK_SIZE) {\n            segments.put(new Segment(i, (int) Math.min(CHUNK_SIZE, fileSize - i - lastChunkSize)));\n        }\n\n        int numThreads = Runtime.getRuntime().availableProcessors();\n        var results = new ArrayBlockingQueue<Map<String, StationStat>>(numThreads);\n        var toMerge = new ArrayList<Map<String, StationStat>>(numThreads + 1);\n        try (var ch = FileChannel.open(FILE, StandardOpenOption.READ); var arena = Arena.ofConfined()) {\n            var threads = IntStream.range(0, numThreads).mapToObj((ignored) -> new ProcessorThread(segments, ch, results::add)).toList();\n            threads.forEach(Thread::start);\n\n            // Process last piece without OOB\n            int margin = lastChunkSize < fileSize ? 1 : 0;\n            var mem = ch.map(FileChannel.MapMode.READ_ONLY, fileSize - lastChunkSize - margin, lastChunkSize + margin, arena);\n            slowProcessChunk(mem, margin, lastChunkSize, toMerge::add);\n\n            for (var thread : threads) {\n                thread.join();\n            }\n        }\n\n        results.drainTo(toMerge);\n        var merged = toMerge.stream().reduce((a, b) -> {\n            b.forEach((k, v) -> a.merge(k, v, StationStat::merge));\n            return a;\n        }).get();\n        printResult(merged);\n    }\n\n    // Simple implementation for the end - so we don't need to worry about reading past the end of the file\n    private static void slowProcessChunk(MemorySegment mem, int startPos, int endPos, Consumer<Map<String, StationStat>> report) {\n        int index = scanForStartPos(mem, startPos);\n        byte[] nameBuf = new byte[MAX_STATION_NAME_LEN];\n        while (index < endPos) {\n            int nameLen = 0;\n            while (mem.get(JAVA_BYTE, index) != ';') {\n                nameBuf[nameLen++] = mem.get(JAVA_BYTE, index);\n                index++;\n            }\n            var name = new String(nameBuf, 0, nameLen);\n            index++;\n            StringBuilder numStr = new StringBuilder(5);\n            while (mem.get(JAVA_BYTE, index) != '\\n') {\n                if (mem.get(JAVA_BYTE, index) != '.') {\n                    numStr.append((char) mem.get(JAVA_BYTE, index));\n                }\n                index++;\n            }\n            index++;\n            int num = Integer.parseInt(numStr.toString());\n            var entry = new HashMap<String, StationStat>(1);\n            entry.put(name, new StationStat(1, num, num, num));\n            report.accept(entry);\n        }\n    }\n\n    static class ProcessorThread extends Thread {\n\n        static final int NUM_BUCKETS = 1024;\n        static final int BUCKET_MASK = 0x3ff;\n        static final int BUCKET_SIZE = 16;\n\n        // n-way hash table state\n        // 16 buckets, then 16 name pointers\n        private final short[] hashTable = new short[2 * BUCKET_SIZE * NUM_BUCKETS];\n        // storage of station name keys for hash collision check\n        private final byte[] nameTable = new byte[MAX_UNIQUE_STATIONS * (MAX_STATION_NAME_LEN + 1)];\n        // values for the hash key stable\n        private final short[] stationIndexes = new short[BUCKET_SIZE * NUM_BUCKETS];\n        private final int[] nextNamePos = { 0 };\n        private final int[] nextStationIndex = { 0 };\n\n        // Accumulator for (10s, 1s, (count*-2), .1s) per station\n        private final long[] accumulators = new long[4 * MAX_UNIQUE_STATIONS];\n        // min and max per station\n        private final int[] minMax = new int[2 * MAX_UNIQUE_STATIONS];\n\n        private final Queue<Segment> segments;\n        private final FileChannel channel;\n        private final Consumer<Map<String, StationStat>> report;\n\n        ProcessorThread(Queue<Segment> segments, FileChannel channel, Consumer<Map<String, StationStat>> report) {\n            this.segments = segments;\n            this.channel = channel;\n            this.report = report;\n            for (int i = 0; i < minMax.length; i += 2) {\n                minMax[i] = Integer.MAX_VALUE;\n                minMax[i + 1] = Integer.MIN_VALUE;\n            }\n        }\n\n        @Override\n        public void run() {\n            try {\n                while (true) {\n                    var segment = segments.poll();\n                    if (segment == null) {\n                        break;\n                    }\n                    int startMargin = segment.start == 0 ? 0 : 1;\n                    int endMargin = 64;\n                    try (var arena = Arena.ofConfined()) {\n                        var mem = channel.map(FileChannel.MapMode.READ_ONLY, segment.start - startMargin, segment.len + endMargin + startMargin, arena);\n                        processChunk(mem, startMargin, segment.len + startMargin, hashTable, nameTable, stationIndexes, minMax, accumulators, nextNamePos, nextStationIndex);\n                    }\n                }\n                report.accept(decodeResult(hashTable, nameTable, stationIndexes, accumulators, minMax));\n            } catch (IOException e) {\n                System.err.println(STR.\"I/O Exception: \\{e}\");\n                throw new RuntimeException(e);\n            }\n        }\n\n        private static void processChunk(MemorySegment mem, int startPos, int endPos, short[] hashTable, byte[] nameTable, short[] stationIndexes, int[] minMax,\n                                         long[] accumulators, int[] nextNamePos, int[] nextStationIndex) {\n            int index = scanForStartPos(mem, startPos);\n            var primeVec = IntVector.fromArray(NAME_HASH_SPECIES, HASH_PRIMES, 0);\n            while (index < endPos) {\n                var lineVec = ByteVector.fromMemorySegment(LINE_SCAN_SPECIES, mem, index, ByteOrder.LITTLE_ENDIAN);\n                int numPos = lineVec.eq((byte) ';').firstTrue() + 1;\n                int nlPos = 0;\n                int stationIndex;\n                if (numPos != LINE_SCAN_LEN + 1) {\n                    // Fast path, station name fits in one SIMD register\n                    nlPos = lineVec.eq((byte) '\\n').firstTrue();\n                    if (nlPos == LINE_SCAN_LEN) {\n                        while (mem.get(JAVA_BYTE, index + nlPos) != '\\n') {\n                            nlPos++;\n                        }\n                    }\n                    var nameVec = lineVec.and(ByteVector.fromArray(LINE_SCAN_SPECIES, PREFIX_MASK, 33 - numPos));\n                    int nameHash = nameVec.reinterpretAsInts().mul(primeVec).reduceLanes(VectorOperators.ADD);\n\n                    stationIndex = fastLookupHash(nameHash, nameVec, hashTable, nameTable, stationIndexes, nextNamePos, nextStationIndex);\n                }\n                else {\n                    // Slow path, station name larger than SIMD register\n                    while (mem.get(JAVA_BYTE, index + numPos - 1) != ';')\n                        numPos++;\n                    while (mem.get(JAVA_BYTE, index + nlPos) != '\\n')\n                        nlPos++;\n\n                    int nameHash = lineVec.reinterpretAsInts().mul(primeVec).reduceLanes(VectorOperators.ADD);\n                    for (int i = LINE_SCAN_LEN; i < numPos - 1; i++) {\n                        nameHash = nameHash * 33 + mem.get(JAVA_BYTE, index + i);\n                    }\n                    stationIndex = lookupHash(nameHash, mem.asSlice(index, numPos - 1), hashTable, nameTable, stationIndexes, nextNamePos, nextStationIndex);\n                }\n                boolean isNegative = mem.get(JAVA_BYTE, index + numPos) == '-';\n                // format; 0: 9.9, 1: 99.9, 2: -9.9, 3: -99.9\n                int numFormat = nlPos - numPos - 3 + (isNegative ? 1 : 0);\n\n                // accumulate sums for mean\n                var numPartsVec = ByteVector.fromMemorySegment(ByteVector.SPECIES_128, mem, index + nlPos - 4, ByteOrder.LITTLE_ENDIAN)\n                        .sub((byte) '0')\n                        .convert(VectorOperators.B2I, 0);\n                var multiplyVec = IntVector.fromArray(IntVector.SPECIES_128, DIGIT_MULTIPLIERS, 4 * numFormat);\n                var toAdd = numPartsVec.mul(multiplyVec).castShape(ACCUMULATOR_SPECIES, 0);\n                var acc = LongVector.fromArray(ACCUMULATOR_SPECIES, accumulators, 4 * stationIndex);\n                acc.add(toAdd).intoArray(accumulators, 4 * stationIndex);\n\n                // record min/max\n                // encode ASCII value to sortable format without parsing\n                int encoded = (mem.get(BIG_ENDIAN_INT, index + nlPos - 4) & DIGIT_MASK[numFormat]) ^ DIGIT_FLIPS[numFormat];\n                minMax[2 * stationIndex] = Math.min(minMax[2 * stationIndex], encoded);\n                minMax[2 * stationIndex + 1] = Math.max(minMax[2 * stationIndex + 1], encoded);\n\n                index += nlPos + 1;\n            }\n        }\n\n        // Look up name that fits in a vector\n        private static int fastLookupHash(int nameHash, ByteVector nameVec, short[] hashTable, byte[] nameTable, short[] stationIndexes, int[] nextNamePos,\n                                          int[] nextStationIndex) {\n            int bucketIdx = nameHash & BUCKET_MASK;\n            short shortHash = (short) (0x8000 | (nameHash >> 16));\n\n            // Look up the station name to find the index\n            while (true) {\n                var bucketVec = ShortVector.fromArray(HASH_LOOKUP_SPECIES, hashTable, 2 * BUCKET_SIZE * bucketIdx);\n                var bucketPos = bucketVec.eq(shortHash).firstTrue();\n                if (bucketPos != HASH_LOOKUP_SPECIES.length()) {\n                    int slotNamePos = 32 * Short.toUnsignedInt(hashTable[2 * BUCKET_SIZE * bucketIdx + BUCKET_SIZE + bucketPos]);\n                    var slotNameVec = ByteVector.fromArray(LINE_SCAN_SPECIES, nameTable, slotNamePos);\n                    if (nameVec.eq(slotNameVec).allTrue()) {\n                        // Hit\n                        return stationIndexes[BUCKET_SIZE * bucketIdx + bucketPos];\n                    }\n                    else {\n                        bucketPos = handleHashCollision(shortHash, bucketIdx, MemorySegment.ofArray(nameVec.toArray()), hashTable, nameTable);\n                        if (bucketPos != -1) {\n                            return stationIndexes[BUCKET_SIZE * bucketIdx + bucketPos];\n                        }\n                    }\n                }\n                var emptyPos = bucketVec.eq((short) 0).firstTrue();\n                if (emptyPos != HASH_LOOKUP_SPECIES.length()) {\n                    // Miss, insert\n                    int stationIndex = nextStationIndex[0]++;\n                    nameVec.intoArray(nameTable, nextNamePos[0]);\n                    hashTable[2 * BUCKET_SIZE * bucketIdx + emptyPos] = shortHash;\n                    hashTable[2 * BUCKET_SIZE * bucketIdx + BUCKET_SIZE + emptyPos] = (short) (nextNamePos[0] / 32);\n                    stationIndexes[BUCKET_SIZE * bucketIdx + emptyPos] = (short) stationIndex;\n                    nextNamePos[0] += nameVec.length();\n                    return stationIndex;\n                }\n                // Try next bucket\n                bucketIdx = (bucketIdx + 1) & BUCKET_MASK;\n            }\n        }\n\n        // Look up long name\n        private static int lookupHash(int nameHash, MemorySegment nameSeg, short[] hashTable, byte[] nameTable, short[] stationIndexes, int[] nextNamePos,\n                                      int[] nextStationIndex) {\n            int bucketIdx = nameHash & BUCKET_MASK;\n            short shortHash = (short) (0x8000 | (nameHash >> 16));\n\n            // Look up the station name to find the index\n            while (true) {\n                var bucketVec = ShortVector.fromArray(HASH_LOOKUP_SPECIES, hashTable, 2 * BUCKET_SIZE * bucketIdx);\n                var bucketPos = bucketVec.eq(shortHash).firstTrue();\n                if (bucketPos != HASH_LOOKUP_SPECIES.length()) {\n                    int slotNamePos = 32 * Short.toUnsignedInt(hashTable[2 * BUCKET_SIZE * bucketIdx + BUCKET_SIZE + bucketPos]);\n                    boolean match = true;\n                    for (int i = 0; i < nameSeg.byteSize(); i++) {\n                        if (nameSeg.get(JAVA_BYTE, i) != nameTable[slotNamePos + i]) {\n                            match = false;\n                        }\n                    }\n                    match = match && nameTable[slotNamePos + (int) nameSeg.byteSize()] == '\\0';\n                    if (match) {\n                        // Hit\n                        return stationIndexes[BUCKET_SIZE * bucketIdx + bucketPos];\n                    }\n                    else {\n                        bucketPos = handleHashCollision(shortHash, bucketIdx, nameSeg, hashTable, nameTable);\n                        if (bucketPos != -1) {\n                            return stationIndexes[BUCKET_SIZE * bucketIdx + bucketPos];\n                        }\n                    }\n                }\n                var emptyPos = bucketVec.eq((short) 0).firstTrue();\n                if (emptyPos != HASH_LOOKUP_SPECIES.length()) {\n                    // Miss, insert\n                    int stationIndex = nextStationIndex[0]++;\n                    hashTable[2 * BUCKET_SIZE * bucketIdx + emptyPos] = shortHash;\n                    hashTable[2 * BUCKET_SIZE * bucketIdx + BUCKET_SIZE + emptyPos] = (short) (nextNamePos[0] / 32);\n                    stationIndexes[BUCKET_SIZE * bucketIdx + emptyPos] = (short) stationIndex;\n                    for (int i = 0; i < nameSeg.byteSize(); i++) {\n                        nameTable[nextNamePos[0]++] = nameSeg.get(JAVA_BYTE, i);\n                    }\n                    nameTable[nextNamePos[0]++] = '\\0';\n                    while (nextNamePos[0] % 32 != 0)\n                        nextNamePos[0]++;\n                    return stationIndex;\n                }\n                // Try next bucket\n                bucketIdx = (bucketIdx + 1) & BUCKET_MASK;\n            }\n        }\n\n        private static int handleHashCollision(short shortHash, int bucketIdx, MemorySegment nameSeg, short[] hashTable, byte[] nameTable) {\n            for (int i = 0; i < BUCKET_SIZE; i++) {\n                if (hashTable[2 * BUCKET_SIZE * bucketIdx + i] == shortHash) {\n                    int namePos = 32 * Short.toUnsignedInt(hashTable[2 * BUCKET_SIZE * bucketIdx + BUCKET_SIZE + i]);\n                    if (Arrays.equals(nameSeg.toArray(JAVA_BYTE), Arrays.copyOfRange(nameTable, namePos, namePos + (int) nameSeg.byteSize()))\n                            && nameTable[namePos + (int) nameSeg.byteSize()] == '\\0') {\n                        return i;\n                    }\n                }\n            }\n            return -1;\n        }\n    }\n\n    // Find next record\n    private static int scanForStartPos(MemorySegment mem, int startPos) {\n        if (startPos == 0) {\n            return startPos;\n        }\n        while (mem.get(JAVA_BYTE, startPos - 1) != '\\n') {\n            startPos++;\n        }\n        return startPos;\n    }\n\n    // Decode the accumulator values to StationStats\n    private static Map<String, StationStat> decodeResult(short[] hashTable, byte[] nameTable, short[] stationIndexes, long[] accumulators, int[] minMax) {\n        var result = new HashMap<String, StationStat>(MAX_UNIQUE_STATIONS);\n        for (int i = 0; i < hashTable.length; i += 32) {\n            for (int j = 0; j < 16; j++) {\n                if (hashTable[i + j] != 0) {\n                    int namePos = 32 * Short.toUnsignedInt(hashTable[i + j + 16]);\n                    int nameLen = 1;\n                    while (nameTable[namePos + nameLen] != '\\0') {\n                        nameLen++;\n                    }\n                    int stationIdx = stationIndexes[i / 2 + j];\n                    // Number of '-2' valued dots seen\n                    long count = accumulators[4 * stationIdx + 2] / -2;\n                    long total = accumulators[4 * stationIdx];\n                    total += accumulators[4 * stationIdx + 1];\n                    total += accumulators[4 * stationIdx + 3];\n                    int min = decodeInteger(minMax[2 * stationIdx]);\n                    int max = decodeInteger(minMax[2 * stationIdx + 1]);\n                    result.put(new String(nameTable, namePos, nameLen), new StationStat(count, total, min, max));\n                }\n            }\n        }\n        return result;\n    }\n\n    private static int decodeInteger(int encoded) {\n        int mask = encoded >> 31;\n        int orig = (encoded ^ mask) & 0x7fffffff;\n        int val = (orig & 0xff) + ((orig >> 16) & 0xff) * 10 + ((orig >> 24) & 0xff) * 100;\n        return val * (mask | 1);\n    }\n\n    private static void printResult(Map<String, StationStat> stats) {\n        System.out.print(\"{\");\n        System.out.print(\n            stats.keySet().stream().sorted()\n                    .map(key -> {\n                        var s = stats.get(key);\n                        return STR.\"\\{key}=\\{s}\";\n                    })\n                    .collect(Collectors.joining(\", \"))\n        );\n        System.out.println(\"}\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_vaidhy.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.function.Function;\nimport java.util.function.Supplier;\n\npublic class CalculateAverage_vaidhy<I, T> {\n\n    private static final class HashEntry {\n        private long startAddress;\n        private long keyLength;\n        private long suffix;\n        private int next;\n        IntSummaryStatistics value;\n    }\n\n    private static class PrimitiveHashMap {\n        private final HashEntry[] entries;\n        private final long[] hashes;\n\n        private final int twoPow;\n        private int next = -1;\n\n        PrimitiveHashMap(int twoPow) {\n            this.twoPow = twoPow;\n            this.entries = new HashEntry[1 << twoPow];\n            this.hashes = new long[1 << twoPow];\n            for (int i = 0; i < entries.length; i++) {\n                this.entries[i] = new HashEntry();\n            }\n        }\n\n        public IntSummaryStatistics find(long startAddress, long endAddress, long hash, long suffix) {\n            int len = entries.length;\n            int h = Long.hashCode(hash);\n            int initialIndex = (h ^ (h >> twoPow)) & (len - 1);\n            int i = initialIndex;\n            long lookupLength = endAddress - startAddress;\n\n            long hashEntry = hashes[i];\n\n            if (hashEntry == hash) {\n                HashEntry entry = entries[i];\n                if (lookupLength <= 7) {\n                    // This works because\n                    // hash = suffix , when simpleHash is just xor.\n                    // Since length is not 8, suffix will have a 0 at the end.\n                    // Since utf-8 strings can't have 0 in middle of a string this means\n                    // we can stop here.\n                    return entry.value;\n                }\n                boolean found = (entry.suffix == suffix &&\n                        compareEntryKeys(startAddress, endAddress, entry.startAddress));\n                if (found) {\n                    return entry.value;\n                }\n            }\n\n            if (hashEntry == 0) {\n                HashEntry entry = entries[i];\n                entry.startAddress = startAddress;\n                entry.keyLength = lookupLength;\n                hashes[i] = hash;\n                entry.suffix = suffix;\n                entry.next = next;\n                this.next = i;\n                entry.value = new IntSummaryStatistics();\n                return entry.value;\n            }\n\n            i++;\n            if (i == len) {\n                i = 0;\n            }\n\n            if (i == initialIndex) {\n                return null;\n            }\n\n            do {\n                hashEntry = hashes[i];\n                if (hashEntry == hash) {\n                    HashEntry entry = entries[i];\n                    if (lookupLength <= 7) {\n                        return entry.value;\n                    }\n                    boolean found = (entry.suffix == suffix &&\n                            compareEntryKeys(startAddress, endAddress, entry.startAddress));\n                    if (found) {\n                        return entry.value;\n                    }\n                }\n                if (hashEntry == 0) {\n                    HashEntry entry = entries[i];\n                    entry.startAddress = startAddress;\n                    entry.keyLength = lookupLength;\n                    hashes[i] = hash;\n                    entry.suffix = suffix;\n                    entry.next = next;\n                    this.next = i;\n                    entry.value = new IntSummaryStatistics();\n                    return entry.value;\n                }\n\n                i++;\n                if (i == len) {\n                    i = 0;\n                }\n            } while (i != initialIndex);\n            return null;\n        }\n\n        private static boolean compareEntryKeys(long startAddress, long endAddress, long entryStartAddress) {\n            long entryIndex = entryStartAddress;\n            long lookupIndex = startAddress;\n            long endAddressStop = endAddress - 7;\n\n            for (; lookupIndex < endAddressStop; lookupIndex += 8) {\n                if (UNSAFE.getLong(entryIndex) != UNSAFE.getLong(lookupIndex)) {\n                    return false;\n                }\n                entryIndex += 8;\n            }\n\n            return true;\n        }\n\n        public Iterable<HashEntry> entrySet() {\n            return () -> new Iterator<>() {\n                int scan = next;\n\n                @Override\n                public boolean hasNext() {\n                    return scan != -1;\n                }\n\n                @Override\n                public HashEntry next() {\n                    HashEntry entry = entries[scan];\n                    scan = entry.next;\n                    return entry;\n                }\n            };\n        }\n    }\n\n    private static final String FILE = \"./measurements.txt\";\n\n    private static long simpleHash(long hash, long nextData) {\n        return hash ^ nextData;\n        // return (hash ^ Long.rotateLeft((nextData * C1), R1)) * C2;\n    }\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            return (Unsafe) theUnsafe.get(Unsafe.class);\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static int parseDouble(long startAddress, long endAddress) {\n        int normalized;\n        int length = (int) (endAddress - startAddress);\n        if (length == 5) {\n            normalized = (UNSAFE.getByte(startAddress + 1) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 2) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 4) ^ 0x30);\n            normalized = -normalized;\n            return normalized;\n        }\n        if (length == 3) {\n            normalized = (UNSAFE.getByte(startAddress) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 2) ^ 0x30);\n            return normalized;\n        }\n\n        if (UNSAFE.getByte(startAddress) == '-') {\n            normalized = (UNSAFE.getByte(startAddress + 1) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 3) ^ 0x30);\n            normalized = -normalized;\n            return normalized;\n        }\n        else {\n            normalized = (UNSAFE.getByte(startAddress) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 1) ^ 0x30);\n            normalized = (normalized << 3) + (normalized << 1) + (UNSAFE.getByte(startAddress + 3) ^ 0x30);\n            return normalized;\n        }\n    }\n\n    interface MapReduce<I> {\n\n        void process(long keyStartAddress, long keyEndAddress, long hash, long suffix, int temperature);\n\n        I result();\n    }\n\n    private final FileService fileService;\n    private final Supplier<MapReduce<I>> chunkProcessCreator;\n    private final Function<List<I>, T> reducer;\n\n    interface FileService {\n        long length();\n\n        long address();\n    }\n\n    CalculateAverage_vaidhy(FileService fileService,\n                            Supplier<MapReduce<I>> mapReduce,\n                            Function<List<I>, T> reducer) {\n        this.fileService = fileService;\n        this.chunkProcessCreator = mapReduce;\n        this.reducer = reducer;\n    }\n\n    static class LineStream {\n        private final long fileEnd;\n        private final long chunkEnd;\n\n        private long position;\n        private long hash;\n\n        private long suffix;\n\n        private final ByteBuffer buf = ByteBuffer\n                .allocate(8)\n                .order(ByteOrder.LITTLE_ENDIAN);\n\n        public LineStream(FileService fileService, long offset, long chunkSize) {\n            long fileStart = fileService.address();\n            this.fileEnd = fileStart + fileService.length();\n            this.chunkEnd = fileStart + offset + chunkSize;\n            this.position = fileStart + offset;\n            this.hash = 0;\n        }\n\n        public boolean hasNext() {\n            return position <= chunkEnd;\n        }\n\n        public long findSemi() {\n            long h = 0;\n            buf.rewind();\n\n            for (long i = position; i < fileEnd; i++) {\n                byte ch = UNSAFE.getByte(i);\n                if (ch == ';') {\n                    int discard = buf.remaining();\n                    buf.rewind();\n                    long nextData = (buf.getLong() << discard) >>> discard;\n                    this.suffix = nextData;\n                    this.hash = simpleHash(h, nextData);\n                    position = i + 1;\n                    return i;\n                }\n                if (buf.hasRemaining()) {\n                    buf.put(ch);\n                }\n                else {\n                    buf.flip();\n                    long nextData = buf.getLong();\n                    h = simpleHash(h, nextData);\n                    buf.rewind();\n                }\n            }\n            this.hash = h;\n            this.suffix = buf.getLong();\n            position = fileEnd;\n            return fileEnd;\n        }\n\n        public long skipLine() {\n            for (long i = position; i < fileEnd; i++) {\n                byte ch = UNSAFE.getByte(i);\n                if (ch == 0x0a) {\n                    position = i + 1;\n                    return i;\n                }\n            }\n            position = fileEnd;\n            return fileEnd;\n        }\n\n        public long findTemperature() {\n            position += 3;\n            for (long i = position; i < fileEnd; i++) {\n                byte ch = UNSAFE.getByte(i);\n                if (ch == 0x0a) {\n                    position = i + 1;\n                    return i;\n                }\n            }\n            position = fileEnd;\n            return fileEnd;\n        }\n    }\n\n    private static final long START_BYTE_INDICATOR = 0x0101_0101_0101_0101L;\n    private static final long END_BYTE_INDICATOR = START_BYTE_INDICATOR << 7;\n\n    private static final long NEW_LINE_DETECTION = START_BYTE_INDICATOR * '\\n';\n\n    private static final long SEMI_DETECTION = START_BYTE_INDICATOR * ';';\n\n    private static final long ALL_ONES = 0xffff_ffff_ffff_ffffL;\n\n    private long findByteOctet(long data, long pattern) {\n        long match = data ^ pattern;\n        return (match - START_BYTE_INDICATOR) & ((~match) & END_BYTE_INDICATOR);\n    }\n\n    private void bigWorker(long offset, long chunkSize, MapReduce<I> lineConsumer) {\n        long chunkStart = offset + fileService.address();\n        long chunkEnd = chunkStart + chunkSize;\n        long fileEnd = fileService.address() + fileService.length();\n        long stopPoint = Math.min(chunkEnd + 1, fileEnd);\n\n        boolean skip = offset != 0;\n        for (long position = chunkStart; position < stopPoint;) {\n            if (skip) {\n                long data = UNSAFE.getLong(position);\n                long newLineMask = findByteOctet(data, NEW_LINE_DETECTION);\n                if (newLineMask != 0) {\n                    int newLinePosition = Long.numberOfTrailingZeros(newLineMask) >>> 3;\n                    skip = false;\n                    position = position + newLinePosition + 1;\n                }\n                else {\n                    position = position + 8;\n                }\n                continue;\n            }\n\n            long stationStart = position;\n            long stationEnd = -1;\n            long hash = 0;\n            long suffix = 0;\n            do {\n                long data = UNSAFE.getLong(position);\n                long semiMask = findByteOctet(data, SEMI_DETECTION);\n                if (semiMask != 0) {\n                    int semiPosition = Long.numberOfTrailingZeros(semiMask) >>> 3;\n                    stationEnd = position + semiPosition;\n                    position = stationEnd + 1;\n\n                    if (semiPosition != 0) {\n                        suffix = data & (ALL_ONES >>> (64 - (semiPosition << 3)));\n                    }\n                    else {\n                        suffix = UNSAFE.getLong(position - 8);\n                    }\n                    hash = simpleHash(hash, suffix);\n                    break;\n                }\n                else {\n                    hash = simpleHash(hash, data);\n                    position = position + 8;\n                }\n            } while (true);\n\n            int temperature = 0;\n            {\n                byte ch = UNSAFE.getByte(position++);\n                boolean negative = false;\n                if (ch == '-') {\n                    negative = true;\n                    ch = UNSAFE.getByte(position++);\n                }\n                do {\n                    if (ch != '.') {\n                        temperature *= 10;\n                        temperature += (ch ^ '0');\n                    }\n                    ch = UNSAFE.getByte(position++);\n                } while (ch != '\\n');\n                if (negative) {\n                    temperature = -temperature;\n                }\n            }\n\n            lineConsumer.process(stationStart, stationEnd, hash, suffix, temperature);\n        }\n    }\n\n    private void smallWorker(long offset, long chunkSize, MapReduce<I> lineConsumer) {\n        LineStream lineStream = new LineStream(fileService, offset, chunkSize);\n\n        if (offset != 0) {\n            if (lineStream.hasNext()) {\n                // Skip the first line.\n                lineStream.skipLine();\n            }\n            else {\n                // No lines then do nothing.\n                return;\n            }\n        }\n        while (lineStream.hasNext()) {\n            long keyStartAddress = lineStream.position;\n            long keyEndAddress = lineStream.findSemi();\n            long keyHash = lineStream.hash;\n            long suffix = lineStream.suffix;\n            long valueStartAddress = lineStream.position;\n            long valueEndAddress = lineStream.findTemperature();\n            int temperature = parseDouble(valueStartAddress, valueEndAddress);\n            // System.out.println(\"Small worker!\");\n            lineConsumer.process(keyStartAddress, keyEndAddress, keyHash, suffix, temperature);\n        }\n    }\n\n    // file size = 7\n    // (0,0) (0,0) small chunk= (0,7)\n    // a;0.1\\n\n\n    public T master(int shards, ExecutorService executor) {\n        List<Future<I>> summaries = new ArrayList<>();\n        long len = fileService.length();\n\n        if (len > 128) {\n            long bigChunk = Math.floorDiv(len, shards);\n            long bigChunkReAlign = bigChunk & 0xffff_ffff_ffff_fff8L;\n\n            long smallChunkStart = bigChunkReAlign * shards;\n            long smallChunkSize = len - smallChunkStart;\n\n            for (long offset = 0; offset < smallChunkStart; offset += bigChunkReAlign) {\n                MapReduce<I> mr = chunkProcessCreator.get();\n                final long transferOffset = offset;\n                Future<I> task = executor.submit(() -> {\n                    bigWorker(transferOffset, bigChunkReAlign, mr);\n                    return mr.result();\n                });\n                summaries.add(task);\n            }\n\n            MapReduce<I> mrLast = chunkProcessCreator.get();\n            Future<I> lastTask = executor.submit(() -> {\n                smallWorker(smallChunkStart, smallChunkSize - 1, mrLast);\n                return mrLast.result();\n            });\n            summaries.add(lastTask);\n        }\n        else {\n\n            MapReduce<I> mrLast = chunkProcessCreator.get();\n            Future<I> lastTask = executor.submit(() -> {\n                smallWorker(0, len - 1, mrLast);\n                return mrLast.result();\n            });\n            summaries.add(lastTask);\n        }\n\n        List<I> summariesDone = summaries.stream()\n                .map(task -> {\n                    try {\n                        return task.get();\n                    }\n                    catch (InterruptedException | ExecutionException e) {\n                        throw new RuntimeException(e);\n                    }\n                })\n                .toList();\n        return reducer.apply(summariesDone);\n    }\n\n    static class DiskFileService implements FileService {\n        private final long fileSize;\n        private final long mappedAddress;\n\n        DiskFileService(String fileName) throws IOException {\n            FileChannel fileChannel = FileChannel.open(Path.of(fileName),\n                    StandardOpenOption.READ);\n            this.fileSize = fileChannel.size();\n            this.mappedAddress = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0,\n                    fileSize, Arena.global()).address();\n        }\n\n        @Override\n        public long length() {\n            return fileSize;\n        }\n\n        @Override\n        public long address() {\n            return mappedAddress;\n        }\n    }\n\n    private static class ChunkProcessorImpl implements MapReduce<PrimitiveHashMap> {\n\n        // 1 << 14 > 10,000 so it works\n        private final PrimitiveHashMap statistics = new PrimitiveHashMap(15);\n\n        @Override\n        public void process(long keyStartAddress, long keyEndAddress, long hash, long suffix, int temperature) {\n            IntSummaryStatistics stats = statistics.find(keyStartAddress, keyEndAddress, hash, suffix);\n            stats.accept(temperature);\n        }\n\n        @Override\n        public PrimitiveHashMap result() {\n            return statistics;\n        }\n    }\n\n    public static void main(String[] args) throws IOException {\n        DiskFileService diskFileService = new DiskFileService(FILE);\n\n        CalculateAverage_vaidhy<PrimitiveHashMap, Map<String, IntSummaryStatistics>> calculateAverageVaidhy = new CalculateAverage_vaidhy<>(\n                diskFileService,\n                ChunkProcessorImpl::new,\n                CalculateAverage_vaidhy::combineOutputs);\n\n        int proc = Runtime.getRuntime().availableProcessors();\n\n        ExecutorService executor = Executors.newFixedThreadPool(proc);\n        Map<String, IntSummaryStatistics> output = calculateAverageVaidhy.master(2 * proc, executor);\n        executor.shutdown();\n\n        Map<String, String> outputStr = toPrintMap(output);\n        System.out.println(outputStr);\n    }\n\n    private static Map<String, String> toPrintMap(Map<String, IntSummaryStatistics> output) {\n\n        Map<String, String> outputStr = new TreeMap<>();\n        for (Map.Entry<String, IntSummaryStatistics> entry : output.entrySet()) {\n            IntSummaryStatistics stat = entry.getValue();\n            outputStr.put(entry.getKey(),\n                    STR.\"\\{stat.getMin() / 10.0}/\\{Math.round(stat.getAverage()) / 10.0}/\\{stat.getMax() / 10.0}\");\n        }\n        return outputStr;\n    }\n\n    private static Map<String, IntSummaryStatistics> combineOutputs(\n                                                                    List<PrimitiveHashMap> list) {\n\n        Map<String, IntSummaryStatistics> output = HashMap.newHashMap(10000);\n        for (PrimitiveHashMap map : list) {\n            for (HashEntry entry : map.entrySet()) {\n                if (entry.value != null) {\n                    String keyStr = unsafeToString(entry.startAddress,\n                            entry.startAddress + entry.keyLength);\n\n                    output.compute(keyStr, (ignore, val) -> {\n                        if (val == null) {\n                            return entry.value;\n                        }\n                        else {\n                            val.combine(entry.value);\n                            return val;\n                        }\n                    });\n                }\n            }\n        }\n\n        return output;\n    }\n\n    private static String unsafeToString(long startAddress, long endAddress) {\n        byte[] keyBytes = new byte[(int) (endAddress - startAddress)];\n        for (int i = 0; i < keyBytes.length; i++) {\n            keyBytes[i] = UNSAFE.getByte(startAddress + i);\n        }\n        return new String(keyBytes, StandardCharsets.UTF_8);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_vemana.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\n\n/**\n * This submission focuses on exploiting the non-SIMD parallelism that is inherent in OOO\n * super-scalar CPUs and avoids using Unsafe, SWAR and other such fine techniques. The hope is to\n * remain readable for a majority of SWEs. At a high level, the approach relies on a few principles\n * listed herein.\n *\n * <p>[Exploit Parallelism] Distribute the work into Shards. Separate threads (one per core) process\n * Shards and follow it up by merging the results. parallelStream() is appealing but carries\n * potential run-time variance (i.e. std. deviation) penalties based on informal testing. Variance\n * is not ideal when trying to minimize the maximum worker latency.\n *\n * <p>[Understand that unmapping is serial and runs in exit()]. This is very much about exploiting\n * parallelism. After adding tracing (plain old printfs), it was clear that the JVM was taking 400ms\n * (out of 1500ms) just to exit. Turns out that the kernel tries to unmap all the mappings as part\n * of the exit() call. Even strace wouldn't report this because the unmapping is running as part of\n * the exit() call. perf stat barely hinted at it, but we had more insights by actually running a\n * couple of experiments: reduce touched pages --> JVM shutdown latency went down; manually run\n * unmap() call to free up the ByteBuffers --> parallel execution doesn't help at all. From this it\n * was conclusive that unmap() executes serially and the 400ms was being spent purely unmapping.\n * Now, the challenge is to both (1) unmap a MappedByteBuffer (no such methods exposed) from code\n * rather than via exit() syscall and (2) do it in parallel without causing lock contention. For 1,\n * use Reflection and (2) is an interesting math problem with a provably optimal solution.\n * Parallelism in munmap() is achieved by using a fast lock that prevents two threads from\n * simultaneously cleaning (i.e. munmap()) the ByteBuffer.\n *\n * <p>[Use ByteBuffers over MemorySegment] Each Shard is further divided in Chunks. This would've\n * been unnecessary except that Shards are too big to be backed by ByteBuffers. Besides,\n * MemorySegment appears slower than ByteBuffers. So, to use ByteBuffers, we have to use smaller\n * chunks.\n *\n * <p>[Straggler freedom] The optimization function here is to minimize the maximal worker thread\n * completion. Law of large number averages means that all the threads will end up with similar\n * amounts of work and similar completion times; but, however ever so often there could be a bad\n * sharding and more importantly, Cores are not created equal; some will be throttled more than\n * others. So, we have a shared {@code LazyShardQueue} that aims to distribute work to minimize the\n * latest completion time.\n *\n * <p>[Work Assignment with LazyShardQueue] The queue provides each thread with its next big-chunk\n * until X% of the work remains. Big-chunks belong to the thread and will not be provided to another\n * thread. Then, it switches to providing small-chunk sizes. Small-chunks comprise the last X% of\n * work and every thread can participate in completing the chunk. Even though the queue is shared\n * across threads, there's no communication across thread during the big-chunk phases. The queue is\n * effectively a per-thread queue while processing big-chunks. The small-chunk phase uses an\n * AtomicLong to coordinate chunk allocation across threads.\n *\n * <p>[Chunk processing] Chunk processing is typical. Process line by line. Find a hash function\n * (polynomial hash fns are slow, but will work fine), hash the city name, resolve conflicts using\n * linear probing and then accumulate the temperature into the appropriate hash slot. The key\n * element then is how fast can you identify the hash slot, read the temperature and update the new\n * temperature in the slot (i.e. min, max, count).\n *\n * <p>[Cache friendliness] 7502P and my machine (7950X) offer 4MB L3 cache/core. This means we can\n * hope to fit all our datastructures in L3 cache. Since SMT is turned on, the Runtime's available\n * processors will show twice the number of actual cores and so we get 2MB L3 cache/thread. To be\n * safe, we try to stay within 1.8 MB/thread and size our hashtable appropriately.\n *\n * <p>[Native ByteOrder is MUCH better] There was almost a 10% lift by reading ints from bytebuffers\n * using native byteorder . It so happens that both the eval machine (7502P) and my machine 7950X\n * use native LITTLE_ENDIAN order, which again apparently is because X86[-64] is little-endian. But,\n * by default, ByteBuffers use BIG_ENDIAN order, which appears to be a somewhat strange default from\n * Java.\n *\n * <p>[Allocation] Since MemorySegment seemed slower than ByteBuffers, backing Chunks by bytebuffers\n * was the logical option. Creating one ByteBuffer per chunk was no bueno because the system doesn't\n * like it (JVM runs out of mapped file handle quota). Other than that, allocation in the hot path\n * was avoided.\n *\n * <p>[General approach to fast hashing and temperature reading] Here, it helps to understand the\n * various bottlenecks in execution. One particular thing that I kept coming back to was to\n * understand the relative costs of instructions: See\n * https://www.agner.org/optimize/instruction_tables.pdf It is helpful to think of hardware as a\n * smart parallel execution machine that can do several operations in one cycle if only you can feed\n * it. So, the idea is to reduce data-dependency chains in the bottleneck path. The other major idea\n * is to just avoid unnecessary work. For example, copying the city name into a byte array just for\n * the purpose of looking it up was costing a noticeable amount. Instead, encoding it as\n * (bytebuffer, start, len) was helpful. Spotting unnecessary work was non-trivial.So, them pesky\n * range checks? see if you can avoid them. For example, sometimes you can eliminate a \"nextPos <\n * endPos\" in a tight loop by breaking it into two pieces: one piece where the check will not be\n * needed and a tail piece where it will be needed.\n *\n * <p>[Understand What Cores like]. Cores like to go straight and loop back. Despite good branch\n * prediction, performance sucks with mispredicted branches.\n *\n * <p>[JIT] Java performance requires understanding the JIT. It is helpful to understand what the\n * JIT likes though it is still somewhat of a mystery to me. In general, it inlines small methods\n * very well and after constant folding, it can optimize quite well across a reasonably deep call\n * chain. My experience with the JIT was that everything I tried to tune it made it worse except for\n * one parameter. I have a new-found respect for JIT - it likes and understands typical Java idioms.\n *\n * <p>[Tuning] Nothing was more insightful than actually playing with various tuning parameters. I\n * can have all the theories but the hardware and JIT are giant blackboxes. I used a bunch of tools\n * to optimize: (1) Command line parameters to tune big and small chunk sizes etc. This was also\n * very helpful in forming a mental model of the JIT. Sometimes, it would compile some methods and\n * sometimes it would just run them interpreted since the compilation threshold wouldn't be reached\n * for intermediate methods. (2) AsyncProfiler - this was the first line tool to understand cache\n * misses and cpu time to figure where to aim the next optimization effort. (3) JitWatch -\n * invaluable for forming a mental model and attempting to tune the JIT.\n *\n * <p>[Things that didn't work]. This is a looong list and the hit rate is quite low. In general,\n * removing unnecessary work had a high hit rate and my pet theories on how things work in hardware\n * had a low hit rate. Java Vector API lacked a good gather API to load from arbitrary memory\n * addresses; this prevented performing real SIMD on the entire dataset, one where you load 64 bytes\n * from 64 different line starting positions (just after a previous line end) and then step through\n * one byte at a time. This to me is the most natural SIMD approach to the 1BRC problem but I\n * couldn't use it. I tried other local uses of the vector API and it was always slower, and mostly\n * much slower. In other words, Java Vector API needs a problem for which it is suited (duh) but,\n * unless I am overlooking something, the API still lacks gather from arbitrary memory addresses.\n *\n * <p>[My general takeaways]. Write simple, idiomatic java code and get 70-80% of the max\n * performance of an optimally hand-tuned code. Focus any optimization efforts on being friendly to\n * the JIT *before* thinking about tuning for the hardware. There's a real cost to EXTREME\n * performance tuning: a loss of abstraction and maintainability, but being JIT friendly is probably\n * much more achievable without sacrificing abstraction.\n */\npublic class CalculateAverage_vemana {\n\n    public static void main(String[] args) throws Exception {\n        Tracing.recordAppStart();\n        Runtime.getRuntime()\n                .addShutdownHook(\n                        new Thread(\n                                () -> {\n                                    Tracing.recordEvent(\"In Shutdown hook\");\n                                }));\n\n        // First process in large chunks without coordination among threads\n        // Use chunkSizeBits for the large-chunk size\n        int chunkSizeBits = 20;\n\n        // For the last commonChunkFraction fraction of total work, use smaller chunk sizes\n        double commonChunkFraction = 0.03;\n\n        // Use commonChunkSizeBits for the small-chunk size\n        int commonChunkSizeBits = 18;\n\n        // Size of the hashtable (attempt to fit in L3)\n        int hashtableSizeBits = 14;\n\n        int minReservedBytesAtFileTail = 9;\n\n        int nThreads = -1;\n\n        String inputFile = \"measurements.txt\";\n\n        double munmapFraction = 0.03;\n\n        boolean fakeAdvance = false;\n\n        for (String arg : args) {\n            String key = arg.substring(0, arg.indexOf('=')).trim();\n            String value = arg.substring(key.length() + 1).trim();\n            switch (key) {\n                case \"chunkSizeBits\":\n                    chunkSizeBits = Integer.parseInt(value);\n                    break;\n                case \"commonChunkFraction\":\n                    commonChunkFraction = Double.parseDouble(value);\n                    break;\n                case \"commonChunkSizeBits\":\n                    commonChunkSizeBits = Integer.parseInt(value);\n                    break;\n                case \"hashtableSizeBits\":\n                    hashtableSizeBits = Integer.parseInt(value);\n                    break;\n                case \"inputfile\":\n                    inputFile = value;\n                    break;\n                case \"munmapFraction\":\n                    munmapFraction = Double.parseDouble(value);\n                    break;\n                case \"fakeAdvance\":\n                    fakeAdvance = Boolean.parseBoolean(value);\n                    break;\n                case \"nThreads\":\n                    nThreads = Integer.parseInt(value);\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Unknown argument: \" + arg);\n            }\n        }\n\n        // System.err.println(STR.\"\"\"\n        // Using the following parameters:\n        // - chunkSizeBits = \\{chunkSizeBits}\n        // - commonChunkFraction = \\{commonChunkFraction}\n        // - commonChunkSizeBits = \\{commonChunkSizeBits}\n        // - hashtableSizeBits = \\{hashtableSizeBits}\n        // \"\"\");\n\n        System.out.println(\n                new Runner(\n                        Path.of(inputFile),\n                        nThreads,\n                        chunkSizeBits,\n                        commonChunkFraction,\n                        commonChunkSizeBits,\n                        hashtableSizeBits,\n                        minReservedBytesAtFileTail,\n                        munmapFraction,\n                        fakeAdvance)\n                                .getSummaryStatistics());\n\n        Tracing.recordEvent(\"Final result printed\");\n    }\n\n  public record AggregateResult(Map<String, Stat> tempStats) {\n\n    @Override\n    public String toString() {\n      return this.tempStats().entrySet().stream()\n          .sorted(Entry.comparingByKey())\n          .map(entry -> \"%s=%s\".formatted(entry.getKey(), entry.getValue()))\n          .collect(Collectors.joining(\", \", \"{\", \"}\"));\n    }\n  }\n\n    // Mutable to avoid allocation\n    public static class ByteRange {\n\n        private static final int BUF_SIZE = 1 << 30;\n\n        private final long fileSize;\n        private final long maxEndPos; // Treat as if the file ends here\n        private final RandomAccessFile raf;\n        private final List<MappedByteBuffer> unclosedBuffers = new ArrayList<>();\n\n        // ***************** What this is doing and why *****************\n        // Reading from ByteBuffer appears faster from MemorySegment, but ByteBuffer can only be\n        // Integer.MAX_VALUE long; Creating one byteBuffer per chunk kills native memory quota\n        // and JVM crashes without futher parameters.\n        //\n        // So, in this solution, create a sliding window of bytebuffers:\n        // - Create a large bytebuffer that spans the chunk\n        // - If the next chunk falls outside the byteBuffer, create another byteBuffer that spans the\n        // chunk. Because chunks are allocated serially, a single large (1<<30) byteBuffer spans\n        // many successive chunks.\n        // - In fact, for serial chunk allocation (which is friendly to page faulting anyway),\n        // the number of created ByteBuffers doesn't exceed [size of shard/(1<<30)] which is less than\n        // 100/thread and is comfortably below what the JVM can handle (65K) without further param\n        // tuning\n        // - This enables (relatively) allocation free chunking implementation. Our chunking impl uses\n        // fine grained chunking for the last say X% of work to avoid being hostage to stragglers\n        // The PUBLIC API\n        public MappedByteBuffer byteBuffer;\n        public int endInBuf; // where the chunk ends inside the buffer\n        public int startInBuf; // where the chunk starts inside the buffer\n        // Private State\n        private long bufferEnd; // byteBuffer's ending coordinate\n        private long bufferStart; // byteBuffer's begin coordinate\n\n        // Uninitialized; for mutability\n        public ByteRange(RandomAccessFile raf, long maxEndPos) {\n            this.raf = raf;\n            this.maxEndPos = maxEndPos;\n            try {\n                this.fileSize = raf.length();\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n            bufferEnd = bufferStart = -1;\n        }\n\n        public void close(String closerId, int shardIdx) {\n            Tracing.recordWorkStart(closerId, shardIdx);\n            if (byteBuffer != null) {\n                unclosedBuffers.add(byteBuffer);\n            }\n            for (MappedByteBuffer buf : unclosedBuffers) {\n                close(buf);\n            }\n            unclosedBuffers.clear();\n            bufferEnd = bufferStart = -1;\n            byteBuffer = null;\n            Tracing.recordWorkEnd(closerId, shardIdx);\n        }\n\n        public void setRange(long rangeStart, long rangeEnd) {\n            if (rangeEnd + 1024 > bufferEnd || rangeStart < bufferStart) {\n                bufferStart = rangeStart;\n                bufferEnd = Math.min(bufferStart + BUF_SIZE, fileSize);\n                setByteBufferToRange(bufferStart, bufferEnd);\n            }\n\n            if (rangeStart > 0) {\n                rangeStart = 1 + nextNewLine(rangeStart);\n            }\n            else {\n                rangeStart = 0;\n            }\n\n            if (rangeEnd < maxEndPos) {\n                rangeEnd = 1 + nextNewLine(rangeEnd);\n            }\n            else {\n                rangeEnd = maxEndPos;\n            }\n\n            startInBuf = (int) (rangeStart - bufferStart);\n            endInBuf = (int) (rangeEnd - bufferStart);\n        }\n\n    @Override\n    public String toString() {\n      return STR.\"\"\"\n        ByteRange {\n          bufferStart = \\{bufferStart}\n          bufferEnd = \\{bufferEnd}\n          startInBuf = \\{startInBuf}\n          endInBuf = \\{endInBuf}\n        }\n        \"\"\";\n    }\n\n        private void close(MappedByteBuffer buffer) {\n            Method cleanerMethod = Reflection.findMethodNamed(buffer, \"cleaner\");\n            cleanerMethod.setAccessible(true);\n            Object cleaner = Reflection.invoke(buffer, cleanerMethod);\n\n            Method cleanMethod = Reflection.findMethodNamed(cleaner, \"clean\");\n            cleanMethod.setAccessible(true);\n            Reflection.invoke(cleaner, cleanMethod);\n        }\n\n        private long nextNewLine(long pos) {\n            int nextPos = (int) (pos - bufferStart);\n            while (byteBuffer.get(nextPos) != '\\n') {\n                nextPos++;\n            }\n            return nextPos + bufferStart;\n        }\n\n        private void setByteBufferToRange(long start, long end) {\n            if (byteBuffer != null) {\n                unclosedBuffers.add(byteBuffer);\n            }\n            try {\n                byteBuffer = raf.getChannel().map(MapMode.READ_ONLY, start, end - start);\n                byteBuffer.order(ByteOrder.nativeOrder());\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public static final class Checks {\n\n        public static void checkArg(boolean condition) {\n            if (!condition) {\n                throw new IllegalArgumentException();\n            }\n        }\n\n        private Checks() {\n        }\n    }\n\n    public interface LazyShardQueue {\n\n        void close(String closerId, int shardIdx);\n\n        Optional<ByteRange> fileTailEndWork(int idx);\n\n        ByteRange take(int shardIdx);\n    }\n\n    static final class Reflection {\n\n        static Method findMethodNamed(Object object, String name, Class... paramTypes) {\n            try {\n                return object.getClass().getMethod(name, paramTypes);\n            }\n            catch (NoSuchMethodException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        static Object invoke(Object receiver, Method method, Object... params) {\n            try {\n                return method.invoke(receiver, params);\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public static class Runner {\n\n        private final double commonChunkFraction;\n        private final int commonChunkSizeBits;\n        private final boolean fakeAdvance;\n        private final int hashtableSizeBits;\n        private final Path inputFile;\n        private final int minReservedBytesAtFileTail;\n        private final double munmapFraction;\n        private final int nThreads;\n        private final int shardSizeBits;\n\n        public Runner(\n                      Path inputFile,\n                      int nThreads,\n                      int chunkSizeBits,\n                      double commonChunkFraction,\n                      int commonChunkSizeBits,\n                      int hashtableSizeBits,\n                      int minReservedBytesAtFileTail,\n                      double munmapFraction,\n                      boolean fakeAdvance) {\n            this.inputFile = inputFile;\n            this.nThreads = nThreads;\n            this.shardSizeBits = chunkSizeBits;\n            this.commonChunkFraction = commonChunkFraction;\n            this.commonChunkSizeBits = commonChunkSizeBits;\n            this.hashtableSizeBits = hashtableSizeBits;\n            this.minReservedBytesAtFileTail = minReservedBytesAtFileTail;\n            this.munmapFraction = munmapFraction;\n            this.fakeAdvance = fakeAdvance;\n        }\n\n        AggregateResult getSummaryStatistics() throws Exception {\n            int nThreads = this.nThreads < 0 ? Runtime.getRuntime().availableProcessors() : this.nThreads;\n\n            LazyShardQueue shardQueue = new SerialLazyShardQueue(\n                    1L << shardSizeBits,\n                    inputFile,\n                    nThreads,\n                    commonChunkFraction,\n                    commonChunkSizeBits,\n                    minReservedBytesAtFileTail,\n                    munmapFraction,\n                    fakeAdvance);\n\n            ExecutorService executorService = Executors.newFixedThreadPool(\n                    nThreads,\n                    runnable -> {\n                        Thread thread = new Thread(runnable);\n                        thread.setDaemon(true);\n                        return thread;\n                    });\n\n            List<Future<AggregateResult>> results = new ArrayList<>();\n            for (int i = 0; i < nThreads; i++) {\n                final int shardIdx = i;\n                final Callable<AggregateResult> callable = () -> {\n                    Tracing.recordWorkStart(\"Shard\", shardIdx);\n                    AggregateResult result = new ShardProcessor(shardQueue, hashtableSizeBits, shardIdx).processShard();\n                    Tracing.recordWorkEnd(\"Shard\", shardIdx);\n                    return result;\n                };\n                results.add(executorService.submit(callable));\n            }\n            Tracing.recordEvent(\"Basic push time\");\n\n            // This particular sequence of Futures is so that both merge and munmap() can work as shards\n            // finish their computation without blocking on the entire set of shards to complete. In\n            // particular, munmap() doesn't need to wait on merge.\n            // First, submit a task to merge the results and then submit a task to cleanup bytebuffers\n            // from completed shards.\n            Future<AggregateResult> resultFutures = executorService.submit(() -> merge(results));\n            // Note that munmap() is serial and not parallel and hence we use just one thread.\n            executorService.submit(() -> closeByteBuffers(results, shardQueue));\n\n            AggregateResult result = resultFutures.get();\n            Tracing.recordEvent(\"Merge results received\");\n\n            Tracing.recordEvent(\"About to shutdown executor and wait\");\n            executorService.shutdown();\n            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);\n            Tracing.recordEvent(\"Executor terminated\");\n\n            Tracing.analyzeWorkThreads(nThreads);\n            return result;\n        }\n\n        private void closeByteBuffers(\n                                      List<Future<AggregateResult>> results, LazyShardQueue shardQueue) {\n            int n = results.size();\n            boolean[] isDone = new boolean[n];\n            int remaining = results.size();\n            while (remaining > 0) {\n                for (int i = 0; i < n; i++) {\n                    if (!isDone[i] && results.get(i).isDone()) {\n                        remaining--;\n                        isDone[i] = true;\n                        shardQueue.close(\"Ending Cleaner\", i);\n                    }\n                }\n            }\n        }\n\n        private AggregateResult merge(List<Future<AggregateResult>> results)\n                throws ExecutionException, InterruptedException {\n            Tracing.recordEvent(\"Merge start time\");\n            Map<String, Stat> output = null;\n            boolean[] isDone = new boolean[results.size()];\n            int remaining = results.size();\n            // Let's be naughty and spin in a busy loop\n            while (remaining > 0) {\n                for (int i = 0; i < results.size(); i++) {\n                    if (!isDone[i] && results.get(i).isDone()) {\n                        isDone[i] = true;\n                        remaining--;\n                        if (output == null) {\n                            output = new TreeMap<>(results.get(i).get().tempStats());\n                        }\n                        else {\n                            for (Entry<String, Stat> entry : results.get(i).get().tempStats().entrySet()) {\n                                output.compute(\n                                        entry.getKey(),\n                                        (key, value) -> value == null ? entry.getValue() : Stat.merge(value, entry.getValue()));\n                            }\n                        }\n                    }\n                }\n            }\n            Tracing.recordEvent(\"Merge end time\");\n            return new AggregateResult(output);\n        }\n    }\n\n    public static class SerialLazyShardQueue implements LazyShardQueue {\n\n        private static long roundToNearestLowerMultipleOf(long divisor, long value) {\n            return value / divisor * divisor;\n        }\n\n        private final ByteRange[] byteRanges;\n        private final long chunkSize;\n        private final long commonChunkSize;\n        private final AtomicLong commonPool;\n        private final long effectiveFileSize;\n        private final boolean fakeAdvance;\n        private final long fileSize;\n        private final long[] perThreadData;\n        private final RandomAccessFile raf;\n        private final SeqLock seqLock;\n\n        public SerialLazyShardQueue(\n                                    long chunkSize,\n                                    Path filePath,\n                                    int shards,\n                                    double commonChunkFraction,\n                                    int commonChunkSizeBits,\n                                    int fileTailReservedBytes,\n                                    double munmapFraction,\n                                    boolean fakeAdvance)\n                throws IOException {\n            this.fakeAdvance = fakeAdvance;\n            Checks.checkArg(commonChunkFraction < 0.9 && commonChunkFraction >= 0);\n            Checks.checkArg(fileTailReservedBytes >= 0);\n            this.raf = new RandomAccessFile(filePath.toFile(), \"r\");\n            this.fileSize = raf.length();\n            fileTailReservedBytes = fileTailReservedBytes == 0\n                    ? 0\n                    : consumeToPreviousNewLineExclusive(raf, fileTailReservedBytes);\n            this.effectiveFileSize = fileSize - fileTailReservedBytes;\n\n            // Common pool\n            long commonPoolStart = Math.min(\n                    roundToNearestLowerMultipleOf(\n                            chunkSize, (long) (effectiveFileSize * (1 - commonChunkFraction))),\n                    effectiveFileSize);\n            this.commonPool = new AtomicLong(commonPoolStart);\n            this.commonChunkSize = 1L << commonChunkSizeBits;\n\n            // Distribute chunks to shards\n            this.perThreadData = new long[shards << 4]; // thread idx -> 16*idx to avoid cache line conflict\n            for (long i = 0,\n                    currentStart = 0,\n                    remainingChunks = (commonPoolStart + chunkSize - 1) / chunkSize; i < shards; i++) {\n                long remainingShards = shards - i;\n                long currentChunks = (remainingChunks + remainingShards - 1) / remainingShards;\n                // Shard i handles: [currentStart, currentStart + currentChunks * chunkSize)\n                int pos = (int) i << 4;\n                perThreadData[pos] = currentStart; // next chunk begin\n                perThreadData[pos + 1] = currentStart + currentChunks * chunkSize; // shard end\n                perThreadData[pos + 2] = currentChunks; // active chunks remaining\n                // threshold below which need to shrink\n                // 0.03 is a practical number but the optimal strategy is this:\n                // Shard number N (1-based) should unmap as soon as it completes (R/(R+1))^N fraction of\n                // its work, where R = relative speed of unmap compared to the computation.\n                // For our problem, R ~ 75 because unmap unmaps 30GB/sec (but, it is serial) while\n                // cores go through data at the rate of 400MB/sec.\n                perThreadData[pos + 3] = (long) (currentChunks * (munmapFraction * (shards - i)));\n                perThreadData[pos + 4] = 1; // true iff munmap() hasn't been triggered yet\n                currentStart += currentChunks * chunkSize;\n                remainingChunks -= currentChunks;\n            }\n            this.chunkSize = chunkSize;\n\n            this.byteRanges = new ByteRange[shards << 4];\n            for (int i = 0; i < shards; i++) {\n                byteRanges[i << 4] = new ByteRange(raf, effectiveFileSize);\n            }\n\n            this.seqLock = new SeqLock();\n        }\n\n        @Override\n        public void close(String closerId, int shardIdx) {\n            byteRanges[shardIdx << 4].close(closerId, shardIdx);\n        }\n\n        @Override\n        public Optional<ByteRange> fileTailEndWork(int idx) {\n            if (idx == 0 && effectiveFileSize < fileSize) {\n                ByteRange chunk = new ByteRange(raf, fileSize);\n                chunk.setRange(\n                        effectiveFileSize == 0 ? 0 : effectiveFileSize - 1 /* will consume newline at eFS-1 */,\n                        fileSize);\n                return Optional.of(chunk);\n            }\n            return Optional.empty();\n        }\n\n        @Override\n        public ByteRange take(int shardIdx) {\n            // Try for thread local range\n            final int pos = shardIdx << 4;\n            final long rangeStart;\n            final long rangeEnd;\n\n            if (perThreadData[pos + 2] >= 1) {\n                rangeStart = perThreadData[pos];\n                rangeEnd = rangeStart + chunkSize;\n                // Don't do this in the if-check; it causes negative values that trigger intermediate\n                // cleanup\n                perThreadData[pos + 2]--;\n                if (!fakeAdvance) {\n                    perThreadData[pos] = rangeEnd;\n                }\n            }\n            else {\n                rangeStart = commonPool.getAndAdd(commonChunkSize);\n                // If that's exhausted too, nothing remains!\n                if (rangeStart >= effectiveFileSize) {\n                    return null;\n                }\n                rangeEnd = rangeStart + commonChunkSize;\n            }\n\n            if (perThreadData[pos + 2] < perThreadData[pos + 3] && perThreadData[pos + 4] > 0) {\n                if (attemptIntermediateClose(shardIdx)) {\n                    perThreadData[pos + 4]--;\n                }\n            }\n\n            ByteRange chunk = byteRanges[pos];\n            chunk.setRange(rangeStart, rangeEnd);\n            return chunk;\n        }\n\n        private boolean attemptIntermediateClose(int shardIdx) {\n            if (seqLock.acquire()) {\n                close(\"Intermediate Cleaner\", shardIdx);\n                seqLock.release();\n                return true;\n            }\n            return false;\n        }\n\n        private int consumeToPreviousNewLineExclusive(RandomAccessFile raf, int minReservedBytes) {\n            try {\n                long pos = Math.max(raf.length() - minReservedBytes - 1, -1);\n                if (pos < 0) {\n                    return (int) raf.length();\n                }\n\n                long start = Math.max(pos - 512, 0);\n                ByteBuffer buf = raf.getChannel().map(MapMode.READ_ONLY, start, pos + 1 - start);\n                while (pos >= 0 && buf.get((int) (pos - start)) != '\\n') {\n                    pos--;\n                }\n                pos++;\n                return (int) (raf.length() - pos);\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /** A low-traffic non-blocking lock. */\n    static class SeqLock {\n\n        private final AtomicBoolean isOccupied = new AtomicBoolean(false);\n\n        boolean acquire() {\n            return !isOccupied.get() && isOccupied.compareAndSet(false, true);\n        }\n\n        void release() {\n            isOccupied.set(false);\n        }\n    }\n\n    public static class ShardProcessor {\n\n        private final int shardIdx;\n        private final LazyShardQueue shardQueue;\n        private final ShardProcessorState state;\n\n        public ShardProcessor(LazyShardQueue shardQueue, int hashtableSizeBits, int shardIdx) {\n            this.shardQueue = shardQueue;\n            this.shardIdx = shardIdx;\n            this.state = new ShardProcessorState(hashtableSizeBits);\n        }\n\n        public AggregateResult processShard() {\n            return processShardReal();\n        }\n\n        public AggregateResult processShardReal() {\n            // First process the file tail work to give ourselves freedom to go past ranges in parsing\n            shardQueue.fileTailEndWork(shardIdx).ifPresent(this::processRangeSlow);\n\n            ByteRange range;\n            while ((range = shardQueue.take(shardIdx)) != null) {\n                processRange(range);\n            }\n            return result();\n        }\n\n        private void processRange(ByteRange range) {\n            MappedByteBuffer mmb = range.byteBuffer;\n            int nextPos = range.startInBuf;\n            int end = range.endInBuf;\n\n            while (nextPos < end) {\n                nextPos = state.processLine(mmb, nextPos);\n            }\n        }\n\n        private void processRangeSlow(ByteRange range) {\n            int nextPos = range.startInBuf;\n            while (nextPos < range.endInBuf) {\n                nextPos = state.processLineSlow(range.byteBuffer, nextPos);\n            }\n        }\n\n        private AggregateResult result() {\n            return state.result();\n        }\n    }\n\n    public static class ShardProcessorState {\n\n        public static final long ONE_MASK = 0x0101010101010101L;\n        private static final ByteOrder NATIVE_BYTE_ORDER = ByteOrder.nativeOrder();\n        private static final long SEMICOLON_MASK = 0x3b3b3b3b3b3b3b3bL;\n        private final byte[][] cityNames;\n        private final int slotsMask;\n        private final Stat[] stats;\n\n        public ShardProcessorState(int slotsBits) {\n            this.stats = new Stat[1 << slotsBits];\n            this.cityNames = new byte[1 << slotsBits][];\n            this.slotsMask = (1 << slotsBits) - 1;\n        }\n\n        public int processLine(MappedByteBuffer mmb, int nextPos) {\n            int originalPos = nextPos;\n            byte nextByte;\n            int hash = 0;\n\n            while (true) {\n                int x = mmb.getInt(nextPos);\n                if (NATIVE_BYTE_ORDER == ByteOrder.BIG_ENDIAN) {\n                    x = Integer.reverseBytes(x);\n                }\n\n                byte a = (byte) (x >>> 0);\n                if (a == ';') {\n                    nextPos += 1;\n                    break;\n                }\n\n                byte b = (byte) (x >>> 8);\n                if (b == ';') {\n                    nextPos += 2;\n                    hash = hash * 31 + (0xFF & x);\n                    break;\n                }\n\n                byte c = (byte) (x >>> 16);\n                if (c == ';') {\n                    nextPos += 3;\n                    hash = hash * 31 + (0xFFFF & x);\n                    break;\n                }\n\n                byte d = (byte) (x >>> 24);\n                if (d == ';') {\n                    nextPos += 4;\n                    hash = hash * 31 + (0xFFFFFF & x);\n                    break;\n                }\n\n                hash = hash * 31 + x;\n                nextPos += 4;\n            }\n            int cityLen = nextPos - 1 - originalPos;\n\n            // Read temperature\n            int temperature = 0;\n            boolean negative = (nextByte = mmb.get(nextPos++)) == '-';\n            if (!negative) {\n                temperature = nextByte - '0';\n            }\n            else {\n                temperature = mmb.get(nextPos++) - '0';\n            }\n\n            while (true) {\n                nextByte = mmb.get(nextPos++);\n                if (nextByte != '.') {\n                    temperature = temperature * 10 + (nextByte - '0');\n                }\n                else {\n                    temperature = temperature * 10 + (mmb.get(nextPos++) - '0');\n                    nextPos++;\n                    break;\n                }\n            }\n\n            linearProbe(\n                    cityLen, hash & slotsMask, negative ? -temperature : temperature, mmb, originalPos);\n\n            return nextPos;\n        }\n\n        /** A slow version which is used only for the tail part of the file. */\n        public int processLineSlow(MappedByteBuffer mmb, int nextPos) {\n            int originalPos = nextPos;\n            byte nextByte;\n            int hash = 0;\n\n            outer: while (true) {\n                int accumulated = 0;\n                for (int i = 0; i < 4; i++) {\n                    nextByte = mmb.get(nextPos++);\n                    if (nextByte == ';') {\n                        if (i > 0) {\n                            hash = hash * 31 + accumulated;\n                        }\n                        break outer;\n                    }\n                    else {\n                        accumulated |= ((int) nextByte << (8 * i));\n                    }\n                }\n                hash = hash * 31 + accumulated;\n            }\n            int cityLen = nextPos - 1 - originalPos;\n\n            int temperature = 0;\n            boolean negative = mmb.get(nextPos) == '-';\n            while ((nextByte = mmb.get(nextPos++)) != '\\n') {\n                if (nextByte != '-' && nextByte != '.') {\n                    temperature = temperature * 10 + (nextByte - '0');\n                }\n            }\n\n            linearProbe(\n                    cityLen, hash & slotsMask, negative ? -temperature : temperature, mmb, originalPos);\n\n            return nextPos;\n        }\n\n        public AggregateResult result() {\n            int N = stats.length;\n            Map<String, Stat> map = new LinkedHashMap<>(5_000);\n            for (int i = 0; i < N; i++) {\n                if (stats[i] != null) {\n                    map.put(new String(cityNames[i]), stats[i]);\n                }\n            }\n            return new AggregateResult(map);\n        }\n\n        private byte[] copyFrom(MappedByteBuffer mmb, int offsetInMmb, int len) {\n            byte[] out = new byte[len];\n            for (int i = 0; i < len; i++) {\n                out[i] = mmb.get(offsetInMmb + i);\n            }\n            return out;\n        }\n\n        private boolean equals(byte[] left, MappedByteBuffer right, int offsetInMmb, int len) {\n            for (int i = 0; i < len; i++) {\n                if (left[i] != right.get(offsetInMmb + i)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        private boolean hasSemicolonByte(long value) {\n            long a = value ^ SEMICOLON_MASK;\n            return (((a - ONE_MASK) & ~a) & (0x8080808080808080L)) != 0;\n        }\n\n        private void linearProbe(int len, int hash, int temp, MappedByteBuffer mmb, int offsetInMmb) {\n            for (int i = hash;; i = (i + 1) & slotsMask) {\n                var curBytes = cityNames[i];\n                if (curBytes == null) {\n                    cityNames[i] = copyFrom(mmb, offsetInMmb, len);\n                    stats[i] = Stat.firstReading(temp);\n                    return;\n                }\n                else {\n                    if (len == curBytes.length && equals(curBytes, mmb, offsetInMmb, len)) {\n                        stats[i].mergeReading(temp);\n                        return;\n                    }\n                }\n            }\n        }\n    }\n\n    /** Represents aggregate stats. */\n    public static class Stat {\n\n        public static Stat firstReading(int temp) {\n            return new Stat(temp, temp, temp, 1);\n        }\n\n        public static Stat merge(Stat left, Stat right) {\n            return new Stat(\n                    Math.min(left.min, right.min),\n                    Math.max(left.max, right.max),\n                    left.sum + right.sum,\n                    left.count + right.count);\n        }\n\n        private long count, sum;\n        private int min, max;\n\n        public Stat(int min, int max, long sum, long count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n\n        // Caution: Mutates\n        public void mergeReading(int curTemp) {\n            // Can this be improved furhter?\n            // Assuming random values for curTemp,\n            // min (&max) gets updated roughly log(N)/N fraction of the time (a small number)\n            // In the worst case, there will be at-most one branch misprediction.\n            if (curTemp > min) { // Mostly passes. On branch misprediction, just update min.\n                if (curTemp > max) { // Mostly fails. On branch misprediction, just update max.\n                    max = curTemp;\n                }\n            }\n            else {\n                min = curTemp;\n            }\n            sum += curTemp;\n            count++;\n        }\n\n        @Override\n        public String toString() {\n            return \"%.1f/%.1f/%.1f\".formatted(min / 10.0, sum / 10.0 / count, max / 10.0);\n        }\n    }\n\n    static class Tracing {\n\n        private static final Map<String, ThreadTimingsArray> knownWorkThreadEvents;\n        private static long startTime;\n\n        static {\n            // Maintain the ordering to be chronological in execution\n            // Map.of(..) screws up ordering\n            knownWorkThreadEvents = new LinkedHashMap<>();\n            for (String id : List.of(\"Shard\", \"Intermediate Cleaner\", \"Ending Cleaner\")) {\n                knownWorkThreadEvents.put(id, new ThreadTimingsArray(id, 1 << 6 << 1));\n            }\n        }\n\n        static void analyzeWorkThreads(int nThreads) {\n            for (ThreadTimingsArray array : knownWorkThreadEvents.values()) {\n                errPrint(array.analyze(nThreads));\n            }\n        }\n\n        static void recordAppStart() {\n            startTime = System.nanoTime();\n        }\n\n        static void recordEvent(String event) {\n            printEvent(event, System.nanoTime());\n        }\n\n        static void recordWorkEnd(String id, int threadId) {\n            knownWorkThreadEvents.get(id).recordEnd(threadId);\n        }\n\n        static void recordWorkStart(String id, int threadId) {\n            knownWorkThreadEvents.get(id).recordStart(threadId);\n        }\n\n        /////////////////////////////////////////////////////////////////////////////////////////////////\n\n        private static void errPrint(String message) {\n            System.err.println(message);\n        }\n\n    private static void printEvent(String message, long nanoTime) {\n      errPrint(STR.\"\\{message} = \\{(nanoTime - startTime) / 1_000_000}ms\");\n    }\n\n        public static class ThreadTimingsArray {\n\n            private static String toString(long[] array) {\n                return Arrays.stream(array)\n                        .map(x -> x < 0 ? -1 : x)\n                        .mapToObj(x -> String.format(\"%6d\", x))\n                        .collect(Collectors.joining(\", \", \"[ \", \" ]\"));\n            }\n\n            private final String id;\n            private final long[] timestamps;\n            private boolean hasData = false;\n\n            public ThreadTimingsArray(String id, int maxSize) {\n                this.timestamps = new long[maxSize];\n                this.id = id;\n            }\n\n      public String analyze(int nThreads) {\n        if (!hasData) {\n          return \"%s has no thread timings data\".formatted(id);\n        }\n        Checks.checkArg(nThreads <= timestamps.length);\n        long minDuration = Long.MAX_VALUE, maxDuration = Long.MIN_VALUE;\n        long minBegin = Long.MAX_VALUE, maxCompletion = Long.MIN_VALUE;\n        long maxBegin = Long.MIN_VALUE, minCompletion = Long.MAX_VALUE;\n\n        long[] durationsMs = new long[nThreads];\n        long[] completionsMs = new long[nThreads];\n        long[] beginMs = new long[nThreads];\n        for (int i = 0; i < nThreads; i++) {\n          long durationNs = timestamps[2 * i + 1] - timestamps[2 * i];\n          durationsMs[i] = durationNs / 1_000_000;\n          completionsMs[i] = (timestamps[2 * i + 1] - startTime) / 1_000_000;\n          beginMs[i] = (timestamps[2 * i] - startTime) / 1_000_000;\n\n          minDuration = Math.min(minDuration, durationNs);\n          maxDuration = Math.max(maxDuration, durationNs);\n\n          minBegin = Math.min(minBegin, timestamps[2 * i] - startTime);\n          maxBegin = Math.max(maxBegin, timestamps[2 * i] - startTime);\n\n          maxCompletion = Math.max(maxCompletion, timestamps[2 * i + 1] - startTime);\n          minCompletion = Math.min(minCompletion, timestamps[2 * i + 1] - startTime);\n        }\n        return STR.\"\"\"\n        -------------------------------------------------------------------------------------------\n                                       \\{id} Stats\n        -------------------------------------------------------------------------------------------\n        Max duration                              = \\{maxDuration / 1_000_000} ms\n        Min duration                              = \\{minDuration / 1_000_000} ms\n        Timespan[max(end)-min(start)]             = \\{(maxCompletion - minBegin) / 1_000_000} ms [\\{maxCompletion / 1_000_000} - \\{minBegin / 1_000_000} ]\n        Completion Timespan[max(end)-min(end)]    = \\{(maxCompletion - minCompletion) / 1_000_000} ms\n        Begin Timespan[max(begin)-min(begin)]     = \\{(maxBegin - minBegin) / 1_000_000} ms\n        Average Duration                          = \\{Arrays.stream(durationsMs)\n                                                            .average()\n                                                            .getAsDouble()} ms\n        Durations                                 = \\{toString(durationsMs)} ms\n        Begin Timestamps                          = \\{toString(beginMs)} ms\n        Completion Timestamps                     = \\{toString(completionsMs)} ms\n        \"\"\";\n      }\n\n            public void recordEnd(int idx) {\n                timestamps[2 * idx + 1] = System.nanoTime();\n                hasData = true;\n            }\n\n            public void recordStart(int idx) {\n                timestamps[2 * idx] = System.nanoTime();\n                hasData = true;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_vemanaNonIdiomatic.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.lang.invoke.MethodHandles;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel.MapMode;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.Optional;\nimport java.util.TreeMap;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.stream.Collectors;\nimport sun.misc.Unsafe;\n\n/**\n * Unlike its sister submission {@code CalculateAverage_vemana}, this submission employs non\n * idiomatic methods such as SWAR and Unsafe.\n *\n * <p>For details on how this solution works, check the documentation on the sister submission.\n */\npublic class CalculateAverage_vemanaNonIdiomatic {\n\n  public static void main(String[] args) throws Exception {\n    String className = MethodHandles.lookup().lookupClass().getSimpleName();\n    System.err.println(\n        STR.\"\"\"\n        ------------------------------------------------\n        Running \\{className}\n        -------------------------------------------------\n        \"\"\");\n    Tracing.recordAppStart();\n    Runtime.getRuntime()\n        .addShutdownHook(\n            new Thread(\n                () -> {\n                  Tracing.recordEvent(\"In Shutdown hook\");\n                }));\n\n    // First process in large chunks without coordination among threads\n    // Use chunkSizeBits for the large-chunk size\n    int chunkSizeBits = 20;\n\n    // For the last commonChunkFraction fraction of total work, use smaller chunk sizes\n    double commonChunkFraction = 0.03;\n\n    // Use commonChunkSizeBits for the small-chunk size\n    int commonChunkSizeBits = 18;\n\n    // Size of the hashtable (attempt to fit in L2 of 512KB of eval machine)\n    int hashtableSizeBits = className.toLowerCase().contains(\"nonidiomatic\") ? 13 : 16;\n\n    // Reserve some number of lines at the end to give us freedom in reading LONGs past ranges\n    int minReservedBytesAtFileTail = 9;\n\n    // Number of threads\n    int nThreads = -1;\n\n    String inputFile = \"measurements.txt\";\n\n    // Parallelize unmap. Thread #n (n=1,2,..N) unmaps its bytebuffer when\n    // munmapFraction * n work remains.\n    double munmapFraction = 0.03;\n\n    boolean fakeAdvance = false;\n\n    for (String arg : args) {\n      String key = arg.substring(0, arg.indexOf('=')).trim();\n      String value = arg.substring(key.length() + 1).trim();\n      switch (key) {\n        case \"chunkSizeBits\":\n          chunkSizeBits = Integer.parseInt(value);\n          break;\n        case \"commonChunkFraction\":\n          commonChunkFraction = Double.parseDouble(value);\n          break;\n        case \"commonChunkSizeBits\":\n          commonChunkSizeBits = Integer.parseInt(value);\n          break;\n        case \"hashtableSizeBits\":\n          hashtableSizeBits = Integer.parseInt(value);\n          break;\n        case \"inputFile\":\n          inputFile = value;\n          break;\n        case \"munmapFraction\":\n          munmapFraction = Double.parseDouble(value);\n          break;\n        case \"fakeAdvance\":\n          fakeAdvance = Boolean.parseBoolean(value);\n          break;\n        case \"nThreads\":\n          nThreads = Integer.parseInt(value);\n          break;\n        default:\n          throw new IllegalArgumentException(\"Unknown argument: \" + arg);\n      }\n    }\n\n    System.out.println(\n        new Runner(\n                Path.of(inputFile),\n                nThreads,\n                chunkSizeBits,\n                commonChunkFraction,\n                commonChunkSizeBits,\n                hashtableSizeBits,\n                minReservedBytesAtFileTail,\n                munmapFraction,\n                fakeAdvance)\n            .getSummaryStatistics());\n\n    Tracing.recordEvent(\"Final result printed\");\n  }\n\n  public record AggregateResult(Map<String, Stat> tempStats) {\n\n    @Override\n    public String toString() {\n      return this.tempStats().entrySet().stream()\n          .sorted(Map.Entry.comparingByKey())\n          .map(entry -> \"%s=%s\".formatted(entry.getKey(), entry.getValue()))\n          .collect(Collectors.joining(\", \", \"{\", \"}\"));\n    }\n  }\n\n    // Mutable to avoid allocation\n    public static class ByteRange {\n\n        private static final int BUF_SIZE = 1 << 28;\n\n        private final long fileSize;\n        private final long maxEndPos; // Treat as if the file ends here\n        private final RandomAccessFile raf;\n        private final int shardIdx;\n        private final List<MappedByteBuffer> unclosedBuffers = new ArrayList<>();\n        // ***************** What this is doing and why *****************\n        // Reading from ByteBuffer appears faster from MemorySegment, but ByteBuffer can only be\n        // Integer.MAX_VALUE long; Creating one byteBuffer per chunk kills native memory quota\n        // and JVM crashes without futher parameters.\n        //\n        // So, in this solution, create a sliding window of bytebuffers:\n        // - Create a large bytebuffer that spans the chunk\n        // - If the next chunk falls outside the byteBuffer, create another byteBuffer that spans the\n        // chunk. Because chunks are allocated serially, a single large (1<<30) byteBuffer spans\n        // many successive chunks.\n        // - In fact, for serial chunk allocation (which is friendly to page faulting anyway),\n        // the number of created ByteBuffers doesn't exceed [size of shard/(1<<30)] which is less than\n        // 100/thread and is comfortably below what the JVM can handle (65K) without further param\n        // tuning\n        // - This enables (relatively) allocation free chunking implementation. Our chunking impl uses\n        // fine grained chunking for the last say X% of work to avoid being hostage to stragglers\n\n        ///////////// The PUBLIC API\n\n        public MappedByteBuffer byteBuffer;\n        public long endAddress; // the virtual memory address corresponding to 'endInBuf'\n        public int endInBuf; // where the chunk ends inside the buffer\n        public long startAddress; // the virtual memory address corresponding to 'startInBuf'\n        public int startInBuf; // where the chunk starts inside the buffer\n\n        ///////////// Private State\n\n        long bufferBaseAddr; // buffer's base virtual memory address\n        long extentEnd; // byteBuffer's ending coordinate\n        long extentStart; // byteBuffer's begin coordinate\n\n        // Uninitialized; for mutability\n        public ByteRange(RandomAccessFile raf, long maxEndPos, int shardIdx) {\n            this.raf = raf;\n            this.maxEndPos = maxEndPos;\n            this.shardIdx = shardIdx;\n            try {\n                this.fileSize = raf.length();\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n            bufferCleanSlate();\n        }\n\n        public void close(String closerId) {\n            Tracing.recordWorkStart(closerId, shardIdx);\n            bufferCleanSlate();\n            for (MappedByteBuffer buf : unclosedBuffers) {\n                close(buf);\n            }\n            unclosedBuffers.clear();\n            Tracing.recordWorkEnd(closerId, shardIdx);\n        }\n\n        public void setRange(long rangeStart, long rangeEnd) {\n            if (rangeEnd + 1024 > extentEnd || rangeStart < extentStart) {\n                setByteBufferExtent(rangeStart, Math.min(rangeStart + BUF_SIZE, fileSize));\n            }\n\n            if (rangeStart > 0) {\n                rangeStart = 1 + nextNewLine(rangeStart);\n            }\n            else {\n                rangeStart = 0;\n            }\n\n            if (rangeEnd < maxEndPos) {\n                // rangeEnd = 1 + nextNewLine(rangeEnd); // not needed\n                rangeEnd = 1 + rangeEnd;\n            }\n            else {\n                rangeEnd = maxEndPos;\n            }\n\n            startInBuf = (int) (rangeStart - extentStart);\n            endInBuf = (int) (rangeEnd - extentStart);\n            startAddress = bufferBaseAddr + startInBuf;\n            endAddress = bufferBaseAddr + endInBuf;\n        }\n\n    @Override\n    public String toString() {\n      return STR.\"\"\"\n        ByteRange {\n          shard                 = \\{shardIdx}\n          extentStart           = \\{extentStart}\n          extentEnd             = \\{extentEnd}\n          startInBuf            = \\{startInBuf}\n          endInBuf              = \\{endInBuf}\n          startAddress          = \\{startAddress}\n          endAddress            = \\{endAddress}\n        }\n        \"\"\";\n    }\n\n        private void bufferCleanSlate() {\n            if (byteBuffer != null) {\n                unclosedBuffers.add(byteBuffer);\n                byteBuffer = null;\n            }\n            extentEnd = extentStart = bufferBaseAddr = startAddress = endAddress = -1;\n        }\n\n        private void close(MappedByteBuffer buffer) {\n            Method cleanerMethod = Reflection.findMethodNamed(buffer, \"cleaner\");\n            cleanerMethod.setAccessible(true);\n            Object cleaner = Reflection.invoke(buffer, cleanerMethod);\n\n            Method cleanMethod = Reflection.findMethodNamed(cleaner, \"clean\");\n            cleanMethod.setAccessible(true);\n            Reflection.invoke(cleaner, cleanMethod);\n        }\n\n        private long getBaseAddr(MappedByteBuffer buffer) {\n            Method addressMethod = Reflection.findMethodNamed(buffer, \"address\");\n            addressMethod.setAccessible(true);\n            return (long) Reflection.invoke(buffer, addressMethod);\n        }\n\n        private long nextNewLine(long pos) {\n            int nextPos = (int) (pos - extentStart);\n            while (byteBuffer.get(nextPos) != '\\n') {\n                nextPos++;\n            }\n            return nextPos + extentStart;\n        }\n\n        /**\n         * Extent different from Range. Range is what needs to be processed. Extent is what the byte\n         * buffer can read without failing.\n         */\n        private void setByteBufferExtent(long start, long end) {\n            bufferCleanSlate();\n            try {\n                byteBuffer = raf.getChannel().map(MapMode.READ_ONLY, start, end - start);\n                byteBuffer.order(ByteOrder.nativeOrder());\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n            extentStart = start;\n            extentEnd = end;\n            bufferBaseAddr = getBaseAddr(byteBuffer);\n        }\n    }\n\n    public static final class Checks {\n\n        public static void checkArg(boolean condition) {\n            if (!condition) {\n                throw new IllegalArgumentException();\n            }\n        }\n\n        private Checks() {\n        }\n    }\n\n    /*\n     * ENTRY SHAPE\n     * Ensure alignment boundaries. 4 bytes on 4 byte, 2 bytes on 2 byte etc.\n     * 32 bytes per entry.\n     * 96 KB L1 cache. 2048 entries should fully fit\n     * -------------------\n     * str: 14 bytes [Defined by constant STR_FIELD_LEN]\n     * hash: 2 bytes\n     * cityNameOffset: 3 bytes // Index in city names array if len > STR_FIELD_LEN bytes\n     * len: 1 byte // Length of string, in bytes\n     * sum: 4 bytes\n     * count: 4 bytes\n     * max: 2 bytes\n     * min: 2 bytes\n     */\n    static class EntryData {\n\n        public static final int ENTRY_SIZE_BITS = 5;\n\n        /////////// OFFSETS ///////////////\n        private static final int OFFSET_STR = 0;\n        private static final int STR_FIELD_LEN = 14;\n        private static final int OFFSET_HASH = OFFSET_STR + STR_FIELD_LEN;\n        private static final int OFFSET_CITY_NAME_EXTRA = OFFSET_HASH + 2;\n        private static final int OFFSET_LEN = OFFSET_CITY_NAME_EXTRA + 3;\n        private static final int OFFSET_SUM = OFFSET_LEN + 1;\n        private static final int OFFSET_COUNT = OFFSET_SUM + 4;\n        private static final int OFFSET_MAX = OFFSET_COUNT + 4;\n        private static final int OFFSET_MIN = OFFSET_MAX + 2;\n\n        public static int strFieldLen() {\n            return STR_FIELD_LEN;\n        }\n\n        private final EntryMeta entryMeta;\n\n        private long baseAddress;\n\n        public EntryData(EntryMeta entryMeta) {\n            this.entryMeta = entryMeta;\n        }\n\n        public long baseAddress() {\n            return baseAddress;\n        }\n\n        public String cityNameString() {\n            int len = len();\n            byte[] zeBytes = new byte[len];\n\n            for (int i = 0; i < Math.min(len, strFieldLen()); i++) {\n                zeBytes[i] = Unsafely.readByte(baseAddress + i);\n            }\n\n            if (len > strFieldLen()) {\n                int rem = len - strFieldLen();\n                long ptr = entryMeta.cityNamesAddress(cityNamesOffset());\n                for (int i = 0; i < rem; i++) {\n                    zeBytes[strFieldLen() + i] = Unsafely.readByte(ptr + i);\n                }\n            }\n\n            return new String(zeBytes);\n        }\n\n        public int cityNamesOffset() {\n            return Unsafely.readInt(baseAddress + OFFSET_CITY_NAME_EXTRA) & 0xFFFFFF;\n        }\n\n        public int count() {\n            return Unsafely.readInt(baseAddress + OFFSET_COUNT);\n        }\n\n        public short hash16() {\n            return Unsafely.readShort(baseAddress + OFFSET_HASH);\n        }\n\n        public int index() {\n            return (int) ((baseAddress() - entryMeta.baseAddress(0)) >> ENTRY_SIZE_BITS);\n        }\n\n        public void init(long srcAddr, int len, short hash16, short temperature) {\n            // Copy the string\n            Unsafely.copyMemory(srcAddr, strAddress(), Math.min(len, EntryData.strFieldLen()));\n            if (len > EntryData.strFieldLen()) {\n                int remaining = len - EntryData.strFieldLen();\n                int cityNamesOffset = entryMeta.getAndIncrementCityNames(remaining);\n                Unsafely.copyMemory(\n                        srcAddr + EntryData.strFieldLen(),\n                        entryMeta.cityNamesAddress(cityNamesOffset),\n                        remaining);\n                setCityNameOffset(cityNamesOffset, len);\n            }\n            else {\n                setLen((byte) len);\n            }\n\n            // and then update the others\n            setHash16(hash16);\n            setSum(temperature);\n            setCount(1);\n            setMax(temperature);\n            setMin(temperature);\n        }\n\n        public boolean isPresent() {\n            return len() > 0;\n        }\n\n        public int len() {\n            return Unsafely.readByte(baseAddress + OFFSET_LEN);\n        }\n\n        public short max() {\n            return Unsafely.readShort(baseAddress + OFFSET_MAX);\n        }\n\n        public short min() {\n            return Unsafely.readShort(baseAddress + OFFSET_MIN);\n        }\n\n        public void setBaseAddress(long baseAddress) {\n            this.baseAddress = baseAddress;\n        }\n\n        public void setCityNameOffset(int cityNamesOffset, int len) {\n            // The 24 here is 3 bytes for Cityname extra index + 1 byte for actual len\n            // that writes 4 bytes in one shot. It is not an offset.\n            Unsafely.setInt(baseAddress + OFFSET_CITY_NAME_EXTRA, cityNamesOffset | (len << 24));\n        }\n\n        public void setCount(int value) {\n            Unsafely.setInt(baseAddress + OFFSET_COUNT, value);\n        }\n\n        public void setHash16(short value) {\n            Unsafely.setShort(baseAddress + OFFSET_HASH, value);\n        }\n\n        public void setIndex(int index) {\n            setBaseAddress(entryMeta.baseAddress(index));\n        }\n\n        public void setLen(byte value) {\n            Unsafely.setByte(baseAddress + OFFSET_LEN, value);\n        }\n\n        public void setMax(short value) {\n            Unsafely.setShort(baseAddress + OFFSET_MAX, value);\n        }\n\n        public void setMin(short value) {\n            Unsafely.setShort(baseAddress + OFFSET_MIN, value);\n        }\n\n        public void setSum(int value) {\n            Unsafely.setInt(baseAddress + OFFSET_SUM, value);\n        }\n\n        public Stat stat() {\n            return new Stat(min(), max(), sum(), count());\n        }\n\n        public long strAddress() {\n            return baseAddress + OFFSET_STR;\n        }\n\n        public int sum() {\n            return Unsafely.readInt(baseAddress + OFFSET_SUM);\n        }\n\n    public String toString() {\n      return STR.\"\"\"\n        min = \\{min()}\n        max = \\{max()}\n        count = \\{count()}\n        sum = \\{sum()}\n        \"\"\";\n    }\n\n        public void update(short temperature) {\n            setMin((short) Math.min(min(), temperature));\n            setMax((short) Math.max(max(), temperature));\n            setCount(count() + 1);\n            setSum(sum() + temperature);\n        }\n\n        public boolean updateOnMatch(\n                                     EntryMeta entryMeta, long srcAddr, int len, short hash16, short temperature) {\n\n            // Quick paths\n            if (len() != len) {\n                return false;\n            }\n            if (hash16() != hash16) {\n                return false;\n            }\n\n            // Actual string comparison\n            if (len <= STR_FIELD_LEN) {\n                if (!Unsafely.matches(srcAddr, strAddress(), len)) {\n                    return false;\n                }\n            }\n            else {\n                if (!Unsafely.matches(srcAddr, strAddress(), STR_FIELD_LEN)) {\n                    return false;\n                }\n                if (!Unsafely.matches(\n                        srcAddr + STR_FIELD_LEN,\n                        entryMeta.cityNamesAddress(cityNamesOffset()),\n                        len - STR_FIELD_LEN)) {\n                    return false;\n                }\n            }\n            update(temperature);\n            return true;\n        }\n    }\n\n    /** Metadata for the collection of entries */\n    static class EntryMeta {\n\n        static int toIntFromUnsignedShort(short x) {\n            int ret = x;\n            if (ret < 0) {\n                ret += (1 << 16);\n            }\n            return ret;\n        }\n\n        private final long baseAddress;\n        private final long cityNamesBaseAddress; // For city names that overflow Entry.STR_FIELD_LEN\n        private final int hashMask;\n        private final int n_entries;\n        private final int n_entriesBits;\n        private long cityNamesEndAddress; // [cityNamesBaseAddress, cityNamesEndAddress)\n\n        EntryMeta(int n_entriesBits, EntryMeta oldEntryMeta) {\n            this.n_entries = 1 << n_entriesBits;\n            this.hashMask = (1 << n_entriesBits) - 1;\n            this.n_entriesBits = n_entriesBits;\n            this.baseAddress = Unsafely.allocateZeroedCacheLineAligned(this.n_entries << EntryData.ENTRY_SIZE_BITS);\n            if (oldEntryMeta == null) {\n                this.cityNamesBaseAddress = Unsafely.allocateZeroedCacheLineAligned(1 << 17);\n                this.cityNamesEndAddress = cityNamesBaseAddress;\n            }\n            else {\n                this.cityNamesBaseAddress = oldEntryMeta.cityNamesBaseAddress;\n                this.cityNamesEndAddress = oldEntryMeta.cityNamesEndAddress;\n            }\n        }\n\n        public long cityNamesAddress(int extraLenOffset) {\n            return cityNamesBaseAddress + extraLenOffset;\n        }\n\n        public int indexFromHash16(short hash16) {\n            return indexFromHash32(toIntFromUnsignedShort(hash16));\n        }\n\n        public int nEntriesBits() {\n            return n_entriesBits;\n        }\n\n        // Base Address of nth entry\n        long baseAddress(int n) {\n            return baseAddress + ((long) n << EntryData.ENTRY_SIZE_BITS);\n        }\n\n        // Size of each entry\n        int entrySizeInBytes() {\n            return 1 << EntryData.ENTRY_SIZE_BITS;\n        }\n\n        int getAndIncrementCityNames(int len) {\n            long ret = cityNamesEndAddress;\n            cityNamesEndAddress += ((len + 7) >> 3) << 3; // use aligned 8 bytes\n            return (int) (ret - cityNamesBaseAddress);\n        }\n\n        // Index of an entry with given hash32\n        int indexFromHash32(int hash32) {\n            return hash32 & hashMask;\n        }\n\n        // Number of entries\n        int nEntries() {\n            return n_entries;\n        }\n\n        int nextIndex(int index) {\n            return (index + 1) & hashMask;\n        }\n    }\n\n    static class Hashtable {\n\n        // State\n        int n_filledEntries;\n        // A single Entry to avoid local allocation\n        private EntryData entry;\n        private EntryMeta entryMeta;\n        // Invariants\n        // hash16 = (short) hash32\n        // index = hash16 & hashMask\n        private int hashHits = 0, hashMisses = 0;\n\n        Hashtable(int slotsBits) {\n            entryMeta = new EntryMeta(slotsBits, null);\n            this.entry = new EntryData(entryMeta);\n        }\n\n        public void addDataPoint(long srcAddr, int len, int hash32, short temperature) {\n            // hashHits++;\n            for (int index = entryMeta.indexFromHash32(hash32);; index = entryMeta.nextIndex(index)) {\n                entry.setIndex(index);\n\n                if (!entry.isPresent()) {\n                    entry.init(srcAddr, len, (short) hash32, temperature);\n                    onNewEntry();\n                    return;\n                }\n\n                if (entry.updateOnMatch(entryMeta, srcAddr, len, (short) hash32, temperature)) {\n                    return;\n                }\n                // hashMisses++;\n            }\n        }\n\n    public AggregateResult result() {\n      Map<String, Stat> map = new LinkedHashMap<>(5_000);\n      for (int i = 0; i < entryMeta.nEntries(); i++) {\n        entry.setIndex(i);\n        if (entry.isPresent()) {\n          map.put(entry.cityNameString(), entry.stat());\n        }\n      }\n      System.err.println(\n          STR.\"\"\"\n        HashHits = \\{hashHits}\n        HashMisses = \\{hashMisses} (\\{hashMisses * 100.0 / hashHits})\n        \"\"\");\n      return new AggregateResult(map);\n    }\n\n        private EntryData getNewEntry(EntryData oldEntry, EntryMeta newEntryMeta) {\n            EntryData newEntry = new EntryData(newEntryMeta);\n            for (int index = newEntryMeta.indexFromHash16(oldEntry.hash16());; index = newEntryMeta.nextIndex(index)) {\n                newEntry.setIndex(index);\n                if (!newEntry.isPresent()) {\n                    return newEntry;\n                }\n            }\n        }\n\n        private void onNewEntry() {\n            if (++n_filledEntries == 450) {\n                reHash(16);\n            }\n        }\n\n        private void reHash(int new_N_EntriesBits) {\n            EntryMeta oldEntryMeta = this.entryMeta;\n            EntryData oldEntry = new EntryData(oldEntryMeta);\n            Checks.checkArg(new_N_EntriesBits <= 16);\n            Checks.checkArg(new_N_EntriesBits > oldEntryMeta.nEntriesBits());\n            EntryMeta newEntryMeta = new EntryMeta(new_N_EntriesBits, oldEntryMeta);\n            for (int i = 0; i < oldEntryMeta.nEntries(); i++) {\n                oldEntry.setIndex(i);\n                if (oldEntry.isPresent()) {\n                    Unsafely.copyMemory(\n                            oldEntry.baseAddress(),\n                            getNewEntry(oldEntry, newEntryMeta).baseAddress(),\n                            oldEntryMeta.entrySizeInBytes());\n                }\n            }\n            this.entryMeta = newEntryMeta;\n            this.entry = new EntryData(this.entryMeta);\n        }\n    }\n\n    public interface LazyShardQueue {\n\n        void close(String closerId, int shardIdx);\n\n        Optional<ByteRange> fileTailEndWork(int idx);\n\n        ByteRange take(int shardIdx);\n    }\n\n    static final class Reflection {\n\n        static Method findMethodNamed(Object object, String name, Class... paramTypes) {\n            try {\n                return object.getClass().getMethod(name, paramTypes);\n            }\n            catch (NoSuchMethodException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        static Object invoke(Object receiver, Method method, Object... params) {\n            try {\n                return method.invoke(receiver, params);\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    public static class Runner {\n\n        private final double commonChunkFraction;\n        private final int commonChunkSizeBits;\n        private final boolean fakeAdvance;\n        private final int hashtableSizeBits;\n        private final Path inputFile;\n        private final int minReservedBytesAtFileTail;\n        private final double munmapFraction;\n        private final int nThreads;\n        private final int shardSizeBits;\n\n        public Runner(\n                      Path inputFile,\n                      int nThreads,\n                      int chunkSizeBits,\n                      double commonChunkFraction,\n                      int commonChunkSizeBits,\n                      int hashtableSizeBits,\n                      int minReservedBytesAtFileTail,\n                      double munmapFraction,\n                      boolean fakeAdvance) {\n            this.inputFile = inputFile;\n            this.nThreads = nThreads;\n            this.shardSizeBits = chunkSizeBits;\n            this.commonChunkFraction = commonChunkFraction;\n            this.commonChunkSizeBits = commonChunkSizeBits;\n            this.hashtableSizeBits = hashtableSizeBits;\n            this.minReservedBytesAtFileTail = minReservedBytesAtFileTail;\n            this.munmapFraction = munmapFraction;\n            this.fakeAdvance = fakeAdvance;\n        }\n\n        AggregateResult getSummaryStatistics() throws Exception {\n            int nThreads = this.nThreads < 0 ? Runtime.getRuntime().availableProcessors() : this.nThreads;\n\n            LazyShardQueue shardQueue = new SerialLazyShardQueue(\n                    1L << shardSizeBits,\n                    inputFile,\n                    nThreads,\n                    commonChunkFraction,\n                    commonChunkSizeBits,\n                    minReservedBytesAtFileTail,\n                    munmapFraction,\n                    fakeAdvance);\n\n            ExecutorService executorService = Executors.newFixedThreadPool(\n                    nThreads,\n                    runnable -> {\n                        Thread thread = new Thread(runnable);\n                        thread.setDaemon(true);\n                        return thread;\n                    });\n\n            List<Future<AggregateResult>> results = new ArrayList<>();\n            for (int i = 0; i < nThreads; i++) {\n                final int shardIdx = i;\n                final Callable<AggregateResult> callable = () -> {\n                    Tracing.recordWorkStart(\"Shard\", shardIdx);\n                    AggregateResult result = new ShardProcessor(shardQueue, hashtableSizeBits, shardIdx).processShard();\n                    Tracing.recordWorkEnd(\"Shard\", shardIdx);\n                    return result;\n                };\n                results.add(executorService.submit(callable));\n            }\n            Tracing.recordEvent(\"Basic push time\");\n\n            // This particular sequence of Futures is so that both merge and munmap() can work as shards\n            // finish their computation without blocking on the entire set of shards to complete. In\n            // particular, munmap() doesn't need to wait on merge.\n            // First, submit a task to merge the results and then submit a task to cleanup bytebuffers\n            // from completed shards.\n            Future<AggregateResult> resultFutures = executorService.submit(() -> merge(results));\n            // Note that munmap() is serial and not parallel and hence we use just one thread.\n            executorService.submit(() -> closeByteBuffers(results, shardQueue));\n\n            AggregateResult result = resultFutures.get();\n            Tracing.recordEvent(\"Merge results received\");\n\n            Tracing.recordEvent(\"About to shutdown executor and wait\");\n            executorService.shutdown();\n            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);\n            Tracing.recordEvent(\"Executor terminated\");\n\n            Tracing.analyzeWorkThreads(nThreads);\n            return result;\n        }\n\n        private void closeByteBuffers(\n                                      List<Future<AggregateResult>> results, LazyShardQueue shardQueue) {\n            int n = results.size();\n            boolean[] isDone = new boolean[n];\n            int remaining = results.size();\n            while (remaining > 0) {\n                for (int i = 0; i < n; i++) {\n                    if (!isDone[i] && results.get(i).isDone()) {\n                        remaining--;\n                        isDone[i] = true;\n                        shardQueue.close(\"Ending Cleaner\", i);\n                    }\n                }\n            }\n        }\n\n        private AggregateResult merge(List<Future<AggregateResult>> results)\n                throws ExecutionException, InterruptedException {\n            Tracing.recordEvent(\"Merge start time\");\n            Map<String, Stat> output = null;\n            boolean[] isDone = new boolean[results.size()];\n            int remaining = results.size();\n            // Let's be naughty and spin in a busy loop\n            while (remaining > 0) {\n                for (int i = 0; i < results.size(); i++) {\n                    if (!isDone[i] && results.get(i).isDone()) {\n                        isDone[i] = true;\n                        remaining--;\n                        if (output == null) {\n                            output = new TreeMap<>(results.get(i).get().tempStats());\n                        }\n                        else {\n                            for (Entry<String, Stat> entry : results.get(i).get().tempStats().entrySet()) {\n                                output.compute(\n                                        entry.getKey(),\n                                        (key, value) -> value == null ? entry.getValue() : Stat.merge(value, entry.getValue()));\n                            }\n                        }\n                    }\n                }\n            }\n            Tracing.recordEvent(\"Merge end time\");\n            return new AggregateResult(output);\n        }\n    }\n\n    public static class SerialLazyShardQueue implements LazyShardQueue {\n\n        private static long roundToNearestLowerMultipleOf(long divisor, long value) {\n            return value / divisor * divisor;\n        }\n\n        private final ByteRange[] byteRanges;\n        private final long chunkSize;\n        private final long commonChunkSize;\n        private final AtomicLong commonPool;\n        private final long effectiveFileSize;\n        private final boolean fakeAdvance;\n        private final long fileSize;\n        private final long[] perThreadData;\n        private final RandomAccessFile raf;\n        private final SeqLock seqLock;\n\n        public SerialLazyShardQueue(\n                                    long chunkSize,\n                                    Path filePath,\n                                    int shards,\n                                    double commonChunkFraction,\n                                    int commonChunkSizeBits,\n                                    int fileTailReservedBytes,\n                                    double munmapFraction,\n                                    boolean fakeAdvance)\n                throws IOException {\n            this.fakeAdvance = fakeAdvance;\n            Checks.checkArg(commonChunkFraction < 0.9 && commonChunkFraction >= 0);\n            Checks.checkArg(fileTailReservedBytes >= 0);\n            this.raf = new RandomAccessFile(filePath.toFile(), \"r\");\n            this.fileSize = raf.length();\n            fileTailReservedBytes = fileTailReservedBytes == 0\n                    ? 0\n                    : consumeToPreviousNewLineExclusive(raf, fileTailReservedBytes);\n            this.effectiveFileSize = fileSize - fileTailReservedBytes;\n\n            // Common pool\n            long commonPoolStart = Math.min(\n                    roundToNearestLowerMultipleOf(\n                            chunkSize, (long) (effectiveFileSize * (1 - commonChunkFraction))),\n                    effectiveFileSize);\n            this.commonPool = new AtomicLong(commonPoolStart);\n            this.commonChunkSize = 1L << commonChunkSizeBits;\n\n            // Distribute chunks to shards\n            this.perThreadData = new long[shards << 4]; // thread idx -> 16*idx to avoid cache line conflict\n            for (long i = 0,\n                    currentStart = 0,\n                    remainingChunks = (commonPoolStart + chunkSize - 1) / chunkSize; i < shards; i++) {\n                long remainingShards = shards - i;\n                long currentChunks = (remainingChunks + remainingShards - 1) / remainingShards;\n                // Shard i handles: [currentStart, currentStart + currentChunks * chunkSize)\n                int pos = (int) i << 4;\n                perThreadData[pos] = currentStart; // next chunk begin\n                perThreadData[pos + 1] = currentStart + currentChunks * chunkSize; // shard end\n                perThreadData[pos + 2] = currentChunks; // active chunks remaining\n                // threshold below which need to shrink\n                // 0.03 is a practical number but the optimal strategy is this:\n                // Shard number N (1-based) should unmap as soon as it completes (R/(R+1))^N fraction of\n                // its work, where R = relative speed of unmap compared to the computation.\n                // For our problem, R ~ 75 because unmap unmaps 30GB/sec (but, it is serial) while\n                // cores go through data at the rate of 400MB/sec.\n                perThreadData[pos + 3] = (long) (currentChunks * (munmapFraction * (shards - i)));\n                perThreadData[pos + 4] = 1; // true iff munmap() hasn't been triggered yet\n                currentStart += currentChunks * chunkSize;\n                remainingChunks -= currentChunks;\n            }\n            this.chunkSize = chunkSize;\n\n            this.byteRanges = new ByteRange[shards << 4];\n            for (int i = 0; i < shards; i++) {\n                byteRanges[i << 4] = new ByteRange(raf, effectiveFileSize, i);\n            }\n\n            this.seqLock = new SeqLock();\n        }\n\n        @Override\n        public void close(String closerId, int shardIdx) {\n            byteRanges[shardIdx << 4].close(closerId);\n        }\n\n        @Override\n        public Optional<ByteRange> fileTailEndWork(int idx) {\n            if (idx == 0 && effectiveFileSize < fileSize) {\n                ByteRange chunk = new ByteRange(raf, fileSize, 0);\n                chunk.setRange(\n                        effectiveFileSize == 0 ? 0 : effectiveFileSize - 1 /* will consume newline at eFS-1 */,\n                        fileSize);\n                return Optional.of(chunk);\n            }\n            return Optional.empty();\n        }\n\n        @Override\n        public ByteRange take(int shardIdx) {\n            // Try for thread local range\n            final int pos = shardIdx << 4;\n            final long rangeStart;\n            final long rangeEnd;\n\n            if (perThreadData[pos + 2] >= 1) {\n                rangeStart = perThreadData[pos];\n                rangeEnd = rangeStart + chunkSize;\n                // Don't do this in the if-check; it causes negative values that trigger intermediate\n                // cleanup\n                perThreadData[pos + 2]--;\n                if (!fakeAdvance) {\n                    perThreadData[pos] = rangeEnd;\n                }\n            }\n            else {\n                rangeStart = commonPool.getAndAdd(commonChunkSize);\n                // If that's exhausted too, nothing remains!\n                if (rangeStart >= effectiveFileSize) {\n                    return null;\n                }\n                rangeEnd = rangeStart + commonChunkSize;\n            }\n\n            if (perThreadData[pos + 2] < perThreadData[pos + 3] && perThreadData[pos + 4] > 0) {\n                if (attemptIntermediateClose(shardIdx)) {\n                    perThreadData[pos + 4]--;\n                }\n            }\n\n            ByteRange chunk = byteRanges[pos];\n            chunk.setRange(rangeStart, rangeEnd);\n            return chunk;\n        }\n\n        private boolean attemptIntermediateClose(int shardIdx) {\n            if (seqLock.acquire()) {\n                close(\"Intermediate Cleaner\", shardIdx);\n                seqLock.release();\n                return true;\n            }\n            return false;\n        }\n\n        private int consumeToPreviousNewLineExclusive(RandomAccessFile raf, int minReservedBytes) {\n            try {\n                long pos = Math.max(raf.length() - minReservedBytes - 1, -1);\n                if (pos < 0) {\n                    return (int) raf.length();\n                }\n\n                long start = Math.max(pos - 512, 0);\n                ByteBuffer buf = raf.getChannel().map(MapMode.READ_ONLY, start, pos + 1 - start);\n                while (pos >= 0 && buf.get((int) (pos - start)) != '\\n') {\n                    pos--;\n                }\n                pos++;\n                return (int) (raf.length() - pos);\n            }\n            catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    /** A low-traffic non-blocking lock. */\n    static class SeqLock {\n\n        private final AtomicBoolean isOccupied = new AtomicBoolean(false);\n\n        boolean acquire() {\n            return !isOccupied.get() && isOccupied.compareAndSet(false, true);\n        }\n\n        void release() {\n            isOccupied.set(false);\n        }\n    }\n\n    public static class ShardProcessor {\n\n        private final int shardIdx;\n        private final LazyShardQueue shardQueue;\n        private final FastShardProcessorState state;\n\n        public ShardProcessor(LazyShardQueue shardQueue, int hashtableSizeBits, int shardIdx) {\n            this.shardQueue = shardQueue;\n            this.shardIdx = shardIdx;\n            this.state = new FastShardProcessorState(hashtableSizeBits);\n        }\n\n        public AggregateResult processShard() {\n            return processShardReal();\n        }\n\n        private void processRange(ByteRange range) {\n            long nextPos = range.startAddress;\n            while (nextPos < range.endAddress) {\n                nextPos = state.processLine(nextPos);\n            }\n        }\n\n        private void processRangeSlow(ByteRange range) {\n            long nextPos = range.startAddress;\n            while (nextPos < range.endAddress) {\n                nextPos = state.processLineSlow(nextPos);\n            }\n        }\n\n        private AggregateResult processShardReal() {\n            // First process the file tail work to give ourselves freedom to go past ranges in parsing\n            shardQueue.fileTailEndWork(shardIdx).ifPresent(this::processRangeSlow);\n\n            ByteRange range;\n            while ((range = shardQueue.take(shardIdx)) != null) {\n                processRange(range);\n            }\n            return result();\n        }\n\n        private AggregateResult result() {\n            return state.result();\n        }\n    }\n\n    public static class FastShardProcessorState {\n\n        private static final long LEADING_ONE_BIT_MASK = 0x8080808080808080L;\n        private static final long ONE_MASK = 0x0101010101010101L;\n        private static final long SEMICOLON_MASK = 0x3b3b3b3b3b3b3b3bL;\n        private final Hashtable hashtable;\n        private final Map<String, Stat> slowProcessStats = new HashMap<>();\n\n        public FastShardProcessorState(int slotsBits) {\n            this.hashtable = new Hashtable(slotsBits);\n            Checks.checkArg(slotsBits <= 16); // since this.hashes is 'short'\n        }\n\n        public long processLine(long nextPos) {\n            final long origPos = nextPos;\n\n            // Trying to extract this into a function made it slower.. so, leaving it at inlining.\n            // It's a pity since the extracted version was more elegant to read\n            long firstLong;\n            int hash = 0;\n            // Don't run Long.numberOfTrailingZeros in hasSemiColon; it is not needed to establish\n            // whether there's a semicolon; only needed for pin-pointing length of the tail.\n            long s = hasSemicolon(firstLong = Unsafely.readLong(nextPos));\n            final int trailingZeroes;\n            if (s == 0) {\n                hash = doHash(firstLong);\n                do {\n                    nextPos += 8;\n                    s = hasSemicolon(Unsafely.readLong(nextPos));\n                } while (s == 0);\n                trailingZeroes = Long.numberOfTrailingZeros(s) + 1; // 8, 16, 24, .. # past ;\n            }\n            else {\n                trailingZeroes = Long.numberOfTrailingZeros(s) + 1; // 8, 16, 24, .. # past ;\n                hash = doHash(firstLong & maskOf(trailingZeroes - 8));\n            }\n            // Sometimes we do mix a tail of length 0..\n            nextPos += (trailingZeroes >> 3);\n\n            final int temp = readTemperature(nextPos);\n            hashtable.addDataPoint(origPos, (int) (nextPos - 1 - origPos), hash, (short) (temp >> 3));\n            return nextPos + (temp & 7);\n        }\n\n        /**\n         * A slow version which is used only for the tail part of the file. Maintaining hashcode sync\n         * between this and the fast version is a pain for experimentation. So, we'll simply use a naive\n         * approach.\n         */\n        public long processLineSlow(long nextPos) {\n            byte nextByte;\n            ByteArrayOutputStream baos = new ByteArrayOutputStream();\n            while ((nextByte = Unsafely.readByte(nextPos++)) != ';') {\n                baos.write(nextByte);\n            }\n\n            int temperature = 0;\n            boolean negative = Unsafely.readByte(nextPos) == '-';\n            while ((nextByte = Unsafely.readByte(nextPos++)) != '\\n') {\n                if (nextByte != '-' && nextByte != '.') {\n                    temperature = temperature * 10 + (nextByte - '0');\n                }\n            }\n            if (negative) {\n                temperature = -temperature;\n            }\n\n            updateStat(slowProcessStats, baos.toString(), Stat.firstReading(temperature));\n            return nextPos;\n        }\n\n        public AggregateResult result() {\n            AggregateResult result = hashtable.result();\n            if (!slowProcessStats.isEmpty()) {\n                // bah.. just mutate the arg of the record...\n                for (Entry<String, Stat> entry : slowProcessStats.entrySet()) {\n                    updateStat(result.tempStats(), entry.getKey(), entry.getValue());\n                }\n            }\n            return result;\n        }\n\n        int readTemperature(long nextPos) {\n            // This Dependency chain\n            // read -> shift -> xor -> compare -> 2 in parallel [ shift -> read ] -> add -> shift\n            // Chain latency: 2 reads + 2 add + 4 logical [assuming compare = add]\n            // vs\n            // Prior Dependency chain (slightly optimized by hand)\n            // read -> compare to '-' -> read -> compare to '.' -> 3 in parallel [read -> imul] -> add\n            // Chain latency: 3 reads + 3 add + 1 mul [assuming compare = add]\n            long data = Unsafely.readLong(nextPos);\n            long d = data ^ (data >> 4);\n            if ((data & 0xFF) == '-') {\n                return TemperatureLookup.firstNeg(d >> 8) + TemperatureLookup.secondNeg(d >> 24);\n            }\n            else {\n                return TemperatureLookup.firstPos(d >> 0) + TemperatureLookup.secondPos(d >> 16);\n            }\n        }\n\n        private int doHash(long value) {\n            long hash = 31L * (int) value + (int) (value >> 32);\n            return (int) (hash ^ (hash >> 17) ^ (hash >> 28));\n        }\n\n        private long hasSemicolon(long x) {\n            long a = (x ^ SEMICOLON_MASK);\n            return (a - ONE_MASK) & (~a) & LEADING_ONE_BIT_MASK;\n        }\n\n        private long maskOf(int bits) {\n            return ~(-1L << bits);\n        }\n\n        private void updateStat(Map<String, Stat> map, String key, Stat curValue) {\n            map.compute(key, (_, value) -> value == null ? curValue : Stat.merge(value, curValue));\n        }\n    }\n\n    /** Represents aggregate stats. */\n    public static class Stat {\n\n        public static Stat firstReading(int temp) {\n            return new Stat(temp, temp, temp, 1);\n        }\n\n        public static Stat merge(Stat left, Stat right) {\n            return new Stat(\n                    Math.min(left.min, right.min),\n                    Math.max(left.max, right.max),\n                    left.sum + right.sum,\n                    left.count + right.count);\n        }\n\n        long count, sum;\n        int min, max;\n\n        public Stat(int min, int max, long sum, long count) {\n            this.min = min;\n            this.max = max;\n            this.sum = sum;\n            this.count = count;\n        }\n\n        // Caution: Mutates\n        public Stat mergeReading(int curTemp) {\n            // Can this be improved furhter?\n            // Assuming random values for curTemp,\n            // min (&max) gets updated roughly log(N)/N fraction of the time (a small number)\n            // In the worst case, there will be at-most one branch misprediction.\n            if (curTemp > min) { // Mostly passes. On branch misprediction, just update min.\n                if (curTemp > max) { // Mostly fails. On branch misprediction, just update max.\n                    max = curTemp;\n                }\n            }\n            else {\n                min = curTemp;\n            }\n            sum += curTemp;\n            count++;\n            return this;\n        }\n\n        @Override\n        public String toString() {\n            return \"%.1f/%.1f/%.1f\".formatted(min / 10.0, sum / 10.0 / count, max / 10.0);\n        }\n    }\n\n    /**\n     * Lookup table for temperature parsing.\n     *\n     * <pre>\n     * 0       0011-0000\n     * 9       0011-1001\n     * .       0010-1110\n     * \\n      0000-1010\n     *\n     * Notice that there's no overlap in the last 4 bits. This means, if we are given two successive\n     * bytes X, Y all of which belong to the above characters, we can REVERSIBLY hash it to\n     * a single byte by doing 8-bit-hash = (last 4 bits of X) concat (last 4 bits of Y).\n     *\n     * Such a hash requires a few more operations than ideal. A more practical hash is:\n     * (X>>4) ^ Y ^ (Y >> 4). This means if you read 4 bytes after the '-',\n     * L = X Y Z W, where each of X Y Z W is a byte, then,\n     * L ^ (L >> 4) = D hash(X, Y) hash(Y, Z) hash(Z, W) where D = don't care. In other words, we\n     * can SWAR the hash.\n     *\n     * This has potential for minor conflicts; for e.g. (3, NewLine) collides with (0, 9). But, we\n     * don't have any collisions between two digits. That is (x, y) will never collide with (a, b)\n     * where x, y, a, b are digits (proof left as an exercise, lol). Along with a couple of other\n     * such no-conflict observations, it suffices for our purposes.\n     *\n     * If we just precompute some values like\n     * - BigTable[hash(X,Y)] = 100*X + 10*Y\n     * - SmallTable[hash(Z,W)] = 10*Z + W\n     *\n     * where potentially X, Y, Z, W can be '.' or '\\n', (and the arithmetic adjusted), we can lookup\n     * the temperature pieces from BigTable and SmallTable and add them together.\n     * </pre>\n     *\n     * <p>This class is an implementation of the above idea. The lookup tables being 256 ints long\n     * will always be resident in L1 cache. What remains then is to also add the information on how\n     * much input is to be consumed; i.e. count the - and newlines too. That can be piggy backed on\n     * top of the values.\n     *\n     * <p>FWIW, this lookup appears to have reduced the temperature reading overhead substantially on\n     * a Ryzen 7950X machine. But, it wasn't done systematically; so, YMMV.\n     */\n    public static class TemperatureLookup {\n\n        // Second is the smaller (units place)\n        // First is the larger (100 & 10)\n\n        // _NEG tables simply negate the value so that call-site can always simply add the values from\n        // the first and second units. Call-sites adding-up First and Second units adds up the\n        // amount of input to consume.\n\n        // Here, 2 is the amount of bytes consumed. This informs how much the reading pointer\n        // should move.\n        // For pattern XY value = ((-100*X -10*Y) << 3) + 2 [2 = 1 for X, 1 for Y]\n        // For pattern Y. value = ((-10*Y) << 3) + 2 [2 = 1 for Y, 1 for .]\n        private static final int[] FIRST_NEG = make(true, true);\n\n        // For pattern XY value = ((100*X + 10*Y) << 3) + 2\n        // For pattern Y. value = ((10*Y) << 3) + 2\n        private static final int[] FIRST_POS = make(true, false);\n\n        // We count newline and any initial '-' as part of SECOND\n        // For pattern .Z value = (-Z << 3) + 2 + 2 [1 each for . and Z, 1 for newline, 1 for minus]\n        // For pattern Zn value = (-Z << 3) + 1 + 2 [1 for Z, 1 for newline, 1 for minus]\n        private static final int[] SECOND_NEG = make(false, true);\n\n        // For pattern .Z value = (Z << 3) + 2 + 1 [1 each for . and Z, 1 for newline]\n        // For pattern Zn value = (Z << 3) + 1 + 1 [1 for Z, 1 for newline]\n        private static final int[] SECOND_POS = make(false, false);\n\n        public static int firstNeg(long b) {\n            return FIRST_NEG[(int) (b & 255)];\n        }\n\n        public static int firstPos(long b) {\n            return FIRST_POS[(int) (b & 255)];\n        }\n\n        public static int secondNeg(long b) {\n            return SECOND_NEG[(int) (b & 255)];\n        }\n\n        public static int secondPos(long b) {\n            return SECOND_POS[(int) (b & 255)];\n        }\n\n        private static byte[] allDigits() {\n            byte[] out = new byte[10];\n            for (byte a = '0'; a <= '9'; a++) {\n                out[a - '0'] = a;\n            }\n            return out;\n        }\n\n        private static int hash(byte msb, byte lsb) {\n            // If K = [D msb lsb], then (K ^ (K>>4)) & 255 == hash(msb, lsb). D = don't care\n            return (msb << 4) ^ lsb ^ (lsb >> 4);\n        }\n\n        private static int[] make(boolean isFirst, boolean isNegative) {\n            int[] ret = new int[256];\n            boolean[] done = new boolean[256];\n\n            // Conventions: X = 100s place, Y = 10s place, Z = 1s place, n = new line\n\n            // All the cases to handle\n            // X Y . Z\n            // Y . Z n\n\n            // In little-endian order it becomes (byte-wise), shown in place value notation\n            // Z . Y X\n            // n Z . Y\n            // First = YX or .Y\n            // Second = Z. or nZ\n\n            // Pattern 'YX'\n            for (byte x : allDigits()) {\n                for (byte y : allDigits()) {\n                    int index = hash(y, x);\n                    // Shouldn't occur in Second\n                    int value = isFirst ? (y - '0') * 10 + (x - '0') * 100 : 12345;\n                    int delta = isFirst ? 2 : 12345;\n                    update(index, isNegative ? -value : value, delta, ret, done);\n                }\n            }\n\n            // Pattern 'Z.'\n            for (byte z : allDigits()) {\n                int index = hash(z, (byte) '.');\n                // shouldn't occur in First\n                int value = isFirst ? 12345 : (z - '0');\n                int delta = isFirst ? 12345 : 2;\n                update(index, isNegative ? -value : value, delta, ret, done);\n            }\n\n            // Pattern '.Y'\n            for (byte y : allDigits()) {\n                int index = hash((byte) '.', y);\n                // Shouldn't occur in Second\n                int value = isFirst ? 10 * (y - '0') : 12345;\n                int delta = isFirst ? 2 : 12345;\n                update(index, isNegative ? -value : value, delta, ret, done);\n            }\n\n            // Pattern 'nZ'\n            for (byte z : allDigits()) {\n                int index = hash((byte) '\\n', z);\n                // shouldn't occur in First\n                int value = isFirst ? 12345 : (z - '0');\n                int delta = isFirst ? 12345 : 1;\n                update(index, isNegative ? -value : value, delta, ret, done);\n            }\n\n            if (!isFirst) {\n                // Adjust the deltas to reflect how much input needs to be consumed\n                // need to consume the newline and any - sign in front\n                for (int i = 0; i < ret.length; i++) {\n                    ret[i] += (isNegative ? 1 : 0) /* for - sign */ + 1 /* for new line */;\n                }\n            }\n            return ret;\n        }\n\n        private static void update(int index, int value, int delta, int[] ret, boolean[] done) {\n            index &= 255;\n            Checks.checkArg(!done[index]); // just a sanity check that our hashing is indeed reversible\n            ret[index] = (value << 3) | delta;\n            done[index] = true;\n        }\n    }\n\n    static class Tracing {\n\n        private static final Map<String, ThreadTimingsArray> knownWorkThreadEvents;\n        private static long startTime;\n\n        static {\n            // Maintain the ordering to be chronological in execution\n            // Map.of(..) screws up ordering\n            knownWorkThreadEvents = new LinkedHashMap<>();\n            for (String id : List.of(\"Shard\", \"Intermediate Cleaner\", \"Ending Cleaner\", \"Buffer Creation\")) {\n                knownWorkThreadEvents.put(id, new ThreadTimingsArray(id, 1 << 10));\n            }\n        }\n\n        static void analyzeWorkThreads(int nThreads) {\n            for (ThreadTimingsArray array : knownWorkThreadEvents.values()) {\n                errPrint(array.analyze(nThreads));\n            }\n        }\n\n        static void recordAppStart() {\n            startTime = System.nanoTime();\n            printEvent(\"Start time\", startTime);\n        }\n\n        static void recordEvent(String event) {\n            printEvent(event, System.nanoTime());\n        }\n\n        static void recordWorkEnd(String id, int threadId) {\n            knownWorkThreadEvents.get(id).recordEnd(threadId);\n        }\n\n        static void recordWorkStart(String id, int threadId) {\n            knownWorkThreadEvents.get(id).recordStart(threadId);\n        }\n\n        /////////////////////////////////////////////////////////////////////////////////////////////////\n\n        private static void errPrint(String message) {\n            System.err.println(message);\n        }\n\n    private static void printEvent(String message, long nanoTime) {\n      errPrint(STR.\"\\{message} = \\{(nanoTime - startTime) / 1_000_000}ms\");\n    }\n\n        public static class ThreadTimingsArray {\n\n            private static String toString(long[] array) {\n                return Arrays.stream(array)\n                        .map(x -> x < 0 ? -1 : x)\n                        .mapToObj(x -> String.format(\"%6d\", x))\n                        .collect(Collectors.joining(\", \", \"[ \", \" ]\"));\n            }\n\n            private final String id;\n            private final long[] timestamps;\n            private boolean hasData = false;\n\n            public ThreadTimingsArray(String id, int maxSize) {\n                this.timestamps = new long[maxSize];\n                this.id = id;\n            }\n\n      public String analyze(int nThreads) {\n        if (!hasData) {\n          return \"%s has no thread timings data\".formatted(id);\n        }\n        Checks.checkArg(nThreads <= timestamps.length);\n        long minDuration = Long.MAX_VALUE, maxDuration = Long.MIN_VALUE;\n        long minBegin = Long.MAX_VALUE, maxCompletion = Long.MIN_VALUE;\n        long maxBegin = Long.MIN_VALUE, minCompletion = Long.MAX_VALUE;\n\n        long[] durationsMs = new long[nThreads];\n        long[] completionsMs = new long[nThreads];\n        long[] beginMs = new long[nThreads];\n        for (int i = 0; i < nThreads; i++) {\n          long durationNs = timestamps[2 * i + 1] - timestamps[2 * i];\n          durationsMs[i] = durationNs / 1_000_000;\n          completionsMs[i] = (timestamps[2 * i + 1] - startTime) / 1_000_000;\n          beginMs[i] = (timestamps[2 * i] - startTime) / 1_000_000;\n\n          minDuration = Math.min(minDuration, durationNs);\n          maxDuration = Math.max(maxDuration, durationNs);\n\n          minBegin = Math.min(minBegin, timestamps[2 * i] - startTime);\n          maxBegin = Math.max(maxBegin, timestamps[2 * i] - startTime);\n\n          maxCompletion = Math.max(maxCompletion, timestamps[2 * i + 1] - startTime);\n          minCompletion = Math.min(minCompletion, timestamps[2 * i + 1] - startTime);\n        }\n        return STR.\"\"\"\n        -------------------------------------------------------------------------------------------\n                                       \\{id} Stats\n        -------------------------------------------------------------------------------------------\n        Max duration                              = \\{maxDuration / 1_000_000} ms\n        Min duration                              = \\{minDuration / 1_000_000} ms\n        Timespan[max(end)-min(start)]             = \\{(maxCompletion - minBegin) / 1_000_000} ms [\\{maxCompletion / 1_000_000} - \\{minBegin / 1_000_000} ]\n        Completion Timespan[max(end)-min(end)]    = \\{(maxCompletion - minCompletion) / 1_000_000} ms\n        Begin Timespan[max(begin)-min(begin)]     = \\{(maxBegin - minBegin) / 1_000_000} ms\n        Average Duration                          = \\{Arrays.stream(durationsMs)\n                                                            .average()\n                                                            .getAsDouble()} ms\n        Durations                                 = \\{toString(durationsMs)} ms\n        Begin Timestamps                          = \\{toString(beginMs)} ms\n        Completion Timestamps                     = \\{toString(completionsMs)} ms\n        \"\"\";\n      }\n\n            public void recordEnd(int idx) {\n                timestamps[2 * idx + 1] = System.nanoTime();\n                hasData = true;\n            }\n\n            public void recordStart(int idx) {\n                timestamps[2 * idx] = System.nanoTime();\n                hasData = true;\n            }\n        }\n    }\n\n    static class Unsafely {\n\n        private static final Unsafe unsafe = getUnsafe();\n\n        public static long allocateZeroedCacheLineAligned(int size) {\n            long address = unsafe.allocateMemory(size + 63);\n            unsafe.setMemory(address, size + 63, (byte) 0);\n            return (address + 63) & ~63;\n        }\n\n        public static void copyMemory(long srcAddress, long destAddress, long byteCount) {\n            unsafe.copyMemory(srcAddress, destAddress, byteCount);\n        }\n\n        public static boolean matches(long srcAddr, long destAddress, int len) {\n            if (len < 8) {\n                return (readLong(srcAddr) & ~(-1L << (len << 3))) == (readLong(destAddress) & ~(-1L << (len << 3)));\n            }\n            if (readLong(srcAddr) != readLong(destAddress)) {\n                return false;\n            }\n            len -= 8;\n\n            if (len < 8) {\n                return (readLong(srcAddr + 8) & ~(-1L << (len << 3))) == (readLong(destAddress + 8) & ~(-1L << (len << 3)));\n            }\n            if (readLong(srcAddr + 8) != readLong(destAddress + 8)) {\n                return false;\n            }\n            len -= 8;\n            srcAddr += 16;\n            destAddress += 16;\n\n            int idx = 0;\n            for (; idx < (len & ~7); idx += 8) {\n                if (Unsafely.readLong(srcAddr + idx) != Unsafely.readLong(destAddress + idx)) {\n                    return false;\n                }\n            }\n\n            if (idx < (len & ~3)) {\n                if (Unsafely.readInt(srcAddr + idx) != Unsafely.readInt(destAddress + idx)) {\n                    return false;\n                }\n                idx += 4;\n            }\n\n            if (idx < (len & ~1)) {\n                if (Unsafely.readShort(srcAddr + idx) != Unsafely.readShort(destAddress + idx)) {\n                    return false;\n                }\n                idx += 2;\n            }\n\n            return idx >= len || Unsafely.readByte(srcAddr + idx) == Unsafely.readByte(destAddress + idx);\n        }\n\n        public static byte readByte(long address) {\n            return unsafe.getByte(address);\n        }\n\n        public static int readInt(long address) {\n            return unsafe.getInt(address);\n        }\n\n        public static long readLong(long address) {\n            return unsafe.getLong(address);\n        }\n\n        public static short readShort(long address) {\n            return unsafe.getShort(address);\n        }\n\n        public static void setByte(long address, byte len) {\n            unsafe.putByte(address, len);\n        }\n\n        public static void setInt(long address, int value) {\n            unsafe.putInt(address, value);\n        }\n\n        public static void setShort(long address, short len) {\n            unsafe.putShort(address, len);\n        }\n\n        private static Unsafe getUnsafe() {\n            try {\n                Field unsafeField = Unsafe.class.getDeclaredField(\"theUnsafe\");\n                unsafeField.setAccessible(true);\n                return (Unsafe) unsafeField.get(null);\n            }\n            catch (NoSuchFieldException | IllegalAccessException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_xpmatteo.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.TreeMap;\nimport java.util.stream.Collectors;\n\n@SuppressWarnings({ \"ReassignedVariable\", \"StatementWithEmptyBody\" })\npublic class CalculateAverage_xpmatteo {\n\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        var fileName = dataFileName(args);\n\n        try (\n                var file = new RandomAccessFile(new File(fileName), \"r\");\n                var channel = file.getChannel()) {\n            var numCpus = Runtime.getRuntime().availableProcessors();\n            var threads = split(channel, numCpus).stream()\n                    .map(Worker::new)\n                    .toList();\n            threads.forEach(Thread::start);\n            for (Worker thread : threads) {\n                thread.join();\n            }\n            var results = threads.stream().map(Worker::getResults)\n                    .reduce(CalculateAverage_xpmatteo::merge)\n                    .orElseThrow();\n            printCities(results);\n        }\n    }\n\n    public static class Worker extends Thread {\n        private final ByteBuffer buffer;\n        private Results results;\n\n        public Worker(ByteBuffer buffer) {\n            this.buffer = buffer;\n        }\n\n        @Override\n        public void run() {\n            this.results = parseData(this.buffer);\n        }\n\n        public Results getResults() {\n            return results;\n        }\n    }\n\n    protected static List<ByteBuffer> split(FileChannel channel, int numCpus) throws IOException {\n        if (channel.size() < 10_000) {\n            return List.of(channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()));\n        }\n\n        long[] increments = new long[numCpus + 1];\n        for (int i = 0; i < numCpus; i++) {\n            increments[i] = i * channel.size() / numCpus;\n            // adjust the increments so that they start on the beginning of a city\n            while (increments[i] > 0 && byteAt(channel, increments[i] - 1) != '\\n') {\n                increments[i]--;\n            }\n        }\n        increments[numCpus] = channel.size();\n\n        List<ByteBuffer> result = new ArrayList<>(numCpus);\n        for (int i = 0; i < numCpus; i++) {\n            long from = increments[i];\n            long to = increments[i + 1];\n            result.add(channel.map(FileChannel.MapMode.READ_ONLY, from, to - from));\n        }\n        return result;\n    }\n\n    private static byte byteAt(FileChannel channel, long offset) throws IOException {\n        ByteBuffer buf = ByteBuffer.allocate(1);\n        channel.position(offset);\n        channel.read(buf);\n        buf.flip();\n        var bytes = new byte[1];\n        buf.get(bytes);\n        return bytes[0];\n    }\n\n    public static String dataFileName(String[] args) {\n        if (args.length == 1) {\n            return args[0];\n        }\n        return FILE;\n    }\n\n    protected static byte[] readAllData(String fileName) throws IOException {\n        return Files.readAllBytes(Path.of(fileName));\n    }\n\n    protected static ByteBuffer memoryMap(String fileName) throws IOException {\n        try (RandomAccessFile file = new RandomAccessFile(new File(fileName), \"r\")) {\n            // Get file channel in read-only mode\n            FileChannel fileChannel = file.getChannel();\n\n            return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());\n        }\n    }\n\n    protected enum State {\n        PARSING_CITY_NAME,\n        SKIPPING_SEMICOLON,\n        PARSING_TEMPERATURE\n    }\n\n    protected static Results parseData(ByteBuffer data) {\n        var results = new Results();\n        var state = State.PARSING_CITY_NAME;\n        int cityStartOffset = 0, cityEndOffset = 0;\n        int temp = 0, sign = 0;\n\n        for (int i = 0; i < data.limit(); i++) {\n            byte currentChar = data.get();\n            if (state == State.PARSING_CITY_NAME && currentChar == ';') {\n                state = State.SKIPPING_SEMICOLON;\n                cityEndOffset = i;\n            }\n            else if (state == State.PARSING_CITY_NAME) {\n                // do nothing\n            }\n            else if (state == State.SKIPPING_SEMICOLON && currentChar == '-') {\n                state = State.PARSING_TEMPERATURE;\n                temp = 0;\n                sign = -1;\n            }\n            else if (state == State.SKIPPING_SEMICOLON && currentChar >= '0' && currentChar <= '9') {\n                state = State.PARSING_TEMPERATURE;\n                temp = currentChar - '0';\n                sign = 1;\n            }\n            else if (state == State.PARSING_TEMPERATURE && currentChar >= '0' && currentChar <= '9') {\n                temp = temp * 10 + currentChar - '0';\n            }\n            else if (state == State.PARSING_TEMPERATURE && currentChar == '.') {\n                // do nothing\n            }\n            else if (state == State.PARSING_TEMPERATURE && currentChar == '\\n') {\n                byte[] bytes = new byte[cityEndOffset - cityStartOffset];\n                data.get(cityStartOffset, bytes);\n                var cityName = new String(bytes);\n                accumulate(results, cityName, temp * sign);\n                state = State.PARSING_CITY_NAME;\n                cityStartOffset = i + 1;\n            }\n        }\n\n        return results;\n    }\n\n    private static void accumulate(Results results, String cityName, int tempTimesTen) {\n        var existing = results.get(cityName);\n        if (existing == null) {\n            results.put(cityName, new CityData(tempTimesTen, tempTimesTen, tempTimesTen, 1));\n        }\n        else {\n            existing.min = Math.min(existing.min, tempTimesTen);\n            existing.sum = existing.sum + tempTimesTen;\n            existing.max = Math.max(existing.max, tempTimesTen);\n            existing.count++;\n        }\n    }\n\n    protected static Results merge(Results a, Results b) {\n        for (var entry : b.entrySet()) {\n            CityData valueInA = a.get(entry.getKey());\n            if (null == valueInA) {\n                a.put(entry.getKey(), entry.getValue());\n            }\n            else {\n                var valueInB = entry.getValue();\n                valueInA.min = Math.min(valueInA.min, valueInB.min);\n                valueInA.sum += valueInB.sum;\n                valueInA.max = Math.max(valueInA.max, valueInB.max);\n                valueInA.count += valueInB.count;\n            }\n        }\n\n        return a;\n    }\n\n    protected static class Results extends TreeMap<String, CityData> {\n\n    }\n\n    protected static class CityData {\n        int min, sum, max, count;\n\n        public CityData(int min, int sum, int max, int count) {\n            this.min = min;\n            this.sum = sum;\n            this.max = max;\n            this.count = count;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n            CityData cityData = (CityData) o;\n            return min == cityData.min && sum == cityData.sum && max == cityData.max && count == cityData.count;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(min, sum, max, count);\n        }\n\n        @Override\n        public String toString() {\n            return STR.\"CityData{min=\\{min}, sum=\\{sum}, max=\\{max}, count=\\{count}\\{'}'}\";\n        }\n    }\n\n    protected static void printCities(Results cities) {\n        System.out.print(\"{\");\n        for (String city : cities.keySet()) {\n            CityData data = cities.get(city);\n            var min = data.min / 10.0;\n            var mean = (data.sum * 10.0 / data.count) / 100.0;\n            var max = data.max / 10.0;\n            System.out.printf(\n                    \"%s=%.1f/%.1f/%.1f, \",\n                    city,\n                    min,\n                    mean,\n                    max);\n        }\n        System.out.print(\"}\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_yavuztas.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.function.Consumer;\n\npublic class CalculateAverage_yavuztas {\n\n    private static final Path FILE = Path.of(\"./measurements.txt\");\n\n    private static final Unsafe UNSAFE = unsafe();\n\n    // I compared all three: MappedByteBuffer, MemorySegment and Unsafe.\n    // Accessing the memory using Unsafe is still the fastest in my experience.\n    // However, I would never use it in production, single programming error will crash your app.\n    private static Unsafe unsafe() {\n        try {\n            final Field f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            return (Unsafe) f.get(null);\n        }\n        catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    /**\n     * Extract bytes from a long\n     */\n    private static long partial(long word, int length) {\n        final long mask = (~0L) << (length << 3);\n        return word & (~mask);\n    }\n\n    // Only one object, both for measurements and keys, less object creation in hotpots is always faster\n    private static final class Record {\n\n        private final long start; // memory address of the underlying data\n        private final int length;\n        private final long word1;\n        private final long word2;\n        private final long wordLast;\n        private final int hash;\n        private Record next; // linked list to resolve hash collisions\n\n        private int min; // calculations over int is faster than double, we convert to double in the end only once\n        private int max;\n        private long sum;\n        private int count;\n\n        public Record(long start, int length, long word1, long word2, long wordLast, int hash, int temp) {\n            this.start = start;\n            this.length = length;\n            this.word1 = word1;\n            this.word2 = word2;\n            this.wordLast = wordLast;\n            this.hash = hash;\n            this.min = temp;\n            this.max = temp;\n            this.sum = temp;\n            this.count = 1;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            final Record record = (Record) o;\n            return equals(record.start, record.word1, record.word2, record.wordLast, record.length);\n        }\n\n        private static boolean notEquals(long address1, long address2, int step) {\n            return UNSAFE.getLong(address1 + step) != UNSAFE.getLong(address2 + step);\n        }\n\n        private static boolean equalsComparingLongs(long start1, long start2, int length) {\n            // first shortcuts\n            if (length < 24)\n                return true;\n            if (length < 32)\n                return !notEquals(start1, start2, 16);\n\n            int step = 24; // starting from 3rd long\n            length -= step;\n            while (length >= 8) { // scan longs\n                if (notEquals(start1, start2, step)) {\n                    return false;\n                }\n                length -= 8;\n                step += 8; // 8 bytes\n            }\n            return true;\n        }\n\n        private boolean equals(long start, long word1, long word2, long last, int length) {\n            if (this.word1 != word1)\n                return false;\n            if (this.word2 != word2)\n                return false;\n\n            // equals check is done by comparing longs instead of byte by byte check, this is faster\n            return equalsComparingLongs(this.start, start, length) && this.wordLast == last;\n        }\n\n        @Override\n        public String toString() {\n            final byte[] bytes = new byte[this.length];\n            UNSAFE.copyMemory(null, this.start, bytes, Unsafe.ARRAY_BYTE_BASE_OFFSET, this.length);\n            return new String(bytes, StandardCharsets.UTF_8);\n        }\n\n        private void collect(int temp) {\n            if (temp < this.min)\n                this.min = temp;\n            if (temp > this.max)\n                this.max = temp;\n            this.sum += temp;\n            this.count++;\n        }\n\n        private void merge(Record that) {\n            if (that.min < this.min)\n                this.min = that.min;\n            if (that.max > this.max)\n                this.max = that.max;\n            this.sum += that.sum;\n            this.count += that.count;\n        }\n\n        private String measurements() {\n            // here is only executed once for each unique key, so StringBuilder creation doesn't harm\n            final StringBuilder sb = new StringBuilder(14);\n            sb.append(round(this.min)).append(\"/\");\n            sb.append(round(1.0 * this.sum / this.count)).append(\"/\");\n            sb.append(round(this.max));\n            return sb.toString();\n        }\n    }\n\n    // Inspired by @spullara - customized hashmap on purpose\n    // The main difference is we hold only one array instead of two, fewer objects is faster\n    private static final class RecordMap {\n\n        // Bigger bucket size less collisions, but you have to find a sweet spot otherwise it is becoming slower.\n        // Also works good enough for 10K stations\n        private static final int SIZE = 1 << 14; // 16kb - enough for 10K\n        private static final int BITMASK = SIZE - 1;\n        private final Record[] keys = new Record[SIZE];\n\n        // int collision;\n\n        private boolean hasNoRecord(int index) {\n            return this.keys[index] == null;\n        }\n\n        private Record getRecord(int index) {\n            return this.keys[index];\n        }\n\n        private static int hashBucket(int hash) {\n            hash = hash ^ (hash >>> 16); // naive bit spreading but surprisingly decreases collision :)\n            return hash & BITMASK; // fast modulo, to find bucket\n        }\n\n        private void putAndCollect(int hash, int temp, long start, int length, long word1, long word2, long wordLast) {\n            final int bucket = hashBucket(hash);\n            if (hasNoRecord(bucket)) {\n                this.keys[bucket] = new Record(start, length, word1, word2, wordLast, hash, temp);\n                return;\n            }\n\n            Record existing = getRecord(bucket);\n            if (existing.equals(start, word1, word2, wordLast, length)) {\n                existing.collect(temp);\n                return;\n            }\n\n            // collision++;\n            // find possible slot by scanning the slot linked list\n            while (existing.next != null) {\n                if (existing.next.equals(start, word1, word2, wordLast, length)) {\n                    existing.next.collect(temp);\n                    return;\n                }\n                existing = existing.next; // go on to next\n                // collision++;\n            }\n            existing.next = new Record(start, length, word1, word2, wordLast, hash, temp);\n        }\n\n        private void putOrMerge(Record key) {\n            final int bucket = hashBucket(key.hash);\n            if (hasNoRecord(bucket)) {\n                key.next = null;\n                this.keys[bucket] = key;\n                return;\n            }\n\n            Record existing = getRecord(bucket);\n            if (existing.equals(key)) {\n                existing.merge(key);\n                return;\n            }\n\n            // collision++;\n            // find possible slot by scanning the slot linked list\n            while (existing.next != null) {\n                if (existing.next.equals(key)) {\n                    existing.next.merge(key);\n                    return;\n                }\n                existing = existing.next; // go on to next\n                // collision++;\n            }\n            key.next = null;\n            existing.next = key;\n        }\n\n        private void forEach(Consumer<Record> consumer) {\n            int pos = 0;\n            Record key;\n            while (pos < SIZE) {\n                if ((key = this.keys[pos++]) == null) {\n                    continue;\n                }\n                Record next = key.next;\n                consumer.accept(key);\n                while (next != null) { // also traverse the records in the collision list\n                    final Record tmp = next.next;\n                    consumer.accept(next);\n                    next = tmp;\n                }\n            }\n        }\n\n        private void merge(RecordMap other) {\n            other.forEach(this::putOrMerge);\n        }\n\n    }\n\n    // One actor for one thread, no synchronization\n    private static final class RegionActor extends Thread {\n\n        private final long startPos; // start of region memory address\n        private final int size;\n\n        private final RecordMap map = new RecordMap();\n\n        public RegionActor(long startPos, int size) {\n            this.startPos = startPos;\n            this.size = size;\n        }\n\n        private static long getWord(long address) {\n            return UNSAFE.getLong(address);\n        }\n\n        // hasvalue & haszero\n        // adapted from https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord\n        private static long hasSemicolon(long word) {\n            // semicolon pattern\n            final long hasVal = word ^ 0x3B3B3B3B3B3B3B3BL; // hasvalue\n            return ((hasVal - 0x0101010101010101L) & ~hasVal & 0x8080808080808080L); // haszero\n        }\n\n        private static int semicolonPos(long hasVal) {\n            return Long.numberOfTrailingZeros(hasVal) >>> 3;\n        }\n\n        private static int decimalPos(long numberWord) {\n            return Long.numberOfTrailingZeros(~numberWord & 0x10101000);\n        }\n\n        private static final int MAX_INNER_LOOP_SIZE = 11;\n\n        @Override\n        public void run() {\n            long pointer = this.startPos;\n            final long size = pointer + this.size;\n            while (pointer < size) { // line start\n                long hash = 0; // reset hash\n                long s; // semicolon check word\n                final int pos; // semicolon position\n                long word1 = getWord(pointer);\n                if ((s = hasSemicolon(word1)) != 0) {\n                    pos = semicolonPos(s);\n                    // read temparature\n                    final long numberWord = getWord(pointer + pos + 1);\n                    final int decimalPos = decimalPos(numberWord);\n                    final int temp = convertIntoNumber(decimalPos, numberWord);\n\n                    word1 = partial(word1, pos); // last word\n                    this.map.putAndCollect(completeHash(hash, word1), temp, pointer, pos, word1, 0, 0);\n\n                    pointer += pos + (decimalPos >>> 3) + 4;\n                }\n                else {\n                    long word2 = getWord(pointer + 8);\n                    if ((s = hasSemicolon(word2)) != 0) {\n                        pos = semicolonPos(s);\n                        // read temparature\n                        final int length = pos + 8;\n                        final long numberWord = getWord(pointer + length + 1);\n                        final int decimalPos = decimalPos(numberWord);\n                        final int temp = convertIntoNumber(decimalPos, numberWord);\n\n                        word2 = partial(word2, pos); // last word\n                        this.map.putAndCollect(completeHash(hash, word1, word2), temp, pointer, length, word1, word2, 0);\n\n                        pointer += length + (decimalPos >>> 3) + 4; // seek to the line end\n                    }\n                    else {\n                        long word = 0;\n                        int length = 16;\n                        hash = appendHash(hash, word1, word2);\n                        // Let the compiler know the loop size ahead\n                        // Then it's automatically unrolled\n                        // Max key length is 13 longs, 2 we've read before, 11 left\n                        for (int i = 0; i < MAX_INNER_LOOP_SIZE; i++) {\n                            if ((s = hasSemicolon((word = getWord(pointer + length)))) != 0) {\n                                break;\n                            }\n                            hash = appendHash(hash, word);\n                            length += 8;\n                        }\n\n                        pos = semicolonPos(s);\n                        length += pos;\n                        // read temparature\n                        final long numberWord = getWord(pointer + length + 1);\n                        final int decimalPos = decimalPos(numberWord);\n                        final int temp = convertIntoNumber(decimalPos, numberWord);\n\n                        word = partial(word, pos); // last word\n                        this.map.putAndCollect(completeHash(hash, word), temp, pointer, length, word1, word2, word);\n\n                        pointer += length + (decimalPos >>> 3) + 4; // seek to the line end\n                    }\n                }\n            }\n        }\n\n        // Hashes are calculated by a Mersenne Prime (1 << 7) -1\n        // This is faster than multiplication in some machines\n        private static long appendHash(long hash, long word) {\n            return (hash << 7) - hash + word;\n        }\n\n        private static long appendHash(long hash, long word1, long word2) {\n            hash = (hash << 7) - hash + word1;\n            return (hash << 7) - hash + word2;\n        }\n\n        private static int completeHash(long hash, long partial) {\n            hash = (hash << 7) - hash + partial;\n            return (int) (hash ^ (hash >>> 25));\n        }\n\n        private static int completeHash(long hash, long word1, long word2) {\n            hash = (hash << 7) - hash + word1;\n            hash = (hash << 7) - hash + word2;\n            return (int) hash ^ (int) (hash >>> 25);\n        }\n\n        // Credits to @merrykitty. Magical solution to parse temparature values branchless!\n        // Taken as without modification, comments belong to @merrykitty\n        private static int convertIntoNumber(int decimalSepPos, long numberWord) {\n            final int shift = 28 - decimalSepPos;\n            // signed is -1 if negative, 0 otherwise\n            final long signed = (~numberWord << 59) >> 63;\n            final long designMask = ~(signed & 0xFF);\n            // Align the number to a specific position and transform the ascii code\n            // to actual digit value in each byte\n            final long digits = ((numberWord & designMask) << shift) & 0x0F000F0F00L;\n            // Now digits is in the form 0xUU00TTHH00 (UU: units digit, TT: tens digit, HH: hundreds digit)\n            // 0xUU00TTHH00 * (100 * 0x1000000 + 10 * 0x10000 + 1) =\n            // 0x000000UU00TTHH00 +\n            // 0x00UU00TTHH000000 * 10 +\n            // 0xUU00TTHH00000000 * 100\n            // Now TT * 100 has 2 trailing zeroes and HH * 100 + TT * 10 + UU < 0x400\n            // This results in our value lies in the bit 32 to 41 of this product\n            // That was close :)\n            final long absValue = ((digits * 0x640a0001) >>> 32) & 0x3FF;\n            final long value = (absValue ^ signed) - signed;\n            return (int) value;\n        }\n\n        /**\n         * blocks until the map is fully collected\n         */\n        private RecordMap get() throws InterruptedException {\n            join();\n            return this.map;\n        }\n    }\n\n    private static double round(double value) {\n        return Math.round(value) / 10.0;\n    }\n\n    /**\n     * Scans the given buffer to the left\n     */\n    private static long findClosestLineEnd(long start, int size) {\n        long position = start + size;\n        while (UNSAFE.getByte(--position) != '\\n') {\n            // read until a linebreak\n            size--;\n        }\n        return size;\n    }\n\n    private static boolean isWorkerProcess(String[] args) {\n        return Arrays.asList(args).contains(\"--worker\");\n    }\n\n    private static void runAsWorker() throws Exception {\n        final ProcessHandle.Info info = ProcessHandle.current().info();\n        final List<String> commands = new ArrayList<>();\n        info.command().ifPresent(commands::add);\n        info.arguments().ifPresent(args -> commands.addAll(Arrays.asList(args)));\n        commands.add(\"--worker\");\n\n        new ProcessBuilder()\n                .command(commands)\n                .start()\n                .getInputStream()\n                .transferTo(System.out);\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        // Dased on @thomaswue's idea, to cut unmapping delay.\n        // Strangely, unmapping delay doesn't occur on macOS/M1 however in Linux/AMD it's substantial - ~200ms\n        if (!isWorkerProcess(args)) {\n            runAsWorker();\n            return;\n        }\n\n        var concurrency = 2 * Runtime.getRuntime().availableProcessors();\n        final long fileSize = Files.size(FILE);\n        long regionSize = fileSize / concurrency;\n\n        // handling extreme cases\n        while (regionSize > Integer.MAX_VALUE) {\n            concurrency *= 2;\n            regionSize /= 2;\n        }\n        if (fileSize <= 1 << 20) { // small file (1mb), no need concurrency\n            concurrency = 1;\n            regionSize = fileSize;\n        }\n\n        long startPos = 0;\n        final FileChannel channel = (FileChannel) Files.newByteChannel(FILE, StandardOpenOption.READ);\n        // get the memory address, this is the only thing we need for Unsafe\n        final long memoryAddress = channel.map(FileChannel.MapMode.READ_ONLY, startPos, fileSize, Arena.global()).address();\n\n        final RegionActor[] actors = new RegionActor[concurrency];\n        for (int i = 0; i < concurrency; i++) {\n            // calculate boundaries\n            long maxSize = (startPos + regionSize > fileSize) ? fileSize - startPos : regionSize;\n            // shift position to back until we find a linebreak\n            maxSize = findClosestLineEnd(memoryAddress + startPos, (int) maxSize);\n\n            final RegionActor region = (actors[i] = new RegionActor(memoryAddress + startPos, (int) maxSize));\n            region.start(); // start processing\n\n            startPos += maxSize;\n        }\n\n        final RecordMap output = new RecordMap(); // output to merge all records\n        for (RegionActor actor : actors) {\n            final RecordMap partial = actor.get(); // blocks until get the result\n            output.merge(partial);\n            // System.out.println(\"collisions: \" + partial.collision);\n        }\n\n        // sort and print the result\n        final TreeMap<String, String> sorted = new TreeMap<>();\n        output.forEach(key -> {\n            sorted.put(key.toString(), key.measurements());\n        });\n        System.out.println(sorted);\n        System.out.close(); // closing the stream will trigger the main process to pick up the output early\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_yehwankim23.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileReader;\nimport java.io.OutputStreamWriter;\nimport java.util.HashMap;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_yehwankim23 {\n    public static void main(String[] args) throws Exception {\n        BufferedReader br = new BufferedReader(new FileReader(\"./measurements.txt\"));\n        HashMap<String, Measurement> hm = new HashMap<>();\n        char[] buffer = new char[107];\n        int offset = 0;\n\n        while (true) {\n            br.read(buffer, offset, 107 - offset);\n            int semicolon = 0;\n\n            while (buffer[semicolon] != ';') {\n                semicolon++;\n            }\n\n            String stationName = new String(buffer, 0, semicolon++);\n            int newline = semicolon;\n\n            while (buffer[newline] != '\\n') {\n                newline++;\n            }\n\n            if (hm.containsKey(stationName)) {\n                hm.get(stationName).update(Double.parseDouble(\n                        new String(buffer, semicolon, newline - semicolon)));\n            }\n            else {\n                hm.put(stationName, new Measurement(\n                        Double.parseDouble(new String(buffer, semicolon, newline - semicolon))));\n            }\n\n            if (buffer[++newline] == 0) {\n                break;\n            }\n\n            offset = 107 - newline;\n            char[] temp = new char[107];\n            System.arraycopy(buffer, newline, temp, 0, offset);\n            buffer = temp;\n        }\n\n        br.close();\n        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));\n        bw.write(new TreeMap<>(hm).toString());\n        bw.newLine();\n        bw.flush();\n        bw.close();\n    }\n\n    private static class Measurement {\n        public double min;\n        public double sum;\n        public int count;\n        public double max;\n\n        public Measurement(double measurement) {\n            min = measurement;\n            sum = measurement;\n            count = 1;\n            max = measurement;\n        }\n\n        public void update(double measurement) {\n            if (measurement < min) {\n                min = measurement;\n            }\n\n            sum += measurement;\n            count++;\n\n            if (max < measurement) {\n                max = measurement;\n            }\n        }\n\n        @Override\n        public String toString() {\n            return min + \"/\" + Math.round(sum / count * 10) / 10.0 + \"/\" + max;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_yemreinci.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.TreeMap;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.function.Consumer;\nimport java.util.function.Supplier;\nimport java.util.stream.Collectors;\n\npublic class CalculateAverage_yemreinci {\n    private static final String FILE = \"./measurements.txt\";\n\n    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {\n        var filename = args.length == 0 ? FILE : args[0];\n        var file = new File(filename);\n        long start = System.currentTimeMillis();\n\n        var totalLines = new AtomicInteger();\n        var results = getFileSegments(file).stream().map(segment -> {\n            var resultMap = new ByteArrayToResultMap();\n            long segmentEnd = segment.end();\n            try (var fileChannel = (FileChannel) Files.newByteChannel(Path.of(filename), StandardOpenOption.READ)) {\n                var bb = fileChannel.map(FileChannel.MapMode.READ_ONLY, segment.start(), segmentEnd - segment.start());\n                var buffer = new byte[64];\n                int lines = 0;\n                int startLine;\n                int limit = bb.limit();\n                while ((startLine = bb.position()) < limit) {\n                    int currentPosition = startLine;\n                    byte b;\n                    int offset = 0;\n                    int hash = 0;\n                    while ((b = bb.get(currentPosition++)) != ';') {\n                        buffer[offset++] = b;\n                        hash = (hash << 5) - hash + b;\n                    }\n\n                    boolean negative = false;\n                    if ((b = bb.get(currentPosition)) == '-') {\n                        negative = true;\n                        currentPosition++;\n                    }\n\n                    double temp;\n                    if ((b = bb.get(currentPosition + 1)) == '.') { // temperature is in either XX.X or X.X form\n                        temp = (bb.get(currentPosition) - '0') + (bb.get(currentPosition + 2) - '0') / 10.0;\n                        currentPosition += 4;\n                    }\n                    else {\n                        temp = (bb.get(currentPosition) - '0') * 10 + (b - '0') + (bb.get(currentPosition + 3) - '0') / 10.0;\n                        currentPosition += 5;\n                    }\n\n                    double finalTemp = (negative ? -temp : temp);\n                    resultMap.putOrMerge(hash, buffer, 0, offset,\n                            () -> new Result(temp),\n                            measurement -> merge(measurement, finalTemp, finalTemp, finalTemp, 1));\n                    lines++;\n                    bb.position(currentPosition);\n                }\n                totalLines.addAndGet(lines);\n                return resultMap;\n            }\n            catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }).parallel().toList();\n\n        var resultMap = results.stream()\n                .flatMap(partition -> partition.getAll().stream())\n                .collect(Collectors.toMap(e -> new String(e.key()), Entry::value, CalculateAverage_yemreinci::merge, TreeMap::new));\n\n        System.out.println(\"Time: \" + (System.currentTimeMillis() - start) + \"ms\");\n        System.out.println(\"Lines processed: \" + totalLines);\n        System.out.println(resultMap);\n    }\n\n    private static List<FileSegment> getFileSegments(File file) throws IOException {\n        int numberOfSegments = Runtime.getRuntime().availableProcessors();\n        long fileSize = file.length();\n        long segmentSize = fileSize / numberOfSegments;\n        List<FileSegment> segments = new ArrayList<>();\n        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, \"r\")) {\n            for (int i = 0; i < numberOfSegments; i++) {\n                long segStart = i * segmentSize;\n                long segEnd = (i == numberOfSegments - 1) ? fileSize : segStart + segmentSize;\n                segStart = findSegment(i, 0, randomAccessFile, segStart, segEnd);\n                segEnd = findSegment(i, numberOfSegments - 1, randomAccessFile, segEnd, fileSize);\n\n                segments.add(new FileSegment(segStart, segEnd));\n            }\n        }\n        return segments;\n    }\n\n    private static Result merge(Result v, Result value) {\n        return merge(v, value.min, value.max, value.sum, value.count);\n    }\n\n    private static Result merge(Result v, double value, double value1, double value2, long value3) {\n        v.min = Math.min(v.min, value);\n        v.max = Math.max(v.max, value1);\n        v.sum += value2;\n        v.count += value3;\n        return v;\n    }\n\n    private static long findSegment(int i, int skipSegment, RandomAccessFile raf, long location, long fileSize) throws IOException {\n        if (i != skipSegment) {\n            raf.seek(location);\n            while (location < fileSize) {\n                location++;\n                if (raf.read() == '\\n')\n                    break;\n            }\n        }\n        return location;\n    }\n\n    static class Result {\n        double min, max, sum;\n        long count;\n\n        Result(double value) {\n            min = max = sum = value;\n            this.count = 1;\n        }\n\n        @Override\n        public String toString() {\n            return round(min) + \"/\" + round(sum / count) + \"/\" + round(max);\n        }\n\n        double round(double v) {\n            return Math.round(v * 10.0) / 10.0;\n        }\n\n    }\n\n    static record Pair(int slot, Result slotValue) {\n    }\n\n    static record Entry(byte[] key, Result value) {\n    }\n\n    static record FileSegment(long start, long end) {\n    }\n\n    static class ByteArrayToResultMap {\n        public static final int MAPSIZE = 1024 * 128;\n        Result[] slots = new Result[MAPSIZE];\n        byte[][] keys = new byte[MAPSIZE][];\n\n        private Pair getPair(int hash, byte[] key, int offset, int size) {\n            int slot = hash & (slots.length - 1);\n            var slotValue = slots[slot];\n            // Linear probe for open slot\n            while (slotValue != null && (keys[slot].length != size || !Arrays.equals(keys[slot], 0, size, key, offset, size))) {\n                slot = (slot + 1) & (slots.length - 1);\n                slotValue = slots[slot];\n            }\n            return new Pair(slot, slotValue);\n        }\n\n        public void putOrMerge(int hash, byte[] key, int offset, int size, Supplier<Result> supplier, Consumer<Result> merge) {\n            Pair result = getPair(hash, key, offset, size);\n            Result value = result.slotValue();\n            if (value == null) {\n                int slot = result.slot();\n                slots[slot] = supplier.get();\n                byte[] bytes = new byte[size];\n                System.arraycopy(key, offset, bytes, 0, size);\n                keys[slot] = bytes;\n            }\n            else {\n                merge.accept(value);\n            }\n        }\n\n        // Get all pairs\n        public List<Entry> getAll() {\n            List<Entry> result = new ArrayList<>();\n            for (int i = 0; i < slots.length; i++) {\n                Result slotValue = slots[i];\n                if (slotValue != null) {\n                    result.add(new Entry(keys[i], slotValue));\n                }\n            }\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_yonatang.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.Map;\nimport java.util.TreeMap;\n\npublic class CalculateAverage_yonatang {\n    private static final String FILE = \"./measurements.txt\";\n\n    private static final int DICT_OFFSET_STATION = 2;\n    private static final int DICT_OFFSET_SUM = 1;\n    private static final int DICT_SIZE = 15000;\n    private static final int DICT_STATION_RECORD_SIZE = 13;\n    private static final int DICT_RECORD_SIZE = DICT_OFFSET_STATION + DICT_STATION_RECORD_SIZE;\n    private static final int DICT_SIZE_BYTES = DICT_SIZE * DICT_RECORD_SIZE;\n    private static final long[] DICT_ZERO_RECORD = new long[DICT_RECORD_SIZE];\n    private static final long DICT_BASELINE_MEASURES = ((long) Short.MAX_VALUE & 0xFFFF) | (((long) Short.MIN_VALUE & 0xFFFF) << 16);\n\n    public static class HashTable {\n\n        // Continuous array of [key, min, max, count, sum], which will be more CPU cache friendly.\n        private final long[] data = new long[DICT_SIZE_BYTES];\n\n        public HashTable() {\n            for (int i = 0; i < DICT_SIZE_BYTES; i += DICT_RECORD_SIZE) {\n                data[i] = DICT_BASELINE_MEASURES;\n            }\n        }\n\n        private int getIndex(long[] station) {\n            long key = 0;\n            short len = (short) (station[0] & 0xFF);\n            int longs = ((len + 1) / 8) + 1;\n            for (int i = 0; i < longs; i++) {\n                key = key ^ station[i];\n            }\n            int idx = Math.abs((int) (key % DICT_SIZE)) * DICT_RECORD_SIZE;\n\n            while (true) {\n                if (data[idx] == DICT_BASELINE_MEASURES) {\n                    break;\n                }\n                if (Arrays.equals(station, 0, longs,\n                        data,\n                        idx + DICT_OFFSET_STATION, idx + DICT_OFFSET_STATION + longs)) {\n                    break;\n                }\n                idx += DICT_RECORD_SIZE;\n                if (idx >= DICT_SIZE_BYTES) {\n                    idx = 0;\n                }\n            }\n            return idx;\n        }\n\n        private void addRawMeasurementAgg(long[] title, long measurements, long sum) {\n            int idx = getIndex(title);\n            short currentMin = (short) (data[idx] & 0xFFFF);\n            short currentMax = (short) ((data[idx] >> 16) & 0xFFFF);\n            int currentCount = (int) (data[idx] >> 32);\n\n            short thisMin = (short) (measurements & 0xFFFF);\n            short thisMax = (short) ((measurements >> 16) & 0xFFFF);\n            int thisCount = (int) (measurements >> 32);\n\n            thisMin = (short) Math.min(thisMin, currentMin);\n            thisMax = (short) Math.max(thisMax, currentMax);\n            thisCount += currentCount;\n\n            data[idx] = ((long) thisMin & 0xFFFF) | (((long) thisMax & 0xFFFF) << 16) | (((long) thisCount) << 32);\n\n            data[idx + DICT_OFFSET_SUM] += sum;\n            System.arraycopy(title, 0, data, idx + DICT_OFFSET_STATION, DICT_STATION_RECORD_SIZE);\n        }\n\n        public TreeMap<String, ResultRow> toMap() {\n            TreeMap<String, ResultRow> finalMap = new TreeMap<>();\n            byte[] bytes = new byte[128];\n            ByteBuffer bb = ByteBuffer.allocate(136);\n            bb.order(ByteOrder.nativeOrder());\n            for (int i = 0; i < DICT_SIZE_BYTES; i += DICT_RECORD_SIZE) {\n                if (data[i] == DICT_BASELINE_MEASURES)\n                    continue;\n\n                short min = (short) (data[i] & 0xFFFF);\n                short max = (short) ((data[i] >> 16) & 0xFFFF);\n                int count = (int) (data[i] >> 32);\n                long sum = data[i + DICT_OFFSET_SUM];\n                for (int j = 0; j < DICT_STATION_RECORD_SIZE; j++) {\n                    bb.putLong(data[i + DICT_OFFSET_STATION + j]);\n                }\n                bb.flip();\n                byte len = bb.get();\n                bb.get(1, bytes, 0, len);\n                bb.clear();\n                String station = new String(bytes, 0, len, Charset.defaultCharset());\n                finalMap.put(station, new ResultRow(min / 10.0, (sum / 10.0) / count, max / 10.0));\n\n            }\n            return finalMap;\n        }\n\n        public void addMeasurement(long[] title, short temp) {\n            int idx = getIndex(title);\n            short min = (short) (data[idx] & 0xFFFF);\n            short max = (short) ((data[idx] >> 16) & 0xFFFF);\n            int count = (int) (data[idx] >> 32);\n            min = (short) Math.min(min, temp);\n            max = (short) Math.max(max, temp);\n            count += 1;\n\n            data[idx] = ((long) min & 0xFFFF) | (((long) max & 0xFFFF) << 16) | (((long) count) << 32);\n            data[idx + DICT_OFFSET_SUM] += temp;\n            System.arraycopy(title, 0, data, idx + DICT_OFFSET_STATION, DICT_STATION_RECORD_SIZE);\n        }\n\n        public void mergeInto(HashTable other) {\n            long[] title = new long[DICT_STATION_RECORD_SIZE];\n            for (int i = 0; i < DICT_SIZE_BYTES; i += DICT_RECORD_SIZE) {\n                if (data[i] == DICT_BASELINE_MEASURES)\n                    continue;\n                System.arraycopy(data, i + DICT_OFFSET_STATION, title, 0, DICT_STATION_RECORD_SIZE);\n                other.addRawMeasurementAgg(title, data[i], data[i + DICT_OFFSET_SUM]);\n            }\n        }\n\n    }\n\n    private static class ResultRow {\n        final double min;\n        final double mean;\n        final double max;\n\n        ResultRow(double min, double mean, double max) {\n            this.min = min;\n            this.mean = mean;\n            this.max = max;\n        }\n\n        public String toString() {\n            return round(min) + \"/\" + round(mean) + \"/\" + round(max);\n        }\n\n        private double round(double value) {\n            return Math.round(value * 10.0) / 10.0;\n        }\n    }\n\n    public static boolean parseStation(MappedByteBuffer byteBuffer, ByteBuffer tempBb, long[] station) {\n        System.arraycopy(DICT_ZERO_RECORD, 0, station, 0, DICT_STATION_RECORD_SIZE);\n        byte len = 1;\n        boolean valid = false;\n        tempBb.clear();\n        tempBb.put((byte) 0);\n        while (byteBuffer.hasRemaining()) {\n            byte ch = byteBuffer.get();\n            if (ch == '\\n') {\n                continue;\n            }\n            if (ch == ';') {\n                valid = true;\n                break;\n            }\n            tempBb.put(ch);\n            // long theNew = ((long) ch) << (len * 8);\n            // stationId[0] = stationId[0] ^ theNew;\n            // int arrIdx = len / 8;\n            // station[arrIdx] = station[arrIdx] ^ theNew;\n            len++;\n        }\n        tempBb.put(0, (byte) (len - 1));\n        if (!valid) {\n            return false;\n        }\n        tempBb.position(0);\n        tempBb.asLongBuffer().get(station);\n\n        int pivotIdx = (len) / 8;\n        long pivotBits = (len % 8) * 8;\n        long pivotMask = (1L << pivotBits) - 1;\n        station[pivotIdx] = station[pivotIdx] & pivotMask;\n        return true;\n    }\n\n    public static short parseShort(MappedByteBuffer byteBuffer) {\n        boolean valid = false;\n        boolean negative = false;\n        int num = 0;\n        while (byteBuffer.hasRemaining()) {\n            byte ch = byteBuffer.get();\n            if (ch == '\\n') {\n                valid = true;\n                break;\n            }\n            if (ch == '-') {\n                negative = true;\n            }\n            else if (ch == '.') {\n                // noop\n            }\n            else {\n                num = (num * 10 + (ch - '0'));\n            }\n        }\n        if (!valid) {\n            return Short.MIN_VALUE;\n        }\n\n        return (short) (negative ? -num : num);\n    }\n\n    private static final int MARGIN = 130;\n\n    private static void processChunk(FileChannel fc, int j, long chunkSize, HashTable[] maps, boolean isLast) {\n        try {\n            HashTable agg = new HashTable();\n            maps[j] = agg;\n            long[] station = new long[DICT_STATION_RECORD_SIZE];\n            ByteBuffer tempBb = ByteBuffer.allocate((DICT_STATION_RECORD_SIZE + 1) * Long.BYTES);\n            tempBb.order(ByteOrder.nativeOrder());\n\n            long startIdx = Math.max(j * chunkSize - MARGIN, 0);\n            int padding;\n            if (isLast) {\n                chunkSize = fc.size() - startIdx;\n                padding = 0;\n            }\n            else {\n                padding = j == 0 ? 0 : MARGIN;\n            }\n            if (chunkSize == 0) {\n                return;\n            }\n            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, startIdx, chunkSize + padding);\n            // search back for the actual start line, at \\n\n            if (startIdx > 0) {\n                int i = MARGIN;\n                while (i > 0) {\n                    byte ch = byteBuffer.get(i);\n                    if (ch == '\\n') {\n                        break;\n                    }\n                    i--;\n                }\n                byteBuffer.position(i);\n            }\n\n            while (byteBuffer.hasRemaining()) {\n                if (!parseStation(byteBuffer, tempBb, station)) {\n                    continue;\n                }\n                short value = parseShort(byteBuffer);\n                if (value == Short.MIN_VALUE) {\n                    continue;\n                }\n                agg.addMeasurement(station, value);\n            }\n        }\n        catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        // long start = System.nanoTime();\n\n        File f = new File(FILE);\n        try (RandomAccessFile raf = new RandomAccessFile(f, \"r\");\n                FileChannel fc = raf.getChannel()) {\n\n            int chunks = f.length() < 1_048_576 ? 1 : (Runtime.getRuntime().availableProcessors());\n\n            long chunkSize = f.length() / chunks;\n\n            Thread[] threads = new Thread[chunks];\n            HashTable totalAgg = new HashTable();\n            HashTable[] maps = new HashTable[chunks];\n\n            for (int i = 0; i < chunks; i++) {\n                final int j = i;\n                Thread thread = new Thread(() -> processChunk(fc, j, chunkSize, maps, j == chunks - 1));\n                threads[i] = thread;\n                thread.start();\n            }\n            for (int i = 0; i < chunks; i++) {\n                threads[i].join();\n                maps[i].mergeInto(totalAgg);\n            }\n\n            Map<String, ResultRow> finalMap = totalAgg.toMap();\n            // long end = System.nanoTime();\n\n            System.out.println(finalMap);\n            // System.err.println(\"Total time: \" + java.time.Duration.ofNanos(end - start).toMillis() + \"ms\");\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_yourwass.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.util.TreeMap;\nimport java.util.concurrent.locks.Lock;\nimport java.util.concurrent.locks.ReentrantLock;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.foreign.MemorySegment;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.ByteOrder;\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorOperators;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\npublic class CalculateAverage_yourwass {\n    static final class Record {\n        private long cityAddr;\n        private long cityLength;\n        private int min;\n        private int max;\n        private int count;\n        private long sum;\n\n        Record(final long cityAddr, final long cityLength) {\n            this.cityAddr = cityAddr;\n            this.cityLength = cityLength;\n            this.min = 1000;\n            this.max = -1000;\n            this.sum = 0;\n            this.count = 0;\n        }\n\n        private Record merge(Record r) {\n            if (r.min < this.min)\n                this.min = r.min;\n            if (r.max > this.max)\n                this.max = r.max;\n            this.sum += r.sum;\n            this.count += r.count;\n            return this;\n        }\n    }\n\n    private final static Lock _mutex = new ReentrantLock(true);\n    private final static TreeMap<String, Record> aggregateResults = new TreeMap<>();\n    private static short lookupDecimal[];\n    private static byte lookupFraction[];\n    private static byte lookupDotPositive[];\n    private static byte lookupDotNegative[];\n    private static MemorySegment VAS;\n    private static final VectorSpecies<Byte> SPECIES = ByteVector.SPECIES_PREFERRED;\n    private static final int MAXINDEX = (1 << 16) + 10000; // short hash + max allowed cities for collisions at the end :p\n    private static final String FILE = \"measurements.txt\";\n    private static long unsafeResults;\n    private static int RECORDSIZE = 36;\n    private static final Unsafe UNSAFE = getUnsafe();\n\n    private static Unsafe getUnsafe() {\n        try {\n            final Field theUnsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            theUnsafe.setAccessible(true);\n            Unsafe unsafe = (Unsafe) theUnsafe.get(null);\n            return unsafe;\n        }\n        catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, Throwable {\n        // prepare lookup tables\n        // the parsing reads two shorts after possible '-'\n        // first short, the Decimal part, can be N. or NN with N:[0..9]\n        // second short, the Fraction part, can be N\\n or .N\n        lookupDecimal = new short[('9' << 8) + '9' + 1];\n        lookupFraction = new byte[('9' << 8) + '.' + 1];\n        lookupDotPositive = new byte[('9' << 8) + '.' + 1];\n        lookupDotNegative = new byte[('9' << 8) + '.' + 1];\n        for (short i = 0; i < 10; i++) {\n            final int ones = i * 10;\n            final int ix256 = i << 8;\n            // case N. i.e. single digit decimals: skip to 11824 = ('.'<<8)+'0'\n            lookupDecimal[11824 + i] = (short) ones;\n            for (short j = 1; j < 10; j++) {\n                // case NN i.e double digits decimals: skip to 12236 = ('0'<<8)+'0'\n                lookupDecimal[12336 + ix256 + j] = (short) (j * 100 + ones);\n            }\n            // case N\\n skip to 2608 = ('\\n'<<8)+'0'\n            lookupFraction[2608 + i] = (byte) i;\n            lookupDotPositive[2608 + i] = 4;\n            lookupDotNegative[2608 + i] = 5;\n            // case .N skip to 12334 = ('0'<<8)+'.'\n            lookupFraction[12334 + ix256] = (byte) i;\n            lookupDotPositive[12334 + ix256] = 5;\n            lookupDotNegative[12334 + ix256] = 6;\n        }\n\n        // open file\n        final FileChannel fileChannel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ);\n        final long fileSize = fileChannel.size();\n        final long mmapAddr = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global()).address();\n        // VAS: Virtual Address Space, as a MemorySegment upto and including the mmaped file.\n        // If the mmaped MemorySegment is used for Vector creation as is, then there are two problems:\n        // 1) fromMemorySegment takes an offset and not an address, so we have to do arithmetic\n        // this is solved by creating a MemorySegment from Address=0\n        // 2) fromMemorySegment checks bounds for memory segment's size - Vector size\n        // this is solved by adding SPECIES.length() to the size of the segment, but\n        // XXX there lies the possibility for an out of bounds read at the end of file, which is not handled here.\n        VAS = MemorySegment.ofAddress(0).reinterpret(mmapAddr + fileSize + SPECIES.length());\n\n        // allocate memory for results\n        final int nThreads = Runtime.getRuntime().availableProcessors();\n        unsafeResults = UNSAFE.allocateMemory(RECORDSIZE * MAXINDEX * nThreads);\n        UNSAFE.setMemory(unsafeResults, RECORDSIZE * MAXINDEX * nThreads, (byte) 0);\n\n        // start and wait for threads to finish\n        Thread[] threadList = new Thread[nThreads];\n        final long chunkSize = fileSize / nThreads;\n        for (int i = 0; i < nThreads; i++) {\n            final int threadIndex = i;\n            final long startAddr = mmapAddr + i * chunkSize;\n            final long endAddr = (i == nThreads - 1) ? mmapAddr + fileSize : mmapAddr + (i + 1) * chunkSize;\n            threadList[i] = new Thread(() -> threadMain(threadIndex, startAddr, endAddr, nThreads));\n            threadList[i].start();\n        }\n        for (int i = 0; i < nThreads; i++)\n            threadList[i].join();\n\n        // prepare string and print\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"{\");\n        for (var entry : aggregateResults.entrySet()) {\n            Record record = entry.getValue();\n            float min = record.min;\n            min /= 10.f;\n            float max = record.max;\n            max /= 10.f;\n            double avg = Math.round((record.sum * 1.0) / record.count) / 10.;\n            sb.append(entry.getKey()).append(\"=\").append(min).append(\"/\").append(avg).append(\"/\").append(max).append(\", \");\n        }\n        int stringLength = sb.length();\n        sb.setCharAt(stringLength - 2, '}');\n        sb.setCharAt(stringLength - 1, '\\n');\n        System.out.print(sb.toString());\n        System.out.close();\n    }\n\n    private static final boolean citiesDiffer(final long a, final long b, final long len) {\n        int part = 0;\n        for (; part < (len - 1) >> 3; part++)\n            if (UNSAFE.getLong(a + (part << 3)) != UNSAFE.getLong(b + (part << 3)))\n                return true;\n        if (((UNSAFE.getLong(a + (part << 3)) ^ (UNSAFE.getLong(b + (part << 3)))) << ((8 - (len & 7)) << 3)) != 0)\n            return true;\n        return false;\n    }\n\n    private static void threadMain(int id, long startAddr, long endAddr, long nThreads) {\n        // snap to newlines\n        if (id != 0)\n            while (UNSAFE.getByte(startAddr++) != '\\n')\n                ;\n        if (id != nThreads - 1)\n            while (UNSAFE.getByte(endAddr++) != '\\n')\n                ;\n\n        final long threadResults = unsafeResults + id * MAXINDEX * RECORDSIZE;\n        final Record[] results = new Record[MAXINDEX];\n        final long VECTORBYTESIZE = SPECIES.length();\n        final ByteOrder BYTEORDER = ByteOrder.nativeOrder();\n        final ByteVector delim = ByteVector.broadcast(SPECIES, ';');\n        long cityAddr = startAddr;\n        long ptr = 0;\n        while (cityAddr < endAddr) {\n            // parse city\n            ByteVector parsed = ByteVector.fromMemorySegment(SPECIES, VAS, cityAddr, BYTEORDER);\n            long mask = parsed.compare(VectorOperators.EQ, delim).toLong();\n            while (mask == 0) {\n                ptr += VECTORBYTESIZE;\n                mask = ByteVector.fromMemorySegment(SPECIES, VAS, cityAddr + ptr, BYTEORDER).compare(VectorOperators.EQ, delim).toLong();\n            }\n            final long cityLength = ptr + Long.numberOfTrailingZeros(mask);\n            final long tempAddr = cityAddr + cityLength + 1;\n            ptr = 0;\n\n            // compute hash table index\n            int index;\n            if (cityLength > 1)\n                index = (UNSAFE.getByte(cityAddr) // mix the first,\n                        ^ (UNSAFE.getByte(cityAddr + 2) << 4) // the third (even if it is the delimiter ';')\n                        ^ (UNSAFE.getByte(tempAddr - 2) << 8) // and the last two bytes of each city's name\n                        ^ (UNSAFE.getByte(tempAddr - 3) << 12))\n                        & 0xFFFF;\n            else\n                index = (UNSAFE.getByte(cityAddr) << 8) & 0xFF00;\n            // resolve collisions with linear probing\n            // use vector api here also, but only if city name fits in one vector length, for faster default case\n            long record = threadResults + index * RECORDSIZE;\n            long recordCityLength = UNSAFE.getLong(record);\n            if (cityLength <= VECTORBYTESIZE) {\n                while (recordCityLength > 0) {\n                    if (cityLength == recordCityLength) {\n                        long sameMask = ByteVector.fromMemorySegment(SPECIES, VAS, UNSAFE.getLong(record + 8), BYTEORDER)\n                                .compare(VectorOperators.EQ, parsed).toLong();\n                        if (Long.numberOfTrailingZeros(~sameMask) >= cityLength)\n                            break;\n                    }\n                    index++;\n                    record = threadResults + index * RECORDSIZE;\n                    recordCityLength = UNSAFE.getLong(record);\n                }\n            }\n            else { // slower normal case for city names with length > VECTORBYTESIZE\n                while (recordCityLength > 0 && (cityLength != recordCityLength || citiesDiffer(UNSAFE.getLong(record + 8), cityAddr, cityLength))) {\n                    index++;\n                    record = threadResults + index * RECORDSIZE;\n                    recordCityLength = UNSAFE.getLong(record);\n                }\n            }\n\n            // add record for new key\n            if (recordCityLength == 0) {\n                UNSAFE.putLong(record, cityLength);\n                UNSAFE.putLong(record + 8, cityAddr);\n                UNSAFE.putInt(record + 16, 1000);\n                UNSAFE.putInt(record + 20, -1000);\n            }\n\n            // parse temp with lookup tables\n            int temp;\n            if (UNSAFE.getByte(tempAddr) == '-') {\n                temp = -lookupDecimal[UNSAFE.getShort(tempAddr + 1)] - lookupFraction[UNSAFE.getShort(tempAddr + 3)];\n                cityAddr = tempAddr + lookupDotNegative[UNSAFE.getShort(tempAddr + 3)];\n            }\n            else {\n                temp = lookupDecimal[UNSAFE.getShort(tempAddr)] + lookupFraction[UNSAFE.getShort(tempAddr + 2)];\n                cityAddr = tempAddr + lookupDotPositive[UNSAFE.getShort(tempAddr + 2)];\n            }\n\n            // merge\n            if (temp < UNSAFE.getInt(record + 16))\n                UNSAFE.putInt(record + 16, temp);\n            if (temp > UNSAFE.getInt(record + 20))\n                UNSAFE.putInt(record + 20, temp);\n            UNSAFE.putLong(record + 24, UNSAFE.getLong(record + 24) + temp);\n            UNSAFE.putInt(record + 32, UNSAFE.getInt(record + 32) + 1);\n        }\n\n        // create strings from raw data\n        // and aggregate results onto TreeMap\n        int idx = 0;\n        byte b[] = new byte[100];\n        _mutex.lock();\n        for (int i = 0; i < MAXINDEX; i++) {\n            if (UNSAFE.getLong(threadResults + i * RECORDSIZE) == 0)\n                continue;\n            final long recordAddress = threadResults + i * RECORDSIZE;\n\n            results[idx] = new Record(UNSAFE.getLong(recordAddress + 8), UNSAFE.getLong(recordAddress));\n            results[idx].min = UNSAFE.getInt(recordAddress + 16);\n            results[idx].max = UNSAFE.getInt(recordAddress + 20);\n            results[idx].sum = UNSAFE.getLong(recordAddress + 24);\n            results[idx].count = UNSAFE.getInt(recordAddress + 32);\n            UNSAFE.copyMemory(null, UNSAFE.getLong(recordAddress + 8), b, Unsafe.ARRAY_BYTE_BASE_OFFSET, UNSAFE.getLong(recordAddress));\n            final Record record = results[idx];\n            aggregateResults.compute(new String(b, 0, (int) results[idx].cityLength, StandardCharsets.UTF_8), (k, v) -> (v == null) ? record : v.merge(record));\n            idx++;\n        }\n        _mutex.unlock();\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CalculateAverage_zerninv.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport sun.misc.Unsafe;\n\nimport java.io.BufferedOutputStream;\nimport java.io.IOException;\nimport java.lang.foreign.Arena;\nimport java.lang.reflect.Field;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.*;\n\npublic class CalculateAverage_zerninv {\n    private static final String FILE = \"./measurements.txt\";\n    private static final int CORES = Runtime.getRuntime().availableProcessors();\n    private static final int CHUNK_SIZE = 1024 * 1024 * 32;\n\n    private static final Unsafe UNSAFE = initUnsafe();\n\n    private static Unsafe initUnsafe() {\n        try {\n            Field unsafe = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            unsafe.setAccessible(true);\n            return (Unsafe) unsafe.get(Unsafe.class);\n        }\n        catch (IllegalAccessException | NoSuchFieldException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        try (var channel = FileChannel.open(Path.of(FILE), StandardOpenOption.READ)) {\n            var fileSize = channel.size();\n            var minChunkSize = Math.min(fileSize, CHUNK_SIZE);\n            var segment = channel.map(FileChannel.MapMode.READ_ONLY, 0, fileSize, Arena.global());\n\n            var tasks = new TaskThread[CORES];\n            for (int i = 0; i < tasks.length; i++) {\n                tasks[i] = new TaskThread((int) (fileSize / minChunkSize / CORES + 1));\n            }\n\n            var chunks = splitByChunks(segment.address(), segment.address() + fileSize, minChunkSize);\n            for (int i = 0; i < chunks.size() - 1; i++) {\n                var task = tasks[i % tasks.length];\n                task.addChunk(chunks.get(i), chunks.get(i + 1));\n            }\n\n            for (var task : tasks) {\n                task.start();\n            }\n\n            var results = new HashMap<String, TemperatureAggregation>();\n            for (var task : tasks) {\n                task.join();\n                task.collectTo(results);\n            }\n\n            var bos = new BufferedOutputStream(System.out);\n            bos.write(new TreeMap<>(results).toString().getBytes(StandardCharsets.UTF_8));\n            bos.write('\\n');\n            bos.flush();\n        }\n    }\n\n    private static List<Long> splitByChunks(long address, long end, long minChunkSize) {\n        // split by chunks\n        List<Long> result = new ArrayList<>((int) ((end - address) / minChunkSize + 1));\n        result.add(address);\n        while (address < end) {\n            address += Math.min(end - address, minChunkSize);\n            while (address < end && UNSAFE.getByte(address++) != '\\n') {\n            }\n            result.add(address);\n        }\n        return result;\n    }\n\n    private static final class TemperatureAggregation {\n        private long sum;\n        private int count;\n        private short min;\n        private short max;\n\n        public TemperatureAggregation(long sum, int count, short min, short max) {\n            this.sum = sum;\n            this.count = count;\n            this.min = min;\n            this.max = max;\n        }\n\n        public void merge(long sum, int count, short min, short max) {\n            this.sum += sum;\n            this.count += count;\n            this.min = this.min < min ? this.min : min;\n            this.max = this.max > max ? this.max : max;\n        }\n\n        @Override\n        public String toString() {\n            return min / 10d + \"/\" + Math.round(sum / 1d / count) / 10d + \"/\" + max / 10d;\n        }\n    }\n\n    private static final class MeasurementContainer {\n        private static final int SIZE = 1 << 17;\n\n        private static final int ENTRY_SIZE = 4 + 4 + 8 + 1 + 8 + 8 + 2 + 2;\n        private static final int COUNT_OFFSET = 0;\n        private static final int HASH_OFFSET = 4;\n        private static final int LAST_BYTES_OFFSET = 8;\n        private static final int SIZE_OFFSET = 16;\n        private static final int ADDRESS_OFFSET = 17;\n        private static final int SUM_OFFSET = 25;\n        private static final int MIN_OFFSET = 33;\n        private static final int MAX_OFFSET = 35;\n\n        private final long address;\n\n        private MeasurementContainer() {\n            address = UNSAFE.allocateMemory(ENTRY_SIZE * SIZE);\n            UNSAFE.setMemory(address, ENTRY_SIZE * SIZE, (byte) 0);\n        }\n\n        public void put(long address, byte size, int hash, long lastBytes, short value) {\n            int idx = Math.abs(hash % SIZE);\n            long ptr = this.address + idx * ENTRY_SIZE;\n            int count;\n            boolean fastEqual;\n\n            while ((count = UNSAFE.getInt(ptr + COUNT_OFFSET)) != 0) {\n                fastEqual = UNSAFE.getInt(ptr + HASH_OFFSET) == hash && UNSAFE.getLong(ptr + LAST_BYTES_OFFSET) == lastBytes;\n                if (fastEqual && UNSAFE.getByte(ptr + SIZE_OFFSET) == size && isEqual(UNSAFE.getLong(ptr + ADDRESS_OFFSET), address, size - 8)) {\n\n                    UNSAFE.putInt(ptr + COUNT_OFFSET, count + 1);\n                    UNSAFE.putLong(ptr + ADDRESS_OFFSET, address);\n                    UNSAFE.putLong(ptr + SUM_OFFSET, UNSAFE.getLong(ptr + SUM_OFFSET) + value);\n                    if (value < UNSAFE.getShort(ptr + MIN_OFFSET)) {\n                        UNSAFE.putShort(ptr + MIN_OFFSET, value);\n                    }\n                    if (value > UNSAFE.getShort(ptr + MAX_OFFSET)) {\n                        UNSAFE.putShort(ptr + MAX_OFFSET, value);\n                    }\n                    return;\n                }\n                idx = (idx + 1) % SIZE;\n                ptr = this.address + idx * ENTRY_SIZE;\n            }\n\n            UNSAFE.putInt(ptr + COUNT_OFFSET, 1);\n            UNSAFE.putInt(ptr + HASH_OFFSET, hash);\n            UNSAFE.putLong(ptr + LAST_BYTES_OFFSET, lastBytes);\n            UNSAFE.putByte(ptr + SIZE_OFFSET, size);\n            UNSAFE.putLong(ptr + ADDRESS_OFFSET, address);\n\n            UNSAFE.putLong(ptr + SUM_OFFSET, value);\n            UNSAFE.putShort(ptr + MIN_OFFSET, value);\n            UNSAFE.putShort(ptr + MAX_OFFSET, value);\n        }\n\n        public void collectTo(Map<String, TemperatureAggregation> results) {\n            int count;\n            for (int i = 0; i < SIZE; i++) {\n                long ptr = this.address + i * ENTRY_SIZE;\n                count = UNSAFE.getInt(ptr + COUNT_OFFSET);\n                if (count != 0) {\n                    var station = createString(UNSAFE.getLong(ptr + ADDRESS_OFFSET), UNSAFE.getByte(ptr + SIZE_OFFSET));\n                    var result = results.get(station);\n                    if (result == null) {\n                        results.put(station, new TemperatureAggregation(\n                                UNSAFE.getLong(ptr + SUM_OFFSET),\n                                count,\n                                UNSAFE.getShort(ptr + MIN_OFFSET),\n                                UNSAFE.getShort(ptr + MAX_OFFSET)));\n                    }\n                    else {\n                        result.merge(UNSAFE.getLong(ptr + SUM_OFFSET), count, UNSAFE.getShort(ptr + MIN_OFFSET), UNSAFE.getShort(ptr + MAX_OFFSET));\n                    }\n                }\n            }\n        }\n\n        private boolean isEqual(long address, long address2, int size) {\n            for (int i = 0; i < size; i += 8) {\n                if (UNSAFE.getLong(address + i) != UNSAFE.getLong(address2 + i)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        private String createString(long address, byte size) {\n            byte[] arr = new byte[size];\n            for (int i = 0; i < size; i++) {\n                arr[i] = UNSAFE.getByte(address + i);\n            }\n            return new String(arr);\n        }\n    }\n\n    private static class TaskThread extends Thread {\n        // #.##\n        private static final int THREE_DIGITS_MASK = 0x2e0000;\n        // #.#\n        private static final int TWO_DIGITS_MASK = 0x2e00;\n        // #.#-\n        private static final int TWO_NEGATIVE_DIGITS_MASK = 0x2e002d;\n        private static final int BYTE_MASK = 0xff;\n\n        private static final int ZERO = '0';\n        private static final long DELIMITER_MASK = 0x3b3b3b3b3b3b3b3bL;\n        private static final long[] SIGNIFICANT_BYTES_MASK = {\n                0,\n                0xff,\n                0xffff,\n                0xffffff,\n                0xffffffffL,\n                0xffffffffffL,\n                0xffffffffffffL,\n                0xffffffffffffffL,\n                0xffffffffffffffffL\n        };\n\n        private final MeasurementContainer container;\n        private final List<Long> begins;\n        private final List<Long> ends;\n\n        private TaskThread(int chunks) {\n            this.container = new MeasurementContainer();\n            this.begins = new ArrayList<>(chunks);\n            this.ends = new ArrayList<>(chunks);\n        }\n\n        public void addChunk(long begin, long end) {\n            begins.add(begin);\n            ends.add(end);\n        }\n\n        @Override\n        public void run() {\n            for (int i = 0; i < begins.size(); i++) {\n                var begin = begins.get(i);\n                var end = ends.get(i) - 1;\n                while (end > begin && UNSAFE.getByte(end - 1) != '\\n') {\n                    end--;\n                }\n                calcForChunk(begin, end);\n                calcLastLine(end);\n            }\n        }\n\n        private void calcLastLine(long offset) {\n            long cityOffset = offset;\n            long lastBytes = 0;\n            int hashCode = 0;\n            byte cityNameSize = 0;\n\n            byte b;\n            while ((b = UNSAFE.getByte(offset++)) != ';') {\n                lastBytes = (lastBytes << 8) | b;\n                hashCode = hashCode * 31 + b;\n                cityNameSize++;\n            }\n\n            int temperature;\n            int word = UNSAFE.getInt(offset);\n            offset += 4;\n\n            if ((word & TWO_NEGATIVE_DIGITS_MASK) == TWO_NEGATIVE_DIGITS_MASK) {\n                word >>>= 8;\n                temperature = ZERO * 11 - ((word & BYTE_MASK) * 10 + ((word >>> 16) & BYTE_MASK));\n            }\n            else if ((word & THREE_DIGITS_MASK) == THREE_DIGITS_MASK) {\n                temperature = (word & BYTE_MASK) * 100 + ((word >>> 8) & BYTE_MASK) * 10 + ((word >>> 24) & BYTE_MASK) - ZERO * 111;\n            }\n            else if ((word & TWO_DIGITS_MASK) == TWO_DIGITS_MASK) {\n                temperature = (word & BYTE_MASK) * 10 + ((word >>> 16) & BYTE_MASK) - ZERO * 11;\n            }\n            else {\n                // #.##-\n                word = (word >>> 8) | (UNSAFE.getByte(offset) << 24);\n                temperature = ZERO * 111 - ((word & BYTE_MASK) * 100 + ((word >>> 8) & BYTE_MASK) * 10 + ((word >>> 24) & BYTE_MASK));\n            }\n            container.put(cityOffset, cityNameSize, hashCode, lastBytes, (short) temperature);\n        }\n\n        private void calcForChunk(long offset, long end) {\n            long cityOffset, lastBytes, city, masked, hashCode;\n            int temperature, word, delimiterIdx;\n            byte cityNameSize;\n\n            while (offset < end) {\n                cityOffset = offset;\n                lastBytes = 0;\n                hashCode = 0;\n                delimiterIdx = 8;\n\n                while (delimiterIdx == 8) {\n                    city = UNSAFE.getLong(offset);\n                    masked = city ^ DELIMITER_MASK;\n                    masked = (masked - 0x0101010101010101L) & ~masked & 0x8080808080808080L;\n                    delimiterIdx = Long.numberOfTrailingZeros(masked) >>> 3;\n                    if (delimiterIdx == 0) {\n                        break;\n                    }\n                    offset += delimiterIdx;\n                    lastBytes = city & SIGNIFICANT_BYTES_MASK[delimiterIdx];\n                    hashCode = ((hashCode >>> 5) ^ lastBytes) * 0x517cc1b727220a95L;\n                }\n\n                cityNameSize = (byte) (offset - cityOffset);\n\n                word = UNSAFE.getInt(++offset);\n                offset += 4;\n\n                if ((word & TWO_NEGATIVE_DIGITS_MASK) == TWO_NEGATIVE_DIGITS_MASK) {\n                    word >>>= 8;\n                    temperature = ZERO * 11 - ((word & BYTE_MASK) * 10 + ((word >>> 16) & BYTE_MASK));\n                }\n                else if ((word & THREE_DIGITS_MASK) == THREE_DIGITS_MASK) {\n                    temperature = (word & BYTE_MASK) * 100 + ((word >>> 8) & BYTE_MASK) * 10 + ((word >>> 24) & BYTE_MASK) - ZERO * 111;\n                }\n                else if ((word & TWO_DIGITS_MASK) == TWO_DIGITS_MASK) {\n                    temperature = (word & BYTE_MASK) * 10 + ((word >>> 16) & BYTE_MASK) - ZERO * 11;\n                    offset--;\n                }\n                else {\n                    // #.##-\n                    word = (word >>> 8) | (UNSAFE.getByte(offset++) << 24);\n                    temperature = ZERO * 111 - ((word & BYTE_MASK) * 100 + ((word >>> 8) & BYTE_MASK) * 10 + ((word >>> 24) & BYTE_MASK));\n                }\n                offset++;\n                container.put(cityOffset, cityNameSize, Long.hashCode(hashCode), lastBytes, (short) temperature);\n            }\n        }\n\n        public void collectTo(Map<String, TemperatureAggregation> results) {\n            container.collectTo(results);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CreateMeasurements.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedWriter;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class CreateMeasurements {\n\n    private static final Path MEASUREMENT_FILE = Path.of(\"./measurements.txt\");\n\n    private record WeatherStation(String id, double meanTemperature) {\n        double measurement() {\n            double m = ThreadLocalRandom.current().nextGaussian(meanTemperature, 10);\n            return Math.round(m * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        long start = System.currentTimeMillis();\n\n        if (args.length != 1) {\n            System.out.println(\"Usage: create_measurements.sh <number of records to create>\");\n            System.exit(1);\n        }\n\n        int size = 0;\n        try {\n            size = Integer.parseInt(args[0]);\n        }\n        catch (NumberFormatException e) {\n            System.out.println(\"Invalid value for <number of records to create>\");\n            System.out.println(\"Usage: CreateMeasurements <number of records to create>\");\n            System.exit(1);\n        }\n\n        // @formatter:off\n        // data from https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature;\n        // converted using https://wikitable2csv.ggor.de/\n        // brought to form using DuckDB:\n        // D copy (\n        //     select City, regexp_extract(Year,'(.*)\\n.*', 1) as AverageTemp\n        //     from (\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_1.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_2.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_3.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_4.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_5.csv', header = true)\n        //         )\n        // ) TO 'output.csv' (HEADER, DELIMITER ',');\n        // @formatter:on\n        List<WeatherStation> stations = List.of(\n                new WeatherStation(\"Abha\", 18.0),\n                new WeatherStation(\"Abidjan\", 26.0),\n                new WeatherStation(\"Abéché\", 29.4),\n                new WeatherStation(\"Accra\", 26.4),\n                new WeatherStation(\"Addis Ababa\", 16.0),\n                new WeatherStation(\"Adelaide\", 17.3),\n                new WeatherStation(\"Aden\", 29.1),\n                new WeatherStation(\"Ahvaz\", 25.4),\n                new WeatherStation(\"Albuquerque\", 14.0),\n                new WeatherStation(\"Alexandra\", 11.0),\n                new WeatherStation(\"Alexandria\", 20.0),\n                new WeatherStation(\"Algiers\", 18.2),\n                new WeatherStation(\"Alice Springs\", 21.0),\n                new WeatherStation(\"Almaty\", 10.0),\n                new WeatherStation(\"Amsterdam\", 10.2),\n                new WeatherStation(\"Anadyr\", -6.9),\n                new WeatherStation(\"Anchorage\", 2.8),\n                new WeatherStation(\"Andorra la Vella\", 9.8),\n                new WeatherStation(\"Ankara\", 12.0),\n                new WeatherStation(\"Antananarivo\", 17.9),\n                new WeatherStation(\"Antsiranana\", 25.2),\n                new WeatherStation(\"Arkhangelsk\", 1.3),\n                new WeatherStation(\"Ashgabat\", 17.1),\n                new WeatherStation(\"Asmara\", 15.6),\n                new WeatherStation(\"Assab\", 30.5),\n                new WeatherStation(\"Astana\", 3.5),\n                new WeatherStation(\"Athens\", 19.2),\n                new WeatherStation(\"Atlanta\", 17.0),\n                new WeatherStation(\"Auckland\", 15.2),\n                new WeatherStation(\"Austin\", 20.7),\n                new WeatherStation(\"Baghdad\", 22.77),\n                new WeatherStation(\"Baguio\", 19.5),\n                new WeatherStation(\"Baku\", 15.1),\n                new WeatherStation(\"Baltimore\", 13.1),\n                new WeatherStation(\"Bamako\", 27.8),\n                new WeatherStation(\"Bangkok\", 28.6),\n                new WeatherStation(\"Bangui\", 26.0),\n                new WeatherStation(\"Banjul\", 26.0),\n                new WeatherStation(\"Barcelona\", 18.2),\n                new WeatherStation(\"Bata\", 25.1),\n                new WeatherStation(\"Batumi\", 14.0),\n                new WeatherStation(\"Beijing\", 12.9),\n                new WeatherStation(\"Beirut\", 20.9),\n                new WeatherStation(\"Belgrade\", 12.5),\n                new WeatherStation(\"Belize City\", 26.7),\n                new WeatherStation(\"Benghazi\", 19.9),\n                new WeatherStation(\"Bergen\", 7.7),\n                new WeatherStation(\"Berlin\", 10.3),\n                new WeatherStation(\"Bilbao\", 14.7),\n                new WeatherStation(\"Birao\", 26.5),\n                new WeatherStation(\"Bishkek\", 11.3),\n                new WeatherStation(\"Bissau\", 27.0),\n                new WeatherStation(\"Blantyre\", 22.2),\n                new WeatherStation(\"Bloemfontein\", 15.6),\n                new WeatherStation(\"Boise\", 11.4),\n                new WeatherStation(\"Bordeaux\", 14.2),\n                new WeatherStation(\"Bosaso\", 30.0),\n                new WeatherStation(\"Boston\", 10.9),\n                new WeatherStation(\"Bouaké\", 26.0),\n                new WeatherStation(\"Bratislava\", 10.5),\n                new WeatherStation(\"Brazzaville\", 25.0),\n                new WeatherStation(\"Bridgetown\", 27.0),\n                new WeatherStation(\"Brisbane\", 21.4),\n                new WeatherStation(\"Brussels\", 10.5),\n                new WeatherStation(\"Bucharest\", 10.8),\n                new WeatherStation(\"Budapest\", 11.3),\n                new WeatherStation(\"Bujumbura\", 23.8),\n                new WeatherStation(\"Bulawayo\", 18.9),\n                new WeatherStation(\"Burnie\", 13.1),\n                new WeatherStation(\"Busan\", 15.0),\n                new WeatherStation(\"Cabo San Lucas\", 23.9),\n                new WeatherStation(\"Cairns\", 25.0),\n                new WeatherStation(\"Cairo\", 21.4),\n                new WeatherStation(\"Calgary\", 4.4),\n                new WeatherStation(\"Canberra\", 13.1),\n                new WeatherStation(\"Cape Town\", 16.2),\n                new WeatherStation(\"Changsha\", 17.4),\n                new WeatherStation(\"Charlotte\", 16.1),\n                new WeatherStation(\"Chiang Mai\", 25.8),\n                new WeatherStation(\"Chicago\", 9.8),\n                new WeatherStation(\"Chihuahua\", 18.6),\n                new WeatherStation(\"Chișinău\", 10.2),\n                new WeatherStation(\"Chittagong\", 25.9),\n                new WeatherStation(\"Chongqing\", 18.6),\n                new WeatherStation(\"Christchurch\", 12.2),\n                new WeatherStation(\"City of San Marino\", 11.8),\n                new WeatherStation(\"Colombo\", 27.4),\n                new WeatherStation(\"Columbus\", 11.7),\n                new WeatherStation(\"Conakry\", 26.4),\n                new WeatherStation(\"Copenhagen\", 9.1),\n                new WeatherStation(\"Cotonou\", 27.2),\n                new WeatherStation(\"Cracow\", 9.3),\n                new WeatherStation(\"Da Lat\", 17.9),\n                new WeatherStation(\"Da Nang\", 25.8),\n                new WeatherStation(\"Dakar\", 24.0),\n                new WeatherStation(\"Dallas\", 19.0),\n                new WeatherStation(\"Damascus\", 17.0),\n                new WeatherStation(\"Dampier\", 26.4),\n                new WeatherStation(\"Dar es Salaam\", 25.8),\n                new WeatherStation(\"Darwin\", 27.6),\n                new WeatherStation(\"Denpasar\", 23.7),\n                new WeatherStation(\"Denver\", 10.4),\n                new WeatherStation(\"Detroit\", 10.0),\n                new WeatherStation(\"Dhaka\", 25.9),\n                new WeatherStation(\"Dikson\", -11.1),\n                new WeatherStation(\"Dili\", 26.6),\n                new WeatherStation(\"Djibouti\", 29.9),\n                new WeatherStation(\"Dodoma\", 22.7),\n                new WeatherStation(\"Dolisie\", 24.0),\n                new WeatherStation(\"Douala\", 26.7),\n                new WeatherStation(\"Dubai\", 26.9),\n                new WeatherStation(\"Dublin\", 9.8),\n                new WeatherStation(\"Dunedin\", 11.1),\n                new WeatherStation(\"Durban\", 20.6),\n                new WeatherStation(\"Dushanbe\", 14.7),\n                new WeatherStation(\"Edinburgh\", 9.3),\n                new WeatherStation(\"Edmonton\", 4.2),\n                new WeatherStation(\"El Paso\", 18.1),\n                new WeatherStation(\"Entebbe\", 21.0),\n                new WeatherStation(\"Erbil\", 19.5),\n                new WeatherStation(\"Erzurum\", 5.1),\n                new WeatherStation(\"Fairbanks\", -2.3),\n                new WeatherStation(\"Fianarantsoa\", 17.9),\n                new WeatherStation(\"Flores,  Petén\", 26.4),\n                new WeatherStation(\"Frankfurt\", 10.6),\n                new WeatherStation(\"Fresno\", 17.9),\n                new WeatherStation(\"Fukuoka\", 17.0),\n                new WeatherStation(\"Gabès\", 19.5),\n                new WeatherStation(\"Gaborone\", 21.0),\n                new WeatherStation(\"Gagnoa\", 26.0),\n                new WeatherStation(\"Gangtok\", 15.2),\n                new WeatherStation(\"Garissa\", 29.3),\n                new WeatherStation(\"Garoua\", 28.3),\n                new WeatherStation(\"George Town\", 27.9),\n                new WeatherStation(\"Ghanzi\", 21.4),\n                new WeatherStation(\"Gjoa Haven\", -14.4),\n                new WeatherStation(\"Guadalajara\", 20.9),\n                new WeatherStation(\"Guangzhou\", 22.4),\n                new WeatherStation(\"Guatemala City\", 20.4),\n                new WeatherStation(\"Halifax\", 7.5),\n                new WeatherStation(\"Hamburg\", 9.7),\n                new WeatherStation(\"Hamilton\", 13.8),\n                new WeatherStation(\"Hanga Roa\", 20.5),\n                new WeatherStation(\"Hanoi\", 23.6),\n                new WeatherStation(\"Harare\", 18.4),\n                new WeatherStation(\"Harbin\", 5.0),\n                new WeatherStation(\"Hargeisa\", 21.7),\n                new WeatherStation(\"Hat Yai\", 27.0),\n                new WeatherStation(\"Havana\", 25.2),\n                new WeatherStation(\"Helsinki\", 5.9),\n                new WeatherStation(\"Heraklion\", 18.9),\n                new WeatherStation(\"Hiroshima\", 16.3),\n                new WeatherStation(\"Ho Chi Minh City\", 27.4),\n                new WeatherStation(\"Hobart\", 12.7),\n                new WeatherStation(\"Hong Kong\", 23.3),\n                new WeatherStation(\"Honiara\", 26.5),\n                new WeatherStation(\"Honolulu\", 25.4),\n                new WeatherStation(\"Houston\", 20.8),\n                new WeatherStation(\"Ifrane\", 11.4),\n                new WeatherStation(\"Indianapolis\", 11.8),\n                new WeatherStation(\"Iqaluit\", -9.3),\n                new WeatherStation(\"Irkutsk\", 1.0),\n                new WeatherStation(\"Istanbul\", 13.9),\n                new WeatherStation(\"İzmir\", 17.9),\n                new WeatherStation(\"Jacksonville\", 20.3),\n                new WeatherStation(\"Jakarta\", 26.7),\n                new WeatherStation(\"Jayapura\", 27.0),\n                new WeatherStation(\"Jerusalem\", 18.3),\n                new WeatherStation(\"Johannesburg\", 15.5),\n                new WeatherStation(\"Jos\", 22.8),\n                new WeatherStation(\"Juba\", 27.8),\n                new WeatherStation(\"Kabul\", 12.1),\n                new WeatherStation(\"Kampala\", 20.0),\n                new WeatherStation(\"Kandi\", 27.7),\n                new WeatherStation(\"Kankan\", 26.5),\n                new WeatherStation(\"Kano\", 26.4),\n                new WeatherStation(\"Kansas City\", 12.5),\n                new WeatherStation(\"Karachi\", 26.0),\n                new WeatherStation(\"Karonga\", 24.4),\n                new WeatherStation(\"Kathmandu\", 18.3),\n                new WeatherStation(\"Khartoum\", 29.9),\n                new WeatherStation(\"Kingston\", 27.4),\n                new WeatherStation(\"Kinshasa\", 25.3),\n                new WeatherStation(\"Kolkata\", 26.7),\n                new WeatherStation(\"Kuala Lumpur\", 27.3),\n                new WeatherStation(\"Kumasi\", 26.0),\n                new WeatherStation(\"Kunming\", 15.7),\n                new WeatherStation(\"Kuopio\", 3.4),\n                new WeatherStation(\"Kuwait City\", 25.7),\n                new WeatherStation(\"Kyiv\", 8.4),\n                new WeatherStation(\"Kyoto\", 15.8),\n                new WeatherStation(\"La Ceiba\", 26.2),\n                new WeatherStation(\"La Paz\", 23.7),\n                new WeatherStation(\"Lagos\", 26.8),\n                new WeatherStation(\"Lahore\", 24.3),\n                new WeatherStation(\"Lake Havasu City\", 23.7),\n                new WeatherStation(\"Lake Tekapo\", 8.7),\n                new WeatherStation(\"Las Palmas de Gran Canaria\", 21.2),\n                new WeatherStation(\"Las Vegas\", 20.3),\n                new WeatherStation(\"Launceston\", 13.1),\n                new WeatherStation(\"Lhasa\", 7.6),\n                new WeatherStation(\"Libreville\", 25.9),\n                new WeatherStation(\"Lisbon\", 17.5),\n                new WeatherStation(\"Livingstone\", 21.8),\n                new WeatherStation(\"Ljubljana\", 10.9),\n                new WeatherStation(\"Lodwar\", 29.3),\n                new WeatherStation(\"Lomé\", 26.9),\n                new WeatherStation(\"London\", 11.3),\n                new WeatherStation(\"Los Angeles\", 18.6),\n                new WeatherStation(\"Louisville\", 13.9),\n                new WeatherStation(\"Luanda\", 25.8),\n                new WeatherStation(\"Lubumbashi\", 20.8),\n                new WeatherStation(\"Lusaka\", 19.9),\n                new WeatherStation(\"Luxembourg City\", 9.3),\n                new WeatherStation(\"Lviv\", 7.8),\n                new WeatherStation(\"Lyon\", 12.5),\n                new WeatherStation(\"Madrid\", 15.0),\n                new WeatherStation(\"Mahajanga\", 26.3),\n                new WeatherStation(\"Makassar\", 26.7),\n                new WeatherStation(\"Makurdi\", 26.0),\n                new WeatherStation(\"Malabo\", 26.3),\n                new WeatherStation(\"Malé\", 28.0),\n                new WeatherStation(\"Managua\", 27.3),\n                new WeatherStation(\"Manama\", 26.5),\n                new WeatherStation(\"Mandalay\", 28.0),\n                new WeatherStation(\"Mango\", 28.1),\n                new WeatherStation(\"Manila\", 28.4),\n                new WeatherStation(\"Maputo\", 22.8),\n                new WeatherStation(\"Marrakesh\", 19.6),\n                new WeatherStation(\"Marseille\", 15.8),\n                new WeatherStation(\"Maun\", 22.4),\n                new WeatherStation(\"Medan\", 26.5),\n                new WeatherStation(\"Mek'ele\", 22.7),\n                new WeatherStation(\"Melbourne\", 15.1),\n                new WeatherStation(\"Memphis\", 17.2),\n                new WeatherStation(\"Mexicali\", 23.1),\n                new WeatherStation(\"Mexico City\", 17.5),\n                new WeatherStation(\"Miami\", 24.9),\n                new WeatherStation(\"Milan\", 13.0),\n                new WeatherStation(\"Milwaukee\", 8.9),\n                new WeatherStation(\"Minneapolis\", 7.8),\n                new WeatherStation(\"Minsk\", 6.7),\n                new WeatherStation(\"Mogadishu\", 27.1),\n                new WeatherStation(\"Mombasa\", 26.3),\n                new WeatherStation(\"Monaco\", 16.4),\n                new WeatherStation(\"Moncton\", 6.1),\n                new WeatherStation(\"Monterrey\", 22.3),\n                new WeatherStation(\"Montreal\", 6.8),\n                new WeatherStation(\"Moscow\", 5.8),\n                new WeatherStation(\"Mumbai\", 27.1),\n                new WeatherStation(\"Murmansk\", 0.6),\n                new WeatherStation(\"Muscat\", 28.0),\n                new WeatherStation(\"Mzuzu\", 17.7),\n                new WeatherStation(\"N'Djamena\", 28.3),\n                new WeatherStation(\"Naha\", 23.1),\n                new WeatherStation(\"Nairobi\", 17.8),\n                new WeatherStation(\"Nakhon Ratchasima\", 27.3),\n                new WeatherStation(\"Napier\", 14.6),\n                new WeatherStation(\"Napoli\", 15.9),\n                new WeatherStation(\"Nashville\", 15.4),\n                new WeatherStation(\"Nassau\", 24.6),\n                new WeatherStation(\"Ndola\", 20.3),\n                new WeatherStation(\"New Delhi\", 25.0),\n                new WeatherStation(\"New Orleans\", 20.7),\n                new WeatherStation(\"New York City\", 12.9),\n                new WeatherStation(\"Ngaoundéré\", 22.0),\n                new WeatherStation(\"Niamey\", 29.3),\n                new WeatherStation(\"Nicosia\", 19.7),\n                new WeatherStation(\"Niigata\", 13.9),\n                new WeatherStation(\"Nouadhibou\", 21.3),\n                new WeatherStation(\"Nouakchott\", 25.7),\n                new WeatherStation(\"Novosibirsk\", 1.7),\n                new WeatherStation(\"Nuuk\", -1.4),\n                new WeatherStation(\"Odesa\", 10.7),\n                new WeatherStation(\"Odienné\", 26.0),\n                new WeatherStation(\"Oklahoma City\", 15.9),\n                new WeatherStation(\"Omaha\", 10.6),\n                new WeatherStation(\"Oranjestad\", 28.1),\n                new WeatherStation(\"Oslo\", 5.7),\n                new WeatherStation(\"Ottawa\", 6.6),\n                new WeatherStation(\"Ouagadougou\", 28.3),\n                new WeatherStation(\"Ouahigouya\", 28.6),\n                new WeatherStation(\"Ouarzazate\", 18.9),\n                new WeatherStation(\"Oulu\", 2.7),\n                new WeatherStation(\"Palembang\", 27.3),\n                new WeatherStation(\"Palermo\", 18.5),\n                new WeatherStation(\"Palm Springs\", 24.5),\n                new WeatherStation(\"Palmerston North\", 13.2),\n                new WeatherStation(\"Panama City\", 28.0),\n                new WeatherStation(\"Parakou\", 26.8),\n                new WeatherStation(\"Paris\", 12.3),\n                new WeatherStation(\"Perth\", 18.7),\n                new WeatherStation(\"Petropavlovsk-Kamchatsky\", 1.9),\n                new WeatherStation(\"Philadelphia\", 13.2),\n                new WeatherStation(\"Phnom Penh\", 28.3),\n                new WeatherStation(\"Phoenix\", 23.9),\n                new WeatherStation(\"Pittsburgh\", 10.8),\n                new WeatherStation(\"Podgorica\", 15.3),\n                new WeatherStation(\"Pointe-Noire\", 26.1),\n                new WeatherStation(\"Pontianak\", 27.7),\n                new WeatherStation(\"Port Moresby\", 26.9),\n                new WeatherStation(\"Port Sudan\", 28.4),\n                new WeatherStation(\"Port Vila\", 24.3),\n                new WeatherStation(\"Port-Gentil\", 26.0),\n                new WeatherStation(\"Portland (OR)\", 12.4),\n                new WeatherStation(\"Porto\", 15.7),\n                new WeatherStation(\"Prague\", 8.4),\n                new WeatherStation(\"Praia\", 24.4),\n                new WeatherStation(\"Pretoria\", 18.2),\n                new WeatherStation(\"Pyongyang\", 10.8),\n                new WeatherStation(\"Rabat\", 17.2),\n                new WeatherStation(\"Rangpur\", 24.4),\n                new WeatherStation(\"Reggane\", 28.3),\n                new WeatherStation(\"Reykjavík\", 4.3),\n                new WeatherStation(\"Riga\", 6.2),\n                new WeatherStation(\"Riyadh\", 26.0),\n                new WeatherStation(\"Rome\", 15.2),\n                new WeatherStation(\"Roseau\", 26.2),\n                new WeatherStation(\"Rostov-on-Don\", 9.9),\n                new WeatherStation(\"Sacramento\", 16.3),\n                new WeatherStation(\"Saint Petersburg\", 5.8),\n                new WeatherStation(\"Saint-Pierre\", 5.7),\n                new WeatherStation(\"Salt Lake City\", 11.6),\n                new WeatherStation(\"San Antonio\", 20.8),\n                new WeatherStation(\"San Diego\", 17.8),\n                new WeatherStation(\"San Francisco\", 14.6),\n                new WeatherStation(\"San Jose\", 16.4),\n                new WeatherStation(\"San José\", 22.6),\n                new WeatherStation(\"San Juan\", 27.2),\n                new WeatherStation(\"San Salvador\", 23.1),\n                new WeatherStation(\"Sana'a\", 20.0),\n                new WeatherStation(\"Santo Domingo\", 25.9),\n                new WeatherStation(\"Sapporo\", 8.9),\n                new WeatherStation(\"Sarajevo\", 10.1),\n                new WeatherStation(\"Saskatoon\", 3.3),\n                new WeatherStation(\"Seattle\", 11.3),\n                new WeatherStation(\"Ségou\", 28.0),\n                new WeatherStation(\"Seoul\", 12.5),\n                new WeatherStation(\"Seville\", 19.2),\n                new WeatherStation(\"Shanghai\", 16.7),\n                new WeatherStation(\"Singapore\", 27.0),\n                new WeatherStation(\"Skopje\", 12.4),\n                new WeatherStation(\"Sochi\", 14.2),\n                new WeatherStation(\"Sofia\", 10.6),\n                new WeatherStation(\"Sokoto\", 28.0),\n                new WeatherStation(\"Split\", 16.1),\n                new WeatherStation(\"St. John's\", 5.0),\n                new WeatherStation(\"St. Louis\", 13.9),\n                new WeatherStation(\"Stockholm\", 6.6),\n                new WeatherStation(\"Surabaya\", 27.1),\n                new WeatherStation(\"Suva\", 25.6),\n                new WeatherStation(\"Suwałki\", 7.2),\n                new WeatherStation(\"Sydney\", 17.7),\n                new WeatherStation(\"Tabora\", 23.0),\n                new WeatherStation(\"Tabriz\", 12.6),\n                new WeatherStation(\"Taipei\", 23.0),\n                new WeatherStation(\"Tallinn\", 6.4),\n                new WeatherStation(\"Tamale\", 27.9),\n                new WeatherStation(\"Tamanrasset\", 21.7),\n                new WeatherStation(\"Tampa\", 22.9),\n                new WeatherStation(\"Tashkent\", 14.8),\n                new WeatherStation(\"Tauranga\", 14.8),\n                new WeatherStation(\"Tbilisi\", 12.9),\n                new WeatherStation(\"Tegucigalpa\", 21.7),\n                new WeatherStation(\"Tehran\", 17.0),\n                new WeatherStation(\"Tel Aviv\", 20.0),\n                new WeatherStation(\"Thessaloniki\", 16.0),\n                new WeatherStation(\"Thiès\", 24.0),\n                new WeatherStation(\"Tijuana\", 17.8),\n                new WeatherStation(\"Timbuktu\", 28.0),\n                new WeatherStation(\"Tirana\", 15.2),\n                new WeatherStation(\"Toamasina\", 23.4),\n                new WeatherStation(\"Tokyo\", 15.4),\n                new WeatherStation(\"Toliara\", 24.1),\n                new WeatherStation(\"Toluca\", 12.4),\n                new WeatherStation(\"Toronto\", 9.4),\n                new WeatherStation(\"Tripoli\", 20.0),\n                new WeatherStation(\"Tromsø\", 2.9),\n                new WeatherStation(\"Tucson\", 20.9),\n                new WeatherStation(\"Tunis\", 18.4),\n                new WeatherStation(\"Ulaanbaatar\", -0.4),\n                new WeatherStation(\"Upington\", 20.4),\n                new WeatherStation(\"Ürümqi\", 7.4),\n                new WeatherStation(\"Vaduz\", 10.1),\n                new WeatherStation(\"Valencia\", 18.3),\n                new WeatherStation(\"Valletta\", 18.8),\n                new WeatherStation(\"Vancouver\", 10.4),\n                new WeatherStation(\"Veracruz\", 25.4),\n                new WeatherStation(\"Vienna\", 10.4),\n                new WeatherStation(\"Vientiane\", 25.9),\n                new WeatherStation(\"Villahermosa\", 27.1),\n                new WeatherStation(\"Vilnius\", 6.0),\n                new WeatherStation(\"Virginia Beach\", 15.8),\n                new WeatherStation(\"Vladivostok\", 4.9),\n                new WeatherStation(\"Warsaw\", 8.5),\n                new WeatherStation(\"Washington, D.C.\", 14.6),\n                new WeatherStation(\"Wau\", 27.8),\n                new WeatherStation(\"Wellington\", 12.9),\n                new WeatherStation(\"Whitehorse\", -0.1),\n                new WeatherStation(\"Wichita\", 13.9),\n                new WeatherStation(\"Willemstad\", 28.0),\n                new WeatherStation(\"Winnipeg\", 3.0),\n                new WeatherStation(\"Wrocław\", 9.6),\n                new WeatherStation(\"Xi'an\", 14.1),\n                new WeatherStation(\"Yakutsk\", -8.8),\n                new WeatherStation(\"Yangon\", 27.5),\n                new WeatherStation(\"Yaoundé\", 23.8),\n                new WeatherStation(\"Yellowknife\", -4.3),\n                new WeatherStation(\"Yerevan\", 12.4),\n                new WeatherStation(\"Yinchuan\", 9.0),\n                new WeatherStation(\"Zagreb\", 10.7),\n                new WeatherStation(\"Zanzibar City\", 26.0),\n                new WeatherStation(\"Zürich\", 9.3));\n\n        try (BufferedWriter bw = Files.newBufferedWriter(MEASUREMENT_FILE)) {\n            for (int i = 0; i < size; i++) {\n                if (i > 0 && i % 50_000_000 == 0) {\n                    System.out.printf(\"Wrote %,d measurements in %s ms%n\", i, System.currentTimeMillis() - start);\n                }\n                WeatherStation station = stations.get(ThreadLocalRandom.current().nextInt(stations.size()));\n                bw.write(station.id());\n                bw.write(\";\" + station.measurement());\n                bw.write('\\n');\n            }\n        }\n        System.out.printf(\"Created file with %,d measurements in %s ms%n\", size, System.currentTimeMillis() - start);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CreateMeasurements2.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport org.rschwietzke.CheaperCharBuffer;\nimport org.rschwietzke.FastRandom;\n\n/**\n * Faster version with some data faking instead of a real Gaussian distribution\n * Good enough for our purppose I guess.\n */\npublic class CreateMeasurements2 {\n\n    private static final String FILE = \"./measurements2.txt\";\n\n    static class WeatherStation {\n        final static char[] NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };\n\n        final String id;\n        final int meanTemperature;\n\n        final char[] firstPart;\n        final FastRandom r = new FastRandom(ThreadLocalRandom.current().nextLong());\n\n        WeatherStation(String id, double meanTemperature) {\n            this.id = id;\n            this.meanTemperature = (int) meanTemperature;\n            // make it directly copyable\n            this.firstPart = (id + \";\").toCharArray();\n        }\n\n        /**\n         * We write out data into the buffer to avoid string conversion\n         * We also no longer use double and gaussian, because for our\n         * purpose, the fake numbers here will do it. Less\n         *\n         * @param buffer the buffer to append to\n         */\n        void measurement(final CheaperCharBuffer buffer) {\n            // fake -10.9 to +10.9 variance without double operations and rounding\n            // gives us -10 to +10\n            int m = meanTemperature + (r.nextInt(21) - 10);\n            // gives us a decimal digit 0 to 9 as char\n            char d = NUMBERS[r.nextInt(10)];\n\n            // just append, only one number has to be converted and we can do\n            // better... if we watn\n            buffer.append(firstPart, 0, firstPart.length)\n                    .append(String.valueOf(m)).append('.').append(d)\n                    .append('\\n');\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        long start = System.currentTimeMillis();\n\n        if (args.length != 1) {\n            System.out.println(\"Usage: create_measurements.sh <number of records to create>\");\n            System.exit(1);\n        }\n\n        int size = 0;\n        try {\n            size = Integer.parseInt(args[0]);\n        }\n        catch (NumberFormatException e) {\n            System.out.println(\"Invalid value for <number of records to create>\");\n            System.out.println(\"Usage: CreateMeasurements <number of records to create>\");\n            System.exit(1);\n        }\n\n        // @formatter:off\n        // data from https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature;\n        // converted using https://wikitable2csv.ggor.de/\n        // brought to form using DuckDB:\n        // D copy (\n        //     select City, regexp_extract(Year,'(.*)\\n.*', 1) as AverageTemp\n        //     from (\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_1.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_2.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_3.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_4.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_5.csv', header = true)\n        //         )\n        // ) TO 'output.csv' (HEADER, DELIMITER ',');\n        // @formatter:on\n        final List<WeatherStation> stations = Arrays.asList(\n                new WeatherStation(\"Abha\", 18.0),\n                new WeatherStation(\"Abidjan\", 26.0),\n                new WeatherStation(\"Abéché\", 29.4),\n                new WeatherStation(\"Accra\", 26.4),\n                new WeatherStation(\"Addis Ababa\", 16.0),\n                new WeatherStation(\"Adelaide\", 17.3),\n                new WeatherStation(\"Aden\", 29.1),\n                new WeatherStation(\"Ahvaz\", 25.4),\n                new WeatherStation(\"Albuquerque\", 14.0),\n                new WeatherStation(\"Alexandra\", 11.0),\n                new WeatherStation(\"Alexandria\", 20.0),\n                new WeatherStation(\"Algiers\", 18.2),\n                new WeatherStation(\"Alice Springs\", 21.0),\n                new WeatherStation(\"Almaty\", 10.0),\n                new WeatherStation(\"Amsterdam\", 10.2),\n                new WeatherStation(\"Anadyr\", -6.9),\n                new WeatherStation(\"Anchorage\", 2.8),\n                new WeatherStation(\"Andorra la Vella\", 9.8),\n                new WeatherStation(\"Ankara\", 12.0),\n                new WeatherStation(\"Antananarivo\", 17.9),\n                new WeatherStation(\"Antsiranana\", 25.2),\n                new WeatherStation(\"Arkhangelsk\", 1.3),\n                new WeatherStation(\"Ashgabat\", 17.1),\n                new WeatherStation(\"Asmara\", 15.6),\n                new WeatherStation(\"Assab\", 30.5),\n                new WeatherStation(\"Astana\", 3.5),\n                new WeatherStation(\"Athens\", 19.2),\n                new WeatherStation(\"Atlanta\", 17.0),\n                new WeatherStation(\"Auckland\", 15.2),\n                new WeatherStation(\"Austin\", 20.7),\n                new WeatherStation(\"Baghdad\", 22.77),\n                new WeatherStation(\"Baguio\", 19.5),\n                new WeatherStation(\"Baku\", 15.1),\n                new WeatherStation(\"Baltimore\", 13.1),\n                new WeatherStation(\"Bamako\", 27.8),\n                new WeatherStation(\"Bangkok\", 28.6),\n                new WeatherStation(\"Bangui\", 26.0),\n                new WeatherStation(\"Banjul\", 26.0),\n                new WeatherStation(\"Barcelona\", 18.2),\n                new WeatherStation(\"Bata\", 25.1),\n                new WeatherStation(\"Batumi\", 14.0),\n                new WeatherStation(\"Beijing\", 12.9),\n                new WeatherStation(\"Beirut\", 20.9),\n                new WeatherStation(\"Belgrade\", 12.5),\n                new WeatherStation(\"Belize City\", 26.7),\n                new WeatherStation(\"Benghazi\", 19.9),\n                new WeatherStation(\"Bergen\", 7.7),\n                new WeatherStation(\"Berlin\", 10.3),\n                new WeatherStation(\"Bilbao\", 14.7),\n                new WeatherStation(\"Birao\", 26.5),\n                new WeatherStation(\"Bishkek\", 11.3),\n                new WeatherStation(\"Bissau\", 27.0),\n                new WeatherStation(\"Blantyre\", 22.2),\n                new WeatherStation(\"Bloemfontein\", 15.6),\n                new WeatherStation(\"Boise\", 11.4),\n                new WeatherStation(\"Bordeaux\", 14.2),\n                new WeatherStation(\"Bosaso\", 30.0),\n                new WeatherStation(\"Boston\", 10.9),\n                new WeatherStation(\"Bouaké\", 26.0),\n                new WeatherStation(\"Bratislava\", 10.5),\n                new WeatherStation(\"Brazzaville\", 25.0),\n                new WeatherStation(\"Bridgetown\", 27.0),\n                new WeatherStation(\"Brisbane\", 21.4),\n                new WeatherStation(\"Brussels\", 10.5),\n                new WeatherStation(\"Bucharest\", 10.8),\n                new WeatherStation(\"Budapest\", 11.3),\n                new WeatherStation(\"Bujumbura\", 23.8),\n                new WeatherStation(\"Bulawayo\", 18.9),\n                new WeatherStation(\"Burnie\", 13.1),\n                new WeatherStation(\"Busan\", 15.0),\n                new WeatherStation(\"Cabo San Lucas\", 23.9),\n                new WeatherStation(\"Cairns\", 25.0),\n                new WeatherStation(\"Cairo\", 21.4),\n                new WeatherStation(\"Calgary\", 4.4),\n                new WeatherStation(\"Canberra\", 13.1),\n                new WeatherStation(\"Cape Town\", 16.2),\n                new WeatherStation(\"Changsha\", 17.4),\n                new WeatherStation(\"Charlotte\", 16.1),\n                new WeatherStation(\"Chiang Mai\", 25.8),\n                new WeatherStation(\"Chicago\", 9.8),\n                new WeatherStation(\"Chihuahua\", 18.6),\n                new WeatherStation(\"Chișinău\", 10.2),\n                new WeatherStation(\"Chittagong\", 25.9),\n                new WeatherStation(\"Chongqing\", 18.6),\n                new WeatherStation(\"Christchurch\", 12.2),\n                new WeatherStation(\"City of San Marino\", 11.8),\n                new WeatherStation(\"Colombo\", 27.4),\n                new WeatherStation(\"Columbus\", 11.7),\n                new WeatherStation(\"Conakry\", 26.4),\n                new WeatherStation(\"Copenhagen\", 9.1),\n                new WeatherStation(\"Cotonou\", 27.2),\n                new WeatherStation(\"Cracow\", 9.3),\n                new WeatherStation(\"Da Lat\", 17.9),\n                new WeatherStation(\"Da Nang\", 25.8),\n                new WeatherStation(\"Dakar\", 24.0),\n                new WeatherStation(\"Dallas\", 19.0),\n                new WeatherStation(\"Damascus\", 17.0),\n                new WeatherStation(\"Dampier\", 26.4),\n                new WeatherStation(\"Dar es Salaam\", 25.8),\n                new WeatherStation(\"Darwin\", 27.6),\n                new WeatherStation(\"Denpasar\", 23.7),\n                new WeatherStation(\"Denver\", 10.4),\n                new WeatherStation(\"Detroit\", 10.0),\n                new WeatherStation(\"Dhaka\", 25.9),\n                new WeatherStation(\"Dikson\", -11.1),\n                new WeatherStation(\"Dili\", 26.6),\n                new WeatherStation(\"Djibouti\", 29.9),\n                new WeatherStation(\"Dodoma\", 22.7),\n                new WeatherStation(\"Dolisie\", 24.0),\n                new WeatherStation(\"Douala\", 26.7),\n                new WeatherStation(\"Dubai\", 26.9),\n                new WeatherStation(\"Dublin\", 9.8),\n                new WeatherStation(\"Dunedin\", 11.1),\n                new WeatherStation(\"Durban\", 20.6),\n                new WeatherStation(\"Dushanbe\", 14.7),\n                new WeatherStation(\"Edinburgh\", 9.3),\n                new WeatherStation(\"Edmonton\", 4.2),\n                new WeatherStation(\"El Paso\", 18.1),\n                new WeatherStation(\"Entebbe\", 21.0),\n                new WeatherStation(\"Erbil\", 19.5),\n                new WeatherStation(\"Erzurum\", 5.1),\n                new WeatherStation(\"Fairbanks\", -2.3),\n                new WeatherStation(\"Fianarantsoa\", 17.9),\n                new WeatherStation(\"Flores,  Petén\", 26.4),\n                new WeatherStation(\"Frankfurt\", 10.6),\n                new WeatherStation(\"Fresno\", 17.9),\n                new WeatherStation(\"Fukuoka\", 17.0),\n                new WeatherStation(\"Gabès\", 19.5),\n                new WeatherStation(\"Gaborone\", 21.0),\n                new WeatherStation(\"Gagnoa\", 26.0),\n                new WeatherStation(\"Gangtok\", 15.2),\n                new WeatherStation(\"Garissa\", 29.3),\n                new WeatherStation(\"Garoua\", 28.3),\n                new WeatherStation(\"George Town\", 27.9),\n                new WeatherStation(\"Ghanzi\", 21.4),\n                new WeatherStation(\"Gjoa Haven\", -14.4),\n                new WeatherStation(\"Guadalajara\", 20.9),\n                new WeatherStation(\"Guangzhou\", 22.4),\n                new WeatherStation(\"Guatemala City\", 20.4),\n                new WeatherStation(\"Halifax\", 7.5),\n                new WeatherStation(\"Hamburg\", 9.7),\n                new WeatherStation(\"Hamilton\", 13.8),\n                new WeatherStation(\"Hanga Roa\", 20.5),\n                new WeatherStation(\"Hanoi\", 23.6),\n                new WeatherStation(\"Harare\", 18.4),\n                new WeatherStation(\"Harbin\", 5.0),\n                new WeatherStation(\"Hargeisa\", 21.7),\n                new WeatherStation(\"Hat Yai\", 27.0),\n                new WeatherStation(\"Havana\", 25.2),\n                new WeatherStation(\"Helsinki\", 5.9),\n                new WeatherStation(\"Heraklion\", 18.9),\n                new WeatherStation(\"Hiroshima\", 16.3),\n                new WeatherStation(\"Ho Chi Minh City\", 27.4),\n                new WeatherStation(\"Hobart\", 12.7),\n                new WeatherStation(\"Hong Kong\", 23.3),\n                new WeatherStation(\"Honiara\", 26.5),\n                new WeatherStation(\"Honolulu\", 25.4),\n                new WeatherStation(\"Houston\", 20.8),\n                new WeatherStation(\"Ifrane\", 11.4),\n                new WeatherStation(\"Indianapolis\", 11.8),\n                new WeatherStation(\"Iqaluit\", -9.3),\n                new WeatherStation(\"Irkutsk\", 1.0),\n                new WeatherStation(\"Istanbul\", 13.9),\n                new WeatherStation(\"İzmir\", 17.9),\n                new WeatherStation(\"Jacksonville\", 20.3),\n                new WeatherStation(\"Jakarta\", 26.7),\n                new WeatherStation(\"Jayapura\", 27.0),\n                new WeatherStation(\"Jerusalem\", 18.3),\n                new WeatherStation(\"Johannesburg\", 15.5),\n                new WeatherStation(\"Jos\", 22.8),\n                new WeatherStation(\"Juba\", 27.8),\n                new WeatherStation(\"Kabul\", 12.1),\n                new WeatherStation(\"Kampala\", 20.0),\n                new WeatherStation(\"Kandi\", 27.7),\n                new WeatherStation(\"Kankan\", 26.5),\n                new WeatherStation(\"Kano\", 26.4),\n                new WeatherStation(\"Kansas City\", 12.5),\n                new WeatherStation(\"Karachi\", 26.0),\n                new WeatherStation(\"Karonga\", 24.4),\n                new WeatherStation(\"Kathmandu\", 18.3),\n                new WeatherStation(\"Khartoum\", 29.9),\n                new WeatherStation(\"Kingston\", 27.4),\n                new WeatherStation(\"Kinshasa\", 25.3),\n                new WeatherStation(\"Kolkata\", 26.7),\n                new WeatherStation(\"Kuala Lumpur\", 27.3),\n                new WeatherStation(\"Kumasi\", 26.0),\n                new WeatherStation(\"Kunming\", 15.7),\n                new WeatherStation(\"Kuopio\", 3.4),\n                new WeatherStation(\"Kuwait City\", 25.7),\n                new WeatherStation(\"Kyiv\", 8.4),\n                new WeatherStation(\"Kyoto\", 15.8),\n                new WeatherStation(\"La Ceiba\", 26.2),\n                new WeatherStation(\"La Paz\", 23.7),\n                new WeatherStation(\"Lagos\", 26.8),\n                new WeatherStation(\"Lahore\", 24.3),\n                new WeatherStation(\"Lake Havasu City\", 23.7),\n                new WeatherStation(\"Lake Tekapo\", 8.7),\n                new WeatherStation(\"Las Palmas de Gran Canaria\", 21.2),\n                new WeatherStation(\"Las Vegas\", 20.3),\n                new WeatherStation(\"Launceston\", 13.1),\n                new WeatherStation(\"Lhasa\", 7.6),\n                new WeatherStation(\"Libreville\", 25.9),\n                new WeatherStation(\"Lisbon\", 17.5),\n                new WeatherStation(\"Livingstone\", 21.8),\n                new WeatherStation(\"Ljubljana\", 10.9),\n                new WeatherStation(\"Lodwar\", 29.3),\n                new WeatherStation(\"Lomé\", 26.9),\n                new WeatherStation(\"London\", 11.3),\n                new WeatherStation(\"Los Angeles\", 18.6),\n                new WeatherStation(\"Louisville\", 13.9),\n                new WeatherStation(\"Luanda\", 25.8),\n                new WeatherStation(\"Lubumbashi\", 20.8),\n                new WeatherStation(\"Lusaka\", 19.9),\n                new WeatherStation(\"Luxembourg City\", 9.3),\n                new WeatherStation(\"Lviv\", 7.8),\n                new WeatherStation(\"Lyon\", 12.5),\n                new WeatherStation(\"Madrid\", 15.0),\n                new WeatherStation(\"Mahajanga\", 26.3),\n                new WeatherStation(\"Makassar\", 26.7),\n                new WeatherStation(\"Makurdi\", 26.0),\n                new WeatherStation(\"Malabo\", 26.3),\n                new WeatherStation(\"Malé\", 28.0),\n                new WeatherStation(\"Managua\", 27.3),\n                new WeatherStation(\"Manama\", 26.5),\n                new WeatherStation(\"Mandalay\", 28.0),\n                new WeatherStation(\"Mango\", 28.1),\n                new WeatherStation(\"Manila\", 28.4),\n                new WeatherStation(\"Maputo\", 22.8),\n                new WeatherStation(\"Marrakesh\", 19.6),\n                new WeatherStation(\"Marseille\", 15.8),\n                new WeatherStation(\"Maun\", 22.4),\n                new WeatherStation(\"Medan\", 26.5),\n                new WeatherStation(\"Mek'ele\", 22.7),\n                new WeatherStation(\"Melbourne\", 15.1),\n                new WeatherStation(\"Memphis\", 17.2),\n                new WeatherStation(\"Mexicali\", 23.1),\n                new WeatherStation(\"Mexico City\", 17.5),\n                new WeatherStation(\"Miami\", 24.9),\n                new WeatherStation(\"Milan\", 13.0),\n                new WeatherStation(\"Milwaukee\", 8.9),\n                new WeatherStation(\"Minneapolis\", 7.8),\n                new WeatherStation(\"Minsk\", 6.7),\n                new WeatherStation(\"Mogadishu\", 27.1),\n                new WeatherStation(\"Mombasa\", 26.3),\n                new WeatherStation(\"Monaco\", 16.4),\n                new WeatherStation(\"Moncton\", 6.1),\n                new WeatherStation(\"Monterrey\", 22.3),\n                new WeatherStation(\"Montreal\", 6.8),\n                new WeatherStation(\"Moscow\", 5.8),\n                new WeatherStation(\"Mumbai\", 27.1),\n                new WeatherStation(\"Murmansk\", 0.6),\n                new WeatherStation(\"Muscat\", 28.0),\n                new WeatherStation(\"Mzuzu\", 17.7),\n                new WeatherStation(\"N'Djamena\", 28.3),\n                new WeatherStation(\"Naha\", 23.1),\n                new WeatherStation(\"Nairobi\", 17.8),\n                new WeatherStation(\"Nakhon Ratchasima\", 27.3),\n                new WeatherStation(\"Napier\", 14.6),\n                new WeatherStation(\"Napoli\", 15.9),\n                new WeatherStation(\"Nashville\", 15.4),\n                new WeatherStation(\"Nassau\", 24.6),\n                new WeatherStation(\"Ndola\", 20.3),\n                new WeatherStation(\"New Delhi\", 25.0),\n                new WeatherStation(\"New Orleans\", 20.7),\n                new WeatherStation(\"New York City\", 12.9),\n                new WeatherStation(\"Ngaoundéré\", 22.0),\n                new WeatherStation(\"Niamey\", 29.3),\n                new WeatherStation(\"Nicosia\", 19.7),\n                new WeatherStation(\"Niigata\", 13.9),\n                new WeatherStation(\"Nouadhibou\", 21.3),\n                new WeatherStation(\"Nouakchott\", 25.7),\n                new WeatherStation(\"Novosibirsk\", 1.7),\n                new WeatherStation(\"Nuuk\", -1.4),\n                new WeatherStation(\"Odesa\", 10.7),\n                new WeatherStation(\"Odienné\", 26.0),\n                new WeatherStation(\"Oklahoma City\", 15.9),\n                new WeatherStation(\"Omaha\", 10.6),\n                new WeatherStation(\"Oranjestad\", 28.1),\n                new WeatherStation(\"Oslo\", 5.7),\n                new WeatherStation(\"Ottawa\", 6.6),\n                new WeatherStation(\"Ouagadougou\", 28.3),\n                new WeatherStation(\"Ouahigouya\", 28.6),\n                new WeatherStation(\"Ouarzazate\", 18.9),\n                new WeatherStation(\"Oulu\", 2.7),\n                new WeatherStation(\"Palembang\", 27.3),\n                new WeatherStation(\"Palermo\", 18.5),\n                new WeatherStation(\"Palm Springs\", 24.5),\n                new WeatherStation(\"Palmerston North\", 13.2),\n                new WeatherStation(\"Panama City\", 28.0),\n                new WeatherStation(\"Parakou\", 26.8),\n                new WeatherStation(\"Paris\", 12.3),\n                new WeatherStation(\"Perth\", 18.7),\n                new WeatherStation(\"Petropavlovsk-Kamchatsky\", 1.9),\n                new WeatherStation(\"Philadelphia\", 13.2),\n                new WeatherStation(\"Phnom Penh\", 28.3),\n                new WeatherStation(\"Phoenix\", 23.9),\n                new WeatherStation(\"Pittsburgh\", 10.8),\n                new WeatherStation(\"Podgorica\", 15.3),\n                new WeatherStation(\"Pointe-Noire\", 26.1),\n                new WeatherStation(\"Pontianak\", 27.7),\n                new WeatherStation(\"Port Moresby\", 26.9),\n                new WeatherStation(\"Port Sudan\", 28.4),\n                new WeatherStation(\"Port Vila\", 24.3),\n                new WeatherStation(\"Port-Gentil\", 26.0),\n                new WeatherStation(\"Portland (OR)\", 12.4),\n                new WeatherStation(\"Porto\", 15.7),\n                new WeatherStation(\"Prague\", 8.4),\n                new WeatherStation(\"Praia\", 24.4),\n                new WeatherStation(\"Pretoria\", 18.2),\n                new WeatherStation(\"Pyongyang\", 10.8),\n                new WeatherStation(\"Rabat\", 17.2),\n                new WeatherStation(\"Rangpur\", 24.4),\n                new WeatherStation(\"Reggane\", 28.3),\n                new WeatherStation(\"Reykjavík\", 4.3),\n                new WeatherStation(\"Riga\", 6.2),\n                new WeatherStation(\"Riyadh\", 26.0),\n                new WeatherStation(\"Rome\", 15.2),\n                new WeatherStation(\"Roseau\", 26.2),\n                new WeatherStation(\"Rostov-on-Don\", 9.9),\n                new WeatherStation(\"Sacramento\", 16.3),\n                new WeatherStation(\"Saint Petersburg\", 5.8),\n                new WeatherStation(\"Saint-Pierre\", 5.7),\n                new WeatherStation(\"Salt Lake City\", 11.6),\n                new WeatherStation(\"San Antonio\", 20.8),\n                new WeatherStation(\"San Diego\", 17.8),\n                new WeatherStation(\"San Francisco\", 14.6),\n                new WeatherStation(\"San Jose\", 16.4),\n                new WeatherStation(\"San José\", 22.6),\n                new WeatherStation(\"San Juan\", 27.2),\n                new WeatherStation(\"San Salvador\", 23.1),\n                new WeatherStation(\"Sana'a\", 20.0),\n                new WeatherStation(\"Santo Domingo\", 25.9),\n                new WeatherStation(\"Sapporo\", 8.9),\n                new WeatherStation(\"Sarajevo\", 10.1),\n                new WeatherStation(\"Saskatoon\", 3.3),\n                new WeatherStation(\"Seattle\", 11.3),\n                new WeatherStation(\"Ségou\", 28.0),\n                new WeatherStation(\"Seoul\", 12.5),\n                new WeatherStation(\"Seville\", 19.2),\n                new WeatherStation(\"Shanghai\", 16.7),\n                new WeatherStation(\"Singapore\", 27.0),\n                new WeatherStation(\"Skopje\", 12.4),\n                new WeatherStation(\"Sochi\", 14.2),\n                new WeatherStation(\"Sofia\", 10.6),\n                new WeatherStation(\"Sokoto\", 28.0),\n                new WeatherStation(\"Split\", 16.1),\n                new WeatherStation(\"St. John's\", 5.0),\n                new WeatherStation(\"St. Louis\", 13.9),\n                new WeatherStation(\"Stockholm\", 6.6),\n                new WeatherStation(\"Surabaya\", 27.1),\n                new WeatherStation(\"Suva\", 25.6),\n                new WeatherStation(\"Suwałki\", 7.2),\n                new WeatherStation(\"Sydney\", 17.7),\n                new WeatherStation(\"Tabora\", 23.0),\n                new WeatherStation(\"Tabriz\", 12.6),\n                new WeatherStation(\"Taipei\", 23.0),\n                new WeatherStation(\"Tallinn\", 6.4),\n                new WeatherStation(\"Tamale\", 27.9),\n                new WeatherStation(\"Tamanrasset\", 21.7),\n                new WeatherStation(\"Tampa\", 22.9),\n                new WeatherStation(\"Tashkent\", 14.8),\n                new WeatherStation(\"Tauranga\", 14.8),\n                new WeatherStation(\"Tbilisi\", 12.9),\n                new WeatherStation(\"Tegucigalpa\", 21.7),\n                new WeatherStation(\"Tehran\", 17.0),\n                new WeatherStation(\"Tel Aviv\", 20.0),\n                new WeatherStation(\"Thessaloniki\", 16.0),\n                new WeatherStation(\"Thiès\", 24.0),\n                new WeatherStation(\"Tijuana\", 17.8),\n                new WeatherStation(\"Timbuktu\", 28.0),\n                new WeatherStation(\"Tirana\", 15.2),\n                new WeatherStation(\"Toamasina\", 23.4),\n                new WeatherStation(\"Tokyo\", 15.4),\n                new WeatherStation(\"Toliara\", 24.1),\n                new WeatherStation(\"Toluca\", 12.4),\n                new WeatherStation(\"Toronto\", 9.4),\n                new WeatherStation(\"Tripoli\", 20.0),\n                new WeatherStation(\"Tromsø\", 2.9),\n                new WeatherStation(\"Tucson\", 20.9),\n                new WeatherStation(\"Tunis\", 18.4),\n                new WeatherStation(\"Ulaanbaatar\", -0.4),\n                new WeatherStation(\"Upington\", 20.4),\n                new WeatherStation(\"Ürümqi\", 7.4),\n                new WeatherStation(\"Vaduz\", 10.1),\n                new WeatherStation(\"Valencia\", 18.3),\n                new WeatherStation(\"Valletta\", 18.8),\n                new WeatherStation(\"Vancouver\", 10.4),\n                new WeatherStation(\"Veracruz\", 25.4),\n                new WeatherStation(\"Vienna\", 10.4),\n                new WeatherStation(\"Vientiane\", 25.9),\n                new WeatherStation(\"Villahermosa\", 27.1),\n                new WeatherStation(\"Vilnius\", 6.0),\n                new WeatherStation(\"Virginia Beach\", 15.8),\n                new WeatherStation(\"Vladivostok\", 4.9),\n                new WeatherStation(\"Warsaw\", 8.5),\n                new WeatherStation(\"Washington, D.C.\", 14.6),\n                new WeatherStation(\"Wau\", 27.8),\n                new WeatherStation(\"Wellington\", 12.9),\n                new WeatherStation(\"Whitehorse\", -0.1),\n                new WeatherStation(\"Wichita\", 13.9),\n                new WeatherStation(\"Willemstad\", 28.0),\n                new WeatherStation(\"Winnipeg\", 3.0),\n                new WeatherStation(\"Wrocław\", 9.6),\n                new WeatherStation(\"Xi'an\", 14.1),\n                new WeatherStation(\"Yakutsk\", -8.8),\n                new WeatherStation(\"Yangon\", 27.5),\n                new WeatherStation(\"Yaoundé\", 23.8),\n                new WeatherStation(\"Yellowknife\", -4.3),\n                new WeatherStation(\"Yerevan\", 12.4),\n                new WeatherStation(\"Yinchuan\", 9.0),\n                new WeatherStation(\"Zagreb\", 10.7),\n                new WeatherStation(\"Zanzibar City\", 26.0),\n                new WeatherStation(\"Zürich\", 9.3));\n\n        File file = new File(FILE);\n\n        // break the loop and unroll it manually\n        int strideSize = 50_000_000;\n        int outer = size / strideSize;\n        int remainder = size - (outer * strideSize);\n\n        try (final BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {\n            for (int i = 0; i < outer; i++) {\n                produce(bw, stations, strideSize);\n\n                // we avoid a modulo if here and use the stride size to print and update\n                System.out.println(\"Wrote %,d measurements in %s ms\".formatted((i + 1) * strideSize, System.currentTimeMillis() - start));\n            }\n            // there might be a rest\n            produce(bw, stations, remainder);\n\n            // write fully before taking measurements\n            bw.flush();\n            System.out.println(\"Created file with %,d measurements in %s ms\".formatted(size, System.currentTimeMillis() - start));\n        }\n    }\n\n    private static void produce(BufferedWriter bw, List<WeatherStation> stations, int count) throws IOException {\n        final int stationCount = stations.size();\n        final int rest = count % 8;\n\n        // use a fast ranodm impl without atomics to be able to utilize the cpu better\n        // and avoid sideeffects, FastRandom is very fake random and does not have a state\n        final FastRandom r1 = new FastRandom(ThreadLocalRandom.current().nextLong());\n        final FastRandom r2 = new FastRandom(ThreadLocalRandom.current().nextLong());\n        final FastRandom r3 = new FastRandom(ThreadLocalRandom.current().nextLong());\n        final FastRandom r4 = new FastRandom(ThreadLocalRandom.current().nextLong());\n\n        // write to a fix buffer first, don't create strings ever\n        // reuse buffer\n        final CheaperCharBuffer sb = new CheaperCharBuffer(200);\n\n        // manual loop unroll for less jumps\n        for (int i = 0; i < count; i = i + 8) {\n            {\n                // try to fill teh cpu pipeline as much as possible with\n                // independent operations\n                int s1 = r1.nextInt(stationCount);\n                int s2 = r2.nextInt(stationCount);\n                int s3 = r3.nextInt(stationCount);\n                int s4 = r4.nextInt(stationCount);\n                // get us the ojects one after the other to have the array\n                // in our L1 cache and not push it out with other data\n                var w1 = stations.get(s1);\n                var w2 = stations.get(s2);\n                var w3 = stations.get(s3);\n                var w4 = stations.get(s4);\n                // write our data to our buffer\n                w1.measurement(sb);\n                w2.measurement(sb);\n                w3.measurement(sb);\n                w4.measurement(sb);\n            }\n            {\n                int s1 = r1.nextInt(stationCount);\n                int s2 = r2.nextInt(stationCount);\n                int s3 = r3.nextInt(stationCount);\n                int s4 = r4.nextInt(stationCount);\n                var w1 = stations.get(s1);\n                var w2 = stations.get(s2);\n                var w3 = stations.get(s3);\n                var w4 = stations.get(s4);\n                w1.measurement(sb);\n                w2.measurement(sb);\n                w3.measurement(sb);\n                w4.measurement(sb);\n            }\n            // write the buffer directly, no intermediate string copy\n            bw.write(sb.data_, 0, sb.length_);\n\n            // reuse buffer, reset only, no cleaning\n            sb.clear();\n        }\n\n        // there might be a rest to write\n        for (int i = 0; i < rest; i++) {\n            sb.clear();\n\n            int s = r1.nextInt(stationCount);\n            var w = stations.get(s);\n            w.measurement(sb);\n\n            bw.write(sb.data_, 0, sb.length_);\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CreateMeasurements3.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.FileReader;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class CreateMeasurements3 {\n\n    public static final int MAX_NAME_LEN = 100;\n    public static final int KEYSET_SIZE = 10_000;\n\n    public static void main(String[] args) throws Exception {\n        if (args.length != 1) {\n            System.out.println(\"Usage: create_measurements3.sh <number of records to create>\");\n            System.exit(1);\n        }\n        int size = 0;\n        try {\n            size = Integer.parseInt(args[0]);\n        }\n        catch (NumberFormatException e) {\n            System.out.println(\"Invalid value for <number of records to create>\");\n            System.out.println(\"Usage: create_measurements3.sh <number of records to create>\");\n            System.exit(1);\n        }\n        final var weatherStations = generateWeatherStations();\n        final var start = System.currentTimeMillis();\n        final var rnd = ThreadLocalRandom.current();\n        try (var out = new BufferedWriter(new FileWriter(\"measurements3.txt\"))) {\n            for (int i = 1; i <= size; i++) {\n                var station = weatherStations.get(rnd.nextInt(KEYSET_SIZE));\n                double temp = rnd.nextGaussian(station.avgTemp, 7.0);\n                out.write(station.name);\n                out.write(';');\n                out.write(Double.toString(Math.round(temp * 10.0) / 10.0));\n                out.write('\\n');\n                if (i % 50_000_000 == 0) {\n                    System.out.printf(\"Wrote %,d measurements in %,d ms%n\", i, System.currentTimeMillis() - start);\n                }\n            }\n        }\n    }\n\n    record WeatherStation(String name, float avgTemp) {\n    }\n\n    private static ArrayList<WeatherStation> generateWeatherStations() throws Exception {\n        // Use a public list of city names and concatenate them all into a long string,\n        // which we'll use as a \"source of city name randomness\"\n        var bigName = new StringBuilder(1 << 20);\n        try (var rows = new BufferedReader(new FileReader(\"data/weather_stations.csv\"));) {\n            skipComments(rows);\n            while (true) {\n                var row = rows.readLine();\n                if (row == null) {\n                    break;\n                }\n                bigName.append(row, 0, row.indexOf(';'));\n            }\n        }\n        final var weatherStations = new ArrayList<WeatherStation>();\n        final var names = new HashSet<String>();\n        var minLen = Integer.MAX_VALUE;\n        var maxLen = Integer.MIN_VALUE;\n        try (var rows = new BufferedReader(new FileReader(\"data/weather_stations.csv\"))) {\n            skipComments(rows);\n            final var nameSource = new StringReader(bigName.toString());\n            final var buf = new char[MAX_NAME_LEN];\n            final var rnd = ThreadLocalRandom.current();\n            final double yOffset = 4;\n            final double factor = 2500;\n            final double xOffset = 0.372;\n            final double power = 7;\n            for (int i = 0; i < KEYSET_SIZE; i++) {\n                var row = rows.readLine();\n                if (row == null) {\n                    break;\n                }\n                // Use a 7th-order curve to simulate the name length distribution.\n                // It gives us mostly short names, but with large outliers.\n                var nameLen = (int) (yOffset + factor * Math.pow(rnd.nextDouble() - xOffset, power));\n                var count = nameSource.read(buf, 0, nameLen);\n                if (count == -1) {\n                    throw new Exception(\"Name source exhausted\");\n                }\n                var nameBuf = new StringBuilder(nameLen);\n                nameBuf.append(buf, 0, nameLen);\n                if (Character.isWhitespace(nameBuf.charAt(0))) {\n                    nameBuf.setCharAt(0, readNonSpace(nameSource));\n                }\n                if (Character.isWhitespace(nameBuf.charAt(nameBuf.length() - 1))) {\n                    nameBuf.setCharAt(nameBuf.length() - 1, readNonSpace(nameSource));\n                }\n                var name = nameBuf.toString();\n                while (names.contains(name)) {\n                    nameBuf.setCharAt(rnd.nextInt(nameBuf.length()), readNonSpace(nameSource));\n                    name = nameBuf.toString();\n                }\n                int actualLen;\n                while (true) {\n                    actualLen = name.getBytes(StandardCharsets.UTF_8).length;\n                    if (actualLen <= 100) {\n                        break;\n                    }\n                    nameBuf.deleteCharAt(nameBuf.length() - 1);\n                    if (Character.isWhitespace(nameBuf.charAt(nameBuf.length() - 1))) {\n                        nameBuf.setCharAt(nameBuf.length() - 1, readNonSpace(nameSource));\n                    }\n                    name = nameBuf.toString();\n                }\n                if (name.indexOf(';') != -1) {\n                    throw new Exception(\"Station name contains a semicolon!\");\n                }\n                names.add(name);\n                minLen = Integer.min(minLen, actualLen);\n                maxLen = Integer.max(maxLen, actualLen);\n                var lat = Float.parseFloat(row.substring(row.indexOf(';') + 1));\n                // Guesstimate mean temperature using cosine of latitude\n                var avgTemp = (float) (30 * Math.cos(Math.toRadians(lat))) - 10;\n                weatherStations.add(new WeatherStation(name, avgTemp));\n            }\n        }\n        System.out.format(\"Generated %,d station names with length from %,d to %,d%n\", KEYSET_SIZE, minLen, maxLen);\n        return weatherStations;\n    }\n\n    private static void skipComments(BufferedReader rows) throws IOException {\n        while (rows.readLine().startsWith(\"#\")) {\n        }\n    }\n\n    private static char readNonSpace(StringReader nameSource) throws IOException {\n        while (true) {\n            var n = nameSource.read();\n            if (n == -1) {\n                throw new IOException(\"Name source exhausted\");\n            }\n            var ch = (char) n;\n            if (ch != ' ') {\n                return ch;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/CreateMeasurementsFast.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.nio.file.Files;\nimport java.nio.file.Path;\nimport java.nio.file.StandardOpenOption;\nimport java.util.List;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.ThreadLocalRandom;\n\npublic class CreateMeasurementsFast {\n\n    private static final Path MEASUREMENT_FILE = Path.of(\"./measurements.txt\");\n    static final Executor EXECUTOR_SERVICE = Executors.newWorkStealingPool();\n\n    private record WeatherStation(String id, double meanTemperature) {\n        double measurement() {\n            double m = ThreadLocalRandom.current().nextGaussian(meanTemperature, 10);\n            return Math.round(m * 10.0) / 10.0;\n        }\n    }\n\n    public static void main(String[] args) throws Exception {\n        long start = System.currentTimeMillis();\n\n        if (args.length != 1) {\n            System.out.println(\"Usage: create_measurements.sh <number of records to create>\");\n            System.exit(1);\n        }\n\n        int size = 0;\n        try {\n            size = Integer.parseInt(args[0]);\n        }\n        catch (NumberFormatException e) {\n            System.out.println(\"Invalid value for <number of records to create>\");\n            System.out.println(\"Usage: CreateMeasurements <number of records to create>\");\n            System.exit(1);\n        }\n\n        try {\n            Files.deleteIfExists(MEASUREMENT_FILE);\n            Files.createFile(MEASUREMENT_FILE);\n        }\n        catch (Exception e) {\n            // ignore\n        }\n\n        // @formatter:off\n        // data from https://en.wikipedia.org/wiki/List_of_cities_by_average_temperature;\n        // converted using https://wikitable2csv.ggor.de/\n        // brought to form using DuckDB:\n        // D copy (\n        //     select City, regexp_extract(Year,'(.*)\\n.*', 1) as AverageTemp\n        //     from (\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_1.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_2.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_3.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_4.csv', header = true)\n        //         union\n        //         select City,Year\n        //         from read_csv_auto('List_of_cities_by_average_temperature_5.csv', header = true)\n        //         )\n        // ) TO 'output.csv' (HEADER, DELIMITER ',');\n        // @formatter:on\n        List<WeatherStation> stations = List.of(\n                new WeatherStation(\"Abha\", 18.0),\n                new WeatherStation(\"Abidjan\", 26.0),\n                new WeatherStation(\"Abéché\", 29.4),\n                new WeatherStation(\"Accra\", 26.4),\n                new WeatherStation(\"Addis Ababa\", 16.0),\n                new WeatherStation(\"Adelaide\", 17.3),\n                new WeatherStation(\"Aden\", 29.1),\n                new WeatherStation(\"Ahvaz\", 25.4),\n                new WeatherStation(\"Albuquerque\", 14.0),\n                new WeatherStation(\"Alexandra\", 11.0),\n                new WeatherStation(\"Alexandria\", 20.0),\n                new WeatherStation(\"Algiers\", 18.2),\n                new WeatherStation(\"Alice Springs\", 21.0),\n                new WeatherStation(\"Almaty\", 10.0),\n                new WeatherStation(\"Amsterdam\", 10.2),\n                new WeatherStation(\"Anadyr\", -6.9),\n                new WeatherStation(\"Anchorage\", 2.8),\n                new WeatherStation(\"Andorra la Vella\", 9.8),\n                new WeatherStation(\"Ankara\", 12.0),\n                new WeatherStation(\"Antananarivo\", 17.9),\n                new WeatherStation(\"Antsiranana\", 25.2),\n                new WeatherStation(\"Arkhangelsk\", 1.3),\n                new WeatherStation(\"Ashgabat\", 17.1),\n                new WeatherStation(\"Asmara\", 15.6),\n                new WeatherStation(\"Assab\", 30.5),\n                new WeatherStation(\"Astana\", 3.5),\n                new WeatherStation(\"Athens\", 19.2),\n                new WeatherStation(\"Atlanta\", 17.0),\n                new WeatherStation(\"Auckland\", 15.2),\n                new WeatherStation(\"Austin\", 20.7),\n                new WeatherStation(\"Baghdad\", 22.77),\n                new WeatherStation(\"Baguio\", 19.5),\n                new WeatherStation(\"Baku\", 15.1),\n                new WeatherStation(\"Baltimore\", 13.1),\n                new WeatherStation(\"Bamako\", 27.8),\n                new WeatherStation(\"Bangkok\", 28.6),\n                new WeatherStation(\"Bangui\", 26.0),\n                new WeatherStation(\"Banjul\", 26.0),\n                new WeatherStation(\"Barcelona\", 18.2),\n                new WeatherStation(\"Bata\", 25.1),\n                new WeatherStation(\"Batumi\", 14.0),\n                new WeatherStation(\"Beijing\", 12.9),\n                new WeatherStation(\"Beirut\", 20.9),\n                new WeatherStation(\"Belgrade\", 12.5),\n                new WeatherStation(\"Belize City\", 26.7),\n                new WeatherStation(\"Benghazi\", 19.9),\n                new WeatherStation(\"Bergen\", 7.7),\n                new WeatherStation(\"Berlin\", 10.3),\n                new WeatherStation(\"Bilbao\", 14.7),\n                new WeatherStation(\"Birao\", 26.5),\n                new WeatherStation(\"Bishkek\", 11.3),\n                new WeatherStation(\"Bissau\", 27.0),\n                new WeatherStation(\"Blantyre\", 22.2),\n                new WeatherStation(\"Bloemfontein\", 15.6),\n                new WeatherStation(\"Boise\", 11.4),\n                new WeatherStation(\"Bordeaux\", 14.2),\n                new WeatherStation(\"Bosaso\", 30.0),\n                new WeatherStation(\"Boston\", 10.9),\n                new WeatherStation(\"Bouaké\", 26.0),\n                new WeatherStation(\"Bratislava\", 10.5),\n                new WeatherStation(\"Brazzaville\", 25.0),\n                new WeatherStation(\"Bridgetown\", 27.0),\n                new WeatherStation(\"Brisbane\", 21.4),\n                new WeatherStation(\"Brussels\", 10.5),\n                new WeatherStation(\"Bucharest\", 10.8),\n                new WeatherStation(\"Budapest\", 11.3),\n                new WeatherStation(\"Bujumbura\", 23.8),\n                new WeatherStation(\"Bulawayo\", 18.9),\n                new WeatherStation(\"Burnie\", 13.1),\n                new WeatherStation(\"Busan\", 15.0),\n                new WeatherStation(\"Cabo San Lucas\", 23.9),\n                new WeatherStation(\"Cairns\", 25.0),\n                new WeatherStation(\"Cairo\", 21.4),\n                new WeatherStation(\"Calgary\", 4.4),\n                new WeatherStation(\"Canberra\", 13.1),\n                new WeatherStation(\"Cape Town\", 16.2),\n                new WeatherStation(\"Changsha\", 17.4),\n                new WeatherStation(\"Charlotte\", 16.1),\n                new WeatherStation(\"Chiang Mai\", 25.8),\n                new WeatherStation(\"Chicago\", 9.8),\n                new WeatherStation(\"Chihuahua\", 18.6),\n                new WeatherStation(\"Chișinău\", 10.2),\n                new WeatherStation(\"Chittagong\", 25.9),\n                new WeatherStation(\"Chongqing\", 18.6),\n                new WeatherStation(\"Christchurch\", 12.2),\n                new WeatherStation(\"City of San Marino\", 11.8),\n                new WeatherStation(\"Colombo\", 27.4),\n                new WeatherStation(\"Columbus\", 11.7),\n                new WeatherStation(\"Conakry\", 26.4),\n                new WeatherStation(\"Copenhagen\", 9.1),\n                new WeatherStation(\"Cotonou\", 27.2),\n                new WeatherStation(\"Cracow\", 9.3),\n                new WeatherStation(\"Da Lat\", 17.9),\n                new WeatherStation(\"Da Nang\", 25.8),\n                new WeatherStation(\"Dakar\", 24.0),\n                new WeatherStation(\"Dallas\", 19.0),\n                new WeatherStation(\"Damascus\", 17.0),\n                new WeatherStation(\"Dampier\", 26.4),\n                new WeatherStation(\"Dar es Salaam\", 25.8),\n                new WeatherStation(\"Darwin\", 27.6),\n                new WeatherStation(\"Denpasar\", 23.7),\n                new WeatherStation(\"Denver\", 10.4),\n                new WeatherStation(\"Detroit\", 10.0),\n                new WeatherStation(\"Dhaka\", 25.9),\n                new WeatherStation(\"Dikson\", -11.1),\n                new WeatherStation(\"Dili\", 26.6),\n                new WeatherStation(\"Djibouti\", 29.9),\n                new WeatherStation(\"Dodoma\", 22.7),\n                new WeatherStation(\"Dolisie\", 24.0),\n                new WeatherStation(\"Douala\", 26.7),\n                new WeatherStation(\"Dubai\", 26.9),\n                new WeatherStation(\"Dublin\", 9.8),\n                new WeatherStation(\"Dunedin\", 11.1),\n                new WeatherStation(\"Durban\", 20.6),\n                new WeatherStation(\"Dushanbe\", 14.7),\n                new WeatherStation(\"Edinburgh\", 9.3),\n                new WeatherStation(\"Edmonton\", 4.2),\n                new WeatherStation(\"El Paso\", 18.1),\n                new WeatherStation(\"Entebbe\", 21.0),\n                new WeatherStation(\"Erbil\", 19.5),\n                new WeatherStation(\"Erzurum\", 5.1),\n                new WeatherStation(\"Fairbanks\", -2.3),\n                new WeatherStation(\"Fianarantsoa\", 17.9),\n                new WeatherStation(\"Flores,  Petén\", 26.4),\n                new WeatherStation(\"Frankfurt\", 10.6),\n                new WeatherStation(\"Fresno\", 17.9),\n                new WeatherStation(\"Fukuoka\", 17.0),\n                new WeatherStation(\"Gabès\", 19.5),\n                new WeatherStation(\"Gaborone\", 21.0),\n                new WeatherStation(\"Gagnoa\", 26.0),\n                new WeatherStation(\"Gangtok\", 15.2),\n                new WeatherStation(\"Garissa\", 29.3),\n                new WeatherStation(\"Garoua\", 28.3),\n                new WeatherStation(\"George Town\", 27.9),\n                new WeatherStation(\"Ghanzi\", 21.4),\n                new WeatherStation(\"Gjoa Haven\", -14.4),\n                new WeatherStation(\"Guadalajara\", 20.9),\n                new WeatherStation(\"Guangzhou\", 22.4),\n                new WeatherStation(\"Guatemala City\", 20.4),\n                new WeatherStation(\"Halifax\", 7.5),\n                new WeatherStation(\"Hamburg\", 9.7),\n                new WeatherStation(\"Hamilton\", 13.8),\n                new WeatherStation(\"Hanga Roa\", 20.5),\n                new WeatherStation(\"Hanoi\", 23.6),\n                new WeatherStation(\"Harare\", 18.4),\n                new WeatherStation(\"Harbin\", 5.0),\n                new WeatherStation(\"Hargeisa\", 21.7),\n                new WeatherStation(\"Hat Yai\", 27.0),\n                new WeatherStation(\"Havana\", 25.2),\n                new WeatherStation(\"Helsinki\", 5.9),\n                new WeatherStation(\"Heraklion\", 18.9),\n                new WeatherStation(\"Hiroshima\", 16.3),\n                new WeatherStation(\"Ho Chi Minh City\", 27.4),\n                new WeatherStation(\"Hobart\", 12.7),\n                new WeatherStation(\"Hong Kong\", 23.3),\n                new WeatherStation(\"Honiara\", 26.5),\n                new WeatherStation(\"Honolulu\", 25.4),\n                new WeatherStation(\"Houston\", 20.8),\n                new WeatherStation(\"Ifrane\", 11.4),\n                new WeatherStation(\"Indianapolis\", 11.8),\n                new WeatherStation(\"Iqaluit\", -9.3),\n                new WeatherStation(\"Irkutsk\", 1.0),\n                new WeatherStation(\"Istanbul\", 13.9),\n                new WeatherStation(\"İzmir\", 17.9),\n                new WeatherStation(\"Jacksonville\", 20.3),\n                new WeatherStation(\"Jakarta\", 26.7),\n                new WeatherStation(\"Jayapura\", 27.0),\n                new WeatherStation(\"Jerusalem\", 18.3),\n                new WeatherStation(\"Johannesburg\", 15.5),\n                new WeatherStation(\"Jos\", 22.8),\n                new WeatherStation(\"Juba\", 27.8),\n                new WeatherStation(\"Kabul\", 12.1),\n                new WeatherStation(\"Kampala\", 20.0),\n                new WeatherStation(\"Kandi\", 27.7),\n                new WeatherStation(\"Kankan\", 26.5),\n                new WeatherStation(\"Kano\", 26.4),\n                new WeatherStation(\"Kansas City\", 12.5),\n                new WeatherStation(\"Karachi\", 26.0),\n                new WeatherStation(\"Karonga\", 24.4),\n                new WeatherStation(\"Kathmandu\", 18.3),\n                new WeatherStation(\"Khartoum\", 29.9),\n                new WeatherStation(\"Kingston\", 27.4),\n                new WeatherStation(\"Kinshasa\", 25.3),\n                new WeatherStation(\"Kolkata\", 26.7),\n                new WeatherStation(\"Kuala Lumpur\", 27.3),\n                new WeatherStation(\"Kumasi\", 26.0),\n                new WeatherStation(\"Kunming\", 15.7),\n                new WeatherStation(\"Kuopio\", 3.4),\n                new WeatherStation(\"Kuwait City\", 25.7),\n                new WeatherStation(\"Kyiv\", 8.4),\n                new WeatherStation(\"Kyoto\", 15.8),\n                new WeatherStation(\"La Ceiba\", 26.2),\n                new WeatherStation(\"La Paz\", 23.7),\n                new WeatherStation(\"Lagos\", 26.8),\n                new WeatherStation(\"Lahore\", 24.3),\n                new WeatherStation(\"Lake Havasu City\", 23.7),\n                new WeatherStation(\"Lake Tekapo\", 8.7),\n                new WeatherStation(\"Las Palmas de Gran Canaria\", 21.2),\n                new WeatherStation(\"Las Vegas\", 20.3),\n                new WeatherStation(\"Launceston\", 13.1),\n                new WeatherStation(\"Lhasa\", 7.6),\n                new WeatherStation(\"Libreville\", 25.9),\n                new WeatherStation(\"Lisbon\", 17.5),\n                new WeatherStation(\"Livingstone\", 21.8),\n                new WeatherStation(\"Ljubljana\", 10.9),\n                new WeatherStation(\"Lodwar\", 29.3),\n                new WeatherStation(\"Lomé\", 26.9),\n                new WeatherStation(\"London\", 11.3),\n                new WeatherStation(\"Los Angeles\", 18.6),\n                new WeatherStation(\"Louisville\", 13.9),\n                new WeatherStation(\"Luanda\", 25.8),\n                new WeatherStation(\"Lubumbashi\", 20.8),\n                new WeatherStation(\"Lusaka\", 19.9),\n                new WeatherStation(\"Luxembourg City\", 9.3),\n                new WeatherStation(\"Lviv\", 7.8),\n                new WeatherStation(\"Lyon\", 12.5),\n                new WeatherStation(\"Madrid\", 15.0),\n                new WeatherStation(\"Mahajanga\", 26.3),\n                new WeatherStation(\"Makassar\", 26.7),\n                new WeatherStation(\"Makurdi\", 26.0),\n                new WeatherStation(\"Malabo\", 26.3),\n                new WeatherStation(\"Malé\", 28.0),\n                new WeatherStation(\"Managua\", 27.3),\n                new WeatherStation(\"Manama\", 26.5),\n                new WeatherStation(\"Mandalay\", 28.0),\n                new WeatherStation(\"Mango\", 28.1),\n                new WeatherStation(\"Manila\", 28.4),\n                new WeatherStation(\"Maputo\", 22.8),\n                new WeatherStation(\"Marrakesh\", 19.6),\n                new WeatherStation(\"Marseille\", 15.8),\n                new WeatherStation(\"Maun\", 22.4),\n                new WeatherStation(\"Medan\", 26.5),\n                new WeatherStation(\"Mek'ele\", 22.7),\n                new WeatherStation(\"Melbourne\", 15.1),\n                new WeatherStation(\"Memphis\", 17.2),\n                new WeatherStation(\"Mexicali\", 23.1),\n                new WeatherStation(\"Mexico City\", 17.5),\n                new WeatherStation(\"Miami\", 24.9),\n                new WeatherStation(\"Milan\", 13.0),\n                new WeatherStation(\"Milwaukee\", 8.9),\n                new WeatherStation(\"Minneapolis\", 7.8),\n                new WeatherStation(\"Minsk\", 6.7),\n                new WeatherStation(\"Mogadishu\", 27.1),\n                new WeatherStation(\"Mombasa\", 26.3),\n                new WeatherStation(\"Monaco\", 16.4),\n                new WeatherStation(\"Moncton\", 6.1),\n                new WeatherStation(\"Monterrey\", 22.3),\n                new WeatherStation(\"Montreal\", 6.8),\n                new WeatherStation(\"Moscow\", 5.8),\n                new WeatherStation(\"Mumbai\", 27.1),\n                new WeatherStation(\"Murmansk\", 0.6),\n                new WeatherStation(\"Muscat\", 28.0),\n                new WeatherStation(\"Mzuzu\", 17.7),\n                new WeatherStation(\"N'Djamena\", 28.3),\n                new WeatherStation(\"Naha\", 23.1),\n                new WeatherStation(\"Nairobi\", 17.8),\n                new WeatherStation(\"Nakhon Ratchasima\", 27.3),\n                new WeatherStation(\"Napier\", 14.6),\n                new WeatherStation(\"Napoli\", 15.9),\n                new WeatherStation(\"Nashville\", 15.4),\n                new WeatherStation(\"Nassau\", 24.6),\n                new WeatherStation(\"Ndola\", 20.3),\n                new WeatherStation(\"New Delhi\", 25.0),\n                new WeatherStation(\"New Orleans\", 20.7),\n                new WeatherStation(\"New York City\", 12.9),\n                new WeatherStation(\"Ngaoundéré\", 22.0),\n                new WeatherStation(\"Niamey\", 29.3),\n                new WeatherStation(\"Nicosia\", 19.7),\n                new WeatherStation(\"Niigata\", 13.9),\n                new WeatherStation(\"Nouadhibou\", 21.3),\n                new WeatherStation(\"Nouakchott\", 25.7),\n                new WeatherStation(\"Novosibirsk\", 1.7),\n                new WeatherStation(\"Nuuk\", -1.4),\n                new WeatherStation(\"Odesa\", 10.7),\n                new WeatherStation(\"Odienné\", 26.0),\n                new WeatherStation(\"Oklahoma City\", 15.9),\n                new WeatherStation(\"Omaha\", 10.6),\n                new WeatherStation(\"Oranjestad\", 28.1),\n                new WeatherStation(\"Oslo\", 5.7),\n                new WeatherStation(\"Ottawa\", 6.6),\n                new WeatherStation(\"Ouagadougou\", 28.3),\n                new WeatherStation(\"Ouahigouya\", 28.6),\n                new WeatherStation(\"Ouarzazate\", 18.9),\n                new WeatherStation(\"Oulu\", 2.7),\n                new WeatherStation(\"Palembang\", 27.3),\n                new WeatherStation(\"Palermo\", 18.5),\n                new WeatherStation(\"Palm Springs\", 24.5),\n                new WeatherStation(\"Palmerston North\", 13.2),\n                new WeatherStation(\"Panama City\", 28.0),\n                new WeatherStation(\"Parakou\", 26.8),\n                new WeatherStation(\"Paris\", 12.3),\n                new WeatherStation(\"Perth\", 18.7),\n                new WeatherStation(\"Petropavlovsk-Kamchatsky\", 1.9),\n                new WeatherStation(\"Philadelphia\", 13.2),\n                new WeatherStation(\"Phnom Penh\", 28.3),\n                new WeatherStation(\"Phoenix\", 23.9),\n                new WeatherStation(\"Pittsburgh\", 10.8),\n                new WeatherStation(\"Podgorica\", 15.3),\n                new WeatherStation(\"Pointe-Noire\", 26.1),\n                new WeatherStation(\"Pontianak\", 27.7),\n                new WeatherStation(\"Port Moresby\", 26.9),\n                new WeatherStation(\"Port Sudan\", 28.4),\n                new WeatherStation(\"Port Vila\", 24.3),\n                new WeatherStation(\"Port-Gentil\", 26.0),\n                new WeatherStation(\"Portland (OR)\", 12.4),\n                new WeatherStation(\"Porto\", 15.7),\n                new WeatherStation(\"Prague\", 8.4),\n                new WeatherStation(\"Praia\", 24.4),\n                new WeatherStation(\"Pretoria\", 18.2),\n                new WeatherStation(\"Pyongyang\", 10.8),\n                new WeatherStation(\"Rabat\", 17.2),\n                new WeatherStation(\"Rangpur\", 24.4),\n                new WeatherStation(\"Reggane\", 28.3),\n                new WeatherStation(\"Reykjavík\", 4.3),\n                new WeatherStation(\"Riga\", 6.2),\n                new WeatherStation(\"Riyadh\", 26.0),\n                new WeatherStation(\"Rome\", 15.2),\n                new WeatherStation(\"Roseau\", 26.2),\n                new WeatherStation(\"Rostov-on-Don\", 9.9),\n                new WeatherStation(\"Sacramento\", 16.3),\n                new WeatherStation(\"Saint Petersburg\", 5.8),\n                new WeatherStation(\"Saint-Pierre\", 5.7),\n                new WeatherStation(\"Salt Lake City\", 11.6),\n                new WeatherStation(\"San Antonio\", 20.8),\n                new WeatherStation(\"San Diego\", 17.8),\n                new WeatherStation(\"San Francisco\", 14.6),\n                new WeatherStation(\"San Jose\", 16.4),\n                new WeatherStation(\"San José\", 22.6),\n                new WeatherStation(\"San Juan\", 27.2),\n                new WeatherStation(\"San Salvador\", 23.1),\n                new WeatherStation(\"Sana'a\", 20.0),\n                new WeatherStation(\"Santo Domingo\", 25.9),\n                new WeatherStation(\"Sapporo\", 8.9),\n                new WeatherStation(\"Sarajevo\", 10.1),\n                new WeatherStation(\"Saskatoon\", 3.3),\n                new WeatherStation(\"Seattle\", 11.3),\n                new WeatherStation(\"Ségou\", 28.0),\n                new WeatherStation(\"Seoul\", 12.5),\n                new WeatherStation(\"Seville\", 19.2),\n                new WeatherStation(\"Shanghai\", 16.7),\n                new WeatherStation(\"Singapore\", 27.0),\n                new WeatherStation(\"Skopje\", 12.4),\n                new WeatherStation(\"Sochi\", 14.2),\n                new WeatherStation(\"Sofia\", 10.6),\n                new WeatherStation(\"Sokoto\", 28.0),\n                new WeatherStation(\"Split\", 16.1),\n                new WeatherStation(\"St. John's\", 5.0),\n                new WeatherStation(\"St. Louis\", 13.9),\n                new WeatherStation(\"Stockholm\", 6.6),\n                new WeatherStation(\"Surabaya\", 27.1),\n                new WeatherStation(\"Suva\", 25.6),\n                new WeatherStation(\"Suwałki\", 7.2),\n                new WeatherStation(\"Sydney\", 17.7),\n                new WeatherStation(\"Tabora\", 23.0),\n                new WeatherStation(\"Tabriz\", 12.6),\n                new WeatherStation(\"Taipei\", 23.0),\n                new WeatherStation(\"Tallinn\", 6.4),\n                new WeatherStation(\"Tamale\", 27.9),\n                new WeatherStation(\"Tamanrasset\", 21.7),\n                new WeatherStation(\"Tampa\", 22.9),\n                new WeatherStation(\"Tashkent\", 14.8),\n                new WeatherStation(\"Tauranga\", 14.8),\n                new WeatherStation(\"Tbilisi\", 12.9),\n                new WeatherStation(\"Tegucigalpa\", 21.7),\n                new WeatherStation(\"Tehran\", 17.0),\n                new WeatherStation(\"Tel Aviv\", 20.0),\n                new WeatherStation(\"Thessaloniki\", 16.0),\n                new WeatherStation(\"Thiès\", 24.0),\n                new WeatherStation(\"Tijuana\", 17.8),\n                new WeatherStation(\"Timbuktu\", 28.0),\n                new WeatherStation(\"Tirana\", 15.2),\n                new WeatherStation(\"Toamasina\", 23.4),\n                new WeatherStation(\"Tokyo\", 15.4),\n                new WeatherStation(\"Toliara\", 24.1),\n                new WeatherStation(\"Toluca\", 12.4),\n                new WeatherStation(\"Toronto\", 9.4),\n                new WeatherStation(\"Tripoli\", 20.0),\n                new WeatherStation(\"Tromsø\", 2.9),\n                new WeatherStation(\"Tucson\", 20.9),\n                new WeatherStation(\"Tunis\", 18.4),\n                new WeatherStation(\"Ulaanbaatar\", -0.4),\n                new WeatherStation(\"Upington\", 20.4),\n                new WeatherStation(\"Ürümqi\", 7.4),\n                new WeatherStation(\"Vaduz\", 10.1),\n                new WeatherStation(\"Valencia\", 18.3),\n                new WeatherStation(\"Valletta\", 18.8),\n                new WeatherStation(\"Vancouver\", 10.4),\n                new WeatherStation(\"Veracruz\", 25.4),\n                new WeatherStation(\"Vienna\", 10.4),\n                new WeatherStation(\"Vientiane\", 25.9),\n                new WeatherStation(\"Villahermosa\", 27.1),\n                new WeatherStation(\"Vilnius\", 6.0),\n                new WeatherStation(\"Virginia Beach\", 15.8),\n                new WeatherStation(\"Vladivostok\", 4.9),\n                new WeatherStation(\"Warsaw\", 8.5),\n                new WeatherStation(\"Washington, D.C.\", 14.6),\n                new WeatherStation(\"Wau\", 27.8),\n                new WeatherStation(\"Wellington\", 12.9),\n                new WeatherStation(\"Whitehorse\", -0.1),\n                new WeatherStation(\"Wichita\", 13.9),\n                new WeatherStation(\"Willemstad\", 28.0),\n                new WeatherStation(\"Winnipeg\", 3.0),\n                new WeatherStation(\"Wrocław\", 9.6),\n                new WeatherStation(\"Xi'an\", 14.1),\n                new WeatherStation(\"Yakutsk\", -8.8),\n                new WeatherStation(\"Yangon\", 27.5),\n                new WeatherStation(\"Yaoundé\", 23.8),\n                new WeatherStation(\"Yellowknife\", -4.3),\n                new WeatherStation(\"Yerevan\", 12.4),\n                new WeatherStation(\"Yinchuan\", 9.0),\n                new WeatherStation(\"Zagreb\", 10.7),\n                new WeatherStation(\"Zanzibar City\", 26.0),\n                new WeatherStation(\"Zürich\", 9.3));\n\n        int chunkSize = (size / 10_000_000) == 0 ? size : 10_000_000;\n        int numberOfFutures = size / chunkSize;\n        if (numberOfFutures == 0) {\n            numberOfFutures = 1;\n        }\n        CompletableFuture<?>[] futures = new CompletableFuture[numberOfFutures];\n\n        for (int n = 0; n < numberOfFutures; n++) {\n            int finalN = n;\n            futures[n] = CompletableFuture.runAsync(() -> {\n                StringBuilder builder = new StringBuilder();\n                for (int i = finalN * chunkSize; i <= (finalN + 1) * chunkSize - 1; i++) {\n                    WeatherStation station = stations.get(ThreadLocalRandom.current().nextInt(stations.size()));\n                    builder.append(station.id())\n                            .append(\";\")\n                            .append(station.measurement())\n                            .append('\\n');\n                }\n                try (BufferedWriter bw = Files.newBufferedWriter(MEASUREMENT_FILE, StandardOpenOption.APPEND)) {\n                    bw.write(builder.toString());\n                }\n                catch (IOException e) {\n                    throw new RuntimeException(e);\n                }\n            }, EXECUTOR_SERVICE);\n        }\n\n        CompletableFuture.allOf(futures).join();\n\n        System.out.printf(\"Created file with %,d measurements in %s ms%n\", size, System.currentTimeMillis() - start);\n    }\n}\n"
  },
  {
    "path": "src/main/java/dev/morling/onebrc/PerfectHashSearch_hundredwatt.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.util.BitSet;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicLong;\nimport java.util.random.RandomGenerator;\nimport java.util.random.RandomGeneratorFactory;\n\n/** Offline script used to find the perfect hash seed for CalculateAverage_hundredwatt. */\npublic class PerfectHashSearch_hundredwatt {\n    public static final int DESIRED_SLOTS = 5003;\n    public static final int N_THREADS = Runtime.getRuntime().availableProcessors() - 1;\n\n    public static void main(String[] args) throws IOException, InterruptedException {\n        AtomicLong magicSeed = new AtomicLong(0);\n        AtomicLong totalAttempts = new AtomicLong(0);\n        AtomicLong maxCardinality = new AtomicLong(0);\n\n        long start = System.currentTimeMillis();\n\n        System.out.println(\"Searching for perfect hash seed for \" + DESIRED_SLOTS + \" slots\");\n\n        // Figure out encoding for all possible temperature values (1999 total)\n        Map<Long, Short> decodeTemperatureMap = new HashMap<>();\n        for (short i = -999; i <= 999; i++) {\n            long word = 0;\n            int shift = 0;\n            if (i < 0) {\n                word |= ((long) '-') << shift;\n                shift += 8;\n            }\n            if (Math.abs(i) >= 100) {\n                int hh = Math.abs(i) / 100;\n                int tt = (Math.abs(i) - hh * 100) / 10;\n\n                word |= ((long) (hh + '0')) << shift;\n                shift += 8;\n                word |= ((long) (tt + '0')) << shift;\n            }\n            else {\n                int tt = Math.abs(i) / 10;\n                // convert to ascii\n                word |= ((long) (tt + '0')) << shift;\n            }\n            shift += 8;\n            word |= ((long) '.') << shift;\n            shift += 8;\n            int uu = Math.abs(i) % 10;\n            word |= ((long) (uu + '0')) << shift;\n\n            // 31302e3000000000\n            decodeTemperatureMap.put(word, i);\n        }\n\n        ExecutorService executor = Executors.newFixedThreadPool(N_THREADS);\n\n        RandomGeneratorFactory factory = RandomGeneratorFactory.of(\"L64X256MixRandom\");\n\n        Runnable search = () -> {\n            // Brute force to find seed:\n            // generate a cryptographically secure random seed\n            RandomGenerator rand;\n            try {\n                byte[] seed = new byte[16];\n                SecureRandom.getInstanceStrong().nextBytes(seed);\n                rand = factory.create(ByteBuffer.wrap(seed).getLong());\n                System.out.println(Thread.currentThread().getName() + \" | Using seed: \" + rand.nextLong());\n            }\n            catch (NoSuchAlgorithmException e) {\n                throw new RuntimeException(e);\n            }\n\n            int max = 0;\n            int attempts = 0;\n            while (true) {\n                BitSet bs = new BitSet(DESIRED_SLOTS);\n                var seed = rand.nextLong();\n                seed |= 0b1; // make sure it's odd\n                for (var word : decodeTemperatureMap.keySet()) {\n                    var h = (word * seed) & ~(1L << 63);\n                    var pos = (int) (h % DESIRED_SLOTS);\n                    bs.set(pos);\n                }\n                var c = bs.cardinality();\n                if (c == decodeTemperatureMap.size()) {\n                    System.out.println(\"FOUND seed: \" + seed + \" cardinality: \" + c + \" max cardinality: \" + max);\n                    magicSeed.set(seed);\n                    return;\n                }\n                max = Math.max(max, c);\n                if (attempts % 100_000 == 0) {\n                    if (magicSeed.get() != 0)\n                        return;\n                    int finalMax = max;\n                    long currentMaxCardinality = maxCardinality.updateAndGet(currentMax -> Math.max(currentMax, finalMax));\n                    long currentTotalAttempts = totalAttempts.addAndGet(100_000);\n\n                    if (Thread.currentThread().getName().endsWith(\"-1\"))\n                        System.out.println(Thread.currentThread().getName() + \" | max cardinality: \" + currentMaxCardinality + \" attempts: \"\n                                + String.format(\"%,d\", currentTotalAttempts));\n                }\n                attempts++;\n            }\n        };\n\n        for (int i = 0; i < Runtime.getRuntime().availableProcessors(); i++) {\n            executor.submit(search);\n        }\n\n        // Wait for the search to complete\n        executor.shutdown();\n        executor.awaitTermination(1, TimeUnit.DAYS);\n\n        short[] TEMPERATURES = new short[DESIRED_SLOTS];\n        long seed = magicSeed.get();\n\n        decodeTemperatureMap.entrySet().stream().forEach(e -> {\n            var word = e.getKey();\n            var h = (word * seed) & ~(1L << 63);\n            var pos = (int) (h % DESIRED_SLOTS);\n            if (TEMPERATURES[pos] != 0)\n                throw new RuntimeException(\"collision at \" + pos);\n            TEMPERATURES[pos] = e.getValue();\n        });\n        System.out.println(\"SUCCESS seed: \" + seed + \" total attempts: \" + totalAttempts.get());\n\n        try {\n            File file = new File(\"seeds.txt\");\n            file.delete();\n            file.createNewFile();\n\n            // Write the seed to seeds.txt\n            FileWriter myWriter = new FileWriter(\"seeds.txt\");\n            myWriter.write(Long.toString(seed));\n            myWriter.write(\"\\n\");\n            myWriter.close();\n\n        }\n        catch (IOException e) {\n            throw new RuntimeException(e);\n        }\n\n        System.out.println(\"Search took \" + ((System.currentTimeMillis() - start) / 1000) + \"s\");\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/rschwietzke/CheaperCharBuffer.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage org.rschwietzke;\n\nimport java.util.Arrays;\n\n/**\n * <p>This class is meant to replaces the old {@link CheaperCharBuffer} in all areas\n * where performance and memory-efficency is key. XMLString compatibility\n * remains in place in case one has used that in their own code.\n *\n * <p>This buffer is mutable and when you use it, make sure you work with\n * it responsibly. In many cases, we will reuse the buffer to avoid fresh\n * memory allocations, hence you have to pay attention to its usage pattern.\n * It is not meant to be a general String replacement.\n *\n * <p>This class avoids many of the standard runtime checks that will result\n * in a runtime or array exception anyway. Why check twice and raise the\n * same exception?\n *\n * @author René Schwietzke\n * @since 3.10.0\n */\npublic class CheaperCharBuffer implements CharSequence {\n    // our data, can grow - that is not safe and has be altered from the original code\n    // to allow speed\n    public char[] data_;\n\n    // the current size of the string data\n    public int length_;\n\n    // the current size of the string data\n    private final int growBy_;\n\n    // how much do we grow if needed, half a cache line\n    public static final int CAPACITY_GROWTH = 64 / 2;\n\n    // what is our start size?\n    // a cache line is 64 byte mostly, the overhead is mostly 24 bytes\n    // a char is two bytes, let's use one cache lines\n    public static final int INITIAL_CAPACITY = (64 - 24) / 2;\n\n    // static empty version; DON'T MODIFY IT\n    public static final CheaperCharBuffer EMPTY = new CheaperCharBuffer(0);\n\n    // the � character\n    private static final char REPLACEMENT_CHARACTER = '\\uFFFD';\n\n    /**\n     * Constructs an XMLCharBuffer with a default size.\n     */\n    public CheaperCharBuffer() {\n        this.data_ = new char[INITIAL_CAPACITY];\n        this.length_ = 0;\n        this.growBy_ = CAPACITY_GROWTH;\n    }\n\n    /**\n     * Constructs an XMLCharBuffer with a desired size.\n     *\n     * @param startSize the size of the buffer to start with\n     */\n    public CheaperCharBuffer(final int startSize) {\n        this(startSize, CAPACITY_GROWTH);\n    }\n\n    /**\n     * Constructs an XMLCharBuffer with a desired size.\n     *\n     * @param startSize the size of the buffer to start with\n     * @param growBy by how much do we want to grow when needed\n     */\n    public CheaperCharBuffer(final int startSize, final int growBy) {\n        this.data_ = new char[startSize];\n        this.length_ = 0;\n        this.growBy_ = Math.max(1, growBy);\n    }\n\n    /**\n     * Constructs an XMLCharBuffer from another buffer. Copies the data\n     * over. The new buffer capacity matches the length of the source.\n     *\n     * @param src the source buffer to copy from\n     */\n    public CheaperCharBuffer(final CheaperCharBuffer src) {\n        this(src, 0);\n    }\n\n    /**\n     * Constructs an XMLCharBuffer from another buffer. Copies the data\n     * over. You can add more capacity on top of the source length. If\n     * you specify 0, the capacity will match the src length.\n     *\n     * @param src the source buffer to copy from\n     * @param addCapacity how much capacity to add to origin length\n     */\n    public CheaperCharBuffer(final CheaperCharBuffer src, final int addCapacity) {\n        this.data_ = Arrays.copyOf(src.data_, src.length_ + Math.max(0, addCapacity));\n        this.length_ = src.length();\n        this.growBy_ = Math.max(1, CAPACITY_GROWTH);\n    }\n\n    /**\n     * Constructs an XMLCharBuffer from a string. To avoid\n     * too much allocation, we just take the string array as is and\n     * don't allocate extra space in the first place.\n     *\n     * @param src the string to copy from\n     */\n    public CheaperCharBuffer(final String src) {\n        this.data_ = src.toCharArray();\n        this.length_ = src.length();\n        this.growBy_ = CAPACITY_GROWTH;\n    }\n\n    /**\n     * Constructs an XMLString structure preset with the specified values.\n     * There will not be any room to grow, if you need that, construct an\n     * empty one and append.\n     *\n     * <p>There are not range checks performed. Make sure your data is correct.\n     *\n     * @param ch     The character array, must not be null\n     * @param offset The offset into the character array.\n     * @param length The length of characters from the offset.\n     */\n    public CheaperCharBuffer(final char[] ch, final int offset, final int length) {\n        // just as big as we need it\n        this(length);\n        append(ch, offset, length);\n    }\n\n    /**\n     * Check capacity and grow if needed automatically\n     *\n     * @param minimumCapacity how much space do we need at least\n     */\n    private void ensureCapacity(final int minimumCapacity) {\n        if (minimumCapacity > this.data_.length) {\n            final int newSize = Math.max(minimumCapacity + this.growBy_, (this.data_.length << 1) + 2);\n            this.data_ = Arrays.copyOf(this.data_, newSize);\n        }\n    }\n\n    /**\n     * Returns the current max capacity without growth. Does not\n     * indicate how much capacity is already in use. Use {@link #length()}\n     * for that.\n     *\n     * @return the current capacity, not taken any usage into account\n     */\n    public int capacity() {\n        return this.data_.length;\n    }\n\n    /**\n     * Appends a single character to the buffer.\n     *\n     * @param c the character to append\n     * @return this instance\n     */\n    public CheaperCharBuffer append(final char c) {\n        final int oldLength = this.length_++;\n\n        // ensureCapacity is not inlined by the compiler, so put that here for the most\n        // called method of all appends. Duplicate code, but for a reason.\n        if (oldLength == this.data_.length) {\n            final int newSize = Math.max(oldLength + this.growBy_, (this.data_.length << 1) + 2);\n            this.data_ = Arrays.copyOf(this.data_, newSize);\n        }\n\n        this.data_[oldLength] = c;\n\n        return this;\n    }\n\n    /**\n     * Append a string to this buffer without copying the string first.\n     *\n     * @param src the string to append\n     * @return this instance\n     */\n    public CheaperCharBuffer append(final String src) {\n        final int start = this.length_;\n        this.length_ = this.length_ + src.length();\n        ensureCapacity(this.length_);\n\n        // copy char by char because we don't get a copy for free\n        // from a string yet, this might change when immutable arrays\n        // make it into Java, but that will not be very soon\n        for (int i = 0; i < src.length(); i++) {\n            this.data_[start + i] = src.charAt(i);\n        }\n\n        return this;\n    }\n\n    /**\n     * Add another buffer to this one.\n     *\n     * @param src the buffer to append\n     * @return this instance\n     */\n    public CheaperCharBuffer append(final CheaperCharBuffer src) {\n        final int start = this.length_;\n        this.length_ = this.length_ + src.length();\n        ensureCapacity(this.length_);\n\n        System.arraycopy(src.data_, 0, this.data_, start, src.length_);\n\n        return this;\n    }\n\n    /**\n     * Add data from a char array to this buffer with the ability to specify\n     * a range to copy from\n     *\n     * @param src the source char array\n     * @param offset the pos to start to copy from\n     * @param length the length of the data to copy\n     *\n     * @return this instance\n     */\n    public CheaperCharBuffer append(final char[] src, final int offset, final int length) {\n        final int start = this.length_;\n        this.length_ = start + length;\n\n        ensureCapacity(this.length_);\n\n        System.arraycopy(src, offset, this.data_, start, length);\n\n        return this;\n    }\n\n    /**\n     * Returns the current length\n     *\n     * @return the length of the charbuffer data\n     */\n    public int length() {\n        return length_;\n    }\n\n    /**\n     * Tell us how much the capacity grows if needed\n     *\n     * @return the value that determines how much we grow the backing\n     *      array in case we have to\n     */\n    public int getGrowBy() {\n        return this.growBy_;\n    }\n\n    /**\n     * Resets the buffer to 0 length. It won't resize it to avoid memory\n     * churn.\n     *\n     * @return this instance for fluid programming\n     */\n    public CheaperCharBuffer clear() {\n        this.length_ = 0;\n\n        return this;\n    }\n\n    /**\n     * Resets the buffer to 0 length and sets the new data. This\n     * is a little cheaper than clear().append(c) depending on\n     * the where  and the inlining decisions.\n     *\n     * @param c the char to set\n     * @return this instance for fluid programming\n     */\n    public CheaperCharBuffer clearAndAppend(final char c) {\n        this.length_ = 0;\n\n        if (this.data_.length > 0) {\n            this.data_[this.length_] = c;\n            this.length_++;\n        }\n        else {\n            // the rare case when we don't have any buffer at hand\n            append(c);\n        }\n\n        return this;\n    }\n\n    /**\n     * Does this buffer end with this string? If we check for\n     * the empty string, we get true. If we would support JDK 11, we could\n     * use Arrays.mismatch and be way faster.\n     *\n     * @param s the string to check the end against\n     * @return true of the end matches the buffer, false otherwise\n     */\n    public boolean endsWith(final String s) {\n        // length does not match, cannot be the end\n        if (this.length_ < s.length()) {\n            return false;\n        }\n\n        // check the string by each char, avoids a copy of the string\n        final int start = this.length_ - s.length();\n\n        // change this to Arrays.mismatch when going JDK 11 or higher\n        for (int i = 0; i < s.length(); i++) {\n            if (this.data_[i + start] != s.charAt(i)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Reduces the buffer to the content between start and end marker when\n     * only whitespaces are found before the startMarker as well as after the end marker.\n     * If both strings overlap due to identical characters such as \"foo\" and \"oof\"\n     * and the buffer is \" foof \", we don't do anything.\n     *\n     * <p>If a marker is empty, it behaves like {@link java.lang.String#trim()} on that side.\n     *\n     * @param startMarker the start string to find, must not be null\n     * @param endMarker the end string to find, must not be null\n     * @return this instance\n     *\n     * @deprecated Use the new method {@link #trimToContent(String, String)} instead.\n     */\n    public CheaperCharBuffer reduceToContent(final String startMarker, final String endMarker) {\n        return trimToContent(startMarker, endMarker);\n    }\n\n    /**\n     * Reduces the buffer to the content between start and end marker when\n     * only whitespaces are found before the startMarker as well as after the end marker.\n     * If both strings overlap due to identical characters such as \"foo\" and \"oof\"\n     * and the buffer is \" foof \", we don't do anything.\n     *\n     * <p>If a marker is empty, it behaves like {@link java.lang.String#trim()} on that side.\n     *\n     * @param startMarker the start string to find, must not be null\n     * @param endMarker the end string to find, must not be null\n     * @return this instance\n     */\n    public CheaperCharBuffer trimToContent(final String startMarker, final String endMarker) {\n        // if both are longer or same length than content, don't do anything\n        final int markerLength = startMarker.length() + endMarker.length();\n        if (markerLength >= this.length_) {\n            return this;\n        }\n\n        // run over starting whitespaces\n        int sPos = 0;\n        for (; sPos < this.length_ - markerLength; sPos++) {\n            if (!Character.isWhitespace(this.data_[sPos])) {\n                break;\n            }\n        }\n\n        // run over ending whitespaces\n        int ePos = this.length_ - 1;\n        for (; ePos > sPos - markerLength; ePos--) {\n            if (!Character.isWhitespace(this.data_[ePos])) {\n                break;\n            }\n        }\n\n        // if we have less content than marker length, give up\n        // this also helps when markers overlap such as\n        // <!-- and --> and the string is \" <!---> \"\n        if (ePos - sPos + 1 < markerLength) {\n            return this;\n        }\n\n        // check the start\n        for (int i = 0; i < startMarker.length(); i++) {\n            if (startMarker.charAt(i) != this.data_[i + sPos]) {\n                // no start match, stop and don't do anything\n                return this;\n            }\n        }\n\n        // check the end, ePos is when the first good char\n        // occurred\n        final int endStartCheckPos = ePos - endMarker.length() + 1;\n        for (int i = 0; i < endMarker.length(); i++) {\n            if (endMarker.charAt(i) != this.data_[endStartCheckPos + i]) {\n                // no start match, stop and don't do anything\n                return this;\n            }\n        }\n\n        // shift left and cut length\n        final int newLength = ePos - sPos + 1 - markerLength;\n        System.arraycopy(this.data_,\n                sPos + startMarker.length(),\n                this.data_,\n                0, newLength);\n        this.length_ = newLength;\n\n        return this;\n    }\n\n    /**\n     * Check if we have only whitespaces\n     *\n     * @return true if we have only whitespace, false otherwise\n     */\n    public boolean isWhitespace() {\n        for (int i = 0; i < this.length_; i++) {\n            if (!Character.isWhitespace(this.data_[i])) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Trims the string similar to {@link java.lang.String#trim()}\n     *\n     * @return a string with removed whitespace at the beginning and the end\n     */\n    public CheaperCharBuffer trim() {\n        // clean the end first, because it is cheap\n        return trimTrailing().trimLeading();\n    }\n\n    /**\n     * Removes all whitespace before the first non-whitespace char.\n     * If all are whitespaces, we get an empty buffer\n     *\n     * @return this instance\n     */\n    public CheaperCharBuffer trimLeading() {\n        // run over starting whitespace\n        int sPos = 0;\n        for (; sPos < this.length_; sPos++) {\n            if (!Character.isWhitespace(this.data_[sPos])) {\n                break;\n            }\n        }\n\n        if (sPos == 0) {\n            // nothing to do\n            return this;\n        }\n        else if (sPos == this.length_) {\n            // only whitespace\n            this.length_ = 0;\n            return this;\n        }\n\n        // shift left\n        final int newLength = this.length_ - sPos;\n        System.arraycopy(this.data_,\n                sPos,\n                this.data_,\n                0, newLength);\n        this.length_ = newLength;\n\n        return this;\n    }\n\n    /**\n     * Removes all whitespace at the end.\n     * If all are whitespace, we get an empty buffer\n     *\n     * @return this instance\n     *\n     * @deprecated Use {@link #trimTrailing()} instead.\n     */\n    public CheaperCharBuffer trimWhitespaceAtEnd() {\n        return trimTrailing();\n    }\n\n    /**\n     * Removes all whitespace at the end.\n     * If all are whitespace, we get an empty buffer\n     *\n     * @return this instance\n     */\n    public CheaperCharBuffer trimTrailing() {\n        // run over ending whitespaces\n        int ePos = this.length_ - 1;\n        for (; ePos >= 0; ePos--) {\n            if (!Character.isWhitespace(this.data_[ePos])) {\n                break;\n            }\n        }\n\n        this.length_ = ePos + 1;\n\n        return this;\n    }\n\n    /**\n     * Shortens the buffer by that many positions. If the count is\n     * larger than the length, we get just an empty buffer. If you pass in negative\n     * values, we are failing, likely often silently. It is all about performance and\n     * not a general all-purpose API.\n     *\n     * @param count a positive number, no runtime checks, if count is larger than\n     *      length, we get length = 0\n     * @return this instance\n     */\n    public CheaperCharBuffer shortenBy(final int count) {\n        final int newLength = this.length_ - count;\n        this.length_ = newLength < 0 ? 0 : newLength;\n\n        return this;\n    }\n\n    /**\n     * Get the characters as char array, this will be a copy!\n     *\n     * @return a copy of the underlying char darta\n     */\n    public char[] getChars() {\n        return Arrays.copyOf(this.data_, this.length_);\n    }\n\n    /**\n     * Returns a string representation of this buffer. This will be a copy\n     * operation. If the buffer is emoty, we get a constant empty String back\n     * to avoid any overhead.\n     *\n     * @return a string of the content of this buffer\n     */\n    @Override\n    public String toString() {\n        if (this.length_ > 0) {\n            return new String(this.data_, 0, this.length_);\n        }\n        else {\n            return \"\";\n        }\n    }\n\n    /**\n     * Returns the char a the given position. Will complain if\n     * we try to read outside the range. We do a range check here\n     * because we might not notice when we are within the buffer\n     * but outside the current length.\n     *\n     * @param index the position to read from\n     * @return the char at the position\n     * @throws IndexOutOfBoundsException\n     *      in case one tries to read outside of valid buffer range\n     */\n    @Override\n    public char charAt(final int index) {\n        if (index > this.length_ - 1 || index < 0) {\n            throw new IndexOutOfBoundsException(\n                    \"Tried to read outside of the valid buffer data\");\n        }\n\n        return this.data_[index];\n    }\n\n    /**\n     * Returns the char at the given position. No checks are\n     * performed. It is up to the caller to make sure we\n     * read correctly. Reading outside of the array will\n     * cause an {@link IndexOutOfBoundsException} but using an\n     * incorrect position in the array (such as beyond length)\n     * might stay unnoticed! This is a performance method,\n     * use at your own risk.\n     *\n     * @param index the position to read from\n     * @return the char at the position\n     */\n    public char unsafeCharAt(final int index) {\n        return this.data_[index];\n    }\n\n    /**\n     * Returns a content copy of this buffer\n     *\n     * @return a copy of this buffer, the capacity might differ\n     */\n    @Override\n    public CheaperCharBuffer clone() {\n        return new CheaperCharBuffer(this);\n    }\n\n    /**\n     * Returns a <code>CharSequence</code> that is a subsequence of this sequence.\n     * The subsequence starts with the <code>char</code> value at the specified index and\n     * ends with the <code>char</code> value at index <tt>end - 1</tt>.  The length\n     * (in <code>char</code>s) of the\n     * returned sequence is <tt>end - start</tt>, so if <tt>start == end</tt>\n     * then an empty sequence is returned.\n     *\n     * @param   start   the start index, inclusive\n     * @param   end     the end index, exclusive\n     *\n     * @return  the specified subsequence\n     *\n     * @throws  IndexOutOfBoundsException\n     *          if <tt>start</tt> or <tt>end</tt> are negative,\n     *          if <tt>end</tt> is greater than <tt>length()</tt>,\n     *          or if <tt>start</tt> is greater than <tt>end</tt>\n     *\n     * @return a charsequence of this buffer\n     */\n    @Override\n    public CharSequence subSequence(final int start, final int end) {\n        if (start < 0) {\n            throw new StringIndexOutOfBoundsException(start);\n        }\n        if (end > this.length_) {\n            throw new StringIndexOutOfBoundsException(end);\n        }\n\n        final int l = end - start;\n        if (l < 0) {\n            throw new StringIndexOutOfBoundsException(l);\n        }\n\n        return new String(this.data_, start, l);\n    }\n\n    /**\n     * Two buffers are identical when the length and\n     * the content of the backing array (only for the\n     * data in view) are identical.\n     *\n     * @param o the object to compare with\n     * @return true if length and array content match, false otherwise\n     */\n    @Override\n    public boolean equals(final Object o) {\n        if (o instanceof CharSequence) {\n            final CharSequence ob = (CharSequence) o;\n\n            if (ob.length() != this.length_) {\n                return false;\n            }\n\n            // ok, in JDK 11 or up, we could use an\n            // Arrays.mismatch, but we cannot do that\n            // due to JDK 8 compatibility\n            for (int i = 0; i < this.length_; i++) {\n                if (ob.charAt(i) != this.data_[i]) {\n                    return false;\n                }\n            }\n\n            // length and content match, be happy\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * We don't cache the hashcode because we mutate often. Don't use this in\n     * hashmaps as key. But you can use that to look up in a hashmap against\n     * a string using the CharSequence interface.\n     *\n     * @return the hashcode, similar to what a normal string would deliver\n     */\n    @Override\n    public int hashCode() {\n        int h = 0;\n\n        for (int i = 0; i < this.length_; i++) {\n            h = ((h << 5) - h) + this.data_[i];\n        }\n\n        return h;\n    }\n\n    /**\n     * Append a character to an XMLCharBuffer. The character is an int value, and\n     * can either be a single UTF-16 character or a supplementary character\n     * represented by two UTF-16 code points.\n     *\n     * @param value The character value.\n     * @return this instance for fluid programming\n     *\n     * @throws IllegalArgumentException if the specified\n     *          {@code codePoint} is not a valid Unicode code point.\n     */\n    public CheaperCharBuffer appendCodePoint(final int value) {\n        if (value <= Character.MAX_VALUE) {\n            return this.append((char) value);\n        }\n        else {\n            try {\n                final char[] chars = Character.toChars(value);\n                return this.append(chars, 0, chars.length);\n            }\n            catch (final IllegalArgumentException e) {\n                // when value is not valid as UTF-16\n                this.append(REPLACEMENT_CHARACTER);\n                throw e;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/java/org/rschwietzke/FastRandom.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage org.rschwietzke;\n\n/**\n * Ultra-fast pseudo random generator that is not synchronized!\n * Don't use anything from Random by inheritance, this will inherit\n * a volatile! Not my idea, copyied in parts some demo random\n * generator lessons.\n *\n * @author rschwietzke\n *\n */\npublic class FastRandom {\n    private long seed;\n\n    public FastRandom() {\n        this.seed = System.currentTimeMillis();\n    }\n\n    public FastRandom(long seed) {\n        this.seed = seed;\n    }\n\n    protected int next(int nbits) {\n        // N.B. Not thread-safe!\n        long x = this.seed;\n        x ^= (x << 21);\n        x ^= (x >>> 35);\n        x ^= (x << 4);\n        this.seed = x;\n\n        x &= ((1L << nbits) - 1);\n\n        return (int) x;\n    }\n\n    /**\n     * Borrowed from the JDK\n     *\n     * @param bound\n     * @return\n     */\n    public int nextInt(int bound) {\n        int r = next(31);\n        int m = bound - 1;\n        if ((bound & m) == 0) // i.e., bound is a power of 2\n            r = (int) ((bound * (long) r) >> 31);\n        else {\n            for (int u = r; u - (r = u % bound) + m < 0; u = next(31))\n                ;\n        }\n        return r;\n    }\n\n    /**\n     * Borrowed from the JDK\n     * @return\n     */\n    public int nextInt() {\n        return next(32);\n    }\n}\n"
  },
  {
    "path": "src/main/java-22/dev/morling/onebrc/CalculateAverage_linl33.java",
    "content": "/*\n *  Copyright 2023 The original authors\n *\n *  Licensed under the Apache License, Version 2.0 (the \"License\");\n *  you may not use this file except in compliance with the License.\n *  You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n *  Unless required by applicable law or agreed to in writing, software\n *  distributed under the License is distributed on an \"AS IS\" BASIS,\n *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *  See the License for the specific language governing permissions and\n *  limitations under the License.\n */\npackage dev.morling.onebrc;\n\nimport jdk.incubator.vector.ByteVector;\nimport jdk.incubator.vector.VectorSpecies;\nimport sun.misc.Unsafe;\n\nimport java.io.IOException;\nimport java.lang.foreign.*;\nimport java.lang.invoke.MethodHandle;\nimport java.nio.ByteOrder;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.Paths;\nimport java.util.Arrays;\nimport java.util.concurrent.CompletableFuture;\nimport java.util.concurrent.Executors;\nimport java.util.stream.IntStream;\n\npublic class CalculateAverage_linl33 {\n    private static final String FILE_PATH_PROPERTY = \"dev.morling.onebrc.CalculateAverage_linl33.measurementsPath\";\n    private static final int WEATHER_STATION_LENGTH_MAX = 100;\n    private static final long WEATHER_STATION_DISTINCT_MAX = 10_000L;\n    private static final int N_THREADS = Runtime.getRuntime().availableProcessors();\n\n    private static final MemorySegment ALL = MemorySegment.NULL.reinterpret(Long.MAX_VALUE);\n    private static final VectorSpecies<Byte> BYTE_SPECIES = ByteVector.SPECIES_PREFERRED;\n\n    private static final Thread.Builder THREAD_BUILDER = Thread\n            .ofPlatform()\n            .name(\"1brc-CalculateAverage-\", 0)\n            .inheritInheritableThreadLocals(false);\n\n    private static final Unsafe UNSAFE;\n\n    static {\n        if (ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN) {\n            throw new UnsupportedOperationException(\"Error: BE JVMs are not supported\");\n        }\n        if ((BYTE_SPECIES.vectorByteSize() & (BYTE_SPECIES.vectorByteSize() - 1)) != 0) {\n            throw new UnsupportedOperationException(STR.\"Unsupported vectorByteSize \\{BYTE_SPECIES.vectorByteSize()}\");\n        }\n\n        try {\n            var f = Unsafe.class.getDeclaredField(\"theUnsafe\");\n            f.setAccessible(true);\n            UNSAFE = (Unsafe) f.get(null);\n        } catch (NoSuchFieldException | IllegalAccessException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main() throws InterruptedException, IOException {\n        final var filePath = Paths.get(System.getProperty(FILE_PATH_PROPERTY, \"./measurements.txt\"));\n\n        try (final var channel = FileChannel.open(filePath)) {\n            final var inputMapped = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size(), Arena.global());\n\n            final var chunkBounds = calcChunkBounds(inputMapped.address(), inputMapped.byteSize());\n            final var maps = new HashTable[N_THREADS];\n\n            try (final var threadPool = Executors.newFixedThreadPool(N_THREADS, THREAD_BUILDER.factory());\n                    final var singleThreadExecutor = Executors.newSingleThreadExecutor(Thread.ofVirtual().factory())) {\n                final var rootTask = CompletableFuture.runAsync(new CalculateAverageTask(maps, chunkBounds, 0), threadPool);\n\n                final var futures = IntStream\n                        .range(1, N_THREADS)\n                        .mapToObj(t -> CompletableFuture\n                                .runAsync(new CalculateAverageTask(maps, chunkBounds, t), threadPool)\n                                .runAfterBothAsync(rootTask, () -> maps[0].merge(maps[t]), singleThreadExecutor))\n                        .toArray(CompletableFuture[]::new);\n\n                CompletableFuture.allOf(futures).join();\n            }\n\n            printSorted(maps[0]);\n        }\n    }\n\n    private static long[] calcChunkBounds(final long mappedAddr, final long fileSizeBytes) {\n        final var chunkBounds = new long[N_THREADS + 1];\n        chunkBounds[0] = mappedAddr;\n        chunkBounds[chunkBounds.length - 1] = mappedAddr + fileSizeBytes;\n\n        final var chunkSize = (fileSizeBytes / N_THREADS) & -CalculateAverageTask.BATCH_SIZE_BYTES;\n        for (int i = 1; i < chunkBounds.length - 1; i++) {\n            chunkBounds[i] = chunkBounds[i - 1] + chunkSize;\n        }\n\n        return chunkBounds;\n    }\n\n    private static void printSorted(final HashTable temperatureMeasurements) {\n        final var weatherStations = new AggregatedMeasurement[(int) temperatureMeasurements.size];\n        final var nameBuffer = new byte[WEATHER_STATION_LENGTH_MAX];\n\n        for (int i = 0; i < weatherStations.length; i++) {\n            final var offset = temperatureMeasurements.getOffset(i);\n            final var nameAddr = UNSAFE.getLong(offset);\n            final var nameLength = UNSAFE.getInt(offset + Integer.BYTES * 7);\n            MemorySegment.copy(ALL, ValueLayout.JAVA_BYTE, nameAddr, nameBuffer, 0, nameLength);\n            final var nameStr = new String(nameBuffer, 0, nameLength, StandardCharsets.UTF_8);\n            weatherStations[i] = new AggregatedMeasurement(nameStr, i);\n        }\n\n        Arrays.sort(weatherStations);\n\n        System.out.print('{');\n        for (int i = 0; i < weatherStations.length - 1; i++) {\n            printAggMeasurement(weatherStations[i], temperatureMeasurements);\n            System.out.print(',');\n            System.out.print(' ');\n        }\n        printAggMeasurement(weatherStations[weatherStations.length - 1], temperatureMeasurements);\n        System.out.println('}');\n    }\n\n    private static void printAggMeasurement(final AggregatedMeasurement aggMeasurement,\n                                            final HashTable temperatureMeasurements) {\n        final var offset = temperatureMeasurements.getOffset(aggMeasurement.id());\n\n        // name\n        System.out.print(aggMeasurement.name());\n        System.out.print('=');\n\n        // min\n        printAsDouble(offset + Integer.BYTES * 5);\n        System.out.print('/');\n\n        // mean\n        final double total = UNSAFE.getLong(offset + Integer.BYTES * 2);\n        final var count = UNSAFE.getInt(offset + Integer.BYTES * 4);\n        System.out.print(round(total / count / 10d));\n        System.out.print('/');\n\n        // max\n        printAsDouble(offset + Integer.BYTES * 6);\n    }\n\n    private static void printAsDouble(final long addr) {\n        final var val = (double) UNSAFE.getInt(addr);\n        System.out.print(val / 10d);\n    }\n\n    private static double round(final double d) {\n        return Math.round(d * 10d) / 10d;\n    }\n\n    private static class CalculateAverageTask implements Runnable {\n        public static final int BATCH_SIZE_BYTES = BYTE_SPECIES.vectorByteSize();\n\n        private final HashTable[] maps;\n        private final long[] chunkBounds;\n        private final long chunkStart;\n        private final long chunkEnd;\n        private final int t;\n\n        private HashTable map;\n\n        public CalculateAverageTask(HashTable[] maps, long[] chunkBounds, int t) {\n            this.maps = maps;\n            this.chunkBounds = chunkBounds;\n            this.chunkStart = chunkBounds[t];\n            this.chunkEnd = chunkBounds[t + 1];\n            this.t = t;\n        }\n\n        @Override\n        public void run() {\n            this.maps[this.t] = new HashTable();\n            this.map = this.maps[this.t];\n\n            var lineStart = this.chunkBounds[0];\n            // walk back to find the previous '\\n' and use it as lineStart\n            for (long i = this.chunkStart - 1; i > this.chunkBounds[0]; i--) {\n                if (UNSAFE.getByte(i) == (byte) '\\n') {\n                    lineStart = i + 1L;\n                    break;\n                }\n            }\n\n            final var vectorLimit = this.chunkStart + ((this.chunkEnd - this.chunkStart) & -BATCH_SIZE_BYTES);\n            for (long i = this.chunkStart; i < vectorLimit; i += BATCH_SIZE_BYTES) {\n                var lfMask = ByteVector.fromMemorySegment(BYTE_SPECIES, ALL, i, ByteOrder.nativeOrder())\n                        .eq((byte) '\\n')\n                        .toLong();\n\n                final var lfCount = Long.bitCount(lfMask);\n                for (int j = 0; j < lfCount; j++) {\n                    final var lfPosRelative = Long.numberOfTrailingZeros(lfMask);\n                    final var lfAddress = i + lfPosRelative;\n                    processLine(lineStart, lfAddress);\n\n                    lineStart = lfAddress + 1L;\n                    // unset the lowest set bit, should compile to BLSR\n                    lfMask &= lfMask - 1L;\n                }\n            }\n\n            if (vectorLimit != this.chunkEnd) {\n                processTrailingBytes(lineStart, vectorLimit, this.chunkEnd);\n            }\n        }\n\n        private void processTrailingBytes(long lineStart,\n                                          final long start,\n                                          final long end) {\n            for (long i = start; i < end; i++) {\n                final var b = UNSAFE.getByte(i);\n                if (b != (byte) '\\n') {\n                    continue;\n                }\n\n                processLine(lineStart, i);\n                lineStart = i + 1;\n            }\n        }\n\n        private void processLine(final long lineStart, final long lfAddress) {\n            // read 5 bytes before '\\n'\n            // the temperature is formatted to 1 decimal place\n            // therefore the shortest temperature value is 0.0\n            // so there are always at least 5 bytes between the location name and '\\n'\n            final var trailing5Bytes = UNSAFE.getLong(lfAddress - 5);\n            final int trailingDWordRaw = (int) (trailing5Bytes >>> 8);\n\n            // select the low nibble for each byte, '0'-'9' -> 0-9, ';' -> 11, '-' -> 13\n            final var trailingDWordLowNibble = trailingDWordRaw & 0x0f_0f_0f_0f;\n            // parse the 2 digits around the decimal point (note that these 2 digits must be present)\n            final var trailingDigitsParsed = (trailingDWordLowNibble * 0x00_0a_00_01) >>> 24;\n\n            // this byte must be ('-' & 0xf), (';' & 0xf), or a valid digit (0-9)\n            final var secondHighestByte = trailingDWordLowNibble & 0xf;\n\n            var temperature = trailingDigitsParsed;\n            var lineLength = lfAddress - lineStart - 4;\n\n            if (secondHighestByte > 9) {\n                if (secondHighestByte == ('-' & 0xf)) {\n                    lineLength--;\n                    temperature = -temperature;\n                }\n            }\n            else {\n                lineLength--;\n                temperature += secondHighestByte * 100;\n\n                final var isNegative = (trailing5Bytes & 0xffL) == '-';\n                if (isNegative) {\n                    lineLength--;\n                    temperature = -temperature;\n                }\n            }\n\n            this.map.putEntry(lineStart, (int) lineLength, temperature);\n        }\n    }\n\n    /**\n     * Open addressing, linear probing hash map backed by off-heap memory\n     */\n    private static class HashTable {\n        private static final int TRUNCATED_HASH_BITS = 26;\n        // max # of unique keys\n        private static final long DENSE_SIZE = WEATHER_STATION_DISTINCT_MAX;\n        // max hash code (exclusive)\n        private static final long SPARSE_SIZE = 1L << (TRUNCATED_HASH_BITS + 1);\n        public static final long SPARSE_SCALE = 32;\n        public static final long DENSE_SCALE = 8;\n\n        public final long sparseAddress;\n        public final long denseAddress;\n        public long size;\n\n        public HashTable() {\n            var arena = new MallocArena(Arena.global());\n            var callocArena = new CallocArena(Arena.global());\n\n            final var sparse = callocArena.allocate(ValueLayout.JAVA_BYTE, SPARSE_SIZE * SPARSE_SCALE);\n            this.sparseAddress = (sparse.address() + MallocArena.MAX_ALIGN) & -MallocArena.MAX_ALIGN;\n\n            final var dense = arena.allocate(ValueLayout.JAVA_BYTE, DENSE_SIZE * DENSE_SCALE);\n            this.denseAddress = (dense.address() + MallocArena.MAX_ALIGN) & -MallocArena.MAX_ALIGN;\n        }\n\n        public long getOffset(final long index) {\n            return UNSAFE.getLong(this.denseAddress + index * DENSE_SCALE);\n        }\n\n        public void putEntry(final long keyAddress, final int keyLength, final int value) {\n            final var hash = hash(keyAddress, keyLength);\n            this.putEntryInternal(hash, keyAddress, keyLength, value, 1, value, value);\n        }\n\n        private void putEntryInternal(final long hash,\n                                      final long keyAddress,\n                                      final int keyLength,\n                                      final long temperature,\n                                      final int count,\n                                      final int temperatureMin,\n                                      final int temperatureMax) {\n            final var sparseOffset = this.sparseAddress + truncateHash(hash) * SPARSE_SCALE;\n\n            for (long n = 0, sparseLinearOffset = sparseOffset; n < WEATHER_STATION_DISTINCT_MAX; n++, sparseLinearOffset += SPARSE_SCALE) {\n                final var entryKeyAddress = UNSAFE.getLong(sparseLinearOffset);\n\n                if (entryKeyAddress == 0L) {\n                    this.add(sparseLinearOffset, keyAddress, keyLength, temperature, count, temperatureMin, temperatureMax);\n                    this.size++;\n                    return;\n                }\n\n                if (mismatch(keyAddress, entryKeyAddress, keyLength)) {\n                    continue;\n                }\n\n                final var currMin = UNSAFE.getInt(sparseLinearOffset + Integer.BYTES * 5);\n                final var currMax = UNSAFE.getInt(sparseLinearOffset + Integer.BYTES * 6);\n                final var currTotal = UNSAFE.getLong(sparseLinearOffset + Integer.BYTES * 2);\n                final var currCount = UNSAFE.getInt(sparseLinearOffset + Integer.BYTES * 4);\n\n                UNSAFE.putLong(sparseLinearOffset + Integer.BYTES * 2, currTotal + temperature);\n                UNSAFE.putInt(sparseLinearOffset + Integer.BYTES * 4, currCount + count);\n\n                if (temperatureMin < currMin) {\n                    UNSAFE.putInt(sparseLinearOffset + Integer.BYTES * 5, temperatureMin);\n                }\n\n                if (temperatureMax > currMax) {\n                    UNSAFE.putInt(sparseLinearOffset + Integer.BYTES * 6, temperatureMax);\n                }\n\n                return;\n            }\n        }\n\n        public void merge(final HashTable other) {\n            final var otherSize = other.size;\n            for (long i = 0; i < otherSize; i++) {\n                final var offset = other.getOffset(i);\n\n                final var keyAddress = UNSAFE.getLong(offset);\n                final var keyLength = UNSAFE.getInt(offset + Integer.BYTES * 7);\n                final var hash = hash(keyAddress, keyLength);\n\n                this.putEntryInternal(\n                        hash,\n                        keyAddress,\n                        keyLength,\n                        UNSAFE.getLong(offset + Integer.BYTES * 2),\n                        UNSAFE.getInt(offset + Integer.BYTES * 4),\n                        UNSAFE.getInt(offset + Integer.BYTES * 5),\n                        UNSAFE.getInt(offset + Integer.BYTES * 6));\n            }\n        }\n\n        private void add(final long sparseOffset,\n                         final long keyAddress,\n                         final int keyLength,\n                         final long temperature,\n                         final int count,\n                         final int temperatureMin,\n                         final int temperatureMax) {\n            // new entry, initialize sparse and dense\n            final var denseOffset = this.denseAddress + this.size * DENSE_SCALE;\n            UNSAFE.putLong(denseOffset, sparseOffset);\n\n            UNSAFE.putLong(sparseOffset, keyAddress);\n            UNSAFE.putLong(sparseOffset + Integer.BYTES * 2, temperature);\n            UNSAFE.putInt(sparseOffset + Integer.BYTES * 4, count);\n            UNSAFE.putInt(sparseOffset + Integer.BYTES * 5, temperatureMin);\n            UNSAFE.putInt(sparseOffset + Integer.BYTES * 6, temperatureMax);\n            UNSAFE.putInt(sparseOffset + Integer.BYTES * 7, keyLength);\n        }\n\n        private static boolean mismatch(final long leftAddr, final long rightAddr, final int length) {\n            // key length compare is unnecessary\n            // strings compared through delimiter byte ';'\n\n            final var loopBound = length >= (BYTE_SPECIES.vectorByteSize() - 1) ? ((length + 1) & -BYTE_SPECIES.vectorByteSize()) : 0;\n            for (long i = 0; i < loopBound; i += BYTE_SPECIES.vectorByteSize()) {\n                final var l = ByteVector.fromMemorySegment(BYTE_SPECIES, ALL, leftAddr + i, ByteOrder.nativeOrder());\n                final var r = ByteVector.fromMemorySegment(BYTE_SPECIES, ALL, rightAddr + i, ByteOrder.nativeOrder());\n                if (!l.eq(r).allTrue()) {\n                    return true;\n                }\n            }\n\n            final var l = ByteVector.fromMemorySegment(BYTE_SPECIES, ALL, leftAddr + loopBound, ByteOrder.nativeOrder());\n            final var r = ByteVector.fromMemorySegment(BYTE_SPECIES, ALL, rightAddr + loopBound, ByteOrder.nativeOrder());\n            final var eqMask = l.eq(r).toLong();\n\n            return Long.numberOfTrailingZeros(~eqMask) < ((length + 1) & (BYTE_SPECIES.vectorByteSize() - 1));\n            // to support platforms without TZCNT, the check can be replaced with\n            // a comparison to lowestZero = ~eqMask & (eqMask + 1)\n        }\n\n        // Use the leading and trailing few bytes as hash\n        // this performs better than computing a good hash\n        private static long hash(final long keyAddress, final int keyLength) {\n            final var leadingQWord = UNSAFE.getLong(keyAddress);\n            // the constant is the 64 bit FNV-1 offset basis\n            final var hash = -3750763034362895579L ^ leadingQWord;\n            if (keyLength < Integer.BYTES) {\n                // the key is at least 2 bytes (if you count the delimiter)\n                return hash & 0xffffL;\n            }\n            else {\n                final var trailingDWord = UNSAFE.getLong(keyAddress + keyLength - Integer.BYTES) & 0xffffffffL;\n                // only the lower dword in hash is guaranteed to exist so shift left 32\n                return (hash << Integer.SIZE) ^ trailingDWord;\n            }\n        }\n\n        private static long truncateHash(final long hash) {\n            return ((hash >>> TRUNCATED_HASH_BITS) ^ hash) & ((1L << TRUNCATED_HASH_BITS) - 1L);\n        }\n    }\n\n    private static class MallocArena implements Arena {\n        public static final long MAX_ALIGN = 1L << 21;\n\n        protected static final Linker LINKER = Linker.nativeLinker();\n        protected static final AddressLayout C_POINTER = (AddressLayout) LINKER.canonicalLayouts().get(\"void*\");\n        protected static final ValueLayout C_SIZE_T = (ValueLayout) LINKER.canonicalLayouts().get(\"size_t\");\n        private static final MethodHandle MALLOC = LINKER.downcallHandle(\n                LINKER.defaultLookup().find(\"malloc\").orElseThrow(),\n                FunctionDescriptor.of(C_POINTER, C_SIZE_T),\n                Linker.Option.critical(false));\n        private static final MethodHandle FREE = LINKER.downcallHandle(\n                LINKER.defaultLookup().find(\"free\").orElseThrow(),\n                FunctionDescriptor.ofVoid(C_POINTER),\n                Linker.Option.critical(false));\n        protected static final MethodHandle CALLOC = LINKER.downcallHandle(\n                LINKER.defaultLookup().find(\"calloc\").orElseThrow(),\n                FunctionDescriptor.of(C_POINTER, C_SIZE_T, C_SIZE_T),\n                Linker.Option.critical(false));\n\n        private final Arena arena;\n\n        public MallocArena(Arena arena) {\n            this.arena = arena;\n        }\n\n        @Override\n        public MemorySegment allocate(final long byteSize, final long byteAlignment) {\n            return malloc(byteSize + MAX_ALIGN).reinterpret(this, MallocArena::free);\n        }\n\n        @Override\n        public MemorySegment.Scope scope() {\n            return arena.scope();\n        }\n\n        @Override\n        public void close() {\n            arena.close();\n        }\n\n        private static MemorySegment malloc(final long byteSize) {\n            try {\n                return ((MemorySegment) MALLOC.invokeExact(byteSize)).reinterpret(byteSize);\n            }\n            catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        protected static void free(final MemorySegment address) {\n            try {\n                FREE.invokeExact(address);\n            }\n            catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private static class CallocArena extends MallocArena {\n        public CallocArena(Arena arena) {\n            super(arena);\n        }\n\n        @Override\n        public MemorySegment allocate(final long byteSize, final long byteAlignment) {\n            return calloc(byteSize + MAX_ALIGN).reinterpret(this, MallocArena::free);\n        }\n\n        private static MemorySegment calloc(final long byteSize) {\n            try {\n                return ((MemorySegment) MallocArena.CALLOC.invokeExact(1L, byteSize)).reinterpret(byteSize);\n            }\n            catch (Throwable e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private record AggregatedMeasurement(String name, long id) implements Comparable<AggregatedMeasurement> {\n\n    @Override\n    public int compareTo(final AggregatedMeasurement other) {\n        return name.compareTo(other.name);\n    }\n}}\n"
  },
  {
    "path": "src/main/python/create_measurements.py",
    "content": "#!/usr/bin/env python\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\n# Based on https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CreateMeasurements.java\n\nimport os\nimport sys\nimport random\nimport time\n\n\ndef check_args(file_args):\n    \"\"\"\n    Sanity checks out input and prints out usage if input is not a positive integer\n    \"\"\"\n    try:\n        if len(file_args) != 2 or int(file_args[1]) <= 0:\n            raise Exception()\n    except:\n        print(\"Usage:  create_measurements.sh <positive integer number of records to create>\")\n        print(\"        You can use underscore notation for large number of records.\")\n        print(\"        For example:  1_000_000_000 for one billion\")\n        exit()\n\n\ndef build_weather_station_name_list():\n    \"\"\"\n    Grabs the weather station names from example data provided in repo and dedups\n    \"\"\"\n    station_names = []\n    with open('../../../data/weather_stations.csv', 'r') as file:\n        file_contents = file.read()\n    for station in file_contents.splitlines():\n        if \"#\" in station:\n            next\n        else:\n            station_names.append(station.split(';')[0])\n    return list(set(station_names))\n\n\ndef convert_bytes(num):\n    \"\"\"\n    Convert bytes to a human-readable format (e.g., KiB, MiB, GiB)\n    \"\"\"\n    for x in ['bytes', 'KiB', 'MiB', 'GiB']:\n        if num < 1024.0:\n            return \"%3.1f %s\" % (num, x)\n        num /= 1024.0\n\n\ndef format_elapsed_time(seconds):\n    \"\"\"\n    Format elapsed time in a human-readable format\n    \"\"\"\n    if seconds < 60:\n        return f\"{seconds:.3f} seconds\"\n    elif seconds < 3600:\n        minutes, seconds = divmod(seconds, 60)\n        return f\"{int(minutes)} minutes {int(seconds)} seconds\"\n    else:\n        hours, remainder = divmod(seconds, 3600)\n        minutes, seconds = divmod(remainder, 60)\n        if minutes == 0:\n            return f\"{int(hours)} hours {int(seconds)} seconds\"\n        else:\n            return f\"{int(hours)} hours {int(minutes)} minutes {int(seconds)} seconds\"\n\n\ndef estimate_file_size(weather_station_names, num_rows_to_create):\n    \"\"\"\n    Tries to estimate how large a file the test data will be\n    \"\"\"\n    total_name_bytes = sum(len(s.encode(\"utf-8\")) for s in weather_station_names)\n    avg_name_bytes = total_name_bytes / float(len(weather_station_names))\n\n    # avg_temp_bytes = sum(len(str(n / 10.0)) for n in range(-999, 1000)) / 1999\n    avg_temp_bytes = 4.400200100050025\n\n    # add 2 for separator and newline\n    avg_line_length = avg_name_bytes + avg_temp_bytes + 2\n\n    human_file_size = convert_bytes(num_rows_to_create * avg_line_length)\n\n    return f\"Estimated max file size is:  {human_file_size}.\"\n\n\ndef build_test_data(weather_station_names, num_rows_to_create):\n    \"\"\"\n    Generates and writes to file the requested length of test data\n    \"\"\"\n    start_time = time.time()\n    coldest_temp = -99.9\n    hottest_temp = 99.9\n    station_names_10k_max = random.choices(weather_station_names, k=10_000)\n    batch_size = 10000 # instead of writing line by line to file, process a batch of stations and put it to disk\n    chunks = num_rows_to_create // batch_size\n    print('Building test data...')\n\n    try:\n        with open(\"../../../data/measurements.txt\", 'w') as file:\n            progress = 0\n            for chunk in range(chunks):\n                \n                batch = random.choices(station_names_10k_max, k=batch_size)\n                prepped_deviated_batch = '\\n'.join([f\"{station};{random.uniform(coldest_temp, hottest_temp):.1f}\" for station in batch]) # :.1f should quicker than round on a large scale, because round utilizes mathematical operation\n                file.write(prepped_deviated_batch + '\\n')\n                \n                # Update progress bar every 1%\n                if (chunk + 1) * 100 // chunks != progress:\n                    progress = (chunk + 1) * 100 // chunks\n                    bars = '=' * (progress // 2)\n                    sys.stdout.write(f\"\\r[{bars:<50}] {progress}%\")\n                    sys.stdout.flush()\n        sys.stdout.write('\\n')\n    except Exception as e:\n        print(\"Something went wrong. Printing error info and exiting...\")\n        print(e)\n        exit()\n    \n    end_time = time.time()\n    elapsed_time = end_time - start_time\n    file_size = os.path.getsize(\"../../../data/measurements.txt\")\n    human_file_size = convert_bytes(file_size)\n \n    print(\"Test data successfully written to 1brc/data/measurements.txt\")\n    print(f\"Actual file size:  {human_file_size}\")\n    print(f\"Elapsed time: {format_elapsed_time(elapsed_time)}\")\n\n\ndef main():\n    \"\"\"\n    main program function\n    \"\"\"\n    check_args(sys.argv)\n    num_rows_to_create = int(sys.argv[1])\n    weather_station_names = []\n    weather_station_names = build_weather_station_name_list()\n    print(estimate_file_size(weather_station_names, num_rows_to_create))\n    build_test_data(weather_station_names, num_rows_to_create)\n    print(\"Test data build complete.\")\n\n\nif __name__ == \"__main__\":\n    main()\nexit()\n"
  },
  {
    "path": "src/main/resources/.dontdelete",
    "content": ""
  },
  {
    "path": "src/test/resources/.dontdelete",
    "content": ""
  },
  {
    "path": "src/test/resources/samples/measurements-1.out",
    "content": "{Kunming=19.8/19.8/19.8}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-1.txt",
    "content": "Kunming;19.8\n"
  },
  {
    "path": "src/test/resources/samples/measurements-10.out",
    "content": "{Adelaide=15.0/15.0/15.0, Cabo San Lucas=14.9/14.9/14.9, Dodoma=22.2/22.2/22.2, Halifax=12.9/12.9/12.9, Karachi=15.4/15.4/15.4, Pittsburgh=9.7/9.7/9.7, Ségou=25.7/25.7/25.7, Tauranga=38.2/38.2/38.2, Xi'an=24.2/24.2/24.2, Zagreb=12.2/12.2/12.2}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-10.txt",
    "content": "Halifax;12.9\nZagreb;12.2\nCabo San Lucas;14.9\nAdelaide;15.0\nSégou;25.7\nPittsburgh;9.7\nKarachi;15.4\nXi'an;24.2\nDodoma;22.2\nTauranga;38.2\n"
  },
  {
    "path": "src/test/resources/samples/measurements-10000-unique-keys.out",
    "content": "{id1=1.0/1.0/1.0, id10=1.0/1.0/1.0, id100=1.0/1.0/1.0, id1000=1.0/1.0/1.0, id10000=1.0/1.0/1.0, id1001=1.0/1.0/1.0, id1002=1.0/1.0/1.0, id1003=1.0/1.0/1.0, id1004=1.0/1.0/1.0, id1005=1.0/1.0/1.0, id1006=1.0/1.0/1.0, id1007=1.0/1.0/1.0, id1008=1.0/1.0/1.0, id1009=1.0/1.0/1.0, id101=1.0/1.0/1.0, id1010=1.0/1.0/1.0, id1011=1.0/1.0/1.0, id1012=1.0/1.0/1.0, id1013=1.0/1.0/1.0, id1014=1.0/1.0/1.0, id1015=1.0/1.0/1.0, id1016=1.0/1.0/1.0, id1017=1.0/1.0/1.0, id1018=1.0/1.0/1.0, id1019=1.0/1.0/1.0, id102=1.0/1.0/1.0, id1020=1.0/1.0/1.0, id1021=1.0/1.0/1.0, id1022=1.0/1.0/1.0, id1023=1.0/1.0/1.0, id1024=1.0/1.0/1.0, id1025=1.0/1.0/1.0, id1026=1.0/1.0/1.0, id1027=1.0/1.0/1.0, id1028=1.0/1.0/1.0, id1029=1.0/1.0/1.0, id103=1.0/1.0/1.0, id1030=1.0/1.0/1.0, id1031=1.0/1.0/1.0, id1032=1.0/1.0/1.0, id1033=1.0/1.0/1.0, id1034=1.0/1.0/1.0, id1035=1.0/1.0/1.0, id1036=1.0/1.0/1.0, id1037=1.0/1.0/1.0, id1038=1.0/1.0/1.0, id1039=1.0/1.0/1.0, id104=1.0/1.0/1.0, id1040=1.0/1.0/1.0, id1041=1.0/1.0/1.0, id1042=1.0/1.0/1.0, id1043=1.0/1.0/1.0, id1044=1.0/1.0/1.0, id1045=1.0/1.0/1.0, id1046=1.0/1.0/1.0, id1047=1.0/1.0/1.0, id1048=1.0/1.0/1.0, id1049=1.0/1.0/1.0, id105=1.0/1.0/1.0, id1050=1.0/1.0/1.0, id1051=1.0/1.0/1.0, id1052=1.0/1.0/1.0, id1053=1.0/1.0/1.0, id1054=1.0/1.0/1.0, id1055=1.0/1.0/1.0, id1056=1.0/1.0/1.0, id1057=1.0/1.0/1.0, id1058=1.0/1.0/1.0, id1059=1.0/1.0/1.0, id106=1.0/1.0/1.0, id1060=1.0/1.0/1.0, id1061=1.0/1.0/1.0, id1062=1.0/1.0/1.0, id1063=1.0/1.0/1.0, id1064=1.0/1.0/1.0, id1065=1.0/1.0/1.0, id1066=1.0/1.0/1.0, id1067=1.0/1.0/1.0, id1068=1.0/1.0/1.0, id1069=1.0/1.0/1.0, id107=1.0/1.0/1.0, id1070=1.0/1.0/1.0, id1071=1.0/1.0/1.0, id1072=1.0/1.0/1.0, id1073=1.0/1.0/1.0, id1074=1.0/1.0/1.0, id1075=1.0/1.0/1.0, id1076=1.0/1.0/1.0, id1077=1.0/1.0/1.0, id1078=1.0/1.0/1.0, id1079=1.0/1.0/1.0, id108=1.0/1.0/1.0, id1080=1.0/1.0/1.0, id1081=1.0/1.0/1.0, id1082=1.0/1.0/1.0, id1083=1.0/1.0/1.0, id1084=1.0/1.0/1.0, id1085=1.0/1.0/1.0, id1086=1.0/1.0/1.0, id1087=1.0/1.0/1.0, id1088=1.0/1.0/1.0, id1089=1.0/1.0/1.0, id109=1.0/1.0/1.0, id1090=1.0/1.0/1.0, id1091=1.0/1.0/1.0, id1092=1.0/1.0/1.0, id1093=1.0/1.0/1.0, id1094=1.0/1.0/1.0, id1095=1.0/1.0/1.0, id1096=1.0/1.0/1.0, id1097=1.0/1.0/1.0, id1098=1.0/1.0/1.0, id1099=1.0/1.0/1.0, id11=1.0/1.0/1.0, id110=1.0/1.0/1.0, id1100=1.0/1.0/1.0, id1101=1.0/1.0/1.0, id1102=1.0/1.0/1.0, id1103=1.0/1.0/1.0, id1104=1.0/1.0/1.0, id1105=1.0/1.0/1.0, id1106=1.0/1.0/1.0, id1107=1.0/1.0/1.0, id1108=1.0/1.0/1.0, id1109=1.0/1.0/1.0, id111=1.0/1.0/1.0, id1110=1.0/1.0/1.0, id1111=1.0/1.0/1.0, id1112=1.0/1.0/1.0, id1113=1.0/1.0/1.0, id1114=1.0/1.0/1.0, id1115=1.0/1.0/1.0, id1116=1.0/1.0/1.0, id1117=1.0/1.0/1.0, id1118=1.0/1.0/1.0, id1119=1.0/1.0/1.0, id112=1.0/1.0/1.0, id1120=1.0/1.0/1.0, id1121=1.0/1.0/1.0, id1122=1.0/1.0/1.0, id1123=1.0/1.0/1.0, id1124=1.0/1.0/1.0, id1125=1.0/1.0/1.0, id1126=1.0/1.0/1.0, id1127=1.0/1.0/1.0, id1128=1.0/1.0/1.0, id1129=1.0/1.0/1.0, id113=1.0/1.0/1.0, id1130=1.0/1.0/1.0, id1131=1.0/1.0/1.0, id1132=1.0/1.0/1.0, id1133=1.0/1.0/1.0, id1134=1.0/1.0/1.0, id1135=1.0/1.0/1.0, id1136=1.0/1.0/1.0, id1137=1.0/1.0/1.0, id1138=1.0/1.0/1.0, id1139=1.0/1.0/1.0, id114=1.0/1.0/1.0, id1140=1.0/1.0/1.0, id1141=1.0/1.0/1.0, id1142=1.0/1.0/1.0, id1143=1.0/1.0/1.0, id1144=1.0/1.0/1.0, id1145=1.0/1.0/1.0, id1146=1.0/1.0/1.0, id1147=1.0/1.0/1.0, id1148=1.0/1.0/1.0, id1149=1.0/1.0/1.0, id115=1.0/1.0/1.0, id1150=1.0/1.0/1.0, id1151=1.0/1.0/1.0, id1152=1.0/1.0/1.0, id1153=1.0/1.0/1.0, id1154=1.0/1.0/1.0, id1155=1.0/1.0/1.0, id1156=1.0/1.0/1.0, id1157=1.0/1.0/1.0, id1158=1.0/1.0/1.0, id1159=1.0/1.0/1.0, id116=1.0/1.0/1.0, id1160=1.0/1.0/1.0, id1161=1.0/1.0/1.0, id1162=1.0/1.0/1.0, id1163=1.0/1.0/1.0, id1164=1.0/1.0/1.0, id1165=1.0/1.0/1.0, id1166=1.0/1.0/1.0, id1167=1.0/1.0/1.0, id1168=1.0/1.0/1.0, id1169=1.0/1.0/1.0, id117=1.0/1.0/1.0, id1170=1.0/1.0/1.0, id1171=1.0/1.0/1.0, id1172=1.0/1.0/1.0, id1173=1.0/1.0/1.0, id1174=1.0/1.0/1.0, id1175=1.0/1.0/1.0, id1176=1.0/1.0/1.0, id1177=1.0/1.0/1.0, id1178=1.0/1.0/1.0, id1179=1.0/1.0/1.0, id118=1.0/1.0/1.0, id1180=1.0/1.0/1.0, id1181=1.0/1.0/1.0, id1182=1.0/1.0/1.0, id1183=1.0/1.0/1.0, id1184=1.0/1.0/1.0, id1185=1.0/1.0/1.0, id1186=1.0/1.0/1.0, id1187=1.0/1.0/1.0, id1188=1.0/1.0/1.0, id1189=1.0/1.0/1.0, id119=1.0/1.0/1.0, id1190=1.0/1.0/1.0, id1191=1.0/1.0/1.0, id1192=1.0/1.0/1.0, id1193=1.0/1.0/1.0, id1194=1.0/1.0/1.0, id1195=1.0/1.0/1.0, id1196=1.0/1.0/1.0, id1197=1.0/1.0/1.0, id1198=1.0/1.0/1.0, id1199=1.0/1.0/1.0, id12=1.0/1.0/1.0, id120=1.0/1.0/1.0, id1200=1.0/1.0/1.0, id1201=1.0/1.0/1.0, id1202=1.0/1.0/1.0, id1203=1.0/1.0/1.0, id1204=1.0/1.0/1.0, id1205=1.0/1.0/1.0, id1206=1.0/1.0/1.0, id1207=1.0/1.0/1.0, id1208=1.0/1.0/1.0, id1209=1.0/1.0/1.0, id121=1.0/1.0/1.0, id1210=1.0/1.0/1.0, id1211=1.0/1.0/1.0, id1212=1.0/1.0/1.0, id1213=1.0/1.0/1.0, id1214=1.0/1.0/1.0, id1215=1.0/1.0/1.0, id1216=1.0/1.0/1.0, id1217=1.0/1.0/1.0, id1218=1.0/1.0/1.0, id1219=1.0/1.0/1.0, id122=1.0/1.0/1.0, id1220=1.0/1.0/1.0, id1221=1.0/1.0/1.0, id1222=1.0/1.0/1.0, id1223=1.0/1.0/1.0, id1224=1.0/1.0/1.0, id1225=1.0/1.0/1.0, id1226=1.0/1.0/1.0, id1227=1.0/1.0/1.0, id1228=1.0/1.0/1.0, id1229=1.0/1.0/1.0, id123=1.0/1.0/1.0, id1230=1.0/1.0/1.0, id1231=1.0/1.0/1.0, id1232=1.0/1.0/1.0, id1233=1.0/1.0/1.0, id1234=1.0/1.0/1.0, id1235=1.0/1.0/1.0, id1236=1.0/1.0/1.0, id1237=1.0/1.0/1.0, id1238=1.0/1.0/1.0, id1239=1.0/1.0/1.0, id124=1.0/1.0/1.0, id1240=1.0/1.0/1.0, id1241=1.0/1.0/1.0, id1242=1.0/1.0/1.0, id1243=1.0/1.0/1.0, id1244=1.0/1.0/1.0, id1245=1.0/1.0/1.0, id1246=1.0/1.0/1.0, id1247=1.0/1.0/1.0, id1248=1.0/1.0/1.0, id1249=1.0/1.0/1.0, id125=1.0/1.0/1.0, id1250=1.0/1.0/1.0, id1251=1.0/1.0/1.0, id1252=1.0/1.0/1.0, id1253=1.0/1.0/1.0, id1254=1.0/1.0/1.0, id1255=1.0/1.0/1.0, id1256=1.0/1.0/1.0, id1257=1.0/1.0/1.0, id1258=1.0/1.0/1.0, id1259=1.0/1.0/1.0, id126=1.0/1.0/1.0, id1260=1.0/1.0/1.0, id1261=1.0/1.0/1.0, id1262=1.0/1.0/1.0, id1263=1.0/1.0/1.0, id1264=1.0/1.0/1.0, id1265=1.0/1.0/1.0, id1266=1.0/1.0/1.0, id1267=1.0/1.0/1.0, id1268=1.0/1.0/1.0, id1269=1.0/1.0/1.0, id127=1.0/1.0/1.0, id1270=1.0/1.0/1.0, id1271=1.0/1.0/1.0, id1272=1.0/1.0/1.0, id1273=1.0/1.0/1.0, id1274=1.0/1.0/1.0, id1275=1.0/1.0/1.0, id1276=1.0/1.0/1.0, id1277=1.0/1.0/1.0, id1278=1.0/1.0/1.0, id1279=1.0/1.0/1.0, id128=1.0/1.0/1.0, id1280=1.0/1.0/1.0, id1281=1.0/1.0/1.0, id1282=1.0/1.0/1.0, id1283=1.0/1.0/1.0, id1284=1.0/1.0/1.0, id1285=1.0/1.0/1.0, id1286=1.0/1.0/1.0, id1287=1.0/1.0/1.0, id1288=1.0/1.0/1.0, id1289=1.0/1.0/1.0, id129=1.0/1.0/1.0, id1290=1.0/1.0/1.0, id1291=1.0/1.0/1.0, id1292=1.0/1.0/1.0, id1293=1.0/1.0/1.0, id1294=1.0/1.0/1.0, id1295=1.0/1.0/1.0, id1296=1.0/1.0/1.0, id1297=1.0/1.0/1.0, id1298=1.0/1.0/1.0, id1299=1.0/1.0/1.0, id13=1.0/1.0/1.0, id130=1.0/1.0/1.0, id1300=1.0/1.0/1.0, id1301=1.0/1.0/1.0, id1302=1.0/1.0/1.0, id1303=1.0/1.0/1.0, id1304=1.0/1.0/1.0, id1305=1.0/1.0/1.0, id1306=1.0/1.0/1.0, id1307=1.0/1.0/1.0, id1308=1.0/1.0/1.0, id1309=1.0/1.0/1.0, id131=1.0/1.0/1.0, id1310=1.0/1.0/1.0, id1311=1.0/1.0/1.0, id1312=1.0/1.0/1.0, id1313=1.0/1.0/1.0, id1314=1.0/1.0/1.0, id1315=1.0/1.0/1.0, id1316=1.0/1.0/1.0, id1317=1.0/1.0/1.0, id1318=1.0/1.0/1.0, id1319=1.0/1.0/1.0, id132=1.0/1.0/1.0, id1320=1.0/1.0/1.0, id1321=1.0/1.0/1.0, id1322=1.0/1.0/1.0, id1323=1.0/1.0/1.0, id1324=1.0/1.0/1.0, id1325=1.0/1.0/1.0, id1326=1.0/1.0/1.0, id1327=1.0/1.0/1.0, id1328=1.0/1.0/1.0, id1329=1.0/1.0/1.0, id133=1.0/1.0/1.0, id1330=1.0/1.0/1.0, id1331=1.0/1.0/1.0, id1332=1.0/1.0/1.0, id1333=1.0/1.0/1.0, id1334=1.0/1.0/1.0, id1335=1.0/1.0/1.0, id1336=1.0/1.0/1.0, id1337=1.0/1.0/1.0, id1338=1.0/1.0/1.0, id1339=1.0/1.0/1.0, id134=1.0/1.0/1.0, id1340=1.0/1.0/1.0, id1341=1.0/1.0/1.0, id1342=1.0/1.0/1.0, id1343=1.0/1.0/1.0, id1344=1.0/1.0/1.0, id1345=1.0/1.0/1.0, id1346=1.0/1.0/1.0, id1347=1.0/1.0/1.0, id1348=1.0/1.0/1.0, id1349=1.0/1.0/1.0, id135=1.0/1.0/1.0, id1350=1.0/1.0/1.0, id1351=1.0/1.0/1.0, id1352=1.0/1.0/1.0, id1353=1.0/1.0/1.0, id1354=1.0/1.0/1.0, id1355=1.0/1.0/1.0, id1356=1.0/1.0/1.0, id1357=1.0/1.0/1.0, id1358=1.0/1.0/1.0, id1359=1.0/1.0/1.0, id136=1.0/1.0/1.0, id1360=1.0/1.0/1.0, id1361=1.0/1.0/1.0, id1362=1.0/1.0/1.0, id1363=1.0/1.0/1.0, id1364=1.0/1.0/1.0, id1365=1.0/1.0/1.0, id1366=1.0/1.0/1.0, id1367=1.0/1.0/1.0, id1368=1.0/1.0/1.0, id1369=1.0/1.0/1.0, id137=1.0/1.0/1.0, id1370=1.0/1.0/1.0, id1371=1.0/1.0/1.0, id1372=1.0/1.0/1.0, id1373=1.0/1.0/1.0, id1374=1.0/1.0/1.0, id1375=1.0/1.0/1.0, id1376=1.0/1.0/1.0, id1377=1.0/1.0/1.0, id1378=1.0/1.0/1.0, id1379=1.0/1.0/1.0, id138=1.0/1.0/1.0, id1380=1.0/1.0/1.0, id1381=1.0/1.0/1.0, id1382=1.0/1.0/1.0, id1383=1.0/1.0/1.0, id1384=1.0/1.0/1.0, id1385=1.0/1.0/1.0, id1386=1.0/1.0/1.0, id1387=1.0/1.0/1.0, id1388=1.0/1.0/1.0, id1389=1.0/1.0/1.0, id139=1.0/1.0/1.0, id1390=1.0/1.0/1.0, id1391=1.0/1.0/1.0, id1392=1.0/1.0/1.0, id1393=1.0/1.0/1.0, id1394=1.0/1.0/1.0, id1395=1.0/1.0/1.0, id1396=1.0/1.0/1.0, id1397=1.0/1.0/1.0, id1398=1.0/1.0/1.0, id1399=1.0/1.0/1.0, id14=1.0/1.0/1.0, id140=1.0/1.0/1.0, id1400=1.0/1.0/1.0, id1401=1.0/1.0/1.0, id1402=1.0/1.0/1.0, id1403=1.0/1.0/1.0, id1404=1.0/1.0/1.0, id1405=1.0/1.0/1.0, id1406=1.0/1.0/1.0, id1407=1.0/1.0/1.0, id1408=1.0/1.0/1.0, id1409=1.0/1.0/1.0, id141=1.0/1.0/1.0, id1410=1.0/1.0/1.0, id1411=1.0/1.0/1.0, id1412=1.0/1.0/1.0, id1413=1.0/1.0/1.0, id1414=1.0/1.0/1.0, id1415=1.0/1.0/1.0, id1416=1.0/1.0/1.0, id1417=1.0/1.0/1.0, id1418=1.0/1.0/1.0, id1419=1.0/1.0/1.0, id142=1.0/1.0/1.0, id1420=1.0/1.0/1.0, id1421=1.0/1.0/1.0, id1422=1.0/1.0/1.0, id1423=1.0/1.0/1.0, id1424=1.0/1.0/1.0, id1425=1.0/1.0/1.0, id1426=1.0/1.0/1.0, id1427=1.0/1.0/1.0, id1428=1.0/1.0/1.0, id1429=1.0/1.0/1.0, id143=1.0/1.0/1.0, id1430=1.0/1.0/1.0, id1431=1.0/1.0/1.0, id1432=1.0/1.0/1.0, id1433=1.0/1.0/1.0, id1434=1.0/1.0/1.0, id1435=1.0/1.0/1.0, id1436=1.0/1.0/1.0, id1437=1.0/1.0/1.0, id1438=1.0/1.0/1.0, id1439=1.0/1.0/1.0, id144=1.0/1.0/1.0, id1440=1.0/1.0/1.0, id1441=1.0/1.0/1.0, id1442=1.0/1.0/1.0, id1443=1.0/1.0/1.0, id1444=1.0/1.0/1.0, id1445=1.0/1.0/1.0, id1446=1.0/1.0/1.0, id1447=1.0/1.0/1.0, id1448=1.0/1.0/1.0, id1449=1.0/1.0/1.0, id145=1.0/1.0/1.0, id1450=1.0/1.0/1.0, id1451=1.0/1.0/1.0, id1452=1.0/1.0/1.0, id1453=1.0/1.0/1.0, id1454=1.0/1.0/1.0, id1455=1.0/1.0/1.0, id1456=1.0/1.0/1.0, id1457=1.0/1.0/1.0, id1458=1.0/1.0/1.0, id1459=1.0/1.0/1.0, id146=1.0/1.0/1.0, id1460=1.0/1.0/1.0, id1461=1.0/1.0/1.0, id1462=1.0/1.0/1.0, id1463=1.0/1.0/1.0, id1464=1.0/1.0/1.0, id1465=1.0/1.0/1.0, id1466=1.0/1.0/1.0, id1467=1.0/1.0/1.0, id1468=1.0/1.0/1.0, id1469=1.0/1.0/1.0, id147=1.0/1.0/1.0, id1470=1.0/1.0/1.0, id1471=1.0/1.0/1.0, id1472=1.0/1.0/1.0, id1473=1.0/1.0/1.0, id1474=1.0/1.0/1.0, id1475=1.0/1.0/1.0, id1476=1.0/1.0/1.0, id1477=1.0/1.0/1.0, id1478=1.0/1.0/1.0, id1479=1.0/1.0/1.0, id148=1.0/1.0/1.0, id1480=1.0/1.0/1.0, id1481=1.0/1.0/1.0, id1482=1.0/1.0/1.0, id1483=1.0/1.0/1.0, id1484=1.0/1.0/1.0, id1485=1.0/1.0/1.0, id1486=1.0/1.0/1.0, id1487=1.0/1.0/1.0, id1488=1.0/1.0/1.0, id1489=1.0/1.0/1.0, id149=1.0/1.0/1.0, id1490=1.0/1.0/1.0, id1491=1.0/1.0/1.0, id1492=1.0/1.0/1.0, id1493=1.0/1.0/1.0, id1494=1.0/1.0/1.0, id1495=1.0/1.0/1.0, id1496=1.0/1.0/1.0, id1497=1.0/1.0/1.0, id1498=1.0/1.0/1.0, id1499=1.0/1.0/1.0, id15=1.0/1.0/1.0, id150=1.0/1.0/1.0, id1500=1.0/1.0/1.0, id1501=1.0/1.0/1.0, id1502=1.0/1.0/1.0, id1503=1.0/1.0/1.0, id1504=1.0/1.0/1.0, id1505=1.0/1.0/1.0, id1506=1.0/1.0/1.0, id1507=1.0/1.0/1.0, id1508=1.0/1.0/1.0, id1509=1.0/1.0/1.0, id151=1.0/1.0/1.0, id1510=1.0/1.0/1.0, id1511=1.0/1.0/1.0, id1512=1.0/1.0/1.0, id1513=1.0/1.0/1.0, id1514=1.0/1.0/1.0, id1515=1.0/1.0/1.0, id1516=1.0/1.0/1.0, id1517=1.0/1.0/1.0, id1518=1.0/1.0/1.0, id1519=1.0/1.0/1.0, id152=1.0/1.0/1.0, id1520=1.0/1.0/1.0, id1521=1.0/1.0/1.0, id1522=1.0/1.0/1.0, id1523=1.0/1.0/1.0, id1524=1.0/1.0/1.0, id1525=1.0/1.0/1.0, id1526=1.0/1.0/1.0, id1527=1.0/1.0/1.0, id1528=1.0/1.0/1.0, id1529=1.0/1.0/1.0, id153=1.0/1.0/1.0, id1530=1.0/1.0/1.0, id1531=1.0/1.0/1.0, id1532=1.0/1.0/1.0, id1533=1.0/1.0/1.0, id1534=1.0/1.0/1.0, id1535=1.0/1.0/1.0, id1536=1.0/1.0/1.0, id1537=1.0/1.0/1.0, id1538=1.0/1.0/1.0, id1539=1.0/1.0/1.0, id154=1.0/1.0/1.0, id1540=1.0/1.0/1.0, id1541=1.0/1.0/1.0, id1542=1.0/1.0/1.0, id1543=1.0/1.0/1.0, id1544=1.0/1.0/1.0, id1545=1.0/1.0/1.0, id1546=1.0/1.0/1.0, id1547=1.0/1.0/1.0, id1548=1.0/1.0/1.0, id1549=1.0/1.0/1.0, id155=1.0/1.0/1.0, id1550=1.0/1.0/1.0, id1551=1.0/1.0/1.0, id1552=1.0/1.0/1.0, id1553=1.0/1.0/1.0, id1554=1.0/1.0/1.0, id1555=1.0/1.0/1.0, id1556=1.0/1.0/1.0, id1557=1.0/1.0/1.0, id1558=1.0/1.0/1.0, id1559=1.0/1.0/1.0, id156=1.0/1.0/1.0, id1560=1.0/1.0/1.0, id1561=1.0/1.0/1.0, id1562=1.0/1.0/1.0, id1563=1.0/1.0/1.0, id1564=1.0/1.0/1.0, id1565=1.0/1.0/1.0, id1566=1.0/1.0/1.0, id1567=1.0/1.0/1.0, id1568=1.0/1.0/1.0, id1569=1.0/1.0/1.0, id157=1.0/1.0/1.0, id1570=1.0/1.0/1.0, id1571=1.0/1.0/1.0, id1572=1.0/1.0/1.0, id1573=1.0/1.0/1.0, id1574=1.0/1.0/1.0, id1575=1.0/1.0/1.0, id1576=1.0/1.0/1.0, id1577=1.0/1.0/1.0, id1578=1.0/1.0/1.0, id1579=1.0/1.0/1.0, id158=1.0/1.0/1.0, id1580=1.0/1.0/1.0, id1581=1.0/1.0/1.0, id1582=1.0/1.0/1.0, id1583=1.0/1.0/1.0, id1584=1.0/1.0/1.0, id1585=1.0/1.0/1.0, id1586=1.0/1.0/1.0, id1587=1.0/1.0/1.0, id1588=1.0/1.0/1.0, id1589=1.0/1.0/1.0, id159=1.0/1.0/1.0, id1590=1.0/1.0/1.0, id1591=1.0/1.0/1.0, id1592=1.0/1.0/1.0, id1593=1.0/1.0/1.0, id1594=1.0/1.0/1.0, id1595=1.0/1.0/1.0, id1596=1.0/1.0/1.0, id1597=1.0/1.0/1.0, id1598=1.0/1.0/1.0, id1599=1.0/1.0/1.0, id16=1.0/1.0/1.0, id160=1.0/1.0/1.0, id1600=1.0/1.0/1.0, id1601=1.0/1.0/1.0, id1602=1.0/1.0/1.0, id1603=1.0/1.0/1.0, id1604=1.0/1.0/1.0, id1605=1.0/1.0/1.0, id1606=1.0/1.0/1.0, id1607=1.0/1.0/1.0, id1608=1.0/1.0/1.0, id1609=1.0/1.0/1.0, id161=1.0/1.0/1.0, id1610=1.0/1.0/1.0, id1611=1.0/1.0/1.0, id1612=1.0/1.0/1.0, id1613=1.0/1.0/1.0, id1614=1.0/1.0/1.0, id1615=1.0/1.0/1.0, id1616=1.0/1.0/1.0, id1617=1.0/1.0/1.0, id1618=1.0/1.0/1.0, id1619=1.0/1.0/1.0, id162=1.0/1.0/1.0, id1620=1.0/1.0/1.0, id1621=1.0/1.0/1.0, id1622=1.0/1.0/1.0, id1623=1.0/1.0/1.0, id1624=1.0/1.0/1.0, id1625=1.0/1.0/1.0, id1626=1.0/1.0/1.0, id1627=1.0/1.0/1.0, id1628=1.0/1.0/1.0, id1629=1.0/1.0/1.0, id163=1.0/1.0/1.0, id1630=1.0/1.0/1.0, id1631=1.0/1.0/1.0, id1632=1.0/1.0/1.0, id1633=1.0/1.0/1.0, id1634=1.0/1.0/1.0, id1635=1.0/1.0/1.0, id1636=1.0/1.0/1.0, id1637=1.0/1.0/1.0, id1638=1.0/1.0/1.0, id1639=1.0/1.0/1.0, id164=1.0/1.0/1.0, id1640=1.0/1.0/1.0, id1641=1.0/1.0/1.0, id1642=1.0/1.0/1.0, id1643=1.0/1.0/1.0, id1644=1.0/1.0/1.0, id1645=1.0/1.0/1.0, id1646=1.0/1.0/1.0, id1647=1.0/1.0/1.0, id1648=1.0/1.0/1.0, id1649=1.0/1.0/1.0, id165=1.0/1.0/1.0, id1650=1.0/1.0/1.0, id1651=1.0/1.0/1.0, id1652=1.0/1.0/1.0, id1653=1.0/1.0/1.0, id1654=1.0/1.0/1.0, id1655=1.0/1.0/1.0, id1656=1.0/1.0/1.0, id1657=1.0/1.0/1.0, id1658=1.0/1.0/1.0, id1659=1.0/1.0/1.0, id166=1.0/1.0/1.0, id1660=1.0/1.0/1.0, id1661=1.0/1.0/1.0, id1662=1.0/1.0/1.0, id1663=1.0/1.0/1.0, id1664=1.0/1.0/1.0, id1665=1.0/1.0/1.0, id1666=1.0/1.0/1.0, id1667=1.0/1.0/1.0, id1668=1.0/1.0/1.0, id1669=1.0/1.0/1.0, id167=1.0/1.0/1.0, id1670=1.0/1.0/1.0, id1671=1.0/1.0/1.0, id1672=1.0/1.0/1.0, id1673=1.0/1.0/1.0, id1674=1.0/1.0/1.0, id1675=1.0/1.0/1.0, id1676=1.0/1.0/1.0, id1677=1.0/1.0/1.0, id1678=1.0/1.0/1.0, id1679=1.0/1.0/1.0, id168=1.0/1.0/1.0, id1680=1.0/1.0/1.0, id1681=1.0/1.0/1.0, id1682=1.0/1.0/1.0, id1683=1.0/1.0/1.0, id1684=1.0/1.0/1.0, id1685=1.0/1.0/1.0, id1686=1.0/1.0/1.0, id1687=1.0/1.0/1.0, id1688=1.0/1.0/1.0, id1689=1.0/1.0/1.0, id169=1.0/1.0/1.0, id1690=1.0/1.0/1.0, id1691=1.0/1.0/1.0, id1692=1.0/1.0/1.0, id1693=1.0/1.0/1.0, id1694=1.0/1.0/1.0, id1695=1.0/1.0/1.0, id1696=1.0/1.0/1.0, id1697=1.0/1.0/1.0, id1698=1.0/1.0/1.0, id1699=1.0/1.0/1.0, id17=1.0/1.0/1.0, id170=1.0/1.0/1.0, id1700=1.0/1.0/1.0, id1701=1.0/1.0/1.0, id1702=1.0/1.0/1.0, id1703=1.0/1.0/1.0, id1704=1.0/1.0/1.0, id1705=1.0/1.0/1.0, id1706=1.0/1.0/1.0, id1707=1.0/1.0/1.0, id1708=1.0/1.0/1.0, id1709=1.0/1.0/1.0, id171=1.0/1.0/1.0, id1710=1.0/1.0/1.0, id1711=1.0/1.0/1.0, id1712=1.0/1.0/1.0, id1713=1.0/1.0/1.0, id1714=1.0/1.0/1.0, id1715=1.0/1.0/1.0, id1716=1.0/1.0/1.0, id1717=1.0/1.0/1.0, id1718=1.0/1.0/1.0, id1719=1.0/1.0/1.0, id172=1.0/1.0/1.0, id1720=1.0/1.0/1.0, id1721=1.0/1.0/1.0, id1722=1.0/1.0/1.0, id1723=1.0/1.0/1.0, id1724=1.0/1.0/1.0, id1725=1.0/1.0/1.0, id1726=1.0/1.0/1.0, id1727=1.0/1.0/1.0, id1728=1.0/1.0/1.0, id1729=1.0/1.0/1.0, id173=1.0/1.0/1.0, id1730=1.0/1.0/1.0, id1731=1.0/1.0/1.0, id1732=1.0/1.0/1.0, id1733=1.0/1.0/1.0, id1734=1.0/1.0/1.0, id1735=1.0/1.0/1.0, id1736=1.0/1.0/1.0, id1737=1.0/1.0/1.0, id1738=1.0/1.0/1.0, id1739=1.0/1.0/1.0, id174=1.0/1.0/1.0, id1740=1.0/1.0/1.0, id1741=1.0/1.0/1.0, id1742=1.0/1.0/1.0, id1743=1.0/1.0/1.0, id1744=1.0/1.0/1.0, id1745=1.0/1.0/1.0, id1746=1.0/1.0/1.0, id1747=1.0/1.0/1.0, id1748=1.0/1.0/1.0, id1749=1.0/1.0/1.0, id175=1.0/1.0/1.0, id1750=1.0/1.0/1.0, id1751=1.0/1.0/1.0, id1752=1.0/1.0/1.0, id1753=1.0/1.0/1.0, id1754=1.0/1.0/1.0, id1755=1.0/1.0/1.0, id1756=1.0/1.0/1.0, id1757=1.0/1.0/1.0, id1758=1.0/1.0/1.0, id1759=1.0/1.0/1.0, id176=1.0/1.0/1.0, id1760=1.0/1.0/1.0, id1761=1.0/1.0/1.0, id1762=1.0/1.0/1.0, id1763=1.0/1.0/1.0, id1764=1.0/1.0/1.0, id1765=1.0/1.0/1.0, id1766=1.0/1.0/1.0, id1767=1.0/1.0/1.0, id1768=1.0/1.0/1.0, id1769=1.0/1.0/1.0, id177=1.0/1.0/1.0, id1770=1.0/1.0/1.0, id1771=1.0/1.0/1.0, id1772=1.0/1.0/1.0, id1773=1.0/1.0/1.0, id1774=1.0/1.0/1.0, id1775=1.0/1.0/1.0, id1776=1.0/1.0/1.0, id1777=1.0/1.0/1.0, id1778=1.0/1.0/1.0, id1779=1.0/1.0/1.0, id178=1.0/1.0/1.0, id1780=1.0/1.0/1.0, id1781=1.0/1.0/1.0, id1782=1.0/1.0/1.0, id1783=1.0/1.0/1.0, id1784=1.0/1.0/1.0, id1785=1.0/1.0/1.0, id1786=1.0/1.0/1.0, id1787=1.0/1.0/1.0, id1788=1.0/1.0/1.0, id1789=1.0/1.0/1.0, id179=1.0/1.0/1.0, id1790=1.0/1.0/1.0, id1791=1.0/1.0/1.0, id1792=1.0/1.0/1.0, id1793=1.0/1.0/1.0, id1794=1.0/1.0/1.0, id1795=1.0/1.0/1.0, id1796=1.0/1.0/1.0, id1797=1.0/1.0/1.0, id1798=1.0/1.0/1.0, id1799=1.0/1.0/1.0, id18=1.0/1.0/1.0, id180=1.0/1.0/1.0, id1800=1.0/1.0/1.0, id1801=1.0/1.0/1.0, id1802=1.0/1.0/1.0, id1803=1.0/1.0/1.0, id1804=1.0/1.0/1.0, id1805=1.0/1.0/1.0, id1806=1.0/1.0/1.0, id1807=1.0/1.0/1.0, id1808=1.0/1.0/1.0, id1809=1.0/1.0/1.0, id181=1.0/1.0/1.0, id1810=1.0/1.0/1.0, id1811=1.0/1.0/1.0, id1812=1.0/1.0/1.0, id1813=1.0/1.0/1.0, id1814=1.0/1.0/1.0, id1815=1.0/1.0/1.0, id1816=1.0/1.0/1.0, id1817=1.0/1.0/1.0, id1818=1.0/1.0/1.0, id1819=1.0/1.0/1.0, id182=1.0/1.0/1.0, id1820=1.0/1.0/1.0, id1821=1.0/1.0/1.0, id1822=1.0/1.0/1.0, id1823=1.0/1.0/1.0, id1824=1.0/1.0/1.0, id1825=1.0/1.0/1.0, id1826=1.0/1.0/1.0, id1827=1.0/1.0/1.0, id1828=1.0/1.0/1.0, id1829=1.0/1.0/1.0, id183=1.0/1.0/1.0, id1830=1.0/1.0/1.0, id1831=1.0/1.0/1.0, id1832=1.0/1.0/1.0, id1833=1.0/1.0/1.0, id1834=1.0/1.0/1.0, id1835=1.0/1.0/1.0, id1836=1.0/1.0/1.0, id1837=1.0/1.0/1.0, id1838=1.0/1.0/1.0, id1839=1.0/1.0/1.0, id184=1.0/1.0/1.0, id1840=1.0/1.0/1.0, id1841=1.0/1.0/1.0, id1842=1.0/1.0/1.0, id1843=1.0/1.0/1.0, id1844=1.0/1.0/1.0, id1845=1.0/1.0/1.0, id1846=1.0/1.0/1.0, id1847=1.0/1.0/1.0, id1848=1.0/1.0/1.0, id1849=1.0/1.0/1.0, id185=1.0/1.0/1.0, id1850=1.0/1.0/1.0, id1851=1.0/1.0/1.0, id1852=1.0/1.0/1.0, id1853=1.0/1.0/1.0, id1854=1.0/1.0/1.0, id1855=1.0/1.0/1.0, id1856=1.0/1.0/1.0, id1857=1.0/1.0/1.0, id1858=1.0/1.0/1.0, id1859=1.0/1.0/1.0, id186=1.0/1.0/1.0, id1860=1.0/1.0/1.0, id1861=1.0/1.0/1.0, id1862=1.0/1.0/1.0, id1863=1.0/1.0/1.0, id1864=1.0/1.0/1.0, id1865=1.0/1.0/1.0, id1866=1.0/1.0/1.0, id1867=1.0/1.0/1.0, id1868=1.0/1.0/1.0, id1869=1.0/1.0/1.0, id187=1.0/1.0/1.0, id1870=1.0/1.0/1.0, id1871=1.0/1.0/1.0, id1872=1.0/1.0/1.0, id1873=1.0/1.0/1.0, id1874=1.0/1.0/1.0, id1875=1.0/1.0/1.0, id1876=1.0/1.0/1.0, id1877=1.0/1.0/1.0, id1878=1.0/1.0/1.0, id1879=1.0/1.0/1.0, id188=1.0/1.0/1.0, id1880=1.0/1.0/1.0, id1881=1.0/1.0/1.0, id1882=1.0/1.0/1.0, id1883=1.0/1.0/1.0, id1884=1.0/1.0/1.0, id1885=1.0/1.0/1.0, id1886=1.0/1.0/1.0, id1887=1.0/1.0/1.0, id1888=1.0/1.0/1.0, id1889=1.0/1.0/1.0, id189=1.0/1.0/1.0, id1890=1.0/1.0/1.0, id1891=1.0/1.0/1.0, id1892=1.0/1.0/1.0, id1893=1.0/1.0/1.0, id1894=1.0/1.0/1.0, id1895=1.0/1.0/1.0, id1896=1.0/1.0/1.0, id1897=1.0/1.0/1.0, id1898=1.0/1.0/1.0, id1899=1.0/1.0/1.0, id19=1.0/1.0/1.0, id190=1.0/1.0/1.0, id1900=1.0/1.0/1.0, id1901=1.0/1.0/1.0, id1902=1.0/1.0/1.0, id1903=1.0/1.0/1.0, id1904=1.0/1.0/1.0, id1905=1.0/1.0/1.0, id1906=1.0/1.0/1.0, id1907=1.0/1.0/1.0, id1908=1.0/1.0/1.0, id1909=1.0/1.0/1.0, id191=1.0/1.0/1.0, id1910=1.0/1.0/1.0, id1911=1.0/1.0/1.0, id1912=1.0/1.0/1.0, id1913=1.0/1.0/1.0, id1914=1.0/1.0/1.0, id1915=1.0/1.0/1.0, id1916=1.0/1.0/1.0, id1917=1.0/1.0/1.0, id1918=1.0/1.0/1.0, id1919=1.0/1.0/1.0, id192=1.0/1.0/1.0, id1920=1.0/1.0/1.0, id1921=1.0/1.0/1.0, id1922=1.0/1.0/1.0, id1923=1.0/1.0/1.0, id1924=1.0/1.0/1.0, id1925=1.0/1.0/1.0, id1926=1.0/1.0/1.0, id1927=1.0/1.0/1.0, id1928=1.0/1.0/1.0, id1929=1.0/1.0/1.0, id193=1.0/1.0/1.0, id1930=1.0/1.0/1.0, id1931=1.0/1.0/1.0, id1932=1.0/1.0/1.0, id1933=1.0/1.0/1.0, id1934=1.0/1.0/1.0, id1935=1.0/1.0/1.0, id1936=1.0/1.0/1.0, id1937=1.0/1.0/1.0, id1938=1.0/1.0/1.0, id1939=1.0/1.0/1.0, id194=1.0/1.0/1.0, id1940=1.0/1.0/1.0, id1941=1.0/1.0/1.0, id1942=1.0/1.0/1.0, id1943=1.0/1.0/1.0, id1944=1.0/1.0/1.0, id1945=1.0/1.0/1.0, id1946=1.0/1.0/1.0, id1947=1.0/1.0/1.0, id1948=1.0/1.0/1.0, id1949=1.0/1.0/1.0, id195=1.0/1.0/1.0, id1950=1.0/1.0/1.0, id1951=1.0/1.0/1.0, id1952=1.0/1.0/1.0, id1953=1.0/1.0/1.0, id1954=1.0/1.0/1.0, id1955=1.0/1.0/1.0, id1956=1.0/1.0/1.0, id1957=1.0/1.0/1.0, id1958=1.0/1.0/1.0, id1959=1.0/1.0/1.0, id196=1.0/1.0/1.0, id1960=1.0/1.0/1.0, id1961=1.0/1.0/1.0, id1962=1.0/1.0/1.0, id1963=1.0/1.0/1.0, id1964=1.0/1.0/1.0, id1965=1.0/1.0/1.0, id1966=1.0/1.0/1.0, id1967=1.0/1.0/1.0, id1968=1.0/1.0/1.0, id1969=1.0/1.0/1.0, id197=1.0/1.0/1.0, id1970=1.0/1.0/1.0, id1971=1.0/1.0/1.0, id1972=1.0/1.0/1.0, id1973=1.0/1.0/1.0, id1974=1.0/1.0/1.0, id1975=1.0/1.0/1.0, id1976=1.0/1.0/1.0, id1977=1.0/1.0/1.0, id1978=1.0/1.0/1.0, id1979=1.0/1.0/1.0, id198=1.0/1.0/1.0, id1980=1.0/1.0/1.0, id1981=1.0/1.0/1.0, id1982=1.0/1.0/1.0, id1983=1.0/1.0/1.0, id1984=1.0/1.0/1.0, id1985=1.0/1.0/1.0, id1986=1.0/1.0/1.0, id1987=1.0/1.0/1.0, id1988=1.0/1.0/1.0, id1989=1.0/1.0/1.0, id199=1.0/1.0/1.0, id1990=1.0/1.0/1.0, id1991=1.0/1.0/1.0, id1992=1.0/1.0/1.0, id1993=1.0/1.0/1.0, id1994=1.0/1.0/1.0, id1995=1.0/1.0/1.0, id1996=1.0/1.0/1.0, id1997=1.0/1.0/1.0, id1998=1.0/1.0/1.0, id1999=1.0/1.0/1.0, id2=1.0/1.0/1.0, id20=1.0/1.0/1.0, id200=1.0/1.0/1.0, id2000=1.0/1.0/1.0, id2001=1.0/1.0/1.0, id2002=1.0/1.0/1.0, id2003=1.0/1.0/1.0, id2004=1.0/1.0/1.0, id2005=1.0/1.0/1.0, id2006=1.0/1.0/1.0, id2007=1.0/1.0/1.0, id2008=1.0/1.0/1.0, id2009=1.0/1.0/1.0, id201=1.0/1.0/1.0, id2010=1.0/1.0/1.0, id2011=1.0/1.0/1.0, id2012=1.0/1.0/1.0, id2013=1.0/1.0/1.0, id2014=1.0/1.0/1.0, id2015=1.0/1.0/1.0, id2016=1.0/1.0/1.0, id2017=1.0/1.0/1.0, id2018=1.0/1.0/1.0, id2019=1.0/1.0/1.0, id202=1.0/1.0/1.0, id2020=1.0/1.0/1.0, id2021=1.0/1.0/1.0, id2022=1.0/1.0/1.0, id2023=1.0/1.0/1.0, id2024=1.0/1.0/1.0, id2025=1.0/1.0/1.0, id2026=1.0/1.0/1.0, id2027=1.0/1.0/1.0, id2028=1.0/1.0/1.0, id2029=1.0/1.0/1.0, id203=1.0/1.0/1.0, id2030=1.0/1.0/1.0, id2031=1.0/1.0/1.0, id2032=1.0/1.0/1.0, id2033=1.0/1.0/1.0, id2034=1.0/1.0/1.0, id2035=1.0/1.0/1.0, id2036=1.0/1.0/1.0, id2037=1.0/1.0/1.0, id2038=1.0/1.0/1.0, id2039=1.0/1.0/1.0, id204=1.0/1.0/1.0, id2040=1.0/1.0/1.0, id2041=1.0/1.0/1.0, id2042=1.0/1.0/1.0, id2043=1.0/1.0/1.0, id2044=1.0/1.0/1.0, id2045=1.0/1.0/1.0, id2046=1.0/1.0/1.0, id2047=1.0/1.0/1.0, id2048=1.0/1.0/1.0, id2049=1.0/1.0/1.0, id205=1.0/1.0/1.0, id2050=1.0/1.0/1.0, id2051=1.0/1.0/1.0, id2052=1.0/1.0/1.0, id2053=1.0/1.0/1.0, id2054=1.0/1.0/1.0, id2055=1.0/1.0/1.0, id2056=1.0/1.0/1.0, id2057=1.0/1.0/1.0, id2058=1.0/1.0/1.0, id2059=1.0/1.0/1.0, id206=1.0/1.0/1.0, id2060=1.0/1.0/1.0, id2061=1.0/1.0/1.0, id2062=1.0/1.0/1.0, id2063=1.0/1.0/1.0, id2064=1.0/1.0/1.0, id2065=1.0/1.0/1.0, id2066=1.0/1.0/1.0, id2067=1.0/1.0/1.0, id2068=1.0/1.0/1.0, id2069=1.0/1.0/1.0, id207=1.0/1.0/1.0, id2070=1.0/1.0/1.0, id2071=1.0/1.0/1.0, id2072=1.0/1.0/1.0, id2073=1.0/1.0/1.0, id2074=1.0/1.0/1.0, id2075=1.0/1.0/1.0, id2076=1.0/1.0/1.0, id2077=1.0/1.0/1.0, id2078=1.0/1.0/1.0, id2079=1.0/1.0/1.0, id208=1.0/1.0/1.0, id2080=1.0/1.0/1.0, id2081=1.0/1.0/1.0, id2082=1.0/1.0/1.0, id2083=1.0/1.0/1.0, id2084=1.0/1.0/1.0, id2085=1.0/1.0/1.0, id2086=1.0/1.0/1.0, id2087=1.0/1.0/1.0, id2088=1.0/1.0/1.0, id2089=1.0/1.0/1.0, id209=1.0/1.0/1.0, id2090=1.0/1.0/1.0, id2091=1.0/1.0/1.0, id2092=1.0/1.0/1.0, id2093=1.0/1.0/1.0, id2094=1.0/1.0/1.0, id2095=1.0/1.0/1.0, id2096=1.0/1.0/1.0, id2097=1.0/1.0/1.0, id2098=1.0/1.0/1.0, id2099=1.0/1.0/1.0, id21=1.0/1.0/1.0, id210=1.0/1.0/1.0, id2100=1.0/1.0/1.0, id2101=1.0/1.0/1.0, id2102=1.0/1.0/1.0, id2103=1.0/1.0/1.0, id2104=1.0/1.0/1.0, id2105=1.0/1.0/1.0, id2106=1.0/1.0/1.0, id2107=1.0/1.0/1.0, id2108=1.0/1.0/1.0, id2109=1.0/1.0/1.0, id211=1.0/1.0/1.0, id2110=1.0/1.0/1.0, id2111=1.0/1.0/1.0, id2112=1.0/1.0/1.0, id2113=1.0/1.0/1.0, id2114=1.0/1.0/1.0, id2115=1.0/1.0/1.0, id2116=1.0/1.0/1.0, id2117=1.0/1.0/1.0, id2118=1.0/1.0/1.0, id2119=1.0/1.0/1.0, id212=1.0/1.0/1.0, id2120=1.0/1.0/1.0, id2121=1.0/1.0/1.0, id2122=1.0/1.0/1.0, id2123=1.0/1.0/1.0, id2124=1.0/1.0/1.0, id2125=1.0/1.0/1.0, id2126=1.0/1.0/1.0, id2127=1.0/1.0/1.0, id2128=1.0/1.0/1.0, id2129=1.0/1.0/1.0, id213=1.0/1.0/1.0, id2130=1.0/1.0/1.0, id2131=1.0/1.0/1.0, id2132=1.0/1.0/1.0, id2133=1.0/1.0/1.0, id2134=1.0/1.0/1.0, id2135=1.0/1.0/1.0, id2136=1.0/1.0/1.0, id2137=1.0/1.0/1.0, id2138=1.0/1.0/1.0, id2139=1.0/1.0/1.0, id214=1.0/1.0/1.0, id2140=1.0/1.0/1.0, id2141=1.0/1.0/1.0, id2142=1.0/1.0/1.0, id2143=1.0/1.0/1.0, id2144=1.0/1.0/1.0, id2145=1.0/1.0/1.0, id2146=1.0/1.0/1.0, id2147=1.0/1.0/1.0, id2148=1.0/1.0/1.0, id2149=1.0/1.0/1.0, id215=1.0/1.0/1.0, id2150=1.0/1.0/1.0, id2151=1.0/1.0/1.0, id2152=1.0/1.0/1.0, id2153=1.0/1.0/1.0, id2154=1.0/1.0/1.0, id2155=1.0/1.0/1.0, id2156=1.0/1.0/1.0, id2157=1.0/1.0/1.0, id2158=1.0/1.0/1.0, id2159=1.0/1.0/1.0, id216=1.0/1.0/1.0, id2160=1.0/1.0/1.0, id2161=1.0/1.0/1.0, id2162=1.0/1.0/1.0, id2163=1.0/1.0/1.0, id2164=1.0/1.0/1.0, id2165=1.0/1.0/1.0, id2166=1.0/1.0/1.0, id2167=1.0/1.0/1.0, id2168=1.0/1.0/1.0, id2169=1.0/1.0/1.0, id217=1.0/1.0/1.0, id2170=1.0/1.0/1.0, id2171=1.0/1.0/1.0, id2172=1.0/1.0/1.0, id2173=1.0/1.0/1.0, id2174=1.0/1.0/1.0, id2175=1.0/1.0/1.0, id2176=1.0/1.0/1.0, id2177=1.0/1.0/1.0, id2178=1.0/1.0/1.0, id2179=1.0/1.0/1.0, id218=1.0/1.0/1.0, id2180=1.0/1.0/1.0, id2181=1.0/1.0/1.0, id2182=1.0/1.0/1.0, id2183=1.0/1.0/1.0, id2184=1.0/1.0/1.0, id2185=1.0/1.0/1.0, id2186=1.0/1.0/1.0, id2187=1.0/1.0/1.0, id2188=1.0/1.0/1.0, id2189=1.0/1.0/1.0, id219=1.0/1.0/1.0, id2190=1.0/1.0/1.0, id2191=1.0/1.0/1.0, id2192=1.0/1.0/1.0, id2193=1.0/1.0/1.0, id2194=1.0/1.0/1.0, id2195=1.0/1.0/1.0, id2196=1.0/1.0/1.0, id2197=1.0/1.0/1.0, id2198=1.0/1.0/1.0, id2199=1.0/1.0/1.0, id22=1.0/1.0/1.0, id220=1.0/1.0/1.0, id2200=1.0/1.0/1.0, id2201=1.0/1.0/1.0, id2202=1.0/1.0/1.0, id2203=1.0/1.0/1.0, id2204=1.0/1.0/1.0, id2205=1.0/1.0/1.0, id2206=1.0/1.0/1.0, id2207=1.0/1.0/1.0, id2208=1.0/1.0/1.0, id2209=1.0/1.0/1.0, id221=1.0/1.0/1.0, id2210=1.0/1.0/1.0, id2211=1.0/1.0/1.0, id2212=1.0/1.0/1.0, id2213=1.0/1.0/1.0, id2214=1.0/1.0/1.0, id2215=1.0/1.0/1.0, id2216=1.0/1.0/1.0, id2217=1.0/1.0/1.0, id2218=1.0/1.0/1.0, id2219=1.0/1.0/1.0, id222=1.0/1.0/1.0, id2220=1.0/1.0/1.0, id2221=1.0/1.0/1.0, id2222=1.0/1.0/1.0, id2223=1.0/1.0/1.0, id2224=1.0/1.0/1.0, id2225=1.0/1.0/1.0, id2226=1.0/1.0/1.0, id2227=1.0/1.0/1.0, id2228=1.0/1.0/1.0, id2229=1.0/1.0/1.0, id223=1.0/1.0/1.0, id2230=1.0/1.0/1.0, id2231=1.0/1.0/1.0, id2232=1.0/1.0/1.0, id2233=1.0/1.0/1.0, id2234=1.0/1.0/1.0, id2235=1.0/1.0/1.0, id2236=1.0/1.0/1.0, id2237=1.0/1.0/1.0, id2238=1.0/1.0/1.0, id2239=1.0/1.0/1.0, id224=1.0/1.0/1.0, id2240=1.0/1.0/1.0, id2241=1.0/1.0/1.0, id2242=1.0/1.0/1.0, id2243=1.0/1.0/1.0, id2244=1.0/1.0/1.0, id2245=1.0/1.0/1.0, id2246=1.0/1.0/1.0, id2247=1.0/1.0/1.0, id2248=1.0/1.0/1.0, id2249=1.0/1.0/1.0, id225=1.0/1.0/1.0, id2250=1.0/1.0/1.0, id2251=1.0/1.0/1.0, id2252=1.0/1.0/1.0, id2253=1.0/1.0/1.0, id2254=1.0/1.0/1.0, id2255=1.0/1.0/1.0, id2256=1.0/1.0/1.0, id2257=1.0/1.0/1.0, id2258=1.0/1.0/1.0, id2259=1.0/1.0/1.0, id226=1.0/1.0/1.0, id2260=1.0/1.0/1.0, id2261=1.0/1.0/1.0, id2262=1.0/1.0/1.0, id2263=1.0/1.0/1.0, id2264=1.0/1.0/1.0, id2265=1.0/1.0/1.0, id2266=1.0/1.0/1.0, id2267=1.0/1.0/1.0, id2268=1.0/1.0/1.0, id2269=1.0/1.0/1.0, id227=1.0/1.0/1.0, id2270=1.0/1.0/1.0, id2271=1.0/1.0/1.0, id2272=1.0/1.0/1.0, id2273=1.0/1.0/1.0, id2274=1.0/1.0/1.0, id2275=1.0/1.0/1.0, id2276=1.0/1.0/1.0, id2277=1.0/1.0/1.0, id2278=1.0/1.0/1.0, id2279=1.0/1.0/1.0, id228=1.0/1.0/1.0, id2280=1.0/1.0/1.0, id2281=1.0/1.0/1.0, id2282=1.0/1.0/1.0, id2283=1.0/1.0/1.0, id2284=1.0/1.0/1.0, id2285=1.0/1.0/1.0, id2286=1.0/1.0/1.0, id2287=1.0/1.0/1.0, id2288=1.0/1.0/1.0, id2289=1.0/1.0/1.0, id229=1.0/1.0/1.0, id2290=1.0/1.0/1.0, id2291=1.0/1.0/1.0, id2292=1.0/1.0/1.0, id2293=1.0/1.0/1.0, id2294=1.0/1.0/1.0, id2295=1.0/1.0/1.0, id2296=1.0/1.0/1.0, id2297=1.0/1.0/1.0, id2298=1.0/1.0/1.0, id2299=1.0/1.0/1.0, id23=1.0/1.0/1.0, id230=1.0/1.0/1.0, id2300=1.0/1.0/1.0, id2301=1.0/1.0/1.0, id2302=1.0/1.0/1.0, id2303=1.0/1.0/1.0, id2304=1.0/1.0/1.0, id2305=1.0/1.0/1.0, id2306=1.0/1.0/1.0, id2307=1.0/1.0/1.0, id2308=1.0/1.0/1.0, id2309=1.0/1.0/1.0, id231=1.0/1.0/1.0, id2310=1.0/1.0/1.0, id2311=1.0/1.0/1.0, id2312=1.0/1.0/1.0, id2313=1.0/1.0/1.0, id2314=1.0/1.0/1.0, id2315=1.0/1.0/1.0, id2316=1.0/1.0/1.0, id2317=1.0/1.0/1.0, id2318=1.0/1.0/1.0, id2319=1.0/1.0/1.0, id232=1.0/1.0/1.0, id2320=1.0/1.0/1.0, id2321=1.0/1.0/1.0, id2322=1.0/1.0/1.0, id2323=1.0/1.0/1.0, id2324=1.0/1.0/1.0, id2325=1.0/1.0/1.0, id2326=1.0/1.0/1.0, id2327=1.0/1.0/1.0, id2328=1.0/1.0/1.0, id2329=1.0/1.0/1.0, id233=1.0/1.0/1.0, id2330=1.0/1.0/1.0, id2331=1.0/1.0/1.0, id2332=1.0/1.0/1.0, id2333=1.0/1.0/1.0, id2334=1.0/1.0/1.0, id2335=1.0/1.0/1.0, id2336=1.0/1.0/1.0, id2337=1.0/1.0/1.0, id2338=1.0/1.0/1.0, id2339=1.0/1.0/1.0, id234=1.0/1.0/1.0, id2340=1.0/1.0/1.0, id2341=1.0/1.0/1.0, id2342=1.0/1.0/1.0, id2343=1.0/1.0/1.0, id2344=1.0/1.0/1.0, id2345=1.0/1.0/1.0, id2346=1.0/1.0/1.0, id2347=1.0/1.0/1.0, id2348=1.0/1.0/1.0, id2349=1.0/1.0/1.0, id235=1.0/1.0/1.0, id2350=1.0/1.0/1.0, id2351=1.0/1.0/1.0, id2352=1.0/1.0/1.0, id2353=1.0/1.0/1.0, id2354=1.0/1.0/1.0, id2355=1.0/1.0/1.0, id2356=1.0/1.0/1.0, id2357=1.0/1.0/1.0, id2358=1.0/1.0/1.0, id2359=1.0/1.0/1.0, id236=1.0/1.0/1.0, id2360=1.0/1.0/1.0, id2361=1.0/1.0/1.0, id2362=1.0/1.0/1.0, id2363=1.0/1.0/1.0, id2364=1.0/1.0/1.0, id2365=1.0/1.0/1.0, id2366=1.0/1.0/1.0, id2367=1.0/1.0/1.0, id2368=1.0/1.0/1.0, id2369=1.0/1.0/1.0, id237=1.0/1.0/1.0, id2370=1.0/1.0/1.0, id2371=1.0/1.0/1.0, id2372=1.0/1.0/1.0, id2373=1.0/1.0/1.0, id2374=1.0/1.0/1.0, id2375=1.0/1.0/1.0, id2376=1.0/1.0/1.0, id2377=1.0/1.0/1.0, id2378=1.0/1.0/1.0, id2379=1.0/1.0/1.0, id238=1.0/1.0/1.0, id2380=1.0/1.0/1.0, id2381=1.0/1.0/1.0, id2382=1.0/1.0/1.0, id2383=1.0/1.0/1.0, id2384=1.0/1.0/1.0, id2385=1.0/1.0/1.0, id2386=1.0/1.0/1.0, id2387=1.0/1.0/1.0, id2388=1.0/1.0/1.0, id2389=1.0/1.0/1.0, id239=1.0/1.0/1.0, id2390=1.0/1.0/1.0, id2391=1.0/1.0/1.0, id2392=1.0/1.0/1.0, id2393=1.0/1.0/1.0, id2394=1.0/1.0/1.0, id2395=1.0/1.0/1.0, id2396=1.0/1.0/1.0, id2397=1.0/1.0/1.0, id2398=1.0/1.0/1.0, id2399=1.0/1.0/1.0, id24=1.0/1.0/1.0, id240=1.0/1.0/1.0, id2400=1.0/1.0/1.0, id2401=1.0/1.0/1.0, id2402=1.0/1.0/1.0, id2403=1.0/1.0/1.0, id2404=1.0/1.0/1.0, id2405=1.0/1.0/1.0, id2406=1.0/1.0/1.0, id2407=1.0/1.0/1.0, id2408=1.0/1.0/1.0, id2409=1.0/1.0/1.0, id241=1.0/1.0/1.0, id2410=1.0/1.0/1.0, id2411=1.0/1.0/1.0, id2412=1.0/1.0/1.0, id2413=1.0/1.0/1.0, id2414=1.0/1.0/1.0, id2415=1.0/1.0/1.0, id2416=1.0/1.0/1.0, id2417=1.0/1.0/1.0, id2418=1.0/1.0/1.0, id2419=1.0/1.0/1.0, id242=1.0/1.0/1.0, id2420=1.0/1.0/1.0, id2421=1.0/1.0/1.0, id2422=1.0/1.0/1.0, id2423=1.0/1.0/1.0, id2424=1.0/1.0/1.0, id2425=1.0/1.0/1.0, id2426=1.0/1.0/1.0, id2427=1.0/1.0/1.0, id2428=1.0/1.0/1.0, id2429=1.0/1.0/1.0, id243=1.0/1.0/1.0, id2430=1.0/1.0/1.0, id2431=1.0/1.0/1.0, id2432=1.0/1.0/1.0, id2433=1.0/1.0/1.0, id2434=1.0/1.0/1.0, id2435=1.0/1.0/1.0, id2436=1.0/1.0/1.0, id2437=1.0/1.0/1.0, id2438=1.0/1.0/1.0, id2439=1.0/1.0/1.0, id244=1.0/1.0/1.0, id2440=1.0/1.0/1.0, id2441=1.0/1.0/1.0, id2442=1.0/1.0/1.0, id2443=1.0/1.0/1.0, id2444=1.0/1.0/1.0, id2445=1.0/1.0/1.0, id2446=1.0/1.0/1.0, id2447=1.0/1.0/1.0, id2448=1.0/1.0/1.0, id2449=1.0/1.0/1.0, id245=1.0/1.0/1.0, id2450=1.0/1.0/1.0, id2451=1.0/1.0/1.0, id2452=1.0/1.0/1.0, id2453=1.0/1.0/1.0, id2454=1.0/1.0/1.0, id2455=1.0/1.0/1.0, id2456=1.0/1.0/1.0, id2457=1.0/1.0/1.0, id2458=1.0/1.0/1.0, id2459=1.0/1.0/1.0, id246=1.0/1.0/1.0, id2460=1.0/1.0/1.0, id2461=1.0/1.0/1.0, id2462=1.0/1.0/1.0, id2463=1.0/1.0/1.0, id2464=1.0/1.0/1.0, id2465=1.0/1.0/1.0, id2466=1.0/1.0/1.0, id2467=1.0/1.0/1.0, id2468=1.0/1.0/1.0, id2469=1.0/1.0/1.0, id247=1.0/1.0/1.0, id2470=1.0/1.0/1.0, id2471=1.0/1.0/1.0, id2472=1.0/1.0/1.0, id2473=1.0/1.0/1.0, id2474=1.0/1.0/1.0, id2475=1.0/1.0/1.0, id2476=1.0/1.0/1.0, id2477=1.0/1.0/1.0, id2478=1.0/1.0/1.0, id2479=1.0/1.0/1.0, id248=1.0/1.0/1.0, id2480=1.0/1.0/1.0, id2481=1.0/1.0/1.0, id2482=1.0/1.0/1.0, id2483=1.0/1.0/1.0, id2484=1.0/1.0/1.0, id2485=1.0/1.0/1.0, id2486=1.0/1.0/1.0, id2487=1.0/1.0/1.0, id2488=1.0/1.0/1.0, id2489=1.0/1.0/1.0, id249=1.0/1.0/1.0, id2490=1.0/1.0/1.0, id2491=1.0/1.0/1.0, id2492=1.0/1.0/1.0, id2493=1.0/1.0/1.0, id2494=1.0/1.0/1.0, id2495=1.0/1.0/1.0, id2496=1.0/1.0/1.0, id2497=1.0/1.0/1.0, id2498=1.0/1.0/1.0, id2499=1.0/1.0/1.0, id25=1.0/1.0/1.0, id250=1.0/1.0/1.0, id2500=1.0/1.0/1.0, id2501=1.0/1.0/1.0, id2502=1.0/1.0/1.0, id2503=1.0/1.0/1.0, id2504=1.0/1.0/1.0, id2505=1.0/1.0/1.0, id2506=1.0/1.0/1.0, id2507=1.0/1.0/1.0, id2508=1.0/1.0/1.0, id2509=1.0/1.0/1.0, id251=1.0/1.0/1.0, id2510=1.0/1.0/1.0, id2511=1.0/1.0/1.0, id2512=1.0/1.0/1.0, id2513=1.0/1.0/1.0, id2514=1.0/1.0/1.0, id2515=1.0/1.0/1.0, id2516=1.0/1.0/1.0, id2517=1.0/1.0/1.0, id2518=1.0/1.0/1.0, id2519=1.0/1.0/1.0, id252=1.0/1.0/1.0, id2520=1.0/1.0/1.0, id2521=1.0/1.0/1.0, id2522=1.0/1.0/1.0, id2523=1.0/1.0/1.0, id2524=1.0/1.0/1.0, id2525=1.0/1.0/1.0, id2526=1.0/1.0/1.0, id2527=1.0/1.0/1.0, id2528=1.0/1.0/1.0, id2529=1.0/1.0/1.0, id253=1.0/1.0/1.0, id2530=1.0/1.0/1.0, id2531=1.0/1.0/1.0, id2532=1.0/1.0/1.0, id2533=1.0/1.0/1.0, id2534=1.0/1.0/1.0, id2535=1.0/1.0/1.0, id2536=1.0/1.0/1.0, id2537=1.0/1.0/1.0, id2538=1.0/1.0/1.0, id2539=1.0/1.0/1.0, id254=1.0/1.0/1.0, id2540=1.0/1.0/1.0, id2541=1.0/1.0/1.0, id2542=1.0/1.0/1.0, id2543=1.0/1.0/1.0, id2544=1.0/1.0/1.0, id2545=1.0/1.0/1.0, id2546=1.0/1.0/1.0, id2547=1.0/1.0/1.0, id2548=1.0/1.0/1.0, id2549=1.0/1.0/1.0, id255=1.0/1.0/1.0, id2550=1.0/1.0/1.0, id2551=1.0/1.0/1.0, id2552=1.0/1.0/1.0, id2553=1.0/1.0/1.0, id2554=1.0/1.0/1.0, id2555=1.0/1.0/1.0, id2556=1.0/1.0/1.0, id2557=1.0/1.0/1.0, id2558=1.0/1.0/1.0, id2559=1.0/1.0/1.0, id256=1.0/1.0/1.0, id2560=1.0/1.0/1.0, id2561=1.0/1.0/1.0, id2562=1.0/1.0/1.0, id2563=1.0/1.0/1.0, id2564=1.0/1.0/1.0, id2565=1.0/1.0/1.0, id2566=1.0/1.0/1.0, id2567=1.0/1.0/1.0, id2568=1.0/1.0/1.0, id2569=1.0/1.0/1.0, id257=1.0/1.0/1.0, id2570=1.0/1.0/1.0, id2571=1.0/1.0/1.0, id2572=1.0/1.0/1.0, id2573=1.0/1.0/1.0, id2574=1.0/1.0/1.0, id2575=1.0/1.0/1.0, id2576=1.0/1.0/1.0, id2577=1.0/1.0/1.0, id2578=1.0/1.0/1.0, id2579=1.0/1.0/1.0, id258=1.0/1.0/1.0, id2580=1.0/1.0/1.0, id2581=1.0/1.0/1.0, id2582=1.0/1.0/1.0, id2583=1.0/1.0/1.0, id2584=1.0/1.0/1.0, id2585=1.0/1.0/1.0, id2586=1.0/1.0/1.0, id2587=1.0/1.0/1.0, id2588=1.0/1.0/1.0, id2589=1.0/1.0/1.0, id259=1.0/1.0/1.0, id2590=1.0/1.0/1.0, id2591=1.0/1.0/1.0, id2592=1.0/1.0/1.0, id2593=1.0/1.0/1.0, id2594=1.0/1.0/1.0, id2595=1.0/1.0/1.0, id2596=1.0/1.0/1.0, id2597=1.0/1.0/1.0, id2598=1.0/1.0/1.0, id2599=1.0/1.0/1.0, id26=1.0/1.0/1.0, id260=1.0/1.0/1.0, id2600=1.0/1.0/1.0, id2601=1.0/1.0/1.0, id2602=1.0/1.0/1.0, id2603=1.0/1.0/1.0, id2604=1.0/1.0/1.0, id2605=1.0/1.0/1.0, id2606=1.0/1.0/1.0, id2607=1.0/1.0/1.0, id2608=1.0/1.0/1.0, id2609=1.0/1.0/1.0, id261=1.0/1.0/1.0, id2610=1.0/1.0/1.0, id2611=1.0/1.0/1.0, id2612=1.0/1.0/1.0, id2613=1.0/1.0/1.0, id2614=1.0/1.0/1.0, id2615=1.0/1.0/1.0, id2616=1.0/1.0/1.0, id2617=1.0/1.0/1.0, id2618=1.0/1.0/1.0, id2619=1.0/1.0/1.0, id262=1.0/1.0/1.0, id2620=1.0/1.0/1.0, id2621=1.0/1.0/1.0, id2622=1.0/1.0/1.0, id2623=1.0/1.0/1.0, id2624=1.0/1.0/1.0, id2625=1.0/1.0/1.0, id2626=1.0/1.0/1.0, id2627=1.0/1.0/1.0, id2628=1.0/1.0/1.0, id2629=1.0/1.0/1.0, id263=1.0/1.0/1.0, id2630=1.0/1.0/1.0, id2631=1.0/1.0/1.0, id2632=1.0/1.0/1.0, id2633=1.0/1.0/1.0, id2634=1.0/1.0/1.0, id2635=1.0/1.0/1.0, id2636=1.0/1.0/1.0, id2637=1.0/1.0/1.0, id2638=1.0/1.0/1.0, id2639=1.0/1.0/1.0, id264=1.0/1.0/1.0, id2640=1.0/1.0/1.0, id2641=1.0/1.0/1.0, id2642=1.0/1.0/1.0, id2643=1.0/1.0/1.0, id2644=1.0/1.0/1.0, id2645=1.0/1.0/1.0, id2646=1.0/1.0/1.0, id2647=1.0/1.0/1.0, id2648=1.0/1.0/1.0, id2649=1.0/1.0/1.0, id265=1.0/1.0/1.0, id2650=1.0/1.0/1.0, id2651=1.0/1.0/1.0, id2652=1.0/1.0/1.0, id2653=1.0/1.0/1.0, id2654=1.0/1.0/1.0, id2655=1.0/1.0/1.0, id2656=1.0/1.0/1.0, id2657=1.0/1.0/1.0, id2658=1.0/1.0/1.0, id2659=1.0/1.0/1.0, id266=1.0/1.0/1.0, id2660=1.0/1.0/1.0, id2661=1.0/1.0/1.0, id2662=1.0/1.0/1.0, id2663=1.0/1.0/1.0, id2664=1.0/1.0/1.0, id2665=1.0/1.0/1.0, id2666=1.0/1.0/1.0, id2667=1.0/1.0/1.0, id2668=1.0/1.0/1.0, id2669=1.0/1.0/1.0, id267=1.0/1.0/1.0, id2670=1.0/1.0/1.0, id2671=1.0/1.0/1.0, id2672=1.0/1.0/1.0, id2673=1.0/1.0/1.0, id2674=1.0/1.0/1.0, id2675=1.0/1.0/1.0, id2676=1.0/1.0/1.0, id2677=1.0/1.0/1.0, id2678=1.0/1.0/1.0, id2679=1.0/1.0/1.0, id268=1.0/1.0/1.0, id2680=1.0/1.0/1.0, id2681=1.0/1.0/1.0, id2682=1.0/1.0/1.0, id2683=1.0/1.0/1.0, id2684=1.0/1.0/1.0, id2685=1.0/1.0/1.0, id2686=1.0/1.0/1.0, id2687=1.0/1.0/1.0, id2688=1.0/1.0/1.0, id2689=1.0/1.0/1.0, id269=1.0/1.0/1.0, id2690=1.0/1.0/1.0, id2691=1.0/1.0/1.0, id2692=1.0/1.0/1.0, id2693=1.0/1.0/1.0, id2694=1.0/1.0/1.0, id2695=1.0/1.0/1.0, id2696=1.0/1.0/1.0, id2697=1.0/1.0/1.0, id2698=1.0/1.0/1.0, id2699=1.0/1.0/1.0, id27=1.0/1.0/1.0, id270=1.0/1.0/1.0, id2700=1.0/1.0/1.0, id2701=1.0/1.0/1.0, id2702=1.0/1.0/1.0, id2703=1.0/1.0/1.0, id2704=1.0/1.0/1.0, id2705=1.0/1.0/1.0, id2706=1.0/1.0/1.0, id2707=1.0/1.0/1.0, id2708=1.0/1.0/1.0, id2709=1.0/1.0/1.0, id271=1.0/1.0/1.0, id2710=1.0/1.0/1.0, id2711=1.0/1.0/1.0, id2712=1.0/1.0/1.0, id2713=1.0/1.0/1.0, id2714=1.0/1.0/1.0, id2715=1.0/1.0/1.0, id2716=1.0/1.0/1.0, id2717=1.0/1.0/1.0, id2718=1.0/1.0/1.0, id2719=1.0/1.0/1.0, id272=1.0/1.0/1.0, id2720=1.0/1.0/1.0, id2721=1.0/1.0/1.0, id2722=1.0/1.0/1.0, id2723=1.0/1.0/1.0, id2724=1.0/1.0/1.0, id2725=1.0/1.0/1.0, id2726=1.0/1.0/1.0, id2727=1.0/1.0/1.0, id2728=1.0/1.0/1.0, id2729=1.0/1.0/1.0, id273=1.0/1.0/1.0, id2730=1.0/1.0/1.0, id2731=1.0/1.0/1.0, id2732=1.0/1.0/1.0, id2733=1.0/1.0/1.0, id2734=1.0/1.0/1.0, id2735=1.0/1.0/1.0, id2736=1.0/1.0/1.0, id2737=1.0/1.0/1.0, id2738=1.0/1.0/1.0, id2739=1.0/1.0/1.0, id274=1.0/1.0/1.0, id2740=1.0/1.0/1.0, id2741=1.0/1.0/1.0, id2742=1.0/1.0/1.0, id2743=1.0/1.0/1.0, id2744=1.0/1.0/1.0, id2745=1.0/1.0/1.0, id2746=1.0/1.0/1.0, id2747=1.0/1.0/1.0, id2748=1.0/1.0/1.0, id2749=1.0/1.0/1.0, id275=1.0/1.0/1.0, id2750=1.0/1.0/1.0, id2751=1.0/1.0/1.0, id2752=1.0/1.0/1.0, id2753=1.0/1.0/1.0, id2754=1.0/1.0/1.0, id2755=1.0/1.0/1.0, id2756=1.0/1.0/1.0, id2757=1.0/1.0/1.0, id2758=1.0/1.0/1.0, id2759=1.0/1.0/1.0, id276=1.0/1.0/1.0, id2760=1.0/1.0/1.0, id2761=1.0/1.0/1.0, id2762=1.0/1.0/1.0, id2763=1.0/1.0/1.0, id2764=1.0/1.0/1.0, id2765=1.0/1.0/1.0, id2766=1.0/1.0/1.0, id2767=1.0/1.0/1.0, id2768=1.0/1.0/1.0, id2769=1.0/1.0/1.0, id277=1.0/1.0/1.0, id2770=1.0/1.0/1.0, id2771=1.0/1.0/1.0, id2772=1.0/1.0/1.0, id2773=1.0/1.0/1.0, id2774=1.0/1.0/1.0, id2775=1.0/1.0/1.0, id2776=1.0/1.0/1.0, id2777=1.0/1.0/1.0, id2778=1.0/1.0/1.0, id2779=1.0/1.0/1.0, id278=1.0/1.0/1.0, id2780=1.0/1.0/1.0, id2781=1.0/1.0/1.0, id2782=1.0/1.0/1.0, id2783=1.0/1.0/1.0, id2784=1.0/1.0/1.0, id2785=1.0/1.0/1.0, id2786=1.0/1.0/1.0, id2787=1.0/1.0/1.0, id2788=1.0/1.0/1.0, id2789=1.0/1.0/1.0, id279=1.0/1.0/1.0, id2790=1.0/1.0/1.0, id2791=1.0/1.0/1.0, id2792=1.0/1.0/1.0, id2793=1.0/1.0/1.0, id2794=1.0/1.0/1.0, id2795=1.0/1.0/1.0, id2796=1.0/1.0/1.0, id2797=1.0/1.0/1.0, id2798=1.0/1.0/1.0, id2799=1.0/1.0/1.0, id28=1.0/1.0/1.0, id280=1.0/1.0/1.0, id2800=1.0/1.0/1.0, id2801=1.0/1.0/1.0, id2802=1.0/1.0/1.0, id2803=1.0/1.0/1.0, id2804=1.0/1.0/1.0, id2805=1.0/1.0/1.0, id2806=1.0/1.0/1.0, id2807=1.0/1.0/1.0, id2808=1.0/1.0/1.0, id2809=1.0/1.0/1.0, id281=1.0/1.0/1.0, id2810=1.0/1.0/1.0, id2811=1.0/1.0/1.0, id2812=1.0/1.0/1.0, id2813=1.0/1.0/1.0, id2814=1.0/1.0/1.0, id2815=1.0/1.0/1.0, id2816=1.0/1.0/1.0, id2817=1.0/1.0/1.0, id2818=1.0/1.0/1.0, id2819=1.0/1.0/1.0, id282=1.0/1.0/1.0, id2820=1.0/1.0/1.0, id2821=1.0/1.0/1.0, id2822=1.0/1.0/1.0, id2823=1.0/1.0/1.0, id2824=1.0/1.0/1.0, id2825=1.0/1.0/1.0, id2826=1.0/1.0/1.0, id2827=1.0/1.0/1.0, id2828=1.0/1.0/1.0, id2829=1.0/1.0/1.0, id283=1.0/1.0/1.0, id2830=1.0/1.0/1.0, id2831=1.0/1.0/1.0, id2832=1.0/1.0/1.0, id2833=1.0/1.0/1.0, id2834=1.0/1.0/1.0, id2835=1.0/1.0/1.0, id2836=1.0/1.0/1.0, id2837=1.0/1.0/1.0, id2838=1.0/1.0/1.0, id2839=1.0/1.0/1.0, id284=1.0/1.0/1.0, id2840=1.0/1.0/1.0, id2841=1.0/1.0/1.0, id2842=1.0/1.0/1.0, id2843=1.0/1.0/1.0, id2844=1.0/1.0/1.0, id2845=1.0/1.0/1.0, id2846=1.0/1.0/1.0, id2847=1.0/1.0/1.0, id2848=1.0/1.0/1.0, id2849=1.0/1.0/1.0, id285=1.0/1.0/1.0, id2850=1.0/1.0/1.0, id2851=1.0/1.0/1.0, id2852=1.0/1.0/1.0, id2853=1.0/1.0/1.0, id2854=1.0/1.0/1.0, id2855=1.0/1.0/1.0, id2856=1.0/1.0/1.0, id2857=1.0/1.0/1.0, id2858=1.0/1.0/1.0, id2859=1.0/1.0/1.0, id286=1.0/1.0/1.0, id2860=1.0/1.0/1.0, id2861=1.0/1.0/1.0, id2862=1.0/1.0/1.0, id2863=1.0/1.0/1.0, id2864=1.0/1.0/1.0, id2865=1.0/1.0/1.0, id2866=1.0/1.0/1.0, id2867=1.0/1.0/1.0, id2868=1.0/1.0/1.0, id2869=1.0/1.0/1.0, id287=1.0/1.0/1.0, id2870=1.0/1.0/1.0, id2871=1.0/1.0/1.0, id2872=1.0/1.0/1.0, id2873=1.0/1.0/1.0, id2874=1.0/1.0/1.0, id2875=1.0/1.0/1.0, id2876=1.0/1.0/1.0, id2877=1.0/1.0/1.0, id2878=1.0/1.0/1.0, id2879=1.0/1.0/1.0, id288=1.0/1.0/1.0, id2880=1.0/1.0/1.0, id2881=1.0/1.0/1.0, id2882=1.0/1.0/1.0, id2883=1.0/1.0/1.0, id2884=1.0/1.0/1.0, id2885=1.0/1.0/1.0, id2886=1.0/1.0/1.0, id2887=1.0/1.0/1.0, id2888=1.0/1.0/1.0, id2889=1.0/1.0/1.0, id289=1.0/1.0/1.0, id2890=1.0/1.0/1.0, id2891=1.0/1.0/1.0, id2892=1.0/1.0/1.0, id2893=1.0/1.0/1.0, id2894=1.0/1.0/1.0, id2895=1.0/1.0/1.0, id2896=1.0/1.0/1.0, id2897=1.0/1.0/1.0, id2898=1.0/1.0/1.0, id2899=1.0/1.0/1.0, id29=1.0/1.0/1.0, id290=1.0/1.0/1.0, id2900=1.0/1.0/1.0, id2901=1.0/1.0/1.0, id2902=1.0/1.0/1.0, id2903=1.0/1.0/1.0, id2904=1.0/1.0/1.0, id2905=1.0/1.0/1.0, id2906=1.0/1.0/1.0, id2907=1.0/1.0/1.0, id2908=1.0/1.0/1.0, id2909=1.0/1.0/1.0, id291=1.0/1.0/1.0, id2910=1.0/1.0/1.0, id2911=1.0/1.0/1.0, id2912=1.0/1.0/1.0, id2913=1.0/1.0/1.0, id2914=1.0/1.0/1.0, id2915=1.0/1.0/1.0, id2916=1.0/1.0/1.0, id2917=1.0/1.0/1.0, id2918=1.0/1.0/1.0, id2919=1.0/1.0/1.0, id292=1.0/1.0/1.0, id2920=1.0/1.0/1.0, id2921=1.0/1.0/1.0, id2922=1.0/1.0/1.0, id2923=1.0/1.0/1.0, id2924=1.0/1.0/1.0, id2925=1.0/1.0/1.0, id2926=1.0/1.0/1.0, id2927=1.0/1.0/1.0, id2928=1.0/1.0/1.0, id2929=1.0/1.0/1.0, id293=1.0/1.0/1.0, id2930=1.0/1.0/1.0, id2931=1.0/1.0/1.0, id2932=1.0/1.0/1.0, id2933=1.0/1.0/1.0, id2934=1.0/1.0/1.0, id2935=1.0/1.0/1.0, id2936=1.0/1.0/1.0, id2937=1.0/1.0/1.0, id2938=1.0/1.0/1.0, id2939=1.0/1.0/1.0, id294=1.0/1.0/1.0, id2940=1.0/1.0/1.0, id2941=1.0/1.0/1.0, id2942=1.0/1.0/1.0, id2943=1.0/1.0/1.0, id2944=1.0/1.0/1.0, id2945=1.0/1.0/1.0, id2946=1.0/1.0/1.0, id2947=1.0/1.0/1.0, id2948=1.0/1.0/1.0, id2949=1.0/1.0/1.0, id295=1.0/1.0/1.0, id2950=1.0/1.0/1.0, id2951=1.0/1.0/1.0, id2952=1.0/1.0/1.0, id2953=1.0/1.0/1.0, id2954=1.0/1.0/1.0, id2955=1.0/1.0/1.0, id2956=1.0/1.0/1.0, id2957=1.0/1.0/1.0, id2958=1.0/1.0/1.0, id2959=1.0/1.0/1.0, id296=1.0/1.0/1.0, id2960=1.0/1.0/1.0, id2961=1.0/1.0/1.0, id2962=1.0/1.0/1.0, id2963=1.0/1.0/1.0, id2964=1.0/1.0/1.0, id2965=1.0/1.0/1.0, id2966=1.0/1.0/1.0, id2967=1.0/1.0/1.0, id2968=1.0/1.0/1.0, id2969=1.0/1.0/1.0, id297=1.0/1.0/1.0, id2970=1.0/1.0/1.0, id2971=1.0/1.0/1.0, id2972=1.0/1.0/1.0, id2973=1.0/1.0/1.0, id2974=1.0/1.0/1.0, id2975=1.0/1.0/1.0, id2976=1.0/1.0/1.0, id2977=1.0/1.0/1.0, id2978=1.0/1.0/1.0, id2979=1.0/1.0/1.0, id298=1.0/1.0/1.0, id2980=1.0/1.0/1.0, id2981=1.0/1.0/1.0, id2982=1.0/1.0/1.0, id2983=1.0/1.0/1.0, id2984=1.0/1.0/1.0, id2985=1.0/1.0/1.0, id2986=1.0/1.0/1.0, id2987=1.0/1.0/1.0, id2988=1.0/1.0/1.0, id2989=1.0/1.0/1.0, id299=1.0/1.0/1.0, id2990=1.0/1.0/1.0, id2991=1.0/1.0/1.0, id2992=1.0/1.0/1.0, id2993=1.0/1.0/1.0, id2994=1.0/1.0/1.0, id2995=1.0/1.0/1.0, id2996=1.0/1.0/1.0, id2997=1.0/1.0/1.0, id2998=1.0/1.0/1.0, id2999=1.0/1.0/1.0, id3=1.0/1.0/1.0, id30=1.0/1.0/1.0, id300=1.0/1.0/1.0, id3000=1.0/1.0/1.0, id3001=1.0/1.0/1.0, id3002=1.0/1.0/1.0, id3003=1.0/1.0/1.0, id3004=1.0/1.0/1.0, id3005=1.0/1.0/1.0, id3006=1.0/1.0/1.0, id3007=1.0/1.0/1.0, id3008=1.0/1.0/1.0, id3009=1.0/1.0/1.0, id301=1.0/1.0/1.0, id3010=1.0/1.0/1.0, id3011=1.0/1.0/1.0, id3012=1.0/1.0/1.0, id3013=1.0/1.0/1.0, id3014=1.0/1.0/1.0, id3015=1.0/1.0/1.0, id3016=1.0/1.0/1.0, id3017=1.0/1.0/1.0, id3018=1.0/1.0/1.0, id3019=1.0/1.0/1.0, id302=1.0/1.0/1.0, id3020=1.0/1.0/1.0, id3021=1.0/1.0/1.0, id3022=1.0/1.0/1.0, id3023=1.0/1.0/1.0, id3024=1.0/1.0/1.0, id3025=1.0/1.0/1.0, id3026=1.0/1.0/1.0, id3027=1.0/1.0/1.0, id3028=1.0/1.0/1.0, id3029=1.0/1.0/1.0, id303=1.0/1.0/1.0, id3030=1.0/1.0/1.0, id3031=1.0/1.0/1.0, id3032=1.0/1.0/1.0, id3033=1.0/1.0/1.0, id3034=1.0/1.0/1.0, id3035=1.0/1.0/1.0, id3036=1.0/1.0/1.0, id3037=1.0/1.0/1.0, id3038=1.0/1.0/1.0, id3039=1.0/1.0/1.0, id304=1.0/1.0/1.0, id3040=1.0/1.0/1.0, id3041=1.0/1.0/1.0, id3042=1.0/1.0/1.0, id3043=1.0/1.0/1.0, id3044=1.0/1.0/1.0, id3045=1.0/1.0/1.0, id3046=1.0/1.0/1.0, id3047=1.0/1.0/1.0, id3048=1.0/1.0/1.0, id3049=1.0/1.0/1.0, id305=1.0/1.0/1.0, id3050=1.0/1.0/1.0, id3051=1.0/1.0/1.0, id3052=1.0/1.0/1.0, id3053=1.0/1.0/1.0, id3054=1.0/1.0/1.0, id3055=1.0/1.0/1.0, id3056=1.0/1.0/1.0, id3057=1.0/1.0/1.0, id3058=1.0/1.0/1.0, id3059=1.0/1.0/1.0, id306=1.0/1.0/1.0, id3060=1.0/1.0/1.0, id3061=1.0/1.0/1.0, id3062=1.0/1.0/1.0, id3063=1.0/1.0/1.0, id3064=1.0/1.0/1.0, id3065=1.0/1.0/1.0, id3066=1.0/1.0/1.0, id3067=1.0/1.0/1.0, id3068=1.0/1.0/1.0, id3069=1.0/1.0/1.0, id307=1.0/1.0/1.0, id3070=1.0/1.0/1.0, id3071=1.0/1.0/1.0, id3072=1.0/1.0/1.0, id3073=1.0/1.0/1.0, id3074=1.0/1.0/1.0, id3075=1.0/1.0/1.0, id3076=1.0/1.0/1.0, id3077=1.0/1.0/1.0, id3078=1.0/1.0/1.0, id3079=1.0/1.0/1.0, id308=1.0/1.0/1.0, id3080=1.0/1.0/1.0, id3081=1.0/1.0/1.0, id3082=1.0/1.0/1.0, id3083=1.0/1.0/1.0, id3084=1.0/1.0/1.0, id3085=1.0/1.0/1.0, id3086=1.0/1.0/1.0, id3087=1.0/1.0/1.0, id3088=1.0/1.0/1.0, id3089=1.0/1.0/1.0, id309=1.0/1.0/1.0, id3090=1.0/1.0/1.0, id3091=1.0/1.0/1.0, id3092=1.0/1.0/1.0, id3093=1.0/1.0/1.0, id3094=1.0/1.0/1.0, id3095=1.0/1.0/1.0, id3096=1.0/1.0/1.0, id3097=1.0/1.0/1.0, id3098=1.0/1.0/1.0, id3099=1.0/1.0/1.0, id31=1.0/1.0/1.0, id310=1.0/1.0/1.0, id3100=1.0/1.0/1.0, id3101=1.0/1.0/1.0, id3102=1.0/1.0/1.0, id3103=1.0/1.0/1.0, id3104=1.0/1.0/1.0, id3105=1.0/1.0/1.0, id3106=1.0/1.0/1.0, id3107=1.0/1.0/1.0, id3108=1.0/1.0/1.0, id3109=1.0/1.0/1.0, id311=1.0/1.0/1.0, id3110=1.0/1.0/1.0, id3111=1.0/1.0/1.0, id3112=1.0/1.0/1.0, id3113=1.0/1.0/1.0, id3114=1.0/1.0/1.0, id3115=1.0/1.0/1.0, id3116=1.0/1.0/1.0, id3117=1.0/1.0/1.0, id3118=1.0/1.0/1.0, id3119=1.0/1.0/1.0, id312=1.0/1.0/1.0, id3120=1.0/1.0/1.0, id3121=1.0/1.0/1.0, id3122=1.0/1.0/1.0, id3123=1.0/1.0/1.0, id3124=1.0/1.0/1.0, id3125=1.0/1.0/1.0, id3126=1.0/1.0/1.0, id3127=1.0/1.0/1.0, id3128=1.0/1.0/1.0, id3129=1.0/1.0/1.0, id313=1.0/1.0/1.0, id3130=1.0/1.0/1.0, id3131=1.0/1.0/1.0, id3132=1.0/1.0/1.0, id3133=1.0/1.0/1.0, id3134=1.0/1.0/1.0, id3135=1.0/1.0/1.0, id3136=1.0/1.0/1.0, id3137=1.0/1.0/1.0, id3138=1.0/1.0/1.0, id3139=1.0/1.0/1.0, id314=1.0/1.0/1.0, id3140=1.0/1.0/1.0, id3141=1.0/1.0/1.0, id3142=1.0/1.0/1.0, id3143=1.0/1.0/1.0, id3144=1.0/1.0/1.0, id3145=1.0/1.0/1.0, id3146=1.0/1.0/1.0, id3147=1.0/1.0/1.0, id3148=1.0/1.0/1.0, id3149=1.0/1.0/1.0, id315=1.0/1.0/1.0, id3150=1.0/1.0/1.0, id3151=1.0/1.0/1.0, id3152=1.0/1.0/1.0, id3153=1.0/1.0/1.0, id3154=1.0/1.0/1.0, id3155=1.0/1.0/1.0, id3156=1.0/1.0/1.0, id3157=1.0/1.0/1.0, id3158=1.0/1.0/1.0, id3159=1.0/1.0/1.0, id316=1.0/1.0/1.0, id3160=1.0/1.0/1.0, id3161=1.0/1.0/1.0, id3162=1.0/1.0/1.0, id3163=1.0/1.0/1.0, id3164=1.0/1.0/1.0, id3165=1.0/1.0/1.0, id3166=1.0/1.0/1.0, id3167=1.0/1.0/1.0, id3168=1.0/1.0/1.0, id3169=1.0/1.0/1.0, id317=1.0/1.0/1.0, id3170=1.0/1.0/1.0, id3171=1.0/1.0/1.0, id3172=1.0/1.0/1.0, id3173=1.0/1.0/1.0, id3174=1.0/1.0/1.0, id3175=1.0/1.0/1.0, id3176=1.0/1.0/1.0, id3177=1.0/1.0/1.0, id3178=1.0/1.0/1.0, id3179=1.0/1.0/1.0, id318=1.0/1.0/1.0, id3180=1.0/1.0/1.0, id3181=1.0/1.0/1.0, id3182=1.0/1.0/1.0, id3183=1.0/1.0/1.0, id3184=1.0/1.0/1.0, id3185=1.0/1.0/1.0, id3186=1.0/1.0/1.0, id3187=1.0/1.0/1.0, id3188=1.0/1.0/1.0, id3189=1.0/1.0/1.0, id319=1.0/1.0/1.0, id3190=1.0/1.0/1.0, id3191=1.0/1.0/1.0, id3192=1.0/1.0/1.0, id3193=1.0/1.0/1.0, id3194=1.0/1.0/1.0, id3195=1.0/1.0/1.0, id3196=1.0/1.0/1.0, id3197=1.0/1.0/1.0, id3198=1.0/1.0/1.0, id3199=1.0/1.0/1.0, id32=1.0/1.0/1.0, id320=1.0/1.0/1.0, id3200=1.0/1.0/1.0, id3201=1.0/1.0/1.0, id3202=1.0/1.0/1.0, id3203=1.0/1.0/1.0, id3204=1.0/1.0/1.0, id3205=1.0/1.0/1.0, id3206=1.0/1.0/1.0, id3207=1.0/1.0/1.0, id3208=1.0/1.0/1.0, id3209=1.0/1.0/1.0, id321=1.0/1.0/1.0, id3210=1.0/1.0/1.0, id3211=1.0/1.0/1.0, id3212=1.0/1.0/1.0, id3213=1.0/1.0/1.0, id3214=1.0/1.0/1.0, id3215=1.0/1.0/1.0, id3216=1.0/1.0/1.0, id3217=1.0/1.0/1.0, id3218=1.0/1.0/1.0, id3219=1.0/1.0/1.0, id322=1.0/1.0/1.0, id3220=1.0/1.0/1.0, id3221=1.0/1.0/1.0, id3222=1.0/1.0/1.0, id3223=1.0/1.0/1.0, id3224=1.0/1.0/1.0, id3225=1.0/1.0/1.0, id3226=1.0/1.0/1.0, id3227=1.0/1.0/1.0, id3228=1.0/1.0/1.0, id3229=1.0/1.0/1.0, id323=1.0/1.0/1.0, id3230=1.0/1.0/1.0, id3231=1.0/1.0/1.0, id3232=1.0/1.0/1.0, id3233=1.0/1.0/1.0, id3234=1.0/1.0/1.0, id3235=1.0/1.0/1.0, id3236=1.0/1.0/1.0, id3237=1.0/1.0/1.0, id3238=1.0/1.0/1.0, id3239=1.0/1.0/1.0, id324=1.0/1.0/1.0, id3240=1.0/1.0/1.0, id3241=1.0/1.0/1.0, id3242=1.0/1.0/1.0, id3243=1.0/1.0/1.0, id3244=1.0/1.0/1.0, id3245=1.0/1.0/1.0, id3246=1.0/1.0/1.0, id3247=1.0/1.0/1.0, id3248=1.0/1.0/1.0, id3249=1.0/1.0/1.0, id325=1.0/1.0/1.0, id3250=1.0/1.0/1.0, id3251=1.0/1.0/1.0, id3252=1.0/1.0/1.0, id3253=1.0/1.0/1.0, id3254=1.0/1.0/1.0, id3255=1.0/1.0/1.0, id3256=1.0/1.0/1.0, id3257=1.0/1.0/1.0, id3258=1.0/1.0/1.0, id3259=1.0/1.0/1.0, id326=1.0/1.0/1.0, id3260=1.0/1.0/1.0, id3261=1.0/1.0/1.0, id3262=1.0/1.0/1.0, id3263=1.0/1.0/1.0, id3264=1.0/1.0/1.0, id3265=1.0/1.0/1.0, id3266=1.0/1.0/1.0, id3267=1.0/1.0/1.0, id3268=1.0/1.0/1.0, id3269=1.0/1.0/1.0, id327=1.0/1.0/1.0, id3270=1.0/1.0/1.0, id3271=1.0/1.0/1.0, id3272=1.0/1.0/1.0, id3273=1.0/1.0/1.0, id3274=1.0/1.0/1.0, id3275=1.0/1.0/1.0, id3276=1.0/1.0/1.0, id3277=1.0/1.0/1.0, id3278=1.0/1.0/1.0, id3279=1.0/1.0/1.0, id328=1.0/1.0/1.0, id3280=1.0/1.0/1.0, id3281=1.0/1.0/1.0, id3282=1.0/1.0/1.0, id3283=1.0/1.0/1.0, id3284=1.0/1.0/1.0, id3285=1.0/1.0/1.0, id3286=1.0/1.0/1.0, id3287=1.0/1.0/1.0, id3288=1.0/1.0/1.0, id3289=1.0/1.0/1.0, id329=1.0/1.0/1.0, id3290=1.0/1.0/1.0, id3291=1.0/1.0/1.0, id3292=1.0/1.0/1.0, id3293=1.0/1.0/1.0, id3294=1.0/1.0/1.0, id3295=1.0/1.0/1.0, id3296=1.0/1.0/1.0, id3297=1.0/1.0/1.0, id3298=1.0/1.0/1.0, id3299=1.0/1.0/1.0, id33=1.0/1.0/1.0, id330=1.0/1.0/1.0, id3300=1.0/1.0/1.0, id3301=1.0/1.0/1.0, id3302=1.0/1.0/1.0, id3303=1.0/1.0/1.0, id3304=1.0/1.0/1.0, id3305=1.0/1.0/1.0, id3306=1.0/1.0/1.0, id3307=1.0/1.0/1.0, id3308=1.0/1.0/1.0, id3309=1.0/1.0/1.0, id331=1.0/1.0/1.0, id3310=1.0/1.0/1.0, id3311=1.0/1.0/1.0, id3312=1.0/1.0/1.0, id3313=1.0/1.0/1.0, id3314=1.0/1.0/1.0, id3315=1.0/1.0/1.0, id3316=1.0/1.0/1.0, id3317=1.0/1.0/1.0, id3318=1.0/1.0/1.0, id3319=1.0/1.0/1.0, id332=1.0/1.0/1.0, id3320=1.0/1.0/1.0, id3321=1.0/1.0/1.0, id3322=1.0/1.0/1.0, id3323=1.0/1.0/1.0, id3324=1.0/1.0/1.0, id3325=1.0/1.0/1.0, id3326=1.0/1.0/1.0, id3327=1.0/1.0/1.0, id3328=1.0/1.0/1.0, id3329=1.0/1.0/1.0, id333=1.0/1.0/1.0, id3330=1.0/1.0/1.0, id3331=1.0/1.0/1.0, id3332=1.0/1.0/1.0, id3333=1.0/1.0/1.0, id3334=1.0/1.0/1.0, id3335=1.0/1.0/1.0, id3336=1.0/1.0/1.0, id3337=1.0/1.0/1.0, id3338=1.0/1.0/1.0, id3339=1.0/1.0/1.0, id334=1.0/1.0/1.0, id3340=1.0/1.0/1.0, id3341=1.0/1.0/1.0, id3342=1.0/1.0/1.0, id3343=1.0/1.0/1.0, id3344=1.0/1.0/1.0, id3345=1.0/1.0/1.0, id3346=1.0/1.0/1.0, id3347=1.0/1.0/1.0, id3348=1.0/1.0/1.0, id3349=1.0/1.0/1.0, id335=1.0/1.0/1.0, id3350=1.0/1.0/1.0, id3351=1.0/1.0/1.0, id3352=1.0/1.0/1.0, id3353=1.0/1.0/1.0, id3354=1.0/1.0/1.0, id3355=1.0/1.0/1.0, id3356=1.0/1.0/1.0, id3357=1.0/1.0/1.0, id3358=1.0/1.0/1.0, id3359=1.0/1.0/1.0, id336=1.0/1.0/1.0, id3360=1.0/1.0/1.0, id3361=1.0/1.0/1.0, id3362=1.0/1.0/1.0, id3363=1.0/1.0/1.0, id3364=1.0/1.0/1.0, id3365=1.0/1.0/1.0, id3366=1.0/1.0/1.0, id3367=1.0/1.0/1.0, id3368=1.0/1.0/1.0, id3369=1.0/1.0/1.0, id337=1.0/1.0/1.0, id3370=1.0/1.0/1.0, id3371=1.0/1.0/1.0, id3372=1.0/1.0/1.0, id3373=1.0/1.0/1.0, id3374=1.0/1.0/1.0, id3375=1.0/1.0/1.0, id3376=1.0/1.0/1.0, id3377=1.0/1.0/1.0, id3378=1.0/1.0/1.0, id3379=1.0/1.0/1.0, id338=1.0/1.0/1.0, id3380=1.0/1.0/1.0, id3381=1.0/1.0/1.0, id3382=1.0/1.0/1.0, id3383=1.0/1.0/1.0, id3384=1.0/1.0/1.0, id3385=1.0/1.0/1.0, id3386=1.0/1.0/1.0, id3387=1.0/1.0/1.0, id3388=1.0/1.0/1.0, id3389=1.0/1.0/1.0, id339=1.0/1.0/1.0, id3390=1.0/1.0/1.0, id3391=1.0/1.0/1.0, id3392=1.0/1.0/1.0, id3393=1.0/1.0/1.0, id3394=1.0/1.0/1.0, id3395=1.0/1.0/1.0, id3396=1.0/1.0/1.0, id3397=1.0/1.0/1.0, id3398=1.0/1.0/1.0, id3399=1.0/1.0/1.0, id34=1.0/1.0/1.0, id340=1.0/1.0/1.0, id3400=1.0/1.0/1.0, id3401=1.0/1.0/1.0, id3402=1.0/1.0/1.0, id3403=1.0/1.0/1.0, id3404=1.0/1.0/1.0, id3405=1.0/1.0/1.0, id3406=1.0/1.0/1.0, id3407=1.0/1.0/1.0, id3408=1.0/1.0/1.0, id3409=1.0/1.0/1.0, id341=1.0/1.0/1.0, id3410=1.0/1.0/1.0, id3411=1.0/1.0/1.0, id3412=1.0/1.0/1.0, id3413=1.0/1.0/1.0, id3414=1.0/1.0/1.0, id3415=1.0/1.0/1.0, id3416=1.0/1.0/1.0, id3417=1.0/1.0/1.0, id3418=1.0/1.0/1.0, id3419=1.0/1.0/1.0, id342=1.0/1.0/1.0, id3420=1.0/1.0/1.0, id3421=1.0/1.0/1.0, id3422=1.0/1.0/1.0, id3423=1.0/1.0/1.0, id3424=1.0/1.0/1.0, id3425=1.0/1.0/1.0, id3426=1.0/1.0/1.0, id3427=1.0/1.0/1.0, id3428=1.0/1.0/1.0, id3429=1.0/1.0/1.0, id343=1.0/1.0/1.0, id3430=1.0/1.0/1.0, id3431=1.0/1.0/1.0, id3432=1.0/1.0/1.0, id3433=1.0/1.0/1.0, id3434=1.0/1.0/1.0, id3435=1.0/1.0/1.0, id3436=1.0/1.0/1.0, id3437=1.0/1.0/1.0, id3438=1.0/1.0/1.0, id3439=1.0/1.0/1.0, id344=1.0/1.0/1.0, id3440=1.0/1.0/1.0, id3441=1.0/1.0/1.0, id3442=1.0/1.0/1.0, id3443=1.0/1.0/1.0, id3444=1.0/1.0/1.0, id3445=1.0/1.0/1.0, id3446=1.0/1.0/1.0, id3447=1.0/1.0/1.0, id3448=1.0/1.0/1.0, id3449=1.0/1.0/1.0, id345=1.0/1.0/1.0, id3450=1.0/1.0/1.0, id3451=1.0/1.0/1.0, id3452=1.0/1.0/1.0, id3453=1.0/1.0/1.0, id3454=1.0/1.0/1.0, id3455=1.0/1.0/1.0, id3456=1.0/1.0/1.0, id3457=1.0/1.0/1.0, id3458=1.0/1.0/1.0, id3459=1.0/1.0/1.0, id346=1.0/1.0/1.0, id3460=1.0/1.0/1.0, id3461=1.0/1.0/1.0, id3462=1.0/1.0/1.0, id3463=1.0/1.0/1.0, id3464=1.0/1.0/1.0, id3465=1.0/1.0/1.0, id3466=1.0/1.0/1.0, id3467=1.0/1.0/1.0, id3468=1.0/1.0/1.0, id3469=1.0/1.0/1.0, id347=1.0/1.0/1.0, id3470=1.0/1.0/1.0, id3471=1.0/1.0/1.0, id3472=1.0/1.0/1.0, id3473=1.0/1.0/1.0, id3474=1.0/1.0/1.0, id3475=1.0/1.0/1.0, id3476=1.0/1.0/1.0, id3477=1.0/1.0/1.0, id3478=1.0/1.0/1.0, id3479=1.0/1.0/1.0, id348=1.0/1.0/1.0, id3480=1.0/1.0/1.0, id3481=1.0/1.0/1.0, id3482=1.0/1.0/1.0, id3483=1.0/1.0/1.0, id3484=1.0/1.0/1.0, id3485=1.0/1.0/1.0, id3486=1.0/1.0/1.0, id3487=1.0/1.0/1.0, id3488=1.0/1.0/1.0, id3489=1.0/1.0/1.0, id349=1.0/1.0/1.0, id3490=1.0/1.0/1.0, id3491=1.0/1.0/1.0, id3492=1.0/1.0/1.0, id3493=1.0/1.0/1.0, id3494=1.0/1.0/1.0, id3495=1.0/1.0/1.0, id3496=1.0/1.0/1.0, id3497=1.0/1.0/1.0, id3498=1.0/1.0/1.0, id3499=1.0/1.0/1.0, id35=1.0/1.0/1.0, id350=1.0/1.0/1.0, id3500=1.0/1.0/1.0, id3501=1.0/1.0/1.0, id3502=1.0/1.0/1.0, id3503=1.0/1.0/1.0, id3504=1.0/1.0/1.0, id3505=1.0/1.0/1.0, id3506=1.0/1.0/1.0, id3507=1.0/1.0/1.0, id3508=1.0/1.0/1.0, id3509=1.0/1.0/1.0, id351=1.0/1.0/1.0, id3510=1.0/1.0/1.0, id3511=1.0/1.0/1.0, id3512=1.0/1.0/1.0, id3513=1.0/1.0/1.0, id3514=1.0/1.0/1.0, id3515=1.0/1.0/1.0, id3516=1.0/1.0/1.0, id3517=1.0/1.0/1.0, id3518=1.0/1.0/1.0, id3519=1.0/1.0/1.0, id352=1.0/1.0/1.0, id3520=1.0/1.0/1.0, id3521=1.0/1.0/1.0, id3522=1.0/1.0/1.0, id3523=1.0/1.0/1.0, id3524=1.0/1.0/1.0, id3525=1.0/1.0/1.0, id3526=1.0/1.0/1.0, id3527=1.0/1.0/1.0, id3528=1.0/1.0/1.0, id3529=1.0/1.0/1.0, id353=1.0/1.0/1.0, id3530=1.0/1.0/1.0, id3531=1.0/1.0/1.0, id3532=1.0/1.0/1.0, id3533=1.0/1.0/1.0, id3534=1.0/1.0/1.0, id3535=1.0/1.0/1.0, id3536=1.0/1.0/1.0, id3537=1.0/1.0/1.0, id3538=1.0/1.0/1.0, id3539=1.0/1.0/1.0, id354=1.0/1.0/1.0, id3540=1.0/1.0/1.0, id3541=1.0/1.0/1.0, id3542=1.0/1.0/1.0, id3543=1.0/1.0/1.0, id3544=1.0/1.0/1.0, id3545=1.0/1.0/1.0, id3546=1.0/1.0/1.0, id3547=1.0/1.0/1.0, id3548=1.0/1.0/1.0, id3549=1.0/1.0/1.0, id355=1.0/1.0/1.0, id3550=1.0/1.0/1.0, id3551=1.0/1.0/1.0, id3552=1.0/1.0/1.0, id3553=1.0/1.0/1.0, id3554=1.0/1.0/1.0, id3555=1.0/1.0/1.0, id3556=1.0/1.0/1.0, id3557=1.0/1.0/1.0, id3558=1.0/1.0/1.0, id3559=1.0/1.0/1.0, id356=1.0/1.0/1.0, id3560=1.0/1.0/1.0, id3561=1.0/1.0/1.0, id3562=1.0/1.0/1.0, id3563=1.0/1.0/1.0, id3564=1.0/1.0/1.0, id3565=1.0/1.0/1.0, id3566=1.0/1.0/1.0, id3567=1.0/1.0/1.0, id3568=1.0/1.0/1.0, id3569=1.0/1.0/1.0, id357=1.0/1.0/1.0, id3570=1.0/1.0/1.0, id3571=1.0/1.0/1.0, id3572=1.0/1.0/1.0, id3573=1.0/1.0/1.0, id3574=1.0/1.0/1.0, id3575=1.0/1.0/1.0, id3576=1.0/1.0/1.0, id3577=1.0/1.0/1.0, id3578=1.0/1.0/1.0, id3579=1.0/1.0/1.0, id358=1.0/1.0/1.0, id3580=1.0/1.0/1.0, id3581=1.0/1.0/1.0, id3582=1.0/1.0/1.0, id3583=1.0/1.0/1.0, id3584=1.0/1.0/1.0, id3585=1.0/1.0/1.0, id3586=1.0/1.0/1.0, id3587=1.0/1.0/1.0, id3588=1.0/1.0/1.0, id3589=1.0/1.0/1.0, id359=1.0/1.0/1.0, id3590=1.0/1.0/1.0, id3591=1.0/1.0/1.0, id3592=1.0/1.0/1.0, id3593=1.0/1.0/1.0, id3594=1.0/1.0/1.0, id3595=1.0/1.0/1.0, id3596=1.0/1.0/1.0, id3597=1.0/1.0/1.0, id3598=1.0/1.0/1.0, id3599=1.0/1.0/1.0, id36=1.0/1.0/1.0, id360=1.0/1.0/1.0, id3600=1.0/1.0/1.0, id3601=1.0/1.0/1.0, id3602=1.0/1.0/1.0, id3603=1.0/1.0/1.0, id3604=1.0/1.0/1.0, id3605=1.0/1.0/1.0, id3606=1.0/1.0/1.0, id3607=1.0/1.0/1.0, id3608=1.0/1.0/1.0, id3609=1.0/1.0/1.0, id361=1.0/1.0/1.0, id3610=1.0/1.0/1.0, id3611=1.0/1.0/1.0, id3612=1.0/1.0/1.0, id3613=1.0/1.0/1.0, id3614=1.0/1.0/1.0, id3615=1.0/1.0/1.0, id3616=1.0/1.0/1.0, id3617=1.0/1.0/1.0, id3618=1.0/1.0/1.0, id3619=1.0/1.0/1.0, id362=1.0/1.0/1.0, id3620=1.0/1.0/1.0, id3621=1.0/1.0/1.0, id3622=1.0/1.0/1.0, id3623=1.0/1.0/1.0, id3624=1.0/1.0/1.0, id3625=1.0/1.0/1.0, id3626=1.0/1.0/1.0, id3627=1.0/1.0/1.0, id3628=1.0/1.0/1.0, id3629=1.0/1.0/1.0, id363=1.0/1.0/1.0, id3630=1.0/1.0/1.0, id3631=1.0/1.0/1.0, id3632=1.0/1.0/1.0, id3633=1.0/1.0/1.0, id3634=1.0/1.0/1.0, id3635=1.0/1.0/1.0, id3636=1.0/1.0/1.0, id3637=1.0/1.0/1.0, id3638=1.0/1.0/1.0, id3639=1.0/1.0/1.0, id364=1.0/1.0/1.0, id3640=1.0/1.0/1.0, id3641=1.0/1.0/1.0, id3642=1.0/1.0/1.0, id3643=1.0/1.0/1.0, id3644=1.0/1.0/1.0, id3645=1.0/1.0/1.0, id3646=1.0/1.0/1.0, id3647=1.0/1.0/1.0, id3648=1.0/1.0/1.0, id3649=1.0/1.0/1.0, id365=1.0/1.0/1.0, id3650=1.0/1.0/1.0, id3651=1.0/1.0/1.0, id3652=1.0/1.0/1.0, id3653=1.0/1.0/1.0, id3654=1.0/1.0/1.0, id3655=1.0/1.0/1.0, id3656=1.0/1.0/1.0, id3657=1.0/1.0/1.0, id3658=1.0/1.0/1.0, id3659=1.0/1.0/1.0, id366=1.0/1.0/1.0, id3660=1.0/1.0/1.0, id3661=1.0/1.0/1.0, id3662=1.0/1.0/1.0, id3663=1.0/1.0/1.0, id3664=1.0/1.0/1.0, id3665=1.0/1.0/1.0, id3666=1.0/1.0/1.0, id3667=1.0/1.0/1.0, id3668=1.0/1.0/1.0, id3669=1.0/1.0/1.0, id367=1.0/1.0/1.0, id3670=1.0/1.0/1.0, id3671=1.0/1.0/1.0, id3672=1.0/1.0/1.0, id3673=1.0/1.0/1.0, id3674=1.0/1.0/1.0, id3675=1.0/1.0/1.0, id3676=1.0/1.0/1.0, id3677=1.0/1.0/1.0, id3678=1.0/1.0/1.0, id3679=1.0/1.0/1.0, id368=1.0/1.0/1.0, id3680=1.0/1.0/1.0, id3681=1.0/1.0/1.0, id3682=1.0/1.0/1.0, id3683=1.0/1.0/1.0, id3684=1.0/1.0/1.0, id3685=1.0/1.0/1.0, id3686=1.0/1.0/1.0, id3687=1.0/1.0/1.0, id3688=1.0/1.0/1.0, id3689=1.0/1.0/1.0, id369=1.0/1.0/1.0, id3690=1.0/1.0/1.0, id3691=1.0/1.0/1.0, id3692=1.0/1.0/1.0, id3693=1.0/1.0/1.0, id3694=1.0/1.0/1.0, id3695=1.0/1.0/1.0, id3696=1.0/1.0/1.0, id3697=1.0/1.0/1.0, id3698=1.0/1.0/1.0, id3699=1.0/1.0/1.0, id37=1.0/1.0/1.0, id370=1.0/1.0/1.0, id3700=1.0/1.0/1.0, id3701=1.0/1.0/1.0, id3702=1.0/1.0/1.0, id3703=1.0/1.0/1.0, id3704=1.0/1.0/1.0, id3705=1.0/1.0/1.0, id3706=1.0/1.0/1.0, id3707=1.0/1.0/1.0, id3708=1.0/1.0/1.0, id3709=1.0/1.0/1.0, id371=1.0/1.0/1.0, id3710=1.0/1.0/1.0, id3711=1.0/1.0/1.0, id3712=1.0/1.0/1.0, id3713=1.0/1.0/1.0, id3714=1.0/1.0/1.0, id3715=1.0/1.0/1.0, id3716=1.0/1.0/1.0, id3717=1.0/1.0/1.0, id3718=1.0/1.0/1.0, id3719=1.0/1.0/1.0, id372=1.0/1.0/1.0, id3720=1.0/1.0/1.0, id3721=1.0/1.0/1.0, id3722=1.0/1.0/1.0, id3723=1.0/1.0/1.0, id3724=1.0/1.0/1.0, id3725=1.0/1.0/1.0, id3726=1.0/1.0/1.0, id3727=1.0/1.0/1.0, id3728=1.0/1.0/1.0, id3729=1.0/1.0/1.0, id373=1.0/1.0/1.0, id3730=1.0/1.0/1.0, id3731=1.0/1.0/1.0, id3732=1.0/1.0/1.0, id3733=1.0/1.0/1.0, id3734=1.0/1.0/1.0, id3735=1.0/1.0/1.0, id3736=1.0/1.0/1.0, id3737=1.0/1.0/1.0, id3738=1.0/1.0/1.0, id3739=1.0/1.0/1.0, id374=1.0/1.0/1.0, id3740=1.0/1.0/1.0, id3741=1.0/1.0/1.0, id3742=1.0/1.0/1.0, id3743=1.0/1.0/1.0, id3744=1.0/1.0/1.0, id3745=1.0/1.0/1.0, id3746=1.0/1.0/1.0, id3747=1.0/1.0/1.0, id3748=1.0/1.0/1.0, id3749=1.0/1.0/1.0, id375=1.0/1.0/1.0, id3750=1.0/1.0/1.0, id3751=1.0/1.0/1.0, id3752=1.0/1.0/1.0, id3753=1.0/1.0/1.0, id3754=1.0/1.0/1.0, id3755=1.0/1.0/1.0, id3756=1.0/1.0/1.0, id3757=1.0/1.0/1.0, id3758=1.0/1.0/1.0, id3759=1.0/1.0/1.0, id376=1.0/1.0/1.0, id3760=1.0/1.0/1.0, id3761=1.0/1.0/1.0, id3762=1.0/1.0/1.0, id3763=1.0/1.0/1.0, id3764=1.0/1.0/1.0, id3765=1.0/1.0/1.0, id3766=1.0/1.0/1.0, id3767=1.0/1.0/1.0, id3768=1.0/1.0/1.0, id3769=1.0/1.0/1.0, id377=1.0/1.0/1.0, id3770=1.0/1.0/1.0, id3771=1.0/1.0/1.0, id3772=1.0/1.0/1.0, id3773=1.0/1.0/1.0, id3774=1.0/1.0/1.0, id3775=1.0/1.0/1.0, id3776=1.0/1.0/1.0, id3777=1.0/1.0/1.0, id3778=1.0/1.0/1.0, id3779=1.0/1.0/1.0, id378=1.0/1.0/1.0, id3780=1.0/1.0/1.0, id3781=1.0/1.0/1.0, id3782=1.0/1.0/1.0, id3783=1.0/1.0/1.0, id3784=1.0/1.0/1.0, id3785=1.0/1.0/1.0, id3786=1.0/1.0/1.0, id3787=1.0/1.0/1.0, id3788=1.0/1.0/1.0, id3789=1.0/1.0/1.0, id379=1.0/1.0/1.0, id3790=1.0/1.0/1.0, id3791=1.0/1.0/1.0, id3792=1.0/1.0/1.0, id3793=1.0/1.0/1.0, id3794=1.0/1.0/1.0, id3795=1.0/1.0/1.0, id3796=1.0/1.0/1.0, id3797=1.0/1.0/1.0, id3798=1.0/1.0/1.0, id3799=1.0/1.0/1.0, id38=1.0/1.0/1.0, id380=1.0/1.0/1.0, id3800=1.0/1.0/1.0, id3801=1.0/1.0/1.0, id3802=1.0/1.0/1.0, id3803=1.0/1.0/1.0, id3804=1.0/1.0/1.0, id3805=1.0/1.0/1.0, id3806=1.0/1.0/1.0, id3807=1.0/1.0/1.0, id3808=1.0/1.0/1.0, id3809=1.0/1.0/1.0, id381=1.0/1.0/1.0, id3810=1.0/1.0/1.0, id3811=1.0/1.0/1.0, id3812=1.0/1.0/1.0, id3813=1.0/1.0/1.0, id3814=1.0/1.0/1.0, id3815=1.0/1.0/1.0, id3816=1.0/1.0/1.0, id3817=1.0/1.0/1.0, id3818=1.0/1.0/1.0, id3819=1.0/1.0/1.0, id382=1.0/1.0/1.0, id3820=1.0/1.0/1.0, id3821=1.0/1.0/1.0, id3822=1.0/1.0/1.0, id3823=1.0/1.0/1.0, id3824=1.0/1.0/1.0, id3825=1.0/1.0/1.0, id3826=1.0/1.0/1.0, id3827=1.0/1.0/1.0, id3828=1.0/1.0/1.0, id3829=1.0/1.0/1.0, id383=1.0/1.0/1.0, id3830=1.0/1.0/1.0, id3831=1.0/1.0/1.0, id3832=1.0/1.0/1.0, id3833=1.0/1.0/1.0, id3834=1.0/1.0/1.0, id3835=1.0/1.0/1.0, id3836=1.0/1.0/1.0, id3837=1.0/1.0/1.0, id3838=1.0/1.0/1.0, id3839=1.0/1.0/1.0, id384=1.0/1.0/1.0, id3840=1.0/1.0/1.0, id3841=1.0/1.0/1.0, id3842=1.0/1.0/1.0, id3843=1.0/1.0/1.0, id3844=1.0/1.0/1.0, id3845=1.0/1.0/1.0, id3846=1.0/1.0/1.0, id3847=1.0/1.0/1.0, id3848=1.0/1.0/1.0, id3849=1.0/1.0/1.0, id385=1.0/1.0/1.0, id3850=1.0/1.0/1.0, id3851=1.0/1.0/1.0, id3852=1.0/1.0/1.0, id3853=1.0/1.0/1.0, id3854=1.0/1.0/1.0, id3855=1.0/1.0/1.0, id3856=1.0/1.0/1.0, id3857=1.0/1.0/1.0, id3858=1.0/1.0/1.0, id3859=1.0/1.0/1.0, id386=1.0/1.0/1.0, id3860=1.0/1.0/1.0, id3861=1.0/1.0/1.0, id3862=1.0/1.0/1.0, id3863=1.0/1.0/1.0, id3864=1.0/1.0/1.0, id3865=1.0/1.0/1.0, id3866=1.0/1.0/1.0, id3867=1.0/1.0/1.0, id3868=1.0/1.0/1.0, id3869=1.0/1.0/1.0, id387=1.0/1.0/1.0, id3870=1.0/1.0/1.0, id3871=1.0/1.0/1.0, id3872=1.0/1.0/1.0, id3873=1.0/1.0/1.0, id3874=1.0/1.0/1.0, id3875=1.0/1.0/1.0, id3876=1.0/1.0/1.0, id3877=1.0/1.0/1.0, id3878=1.0/1.0/1.0, id3879=1.0/1.0/1.0, id388=1.0/1.0/1.0, id3880=1.0/1.0/1.0, id3881=1.0/1.0/1.0, id3882=1.0/1.0/1.0, id3883=1.0/1.0/1.0, id3884=1.0/1.0/1.0, id3885=1.0/1.0/1.0, id3886=1.0/1.0/1.0, id3887=1.0/1.0/1.0, id3888=1.0/1.0/1.0, id3889=1.0/1.0/1.0, id389=1.0/1.0/1.0, id3890=1.0/1.0/1.0, id3891=1.0/1.0/1.0, id3892=1.0/1.0/1.0, id3893=1.0/1.0/1.0, id3894=1.0/1.0/1.0, id3895=1.0/1.0/1.0, id3896=1.0/1.0/1.0, id3897=1.0/1.0/1.0, id3898=1.0/1.0/1.0, id3899=1.0/1.0/1.0, id39=1.0/1.0/1.0, id390=1.0/1.0/1.0, id3900=1.0/1.0/1.0, id3901=1.0/1.0/1.0, id3902=1.0/1.0/1.0, id3903=1.0/1.0/1.0, id3904=1.0/1.0/1.0, id3905=1.0/1.0/1.0, id3906=1.0/1.0/1.0, id3907=1.0/1.0/1.0, id3908=1.0/1.0/1.0, id3909=1.0/1.0/1.0, id391=1.0/1.0/1.0, id3910=1.0/1.0/1.0, id3911=1.0/1.0/1.0, id3912=1.0/1.0/1.0, id3913=1.0/1.0/1.0, id3914=1.0/1.0/1.0, id3915=1.0/1.0/1.0, id3916=1.0/1.0/1.0, id3917=1.0/1.0/1.0, id3918=1.0/1.0/1.0, id3919=1.0/1.0/1.0, id392=1.0/1.0/1.0, id3920=1.0/1.0/1.0, id3921=1.0/1.0/1.0, id3922=1.0/1.0/1.0, id3923=1.0/1.0/1.0, id3924=1.0/1.0/1.0, id3925=1.0/1.0/1.0, id3926=1.0/1.0/1.0, id3927=1.0/1.0/1.0, id3928=1.0/1.0/1.0, id3929=1.0/1.0/1.0, id393=1.0/1.0/1.0, id3930=1.0/1.0/1.0, id3931=1.0/1.0/1.0, id3932=1.0/1.0/1.0, id3933=1.0/1.0/1.0, id3934=1.0/1.0/1.0, id3935=1.0/1.0/1.0, id3936=1.0/1.0/1.0, id3937=1.0/1.0/1.0, id3938=1.0/1.0/1.0, id3939=1.0/1.0/1.0, id394=1.0/1.0/1.0, id3940=1.0/1.0/1.0, id3941=1.0/1.0/1.0, id3942=1.0/1.0/1.0, id3943=1.0/1.0/1.0, id3944=1.0/1.0/1.0, id3945=1.0/1.0/1.0, id3946=1.0/1.0/1.0, id3947=1.0/1.0/1.0, id3948=1.0/1.0/1.0, id3949=1.0/1.0/1.0, id395=1.0/1.0/1.0, id3950=1.0/1.0/1.0, id3951=1.0/1.0/1.0, id3952=1.0/1.0/1.0, id3953=1.0/1.0/1.0, id3954=1.0/1.0/1.0, id3955=1.0/1.0/1.0, id3956=1.0/1.0/1.0, id3957=1.0/1.0/1.0, id3958=1.0/1.0/1.0, id3959=1.0/1.0/1.0, id396=1.0/1.0/1.0, id3960=1.0/1.0/1.0, id3961=1.0/1.0/1.0, id3962=1.0/1.0/1.0, id3963=1.0/1.0/1.0, id3964=1.0/1.0/1.0, id3965=1.0/1.0/1.0, id3966=1.0/1.0/1.0, id3967=1.0/1.0/1.0, id3968=1.0/1.0/1.0, id3969=1.0/1.0/1.0, id397=1.0/1.0/1.0, id3970=1.0/1.0/1.0, id3971=1.0/1.0/1.0, id3972=1.0/1.0/1.0, id3973=1.0/1.0/1.0, id3974=1.0/1.0/1.0, id3975=1.0/1.0/1.0, id3976=1.0/1.0/1.0, id3977=1.0/1.0/1.0, id3978=1.0/1.0/1.0, id3979=1.0/1.0/1.0, id398=1.0/1.0/1.0, id3980=1.0/1.0/1.0, id3981=1.0/1.0/1.0, id3982=1.0/1.0/1.0, id3983=1.0/1.0/1.0, id3984=1.0/1.0/1.0, id3985=1.0/1.0/1.0, id3986=1.0/1.0/1.0, id3987=1.0/1.0/1.0, id3988=1.0/1.0/1.0, id3989=1.0/1.0/1.0, id399=1.0/1.0/1.0, id3990=1.0/1.0/1.0, id3991=1.0/1.0/1.0, id3992=1.0/1.0/1.0, id3993=1.0/1.0/1.0, id3994=1.0/1.0/1.0, id3995=1.0/1.0/1.0, id3996=1.0/1.0/1.0, id3997=1.0/1.0/1.0, id3998=1.0/1.0/1.0, id3999=1.0/1.0/1.0, id4=1.0/1.0/1.0, id40=1.0/1.0/1.0, id400=1.0/1.0/1.0, id4000=1.0/1.0/1.0, id4001=1.0/1.0/1.0, id4002=1.0/1.0/1.0, id4003=1.0/1.0/1.0, id4004=1.0/1.0/1.0, id4005=1.0/1.0/1.0, id4006=1.0/1.0/1.0, id4007=1.0/1.0/1.0, id4008=1.0/1.0/1.0, id4009=1.0/1.0/1.0, id401=1.0/1.0/1.0, id4010=1.0/1.0/1.0, id4011=1.0/1.0/1.0, id4012=1.0/1.0/1.0, id4013=1.0/1.0/1.0, id4014=1.0/1.0/1.0, id4015=1.0/1.0/1.0, id4016=1.0/1.0/1.0, id4017=1.0/1.0/1.0, id4018=1.0/1.0/1.0, id4019=1.0/1.0/1.0, id402=1.0/1.0/1.0, id4020=1.0/1.0/1.0, id4021=1.0/1.0/1.0, id4022=1.0/1.0/1.0, id4023=1.0/1.0/1.0, id4024=1.0/1.0/1.0, id4025=1.0/1.0/1.0, id4026=1.0/1.0/1.0, id4027=1.0/1.0/1.0, id4028=1.0/1.0/1.0, id4029=1.0/1.0/1.0, id403=1.0/1.0/1.0, id4030=1.0/1.0/1.0, id4031=1.0/1.0/1.0, id4032=1.0/1.0/1.0, id4033=1.0/1.0/1.0, id4034=1.0/1.0/1.0, id4035=1.0/1.0/1.0, id4036=1.0/1.0/1.0, id4037=1.0/1.0/1.0, id4038=1.0/1.0/1.0, id4039=1.0/1.0/1.0, id404=1.0/1.0/1.0, id4040=1.0/1.0/1.0, id4041=1.0/1.0/1.0, id4042=1.0/1.0/1.0, id4043=1.0/1.0/1.0, id4044=1.0/1.0/1.0, id4045=1.0/1.0/1.0, id4046=1.0/1.0/1.0, id4047=1.0/1.0/1.0, id4048=1.0/1.0/1.0, id4049=1.0/1.0/1.0, id405=1.0/1.0/1.0, id4050=1.0/1.0/1.0, id4051=1.0/1.0/1.0, id4052=1.0/1.0/1.0, id4053=1.0/1.0/1.0, id4054=1.0/1.0/1.0, id4055=1.0/1.0/1.0, id4056=1.0/1.0/1.0, id4057=1.0/1.0/1.0, id4058=1.0/1.0/1.0, id4059=1.0/1.0/1.0, id406=1.0/1.0/1.0, id4060=1.0/1.0/1.0, id4061=1.0/1.0/1.0, id4062=1.0/1.0/1.0, id4063=1.0/1.0/1.0, id4064=1.0/1.0/1.0, id4065=1.0/1.0/1.0, id4066=1.0/1.0/1.0, id4067=1.0/1.0/1.0, id4068=1.0/1.0/1.0, id4069=1.0/1.0/1.0, id407=1.0/1.0/1.0, id4070=1.0/1.0/1.0, id4071=1.0/1.0/1.0, id4072=1.0/1.0/1.0, id4073=1.0/1.0/1.0, id4074=1.0/1.0/1.0, id4075=1.0/1.0/1.0, id4076=1.0/1.0/1.0, id4077=1.0/1.0/1.0, id4078=1.0/1.0/1.0, id4079=1.0/1.0/1.0, id408=1.0/1.0/1.0, id4080=1.0/1.0/1.0, id4081=1.0/1.0/1.0, id4082=1.0/1.0/1.0, id4083=1.0/1.0/1.0, id4084=1.0/1.0/1.0, id4085=1.0/1.0/1.0, id4086=1.0/1.0/1.0, id4087=1.0/1.0/1.0, id4088=1.0/1.0/1.0, id4089=1.0/1.0/1.0, id409=1.0/1.0/1.0, id4090=1.0/1.0/1.0, id4091=1.0/1.0/1.0, id4092=1.0/1.0/1.0, id4093=1.0/1.0/1.0, id4094=1.0/1.0/1.0, id4095=1.0/1.0/1.0, id4096=1.0/1.0/1.0, id4097=1.0/1.0/1.0, id4098=1.0/1.0/1.0, id4099=1.0/1.0/1.0, id41=1.0/1.0/1.0, id410=1.0/1.0/1.0, id4100=1.0/1.0/1.0, id4101=1.0/1.0/1.0, id4102=1.0/1.0/1.0, id4103=1.0/1.0/1.0, id4104=1.0/1.0/1.0, id4105=1.0/1.0/1.0, id4106=1.0/1.0/1.0, id4107=1.0/1.0/1.0, id4108=1.0/1.0/1.0, id4109=1.0/1.0/1.0, id411=1.0/1.0/1.0, id4110=1.0/1.0/1.0, id4111=1.0/1.0/1.0, id4112=1.0/1.0/1.0, id4113=1.0/1.0/1.0, id4114=1.0/1.0/1.0, id4115=1.0/1.0/1.0, id4116=1.0/1.0/1.0, id4117=1.0/1.0/1.0, id4118=1.0/1.0/1.0, id4119=1.0/1.0/1.0, id412=1.0/1.0/1.0, id4120=1.0/1.0/1.0, id4121=1.0/1.0/1.0, id4122=1.0/1.0/1.0, id4123=1.0/1.0/1.0, id4124=1.0/1.0/1.0, id4125=1.0/1.0/1.0, id4126=1.0/1.0/1.0, id4127=1.0/1.0/1.0, id4128=1.0/1.0/1.0, id4129=1.0/1.0/1.0, id413=1.0/1.0/1.0, id4130=1.0/1.0/1.0, id4131=1.0/1.0/1.0, id4132=1.0/1.0/1.0, id4133=1.0/1.0/1.0, id4134=1.0/1.0/1.0, id4135=1.0/1.0/1.0, id4136=1.0/1.0/1.0, id4137=1.0/1.0/1.0, id4138=1.0/1.0/1.0, id4139=1.0/1.0/1.0, id414=1.0/1.0/1.0, id4140=1.0/1.0/1.0, id4141=1.0/1.0/1.0, id4142=1.0/1.0/1.0, id4143=1.0/1.0/1.0, id4144=1.0/1.0/1.0, id4145=1.0/1.0/1.0, id4146=1.0/1.0/1.0, id4147=1.0/1.0/1.0, id4148=1.0/1.0/1.0, id4149=1.0/1.0/1.0, id415=1.0/1.0/1.0, id4150=1.0/1.0/1.0, id4151=1.0/1.0/1.0, id4152=1.0/1.0/1.0, id4153=1.0/1.0/1.0, id4154=1.0/1.0/1.0, id4155=1.0/1.0/1.0, id4156=1.0/1.0/1.0, id4157=1.0/1.0/1.0, id4158=1.0/1.0/1.0, id4159=1.0/1.0/1.0, id416=1.0/1.0/1.0, id4160=1.0/1.0/1.0, id4161=1.0/1.0/1.0, id4162=1.0/1.0/1.0, id4163=1.0/1.0/1.0, id4164=1.0/1.0/1.0, id4165=1.0/1.0/1.0, id4166=1.0/1.0/1.0, id4167=1.0/1.0/1.0, id4168=1.0/1.0/1.0, id4169=1.0/1.0/1.0, id417=1.0/1.0/1.0, id4170=1.0/1.0/1.0, id4171=1.0/1.0/1.0, id4172=1.0/1.0/1.0, id4173=1.0/1.0/1.0, id4174=1.0/1.0/1.0, id4175=1.0/1.0/1.0, id4176=1.0/1.0/1.0, id4177=1.0/1.0/1.0, id4178=1.0/1.0/1.0, id4179=1.0/1.0/1.0, id418=1.0/1.0/1.0, id4180=1.0/1.0/1.0, id4181=1.0/1.0/1.0, id4182=1.0/1.0/1.0, id4183=1.0/1.0/1.0, id4184=1.0/1.0/1.0, id4185=1.0/1.0/1.0, id4186=1.0/1.0/1.0, id4187=1.0/1.0/1.0, id4188=1.0/1.0/1.0, id4189=1.0/1.0/1.0, id419=1.0/1.0/1.0, id4190=1.0/1.0/1.0, id4191=1.0/1.0/1.0, id4192=1.0/1.0/1.0, id4193=1.0/1.0/1.0, id4194=1.0/1.0/1.0, id4195=1.0/1.0/1.0, id4196=1.0/1.0/1.0, id4197=1.0/1.0/1.0, id4198=1.0/1.0/1.0, id4199=1.0/1.0/1.0, id42=1.0/1.0/1.0, id420=1.0/1.0/1.0, id4200=1.0/1.0/1.0, id4201=1.0/1.0/1.0, id4202=1.0/1.0/1.0, id4203=1.0/1.0/1.0, id4204=1.0/1.0/1.0, id4205=1.0/1.0/1.0, id4206=1.0/1.0/1.0, id4207=1.0/1.0/1.0, id4208=1.0/1.0/1.0, id4209=1.0/1.0/1.0, id421=1.0/1.0/1.0, id4210=1.0/1.0/1.0, id4211=1.0/1.0/1.0, id4212=1.0/1.0/1.0, id4213=1.0/1.0/1.0, id4214=1.0/1.0/1.0, id4215=1.0/1.0/1.0, id4216=1.0/1.0/1.0, id4217=1.0/1.0/1.0, id4218=1.0/1.0/1.0, id4219=1.0/1.0/1.0, id422=1.0/1.0/1.0, id4220=1.0/1.0/1.0, id4221=1.0/1.0/1.0, id4222=1.0/1.0/1.0, id4223=1.0/1.0/1.0, id4224=1.0/1.0/1.0, id4225=1.0/1.0/1.0, id4226=1.0/1.0/1.0, id4227=1.0/1.0/1.0, id4228=1.0/1.0/1.0, id4229=1.0/1.0/1.0, id423=1.0/1.0/1.0, id4230=1.0/1.0/1.0, id4231=1.0/1.0/1.0, id4232=1.0/1.0/1.0, id4233=1.0/1.0/1.0, id4234=1.0/1.0/1.0, id4235=1.0/1.0/1.0, id4236=1.0/1.0/1.0, id4237=1.0/1.0/1.0, id4238=1.0/1.0/1.0, id4239=1.0/1.0/1.0, id424=1.0/1.0/1.0, id4240=1.0/1.0/1.0, id4241=1.0/1.0/1.0, id4242=1.0/1.0/1.0, id4243=1.0/1.0/1.0, id4244=1.0/1.0/1.0, id4245=1.0/1.0/1.0, id4246=1.0/1.0/1.0, id4247=1.0/1.0/1.0, id4248=1.0/1.0/1.0, id4249=1.0/1.0/1.0, id425=1.0/1.0/1.0, id4250=1.0/1.0/1.0, id4251=1.0/1.0/1.0, id4252=1.0/1.0/1.0, id4253=1.0/1.0/1.0, id4254=1.0/1.0/1.0, id4255=1.0/1.0/1.0, id4256=1.0/1.0/1.0, id4257=1.0/1.0/1.0, id4258=1.0/1.0/1.0, id4259=1.0/1.0/1.0, id426=1.0/1.0/1.0, id4260=1.0/1.0/1.0, id4261=1.0/1.0/1.0, id4262=1.0/1.0/1.0, id4263=1.0/1.0/1.0, id4264=1.0/1.0/1.0, id4265=1.0/1.0/1.0, id4266=1.0/1.0/1.0, id4267=1.0/1.0/1.0, id4268=1.0/1.0/1.0, id4269=1.0/1.0/1.0, id427=1.0/1.0/1.0, id4270=1.0/1.0/1.0, id4271=1.0/1.0/1.0, id4272=1.0/1.0/1.0, id4273=1.0/1.0/1.0, id4274=1.0/1.0/1.0, id4275=1.0/1.0/1.0, id4276=1.0/1.0/1.0, id4277=1.0/1.0/1.0, id4278=1.0/1.0/1.0, id4279=1.0/1.0/1.0, id428=1.0/1.0/1.0, id4280=1.0/1.0/1.0, id4281=1.0/1.0/1.0, id4282=1.0/1.0/1.0, id4283=1.0/1.0/1.0, id4284=1.0/1.0/1.0, id4285=1.0/1.0/1.0, id4286=1.0/1.0/1.0, id4287=1.0/1.0/1.0, id4288=1.0/1.0/1.0, id4289=1.0/1.0/1.0, id429=1.0/1.0/1.0, id4290=1.0/1.0/1.0, id4291=1.0/1.0/1.0, id4292=1.0/1.0/1.0, id4293=1.0/1.0/1.0, id4294=1.0/1.0/1.0, id4295=1.0/1.0/1.0, id4296=1.0/1.0/1.0, id4297=1.0/1.0/1.0, id4298=1.0/1.0/1.0, id4299=1.0/1.0/1.0, id43=1.0/1.0/1.0, id430=1.0/1.0/1.0, id4300=1.0/1.0/1.0, id4301=1.0/1.0/1.0, id4302=1.0/1.0/1.0, id4303=1.0/1.0/1.0, id4304=1.0/1.0/1.0, id4305=1.0/1.0/1.0, id4306=1.0/1.0/1.0, id4307=1.0/1.0/1.0, id4308=1.0/1.0/1.0, id4309=1.0/1.0/1.0, id431=1.0/1.0/1.0, id4310=1.0/1.0/1.0, id4311=1.0/1.0/1.0, id4312=1.0/1.0/1.0, id4313=1.0/1.0/1.0, id4314=1.0/1.0/1.0, id4315=1.0/1.0/1.0, id4316=1.0/1.0/1.0, id4317=1.0/1.0/1.0, id4318=1.0/1.0/1.0, id4319=1.0/1.0/1.0, id432=1.0/1.0/1.0, id4320=1.0/1.0/1.0, id4321=1.0/1.0/1.0, id4322=1.0/1.0/1.0, id4323=1.0/1.0/1.0, id4324=1.0/1.0/1.0, id4325=1.0/1.0/1.0, id4326=1.0/1.0/1.0, id4327=1.0/1.0/1.0, id4328=1.0/1.0/1.0, id4329=1.0/1.0/1.0, id433=1.0/1.0/1.0, id4330=1.0/1.0/1.0, id4331=1.0/1.0/1.0, id4332=1.0/1.0/1.0, id4333=1.0/1.0/1.0, id4334=1.0/1.0/1.0, id4335=1.0/1.0/1.0, id4336=1.0/1.0/1.0, id4337=1.0/1.0/1.0, id4338=1.0/1.0/1.0, id4339=1.0/1.0/1.0, id434=1.0/1.0/1.0, id4340=1.0/1.0/1.0, id4341=1.0/1.0/1.0, id4342=1.0/1.0/1.0, id4343=1.0/1.0/1.0, id4344=1.0/1.0/1.0, id4345=1.0/1.0/1.0, id4346=1.0/1.0/1.0, id4347=1.0/1.0/1.0, id4348=1.0/1.0/1.0, id4349=1.0/1.0/1.0, id435=1.0/1.0/1.0, id4350=1.0/1.0/1.0, id4351=1.0/1.0/1.0, id4352=1.0/1.0/1.0, id4353=1.0/1.0/1.0, id4354=1.0/1.0/1.0, id4355=1.0/1.0/1.0, id4356=1.0/1.0/1.0, id4357=1.0/1.0/1.0, id4358=1.0/1.0/1.0, id4359=1.0/1.0/1.0, id436=1.0/1.0/1.0, id4360=1.0/1.0/1.0, id4361=1.0/1.0/1.0, id4362=1.0/1.0/1.0, id4363=1.0/1.0/1.0, id4364=1.0/1.0/1.0, id4365=1.0/1.0/1.0, id4366=1.0/1.0/1.0, id4367=1.0/1.0/1.0, id4368=1.0/1.0/1.0, id4369=1.0/1.0/1.0, id437=1.0/1.0/1.0, id4370=1.0/1.0/1.0, id4371=1.0/1.0/1.0, id4372=1.0/1.0/1.0, id4373=1.0/1.0/1.0, id4374=1.0/1.0/1.0, id4375=1.0/1.0/1.0, id4376=1.0/1.0/1.0, id4377=1.0/1.0/1.0, id4378=1.0/1.0/1.0, id4379=1.0/1.0/1.0, id438=1.0/1.0/1.0, id4380=1.0/1.0/1.0, id4381=1.0/1.0/1.0, id4382=1.0/1.0/1.0, id4383=1.0/1.0/1.0, id4384=1.0/1.0/1.0, id4385=1.0/1.0/1.0, id4386=1.0/1.0/1.0, id4387=1.0/1.0/1.0, id4388=1.0/1.0/1.0, id4389=1.0/1.0/1.0, id439=1.0/1.0/1.0, id4390=1.0/1.0/1.0, id4391=1.0/1.0/1.0, id4392=1.0/1.0/1.0, id4393=1.0/1.0/1.0, id4394=1.0/1.0/1.0, id4395=1.0/1.0/1.0, id4396=1.0/1.0/1.0, id4397=1.0/1.0/1.0, id4398=1.0/1.0/1.0, id4399=1.0/1.0/1.0, id44=1.0/1.0/1.0, id440=1.0/1.0/1.0, id4400=1.0/1.0/1.0, id4401=1.0/1.0/1.0, id4402=1.0/1.0/1.0, id4403=1.0/1.0/1.0, id4404=1.0/1.0/1.0, id4405=1.0/1.0/1.0, id4406=1.0/1.0/1.0, id4407=1.0/1.0/1.0, id4408=1.0/1.0/1.0, id4409=1.0/1.0/1.0, id441=1.0/1.0/1.0, id4410=1.0/1.0/1.0, id4411=1.0/1.0/1.0, id4412=1.0/1.0/1.0, id4413=1.0/1.0/1.0, id4414=1.0/1.0/1.0, id4415=1.0/1.0/1.0, id4416=1.0/1.0/1.0, id4417=1.0/1.0/1.0, id4418=1.0/1.0/1.0, id4419=1.0/1.0/1.0, id442=1.0/1.0/1.0, id4420=1.0/1.0/1.0, id4421=1.0/1.0/1.0, id4422=1.0/1.0/1.0, id4423=1.0/1.0/1.0, id4424=1.0/1.0/1.0, id4425=1.0/1.0/1.0, id4426=1.0/1.0/1.0, id4427=1.0/1.0/1.0, id4428=1.0/1.0/1.0, id4429=1.0/1.0/1.0, id443=1.0/1.0/1.0, id4430=1.0/1.0/1.0, id4431=1.0/1.0/1.0, id4432=1.0/1.0/1.0, id4433=1.0/1.0/1.0, id4434=1.0/1.0/1.0, id4435=1.0/1.0/1.0, id4436=1.0/1.0/1.0, id4437=1.0/1.0/1.0, id4438=1.0/1.0/1.0, id4439=1.0/1.0/1.0, id444=1.0/1.0/1.0, id4440=1.0/1.0/1.0, id4441=1.0/1.0/1.0, id4442=1.0/1.0/1.0, id4443=1.0/1.0/1.0, id4444=1.0/1.0/1.0, id4445=1.0/1.0/1.0, id4446=1.0/1.0/1.0, id4447=1.0/1.0/1.0, id4448=1.0/1.0/1.0, id4449=1.0/1.0/1.0, id445=1.0/1.0/1.0, id4450=1.0/1.0/1.0, id4451=1.0/1.0/1.0, id4452=1.0/1.0/1.0, id4453=1.0/1.0/1.0, id4454=1.0/1.0/1.0, id4455=1.0/1.0/1.0, id4456=1.0/1.0/1.0, id4457=1.0/1.0/1.0, id4458=1.0/1.0/1.0, id4459=1.0/1.0/1.0, id446=1.0/1.0/1.0, id4460=1.0/1.0/1.0, id4461=1.0/1.0/1.0, id4462=1.0/1.0/1.0, id4463=1.0/1.0/1.0, id4464=1.0/1.0/1.0, id4465=1.0/1.0/1.0, id4466=1.0/1.0/1.0, id4467=1.0/1.0/1.0, id4468=1.0/1.0/1.0, id4469=1.0/1.0/1.0, id447=1.0/1.0/1.0, id4470=1.0/1.0/1.0, id4471=1.0/1.0/1.0, id4472=1.0/1.0/1.0, id4473=1.0/1.0/1.0, id4474=1.0/1.0/1.0, id4475=1.0/1.0/1.0, id4476=1.0/1.0/1.0, id4477=1.0/1.0/1.0, id4478=1.0/1.0/1.0, id4479=1.0/1.0/1.0, id448=1.0/1.0/1.0, id4480=1.0/1.0/1.0, id4481=1.0/1.0/1.0, id4482=1.0/1.0/1.0, id4483=1.0/1.0/1.0, id4484=1.0/1.0/1.0, id4485=1.0/1.0/1.0, id4486=1.0/1.0/1.0, id4487=1.0/1.0/1.0, id4488=1.0/1.0/1.0, id4489=1.0/1.0/1.0, id449=1.0/1.0/1.0, id4490=1.0/1.0/1.0, id4491=1.0/1.0/1.0, id4492=1.0/1.0/1.0, id4493=1.0/1.0/1.0, id4494=1.0/1.0/1.0, id4495=1.0/1.0/1.0, id4496=1.0/1.0/1.0, id4497=1.0/1.0/1.0, id4498=1.0/1.0/1.0, id4499=1.0/1.0/1.0, id45=1.0/1.0/1.0, id450=1.0/1.0/1.0, id4500=1.0/1.0/1.0, id4501=1.0/1.0/1.0, id4502=1.0/1.0/1.0, id4503=1.0/1.0/1.0, id4504=1.0/1.0/1.0, id4505=1.0/1.0/1.0, id4506=1.0/1.0/1.0, id4507=1.0/1.0/1.0, id4508=1.0/1.0/1.0, id4509=1.0/1.0/1.0, id451=1.0/1.0/1.0, id4510=1.0/1.0/1.0, id4511=1.0/1.0/1.0, id4512=1.0/1.0/1.0, id4513=1.0/1.0/1.0, id4514=1.0/1.0/1.0, id4515=1.0/1.0/1.0, id4516=1.0/1.0/1.0, id4517=1.0/1.0/1.0, id4518=1.0/1.0/1.0, id4519=1.0/1.0/1.0, id452=1.0/1.0/1.0, id4520=1.0/1.0/1.0, id4521=1.0/1.0/1.0, id4522=1.0/1.0/1.0, id4523=1.0/1.0/1.0, id4524=1.0/1.0/1.0, id4525=1.0/1.0/1.0, id4526=1.0/1.0/1.0, id4527=1.0/1.0/1.0, id4528=1.0/1.0/1.0, id4529=1.0/1.0/1.0, id453=1.0/1.0/1.0, id4530=1.0/1.0/1.0, id4531=1.0/1.0/1.0, id4532=1.0/1.0/1.0, id4533=1.0/1.0/1.0, id4534=1.0/1.0/1.0, id4535=1.0/1.0/1.0, id4536=1.0/1.0/1.0, id4537=1.0/1.0/1.0, id4538=1.0/1.0/1.0, id4539=1.0/1.0/1.0, id454=1.0/1.0/1.0, id4540=1.0/1.0/1.0, id4541=1.0/1.0/1.0, id4542=1.0/1.0/1.0, id4543=1.0/1.0/1.0, id4544=1.0/1.0/1.0, id4545=1.0/1.0/1.0, id4546=1.0/1.0/1.0, id4547=1.0/1.0/1.0, id4548=1.0/1.0/1.0, id4549=1.0/1.0/1.0, id455=1.0/1.0/1.0, id4550=1.0/1.0/1.0, id4551=1.0/1.0/1.0, id4552=1.0/1.0/1.0, id4553=1.0/1.0/1.0, id4554=1.0/1.0/1.0, id4555=1.0/1.0/1.0, id4556=1.0/1.0/1.0, id4557=1.0/1.0/1.0, id4558=1.0/1.0/1.0, id4559=1.0/1.0/1.0, id456=1.0/1.0/1.0, id4560=1.0/1.0/1.0, id4561=1.0/1.0/1.0, id4562=1.0/1.0/1.0, id4563=1.0/1.0/1.0, id4564=1.0/1.0/1.0, id4565=1.0/1.0/1.0, id4566=1.0/1.0/1.0, id4567=1.0/1.0/1.0, id4568=1.0/1.0/1.0, id4569=1.0/1.0/1.0, id457=1.0/1.0/1.0, id4570=1.0/1.0/1.0, id4571=1.0/1.0/1.0, id4572=1.0/1.0/1.0, id4573=1.0/1.0/1.0, id4574=1.0/1.0/1.0, id4575=1.0/1.0/1.0, id4576=1.0/1.0/1.0, id4577=1.0/1.0/1.0, id4578=1.0/1.0/1.0, id4579=1.0/1.0/1.0, id458=1.0/1.0/1.0, id4580=1.0/1.0/1.0, id4581=1.0/1.0/1.0, id4582=1.0/1.0/1.0, id4583=1.0/1.0/1.0, id4584=1.0/1.0/1.0, id4585=1.0/1.0/1.0, id4586=1.0/1.0/1.0, id4587=1.0/1.0/1.0, id4588=1.0/1.0/1.0, id4589=1.0/1.0/1.0, id459=1.0/1.0/1.0, id4590=1.0/1.0/1.0, id4591=1.0/1.0/1.0, id4592=1.0/1.0/1.0, id4593=1.0/1.0/1.0, id4594=1.0/1.0/1.0, id4595=1.0/1.0/1.0, id4596=1.0/1.0/1.0, id4597=1.0/1.0/1.0, id4598=1.0/1.0/1.0, id4599=1.0/1.0/1.0, id46=1.0/1.0/1.0, id460=1.0/1.0/1.0, id4600=1.0/1.0/1.0, id4601=1.0/1.0/1.0, id4602=1.0/1.0/1.0, id4603=1.0/1.0/1.0, id4604=1.0/1.0/1.0, id4605=1.0/1.0/1.0, id4606=1.0/1.0/1.0, id4607=1.0/1.0/1.0, id4608=1.0/1.0/1.0, id4609=1.0/1.0/1.0, id461=1.0/1.0/1.0, id4610=1.0/1.0/1.0, id4611=1.0/1.0/1.0, id4612=1.0/1.0/1.0, id4613=1.0/1.0/1.0, id4614=1.0/1.0/1.0, id4615=1.0/1.0/1.0, id4616=1.0/1.0/1.0, id4617=1.0/1.0/1.0, id4618=1.0/1.0/1.0, id4619=1.0/1.0/1.0, id462=1.0/1.0/1.0, id4620=1.0/1.0/1.0, id4621=1.0/1.0/1.0, id4622=1.0/1.0/1.0, id4623=1.0/1.0/1.0, id4624=1.0/1.0/1.0, id4625=1.0/1.0/1.0, id4626=1.0/1.0/1.0, id4627=1.0/1.0/1.0, id4628=1.0/1.0/1.0, id4629=1.0/1.0/1.0, id463=1.0/1.0/1.0, id4630=1.0/1.0/1.0, id4631=1.0/1.0/1.0, id4632=1.0/1.0/1.0, id4633=1.0/1.0/1.0, id4634=1.0/1.0/1.0, id4635=1.0/1.0/1.0, id4636=1.0/1.0/1.0, id4637=1.0/1.0/1.0, id4638=1.0/1.0/1.0, id4639=1.0/1.0/1.0, id464=1.0/1.0/1.0, id4640=1.0/1.0/1.0, id4641=1.0/1.0/1.0, id4642=1.0/1.0/1.0, id4643=1.0/1.0/1.0, id4644=1.0/1.0/1.0, id4645=1.0/1.0/1.0, id4646=1.0/1.0/1.0, id4647=1.0/1.0/1.0, id4648=1.0/1.0/1.0, id4649=1.0/1.0/1.0, id465=1.0/1.0/1.0, id4650=1.0/1.0/1.0, id4651=1.0/1.0/1.0, id4652=1.0/1.0/1.0, id4653=1.0/1.0/1.0, id4654=1.0/1.0/1.0, id4655=1.0/1.0/1.0, id4656=1.0/1.0/1.0, id4657=1.0/1.0/1.0, id4658=1.0/1.0/1.0, id4659=1.0/1.0/1.0, id466=1.0/1.0/1.0, id4660=1.0/1.0/1.0, id4661=1.0/1.0/1.0, id4662=1.0/1.0/1.0, id4663=1.0/1.0/1.0, id4664=1.0/1.0/1.0, id4665=1.0/1.0/1.0, id4666=1.0/1.0/1.0, id4667=1.0/1.0/1.0, id4668=1.0/1.0/1.0, id4669=1.0/1.0/1.0, id467=1.0/1.0/1.0, id4670=1.0/1.0/1.0, id4671=1.0/1.0/1.0, id4672=1.0/1.0/1.0, id4673=1.0/1.0/1.0, id4674=1.0/1.0/1.0, id4675=1.0/1.0/1.0, id4676=1.0/1.0/1.0, id4677=1.0/1.0/1.0, id4678=1.0/1.0/1.0, id4679=1.0/1.0/1.0, id468=1.0/1.0/1.0, id4680=1.0/1.0/1.0, id4681=1.0/1.0/1.0, id4682=1.0/1.0/1.0, id4683=1.0/1.0/1.0, id4684=1.0/1.0/1.0, id4685=1.0/1.0/1.0, id4686=1.0/1.0/1.0, id4687=1.0/1.0/1.0, id4688=1.0/1.0/1.0, id4689=1.0/1.0/1.0, id469=1.0/1.0/1.0, id4690=1.0/1.0/1.0, id4691=1.0/1.0/1.0, id4692=1.0/1.0/1.0, id4693=1.0/1.0/1.0, id4694=1.0/1.0/1.0, id4695=1.0/1.0/1.0, id4696=1.0/1.0/1.0, id4697=1.0/1.0/1.0, id4698=1.0/1.0/1.0, id4699=1.0/1.0/1.0, id47=1.0/1.0/1.0, id470=1.0/1.0/1.0, id4700=1.0/1.0/1.0, id4701=1.0/1.0/1.0, id4702=1.0/1.0/1.0, id4703=1.0/1.0/1.0, id4704=1.0/1.0/1.0, id4705=1.0/1.0/1.0, id4706=1.0/1.0/1.0, id4707=1.0/1.0/1.0, id4708=1.0/1.0/1.0, id4709=1.0/1.0/1.0, id471=1.0/1.0/1.0, id4710=1.0/1.0/1.0, id4711=1.0/1.0/1.0, id4712=1.0/1.0/1.0, id4713=1.0/1.0/1.0, id4714=1.0/1.0/1.0, id4715=1.0/1.0/1.0, id4716=1.0/1.0/1.0, id4717=1.0/1.0/1.0, id4718=1.0/1.0/1.0, id4719=1.0/1.0/1.0, id472=1.0/1.0/1.0, id4720=1.0/1.0/1.0, id4721=1.0/1.0/1.0, id4722=1.0/1.0/1.0, id4723=1.0/1.0/1.0, id4724=1.0/1.0/1.0, id4725=1.0/1.0/1.0, id4726=1.0/1.0/1.0, id4727=1.0/1.0/1.0, id4728=1.0/1.0/1.0, id4729=1.0/1.0/1.0, id473=1.0/1.0/1.0, id4730=1.0/1.0/1.0, id4731=1.0/1.0/1.0, id4732=1.0/1.0/1.0, id4733=1.0/1.0/1.0, id4734=1.0/1.0/1.0, id4735=1.0/1.0/1.0, id4736=1.0/1.0/1.0, id4737=1.0/1.0/1.0, id4738=1.0/1.0/1.0, id4739=1.0/1.0/1.0, id474=1.0/1.0/1.0, id4740=1.0/1.0/1.0, id4741=1.0/1.0/1.0, id4742=1.0/1.0/1.0, id4743=1.0/1.0/1.0, id4744=1.0/1.0/1.0, id4745=1.0/1.0/1.0, id4746=1.0/1.0/1.0, id4747=1.0/1.0/1.0, id4748=1.0/1.0/1.0, id4749=1.0/1.0/1.0, id475=1.0/1.0/1.0, id4750=1.0/1.0/1.0, id4751=1.0/1.0/1.0, id4752=1.0/1.0/1.0, id4753=1.0/1.0/1.0, id4754=1.0/1.0/1.0, id4755=1.0/1.0/1.0, id4756=1.0/1.0/1.0, id4757=1.0/1.0/1.0, id4758=1.0/1.0/1.0, id4759=1.0/1.0/1.0, id476=1.0/1.0/1.0, id4760=1.0/1.0/1.0, id4761=1.0/1.0/1.0, id4762=1.0/1.0/1.0, id4763=1.0/1.0/1.0, id4764=1.0/1.0/1.0, id4765=1.0/1.0/1.0, id4766=1.0/1.0/1.0, id4767=1.0/1.0/1.0, id4768=1.0/1.0/1.0, id4769=1.0/1.0/1.0, id477=1.0/1.0/1.0, id4770=1.0/1.0/1.0, id4771=1.0/1.0/1.0, id4772=1.0/1.0/1.0, id4773=1.0/1.0/1.0, id4774=1.0/1.0/1.0, id4775=1.0/1.0/1.0, id4776=1.0/1.0/1.0, id4777=1.0/1.0/1.0, id4778=1.0/1.0/1.0, id4779=1.0/1.0/1.0, id478=1.0/1.0/1.0, id4780=1.0/1.0/1.0, id4781=1.0/1.0/1.0, id4782=1.0/1.0/1.0, id4783=1.0/1.0/1.0, id4784=1.0/1.0/1.0, id4785=1.0/1.0/1.0, id4786=1.0/1.0/1.0, id4787=1.0/1.0/1.0, id4788=1.0/1.0/1.0, id4789=1.0/1.0/1.0, id479=1.0/1.0/1.0, id4790=1.0/1.0/1.0, id4791=1.0/1.0/1.0, id4792=1.0/1.0/1.0, id4793=1.0/1.0/1.0, id4794=1.0/1.0/1.0, id4795=1.0/1.0/1.0, id4796=1.0/1.0/1.0, id4797=1.0/1.0/1.0, id4798=1.0/1.0/1.0, id4799=1.0/1.0/1.0, id48=1.0/1.0/1.0, id480=1.0/1.0/1.0, id4800=1.0/1.0/1.0, id4801=1.0/1.0/1.0, id4802=1.0/1.0/1.0, id4803=1.0/1.0/1.0, id4804=1.0/1.0/1.0, id4805=1.0/1.0/1.0, id4806=1.0/1.0/1.0, id4807=1.0/1.0/1.0, id4808=1.0/1.0/1.0, id4809=1.0/1.0/1.0, id481=1.0/1.0/1.0, id4810=1.0/1.0/1.0, id4811=1.0/1.0/1.0, id4812=1.0/1.0/1.0, id4813=1.0/1.0/1.0, id4814=1.0/1.0/1.0, id4815=1.0/1.0/1.0, id4816=1.0/1.0/1.0, id4817=1.0/1.0/1.0, id4818=1.0/1.0/1.0, id4819=1.0/1.0/1.0, id482=1.0/1.0/1.0, id4820=1.0/1.0/1.0, id4821=1.0/1.0/1.0, id4822=1.0/1.0/1.0, id4823=1.0/1.0/1.0, id4824=1.0/1.0/1.0, id4825=1.0/1.0/1.0, id4826=1.0/1.0/1.0, id4827=1.0/1.0/1.0, id4828=1.0/1.0/1.0, id4829=1.0/1.0/1.0, id483=1.0/1.0/1.0, id4830=1.0/1.0/1.0, id4831=1.0/1.0/1.0, id4832=1.0/1.0/1.0, id4833=1.0/1.0/1.0, id4834=1.0/1.0/1.0, id4835=1.0/1.0/1.0, id4836=1.0/1.0/1.0, id4837=1.0/1.0/1.0, id4838=1.0/1.0/1.0, id4839=1.0/1.0/1.0, id484=1.0/1.0/1.0, id4840=1.0/1.0/1.0, id4841=1.0/1.0/1.0, id4842=1.0/1.0/1.0, id4843=1.0/1.0/1.0, id4844=1.0/1.0/1.0, id4845=1.0/1.0/1.0, id4846=1.0/1.0/1.0, id4847=1.0/1.0/1.0, id4848=1.0/1.0/1.0, id4849=1.0/1.0/1.0, id485=1.0/1.0/1.0, id4850=1.0/1.0/1.0, id4851=1.0/1.0/1.0, id4852=1.0/1.0/1.0, id4853=1.0/1.0/1.0, id4854=1.0/1.0/1.0, id4855=1.0/1.0/1.0, id4856=1.0/1.0/1.0, id4857=1.0/1.0/1.0, id4858=1.0/1.0/1.0, id4859=1.0/1.0/1.0, id486=1.0/1.0/1.0, id4860=1.0/1.0/1.0, id4861=1.0/1.0/1.0, id4862=1.0/1.0/1.0, id4863=1.0/1.0/1.0, id4864=1.0/1.0/1.0, id4865=1.0/1.0/1.0, id4866=1.0/1.0/1.0, id4867=1.0/1.0/1.0, id4868=1.0/1.0/1.0, id4869=1.0/1.0/1.0, id487=1.0/1.0/1.0, id4870=1.0/1.0/1.0, id4871=1.0/1.0/1.0, id4872=1.0/1.0/1.0, id4873=1.0/1.0/1.0, id4874=1.0/1.0/1.0, id4875=1.0/1.0/1.0, id4876=1.0/1.0/1.0, id4877=1.0/1.0/1.0, id4878=1.0/1.0/1.0, id4879=1.0/1.0/1.0, id488=1.0/1.0/1.0, id4880=1.0/1.0/1.0, id4881=1.0/1.0/1.0, id4882=1.0/1.0/1.0, id4883=1.0/1.0/1.0, id4884=1.0/1.0/1.0, id4885=1.0/1.0/1.0, id4886=1.0/1.0/1.0, id4887=1.0/1.0/1.0, id4888=1.0/1.0/1.0, id4889=1.0/1.0/1.0, id489=1.0/1.0/1.0, id4890=1.0/1.0/1.0, id4891=1.0/1.0/1.0, id4892=1.0/1.0/1.0, id4893=1.0/1.0/1.0, id4894=1.0/1.0/1.0, id4895=1.0/1.0/1.0, id4896=1.0/1.0/1.0, id4897=1.0/1.0/1.0, id4898=1.0/1.0/1.0, id4899=1.0/1.0/1.0, id49=1.0/1.0/1.0, id490=1.0/1.0/1.0, id4900=1.0/1.0/1.0, id4901=1.0/1.0/1.0, id4902=1.0/1.0/1.0, id4903=1.0/1.0/1.0, id4904=1.0/1.0/1.0, id4905=1.0/1.0/1.0, id4906=1.0/1.0/1.0, id4907=1.0/1.0/1.0, id4908=1.0/1.0/1.0, id4909=1.0/1.0/1.0, id491=1.0/1.0/1.0, id4910=1.0/1.0/1.0, id4911=1.0/1.0/1.0, id4912=1.0/1.0/1.0, id4913=1.0/1.0/1.0, id4914=1.0/1.0/1.0, id4915=1.0/1.0/1.0, id4916=1.0/1.0/1.0, id4917=1.0/1.0/1.0, id4918=1.0/1.0/1.0, id4919=1.0/1.0/1.0, id492=1.0/1.0/1.0, id4920=1.0/1.0/1.0, id4921=1.0/1.0/1.0, id4922=1.0/1.0/1.0, id4923=1.0/1.0/1.0, id4924=1.0/1.0/1.0, id4925=1.0/1.0/1.0, id4926=1.0/1.0/1.0, id4927=1.0/1.0/1.0, id4928=1.0/1.0/1.0, id4929=1.0/1.0/1.0, id493=1.0/1.0/1.0, id4930=1.0/1.0/1.0, id4931=1.0/1.0/1.0, id4932=1.0/1.0/1.0, id4933=1.0/1.0/1.0, id4934=1.0/1.0/1.0, id4935=1.0/1.0/1.0, id4936=1.0/1.0/1.0, id4937=1.0/1.0/1.0, id4938=1.0/1.0/1.0, id4939=1.0/1.0/1.0, id494=1.0/1.0/1.0, id4940=1.0/1.0/1.0, id4941=1.0/1.0/1.0, id4942=1.0/1.0/1.0, id4943=1.0/1.0/1.0, id4944=1.0/1.0/1.0, id4945=1.0/1.0/1.0, id4946=1.0/1.0/1.0, id4947=1.0/1.0/1.0, id4948=1.0/1.0/1.0, id4949=1.0/1.0/1.0, id495=1.0/1.0/1.0, id4950=1.0/1.0/1.0, id4951=1.0/1.0/1.0, id4952=1.0/1.0/1.0, id4953=1.0/1.0/1.0, id4954=1.0/1.0/1.0, id4955=1.0/1.0/1.0, id4956=1.0/1.0/1.0, id4957=1.0/1.0/1.0, id4958=1.0/1.0/1.0, id4959=1.0/1.0/1.0, id496=1.0/1.0/1.0, id4960=1.0/1.0/1.0, id4961=1.0/1.0/1.0, id4962=1.0/1.0/1.0, id4963=1.0/1.0/1.0, id4964=1.0/1.0/1.0, id4965=1.0/1.0/1.0, id4966=1.0/1.0/1.0, id4967=1.0/1.0/1.0, id4968=1.0/1.0/1.0, id4969=1.0/1.0/1.0, id497=1.0/1.0/1.0, id4970=1.0/1.0/1.0, id4971=1.0/1.0/1.0, id4972=1.0/1.0/1.0, id4973=1.0/1.0/1.0, id4974=1.0/1.0/1.0, id4975=1.0/1.0/1.0, id4976=1.0/1.0/1.0, id4977=1.0/1.0/1.0, id4978=1.0/1.0/1.0, id4979=1.0/1.0/1.0, id498=1.0/1.0/1.0, id4980=1.0/1.0/1.0, id4981=1.0/1.0/1.0, id4982=1.0/1.0/1.0, id4983=1.0/1.0/1.0, id4984=1.0/1.0/1.0, id4985=1.0/1.0/1.0, id4986=1.0/1.0/1.0, id4987=1.0/1.0/1.0, id4988=1.0/1.0/1.0, id4989=1.0/1.0/1.0, id499=1.0/1.0/1.0, id4990=1.0/1.0/1.0, id4991=1.0/1.0/1.0, id4992=1.0/1.0/1.0, id4993=1.0/1.0/1.0, id4994=1.0/1.0/1.0, id4995=1.0/1.0/1.0, id4996=1.0/1.0/1.0, id4997=1.0/1.0/1.0, id4998=1.0/1.0/1.0, id4999=1.0/1.0/1.0, id5=1.0/1.0/1.0, id50=1.0/1.0/1.0, id500=1.0/1.0/1.0, id5000=1.0/1.0/1.0, id5001=1.0/1.0/1.0, id5002=1.0/1.0/1.0, id5003=1.0/1.0/1.0, id5004=1.0/1.0/1.0, id5005=1.0/1.0/1.0, id5006=1.0/1.0/1.0, id5007=1.0/1.0/1.0, id5008=1.0/1.0/1.0, id5009=1.0/1.0/1.0, id501=1.0/1.0/1.0, id5010=1.0/1.0/1.0, id5011=1.0/1.0/1.0, id5012=1.0/1.0/1.0, id5013=1.0/1.0/1.0, id5014=1.0/1.0/1.0, id5015=1.0/1.0/1.0, id5016=1.0/1.0/1.0, id5017=1.0/1.0/1.0, id5018=1.0/1.0/1.0, id5019=1.0/1.0/1.0, id502=1.0/1.0/1.0, id5020=1.0/1.0/1.0, id5021=1.0/1.0/1.0, id5022=1.0/1.0/1.0, id5023=1.0/1.0/1.0, id5024=1.0/1.0/1.0, id5025=1.0/1.0/1.0, id5026=1.0/1.0/1.0, id5027=1.0/1.0/1.0, id5028=1.0/1.0/1.0, id5029=1.0/1.0/1.0, id503=1.0/1.0/1.0, id5030=1.0/1.0/1.0, id5031=1.0/1.0/1.0, id5032=1.0/1.0/1.0, id5033=1.0/1.0/1.0, id5034=1.0/1.0/1.0, id5035=1.0/1.0/1.0, id5036=1.0/1.0/1.0, id5037=1.0/1.0/1.0, id5038=1.0/1.0/1.0, id5039=1.0/1.0/1.0, id504=1.0/1.0/1.0, id5040=1.0/1.0/1.0, id5041=1.0/1.0/1.0, id5042=1.0/1.0/1.0, id5043=1.0/1.0/1.0, id5044=1.0/1.0/1.0, id5045=1.0/1.0/1.0, id5046=1.0/1.0/1.0, id5047=1.0/1.0/1.0, id5048=1.0/1.0/1.0, id5049=1.0/1.0/1.0, id505=1.0/1.0/1.0, id5050=1.0/1.0/1.0, id5051=1.0/1.0/1.0, id5052=1.0/1.0/1.0, id5053=1.0/1.0/1.0, id5054=1.0/1.0/1.0, id5055=1.0/1.0/1.0, id5056=1.0/1.0/1.0, id5057=1.0/1.0/1.0, id5058=1.0/1.0/1.0, id5059=1.0/1.0/1.0, id506=1.0/1.0/1.0, id5060=1.0/1.0/1.0, id5061=1.0/1.0/1.0, id5062=1.0/1.0/1.0, id5063=1.0/1.0/1.0, id5064=1.0/1.0/1.0, id5065=1.0/1.0/1.0, id5066=1.0/1.0/1.0, id5067=1.0/1.0/1.0, id5068=1.0/1.0/1.0, id5069=1.0/1.0/1.0, id507=1.0/1.0/1.0, id5070=1.0/1.0/1.0, id5071=1.0/1.0/1.0, id5072=1.0/1.0/1.0, id5073=1.0/1.0/1.0, id5074=1.0/1.0/1.0, id5075=1.0/1.0/1.0, id5076=1.0/1.0/1.0, id5077=1.0/1.0/1.0, id5078=1.0/1.0/1.0, id5079=1.0/1.0/1.0, id508=1.0/1.0/1.0, id5080=1.0/1.0/1.0, id5081=1.0/1.0/1.0, id5082=1.0/1.0/1.0, id5083=1.0/1.0/1.0, id5084=1.0/1.0/1.0, id5085=1.0/1.0/1.0, id5086=1.0/1.0/1.0, id5087=1.0/1.0/1.0, id5088=1.0/1.0/1.0, id5089=1.0/1.0/1.0, id509=1.0/1.0/1.0, id5090=1.0/1.0/1.0, id5091=1.0/1.0/1.0, id5092=1.0/1.0/1.0, id5093=1.0/1.0/1.0, id5094=1.0/1.0/1.0, id5095=1.0/1.0/1.0, id5096=1.0/1.0/1.0, id5097=1.0/1.0/1.0, id5098=1.0/1.0/1.0, id5099=1.0/1.0/1.0, id51=1.0/1.0/1.0, id510=1.0/1.0/1.0, id5100=1.0/1.0/1.0, id5101=1.0/1.0/1.0, id5102=1.0/1.0/1.0, id5103=1.0/1.0/1.0, id5104=1.0/1.0/1.0, id5105=1.0/1.0/1.0, id5106=1.0/1.0/1.0, id5107=1.0/1.0/1.0, id5108=1.0/1.0/1.0, id5109=1.0/1.0/1.0, id511=1.0/1.0/1.0, id5110=1.0/1.0/1.0, id5111=1.0/1.0/1.0, id5112=1.0/1.0/1.0, id5113=1.0/1.0/1.0, id5114=1.0/1.0/1.0, id5115=1.0/1.0/1.0, id5116=1.0/1.0/1.0, id5117=1.0/1.0/1.0, id5118=1.0/1.0/1.0, id5119=1.0/1.0/1.0, id512=1.0/1.0/1.0, id5120=1.0/1.0/1.0, id5121=1.0/1.0/1.0, id5122=1.0/1.0/1.0, id5123=1.0/1.0/1.0, id5124=1.0/1.0/1.0, id5125=1.0/1.0/1.0, id5126=1.0/1.0/1.0, id5127=1.0/1.0/1.0, id5128=1.0/1.0/1.0, id5129=1.0/1.0/1.0, id513=1.0/1.0/1.0, id5130=1.0/1.0/1.0, id5131=1.0/1.0/1.0, id5132=1.0/1.0/1.0, id5133=1.0/1.0/1.0, id5134=1.0/1.0/1.0, id5135=1.0/1.0/1.0, id5136=1.0/1.0/1.0, id5137=1.0/1.0/1.0, id5138=1.0/1.0/1.0, id5139=1.0/1.0/1.0, id514=1.0/1.0/1.0, id5140=1.0/1.0/1.0, id5141=1.0/1.0/1.0, id5142=1.0/1.0/1.0, id5143=1.0/1.0/1.0, id5144=1.0/1.0/1.0, id5145=1.0/1.0/1.0, id5146=1.0/1.0/1.0, id5147=1.0/1.0/1.0, id5148=1.0/1.0/1.0, id5149=1.0/1.0/1.0, id515=1.0/1.0/1.0, id5150=1.0/1.0/1.0, id5151=1.0/1.0/1.0, id5152=1.0/1.0/1.0, id5153=1.0/1.0/1.0, id5154=1.0/1.0/1.0, id5155=1.0/1.0/1.0, id5156=1.0/1.0/1.0, id5157=1.0/1.0/1.0, id5158=1.0/1.0/1.0, id5159=1.0/1.0/1.0, id516=1.0/1.0/1.0, id5160=1.0/1.0/1.0, id5161=1.0/1.0/1.0, id5162=1.0/1.0/1.0, id5163=1.0/1.0/1.0, id5164=1.0/1.0/1.0, id5165=1.0/1.0/1.0, id5166=1.0/1.0/1.0, id5167=1.0/1.0/1.0, id5168=1.0/1.0/1.0, id5169=1.0/1.0/1.0, id517=1.0/1.0/1.0, id5170=1.0/1.0/1.0, id5171=1.0/1.0/1.0, id5172=1.0/1.0/1.0, id5173=1.0/1.0/1.0, id5174=1.0/1.0/1.0, id5175=1.0/1.0/1.0, id5176=1.0/1.0/1.0, id5177=1.0/1.0/1.0, id5178=1.0/1.0/1.0, id5179=1.0/1.0/1.0, id518=1.0/1.0/1.0, id5180=1.0/1.0/1.0, id5181=1.0/1.0/1.0, id5182=1.0/1.0/1.0, id5183=1.0/1.0/1.0, id5184=1.0/1.0/1.0, id5185=1.0/1.0/1.0, id5186=1.0/1.0/1.0, id5187=1.0/1.0/1.0, id5188=1.0/1.0/1.0, id5189=1.0/1.0/1.0, id519=1.0/1.0/1.0, id5190=1.0/1.0/1.0, id5191=1.0/1.0/1.0, id5192=1.0/1.0/1.0, id5193=1.0/1.0/1.0, id5194=1.0/1.0/1.0, id5195=1.0/1.0/1.0, id5196=1.0/1.0/1.0, id5197=1.0/1.0/1.0, id5198=1.0/1.0/1.0, id5199=1.0/1.0/1.0, id52=1.0/1.0/1.0, id520=1.0/1.0/1.0, id5200=1.0/1.0/1.0, id5201=1.0/1.0/1.0, id5202=1.0/1.0/1.0, id5203=1.0/1.0/1.0, id5204=1.0/1.0/1.0, id5205=1.0/1.0/1.0, id5206=1.0/1.0/1.0, id5207=1.0/1.0/1.0, id5208=1.0/1.0/1.0, id5209=1.0/1.0/1.0, id521=1.0/1.0/1.0, id5210=1.0/1.0/1.0, id5211=1.0/1.0/1.0, id5212=1.0/1.0/1.0, id5213=1.0/1.0/1.0, id5214=1.0/1.0/1.0, id5215=1.0/1.0/1.0, id5216=1.0/1.0/1.0, id5217=1.0/1.0/1.0, id5218=1.0/1.0/1.0, id5219=1.0/1.0/1.0, id522=1.0/1.0/1.0, id5220=1.0/1.0/1.0, id5221=1.0/1.0/1.0, id5222=1.0/1.0/1.0, id5223=1.0/1.0/1.0, id5224=1.0/1.0/1.0, id5225=1.0/1.0/1.0, id5226=1.0/1.0/1.0, id5227=1.0/1.0/1.0, id5228=1.0/1.0/1.0, id5229=1.0/1.0/1.0, id523=1.0/1.0/1.0, id5230=1.0/1.0/1.0, id5231=1.0/1.0/1.0, id5232=1.0/1.0/1.0, id5233=1.0/1.0/1.0, id5234=1.0/1.0/1.0, id5235=1.0/1.0/1.0, id5236=1.0/1.0/1.0, id5237=1.0/1.0/1.0, id5238=1.0/1.0/1.0, id5239=1.0/1.0/1.0, id524=1.0/1.0/1.0, id5240=1.0/1.0/1.0, id5241=1.0/1.0/1.0, id5242=1.0/1.0/1.0, id5243=1.0/1.0/1.0, id5244=1.0/1.0/1.0, id5245=1.0/1.0/1.0, id5246=1.0/1.0/1.0, id5247=1.0/1.0/1.0, id5248=1.0/1.0/1.0, id5249=1.0/1.0/1.0, id525=1.0/1.0/1.0, id5250=1.0/1.0/1.0, id5251=1.0/1.0/1.0, id5252=1.0/1.0/1.0, id5253=1.0/1.0/1.0, id5254=1.0/1.0/1.0, id5255=1.0/1.0/1.0, id5256=1.0/1.0/1.0, id5257=1.0/1.0/1.0, id5258=1.0/1.0/1.0, id5259=1.0/1.0/1.0, id526=1.0/1.0/1.0, id5260=1.0/1.0/1.0, id5261=1.0/1.0/1.0, id5262=1.0/1.0/1.0, id5263=1.0/1.0/1.0, id5264=1.0/1.0/1.0, id5265=1.0/1.0/1.0, id5266=1.0/1.0/1.0, id5267=1.0/1.0/1.0, id5268=1.0/1.0/1.0, id5269=1.0/1.0/1.0, id527=1.0/1.0/1.0, id5270=1.0/1.0/1.0, id5271=1.0/1.0/1.0, id5272=1.0/1.0/1.0, id5273=1.0/1.0/1.0, id5274=1.0/1.0/1.0, id5275=1.0/1.0/1.0, id5276=1.0/1.0/1.0, id5277=1.0/1.0/1.0, id5278=1.0/1.0/1.0, id5279=1.0/1.0/1.0, id528=1.0/1.0/1.0, id5280=1.0/1.0/1.0, id5281=1.0/1.0/1.0, id5282=1.0/1.0/1.0, id5283=1.0/1.0/1.0, id5284=1.0/1.0/1.0, id5285=1.0/1.0/1.0, id5286=1.0/1.0/1.0, id5287=1.0/1.0/1.0, id5288=1.0/1.0/1.0, id5289=1.0/1.0/1.0, id529=1.0/1.0/1.0, id5290=1.0/1.0/1.0, id5291=1.0/1.0/1.0, id5292=1.0/1.0/1.0, id5293=1.0/1.0/1.0, id5294=1.0/1.0/1.0, id5295=1.0/1.0/1.0, id5296=1.0/1.0/1.0, id5297=1.0/1.0/1.0, id5298=1.0/1.0/1.0, id5299=1.0/1.0/1.0, id53=1.0/1.0/1.0, id530=1.0/1.0/1.0, id5300=1.0/1.0/1.0, id5301=1.0/1.0/1.0, id5302=1.0/1.0/1.0, id5303=1.0/1.0/1.0, id5304=1.0/1.0/1.0, id5305=1.0/1.0/1.0, id5306=1.0/1.0/1.0, id5307=1.0/1.0/1.0, id5308=1.0/1.0/1.0, id5309=1.0/1.0/1.0, id531=1.0/1.0/1.0, id5310=1.0/1.0/1.0, id5311=1.0/1.0/1.0, id5312=1.0/1.0/1.0, id5313=1.0/1.0/1.0, id5314=1.0/1.0/1.0, id5315=1.0/1.0/1.0, id5316=1.0/1.0/1.0, id5317=1.0/1.0/1.0, id5318=1.0/1.0/1.0, id5319=1.0/1.0/1.0, id532=1.0/1.0/1.0, id5320=1.0/1.0/1.0, id5321=1.0/1.0/1.0, id5322=1.0/1.0/1.0, id5323=1.0/1.0/1.0, id5324=1.0/1.0/1.0, id5325=1.0/1.0/1.0, id5326=1.0/1.0/1.0, id5327=1.0/1.0/1.0, id5328=1.0/1.0/1.0, id5329=1.0/1.0/1.0, id533=1.0/1.0/1.0, id5330=1.0/1.0/1.0, id5331=1.0/1.0/1.0, id5332=1.0/1.0/1.0, id5333=1.0/1.0/1.0, id5334=1.0/1.0/1.0, id5335=1.0/1.0/1.0, id5336=1.0/1.0/1.0, id5337=1.0/1.0/1.0, id5338=1.0/1.0/1.0, id5339=1.0/1.0/1.0, id534=1.0/1.0/1.0, id5340=1.0/1.0/1.0, id5341=1.0/1.0/1.0, id5342=1.0/1.0/1.0, id5343=1.0/1.0/1.0, id5344=1.0/1.0/1.0, id5345=1.0/1.0/1.0, id5346=1.0/1.0/1.0, id5347=1.0/1.0/1.0, id5348=1.0/1.0/1.0, id5349=1.0/1.0/1.0, id535=1.0/1.0/1.0, id5350=1.0/1.0/1.0, id5351=1.0/1.0/1.0, id5352=1.0/1.0/1.0, id5353=1.0/1.0/1.0, id5354=1.0/1.0/1.0, id5355=1.0/1.0/1.0, id5356=1.0/1.0/1.0, id5357=1.0/1.0/1.0, id5358=1.0/1.0/1.0, id5359=1.0/1.0/1.0, id536=1.0/1.0/1.0, id5360=1.0/1.0/1.0, id5361=1.0/1.0/1.0, id5362=1.0/1.0/1.0, id5363=1.0/1.0/1.0, id5364=1.0/1.0/1.0, id5365=1.0/1.0/1.0, id5366=1.0/1.0/1.0, id5367=1.0/1.0/1.0, id5368=1.0/1.0/1.0, id5369=1.0/1.0/1.0, id537=1.0/1.0/1.0, id5370=1.0/1.0/1.0, id5371=1.0/1.0/1.0, id5372=1.0/1.0/1.0, id5373=1.0/1.0/1.0, id5374=1.0/1.0/1.0, id5375=1.0/1.0/1.0, id5376=1.0/1.0/1.0, id5377=1.0/1.0/1.0, id5378=1.0/1.0/1.0, id5379=1.0/1.0/1.0, id538=1.0/1.0/1.0, id5380=1.0/1.0/1.0, id5381=1.0/1.0/1.0, id5382=1.0/1.0/1.0, id5383=1.0/1.0/1.0, id5384=1.0/1.0/1.0, id5385=1.0/1.0/1.0, id5386=1.0/1.0/1.0, id5387=1.0/1.0/1.0, id5388=1.0/1.0/1.0, id5389=1.0/1.0/1.0, id539=1.0/1.0/1.0, id5390=1.0/1.0/1.0, id5391=1.0/1.0/1.0, id5392=1.0/1.0/1.0, id5393=1.0/1.0/1.0, id5394=1.0/1.0/1.0, id5395=1.0/1.0/1.0, id5396=1.0/1.0/1.0, id5397=1.0/1.0/1.0, id5398=1.0/1.0/1.0, id5399=1.0/1.0/1.0, id54=1.0/1.0/1.0, id540=1.0/1.0/1.0, id5400=1.0/1.0/1.0, id5401=1.0/1.0/1.0, id5402=1.0/1.0/1.0, id5403=1.0/1.0/1.0, id5404=1.0/1.0/1.0, id5405=1.0/1.0/1.0, id5406=1.0/1.0/1.0, id5407=1.0/1.0/1.0, id5408=1.0/1.0/1.0, id5409=1.0/1.0/1.0, id541=1.0/1.0/1.0, id5410=1.0/1.0/1.0, id5411=1.0/1.0/1.0, id5412=1.0/1.0/1.0, id5413=1.0/1.0/1.0, id5414=1.0/1.0/1.0, id5415=1.0/1.0/1.0, id5416=1.0/1.0/1.0, id5417=1.0/1.0/1.0, id5418=1.0/1.0/1.0, id5419=1.0/1.0/1.0, id542=1.0/1.0/1.0, id5420=1.0/1.0/1.0, id5421=1.0/1.0/1.0, id5422=1.0/1.0/1.0, id5423=1.0/1.0/1.0, id5424=1.0/1.0/1.0, id5425=1.0/1.0/1.0, id5426=1.0/1.0/1.0, id5427=1.0/1.0/1.0, id5428=1.0/1.0/1.0, id5429=1.0/1.0/1.0, id543=1.0/1.0/1.0, id5430=1.0/1.0/1.0, id5431=1.0/1.0/1.0, id5432=1.0/1.0/1.0, id5433=1.0/1.0/1.0, id5434=1.0/1.0/1.0, id5435=1.0/1.0/1.0, id5436=1.0/1.0/1.0, id5437=1.0/1.0/1.0, id5438=1.0/1.0/1.0, id5439=1.0/1.0/1.0, id544=1.0/1.0/1.0, id5440=1.0/1.0/1.0, id5441=1.0/1.0/1.0, id5442=1.0/1.0/1.0, id5443=1.0/1.0/1.0, id5444=1.0/1.0/1.0, id5445=1.0/1.0/1.0, id5446=1.0/1.0/1.0, id5447=1.0/1.0/1.0, id5448=1.0/1.0/1.0, id5449=1.0/1.0/1.0, id545=1.0/1.0/1.0, id5450=1.0/1.0/1.0, id5451=1.0/1.0/1.0, id5452=1.0/1.0/1.0, id5453=1.0/1.0/1.0, id5454=1.0/1.0/1.0, id5455=1.0/1.0/1.0, id5456=1.0/1.0/1.0, id5457=1.0/1.0/1.0, id5458=1.0/1.0/1.0, id5459=1.0/1.0/1.0, id546=1.0/1.0/1.0, id5460=1.0/1.0/1.0, id5461=1.0/1.0/1.0, id5462=1.0/1.0/1.0, id5463=1.0/1.0/1.0, id5464=1.0/1.0/1.0, id5465=1.0/1.0/1.0, id5466=1.0/1.0/1.0, id5467=1.0/1.0/1.0, id5468=1.0/1.0/1.0, id5469=1.0/1.0/1.0, id547=1.0/1.0/1.0, id5470=1.0/1.0/1.0, id5471=1.0/1.0/1.0, id5472=1.0/1.0/1.0, id5473=1.0/1.0/1.0, id5474=1.0/1.0/1.0, id5475=1.0/1.0/1.0, id5476=1.0/1.0/1.0, id5477=1.0/1.0/1.0, id5478=1.0/1.0/1.0, id5479=1.0/1.0/1.0, id548=1.0/1.0/1.0, id5480=1.0/1.0/1.0, id5481=1.0/1.0/1.0, id5482=1.0/1.0/1.0, id5483=1.0/1.0/1.0, id5484=1.0/1.0/1.0, id5485=1.0/1.0/1.0, id5486=1.0/1.0/1.0, id5487=1.0/1.0/1.0, id5488=1.0/1.0/1.0, id5489=1.0/1.0/1.0, id549=1.0/1.0/1.0, id5490=1.0/1.0/1.0, id5491=1.0/1.0/1.0, id5492=1.0/1.0/1.0, id5493=1.0/1.0/1.0, id5494=1.0/1.0/1.0, id5495=1.0/1.0/1.0, id5496=1.0/1.0/1.0, id5497=1.0/1.0/1.0, id5498=1.0/1.0/1.0, id5499=1.0/1.0/1.0, id55=1.0/1.0/1.0, id550=1.0/1.0/1.0, id5500=1.0/1.0/1.0, id5501=1.0/1.0/1.0, id5502=1.0/1.0/1.0, id5503=1.0/1.0/1.0, id5504=1.0/1.0/1.0, id5505=1.0/1.0/1.0, id5506=1.0/1.0/1.0, id5507=1.0/1.0/1.0, id5508=1.0/1.0/1.0, id5509=1.0/1.0/1.0, id551=1.0/1.0/1.0, id5510=1.0/1.0/1.0, id5511=1.0/1.0/1.0, id5512=1.0/1.0/1.0, id5513=1.0/1.0/1.0, id5514=1.0/1.0/1.0, id5515=1.0/1.0/1.0, id5516=1.0/1.0/1.0, id5517=1.0/1.0/1.0, id5518=1.0/1.0/1.0, id5519=1.0/1.0/1.0, id552=1.0/1.0/1.0, id5520=1.0/1.0/1.0, id5521=1.0/1.0/1.0, id5522=1.0/1.0/1.0, id5523=1.0/1.0/1.0, id5524=1.0/1.0/1.0, id5525=1.0/1.0/1.0, id5526=1.0/1.0/1.0, id5527=1.0/1.0/1.0, id5528=1.0/1.0/1.0, id5529=1.0/1.0/1.0, id553=1.0/1.0/1.0, id5530=1.0/1.0/1.0, id5531=1.0/1.0/1.0, id5532=1.0/1.0/1.0, id5533=1.0/1.0/1.0, id5534=1.0/1.0/1.0, id5535=1.0/1.0/1.0, id5536=1.0/1.0/1.0, id5537=1.0/1.0/1.0, id5538=1.0/1.0/1.0, id5539=1.0/1.0/1.0, id554=1.0/1.0/1.0, id5540=1.0/1.0/1.0, id5541=1.0/1.0/1.0, id5542=1.0/1.0/1.0, id5543=1.0/1.0/1.0, id5544=1.0/1.0/1.0, id5545=1.0/1.0/1.0, id5546=1.0/1.0/1.0, id5547=1.0/1.0/1.0, id5548=1.0/1.0/1.0, id5549=1.0/1.0/1.0, id555=1.0/1.0/1.0, id5550=1.0/1.0/1.0, id5551=1.0/1.0/1.0, id5552=1.0/1.0/1.0, id5553=1.0/1.0/1.0, id5554=1.0/1.0/1.0, id5555=1.0/1.0/1.0, id5556=1.0/1.0/1.0, id5557=1.0/1.0/1.0, id5558=1.0/1.0/1.0, id5559=1.0/1.0/1.0, id556=1.0/1.0/1.0, id5560=1.0/1.0/1.0, id5561=1.0/1.0/1.0, id5562=1.0/1.0/1.0, id5563=1.0/1.0/1.0, id5564=1.0/1.0/1.0, id5565=1.0/1.0/1.0, id5566=1.0/1.0/1.0, id5567=1.0/1.0/1.0, id5568=1.0/1.0/1.0, id5569=1.0/1.0/1.0, id557=1.0/1.0/1.0, id5570=1.0/1.0/1.0, id5571=1.0/1.0/1.0, id5572=1.0/1.0/1.0, id5573=1.0/1.0/1.0, id5574=1.0/1.0/1.0, id5575=1.0/1.0/1.0, id5576=1.0/1.0/1.0, id5577=1.0/1.0/1.0, id5578=1.0/1.0/1.0, id5579=1.0/1.0/1.0, id558=1.0/1.0/1.0, id5580=1.0/1.0/1.0, id5581=1.0/1.0/1.0, id5582=1.0/1.0/1.0, id5583=1.0/1.0/1.0, id5584=1.0/1.0/1.0, id5585=1.0/1.0/1.0, id5586=1.0/1.0/1.0, id5587=1.0/1.0/1.0, id5588=1.0/1.0/1.0, id5589=1.0/1.0/1.0, id559=1.0/1.0/1.0, id5590=1.0/1.0/1.0, id5591=1.0/1.0/1.0, id5592=1.0/1.0/1.0, id5593=1.0/1.0/1.0, id5594=1.0/1.0/1.0, id5595=1.0/1.0/1.0, id5596=1.0/1.0/1.0, id5597=1.0/1.0/1.0, id5598=1.0/1.0/1.0, id5599=1.0/1.0/1.0, id56=1.0/1.0/1.0, id560=1.0/1.0/1.0, id5600=1.0/1.0/1.0, id5601=1.0/1.0/1.0, id5602=1.0/1.0/1.0, id5603=1.0/1.0/1.0, id5604=1.0/1.0/1.0, id5605=1.0/1.0/1.0, id5606=1.0/1.0/1.0, id5607=1.0/1.0/1.0, id5608=1.0/1.0/1.0, id5609=1.0/1.0/1.0, id561=1.0/1.0/1.0, id5610=1.0/1.0/1.0, id5611=1.0/1.0/1.0, id5612=1.0/1.0/1.0, id5613=1.0/1.0/1.0, id5614=1.0/1.0/1.0, id5615=1.0/1.0/1.0, id5616=1.0/1.0/1.0, id5617=1.0/1.0/1.0, id5618=1.0/1.0/1.0, id5619=1.0/1.0/1.0, id562=1.0/1.0/1.0, id5620=1.0/1.0/1.0, id5621=1.0/1.0/1.0, id5622=1.0/1.0/1.0, id5623=1.0/1.0/1.0, id5624=1.0/1.0/1.0, id5625=1.0/1.0/1.0, id5626=1.0/1.0/1.0, id5627=1.0/1.0/1.0, id5628=1.0/1.0/1.0, id5629=1.0/1.0/1.0, id563=1.0/1.0/1.0, id5630=1.0/1.0/1.0, id5631=1.0/1.0/1.0, id5632=1.0/1.0/1.0, id5633=1.0/1.0/1.0, id5634=1.0/1.0/1.0, id5635=1.0/1.0/1.0, id5636=1.0/1.0/1.0, id5637=1.0/1.0/1.0, id5638=1.0/1.0/1.0, id5639=1.0/1.0/1.0, id564=1.0/1.0/1.0, id5640=1.0/1.0/1.0, id5641=1.0/1.0/1.0, id5642=1.0/1.0/1.0, id5643=1.0/1.0/1.0, id5644=1.0/1.0/1.0, id5645=1.0/1.0/1.0, id5646=1.0/1.0/1.0, id5647=1.0/1.0/1.0, id5648=1.0/1.0/1.0, id5649=1.0/1.0/1.0, id565=1.0/1.0/1.0, id5650=1.0/1.0/1.0, id5651=1.0/1.0/1.0, id5652=1.0/1.0/1.0, id5653=1.0/1.0/1.0, id5654=1.0/1.0/1.0, id5655=1.0/1.0/1.0, id5656=1.0/1.0/1.0, id5657=1.0/1.0/1.0, id5658=1.0/1.0/1.0, id5659=1.0/1.0/1.0, id566=1.0/1.0/1.0, id5660=1.0/1.0/1.0, id5661=1.0/1.0/1.0, id5662=1.0/1.0/1.0, id5663=1.0/1.0/1.0, id5664=1.0/1.0/1.0, id5665=1.0/1.0/1.0, id5666=1.0/1.0/1.0, id5667=1.0/1.0/1.0, id5668=1.0/1.0/1.0, id5669=1.0/1.0/1.0, id567=1.0/1.0/1.0, id5670=1.0/1.0/1.0, id5671=1.0/1.0/1.0, id5672=1.0/1.0/1.0, id5673=1.0/1.0/1.0, id5674=1.0/1.0/1.0, id5675=1.0/1.0/1.0, id5676=1.0/1.0/1.0, id5677=1.0/1.0/1.0, id5678=1.0/1.0/1.0, id5679=1.0/1.0/1.0, id568=1.0/1.0/1.0, id5680=1.0/1.0/1.0, id5681=1.0/1.0/1.0, id5682=1.0/1.0/1.0, id5683=1.0/1.0/1.0, id5684=1.0/1.0/1.0, id5685=1.0/1.0/1.0, id5686=1.0/1.0/1.0, id5687=1.0/1.0/1.0, id5688=1.0/1.0/1.0, id5689=1.0/1.0/1.0, id569=1.0/1.0/1.0, id5690=1.0/1.0/1.0, id5691=1.0/1.0/1.0, id5692=1.0/1.0/1.0, id5693=1.0/1.0/1.0, id5694=1.0/1.0/1.0, id5695=1.0/1.0/1.0, id5696=1.0/1.0/1.0, id5697=1.0/1.0/1.0, id5698=1.0/1.0/1.0, id5699=1.0/1.0/1.0, id57=1.0/1.0/1.0, id570=1.0/1.0/1.0, id5700=1.0/1.0/1.0, id5701=1.0/1.0/1.0, id5702=1.0/1.0/1.0, id5703=1.0/1.0/1.0, id5704=1.0/1.0/1.0, id5705=1.0/1.0/1.0, id5706=1.0/1.0/1.0, id5707=1.0/1.0/1.0, id5708=1.0/1.0/1.0, id5709=1.0/1.0/1.0, id571=1.0/1.0/1.0, id5710=1.0/1.0/1.0, id5711=1.0/1.0/1.0, id5712=1.0/1.0/1.0, id5713=1.0/1.0/1.0, id5714=1.0/1.0/1.0, id5715=1.0/1.0/1.0, id5716=1.0/1.0/1.0, id5717=1.0/1.0/1.0, id5718=1.0/1.0/1.0, id5719=1.0/1.0/1.0, id572=1.0/1.0/1.0, id5720=1.0/1.0/1.0, id5721=1.0/1.0/1.0, id5722=1.0/1.0/1.0, id5723=1.0/1.0/1.0, id5724=1.0/1.0/1.0, id5725=1.0/1.0/1.0, id5726=1.0/1.0/1.0, id5727=1.0/1.0/1.0, id5728=1.0/1.0/1.0, id5729=1.0/1.0/1.0, id573=1.0/1.0/1.0, id5730=1.0/1.0/1.0, id5731=1.0/1.0/1.0, id5732=1.0/1.0/1.0, id5733=1.0/1.0/1.0, id5734=1.0/1.0/1.0, id5735=1.0/1.0/1.0, id5736=1.0/1.0/1.0, id5737=1.0/1.0/1.0, id5738=1.0/1.0/1.0, id5739=1.0/1.0/1.0, id574=1.0/1.0/1.0, id5740=1.0/1.0/1.0, id5741=1.0/1.0/1.0, id5742=1.0/1.0/1.0, id5743=1.0/1.0/1.0, id5744=1.0/1.0/1.0, id5745=1.0/1.0/1.0, id5746=1.0/1.0/1.0, id5747=1.0/1.0/1.0, id5748=1.0/1.0/1.0, id5749=1.0/1.0/1.0, id575=1.0/1.0/1.0, id5750=1.0/1.0/1.0, id5751=1.0/1.0/1.0, id5752=1.0/1.0/1.0, id5753=1.0/1.0/1.0, id5754=1.0/1.0/1.0, id5755=1.0/1.0/1.0, id5756=1.0/1.0/1.0, id5757=1.0/1.0/1.0, id5758=1.0/1.0/1.0, id5759=1.0/1.0/1.0, id576=1.0/1.0/1.0, id5760=1.0/1.0/1.0, id5761=1.0/1.0/1.0, id5762=1.0/1.0/1.0, id5763=1.0/1.0/1.0, id5764=1.0/1.0/1.0, id5765=1.0/1.0/1.0, id5766=1.0/1.0/1.0, id5767=1.0/1.0/1.0, id5768=1.0/1.0/1.0, id5769=1.0/1.0/1.0, id577=1.0/1.0/1.0, id5770=1.0/1.0/1.0, id5771=1.0/1.0/1.0, id5772=1.0/1.0/1.0, id5773=1.0/1.0/1.0, id5774=1.0/1.0/1.0, id5775=1.0/1.0/1.0, id5776=1.0/1.0/1.0, id5777=1.0/1.0/1.0, id5778=1.0/1.0/1.0, id5779=1.0/1.0/1.0, id578=1.0/1.0/1.0, id5780=1.0/1.0/1.0, id5781=1.0/1.0/1.0, id5782=1.0/1.0/1.0, id5783=1.0/1.0/1.0, id5784=1.0/1.0/1.0, id5785=1.0/1.0/1.0, id5786=1.0/1.0/1.0, id5787=1.0/1.0/1.0, id5788=1.0/1.0/1.0, id5789=1.0/1.0/1.0, id579=1.0/1.0/1.0, id5790=1.0/1.0/1.0, id5791=1.0/1.0/1.0, id5792=1.0/1.0/1.0, id5793=1.0/1.0/1.0, id5794=1.0/1.0/1.0, id5795=1.0/1.0/1.0, id5796=1.0/1.0/1.0, id5797=1.0/1.0/1.0, id5798=1.0/1.0/1.0, id5799=1.0/1.0/1.0, id58=1.0/1.0/1.0, id580=1.0/1.0/1.0, id5800=1.0/1.0/1.0, id5801=1.0/1.0/1.0, id5802=1.0/1.0/1.0, id5803=1.0/1.0/1.0, id5804=1.0/1.0/1.0, id5805=1.0/1.0/1.0, id5806=1.0/1.0/1.0, id5807=1.0/1.0/1.0, id5808=1.0/1.0/1.0, id5809=1.0/1.0/1.0, id581=1.0/1.0/1.0, id5810=1.0/1.0/1.0, id5811=1.0/1.0/1.0, id5812=1.0/1.0/1.0, id5813=1.0/1.0/1.0, id5814=1.0/1.0/1.0, id5815=1.0/1.0/1.0, id5816=1.0/1.0/1.0, id5817=1.0/1.0/1.0, id5818=1.0/1.0/1.0, id5819=1.0/1.0/1.0, id582=1.0/1.0/1.0, id5820=1.0/1.0/1.0, id5821=1.0/1.0/1.0, id5822=1.0/1.0/1.0, id5823=1.0/1.0/1.0, id5824=1.0/1.0/1.0, id5825=1.0/1.0/1.0, id5826=1.0/1.0/1.0, id5827=1.0/1.0/1.0, id5828=1.0/1.0/1.0, id5829=1.0/1.0/1.0, id583=1.0/1.0/1.0, id5830=1.0/1.0/1.0, id5831=1.0/1.0/1.0, id5832=1.0/1.0/1.0, id5833=1.0/1.0/1.0, id5834=1.0/1.0/1.0, id5835=1.0/1.0/1.0, id5836=1.0/1.0/1.0, id5837=1.0/1.0/1.0, id5838=1.0/1.0/1.0, id5839=1.0/1.0/1.0, id584=1.0/1.0/1.0, id5840=1.0/1.0/1.0, id5841=1.0/1.0/1.0, id5842=1.0/1.0/1.0, id5843=1.0/1.0/1.0, id5844=1.0/1.0/1.0, id5845=1.0/1.0/1.0, id5846=1.0/1.0/1.0, id5847=1.0/1.0/1.0, id5848=1.0/1.0/1.0, id5849=1.0/1.0/1.0, id585=1.0/1.0/1.0, id5850=1.0/1.0/1.0, id5851=1.0/1.0/1.0, id5852=1.0/1.0/1.0, id5853=1.0/1.0/1.0, id5854=1.0/1.0/1.0, id5855=1.0/1.0/1.0, id5856=1.0/1.0/1.0, id5857=1.0/1.0/1.0, id5858=1.0/1.0/1.0, id5859=1.0/1.0/1.0, id586=1.0/1.0/1.0, id5860=1.0/1.0/1.0, id5861=1.0/1.0/1.0, id5862=1.0/1.0/1.0, id5863=1.0/1.0/1.0, id5864=1.0/1.0/1.0, id5865=1.0/1.0/1.0, id5866=1.0/1.0/1.0, id5867=1.0/1.0/1.0, id5868=1.0/1.0/1.0, id5869=1.0/1.0/1.0, id587=1.0/1.0/1.0, id5870=1.0/1.0/1.0, id5871=1.0/1.0/1.0, id5872=1.0/1.0/1.0, id5873=1.0/1.0/1.0, id5874=1.0/1.0/1.0, id5875=1.0/1.0/1.0, id5876=1.0/1.0/1.0, id5877=1.0/1.0/1.0, id5878=1.0/1.0/1.0, id5879=1.0/1.0/1.0, id588=1.0/1.0/1.0, id5880=1.0/1.0/1.0, id5881=1.0/1.0/1.0, id5882=1.0/1.0/1.0, id5883=1.0/1.0/1.0, id5884=1.0/1.0/1.0, id5885=1.0/1.0/1.0, id5886=1.0/1.0/1.0, id5887=1.0/1.0/1.0, id5888=1.0/1.0/1.0, id5889=1.0/1.0/1.0, id589=1.0/1.0/1.0, id5890=1.0/1.0/1.0, id5891=1.0/1.0/1.0, id5892=1.0/1.0/1.0, id5893=1.0/1.0/1.0, id5894=1.0/1.0/1.0, id5895=1.0/1.0/1.0, id5896=1.0/1.0/1.0, id5897=1.0/1.0/1.0, id5898=1.0/1.0/1.0, id5899=1.0/1.0/1.0, id59=1.0/1.0/1.0, id590=1.0/1.0/1.0, id5900=1.0/1.0/1.0, id5901=1.0/1.0/1.0, id5902=1.0/1.0/1.0, id5903=1.0/1.0/1.0, id5904=1.0/1.0/1.0, id5905=1.0/1.0/1.0, id5906=1.0/1.0/1.0, id5907=1.0/1.0/1.0, id5908=1.0/1.0/1.0, id5909=1.0/1.0/1.0, id591=1.0/1.0/1.0, id5910=1.0/1.0/1.0, id5911=1.0/1.0/1.0, id5912=1.0/1.0/1.0, id5913=1.0/1.0/1.0, id5914=1.0/1.0/1.0, id5915=1.0/1.0/1.0, id5916=1.0/1.0/1.0, id5917=1.0/1.0/1.0, id5918=1.0/1.0/1.0, id5919=1.0/1.0/1.0, id592=1.0/1.0/1.0, id5920=1.0/1.0/1.0, id5921=1.0/1.0/1.0, id5922=1.0/1.0/1.0, id5923=1.0/1.0/1.0, id5924=1.0/1.0/1.0, id5925=1.0/1.0/1.0, id5926=1.0/1.0/1.0, id5927=1.0/1.0/1.0, id5928=1.0/1.0/1.0, id5929=1.0/1.0/1.0, id593=1.0/1.0/1.0, id5930=1.0/1.0/1.0, id5931=1.0/1.0/1.0, id5932=1.0/1.0/1.0, id5933=1.0/1.0/1.0, id5934=1.0/1.0/1.0, id5935=1.0/1.0/1.0, id5936=1.0/1.0/1.0, id5937=1.0/1.0/1.0, id5938=1.0/1.0/1.0, id5939=1.0/1.0/1.0, id594=1.0/1.0/1.0, id5940=1.0/1.0/1.0, id5941=1.0/1.0/1.0, id5942=1.0/1.0/1.0, id5943=1.0/1.0/1.0, id5944=1.0/1.0/1.0, id5945=1.0/1.0/1.0, id5946=1.0/1.0/1.0, id5947=1.0/1.0/1.0, id5948=1.0/1.0/1.0, id5949=1.0/1.0/1.0, id595=1.0/1.0/1.0, id5950=1.0/1.0/1.0, id5951=1.0/1.0/1.0, id5952=1.0/1.0/1.0, id5953=1.0/1.0/1.0, id5954=1.0/1.0/1.0, id5955=1.0/1.0/1.0, id5956=1.0/1.0/1.0, id5957=1.0/1.0/1.0, id5958=1.0/1.0/1.0, id5959=1.0/1.0/1.0, id596=1.0/1.0/1.0, id5960=1.0/1.0/1.0, id5961=1.0/1.0/1.0, id5962=1.0/1.0/1.0, id5963=1.0/1.0/1.0, id5964=1.0/1.0/1.0, id5965=1.0/1.0/1.0, id5966=1.0/1.0/1.0, id5967=1.0/1.0/1.0, id5968=1.0/1.0/1.0, id5969=1.0/1.0/1.0, id597=1.0/1.0/1.0, id5970=1.0/1.0/1.0, id5971=1.0/1.0/1.0, id5972=1.0/1.0/1.0, id5973=1.0/1.0/1.0, id5974=1.0/1.0/1.0, id5975=1.0/1.0/1.0, id5976=1.0/1.0/1.0, id5977=1.0/1.0/1.0, id5978=1.0/1.0/1.0, id5979=1.0/1.0/1.0, id598=1.0/1.0/1.0, id5980=1.0/1.0/1.0, id5981=1.0/1.0/1.0, id5982=1.0/1.0/1.0, id5983=1.0/1.0/1.0, id5984=1.0/1.0/1.0, id5985=1.0/1.0/1.0, id5986=1.0/1.0/1.0, id5987=1.0/1.0/1.0, id5988=1.0/1.0/1.0, id5989=1.0/1.0/1.0, id599=1.0/1.0/1.0, id5990=1.0/1.0/1.0, id5991=1.0/1.0/1.0, id5992=1.0/1.0/1.0, id5993=1.0/1.0/1.0, id5994=1.0/1.0/1.0, id5995=1.0/1.0/1.0, id5996=1.0/1.0/1.0, id5997=1.0/1.0/1.0, id5998=1.0/1.0/1.0, id5999=1.0/1.0/1.0, id6=1.0/1.0/1.0, id60=1.0/1.0/1.0, id600=1.0/1.0/1.0, id6000=1.0/1.0/1.0, id6001=1.0/1.0/1.0, id6002=1.0/1.0/1.0, id6003=1.0/1.0/1.0, id6004=1.0/1.0/1.0, id6005=1.0/1.0/1.0, id6006=1.0/1.0/1.0, id6007=1.0/1.0/1.0, id6008=1.0/1.0/1.0, id6009=1.0/1.0/1.0, id601=1.0/1.0/1.0, id6010=1.0/1.0/1.0, id6011=1.0/1.0/1.0, id6012=1.0/1.0/1.0, id6013=1.0/1.0/1.0, id6014=1.0/1.0/1.0, id6015=1.0/1.0/1.0, id6016=1.0/1.0/1.0, id6017=1.0/1.0/1.0, id6018=1.0/1.0/1.0, id6019=1.0/1.0/1.0, id602=1.0/1.0/1.0, id6020=1.0/1.0/1.0, id6021=1.0/1.0/1.0, id6022=1.0/1.0/1.0, id6023=1.0/1.0/1.0, id6024=1.0/1.0/1.0, id6025=1.0/1.0/1.0, id6026=1.0/1.0/1.0, id6027=1.0/1.0/1.0, id6028=1.0/1.0/1.0, id6029=1.0/1.0/1.0, id603=1.0/1.0/1.0, id6030=1.0/1.0/1.0, id6031=1.0/1.0/1.0, id6032=1.0/1.0/1.0, id6033=1.0/1.0/1.0, id6034=1.0/1.0/1.0, id6035=1.0/1.0/1.0, id6036=1.0/1.0/1.0, id6037=1.0/1.0/1.0, id6038=1.0/1.0/1.0, id6039=1.0/1.0/1.0, id604=1.0/1.0/1.0, id6040=1.0/1.0/1.0, id6041=1.0/1.0/1.0, id6042=1.0/1.0/1.0, id6043=1.0/1.0/1.0, id6044=1.0/1.0/1.0, id6045=1.0/1.0/1.0, id6046=1.0/1.0/1.0, id6047=1.0/1.0/1.0, id6048=1.0/1.0/1.0, id6049=1.0/1.0/1.0, id605=1.0/1.0/1.0, id6050=1.0/1.0/1.0, id6051=1.0/1.0/1.0, id6052=1.0/1.0/1.0, id6053=1.0/1.0/1.0, id6054=1.0/1.0/1.0, id6055=1.0/1.0/1.0, id6056=1.0/1.0/1.0, id6057=1.0/1.0/1.0, id6058=1.0/1.0/1.0, id6059=1.0/1.0/1.0, id606=1.0/1.0/1.0, id6060=1.0/1.0/1.0, id6061=1.0/1.0/1.0, id6062=1.0/1.0/1.0, id6063=1.0/1.0/1.0, id6064=1.0/1.0/1.0, id6065=1.0/1.0/1.0, id6066=1.0/1.0/1.0, id6067=1.0/1.0/1.0, id6068=1.0/1.0/1.0, id6069=1.0/1.0/1.0, id607=1.0/1.0/1.0, id6070=1.0/1.0/1.0, id6071=1.0/1.0/1.0, id6072=1.0/1.0/1.0, id6073=1.0/1.0/1.0, id6074=1.0/1.0/1.0, id6075=1.0/1.0/1.0, id6076=1.0/1.0/1.0, id6077=1.0/1.0/1.0, id6078=1.0/1.0/1.0, id6079=1.0/1.0/1.0, id608=1.0/1.0/1.0, id6080=1.0/1.0/1.0, id6081=1.0/1.0/1.0, id6082=1.0/1.0/1.0, id6083=1.0/1.0/1.0, id6084=1.0/1.0/1.0, id6085=1.0/1.0/1.0, id6086=1.0/1.0/1.0, id6087=1.0/1.0/1.0, id6088=1.0/1.0/1.0, id6089=1.0/1.0/1.0, id609=1.0/1.0/1.0, id6090=1.0/1.0/1.0, id6091=1.0/1.0/1.0, id6092=1.0/1.0/1.0, id6093=1.0/1.0/1.0, id6094=1.0/1.0/1.0, id6095=1.0/1.0/1.0, id6096=1.0/1.0/1.0, id6097=1.0/1.0/1.0, id6098=1.0/1.0/1.0, id6099=1.0/1.0/1.0, id61=1.0/1.0/1.0, id610=1.0/1.0/1.0, id6100=1.0/1.0/1.0, id6101=1.0/1.0/1.0, id6102=1.0/1.0/1.0, id6103=1.0/1.0/1.0, id6104=1.0/1.0/1.0, id6105=1.0/1.0/1.0, id6106=1.0/1.0/1.0, id6107=1.0/1.0/1.0, id6108=1.0/1.0/1.0, id6109=1.0/1.0/1.0, id611=1.0/1.0/1.0, id6110=1.0/1.0/1.0, id6111=1.0/1.0/1.0, id6112=1.0/1.0/1.0, id6113=1.0/1.0/1.0, id6114=1.0/1.0/1.0, id6115=1.0/1.0/1.0, id6116=1.0/1.0/1.0, id6117=1.0/1.0/1.0, id6118=1.0/1.0/1.0, id6119=1.0/1.0/1.0, id612=1.0/1.0/1.0, id6120=1.0/1.0/1.0, id6121=1.0/1.0/1.0, id6122=1.0/1.0/1.0, id6123=1.0/1.0/1.0, id6124=1.0/1.0/1.0, id6125=1.0/1.0/1.0, id6126=1.0/1.0/1.0, id6127=1.0/1.0/1.0, id6128=1.0/1.0/1.0, id6129=1.0/1.0/1.0, id613=1.0/1.0/1.0, id6130=1.0/1.0/1.0, id6131=1.0/1.0/1.0, id6132=1.0/1.0/1.0, id6133=1.0/1.0/1.0, id6134=1.0/1.0/1.0, id6135=1.0/1.0/1.0, id6136=1.0/1.0/1.0, id6137=1.0/1.0/1.0, id6138=1.0/1.0/1.0, id6139=1.0/1.0/1.0, id614=1.0/1.0/1.0, id6140=1.0/1.0/1.0, id6141=1.0/1.0/1.0, id6142=1.0/1.0/1.0, id6143=1.0/1.0/1.0, id6144=1.0/1.0/1.0, id6145=1.0/1.0/1.0, id6146=1.0/1.0/1.0, id6147=1.0/1.0/1.0, id6148=1.0/1.0/1.0, id6149=1.0/1.0/1.0, id615=1.0/1.0/1.0, id6150=1.0/1.0/1.0, id6151=1.0/1.0/1.0, id6152=1.0/1.0/1.0, id6153=1.0/1.0/1.0, id6154=1.0/1.0/1.0, id6155=1.0/1.0/1.0, id6156=1.0/1.0/1.0, id6157=1.0/1.0/1.0, id6158=1.0/1.0/1.0, id6159=1.0/1.0/1.0, id616=1.0/1.0/1.0, id6160=1.0/1.0/1.0, id6161=1.0/1.0/1.0, id6162=1.0/1.0/1.0, id6163=1.0/1.0/1.0, id6164=1.0/1.0/1.0, id6165=1.0/1.0/1.0, id6166=1.0/1.0/1.0, id6167=1.0/1.0/1.0, id6168=1.0/1.0/1.0, id6169=1.0/1.0/1.0, id617=1.0/1.0/1.0, id6170=1.0/1.0/1.0, id6171=1.0/1.0/1.0, id6172=1.0/1.0/1.0, id6173=1.0/1.0/1.0, id6174=1.0/1.0/1.0, id6175=1.0/1.0/1.0, id6176=1.0/1.0/1.0, id6177=1.0/1.0/1.0, id6178=1.0/1.0/1.0, id6179=1.0/1.0/1.0, id618=1.0/1.0/1.0, id6180=1.0/1.0/1.0, id6181=1.0/1.0/1.0, id6182=1.0/1.0/1.0, id6183=1.0/1.0/1.0, id6184=1.0/1.0/1.0, id6185=1.0/1.0/1.0, id6186=1.0/1.0/1.0, id6187=1.0/1.0/1.0, id6188=1.0/1.0/1.0, id6189=1.0/1.0/1.0, id619=1.0/1.0/1.0, id6190=1.0/1.0/1.0, id6191=1.0/1.0/1.0, id6192=1.0/1.0/1.0, id6193=1.0/1.0/1.0, id6194=1.0/1.0/1.0, id6195=1.0/1.0/1.0, id6196=1.0/1.0/1.0, id6197=1.0/1.0/1.0, id6198=1.0/1.0/1.0, id6199=1.0/1.0/1.0, id62=1.0/1.0/1.0, id620=1.0/1.0/1.0, id6200=1.0/1.0/1.0, id6201=1.0/1.0/1.0, id6202=1.0/1.0/1.0, id6203=1.0/1.0/1.0, id6204=1.0/1.0/1.0, id6205=1.0/1.0/1.0, id6206=1.0/1.0/1.0, id6207=1.0/1.0/1.0, id6208=1.0/1.0/1.0, id6209=1.0/1.0/1.0, id621=1.0/1.0/1.0, id6210=1.0/1.0/1.0, id6211=1.0/1.0/1.0, id6212=1.0/1.0/1.0, id6213=1.0/1.0/1.0, id6214=1.0/1.0/1.0, id6215=1.0/1.0/1.0, id6216=1.0/1.0/1.0, id6217=1.0/1.0/1.0, id6218=1.0/1.0/1.0, id6219=1.0/1.0/1.0, id622=1.0/1.0/1.0, id6220=1.0/1.0/1.0, id6221=1.0/1.0/1.0, id6222=1.0/1.0/1.0, id6223=1.0/1.0/1.0, id6224=1.0/1.0/1.0, id6225=1.0/1.0/1.0, id6226=1.0/1.0/1.0, id6227=1.0/1.0/1.0, id6228=1.0/1.0/1.0, id6229=1.0/1.0/1.0, id623=1.0/1.0/1.0, id6230=1.0/1.0/1.0, id6231=1.0/1.0/1.0, id6232=1.0/1.0/1.0, id6233=1.0/1.0/1.0, id6234=1.0/1.0/1.0, id6235=1.0/1.0/1.0, id6236=1.0/1.0/1.0, id6237=1.0/1.0/1.0, id6238=1.0/1.0/1.0, id6239=1.0/1.0/1.0, id624=1.0/1.0/1.0, id6240=1.0/1.0/1.0, id6241=1.0/1.0/1.0, id6242=1.0/1.0/1.0, id6243=1.0/1.0/1.0, id6244=1.0/1.0/1.0, id6245=1.0/1.0/1.0, id6246=1.0/1.0/1.0, id6247=1.0/1.0/1.0, id6248=1.0/1.0/1.0, id6249=1.0/1.0/1.0, id625=1.0/1.0/1.0, id6250=1.0/1.0/1.0, id6251=1.0/1.0/1.0, id6252=1.0/1.0/1.0, id6253=1.0/1.0/1.0, id6254=1.0/1.0/1.0, id6255=1.0/1.0/1.0, id6256=1.0/1.0/1.0, id6257=1.0/1.0/1.0, id6258=1.0/1.0/1.0, id6259=1.0/1.0/1.0, id626=1.0/1.0/1.0, id6260=1.0/1.0/1.0, id6261=1.0/1.0/1.0, id6262=1.0/1.0/1.0, id6263=1.0/1.0/1.0, id6264=1.0/1.0/1.0, id6265=1.0/1.0/1.0, id6266=1.0/1.0/1.0, id6267=1.0/1.0/1.0, id6268=1.0/1.0/1.0, id6269=1.0/1.0/1.0, id627=1.0/1.0/1.0, id6270=1.0/1.0/1.0, id6271=1.0/1.0/1.0, id6272=1.0/1.0/1.0, id6273=1.0/1.0/1.0, id6274=1.0/1.0/1.0, id6275=1.0/1.0/1.0, id6276=1.0/1.0/1.0, id6277=1.0/1.0/1.0, id6278=1.0/1.0/1.0, id6279=1.0/1.0/1.0, id628=1.0/1.0/1.0, id6280=1.0/1.0/1.0, id6281=1.0/1.0/1.0, id6282=1.0/1.0/1.0, id6283=1.0/1.0/1.0, id6284=1.0/1.0/1.0, id6285=1.0/1.0/1.0, id6286=1.0/1.0/1.0, id6287=1.0/1.0/1.0, id6288=1.0/1.0/1.0, id6289=1.0/1.0/1.0, id629=1.0/1.0/1.0, id6290=1.0/1.0/1.0, id6291=1.0/1.0/1.0, id6292=1.0/1.0/1.0, id6293=1.0/1.0/1.0, id6294=1.0/1.0/1.0, id6295=1.0/1.0/1.0, id6296=1.0/1.0/1.0, id6297=1.0/1.0/1.0, id6298=1.0/1.0/1.0, id6299=1.0/1.0/1.0, id63=1.0/1.0/1.0, id630=1.0/1.0/1.0, id6300=1.0/1.0/1.0, id6301=1.0/1.0/1.0, id6302=1.0/1.0/1.0, id6303=1.0/1.0/1.0, id6304=1.0/1.0/1.0, id6305=1.0/1.0/1.0, id6306=1.0/1.0/1.0, id6307=1.0/1.0/1.0, id6308=1.0/1.0/1.0, id6309=1.0/1.0/1.0, id631=1.0/1.0/1.0, id6310=1.0/1.0/1.0, id6311=1.0/1.0/1.0, id6312=1.0/1.0/1.0, id6313=1.0/1.0/1.0, id6314=1.0/1.0/1.0, id6315=1.0/1.0/1.0, id6316=1.0/1.0/1.0, id6317=1.0/1.0/1.0, id6318=1.0/1.0/1.0, id6319=1.0/1.0/1.0, id632=1.0/1.0/1.0, id6320=1.0/1.0/1.0, id6321=1.0/1.0/1.0, id6322=1.0/1.0/1.0, id6323=1.0/1.0/1.0, id6324=1.0/1.0/1.0, id6325=1.0/1.0/1.0, id6326=1.0/1.0/1.0, id6327=1.0/1.0/1.0, id6328=1.0/1.0/1.0, id6329=1.0/1.0/1.0, id633=1.0/1.0/1.0, id6330=1.0/1.0/1.0, id6331=1.0/1.0/1.0, id6332=1.0/1.0/1.0, id6333=1.0/1.0/1.0, id6334=1.0/1.0/1.0, id6335=1.0/1.0/1.0, id6336=1.0/1.0/1.0, id6337=1.0/1.0/1.0, id6338=1.0/1.0/1.0, id6339=1.0/1.0/1.0, id634=1.0/1.0/1.0, id6340=1.0/1.0/1.0, id6341=1.0/1.0/1.0, id6342=1.0/1.0/1.0, id6343=1.0/1.0/1.0, id6344=1.0/1.0/1.0, id6345=1.0/1.0/1.0, id6346=1.0/1.0/1.0, id6347=1.0/1.0/1.0, id6348=1.0/1.0/1.0, id6349=1.0/1.0/1.0, id635=1.0/1.0/1.0, id6350=1.0/1.0/1.0, id6351=1.0/1.0/1.0, id6352=1.0/1.0/1.0, id6353=1.0/1.0/1.0, id6354=1.0/1.0/1.0, id6355=1.0/1.0/1.0, id6356=1.0/1.0/1.0, id6357=1.0/1.0/1.0, id6358=1.0/1.0/1.0, id6359=1.0/1.0/1.0, id636=1.0/1.0/1.0, id6360=1.0/1.0/1.0, id6361=1.0/1.0/1.0, id6362=1.0/1.0/1.0, id6363=1.0/1.0/1.0, id6364=1.0/1.0/1.0, id6365=1.0/1.0/1.0, id6366=1.0/1.0/1.0, id6367=1.0/1.0/1.0, id6368=1.0/1.0/1.0, id6369=1.0/1.0/1.0, id637=1.0/1.0/1.0, id6370=1.0/1.0/1.0, id6371=1.0/1.0/1.0, id6372=1.0/1.0/1.0, id6373=1.0/1.0/1.0, id6374=1.0/1.0/1.0, id6375=1.0/1.0/1.0, id6376=1.0/1.0/1.0, id6377=1.0/1.0/1.0, id6378=1.0/1.0/1.0, id6379=1.0/1.0/1.0, id638=1.0/1.0/1.0, id6380=1.0/1.0/1.0, id6381=1.0/1.0/1.0, id6382=1.0/1.0/1.0, id6383=1.0/1.0/1.0, id6384=1.0/1.0/1.0, id6385=1.0/1.0/1.0, id6386=1.0/1.0/1.0, id6387=1.0/1.0/1.0, id6388=1.0/1.0/1.0, id6389=1.0/1.0/1.0, id639=1.0/1.0/1.0, id6390=1.0/1.0/1.0, id6391=1.0/1.0/1.0, id6392=1.0/1.0/1.0, id6393=1.0/1.0/1.0, id6394=1.0/1.0/1.0, id6395=1.0/1.0/1.0, id6396=1.0/1.0/1.0, id6397=1.0/1.0/1.0, id6398=1.0/1.0/1.0, id6399=1.0/1.0/1.0, id64=1.0/1.0/1.0, id640=1.0/1.0/1.0, id6400=1.0/1.0/1.0, id6401=1.0/1.0/1.0, id6402=1.0/1.0/1.0, id6403=1.0/1.0/1.0, id6404=1.0/1.0/1.0, id6405=1.0/1.0/1.0, id6406=1.0/1.0/1.0, id6407=1.0/1.0/1.0, id6408=1.0/1.0/1.0, id6409=1.0/1.0/1.0, id641=1.0/1.0/1.0, id6410=1.0/1.0/1.0, id6411=1.0/1.0/1.0, id6412=1.0/1.0/1.0, id6413=1.0/1.0/1.0, id6414=1.0/1.0/1.0, id6415=1.0/1.0/1.0, id6416=1.0/1.0/1.0, id6417=1.0/1.0/1.0, id6418=1.0/1.0/1.0, id6419=1.0/1.0/1.0, id642=1.0/1.0/1.0, id6420=1.0/1.0/1.0, id6421=1.0/1.0/1.0, id6422=1.0/1.0/1.0, id6423=1.0/1.0/1.0, id6424=1.0/1.0/1.0, id6425=1.0/1.0/1.0, id6426=1.0/1.0/1.0, id6427=1.0/1.0/1.0, id6428=1.0/1.0/1.0, id6429=1.0/1.0/1.0, id643=1.0/1.0/1.0, id6430=1.0/1.0/1.0, id6431=1.0/1.0/1.0, id6432=1.0/1.0/1.0, id6433=1.0/1.0/1.0, id6434=1.0/1.0/1.0, id6435=1.0/1.0/1.0, id6436=1.0/1.0/1.0, id6437=1.0/1.0/1.0, id6438=1.0/1.0/1.0, id6439=1.0/1.0/1.0, id644=1.0/1.0/1.0, id6440=1.0/1.0/1.0, id6441=1.0/1.0/1.0, id6442=1.0/1.0/1.0, id6443=1.0/1.0/1.0, id6444=1.0/1.0/1.0, id6445=1.0/1.0/1.0, id6446=1.0/1.0/1.0, id6447=1.0/1.0/1.0, id6448=1.0/1.0/1.0, id6449=1.0/1.0/1.0, id645=1.0/1.0/1.0, id6450=1.0/1.0/1.0, id6451=1.0/1.0/1.0, id6452=1.0/1.0/1.0, id6453=1.0/1.0/1.0, id6454=1.0/1.0/1.0, id6455=1.0/1.0/1.0, id6456=1.0/1.0/1.0, id6457=1.0/1.0/1.0, id6458=1.0/1.0/1.0, id6459=1.0/1.0/1.0, id646=1.0/1.0/1.0, id6460=1.0/1.0/1.0, id6461=1.0/1.0/1.0, id6462=1.0/1.0/1.0, id6463=1.0/1.0/1.0, id6464=1.0/1.0/1.0, id6465=1.0/1.0/1.0, id6466=1.0/1.0/1.0, id6467=1.0/1.0/1.0, id6468=1.0/1.0/1.0, id6469=1.0/1.0/1.0, id647=1.0/1.0/1.0, id6470=1.0/1.0/1.0, id6471=1.0/1.0/1.0, id6472=1.0/1.0/1.0, id6473=1.0/1.0/1.0, id6474=1.0/1.0/1.0, id6475=1.0/1.0/1.0, id6476=1.0/1.0/1.0, id6477=1.0/1.0/1.0, id6478=1.0/1.0/1.0, id6479=1.0/1.0/1.0, id648=1.0/1.0/1.0, id6480=1.0/1.0/1.0, id6481=1.0/1.0/1.0, id6482=1.0/1.0/1.0, id6483=1.0/1.0/1.0, id6484=1.0/1.0/1.0, id6485=1.0/1.0/1.0, id6486=1.0/1.0/1.0, id6487=1.0/1.0/1.0, id6488=1.0/1.0/1.0, id6489=1.0/1.0/1.0, id649=1.0/1.0/1.0, id6490=1.0/1.0/1.0, id6491=1.0/1.0/1.0, id6492=1.0/1.0/1.0, id6493=1.0/1.0/1.0, id6494=1.0/1.0/1.0, id6495=1.0/1.0/1.0, id6496=1.0/1.0/1.0, id6497=1.0/1.0/1.0, id6498=1.0/1.0/1.0, id6499=1.0/1.0/1.0, id65=1.0/1.0/1.0, id650=1.0/1.0/1.0, id6500=1.0/1.0/1.0, id6501=1.0/1.0/1.0, id6502=1.0/1.0/1.0, id6503=1.0/1.0/1.0, id6504=1.0/1.0/1.0, id6505=1.0/1.0/1.0, id6506=1.0/1.0/1.0, id6507=1.0/1.0/1.0, id6508=1.0/1.0/1.0, id6509=1.0/1.0/1.0, id651=1.0/1.0/1.0, id6510=1.0/1.0/1.0, id6511=1.0/1.0/1.0, id6512=1.0/1.0/1.0, id6513=1.0/1.0/1.0, id6514=1.0/1.0/1.0, id6515=1.0/1.0/1.0, id6516=1.0/1.0/1.0, id6517=1.0/1.0/1.0, id6518=1.0/1.0/1.0, id6519=1.0/1.0/1.0, id652=1.0/1.0/1.0, id6520=1.0/1.0/1.0, id6521=1.0/1.0/1.0, id6522=1.0/1.0/1.0, id6523=1.0/1.0/1.0, id6524=1.0/1.0/1.0, id6525=1.0/1.0/1.0, id6526=1.0/1.0/1.0, id6527=1.0/1.0/1.0, id6528=1.0/1.0/1.0, id6529=1.0/1.0/1.0, id653=1.0/1.0/1.0, id6530=1.0/1.0/1.0, id6531=1.0/1.0/1.0, id6532=1.0/1.0/1.0, id6533=1.0/1.0/1.0, id6534=1.0/1.0/1.0, id6535=1.0/1.0/1.0, id6536=1.0/1.0/1.0, id6537=1.0/1.0/1.0, id6538=1.0/1.0/1.0, id6539=1.0/1.0/1.0, id654=1.0/1.0/1.0, id6540=1.0/1.0/1.0, id6541=1.0/1.0/1.0, id6542=1.0/1.0/1.0, id6543=1.0/1.0/1.0, id6544=1.0/1.0/1.0, id6545=1.0/1.0/1.0, id6546=1.0/1.0/1.0, id6547=1.0/1.0/1.0, id6548=1.0/1.0/1.0, id6549=1.0/1.0/1.0, id655=1.0/1.0/1.0, id6550=1.0/1.0/1.0, id6551=1.0/1.0/1.0, id6552=1.0/1.0/1.0, id6553=1.0/1.0/1.0, id6554=1.0/1.0/1.0, id6555=1.0/1.0/1.0, id6556=1.0/1.0/1.0, id6557=1.0/1.0/1.0, id6558=1.0/1.0/1.0, id6559=1.0/1.0/1.0, id656=1.0/1.0/1.0, id6560=1.0/1.0/1.0, id6561=1.0/1.0/1.0, id6562=1.0/1.0/1.0, id6563=1.0/1.0/1.0, id6564=1.0/1.0/1.0, id6565=1.0/1.0/1.0, id6566=1.0/1.0/1.0, id6567=1.0/1.0/1.0, id6568=1.0/1.0/1.0, id6569=1.0/1.0/1.0, id657=1.0/1.0/1.0, id6570=1.0/1.0/1.0, id6571=1.0/1.0/1.0, id6572=1.0/1.0/1.0, id6573=1.0/1.0/1.0, id6574=1.0/1.0/1.0, id6575=1.0/1.0/1.0, id6576=1.0/1.0/1.0, id6577=1.0/1.0/1.0, id6578=1.0/1.0/1.0, id6579=1.0/1.0/1.0, id658=1.0/1.0/1.0, id6580=1.0/1.0/1.0, id6581=1.0/1.0/1.0, id6582=1.0/1.0/1.0, id6583=1.0/1.0/1.0, id6584=1.0/1.0/1.0, id6585=1.0/1.0/1.0, id6586=1.0/1.0/1.0, id6587=1.0/1.0/1.0, id6588=1.0/1.0/1.0, id6589=1.0/1.0/1.0, id659=1.0/1.0/1.0, id6590=1.0/1.0/1.0, id6591=1.0/1.0/1.0, id6592=1.0/1.0/1.0, id6593=1.0/1.0/1.0, id6594=1.0/1.0/1.0, id6595=1.0/1.0/1.0, id6596=1.0/1.0/1.0, id6597=1.0/1.0/1.0, id6598=1.0/1.0/1.0, id6599=1.0/1.0/1.0, id66=1.0/1.0/1.0, id660=1.0/1.0/1.0, id6600=1.0/1.0/1.0, id6601=1.0/1.0/1.0, id6602=1.0/1.0/1.0, id6603=1.0/1.0/1.0, id6604=1.0/1.0/1.0, id6605=1.0/1.0/1.0, id6606=1.0/1.0/1.0, id6607=1.0/1.0/1.0, id6608=1.0/1.0/1.0, id6609=1.0/1.0/1.0, id661=1.0/1.0/1.0, id6610=1.0/1.0/1.0, id6611=1.0/1.0/1.0, id6612=1.0/1.0/1.0, id6613=1.0/1.0/1.0, id6614=1.0/1.0/1.0, id6615=1.0/1.0/1.0, id6616=1.0/1.0/1.0, id6617=1.0/1.0/1.0, id6618=1.0/1.0/1.0, id6619=1.0/1.0/1.0, id662=1.0/1.0/1.0, id6620=1.0/1.0/1.0, id6621=1.0/1.0/1.0, id6622=1.0/1.0/1.0, id6623=1.0/1.0/1.0, id6624=1.0/1.0/1.0, id6625=1.0/1.0/1.0, id6626=1.0/1.0/1.0, id6627=1.0/1.0/1.0, id6628=1.0/1.0/1.0, id6629=1.0/1.0/1.0, id663=1.0/1.0/1.0, id6630=1.0/1.0/1.0, id6631=1.0/1.0/1.0, id6632=1.0/1.0/1.0, id6633=1.0/1.0/1.0, id6634=1.0/1.0/1.0, id6635=1.0/1.0/1.0, id6636=1.0/1.0/1.0, id6637=1.0/1.0/1.0, id6638=1.0/1.0/1.0, id6639=1.0/1.0/1.0, id664=1.0/1.0/1.0, id6640=1.0/1.0/1.0, id6641=1.0/1.0/1.0, id6642=1.0/1.0/1.0, id6643=1.0/1.0/1.0, id6644=1.0/1.0/1.0, id6645=1.0/1.0/1.0, id6646=1.0/1.0/1.0, id6647=1.0/1.0/1.0, id6648=1.0/1.0/1.0, id6649=1.0/1.0/1.0, id665=1.0/1.0/1.0, id6650=1.0/1.0/1.0, id6651=1.0/1.0/1.0, id6652=1.0/1.0/1.0, id6653=1.0/1.0/1.0, id6654=1.0/1.0/1.0, id6655=1.0/1.0/1.0, id6656=1.0/1.0/1.0, id6657=1.0/1.0/1.0, id6658=1.0/1.0/1.0, id6659=1.0/1.0/1.0, id666=1.0/1.0/1.0, id6660=1.0/1.0/1.0, id6661=1.0/1.0/1.0, id6662=1.0/1.0/1.0, id6663=1.0/1.0/1.0, id6664=1.0/1.0/1.0, id6665=1.0/1.0/1.0, id6666=1.0/1.0/1.0, id6667=1.0/1.0/1.0, id6668=1.0/1.0/1.0, id6669=1.0/1.0/1.0, id667=1.0/1.0/1.0, id6670=1.0/1.0/1.0, id6671=1.0/1.0/1.0, id6672=1.0/1.0/1.0, id6673=1.0/1.0/1.0, id6674=1.0/1.0/1.0, id6675=1.0/1.0/1.0, id6676=1.0/1.0/1.0, id6677=1.0/1.0/1.0, id6678=1.0/1.0/1.0, id6679=1.0/1.0/1.0, id668=1.0/1.0/1.0, id6680=1.0/1.0/1.0, id6681=1.0/1.0/1.0, id6682=1.0/1.0/1.0, id6683=1.0/1.0/1.0, id6684=1.0/1.0/1.0, id6685=1.0/1.0/1.0, id6686=1.0/1.0/1.0, id6687=1.0/1.0/1.0, id6688=1.0/1.0/1.0, id6689=1.0/1.0/1.0, id669=1.0/1.0/1.0, id6690=1.0/1.0/1.0, id6691=1.0/1.0/1.0, id6692=1.0/1.0/1.0, id6693=1.0/1.0/1.0, id6694=1.0/1.0/1.0, id6695=1.0/1.0/1.0, id6696=1.0/1.0/1.0, id6697=1.0/1.0/1.0, id6698=1.0/1.0/1.0, id6699=1.0/1.0/1.0, id67=1.0/1.0/1.0, id670=1.0/1.0/1.0, id6700=1.0/1.0/1.0, id6701=1.0/1.0/1.0, id6702=1.0/1.0/1.0, id6703=1.0/1.0/1.0, id6704=1.0/1.0/1.0, id6705=1.0/1.0/1.0, id6706=1.0/1.0/1.0, id6707=1.0/1.0/1.0, id6708=1.0/1.0/1.0, id6709=1.0/1.0/1.0, id671=1.0/1.0/1.0, id6710=1.0/1.0/1.0, id6711=1.0/1.0/1.0, id6712=1.0/1.0/1.0, id6713=1.0/1.0/1.0, id6714=1.0/1.0/1.0, id6715=1.0/1.0/1.0, id6716=1.0/1.0/1.0, id6717=1.0/1.0/1.0, id6718=1.0/1.0/1.0, id6719=1.0/1.0/1.0, id672=1.0/1.0/1.0, id6720=1.0/1.0/1.0, id6721=1.0/1.0/1.0, id6722=1.0/1.0/1.0, id6723=1.0/1.0/1.0, id6724=1.0/1.0/1.0, id6725=1.0/1.0/1.0, id6726=1.0/1.0/1.0, id6727=1.0/1.0/1.0, id6728=1.0/1.0/1.0, id6729=1.0/1.0/1.0, id673=1.0/1.0/1.0, id6730=1.0/1.0/1.0, id6731=1.0/1.0/1.0, id6732=1.0/1.0/1.0, id6733=1.0/1.0/1.0, id6734=1.0/1.0/1.0, id6735=1.0/1.0/1.0, id6736=1.0/1.0/1.0, id6737=1.0/1.0/1.0, id6738=1.0/1.0/1.0, id6739=1.0/1.0/1.0, id674=1.0/1.0/1.0, id6740=1.0/1.0/1.0, id6741=1.0/1.0/1.0, id6742=1.0/1.0/1.0, id6743=1.0/1.0/1.0, id6744=1.0/1.0/1.0, id6745=1.0/1.0/1.0, id6746=1.0/1.0/1.0, id6747=1.0/1.0/1.0, id6748=1.0/1.0/1.0, id6749=1.0/1.0/1.0, id675=1.0/1.0/1.0, id6750=1.0/1.0/1.0, id6751=1.0/1.0/1.0, id6752=1.0/1.0/1.0, id6753=1.0/1.0/1.0, id6754=1.0/1.0/1.0, id6755=1.0/1.0/1.0, id6756=1.0/1.0/1.0, id6757=1.0/1.0/1.0, id6758=1.0/1.0/1.0, id6759=1.0/1.0/1.0, id676=1.0/1.0/1.0, id6760=1.0/1.0/1.0, id6761=1.0/1.0/1.0, id6762=1.0/1.0/1.0, id6763=1.0/1.0/1.0, id6764=1.0/1.0/1.0, id6765=1.0/1.0/1.0, id6766=1.0/1.0/1.0, id6767=1.0/1.0/1.0, id6768=1.0/1.0/1.0, id6769=1.0/1.0/1.0, id677=1.0/1.0/1.0, id6770=1.0/1.0/1.0, id6771=1.0/1.0/1.0, id6772=1.0/1.0/1.0, id6773=1.0/1.0/1.0, id6774=1.0/1.0/1.0, id6775=1.0/1.0/1.0, id6776=1.0/1.0/1.0, id6777=1.0/1.0/1.0, id6778=1.0/1.0/1.0, id6779=1.0/1.0/1.0, id678=1.0/1.0/1.0, id6780=1.0/1.0/1.0, id6781=1.0/1.0/1.0, id6782=1.0/1.0/1.0, id6783=1.0/1.0/1.0, id6784=1.0/1.0/1.0, id6785=1.0/1.0/1.0, id6786=1.0/1.0/1.0, id6787=1.0/1.0/1.0, id6788=1.0/1.0/1.0, id6789=1.0/1.0/1.0, id679=1.0/1.0/1.0, id6790=1.0/1.0/1.0, id6791=1.0/1.0/1.0, id6792=1.0/1.0/1.0, id6793=1.0/1.0/1.0, id6794=1.0/1.0/1.0, id6795=1.0/1.0/1.0, id6796=1.0/1.0/1.0, id6797=1.0/1.0/1.0, id6798=1.0/1.0/1.0, id6799=1.0/1.0/1.0, id68=1.0/1.0/1.0, id680=1.0/1.0/1.0, id6800=1.0/1.0/1.0, id6801=1.0/1.0/1.0, id6802=1.0/1.0/1.0, id6803=1.0/1.0/1.0, id6804=1.0/1.0/1.0, id6805=1.0/1.0/1.0, id6806=1.0/1.0/1.0, id6807=1.0/1.0/1.0, id6808=1.0/1.0/1.0, id6809=1.0/1.0/1.0, id681=1.0/1.0/1.0, id6810=1.0/1.0/1.0, id6811=1.0/1.0/1.0, id6812=1.0/1.0/1.0, id6813=1.0/1.0/1.0, id6814=1.0/1.0/1.0, id6815=1.0/1.0/1.0, id6816=1.0/1.0/1.0, id6817=1.0/1.0/1.0, id6818=1.0/1.0/1.0, id6819=1.0/1.0/1.0, id682=1.0/1.0/1.0, id6820=1.0/1.0/1.0, id6821=1.0/1.0/1.0, id6822=1.0/1.0/1.0, id6823=1.0/1.0/1.0, id6824=1.0/1.0/1.0, id6825=1.0/1.0/1.0, id6826=1.0/1.0/1.0, id6827=1.0/1.0/1.0, id6828=1.0/1.0/1.0, id6829=1.0/1.0/1.0, id683=1.0/1.0/1.0, id6830=1.0/1.0/1.0, id6831=1.0/1.0/1.0, id6832=1.0/1.0/1.0, id6833=1.0/1.0/1.0, id6834=1.0/1.0/1.0, id6835=1.0/1.0/1.0, id6836=1.0/1.0/1.0, id6837=1.0/1.0/1.0, id6838=1.0/1.0/1.0, id6839=1.0/1.0/1.0, id684=1.0/1.0/1.0, id6840=1.0/1.0/1.0, id6841=1.0/1.0/1.0, id6842=1.0/1.0/1.0, id6843=1.0/1.0/1.0, id6844=1.0/1.0/1.0, id6845=1.0/1.0/1.0, id6846=1.0/1.0/1.0, id6847=1.0/1.0/1.0, id6848=1.0/1.0/1.0, id6849=1.0/1.0/1.0, id685=1.0/1.0/1.0, id6850=1.0/1.0/1.0, id6851=1.0/1.0/1.0, id6852=1.0/1.0/1.0, id6853=1.0/1.0/1.0, id6854=1.0/1.0/1.0, id6855=1.0/1.0/1.0, id6856=1.0/1.0/1.0, id6857=1.0/1.0/1.0, id6858=1.0/1.0/1.0, id6859=1.0/1.0/1.0, id686=1.0/1.0/1.0, id6860=1.0/1.0/1.0, id6861=1.0/1.0/1.0, id6862=1.0/1.0/1.0, id6863=1.0/1.0/1.0, id6864=1.0/1.0/1.0, id6865=1.0/1.0/1.0, id6866=1.0/1.0/1.0, id6867=1.0/1.0/1.0, id6868=1.0/1.0/1.0, id6869=1.0/1.0/1.0, id687=1.0/1.0/1.0, id6870=1.0/1.0/1.0, id6871=1.0/1.0/1.0, id6872=1.0/1.0/1.0, id6873=1.0/1.0/1.0, id6874=1.0/1.0/1.0, id6875=1.0/1.0/1.0, id6876=1.0/1.0/1.0, id6877=1.0/1.0/1.0, id6878=1.0/1.0/1.0, id6879=1.0/1.0/1.0, id688=1.0/1.0/1.0, id6880=1.0/1.0/1.0, id6881=1.0/1.0/1.0, id6882=1.0/1.0/1.0, id6883=1.0/1.0/1.0, id6884=1.0/1.0/1.0, id6885=1.0/1.0/1.0, id6886=1.0/1.0/1.0, id6887=1.0/1.0/1.0, id6888=1.0/1.0/1.0, id6889=1.0/1.0/1.0, id689=1.0/1.0/1.0, id6890=1.0/1.0/1.0, id6891=1.0/1.0/1.0, id6892=1.0/1.0/1.0, id6893=1.0/1.0/1.0, id6894=1.0/1.0/1.0, id6895=1.0/1.0/1.0, id6896=1.0/1.0/1.0, id6897=1.0/1.0/1.0, id6898=1.0/1.0/1.0, id6899=1.0/1.0/1.0, id69=1.0/1.0/1.0, id690=1.0/1.0/1.0, id6900=1.0/1.0/1.0, id6901=1.0/1.0/1.0, id6902=1.0/1.0/1.0, id6903=1.0/1.0/1.0, id6904=1.0/1.0/1.0, id6905=1.0/1.0/1.0, id6906=1.0/1.0/1.0, id6907=1.0/1.0/1.0, id6908=1.0/1.0/1.0, id6909=1.0/1.0/1.0, id691=1.0/1.0/1.0, id6910=1.0/1.0/1.0, id6911=1.0/1.0/1.0, id6912=1.0/1.0/1.0, id6913=1.0/1.0/1.0, id6914=1.0/1.0/1.0, id6915=1.0/1.0/1.0, id6916=1.0/1.0/1.0, id6917=1.0/1.0/1.0, id6918=1.0/1.0/1.0, id6919=1.0/1.0/1.0, id692=1.0/1.0/1.0, id6920=1.0/1.0/1.0, id6921=1.0/1.0/1.0, id6922=1.0/1.0/1.0, id6923=1.0/1.0/1.0, id6924=1.0/1.0/1.0, id6925=1.0/1.0/1.0, id6926=1.0/1.0/1.0, id6927=1.0/1.0/1.0, id6928=1.0/1.0/1.0, id6929=1.0/1.0/1.0, id693=1.0/1.0/1.0, id6930=1.0/1.0/1.0, id6931=1.0/1.0/1.0, id6932=1.0/1.0/1.0, id6933=1.0/1.0/1.0, id6934=1.0/1.0/1.0, id6935=1.0/1.0/1.0, id6936=1.0/1.0/1.0, id6937=1.0/1.0/1.0, id6938=1.0/1.0/1.0, id6939=1.0/1.0/1.0, id694=1.0/1.0/1.0, id6940=1.0/1.0/1.0, id6941=1.0/1.0/1.0, id6942=1.0/1.0/1.0, id6943=1.0/1.0/1.0, id6944=1.0/1.0/1.0, id6945=1.0/1.0/1.0, id6946=1.0/1.0/1.0, id6947=1.0/1.0/1.0, id6948=1.0/1.0/1.0, id6949=1.0/1.0/1.0, id695=1.0/1.0/1.0, id6950=1.0/1.0/1.0, id6951=1.0/1.0/1.0, id6952=1.0/1.0/1.0, id6953=1.0/1.0/1.0, id6954=1.0/1.0/1.0, id6955=1.0/1.0/1.0, id6956=1.0/1.0/1.0, id6957=1.0/1.0/1.0, id6958=1.0/1.0/1.0, id6959=1.0/1.0/1.0, id696=1.0/1.0/1.0, id6960=1.0/1.0/1.0, id6961=1.0/1.0/1.0, id6962=1.0/1.0/1.0, id6963=1.0/1.0/1.0, id6964=1.0/1.0/1.0, id6965=1.0/1.0/1.0, id6966=1.0/1.0/1.0, id6967=1.0/1.0/1.0, id6968=1.0/1.0/1.0, id6969=1.0/1.0/1.0, id697=1.0/1.0/1.0, id6970=1.0/1.0/1.0, id6971=1.0/1.0/1.0, id6972=1.0/1.0/1.0, id6973=1.0/1.0/1.0, id6974=1.0/1.0/1.0, id6975=1.0/1.0/1.0, id6976=1.0/1.0/1.0, id6977=1.0/1.0/1.0, id6978=1.0/1.0/1.0, id6979=1.0/1.0/1.0, id698=1.0/1.0/1.0, id6980=1.0/1.0/1.0, id6981=1.0/1.0/1.0, id6982=1.0/1.0/1.0, id6983=1.0/1.0/1.0, id6984=1.0/1.0/1.0, id6985=1.0/1.0/1.0, id6986=1.0/1.0/1.0, id6987=1.0/1.0/1.0, id6988=1.0/1.0/1.0, id6989=1.0/1.0/1.0, id699=1.0/1.0/1.0, id6990=1.0/1.0/1.0, id6991=1.0/1.0/1.0, id6992=1.0/1.0/1.0, id6993=1.0/1.0/1.0, id6994=1.0/1.0/1.0, id6995=1.0/1.0/1.0, id6996=1.0/1.0/1.0, id6997=1.0/1.0/1.0, id6998=1.0/1.0/1.0, id6999=1.0/1.0/1.0, id7=1.0/1.0/1.0, id70=1.0/1.0/1.0, id700=1.0/1.0/1.0, id7000=1.0/1.0/1.0, id7001=1.0/1.0/1.0, id7002=1.0/1.0/1.0, id7003=1.0/1.0/1.0, id7004=1.0/1.0/1.0, id7005=1.0/1.0/1.0, id7006=1.0/1.0/1.0, id7007=1.0/1.0/1.0, id7008=1.0/1.0/1.0, id7009=1.0/1.0/1.0, id701=1.0/1.0/1.0, id7010=1.0/1.0/1.0, id7011=1.0/1.0/1.0, id7012=1.0/1.0/1.0, id7013=1.0/1.0/1.0, id7014=1.0/1.0/1.0, id7015=1.0/1.0/1.0, id7016=1.0/1.0/1.0, id7017=1.0/1.0/1.0, id7018=1.0/1.0/1.0, id7019=1.0/1.0/1.0, id702=1.0/1.0/1.0, id7020=1.0/1.0/1.0, id7021=1.0/1.0/1.0, id7022=1.0/1.0/1.0, id7023=1.0/1.0/1.0, id7024=1.0/1.0/1.0, id7025=1.0/1.0/1.0, id7026=1.0/1.0/1.0, id7027=1.0/1.0/1.0, id7028=1.0/1.0/1.0, id7029=1.0/1.0/1.0, id703=1.0/1.0/1.0, id7030=1.0/1.0/1.0, id7031=1.0/1.0/1.0, id7032=1.0/1.0/1.0, id7033=1.0/1.0/1.0, id7034=1.0/1.0/1.0, id7035=1.0/1.0/1.0, id7036=1.0/1.0/1.0, id7037=1.0/1.0/1.0, id7038=1.0/1.0/1.0, id7039=1.0/1.0/1.0, id704=1.0/1.0/1.0, id7040=1.0/1.0/1.0, id7041=1.0/1.0/1.0, id7042=1.0/1.0/1.0, id7043=1.0/1.0/1.0, id7044=1.0/1.0/1.0, id7045=1.0/1.0/1.0, id7046=1.0/1.0/1.0, id7047=1.0/1.0/1.0, id7048=1.0/1.0/1.0, id7049=1.0/1.0/1.0, id705=1.0/1.0/1.0, id7050=1.0/1.0/1.0, id7051=1.0/1.0/1.0, id7052=1.0/1.0/1.0, id7053=1.0/1.0/1.0, id7054=1.0/1.0/1.0, id7055=1.0/1.0/1.0, id7056=1.0/1.0/1.0, id7057=1.0/1.0/1.0, id7058=1.0/1.0/1.0, id7059=1.0/1.0/1.0, id706=1.0/1.0/1.0, id7060=1.0/1.0/1.0, id7061=1.0/1.0/1.0, id7062=1.0/1.0/1.0, id7063=1.0/1.0/1.0, id7064=1.0/1.0/1.0, id7065=1.0/1.0/1.0, id7066=1.0/1.0/1.0, id7067=1.0/1.0/1.0, id7068=1.0/1.0/1.0, id7069=1.0/1.0/1.0, id707=1.0/1.0/1.0, id7070=1.0/1.0/1.0, id7071=1.0/1.0/1.0, id7072=1.0/1.0/1.0, id7073=1.0/1.0/1.0, id7074=1.0/1.0/1.0, id7075=1.0/1.0/1.0, id7076=1.0/1.0/1.0, id7077=1.0/1.0/1.0, id7078=1.0/1.0/1.0, id7079=1.0/1.0/1.0, id708=1.0/1.0/1.0, id7080=1.0/1.0/1.0, id7081=1.0/1.0/1.0, id7082=1.0/1.0/1.0, id7083=1.0/1.0/1.0, id7084=1.0/1.0/1.0, id7085=1.0/1.0/1.0, id7086=1.0/1.0/1.0, id7087=1.0/1.0/1.0, id7088=1.0/1.0/1.0, id7089=1.0/1.0/1.0, id709=1.0/1.0/1.0, id7090=1.0/1.0/1.0, id7091=1.0/1.0/1.0, id7092=1.0/1.0/1.0, id7093=1.0/1.0/1.0, id7094=1.0/1.0/1.0, id7095=1.0/1.0/1.0, id7096=1.0/1.0/1.0, id7097=1.0/1.0/1.0, id7098=1.0/1.0/1.0, id7099=1.0/1.0/1.0, id71=1.0/1.0/1.0, id710=1.0/1.0/1.0, id7100=1.0/1.0/1.0, id7101=1.0/1.0/1.0, id7102=1.0/1.0/1.0, id7103=1.0/1.0/1.0, id7104=1.0/1.0/1.0, id7105=1.0/1.0/1.0, id7106=1.0/1.0/1.0, id7107=1.0/1.0/1.0, id7108=1.0/1.0/1.0, id7109=1.0/1.0/1.0, id711=1.0/1.0/1.0, id7110=1.0/1.0/1.0, id7111=1.0/1.0/1.0, id7112=1.0/1.0/1.0, id7113=1.0/1.0/1.0, id7114=1.0/1.0/1.0, id7115=1.0/1.0/1.0, id7116=1.0/1.0/1.0, id7117=1.0/1.0/1.0, id7118=1.0/1.0/1.0, id7119=1.0/1.0/1.0, id712=1.0/1.0/1.0, id7120=1.0/1.0/1.0, id7121=1.0/1.0/1.0, id7122=1.0/1.0/1.0, id7123=1.0/1.0/1.0, id7124=1.0/1.0/1.0, id7125=1.0/1.0/1.0, id7126=1.0/1.0/1.0, id7127=1.0/1.0/1.0, id7128=1.0/1.0/1.0, id7129=1.0/1.0/1.0, id713=1.0/1.0/1.0, id7130=1.0/1.0/1.0, id7131=1.0/1.0/1.0, id7132=1.0/1.0/1.0, id7133=1.0/1.0/1.0, id7134=1.0/1.0/1.0, id7135=1.0/1.0/1.0, id7136=1.0/1.0/1.0, id7137=1.0/1.0/1.0, id7138=1.0/1.0/1.0, id7139=1.0/1.0/1.0, id714=1.0/1.0/1.0, id7140=1.0/1.0/1.0, id7141=1.0/1.0/1.0, id7142=1.0/1.0/1.0, id7143=1.0/1.0/1.0, id7144=1.0/1.0/1.0, id7145=1.0/1.0/1.0, id7146=1.0/1.0/1.0, id7147=1.0/1.0/1.0, id7148=1.0/1.0/1.0, id7149=1.0/1.0/1.0, id715=1.0/1.0/1.0, id7150=1.0/1.0/1.0, id7151=1.0/1.0/1.0, id7152=1.0/1.0/1.0, id7153=1.0/1.0/1.0, id7154=1.0/1.0/1.0, id7155=1.0/1.0/1.0, id7156=1.0/1.0/1.0, id7157=1.0/1.0/1.0, id7158=1.0/1.0/1.0, id7159=1.0/1.0/1.0, id716=1.0/1.0/1.0, id7160=1.0/1.0/1.0, id7161=1.0/1.0/1.0, id7162=1.0/1.0/1.0, id7163=1.0/1.0/1.0, id7164=1.0/1.0/1.0, id7165=1.0/1.0/1.0, id7166=1.0/1.0/1.0, id7167=1.0/1.0/1.0, id7168=1.0/1.0/1.0, id7169=1.0/1.0/1.0, id717=1.0/1.0/1.0, id7170=1.0/1.0/1.0, id7171=1.0/1.0/1.0, id7172=1.0/1.0/1.0, id7173=1.0/1.0/1.0, id7174=1.0/1.0/1.0, id7175=1.0/1.0/1.0, id7176=1.0/1.0/1.0, id7177=1.0/1.0/1.0, id7178=1.0/1.0/1.0, id7179=1.0/1.0/1.0, id718=1.0/1.0/1.0, id7180=1.0/1.0/1.0, id7181=1.0/1.0/1.0, id7182=1.0/1.0/1.0, id7183=1.0/1.0/1.0, id7184=1.0/1.0/1.0, id7185=1.0/1.0/1.0, id7186=1.0/1.0/1.0, id7187=1.0/1.0/1.0, id7188=1.0/1.0/1.0, id7189=1.0/1.0/1.0, id719=1.0/1.0/1.0, id7190=1.0/1.0/1.0, id7191=1.0/1.0/1.0, id7192=1.0/1.0/1.0, id7193=1.0/1.0/1.0, id7194=1.0/1.0/1.0, id7195=1.0/1.0/1.0, id7196=1.0/1.0/1.0, id7197=1.0/1.0/1.0, id7198=1.0/1.0/1.0, id7199=1.0/1.0/1.0, id72=1.0/1.0/1.0, id720=1.0/1.0/1.0, id7200=1.0/1.0/1.0, id7201=1.0/1.0/1.0, id7202=1.0/1.0/1.0, id7203=1.0/1.0/1.0, id7204=1.0/1.0/1.0, id7205=1.0/1.0/1.0, id7206=1.0/1.0/1.0, id7207=1.0/1.0/1.0, id7208=1.0/1.0/1.0, id7209=1.0/1.0/1.0, id721=1.0/1.0/1.0, id7210=1.0/1.0/1.0, id7211=1.0/1.0/1.0, id7212=1.0/1.0/1.0, id7213=1.0/1.0/1.0, id7214=1.0/1.0/1.0, id7215=1.0/1.0/1.0, id7216=1.0/1.0/1.0, id7217=1.0/1.0/1.0, id7218=1.0/1.0/1.0, id7219=1.0/1.0/1.0, id722=1.0/1.0/1.0, id7220=1.0/1.0/1.0, id7221=1.0/1.0/1.0, id7222=1.0/1.0/1.0, id7223=1.0/1.0/1.0, id7224=1.0/1.0/1.0, id7225=1.0/1.0/1.0, id7226=1.0/1.0/1.0, id7227=1.0/1.0/1.0, id7228=1.0/1.0/1.0, id7229=1.0/1.0/1.0, id723=1.0/1.0/1.0, id7230=1.0/1.0/1.0, id7231=1.0/1.0/1.0, id7232=1.0/1.0/1.0, id7233=1.0/1.0/1.0, id7234=1.0/1.0/1.0, id7235=1.0/1.0/1.0, id7236=1.0/1.0/1.0, id7237=1.0/1.0/1.0, id7238=1.0/1.0/1.0, id7239=1.0/1.0/1.0, id724=1.0/1.0/1.0, id7240=1.0/1.0/1.0, id7241=1.0/1.0/1.0, id7242=1.0/1.0/1.0, id7243=1.0/1.0/1.0, id7244=1.0/1.0/1.0, id7245=1.0/1.0/1.0, id7246=1.0/1.0/1.0, id7247=1.0/1.0/1.0, id7248=1.0/1.0/1.0, id7249=1.0/1.0/1.0, id725=1.0/1.0/1.0, id7250=1.0/1.0/1.0, id7251=1.0/1.0/1.0, id7252=1.0/1.0/1.0, id7253=1.0/1.0/1.0, id7254=1.0/1.0/1.0, id7255=1.0/1.0/1.0, id7256=1.0/1.0/1.0, id7257=1.0/1.0/1.0, id7258=1.0/1.0/1.0, id7259=1.0/1.0/1.0, id726=1.0/1.0/1.0, id7260=1.0/1.0/1.0, id7261=1.0/1.0/1.0, id7262=1.0/1.0/1.0, id7263=1.0/1.0/1.0, id7264=1.0/1.0/1.0, id7265=1.0/1.0/1.0, id7266=1.0/1.0/1.0, id7267=1.0/1.0/1.0, id7268=1.0/1.0/1.0, id7269=1.0/1.0/1.0, id727=1.0/1.0/1.0, id7270=1.0/1.0/1.0, id7271=1.0/1.0/1.0, id7272=1.0/1.0/1.0, id7273=1.0/1.0/1.0, id7274=1.0/1.0/1.0, id7275=1.0/1.0/1.0, id7276=1.0/1.0/1.0, id7277=1.0/1.0/1.0, id7278=1.0/1.0/1.0, id7279=1.0/1.0/1.0, id728=1.0/1.0/1.0, id7280=1.0/1.0/1.0, id7281=1.0/1.0/1.0, id7282=1.0/1.0/1.0, id7283=1.0/1.0/1.0, id7284=1.0/1.0/1.0, id7285=1.0/1.0/1.0, id7286=1.0/1.0/1.0, id7287=1.0/1.0/1.0, id7288=1.0/1.0/1.0, id7289=1.0/1.0/1.0, id729=1.0/1.0/1.0, id7290=1.0/1.0/1.0, id7291=1.0/1.0/1.0, id7292=1.0/1.0/1.0, id7293=1.0/1.0/1.0, id7294=1.0/1.0/1.0, id7295=1.0/1.0/1.0, id7296=1.0/1.0/1.0, id7297=1.0/1.0/1.0, id7298=1.0/1.0/1.0, id7299=1.0/1.0/1.0, id73=1.0/1.0/1.0, id730=1.0/1.0/1.0, id7300=1.0/1.0/1.0, id7301=1.0/1.0/1.0, id7302=1.0/1.0/1.0, id7303=1.0/1.0/1.0, id7304=1.0/1.0/1.0, id7305=1.0/1.0/1.0, id7306=1.0/1.0/1.0, id7307=1.0/1.0/1.0, id7308=1.0/1.0/1.0, id7309=1.0/1.0/1.0, id731=1.0/1.0/1.0, id7310=1.0/1.0/1.0, id7311=1.0/1.0/1.0, id7312=1.0/1.0/1.0, id7313=1.0/1.0/1.0, id7314=1.0/1.0/1.0, id7315=1.0/1.0/1.0, id7316=1.0/1.0/1.0, id7317=1.0/1.0/1.0, id7318=1.0/1.0/1.0, id7319=1.0/1.0/1.0, id732=1.0/1.0/1.0, id7320=1.0/1.0/1.0, id7321=1.0/1.0/1.0, id7322=1.0/1.0/1.0, id7323=1.0/1.0/1.0, id7324=1.0/1.0/1.0, id7325=1.0/1.0/1.0, id7326=1.0/1.0/1.0, id7327=1.0/1.0/1.0, id7328=1.0/1.0/1.0, id7329=1.0/1.0/1.0, id733=1.0/1.0/1.0, id7330=1.0/1.0/1.0, id7331=1.0/1.0/1.0, id7332=1.0/1.0/1.0, id7333=1.0/1.0/1.0, id7334=1.0/1.0/1.0, id7335=1.0/1.0/1.0, id7336=1.0/1.0/1.0, id7337=1.0/1.0/1.0, id7338=1.0/1.0/1.0, id7339=1.0/1.0/1.0, id734=1.0/1.0/1.0, id7340=1.0/1.0/1.0, id7341=1.0/1.0/1.0, id7342=1.0/1.0/1.0, id7343=1.0/1.0/1.0, id7344=1.0/1.0/1.0, id7345=1.0/1.0/1.0, id7346=1.0/1.0/1.0, id7347=1.0/1.0/1.0, id7348=1.0/1.0/1.0, id7349=1.0/1.0/1.0, id735=1.0/1.0/1.0, id7350=1.0/1.0/1.0, id7351=1.0/1.0/1.0, id7352=1.0/1.0/1.0, id7353=1.0/1.0/1.0, id7354=1.0/1.0/1.0, id7355=1.0/1.0/1.0, id7356=1.0/1.0/1.0, id7357=1.0/1.0/1.0, id7358=1.0/1.0/1.0, id7359=1.0/1.0/1.0, id736=1.0/1.0/1.0, id7360=1.0/1.0/1.0, id7361=1.0/1.0/1.0, id7362=1.0/1.0/1.0, id7363=1.0/1.0/1.0, id7364=1.0/1.0/1.0, id7365=1.0/1.0/1.0, id7366=1.0/1.0/1.0, id7367=1.0/1.0/1.0, id7368=1.0/1.0/1.0, id7369=1.0/1.0/1.0, id737=1.0/1.0/1.0, id7370=1.0/1.0/1.0, id7371=1.0/1.0/1.0, id7372=1.0/1.0/1.0, id7373=1.0/1.0/1.0, id7374=1.0/1.0/1.0, id7375=1.0/1.0/1.0, id7376=1.0/1.0/1.0, id7377=1.0/1.0/1.0, id7378=1.0/1.0/1.0, id7379=1.0/1.0/1.0, id738=1.0/1.0/1.0, id7380=1.0/1.0/1.0, id7381=1.0/1.0/1.0, id7382=1.0/1.0/1.0, id7383=1.0/1.0/1.0, id7384=1.0/1.0/1.0, id7385=1.0/1.0/1.0, id7386=1.0/1.0/1.0, id7387=1.0/1.0/1.0, id7388=1.0/1.0/1.0, id7389=1.0/1.0/1.0, id739=1.0/1.0/1.0, id7390=1.0/1.0/1.0, id7391=1.0/1.0/1.0, id7392=1.0/1.0/1.0, id7393=1.0/1.0/1.0, id7394=1.0/1.0/1.0, id7395=1.0/1.0/1.0, id7396=1.0/1.0/1.0, id7397=1.0/1.0/1.0, id7398=1.0/1.0/1.0, id7399=1.0/1.0/1.0, id74=1.0/1.0/1.0, id740=1.0/1.0/1.0, id7400=1.0/1.0/1.0, id7401=1.0/1.0/1.0, id7402=1.0/1.0/1.0, id7403=1.0/1.0/1.0, id7404=1.0/1.0/1.0, id7405=1.0/1.0/1.0, id7406=1.0/1.0/1.0, id7407=1.0/1.0/1.0, id7408=1.0/1.0/1.0, id7409=1.0/1.0/1.0, id741=1.0/1.0/1.0, id7410=1.0/1.0/1.0, id7411=1.0/1.0/1.0, id7412=1.0/1.0/1.0, id7413=1.0/1.0/1.0, id7414=1.0/1.0/1.0, id7415=1.0/1.0/1.0, id7416=1.0/1.0/1.0, id7417=1.0/1.0/1.0, id7418=1.0/1.0/1.0, id7419=1.0/1.0/1.0, id742=1.0/1.0/1.0, id7420=1.0/1.0/1.0, id7421=1.0/1.0/1.0, id7422=1.0/1.0/1.0, id7423=1.0/1.0/1.0, id7424=1.0/1.0/1.0, id7425=1.0/1.0/1.0, id7426=1.0/1.0/1.0, id7427=1.0/1.0/1.0, id7428=1.0/1.0/1.0, id7429=1.0/1.0/1.0, id743=1.0/1.0/1.0, id7430=1.0/1.0/1.0, id7431=1.0/1.0/1.0, id7432=1.0/1.0/1.0, id7433=1.0/1.0/1.0, id7434=1.0/1.0/1.0, id7435=1.0/1.0/1.0, id7436=1.0/1.0/1.0, id7437=1.0/1.0/1.0, id7438=1.0/1.0/1.0, id7439=1.0/1.0/1.0, id744=1.0/1.0/1.0, id7440=1.0/1.0/1.0, id7441=1.0/1.0/1.0, id7442=1.0/1.0/1.0, id7443=1.0/1.0/1.0, id7444=1.0/1.0/1.0, id7445=1.0/1.0/1.0, id7446=1.0/1.0/1.0, id7447=1.0/1.0/1.0, id7448=1.0/1.0/1.0, id7449=1.0/1.0/1.0, id745=1.0/1.0/1.0, id7450=1.0/1.0/1.0, id7451=1.0/1.0/1.0, id7452=1.0/1.0/1.0, id7453=1.0/1.0/1.0, id7454=1.0/1.0/1.0, id7455=1.0/1.0/1.0, id7456=1.0/1.0/1.0, id7457=1.0/1.0/1.0, id7458=1.0/1.0/1.0, id7459=1.0/1.0/1.0, id746=1.0/1.0/1.0, id7460=1.0/1.0/1.0, id7461=1.0/1.0/1.0, id7462=1.0/1.0/1.0, id7463=1.0/1.0/1.0, id7464=1.0/1.0/1.0, id7465=1.0/1.0/1.0, id7466=1.0/1.0/1.0, id7467=1.0/1.0/1.0, id7468=1.0/1.0/1.0, id7469=1.0/1.0/1.0, id747=1.0/1.0/1.0, id7470=1.0/1.0/1.0, id7471=1.0/1.0/1.0, id7472=1.0/1.0/1.0, id7473=1.0/1.0/1.0, id7474=1.0/1.0/1.0, id7475=1.0/1.0/1.0, id7476=1.0/1.0/1.0, id7477=1.0/1.0/1.0, id7478=1.0/1.0/1.0, id7479=1.0/1.0/1.0, id748=1.0/1.0/1.0, id7480=1.0/1.0/1.0, id7481=1.0/1.0/1.0, id7482=1.0/1.0/1.0, id7483=1.0/1.0/1.0, id7484=1.0/1.0/1.0, id7485=1.0/1.0/1.0, id7486=1.0/1.0/1.0, id7487=1.0/1.0/1.0, id7488=1.0/1.0/1.0, id7489=1.0/1.0/1.0, id749=1.0/1.0/1.0, id7490=1.0/1.0/1.0, id7491=1.0/1.0/1.0, id7492=1.0/1.0/1.0, id7493=1.0/1.0/1.0, id7494=1.0/1.0/1.0, id7495=1.0/1.0/1.0, id7496=1.0/1.0/1.0, id7497=1.0/1.0/1.0, id7498=1.0/1.0/1.0, id7499=1.0/1.0/1.0, id75=1.0/1.0/1.0, id750=1.0/1.0/1.0, id7500=1.0/1.0/1.0, id7501=1.0/1.0/1.0, id7502=1.0/1.0/1.0, id7503=1.0/1.0/1.0, id7504=1.0/1.0/1.0, id7505=1.0/1.0/1.0, id7506=1.0/1.0/1.0, id7507=1.0/1.0/1.0, id7508=1.0/1.0/1.0, id7509=1.0/1.0/1.0, id751=1.0/1.0/1.0, id7510=1.0/1.0/1.0, id7511=1.0/1.0/1.0, id7512=1.0/1.0/1.0, id7513=1.0/1.0/1.0, id7514=1.0/1.0/1.0, id7515=1.0/1.0/1.0, id7516=1.0/1.0/1.0, id7517=1.0/1.0/1.0, id7518=1.0/1.0/1.0, id7519=1.0/1.0/1.0, id752=1.0/1.0/1.0, id7520=1.0/1.0/1.0, id7521=1.0/1.0/1.0, id7522=1.0/1.0/1.0, id7523=1.0/1.0/1.0, id7524=1.0/1.0/1.0, id7525=1.0/1.0/1.0, id7526=1.0/1.0/1.0, id7527=1.0/1.0/1.0, id7528=1.0/1.0/1.0, id7529=1.0/1.0/1.0, id753=1.0/1.0/1.0, id7530=1.0/1.0/1.0, id7531=1.0/1.0/1.0, id7532=1.0/1.0/1.0, id7533=1.0/1.0/1.0, id7534=1.0/1.0/1.0, id7535=1.0/1.0/1.0, id7536=1.0/1.0/1.0, id7537=1.0/1.0/1.0, id7538=1.0/1.0/1.0, id7539=1.0/1.0/1.0, id754=1.0/1.0/1.0, id7540=1.0/1.0/1.0, id7541=1.0/1.0/1.0, id7542=1.0/1.0/1.0, id7543=1.0/1.0/1.0, id7544=1.0/1.0/1.0, id7545=1.0/1.0/1.0, id7546=1.0/1.0/1.0, id7547=1.0/1.0/1.0, id7548=1.0/1.0/1.0, id7549=1.0/1.0/1.0, id755=1.0/1.0/1.0, id7550=1.0/1.0/1.0, id7551=1.0/1.0/1.0, id7552=1.0/1.0/1.0, id7553=1.0/1.0/1.0, id7554=1.0/1.0/1.0, id7555=1.0/1.0/1.0, id7556=1.0/1.0/1.0, id7557=1.0/1.0/1.0, id7558=1.0/1.0/1.0, id7559=1.0/1.0/1.0, id756=1.0/1.0/1.0, id7560=1.0/1.0/1.0, id7561=1.0/1.0/1.0, id7562=1.0/1.0/1.0, id7563=1.0/1.0/1.0, id7564=1.0/1.0/1.0, id7565=1.0/1.0/1.0, id7566=1.0/1.0/1.0, id7567=1.0/1.0/1.0, id7568=1.0/1.0/1.0, id7569=1.0/1.0/1.0, id757=1.0/1.0/1.0, id7570=1.0/1.0/1.0, id7571=1.0/1.0/1.0, id7572=1.0/1.0/1.0, id7573=1.0/1.0/1.0, id7574=1.0/1.0/1.0, id7575=1.0/1.0/1.0, id7576=1.0/1.0/1.0, id7577=1.0/1.0/1.0, id7578=1.0/1.0/1.0, id7579=1.0/1.0/1.0, id758=1.0/1.0/1.0, id7580=1.0/1.0/1.0, id7581=1.0/1.0/1.0, id7582=1.0/1.0/1.0, id7583=1.0/1.0/1.0, id7584=1.0/1.0/1.0, id7585=1.0/1.0/1.0, id7586=1.0/1.0/1.0, id7587=1.0/1.0/1.0, id7588=1.0/1.0/1.0, id7589=1.0/1.0/1.0, id759=1.0/1.0/1.0, id7590=1.0/1.0/1.0, id7591=1.0/1.0/1.0, id7592=1.0/1.0/1.0, id7593=1.0/1.0/1.0, id7594=1.0/1.0/1.0, id7595=1.0/1.0/1.0, id7596=1.0/1.0/1.0, id7597=1.0/1.0/1.0, id7598=1.0/1.0/1.0, id7599=1.0/1.0/1.0, id76=1.0/1.0/1.0, id760=1.0/1.0/1.0, id7600=1.0/1.0/1.0, id7601=1.0/1.0/1.0, id7602=1.0/1.0/1.0, id7603=1.0/1.0/1.0, id7604=1.0/1.0/1.0, id7605=1.0/1.0/1.0, id7606=1.0/1.0/1.0, id7607=1.0/1.0/1.0, id7608=1.0/1.0/1.0, id7609=1.0/1.0/1.0, id761=1.0/1.0/1.0, id7610=1.0/1.0/1.0, id7611=1.0/1.0/1.0, id7612=1.0/1.0/1.0, id7613=1.0/1.0/1.0, id7614=1.0/1.0/1.0, id7615=1.0/1.0/1.0, id7616=1.0/1.0/1.0, id7617=1.0/1.0/1.0, id7618=1.0/1.0/1.0, id7619=1.0/1.0/1.0, id762=1.0/1.0/1.0, id7620=1.0/1.0/1.0, id7621=1.0/1.0/1.0, id7622=1.0/1.0/1.0, id7623=1.0/1.0/1.0, id7624=1.0/1.0/1.0, id7625=1.0/1.0/1.0, id7626=1.0/1.0/1.0, id7627=1.0/1.0/1.0, id7628=1.0/1.0/1.0, id7629=1.0/1.0/1.0, id763=1.0/1.0/1.0, id7630=1.0/1.0/1.0, id7631=1.0/1.0/1.0, id7632=1.0/1.0/1.0, id7633=1.0/1.0/1.0, id7634=1.0/1.0/1.0, id7635=1.0/1.0/1.0, id7636=1.0/1.0/1.0, id7637=1.0/1.0/1.0, id7638=1.0/1.0/1.0, id7639=1.0/1.0/1.0, id764=1.0/1.0/1.0, id7640=1.0/1.0/1.0, id7641=1.0/1.0/1.0, id7642=1.0/1.0/1.0, id7643=1.0/1.0/1.0, id7644=1.0/1.0/1.0, id7645=1.0/1.0/1.0, id7646=1.0/1.0/1.0, id7647=1.0/1.0/1.0, id7648=1.0/1.0/1.0, id7649=1.0/1.0/1.0, id765=1.0/1.0/1.0, id7650=1.0/1.0/1.0, id7651=1.0/1.0/1.0, id7652=1.0/1.0/1.0, id7653=1.0/1.0/1.0, id7654=1.0/1.0/1.0, id7655=1.0/1.0/1.0, id7656=1.0/1.0/1.0, id7657=1.0/1.0/1.0, id7658=1.0/1.0/1.0, id7659=1.0/1.0/1.0, id766=1.0/1.0/1.0, id7660=1.0/1.0/1.0, id7661=1.0/1.0/1.0, id7662=1.0/1.0/1.0, id7663=1.0/1.0/1.0, id7664=1.0/1.0/1.0, id7665=1.0/1.0/1.0, id7666=1.0/1.0/1.0, id7667=1.0/1.0/1.0, id7668=1.0/1.0/1.0, id7669=1.0/1.0/1.0, id767=1.0/1.0/1.0, id7670=1.0/1.0/1.0, id7671=1.0/1.0/1.0, id7672=1.0/1.0/1.0, id7673=1.0/1.0/1.0, id7674=1.0/1.0/1.0, id7675=1.0/1.0/1.0, id7676=1.0/1.0/1.0, id7677=1.0/1.0/1.0, id7678=1.0/1.0/1.0, id7679=1.0/1.0/1.0, id768=1.0/1.0/1.0, id7680=1.0/1.0/1.0, id7681=1.0/1.0/1.0, id7682=1.0/1.0/1.0, id7683=1.0/1.0/1.0, id7684=1.0/1.0/1.0, id7685=1.0/1.0/1.0, id7686=1.0/1.0/1.0, id7687=1.0/1.0/1.0, id7688=1.0/1.0/1.0, id7689=1.0/1.0/1.0, id769=1.0/1.0/1.0, id7690=1.0/1.0/1.0, id7691=1.0/1.0/1.0, id7692=1.0/1.0/1.0, id7693=1.0/1.0/1.0, id7694=1.0/1.0/1.0, id7695=1.0/1.0/1.0, id7696=1.0/1.0/1.0, id7697=1.0/1.0/1.0, id7698=1.0/1.0/1.0, id7699=1.0/1.0/1.0, id77=1.0/1.0/1.0, id770=1.0/1.0/1.0, id7700=1.0/1.0/1.0, id7701=1.0/1.0/1.0, id7702=1.0/1.0/1.0, id7703=1.0/1.0/1.0, id7704=1.0/1.0/1.0, id7705=1.0/1.0/1.0, id7706=1.0/1.0/1.0, id7707=1.0/1.0/1.0, id7708=1.0/1.0/1.0, id7709=1.0/1.0/1.0, id771=1.0/1.0/1.0, id7710=1.0/1.0/1.0, id7711=1.0/1.0/1.0, id7712=1.0/1.0/1.0, id7713=1.0/1.0/1.0, id7714=1.0/1.0/1.0, id7715=1.0/1.0/1.0, id7716=1.0/1.0/1.0, id7717=1.0/1.0/1.0, id7718=1.0/1.0/1.0, id7719=1.0/1.0/1.0, id772=1.0/1.0/1.0, id7720=1.0/1.0/1.0, id7721=1.0/1.0/1.0, id7722=1.0/1.0/1.0, id7723=1.0/1.0/1.0, id7724=1.0/1.0/1.0, id7725=1.0/1.0/1.0, id7726=1.0/1.0/1.0, id7727=1.0/1.0/1.0, id7728=1.0/1.0/1.0, id7729=1.0/1.0/1.0, id773=1.0/1.0/1.0, id7730=1.0/1.0/1.0, id7731=1.0/1.0/1.0, id7732=1.0/1.0/1.0, id7733=1.0/1.0/1.0, id7734=1.0/1.0/1.0, id7735=1.0/1.0/1.0, id7736=1.0/1.0/1.0, id7737=1.0/1.0/1.0, id7738=1.0/1.0/1.0, id7739=1.0/1.0/1.0, id774=1.0/1.0/1.0, id7740=1.0/1.0/1.0, id7741=1.0/1.0/1.0, id7742=1.0/1.0/1.0, id7743=1.0/1.0/1.0, id7744=1.0/1.0/1.0, id7745=1.0/1.0/1.0, id7746=1.0/1.0/1.0, id7747=1.0/1.0/1.0, id7748=1.0/1.0/1.0, id7749=1.0/1.0/1.0, id775=1.0/1.0/1.0, id7750=1.0/1.0/1.0, id7751=1.0/1.0/1.0, id7752=1.0/1.0/1.0, id7753=1.0/1.0/1.0, id7754=1.0/1.0/1.0, id7755=1.0/1.0/1.0, id7756=1.0/1.0/1.0, id7757=1.0/1.0/1.0, id7758=1.0/1.0/1.0, id7759=1.0/1.0/1.0, id776=1.0/1.0/1.0, id7760=1.0/1.0/1.0, id7761=1.0/1.0/1.0, id7762=1.0/1.0/1.0, id7763=1.0/1.0/1.0, id7764=1.0/1.0/1.0, id7765=1.0/1.0/1.0, id7766=1.0/1.0/1.0, id7767=1.0/1.0/1.0, id7768=1.0/1.0/1.0, id7769=1.0/1.0/1.0, id777=1.0/1.0/1.0, id7770=1.0/1.0/1.0, id7771=1.0/1.0/1.0, id7772=1.0/1.0/1.0, id7773=1.0/1.0/1.0, id7774=1.0/1.0/1.0, id7775=1.0/1.0/1.0, id7776=1.0/1.0/1.0, id7777=1.0/1.0/1.0, id7778=1.0/1.0/1.0, id7779=1.0/1.0/1.0, id778=1.0/1.0/1.0, id7780=1.0/1.0/1.0, id7781=1.0/1.0/1.0, id7782=1.0/1.0/1.0, id7783=1.0/1.0/1.0, id7784=1.0/1.0/1.0, id7785=1.0/1.0/1.0, id7786=1.0/1.0/1.0, id7787=1.0/1.0/1.0, id7788=1.0/1.0/1.0, id7789=1.0/1.0/1.0, id779=1.0/1.0/1.0, id7790=1.0/1.0/1.0, id7791=1.0/1.0/1.0, id7792=1.0/1.0/1.0, id7793=1.0/1.0/1.0, id7794=1.0/1.0/1.0, id7795=1.0/1.0/1.0, id7796=1.0/1.0/1.0, id7797=1.0/1.0/1.0, id7798=1.0/1.0/1.0, id7799=1.0/1.0/1.0, id78=1.0/1.0/1.0, id780=1.0/1.0/1.0, id7800=1.0/1.0/1.0, id7801=1.0/1.0/1.0, id7802=1.0/1.0/1.0, id7803=1.0/1.0/1.0, id7804=1.0/1.0/1.0, id7805=1.0/1.0/1.0, id7806=1.0/1.0/1.0, id7807=1.0/1.0/1.0, id7808=1.0/1.0/1.0, id7809=1.0/1.0/1.0, id781=1.0/1.0/1.0, id7810=1.0/1.0/1.0, id7811=1.0/1.0/1.0, id7812=1.0/1.0/1.0, id7813=1.0/1.0/1.0, id7814=1.0/1.0/1.0, id7815=1.0/1.0/1.0, id7816=1.0/1.0/1.0, id7817=1.0/1.0/1.0, id7818=1.0/1.0/1.0, id7819=1.0/1.0/1.0, id782=1.0/1.0/1.0, id7820=1.0/1.0/1.0, id7821=1.0/1.0/1.0, id7822=1.0/1.0/1.0, id7823=1.0/1.0/1.0, id7824=1.0/1.0/1.0, id7825=1.0/1.0/1.0, id7826=1.0/1.0/1.0, id7827=1.0/1.0/1.0, id7828=1.0/1.0/1.0, id7829=1.0/1.0/1.0, id783=1.0/1.0/1.0, id7830=1.0/1.0/1.0, id7831=1.0/1.0/1.0, id7832=1.0/1.0/1.0, id7833=1.0/1.0/1.0, id7834=1.0/1.0/1.0, id7835=1.0/1.0/1.0, id7836=1.0/1.0/1.0, id7837=1.0/1.0/1.0, id7838=1.0/1.0/1.0, id7839=1.0/1.0/1.0, id784=1.0/1.0/1.0, id7840=1.0/1.0/1.0, id7841=1.0/1.0/1.0, id7842=1.0/1.0/1.0, id7843=1.0/1.0/1.0, id7844=1.0/1.0/1.0, id7845=1.0/1.0/1.0, id7846=1.0/1.0/1.0, id7847=1.0/1.0/1.0, id7848=1.0/1.0/1.0, id7849=1.0/1.0/1.0, id785=1.0/1.0/1.0, id7850=1.0/1.0/1.0, id7851=1.0/1.0/1.0, id7852=1.0/1.0/1.0, id7853=1.0/1.0/1.0, id7854=1.0/1.0/1.0, id7855=1.0/1.0/1.0, id7856=1.0/1.0/1.0, id7857=1.0/1.0/1.0, id7858=1.0/1.0/1.0, id7859=1.0/1.0/1.0, id786=1.0/1.0/1.0, id7860=1.0/1.0/1.0, id7861=1.0/1.0/1.0, id7862=1.0/1.0/1.0, id7863=1.0/1.0/1.0, id7864=1.0/1.0/1.0, id7865=1.0/1.0/1.0, id7866=1.0/1.0/1.0, id7867=1.0/1.0/1.0, id7868=1.0/1.0/1.0, id7869=1.0/1.0/1.0, id787=1.0/1.0/1.0, id7870=1.0/1.0/1.0, id7871=1.0/1.0/1.0, id7872=1.0/1.0/1.0, id7873=1.0/1.0/1.0, id7874=1.0/1.0/1.0, id7875=1.0/1.0/1.0, id7876=1.0/1.0/1.0, id7877=1.0/1.0/1.0, id7878=1.0/1.0/1.0, id7879=1.0/1.0/1.0, id788=1.0/1.0/1.0, id7880=1.0/1.0/1.0, id7881=1.0/1.0/1.0, id7882=1.0/1.0/1.0, id7883=1.0/1.0/1.0, id7884=1.0/1.0/1.0, id7885=1.0/1.0/1.0, id7886=1.0/1.0/1.0, id7887=1.0/1.0/1.0, id7888=1.0/1.0/1.0, id7889=1.0/1.0/1.0, id789=1.0/1.0/1.0, id7890=1.0/1.0/1.0, id7891=1.0/1.0/1.0, id7892=1.0/1.0/1.0, id7893=1.0/1.0/1.0, id7894=1.0/1.0/1.0, id7895=1.0/1.0/1.0, id7896=1.0/1.0/1.0, id7897=1.0/1.0/1.0, id7898=1.0/1.0/1.0, id7899=1.0/1.0/1.0, id79=1.0/1.0/1.0, id790=1.0/1.0/1.0, id7900=1.0/1.0/1.0, id7901=1.0/1.0/1.0, id7902=1.0/1.0/1.0, id7903=1.0/1.0/1.0, id7904=1.0/1.0/1.0, id7905=1.0/1.0/1.0, id7906=1.0/1.0/1.0, id7907=1.0/1.0/1.0, id7908=1.0/1.0/1.0, id7909=1.0/1.0/1.0, id791=1.0/1.0/1.0, id7910=1.0/1.0/1.0, id7911=1.0/1.0/1.0, id7912=1.0/1.0/1.0, id7913=1.0/1.0/1.0, id7914=1.0/1.0/1.0, id7915=1.0/1.0/1.0, id7916=1.0/1.0/1.0, id7917=1.0/1.0/1.0, id7918=1.0/1.0/1.0, id7919=1.0/1.0/1.0, id792=1.0/1.0/1.0, id7920=1.0/1.0/1.0, id7921=1.0/1.0/1.0, id7922=1.0/1.0/1.0, id7923=1.0/1.0/1.0, id7924=1.0/1.0/1.0, id7925=1.0/1.0/1.0, id7926=1.0/1.0/1.0, id7927=1.0/1.0/1.0, id7928=1.0/1.0/1.0, id7929=1.0/1.0/1.0, id793=1.0/1.0/1.0, id7930=1.0/1.0/1.0, id7931=1.0/1.0/1.0, id7932=1.0/1.0/1.0, id7933=1.0/1.0/1.0, id7934=1.0/1.0/1.0, id7935=1.0/1.0/1.0, id7936=1.0/1.0/1.0, id7937=1.0/1.0/1.0, id7938=1.0/1.0/1.0, id7939=1.0/1.0/1.0, id794=1.0/1.0/1.0, id7940=1.0/1.0/1.0, id7941=1.0/1.0/1.0, id7942=1.0/1.0/1.0, id7943=1.0/1.0/1.0, id7944=1.0/1.0/1.0, id7945=1.0/1.0/1.0, id7946=1.0/1.0/1.0, id7947=1.0/1.0/1.0, id7948=1.0/1.0/1.0, id7949=1.0/1.0/1.0, id795=1.0/1.0/1.0, id7950=1.0/1.0/1.0, id7951=1.0/1.0/1.0, id7952=1.0/1.0/1.0, id7953=1.0/1.0/1.0, id7954=1.0/1.0/1.0, id7955=1.0/1.0/1.0, id7956=1.0/1.0/1.0, id7957=1.0/1.0/1.0, id7958=1.0/1.0/1.0, id7959=1.0/1.0/1.0, id796=1.0/1.0/1.0, id7960=1.0/1.0/1.0, id7961=1.0/1.0/1.0, id7962=1.0/1.0/1.0, id7963=1.0/1.0/1.0, id7964=1.0/1.0/1.0, id7965=1.0/1.0/1.0, id7966=1.0/1.0/1.0, id7967=1.0/1.0/1.0, id7968=1.0/1.0/1.0, id7969=1.0/1.0/1.0, id797=1.0/1.0/1.0, id7970=1.0/1.0/1.0, id7971=1.0/1.0/1.0, id7972=1.0/1.0/1.0, id7973=1.0/1.0/1.0, id7974=1.0/1.0/1.0, id7975=1.0/1.0/1.0, id7976=1.0/1.0/1.0, id7977=1.0/1.0/1.0, id7978=1.0/1.0/1.0, id7979=1.0/1.0/1.0, id798=1.0/1.0/1.0, id7980=1.0/1.0/1.0, id7981=1.0/1.0/1.0, id7982=1.0/1.0/1.0, id7983=1.0/1.0/1.0, id7984=1.0/1.0/1.0, id7985=1.0/1.0/1.0, id7986=1.0/1.0/1.0, id7987=1.0/1.0/1.0, id7988=1.0/1.0/1.0, id7989=1.0/1.0/1.0, id799=1.0/1.0/1.0, id7990=1.0/1.0/1.0, id7991=1.0/1.0/1.0, id7992=1.0/1.0/1.0, id7993=1.0/1.0/1.0, id7994=1.0/1.0/1.0, id7995=1.0/1.0/1.0, id7996=1.0/1.0/1.0, id7997=1.0/1.0/1.0, id7998=1.0/1.0/1.0, id7999=1.0/1.0/1.0, id8=1.0/1.0/1.0, id80=1.0/1.0/1.0, id800=1.0/1.0/1.0, id8000=1.0/1.0/1.0, id8001=1.0/1.0/1.0, id8002=1.0/1.0/1.0, id8003=1.0/1.0/1.0, id8004=1.0/1.0/1.0, id8005=1.0/1.0/1.0, id8006=1.0/1.0/1.0, id8007=1.0/1.0/1.0, id8008=1.0/1.0/1.0, id8009=1.0/1.0/1.0, id801=1.0/1.0/1.0, id8010=1.0/1.0/1.0, id8011=1.0/1.0/1.0, id8012=1.0/1.0/1.0, id8013=1.0/1.0/1.0, id8014=1.0/1.0/1.0, id8015=1.0/1.0/1.0, id8016=1.0/1.0/1.0, id8017=1.0/1.0/1.0, id8018=1.0/1.0/1.0, id8019=1.0/1.0/1.0, id802=1.0/1.0/1.0, id8020=1.0/1.0/1.0, id8021=1.0/1.0/1.0, id8022=1.0/1.0/1.0, id8023=1.0/1.0/1.0, id8024=1.0/1.0/1.0, id8025=1.0/1.0/1.0, id8026=1.0/1.0/1.0, id8027=1.0/1.0/1.0, id8028=1.0/1.0/1.0, id8029=1.0/1.0/1.0, id803=1.0/1.0/1.0, id8030=1.0/1.0/1.0, id8031=1.0/1.0/1.0, id8032=1.0/1.0/1.0, id8033=1.0/1.0/1.0, id8034=1.0/1.0/1.0, id8035=1.0/1.0/1.0, id8036=1.0/1.0/1.0, id8037=1.0/1.0/1.0, id8038=1.0/1.0/1.0, id8039=1.0/1.0/1.0, id804=1.0/1.0/1.0, id8040=1.0/1.0/1.0, id8041=1.0/1.0/1.0, id8042=1.0/1.0/1.0, id8043=1.0/1.0/1.0, id8044=1.0/1.0/1.0, id8045=1.0/1.0/1.0, id8046=1.0/1.0/1.0, id8047=1.0/1.0/1.0, id8048=1.0/1.0/1.0, id8049=1.0/1.0/1.0, id805=1.0/1.0/1.0, id8050=1.0/1.0/1.0, id8051=1.0/1.0/1.0, id8052=1.0/1.0/1.0, id8053=1.0/1.0/1.0, id8054=1.0/1.0/1.0, id8055=1.0/1.0/1.0, id8056=1.0/1.0/1.0, id8057=1.0/1.0/1.0, id8058=1.0/1.0/1.0, id8059=1.0/1.0/1.0, id806=1.0/1.0/1.0, id8060=1.0/1.0/1.0, id8061=1.0/1.0/1.0, id8062=1.0/1.0/1.0, id8063=1.0/1.0/1.0, id8064=1.0/1.0/1.0, id8065=1.0/1.0/1.0, id8066=1.0/1.0/1.0, id8067=1.0/1.0/1.0, id8068=1.0/1.0/1.0, id8069=1.0/1.0/1.0, id807=1.0/1.0/1.0, id8070=1.0/1.0/1.0, id8071=1.0/1.0/1.0, id8072=1.0/1.0/1.0, id8073=1.0/1.0/1.0, id8074=1.0/1.0/1.0, id8075=1.0/1.0/1.0, id8076=1.0/1.0/1.0, id8077=1.0/1.0/1.0, id8078=1.0/1.0/1.0, id8079=1.0/1.0/1.0, id808=1.0/1.0/1.0, id8080=1.0/1.0/1.0, id8081=1.0/1.0/1.0, id8082=1.0/1.0/1.0, id8083=1.0/1.0/1.0, id8084=1.0/1.0/1.0, id8085=1.0/1.0/1.0, id8086=1.0/1.0/1.0, id8087=1.0/1.0/1.0, id8088=1.0/1.0/1.0, id8089=1.0/1.0/1.0, id809=1.0/1.0/1.0, id8090=1.0/1.0/1.0, id8091=1.0/1.0/1.0, id8092=1.0/1.0/1.0, id8093=1.0/1.0/1.0, id8094=1.0/1.0/1.0, id8095=1.0/1.0/1.0, id8096=1.0/1.0/1.0, id8097=1.0/1.0/1.0, id8098=1.0/1.0/1.0, id8099=1.0/1.0/1.0, id81=1.0/1.0/1.0, id810=1.0/1.0/1.0, id8100=1.0/1.0/1.0, id8101=1.0/1.0/1.0, id8102=1.0/1.0/1.0, id8103=1.0/1.0/1.0, id8104=1.0/1.0/1.0, id8105=1.0/1.0/1.0, id8106=1.0/1.0/1.0, id8107=1.0/1.0/1.0, id8108=1.0/1.0/1.0, id8109=1.0/1.0/1.0, id811=1.0/1.0/1.0, id8110=1.0/1.0/1.0, id8111=1.0/1.0/1.0, id8112=1.0/1.0/1.0, id8113=1.0/1.0/1.0, id8114=1.0/1.0/1.0, id8115=1.0/1.0/1.0, id8116=1.0/1.0/1.0, id8117=1.0/1.0/1.0, id8118=1.0/1.0/1.0, id8119=1.0/1.0/1.0, id812=1.0/1.0/1.0, id8120=1.0/1.0/1.0, id8121=1.0/1.0/1.0, id8122=1.0/1.0/1.0, id8123=1.0/1.0/1.0, id8124=1.0/1.0/1.0, id8125=1.0/1.0/1.0, id8126=1.0/1.0/1.0, id8127=1.0/1.0/1.0, id8128=1.0/1.0/1.0, id8129=1.0/1.0/1.0, id813=1.0/1.0/1.0, id8130=1.0/1.0/1.0, id8131=1.0/1.0/1.0, id8132=1.0/1.0/1.0, id8133=1.0/1.0/1.0, id8134=1.0/1.0/1.0, id8135=1.0/1.0/1.0, id8136=1.0/1.0/1.0, id8137=1.0/1.0/1.0, id8138=1.0/1.0/1.0, id8139=1.0/1.0/1.0, id814=1.0/1.0/1.0, id8140=1.0/1.0/1.0, id8141=1.0/1.0/1.0, id8142=1.0/1.0/1.0, id8143=1.0/1.0/1.0, id8144=1.0/1.0/1.0, id8145=1.0/1.0/1.0, id8146=1.0/1.0/1.0, id8147=1.0/1.0/1.0, id8148=1.0/1.0/1.0, id8149=1.0/1.0/1.0, id815=1.0/1.0/1.0, id8150=1.0/1.0/1.0, id8151=1.0/1.0/1.0, id8152=1.0/1.0/1.0, id8153=1.0/1.0/1.0, id8154=1.0/1.0/1.0, id8155=1.0/1.0/1.0, id8156=1.0/1.0/1.0, id8157=1.0/1.0/1.0, id8158=1.0/1.0/1.0, id8159=1.0/1.0/1.0, id816=1.0/1.0/1.0, id8160=1.0/1.0/1.0, id8161=1.0/1.0/1.0, id8162=1.0/1.0/1.0, id8163=1.0/1.0/1.0, id8164=1.0/1.0/1.0, id8165=1.0/1.0/1.0, id8166=1.0/1.0/1.0, id8167=1.0/1.0/1.0, id8168=1.0/1.0/1.0, id8169=1.0/1.0/1.0, id817=1.0/1.0/1.0, id8170=1.0/1.0/1.0, id8171=1.0/1.0/1.0, id8172=1.0/1.0/1.0, id8173=1.0/1.0/1.0, id8174=1.0/1.0/1.0, id8175=1.0/1.0/1.0, id8176=1.0/1.0/1.0, id8177=1.0/1.0/1.0, id8178=1.0/1.0/1.0, id8179=1.0/1.0/1.0, id818=1.0/1.0/1.0, id8180=1.0/1.0/1.0, id8181=1.0/1.0/1.0, id8182=1.0/1.0/1.0, id8183=1.0/1.0/1.0, id8184=1.0/1.0/1.0, id8185=1.0/1.0/1.0, id8186=1.0/1.0/1.0, id8187=1.0/1.0/1.0, id8188=1.0/1.0/1.0, id8189=1.0/1.0/1.0, id819=1.0/1.0/1.0, id8190=1.0/1.0/1.0, id8191=1.0/1.0/1.0, id8192=1.0/1.0/1.0, id8193=1.0/1.0/1.0, id8194=1.0/1.0/1.0, id8195=1.0/1.0/1.0, id8196=1.0/1.0/1.0, id8197=1.0/1.0/1.0, id8198=1.0/1.0/1.0, id8199=1.0/1.0/1.0, id82=1.0/1.0/1.0, id820=1.0/1.0/1.0, id8200=1.0/1.0/1.0, id8201=1.0/1.0/1.0, id8202=1.0/1.0/1.0, id8203=1.0/1.0/1.0, id8204=1.0/1.0/1.0, id8205=1.0/1.0/1.0, id8206=1.0/1.0/1.0, id8207=1.0/1.0/1.0, id8208=1.0/1.0/1.0, id8209=1.0/1.0/1.0, id821=1.0/1.0/1.0, id8210=1.0/1.0/1.0, id8211=1.0/1.0/1.0, id8212=1.0/1.0/1.0, id8213=1.0/1.0/1.0, id8214=1.0/1.0/1.0, id8215=1.0/1.0/1.0, id8216=1.0/1.0/1.0, id8217=1.0/1.0/1.0, id8218=1.0/1.0/1.0, id8219=1.0/1.0/1.0, id822=1.0/1.0/1.0, id8220=1.0/1.0/1.0, id8221=1.0/1.0/1.0, id8222=1.0/1.0/1.0, id8223=1.0/1.0/1.0, id8224=1.0/1.0/1.0, id8225=1.0/1.0/1.0, id8226=1.0/1.0/1.0, id8227=1.0/1.0/1.0, id8228=1.0/1.0/1.0, id8229=1.0/1.0/1.0, id823=1.0/1.0/1.0, id8230=1.0/1.0/1.0, id8231=1.0/1.0/1.0, id8232=1.0/1.0/1.0, id8233=1.0/1.0/1.0, id8234=1.0/1.0/1.0, id8235=1.0/1.0/1.0, id8236=1.0/1.0/1.0, id8237=1.0/1.0/1.0, id8238=1.0/1.0/1.0, id8239=1.0/1.0/1.0, id824=1.0/1.0/1.0, id8240=1.0/1.0/1.0, id8241=1.0/1.0/1.0, id8242=1.0/1.0/1.0, id8243=1.0/1.0/1.0, id8244=1.0/1.0/1.0, id8245=1.0/1.0/1.0, id8246=1.0/1.0/1.0, id8247=1.0/1.0/1.0, id8248=1.0/1.0/1.0, id8249=1.0/1.0/1.0, id825=1.0/1.0/1.0, id8250=1.0/1.0/1.0, id8251=1.0/1.0/1.0, id8252=1.0/1.0/1.0, id8253=1.0/1.0/1.0, id8254=1.0/1.0/1.0, id8255=1.0/1.0/1.0, id8256=1.0/1.0/1.0, id8257=1.0/1.0/1.0, id8258=1.0/1.0/1.0, id8259=1.0/1.0/1.0, id826=1.0/1.0/1.0, id8260=1.0/1.0/1.0, id8261=1.0/1.0/1.0, id8262=1.0/1.0/1.0, id8263=1.0/1.0/1.0, id8264=1.0/1.0/1.0, id8265=1.0/1.0/1.0, id8266=1.0/1.0/1.0, id8267=1.0/1.0/1.0, id8268=1.0/1.0/1.0, id8269=1.0/1.0/1.0, id827=1.0/1.0/1.0, id8270=1.0/1.0/1.0, id8271=1.0/1.0/1.0, id8272=1.0/1.0/1.0, id8273=1.0/1.0/1.0, id8274=1.0/1.0/1.0, id8275=1.0/1.0/1.0, id8276=1.0/1.0/1.0, id8277=1.0/1.0/1.0, id8278=1.0/1.0/1.0, id8279=1.0/1.0/1.0, id828=1.0/1.0/1.0, id8280=1.0/1.0/1.0, id8281=1.0/1.0/1.0, id8282=1.0/1.0/1.0, id8283=1.0/1.0/1.0, id8284=1.0/1.0/1.0, id8285=1.0/1.0/1.0, id8286=1.0/1.0/1.0, id8287=1.0/1.0/1.0, id8288=1.0/1.0/1.0, id8289=1.0/1.0/1.0, id829=1.0/1.0/1.0, id8290=1.0/1.0/1.0, id8291=1.0/1.0/1.0, id8292=1.0/1.0/1.0, id8293=1.0/1.0/1.0, id8294=1.0/1.0/1.0, id8295=1.0/1.0/1.0, id8296=1.0/1.0/1.0, id8297=1.0/1.0/1.0, id8298=1.0/1.0/1.0, id8299=1.0/1.0/1.0, id83=1.0/1.0/1.0, id830=1.0/1.0/1.0, id8300=1.0/1.0/1.0, id8301=1.0/1.0/1.0, id8302=1.0/1.0/1.0, id8303=1.0/1.0/1.0, id8304=1.0/1.0/1.0, id8305=1.0/1.0/1.0, id8306=1.0/1.0/1.0, id8307=1.0/1.0/1.0, id8308=1.0/1.0/1.0, id8309=1.0/1.0/1.0, id831=1.0/1.0/1.0, id8310=1.0/1.0/1.0, id8311=1.0/1.0/1.0, id8312=1.0/1.0/1.0, id8313=1.0/1.0/1.0, id8314=1.0/1.0/1.0, id8315=1.0/1.0/1.0, id8316=1.0/1.0/1.0, id8317=1.0/1.0/1.0, id8318=1.0/1.0/1.0, id8319=1.0/1.0/1.0, id832=1.0/1.0/1.0, id8320=1.0/1.0/1.0, id8321=1.0/1.0/1.0, id8322=1.0/1.0/1.0, id8323=1.0/1.0/1.0, id8324=1.0/1.0/1.0, id8325=1.0/1.0/1.0, id8326=1.0/1.0/1.0, id8327=1.0/1.0/1.0, id8328=1.0/1.0/1.0, id8329=1.0/1.0/1.0, id833=1.0/1.0/1.0, id8330=1.0/1.0/1.0, id8331=1.0/1.0/1.0, id8332=1.0/1.0/1.0, id8333=1.0/1.0/1.0, id8334=1.0/1.0/1.0, id8335=1.0/1.0/1.0, id8336=1.0/1.0/1.0, id8337=1.0/1.0/1.0, id8338=1.0/1.0/1.0, id8339=1.0/1.0/1.0, id834=1.0/1.0/1.0, id8340=1.0/1.0/1.0, id8341=1.0/1.0/1.0, id8342=1.0/1.0/1.0, id8343=1.0/1.0/1.0, id8344=1.0/1.0/1.0, id8345=1.0/1.0/1.0, id8346=1.0/1.0/1.0, id8347=1.0/1.0/1.0, id8348=1.0/1.0/1.0, id8349=1.0/1.0/1.0, id835=1.0/1.0/1.0, id8350=1.0/1.0/1.0, id8351=1.0/1.0/1.0, id8352=1.0/1.0/1.0, id8353=1.0/1.0/1.0, id8354=1.0/1.0/1.0, id8355=1.0/1.0/1.0, id8356=1.0/1.0/1.0, id8357=1.0/1.0/1.0, id8358=1.0/1.0/1.0, id8359=1.0/1.0/1.0, id836=1.0/1.0/1.0, id8360=1.0/1.0/1.0, id8361=1.0/1.0/1.0, id8362=1.0/1.0/1.0, id8363=1.0/1.0/1.0, id8364=1.0/1.0/1.0, id8365=1.0/1.0/1.0, id8366=1.0/1.0/1.0, id8367=1.0/1.0/1.0, id8368=1.0/1.0/1.0, id8369=1.0/1.0/1.0, id837=1.0/1.0/1.0, id8370=1.0/1.0/1.0, id8371=1.0/1.0/1.0, id8372=1.0/1.0/1.0, id8373=1.0/1.0/1.0, id8374=1.0/1.0/1.0, id8375=1.0/1.0/1.0, id8376=1.0/1.0/1.0, id8377=1.0/1.0/1.0, id8378=1.0/1.0/1.0, id8379=1.0/1.0/1.0, id838=1.0/1.0/1.0, id8380=1.0/1.0/1.0, id8381=1.0/1.0/1.0, id8382=1.0/1.0/1.0, id8383=1.0/1.0/1.0, id8384=1.0/1.0/1.0, id8385=1.0/1.0/1.0, id8386=1.0/1.0/1.0, id8387=1.0/1.0/1.0, id8388=1.0/1.0/1.0, id8389=1.0/1.0/1.0, id839=1.0/1.0/1.0, id8390=1.0/1.0/1.0, id8391=1.0/1.0/1.0, id8392=1.0/1.0/1.0, id8393=1.0/1.0/1.0, id8394=1.0/1.0/1.0, id8395=1.0/1.0/1.0, id8396=1.0/1.0/1.0, id8397=1.0/1.0/1.0, id8398=1.0/1.0/1.0, id8399=1.0/1.0/1.0, id84=1.0/1.0/1.0, id840=1.0/1.0/1.0, id8400=1.0/1.0/1.0, id8401=1.0/1.0/1.0, id8402=1.0/1.0/1.0, id8403=1.0/1.0/1.0, id8404=1.0/1.0/1.0, id8405=1.0/1.0/1.0, id8406=1.0/1.0/1.0, id8407=1.0/1.0/1.0, id8408=1.0/1.0/1.0, id8409=1.0/1.0/1.0, id841=1.0/1.0/1.0, id8410=1.0/1.0/1.0, id8411=1.0/1.0/1.0, id8412=1.0/1.0/1.0, id8413=1.0/1.0/1.0, id8414=1.0/1.0/1.0, id8415=1.0/1.0/1.0, id8416=1.0/1.0/1.0, id8417=1.0/1.0/1.0, id8418=1.0/1.0/1.0, id8419=1.0/1.0/1.0, id842=1.0/1.0/1.0, id8420=1.0/1.0/1.0, id8421=1.0/1.0/1.0, id8422=1.0/1.0/1.0, id8423=1.0/1.0/1.0, id8424=1.0/1.0/1.0, id8425=1.0/1.0/1.0, id8426=1.0/1.0/1.0, id8427=1.0/1.0/1.0, id8428=1.0/1.0/1.0, id8429=1.0/1.0/1.0, id843=1.0/1.0/1.0, id8430=1.0/1.0/1.0, id8431=1.0/1.0/1.0, id8432=1.0/1.0/1.0, id8433=1.0/1.0/1.0, id8434=1.0/1.0/1.0, id8435=1.0/1.0/1.0, id8436=1.0/1.0/1.0, id8437=1.0/1.0/1.0, id8438=1.0/1.0/1.0, id8439=1.0/1.0/1.0, id844=1.0/1.0/1.0, id8440=1.0/1.0/1.0, id8441=1.0/1.0/1.0, id8442=1.0/1.0/1.0, id8443=1.0/1.0/1.0, id8444=1.0/1.0/1.0, id8445=1.0/1.0/1.0, id8446=1.0/1.0/1.0, id8447=1.0/1.0/1.0, id8448=1.0/1.0/1.0, id8449=1.0/1.0/1.0, id845=1.0/1.0/1.0, id8450=1.0/1.0/1.0, id8451=1.0/1.0/1.0, id8452=1.0/1.0/1.0, id8453=1.0/1.0/1.0, id8454=1.0/1.0/1.0, id8455=1.0/1.0/1.0, id8456=1.0/1.0/1.0, id8457=1.0/1.0/1.0, id8458=1.0/1.0/1.0, id8459=1.0/1.0/1.0, id846=1.0/1.0/1.0, id8460=1.0/1.0/1.0, id8461=1.0/1.0/1.0, id8462=1.0/1.0/1.0, id8463=1.0/1.0/1.0, id8464=1.0/1.0/1.0, id8465=1.0/1.0/1.0, id8466=1.0/1.0/1.0, id8467=1.0/1.0/1.0, id8468=1.0/1.0/1.0, id8469=1.0/1.0/1.0, id847=1.0/1.0/1.0, id8470=1.0/1.0/1.0, id8471=1.0/1.0/1.0, id8472=1.0/1.0/1.0, id8473=1.0/1.0/1.0, id8474=1.0/1.0/1.0, id8475=1.0/1.0/1.0, id8476=1.0/1.0/1.0, id8477=1.0/1.0/1.0, id8478=1.0/1.0/1.0, id8479=1.0/1.0/1.0, id848=1.0/1.0/1.0, id8480=1.0/1.0/1.0, id8481=1.0/1.0/1.0, id8482=1.0/1.0/1.0, id8483=1.0/1.0/1.0, id8484=1.0/1.0/1.0, id8485=1.0/1.0/1.0, id8486=1.0/1.0/1.0, id8487=1.0/1.0/1.0, id8488=1.0/1.0/1.0, id8489=1.0/1.0/1.0, id849=1.0/1.0/1.0, id8490=1.0/1.0/1.0, id8491=1.0/1.0/1.0, id8492=1.0/1.0/1.0, id8493=1.0/1.0/1.0, id8494=1.0/1.0/1.0, id8495=1.0/1.0/1.0, id8496=1.0/1.0/1.0, id8497=1.0/1.0/1.0, id8498=1.0/1.0/1.0, id8499=1.0/1.0/1.0, id85=1.0/1.0/1.0, id850=1.0/1.0/1.0, id8500=1.0/1.0/1.0, id8501=1.0/1.0/1.0, id8502=1.0/1.0/1.0, id8503=1.0/1.0/1.0, id8504=1.0/1.0/1.0, id8505=1.0/1.0/1.0, id8506=1.0/1.0/1.0, id8507=1.0/1.0/1.0, id8508=1.0/1.0/1.0, id8509=1.0/1.0/1.0, id851=1.0/1.0/1.0, id8510=1.0/1.0/1.0, id8511=1.0/1.0/1.0, id8512=1.0/1.0/1.0, id8513=1.0/1.0/1.0, id8514=1.0/1.0/1.0, id8515=1.0/1.0/1.0, id8516=1.0/1.0/1.0, id8517=1.0/1.0/1.0, id8518=1.0/1.0/1.0, id8519=1.0/1.0/1.0, id852=1.0/1.0/1.0, id8520=1.0/1.0/1.0, id8521=1.0/1.0/1.0, id8522=1.0/1.0/1.0, id8523=1.0/1.0/1.0, id8524=1.0/1.0/1.0, id8525=1.0/1.0/1.0, id8526=1.0/1.0/1.0, id8527=1.0/1.0/1.0, id8528=1.0/1.0/1.0, id8529=1.0/1.0/1.0, id853=1.0/1.0/1.0, id8530=1.0/1.0/1.0, id8531=1.0/1.0/1.0, id8532=1.0/1.0/1.0, id8533=1.0/1.0/1.0, id8534=1.0/1.0/1.0, id8535=1.0/1.0/1.0, id8536=1.0/1.0/1.0, id8537=1.0/1.0/1.0, id8538=1.0/1.0/1.0, id8539=1.0/1.0/1.0, id854=1.0/1.0/1.0, id8540=1.0/1.0/1.0, id8541=1.0/1.0/1.0, id8542=1.0/1.0/1.0, id8543=1.0/1.0/1.0, id8544=1.0/1.0/1.0, id8545=1.0/1.0/1.0, id8546=1.0/1.0/1.0, id8547=1.0/1.0/1.0, id8548=1.0/1.0/1.0, id8549=1.0/1.0/1.0, id855=1.0/1.0/1.0, id8550=1.0/1.0/1.0, id8551=1.0/1.0/1.0, id8552=1.0/1.0/1.0, id8553=1.0/1.0/1.0, id8554=1.0/1.0/1.0, id8555=1.0/1.0/1.0, id8556=1.0/1.0/1.0, id8557=1.0/1.0/1.0, id8558=1.0/1.0/1.0, id8559=1.0/1.0/1.0, id856=1.0/1.0/1.0, id8560=1.0/1.0/1.0, id8561=1.0/1.0/1.0, id8562=1.0/1.0/1.0, id8563=1.0/1.0/1.0, id8564=1.0/1.0/1.0, id8565=1.0/1.0/1.0, id8566=1.0/1.0/1.0, id8567=1.0/1.0/1.0, id8568=1.0/1.0/1.0, id8569=1.0/1.0/1.0, id857=1.0/1.0/1.0, id8570=1.0/1.0/1.0, id8571=1.0/1.0/1.0, id8572=1.0/1.0/1.0, id8573=1.0/1.0/1.0, id8574=1.0/1.0/1.0, id8575=1.0/1.0/1.0, id8576=1.0/1.0/1.0, id8577=1.0/1.0/1.0, id8578=1.0/1.0/1.0, id8579=1.0/1.0/1.0, id858=1.0/1.0/1.0, id8580=1.0/1.0/1.0, id8581=1.0/1.0/1.0, id8582=1.0/1.0/1.0, id8583=1.0/1.0/1.0, id8584=1.0/1.0/1.0, id8585=1.0/1.0/1.0, id8586=1.0/1.0/1.0, id8587=1.0/1.0/1.0, id8588=1.0/1.0/1.0, id8589=1.0/1.0/1.0, id859=1.0/1.0/1.0, id8590=1.0/1.0/1.0, id8591=1.0/1.0/1.0, id8592=1.0/1.0/1.0, id8593=1.0/1.0/1.0, id8594=1.0/1.0/1.0, id8595=1.0/1.0/1.0, id8596=1.0/1.0/1.0, id8597=1.0/1.0/1.0, id8598=1.0/1.0/1.0, id8599=1.0/1.0/1.0, id86=1.0/1.0/1.0, id860=1.0/1.0/1.0, id8600=1.0/1.0/1.0, id8601=1.0/1.0/1.0, id8602=1.0/1.0/1.0, id8603=1.0/1.0/1.0, id8604=1.0/1.0/1.0, id8605=1.0/1.0/1.0, id8606=1.0/1.0/1.0, id8607=1.0/1.0/1.0, id8608=1.0/1.0/1.0, id8609=1.0/1.0/1.0, id861=1.0/1.0/1.0, id8610=1.0/1.0/1.0, id8611=1.0/1.0/1.0, id8612=1.0/1.0/1.0, id8613=1.0/1.0/1.0, id8614=1.0/1.0/1.0, id8615=1.0/1.0/1.0, id8616=1.0/1.0/1.0, id8617=1.0/1.0/1.0, id8618=1.0/1.0/1.0, id8619=1.0/1.0/1.0, id862=1.0/1.0/1.0, id8620=1.0/1.0/1.0, id8621=1.0/1.0/1.0, id8622=1.0/1.0/1.0, id8623=1.0/1.0/1.0, id8624=1.0/1.0/1.0, id8625=1.0/1.0/1.0, id8626=1.0/1.0/1.0, id8627=1.0/1.0/1.0, id8628=1.0/1.0/1.0, id8629=1.0/1.0/1.0, id863=1.0/1.0/1.0, id8630=1.0/1.0/1.0, id8631=1.0/1.0/1.0, id8632=1.0/1.0/1.0, id8633=1.0/1.0/1.0, id8634=1.0/1.0/1.0, id8635=1.0/1.0/1.0, id8636=1.0/1.0/1.0, id8637=1.0/1.0/1.0, id8638=1.0/1.0/1.0, id8639=1.0/1.0/1.0, id864=1.0/1.0/1.0, id8640=1.0/1.0/1.0, id8641=1.0/1.0/1.0, id8642=1.0/1.0/1.0, id8643=1.0/1.0/1.0, id8644=1.0/1.0/1.0, id8645=1.0/1.0/1.0, id8646=1.0/1.0/1.0, id8647=1.0/1.0/1.0, id8648=1.0/1.0/1.0, id8649=1.0/1.0/1.0, id865=1.0/1.0/1.0, id8650=1.0/1.0/1.0, id8651=1.0/1.0/1.0, id8652=1.0/1.0/1.0, id8653=1.0/1.0/1.0, id8654=1.0/1.0/1.0, id8655=1.0/1.0/1.0, id8656=1.0/1.0/1.0, id8657=1.0/1.0/1.0, id8658=1.0/1.0/1.0, id8659=1.0/1.0/1.0, id866=1.0/1.0/1.0, id8660=1.0/1.0/1.0, id8661=1.0/1.0/1.0, id8662=1.0/1.0/1.0, id8663=1.0/1.0/1.0, id8664=1.0/1.0/1.0, id8665=1.0/1.0/1.0, id8666=1.0/1.0/1.0, id8667=1.0/1.0/1.0, id8668=1.0/1.0/1.0, id8669=1.0/1.0/1.0, id867=1.0/1.0/1.0, id8670=1.0/1.0/1.0, id8671=1.0/1.0/1.0, id8672=1.0/1.0/1.0, id8673=1.0/1.0/1.0, id8674=1.0/1.0/1.0, id8675=1.0/1.0/1.0, id8676=1.0/1.0/1.0, id8677=1.0/1.0/1.0, id8678=1.0/1.0/1.0, id8679=1.0/1.0/1.0, id868=1.0/1.0/1.0, id8680=1.0/1.0/1.0, id8681=1.0/1.0/1.0, id8682=1.0/1.0/1.0, id8683=1.0/1.0/1.0, id8684=1.0/1.0/1.0, id8685=1.0/1.0/1.0, id8686=1.0/1.0/1.0, id8687=1.0/1.0/1.0, id8688=1.0/1.0/1.0, id8689=1.0/1.0/1.0, id869=1.0/1.0/1.0, id8690=1.0/1.0/1.0, id8691=1.0/1.0/1.0, id8692=1.0/1.0/1.0, id8693=1.0/1.0/1.0, id8694=1.0/1.0/1.0, id8695=1.0/1.0/1.0, id8696=1.0/1.0/1.0, id8697=1.0/1.0/1.0, id8698=1.0/1.0/1.0, id8699=1.0/1.0/1.0, id87=1.0/1.0/1.0, id870=1.0/1.0/1.0, id8700=1.0/1.0/1.0, id8701=1.0/1.0/1.0, id8702=1.0/1.0/1.0, id8703=1.0/1.0/1.0, id8704=1.0/1.0/1.0, id8705=1.0/1.0/1.0, id8706=1.0/1.0/1.0, id8707=1.0/1.0/1.0, id8708=1.0/1.0/1.0, id8709=1.0/1.0/1.0, id871=1.0/1.0/1.0, id8710=1.0/1.0/1.0, id8711=1.0/1.0/1.0, id8712=1.0/1.0/1.0, id8713=1.0/1.0/1.0, id8714=1.0/1.0/1.0, id8715=1.0/1.0/1.0, id8716=1.0/1.0/1.0, id8717=1.0/1.0/1.0, id8718=1.0/1.0/1.0, id8719=1.0/1.0/1.0, id872=1.0/1.0/1.0, id8720=1.0/1.0/1.0, id8721=1.0/1.0/1.0, id8722=1.0/1.0/1.0, id8723=1.0/1.0/1.0, id8724=1.0/1.0/1.0, id8725=1.0/1.0/1.0, id8726=1.0/1.0/1.0, id8727=1.0/1.0/1.0, id8728=1.0/1.0/1.0, id8729=1.0/1.0/1.0, id873=1.0/1.0/1.0, id8730=1.0/1.0/1.0, id8731=1.0/1.0/1.0, id8732=1.0/1.0/1.0, id8733=1.0/1.0/1.0, id8734=1.0/1.0/1.0, id8735=1.0/1.0/1.0, id8736=1.0/1.0/1.0, id8737=1.0/1.0/1.0, id8738=1.0/1.0/1.0, id8739=1.0/1.0/1.0, id874=1.0/1.0/1.0, id8740=1.0/1.0/1.0, id8741=1.0/1.0/1.0, id8742=1.0/1.0/1.0, id8743=1.0/1.0/1.0, id8744=1.0/1.0/1.0, id8745=1.0/1.0/1.0, id8746=1.0/1.0/1.0, id8747=1.0/1.0/1.0, id8748=1.0/1.0/1.0, id8749=1.0/1.0/1.0, id875=1.0/1.0/1.0, id8750=1.0/1.0/1.0, id8751=1.0/1.0/1.0, id8752=1.0/1.0/1.0, id8753=1.0/1.0/1.0, id8754=1.0/1.0/1.0, id8755=1.0/1.0/1.0, id8756=1.0/1.0/1.0, id8757=1.0/1.0/1.0, id8758=1.0/1.0/1.0, id8759=1.0/1.0/1.0, id876=1.0/1.0/1.0, id8760=1.0/1.0/1.0, id8761=1.0/1.0/1.0, id8762=1.0/1.0/1.0, id8763=1.0/1.0/1.0, id8764=1.0/1.0/1.0, id8765=1.0/1.0/1.0, id8766=1.0/1.0/1.0, id8767=1.0/1.0/1.0, id8768=1.0/1.0/1.0, id8769=1.0/1.0/1.0, id877=1.0/1.0/1.0, id8770=1.0/1.0/1.0, id8771=1.0/1.0/1.0, id8772=1.0/1.0/1.0, id8773=1.0/1.0/1.0, id8774=1.0/1.0/1.0, id8775=1.0/1.0/1.0, id8776=1.0/1.0/1.0, id8777=1.0/1.0/1.0, id8778=1.0/1.0/1.0, id8779=1.0/1.0/1.0, id878=1.0/1.0/1.0, id8780=1.0/1.0/1.0, id8781=1.0/1.0/1.0, id8782=1.0/1.0/1.0, id8783=1.0/1.0/1.0, id8784=1.0/1.0/1.0, id8785=1.0/1.0/1.0, id8786=1.0/1.0/1.0, id8787=1.0/1.0/1.0, id8788=1.0/1.0/1.0, id8789=1.0/1.0/1.0, id879=1.0/1.0/1.0, id8790=1.0/1.0/1.0, id8791=1.0/1.0/1.0, id8792=1.0/1.0/1.0, id8793=1.0/1.0/1.0, id8794=1.0/1.0/1.0, id8795=1.0/1.0/1.0, id8796=1.0/1.0/1.0, id8797=1.0/1.0/1.0, id8798=1.0/1.0/1.0, id8799=1.0/1.0/1.0, id88=1.0/1.0/1.0, id880=1.0/1.0/1.0, id8800=1.0/1.0/1.0, id8801=1.0/1.0/1.0, id8802=1.0/1.0/1.0, id8803=1.0/1.0/1.0, id8804=1.0/1.0/1.0, id8805=1.0/1.0/1.0, id8806=1.0/1.0/1.0, id8807=1.0/1.0/1.0, id8808=1.0/1.0/1.0, id8809=1.0/1.0/1.0, id881=1.0/1.0/1.0, id8810=1.0/1.0/1.0, id8811=1.0/1.0/1.0, id8812=1.0/1.0/1.0, id8813=1.0/1.0/1.0, id8814=1.0/1.0/1.0, id8815=1.0/1.0/1.0, id8816=1.0/1.0/1.0, id8817=1.0/1.0/1.0, id8818=1.0/1.0/1.0, id8819=1.0/1.0/1.0, id882=1.0/1.0/1.0, id8820=1.0/1.0/1.0, id8821=1.0/1.0/1.0, id8822=1.0/1.0/1.0, id8823=1.0/1.0/1.0, id8824=1.0/1.0/1.0, id8825=1.0/1.0/1.0, id8826=1.0/1.0/1.0, id8827=1.0/1.0/1.0, id8828=1.0/1.0/1.0, id8829=1.0/1.0/1.0, id883=1.0/1.0/1.0, id8830=1.0/1.0/1.0, id8831=1.0/1.0/1.0, id8832=1.0/1.0/1.0, id8833=1.0/1.0/1.0, id8834=1.0/1.0/1.0, id8835=1.0/1.0/1.0, id8836=1.0/1.0/1.0, id8837=1.0/1.0/1.0, id8838=1.0/1.0/1.0, id8839=1.0/1.0/1.0, id884=1.0/1.0/1.0, id8840=1.0/1.0/1.0, id8841=1.0/1.0/1.0, id8842=1.0/1.0/1.0, id8843=1.0/1.0/1.0, id8844=1.0/1.0/1.0, id8845=1.0/1.0/1.0, id8846=1.0/1.0/1.0, id8847=1.0/1.0/1.0, id8848=1.0/1.0/1.0, id8849=1.0/1.0/1.0, id885=1.0/1.0/1.0, id8850=1.0/1.0/1.0, id8851=1.0/1.0/1.0, id8852=1.0/1.0/1.0, id8853=1.0/1.0/1.0, id8854=1.0/1.0/1.0, id8855=1.0/1.0/1.0, id8856=1.0/1.0/1.0, id8857=1.0/1.0/1.0, id8858=1.0/1.0/1.0, id8859=1.0/1.0/1.0, id886=1.0/1.0/1.0, id8860=1.0/1.0/1.0, id8861=1.0/1.0/1.0, id8862=1.0/1.0/1.0, id8863=1.0/1.0/1.0, id8864=1.0/1.0/1.0, id8865=1.0/1.0/1.0, id8866=1.0/1.0/1.0, id8867=1.0/1.0/1.0, id8868=1.0/1.0/1.0, id8869=1.0/1.0/1.0, id887=1.0/1.0/1.0, id8870=1.0/1.0/1.0, id8871=1.0/1.0/1.0, id8872=1.0/1.0/1.0, id8873=1.0/1.0/1.0, id8874=1.0/1.0/1.0, id8875=1.0/1.0/1.0, id8876=1.0/1.0/1.0, id8877=1.0/1.0/1.0, id8878=1.0/1.0/1.0, id8879=1.0/1.0/1.0, id888=1.0/1.0/1.0, id8880=1.0/1.0/1.0, id8881=1.0/1.0/1.0, id8882=1.0/1.0/1.0, id8883=1.0/1.0/1.0, id8884=1.0/1.0/1.0, id8885=1.0/1.0/1.0, id8886=1.0/1.0/1.0, id8887=1.0/1.0/1.0, id8888=1.0/1.0/1.0, id8889=1.0/1.0/1.0, id889=1.0/1.0/1.0, id8890=1.0/1.0/1.0, id8891=1.0/1.0/1.0, id8892=1.0/1.0/1.0, id8893=1.0/1.0/1.0, id8894=1.0/1.0/1.0, id8895=1.0/1.0/1.0, id8896=1.0/1.0/1.0, id8897=1.0/1.0/1.0, id8898=1.0/1.0/1.0, id8899=1.0/1.0/1.0, id89=1.0/1.0/1.0, id890=1.0/1.0/1.0, id8900=1.0/1.0/1.0, id8901=1.0/1.0/1.0, id8902=1.0/1.0/1.0, id8903=1.0/1.0/1.0, id8904=1.0/1.0/1.0, id8905=1.0/1.0/1.0, id8906=1.0/1.0/1.0, id8907=1.0/1.0/1.0, id8908=1.0/1.0/1.0, id8909=1.0/1.0/1.0, id891=1.0/1.0/1.0, id8910=1.0/1.0/1.0, id8911=1.0/1.0/1.0, id8912=1.0/1.0/1.0, id8913=1.0/1.0/1.0, id8914=1.0/1.0/1.0, id8915=1.0/1.0/1.0, id8916=1.0/1.0/1.0, id8917=1.0/1.0/1.0, id8918=1.0/1.0/1.0, id8919=1.0/1.0/1.0, id892=1.0/1.0/1.0, id8920=1.0/1.0/1.0, id8921=1.0/1.0/1.0, id8922=1.0/1.0/1.0, id8923=1.0/1.0/1.0, id8924=1.0/1.0/1.0, id8925=1.0/1.0/1.0, id8926=1.0/1.0/1.0, id8927=1.0/1.0/1.0, id8928=1.0/1.0/1.0, id8929=1.0/1.0/1.0, id893=1.0/1.0/1.0, id8930=1.0/1.0/1.0, id8931=1.0/1.0/1.0, id8932=1.0/1.0/1.0, id8933=1.0/1.0/1.0, id8934=1.0/1.0/1.0, id8935=1.0/1.0/1.0, id8936=1.0/1.0/1.0, id8937=1.0/1.0/1.0, id8938=1.0/1.0/1.0, id8939=1.0/1.0/1.0, id894=1.0/1.0/1.0, id8940=1.0/1.0/1.0, id8941=1.0/1.0/1.0, id8942=1.0/1.0/1.0, id8943=1.0/1.0/1.0, id8944=1.0/1.0/1.0, id8945=1.0/1.0/1.0, id8946=1.0/1.0/1.0, id8947=1.0/1.0/1.0, id8948=1.0/1.0/1.0, id8949=1.0/1.0/1.0, id895=1.0/1.0/1.0, id8950=1.0/1.0/1.0, id8951=1.0/1.0/1.0, id8952=1.0/1.0/1.0, id8953=1.0/1.0/1.0, id8954=1.0/1.0/1.0, id8955=1.0/1.0/1.0, id8956=1.0/1.0/1.0, id8957=1.0/1.0/1.0, id8958=1.0/1.0/1.0, id8959=1.0/1.0/1.0, id896=1.0/1.0/1.0, id8960=1.0/1.0/1.0, id8961=1.0/1.0/1.0, id8962=1.0/1.0/1.0, id8963=1.0/1.0/1.0, id8964=1.0/1.0/1.0, id8965=1.0/1.0/1.0, id8966=1.0/1.0/1.0, id8967=1.0/1.0/1.0, id8968=1.0/1.0/1.0, id8969=1.0/1.0/1.0, id897=1.0/1.0/1.0, id8970=1.0/1.0/1.0, id8971=1.0/1.0/1.0, id8972=1.0/1.0/1.0, id8973=1.0/1.0/1.0, id8974=1.0/1.0/1.0, id8975=1.0/1.0/1.0, id8976=1.0/1.0/1.0, id8977=1.0/1.0/1.0, id8978=1.0/1.0/1.0, id8979=1.0/1.0/1.0, id898=1.0/1.0/1.0, id8980=1.0/1.0/1.0, id8981=1.0/1.0/1.0, id8982=1.0/1.0/1.0, id8983=1.0/1.0/1.0, id8984=1.0/1.0/1.0, id8985=1.0/1.0/1.0, id8986=1.0/1.0/1.0, id8987=1.0/1.0/1.0, id8988=1.0/1.0/1.0, id8989=1.0/1.0/1.0, id899=1.0/1.0/1.0, id8990=1.0/1.0/1.0, id8991=1.0/1.0/1.0, id8992=1.0/1.0/1.0, id8993=1.0/1.0/1.0, id8994=1.0/1.0/1.0, id8995=1.0/1.0/1.0, id8996=1.0/1.0/1.0, id8997=1.0/1.0/1.0, id8998=1.0/1.0/1.0, id8999=1.0/1.0/1.0, id9=1.0/1.0/1.0, id90=1.0/1.0/1.0, id900=1.0/1.0/1.0, id9000=1.0/1.0/1.0, id9001=1.0/1.0/1.0, id9002=1.0/1.0/1.0, id9003=1.0/1.0/1.0, id9004=1.0/1.0/1.0, id9005=1.0/1.0/1.0, id9006=1.0/1.0/1.0, id9007=1.0/1.0/1.0, id9008=1.0/1.0/1.0, id9009=1.0/1.0/1.0, id901=1.0/1.0/1.0, id9010=1.0/1.0/1.0, id9011=1.0/1.0/1.0, id9012=1.0/1.0/1.0, id9013=1.0/1.0/1.0, id9014=1.0/1.0/1.0, id9015=1.0/1.0/1.0, id9016=1.0/1.0/1.0, id9017=1.0/1.0/1.0, id9018=1.0/1.0/1.0, id9019=1.0/1.0/1.0, id902=1.0/1.0/1.0, id9020=1.0/1.0/1.0, id9021=1.0/1.0/1.0, id9022=1.0/1.0/1.0, id9023=1.0/1.0/1.0, id9024=1.0/1.0/1.0, id9025=1.0/1.0/1.0, id9026=1.0/1.0/1.0, id9027=1.0/1.0/1.0, id9028=1.0/1.0/1.0, id9029=1.0/1.0/1.0, id903=1.0/1.0/1.0, id9030=1.0/1.0/1.0, id9031=1.0/1.0/1.0, id9032=1.0/1.0/1.0, id9033=1.0/1.0/1.0, id9034=1.0/1.0/1.0, id9035=1.0/1.0/1.0, id9036=1.0/1.0/1.0, id9037=1.0/1.0/1.0, id9038=1.0/1.0/1.0, id9039=1.0/1.0/1.0, id904=1.0/1.0/1.0, id9040=1.0/1.0/1.0, id9041=1.0/1.0/1.0, id9042=1.0/1.0/1.0, id9043=1.0/1.0/1.0, id9044=1.0/1.0/1.0, id9045=1.0/1.0/1.0, id9046=1.0/1.0/1.0, id9047=1.0/1.0/1.0, id9048=1.0/1.0/1.0, id9049=1.0/1.0/1.0, id905=1.0/1.0/1.0, id9050=1.0/1.0/1.0, id9051=1.0/1.0/1.0, id9052=1.0/1.0/1.0, id9053=1.0/1.0/1.0, id9054=1.0/1.0/1.0, id9055=1.0/1.0/1.0, id9056=1.0/1.0/1.0, id9057=1.0/1.0/1.0, id9058=1.0/1.0/1.0, id9059=1.0/1.0/1.0, id906=1.0/1.0/1.0, id9060=1.0/1.0/1.0, id9061=1.0/1.0/1.0, id9062=1.0/1.0/1.0, id9063=1.0/1.0/1.0, id9064=1.0/1.0/1.0, id9065=1.0/1.0/1.0, id9066=1.0/1.0/1.0, id9067=1.0/1.0/1.0, id9068=1.0/1.0/1.0, id9069=1.0/1.0/1.0, id907=1.0/1.0/1.0, id9070=1.0/1.0/1.0, id9071=1.0/1.0/1.0, id9072=1.0/1.0/1.0, id9073=1.0/1.0/1.0, id9074=1.0/1.0/1.0, id9075=1.0/1.0/1.0, id9076=1.0/1.0/1.0, id9077=1.0/1.0/1.0, id9078=1.0/1.0/1.0, id9079=1.0/1.0/1.0, id908=1.0/1.0/1.0, id9080=1.0/1.0/1.0, id9081=1.0/1.0/1.0, id9082=1.0/1.0/1.0, id9083=1.0/1.0/1.0, id9084=1.0/1.0/1.0, id9085=1.0/1.0/1.0, id9086=1.0/1.0/1.0, id9087=1.0/1.0/1.0, id9088=1.0/1.0/1.0, id9089=1.0/1.0/1.0, id909=1.0/1.0/1.0, id9090=1.0/1.0/1.0, id9091=1.0/1.0/1.0, id9092=1.0/1.0/1.0, id9093=1.0/1.0/1.0, id9094=1.0/1.0/1.0, id9095=1.0/1.0/1.0, id9096=1.0/1.0/1.0, id9097=1.0/1.0/1.0, id9098=1.0/1.0/1.0, id9099=1.0/1.0/1.0, id91=1.0/1.0/1.0, id910=1.0/1.0/1.0, id9100=1.0/1.0/1.0, id9101=1.0/1.0/1.0, id9102=1.0/1.0/1.0, id9103=1.0/1.0/1.0, id9104=1.0/1.0/1.0, id9105=1.0/1.0/1.0, id9106=1.0/1.0/1.0, id9107=1.0/1.0/1.0, id9108=1.0/1.0/1.0, id9109=1.0/1.0/1.0, id911=1.0/1.0/1.0, id9110=1.0/1.0/1.0, id9111=1.0/1.0/1.0, id9112=1.0/1.0/1.0, id9113=1.0/1.0/1.0, id9114=1.0/1.0/1.0, id9115=1.0/1.0/1.0, id9116=1.0/1.0/1.0, id9117=1.0/1.0/1.0, id9118=1.0/1.0/1.0, id9119=1.0/1.0/1.0, id912=1.0/1.0/1.0, id9120=1.0/1.0/1.0, id9121=1.0/1.0/1.0, id9122=1.0/1.0/1.0, id9123=1.0/1.0/1.0, id9124=1.0/1.0/1.0, id9125=1.0/1.0/1.0, id9126=1.0/1.0/1.0, id9127=1.0/1.0/1.0, id9128=1.0/1.0/1.0, id9129=1.0/1.0/1.0, id913=1.0/1.0/1.0, id9130=1.0/1.0/1.0, id9131=1.0/1.0/1.0, id9132=1.0/1.0/1.0, id9133=1.0/1.0/1.0, id9134=1.0/1.0/1.0, id9135=1.0/1.0/1.0, id9136=1.0/1.0/1.0, id9137=1.0/1.0/1.0, id9138=1.0/1.0/1.0, id9139=1.0/1.0/1.0, id914=1.0/1.0/1.0, id9140=1.0/1.0/1.0, id9141=1.0/1.0/1.0, id9142=1.0/1.0/1.0, id9143=1.0/1.0/1.0, id9144=1.0/1.0/1.0, id9145=1.0/1.0/1.0, id9146=1.0/1.0/1.0, id9147=1.0/1.0/1.0, id9148=1.0/1.0/1.0, id9149=1.0/1.0/1.0, id915=1.0/1.0/1.0, id9150=1.0/1.0/1.0, id9151=1.0/1.0/1.0, id9152=1.0/1.0/1.0, id9153=1.0/1.0/1.0, id9154=1.0/1.0/1.0, id9155=1.0/1.0/1.0, id9156=1.0/1.0/1.0, id9157=1.0/1.0/1.0, id9158=1.0/1.0/1.0, id9159=1.0/1.0/1.0, id916=1.0/1.0/1.0, id9160=1.0/1.0/1.0, id9161=1.0/1.0/1.0, id9162=1.0/1.0/1.0, id9163=1.0/1.0/1.0, id9164=1.0/1.0/1.0, id9165=1.0/1.0/1.0, id9166=1.0/1.0/1.0, id9167=1.0/1.0/1.0, id9168=1.0/1.0/1.0, id9169=1.0/1.0/1.0, id917=1.0/1.0/1.0, id9170=1.0/1.0/1.0, id9171=1.0/1.0/1.0, id9172=1.0/1.0/1.0, id9173=1.0/1.0/1.0, id9174=1.0/1.0/1.0, id9175=1.0/1.0/1.0, id9176=1.0/1.0/1.0, id9177=1.0/1.0/1.0, id9178=1.0/1.0/1.0, id9179=1.0/1.0/1.0, id918=1.0/1.0/1.0, id9180=1.0/1.0/1.0, id9181=1.0/1.0/1.0, id9182=1.0/1.0/1.0, id9183=1.0/1.0/1.0, id9184=1.0/1.0/1.0, id9185=1.0/1.0/1.0, id9186=1.0/1.0/1.0, id9187=1.0/1.0/1.0, id9188=1.0/1.0/1.0, id9189=1.0/1.0/1.0, id919=1.0/1.0/1.0, id9190=1.0/1.0/1.0, id9191=1.0/1.0/1.0, id9192=1.0/1.0/1.0, id9193=1.0/1.0/1.0, id9194=1.0/1.0/1.0, id9195=1.0/1.0/1.0, id9196=1.0/1.0/1.0, id9197=1.0/1.0/1.0, id9198=1.0/1.0/1.0, id9199=1.0/1.0/1.0, id92=1.0/1.0/1.0, id920=1.0/1.0/1.0, id9200=1.0/1.0/1.0, id9201=1.0/1.0/1.0, id9202=1.0/1.0/1.0, id9203=1.0/1.0/1.0, id9204=1.0/1.0/1.0, id9205=1.0/1.0/1.0, id9206=1.0/1.0/1.0, id9207=1.0/1.0/1.0, id9208=1.0/1.0/1.0, id9209=1.0/1.0/1.0, id921=1.0/1.0/1.0, id9210=1.0/1.0/1.0, id9211=1.0/1.0/1.0, id9212=1.0/1.0/1.0, id9213=1.0/1.0/1.0, id9214=1.0/1.0/1.0, id9215=1.0/1.0/1.0, id9216=1.0/1.0/1.0, id9217=1.0/1.0/1.0, id9218=1.0/1.0/1.0, id9219=1.0/1.0/1.0, id922=1.0/1.0/1.0, id9220=1.0/1.0/1.0, id9221=1.0/1.0/1.0, id9222=1.0/1.0/1.0, id9223=1.0/1.0/1.0, id9224=1.0/1.0/1.0, id9225=1.0/1.0/1.0, id9226=1.0/1.0/1.0, id9227=1.0/1.0/1.0, id9228=1.0/1.0/1.0, id9229=1.0/1.0/1.0, id923=1.0/1.0/1.0, id9230=1.0/1.0/1.0, id9231=1.0/1.0/1.0, id9232=1.0/1.0/1.0, id9233=1.0/1.0/1.0, id9234=1.0/1.0/1.0, id9235=1.0/1.0/1.0, id9236=1.0/1.0/1.0, id9237=1.0/1.0/1.0, id9238=1.0/1.0/1.0, id9239=1.0/1.0/1.0, id924=1.0/1.0/1.0, id9240=1.0/1.0/1.0, id9241=1.0/1.0/1.0, id9242=1.0/1.0/1.0, id9243=1.0/1.0/1.0, id9244=1.0/1.0/1.0, id9245=1.0/1.0/1.0, id9246=1.0/1.0/1.0, id9247=1.0/1.0/1.0, id9248=1.0/1.0/1.0, id9249=1.0/1.0/1.0, id925=1.0/1.0/1.0, id9250=1.0/1.0/1.0, id9251=1.0/1.0/1.0, id9252=1.0/1.0/1.0, id9253=1.0/1.0/1.0, id9254=1.0/1.0/1.0, id9255=1.0/1.0/1.0, id9256=1.0/1.0/1.0, id9257=1.0/1.0/1.0, id9258=1.0/1.0/1.0, id9259=1.0/1.0/1.0, id926=1.0/1.0/1.0, id9260=1.0/1.0/1.0, id9261=1.0/1.0/1.0, id9262=1.0/1.0/1.0, id9263=1.0/1.0/1.0, id9264=1.0/1.0/1.0, id9265=1.0/1.0/1.0, id9266=1.0/1.0/1.0, id9267=1.0/1.0/1.0, id9268=1.0/1.0/1.0, id9269=1.0/1.0/1.0, id927=1.0/1.0/1.0, id9270=1.0/1.0/1.0, id9271=1.0/1.0/1.0, id9272=1.0/1.0/1.0, id9273=1.0/1.0/1.0, id9274=1.0/1.0/1.0, id9275=1.0/1.0/1.0, id9276=1.0/1.0/1.0, id9277=1.0/1.0/1.0, id9278=1.0/1.0/1.0, id9279=1.0/1.0/1.0, id928=1.0/1.0/1.0, id9280=1.0/1.0/1.0, id9281=1.0/1.0/1.0, id9282=1.0/1.0/1.0, id9283=1.0/1.0/1.0, id9284=1.0/1.0/1.0, id9285=1.0/1.0/1.0, id9286=1.0/1.0/1.0, id9287=1.0/1.0/1.0, id9288=1.0/1.0/1.0, id9289=1.0/1.0/1.0, id929=1.0/1.0/1.0, id9290=1.0/1.0/1.0, id9291=1.0/1.0/1.0, id9292=1.0/1.0/1.0, id9293=1.0/1.0/1.0, id9294=1.0/1.0/1.0, id9295=1.0/1.0/1.0, id9296=1.0/1.0/1.0, id9297=1.0/1.0/1.0, id9298=1.0/1.0/1.0, id9299=1.0/1.0/1.0, id93=1.0/1.0/1.0, id930=1.0/1.0/1.0, id9300=1.0/1.0/1.0, id9301=1.0/1.0/1.0, id9302=1.0/1.0/1.0, id9303=1.0/1.0/1.0, id9304=1.0/1.0/1.0, id9305=1.0/1.0/1.0, id9306=1.0/1.0/1.0, id9307=1.0/1.0/1.0, id9308=1.0/1.0/1.0, id9309=1.0/1.0/1.0, id931=1.0/1.0/1.0, id9310=1.0/1.0/1.0, id9311=1.0/1.0/1.0, id9312=1.0/1.0/1.0, id9313=1.0/1.0/1.0, id9314=1.0/1.0/1.0, id9315=1.0/1.0/1.0, id9316=1.0/1.0/1.0, id9317=1.0/1.0/1.0, id9318=1.0/1.0/1.0, id9319=1.0/1.0/1.0, id932=1.0/1.0/1.0, id9320=1.0/1.0/1.0, id9321=1.0/1.0/1.0, id9322=1.0/1.0/1.0, id9323=1.0/1.0/1.0, id9324=1.0/1.0/1.0, id9325=1.0/1.0/1.0, id9326=1.0/1.0/1.0, id9327=1.0/1.0/1.0, id9328=1.0/1.0/1.0, id9329=1.0/1.0/1.0, id933=1.0/1.0/1.0, id9330=1.0/1.0/1.0, id9331=1.0/1.0/1.0, id9332=1.0/1.0/1.0, id9333=1.0/1.0/1.0, id9334=1.0/1.0/1.0, id9335=1.0/1.0/1.0, id9336=1.0/1.0/1.0, id9337=1.0/1.0/1.0, id9338=1.0/1.0/1.0, id9339=1.0/1.0/1.0, id934=1.0/1.0/1.0, id9340=1.0/1.0/1.0, id9341=1.0/1.0/1.0, id9342=1.0/1.0/1.0, id9343=1.0/1.0/1.0, id9344=1.0/1.0/1.0, id9345=1.0/1.0/1.0, id9346=1.0/1.0/1.0, id9347=1.0/1.0/1.0, id9348=1.0/1.0/1.0, id9349=1.0/1.0/1.0, id935=1.0/1.0/1.0, id9350=1.0/1.0/1.0, id9351=1.0/1.0/1.0, id9352=1.0/1.0/1.0, id9353=1.0/1.0/1.0, id9354=1.0/1.0/1.0, id9355=1.0/1.0/1.0, id9356=1.0/1.0/1.0, id9357=1.0/1.0/1.0, id9358=1.0/1.0/1.0, id9359=1.0/1.0/1.0, id936=1.0/1.0/1.0, id9360=1.0/1.0/1.0, id9361=1.0/1.0/1.0, id9362=1.0/1.0/1.0, id9363=1.0/1.0/1.0, id9364=1.0/1.0/1.0, id9365=1.0/1.0/1.0, id9366=1.0/1.0/1.0, id9367=1.0/1.0/1.0, id9368=1.0/1.0/1.0, id9369=1.0/1.0/1.0, id937=1.0/1.0/1.0, id9370=1.0/1.0/1.0, id9371=1.0/1.0/1.0, id9372=1.0/1.0/1.0, id9373=1.0/1.0/1.0, id9374=1.0/1.0/1.0, id9375=1.0/1.0/1.0, id9376=1.0/1.0/1.0, id9377=1.0/1.0/1.0, id9378=1.0/1.0/1.0, id9379=1.0/1.0/1.0, id938=1.0/1.0/1.0, id9380=1.0/1.0/1.0, id9381=1.0/1.0/1.0, id9382=1.0/1.0/1.0, id9383=1.0/1.0/1.0, id9384=1.0/1.0/1.0, id9385=1.0/1.0/1.0, id9386=1.0/1.0/1.0, id9387=1.0/1.0/1.0, id9388=1.0/1.0/1.0, id9389=1.0/1.0/1.0, id939=1.0/1.0/1.0, id9390=1.0/1.0/1.0, id9391=1.0/1.0/1.0, id9392=1.0/1.0/1.0, id9393=1.0/1.0/1.0, id9394=1.0/1.0/1.0, id9395=1.0/1.0/1.0, id9396=1.0/1.0/1.0, id9397=1.0/1.0/1.0, id9398=1.0/1.0/1.0, id9399=1.0/1.0/1.0, id94=1.0/1.0/1.0, id940=1.0/1.0/1.0, id9400=1.0/1.0/1.0, id9401=1.0/1.0/1.0, id9402=1.0/1.0/1.0, id9403=1.0/1.0/1.0, id9404=1.0/1.0/1.0, id9405=1.0/1.0/1.0, id9406=1.0/1.0/1.0, id9407=1.0/1.0/1.0, id9408=1.0/1.0/1.0, id9409=1.0/1.0/1.0, id941=1.0/1.0/1.0, id9410=1.0/1.0/1.0, id9411=1.0/1.0/1.0, id9412=1.0/1.0/1.0, id9413=1.0/1.0/1.0, id9414=1.0/1.0/1.0, id9415=1.0/1.0/1.0, id9416=1.0/1.0/1.0, id9417=1.0/1.0/1.0, id9418=1.0/1.0/1.0, id9419=1.0/1.0/1.0, id942=1.0/1.0/1.0, id9420=1.0/1.0/1.0, id9421=1.0/1.0/1.0, id9422=1.0/1.0/1.0, id9423=1.0/1.0/1.0, id9424=1.0/1.0/1.0, id9425=1.0/1.0/1.0, id9426=1.0/1.0/1.0, id9427=1.0/1.0/1.0, id9428=1.0/1.0/1.0, id9429=1.0/1.0/1.0, id943=1.0/1.0/1.0, id9430=1.0/1.0/1.0, id9431=1.0/1.0/1.0, id9432=1.0/1.0/1.0, id9433=1.0/1.0/1.0, id9434=1.0/1.0/1.0, id9435=1.0/1.0/1.0, id9436=1.0/1.0/1.0, id9437=1.0/1.0/1.0, id9438=1.0/1.0/1.0, id9439=1.0/1.0/1.0, id944=1.0/1.0/1.0, id9440=1.0/1.0/1.0, id9441=1.0/1.0/1.0, id9442=1.0/1.0/1.0, id9443=1.0/1.0/1.0, id9444=1.0/1.0/1.0, id9445=1.0/1.0/1.0, id9446=1.0/1.0/1.0, id9447=1.0/1.0/1.0, id9448=1.0/1.0/1.0, id9449=1.0/1.0/1.0, id945=1.0/1.0/1.0, id9450=1.0/1.0/1.0, id9451=1.0/1.0/1.0, id9452=1.0/1.0/1.0, id9453=1.0/1.0/1.0, id9454=1.0/1.0/1.0, id9455=1.0/1.0/1.0, id9456=1.0/1.0/1.0, id9457=1.0/1.0/1.0, id9458=1.0/1.0/1.0, id9459=1.0/1.0/1.0, id946=1.0/1.0/1.0, id9460=1.0/1.0/1.0, id9461=1.0/1.0/1.0, id9462=1.0/1.0/1.0, id9463=1.0/1.0/1.0, id9464=1.0/1.0/1.0, id9465=1.0/1.0/1.0, id9466=1.0/1.0/1.0, id9467=1.0/1.0/1.0, id9468=1.0/1.0/1.0, id9469=1.0/1.0/1.0, id947=1.0/1.0/1.0, id9470=1.0/1.0/1.0, id9471=1.0/1.0/1.0, id9472=1.0/1.0/1.0, id9473=1.0/1.0/1.0, id9474=1.0/1.0/1.0, id9475=1.0/1.0/1.0, id9476=1.0/1.0/1.0, id9477=1.0/1.0/1.0, id9478=1.0/1.0/1.0, id9479=1.0/1.0/1.0, id948=1.0/1.0/1.0, id9480=1.0/1.0/1.0, id9481=1.0/1.0/1.0, id9482=1.0/1.0/1.0, id9483=1.0/1.0/1.0, id9484=1.0/1.0/1.0, id9485=1.0/1.0/1.0, id9486=1.0/1.0/1.0, id9487=1.0/1.0/1.0, id9488=1.0/1.0/1.0, id9489=1.0/1.0/1.0, id949=1.0/1.0/1.0, id9490=1.0/1.0/1.0, id9491=1.0/1.0/1.0, id9492=1.0/1.0/1.0, id9493=1.0/1.0/1.0, id9494=1.0/1.0/1.0, id9495=1.0/1.0/1.0, id9496=1.0/1.0/1.0, id9497=1.0/1.0/1.0, id9498=1.0/1.0/1.0, id9499=1.0/1.0/1.0, id95=1.0/1.0/1.0, id950=1.0/1.0/1.0, id9500=1.0/1.0/1.0, id9501=1.0/1.0/1.0, id9502=1.0/1.0/1.0, id9503=1.0/1.0/1.0, id9504=1.0/1.0/1.0, id9505=1.0/1.0/1.0, id9506=1.0/1.0/1.0, id9507=1.0/1.0/1.0, id9508=1.0/1.0/1.0, id9509=1.0/1.0/1.0, id951=1.0/1.0/1.0, id9510=1.0/1.0/1.0, id9511=1.0/1.0/1.0, id9512=1.0/1.0/1.0, id9513=1.0/1.0/1.0, id9514=1.0/1.0/1.0, id9515=1.0/1.0/1.0, id9516=1.0/1.0/1.0, id9517=1.0/1.0/1.0, id9518=1.0/1.0/1.0, id9519=1.0/1.0/1.0, id952=1.0/1.0/1.0, id9520=1.0/1.0/1.0, id9521=1.0/1.0/1.0, id9522=1.0/1.0/1.0, id9523=1.0/1.0/1.0, id9524=1.0/1.0/1.0, id9525=1.0/1.0/1.0, id9526=1.0/1.0/1.0, id9527=1.0/1.0/1.0, id9528=1.0/1.0/1.0, id9529=1.0/1.0/1.0, id953=1.0/1.0/1.0, id9530=1.0/1.0/1.0, id9531=1.0/1.0/1.0, id9532=1.0/1.0/1.0, id9533=1.0/1.0/1.0, id9534=1.0/1.0/1.0, id9535=1.0/1.0/1.0, id9536=1.0/1.0/1.0, id9537=1.0/1.0/1.0, id9538=1.0/1.0/1.0, id9539=1.0/1.0/1.0, id954=1.0/1.0/1.0, id9540=1.0/1.0/1.0, id9541=1.0/1.0/1.0, id9542=1.0/1.0/1.0, id9543=1.0/1.0/1.0, id9544=1.0/1.0/1.0, id9545=1.0/1.0/1.0, id9546=1.0/1.0/1.0, id9547=1.0/1.0/1.0, id9548=1.0/1.0/1.0, id9549=1.0/1.0/1.0, id955=1.0/1.0/1.0, id9550=1.0/1.0/1.0, id9551=1.0/1.0/1.0, id9552=1.0/1.0/1.0, id9553=1.0/1.0/1.0, id9554=1.0/1.0/1.0, id9555=1.0/1.0/1.0, id9556=1.0/1.0/1.0, id9557=1.0/1.0/1.0, id9558=1.0/1.0/1.0, id9559=1.0/1.0/1.0, id956=1.0/1.0/1.0, id9560=1.0/1.0/1.0, id9561=1.0/1.0/1.0, id9562=1.0/1.0/1.0, id9563=1.0/1.0/1.0, id9564=1.0/1.0/1.0, id9565=1.0/1.0/1.0, id9566=1.0/1.0/1.0, id9567=1.0/1.0/1.0, id9568=1.0/1.0/1.0, id9569=1.0/1.0/1.0, id957=1.0/1.0/1.0, id9570=1.0/1.0/1.0, id9571=1.0/1.0/1.0, id9572=1.0/1.0/1.0, id9573=1.0/1.0/1.0, id9574=1.0/1.0/1.0, id9575=1.0/1.0/1.0, id9576=1.0/1.0/1.0, id9577=1.0/1.0/1.0, id9578=1.0/1.0/1.0, id9579=1.0/1.0/1.0, id958=1.0/1.0/1.0, id9580=1.0/1.0/1.0, id9581=1.0/1.0/1.0, id9582=1.0/1.0/1.0, id9583=1.0/1.0/1.0, id9584=1.0/1.0/1.0, id9585=1.0/1.0/1.0, id9586=1.0/1.0/1.0, id9587=1.0/1.0/1.0, id9588=1.0/1.0/1.0, id9589=1.0/1.0/1.0, id959=1.0/1.0/1.0, id9590=1.0/1.0/1.0, id9591=1.0/1.0/1.0, id9592=1.0/1.0/1.0, id9593=1.0/1.0/1.0, id9594=1.0/1.0/1.0, id9595=1.0/1.0/1.0, id9596=1.0/1.0/1.0, id9597=1.0/1.0/1.0, id9598=1.0/1.0/1.0, id9599=1.0/1.0/1.0, id96=1.0/1.0/1.0, id960=1.0/1.0/1.0, id9600=1.0/1.0/1.0, id9601=1.0/1.0/1.0, id9602=1.0/1.0/1.0, id9603=1.0/1.0/1.0, id9604=1.0/1.0/1.0, id9605=1.0/1.0/1.0, id9606=1.0/1.0/1.0, id9607=1.0/1.0/1.0, id9608=1.0/1.0/1.0, id9609=1.0/1.0/1.0, id961=1.0/1.0/1.0, id9610=1.0/1.0/1.0, id9611=1.0/1.0/1.0, id9612=1.0/1.0/1.0, id9613=1.0/1.0/1.0, id9614=1.0/1.0/1.0, id9615=1.0/1.0/1.0, id9616=1.0/1.0/1.0, id9617=1.0/1.0/1.0, id9618=1.0/1.0/1.0, id9619=1.0/1.0/1.0, id962=1.0/1.0/1.0, id9620=1.0/1.0/1.0, id9621=1.0/1.0/1.0, id9622=1.0/1.0/1.0, id9623=1.0/1.0/1.0, id9624=1.0/1.0/1.0, id9625=1.0/1.0/1.0, id9626=1.0/1.0/1.0, id9627=1.0/1.0/1.0, id9628=1.0/1.0/1.0, id9629=1.0/1.0/1.0, id963=1.0/1.0/1.0, id9630=1.0/1.0/1.0, id9631=1.0/1.0/1.0, id9632=1.0/1.0/1.0, id9633=1.0/1.0/1.0, id9634=1.0/1.0/1.0, id9635=1.0/1.0/1.0, id9636=1.0/1.0/1.0, id9637=1.0/1.0/1.0, id9638=1.0/1.0/1.0, id9639=1.0/1.0/1.0, id964=1.0/1.0/1.0, id9640=1.0/1.0/1.0, id9641=1.0/1.0/1.0, id9642=1.0/1.0/1.0, id9643=1.0/1.0/1.0, id9644=1.0/1.0/1.0, id9645=1.0/1.0/1.0, id9646=1.0/1.0/1.0, id9647=1.0/1.0/1.0, id9648=1.0/1.0/1.0, id9649=1.0/1.0/1.0, id965=1.0/1.0/1.0, id9650=1.0/1.0/1.0, id9651=1.0/1.0/1.0, id9652=1.0/1.0/1.0, id9653=1.0/1.0/1.0, id9654=1.0/1.0/1.0, id9655=1.0/1.0/1.0, id9656=1.0/1.0/1.0, id9657=1.0/1.0/1.0, id9658=1.0/1.0/1.0, id9659=1.0/1.0/1.0, id966=1.0/1.0/1.0, id9660=1.0/1.0/1.0, id9661=1.0/1.0/1.0, id9662=1.0/1.0/1.0, id9663=1.0/1.0/1.0, id9664=1.0/1.0/1.0, id9665=1.0/1.0/1.0, id9666=1.0/1.0/1.0, id9667=1.0/1.0/1.0, id9668=1.0/1.0/1.0, id9669=1.0/1.0/1.0, id967=1.0/1.0/1.0, id9670=1.0/1.0/1.0, id9671=1.0/1.0/1.0, id9672=1.0/1.0/1.0, id9673=1.0/1.0/1.0, id9674=1.0/1.0/1.0, id9675=1.0/1.0/1.0, id9676=1.0/1.0/1.0, id9677=1.0/1.0/1.0, id9678=1.0/1.0/1.0, id9679=1.0/1.0/1.0, id968=1.0/1.0/1.0, id9680=1.0/1.0/1.0, id9681=1.0/1.0/1.0, id9682=1.0/1.0/1.0, id9683=1.0/1.0/1.0, id9684=1.0/1.0/1.0, id9685=1.0/1.0/1.0, id9686=1.0/1.0/1.0, id9687=1.0/1.0/1.0, id9688=1.0/1.0/1.0, id9689=1.0/1.0/1.0, id969=1.0/1.0/1.0, id9690=1.0/1.0/1.0, id9691=1.0/1.0/1.0, id9692=1.0/1.0/1.0, id9693=1.0/1.0/1.0, id9694=1.0/1.0/1.0, id9695=1.0/1.0/1.0, id9696=1.0/1.0/1.0, id9697=1.0/1.0/1.0, id9698=1.0/1.0/1.0, id9699=1.0/1.0/1.0, id97=1.0/1.0/1.0, id970=1.0/1.0/1.0, id9700=1.0/1.0/1.0, id9701=1.0/1.0/1.0, id9702=1.0/1.0/1.0, id9703=1.0/1.0/1.0, id9704=1.0/1.0/1.0, id9705=1.0/1.0/1.0, id9706=1.0/1.0/1.0, id9707=1.0/1.0/1.0, id9708=1.0/1.0/1.0, id9709=1.0/1.0/1.0, id971=1.0/1.0/1.0, id9710=1.0/1.0/1.0, id9711=1.0/1.0/1.0, id9712=1.0/1.0/1.0, id9713=1.0/1.0/1.0, id9714=1.0/1.0/1.0, id9715=1.0/1.0/1.0, id9716=1.0/1.0/1.0, id9717=1.0/1.0/1.0, id9718=1.0/1.0/1.0, id9719=1.0/1.0/1.0, id972=1.0/1.0/1.0, id9720=1.0/1.0/1.0, id9721=1.0/1.0/1.0, id9722=1.0/1.0/1.0, id9723=1.0/1.0/1.0, id9724=1.0/1.0/1.0, id9725=1.0/1.0/1.0, id9726=1.0/1.0/1.0, id9727=1.0/1.0/1.0, id9728=1.0/1.0/1.0, id9729=1.0/1.0/1.0, id973=1.0/1.0/1.0, id9730=1.0/1.0/1.0, id9731=1.0/1.0/1.0, id9732=1.0/1.0/1.0, id9733=1.0/1.0/1.0, id9734=1.0/1.0/1.0, id9735=1.0/1.0/1.0, id9736=1.0/1.0/1.0, id9737=1.0/1.0/1.0, id9738=1.0/1.0/1.0, id9739=1.0/1.0/1.0, id974=1.0/1.0/1.0, id9740=1.0/1.0/1.0, id9741=1.0/1.0/1.0, id9742=1.0/1.0/1.0, id9743=1.0/1.0/1.0, id9744=1.0/1.0/1.0, id9745=1.0/1.0/1.0, id9746=1.0/1.0/1.0, id9747=1.0/1.0/1.0, id9748=1.0/1.0/1.0, id9749=1.0/1.0/1.0, id975=1.0/1.0/1.0, id9750=1.0/1.0/1.0, id9751=1.0/1.0/1.0, id9752=1.0/1.0/1.0, id9753=1.0/1.0/1.0, id9754=1.0/1.0/1.0, id9755=1.0/1.0/1.0, id9756=1.0/1.0/1.0, id9757=1.0/1.0/1.0, id9758=1.0/1.0/1.0, id9759=1.0/1.0/1.0, id976=1.0/1.0/1.0, id9760=1.0/1.0/1.0, id9761=1.0/1.0/1.0, id9762=1.0/1.0/1.0, id9763=1.0/1.0/1.0, id9764=1.0/1.0/1.0, id9765=1.0/1.0/1.0, id9766=1.0/1.0/1.0, id9767=1.0/1.0/1.0, id9768=1.0/1.0/1.0, id9769=1.0/1.0/1.0, id977=1.0/1.0/1.0, id9770=1.0/1.0/1.0, id9771=1.0/1.0/1.0, id9772=1.0/1.0/1.0, id9773=1.0/1.0/1.0, id9774=1.0/1.0/1.0, id9775=1.0/1.0/1.0, id9776=1.0/1.0/1.0, id9777=1.0/1.0/1.0, id9778=1.0/1.0/1.0, id9779=1.0/1.0/1.0, id978=1.0/1.0/1.0, id9780=1.0/1.0/1.0, id9781=1.0/1.0/1.0, id9782=1.0/1.0/1.0, id9783=1.0/1.0/1.0, id9784=1.0/1.0/1.0, id9785=1.0/1.0/1.0, id9786=1.0/1.0/1.0, id9787=1.0/1.0/1.0, id9788=1.0/1.0/1.0, id9789=1.0/1.0/1.0, id979=1.0/1.0/1.0, id9790=1.0/1.0/1.0, id9791=1.0/1.0/1.0, id9792=1.0/1.0/1.0, id9793=1.0/1.0/1.0, id9794=1.0/1.0/1.0, id9795=1.0/1.0/1.0, id9796=1.0/1.0/1.0, id9797=1.0/1.0/1.0, id9798=1.0/1.0/1.0, id9799=1.0/1.0/1.0, id98=1.0/1.0/1.0, id980=1.0/1.0/1.0, id9800=1.0/1.0/1.0, id9801=1.0/1.0/1.0, id9802=1.0/1.0/1.0, id9803=1.0/1.0/1.0, id9804=1.0/1.0/1.0, id9805=1.0/1.0/1.0, id9806=1.0/1.0/1.0, id9807=1.0/1.0/1.0, id9808=1.0/1.0/1.0, id9809=1.0/1.0/1.0, id981=1.0/1.0/1.0, id9810=1.0/1.0/1.0, id9811=1.0/1.0/1.0, id9812=1.0/1.0/1.0, id9813=1.0/1.0/1.0, id9814=1.0/1.0/1.0, id9815=1.0/1.0/1.0, id9816=1.0/1.0/1.0, id9817=1.0/1.0/1.0, id9818=1.0/1.0/1.0, id9819=1.0/1.0/1.0, id982=1.0/1.0/1.0, id9820=1.0/1.0/1.0, id9821=1.0/1.0/1.0, id9822=1.0/1.0/1.0, id9823=1.0/1.0/1.0, id9824=1.0/1.0/1.0, id9825=1.0/1.0/1.0, id9826=1.0/1.0/1.0, id9827=1.0/1.0/1.0, id9828=1.0/1.0/1.0, id9829=1.0/1.0/1.0, id983=1.0/1.0/1.0, id9830=1.0/1.0/1.0, id9831=1.0/1.0/1.0, id9832=1.0/1.0/1.0, id9833=1.0/1.0/1.0, id9834=1.0/1.0/1.0, id9835=1.0/1.0/1.0, id9836=1.0/1.0/1.0, id9837=1.0/1.0/1.0, id9838=1.0/1.0/1.0, id9839=1.0/1.0/1.0, id984=1.0/1.0/1.0, id9840=1.0/1.0/1.0, id9841=1.0/1.0/1.0, id9842=1.0/1.0/1.0, id9843=1.0/1.0/1.0, id9844=1.0/1.0/1.0, id9845=1.0/1.0/1.0, id9846=1.0/1.0/1.0, id9847=1.0/1.0/1.0, id9848=1.0/1.0/1.0, id9849=1.0/1.0/1.0, id985=1.0/1.0/1.0, id9850=1.0/1.0/1.0, id9851=1.0/1.0/1.0, id9852=1.0/1.0/1.0, id9853=1.0/1.0/1.0, id9854=1.0/1.0/1.0, id9855=1.0/1.0/1.0, id9856=1.0/1.0/1.0, id9857=1.0/1.0/1.0, id9858=1.0/1.0/1.0, id9859=1.0/1.0/1.0, id986=1.0/1.0/1.0, id9860=1.0/1.0/1.0, id9861=1.0/1.0/1.0, id9862=1.0/1.0/1.0, id9863=1.0/1.0/1.0, id9864=1.0/1.0/1.0, id9865=1.0/1.0/1.0, id9866=1.0/1.0/1.0, id9867=1.0/1.0/1.0, id9868=1.0/1.0/1.0, id9869=1.0/1.0/1.0, id987=1.0/1.0/1.0, id9870=1.0/1.0/1.0, id9871=1.0/1.0/1.0, id9872=1.0/1.0/1.0, id9873=1.0/1.0/1.0, id9874=1.0/1.0/1.0, id9875=1.0/1.0/1.0, id9876=1.0/1.0/1.0, id9877=1.0/1.0/1.0, id9878=1.0/1.0/1.0, id9879=1.0/1.0/1.0, id988=1.0/1.0/1.0, id9880=1.0/1.0/1.0, id9881=1.0/1.0/1.0, id9882=1.0/1.0/1.0, id9883=1.0/1.0/1.0, id9884=1.0/1.0/1.0, id9885=1.0/1.0/1.0, id9886=1.0/1.0/1.0, id9887=1.0/1.0/1.0, id9888=1.0/1.0/1.0, id9889=1.0/1.0/1.0, id989=1.0/1.0/1.0, id9890=1.0/1.0/1.0, id9891=1.0/1.0/1.0, id9892=1.0/1.0/1.0, id9893=1.0/1.0/1.0, id9894=1.0/1.0/1.0, id9895=1.0/1.0/1.0, id9896=1.0/1.0/1.0, id9897=1.0/1.0/1.0, id9898=1.0/1.0/1.0, id9899=1.0/1.0/1.0, id99=1.0/1.0/1.0, id990=1.0/1.0/1.0, id9900=1.0/1.0/1.0, id9901=1.0/1.0/1.0, id9902=1.0/1.0/1.0, id9903=1.0/1.0/1.0, id9904=1.0/1.0/1.0, id9905=1.0/1.0/1.0, id9906=1.0/1.0/1.0, id9907=1.0/1.0/1.0, id9908=1.0/1.0/1.0, id9909=1.0/1.0/1.0, id991=1.0/1.0/1.0, id9910=1.0/1.0/1.0, id9911=1.0/1.0/1.0, id9912=1.0/1.0/1.0, id9913=1.0/1.0/1.0, id9914=1.0/1.0/1.0, id9915=1.0/1.0/1.0, id9916=1.0/1.0/1.0, id9917=1.0/1.0/1.0, id9918=1.0/1.0/1.0, id9919=1.0/1.0/1.0, id992=1.0/1.0/1.0, id9920=1.0/1.0/1.0, id9921=1.0/1.0/1.0, id9922=1.0/1.0/1.0, id9923=1.0/1.0/1.0, id9924=1.0/1.0/1.0, id9925=1.0/1.0/1.0, id9926=1.0/1.0/1.0, id9927=1.0/1.0/1.0, id9928=1.0/1.0/1.0, id9929=1.0/1.0/1.0, id993=1.0/1.0/1.0, id9930=1.0/1.0/1.0, id9931=1.0/1.0/1.0, id9932=1.0/1.0/1.0, id9933=1.0/1.0/1.0, id9934=1.0/1.0/1.0, id9935=1.0/1.0/1.0, id9936=1.0/1.0/1.0, id9937=1.0/1.0/1.0, id9938=1.0/1.0/1.0, id9939=1.0/1.0/1.0, id994=1.0/1.0/1.0, id9940=1.0/1.0/1.0, id9941=1.0/1.0/1.0, id9942=1.0/1.0/1.0, id9943=1.0/1.0/1.0, id9944=1.0/1.0/1.0, id9945=1.0/1.0/1.0, id9946=1.0/1.0/1.0, id9947=1.0/1.0/1.0, id9948=1.0/1.0/1.0, id9949=1.0/1.0/1.0, id995=1.0/1.0/1.0, id9950=1.0/1.0/1.0, id9951=1.0/1.0/1.0, id9952=1.0/1.0/1.0, id9953=1.0/1.0/1.0, id9954=1.0/1.0/1.0, id9955=1.0/1.0/1.0, id9956=1.0/1.0/1.0, id9957=1.0/1.0/1.0, id9958=1.0/1.0/1.0, id9959=1.0/1.0/1.0, id996=1.0/1.0/1.0, id9960=1.0/1.0/1.0, id9961=1.0/1.0/1.0, id9962=1.0/1.0/1.0, id9963=1.0/1.0/1.0, id9964=1.0/1.0/1.0, id9965=1.0/1.0/1.0, id9966=1.0/1.0/1.0, id9967=1.0/1.0/1.0, id9968=1.0/1.0/1.0, id9969=1.0/1.0/1.0, id997=1.0/1.0/1.0, id9970=1.0/1.0/1.0, id9971=1.0/1.0/1.0, id9972=1.0/1.0/1.0, id9973=1.0/1.0/1.0, id9974=1.0/1.0/1.0, id9975=1.0/1.0/1.0, id9976=1.0/1.0/1.0, id9977=1.0/1.0/1.0, id9978=1.0/1.0/1.0, id9979=1.0/1.0/1.0, id998=1.0/1.0/1.0, id9980=1.0/1.0/1.0, id9981=1.0/1.0/1.0, id9982=1.0/1.0/1.0, id9983=1.0/1.0/1.0, id9984=1.0/1.0/1.0, id9985=1.0/1.0/1.0, id9986=1.0/1.0/1.0, id9987=1.0/1.0/1.0, id9988=1.0/1.0/1.0, id9989=1.0/1.0/1.0, id999=1.0/1.0/1.0, id9990=1.0/1.0/1.0, id9991=1.0/1.0/1.0, id9992=1.0/1.0/1.0, id9993=1.0/1.0/1.0, id9994=1.0/1.0/1.0, id9995=1.0/1.0/1.0, id9996=1.0/1.0/1.0, id9997=1.0/1.0/1.0, id9998=1.0/1.0/1.0, id9999=1.0/1.0/1.0}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-10000-unique-keys.txt",
    "content": "id1;1.0\nid2;1.0\nid3;1.0\nid4;1.0\nid5;1.0\nid6;1.0\nid7;1.0\nid8;1.0\nid9;1.0\nid10;1.0\nid11;1.0\nid12;1.0\nid13;1.0\nid14;1.0\nid15;1.0\nid16;1.0\nid17;1.0\nid18;1.0\nid19;1.0\nid20;1.0\nid21;1.0\nid22;1.0\nid23;1.0\nid24;1.0\nid25;1.0\nid26;1.0\nid27;1.0\nid28;1.0\nid29;1.0\nid30;1.0\nid31;1.0\nid32;1.0\nid33;1.0\nid34;1.0\nid35;1.0\nid36;1.0\nid37;1.0\nid38;1.0\nid39;1.0\nid40;1.0\nid41;1.0\nid42;1.0\nid43;1.0\nid44;1.0\nid45;1.0\nid46;1.0\nid47;1.0\nid48;1.0\nid49;1.0\nid50;1.0\nid51;1.0\nid52;1.0\nid53;1.0\nid54;1.0\nid55;1.0\nid56;1.0\nid57;1.0\nid58;1.0\nid59;1.0\nid60;1.0\nid61;1.0\nid62;1.0\nid63;1.0\nid64;1.0\nid65;1.0\nid66;1.0\nid67;1.0\nid68;1.0\nid69;1.0\nid70;1.0\nid71;1.0\nid72;1.0\nid73;1.0\nid74;1.0\nid75;1.0\nid76;1.0\nid77;1.0\nid78;1.0\nid79;1.0\nid80;1.0\nid81;1.0\nid82;1.0\nid83;1.0\nid84;1.0\nid85;1.0\nid86;1.0\nid87;1.0\nid88;1.0\nid89;1.0\nid90;1.0\nid91;1.0\nid92;1.0\nid93;1.0\nid94;1.0\nid95;1.0\nid96;1.0\nid97;1.0\nid98;1.0\nid99;1.0\nid100;1.0\nid101;1.0\nid102;1.0\nid103;1.0\nid104;1.0\nid105;1.0\nid106;1.0\nid107;1.0\nid108;1.0\nid109;1.0\nid110;1.0\nid111;1.0\nid112;1.0\nid113;1.0\nid114;1.0\nid115;1.0\nid116;1.0\nid117;1.0\nid118;1.0\nid119;1.0\nid120;1.0\nid121;1.0\nid122;1.0\nid123;1.0\nid124;1.0\nid125;1.0\nid126;1.0\nid127;1.0\nid128;1.0\nid129;1.0\nid130;1.0\nid131;1.0\nid132;1.0\nid133;1.0\nid134;1.0\nid135;1.0\nid136;1.0\nid137;1.0\nid138;1.0\nid139;1.0\nid140;1.0\nid141;1.0\nid142;1.0\nid143;1.0\nid144;1.0\nid145;1.0\nid146;1.0\nid147;1.0\nid148;1.0\nid149;1.0\nid150;1.0\nid151;1.0\nid152;1.0\nid153;1.0\nid154;1.0\nid155;1.0\nid156;1.0\nid157;1.0\nid158;1.0\nid159;1.0\nid160;1.0\nid161;1.0\nid162;1.0\nid163;1.0\nid164;1.0\nid165;1.0\nid166;1.0\nid167;1.0\nid168;1.0\nid169;1.0\nid170;1.0\nid171;1.0\nid172;1.0\nid173;1.0\nid174;1.0\nid175;1.0\nid176;1.0\nid177;1.0\nid178;1.0\nid179;1.0\nid180;1.0\nid181;1.0\nid182;1.0\nid183;1.0\nid184;1.0\nid185;1.0\nid186;1.0\nid187;1.0\nid188;1.0\nid189;1.0\nid190;1.0\nid191;1.0\nid192;1.0\nid193;1.0\nid194;1.0\nid195;1.0\nid196;1.0\nid197;1.0\nid198;1.0\nid199;1.0\nid200;1.0\nid201;1.0\nid202;1.0\nid203;1.0\nid204;1.0\nid205;1.0\nid206;1.0\nid207;1.0\nid208;1.0\nid209;1.0\nid210;1.0\nid211;1.0\nid212;1.0\nid213;1.0\nid214;1.0\nid215;1.0\nid216;1.0\nid217;1.0\nid218;1.0\nid219;1.0\nid220;1.0\nid221;1.0\nid222;1.0\nid223;1.0\nid224;1.0\nid225;1.0\nid226;1.0\nid227;1.0\nid228;1.0\nid229;1.0\nid230;1.0\nid231;1.0\nid232;1.0\nid233;1.0\nid234;1.0\nid235;1.0\nid236;1.0\nid237;1.0\nid238;1.0\nid239;1.0\nid240;1.0\nid241;1.0\nid242;1.0\nid243;1.0\nid244;1.0\nid245;1.0\nid246;1.0\nid247;1.0\nid248;1.0\nid249;1.0\nid250;1.0\nid251;1.0\nid252;1.0\nid253;1.0\nid254;1.0\nid255;1.0\nid256;1.0\nid257;1.0\nid258;1.0\nid259;1.0\nid260;1.0\nid261;1.0\nid262;1.0\nid263;1.0\nid264;1.0\nid265;1.0\nid266;1.0\nid267;1.0\nid268;1.0\nid269;1.0\nid270;1.0\nid271;1.0\nid272;1.0\nid273;1.0\nid274;1.0\nid275;1.0\nid276;1.0\nid277;1.0\nid278;1.0\nid279;1.0\nid280;1.0\nid281;1.0\nid282;1.0\nid283;1.0\nid284;1.0\nid285;1.0\nid286;1.0\nid287;1.0\nid288;1.0\nid289;1.0\nid290;1.0\nid291;1.0\nid292;1.0\nid293;1.0\nid294;1.0\nid295;1.0\nid296;1.0\nid297;1.0\nid298;1.0\nid299;1.0\nid300;1.0\nid301;1.0\nid302;1.0\nid303;1.0\nid304;1.0\nid305;1.0\nid306;1.0\nid307;1.0\nid308;1.0\nid309;1.0\nid310;1.0\nid311;1.0\nid312;1.0\nid313;1.0\nid314;1.0\nid315;1.0\nid316;1.0\nid317;1.0\nid318;1.0\nid319;1.0\nid320;1.0\nid321;1.0\nid322;1.0\nid323;1.0\nid324;1.0\nid325;1.0\nid326;1.0\nid327;1.0\nid328;1.0\nid329;1.0\nid330;1.0\nid331;1.0\nid332;1.0\nid333;1.0\nid334;1.0\nid335;1.0\nid336;1.0\nid337;1.0\nid338;1.0\nid339;1.0\nid340;1.0\nid341;1.0\nid342;1.0\nid343;1.0\nid344;1.0\nid345;1.0\nid346;1.0\nid347;1.0\nid348;1.0\nid349;1.0\nid350;1.0\nid351;1.0\nid352;1.0\nid353;1.0\nid354;1.0\nid355;1.0\nid356;1.0\nid357;1.0\nid358;1.0\nid359;1.0\nid360;1.0\nid361;1.0\nid362;1.0\nid363;1.0\nid364;1.0\nid365;1.0\nid366;1.0\nid367;1.0\nid368;1.0\nid369;1.0\nid370;1.0\nid371;1.0\nid372;1.0\nid373;1.0\nid374;1.0\nid375;1.0\nid376;1.0\nid377;1.0\nid378;1.0\nid379;1.0\nid380;1.0\nid381;1.0\nid382;1.0\nid383;1.0\nid384;1.0\nid385;1.0\nid386;1.0\nid387;1.0\nid388;1.0\nid389;1.0\nid390;1.0\nid391;1.0\nid392;1.0\nid393;1.0\nid394;1.0\nid395;1.0\nid396;1.0\nid397;1.0\nid398;1.0\nid399;1.0\nid400;1.0\nid401;1.0\nid402;1.0\nid403;1.0\nid404;1.0\nid405;1.0\nid406;1.0\nid407;1.0\nid408;1.0\nid409;1.0\nid410;1.0\nid411;1.0\nid412;1.0\nid413;1.0\nid414;1.0\nid415;1.0\nid416;1.0\nid417;1.0\nid418;1.0\nid419;1.0\nid420;1.0\nid421;1.0\nid422;1.0\nid423;1.0\nid424;1.0\nid425;1.0\nid426;1.0\nid427;1.0\nid428;1.0\nid429;1.0\nid430;1.0\nid431;1.0\nid432;1.0\nid433;1.0\nid434;1.0\nid435;1.0\nid436;1.0\nid437;1.0\nid438;1.0\nid439;1.0\nid440;1.0\nid441;1.0\nid442;1.0\nid443;1.0\nid444;1.0\nid445;1.0\nid446;1.0\nid447;1.0\nid448;1.0\nid449;1.0\nid450;1.0\nid451;1.0\nid452;1.0\nid453;1.0\nid454;1.0\nid455;1.0\nid456;1.0\nid457;1.0\nid458;1.0\nid459;1.0\nid460;1.0\nid461;1.0\nid462;1.0\nid463;1.0\nid464;1.0\nid465;1.0\nid466;1.0\nid467;1.0\nid468;1.0\nid469;1.0\nid470;1.0\nid471;1.0\nid472;1.0\nid473;1.0\nid474;1.0\nid475;1.0\nid476;1.0\nid477;1.0\nid478;1.0\nid479;1.0\nid480;1.0\nid481;1.0\nid482;1.0\nid483;1.0\nid484;1.0\nid485;1.0\nid486;1.0\nid487;1.0\nid488;1.0\nid489;1.0\nid490;1.0\nid491;1.0\nid492;1.0\nid493;1.0\nid494;1.0\nid495;1.0\nid496;1.0\nid497;1.0\nid498;1.0\nid499;1.0\nid500;1.0\nid501;1.0\nid502;1.0\nid503;1.0\nid504;1.0\nid505;1.0\nid506;1.0\nid507;1.0\nid508;1.0\nid509;1.0\nid510;1.0\nid511;1.0\nid512;1.0\nid513;1.0\nid514;1.0\nid515;1.0\nid516;1.0\nid517;1.0\nid518;1.0\nid519;1.0\nid520;1.0\nid521;1.0\nid522;1.0\nid523;1.0\nid524;1.0\nid525;1.0\nid526;1.0\nid527;1.0\nid528;1.0\nid529;1.0\nid530;1.0\nid531;1.0\nid532;1.0\nid533;1.0\nid534;1.0\nid535;1.0\nid536;1.0\nid537;1.0\nid538;1.0\nid539;1.0\nid540;1.0\nid541;1.0\nid542;1.0\nid543;1.0\nid544;1.0\nid545;1.0\nid546;1.0\nid547;1.0\nid548;1.0\nid549;1.0\nid550;1.0\nid551;1.0\nid552;1.0\nid553;1.0\nid554;1.0\nid555;1.0\nid556;1.0\nid557;1.0\nid558;1.0\nid559;1.0\nid560;1.0\nid561;1.0\nid562;1.0\nid563;1.0\nid564;1.0\nid565;1.0\nid566;1.0\nid567;1.0\nid568;1.0\nid569;1.0\nid570;1.0\nid571;1.0\nid572;1.0\nid573;1.0\nid574;1.0\nid575;1.0\nid576;1.0\nid577;1.0\nid578;1.0\nid579;1.0\nid580;1.0\nid581;1.0\nid582;1.0\nid583;1.0\nid584;1.0\nid585;1.0\nid586;1.0\nid587;1.0\nid588;1.0\nid589;1.0\nid590;1.0\nid591;1.0\nid592;1.0\nid593;1.0\nid594;1.0\nid595;1.0\nid596;1.0\nid597;1.0\nid598;1.0\nid599;1.0\nid600;1.0\nid601;1.0\nid602;1.0\nid603;1.0\nid604;1.0\nid605;1.0\nid606;1.0\nid607;1.0\nid608;1.0\nid609;1.0\nid610;1.0\nid611;1.0\nid612;1.0\nid613;1.0\nid614;1.0\nid615;1.0\nid616;1.0\nid617;1.0\nid618;1.0\nid619;1.0\nid620;1.0\nid621;1.0\nid622;1.0\nid623;1.0\nid624;1.0\nid625;1.0\nid626;1.0\nid627;1.0\nid628;1.0\nid629;1.0\nid630;1.0\nid631;1.0\nid632;1.0\nid633;1.0\nid634;1.0\nid635;1.0\nid636;1.0\nid637;1.0\nid638;1.0\nid639;1.0\nid640;1.0\nid641;1.0\nid642;1.0\nid643;1.0\nid644;1.0\nid645;1.0\nid646;1.0\nid647;1.0\nid648;1.0\nid649;1.0\nid650;1.0\nid651;1.0\nid652;1.0\nid653;1.0\nid654;1.0\nid655;1.0\nid656;1.0\nid657;1.0\nid658;1.0\nid659;1.0\nid660;1.0\nid661;1.0\nid662;1.0\nid663;1.0\nid664;1.0\nid665;1.0\nid666;1.0\nid667;1.0\nid668;1.0\nid669;1.0\nid670;1.0\nid671;1.0\nid672;1.0\nid673;1.0\nid674;1.0\nid675;1.0\nid676;1.0\nid677;1.0\nid678;1.0\nid679;1.0\nid680;1.0\nid681;1.0\nid682;1.0\nid683;1.0\nid684;1.0\nid685;1.0\nid686;1.0\nid687;1.0\nid688;1.0\nid689;1.0\nid690;1.0\nid691;1.0\nid692;1.0\nid693;1.0\nid694;1.0\nid695;1.0\nid696;1.0\nid697;1.0\nid698;1.0\nid699;1.0\nid700;1.0\nid701;1.0\nid702;1.0\nid703;1.0\nid704;1.0\nid705;1.0\nid706;1.0\nid707;1.0\nid708;1.0\nid709;1.0\nid710;1.0\nid711;1.0\nid712;1.0\nid713;1.0\nid714;1.0\nid715;1.0\nid716;1.0\nid717;1.0\nid718;1.0\nid719;1.0\nid720;1.0\nid721;1.0\nid722;1.0\nid723;1.0\nid724;1.0\nid725;1.0\nid726;1.0\nid727;1.0\nid728;1.0\nid729;1.0\nid730;1.0\nid731;1.0\nid732;1.0\nid733;1.0\nid734;1.0\nid735;1.0\nid736;1.0\nid737;1.0\nid738;1.0\nid739;1.0\nid740;1.0\nid741;1.0\nid742;1.0\nid743;1.0\nid744;1.0\nid745;1.0\nid746;1.0\nid747;1.0\nid748;1.0\nid749;1.0\nid750;1.0\nid751;1.0\nid752;1.0\nid753;1.0\nid754;1.0\nid755;1.0\nid756;1.0\nid757;1.0\nid758;1.0\nid759;1.0\nid760;1.0\nid761;1.0\nid762;1.0\nid763;1.0\nid764;1.0\nid765;1.0\nid766;1.0\nid767;1.0\nid768;1.0\nid769;1.0\nid770;1.0\nid771;1.0\nid772;1.0\nid773;1.0\nid774;1.0\nid775;1.0\nid776;1.0\nid777;1.0\nid778;1.0\nid779;1.0\nid780;1.0\nid781;1.0\nid782;1.0\nid783;1.0\nid784;1.0\nid785;1.0\nid786;1.0\nid787;1.0\nid788;1.0\nid789;1.0\nid790;1.0\nid791;1.0\nid792;1.0\nid793;1.0\nid794;1.0\nid795;1.0\nid796;1.0\nid797;1.0\nid798;1.0\nid799;1.0\nid800;1.0\nid801;1.0\nid802;1.0\nid803;1.0\nid804;1.0\nid805;1.0\nid806;1.0\nid807;1.0\nid808;1.0\nid809;1.0\nid810;1.0\nid811;1.0\nid812;1.0\nid813;1.0\nid814;1.0\nid815;1.0\nid816;1.0\nid817;1.0\nid818;1.0\nid819;1.0\nid820;1.0\nid821;1.0\nid822;1.0\nid823;1.0\nid824;1.0\nid825;1.0\nid826;1.0\nid827;1.0\nid828;1.0\nid829;1.0\nid830;1.0\nid831;1.0\nid832;1.0\nid833;1.0\nid834;1.0\nid835;1.0\nid836;1.0\nid837;1.0\nid838;1.0\nid839;1.0\nid840;1.0\nid841;1.0\nid842;1.0\nid843;1.0\nid844;1.0\nid845;1.0\nid846;1.0\nid847;1.0\nid848;1.0\nid849;1.0\nid850;1.0\nid851;1.0\nid852;1.0\nid853;1.0\nid854;1.0\nid855;1.0\nid856;1.0\nid857;1.0\nid858;1.0\nid859;1.0\nid860;1.0\nid861;1.0\nid862;1.0\nid863;1.0\nid864;1.0\nid865;1.0\nid866;1.0\nid867;1.0\nid868;1.0\nid869;1.0\nid870;1.0\nid871;1.0\nid872;1.0\nid873;1.0\nid874;1.0\nid875;1.0\nid876;1.0\nid877;1.0\nid878;1.0\nid879;1.0\nid880;1.0\nid881;1.0\nid882;1.0\nid883;1.0\nid884;1.0\nid885;1.0\nid886;1.0\nid887;1.0\nid888;1.0\nid889;1.0\nid890;1.0\nid891;1.0\nid892;1.0\nid893;1.0\nid894;1.0\nid895;1.0\nid896;1.0\nid897;1.0\nid898;1.0\nid899;1.0\nid900;1.0\nid901;1.0\nid902;1.0\nid903;1.0\nid904;1.0\nid905;1.0\nid906;1.0\nid907;1.0\nid908;1.0\nid909;1.0\nid910;1.0\nid911;1.0\nid912;1.0\nid913;1.0\nid914;1.0\nid915;1.0\nid916;1.0\nid917;1.0\nid918;1.0\nid919;1.0\nid920;1.0\nid921;1.0\nid922;1.0\nid923;1.0\nid924;1.0\nid925;1.0\nid926;1.0\nid927;1.0\nid928;1.0\nid929;1.0\nid930;1.0\nid931;1.0\nid932;1.0\nid933;1.0\nid934;1.0\nid935;1.0\nid936;1.0\nid937;1.0\nid938;1.0\nid939;1.0\nid940;1.0\nid941;1.0\nid942;1.0\nid943;1.0\nid944;1.0\nid945;1.0\nid946;1.0\nid947;1.0\nid948;1.0\nid949;1.0\nid950;1.0\nid951;1.0\nid952;1.0\nid953;1.0\nid954;1.0\nid955;1.0\nid956;1.0\nid957;1.0\nid958;1.0\nid959;1.0\nid960;1.0\nid961;1.0\nid962;1.0\nid963;1.0\nid964;1.0\nid965;1.0\nid966;1.0\nid967;1.0\nid968;1.0\nid969;1.0\nid970;1.0\nid971;1.0\nid972;1.0\nid973;1.0\nid974;1.0\nid975;1.0\nid976;1.0\nid977;1.0\nid978;1.0\nid979;1.0\nid980;1.0\nid981;1.0\nid982;1.0\nid983;1.0\nid984;1.0\nid985;1.0\nid986;1.0\nid987;1.0\nid988;1.0\nid989;1.0\nid990;1.0\nid991;1.0\nid992;1.0\nid993;1.0\nid994;1.0\nid995;1.0\nid996;1.0\nid997;1.0\nid998;1.0\nid999;1.0\nid1000;1.0\nid1001;1.0\nid1002;1.0\nid1003;1.0\nid1004;1.0\nid1005;1.0\nid1006;1.0\nid1007;1.0\nid1008;1.0\nid1009;1.0\nid1010;1.0\nid1011;1.0\nid1012;1.0\nid1013;1.0\nid1014;1.0\nid1015;1.0\nid1016;1.0\nid1017;1.0\nid1018;1.0\nid1019;1.0\nid1020;1.0\nid1021;1.0\nid1022;1.0\nid1023;1.0\nid1024;1.0\nid1025;1.0\nid1026;1.0\nid1027;1.0\nid1028;1.0\nid1029;1.0\nid1030;1.0\nid1031;1.0\nid1032;1.0\nid1033;1.0\nid1034;1.0\nid1035;1.0\nid1036;1.0\nid1037;1.0\nid1038;1.0\nid1039;1.0\nid1040;1.0\nid1041;1.0\nid1042;1.0\nid1043;1.0\nid1044;1.0\nid1045;1.0\nid1046;1.0\nid1047;1.0\nid1048;1.0\nid1049;1.0\nid1050;1.0\nid1051;1.0\nid1052;1.0\nid1053;1.0\nid1054;1.0\nid1055;1.0\nid1056;1.0\nid1057;1.0\nid1058;1.0\nid1059;1.0\nid1060;1.0\nid1061;1.0\nid1062;1.0\nid1063;1.0\nid1064;1.0\nid1065;1.0\nid1066;1.0\nid1067;1.0\nid1068;1.0\nid1069;1.0\nid1070;1.0\nid1071;1.0\nid1072;1.0\nid1073;1.0\nid1074;1.0\nid1075;1.0\nid1076;1.0\nid1077;1.0\nid1078;1.0\nid1079;1.0\nid1080;1.0\nid1081;1.0\nid1082;1.0\nid1083;1.0\nid1084;1.0\nid1085;1.0\nid1086;1.0\nid1087;1.0\nid1088;1.0\nid1089;1.0\nid1090;1.0\nid1091;1.0\nid1092;1.0\nid1093;1.0\nid1094;1.0\nid1095;1.0\nid1096;1.0\nid1097;1.0\nid1098;1.0\nid1099;1.0\nid1100;1.0\nid1101;1.0\nid1102;1.0\nid1103;1.0\nid1104;1.0\nid1105;1.0\nid1106;1.0\nid1107;1.0\nid1108;1.0\nid1109;1.0\nid1110;1.0\nid1111;1.0\nid1112;1.0\nid1113;1.0\nid1114;1.0\nid1115;1.0\nid1116;1.0\nid1117;1.0\nid1118;1.0\nid1119;1.0\nid1120;1.0\nid1121;1.0\nid1122;1.0\nid1123;1.0\nid1124;1.0\nid1125;1.0\nid1126;1.0\nid1127;1.0\nid1128;1.0\nid1129;1.0\nid1130;1.0\nid1131;1.0\nid1132;1.0\nid1133;1.0\nid1134;1.0\nid1135;1.0\nid1136;1.0\nid1137;1.0\nid1138;1.0\nid1139;1.0\nid1140;1.0\nid1141;1.0\nid1142;1.0\nid1143;1.0\nid1144;1.0\nid1145;1.0\nid1146;1.0\nid1147;1.0\nid1148;1.0\nid1149;1.0\nid1150;1.0\nid1151;1.0\nid1152;1.0\nid1153;1.0\nid1154;1.0\nid1155;1.0\nid1156;1.0\nid1157;1.0\nid1158;1.0\nid1159;1.0\nid1160;1.0\nid1161;1.0\nid1162;1.0\nid1163;1.0\nid1164;1.0\nid1165;1.0\nid1166;1.0\nid1167;1.0\nid1168;1.0\nid1169;1.0\nid1170;1.0\nid1171;1.0\nid1172;1.0\nid1173;1.0\nid1174;1.0\nid1175;1.0\nid1176;1.0\nid1177;1.0\nid1178;1.0\nid1179;1.0\nid1180;1.0\nid1181;1.0\nid1182;1.0\nid1183;1.0\nid1184;1.0\nid1185;1.0\nid1186;1.0\nid1187;1.0\nid1188;1.0\nid1189;1.0\nid1190;1.0\nid1191;1.0\nid1192;1.0\nid1193;1.0\nid1194;1.0\nid1195;1.0\nid1196;1.0\nid1197;1.0\nid1198;1.0\nid1199;1.0\nid1200;1.0\nid1201;1.0\nid1202;1.0\nid1203;1.0\nid1204;1.0\nid1205;1.0\nid1206;1.0\nid1207;1.0\nid1208;1.0\nid1209;1.0\nid1210;1.0\nid1211;1.0\nid1212;1.0\nid1213;1.0\nid1214;1.0\nid1215;1.0\nid1216;1.0\nid1217;1.0\nid1218;1.0\nid1219;1.0\nid1220;1.0\nid1221;1.0\nid1222;1.0\nid1223;1.0\nid1224;1.0\nid1225;1.0\nid1226;1.0\nid1227;1.0\nid1228;1.0\nid1229;1.0\nid1230;1.0\nid1231;1.0\nid1232;1.0\nid1233;1.0\nid1234;1.0\nid1235;1.0\nid1236;1.0\nid1237;1.0\nid1238;1.0\nid1239;1.0\nid1240;1.0\nid1241;1.0\nid1242;1.0\nid1243;1.0\nid1244;1.0\nid1245;1.0\nid1246;1.0\nid1247;1.0\nid1248;1.0\nid1249;1.0\nid1250;1.0\nid1251;1.0\nid1252;1.0\nid1253;1.0\nid1254;1.0\nid1255;1.0\nid1256;1.0\nid1257;1.0\nid1258;1.0\nid1259;1.0\nid1260;1.0\nid1261;1.0\nid1262;1.0\nid1263;1.0\nid1264;1.0\nid1265;1.0\nid1266;1.0\nid1267;1.0\nid1268;1.0\nid1269;1.0\nid1270;1.0\nid1271;1.0\nid1272;1.0\nid1273;1.0\nid1274;1.0\nid1275;1.0\nid1276;1.0\nid1277;1.0\nid1278;1.0\nid1279;1.0\nid1280;1.0\nid1281;1.0\nid1282;1.0\nid1283;1.0\nid1284;1.0\nid1285;1.0\nid1286;1.0\nid1287;1.0\nid1288;1.0\nid1289;1.0\nid1290;1.0\nid1291;1.0\nid1292;1.0\nid1293;1.0\nid1294;1.0\nid1295;1.0\nid1296;1.0\nid1297;1.0\nid1298;1.0\nid1299;1.0\nid1300;1.0\nid1301;1.0\nid1302;1.0\nid1303;1.0\nid1304;1.0\nid1305;1.0\nid1306;1.0\nid1307;1.0\nid1308;1.0\nid1309;1.0\nid1310;1.0\nid1311;1.0\nid1312;1.0\nid1313;1.0\nid1314;1.0\nid1315;1.0\nid1316;1.0\nid1317;1.0\nid1318;1.0\nid1319;1.0\nid1320;1.0\nid1321;1.0\nid1322;1.0\nid1323;1.0\nid1324;1.0\nid1325;1.0\nid1326;1.0\nid1327;1.0\nid1328;1.0\nid1329;1.0\nid1330;1.0\nid1331;1.0\nid1332;1.0\nid1333;1.0\nid1334;1.0\nid1335;1.0\nid1336;1.0\nid1337;1.0\nid1338;1.0\nid1339;1.0\nid1340;1.0\nid1341;1.0\nid1342;1.0\nid1343;1.0\nid1344;1.0\nid1345;1.0\nid1346;1.0\nid1347;1.0\nid1348;1.0\nid1349;1.0\nid1350;1.0\nid1351;1.0\nid1352;1.0\nid1353;1.0\nid1354;1.0\nid1355;1.0\nid1356;1.0\nid1357;1.0\nid1358;1.0\nid1359;1.0\nid1360;1.0\nid1361;1.0\nid1362;1.0\nid1363;1.0\nid1364;1.0\nid1365;1.0\nid1366;1.0\nid1367;1.0\nid1368;1.0\nid1369;1.0\nid1370;1.0\nid1371;1.0\nid1372;1.0\nid1373;1.0\nid1374;1.0\nid1375;1.0\nid1376;1.0\nid1377;1.0\nid1378;1.0\nid1379;1.0\nid1380;1.0\nid1381;1.0\nid1382;1.0\nid1383;1.0\nid1384;1.0\nid1385;1.0\nid1386;1.0\nid1387;1.0\nid1388;1.0\nid1389;1.0\nid1390;1.0\nid1391;1.0\nid1392;1.0\nid1393;1.0\nid1394;1.0\nid1395;1.0\nid1396;1.0\nid1397;1.0\nid1398;1.0\nid1399;1.0\nid1400;1.0\nid1401;1.0\nid1402;1.0\nid1403;1.0\nid1404;1.0\nid1405;1.0\nid1406;1.0\nid1407;1.0\nid1408;1.0\nid1409;1.0\nid1410;1.0\nid1411;1.0\nid1412;1.0\nid1413;1.0\nid1414;1.0\nid1415;1.0\nid1416;1.0\nid1417;1.0\nid1418;1.0\nid1419;1.0\nid1420;1.0\nid1421;1.0\nid1422;1.0\nid1423;1.0\nid1424;1.0\nid1425;1.0\nid1426;1.0\nid1427;1.0\nid1428;1.0\nid1429;1.0\nid1430;1.0\nid1431;1.0\nid1432;1.0\nid1433;1.0\nid1434;1.0\nid1435;1.0\nid1436;1.0\nid1437;1.0\nid1438;1.0\nid1439;1.0\nid1440;1.0\nid1441;1.0\nid1442;1.0\nid1443;1.0\nid1444;1.0\nid1445;1.0\nid1446;1.0\nid1447;1.0\nid1448;1.0\nid1449;1.0\nid1450;1.0\nid1451;1.0\nid1452;1.0\nid1453;1.0\nid1454;1.0\nid1455;1.0\nid1456;1.0\nid1457;1.0\nid1458;1.0\nid1459;1.0\nid1460;1.0\nid1461;1.0\nid1462;1.0\nid1463;1.0\nid1464;1.0\nid1465;1.0\nid1466;1.0\nid1467;1.0\nid1468;1.0\nid1469;1.0\nid1470;1.0\nid1471;1.0\nid1472;1.0\nid1473;1.0\nid1474;1.0\nid1475;1.0\nid1476;1.0\nid1477;1.0\nid1478;1.0\nid1479;1.0\nid1480;1.0\nid1481;1.0\nid1482;1.0\nid1483;1.0\nid1484;1.0\nid1485;1.0\nid1486;1.0\nid1487;1.0\nid1488;1.0\nid1489;1.0\nid1490;1.0\nid1491;1.0\nid1492;1.0\nid1493;1.0\nid1494;1.0\nid1495;1.0\nid1496;1.0\nid1497;1.0\nid1498;1.0\nid1499;1.0\nid1500;1.0\nid1501;1.0\nid1502;1.0\nid1503;1.0\nid1504;1.0\nid1505;1.0\nid1506;1.0\nid1507;1.0\nid1508;1.0\nid1509;1.0\nid1510;1.0\nid1511;1.0\nid1512;1.0\nid1513;1.0\nid1514;1.0\nid1515;1.0\nid1516;1.0\nid1517;1.0\nid1518;1.0\nid1519;1.0\nid1520;1.0\nid1521;1.0\nid1522;1.0\nid1523;1.0\nid1524;1.0\nid1525;1.0\nid1526;1.0\nid1527;1.0\nid1528;1.0\nid1529;1.0\nid1530;1.0\nid1531;1.0\nid1532;1.0\nid1533;1.0\nid1534;1.0\nid1535;1.0\nid1536;1.0\nid1537;1.0\nid1538;1.0\nid1539;1.0\nid1540;1.0\nid1541;1.0\nid1542;1.0\nid1543;1.0\nid1544;1.0\nid1545;1.0\nid1546;1.0\nid1547;1.0\nid1548;1.0\nid1549;1.0\nid1550;1.0\nid1551;1.0\nid1552;1.0\nid1553;1.0\nid1554;1.0\nid1555;1.0\nid1556;1.0\nid1557;1.0\nid1558;1.0\nid1559;1.0\nid1560;1.0\nid1561;1.0\nid1562;1.0\nid1563;1.0\nid1564;1.0\nid1565;1.0\nid1566;1.0\nid1567;1.0\nid1568;1.0\nid1569;1.0\nid1570;1.0\nid1571;1.0\nid1572;1.0\nid1573;1.0\nid1574;1.0\nid1575;1.0\nid1576;1.0\nid1577;1.0\nid1578;1.0\nid1579;1.0\nid1580;1.0\nid1581;1.0\nid1582;1.0\nid1583;1.0\nid1584;1.0\nid1585;1.0\nid1586;1.0\nid1587;1.0\nid1588;1.0\nid1589;1.0\nid1590;1.0\nid1591;1.0\nid1592;1.0\nid1593;1.0\nid1594;1.0\nid1595;1.0\nid1596;1.0\nid1597;1.0\nid1598;1.0\nid1599;1.0\nid1600;1.0\nid1601;1.0\nid1602;1.0\nid1603;1.0\nid1604;1.0\nid1605;1.0\nid1606;1.0\nid1607;1.0\nid1608;1.0\nid1609;1.0\nid1610;1.0\nid1611;1.0\nid1612;1.0\nid1613;1.0\nid1614;1.0\nid1615;1.0\nid1616;1.0\nid1617;1.0\nid1618;1.0\nid1619;1.0\nid1620;1.0\nid1621;1.0\nid1622;1.0\nid1623;1.0\nid1624;1.0\nid1625;1.0\nid1626;1.0\nid1627;1.0\nid1628;1.0\nid1629;1.0\nid1630;1.0\nid1631;1.0\nid1632;1.0\nid1633;1.0\nid1634;1.0\nid1635;1.0\nid1636;1.0\nid1637;1.0\nid1638;1.0\nid1639;1.0\nid1640;1.0\nid1641;1.0\nid1642;1.0\nid1643;1.0\nid1644;1.0\nid1645;1.0\nid1646;1.0\nid1647;1.0\nid1648;1.0\nid1649;1.0\nid1650;1.0\nid1651;1.0\nid1652;1.0\nid1653;1.0\nid1654;1.0\nid1655;1.0\nid1656;1.0\nid1657;1.0\nid1658;1.0\nid1659;1.0\nid1660;1.0\nid1661;1.0\nid1662;1.0\nid1663;1.0\nid1664;1.0\nid1665;1.0\nid1666;1.0\nid1667;1.0\nid1668;1.0\nid1669;1.0\nid1670;1.0\nid1671;1.0\nid1672;1.0\nid1673;1.0\nid1674;1.0\nid1675;1.0\nid1676;1.0\nid1677;1.0\nid1678;1.0\nid1679;1.0\nid1680;1.0\nid1681;1.0\nid1682;1.0\nid1683;1.0\nid1684;1.0\nid1685;1.0\nid1686;1.0\nid1687;1.0\nid1688;1.0\nid1689;1.0\nid1690;1.0\nid1691;1.0\nid1692;1.0\nid1693;1.0\nid1694;1.0\nid1695;1.0\nid1696;1.0\nid1697;1.0\nid1698;1.0\nid1699;1.0\nid1700;1.0\nid1701;1.0\nid1702;1.0\nid1703;1.0\nid1704;1.0\nid1705;1.0\nid1706;1.0\nid1707;1.0\nid1708;1.0\nid1709;1.0\nid1710;1.0\nid1711;1.0\nid1712;1.0\nid1713;1.0\nid1714;1.0\nid1715;1.0\nid1716;1.0\nid1717;1.0\nid1718;1.0\nid1719;1.0\nid1720;1.0\nid1721;1.0\nid1722;1.0\nid1723;1.0\nid1724;1.0\nid1725;1.0\nid1726;1.0\nid1727;1.0\nid1728;1.0\nid1729;1.0\nid1730;1.0\nid1731;1.0\nid1732;1.0\nid1733;1.0\nid1734;1.0\nid1735;1.0\nid1736;1.0\nid1737;1.0\nid1738;1.0\nid1739;1.0\nid1740;1.0\nid1741;1.0\nid1742;1.0\nid1743;1.0\nid1744;1.0\nid1745;1.0\nid1746;1.0\nid1747;1.0\nid1748;1.0\nid1749;1.0\nid1750;1.0\nid1751;1.0\nid1752;1.0\nid1753;1.0\nid1754;1.0\nid1755;1.0\nid1756;1.0\nid1757;1.0\nid1758;1.0\nid1759;1.0\nid1760;1.0\nid1761;1.0\nid1762;1.0\nid1763;1.0\nid1764;1.0\nid1765;1.0\nid1766;1.0\nid1767;1.0\nid1768;1.0\nid1769;1.0\nid1770;1.0\nid1771;1.0\nid1772;1.0\nid1773;1.0\nid1774;1.0\nid1775;1.0\nid1776;1.0\nid1777;1.0\nid1778;1.0\nid1779;1.0\nid1780;1.0\nid1781;1.0\nid1782;1.0\nid1783;1.0\nid1784;1.0\nid1785;1.0\nid1786;1.0\nid1787;1.0\nid1788;1.0\nid1789;1.0\nid1790;1.0\nid1791;1.0\nid1792;1.0\nid1793;1.0\nid1794;1.0\nid1795;1.0\nid1796;1.0\nid1797;1.0\nid1798;1.0\nid1799;1.0\nid1800;1.0\nid1801;1.0\nid1802;1.0\nid1803;1.0\nid1804;1.0\nid1805;1.0\nid1806;1.0\nid1807;1.0\nid1808;1.0\nid1809;1.0\nid1810;1.0\nid1811;1.0\nid1812;1.0\nid1813;1.0\nid1814;1.0\nid1815;1.0\nid1816;1.0\nid1817;1.0\nid1818;1.0\nid1819;1.0\nid1820;1.0\nid1821;1.0\nid1822;1.0\nid1823;1.0\nid1824;1.0\nid1825;1.0\nid1826;1.0\nid1827;1.0\nid1828;1.0\nid1829;1.0\nid1830;1.0\nid1831;1.0\nid1832;1.0\nid1833;1.0\nid1834;1.0\nid1835;1.0\nid1836;1.0\nid1837;1.0\nid1838;1.0\nid1839;1.0\nid1840;1.0\nid1841;1.0\nid1842;1.0\nid1843;1.0\nid1844;1.0\nid1845;1.0\nid1846;1.0\nid1847;1.0\nid1848;1.0\nid1849;1.0\nid1850;1.0\nid1851;1.0\nid1852;1.0\nid1853;1.0\nid1854;1.0\nid1855;1.0\nid1856;1.0\nid1857;1.0\nid1858;1.0\nid1859;1.0\nid1860;1.0\nid1861;1.0\nid1862;1.0\nid1863;1.0\nid1864;1.0\nid1865;1.0\nid1866;1.0\nid1867;1.0\nid1868;1.0\nid1869;1.0\nid1870;1.0\nid1871;1.0\nid1872;1.0\nid1873;1.0\nid1874;1.0\nid1875;1.0\nid1876;1.0\nid1877;1.0\nid1878;1.0\nid1879;1.0\nid1880;1.0\nid1881;1.0\nid1882;1.0\nid1883;1.0\nid1884;1.0\nid1885;1.0\nid1886;1.0\nid1887;1.0\nid1888;1.0\nid1889;1.0\nid1890;1.0\nid1891;1.0\nid1892;1.0\nid1893;1.0\nid1894;1.0\nid1895;1.0\nid1896;1.0\nid1897;1.0\nid1898;1.0\nid1899;1.0\nid1900;1.0\nid1901;1.0\nid1902;1.0\nid1903;1.0\nid1904;1.0\nid1905;1.0\nid1906;1.0\nid1907;1.0\nid1908;1.0\nid1909;1.0\nid1910;1.0\nid1911;1.0\nid1912;1.0\nid1913;1.0\nid1914;1.0\nid1915;1.0\nid1916;1.0\nid1917;1.0\nid1918;1.0\nid1919;1.0\nid1920;1.0\nid1921;1.0\nid1922;1.0\nid1923;1.0\nid1924;1.0\nid1925;1.0\nid1926;1.0\nid1927;1.0\nid1928;1.0\nid1929;1.0\nid1930;1.0\nid1931;1.0\nid1932;1.0\nid1933;1.0\nid1934;1.0\nid1935;1.0\nid1936;1.0\nid1937;1.0\nid1938;1.0\nid1939;1.0\nid1940;1.0\nid1941;1.0\nid1942;1.0\nid1943;1.0\nid1944;1.0\nid1945;1.0\nid1946;1.0\nid1947;1.0\nid1948;1.0\nid1949;1.0\nid1950;1.0\nid1951;1.0\nid1952;1.0\nid1953;1.0\nid1954;1.0\nid1955;1.0\nid1956;1.0\nid1957;1.0\nid1958;1.0\nid1959;1.0\nid1960;1.0\nid1961;1.0\nid1962;1.0\nid1963;1.0\nid1964;1.0\nid1965;1.0\nid1966;1.0\nid1967;1.0\nid1968;1.0\nid1969;1.0\nid1970;1.0\nid1971;1.0\nid1972;1.0\nid1973;1.0\nid1974;1.0\nid1975;1.0\nid1976;1.0\nid1977;1.0\nid1978;1.0\nid1979;1.0\nid1980;1.0\nid1981;1.0\nid1982;1.0\nid1983;1.0\nid1984;1.0\nid1985;1.0\nid1986;1.0\nid1987;1.0\nid1988;1.0\nid1989;1.0\nid1990;1.0\nid1991;1.0\nid1992;1.0\nid1993;1.0\nid1994;1.0\nid1995;1.0\nid1996;1.0\nid1997;1.0\nid1998;1.0\nid1999;1.0\nid2000;1.0\nid2001;1.0\nid2002;1.0\nid2003;1.0\nid2004;1.0\nid2005;1.0\nid2006;1.0\nid2007;1.0\nid2008;1.0\nid2009;1.0\nid2010;1.0\nid2011;1.0\nid2012;1.0\nid2013;1.0\nid2014;1.0\nid2015;1.0\nid2016;1.0\nid2017;1.0\nid2018;1.0\nid2019;1.0\nid2020;1.0\nid2021;1.0\nid2022;1.0\nid2023;1.0\nid2024;1.0\nid2025;1.0\nid2026;1.0\nid2027;1.0\nid2028;1.0\nid2029;1.0\nid2030;1.0\nid2031;1.0\nid2032;1.0\nid2033;1.0\nid2034;1.0\nid2035;1.0\nid2036;1.0\nid2037;1.0\nid2038;1.0\nid2039;1.0\nid2040;1.0\nid2041;1.0\nid2042;1.0\nid2043;1.0\nid2044;1.0\nid2045;1.0\nid2046;1.0\nid2047;1.0\nid2048;1.0\nid2049;1.0\nid2050;1.0\nid2051;1.0\nid2052;1.0\nid2053;1.0\nid2054;1.0\nid2055;1.0\nid2056;1.0\nid2057;1.0\nid2058;1.0\nid2059;1.0\nid2060;1.0\nid2061;1.0\nid2062;1.0\nid2063;1.0\nid2064;1.0\nid2065;1.0\nid2066;1.0\nid2067;1.0\nid2068;1.0\nid2069;1.0\nid2070;1.0\nid2071;1.0\nid2072;1.0\nid2073;1.0\nid2074;1.0\nid2075;1.0\nid2076;1.0\nid2077;1.0\nid2078;1.0\nid2079;1.0\nid2080;1.0\nid2081;1.0\nid2082;1.0\nid2083;1.0\nid2084;1.0\nid2085;1.0\nid2086;1.0\nid2087;1.0\nid2088;1.0\nid2089;1.0\nid2090;1.0\nid2091;1.0\nid2092;1.0\nid2093;1.0\nid2094;1.0\nid2095;1.0\nid2096;1.0\nid2097;1.0\nid2098;1.0\nid2099;1.0\nid2100;1.0\nid2101;1.0\nid2102;1.0\nid2103;1.0\nid2104;1.0\nid2105;1.0\nid2106;1.0\nid2107;1.0\nid2108;1.0\nid2109;1.0\nid2110;1.0\nid2111;1.0\nid2112;1.0\nid2113;1.0\nid2114;1.0\nid2115;1.0\nid2116;1.0\nid2117;1.0\nid2118;1.0\nid2119;1.0\nid2120;1.0\nid2121;1.0\nid2122;1.0\nid2123;1.0\nid2124;1.0\nid2125;1.0\nid2126;1.0\nid2127;1.0\nid2128;1.0\nid2129;1.0\nid2130;1.0\nid2131;1.0\nid2132;1.0\nid2133;1.0\nid2134;1.0\nid2135;1.0\nid2136;1.0\nid2137;1.0\nid2138;1.0\nid2139;1.0\nid2140;1.0\nid2141;1.0\nid2142;1.0\nid2143;1.0\nid2144;1.0\nid2145;1.0\nid2146;1.0\nid2147;1.0\nid2148;1.0\nid2149;1.0\nid2150;1.0\nid2151;1.0\nid2152;1.0\nid2153;1.0\nid2154;1.0\nid2155;1.0\nid2156;1.0\nid2157;1.0\nid2158;1.0\nid2159;1.0\nid2160;1.0\nid2161;1.0\nid2162;1.0\nid2163;1.0\nid2164;1.0\nid2165;1.0\nid2166;1.0\nid2167;1.0\nid2168;1.0\nid2169;1.0\nid2170;1.0\nid2171;1.0\nid2172;1.0\nid2173;1.0\nid2174;1.0\nid2175;1.0\nid2176;1.0\nid2177;1.0\nid2178;1.0\nid2179;1.0\nid2180;1.0\nid2181;1.0\nid2182;1.0\nid2183;1.0\nid2184;1.0\nid2185;1.0\nid2186;1.0\nid2187;1.0\nid2188;1.0\nid2189;1.0\nid2190;1.0\nid2191;1.0\nid2192;1.0\nid2193;1.0\nid2194;1.0\nid2195;1.0\nid2196;1.0\nid2197;1.0\nid2198;1.0\nid2199;1.0\nid2200;1.0\nid2201;1.0\nid2202;1.0\nid2203;1.0\nid2204;1.0\nid2205;1.0\nid2206;1.0\nid2207;1.0\nid2208;1.0\nid2209;1.0\nid2210;1.0\nid2211;1.0\nid2212;1.0\nid2213;1.0\nid2214;1.0\nid2215;1.0\nid2216;1.0\nid2217;1.0\nid2218;1.0\nid2219;1.0\nid2220;1.0\nid2221;1.0\nid2222;1.0\nid2223;1.0\nid2224;1.0\nid2225;1.0\nid2226;1.0\nid2227;1.0\nid2228;1.0\nid2229;1.0\nid2230;1.0\nid2231;1.0\nid2232;1.0\nid2233;1.0\nid2234;1.0\nid2235;1.0\nid2236;1.0\nid2237;1.0\nid2238;1.0\nid2239;1.0\nid2240;1.0\nid2241;1.0\nid2242;1.0\nid2243;1.0\nid2244;1.0\nid2245;1.0\nid2246;1.0\nid2247;1.0\nid2248;1.0\nid2249;1.0\nid2250;1.0\nid2251;1.0\nid2252;1.0\nid2253;1.0\nid2254;1.0\nid2255;1.0\nid2256;1.0\nid2257;1.0\nid2258;1.0\nid2259;1.0\nid2260;1.0\nid2261;1.0\nid2262;1.0\nid2263;1.0\nid2264;1.0\nid2265;1.0\nid2266;1.0\nid2267;1.0\nid2268;1.0\nid2269;1.0\nid2270;1.0\nid2271;1.0\nid2272;1.0\nid2273;1.0\nid2274;1.0\nid2275;1.0\nid2276;1.0\nid2277;1.0\nid2278;1.0\nid2279;1.0\nid2280;1.0\nid2281;1.0\nid2282;1.0\nid2283;1.0\nid2284;1.0\nid2285;1.0\nid2286;1.0\nid2287;1.0\nid2288;1.0\nid2289;1.0\nid2290;1.0\nid2291;1.0\nid2292;1.0\nid2293;1.0\nid2294;1.0\nid2295;1.0\nid2296;1.0\nid2297;1.0\nid2298;1.0\nid2299;1.0\nid2300;1.0\nid2301;1.0\nid2302;1.0\nid2303;1.0\nid2304;1.0\nid2305;1.0\nid2306;1.0\nid2307;1.0\nid2308;1.0\nid2309;1.0\nid2310;1.0\nid2311;1.0\nid2312;1.0\nid2313;1.0\nid2314;1.0\nid2315;1.0\nid2316;1.0\nid2317;1.0\nid2318;1.0\nid2319;1.0\nid2320;1.0\nid2321;1.0\nid2322;1.0\nid2323;1.0\nid2324;1.0\nid2325;1.0\nid2326;1.0\nid2327;1.0\nid2328;1.0\nid2329;1.0\nid2330;1.0\nid2331;1.0\nid2332;1.0\nid2333;1.0\nid2334;1.0\nid2335;1.0\nid2336;1.0\nid2337;1.0\nid2338;1.0\nid2339;1.0\nid2340;1.0\nid2341;1.0\nid2342;1.0\nid2343;1.0\nid2344;1.0\nid2345;1.0\nid2346;1.0\nid2347;1.0\nid2348;1.0\nid2349;1.0\nid2350;1.0\nid2351;1.0\nid2352;1.0\nid2353;1.0\nid2354;1.0\nid2355;1.0\nid2356;1.0\nid2357;1.0\nid2358;1.0\nid2359;1.0\nid2360;1.0\nid2361;1.0\nid2362;1.0\nid2363;1.0\nid2364;1.0\nid2365;1.0\nid2366;1.0\nid2367;1.0\nid2368;1.0\nid2369;1.0\nid2370;1.0\nid2371;1.0\nid2372;1.0\nid2373;1.0\nid2374;1.0\nid2375;1.0\nid2376;1.0\nid2377;1.0\nid2378;1.0\nid2379;1.0\nid2380;1.0\nid2381;1.0\nid2382;1.0\nid2383;1.0\nid2384;1.0\nid2385;1.0\nid2386;1.0\nid2387;1.0\nid2388;1.0\nid2389;1.0\nid2390;1.0\nid2391;1.0\nid2392;1.0\nid2393;1.0\nid2394;1.0\nid2395;1.0\nid2396;1.0\nid2397;1.0\nid2398;1.0\nid2399;1.0\nid2400;1.0\nid2401;1.0\nid2402;1.0\nid2403;1.0\nid2404;1.0\nid2405;1.0\nid2406;1.0\nid2407;1.0\nid2408;1.0\nid2409;1.0\nid2410;1.0\nid2411;1.0\nid2412;1.0\nid2413;1.0\nid2414;1.0\nid2415;1.0\nid2416;1.0\nid2417;1.0\nid2418;1.0\nid2419;1.0\nid2420;1.0\nid2421;1.0\nid2422;1.0\nid2423;1.0\nid2424;1.0\nid2425;1.0\nid2426;1.0\nid2427;1.0\nid2428;1.0\nid2429;1.0\nid2430;1.0\nid2431;1.0\nid2432;1.0\nid2433;1.0\nid2434;1.0\nid2435;1.0\nid2436;1.0\nid2437;1.0\nid2438;1.0\nid2439;1.0\nid2440;1.0\nid2441;1.0\nid2442;1.0\nid2443;1.0\nid2444;1.0\nid2445;1.0\nid2446;1.0\nid2447;1.0\nid2448;1.0\nid2449;1.0\nid2450;1.0\nid2451;1.0\nid2452;1.0\nid2453;1.0\nid2454;1.0\nid2455;1.0\nid2456;1.0\nid2457;1.0\nid2458;1.0\nid2459;1.0\nid2460;1.0\nid2461;1.0\nid2462;1.0\nid2463;1.0\nid2464;1.0\nid2465;1.0\nid2466;1.0\nid2467;1.0\nid2468;1.0\nid2469;1.0\nid2470;1.0\nid2471;1.0\nid2472;1.0\nid2473;1.0\nid2474;1.0\nid2475;1.0\nid2476;1.0\nid2477;1.0\nid2478;1.0\nid2479;1.0\nid2480;1.0\nid2481;1.0\nid2482;1.0\nid2483;1.0\nid2484;1.0\nid2485;1.0\nid2486;1.0\nid2487;1.0\nid2488;1.0\nid2489;1.0\nid2490;1.0\nid2491;1.0\nid2492;1.0\nid2493;1.0\nid2494;1.0\nid2495;1.0\nid2496;1.0\nid2497;1.0\nid2498;1.0\nid2499;1.0\nid2500;1.0\nid2501;1.0\nid2502;1.0\nid2503;1.0\nid2504;1.0\nid2505;1.0\nid2506;1.0\nid2507;1.0\nid2508;1.0\nid2509;1.0\nid2510;1.0\nid2511;1.0\nid2512;1.0\nid2513;1.0\nid2514;1.0\nid2515;1.0\nid2516;1.0\nid2517;1.0\nid2518;1.0\nid2519;1.0\nid2520;1.0\nid2521;1.0\nid2522;1.0\nid2523;1.0\nid2524;1.0\nid2525;1.0\nid2526;1.0\nid2527;1.0\nid2528;1.0\nid2529;1.0\nid2530;1.0\nid2531;1.0\nid2532;1.0\nid2533;1.0\nid2534;1.0\nid2535;1.0\nid2536;1.0\nid2537;1.0\nid2538;1.0\nid2539;1.0\nid2540;1.0\nid2541;1.0\nid2542;1.0\nid2543;1.0\nid2544;1.0\nid2545;1.0\nid2546;1.0\nid2547;1.0\nid2548;1.0\nid2549;1.0\nid2550;1.0\nid2551;1.0\nid2552;1.0\nid2553;1.0\nid2554;1.0\nid2555;1.0\nid2556;1.0\nid2557;1.0\nid2558;1.0\nid2559;1.0\nid2560;1.0\nid2561;1.0\nid2562;1.0\nid2563;1.0\nid2564;1.0\nid2565;1.0\nid2566;1.0\nid2567;1.0\nid2568;1.0\nid2569;1.0\nid2570;1.0\nid2571;1.0\nid2572;1.0\nid2573;1.0\nid2574;1.0\nid2575;1.0\nid2576;1.0\nid2577;1.0\nid2578;1.0\nid2579;1.0\nid2580;1.0\nid2581;1.0\nid2582;1.0\nid2583;1.0\nid2584;1.0\nid2585;1.0\nid2586;1.0\nid2587;1.0\nid2588;1.0\nid2589;1.0\nid2590;1.0\nid2591;1.0\nid2592;1.0\nid2593;1.0\nid2594;1.0\nid2595;1.0\nid2596;1.0\nid2597;1.0\nid2598;1.0\nid2599;1.0\nid2600;1.0\nid2601;1.0\nid2602;1.0\nid2603;1.0\nid2604;1.0\nid2605;1.0\nid2606;1.0\nid2607;1.0\nid2608;1.0\nid2609;1.0\nid2610;1.0\nid2611;1.0\nid2612;1.0\nid2613;1.0\nid2614;1.0\nid2615;1.0\nid2616;1.0\nid2617;1.0\nid2618;1.0\nid2619;1.0\nid2620;1.0\nid2621;1.0\nid2622;1.0\nid2623;1.0\nid2624;1.0\nid2625;1.0\nid2626;1.0\nid2627;1.0\nid2628;1.0\nid2629;1.0\nid2630;1.0\nid2631;1.0\nid2632;1.0\nid2633;1.0\nid2634;1.0\nid2635;1.0\nid2636;1.0\nid2637;1.0\nid2638;1.0\nid2639;1.0\nid2640;1.0\nid2641;1.0\nid2642;1.0\nid2643;1.0\nid2644;1.0\nid2645;1.0\nid2646;1.0\nid2647;1.0\nid2648;1.0\nid2649;1.0\nid2650;1.0\nid2651;1.0\nid2652;1.0\nid2653;1.0\nid2654;1.0\nid2655;1.0\nid2656;1.0\nid2657;1.0\nid2658;1.0\nid2659;1.0\nid2660;1.0\nid2661;1.0\nid2662;1.0\nid2663;1.0\nid2664;1.0\nid2665;1.0\nid2666;1.0\nid2667;1.0\nid2668;1.0\nid2669;1.0\nid2670;1.0\nid2671;1.0\nid2672;1.0\nid2673;1.0\nid2674;1.0\nid2675;1.0\nid2676;1.0\nid2677;1.0\nid2678;1.0\nid2679;1.0\nid2680;1.0\nid2681;1.0\nid2682;1.0\nid2683;1.0\nid2684;1.0\nid2685;1.0\nid2686;1.0\nid2687;1.0\nid2688;1.0\nid2689;1.0\nid2690;1.0\nid2691;1.0\nid2692;1.0\nid2693;1.0\nid2694;1.0\nid2695;1.0\nid2696;1.0\nid2697;1.0\nid2698;1.0\nid2699;1.0\nid2700;1.0\nid2701;1.0\nid2702;1.0\nid2703;1.0\nid2704;1.0\nid2705;1.0\nid2706;1.0\nid2707;1.0\nid2708;1.0\nid2709;1.0\nid2710;1.0\nid2711;1.0\nid2712;1.0\nid2713;1.0\nid2714;1.0\nid2715;1.0\nid2716;1.0\nid2717;1.0\nid2718;1.0\nid2719;1.0\nid2720;1.0\nid2721;1.0\nid2722;1.0\nid2723;1.0\nid2724;1.0\nid2725;1.0\nid2726;1.0\nid2727;1.0\nid2728;1.0\nid2729;1.0\nid2730;1.0\nid2731;1.0\nid2732;1.0\nid2733;1.0\nid2734;1.0\nid2735;1.0\nid2736;1.0\nid2737;1.0\nid2738;1.0\nid2739;1.0\nid2740;1.0\nid2741;1.0\nid2742;1.0\nid2743;1.0\nid2744;1.0\nid2745;1.0\nid2746;1.0\nid2747;1.0\nid2748;1.0\nid2749;1.0\nid2750;1.0\nid2751;1.0\nid2752;1.0\nid2753;1.0\nid2754;1.0\nid2755;1.0\nid2756;1.0\nid2757;1.0\nid2758;1.0\nid2759;1.0\nid2760;1.0\nid2761;1.0\nid2762;1.0\nid2763;1.0\nid2764;1.0\nid2765;1.0\nid2766;1.0\nid2767;1.0\nid2768;1.0\nid2769;1.0\nid2770;1.0\nid2771;1.0\nid2772;1.0\nid2773;1.0\nid2774;1.0\nid2775;1.0\nid2776;1.0\nid2777;1.0\nid2778;1.0\nid2779;1.0\nid2780;1.0\nid2781;1.0\nid2782;1.0\nid2783;1.0\nid2784;1.0\nid2785;1.0\nid2786;1.0\nid2787;1.0\nid2788;1.0\nid2789;1.0\nid2790;1.0\nid2791;1.0\nid2792;1.0\nid2793;1.0\nid2794;1.0\nid2795;1.0\nid2796;1.0\nid2797;1.0\nid2798;1.0\nid2799;1.0\nid2800;1.0\nid2801;1.0\nid2802;1.0\nid2803;1.0\nid2804;1.0\nid2805;1.0\nid2806;1.0\nid2807;1.0\nid2808;1.0\nid2809;1.0\nid2810;1.0\nid2811;1.0\nid2812;1.0\nid2813;1.0\nid2814;1.0\nid2815;1.0\nid2816;1.0\nid2817;1.0\nid2818;1.0\nid2819;1.0\nid2820;1.0\nid2821;1.0\nid2822;1.0\nid2823;1.0\nid2824;1.0\nid2825;1.0\nid2826;1.0\nid2827;1.0\nid2828;1.0\nid2829;1.0\nid2830;1.0\nid2831;1.0\nid2832;1.0\nid2833;1.0\nid2834;1.0\nid2835;1.0\nid2836;1.0\nid2837;1.0\nid2838;1.0\nid2839;1.0\nid2840;1.0\nid2841;1.0\nid2842;1.0\nid2843;1.0\nid2844;1.0\nid2845;1.0\nid2846;1.0\nid2847;1.0\nid2848;1.0\nid2849;1.0\nid2850;1.0\nid2851;1.0\nid2852;1.0\nid2853;1.0\nid2854;1.0\nid2855;1.0\nid2856;1.0\nid2857;1.0\nid2858;1.0\nid2859;1.0\nid2860;1.0\nid2861;1.0\nid2862;1.0\nid2863;1.0\nid2864;1.0\nid2865;1.0\nid2866;1.0\nid2867;1.0\nid2868;1.0\nid2869;1.0\nid2870;1.0\nid2871;1.0\nid2872;1.0\nid2873;1.0\nid2874;1.0\nid2875;1.0\nid2876;1.0\nid2877;1.0\nid2878;1.0\nid2879;1.0\nid2880;1.0\nid2881;1.0\nid2882;1.0\nid2883;1.0\nid2884;1.0\nid2885;1.0\nid2886;1.0\nid2887;1.0\nid2888;1.0\nid2889;1.0\nid2890;1.0\nid2891;1.0\nid2892;1.0\nid2893;1.0\nid2894;1.0\nid2895;1.0\nid2896;1.0\nid2897;1.0\nid2898;1.0\nid2899;1.0\nid2900;1.0\nid2901;1.0\nid2902;1.0\nid2903;1.0\nid2904;1.0\nid2905;1.0\nid2906;1.0\nid2907;1.0\nid2908;1.0\nid2909;1.0\nid2910;1.0\nid2911;1.0\nid2912;1.0\nid2913;1.0\nid2914;1.0\nid2915;1.0\nid2916;1.0\nid2917;1.0\nid2918;1.0\nid2919;1.0\nid2920;1.0\nid2921;1.0\nid2922;1.0\nid2923;1.0\nid2924;1.0\nid2925;1.0\nid2926;1.0\nid2927;1.0\nid2928;1.0\nid2929;1.0\nid2930;1.0\nid2931;1.0\nid2932;1.0\nid2933;1.0\nid2934;1.0\nid2935;1.0\nid2936;1.0\nid2937;1.0\nid2938;1.0\nid2939;1.0\nid2940;1.0\nid2941;1.0\nid2942;1.0\nid2943;1.0\nid2944;1.0\nid2945;1.0\nid2946;1.0\nid2947;1.0\nid2948;1.0\nid2949;1.0\nid2950;1.0\nid2951;1.0\nid2952;1.0\nid2953;1.0\nid2954;1.0\nid2955;1.0\nid2956;1.0\nid2957;1.0\nid2958;1.0\nid2959;1.0\nid2960;1.0\nid2961;1.0\nid2962;1.0\nid2963;1.0\nid2964;1.0\nid2965;1.0\nid2966;1.0\nid2967;1.0\nid2968;1.0\nid2969;1.0\nid2970;1.0\nid2971;1.0\nid2972;1.0\nid2973;1.0\nid2974;1.0\nid2975;1.0\nid2976;1.0\nid2977;1.0\nid2978;1.0\nid2979;1.0\nid2980;1.0\nid2981;1.0\nid2982;1.0\nid2983;1.0\nid2984;1.0\nid2985;1.0\nid2986;1.0\nid2987;1.0\nid2988;1.0\nid2989;1.0\nid2990;1.0\nid2991;1.0\nid2992;1.0\nid2993;1.0\nid2994;1.0\nid2995;1.0\nid2996;1.0\nid2997;1.0\nid2998;1.0\nid2999;1.0\nid3000;1.0\nid3001;1.0\nid3002;1.0\nid3003;1.0\nid3004;1.0\nid3005;1.0\nid3006;1.0\nid3007;1.0\nid3008;1.0\nid3009;1.0\nid3010;1.0\nid3011;1.0\nid3012;1.0\nid3013;1.0\nid3014;1.0\nid3015;1.0\nid3016;1.0\nid3017;1.0\nid3018;1.0\nid3019;1.0\nid3020;1.0\nid3021;1.0\nid3022;1.0\nid3023;1.0\nid3024;1.0\nid3025;1.0\nid3026;1.0\nid3027;1.0\nid3028;1.0\nid3029;1.0\nid3030;1.0\nid3031;1.0\nid3032;1.0\nid3033;1.0\nid3034;1.0\nid3035;1.0\nid3036;1.0\nid3037;1.0\nid3038;1.0\nid3039;1.0\nid3040;1.0\nid3041;1.0\nid3042;1.0\nid3043;1.0\nid3044;1.0\nid3045;1.0\nid3046;1.0\nid3047;1.0\nid3048;1.0\nid3049;1.0\nid3050;1.0\nid3051;1.0\nid3052;1.0\nid3053;1.0\nid3054;1.0\nid3055;1.0\nid3056;1.0\nid3057;1.0\nid3058;1.0\nid3059;1.0\nid3060;1.0\nid3061;1.0\nid3062;1.0\nid3063;1.0\nid3064;1.0\nid3065;1.0\nid3066;1.0\nid3067;1.0\nid3068;1.0\nid3069;1.0\nid3070;1.0\nid3071;1.0\nid3072;1.0\nid3073;1.0\nid3074;1.0\nid3075;1.0\nid3076;1.0\nid3077;1.0\nid3078;1.0\nid3079;1.0\nid3080;1.0\nid3081;1.0\nid3082;1.0\nid3083;1.0\nid3084;1.0\nid3085;1.0\nid3086;1.0\nid3087;1.0\nid3088;1.0\nid3089;1.0\nid3090;1.0\nid3091;1.0\nid3092;1.0\nid3093;1.0\nid3094;1.0\nid3095;1.0\nid3096;1.0\nid3097;1.0\nid3098;1.0\nid3099;1.0\nid3100;1.0\nid3101;1.0\nid3102;1.0\nid3103;1.0\nid3104;1.0\nid3105;1.0\nid3106;1.0\nid3107;1.0\nid3108;1.0\nid3109;1.0\nid3110;1.0\nid3111;1.0\nid3112;1.0\nid3113;1.0\nid3114;1.0\nid3115;1.0\nid3116;1.0\nid3117;1.0\nid3118;1.0\nid3119;1.0\nid3120;1.0\nid3121;1.0\nid3122;1.0\nid3123;1.0\nid3124;1.0\nid3125;1.0\nid3126;1.0\nid3127;1.0\nid3128;1.0\nid3129;1.0\nid3130;1.0\nid3131;1.0\nid3132;1.0\nid3133;1.0\nid3134;1.0\nid3135;1.0\nid3136;1.0\nid3137;1.0\nid3138;1.0\nid3139;1.0\nid3140;1.0\nid3141;1.0\nid3142;1.0\nid3143;1.0\nid3144;1.0\nid3145;1.0\nid3146;1.0\nid3147;1.0\nid3148;1.0\nid3149;1.0\nid3150;1.0\nid3151;1.0\nid3152;1.0\nid3153;1.0\nid3154;1.0\nid3155;1.0\nid3156;1.0\nid3157;1.0\nid3158;1.0\nid3159;1.0\nid3160;1.0\nid3161;1.0\nid3162;1.0\nid3163;1.0\nid3164;1.0\nid3165;1.0\nid3166;1.0\nid3167;1.0\nid3168;1.0\nid3169;1.0\nid3170;1.0\nid3171;1.0\nid3172;1.0\nid3173;1.0\nid3174;1.0\nid3175;1.0\nid3176;1.0\nid3177;1.0\nid3178;1.0\nid3179;1.0\nid3180;1.0\nid3181;1.0\nid3182;1.0\nid3183;1.0\nid3184;1.0\nid3185;1.0\nid3186;1.0\nid3187;1.0\nid3188;1.0\nid3189;1.0\nid3190;1.0\nid3191;1.0\nid3192;1.0\nid3193;1.0\nid3194;1.0\nid3195;1.0\nid3196;1.0\nid3197;1.0\nid3198;1.0\nid3199;1.0\nid3200;1.0\nid3201;1.0\nid3202;1.0\nid3203;1.0\nid3204;1.0\nid3205;1.0\nid3206;1.0\nid3207;1.0\nid3208;1.0\nid3209;1.0\nid3210;1.0\nid3211;1.0\nid3212;1.0\nid3213;1.0\nid3214;1.0\nid3215;1.0\nid3216;1.0\nid3217;1.0\nid3218;1.0\nid3219;1.0\nid3220;1.0\nid3221;1.0\nid3222;1.0\nid3223;1.0\nid3224;1.0\nid3225;1.0\nid3226;1.0\nid3227;1.0\nid3228;1.0\nid3229;1.0\nid3230;1.0\nid3231;1.0\nid3232;1.0\nid3233;1.0\nid3234;1.0\nid3235;1.0\nid3236;1.0\nid3237;1.0\nid3238;1.0\nid3239;1.0\nid3240;1.0\nid3241;1.0\nid3242;1.0\nid3243;1.0\nid3244;1.0\nid3245;1.0\nid3246;1.0\nid3247;1.0\nid3248;1.0\nid3249;1.0\nid3250;1.0\nid3251;1.0\nid3252;1.0\nid3253;1.0\nid3254;1.0\nid3255;1.0\nid3256;1.0\nid3257;1.0\nid3258;1.0\nid3259;1.0\nid3260;1.0\nid3261;1.0\nid3262;1.0\nid3263;1.0\nid3264;1.0\nid3265;1.0\nid3266;1.0\nid3267;1.0\nid3268;1.0\nid3269;1.0\nid3270;1.0\nid3271;1.0\nid3272;1.0\nid3273;1.0\nid3274;1.0\nid3275;1.0\nid3276;1.0\nid3277;1.0\nid3278;1.0\nid3279;1.0\nid3280;1.0\nid3281;1.0\nid3282;1.0\nid3283;1.0\nid3284;1.0\nid3285;1.0\nid3286;1.0\nid3287;1.0\nid3288;1.0\nid3289;1.0\nid3290;1.0\nid3291;1.0\nid3292;1.0\nid3293;1.0\nid3294;1.0\nid3295;1.0\nid3296;1.0\nid3297;1.0\nid3298;1.0\nid3299;1.0\nid3300;1.0\nid3301;1.0\nid3302;1.0\nid3303;1.0\nid3304;1.0\nid3305;1.0\nid3306;1.0\nid3307;1.0\nid3308;1.0\nid3309;1.0\nid3310;1.0\nid3311;1.0\nid3312;1.0\nid3313;1.0\nid3314;1.0\nid3315;1.0\nid3316;1.0\nid3317;1.0\nid3318;1.0\nid3319;1.0\nid3320;1.0\nid3321;1.0\nid3322;1.0\nid3323;1.0\nid3324;1.0\nid3325;1.0\nid3326;1.0\nid3327;1.0\nid3328;1.0\nid3329;1.0\nid3330;1.0\nid3331;1.0\nid3332;1.0\nid3333;1.0\nid3334;1.0\nid3335;1.0\nid3336;1.0\nid3337;1.0\nid3338;1.0\nid3339;1.0\nid3340;1.0\nid3341;1.0\nid3342;1.0\nid3343;1.0\nid3344;1.0\nid3345;1.0\nid3346;1.0\nid3347;1.0\nid3348;1.0\nid3349;1.0\nid3350;1.0\nid3351;1.0\nid3352;1.0\nid3353;1.0\nid3354;1.0\nid3355;1.0\nid3356;1.0\nid3357;1.0\nid3358;1.0\nid3359;1.0\nid3360;1.0\nid3361;1.0\nid3362;1.0\nid3363;1.0\nid3364;1.0\nid3365;1.0\nid3366;1.0\nid3367;1.0\nid3368;1.0\nid3369;1.0\nid3370;1.0\nid3371;1.0\nid3372;1.0\nid3373;1.0\nid3374;1.0\nid3375;1.0\nid3376;1.0\nid3377;1.0\nid3378;1.0\nid3379;1.0\nid3380;1.0\nid3381;1.0\nid3382;1.0\nid3383;1.0\nid3384;1.0\nid3385;1.0\nid3386;1.0\nid3387;1.0\nid3388;1.0\nid3389;1.0\nid3390;1.0\nid3391;1.0\nid3392;1.0\nid3393;1.0\nid3394;1.0\nid3395;1.0\nid3396;1.0\nid3397;1.0\nid3398;1.0\nid3399;1.0\nid3400;1.0\nid3401;1.0\nid3402;1.0\nid3403;1.0\nid3404;1.0\nid3405;1.0\nid3406;1.0\nid3407;1.0\nid3408;1.0\nid3409;1.0\nid3410;1.0\nid3411;1.0\nid3412;1.0\nid3413;1.0\nid3414;1.0\nid3415;1.0\nid3416;1.0\nid3417;1.0\nid3418;1.0\nid3419;1.0\nid3420;1.0\nid3421;1.0\nid3422;1.0\nid3423;1.0\nid3424;1.0\nid3425;1.0\nid3426;1.0\nid3427;1.0\nid3428;1.0\nid3429;1.0\nid3430;1.0\nid3431;1.0\nid3432;1.0\nid3433;1.0\nid3434;1.0\nid3435;1.0\nid3436;1.0\nid3437;1.0\nid3438;1.0\nid3439;1.0\nid3440;1.0\nid3441;1.0\nid3442;1.0\nid3443;1.0\nid3444;1.0\nid3445;1.0\nid3446;1.0\nid3447;1.0\nid3448;1.0\nid3449;1.0\nid3450;1.0\nid3451;1.0\nid3452;1.0\nid3453;1.0\nid3454;1.0\nid3455;1.0\nid3456;1.0\nid3457;1.0\nid3458;1.0\nid3459;1.0\nid3460;1.0\nid3461;1.0\nid3462;1.0\nid3463;1.0\nid3464;1.0\nid3465;1.0\nid3466;1.0\nid3467;1.0\nid3468;1.0\nid3469;1.0\nid3470;1.0\nid3471;1.0\nid3472;1.0\nid3473;1.0\nid3474;1.0\nid3475;1.0\nid3476;1.0\nid3477;1.0\nid3478;1.0\nid3479;1.0\nid3480;1.0\nid3481;1.0\nid3482;1.0\nid3483;1.0\nid3484;1.0\nid3485;1.0\nid3486;1.0\nid3487;1.0\nid3488;1.0\nid3489;1.0\nid3490;1.0\nid3491;1.0\nid3492;1.0\nid3493;1.0\nid3494;1.0\nid3495;1.0\nid3496;1.0\nid3497;1.0\nid3498;1.0\nid3499;1.0\nid3500;1.0\nid3501;1.0\nid3502;1.0\nid3503;1.0\nid3504;1.0\nid3505;1.0\nid3506;1.0\nid3507;1.0\nid3508;1.0\nid3509;1.0\nid3510;1.0\nid3511;1.0\nid3512;1.0\nid3513;1.0\nid3514;1.0\nid3515;1.0\nid3516;1.0\nid3517;1.0\nid3518;1.0\nid3519;1.0\nid3520;1.0\nid3521;1.0\nid3522;1.0\nid3523;1.0\nid3524;1.0\nid3525;1.0\nid3526;1.0\nid3527;1.0\nid3528;1.0\nid3529;1.0\nid3530;1.0\nid3531;1.0\nid3532;1.0\nid3533;1.0\nid3534;1.0\nid3535;1.0\nid3536;1.0\nid3537;1.0\nid3538;1.0\nid3539;1.0\nid3540;1.0\nid3541;1.0\nid3542;1.0\nid3543;1.0\nid3544;1.0\nid3545;1.0\nid3546;1.0\nid3547;1.0\nid3548;1.0\nid3549;1.0\nid3550;1.0\nid3551;1.0\nid3552;1.0\nid3553;1.0\nid3554;1.0\nid3555;1.0\nid3556;1.0\nid3557;1.0\nid3558;1.0\nid3559;1.0\nid3560;1.0\nid3561;1.0\nid3562;1.0\nid3563;1.0\nid3564;1.0\nid3565;1.0\nid3566;1.0\nid3567;1.0\nid3568;1.0\nid3569;1.0\nid3570;1.0\nid3571;1.0\nid3572;1.0\nid3573;1.0\nid3574;1.0\nid3575;1.0\nid3576;1.0\nid3577;1.0\nid3578;1.0\nid3579;1.0\nid3580;1.0\nid3581;1.0\nid3582;1.0\nid3583;1.0\nid3584;1.0\nid3585;1.0\nid3586;1.0\nid3587;1.0\nid3588;1.0\nid3589;1.0\nid3590;1.0\nid3591;1.0\nid3592;1.0\nid3593;1.0\nid3594;1.0\nid3595;1.0\nid3596;1.0\nid3597;1.0\nid3598;1.0\nid3599;1.0\nid3600;1.0\nid3601;1.0\nid3602;1.0\nid3603;1.0\nid3604;1.0\nid3605;1.0\nid3606;1.0\nid3607;1.0\nid3608;1.0\nid3609;1.0\nid3610;1.0\nid3611;1.0\nid3612;1.0\nid3613;1.0\nid3614;1.0\nid3615;1.0\nid3616;1.0\nid3617;1.0\nid3618;1.0\nid3619;1.0\nid3620;1.0\nid3621;1.0\nid3622;1.0\nid3623;1.0\nid3624;1.0\nid3625;1.0\nid3626;1.0\nid3627;1.0\nid3628;1.0\nid3629;1.0\nid3630;1.0\nid3631;1.0\nid3632;1.0\nid3633;1.0\nid3634;1.0\nid3635;1.0\nid3636;1.0\nid3637;1.0\nid3638;1.0\nid3639;1.0\nid3640;1.0\nid3641;1.0\nid3642;1.0\nid3643;1.0\nid3644;1.0\nid3645;1.0\nid3646;1.0\nid3647;1.0\nid3648;1.0\nid3649;1.0\nid3650;1.0\nid3651;1.0\nid3652;1.0\nid3653;1.0\nid3654;1.0\nid3655;1.0\nid3656;1.0\nid3657;1.0\nid3658;1.0\nid3659;1.0\nid3660;1.0\nid3661;1.0\nid3662;1.0\nid3663;1.0\nid3664;1.0\nid3665;1.0\nid3666;1.0\nid3667;1.0\nid3668;1.0\nid3669;1.0\nid3670;1.0\nid3671;1.0\nid3672;1.0\nid3673;1.0\nid3674;1.0\nid3675;1.0\nid3676;1.0\nid3677;1.0\nid3678;1.0\nid3679;1.0\nid3680;1.0\nid3681;1.0\nid3682;1.0\nid3683;1.0\nid3684;1.0\nid3685;1.0\nid3686;1.0\nid3687;1.0\nid3688;1.0\nid3689;1.0\nid3690;1.0\nid3691;1.0\nid3692;1.0\nid3693;1.0\nid3694;1.0\nid3695;1.0\nid3696;1.0\nid3697;1.0\nid3698;1.0\nid3699;1.0\nid3700;1.0\nid3701;1.0\nid3702;1.0\nid3703;1.0\nid3704;1.0\nid3705;1.0\nid3706;1.0\nid3707;1.0\nid3708;1.0\nid3709;1.0\nid3710;1.0\nid3711;1.0\nid3712;1.0\nid3713;1.0\nid3714;1.0\nid3715;1.0\nid3716;1.0\nid3717;1.0\nid3718;1.0\nid3719;1.0\nid3720;1.0\nid3721;1.0\nid3722;1.0\nid3723;1.0\nid3724;1.0\nid3725;1.0\nid3726;1.0\nid3727;1.0\nid3728;1.0\nid3729;1.0\nid3730;1.0\nid3731;1.0\nid3732;1.0\nid3733;1.0\nid3734;1.0\nid3735;1.0\nid3736;1.0\nid3737;1.0\nid3738;1.0\nid3739;1.0\nid3740;1.0\nid3741;1.0\nid3742;1.0\nid3743;1.0\nid3744;1.0\nid3745;1.0\nid3746;1.0\nid3747;1.0\nid3748;1.0\nid3749;1.0\nid3750;1.0\nid3751;1.0\nid3752;1.0\nid3753;1.0\nid3754;1.0\nid3755;1.0\nid3756;1.0\nid3757;1.0\nid3758;1.0\nid3759;1.0\nid3760;1.0\nid3761;1.0\nid3762;1.0\nid3763;1.0\nid3764;1.0\nid3765;1.0\nid3766;1.0\nid3767;1.0\nid3768;1.0\nid3769;1.0\nid3770;1.0\nid3771;1.0\nid3772;1.0\nid3773;1.0\nid3774;1.0\nid3775;1.0\nid3776;1.0\nid3777;1.0\nid3778;1.0\nid3779;1.0\nid3780;1.0\nid3781;1.0\nid3782;1.0\nid3783;1.0\nid3784;1.0\nid3785;1.0\nid3786;1.0\nid3787;1.0\nid3788;1.0\nid3789;1.0\nid3790;1.0\nid3791;1.0\nid3792;1.0\nid3793;1.0\nid3794;1.0\nid3795;1.0\nid3796;1.0\nid3797;1.0\nid3798;1.0\nid3799;1.0\nid3800;1.0\nid3801;1.0\nid3802;1.0\nid3803;1.0\nid3804;1.0\nid3805;1.0\nid3806;1.0\nid3807;1.0\nid3808;1.0\nid3809;1.0\nid3810;1.0\nid3811;1.0\nid3812;1.0\nid3813;1.0\nid3814;1.0\nid3815;1.0\nid3816;1.0\nid3817;1.0\nid3818;1.0\nid3819;1.0\nid3820;1.0\nid3821;1.0\nid3822;1.0\nid3823;1.0\nid3824;1.0\nid3825;1.0\nid3826;1.0\nid3827;1.0\nid3828;1.0\nid3829;1.0\nid3830;1.0\nid3831;1.0\nid3832;1.0\nid3833;1.0\nid3834;1.0\nid3835;1.0\nid3836;1.0\nid3837;1.0\nid3838;1.0\nid3839;1.0\nid3840;1.0\nid3841;1.0\nid3842;1.0\nid3843;1.0\nid3844;1.0\nid3845;1.0\nid3846;1.0\nid3847;1.0\nid3848;1.0\nid3849;1.0\nid3850;1.0\nid3851;1.0\nid3852;1.0\nid3853;1.0\nid3854;1.0\nid3855;1.0\nid3856;1.0\nid3857;1.0\nid3858;1.0\nid3859;1.0\nid3860;1.0\nid3861;1.0\nid3862;1.0\nid3863;1.0\nid3864;1.0\nid3865;1.0\nid3866;1.0\nid3867;1.0\nid3868;1.0\nid3869;1.0\nid3870;1.0\nid3871;1.0\nid3872;1.0\nid3873;1.0\nid3874;1.0\nid3875;1.0\nid3876;1.0\nid3877;1.0\nid3878;1.0\nid3879;1.0\nid3880;1.0\nid3881;1.0\nid3882;1.0\nid3883;1.0\nid3884;1.0\nid3885;1.0\nid3886;1.0\nid3887;1.0\nid3888;1.0\nid3889;1.0\nid3890;1.0\nid3891;1.0\nid3892;1.0\nid3893;1.0\nid3894;1.0\nid3895;1.0\nid3896;1.0\nid3897;1.0\nid3898;1.0\nid3899;1.0\nid3900;1.0\nid3901;1.0\nid3902;1.0\nid3903;1.0\nid3904;1.0\nid3905;1.0\nid3906;1.0\nid3907;1.0\nid3908;1.0\nid3909;1.0\nid3910;1.0\nid3911;1.0\nid3912;1.0\nid3913;1.0\nid3914;1.0\nid3915;1.0\nid3916;1.0\nid3917;1.0\nid3918;1.0\nid3919;1.0\nid3920;1.0\nid3921;1.0\nid3922;1.0\nid3923;1.0\nid3924;1.0\nid3925;1.0\nid3926;1.0\nid3927;1.0\nid3928;1.0\nid3929;1.0\nid3930;1.0\nid3931;1.0\nid3932;1.0\nid3933;1.0\nid3934;1.0\nid3935;1.0\nid3936;1.0\nid3937;1.0\nid3938;1.0\nid3939;1.0\nid3940;1.0\nid3941;1.0\nid3942;1.0\nid3943;1.0\nid3944;1.0\nid3945;1.0\nid3946;1.0\nid3947;1.0\nid3948;1.0\nid3949;1.0\nid3950;1.0\nid3951;1.0\nid3952;1.0\nid3953;1.0\nid3954;1.0\nid3955;1.0\nid3956;1.0\nid3957;1.0\nid3958;1.0\nid3959;1.0\nid3960;1.0\nid3961;1.0\nid3962;1.0\nid3963;1.0\nid3964;1.0\nid3965;1.0\nid3966;1.0\nid3967;1.0\nid3968;1.0\nid3969;1.0\nid3970;1.0\nid3971;1.0\nid3972;1.0\nid3973;1.0\nid3974;1.0\nid3975;1.0\nid3976;1.0\nid3977;1.0\nid3978;1.0\nid3979;1.0\nid3980;1.0\nid3981;1.0\nid3982;1.0\nid3983;1.0\nid3984;1.0\nid3985;1.0\nid3986;1.0\nid3987;1.0\nid3988;1.0\nid3989;1.0\nid3990;1.0\nid3991;1.0\nid3992;1.0\nid3993;1.0\nid3994;1.0\nid3995;1.0\nid3996;1.0\nid3997;1.0\nid3998;1.0\nid3999;1.0\nid4000;1.0\nid4001;1.0\nid4002;1.0\nid4003;1.0\nid4004;1.0\nid4005;1.0\nid4006;1.0\nid4007;1.0\nid4008;1.0\nid4009;1.0\nid4010;1.0\nid4011;1.0\nid4012;1.0\nid4013;1.0\nid4014;1.0\nid4015;1.0\nid4016;1.0\nid4017;1.0\nid4018;1.0\nid4019;1.0\nid4020;1.0\nid4021;1.0\nid4022;1.0\nid4023;1.0\nid4024;1.0\nid4025;1.0\nid4026;1.0\nid4027;1.0\nid4028;1.0\nid4029;1.0\nid4030;1.0\nid4031;1.0\nid4032;1.0\nid4033;1.0\nid4034;1.0\nid4035;1.0\nid4036;1.0\nid4037;1.0\nid4038;1.0\nid4039;1.0\nid4040;1.0\nid4041;1.0\nid4042;1.0\nid4043;1.0\nid4044;1.0\nid4045;1.0\nid4046;1.0\nid4047;1.0\nid4048;1.0\nid4049;1.0\nid4050;1.0\nid4051;1.0\nid4052;1.0\nid4053;1.0\nid4054;1.0\nid4055;1.0\nid4056;1.0\nid4057;1.0\nid4058;1.0\nid4059;1.0\nid4060;1.0\nid4061;1.0\nid4062;1.0\nid4063;1.0\nid4064;1.0\nid4065;1.0\nid4066;1.0\nid4067;1.0\nid4068;1.0\nid4069;1.0\nid4070;1.0\nid4071;1.0\nid4072;1.0\nid4073;1.0\nid4074;1.0\nid4075;1.0\nid4076;1.0\nid4077;1.0\nid4078;1.0\nid4079;1.0\nid4080;1.0\nid4081;1.0\nid4082;1.0\nid4083;1.0\nid4084;1.0\nid4085;1.0\nid4086;1.0\nid4087;1.0\nid4088;1.0\nid4089;1.0\nid4090;1.0\nid4091;1.0\nid4092;1.0\nid4093;1.0\nid4094;1.0\nid4095;1.0\nid4096;1.0\nid4097;1.0\nid4098;1.0\nid4099;1.0\nid4100;1.0\nid4101;1.0\nid4102;1.0\nid4103;1.0\nid4104;1.0\nid4105;1.0\nid4106;1.0\nid4107;1.0\nid4108;1.0\nid4109;1.0\nid4110;1.0\nid4111;1.0\nid4112;1.0\nid4113;1.0\nid4114;1.0\nid4115;1.0\nid4116;1.0\nid4117;1.0\nid4118;1.0\nid4119;1.0\nid4120;1.0\nid4121;1.0\nid4122;1.0\nid4123;1.0\nid4124;1.0\nid4125;1.0\nid4126;1.0\nid4127;1.0\nid4128;1.0\nid4129;1.0\nid4130;1.0\nid4131;1.0\nid4132;1.0\nid4133;1.0\nid4134;1.0\nid4135;1.0\nid4136;1.0\nid4137;1.0\nid4138;1.0\nid4139;1.0\nid4140;1.0\nid4141;1.0\nid4142;1.0\nid4143;1.0\nid4144;1.0\nid4145;1.0\nid4146;1.0\nid4147;1.0\nid4148;1.0\nid4149;1.0\nid4150;1.0\nid4151;1.0\nid4152;1.0\nid4153;1.0\nid4154;1.0\nid4155;1.0\nid4156;1.0\nid4157;1.0\nid4158;1.0\nid4159;1.0\nid4160;1.0\nid4161;1.0\nid4162;1.0\nid4163;1.0\nid4164;1.0\nid4165;1.0\nid4166;1.0\nid4167;1.0\nid4168;1.0\nid4169;1.0\nid4170;1.0\nid4171;1.0\nid4172;1.0\nid4173;1.0\nid4174;1.0\nid4175;1.0\nid4176;1.0\nid4177;1.0\nid4178;1.0\nid4179;1.0\nid4180;1.0\nid4181;1.0\nid4182;1.0\nid4183;1.0\nid4184;1.0\nid4185;1.0\nid4186;1.0\nid4187;1.0\nid4188;1.0\nid4189;1.0\nid4190;1.0\nid4191;1.0\nid4192;1.0\nid4193;1.0\nid4194;1.0\nid4195;1.0\nid4196;1.0\nid4197;1.0\nid4198;1.0\nid4199;1.0\nid4200;1.0\nid4201;1.0\nid4202;1.0\nid4203;1.0\nid4204;1.0\nid4205;1.0\nid4206;1.0\nid4207;1.0\nid4208;1.0\nid4209;1.0\nid4210;1.0\nid4211;1.0\nid4212;1.0\nid4213;1.0\nid4214;1.0\nid4215;1.0\nid4216;1.0\nid4217;1.0\nid4218;1.0\nid4219;1.0\nid4220;1.0\nid4221;1.0\nid4222;1.0\nid4223;1.0\nid4224;1.0\nid4225;1.0\nid4226;1.0\nid4227;1.0\nid4228;1.0\nid4229;1.0\nid4230;1.0\nid4231;1.0\nid4232;1.0\nid4233;1.0\nid4234;1.0\nid4235;1.0\nid4236;1.0\nid4237;1.0\nid4238;1.0\nid4239;1.0\nid4240;1.0\nid4241;1.0\nid4242;1.0\nid4243;1.0\nid4244;1.0\nid4245;1.0\nid4246;1.0\nid4247;1.0\nid4248;1.0\nid4249;1.0\nid4250;1.0\nid4251;1.0\nid4252;1.0\nid4253;1.0\nid4254;1.0\nid4255;1.0\nid4256;1.0\nid4257;1.0\nid4258;1.0\nid4259;1.0\nid4260;1.0\nid4261;1.0\nid4262;1.0\nid4263;1.0\nid4264;1.0\nid4265;1.0\nid4266;1.0\nid4267;1.0\nid4268;1.0\nid4269;1.0\nid4270;1.0\nid4271;1.0\nid4272;1.0\nid4273;1.0\nid4274;1.0\nid4275;1.0\nid4276;1.0\nid4277;1.0\nid4278;1.0\nid4279;1.0\nid4280;1.0\nid4281;1.0\nid4282;1.0\nid4283;1.0\nid4284;1.0\nid4285;1.0\nid4286;1.0\nid4287;1.0\nid4288;1.0\nid4289;1.0\nid4290;1.0\nid4291;1.0\nid4292;1.0\nid4293;1.0\nid4294;1.0\nid4295;1.0\nid4296;1.0\nid4297;1.0\nid4298;1.0\nid4299;1.0\nid4300;1.0\nid4301;1.0\nid4302;1.0\nid4303;1.0\nid4304;1.0\nid4305;1.0\nid4306;1.0\nid4307;1.0\nid4308;1.0\nid4309;1.0\nid4310;1.0\nid4311;1.0\nid4312;1.0\nid4313;1.0\nid4314;1.0\nid4315;1.0\nid4316;1.0\nid4317;1.0\nid4318;1.0\nid4319;1.0\nid4320;1.0\nid4321;1.0\nid4322;1.0\nid4323;1.0\nid4324;1.0\nid4325;1.0\nid4326;1.0\nid4327;1.0\nid4328;1.0\nid4329;1.0\nid4330;1.0\nid4331;1.0\nid4332;1.0\nid4333;1.0\nid4334;1.0\nid4335;1.0\nid4336;1.0\nid4337;1.0\nid4338;1.0\nid4339;1.0\nid4340;1.0\nid4341;1.0\nid4342;1.0\nid4343;1.0\nid4344;1.0\nid4345;1.0\nid4346;1.0\nid4347;1.0\nid4348;1.0\nid4349;1.0\nid4350;1.0\nid4351;1.0\nid4352;1.0\nid4353;1.0\nid4354;1.0\nid4355;1.0\nid4356;1.0\nid4357;1.0\nid4358;1.0\nid4359;1.0\nid4360;1.0\nid4361;1.0\nid4362;1.0\nid4363;1.0\nid4364;1.0\nid4365;1.0\nid4366;1.0\nid4367;1.0\nid4368;1.0\nid4369;1.0\nid4370;1.0\nid4371;1.0\nid4372;1.0\nid4373;1.0\nid4374;1.0\nid4375;1.0\nid4376;1.0\nid4377;1.0\nid4378;1.0\nid4379;1.0\nid4380;1.0\nid4381;1.0\nid4382;1.0\nid4383;1.0\nid4384;1.0\nid4385;1.0\nid4386;1.0\nid4387;1.0\nid4388;1.0\nid4389;1.0\nid4390;1.0\nid4391;1.0\nid4392;1.0\nid4393;1.0\nid4394;1.0\nid4395;1.0\nid4396;1.0\nid4397;1.0\nid4398;1.0\nid4399;1.0\nid4400;1.0\nid4401;1.0\nid4402;1.0\nid4403;1.0\nid4404;1.0\nid4405;1.0\nid4406;1.0\nid4407;1.0\nid4408;1.0\nid4409;1.0\nid4410;1.0\nid4411;1.0\nid4412;1.0\nid4413;1.0\nid4414;1.0\nid4415;1.0\nid4416;1.0\nid4417;1.0\nid4418;1.0\nid4419;1.0\nid4420;1.0\nid4421;1.0\nid4422;1.0\nid4423;1.0\nid4424;1.0\nid4425;1.0\nid4426;1.0\nid4427;1.0\nid4428;1.0\nid4429;1.0\nid4430;1.0\nid4431;1.0\nid4432;1.0\nid4433;1.0\nid4434;1.0\nid4435;1.0\nid4436;1.0\nid4437;1.0\nid4438;1.0\nid4439;1.0\nid4440;1.0\nid4441;1.0\nid4442;1.0\nid4443;1.0\nid4444;1.0\nid4445;1.0\nid4446;1.0\nid4447;1.0\nid4448;1.0\nid4449;1.0\nid4450;1.0\nid4451;1.0\nid4452;1.0\nid4453;1.0\nid4454;1.0\nid4455;1.0\nid4456;1.0\nid4457;1.0\nid4458;1.0\nid4459;1.0\nid4460;1.0\nid4461;1.0\nid4462;1.0\nid4463;1.0\nid4464;1.0\nid4465;1.0\nid4466;1.0\nid4467;1.0\nid4468;1.0\nid4469;1.0\nid4470;1.0\nid4471;1.0\nid4472;1.0\nid4473;1.0\nid4474;1.0\nid4475;1.0\nid4476;1.0\nid4477;1.0\nid4478;1.0\nid4479;1.0\nid4480;1.0\nid4481;1.0\nid4482;1.0\nid4483;1.0\nid4484;1.0\nid4485;1.0\nid4486;1.0\nid4487;1.0\nid4488;1.0\nid4489;1.0\nid4490;1.0\nid4491;1.0\nid4492;1.0\nid4493;1.0\nid4494;1.0\nid4495;1.0\nid4496;1.0\nid4497;1.0\nid4498;1.0\nid4499;1.0\nid4500;1.0\nid4501;1.0\nid4502;1.0\nid4503;1.0\nid4504;1.0\nid4505;1.0\nid4506;1.0\nid4507;1.0\nid4508;1.0\nid4509;1.0\nid4510;1.0\nid4511;1.0\nid4512;1.0\nid4513;1.0\nid4514;1.0\nid4515;1.0\nid4516;1.0\nid4517;1.0\nid4518;1.0\nid4519;1.0\nid4520;1.0\nid4521;1.0\nid4522;1.0\nid4523;1.0\nid4524;1.0\nid4525;1.0\nid4526;1.0\nid4527;1.0\nid4528;1.0\nid4529;1.0\nid4530;1.0\nid4531;1.0\nid4532;1.0\nid4533;1.0\nid4534;1.0\nid4535;1.0\nid4536;1.0\nid4537;1.0\nid4538;1.0\nid4539;1.0\nid4540;1.0\nid4541;1.0\nid4542;1.0\nid4543;1.0\nid4544;1.0\nid4545;1.0\nid4546;1.0\nid4547;1.0\nid4548;1.0\nid4549;1.0\nid4550;1.0\nid4551;1.0\nid4552;1.0\nid4553;1.0\nid4554;1.0\nid4555;1.0\nid4556;1.0\nid4557;1.0\nid4558;1.0\nid4559;1.0\nid4560;1.0\nid4561;1.0\nid4562;1.0\nid4563;1.0\nid4564;1.0\nid4565;1.0\nid4566;1.0\nid4567;1.0\nid4568;1.0\nid4569;1.0\nid4570;1.0\nid4571;1.0\nid4572;1.0\nid4573;1.0\nid4574;1.0\nid4575;1.0\nid4576;1.0\nid4577;1.0\nid4578;1.0\nid4579;1.0\nid4580;1.0\nid4581;1.0\nid4582;1.0\nid4583;1.0\nid4584;1.0\nid4585;1.0\nid4586;1.0\nid4587;1.0\nid4588;1.0\nid4589;1.0\nid4590;1.0\nid4591;1.0\nid4592;1.0\nid4593;1.0\nid4594;1.0\nid4595;1.0\nid4596;1.0\nid4597;1.0\nid4598;1.0\nid4599;1.0\nid4600;1.0\nid4601;1.0\nid4602;1.0\nid4603;1.0\nid4604;1.0\nid4605;1.0\nid4606;1.0\nid4607;1.0\nid4608;1.0\nid4609;1.0\nid4610;1.0\nid4611;1.0\nid4612;1.0\nid4613;1.0\nid4614;1.0\nid4615;1.0\nid4616;1.0\nid4617;1.0\nid4618;1.0\nid4619;1.0\nid4620;1.0\nid4621;1.0\nid4622;1.0\nid4623;1.0\nid4624;1.0\nid4625;1.0\nid4626;1.0\nid4627;1.0\nid4628;1.0\nid4629;1.0\nid4630;1.0\nid4631;1.0\nid4632;1.0\nid4633;1.0\nid4634;1.0\nid4635;1.0\nid4636;1.0\nid4637;1.0\nid4638;1.0\nid4639;1.0\nid4640;1.0\nid4641;1.0\nid4642;1.0\nid4643;1.0\nid4644;1.0\nid4645;1.0\nid4646;1.0\nid4647;1.0\nid4648;1.0\nid4649;1.0\nid4650;1.0\nid4651;1.0\nid4652;1.0\nid4653;1.0\nid4654;1.0\nid4655;1.0\nid4656;1.0\nid4657;1.0\nid4658;1.0\nid4659;1.0\nid4660;1.0\nid4661;1.0\nid4662;1.0\nid4663;1.0\nid4664;1.0\nid4665;1.0\nid4666;1.0\nid4667;1.0\nid4668;1.0\nid4669;1.0\nid4670;1.0\nid4671;1.0\nid4672;1.0\nid4673;1.0\nid4674;1.0\nid4675;1.0\nid4676;1.0\nid4677;1.0\nid4678;1.0\nid4679;1.0\nid4680;1.0\nid4681;1.0\nid4682;1.0\nid4683;1.0\nid4684;1.0\nid4685;1.0\nid4686;1.0\nid4687;1.0\nid4688;1.0\nid4689;1.0\nid4690;1.0\nid4691;1.0\nid4692;1.0\nid4693;1.0\nid4694;1.0\nid4695;1.0\nid4696;1.0\nid4697;1.0\nid4698;1.0\nid4699;1.0\nid4700;1.0\nid4701;1.0\nid4702;1.0\nid4703;1.0\nid4704;1.0\nid4705;1.0\nid4706;1.0\nid4707;1.0\nid4708;1.0\nid4709;1.0\nid4710;1.0\nid4711;1.0\nid4712;1.0\nid4713;1.0\nid4714;1.0\nid4715;1.0\nid4716;1.0\nid4717;1.0\nid4718;1.0\nid4719;1.0\nid4720;1.0\nid4721;1.0\nid4722;1.0\nid4723;1.0\nid4724;1.0\nid4725;1.0\nid4726;1.0\nid4727;1.0\nid4728;1.0\nid4729;1.0\nid4730;1.0\nid4731;1.0\nid4732;1.0\nid4733;1.0\nid4734;1.0\nid4735;1.0\nid4736;1.0\nid4737;1.0\nid4738;1.0\nid4739;1.0\nid4740;1.0\nid4741;1.0\nid4742;1.0\nid4743;1.0\nid4744;1.0\nid4745;1.0\nid4746;1.0\nid4747;1.0\nid4748;1.0\nid4749;1.0\nid4750;1.0\nid4751;1.0\nid4752;1.0\nid4753;1.0\nid4754;1.0\nid4755;1.0\nid4756;1.0\nid4757;1.0\nid4758;1.0\nid4759;1.0\nid4760;1.0\nid4761;1.0\nid4762;1.0\nid4763;1.0\nid4764;1.0\nid4765;1.0\nid4766;1.0\nid4767;1.0\nid4768;1.0\nid4769;1.0\nid4770;1.0\nid4771;1.0\nid4772;1.0\nid4773;1.0\nid4774;1.0\nid4775;1.0\nid4776;1.0\nid4777;1.0\nid4778;1.0\nid4779;1.0\nid4780;1.0\nid4781;1.0\nid4782;1.0\nid4783;1.0\nid4784;1.0\nid4785;1.0\nid4786;1.0\nid4787;1.0\nid4788;1.0\nid4789;1.0\nid4790;1.0\nid4791;1.0\nid4792;1.0\nid4793;1.0\nid4794;1.0\nid4795;1.0\nid4796;1.0\nid4797;1.0\nid4798;1.0\nid4799;1.0\nid4800;1.0\nid4801;1.0\nid4802;1.0\nid4803;1.0\nid4804;1.0\nid4805;1.0\nid4806;1.0\nid4807;1.0\nid4808;1.0\nid4809;1.0\nid4810;1.0\nid4811;1.0\nid4812;1.0\nid4813;1.0\nid4814;1.0\nid4815;1.0\nid4816;1.0\nid4817;1.0\nid4818;1.0\nid4819;1.0\nid4820;1.0\nid4821;1.0\nid4822;1.0\nid4823;1.0\nid4824;1.0\nid4825;1.0\nid4826;1.0\nid4827;1.0\nid4828;1.0\nid4829;1.0\nid4830;1.0\nid4831;1.0\nid4832;1.0\nid4833;1.0\nid4834;1.0\nid4835;1.0\nid4836;1.0\nid4837;1.0\nid4838;1.0\nid4839;1.0\nid4840;1.0\nid4841;1.0\nid4842;1.0\nid4843;1.0\nid4844;1.0\nid4845;1.0\nid4846;1.0\nid4847;1.0\nid4848;1.0\nid4849;1.0\nid4850;1.0\nid4851;1.0\nid4852;1.0\nid4853;1.0\nid4854;1.0\nid4855;1.0\nid4856;1.0\nid4857;1.0\nid4858;1.0\nid4859;1.0\nid4860;1.0\nid4861;1.0\nid4862;1.0\nid4863;1.0\nid4864;1.0\nid4865;1.0\nid4866;1.0\nid4867;1.0\nid4868;1.0\nid4869;1.0\nid4870;1.0\nid4871;1.0\nid4872;1.0\nid4873;1.0\nid4874;1.0\nid4875;1.0\nid4876;1.0\nid4877;1.0\nid4878;1.0\nid4879;1.0\nid4880;1.0\nid4881;1.0\nid4882;1.0\nid4883;1.0\nid4884;1.0\nid4885;1.0\nid4886;1.0\nid4887;1.0\nid4888;1.0\nid4889;1.0\nid4890;1.0\nid4891;1.0\nid4892;1.0\nid4893;1.0\nid4894;1.0\nid4895;1.0\nid4896;1.0\nid4897;1.0\nid4898;1.0\nid4899;1.0\nid4900;1.0\nid4901;1.0\nid4902;1.0\nid4903;1.0\nid4904;1.0\nid4905;1.0\nid4906;1.0\nid4907;1.0\nid4908;1.0\nid4909;1.0\nid4910;1.0\nid4911;1.0\nid4912;1.0\nid4913;1.0\nid4914;1.0\nid4915;1.0\nid4916;1.0\nid4917;1.0\nid4918;1.0\nid4919;1.0\nid4920;1.0\nid4921;1.0\nid4922;1.0\nid4923;1.0\nid4924;1.0\nid4925;1.0\nid4926;1.0\nid4927;1.0\nid4928;1.0\nid4929;1.0\nid4930;1.0\nid4931;1.0\nid4932;1.0\nid4933;1.0\nid4934;1.0\nid4935;1.0\nid4936;1.0\nid4937;1.0\nid4938;1.0\nid4939;1.0\nid4940;1.0\nid4941;1.0\nid4942;1.0\nid4943;1.0\nid4944;1.0\nid4945;1.0\nid4946;1.0\nid4947;1.0\nid4948;1.0\nid4949;1.0\nid4950;1.0\nid4951;1.0\nid4952;1.0\nid4953;1.0\nid4954;1.0\nid4955;1.0\nid4956;1.0\nid4957;1.0\nid4958;1.0\nid4959;1.0\nid4960;1.0\nid4961;1.0\nid4962;1.0\nid4963;1.0\nid4964;1.0\nid4965;1.0\nid4966;1.0\nid4967;1.0\nid4968;1.0\nid4969;1.0\nid4970;1.0\nid4971;1.0\nid4972;1.0\nid4973;1.0\nid4974;1.0\nid4975;1.0\nid4976;1.0\nid4977;1.0\nid4978;1.0\nid4979;1.0\nid4980;1.0\nid4981;1.0\nid4982;1.0\nid4983;1.0\nid4984;1.0\nid4985;1.0\nid4986;1.0\nid4987;1.0\nid4988;1.0\nid4989;1.0\nid4990;1.0\nid4991;1.0\nid4992;1.0\nid4993;1.0\nid4994;1.0\nid4995;1.0\nid4996;1.0\nid4997;1.0\nid4998;1.0\nid4999;1.0\nid5000;1.0\nid5001;1.0\nid5002;1.0\nid5003;1.0\nid5004;1.0\nid5005;1.0\nid5006;1.0\nid5007;1.0\nid5008;1.0\nid5009;1.0\nid5010;1.0\nid5011;1.0\nid5012;1.0\nid5013;1.0\nid5014;1.0\nid5015;1.0\nid5016;1.0\nid5017;1.0\nid5018;1.0\nid5019;1.0\nid5020;1.0\nid5021;1.0\nid5022;1.0\nid5023;1.0\nid5024;1.0\nid5025;1.0\nid5026;1.0\nid5027;1.0\nid5028;1.0\nid5029;1.0\nid5030;1.0\nid5031;1.0\nid5032;1.0\nid5033;1.0\nid5034;1.0\nid5035;1.0\nid5036;1.0\nid5037;1.0\nid5038;1.0\nid5039;1.0\nid5040;1.0\nid5041;1.0\nid5042;1.0\nid5043;1.0\nid5044;1.0\nid5045;1.0\nid5046;1.0\nid5047;1.0\nid5048;1.0\nid5049;1.0\nid5050;1.0\nid5051;1.0\nid5052;1.0\nid5053;1.0\nid5054;1.0\nid5055;1.0\nid5056;1.0\nid5057;1.0\nid5058;1.0\nid5059;1.0\nid5060;1.0\nid5061;1.0\nid5062;1.0\nid5063;1.0\nid5064;1.0\nid5065;1.0\nid5066;1.0\nid5067;1.0\nid5068;1.0\nid5069;1.0\nid5070;1.0\nid5071;1.0\nid5072;1.0\nid5073;1.0\nid5074;1.0\nid5075;1.0\nid5076;1.0\nid5077;1.0\nid5078;1.0\nid5079;1.0\nid5080;1.0\nid5081;1.0\nid5082;1.0\nid5083;1.0\nid5084;1.0\nid5085;1.0\nid5086;1.0\nid5087;1.0\nid5088;1.0\nid5089;1.0\nid5090;1.0\nid5091;1.0\nid5092;1.0\nid5093;1.0\nid5094;1.0\nid5095;1.0\nid5096;1.0\nid5097;1.0\nid5098;1.0\nid5099;1.0\nid5100;1.0\nid5101;1.0\nid5102;1.0\nid5103;1.0\nid5104;1.0\nid5105;1.0\nid5106;1.0\nid5107;1.0\nid5108;1.0\nid5109;1.0\nid5110;1.0\nid5111;1.0\nid5112;1.0\nid5113;1.0\nid5114;1.0\nid5115;1.0\nid5116;1.0\nid5117;1.0\nid5118;1.0\nid5119;1.0\nid5120;1.0\nid5121;1.0\nid5122;1.0\nid5123;1.0\nid5124;1.0\nid5125;1.0\nid5126;1.0\nid5127;1.0\nid5128;1.0\nid5129;1.0\nid5130;1.0\nid5131;1.0\nid5132;1.0\nid5133;1.0\nid5134;1.0\nid5135;1.0\nid5136;1.0\nid5137;1.0\nid5138;1.0\nid5139;1.0\nid5140;1.0\nid5141;1.0\nid5142;1.0\nid5143;1.0\nid5144;1.0\nid5145;1.0\nid5146;1.0\nid5147;1.0\nid5148;1.0\nid5149;1.0\nid5150;1.0\nid5151;1.0\nid5152;1.0\nid5153;1.0\nid5154;1.0\nid5155;1.0\nid5156;1.0\nid5157;1.0\nid5158;1.0\nid5159;1.0\nid5160;1.0\nid5161;1.0\nid5162;1.0\nid5163;1.0\nid5164;1.0\nid5165;1.0\nid5166;1.0\nid5167;1.0\nid5168;1.0\nid5169;1.0\nid5170;1.0\nid5171;1.0\nid5172;1.0\nid5173;1.0\nid5174;1.0\nid5175;1.0\nid5176;1.0\nid5177;1.0\nid5178;1.0\nid5179;1.0\nid5180;1.0\nid5181;1.0\nid5182;1.0\nid5183;1.0\nid5184;1.0\nid5185;1.0\nid5186;1.0\nid5187;1.0\nid5188;1.0\nid5189;1.0\nid5190;1.0\nid5191;1.0\nid5192;1.0\nid5193;1.0\nid5194;1.0\nid5195;1.0\nid5196;1.0\nid5197;1.0\nid5198;1.0\nid5199;1.0\nid5200;1.0\nid5201;1.0\nid5202;1.0\nid5203;1.0\nid5204;1.0\nid5205;1.0\nid5206;1.0\nid5207;1.0\nid5208;1.0\nid5209;1.0\nid5210;1.0\nid5211;1.0\nid5212;1.0\nid5213;1.0\nid5214;1.0\nid5215;1.0\nid5216;1.0\nid5217;1.0\nid5218;1.0\nid5219;1.0\nid5220;1.0\nid5221;1.0\nid5222;1.0\nid5223;1.0\nid5224;1.0\nid5225;1.0\nid5226;1.0\nid5227;1.0\nid5228;1.0\nid5229;1.0\nid5230;1.0\nid5231;1.0\nid5232;1.0\nid5233;1.0\nid5234;1.0\nid5235;1.0\nid5236;1.0\nid5237;1.0\nid5238;1.0\nid5239;1.0\nid5240;1.0\nid5241;1.0\nid5242;1.0\nid5243;1.0\nid5244;1.0\nid5245;1.0\nid5246;1.0\nid5247;1.0\nid5248;1.0\nid5249;1.0\nid5250;1.0\nid5251;1.0\nid5252;1.0\nid5253;1.0\nid5254;1.0\nid5255;1.0\nid5256;1.0\nid5257;1.0\nid5258;1.0\nid5259;1.0\nid5260;1.0\nid5261;1.0\nid5262;1.0\nid5263;1.0\nid5264;1.0\nid5265;1.0\nid5266;1.0\nid5267;1.0\nid5268;1.0\nid5269;1.0\nid5270;1.0\nid5271;1.0\nid5272;1.0\nid5273;1.0\nid5274;1.0\nid5275;1.0\nid5276;1.0\nid5277;1.0\nid5278;1.0\nid5279;1.0\nid5280;1.0\nid5281;1.0\nid5282;1.0\nid5283;1.0\nid5284;1.0\nid5285;1.0\nid5286;1.0\nid5287;1.0\nid5288;1.0\nid5289;1.0\nid5290;1.0\nid5291;1.0\nid5292;1.0\nid5293;1.0\nid5294;1.0\nid5295;1.0\nid5296;1.0\nid5297;1.0\nid5298;1.0\nid5299;1.0\nid5300;1.0\nid5301;1.0\nid5302;1.0\nid5303;1.0\nid5304;1.0\nid5305;1.0\nid5306;1.0\nid5307;1.0\nid5308;1.0\nid5309;1.0\nid5310;1.0\nid5311;1.0\nid5312;1.0\nid5313;1.0\nid5314;1.0\nid5315;1.0\nid5316;1.0\nid5317;1.0\nid5318;1.0\nid5319;1.0\nid5320;1.0\nid5321;1.0\nid5322;1.0\nid5323;1.0\nid5324;1.0\nid5325;1.0\nid5326;1.0\nid5327;1.0\nid5328;1.0\nid5329;1.0\nid5330;1.0\nid5331;1.0\nid5332;1.0\nid5333;1.0\nid5334;1.0\nid5335;1.0\nid5336;1.0\nid5337;1.0\nid5338;1.0\nid5339;1.0\nid5340;1.0\nid5341;1.0\nid5342;1.0\nid5343;1.0\nid5344;1.0\nid5345;1.0\nid5346;1.0\nid5347;1.0\nid5348;1.0\nid5349;1.0\nid5350;1.0\nid5351;1.0\nid5352;1.0\nid5353;1.0\nid5354;1.0\nid5355;1.0\nid5356;1.0\nid5357;1.0\nid5358;1.0\nid5359;1.0\nid5360;1.0\nid5361;1.0\nid5362;1.0\nid5363;1.0\nid5364;1.0\nid5365;1.0\nid5366;1.0\nid5367;1.0\nid5368;1.0\nid5369;1.0\nid5370;1.0\nid5371;1.0\nid5372;1.0\nid5373;1.0\nid5374;1.0\nid5375;1.0\nid5376;1.0\nid5377;1.0\nid5378;1.0\nid5379;1.0\nid5380;1.0\nid5381;1.0\nid5382;1.0\nid5383;1.0\nid5384;1.0\nid5385;1.0\nid5386;1.0\nid5387;1.0\nid5388;1.0\nid5389;1.0\nid5390;1.0\nid5391;1.0\nid5392;1.0\nid5393;1.0\nid5394;1.0\nid5395;1.0\nid5396;1.0\nid5397;1.0\nid5398;1.0\nid5399;1.0\nid5400;1.0\nid5401;1.0\nid5402;1.0\nid5403;1.0\nid5404;1.0\nid5405;1.0\nid5406;1.0\nid5407;1.0\nid5408;1.0\nid5409;1.0\nid5410;1.0\nid5411;1.0\nid5412;1.0\nid5413;1.0\nid5414;1.0\nid5415;1.0\nid5416;1.0\nid5417;1.0\nid5418;1.0\nid5419;1.0\nid5420;1.0\nid5421;1.0\nid5422;1.0\nid5423;1.0\nid5424;1.0\nid5425;1.0\nid5426;1.0\nid5427;1.0\nid5428;1.0\nid5429;1.0\nid5430;1.0\nid5431;1.0\nid5432;1.0\nid5433;1.0\nid5434;1.0\nid5435;1.0\nid5436;1.0\nid5437;1.0\nid5438;1.0\nid5439;1.0\nid5440;1.0\nid5441;1.0\nid5442;1.0\nid5443;1.0\nid5444;1.0\nid5445;1.0\nid5446;1.0\nid5447;1.0\nid5448;1.0\nid5449;1.0\nid5450;1.0\nid5451;1.0\nid5452;1.0\nid5453;1.0\nid5454;1.0\nid5455;1.0\nid5456;1.0\nid5457;1.0\nid5458;1.0\nid5459;1.0\nid5460;1.0\nid5461;1.0\nid5462;1.0\nid5463;1.0\nid5464;1.0\nid5465;1.0\nid5466;1.0\nid5467;1.0\nid5468;1.0\nid5469;1.0\nid5470;1.0\nid5471;1.0\nid5472;1.0\nid5473;1.0\nid5474;1.0\nid5475;1.0\nid5476;1.0\nid5477;1.0\nid5478;1.0\nid5479;1.0\nid5480;1.0\nid5481;1.0\nid5482;1.0\nid5483;1.0\nid5484;1.0\nid5485;1.0\nid5486;1.0\nid5487;1.0\nid5488;1.0\nid5489;1.0\nid5490;1.0\nid5491;1.0\nid5492;1.0\nid5493;1.0\nid5494;1.0\nid5495;1.0\nid5496;1.0\nid5497;1.0\nid5498;1.0\nid5499;1.0\nid5500;1.0\nid5501;1.0\nid5502;1.0\nid5503;1.0\nid5504;1.0\nid5505;1.0\nid5506;1.0\nid5507;1.0\nid5508;1.0\nid5509;1.0\nid5510;1.0\nid5511;1.0\nid5512;1.0\nid5513;1.0\nid5514;1.0\nid5515;1.0\nid5516;1.0\nid5517;1.0\nid5518;1.0\nid5519;1.0\nid5520;1.0\nid5521;1.0\nid5522;1.0\nid5523;1.0\nid5524;1.0\nid5525;1.0\nid5526;1.0\nid5527;1.0\nid5528;1.0\nid5529;1.0\nid5530;1.0\nid5531;1.0\nid5532;1.0\nid5533;1.0\nid5534;1.0\nid5535;1.0\nid5536;1.0\nid5537;1.0\nid5538;1.0\nid5539;1.0\nid5540;1.0\nid5541;1.0\nid5542;1.0\nid5543;1.0\nid5544;1.0\nid5545;1.0\nid5546;1.0\nid5547;1.0\nid5548;1.0\nid5549;1.0\nid5550;1.0\nid5551;1.0\nid5552;1.0\nid5553;1.0\nid5554;1.0\nid5555;1.0\nid5556;1.0\nid5557;1.0\nid5558;1.0\nid5559;1.0\nid5560;1.0\nid5561;1.0\nid5562;1.0\nid5563;1.0\nid5564;1.0\nid5565;1.0\nid5566;1.0\nid5567;1.0\nid5568;1.0\nid5569;1.0\nid5570;1.0\nid5571;1.0\nid5572;1.0\nid5573;1.0\nid5574;1.0\nid5575;1.0\nid5576;1.0\nid5577;1.0\nid5578;1.0\nid5579;1.0\nid5580;1.0\nid5581;1.0\nid5582;1.0\nid5583;1.0\nid5584;1.0\nid5585;1.0\nid5586;1.0\nid5587;1.0\nid5588;1.0\nid5589;1.0\nid5590;1.0\nid5591;1.0\nid5592;1.0\nid5593;1.0\nid5594;1.0\nid5595;1.0\nid5596;1.0\nid5597;1.0\nid5598;1.0\nid5599;1.0\nid5600;1.0\nid5601;1.0\nid5602;1.0\nid5603;1.0\nid5604;1.0\nid5605;1.0\nid5606;1.0\nid5607;1.0\nid5608;1.0\nid5609;1.0\nid5610;1.0\nid5611;1.0\nid5612;1.0\nid5613;1.0\nid5614;1.0\nid5615;1.0\nid5616;1.0\nid5617;1.0\nid5618;1.0\nid5619;1.0\nid5620;1.0\nid5621;1.0\nid5622;1.0\nid5623;1.0\nid5624;1.0\nid5625;1.0\nid5626;1.0\nid5627;1.0\nid5628;1.0\nid5629;1.0\nid5630;1.0\nid5631;1.0\nid5632;1.0\nid5633;1.0\nid5634;1.0\nid5635;1.0\nid5636;1.0\nid5637;1.0\nid5638;1.0\nid5639;1.0\nid5640;1.0\nid5641;1.0\nid5642;1.0\nid5643;1.0\nid5644;1.0\nid5645;1.0\nid5646;1.0\nid5647;1.0\nid5648;1.0\nid5649;1.0\nid5650;1.0\nid5651;1.0\nid5652;1.0\nid5653;1.0\nid5654;1.0\nid5655;1.0\nid5656;1.0\nid5657;1.0\nid5658;1.0\nid5659;1.0\nid5660;1.0\nid5661;1.0\nid5662;1.0\nid5663;1.0\nid5664;1.0\nid5665;1.0\nid5666;1.0\nid5667;1.0\nid5668;1.0\nid5669;1.0\nid5670;1.0\nid5671;1.0\nid5672;1.0\nid5673;1.0\nid5674;1.0\nid5675;1.0\nid5676;1.0\nid5677;1.0\nid5678;1.0\nid5679;1.0\nid5680;1.0\nid5681;1.0\nid5682;1.0\nid5683;1.0\nid5684;1.0\nid5685;1.0\nid5686;1.0\nid5687;1.0\nid5688;1.0\nid5689;1.0\nid5690;1.0\nid5691;1.0\nid5692;1.0\nid5693;1.0\nid5694;1.0\nid5695;1.0\nid5696;1.0\nid5697;1.0\nid5698;1.0\nid5699;1.0\nid5700;1.0\nid5701;1.0\nid5702;1.0\nid5703;1.0\nid5704;1.0\nid5705;1.0\nid5706;1.0\nid5707;1.0\nid5708;1.0\nid5709;1.0\nid5710;1.0\nid5711;1.0\nid5712;1.0\nid5713;1.0\nid5714;1.0\nid5715;1.0\nid5716;1.0\nid5717;1.0\nid5718;1.0\nid5719;1.0\nid5720;1.0\nid5721;1.0\nid5722;1.0\nid5723;1.0\nid5724;1.0\nid5725;1.0\nid5726;1.0\nid5727;1.0\nid5728;1.0\nid5729;1.0\nid5730;1.0\nid5731;1.0\nid5732;1.0\nid5733;1.0\nid5734;1.0\nid5735;1.0\nid5736;1.0\nid5737;1.0\nid5738;1.0\nid5739;1.0\nid5740;1.0\nid5741;1.0\nid5742;1.0\nid5743;1.0\nid5744;1.0\nid5745;1.0\nid5746;1.0\nid5747;1.0\nid5748;1.0\nid5749;1.0\nid5750;1.0\nid5751;1.0\nid5752;1.0\nid5753;1.0\nid5754;1.0\nid5755;1.0\nid5756;1.0\nid5757;1.0\nid5758;1.0\nid5759;1.0\nid5760;1.0\nid5761;1.0\nid5762;1.0\nid5763;1.0\nid5764;1.0\nid5765;1.0\nid5766;1.0\nid5767;1.0\nid5768;1.0\nid5769;1.0\nid5770;1.0\nid5771;1.0\nid5772;1.0\nid5773;1.0\nid5774;1.0\nid5775;1.0\nid5776;1.0\nid5777;1.0\nid5778;1.0\nid5779;1.0\nid5780;1.0\nid5781;1.0\nid5782;1.0\nid5783;1.0\nid5784;1.0\nid5785;1.0\nid5786;1.0\nid5787;1.0\nid5788;1.0\nid5789;1.0\nid5790;1.0\nid5791;1.0\nid5792;1.0\nid5793;1.0\nid5794;1.0\nid5795;1.0\nid5796;1.0\nid5797;1.0\nid5798;1.0\nid5799;1.0\nid5800;1.0\nid5801;1.0\nid5802;1.0\nid5803;1.0\nid5804;1.0\nid5805;1.0\nid5806;1.0\nid5807;1.0\nid5808;1.0\nid5809;1.0\nid5810;1.0\nid5811;1.0\nid5812;1.0\nid5813;1.0\nid5814;1.0\nid5815;1.0\nid5816;1.0\nid5817;1.0\nid5818;1.0\nid5819;1.0\nid5820;1.0\nid5821;1.0\nid5822;1.0\nid5823;1.0\nid5824;1.0\nid5825;1.0\nid5826;1.0\nid5827;1.0\nid5828;1.0\nid5829;1.0\nid5830;1.0\nid5831;1.0\nid5832;1.0\nid5833;1.0\nid5834;1.0\nid5835;1.0\nid5836;1.0\nid5837;1.0\nid5838;1.0\nid5839;1.0\nid5840;1.0\nid5841;1.0\nid5842;1.0\nid5843;1.0\nid5844;1.0\nid5845;1.0\nid5846;1.0\nid5847;1.0\nid5848;1.0\nid5849;1.0\nid5850;1.0\nid5851;1.0\nid5852;1.0\nid5853;1.0\nid5854;1.0\nid5855;1.0\nid5856;1.0\nid5857;1.0\nid5858;1.0\nid5859;1.0\nid5860;1.0\nid5861;1.0\nid5862;1.0\nid5863;1.0\nid5864;1.0\nid5865;1.0\nid5866;1.0\nid5867;1.0\nid5868;1.0\nid5869;1.0\nid5870;1.0\nid5871;1.0\nid5872;1.0\nid5873;1.0\nid5874;1.0\nid5875;1.0\nid5876;1.0\nid5877;1.0\nid5878;1.0\nid5879;1.0\nid5880;1.0\nid5881;1.0\nid5882;1.0\nid5883;1.0\nid5884;1.0\nid5885;1.0\nid5886;1.0\nid5887;1.0\nid5888;1.0\nid5889;1.0\nid5890;1.0\nid5891;1.0\nid5892;1.0\nid5893;1.0\nid5894;1.0\nid5895;1.0\nid5896;1.0\nid5897;1.0\nid5898;1.0\nid5899;1.0\nid5900;1.0\nid5901;1.0\nid5902;1.0\nid5903;1.0\nid5904;1.0\nid5905;1.0\nid5906;1.0\nid5907;1.0\nid5908;1.0\nid5909;1.0\nid5910;1.0\nid5911;1.0\nid5912;1.0\nid5913;1.0\nid5914;1.0\nid5915;1.0\nid5916;1.0\nid5917;1.0\nid5918;1.0\nid5919;1.0\nid5920;1.0\nid5921;1.0\nid5922;1.0\nid5923;1.0\nid5924;1.0\nid5925;1.0\nid5926;1.0\nid5927;1.0\nid5928;1.0\nid5929;1.0\nid5930;1.0\nid5931;1.0\nid5932;1.0\nid5933;1.0\nid5934;1.0\nid5935;1.0\nid5936;1.0\nid5937;1.0\nid5938;1.0\nid5939;1.0\nid5940;1.0\nid5941;1.0\nid5942;1.0\nid5943;1.0\nid5944;1.0\nid5945;1.0\nid5946;1.0\nid5947;1.0\nid5948;1.0\nid5949;1.0\nid5950;1.0\nid5951;1.0\nid5952;1.0\nid5953;1.0\nid5954;1.0\nid5955;1.0\nid5956;1.0\nid5957;1.0\nid5958;1.0\nid5959;1.0\nid5960;1.0\nid5961;1.0\nid5962;1.0\nid5963;1.0\nid5964;1.0\nid5965;1.0\nid5966;1.0\nid5967;1.0\nid5968;1.0\nid5969;1.0\nid5970;1.0\nid5971;1.0\nid5972;1.0\nid5973;1.0\nid5974;1.0\nid5975;1.0\nid5976;1.0\nid5977;1.0\nid5978;1.0\nid5979;1.0\nid5980;1.0\nid5981;1.0\nid5982;1.0\nid5983;1.0\nid5984;1.0\nid5985;1.0\nid5986;1.0\nid5987;1.0\nid5988;1.0\nid5989;1.0\nid5990;1.0\nid5991;1.0\nid5992;1.0\nid5993;1.0\nid5994;1.0\nid5995;1.0\nid5996;1.0\nid5997;1.0\nid5998;1.0\nid5999;1.0\nid6000;1.0\nid6001;1.0\nid6002;1.0\nid6003;1.0\nid6004;1.0\nid6005;1.0\nid6006;1.0\nid6007;1.0\nid6008;1.0\nid6009;1.0\nid6010;1.0\nid6011;1.0\nid6012;1.0\nid6013;1.0\nid6014;1.0\nid6015;1.0\nid6016;1.0\nid6017;1.0\nid6018;1.0\nid6019;1.0\nid6020;1.0\nid6021;1.0\nid6022;1.0\nid6023;1.0\nid6024;1.0\nid6025;1.0\nid6026;1.0\nid6027;1.0\nid6028;1.0\nid6029;1.0\nid6030;1.0\nid6031;1.0\nid6032;1.0\nid6033;1.0\nid6034;1.0\nid6035;1.0\nid6036;1.0\nid6037;1.0\nid6038;1.0\nid6039;1.0\nid6040;1.0\nid6041;1.0\nid6042;1.0\nid6043;1.0\nid6044;1.0\nid6045;1.0\nid6046;1.0\nid6047;1.0\nid6048;1.0\nid6049;1.0\nid6050;1.0\nid6051;1.0\nid6052;1.0\nid6053;1.0\nid6054;1.0\nid6055;1.0\nid6056;1.0\nid6057;1.0\nid6058;1.0\nid6059;1.0\nid6060;1.0\nid6061;1.0\nid6062;1.0\nid6063;1.0\nid6064;1.0\nid6065;1.0\nid6066;1.0\nid6067;1.0\nid6068;1.0\nid6069;1.0\nid6070;1.0\nid6071;1.0\nid6072;1.0\nid6073;1.0\nid6074;1.0\nid6075;1.0\nid6076;1.0\nid6077;1.0\nid6078;1.0\nid6079;1.0\nid6080;1.0\nid6081;1.0\nid6082;1.0\nid6083;1.0\nid6084;1.0\nid6085;1.0\nid6086;1.0\nid6087;1.0\nid6088;1.0\nid6089;1.0\nid6090;1.0\nid6091;1.0\nid6092;1.0\nid6093;1.0\nid6094;1.0\nid6095;1.0\nid6096;1.0\nid6097;1.0\nid6098;1.0\nid6099;1.0\nid6100;1.0\nid6101;1.0\nid6102;1.0\nid6103;1.0\nid6104;1.0\nid6105;1.0\nid6106;1.0\nid6107;1.0\nid6108;1.0\nid6109;1.0\nid6110;1.0\nid6111;1.0\nid6112;1.0\nid6113;1.0\nid6114;1.0\nid6115;1.0\nid6116;1.0\nid6117;1.0\nid6118;1.0\nid6119;1.0\nid6120;1.0\nid6121;1.0\nid6122;1.0\nid6123;1.0\nid6124;1.0\nid6125;1.0\nid6126;1.0\nid6127;1.0\nid6128;1.0\nid6129;1.0\nid6130;1.0\nid6131;1.0\nid6132;1.0\nid6133;1.0\nid6134;1.0\nid6135;1.0\nid6136;1.0\nid6137;1.0\nid6138;1.0\nid6139;1.0\nid6140;1.0\nid6141;1.0\nid6142;1.0\nid6143;1.0\nid6144;1.0\nid6145;1.0\nid6146;1.0\nid6147;1.0\nid6148;1.0\nid6149;1.0\nid6150;1.0\nid6151;1.0\nid6152;1.0\nid6153;1.0\nid6154;1.0\nid6155;1.0\nid6156;1.0\nid6157;1.0\nid6158;1.0\nid6159;1.0\nid6160;1.0\nid6161;1.0\nid6162;1.0\nid6163;1.0\nid6164;1.0\nid6165;1.0\nid6166;1.0\nid6167;1.0\nid6168;1.0\nid6169;1.0\nid6170;1.0\nid6171;1.0\nid6172;1.0\nid6173;1.0\nid6174;1.0\nid6175;1.0\nid6176;1.0\nid6177;1.0\nid6178;1.0\nid6179;1.0\nid6180;1.0\nid6181;1.0\nid6182;1.0\nid6183;1.0\nid6184;1.0\nid6185;1.0\nid6186;1.0\nid6187;1.0\nid6188;1.0\nid6189;1.0\nid6190;1.0\nid6191;1.0\nid6192;1.0\nid6193;1.0\nid6194;1.0\nid6195;1.0\nid6196;1.0\nid6197;1.0\nid6198;1.0\nid6199;1.0\nid6200;1.0\nid6201;1.0\nid6202;1.0\nid6203;1.0\nid6204;1.0\nid6205;1.0\nid6206;1.0\nid6207;1.0\nid6208;1.0\nid6209;1.0\nid6210;1.0\nid6211;1.0\nid6212;1.0\nid6213;1.0\nid6214;1.0\nid6215;1.0\nid6216;1.0\nid6217;1.0\nid6218;1.0\nid6219;1.0\nid6220;1.0\nid6221;1.0\nid6222;1.0\nid6223;1.0\nid6224;1.0\nid6225;1.0\nid6226;1.0\nid6227;1.0\nid6228;1.0\nid6229;1.0\nid6230;1.0\nid6231;1.0\nid6232;1.0\nid6233;1.0\nid6234;1.0\nid6235;1.0\nid6236;1.0\nid6237;1.0\nid6238;1.0\nid6239;1.0\nid6240;1.0\nid6241;1.0\nid6242;1.0\nid6243;1.0\nid6244;1.0\nid6245;1.0\nid6246;1.0\nid6247;1.0\nid6248;1.0\nid6249;1.0\nid6250;1.0\nid6251;1.0\nid6252;1.0\nid6253;1.0\nid6254;1.0\nid6255;1.0\nid6256;1.0\nid6257;1.0\nid6258;1.0\nid6259;1.0\nid6260;1.0\nid6261;1.0\nid6262;1.0\nid6263;1.0\nid6264;1.0\nid6265;1.0\nid6266;1.0\nid6267;1.0\nid6268;1.0\nid6269;1.0\nid6270;1.0\nid6271;1.0\nid6272;1.0\nid6273;1.0\nid6274;1.0\nid6275;1.0\nid6276;1.0\nid6277;1.0\nid6278;1.0\nid6279;1.0\nid6280;1.0\nid6281;1.0\nid6282;1.0\nid6283;1.0\nid6284;1.0\nid6285;1.0\nid6286;1.0\nid6287;1.0\nid6288;1.0\nid6289;1.0\nid6290;1.0\nid6291;1.0\nid6292;1.0\nid6293;1.0\nid6294;1.0\nid6295;1.0\nid6296;1.0\nid6297;1.0\nid6298;1.0\nid6299;1.0\nid6300;1.0\nid6301;1.0\nid6302;1.0\nid6303;1.0\nid6304;1.0\nid6305;1.0\nid6306;1.0\nid6307;1.0\nid6308;1.0\nid6309;1.0\nid6310;1.0\nid6311;1.0\nid6312;1.0\nid6313;1.0\nid6314;1.0\nid6315;1.0\nid6316;1.0\nid6317;1.0\nid6318;1.0\nid6319;1.0\nid6320;1.0\nid6321;1.0\nid6322;1.0\nid6323;1.0\nid6324;1.0\nid6325;1.0\nid6326;1.0\nid6327;1.0\nid6328;1.0\nid6329;1.0\nid6330;1.0\nid6331;1.0\nid6332;1.0\nid6333;1.0\nid6334;1.0\nid6335;1.0\nid6336;1.0\nid6337;1.0\nid6338;1.0\nid6339;1.0\nid6340;1.0\nid6341;1.0\nid6342;1.0\nid6343;1.0\nid6344;1.0\nid6345;1.0\nid6346;1.0\nid6347;1.0\nid6348;1.0\nid6349;1.0\nid6350;1.0\nid6351;1.0\nid6352;1.0\nid6353;1.0\nid6354;1.0\nid6355;1.0\nid6356;1.0\nid6357;1.0\nid6358;1.0\nid6359;1.0\nid6360;1.0\nid6361;1.0\nid6362;1.0\nid6363;1.0\nid6364;1.0\nid6365;1.0\nid6366;1.0\nid6367;1.0\nid6368;1.0\nid6369;1.0\nid6370;1.0\nid6371;1.0\nid6372;1.0\nid6373;1.0\nid6374;1.0\nid6375;1.0\nid6376;1.0\nid6377;1.0\nid6378;1.0\nid6379;1.0\nid6380;1.0\nid6381;1.0\nid6382;1.0\nid6383;1.0\nid6384;1.0\nid6385;1.0\nid6386;1.0\nid6387;1.0\nid6388;1.0\nid6389;1.0\nid6390;1.0\nid6391;1.0\nid6392;1.0\nid6393;1.0\nid6394;1.0\nid6395;1.0\nid6396;1.0\nid6397;1.0\nid6398;1.0\nid6399;1.0\nid6400;1.0\nid6401;1.0\nid6402;1.0\nid6403;1.0\nid6404;1.0\nid6405;1.0\nid6406;1.0\nid6407;1.0\nid6408;1.0\nid6409;1.0\nid6410;1.0\nid6411;1.0\nid6412;1.0\nid6413;1.0\nid6414;1.0\nid6415;1.0\nid6416;1.0\nid6417;1.0\nid6418;1.0\nid6419;1.0\nid6420;1.0\nid6421;1.0\nid6422;1.0\nid6423;1.0\nid6424;1.0\nid6425;1.0\nid6426;1.0\nid6427;1.0\nid6428;1.0\nid6429;1.0\nid6430;1.0\nid6431;1.0\nid6432;1.0\nid6433;1.0\nid6434;1.0\nid6435;1.0\nid6436;1.0\nid6437;1.0\nid6438;1.0\nid6439;1.0\nid6440;1.0\nid6441;1.0\nid6442;1.0\nid6443;1.0\nid6444;1.0\nid6445;1.0\nid6446;1.0\nid6447;1.0\nid6448;1.0\nid6449;1.0\nid6450;1.0\nid6451;1.0\nid6452;1.0\nid6453;1.0\nid6454;1.0\nid6455;1.0\nid6456;1.0\nid6457;1.0\nid6458;1.0\nid6459;1.0\nid6460;1.0\nid6461;1.0\nid6462;1.0\nid6463;1.0\nid6464;1.0\nid6465;1.0\nid6466;1.0\nid6467;1.0\nid6468;1.0\nid6469;1.0\nid6470;1.0\nid6471;1.0\nid6472;1.0\nid6473;1.0\nid6474;1.0\nid6475;1.0\nid6476;1.0\nid6477;1.0\nid6478;1.0\nid6479;1.0\nid6480;1.0\nid6481;1.0\nid6482;1.0\nid6483;1.0\nid6484;1.0\nid6485;1.0\nid6486;1.0\nid6487;1.0\nid6488;1.0\nid6489;1.0\nid6490;1.0\nid6491;1.0\nid6492;1.0\nid6493;1.0\nid6494;1.0\nid6495;1.0\nid6496;1.0\nid6497;1.0\nid6498;1.0\nid6499;1.0\nid6500;1.0\nid6501;1.0\nid6502;1.0\nid6503;1.0\nid6504;1.0\nid6505;1.0\nid6506;1.0\nid6507;1.0\nid6508;1.0\nid6509;1.0\nid6510;1.0\nid6511;1.0\nid6512;1.0\nid6513;1.0\nid6514;1.0\nid6515;1.0\nid6516;1.0\nid6517;1.0\nid6518;1.0\nid6519;1.0\nid6520;1.0\nid6521;1.0\nid6522;1.0\nid6523;1.0\nid6524;1.0\nid6525;1.0\nid6526;1.0\nid6527;1.0\nid6528;1.0\nid6529;1.0\nid6530;1.0\nid6531;1.0\nid6532;1.0\nid6533;1.0\nid6534;1.0\nid6535;1.0\nid6536;1.0\nid6537;1.0\nid6538;1.0\nid6539;1.0\nid6540;1.0\nid6541;1.0\nid6542;1.0\nid6543;1.0\nid6544;1.0\nid6545;1.0\nid6546;1.0\nid6547;1.0\nid6548;1.0\nid6549;1.0\nid6550;1.0\nid6551;1.0\nid6552;1.0\nid6553;1.0\nid6554;1.0\nid6555;1.0\nid6556;1.0\nid6557;1.0\nid6558;1.0\nid6559;1.0\nid6560;1.0\nid6561;1.0\nid6562;1.0\nid6563;1.0\nid6564;1.0\nid6565;1.0\nid6566;1.0\nid6567;1.0\nid6568;1.0\nid6569;1.0\nid6570;1.0\nid6571;1.0\nid6572;1.0\nid6573;1.0\nid6574;1.0\nid6575;1.0\nid6576;1.0\nid6577;1.0\nid6578;1.0\nid6579;1.0\nid6580;1.0\nid6581;1.0\nid6582;1.0\nid6583;1.0\nid6584;1.0\nid6585;1.0\nid6586;1.0\nid6587;1.0\nid6588;1.0\nid6589;1.0\nid6590;1.0\nid6591;1.0\nid6592;1.0\nid6593;1.0\nid6594;1.0\nid6595;1.0\nid6596;1.0\nid6597;1.0\nid6598;1.0\nid6599;1.0\nid6600;1.0\nid6601;1.0\nid6602;1.0\nid6603;1.0\nid6604;1.0\nid6605;1.0\nid6606;1.0\nid6607;1.0\nid6608;1.0\nid6609;1.0\nid6610;1.0\nid6611;1.0\nid6612;1.0\nid6613;1.0\nid6614;1.0\nid6615;1.0\nid6616;1.0\nid6617;1.0\nid6618;1.0\nid6619;1.0\nid6620;1.0\nid6621;1.0\nid6622;1.0\nid6623;1.0\nid6624;1.0\nid6625;1.0\nid6626;1.0\nid6627;1.0\nid6628;1.0\nid6629;1.0\nid6630;1.0\nid6631;1.0\nid6632;1.0\nid6633;1.0\nid6634;1.0\nid6635;1.0\nid6636;1.0\nid6637;1.0\nid6638;1.0\nid6639;1.0\nid6640;1.0\nid6641;1.0\nid6642;1.0\nid6643;1.0\nid6644;1.0\nid6645;1.0\nid6646;1.0\nid6647;1.0\nid6648;1.0\nid6649;1.0\nid6650;1.0\nid6651;1.0\nid6652;1.0\nid6653;1.0\nid6654;1.0\nid6655;1.0\nid6656;1.0\nid6657;1.0\nid6658;1.0\nid6659;1.0\nid6660;1.0\nid6661;1.0\nid6662;1.0\nid6663;1.0\nid6664;1.0\nid6665;1.0\nid6666;1.0\nid6667;1.0\nid6668;1.0\nid6669;1.0\nid6670;1.0\nid6671;1.0\nid6672;1.0\nid6673;1.0\nid6674;1.0\nid6675;1.0\nid6676;1.0\nid6677;1.0\nid6678;1.0\nid6679;1.0\nid6680;1.0\nid6681;1.0\nid6682;1.0\nid6683;1.0\nid6684;1.0\nid6685;1.0\nid6686;1.0\nid6687;1.0\nid6688;1.0\nid6689;1.0\nid6690;1.0\nid6691;1.0\nid6692;1.0\nid6693;1.0\nid6694;1.0\nid6695;1.0\nid6696;1.0\nid6697;1.0\nid6698;1.0\nid6699;1.0\nid6700;1.0\nid6701;1.0\nid6702;1.0\nid6703;1.0\nid6704;1.0\nid6705;1.0\nid6706;1.0\nid6707;1.0\nid6708;1.0\nid6709;1.0\nid6710;1.0\nid6711;1.0\nid6712;1.0\nid6713;1.0\nid6714;1.0\nid6715;1.0\nid6716;1.0\nid6717;1.0\nid6718;1.0\nid6719;1.0\nid6720;1.0\nid6721;1.0\nid6722;1.0\nid6723;1.0\nid6724;1.0\nid6725;1.0\nid6726;1.0\nid6727;1.0\nid6728;1.0\nid6729;1.0\nid6730;1.0\nid6731;1.0\nid6732;1.0\nid6733;1.0\nid6734;1.0\nid6735;1.0\nid6736;1.0\nid6737;1.0\nid6738;1.0\nid6739;1.0\nid6740;1.0\nid6741;1.0\nid6742;1.0\nid6743;1.0\nid6744;1.0\nid6745;1.0\nid6746;1.0\nid6747;1.0\nid6748;1.0\nid6749;1.0\nid6750;1.0\nid6751;1.0\nid6752;1.0\nid6753;1.0\nid6754;1.0\nid6755;1.0\nid6756;1.0\nid6757;1.0\nid6758;1.0\nid6759;1.0\nid6760;1.0\nid6761;1.0\nid6762;1.0\nid6763;1.0\nid6764;1.0\nid6765;1.0\nid6766;1.0\nid6767;1.0\nid6768;1.0\nid6769;1.0\nid6770;1.0\nid6771;1.0\nid6772;1.0\nid6773;1.0\nid6774;1.0\nid6775;1.0\nid6776;1.0\nid6777;1.0\nid6778;1.0\nid6779;1.0\nid6780;1.0\nid6781;1.0\nid6782;1.0\nid6783;1.0\nid6784;1.0\nid6785;1.0\nid6786;1.0\nid6787;1.0\nid6788;1.0\nid6789;1.0\nid6790;1.0\nid6791;1.0\nid6792;1.0\nid6793;1.0\nid6794;1.0\nid6795;1.0\nid6796;1.0\nid6797;1.0\nid6798;1.0\nid6799;1.0\nid6800;1.0\nid6801;1.0\nid6802;1.0\nid6803;1.0\nid6804;1.0\nid6805;1.0\nid6806;1.0\nid6807;1.0\nid6808;1.0\nid6809;1.0\nid6810;1.0\nid6811;1.0\nid6812;1.0\nid6813;1.0\nid6814;1.0\nid6815;1.0\nid6816;1.0\nid6817;1.0\nid6818;1.0\nid6819;1.0\nid6820;1.0\nid6821;1.0\nid6822;1.0\nid6823;1.0\nid6824;1.0\nid6825;1.0\nid6826;1.0\nid6827;1.0\nid6828;1.0\nid6829;1.0\nid6830;1.0\nid6831;1.0\nid6832;1.0\nid6833;1.0\nid6834;1.0\nid6835;1.0\nid6836;1.0\nid6837;1.0\nid6838;1.0\nid6839;1.0\nid6840;1.0\nid6841;1.0\nid6842;1.0\nid6843;1.0\nid6844;1.0\nid6845;1.0\nid6846;1.0\nid6847;1.0\nid6848;1.0\nid6849;1.0\nid6850;1.0\nid6851;1.0\nid6852;1.0\nid6853;1.0\nid6854;1.0\nid6855;1.0\nid6856;1.0\nid6857;1.0\nid6858;1.0\nid6859;1.0\nid6860;1.0\nid6861;1.0\nid6862;1.0\nid6863;1.0\nid6864;1.0\nid6865;1.0\nid6866;1.0\nid6867;1.0\nid6868;1.0\nid6869;1.0\nid6870;1.0\nid6871;1.0\nid6872;1.0\nid6873;1.0\nid6874;1.0\nid6875;1.0\nid6876;1.0\nid6877;1.0\nid6878;1.0\nid6879;1.0\nid6880;1.0\nid6881;1.0\nid6882;1.0\nid6883;1.0\nid6884;1.0\nid6885;1.0\nid6886;1.0\nid6887;1.0\nid6888;1.0\nid6889;1.0\nid6890;1.0\nid6891;1.0\nid6892;1.0\nid6893;1.0\nid6894;1.0\nid6895;1.0\nid6896;1.0\nid6897;1.0\nid6898;1.0\nid6899;1.0\nid6900;1.0\nid6901;1.0\nid6902;1.0\nid6903;1.0\nid6904;1.0\nid6905;1.0\nid6906;1.0\nid6907;1.0\nid6908;1.0\nid6909;1.0\nid6910;1.0\nid6911;1.0\nid6912;1.0\nid6913;1.0\nid6914;1.0\nid6915;1.0\nid6916;1.0\nid6917;1.0\nid6918;1.0\nid6919;1.0\nid6920;1.0\nid6921;1.0\nid6922;1.0\nid6923;1.0\nid6924;1.0\nid6925;1.0\nid6926;1.0\nid6927;1.0\nid6928;1.0\nid6929;1.0\nid6930;1.0\nid6931;1.0\nid6932;1.0\nid6933;1.0\nid6934;1.0\nid6935;1.0\nid6936;1.0\nid6937;1.0\nid6938;1.0\nid6939;1.0\nid6940;1.0\nid6941;1.0\nid6942;1.0\nid6943;1.0\nid6944;1.0\nid6945;1.0\nid6946;1.0\nid6947;1.0\nid6948;1.0\nid6949;1.0\nid6950;1.0\nid6951;1.0\nid6952;1.0\nid6953;1.0\nid6954;1.0\nid6955;1.0\nid6956;1.0\nid6957;1.0\nid6958;1.0\nid6959;1.0\nid6960;1.0\nid6961;1.0\nid6962;1.0\nid6963;1.0\nid6964;1.0\nid6965;1.0\nid6966;1.0\nid6967;1.0\nid6968;1.0\nid6969;1.0\nid6970;1.0\nid6971;1.0\nid6972;1.0\nid6973;1.0\nid6974;1.0\nid6975;1.0\nid6976;1.0\nid6977;1.0\nid6978;1.0\nid6979;1.0\nid6980;1.0\nid6981;1.0\nid6982;1.0\nid6983;1.0\nid6984;1.0\nid6985;1.0\nid6986;1.0\nid6987;1.0\nid6988;1.0\nid6989;1.0\nid6990;1.0\nid6991;1.0\nid6992;1.0\nid6993;1.0\nid6994;1.0\nid6995;1.0\nid6996;1.0\nid6997;1.0\nid6998;1.0\nid6999;1.0\nid7000;1.0\nid7001;1.0\nid7002;1.0\nid7003;1.0\nid7004;1.0\nid7005;1.0\nid7006;1.0\nid7007;1.0\nid7008;1.0\nid7009;1.0\nid7010;1.0\nid7011;1.0\nid7012;1.0\nid7013;1.0\nid7014;1.0\nid7015;1.0\nid7016;1.0\nid7017;1.0\nid7018;1.0\nid7019;1.0\nid7020;1.0\nid7021;1.0\nid7022;1.0\nid7023;1.0\nid7024;1.0\nid7025;1.0\nid7026;1.0\nid7027;1.0\nid7028;1.0\nid7029;1.0\nid7030;1.0\nid7031;1.0\nid7032;1.0\nid7033;1.0\nid7034;1.0\nid7035;1.0\nid7036;1.0\nid7037;1.0\nid7038;1.0\nid7039;1.0\nid7040;1.0\nid7041;1.0\nid7042;1.0\nid7043;1.0\nid7044;1.0\nid7045;1.0\nid7046;1.0\nid7047;1.0\nid7048;1.0\nid7049;1.0\nid7050;1.0\nid7051;1.0\nid7052;1.0\nid7053;1.0\nid7054;1.0\nid7055;1.0\nid7056;1.0\nid7057;1.0\nid7058;1.0\nid7059;1.0\nid7060;1.0\nid7061;1.0\nid7062;1.0\nid7063;1.0\nid7064;1.0\nid7065;1.0\nid7066;1.0\nid7067;1.0\nid7068;1.0\nid7069;1.0\nid7070;1.0\nid7071;1.0\nid7072;1.0\nid7073;1.0\nid7074;1.0\nid7075;1.0\nid7076;1.0\nid7077;1.0\nid7078;1.0\nid7079;1.0\nid7080;1.0\nid7081;1.0\nid7082;1.0\nid7083;1.0\nid7084;1.0\nid7085;1.0\nid7086;1.0\nid7087;1.0\nid7088;1.0\nid7089;1.0\nid7090;1.0\nid7091;1.0\nid7092;1.0\nid7093;1.0\nid7094;1.0\nid7095;1.0\nid7096;1.0\nid7097;1.0\nid7098;1.0\nid7099;1.0\nid7100;1.0\nid7101;1.0\nid7102;1.0\nid7103;1.0\nid7104;1.0\nid7105;1.0\nid7106;1.0\nid7107;1.0\nid7108;1.0\nid7109;1.0\nid7110;1.0\nid7111;1.0\nid7112;1.0\nid7113;1.0\nid7114;1.0\nid7115;1.0\nid7116;1.0\nid7117;1.0\nid7118;1.0\nid7119;1.0\nid7120;1.0\nid7121;1.0\nid7122;1.0\nid7123;1.0\nid7124;1.0\nid7125;1.0\nid7126;1.0\nid7127;1.0\nid7128;1.0\nid7129;1.0\nid7130;1.0\nid7131;1.0\nid7132;1.0\nid7133;1.0\nid7134;1.0\nid7135;1.0\nid7136;1.0\nid7137;1.0\nid7138;1.0\nid7139;1.0\nid7140;1.0\nid7141;1.0\nid7142;1.0\nid7143;1.0\nid7144;1.0\nid7145;1.0\nid7146;1.0\nid7147;1.0\nid7148;1.0\nid7149;1.0\nid7150;1.0\nid7151;1.0\nid7152;1.0\nid7153;1.0\nid7154;1.0\nid7155;1.0\nid7156;1.0\nid7157;1.0\nid7158;1.0\nid7159;1.0\nid7160;1.0\nid7161;1.0\nid7162;1.0\nid7163;1.0\nid7164;1.0\nid7165;1.0\nid7166;1.0\nid7167;1.0\nid7168;1.0\nid7169;1.0\nid7170;1.0\nid7171;1.0\nid7172;1.0\nid7173;1.0\nid7174;1.0\nid7175;1.0\nid7176;1.0\nid7177;1.0\nid7178;1.0\nid7179;1.0\nid7180;1.0\nid7181;1.0\nid7182;1.0\nid7183;1.0\nid7184;1.0\nid7185;1.0\nid7186;1.0\nid7187;1.0\nid7188;1.0\nid7189;1.0\nid7190;1.0\nid7191;1.0\nid7192;1.0\nid7193;1.0\nid7194;1.0\nid7195;1.0\nid7196;1.0\nid7197;1.0\nid7198;1.0\nid7199;1.0\nid7200;1.0\nid7201;1.0\nid7202;1.0\nid7203;1.0\nid7204;1.0\nid7205;1.0\nid7206;1.0\nid7207;1.0\nid7208;1.0\nid7209;1.0\nid7210;1.0\nid7211;1.0\nid7212;1.0\nid7213;1.0\nid7214;1.0\nid7215;1.0\nid7216;1.0\nid7217;1.0\nid7218;1.0\nid7219;1.0\nid7220;1.0\nid7221;1.0\nid7222;1.0\nid7223;1.0\nid7224;1.0\nid7225;1.0\nid7226;1.0\nid7227;1.0\nid7228;1.0\nid7229;1.0\nid7230;1.0\nid7231;1.0\nid7232;1.0\nid7233;1.0\nid7234;1.0\nid7235;1.0\nid7236;1.0\nid7237;1.0\nid7238;1.0\nid7239;1.0\nid7240;1.0\nid7241;1.0\nid7242;1.0\nid7243;1.0\nid7244;1.0\nid7245;1.0\nid7246;1.0\nid7247;1.0\nid7248;1.0\nid7249;1.0\nid7250;1.0\nid7251;1.0\nid7252;1.0\nid7253;1.0\nid7254;1.0\nid7255;1.0\nid7256;1.0\nid7257;1.0\nid7258;1.0\nid7259;1.0\nid7260;1.0\nid7261;1.0\nid7262;1.0\nid7263;1.0\nid7264;1.0\nid7265;1.0\nid7266;1.0\nid7267;1.0\nid7268;1.0\nid7269;1.0\nid7270;1.0\nid7271;1.0\nid7272;1.0\nid7273;1.0\nid7274;1.0\nid7275;1.0\nid7276;1.0\nid7277;1.0\nid7278;1.0\nid7279;1.0\nid7280;1.0\nid7281;1.0\nid7282;1.0\nid7283;1.0\nid7284;1.0\nid7285;1.0\nid7286;1.0\nid7287;1.0\nid7288;1.0\nid7289;1.0\nid7290;1.0\nid7291;1.0\nid7292;1.0\nid7293;1.0\nid7294;1.0\nid7295;1.0\nid7296;1.0\nid7297;1.0\nid7298;1.0\nid7299;1.0\nid7300;1.0\nid7301;1.0\nid7302;1.0\nid7303;1.0\nid7304;1.0\nid7305;1.0\nid7306;1.0\nid7307;1.0\nid7308;1.0\nid7309;1.0\nid7310;1.0\nid7311;1.0\nid7312;1.0\nid7313;1.0\nid7314;1.0\nid7315;1.0\nid7316;1.0\nid7317;1.0\nid7318;1.0\nid7319;1.0\nid7320;1.0\nid7321;1.0\nid7322;1.0\nid7323;1.0\nid7324;1.0\nid7325;1.0\nid7326;1.0\nid7327;1.0\nid7328;1.0\nid7329;1.0\nid7330;1.0\nid7331;1.0\nid7332;1.0\nid7333;1.0\nid7334;1.0\nid7335;1.0\nid7336;1.0\nid7337;1.0\nid7338;1.0\nid7339;1.0\nid7340;1.0\nid7341;1.0\nid7342;1.0\nid7343;1.0\nid7344;1.0\nid7345;1.0\nid7346;1.0\nid7347;1.0\nid7348;1.0\nid7349;1.0\nid7350;1.0\nid7351;1.0\nid7352;1.0\nid7353;1.0\nid7354;1.0\nid7355;1.0\nid7356;1.0\nid7357;1.0\nid7358;1.0\nid7359;1.0\nid7360;1.0\nid7361;1.0\nid7362;1.0\nid7363;1.0\nid7364;1.0\nid7365;1.0\nid7366;1.0\nid7367;1.0\nid7368;1.0\nid7369;1.0\nid7370;1.0\nid7371;1.0\nid7372;1.0\nid7373;1.0\nid7374;1.0\nid7375;1.0\nid7376;1.0\nid7377;1.0\nid7378;1.0\nid7379;1.0\nid7380;1.0\nid7381;1.0\nid7382;1.0\nid7383;1.0\nid7384;1.0\nid7385;1.0\nid7386;1.0\nid7387;1.0\nid7388;1.0\nid7389;1.0\nid7390;1.0\nid7391;1.0\nid7392;1.0\nid7393;1.0\nid7394;1.0\nid7395;1.0\nid7396;1.0\nid7397;1.0\nid7398;1.0\nid7399;1.0\nid7400;1.0\nid7401;1.0\nid7402;1.0\nid7403;1.0\nid7404;1.0\nid7405;1.0\nid7406;1.0\nid7407;1.0\nid7408;1.0\nid7409;1.0\nid7410;1.0\nid7411;1.0\nid7412;1.0\nid7413;1.0\nid7414;1.0\nid7415;1.0\nid7416;1.0\nid7417;1.0\nid7418;1.0\nid7419;1.0\nid7420;1.0\nid7421;1.0\nid7422;1.0\nid7423;1.0\nid7424;1.0\nid7425;1.0\nid7426;1.0\nid7427;1.0\nid7428;1.0\nid7429;1.0\nid7430;1.0\nid7431;1.0\nid7432;1.0\nid7433;1.0\nid7434;1.0\nid7435;1.0\nid7436;1.0\nid7437;1.0\nid7438;1.0\nid7439;1.0\nid7440;1.0\nid7441;1.0\nid7442;1.0\nid7443;1.0\nid7444;1.0\nid7445;1.0\nid7446;1.0\nid7447;1.0\nid7448;1.0\nid7449;1.0\nid7450;1.0\nid7451;1.0\nid7452;1.0\nid7453;1.0\nid7454;1.0\nid7455;1.0\nid7456;1.0\nid7457;1.0\nid7458;1.0\nid7459;1.0\nid7460;1.0\nid7461;1.0\nid7462;1.0\nid7463;1.0\nid7464;1.0\nid7465;1.0\nid7466;1.0\nid7467;1.0\nid7468;1.0\nid7469;1.0\nid7470;1.0\nid7471;1.0\nid7472;1.0\nid7473;1.0\nid7474;1.0\nid7475;1.0\nid7476;1.0\nid7477;1.0\nid7478;1.0\nid7479;1.0\nid7480;1.0\nid7481;1.0\nid7482;1.0\nid7483;1.0\nid7484;1.0\nid7485;1.0\nid7486;1.0\nid7487;1.0\nid7488;1.0\nid7489;1.0\nid7490;1.0\nid7491;1.0\nid7492;1.0\nid7493;1.0\nid7494;1.0\nid7495;1.0\nid7496;1.0\nid7497;1.0\nid7498;1.0\nid7499;1.0\nid7500;1.0\nid7501;1.0\nid7502;1.0\nid7503;1.0\nid7504;1.0\nid7505;1.0\nid7506;1.0\nid7507;1.0\nid7508;1.0\nid7509;1.0\nid7510;1.0\nid7511;1.0\nid7512;1.0\nid7513;1.0\nid7514;1.0\nid7515;1.0\nid7516;1.0\nid7517;1.0\nid7518;1.0\nid7519;1.0\nid7520;1.0\nid7521;1.0\nid7522;1.0\nid7523;1.0\nid7524;1.0\nid7525;1.0\nid7526;1.0\nid7527;1.0\nid7528;1.0\nid7529;1.0\nid7530;1.0\nid7531;1.0\nid7532;1.0\nid7533;1.0\nid7534;1.0\nid7535;1.0\nid7536;1.0\nid7537;1.0\nid7538;1.0\nid7539;1.0\nid7540;1.0\nid7541;1.0\nid7542;1.0\nid7543;1.0\nid7544;1.0\nid7545;1.0\nid7546;1.0\nid7547;1.0\nid7548;1.0\nid7549;1.0\nid7550;1.0\nid7551;1.0\nid7552;1.0\nid7553;1.0\nid7554;1.0\nid7555;1.0\nid7556;1.0\nid7557;1.0\nid7558;1.0\nid7559;1.0\nid7560;1.0\nid7561;1.0\nid7562;1.0\nid7563;1.0\nid7564;1.0\nid7565;1.0\nid7566;1.0\nid7567;1.0\nid7568;1.0\nid7569;1.0\nid7570;1.0\nid7571;1.0\nid7572;1.0\nid7573;1.0\nid7574;1.0\nid7575;1.0\nid7576;1.0\nid7577;1.0\nid7578;1.0\nid7579;1.0\nid7580;1.0\nid7581;1.0\nid7582;1.0\nid7583;1.0\nid7584;1.0\nid7585;1.0\nid7586;1.0\nid7587;1.0\nid7588;1.0\nid7589;1.0\nid7590;1.0\nid7591;1.0\nid7592;1.0\nid7593;1.0\nid7594;1.0\nid7595;1.0\nid7596;1.0\nid7597;1.0\nid7598;1.0\nid7599;1.0\nid7600;1.0\nid7601;1.0\nid7602;1.0\nid7603;1.0\nid7604;1.0\nid7605;1.0\nid7606;1.0\nid7607;1.0\nid7608;1.0\nid7609;1.0\nid7610;1.0\nid7611;1.0\nid7612;1.0\nid7613;1.0\nid7614;1.0\nid7615;1.0\nid7616;1.0\nid7617;1.0\nid7618;1.0\nid7619;1.0\nid7620;1.0\nid7621;1.0\nid7622;1.0\nid7623;1.0\nid7624;1.0\nid7625;1.0\nid7626;1.0\nid7627;1.0\nid7628;1.0\nid7629;1.0\nid7630;1.0\nid7631;1.0\nid7632;1.0\nid7633;1.0\nid7634;1.0\nid7635;1.0\nid7636;1.0\nid7637;1.0\nid7638;1.0\nid7639;1.0\nid7640;1.0\nid7641;1.0\nid7642;1.0\nid7643;1.0\nid7644;1.0\nid7645;1.0\nid7646;1.0\nid7647;1.0\nid7648;1.0\nid7649;1.0\nid7650;1.0\nid7651;1.0\nid7652;1.0\nid7653;1.0\nid7654;1.0\nid7655;1.0\nid7656;1.0\nid7657;1.0\nid7658;1.0\nid7659;1.0\nid7660;1.0\nid7661;1.0\nid7662;1.0\nid7663;1.0\nid7664;1.0\nid7665;1.0\nid7666;1.0\nid7667;1.0\nid7668;1.0\nid7669;1.0\nid7670;1.0\nid7671;1.0\nid7672;1.0\nid7673;1.0\nid7674;1.0\nid7675;1.0\nid7676;1.0\nid7677;1.0\nid7678;1.0\nid7679;1.0\nid7680;1.0\nid7681;1.0\nid7682;1.0\nid7683;1.0\nid7684;1.0\nid7685;1.0\nid7686;1.0\nid7687;1.0\nid7688;1.0\nid7689;1.0\nid7690;1.0\nid7691;1.0\nid7692;1.0\nid7693;1.0\nid7694;1.0\nid7695;1.0\nid7696;1.0\nid7697;1.0\nid7698;1.0\nid7699;1.0\nid7700;1.0\nid7701;1.0\nid7702;1.0\nid7703;1.0\nid7704;1.0\nid7705;1.0\nid7706;1.0\nid7707;1.0\nid7708;1.0\nid7709;1.0\nid7710;1.0\nid7711;1.0\nid7712;1.0\nid7713;1.0\nid7714;1.0\nid7715;1.0\nid7716;1.0\nid7717;1.0\nid7718;1.0\nid7719;1.0\nid7720;1.0\nid7721;1.0\nid7722;1.0\nid7723;1.0\nid7724;1.0\nid7725;1.0\nid7726;1.0\nid7727;1.0\nid7728;1.0\nid7729;1.0\nid7730;1.0\nid7731;1.0\nid7732;1.0\nid7733;1.0\nid7734;1.0\nid7735;1.0\nid7736;1.0\nid7737;1.0\nid7738;1.0\nid7739;1.0\nid7740;1.0\nid7741;1.0\nid7742;1.0\nid7743;1.0\nid7744;1.0\nid7745;1.0\nid7746;1.0\nid7747;1.0\nid7748;1.0\nid7749;1.0\nid7750;1.0\nid7751;1.0\nid7752;1.0\nid7753;1.0\nid7754;1.0\nid7755;1.0\nid7756;1.0\nid7757;1.0\nid7758;1.0\nid7759;1.0\nid7760;1.0\nid7761;1.0\nid7762;1.0\nid7763;1.0\nid7764;1.0\nid7765;1.0\nid7766;1.0\nid7767;1.0\nid7768;1.0\nid7769;1.0\nid7770;1.0\nid7771;1.0\nid7772;1.0\nid7773;1.0\nid7774;1.0\nid7775;1.0\nid7776;1.0\nid7777;1.0\nid7778;1.0\nid7779;1.0\nid7780;1.0\nid7781;1.0\nid7782;1.0\nid7783;1.0\nid7784;1.0\nid7785;1.0\nid7786;1.0\nid7787;1.0\nid7788;1.0\nid7789;1.0\nid7790;1.0\nid7791;1.0\nid7792;1.0\nid7793;1.0\nid7794;1.0\nid7795;1.0\nid7796;1.0\nid7797;1.0\nid7798;1.0\nid7799;1.0\nid7800;1.0\nid7801;1.0\nid7802;1.0\nid7803;1.0\nid7804;1.0\nid7805;1.0\nid7806;1.0\nid7807;1.0\nid7808;1.0\nid7809;1.0\nid7810;1.0\nid7811;1.0\nid7812;1.0\nid7813;1.0\nid7814;1.0\nid7815;1.0\nid7816;1.0\nid7817;1.0\nid7818;1.0\nid7819;1.0\nid7820;1.0\nid7821;1.0\nid7822;1.0\nid7823;1.0\nid7824;1.0\nid7825;1.0\nid7826;1.0\nid7827;1.0\nid7828;1.0\nid7829;1.0\nid7830;1.0\nid7831;1.0\nid7832;1.0\nid7833;1.0\nid7834;1.0\nid7835;1.0\nid7836;1.0\nid7837;1.0\nid7838;1.0\nid7839;1.0\nid7840;1.0\nid7841;1.0\nid7842;1.0\nid7843;1.0\nid7844;1.0\nid7845;1.0\nid7846;1.0\nid7847;1.0\nid7848;1.0\nid7849;1.0\nid7850;1.0\nid7851;1.0\nid7852;1.0\nid7853;1.0\nid7854;1.0\nid7855;1.0\nid7856;1.0\nid7857;1.0\nid7858;1.0\nid7859;1.0\nid7860;1.0\nid7861;1.0\nid7862;1.0\nid7863;1.0\nid7864;1.0\nid7865;1.0\nid7866;1.0\nid7867;1.0\nid7868;1.0\nid7869;1.0\nid7870;1.0\nid7871;1.0\nid7872;1.0\nid7873;1.0\nid7874;1.0\nid7875;1.0\nid7876;1.0\nid7877;1.0\nid7878;1.0\nid7879;1.0\nid7880;1.0\nid7881;1.0\nid7882;1.0\nid7883;1.0\nid7884;1.0\nid7885;1.0\nid7886;1.0\nid7887;1.0\nid7888;1.0\nid7889;1.0\nid7890;1.0\nid7891;1.0\nid7892;1.0\nid7893;1.0\nid7894;1.0\nid7895;1.0\nid7896;1.0\nid7897;1.0\nid7898;1.0\nid7899;1.0\nid7900;1.0\nid7901;1.0\nid7902;1.0\nid7903;1.0\nid7904;1.0\nid7905;1.0\nid7906;1.0\nid7907;1.0\nid7908;1.0\nid7909;1.0\nid7910;1.0\nid7911;1.0\nid7912;1.0\nid7913;1.0\nid7914;1.0\nid7915;1.0\nid7916;1.0\nid7917;1.0\nid7918;1.0\nid7919;1.0\nid7920;1.0\nid7921;1.0\nid7922;1.0\nid7923;1.0\nid7924;1.0\nid7925;1.0\nid7926;1.0\nid7927;1.0\nid7928;1.0\nid7929;1.0\nid7930;1.0\nid7931;1.0\nid7932;1.0\nid7933;1.0\nid7934;1.0\nid7935;1.0\nid7936;1.0\nid7937;1.0\nid7938;1.0\nid7939;1.0\nid7940;1.0\nid7941;1.0\nid7942;1.0\nid7943;1.0\nid7944;1.0\nid7945;1.0\nid7946;1.0\nid7947;1.0\nid7948;1.0\nid7949;1.0\nid7950;1.0\nid7951;1.0\nid7952;1.0\nid7953;1.0\nid7954;1.0\nid7955;1.0\nid7956;1.0\nid7957;1.0\nid7958;1.0\nid7959;1.0\nid7960;1.0\nid7961;1.0\nid7962;1.0\nid7963;1.0\nid7964;1.0\nid7965;1.0\nid7966;1.0\nid7967;1.0\nid7968;1.0\nid7969;1.0\nid7970;1.0\nid7971;1.0\nid7972;1.0\nid7973;1.0\nid7974;1.0\nid7975;1.0\nid7976;1.0\nid7977;1.0\nid7978;1.0\nid7979;1.0\nid7980;1.0\nid7981;1.0\nid7982;1.0\nid7983;1.0\nid7984;1.0\nid7985;1.0\nid7986;1.0\nid7987;1.0\nid7988;1.0\nid7989;1.0\nid7990;1.0\nid7991;1.0\nid7992;1.0\nid7993;1.0\nid7994;1.0\nid7995;1.0\nid7996;1.0\nid7997;1.0\nid7998;1.0\nid7999;1.0\nid8000;1.0\nid8001;1.0\nid8002;1.0\nid8003;1.0\nid8004;1.0\nid8005;1.0\nid8006;1.0\nid8007;1.0\nid8008;1.0\nid8009;1.0\nid8010;1.0\nid8011;1.0\nid8012;1.0\nid8013;1.0\nid8014;1.0\nid8015;1.0\nid8016;1.0\nid8017;1.0\nid8018;1.0\nid8019;1.0\nid8020;1.0\nid8021;1.0\nid8022;1.0\nid8023;1.0\nid8024;1.0\nid8025;1.0\nid8026;1.0\nid8027;1.0\nid8028;1.0\nid8029;1.0\nid8030;1.0\nid8031;1.0\nid8032;1.0\nid8033;1.0\nid8034;1.0\nid8035;1.0\nid8036;1.0\nid8037;1.0\nid8038;1.0\nid8039;1.0\nid8040;1.0\nid8041;1.0\nid8042;1.0\nid8043;1.0\nid8044;1.0\nid8045;1.0\nid8046;1.0\nid8047;1.0\nid8048;1.0\nid8049;1.0\nid8050;1.0\nid8051;1.0\nid8052;1.0\nid8053;1.0\nid8054;1.0\nid8055;1.0\nid8056;1.0\nid8057;1.0\nid8058;1.0\nid8059;1.0\nid8060;1.0\nid8061;1.0\nid8062;1.0\nid8063;1.0\nid8064;1.0\nid8065;1.0\nid8066;1.0\nid8067;1.0\nid8068;1.0\nid8069;1.0\nid8070;1.0\nid8071;1.0\nid8072;1.0\nid8073;1.0\nid8074;1.0\nid8075;1.0\nid8076;1.0\nid8077;1.0\nid8078;1.0\nid8079;1.0\nid8080;1.0\nid8081;1.0\nid8082;1.0\nid8083;1.0\nid8084;1.0\nid8085;1.0\nid8086;1.0\nid8087;1.0\nid8088;1.0\nid8089;1.0\nid8090;1.0\nid8091;1.0\nid8092;1.0\nid8093;1.0\nid8094;1.0\nid8095;1.0\nid8096;1.0\nid8097;1.0\nid8098;1.0\nid8099;1.0\nid8100;1.0\nid8101;1.0\nid8102;1.0\nid8103;1.0\nid8104;1.0\nid8105;1.0\nid8106;1.0\nid8107;1.0\nid8108;1.0\nid8109;1.0\nid8110;1.0\nid8111;1.0\nid8112;1.0\nid8113;1.0\nid8114;1.0\nid8115;1.0\nid8116;1.0\nid8117;1.0\nid8118;1.0\nid8119;1.0\nid8120;1.0\nid8121;1.0\nid8122;1.0\nid8123;1.0\nid8124;1.0\nid8125;1.0\nid8126;1.0\nid8127;1.0\nid8128;1.0\nid8129;1.0\nid8130;1.0\nid8131;1.0\nid8132;1.0\nid8133;1.0\nid8134;1.0\nid8135;1.0\nid8136;1.0\nid8137;1.0\nid8138;1.0\nid8139;1.0\nid8140;1.0\nid8141;1.0\nid8142;1.0\nid8143;1.0\nid8144;1.0\nid8145;1.0\nid8146;1.0\nid8147;1.0\nid8148;1.0\nid8149;1.0\nid8150;1.0\nid8151;1.0\nid8152;1.0\nid8153;1.0\nid8154;1.0\nid8155;1.0\nid8156;1.0\nid8157;1.0\nid8158;1.0\nid8159;1.0\nid8160;1.0\nid8161;1.0\nid8162;1.0\nid8163;1.0\nid8164;1.0\nid8165;1.0\nid8166;1.0\nid8167;1.0\nid8168;1.0\nid8169;1.0\nid8170;1.0\nid8171;1.0\nid8172;1.0\nid8173;1.0\nid8174;1.0\nid8175;1.0\nid8176;1.0\nid8177;1.0\nid8178;1.0\nid8179;1.0\nid8180;1.0\nid8181;1.0\nid8182;1.0\nid8183;1.0\nid8184;1.0\nid8185;1.0\nid8186;1.0\nid8187;1.0\nid8188;1.0\nid8189;1.0\nid8190;1.0\nid8191;1.0\nid8192;1.0\nid8193;1.0\nid8194;1.0\nid8195;1.0\nid8196;1.0\nid8197;1.0\nid8198;1.0\nid8199;1.0\nid8200;1.0\nid8201;1.0\nid8202;1.0\nid8203;1.0\nid8204;1.0\nid8205;1.0\nid8206;1.0\nid8207;1.0\nid8208;1.0\nid8209;1.0\nid8210;1.0\nid8211;1.0\nid8212;1.0\nid8213;1.0\nid8214;1.0\nid8215;1.0\nid8216;1.0\nid8217;1.0\nid8218;1.0\nid8219;1.0\nid8220;1.0\nid8221;1.0\nid8222;1.0\nid8223;1.0\nid8224;1.0\nid8225;1.0\nid8226;1.0\nid8227;1.0\nid8228;1.0\nid8229;1.0\nid8230;1.0\nid8231;1.0\nid8232;1.0\nid8233;1.0\nid8234;1.0\nid8235;1.0\nid8236;1.0\nid8237;1.0\nid8238;1.0\nid8239;1.0\nid8240;1.0\nid8241;1.0\nid8242;1.0\nid8243;1.0\nid8244;1.0\nid8245;1.0\nid8246;1.0\nid8247;1.0\nid8248;1.0\nid8249;1.0\nid8250;1.0\nid8251;1.0\nid8252;1.0\nid8253;1.0\nid8254;1.0\nid8255;1.0\nid8256;1.0\nid8257;1.0\nid8258;1.0\nid8259;1.0\nid8260;1.0\nid8261;1.0\nid8262;1.0\nid8263;1.0\nid8264;1.0\nid8265;1.0\nid8266;1.0\nid8267;1.0\nid8268;1.0\nid8269;1.0\nid8270;1.0\nid8271;1.0\nid8272;1.0\nid8273;1.0\nid8274;1.0\nid8275;1.0\nid8276;1.0\nid8277;1.0\nid8278;1.0\nid8279;1.0\nid8280;1.0\nid8281;1.0\nid8282;1.0\nid8283;1.0\nid8284;1.0\nid8285;1.0\nid8286;1.0\nid8287;1.0\nid8288;1.0\nid8289;1.0\nid8290;1.0\nid8291;1.0\nid8292;1.0\nid8293;1.0\nid8294;1.0\nid8295;1.0\nid8296;1.0\nid8297;1.0\nid8298;1.0\nid8299;1.0\nid8300;1.0\nid8301;1.0\nid8302;1.0\nid8303;1.0\nid8304;1.0\nid8305;1.0\nid8306;1.0\nid8307;1.0\nid8308;1.0\nid8309;1.0\nid8310;1.0\nid8311;1.0\nid8312;1.0\nid8313;1.0\nid8314;1.0\nid8315;1.0\nid8316;1.0\nid8317;1.0\nid8318;1.0\nid8319;1.0\nid8320;1.0\nid8321;1.0\nid8322;1.0\nid8323;1.0\nid8324;1.0\nid8325;1.0\nid8326;1.0\nid8327;1.0\nid8328;1.0\nid8329;1.0\nid8330;1.0\nid8331;1.0\nid8332;1.0\nid8333;1.0\nid8334;1.0\nid8335;1.0\nid8336;1.0\nid8337;1.0\nid8338;1.0\nid8339;1.0\nid8340;1.0\nid8341;1.0\nid8342;1.0\nid8343;1.0\nid8344;1.0\nid8345;1.0\nid8346;1.0\nid8347;1.0\nid8348;1.0\nid8349;1.0\nid8350;1.0\nid8351;1.0\nid8352;1.0\nid8353;1.0\nid8354;1.0\nid8355;1.0\nid8356;1.0\nid8357;1.0\nid8358;1.0\nid8359;1.0\nid8360;1.0\nid8361;1.0\nid8362;1.0\nid8363;1.0\nid8364;1.0\nid8365;1.0\nid8366;1.0\nid8367;1.0\nid8368;1.0\nid8369;1.0\nid8370;1.0\nid8371;1.0\nid8372;1.0\nid8373;1.0\nid8374;1.0\nid8375;1.0\nid8376;1.0\nid8377;1.0\nid8378;1.0\nid8379;1.0\nid8380;1.0\nid8381;1.0\nid8382;1.0\nid8383;1.0\nid8384;1.0\nid8385;1.0\nid8386;1.0\nid8387;1.0\nid8388;1.0\nid8389;1.0\nid8390;1.0\nid8391;1.0\nid8392;1.0\nid8393;1.0\nid8394;1.0\nid8395;1.0\nid8396;1.0\nid8397;1.0\nid8398;1.0\nid8399;1.0\nid8400;1.0\nid8401;1.0\nid8402;1.0\nid8403;1.0\nid8404;1.0\nid8405;1.0\nid8406;1.0\nid8407;1.0\nid8408;1.0\nid8409;1.0\nid8410;1.0\nid8411;1.0\nid8412;1.0\nid8413;1.0\nid8414;1.0\nid8415;1.0\nid8416;1.0\nid8417;1.0\nid8418;1.0\nid8419;1.0\nid8420;1.0\nid8421;1.0\nid8422;1.0\nid8423;1.0\nid8424;1.0\nid8425;1.0\nid8426;1.0\nid8427;1.0\nid8428;1.0\nid8429;1.0\nid8430;1.0\nid8431;1.0\nid8432;1.0\nid8433;1.0\nid8434;1.0\nid8435;1.0\nid8436;1.0\nid8437;1.0\nid8438;1.0\nid8439;1.0\nid8440;1.0\nid8441;1.0\nid8442;1.0\nid8443;1.0\nid8444;1.0\nid8445;1.0\nid8446;1.0\nid8447;1.0\nid8448;1.0\nid8449;1.0\nid8450;1.0\nid8451;1.0\nid8452;1.0\nid8453;1.0\nid8454;1.0\nid8455;1.0\nid8456;1.0\nid8457;1.0\nid8458;1.0\nid8459;1.0\nid8460;1.0\nid8461;1.0\nid8462;1.0\nid8463;1.0\nid8464;1.0\nid8465;1.0\nid8466;1.0\nid8467;1.0\nid8468;1.0\nid8469;1.0\nid8470;1.0\nid8471;1.0\nid8472;1.0\nid8473;1.0\nid8474;1.0\nid8475;1.0\nid8476;1.0\nid8477;1.0\nid8478;1.0\nid8479;1.0\nid8480;1.0\nid8481;1.0\nid8482;1.0\nid8483;1.0\nid8484;1.0\nid8485;1.0\nid8486;1.0\nid8487;1.0\nid8488;1.0\nid8489;1.0\nid8490;1.0\nid8491;1.0\nid8492;1.0\nid8493;1.0\nid8494;1.0\nid8495;1.0\nid8496;1.0\nid8497;1.0\nid8498;1.0\nid8499;1.0\nid8500;1.0\nid8501;1.0\nid8502;1.0\nid8503;1.0\nid8504;1.0\nid8505;1.0\nid8506;1.0\nid8507;1.0\nid8508;1.0\nid8509;1.0\nid8510;1.0\nid8511;1.0\nid8512;1.0\nid8513;1.0\nid8514;1.0\nid8515;1.0\nid8516;1.0\nid8517;1.0\nid8518;1.0\nid8519;1.0\nid8520;1.0\nid8521;1.0\nid8522;1.0\nid8523;1.0\nid8524;1.0\nid8525;1.0\nid8526;1.0\nid8527;1.0\nid8528;1.0\nid8529;1.0\nid8530;1.0\nid8531;1.0\nid8532;1.0\nid8533;1.0\nid8534;1.0\nid8535;1.0\nid8536;1.0\nid8537;1.0\nid8538;1.0\nid8539;1.0\nid8540;1.0\nid8541;1.0\nid8542;1.0\nid8543;1.0\nid8544;1.0\nid8545;1.0\nid8546;1.0\nid8547;1.0\nid8548;1.0\nid8549;1.0\nid8550;1.0\nid8551;1.0\nid8552;1.0\nid8553;1.0\nid8554;1.0\nid8555;1.0\nid8556;1.0\nid8557;1.0\nid8558;1.0\nid8559;1.0\nid8560;1.0\nid8561;1.0\nid8562;1.0\nid8563;1.0\nid8564;1.0\nid8565;1.0\nid8566;1.0\nid8567;1.0\nid8568;1.0\nid8569;1.0\nid8570;1.0\nid8571;1.0\nid8572;1.0\nid8573;1.0\nid8574;1.0\nid8575;1.0\nid8576;1.0\nid8577;1.0\nid8578;1.0\nid8579;1.0\nid8580;1.0\nid8581;1.0\nid8582;1.0\nid8583;1.0\nid8584;1.0\nid8585;1.0\nid8586;1.0\nid8587;1.0\nid8588;1.0\nid8589;1.0\nid8590;1.0\nid8591;1.0\nid8592;1.0\nid8593;1.0\nid8594;1.0\nid8595;1.0\nid8596;1.0\nid8597;1.0\nid8598;1.0\nid8599;1.0\nid8600;1.0\nid8601;1.0\nid8602;1.0\nid8603;1.0\nid8604;1.0\nid8605;1.0\nid8606;1.0\nid8607;1.0\nid8608;1.0\nid8609;1.0\nid8610;1.0\nid8611;1.0\nid8612;1.0\nid8613;1.0\nid8614;1.0\nid8615;1.0\nid8616;1.0\nid8617;1.0\nid8618;1.0\nid8619;1.0\nid8620;1.0\nid8621;1.0\nid8622;1.0\nid8623;1.0\nid8624;1.0\nid8625;1.0\nid8626;1.0\nid8627;1.0\nid8628;1.0\nid8629;1.0\nid8630;1.0\nid8631;1.0\nid8632;1.0\nid8633;1.0\nid8634;1.0\nid8635;1.0\nid8636;1.0\nid8637;1.0\nid8638;1.0\nid8639;1.0\nid8640;1.0\nid8641;1.0\nid8642;1.0\nid8643;1.0\nid8644;1.0\nid8645;1.0\nid8646;1.0\nid8647;1.0\nid8648;1.0\nid8649;1.0\nid8650;1.0\nid8651;1.0\nid8652;1.0\nid8653;1.0\nid8654;1.0\nid8655;1.0\nid8656;1.0\nid8657;1.0\nid8658;1.0\nid8659;1.0\nid8660;1.0\nid8661;1.0\nid8662;1.0\nid8663;1.0\nid8664;1.0\nid8665;1.0\nid8666;1.0\nid8667;1.0\nid8668;1.0\nid8669;1.0\nid8670;1.0\nid8671;1.0\nid8672;1.0\nid8673;1.0\nid8674;1.0\nid8675;1.0\nid8676;1.0\nid8677;1.0\nid8678;1.0\nid8679;1.0\nid8680;1.0\nid8681;1.0\nid8682;1.0\nid8683;1.0\nid8684;1.0\nid8685;1.0\nid8686;1.0\nid8687;1.0\nid8688;1.0\nid8689;1.0\nid8690;1.0\nid8691;1.0\nid8692;1.0\nid8693;1.0\nid8694;1.0\nid8695;1.0\nid8696;1.0\nid8697;1.0\nid8698;1.0\nid8699;1.0\nid8700;1.0\nid8701;1.0\nid8702;1.0\nid8703;1.0\nid8704;1.0\nid8705;1.0\nid8706;1.0\nid8707;1.0\nid8708;1.0\nid8709;1.0\nid8710;1.0\nid8711;1.0\nid8712;1.0\nid8713;1.0\nid8714;1.0\nid8715;1.0\nid8716;1.0\nid8717;1.0\nid8718;1.0\nid8719;1.0\nid8720;1.0\nid8721;1.0\nid8722;1.0\nid8723;1.0\nid8724;1.0\nid8725;1.0\nid8726;1.0\nid8727;1.0\nid8728;1.0\nid8729;1.0\nid8730;1.0\nid8731;1.0\nid8732;1.0\nid8733;1.0\nid8734;1.0\nid8735;1.0\nid8736;1.0\nid8737;1.0\nid8738;1.0\nid8739;1.0\nid8740;1.0\nid8741;1.0\nid8742;1.0\nid8743;1.0\nid8744;1.0\nid8745;1.0\nid8746;1.0\nid8747;1.0\nid8748;1.0\nid8749;1.0\nid8750;1.0\nid8751;1.0\nid8752;1.0\nid8753;1.0\nid8754;1.0\nid8755;1.0\nid8756;1.0\nid8757;1.0\nid8758;1.0\nid8759;1.0\nid8760;1.0\nid8761;1.0\nid8762;1.0\nid8763;1.0\nid8764;1.0\nid8765;1.0\nid8766;1.0\nid8767;1.0\nid8768;1.0\nid8769;1.0\nid8770;1.0\nid8771;1.0\nid8772;1.0\nid8773;1.0\nid8774;1.0\nid8775;1.0\nid8776;1.0\nid8777;1.0\nid8778;1.0\nid8779;1.0\nid8780;1.0\nid8781;1.0\nid8782;1.0\nid8783;1.0\nid8784;1.0\nid8785;1.0\nid8786;1.0\nid8787;1.0\nid8788;1.0\nid8789;1.0\nid8790;1.0\nid8791;1.0\nid8792;1.0\nid8793;1.0\nid8794;1.0\nid8795;1.0\nid8796;1.0\nid8797;1.0\nid8798;1.0\nid8799;1.0\nid8800;1.0\nid8801;1.0\nid8802;1.0\nid8803;1.0\nid8804;1.0\nid8805;1.0\nid8806;1.0\nid8807;1.0\nid8808;1.0\nid8809;1.0\nid8810;1.0\nid8811;1.0\nid8812;1.0\nid8813;1.0\nid8814;1.0\nid8815;1.0\nid8816;1.0\nid8817;1.0\nid8818;1.0\nid8819;1.0\nid8820;1.0\nid8821;1.0\nid8822;1.0\nid8823;1.0\nid8824;1.0\nid8825;1.0\nid8826;1.0\nid8827;1.0\nid8828;1.0\nid8829;1.0\nid8830;1.0\nid8831;1.0\nid8832;1.0\nid8833;1.0\nid8834;1.0\nid8835;1.0\nid8836;1.0\nid8837;1.0\nid8838;1.0\nid8839;1.0\nid8840;1.0\nid8841;1.0\nid8842;1.0\nid8843;1.0\nid8844;1.0\nid8845;1.0\nid8846;1.0\nid8847;1.0\nid8848;1.0\nid8849;1.0\nid8850;1.0\nid8851;1.0\nid8852;1.0\nid8853;1.0\nid8854;1.0\nid8855;1.0\nid8856;1.0\nid8857;1.0\nid8858;1.0\nid8859;1.0\nid8860;1.0\nid8861;1.0\nid8862;1.0\nid8863;1.0\nid8864;1.0\nid8865;1.0\nid8866;1.0\nid8867;1.0\nid8868;1.0\nid8869;1.0\nid8870;1.0\nid8871;1.0\nid8872;1.0\nid8873;1.0\nid8874;1.0\nid8875;1.0\nid8876;1.0\nid8877;1.0\nid8878;1.0\nid8879;1.0\nid8880;1.0\nid8881;1.0\nid8882;1.0\nid8883;1.0\nid8884;1.0\nid8885;1.0\nid8886;1.0\nid8887;1.0\nid8888;1.0\nid8889;1.0\nid8890;1.0\nid8891;1.0\nid8892;1.0\nid8893;1.0\nid8894;1.0\nid8895;1.0\nid8896;1.0\nid8897;1.0\nid8898;1.0\nid8899;1.0\nid8900;1.0\nid8901;1.0\nid8902;1.0\nid8903;1.0\nid8904;1.0\nid8905;1.0\nid8906;1.0\nid8907;1.0\nid8908;1.0\nid8909;1.0\nid8910;1.0\nid8911;1.0\nid8912;1.0\nid8913;1.0\nid8914;1.0\nid8915;1.0\nid8916;1.0\nid8917;1.0\nid8918;1.0\nid8919;1.0\nid8920;1.0\nid8921;1.0\nid8922;1.0\nid8923;1.0\nid8924;1.0\nid8925;1.0\nid8926;1.0\nid8927;1.0\nid8928;1.0\nid8929;1.0\nid8930;1.0\nid8931;1.0\nid8932;1.0\nid8933;1.0\nid8934;1.0\nid8935;1.0\nid8936;1.0\nid8937;1.0\nid8938;1.0\nid8939;1.0\nid8940;1.0\nid8941;1.0\nid8942;1.0\nid8943;1.0\nid8944;1.0\nid8945;1.0\nid8946;1.0\nid8947;1.0\nid8948;1.0\nid8949;1.0\nid8950;1.0\nid8951;1.0\nid8952;1.0\nid8953;1.0\nid8954;1.0\nid8955;1.0\nid8956;1.0\nid8957;1.0\nid8958;1.0\nid8959;1.0\nid8960;1.0\nid8961;1.0\nid8962;1.0\nid8963;1.0\nid8964;1.0\nid8965;1.0\nid8966;1.0\nid8967;1.0\nid8968;1.0\nid8969;1.0\nid8970;1.0\nid8971;1.0\nid8972;1.0\nid8973;1.0\nid8974;1.0\nid8975;1.0\nid8976;1.0\nid8977;1.0\nid8978;1.0\nid8979;1.0\nid8980;1.0\nid8981;1.0\nid8982;1.0\nid8983;1.0\nid8984;1.0\nid8985;1.0\nid8986;1.0\nid8987;1.0\nid8988;1.0\nid8989;1.0\nid8990;1.0\nid8991;1.0\nid8992;1.0\nid8993;1.0\nid8994;1.0\nid8995;1.0\nid8996;1.0\nid8997;1.0\nid8998;1.0\nid8999;1.0\nid9000;1.0\nid9001;1.0\nid9002;1.0\nid9003;1.0\nid9004;1.0\nid9005;1.0\nid9006;1.0\nid9007;1.0\nid9008;1.0\nid9009;1.0\nid9010;1.0\nid9011;1.0\nid9012;1.0\nid9013;1.0\nid9014;1.0\nid9015;1.0\nid9016;1.0\nid9017;1.0\nid9018;1.0\nid9019;1.0\nid9020;1.0\nid9021;1.0\nid9022;1.0\nid9023;1.0\nid9024;1.0\nid9025;1.0\nid9026;1.0\nid9027;1.0\nid9028;1.0\nid9029;1.0\nid9030;1.0\nid9031;1.0\nid9032;1.0\nid9033;1.0\nid9034;1.0\nid9035;1.0\nid9036;1.0\nid9037;1.0\nid9038;1.0\nid9039;1.0\nid9040;1.0\nid9041;1.0\nid9042;1.0\nid9043;1.0\nid9044;1.0\nid9045;1.0\nid9046;1.0\nid9047;1.0\nid9048;1.0\nid9049;1.0\nid9050;1.0\nid9051;1.0\nid9052;1.0\nid9053;1.0\nid9054;1.0\nid9055;1.0\nid9056;1.0\nid9057;1.0\nid9058;1.0\nid9059;1.0\nid9060;1.0\nid9061;1.0\nid9062;1.0\nid9063;1.0\nid9064;1.0\nid9065;1.0\nid9066;1.0\nid9067;1.0\nid9068;1.0\nid9069;1.0\nid9070;1.0\nid9071;1.0\nid9072;1.0\nid9073;1.0\nid9074;1.0\nid9075;1.0\nid9076;1.0\nid9077;1.0\nid9078;1.0\nid9079;1.0\nid9080;1.0\nid9081;1.0\nid9082;1.0\nid9083;1.0\nid9084;1.0\nid9085;1.0\nid9086;1.0\nid9087;1.0\nid9088;1.0\nid9089;1.0\nid9090;1.0\nid9091;1.0\nid9092;1.0\nid9093;1.0\nid9094;1.0\nid9095;1.0\nid9096;1.0\nid9097;1.0\nid9098;1.0\nid9099;1.0\nid9100;1.0\nid9101;1.0\nid9102;1.0\nid9103;1.0\nid9104;1.0\nid9105;1.0\nid9106;1.0\nid9107;1.0\nid9108;1.0\nid9109;1.0\nid9110;1.0\nid9111;1.0\nid9112;1.0\nid9113;1.0\nid9114;1.0\nid9115;1.0\nid9116;1.0\nid9117;1.0\nid9118;1.0\nid9119;1.0\nid9120;1.0\nid9121;1.0\nid9122;1.0\nid9123;1.0\nid9124;1.0\nid9125;1.0\nid9126;1.0\nid9127;1.0\nid9128;1.0\nid9129;1.0\nid9130;1.0\nid9131;1.0\nid9132;1.0\nid9133;1.0\nid9134;1.0\nid9135;1.0\nid9136;1.0\nid9137;1.0\nid9138;1.0\nid9139;1.0\nid9140;1.0\nid9141;1.0\nid9142;1.0\nid9143;1.0\nid9144;1.0\nid9145;1.0\nid9146;1.0\nid9147;1.0\nid9148;1.0\nid9149;1.0\nid9150;1.0\nid9151;1.0\nid9152;1.0\nid9153;1.0\nid9154;1.0\nid9155;1.0\nid9156;1.0\nid9157;1.0\nid9158;1.0\nid9159;1.0\nid9160;1.0\nid9161;1.0\nid9162;1.0\nid9163;1.0\nid9164;1.0\nid9165;1.0\nid9166;1.0\nid9167;1.0\nid9168;1.0\nid9169;1.0\nid9170;1.0\nid9171;1.0\nid9172;1.0\nid9173;1.0\nid9174;1.0\nid9175;1.0\nid9176;1.0\nid9177;1.0\nid9178;1.0\nid9179;1.0\nid9180;1.0\nid9181;1.0\nid9182;1.0\nid9183;1.0\nid9184;1.0\nid9185;1.0\nid9186;1.0\nid9187;1.0\nid9188;1.0\nid9189;1.0\nid9190;1.0\nid9191;1.0\nid9192;1.0\nid9193;1.0\nid9194;1.0\nid9195;1.0\nid9196;1.0\nid9197;1.0\nid9198;1.0\nid9199;1.0\nid9200;1.0\nid9201;1.0\nid9202;1.0\nid9203;1.0\nid9204;1.0\nid9205;1.0\nid9206;1.0\nid9207;1.0\nid9208;1.0\nid9209;1.0\nid9210;1.0\nid9211;1.0\nid9212;1.0\nid9213;1.0\nid9214;1.0\nid9215;1.0\nid9216;1.0\nid9217;1.0\nid9218;1.0\nid9219;1.0\nid9220;1.0\nid9221;1.0\nid9222;1.0\nid9223;1.0\nid9224;1.0\nid9225;1.0\nid9226;1.0\nid9227;1.0\nid9228;1.0\nid9229;1.0\nid9230;1.0\nid9231;1.0\nid9232;1.0\nid9233;1.0\nid9234;1.0\nid9235;1.0\nid9236;1.0\nid9237;1.0\nid9238;1.0\nid9239;1.0\nid9240;1.0\nid9241;1.0\nid9242;1.0\nid9243;1.0\nid9244;1.0\nid9245;1.0\nid9246;1.0\nid9247;1.0\nid9248;1.0\nid9249;1.0\nid9250;1.0\nid9251;1.0\nid9252;1.0\nid9253;1.0\nid9254;1.0\nid9255;1.0\nid9256;1.0\nid9257;1.0\nid9258;1.0\nid9259;1.0\nid9260;1.0\nid9261;1.0\nid9262;1.0\nid9263;1.0\nid9264;1.0\nid9265;1.0\nid9266;1.0\nid9267;1.0\nid9268;1.0\nid9269;1.0\nid9270;1.0\nid9271;1.0\nid9272;1.0\nid9273;1.0\nid9274;1.0\nid9275;1.0\nid9276;1.0\nid9277;1.0\nid9278;1.0\nid9279;1.0\nid9280;1.0\nid9281;1.0\nid9282;1.0\nid9283;1.0\nid9284;1.0\nid9285;1.0\nid9286;1.0\nid9287;1.0\nid9288;1.0\nid9289;1.0\nid9290;1.0\nid9291;1.0\nid9292;1.0\nid9293;1.0\nid9294;1.0\nid9295;1.0\nid9296;1.0\nid9297;1.0\nid9298;1.0\nid9299;1.0\nid9300;1.0\nid9301;1.0\nid9302;1.0\nid9303;1.0\nid9304;1.0\nid9305;1.0\nid9306;1.0\nid9307;1.0\nid9308;1.0\nid9309;1.0\nid9310;1.0\nid9311;1.0\nid9312;1.0\nid9313;1.0\nid9314;1.0\nid9315;1.0\nid9316;1.0\nid9317;1.0\nid9318;1.0\nid9319;1.0\nid9320;1.0\nid9321;1.0\nid9322;1.0\nid9323;1.0\nid9324;1.0\nid9325;1.0\nid9326;1.0\nid9327;1.0\nid9328;1.0\nid9329;1.0\nid9330;1.0\nid9331;1.0\nid9332;1.0\nid9333;1.0\nid9334;1.0\nid9335;1.0\nid9336;1.0\nid9337;1.0\nid9338;1.0\nid9339;1.0\nid9340;1.0\nid9341;1.0\nid9342;1.0\nid9343;1.0\nid9344;1.0\nid9345;1.0\nid9346;1.0\nid9347;1.0\nid9348;1.0\nid9349;1.0\nid9350;1.0\nid9351;1.0\nid9352;1.0\nid9353;1.0\nid9354;1.0\nid9355;1.0\nid9356;1.0\nid9357;1.0\nid9358;1.0\nid9359;1.0\nid9360;1.0\nid9361;1.0\nid9362;1.0\nid9363;1.0\nid9364;1.0\nid9365;1.0\nid9366;1.0\nid9367;1.0\nid9368;1.0\nid9369;1.0\nid9370;1.0\nid9371;1.0\nid9372;1.0\nid9373;1.0\nid9374;1.0\nid9375;1.0\nid9376;1.0\nid9377;1.0\nid9378;1.0\nid9379;1.0\nid9380;1.0\nid9381;1.0\nid9382;1.0\nid9383;1.0\nid9384;1.0\nid9385;1.0\nid9386;1.0\nid9387;1.0\nid9388;1.0\nid9389;1.0\nid9390;1.0\nid9391;1.0\nid9392;1.0\nid9393;1.0\nid9394;1.0\nid9395;1.0\nid9396;1.0\nid9397;1.0\nid9398;1.0\nid9399;1.0\nid9400;1.0\nid9401;1.0\nid9402;1.0\nid9403;1.0\nid9404;1.0\nid9405;1.0\nid9406;1.0\nid9407;1.0\nid9408;1.0\nid9409;1.0\nid9410;1.0\nid9411;1.0\nid9412;1.0\nid9413;1.0\nid9414;1.0\nid9415;1.0\nid9416;1.0\nid9417;1.0\nid9418;1.0\nid9419;1.0\nid9420;1.0\nid9421;1.0\nid9422;1.0\nid9423;1.0\nid9424;1.0\nid9425;1.0\nid9426;1.0\nid9427;1.0\nid9428;1.0\nid9429;1.0\nid9430;1.0\nid9431;1.0\nid9432;1.0\nid9433;1.0\nid9434;1.0\nid9435;1.0\nid9436;1.0\nid9437;1.0\nid9438;1.0\nid9439;1.0\nid9440;1.0\nid9441;1.0\nid9442;1.0\nid9443;1.0\nid9444;1.0\nid9445;1.0\nid9446;1.0\nid9447;1.0\nid9448;1.0\nid9449;1.0\nid9450;1.0\nid9451;1.0\nid9452;1.0\nid9453;1.0\nid9454;1.0\nid9455;1.0\nid9456;1.0\nid9457;1.0\nid9458;1.0\nid9459;1.0\nid9460;1.0\nid9461;1.0\nid9462;1.0\nid9463;1.0\nid9464;1.0\nid9465;1.0\nid9466;1.0\nid9467;1.0\nid9468;1.0\nid9469;1.0\nid9470;1.0\nid9471;1.0\nid9472;1.0\nid9473;1.0\nid9474;1.0\nid9475;1.0\nid9476;1.0\nid9477;1.0\nid9478;1.0\nid9479;1.0\nid9480;1.0\nid9481;1.0\nid9482;1.0\nid9483;1.0\nid9484;1.0\nid9485;1.0\nid9486;1.0\nid9487;1.0\nid9488;1.0\nid9489;1.0\nid9490;1.0\nid9491;1.0\nid9492;1.0\nid9493;1.0\nid9494;1.0\nid9495;1.0\nid9496;1.0\nid9497;1.0\nid9498;1.0\nid9499;1.0\nid9500;1.0\nid9501;1.0\nid9502;1.0\nid9503;1.0\nid9504;1.0\nid9505;1.0\nid9506;1.0\nid9507;1.0\nid9508;1.0\nid9509;1.0\nid9510;1.0\nid9511;1.0\nid9512;1.0\nid9513;1.0\nid9514;1.0\nid9515;1.0\nid9516;1.0\nid9517;1.0\nid9518;1.0\nid9519;1.0\nid9520;1.0\nid9521;1.0\nid9522;1.0\nid9523;1.0\nid9524;1.0\nid9525;1.0\nid9526;1.0\nid9527;1.0\nid9528;1.0\nid9529;1.0\nid9530;1.0\nid9531;1.0\nid9532;1.0\nid9533;1.0\nid9534;1.0\nid9535;1.0\nid9536;1.0\nid9537;1.0\nid9538;1.0\nid9539;1.0\nid9540;1.0\nid9541;1.0\nid9542;1.0\nid9543;1.0\nid9544;1.0\nid9545;1.0\nid9546;1.0\nid9547;1.0\nid9548;1.0\nid9549;1.0\nid9550;1.0\nid9551;1.0\nid9552;1.0\nid9553;1.0\nid9554;1.0\nid9555;1.0\nid9556;1.0\nid9557;1.0\nid9558;1.0\nid9559;1.0\nid9560;1.0\nid9561;1.0\nid9562;1.0\nid9563;1.0\nid9564;1.0\nid9565;1.0\nid9566;1.0\nid9567;1.0\nid9568;1.0\nid9569;1.0\nid9570;1.0\nid9571;1.0\nid9572;1.0\nid9573;1.0\nid9574;1.0\nid9575;1.0\nid9576;1.0\nid9577;1.0\nid9578;1.0\nid9579;1.0\nid9580;1.0\nid9581;1.0\nid9582;1.0\nid9583;1.0\nid9584;1.0\nid9585;1.0\nid9586;1.0\nid9587;1.0\nid9588;1.0\nid9589;1.0\nid9590;1.0\nid9591;1.0\nid9592;1.0\nid9593;1.0\nid9594;1.0\nid9595;1.0\nid9596;1.0\nid9597;1.0\nid9598;1.0\nid9599;1.0\nid9600;1.0\nid9601;1.0\nid9602;1.0\nid9603;1.0\nid9604;1.0\nid9605;1.0\nid9606;1.0\nid9607;1.0\nid9608;1.0\nid9609;1.0\nid9610;1.0\nid9611;1.0\nid9612;1.0\nid9613;1.0\nid9614;1.0\nid9615;1.0\nid9616;1.0\nid9617;1.0\nid9618;1.0\nid9619;1.0\nid9620;1.0\nid9621;1.0\nid9622;1.0\nid9623;1.0\nid9624;1.0\nid9625;1.0\nid9626;1.0\nid9627;1.0\nid9628;1.0\nid9629;1.0\nid9630;1.0\nid9631;1.0\nid9632;1.0\nid9633;1.0\nid9634;1.0\nid9635;1.0\nid9636;1.0\nid9637;1.0\nid9638;1.0\nid9639;1.0\nid9640;1.0\nid9641;1.0\nid9642;1.0\nid9643;1.0\nid9644;1.0\nid9645;1.0\nid9646;1.0\nid9647;1.0\nid9648;1.0\nid9649;1.0\nid9650;1.0\nid9651;1.0\nid9652;1.0\nid9653;1.0\nid9654;1.0\nid9655;1.0\nid9656;1.0\nid9657;1.0\nid9658;1.0\nid9659;1.0\nid9660;1.0\nid9661;1.0\nid9662;1.0\nid9663;1.0\nid9664;1.0\nid9665;1.0\nid9666;1.0\nid9667;1.0\nid9668;1.0\nid9669;1.0\nid9670;1.0\nid9671;1.0\nid9672;1.0\nid9673;1.0\nid9674;1.0\nid9675;1.0\nid9676;1.0\nid9677;1.0\nid9678;1.0\nid9679;1.0\nid9680;1.0\nid9681;1.0\nid9682;1.0\nid9683;1.0\nid9684;1.0\nid9685;1.0\nid9686;1.0\nid9687;1.0\nid9688;1.0\nid9689;1.0\nid9690;1.0\nid9691;1.0\nid9692;1.0\nid9693;1.0\nid9694;1.0\nid9695;1.0\nid9696;1.0\nid9697;1.0\nid9698;1.0\nid9699;1.0\nid9700;1.0\nid9701;1.0\nid9702;1.0\nid9703;1.0\nid9704;1.0\nid9705;1.0\nid9706;1.0\nid9707;1.0\nid9708;1.0\nid9709;1.0\nid9710;1.0\nid9711;1.0\nid9712;1.0\nid9713;1.0\nid9714;1.0\nid9715;1.0\nid9716;1.0\nid9717;1.0\nid9718;1.0\nid9719;1.0\nid9720;1.0\nid9721;1.0\nid9722;1.0\nid9723;1.0\nid9724;1.0\nid9725;1.0\nid9726;1.0\nid9727;1.0\nid9728;1.0\nid9729;1.0\nid9730;1.0\nid9731;1.0\nid9732;1.0\nid9733;1.0\nid9734;1.0\nid9735;1.0\nid9736;1.0\nid9737;1.0\nid9738;1.0\nid9739;1.0\nid9740;1.0\nid9741;1.0\nid9742;1.0\nid9743;1.0\nid9744;1.0\nid9745;1.0\nid9746;1.0\nid9747;1.0\nid9748;1.0\nid9749;1.0\nid9750;1.0\nid9751;1.0\nid9752;1.0\nid9753;1.0\nid9754;1.0\nid9755;1.0\nid9756;1.0\nid9757;1.0\nid9758;1.0\nid9759;1.0\nid9760;1.0\nid9761;1.0\nid9762;1.0\nid9763;1.0\nid9764;1.0\nid9765;1.0\nid9766;1.0\nid9767;1.0\nid9768;1.0\nid9769;1.0\nid9770;1.0\nid9771;1.0\nid9772;1.0\nid9773;1.0\nid9774;1.0\nid9775;1.0\nid9776;1.0\nid9777;1.0\nid9778;1.0\nid9779;1.0\nid9780;1.0\nid9781;1.0\nid9782;1.0\nid9783;1.0\nid9784;1.0\nid9785;1.0\nid9786;1.0\nid9787;1.0\nid9788;1.0\nid9789;1.0\nid9790;1.0\nid9791;1.0\nid9792;1.0\nid9793;1.0\nid9794;1.0\nid9795;1.0\nid9796;1.0\nid9797;1.0\nid9798;1.0\nid9799;1.0\nid9800;1.0\nid9801;1.0\nid9802;1.0\nid9803;1.0\nid9804;1.0\nid9805;1.0\nid9806;1.0\nid9807;1.0\nid9808;1.0\nid9809;1.0\nid9810;1.0\nid9811;1.0\nid9812;1.0\nid9813;1.0\nid9814;1.0\nid9815;1.0\nid9816;1.0\nid9817;1.0\nid9818;1.0\nid9819;1.0\nid9820;1.0\nid9821;1.0\nid9822;1.0\nid9823;1.0\nid9824;1.0\nid9825;1.0\nid9826;1.0\nid9827;1.0\nid9828;1.0\nid9829;1.0\nid9830;1.0\nid9831;1.0\nid9832;1.0\nid9833;1.0\nid9834;1.0\nid9835;1.0\nid9836;1.0\nid9837;1.0\nid9838;1.0\nid9839;1.0\nid9840;1.0\nid9841;1.0\nid9842;1.0\nid9843;1.0\nid9844;1.0\nid9845;1.0\nid9846;1.0\nid9847;1.0\nid9848;1.0\nid9849;1.0\nid9850;1.0\nid9851;1.0\nid9852;1.0\nid9853;1.0\nid9854;1.0\nid9855;1.0\nid9856;1.0\nid9857;1.0\nid9858;1.0\nid9859;1.0\nid9860;1.0\nid9861;1.0\nid9862;1.0\nid9863;1.0\nid9864;1.0\nid9865;1.0\nid9866;1.0\nid9867;1.0\nid9868;1.0\nid9869;1.0\nid9870;1.0\nid9871;1.0\nid9872;1.0\nid9873;1.0\nid9874;1.0\nid9875;1.0\nid9876;1.0\nid9877;1.0\nid9878;1.0\nid9879;1.0\nid9880;1.0\nid9881;1.0\nid9882;1.0\nid9883;1.0\nid9884;1.0\nid9885;1.0\nid9886;1.0\nid9887;1.0\nid9888;1.0\nid9889;1.0\nid9890;1.0\nid9891;1.0\nid9892;1.0\nid9893;1.0\nid9894;1.0\nid9895;1.0\nid9896;1.0\nid9897;1.0\nid9898;1.0\nid9899;1.0\nid9900;1.0\nid9901;1.0\nid9902;1.0\nid9903;1.0\nid9904;1.0\nid9905;1.0\nid9906;1.0\nid9907;1.0\nid9908;1.0\nid9909;1.0\nid9910;1.0\nid9911;1.0\nid9912;1.0\nid9913;1.0\nid9914;1.0\nid9915;1.0\nid9916;1.0\nid9917;1.0\nid9918;1.0\nid9919;1.0\nid9920;1.0\nid9921;1.0\nid9922;1.0\nid9923;1.0\nid9924;1.0\nid9925;1.0\nid9926;1.0\nid9927;1.0\nid9928;1.0\nid9929;1.0\nid9930;1.0\nid9931;1.0\nid9932;1.0\nid9933;1.0\nid9934;1.0\nid9935;1.0\nid9936;1.0\nid9937;1.0\nid9938;1.0\nid9939;1.0\nid9940;1.0\nid9941;1.0\nid9942;1.0\nid9943;1.0\nid9944;1.0\nid9945;1.0\nid9946;1.0\nid9947;1.0\nid9948;1.0\nid9949;1.0\nid9950;1.0\nid9951;1.0\nid9952;1.0\nid9953;1.0\nid9954;1.0\nid9955;1.0\nid9956;1.0\nid9957;1.0\nid9958;1.0\nid9959;1.0\nid9960;1.0\nid9961;1.0\nid9962;1.0\nid9963;1.0\nid9964;1.0\nid9965;1.0\nid9966;1.0\nid9967;1.0\nid9968;1.0\nid9969;1.0\nid9970;1.0\nid9971;1.0\nid9972;1.0\nid9973;1.0\nid9974;1.0\nid9975;1.0\nid9976;1.0\nid9977;1.0\nid9978;1.0\nid9979;1.0\nid9980;1.0\nid9981;1.0\nid9982;1.0\nid9983;1.0\nid9984;1.0\nid9985;1.0\nid9986;1.0\nid9987;1.0\nid9988;1.0\nid9989;1.0\nid9990;1.0\nid9991;1.0\nid9992;1.0\nid9993;1.0\nid9994;1.0\nid9995;1.0\nid9996;1.0\nid9997;1.0\nid9998;1.0\nid9999;1.0\nid10000;1.0\n"
  },
  {
    "path": "src/test/resources/samples/measurements-2.out",
    "content": "{Bosaso=19.2/19.2/19.2, Petropavlovsk-Kamchatsky=9.5/9.5/9.5}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-2.txt",
    "content": "Bosaso;19.2\nPetropavlovsk-Kamchatsky;9.5\n"
  },
  {
    "path": "src/test/resources/samples/measurements-20.out",
    "content": "{Abéché1️⃣🐝🏎️=27.3/27.3/27.3, Almaty1️⃣🐝🏎️=15.3/15.3/15.3, Baghdad1️⃣🐝🏎️=26.0/26.0/26.0, Bangkok1️⃣🐝🏎️=25.6/25.6/25.6, Berlin1️⃣🐝🏎️=-0.3/-0.3/-0.3, Birao1️⃣🐝🏎️=33.5/33.5/33.5, Canberra1️⃣🐝🏎️=5.2/5.2/5.2, Chittagong1️⃣🐝🏎️=12.6/12.6/12.6, Da Nang1️⃣🐝🏎️=33.7/33.7/33.7, Edinburgh1️⃣🐝🏎️=19.8/19.8/19.8, Irkutsk1️⃣🐝🏎️=9.9/9.9/9.9, Lhasa1️⃣🐝🏎️=13.4/13.4/13.4, Lyon1️⃣🐝🏎️=1.8/1.8/1.8, Mogadishu1️⃣🐝🏎️=11.5/11.5/11.5, Nashville1️⃣🐝🏎️=-4.9/-4.9/-4.9, Odesa1️⃣🐝🏎️=6.5/6.5/6.5, Parakou1️⃣🐝🏎️=36.3/36.3/36.3, Tamanrasset1️⃣🐝🏎️=17.9/17.9/17.9, Tirana1️⃣🐝🏎️=27.7/27.7/27.7, Xi'an1️⃣🐝🏎️=17.5/17.5/17.5}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-20.txt",
    "content": "Odesa1️⃣🐝🏎️;6.5\nCanberra1️⃣🐝🏎️;5.2\nLhasa1️⃣🐝🏎️;13.4\nEdinburgh1️⃣🐝🏎️;19.8\nDa Nang1️⃣🐝🏎️;33.7\nXi'an1️⃣🐝🏎️;17.5\nBerlin1️⃣🐝🏎️;-0.3\nTamanrasset1️⃣🐝🏎️;17.9\nAbéché1️⃣🐝🏎️;27.3\nBaghdad1️⃣🐝🏎️;26.0\nLyon1️⃣🐝🏎️;1.8\nMogadishu1️⃣🐝🏎️;11.5\nBangkok1️⃣🐝🏎️;25.6\nIrkutsk1️⃣🐝🏎️;9.9\nParakou1️⃣🐝🏎️;36.3\nAlmaty1️⃣🐝🏎️;15.3\nBirao1️⃣🐝🏎️;33.5\nChittagong1️⃣🐝🏎️;12.6\nTirana1️⃣🐝🏎️;27.7\nNashville1️⃣🐝🏎️;-4.9\n"
  },
  {
    "path": "src/test/resources/samples/measurements-3.out",
    "content": "{Bosaso=-15.0/1.3/20.0, Petropavlovsk-Kamchatsky=-9.5/0.0/9.5}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-3.txt",
    "content": "Bosaso;5.0\nBosaso;20.0\nBosaso;-5.0\nBosaso;-15.0\nPetropavlovsk-Kamchatsky;9.5\nPetropavlovsk-Kamchatsky;-9.5\n"
  },
  {
    "path": "src/test/resources/samples/measurements-boundaries.out",
    "content": "{Bosaso=-99.9/-99.9/-99.9, Petropavlovsk-Kamchatsky=99.9/99.9/99.9}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-boundaries.txt",
    "content": "Bosaso;-99.9\nPetropavlovsk-Kamchatsky;99.9\n"
  },
  {
    "path": "src/test/resources/samples/measurements-complex-utf8.out",
    "content": "{B=8.9/8.9/8.9, C=38.9/38.9/38.9, CabindaKermānZunhuaRochesterValenzuelaOrūmīyehWugangShuangqiaoTshikapa=3.0/3.0/3.0, ChesterLobnyaSan LeandroHemeiSolweziGrand BourgKaliboS=23.4/23.4/23.4, MirnaPehčevoRopažiGus=16.7/16.7/16.7, PototanSahuayo de MorelosBambergMosigkauFrancisco BeltrãoJelenia GóraTelêmaco Borb=17.5/17.5/17.5, TanjungpinangKasselHaldiaLuxorLạng SơnAt TājīTaraka=10.6/10.6/10.6, aniCartagoEṭ ṬīraTemerinCormeilles-en-ParisisZawyat ech CheïkhS=25.4/25.4/25.4, burgazAl ḨawīyahSalamancaMbanza KongoNchelengeZhangaözenTurbatMatiMangghystaūMalak=21.5/21.5/21.5, cotánSan Ramón de la Nueva OránWausauGbaweTailaiRochester HillsVilla ElisaToba TekS=11.2/11.2/11.2, eLafayetteAsh Shaţ=14.2/14.2/14.2, en IslandKota BharuCiudad López MateosCelayaVinhDuyunLos Mochis‘AjmānNyalaLarkanaWichitaNishi=11.9/11.9/11.9, epé=28.2/28.2/28.2, hanVarkkallaiPort LokoD=10.9/10.9/10.9, iCoahuitlánRabatJahāngīrpur SālkhaniCamUniversity of California-Santa BarbaraSerravalleTelkathuM=13.4/13.4/13.4, igButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkomunGornji PetrovciRibnicaKon TumŠavnikPoul=22.5/22.5/22.5, igButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkopunGornji PetrovciRibnicaKon TumŠavnikPodl=11.5/11.5/11.5, igButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkopunGornji PetrovciRibnicaKon TumŠavnikPoul=18.5/18.5/18.5, inhoSökeDordrechtPoáLaloG=13.1/13.1/13.1, iudad Melchor MúzquizQuinhámelDa=40.5/40.5/40.5, ixButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkomunGornji PetrovciRibnicaKon TumŠavnikPoul=0.1/0.1/0.1, l ‘=14.6/14.6/14.6, lhuleuTacurongNavapolatskPiscoDera Ismail KhanLabéAltamiraCavite CityYevpatoriiaTait=22.8/22.8/22.8, liLoretoPlacentiaAliso ViejoChomaPen-y-Bont ar OgwrCojutepeque=12.4/12.4/12.4, lioúpoliBarahonaHoPhuketLe BardoBuena ParkKayesChampigny-sur-MarneHaskovoChathamBatleyEsteioRe=22.5/22.5/22.5, m el Bo=14.6/14.6/14.6, mazunchaleZrenjaninFouchanaSurtPanč=6.7/6.7/6.7, ngoDübendorfC=11.7/11.7/11.7, nt-A=9.2/9.2/9.2, ntington StationKampong SpeuKakataMoschátoBressoVentspilsSaint-CloudTamboSidi Smai’ilDandenon=14.6/14.6/14.6, oCanagatanHelsinkiJabalpurProvidenceRuchengNizhniy NovgorodAhvāzJeparaShaoyangComayagüe=17.3/17.3/17.3, oGumlāSamā’=14.9/14.9/14.9, os Reyes de SalgadoCinisello BalsamoKashibaH=20.0/20.0/20.0, picuíbaJhang CityTepicJayapuraRio BrancoToyamaFangtingSanandajDelhi CantonmentLinghaiShorāpurToy=13.0/13.0/13.0, raKielSibuYatoParanáSanta ClaraYamagataKatihārBeykozImperat=13.5/13.5/13.5, rhamDera Ghazi KhanMiyazakiBhātpār=21.3/21.3/21.3, rugarhVerāvalAlagoinhasEdremitBandırmaSalavatGandajikaLucapaLeesburgTamaRas Tan=10.9/10.9/10.9, skişeh=12.9/12.9/12.9, venGaopingDunhuaAz Zarqā’SylhetKaihuaCaerdyddJāmnagarFuyuanGayaFlorianópolisC=1.9/1.9/1.9, y-le-MoutierSant’ArpinoPljevljaRo=0.8/0.8/0.8, ça PaulistaDarmstadtZhengdingPindamonhangabaEnschedeGirónUttarpāraHeidelbergK=6.0/6.0/6.0, üSosnowiecTanauanMya=18.4/18.4/18.4, ālSongnimSanto TomasKoiduHoshangābādOpoleNovocheboksarskArarasKhannaPunoKoforiduaAhmadpur E=19.4/19.4/19.4, āng=15.7/15.7/15.7, ġFis=9.6/9.6/9.6, ‘AqabahPembaNowgongQu=12.9/12.9/12.9}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-complex-utf8.txt",
    "content": "aniCartagoEṭ ṬīraTemerinCormeilles-en-ParisisZawyat ech CheïkhS;25.4\npicuíbaJhang CityTepicJayapuraRio BrancoToyamaFangtingSanandajDelhi CantonmentLinghaiShorāpurToy;13.0\nlhuleuTacurongNavapolatskPiscoDera Ismail KhanLabéAltamiraCavite CityYevpatoriiaTait;22.8\nāng;15.7\nhanVarkkallaiPort LokoD;10.9\neLafayetteAsh Shaţ;14.2\n‘AqabahPembaNowgongQu;12.9\ninhoSökeDordrechtPoáLaloG;13.1\nskişeh;12.9\nrhamDera Ghazi KhanMiyazakiBhātpār;21.3\nigButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkopunGornji PetrovciRibnicaKon TumŠavnikPodl;11.5\nigButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkopunGornji PetrovciRibnicaKon TumŠavnikPoul;18.5\nigButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkomunGornji PetrovciRibnicaKon TumŠavnikPoul;22.5\nixButeboJuršinciKoaniImdinaNova VasDestrnikVarvarinSkomunGornji PetrovciRibnicaKon TumŠavnikPoul;0.1\nB;8.9\nC;38.9\nnt-A;9.2\ny-le-MoutierSant’ArpinoPljevljaRo;0.8\noGumlāSamā’;14.9\nos Reyes de SalgadoCinisello BalsamoKashibaH;20.0\nm el Bo;14.6\nmazunchaleZrenjaninFouchanaSurtPanč;6.7\nġFis;9.6\nepé;28.2\nālSongnimSanto TomasKoiduHoshangābādOpoleNovocheboksarskArarasKhannaPunoKoforiduaAhmadpur E;19.4\niudad Melchor MúzquizQuinhámelDa;40.5\nChesterLobnyaSan LeandroHemeiSolweziGrand BourgKaliboS;23.4\ncotánSan Ramón de la Nueva OránWausauGbaweTailaiRochester HillsVilla ElisaToba TekS;11.2\nraKielSibuYatoParanáSanta ClaraYamagataKatihārBeykozImperat;13.5\nl ‘;14.6\nTanjungpinangKasselHaldiaLuxorLạng SơnAt TājīTaraka;10.6\nMirnaPehčevoRopažiGus;16.7\nüSosnowiecTanauanMya;18.4\nngoDübendorfC;11.7\nliLoretoPlacentiaAliso ViejoChomaPen-y-Bont ar OgwrCojutepeque;12.4\nburgazAl ḨawīyahSalamancaMbanza KongoNchelengeZhangaözenTurbatMatiMangghystaūMalak;21.5\niCoahuitlánRabatJahāngīrpur SālkhaniCamUniversity of California-Santa BarbaraSerravalleTelkathuM;13.4\nlioúpoliBarahonaHoPhuketLe BardoBuena ParkKayesChampigny-sur-MarneHaskovoChathamBatleyEsteioRe;22.5\nPototanSahuayo de MorelosBambergMosigkauFrancisco BeltrãoJelenia GóraTelêmaco Borb;17.5\nCabindaKermānZunhuaRochesterValenzuelaOrūmīyehWugangShuangqiaoTshikapa;3.0\nvenGaopingDunhuaAz Zarqā’SylhetKaihuaCaerdyddJāmnagarFuyuanGayaFlorianópolisC;1.9\nntington StationKampong SpeuKakataMoschátoBressoVentspilsSaint-CloudTamboSidi Smai’ilDandenon;14.6\nrugarhVerāvalAlagoinhasEdremitBandırmaSalavatGandajikaLucapaLeesburgTamaRas Tan;10.9\noCanagatanHelsinkiJabalpurProvidenceRuchengNizhniy NovgorodAhvāzJeparaShaoyangComayagüe;17.3\nça PaulistaDarmstadtZhengdingPindamonhangabaEnschedeGirónUttarpāraHeidelbergK;6.0\nen IslandKota BharuCiudad López MateosCelayaVinhDuyunLos Mochis‘AjmānNyalaLarkanaWichitaNishi;11.9\n"
  },
  {
    "path": "src/test/resources/samples/measurements-dot.out",
    "content": "{-=1.0/1.5/2.0, .=1.0/1.0/1.0}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-dot.txt",
    "content": ".;1.0\n-;1.0\n-;2.0\n"
  },
  {
    "path": "src/test/resources/samples/measurements-rounding.out",
    "content": "{ham=14.6/25.5/33.6, jel=-9.0/18.0/46.5}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-rounding.txt",
    "content": "ham;33.6\nham;31.7\nham;21.9\nham;14.6\njel;18.6\njel;12.8\njel;20.7\njel;13.8\njel;26.7\njel;17.7\njel;24.7\njel;18.4\njel;10.7\njel;21.9\njel;35.6\njel;19.5\njel;15.9\njel;18.6\njel;24.7\njel;11.0\njel;26.4\njel;16.6\njel;24.3\njel;18.2\njel;15.7\njel;23.7\njel;20.1\njel;22.4\njel;1.7\njel;23.8\njel;9.0\njel;18.9\njel;1.0\njel;9.5\njel;25.6\njel;19.6\njel;-0.9\njel;13.0\njel;19.3\njel;12.0\njel;9.3\njel;24.8\njel;26.7\njel;15.3\njel;20.0\njel;25.8\njel;12.9\njel;23.4\njel;15.0\njel;16.9\njel;27.0\njel;17.7\njel;23.4\njel;16.1\njel;15.2\njel;28.0\njel;18.5\njel;30.1\njel;11.7\njel;19.9\njel;32.0\njel;20.3\njel;17.1\njel;16.9\njel;13.1\njel;28.4\njel;16.0\njel;26.1\njel;24.4\njel;16.1\njel;18.1\njel;6.6\njel;11.5\njel;20.5\njel;18.2\njel;22.3\njel;10.4\njel;0.3\njel;15.6\njel;19.7\njel;28.7\njel;10.8\njel;32.0\njel;31.8\njel;20.8\njel;14.0\njel;19.1\njel;26.3\njel;10.3\njel;6.8\njel;16.3\njel;18.8\njel;13.9\njel;27.9\njel;14.9\njel;25.8\njel;21.0\njel;15.4\njel;19.5\njel;16.7\njel;17.1\njel;18.6\njel;8.5\njel;27.4\njel;21.2\njel;33.4\njel;19.8\njel;19.6\njel;24.2\njel;15.0\njel;27.2\njel;7.8\njel;17.4\njel;16.1\njel;23.2\njel;16.3\njel;11.1\njel;20.4\njel;14.3\njel;18.8\njel;26.1\njel;13.8\njel;14.8\njel;11.9\njel;22.0\njel;13.1\njel;18.1\njel;17.5\njel;25.1\njel;26.4\njel;16.1\njel;6.6\njel;18.5\njel;22.6\njel;15.7\njel;20.6\njel;26.6\njel;25.5\njel;7.5\njel;25.4\njel;14.7\njel;19.8\njel;24.6\njel;27.7\njel;20.8\njel;11.2\njel;34.3\njel;19.0\njel;13.4\njel;20.0\njel;11.6\njel;16.3\njel;19.8\njel;22.0\njel;19.4\njel;10.6\njel;24.0\njel;13.5\njel;20.7\njel;23.5\njel;16.0\njel;18.8\njel;11.5\njel;11.8\njel;15.8\njel;9.7\njel;13.8\njel;23.9\njel;13.1\njel;23.9\njel;16.0\njel;11.1\njel;14.6\njel;12.3\njel;14.6\njel;12.8\njel;19.9\njel;10.7\njel;19.5\njel;14.0\njel;16.4\njel;25.8\njel;22.7\njel;20.9\njel;26.5\njel;20.3\njel;24.6\njel;31.9\njel;26.8\njel;21.0\njel;20.9\njel;19.3\njel;25.0\njel;23.1\njel;15.3\njel;13.4\njel;24.1\njel;15.6\njel;16.5\njel;14.6\njel;33.5\njel;17.3\njel;15.2\njel;23.9\njel;20.5\njel;16.2\njel;15.8\njel;27.7\njel;13.6\njel;35.0\njel;24.1\njel;21.6\njel;6.8\njel;6.6\njel;16.5\njel;34.1\njel;8.6\njel;14.6\njel;20.0\njel;28.4\njel;19.4\njel;22.5\njel;18.9\njel;9.8\njel;-0.5\njel;7.0\njel;11.4\njel;18.9\njel;16.5\njel;27.0\njel;1.8\njel;19.7\njel;12.5\njel;1.3\njel;8.8\njel;26.9\njel;24.5\njel;19.5\njel;22.9\njel;9.4\njel;18.1\njel;6.0\njel;10.9\njel;24.3\njel;16.6\njel;22.5\njel;18.6\njel;13.0\njel;16.3\njel;19.1\njel;19.9\njel;17.1\njel;23.5\njel;15.5\njel;15.1\njel;12.9\njel;22.2\njel;24.6\njel;10.4\njel;11.4\njel;10.2\njel;26.3\njel;31.0\njel;17.2\njel;12.0\njel;28.4\njel;24.2\njel;21.3\njel;7.3\njel;18.7\njel;12.8\njel;21.2\njel;7.7\njel;19.1\njel;18.6\njel;23.0\njel;13.3\njel;14.4\njel;17.6\njel;4.4\njel;16.1\njel;7.9\njel;20.9\njel;20.3\njel;25.8\njel;13.0\njel;14.4\njel;20.8\njel;30.4\njel;24.5\njel;20.1\njel;28.4\njel;15.7\njel;32.5\njel;30.0\njel;13.0\njel;17.8\njel;22.0\njel;24.3\njel;22.2\njel;23.8\njel;19.6\njel;15.7\njel;20.9\njel;9.8\njel;14.1\njel;15.0\njel;7.7\njel;22.2\njel;15.0\njel;25.9\njel;10.3\njel;13.8\njel;10.8\njel;14.8\njel;36.4\njel;22.4\njel;19.4\njel;18.6\njel;10.4\njel;17.6\njel;22.8\njel;10.0\njel;18.9\njel;23.0\njel;16.3\njel;22.6\njel;13.2\njel;19.4\njel;9.1\njel;6.3\njel;16.5\njel;13.2\njel;5.5\njel;19.3\njel;23.2\njel;22.8\njel;7.3\njel;16.4\njel;5.9\njel;20.9\njel;-3.0\njel;24.0\njel;25.7\njel;14.0\njel;13.5\njel;16.3\njel;23.2\njel;28.5\njel;20.0\njel;16.1\njel;21.7\njel;34.9\njel;17.3\njel;10.8\njel;17.3\njel;23.5\njel;14.1\njel;4.2\njel;14.4\njel;17.2\njel;21.1\njel;17.1\njel;6.5\njel;13.9\njel;13.5\njel;22.8\njel;29.1\njel;16.5\njel;10.2\njel;26.4\njel;30.4\njel;11.9\njel;21.5\njel;16.6\njel;14.9\njel;13.3\njel;11.6\njel;14.2\njel;11.3\njel;24.9\njel;27.7\njel;14.6\njel;18.1\njel;11.1\njel;9.2\njel;27.9\njel;13.2\njel;11.3\njel;11.9\njel;17.5\njel;15.9\njel;22.8\njel;8.1\njel;30.4\njel;24.3\njel;19.4\njel;15.0\njel;23.7\njel;18.0\njel;29.0\njel;15.7\njel;12.7\njel;18.9\njel;19.2\njel;28.6\njel;20.6\njel;21.0\njel;18.3\njel;9.3\njel;20.9\njel;20.7\njel;5.4\njel;18.0\njel;7.8\njel;7.4\njel;19.9\njel;17.0\njel;12.6\njel;36.4\njel;25.0\njel;21.9\njel;24.2\njel;18.5\njel;17.9\njel;14.0\njel;13.6\njel;21.9\njel;11.2\njel;28.0\njel;19.0\njel;11.7\njel;31.9\njel;6.3\njel;23.4\njel;19.9\njel;23.2\njel;13.3\njel;19.7\njel;23.1\njel;16.0\njel;28.9\njel;18.3\njel;19.6\njel;26.0\njel;20.2\njel;14.5\njel;27.5\njel;15.1\njel;27.3\njel;15.6\njel;16.9\njel;7.6\njel;8.0\njel;16.8\njel;4.5\njel;21.2\njel;17.6\njel;20.1\njel;23.1\njel;12.6\njel;35.7\njel;14.8\njel;24.3\njel;21.4\njel;23.7\njel;3.9\njel;30.7\njel;27.1\njel;8.5\njel;15.2\njel;15.3\njel;28.2\njel;22.4\njel;13.6\njel;20.1\njel;9.4\njel;16.0\njel;8.4\njel;18.3\njel;9.9\njel;24.8\njel;11.8\njel;25.5\njel;15.2\njel;23.2\njel;20.4\njel;11.6\njel;9.3\njel;16.5\njel;13.2\njel;16.4\njel;21.3\njel;18.3\njel;8.8\njel;22.8\njel;7.0\njel;18.3\njel;32.8\njel;4.3\njel;12.6\njel;24.3\njel;9.9\njel;19.6\njel;18.8\njel;21.1\njel;28.8\njel;25.3\njel;4.1\njel;13.0\njel;17.6\njel;30.9\njel;17.2\njel;24.7\njel;8.8\njel;16.3\njel;19.1\njel;8.9\njel;24.6\njel;21.8\njel;24.7\njel;15.1\njel;13.5\njel;19.6\njel;22.8\njel;15.1\njel;24.0\njel;21.1\njel;26.3\njel;13.3\njel;10.7\njel;18.2\njel;17.3\njel;17.2\njel;17.5\njel;14.5\njel;22.1\njel;26.8\njel;19.2\njel;21.4\njel;12.5\njel;31.8\njel;18.9\njel;13.3\njel;18.2\njel;6.5\njel;9.5\njel;15.6\njel;32.9\njel;22.8\njel;22.1\njel;15.4\njel;17.2\njel;14.4\njel;6.2\njel;21.5\njel;-2.9\njel;20.9\njel;21.5\njel;14.7\njel;29.7\njel;12.9\njel;29.7\njel;7.5\njel;6.2\njel;16.8\njel;15.4\njel;20.2\njel;16.7\njel;18.4\njel;17.5\njel;14.8\njel;10.8\njel;13.4\njel;18.6\njel;28.0\njel;4.5\njel;8.0\njel;16.5\njel;21.3\njel;15.8\njel;22.7\njel;16.0\njel;21.7\njel;22.0\njel;20.5\njel;13.4\njel;3.0\njel;20.7\njel;6.5\njel;36.7\njel;18.7\njel;22.6\njel;19.9\njel;30.8\njel;24.5\njel;18.1\njel;21.3\njel;27.3\njel;13.0\njel;34.4\njel;10.3\njel;13.8\njel;26.1\njel;14.1\njel;18.2\njel;21.1\njel;15.1\njel;13.1\njel;24.1\njel;13.0\njel;17.9\njel;22.0\njel;12.3\njel;38.0\njel;20.9\njel;12.0\njel;19.9\njel;29.7\njel;16.2\njel;17.9\njel;15.9\njel;16.7\njel;10.7\njel;0.1\njel;20.3\njel;13.4\njel;13.9\njel;15.7\njel;22.5\njel;11.0\njel;17.6\njel;22.1\njel;16.6\njel;19.9\njel;21.3\njel;8.8\njel;22.3\njel;21.4\njel;12.8\njel;20.1\njel;8.5\njel;19.3\njel;22.0\njel;18.9\njel;23.5\njel;4.2\njel;33.4\njel;34.5\njel;15.1\njel;7.7\njel;22.1\njel;14.8\njel;20.8\njel;18.9\njel;13.6\njel;10.7\njel;20.2\njel;18.3\njel;13.3\njel;20.6\njel;13.7\njel;23.1\njel;12.8\njel;28.1\njel;19.6\njel;13.5\njel;21.0\njel;15.6\njel;20.5\njel;19.6\njel;18.8\njel;19.2\njel;24.3\njel;29.8\njel;15.4\njel;16.9\njel;20.6\njel;20.5\njel;30.6\njel;13.9\njel;16.0\njel;13.7\njel;16.3\njel;30.6\njel;9.3\njel;27.7\njel;21.0\njel;31.5\njel;23.7\njel;26.9\njel;14.1\njel;14.5\njel;19.1\njel;24.9\njel;1.8\njel;35.5\njel;23.2\njel;18.6\njel;17.8\njel;28.8\njel;9.6\njel;20.7\njel;17.7\njel;14.5\njel;7.1\njel;18.1\njel;20.2\njel;10.6\njel;21.5\njel;7.6\njel;29.7\njel;14.6\njel;22.2\njel;16.0\njel;23.3\njel;21.6\njel;14.8\njel;19.7\njel;19.4\njel;20.5\njel;16.3\njel;8.7\njel;2.3\njel;8.1\njel;19.1\njel;24.7\njel;12.1\njel;8.7\njel;25.8\njel;24.6\njel;15.7\njel;20.4\njel;12.4\njel;29.7\njel;10.1\njel;20.5\njel;20.5\njel;30.2\njel;22.3\njel;19.4\njel;33.9\njel;18.9\njel;23.8\njel;34.0\njel;20.5\njel;13.4\njel;15.8\njel;13.6\njel;14.9\njel;20.5\njel;13.3\njel;22.6\njel;29.3\njel;26.3\njel;21.2\njel;20.8\njel;22.4\njel;18.3\njel;10.5\njel;29.6\njel;22.5\njel;28.5\njel;10.4\njel;10.3\njel;27.9\njel;14.4\njel;21.5\njel;14.0\njel;20.7\njel;20.5\njel;8.8\njel;24.3\njel;29.6\njel;18.9\njel;14.3\njel;14.1\njel;7.4\njel;19.4\njel;11.9\njel;15.2\njel;7.5\njel;12.2\njel;19.3\njel;18.6\njel;3.7\njel;8.0\njel;31.5\njel;24.3\njel;28.5\njel;18.6\njel;9.2\njel;5.6\njel;3.4\njel;26.2\njel;20.9\njel;16.6\njel;26.0\njel;11.2\njel;20.0\njel;5.1\njel;21.2\njel;22.8\njel;31.3\njel;20.8\njel;13.2\njel;35.8\njel;26.7\njel;17.9\njel;-8.0\njel;8.4\njel;12.6\njel;21.4\njel;27.0\njel;27.1\njel;28.0\njel;19.5\njel;17.5\njel;17.0\njel;19.9\njel;25.9\njel;19.9\njel;11.1\njel;20.7\njel;29.2\njel;23.6\njel;-2.8\njel;25.0\njel;19.0\njel;20.7\njel;17.0\njel;20.3\njel;21.3\njel;13.4\njel;14.5\njel;13.2\njel;6.0\njel;17.9\njel;29.2\njel;7.6\njel;32.5\njel;32.5\njel;21.0\njel;23.7\njel;22.7\njel;23.4\njel;17.2\njel;13.5\njel;26.9\njel;26.2\njel;17.0\njel;2.4\njel;26.4\njel;14.1\njel;22.4\njel;11.0\njel;8.1\njel;2.5\njel;10.6\njel;12.5\njel;13.5\njel;13.6\njel;24.4\njel;20.4\njel;10.4\njel;20.7\njel;21.6\njel;20.7\njel;14.4\njel;16.8\njel;22.3\njel;0.6\njel;18.5\njel;16.8\njel;17.1\njel;19.5\njel;11.0\njel;16.6\njel;19.7\njel;24.3\njel;17.8\njel;21.5\njel;9.3\njel;30.8\njel;13.4\njel;13.1\njel;14.9\njel;22.1\njel;-6.0\njel;8.3\njel;15.5\njel;17.2\njel;12.8\njel;20.1\njel;8.6\njel;22.3\njel;20.3\njel;17.4\njel;19.2\njel;28.8\njel;25.2\njel;21.4\njel;20.3\njel;18.2\njel;13.3\njel;23.9\njel;28.2\njel;17.5\njel;28.3\njel;12.0\njel;14.1\njel;16.0\njel;15.8\njel;11.2\njel;14.4\njel;19.4\njel;26.9\njel;14.5\njel;9.0\njel;16.0\njel;25.3\njel;19.7\njel;0.1\njel;24.7\njel;20.1\njel;16.1\njel;27.0\njel;17.7\njel;15.7\njel;11.8\njel;5.9\njel;15.5\njel;16.9\njel;16.1\njel;25.1\njel;9.6\njel;11.4\njel;20.9\njel;13.1\njel;18.9\njel;11.2\njel;5.8\njel;19.2\njel;23.3\njel;11.7\njel;37.7\njel;23.5\njel;6.9\njel;24.3\njel;21.4\njel;12.4\njel;8.7\njel;18.2\njel;15.7\njel;14.1\njel;12.8\njel;14.4\njel;12.4\njel;31.4\njel;22.6\njel;21.6\njel;26.9\njel;21.3\njel;17.4\njel;19.2\njel;22.1\njel;26.4\njel;23.0\njel;31.1\njel;16.2\njel;27.3\njel;18.6\njel;10.5\njel;33.6\njel;19.1\njel;14.1\njel;21.1\njel;35.8\njel;19.7\njel;10.5\njel;30.0\njel;19.0\njel;27.6\njel;22.2\njel;13.5\njel;15.5\njel;11.6\njel;11.2\njel;8.0\njel;24.8\njel;29.0\njel;29.1\njel;22.4\njel;23.2\njel;11.2\njel;25.7\njel;18.3\njel;19.1\njel;15.0\njel;12.3\njel;36.9\njel;10.5\njel;24.2\njel;14.4\njel;18.1\njel;8.4\njel;22.5\njel;11.8\njel;16.9\njel;19.3\njel;16.0\njel;18.6\njel;16.2\njel;30.3\njel;8.3\njel;17.7\njel;23.0\njel;29.8\njel;17.7\njel;8.8\njel;17.3\njel;3.6\njel;15.3\njel;20.1\njel;11.3\njel;13.4\njel;20.4\njel;22.0\njel;16.5\njel;4.7\njel;22.7\njel;16.0\njel;22.7\njel;15.3\njel;28.6\njel;17.0\njel;16.6\njel;13.3\njel;21.1\njel;-0.3\njel;19.7\njel;22.9\njel;25.4\njel;19.5\njel;25.4\njel;22.4\njel;19.1\njel;7.1\njel;27.7\njel;14.5\njel;20.7\njel;17.0\njel;24.6\njel;9.4\njel;27.7\njel;14.6\njel;10.3\njel;30.5\njel;24.9\njel;15.1\njel;10.0\njel;19.1\njel;22.4\njel;23.0\njel;13.0\njel;17.8\njel;10.3\njel;25.9\njel;17.1\njel;9.7\njel;22.5\njel;3.5\njel;25.1\njel;26.8\njel;18.9\njel;15.5\njel;12.8\njel;28.4\njel;23.8\njel;19.5\njel;21.0\njel;20.2\njel;24.9\njel;24.1\njel;18.5\njel;22.4\njel;11.6\njel;15.4\njel;21.6\njel;14.0\njel;23.8\njel;9.2\njel;18.2\njel;22.2\njel;10.7\njel;22.1\njel;19.2\njel;25.5\njel;12.0\njel;11.5\njel;16.1\njel;25.8\njel;22.1\njel;24.0\njel;20.6\njel;22.9\njel;10.9\njel;20.1\njel;29.6\njel;7.7\njel;18.8\njel;20.1\njel;22.8\njel;21.3\njel;14.1\njel;13.8\njel;9.8\njel;12.5\njel;17.4\njel;9.4\njel;17.2\njel;21.1\njel;14.1\njel;11.1\njel;11.9\njel;0.1\njel;10.8\njel;15.0\njel;22.4\njel;27.8\njel;24.7\njel;23.3\njel;25.5\njel;18.6\njel;22.9\njel;21.7\njel;24.1\njel;22.9\njel;16.7\njel;21.9\njel;14.2\njel;14.2\njel;32.9\njel;22.4\njel;25.8\njel;19.6\njel;17.2\njel;23.4\njel;10.6\njel;21.2\njel;22.5\njel;10.1\njel;14.0\njel;16.4\njel;10.9\njel;37.3\njel;16.4\njel;4.8\njel;11.6\njel;9.9\njel;10.3\njel;23.7\njel;17.5\njel;19.8\njel;13.5\njel;19.8\njel;16.1\njel;20.2\njel;12.6\njel;29.5\njel;11.5\njel;24.2\njel;27.0\njel;20.0\njel;17.6\njel;16.3\njel;10.6\njel;18.0\njel;14.1\njel;11.8\njel;22.0\njel;22.9\njel;18.4\njel;14.4\njel;22.1\njel;27.9\njel;13.5\njel;9.5\njel;16.5\njel;21.9\njel;12.4\njel;23.9\njel;13.3\njel;12.2\njel;26.2\njel;13.4\njel;6.7\njel;20.8\njel;17.8\njel;24.0\njel;17.5\njel;26.6\njel;22.8\njel;27.7\njel;18.5\njel;6.6\njel;20.2\njel;6.9\njel;21.3\njel;20.0\njel;18.7\njel;18.4\njel;18.8\njel;14.9\njel;8.5\njel;23.2\njel;4.6\njel;22.2\njel;14.6\njel;34.2\njel;11.6\njel;16.0\njel;14.2\njel;9.8\njel;15.7\njel;14.5\njel;22.2\njel;10.6\njel;20.2\njel;12.0\njel;20.8\njel;26.2\njel;20.8\njel;12.7\njel;16.7\njel;9.4\njel;20.9\njel;25.6\njel;19.4\njel;18.4\njel;17.6\njel;22.0\njel;26.9\njel;26.9\njel;21.5\njel;22.1\njel;21.2\njel;16.6\njel;34.0\njel;15.8\njel;18.0\njel;14.7\njel;19.8\njel;8.5\njel;16.5\njel;22.1\njel;25.8\njel;19.2\njel;16.0\njel;4.4\njel;9.5\njel;12.2\njel;6.8\njel;16.3\njel;23.1\njel;13.9\njel;21.9\njel;17.3\njel;15.7\njel;19.4\njel;12.2\njel;24.1\njel;16.4\njel;23.2\njel;17.0\njel;15.8\njel;15.8\njel;14.4\njel;12.7\njel;17.3\njel;22.4\njel;29.6\njel;23.7\njel;11.9\njel;7.3\njel;23.1\njel;7.7\njel;8.1\njel;6.2\njel;10.4\njel;15.7\njel;14.5\njel;22.5\njel;13.0\njel;10.9\njel;22.3\njel;31.4\njel;12.0\njel;16.0\njel;27.0\njel;18.8\njel;15.7\njel;32.3\njel;23.3\njel;16.6\njel;19.7\njel;19.7\njel;21.9\njel;18.7\njel;19.2\njel;6.1\njel;25.5\njel;9.2\njel;26.8\njel;20.0\njel;24.3\njel;26.1\njel;17.0\njel;16.6\njel;14.0\njel;13.1\njel;23.1\njel;14.9\njel;16.2\njel;18.2\njel;20.0\njel;21.5\njel;23.0\njel;8.6\njel;9.7\njel;27.1\njel;23.7\njel;21.0\njel;14.4\njel;21.7\njel;17.2\njel;21.9\njel;8.9\njel;20.9\njel;20.1\njel;19.1\njel;19.3\njel;18.4\njel;15.8\njel;15.9\njel;14.9\njel;13.9\njel;20.9\njel;19.9\njel;17.6\njel;29.0\njel;24.2\njel;8.8\njel;17.5\njel;20.8\njel;14.9\njel;24.5\njel;29.9\njel;19.7\njel;14.6\njel;11.6\njel;14.7\njel;9.0\njel;24.1\njel;37.5\njel;2.2\njel;16.9\njel;15.9\njel;9.1\njel;19.6\njel;27.9\njel;11.5\njel;18.9\njel;23.9\njel;20.4\njel;27.0\njel;23.2\njel;22.5\njel;20.1\njel;33.2\njel;12.6\njel;21.8\njel;18.1\njel;20.0\njel;3.5\njel;10.1\njel;14.2\njel;14.5\njel;12.0\njel;22.7\njel;22.6\njel;28.5\njel;13.6\njel;13.0\njel;14.7\njel;13.6\njel;33.6\njel;21.9\njel;33.2\njel;18.3\njel;13.6\njel;17.6\njel;3.5\njel;3.2\njel;12.6\njel;30.7\njel;24.4\njel;19.4\njel;20.9\njel;29.4\njel;30.3\njel;23.8\njel;11.8\njel;20.6\njel;26.2\njel;10.4\njel;14.5\njel;5.2\njel;10.8\njel;20.2\njel;12.4\njel;20.5\njel;18.1\njel;3.8\njel;12.1\njel;15.7\njel;4.8\njel;21.5\njel;15.1\njel;9.2\njel;28.1\njel;28.1\njel;23.8\njel;26.8\njel;4.3\njel;8.2\njel;30.6\njel;10.7\njel;7.1\njel;16.5\njel;13.3\njel;8.4\njel;30.5\njel;13.5\njel;13.9\njel;-2.5\njel;25.3\njel;16.4\njel;15.6\njel;20.1\njel;16.6\njel;16.9\njel;23.5\njel;19.4\njel;21.1\njel;19.7\njel;10.7\njel;2.1\njel;25.8\njel;21.3\njel;16.5\njel;14.8\njel;14.2\njel;21.3\njel;11.3\njel;18.8\njel;6.7\njel;30.5\njel;31.8\njel;28.9\njel;12.1\njel;23.8\njel;4.0\njel;20.8\njel;24.6\njel;9.4\njel;7.3\njel;24.9\njel;34.1\njel;16.2\njel;25.3\njel;6.8\njel;21.8\njel;21.4\njel;28.9\njel;14.4\njel;18.8\njel;28.6\njel;21.3\njel;12.6\njel;18.0\njel;15.1\njel;6.8\njel;9.6\njel;20.5\njel;23.2\njel;14.4\njel;23.3\njel;19.6\njel;21.0\njel;6.5\njel;17.5\njel;25.6\njel;22.8\njel;24.6\njel;17.9\njel;20.4\njel;22.5\njel;24.2\njel;17.1\njel;13.0\njel;27.4\njel;18.8\njel;15.3\njel;24.0\njel;25.8\njel;17.8\njel;14.3\njel;24.9\njel;24.9\njel;6.5\njel;32.1\njel;25.2\njel;35.4\njel;25.6\njel;27.9\njel;15.8\njel;19.8\njel;15.5\njel;19.1\njel;17.6\njel;13.7\njel;27.4\njel;15.4\njel;18.2\njel;9.3\njel;32.5\njel;18.2\njel;19.6\njel;18.2\njel;12.7\njel;15.2\njel;26.1\njel;20.2\njel;16.0\njel;17.1\njel;29.2\njel;14.3\njel;6.8\njel;13.5\njel;15.9\njel;13.2\njel;12.3\njel;19.1\njel;5.6\njel;7.5\njel;20.7\njel;20.9\njel;14.5\njel;11.1\njel;11.2\njel;17.4\njel;13.1\njel;26.8\njel;17.4\njel;23.3\njel;11.9\njel;17.7\njel;19.3\njel;17.6\njel;22.3\njel;18.6\njel;30.4\njel;13.2\njel;15.9\njel;17.8\njel;7.4\njel;16.0\njel;5.2\njel;17.5\njel;12.1\njel;12.3\njel;24.8\njel;7.3\njel;20.1\njel;18.7\njel;17.9\njel;17.4\njel;8.7\njel;29.8\njel;21.1\njel;22.6\njel;17.3\njel;15.9\njel;20.8\njel;14.8\njel;27.2\njel;22.0\njel;12.8\njel;9.8\njel;17.3\njel;18.9\njel;26.6\njel;15.5\njel;17.5\njel;15.1\njel;14.6\njel;20.4\njel;12.9\njel;18.5\njel;16.3\njel;12.2\njel;31.7\njel;13.7\njel;5.4\njel;17.8\njel;28.5\njel;17.3\njel;10.0\njel;14.5\njel;12.7\njel;15.8\njel;8.6\njel;21.0\njel;16.2\njel;31.6\njel;18.3\njel;18.6\njel;32.7\njel;15.4\njel;9.1\njel;15.6\njel;11.9\njel;15.2\njel;21.8\njel;8.3\njel;30.0\njel;32.4\njel;25.0\njel;14.2\njel;15.3\njel;11.2\njel;22.9\njel;19.9\njel;22.5\njel;31.8\njel;20.3\njel;26.0\njel;21.2\njel;13.1\njel;19.7\njel;21.3\njel;13.7\njel;32.5\njel;11.8\njel;16.5\njel;21.3\njel;8.7\njel;24.1\njel;14.6\njel;25.9\njel;28.0\njel;19.8\njel;9.5\njel;10.0\njel;12.7\njel;14.4\njel;9.2\njel;8.6\njel;17.2\njel;32.1\njel;3.9\njel;20.2\njel;23.4\njel;21.2\njel;20.9\njel;7.0\njel;20.7\njel;13.6\njel;13.6\njel;29.8\njel;25.6\njel;22.3\njel;13.1\njel;24.5\njel;14.5\njel;5.2\njel;17.2\njel;14.7\njel;23.9\njel;15.2\njel;32.5\njel;24.6\njel;9.0\njel;30.0\njel;15.9\njel;20.9\njel;5.0\njel;14.5\njel;16.1\njel;6.8\njel;20.6\njel;24.6\njel;15.5\njel;20.6\njel;19.2\njel;12.4\njel;31.8\njel;20.3\njel;18.3\njel;12.2\njel;19.1\njel;15.3\njel;-0.5\njel;20.3\njel;20.7\njel;30.0\njel;11.7\njel;13.6\njel;15.9\njel;19.6\njel;6.9\njel;20.6\njel;18.0\njel;10.0\njel;8.4\njel;18.5\njel;10.1\njel;16.5\njel;18.9\njel;17.6\njel;10.2\njel;23.7\njel;4.4\njel;16.9\njel;16.4\njel;14.2\njel;32.1\njel;19.4\njel;8.2\njel;23.2\njel;14.4\njel;15.1\njel;15.4\njel;15.0\njel;30.1\njel;19.9\njel;19.2\njel;25.7\njel;6.0\njel;20.4\njel;17.8\njel;5.0\njel;23.3\njel;6.2\njel;8.2\njel;29.3\njel;20.5\njel;17.4\njel;17.4\njel;27.3\njel;17.7\njel;8.8\njel;14.0\njel;10.3\njel;12.6\njel;7.3\njel;18.7\njel;18.9\njel;11.2\njel;17.5\njel;24.2\njel;17.8\njel;12.7\njel;9.5\njel;24.2\njel;11.6\njel;20.4\njel;35.6\njel;12.2\njel;25.7\njel;6.1\njel;7.6\njel;18.3\njel;31.1\njel;12.2\njel;12.5\njel;11.5\njel;15.7\njel;15.1\njel;18.5\njel;17.5\njel;18.4\njel;16.9\njel;18.4\njel;13.3\njel;13.8\njel;18.9\njel;15.4\njel;4.1\njel;18.4\njel;15.9\njel;10.2\njel;21.5\njel;18.0\njel;30.9\njel;20.6\njel;21.1\njel;15.0\njel;15.2\njel;23.1\njel;28.9\njel;18.9\njel;20.6\njel;17.2\njel;20.3\njel;14.7\njel;32.5\njel;22.5\njel;22.8\njel;26.1\njel;23.4\njel;25.6\njel;8.6\njel;28.5\njel;12.7\njel;12.5\njel;8.6\njel;6.1\njel;17.2\njel;25.9\njel;12.4\njel;18.5\njel;33.5\njel;16.4\njel;19.8\njel;10.6\njel;20.2\njel;16.6\njel;27.5\njel;22.0\njel;23.1\njel;18.6\njel;12.2\njel;17.0\njel;20.3\njel;22.7\njel;21.7\njel;18.7\njel;25.2\njel;16.3\njel;24.3\njel;23.1\njel;23.1\njel;27.2\njel;14.6\njel;19.8\njel;2.5\njel;17.9\njel;19.1\njel;21.1\njel;10.8\njel;19.2\njel;18.2\njel;19.7\njel;10.9\njel;26.7\njel;26.7\njel;16.7\njel;-1.2\njel;1.5\njel;20.7\njel;10.3\njel;18.9\njel;9.7\njel;23.9\njel;21.3\njel;13.7\njel;13.5\njel;19.0\njel;16.4\njel;13.4\njel;19.9\njel;3.5\njel;6.9\njel;18.6\njel;8.0\njel;25.1\njel;13.9\njel;13.4\njel;21.1\njel;14.5\njel;15.2\njel;13.6\njel;26.0\njel;18.0\njel;24.0\njel;28.1\njel;19.2\njel;20.3\njel;22.5\njel;17.8\njel;16.5\njel;20.4\njel;19.5\njel;17.7\njel;8.4\njel;18.9\njel;24.8\njel;11.8\njel;12.3\njel;18.9\njel;27.4\njel;21.0\njel;5.7\njel;21.2\njel;23.9\njel;15.7\njel;16.7\njel;15.6\njel;6.1\njel;8.9\njel;16.6\njel;18.9\njel;23.9\njel;21.0\njel;26.7\njel;20.0\njel;15.7\njel;17.9\njel;15.1\njel;13.1\njel;17.0\njel;24.0\njel;18.3\njel;14.0\njel;12.6\njel;15.8\njel;9.8\njel;26.7\njel;18.4\njel;11.9\njel;24.8\njel;19.1\njel;24.8\njel;22.3\njel;21.3\njel;25.3\njel;27.4\njel;21.3\njel;16.3\njel;29.9\njel;21.9\njel;27.6\njel;13.2\njel;14.6\njel;10.3\njel;29.1\njel;35.0\njel;23.8\njel;19.9\njel;2.8\njel;10.2\njel;24.8\njel;15.6\njel;17.9\njel;19.9\njel;21.6\njel;7.4\njel;14.7\njel;10.2\njel;21.7\njel;11.7\njel;19.5\njel;13.1\njel;15.8\njel;13.1\njel;11.3\njel;13.7\njel;18.7\njel;14.4\njel;10.9\njel;34.2\njel;22.3\njel;17.9\njel;25.6\njel;21.2\njel;20.4\njel;9.5\njel;17.8\njel;19.6\njel;18.0\njel;19.4\njel;-1.8\njel;18.9\njel;24.6\njel;13.4\njel;4.9\njel;18.2\njel;16.8\njel;17.9\njel;9.9\njel;13.3\njel;18.1\njel;24.2\njel;24.4\njel;26.9\njel;20.7\njel;17.0\njel;21.0\njel;19.8\njel;26.8\njel;31.2\njel;20.2\njel;20.0\njel;15.4\njel;1.7\njel;23.9\njel;12.5\njel;26.7\njel;13.5\njel;21.4\njel;24.0\njel;12.8\njel;28.5\njel;18.8\njel;17.5\njel;17.9\njel;16.6\njel;13.2\njel;17.3\njel;-9.0\njel;18.6\njel;18.6\njel;14.4\njel;19.8\njel;31.6\njel;13.0\njel;26.2\njel;8.7\njel;14.3\njel;12.8\njel;19.8\njel;11.7\njel;29.8\njel;20.9\njel;26.5\njel;23.7\njel;24.0\njel;27.4\njel;18.0\njel;19.4\njel;30.3\njel;22.5\njel;15.5\njel;18.2\njel;18.3\njel;22.2\njel;16.1\njel;14.5\njel;-3.7\njel;12.1\njel;14.6\njel;20.5\njel;8.2\njel;14.5\njel;19.4\njel;32.5\njel;14.0\njel;19.1\njel;13.3\njel;28.0\njel;23.5\njel;33.8\njel;22.0\njel;18.3\njel;22.7\njel;7.3\njel;4.3\njel;18.3\njel;18.7\njel;15.0\njel;9.3\njel;20.2\njel;19.3\njel;18.4\njel;12.1\njel;29.3\njel;19.9\njel;6.8\njel;30.7\njel;12.6\njel;16.2\njel;19.7\njel;25.9\njel;0.6\njel;17.7\njel;27.2\njel;13.5\njel;18.3\njel;24.2\njel;24.4\njel;11.1\njel;17.0\njel;-0.7\njel;18.5\njel;23.6\njel;8.3\njel;18.6\njel;0.0\njel;13.1\njel;13.0\njel;14.7\njel;30.4\njel;18.8\njel;14.4\njel;29.0\njel;14.0\njel;3.4\njel;13.2\njel;16.1\njel;18.6\njel;24.5\njel;7.4\njel;21.9\njel;16.9\njel;13.1\njel;29.3\njel;8.5\njel;17.2\njel;18.0\njel;20.6\njel;21.7\njel;27.5\njel;14.6\njel;20.3\njel;33.6\njel;18.4\njel;18.4\njel;20.7\njel;8.5\njel;3.1\njel;26.7\njel;10.4\njel;14.5\njel;2.8\njel;14.2\njel;7.4\njel;17.4\njel;15.6\njel;14.8\njel;24.5\njel;12.1\njel;22.5\njel;10.5\njel;25.1\njel;22.2\njel;16.2\njel;15.5\njel;17.5\njel;16.1\njel;10.4\njel;17.2\njel;11.8\njel;13.6\njel;-6.9\njel;17.2\njel;17.6\njel;28.0\njel;10.7\njel;25.3\njel;10.7\njel;17.3\njel;22.9\njel;26.1\njel;33.9\njel;9.8\njel;14.0\njel;18.5\njel;29.9\njel;12.4\njel;16.1\njel;15.1\njel;17.0\njel;20.9\njel;7.8\njel;13.9\njel;16.3\njel;18.1\njel;20.7\njel;23.4\njel;21.0\njel;12.3\njel;15.3\njel;24.0\njel;23.5\njel;16.3\njel;16.1\njel;24.0\njel;19.4\njel;23.3\njel;18.5\njel;11.6\njel;29.6\njel;11.3\njel;19.6\njel;21.7\njel;20.7\njel;17.6\njel;11.9\njel;17.3\njel;25.7\njel;11.9\njel;20.1\njel;22.9\njel;7.2\njel;17.3\njel;33.4\njel;14.3\njel;31.4\njel;21.1\njel;20.8\njel;14.6\njel;21.4\njel;1.9\njel;26.5\njel;28.5\njel;23.8\njel;25.3\njel;18.6\njel;29.1\njel;5.6\njel;19.7\njel;20.5\njel;9.0\njel;22.7\njel;12.8\njel;21.5\njel;22.6\njel;10.2\njel;16.7\njel;13.0\njel;10.8\njel;17.6\njel;18.3\njel;21.6\njel;11.5\njel;22.0\njel;15.5\njel;21.8\njel;32.2\njel;12.1\njel;25.8\njel;2.3\njel;17.1\njel;8.2\njel;17.6\njel;24.4\njel;15.8\njel;-0.5\njel;10.7\njel;30.3\njel;17.0\njel;25.1\njel;11.0\njel;23.2\njel;20.5\njel;16.9\njel;20.1\njel;24.0\njel;15.7\njel;7.3\njel;22.7\njel;20.7\njel;21.5\njel;12.9\njel;13.0\njel;12.3\njel;14.6\njel;9.0\njel;16.0\njel;20.1\njel;9.2\njel;25.3\njel;26.0\njel;19.0\njel;21.2\njel;27.8\njel;25.4\njel;19.1\njel;26.7\njel;2.0\njel;11.9\njel;9.9\njel;29.5\njel;10.9\njel;4.1\njel;26.1\njel;29.0\njel;24.0\njel;5.4\njel;9.5\njel;5.8\njel;20.1\njel;24.3\njel;35.4\njel;26.3\njel;15.1\njel;26.8\njel;11.8\njel;16.1\njel;17.5\njel;15.3\njel;10.0\njel;20.7\njel;18.6\njel;29.0\njel;12.9\njel;12.0\njel;18.0\njel;14.4\njel;18.8\njel;26.4\njel;12.7\njel;20.7\njel;23.6\njel;13.1\njel;24.4\njel;17.6\njel;16.6\njel;12.5\njel;20.1\njel;26.2\njel;11.8\njel;21.6\njel;10.5\njel;23.8\njel;9.4\njel;19.4\njel;25.0\njel;17.1\njel;4.9\njel;29.1\njel;16.5\njel;17.2\njel;20.9\njel;11.4\njel;26.4\njel;16.6\njel;18.2\njel;23.0\njel;18.2\njel;20.5\njel;19.8\njel;20.0\njel;25.7\njel;23.0\njel;5.8\njel;21.0\njel;18.4\njel;23.0\njel;9.5\njel;-0.8\njel;9.7\njel;13.6\njel;22.5\njel;20.1\njel;14.7\njel;23.4\njel;15.8\njel;18.3\njel;30.7\njel;18.9\njel;31.5\njel;27.5\njel;19.6\njel;29.8\njel;10.1\njel;26.8\njel;17.5\njel;17.0\njel;20.5\njel;4.5\njel;24.3\njel;13.7\njel;15.7\njel;8.5\njel;16.1\njel;14.7\njel;31.1\njel;12.9\njel;13.4\njel;23.2\njel;15.7\njel;25.2\njel;22.1\njel;23.6\njel;17.1\njel;22.4\njel;5.7\njel;6.9\njel;12.0\njel;17.3\njel;15.9\njel;19.3\njel;27.5\njel;19.5\njel;21.2\njel;20.3\njel;27.3\njel;17.1\njel;11.8\njel;29.0\njel;19.8\njel;27.3\njel;16.5\njel;29.5\njel;27.1\njel;30.5\njel;25.6\njel;17.9\njel;7.2\njel;10.0\njel;23.1\njel;10.0\njel;31.1\njel;23.6\njel;13.8\njel;12.7\njel;26.5\njel;20.3\njel;17.0\njel;9.9\njel;15.8\njel;9.8\njel;21.6\njel;21.3\njel;7.1\njel;10.6\njel;20.5\njel;22.4\njel;20.4\njel;16.8\njel;21.6\njel;15.1\njel;13.4\njel;27.3\njel;16.8\njel;25.9\njel;10.4\njel;29.5\njel;9.3\njel;29.1\njel;10.6\njel;17.9\njel;19.1\njel;23.8\njel;14.5\njel;22.9\njel;28.0\njel;23.4\njel;26.0\njel;6.6\njel;16.1\njel;21.9\njel;15.1\njel;11.3\njel;16.6\njel;20.6\njel;17.0\njel;20.3\njel;11.2\njel;19.6\njel;22.7\njel;18.0\njel;9.4\njel;21.7\njel;14.5\njel;18.0\njel;28.1\njel;13.4\njel;26.0\njel;9.0\njel;18.3\njel;12.8\njel;30.2\njel;19.9\njel;16.4\njel;13.9\njel;19.9\njel;32.2\njel;18.9\njel;3.1\njel;17.4\njel;19.3\njel;12.5\njel;19.2\njel;20.0\njel;14.7\njel;13.9\njel;17.1\njel;27.8\njel;20.8\njel;15.0\njel;8.8\njel;13.6\njel;22.1\njel;18.4\njel;10.0\njel;9.6\njel;26.7\njel;23.2\njel;3.7\njel;19.8\njel;14.6\njel;26.4\njel;14.0\njel;24.0\njel;17.2\njel;26.8\njel;33.4\njel;23.4\njel;11.9\njel;13.7\njel;19.1\njel;9.2\njel;32.7\njel;16.0\njel;26.1\njel;16.0\njel;18.9\njel;16.6\njel;33.1\njel;15.6\njel;26.2\njel;19.3\njel;20.7\njel;21.4\njel;9.2\njel;15.4\njel;29.9\njel;10.1\njel;8.9\njel;17.9\njel;14.1\njel;22.9\njel;3.4\njel;14.9\njel;27.0\njel;21.2\njel;18.8\njel;8.7\njel;21.7\njel;16.3\njel;9.2\njel;19.1\njel;10.3\njel;16.3\njel;20.5\njel;10.6\njel;22.4\njel;19.1\njel;18.8\njel;8.8\njel;22.4\njel;10.2\njel;22.4\njel;19.6\njel;12.0\njel;19.6\njel;19.2\njel;13.3\njel;13.1\njel;13.3\njel;16.9\njel;9.0\njel;17.7\njel;24.9\njel;6.5\njel;18.0\njel;13.9\njel;16.6\njel;23.2\njel;22.7\njel;26.2\njel;24.6\njel;11.7\njel;16.8\njel;20.6\njel;20.8\njel;19.5\njel;13.7\njel;14.3\njel;19.9\njel;15.7\njel;12.0\njel;7.7\njel;22.7\njel;26.2\njel;23.5\njel;15.6\njel;29.1\njel;21.0\njel;6.3\njel;11.2\njel;21.7\njel;26.7\njel;5.9\njel;15.8\njel;15.4\njel;24.1\njel;15.8\njel;16.2\njel;23.8\njel;16.4\njel;20.4\njel;22.4\njel;21.8\njel;26.6\njel;10.6\njel;19.5\njel;10.7\njel;11.4\njel;26.1\njel;12.3\njel;15.0\njel;11.9\njel;11.7\njel;19.8\njel;12.4\njel;12.0\njel;40.7\njel;17.3\njel;13.0\njel;21.9\njel;29.6\njel;27.1\njel;20.9\njel;17.4\njel;18.3\njel;18.8\njel;25.1\njel;21.6\njel;15.4\njel;20.9\njel;0.2\njel;25.8\njel;32.0\njel;11.1\njel;8.1\njel;9.4\njel;10.5\njel;6.3\njel;11.1\njel;17.2\njel;9.8\njel;26.0\njel;21.2\njel;15.1\njel;15.8\njel;3.2\njel;17.9\njel;12.4\njel;25.9\njel;19.0\njel;18.4\njel;14.8\njel;18.1\njel;19.1\njel;8.3\njel;13.1\njel;14.0\njel;10.0\njel;33.7\njel;18.0\njel;20.2\njel;17.3\njel;15.7\njel;18.8\njel;28.5\njel;28.9\njel;28.2\njel;40.9\njel;32.1\njel;14.8\njel;19.3\njel;23.3\njel;30.8\njel;21.5\njel;13.2\njel;21.7\njel;23.6\njel;8.8\njel;21.0\njel;24.7\njel;22.6\njel;21.6\njel;8.3\njel;20.4\njel;6.8\njel;22.4\njel;26.5\njel;3.7\njel;21.9\njel;27.7\njel;19.9\njel;24.8\njel;14.2\njel;37.5\njel;15.1\njel;11.6\njel;11.8\njel;18.1\njel;26.6\njel;11.2\njel;19.6\njel;22.6\njel;14.5\njel;14.7\njel;24.7\njel;25.1\njel;15.6\njel;24.9\njel;20.2\njel;16.4\njel;20.0\njel;26.9\njel;24.8\njel;12.4\njel;20.5\njel;18.4\njel;12.0\njel;18.1\njel;21.0\njel;32.7\njel;19.7\njel;10.1\njel;23.3\njel;6.6\njel;20.5\njel;24.5\njel;19.3\njel;18.9\njel;17.0\njel;11.1\njel;26.5\njel;12.1\njel;10.9\njel;15.4\njel;11.3\njel;21.1\njel;1.7\njel;21.6\njel;4.1\njel;14.3\njel;17.1\njel;21.3\njel;14.6\njel;14.9\njel;21.7\njel;33.3\njel;22.7\njel;14.6\njel;22.7\njel;16.0\njel;22.7\njel;18.6\njel;21.3\njel;23.2\njel;21.2\njel;15.5\njel;17.0\njel;10.3\njel;14.7\njel;14.0\njel;16.9\njel;21.3\njel;2.8\njel;25.9\njel;23.9\njel;16.8\njel;29.5\njel;25.8\njel;10.4\njel;23.0\njel;24.7\njel;17.0\njel;13.3\njel;1.3\njel;9.8\njel;21.6\njel;22.3\njel;4.7\njel;18.7\njel;19.5\njel;29.4\njel;13.7\njel;24.1\njel;13.1\njel;27.7\njel;17.0\njel;19.2\njel;17.3\njel;28.2\njel;7.6\njel;8.5\njel;20.4\njel;16.0\njel;17.9\njel;17.6\njel;24.2\njel;11.0\njel;16.6\njel;7.7\njel;18.1\njel;19.4\njel;22.4\njel;21.5\njel;24.8\njel;14.0\njel;20.0\njel;20.1\njel;8.8\njel;20.6\njel;18.1\njel;20.5\njel;19.9\njel;18.9\njel;13.5\njel;7.7\njel;21.4\njel;23.1\njel;20.8\njel;18.6\njel;25.6\njel;12.8\njel;21.3\njel;19.0\njel;10.9\njel;35.0\njel;5.9\njel;19.6\njel;9.2\njel;12.0\njel;21.6\njel;15.6\njel;20.4\njel;13.9\njel;13.4\njel;3.5\njel;34.4\njel;12.7\njel;8.2\njel;15.6\njel;20.7\njel;16.5\njel;18.0\njel;21.4\njel;17.9\njel;19.6\njel;11.7\njel;18.9\njel;8.5\njel;23.7\njel;25.3\njel;20.6\njel;17.4\njel;15.8\njel;19.4\njel;14.9\njel;25.1\njel;18.9\njel;8.0\njel;11.4\njel;14.9\njel;17.6\njel;20.8\njel;21.3\njel;17.9\njel;9.1\njel;5.5\njel;15.7\njel;20.6\njel;17.0\njel;27.1\njel;5.1\njel;10.0\njel;21.5\njel;10.6\njel;19.7\njel;25.7\njel;2.2\njel;26.6\njel;10.3\njel;21.2\njel;17.3\njel;23.0\njel;23.2\njel;15.4\njel;6.9\njel;22.5\njel;13.2\njel;19.6\njel;8.9\njel;17.9\njel;25.1\njel;20.5\njel;25.5\njel;18.3\njel;21.6\njel;16.6\njel;23.8\njel;23.2\njel;14.2\njel;15.9\njel;19.3\njel;11.8\njel;28.4\njel;16.4\njel;11.1\njel;17.6\njel;21.7\njel;18.6\njel;10.8\njel;15.2\njel;13.6\njel;6.3\njel;21.3\njel;23.7\njel;4.8\njel;13.5\njel;13.0\njel;9.4\njel;14.0\njel;26.8\njel;7.5\njel;24.3\njel;27.2\njel;24.5\njel;14.5\njel;16.1\njel;14.1\njel;12.9\njel;25.8\njel;21.8\njel;25.3\njel;12.7\njel;11.9\njel;21.0\njel;21.9\njel;28.0\njel;29.0\njel;17.6\njel;25.7\njel;11.9\njel;23.6\njel;13.6\njel;9.2\njel;9.6\njel;16.7\njel;22.2\njel;19.5\njel;29.1\njel;21.7\njel;12.2\njel;14.2\njel;20.7\njel;1.4\njel;29.0\njel;29.6\njel;30.2\njel;24.5\njel;32.6\njel;7.3\njel;15.0\njel;21.5\njel;8.1\njel;16.0\njel;17.4\njel;6.9\njel;17.8\njel;27.5\njel;9.6\njel;33.7\njel;18.8\njel;21.3\njel;33.8\njel;16.1\njel;24.0\njel;15.2\njel;11.8\njel;9.7\njel;25.5\njel;22.0\njel;26.5\njel;19.8\njel;10.0\njel;14.5\njel;13.9\njel;22.6\njel;19.0\njel;24.1\njel;12.1\njel;15.3\njel;18.4\njel;20.3\njel;33.4\njel;22.2\njel;22.5\njel;15.9\njel;17.9\njel;28.3\njel;3.4\njel;22.2\njel;13.0\njel;19.8\njel;20.3\njel;21.4\njel;19.9\njel;19.6\njel;14.8\njel;18.6\njel;21.5\njel;15.4\njel;10.8\njel;27.6\njel;17.8\njel;36.0\njel;13.5\njel;9.8\njel;14.2\njel;8.8\njel;21.3\njel;22.1\njel;5.4\njel;10.3\njel;13.8\njel;21.0\njel;19.3\njel;23.1\njel;28.2\njel;16.3\njel;19.2\njel;8.9\njel;18.6\njel;21.5\njel;24.4\njel;9.8\njel;26.2\njel;31.4\njel;28.3\njel;18.5\njel;2.0\njel;21.2\njel;15.9\njel;27.9\njel;23.2\njel;17.3\njel;12.9\njel;18.7\njel;5.0\njel;16.8\njel;13.1\njel;26.6\njel;17.8\njel;16.7\njel;18.5\njel;12.7\njel;28.9\njel;21.9\njel;20.2\njel;15.3\njel;25.3\njel;32.4\njel;29.1\njel;19.4\njel;14.7\njel;22.7\njel;26.8\njel;9.3\njel;19.3\njel;25.9\njel;24.7\njel;25.4\njel;28.9\njel;11.9\njel;15.8\njel;22.4\njel;16.4\njel;28.1\njel;20.1\njel;10.7\njel;12.4\njel;16.3\njel;6.4\njel;22.5\njel;6.4\njel;27.1\njel;22.9\njel;23.2\njel;26.6\njel;25.3\njel;15.5\njel;20.9\njel;21.9\njel;13.1\njel;21.6\njel;12.4\njel;29.8\njel;10.5\njel;15.4\njel;23.9\njel;6.4\njel;20.4\njel;17.3\njel;24.7\njel;18.0\njel;20.5\njel;9.3\njel;14.0\njel;27.2\njel;27.6\njel;20.6\njel;13.5\njel;21.5\njel;14.1\njel;23.4\njel;12.8\njel;16.5\njel;18.0\njel;18.8\njel;25.2\njel;17.7\njel;7.0\njel;27.8\njel;20.0\njel;4.9\njel;15.6\njel;14.7\njel;21.1\njel;12.4\njel;32.0\njel;24.0\njel;19.2\njel;20.0\njel;25.6\njel;22.2\njel;27.1\njel;19.2\njel;12.1\njel;27.4\njel;11.9\njel;20.2\njel;13.9\njel;26.3\njel;15.8\njel;13.6\njel;7.8\njel;12.4\njel;11.7\njel;19.4\njel;19.5\njel;18.5\njel;22.3\njel;15.0\njel;13.4\njel;0.8\njel;12.0\njel;9.5\njel;16.1\njel;21.2\njel;14.5\njel;26.4\njel;21.3\njel;19.0\njel;10.4\njel;17.7\njel;14.2\njel;26.1\njel;19.1\njel;25.3\njel;20.0\njel;1.1\njel;22.1\njel;26.9\njel;15.0\njel;23.2\njel;20.0\njel;14.0\njel;23.0\njel;13.4\njel;19.2\njel;31.2\njel;11.5\njel;20.9\njel;20.1\njel;-0.5\njel;18.1\njel;15.9\njel;9.3\njel;17.6\njel;15.3\njel;17.2\njel;20.3\njel;14.4\njel;14.4\njel;29.0\njel;14.9\njel;25.5\njel;14.1\njel;12.8\njel;14.4\njel;16.7\njel;13.3\njel;11.9\njel;8.8\njel;12.1\njel;16.1\njel;7.5\njel;17.0\njel;18.7\njel;21.7\njel;22.1\njel;12.1\njel;26.0\njel;4.1\njel;15.4\njel;2.3\njel;12.8\njel;15.8\njel;16.2\njel;22.2\njel;21.2\njel;18.2\njel;29.1\njel;16.2\njel;5.5\njel;18.4\njel;21.1\njel;24.4\njel;20.9\njel;14.8\njel;24.2\njel;31.4\njel;20.6\njel;13.3\njel;15.7\njel;10.2\njel;25.7\njel;17.1\njel;11.9\njel;13.7\njel;20.6\njel;9.4\njel;20.5\njel;22.1\njel;19.8\njel;12.1\njel;13.3\njel;14.7\njel;37.3\njel;14.5\njel;23.4\njel;15.8\njel;17.1\njel;12.2\njel;20.6\njel;26.0\njel;17.5\njel;19.6\njel;4.2\njel;23.1\njel;21.3\njel;22.1\njel;16.1\njel;3.6\njel;23.7\njel;21.9\njel;19.5\njel;15.2\njel;23.7\njel;6.1\njel;24.5\njel;22.4\njel;27.6\njel;16.7\njel;10.4\njel;30.0\njel;12.7\njel;33.5\njel;16.1\njel;19.7\njel;32.0\njel;15.4\njel;17.2\njel;26.4\njel;13.5\njel;16.5\njel;23.8\njel;11.9\njel;10.9\njel;15.7\njel;4.0\njel;18.9\njel;8.4\njel;6.0\njel;-4.5\njel;18.5\njel;15.3\njel;0.2\njel;28.9\njel;10.5\njel;14.4\njel;8.6\njel;19.3\njel;14.0\njel;25.7\njel;16.3\njel;38.6\njel;27.1\njel;24.2\njel;33.2\njel;7.4\njel;21.0\njel;14.5\njel;22.9\njel;11.6\njel;26.0\njel;7.4\njel;10.6\njel;25.1\njel;16.9\njel;16.9\njel;14.0\njel;14.8\njel;22.6\njel;24.4\njel;23.9\njel;24.1\njel;15.6\njel;29.0\njel;8.5\njel;14.4\njel;17.7\njel;6.8\njel;7.8\njel;13.5\njel;20.3\njel;19.9\njel;9.7\njel;21.2\njel;14.4\njel;13.9\njel;20.9\njel;28.9\njel;23.4\njel;17.5\njel;17.0\njel;15.9\njel;25.4\njel;11.3\njel;12.4\njel;24.1\njel;8.7\njel;29.6\njel;13.0\njel;24.1\njel;10.7\njel;10.3\njel;26.9\njel;10.9\njel;9.9\njel;14.1\njel;24.4\njel;11.9\njel;22.0\njel;7.9\njel;16.2\njel;14.4\njel;20.2\njel;16.5\njel;18.1\njel;15.4\njel;7.1\njel;21.8\njel;12.5\njel;15.5\njel;19.8\njel;12.6\njel;18.4\njel;16.1\njel;34.1\njel;15.3\njel;6.2\njel;6.6\njel;17.5\njel;25.1\njel;31.3\njel;26.7\njel;21.2\njel;17.7\njel;22.9\njel;20.6\njel;26.3\njel;17.4\njel;15.9\njel;7.1\njel;22.5\njel;21.3\njel;15.3\njel;17.2\njel;23.6\njel;9.2\njel;16.7\njel;23.6\njel;21.2\njel;18.3\njel;9.5\njel;10.2\njel;17.8\njel;7.7\njel;29.9\njel;16.5\njel;15.1\njel;18.4\njel;29.4\njel;25.7\njel;19.2\njel;14.9\njel;27.2\njel;22.8\njel;17.5\njel;4.5\njel;31.9\njel;19.7\njel;14.4\njel;26.0\njel;24.6\njel;15.5\njel;18.2\njel;15.5\njel;10.6\njel;22.3\njel;16.5\njel;22.8\njel;8.0\njel;18.0\njel;20.3\njel;22.9\njel;19.7\njel;17.6\njel;15.5\njel;9.7\njel;14.5\njel;13.9\njel;15.0\njel;23.6\njel;25.6\njel;15.4\njel;16.5\njel;31.1\njel;5.2\njel;19.7\njel;6.4\njel;22.4\njel;3.7\njel;24.3\njel;30.1\njel;14.1\njel;12.8\njel;16.4\njel;14.7\njel;27.2\njel;21.7\njel;13.9\njel;16.7\njel;14.4\njel;18.1\njel;27.0\njel;17.0\njel;8.6\njel;23.7\njel;14.0\njel;5.5\njel;7.0\njel;18.8\njel;21.2\njel;31.5\njel;20.7\njel;32.5\njel;13.6\njel;25.4\njel;12.4\njel;23.1\njel;26.9\njel;32.7\njel;23.9\njel;19.7\njel;9.5\njel;8.8\njel;17.6\njel;18.2\njel;19.7\njel;8.5\njel;17.8\njel;25.6\njel;23.4\njel;16.7\njel;5.3\njel;11.2\njel;8.5\njel;15.1\njel;23.4\njel;20.6\njel;21.5\njel;16.4\njel;22.1\njel;24.3\njel;18.5\njel;11.6\njel;18.0\njel;18.0\njel;15.1\njel;19.0\njel;20.3\njel;10.5\njel;21.6\njel;23.9\njel;16.0\njel;20.6\njel;14.4\njel;14.6\njel;14.7\njel;22.9\njel;13.3\njel;18.5\njel;17.6\njel;16.3\njel;10.5\njel;28.0\njel;18.4\njel;-5.1\njel;20.1\njel;21.6\njel;17.4\njel;11.7\njel;3.8\njel;14.8\njel;23.0\njel;24.3\njel;15.1\njel;26.5\njel;10.4\njel;17.6\njel;31.0\njel;16.7\njel;17.2\njel;-2.0\njel;16.1\njel;19.7\njel;17.2\njel;16.9\njel;17.5\njel;11.6\njel;21.0\njel;13.6\njel;25.5\njel;29.7\njel;22.2\njel;15.4\njel;17.8\njel;24.0\njel;15.8\njel;23.9\njel;23.6\njel;17.1\njel;21.1\njel;19.7\njel;15.1\njel;20.6\njel;31.1\njel;17.6\njel;26.9\njel;13.9\njel;26.0\njel;21.3\njel;22.5\njel;21.9\njel;22.5\njel;27.3\njel;18.9\njel;15.0\njel;16.5\njel;19.7\njel;16.1\njel;13.1\njel;25.3\njel;25.6\njel;17.5\njel;19.4\njel;20.5\njel;23.0\njel;15.5\njel;22.5\njel;17.8\njel;25.5\njel;10.6\njel;14.2\njel;23.6\njel;21.7\njel;23.9\njel;17.9\njel;22.0\njel;11.7\njel;16.3\njel;5.5\njel;11.1\njel;20.5\njel;29.4\njel;24.5\njel;23.0\njel;13.7\njel;30.3\njel;23.8\njel;17.4\njel;7.2\njel;26.1\njel;6.5\njel;19.7\njel;23.4\njel;22.2\njel;18.1\njel;26.0\njel;12.3\njel;17.9\njel;16.7\njel;12.0\njel;23.7\njel;16.1\njel;22.3\njel;16.8\njel;25.3\njel;12.9\njel;13.5\njel;21.8\njel;23.6\njel;23.3\njel;5.1\njel;9.5\njel;11.1\njel;17.9\njel;17.0\njel;26.8\njel;27.4\njel;4.1\njel;10.7\njel;14.8\njel;19.5\njel;12.6\njel;30.2\njel;20.6\njel;10.1\njel;13.7\njel;18.4\njel;4.3\njel;23.1\njel;17.6\njel;14.3\njel;17.7\njel;23.7\njel;11.9\njel;13.7\njel;7.8\njel;14.3\njel;17.2\njel;5.1\njel;21.8\njel;5.7\njel;22.5\njel;22.6\njel;13.8\njel;26.9\njel;12.6\njel;19.8\njel;16.7\njel;17.0\njel;23.7\njel;11.4\njel;3.7\njel;11.1\njel;14.7\njel;20.7\njel;18.2\njel;9.6\njel;21.9\njel;11.5\njel;13.1\njel;16.2\njel;31.9\njel;9.4\njel;16.1\njel;21.7\njel;11.9\njel;19.1\njel;25.7\njel;21.7\njel;18.5\njel;5.5\njel;12.7\njel;11.5\njel;7.8\njel;21.6\njel;7.1\njel;12.4\njel;5.5\njel;25.8\njel;15.2\njel;17.6\njel;25.8\njel;7.5\njel;26.5\njel;30.3\njel;25.5\njel;20.0\njel;16.0\njel;21.2\njel;7.2\njel;7.6\njel;19.1\njel;26.4\njel;11.1\njel;10.2\njel;4.5\njel;27.6\njel;15.7\njel;-2.5\njel;18.7\njel;16.4\njel;14.9\njel;18.1\njel;23.0\njel;9.0\njel;14.5\njel;29.6\njel;5.6\njel;12.6\njel;12.7\njel;20.6\njel;26.2\njel;30.1\njel;26.4\njel;6.8\njel;8.9\njel;25.5\njel;34.0\njel;12.9\njel;7.5\njel;20.2\njel;34.0\njel;16.5\njel;21.3\njel;33.0\njel;26.8\njel;17.0\njel;8.9\njel;7.9\njel;2.3\njel;25.7\njel;25.2\njel;29.4\njel;9.1\njel;8.0\njel;20.5\njel;16.1\njel;14.2\njel;20.5\njel;15.6\njel;8.9\njel;11.2\njel;5.2\njel;12.3\njel;19.1\njel;18.3\njel;21.3\njel;25.9\njel;15.9\njel;11.5\njel;19.9\njel;30.8\njel;18.5\njel;29.4\njel;13.2\njel;20.1\njel;29.3\njel;26.0\njel;8.8\njel;32.9\njel;14.9\njel;15.7\njel;28.5\njel;7.7\njel;14.6\njel;15.4\njel;14.4\njel;17.8\njel;17.3\njel;8.9\njel;19.0\njel;22.8\njel;17.0\njel;21.6\njel;5.8\njel;22.7\njel;9.4\njel;17.6\njel;12.2\njel;19.8\njel;32.0\njel;22.2\njel;16.8\njel;21.4\njel;18.5\njel;19.7\njel;18.9\njel;9.3\njel;19.0\njel;14.9\njel;16.8\njel;17.5\njel;16.2\njel;22.6\njel;14.5\njel;7.5\njel;24.1\njel;23.4\njel;29.7\njel;20.5\njel;14.6\njel;29.1\njel;17.9\njel;15.1\njel;8.6\njel;24.6\njel;24.9\njel;15.0\njel;24.2\njel;15.7\njel;19.8\njel;19.3\njel;23.5\njel;6.8\njel;30.0\njel;10.0\njel;23.6\njel;25.0\njel;16.3\njel;24.3\njel;24.4\njel;18.2\njel;16.5\njel;15.3\njel;23.9\njel;14.4\njel;15.1\njel;27.2\njel;27.8\njel;24.9\njel;20.6\njel;39.4\njel;19.0\njel;14.9\njel;-3.7\njel;17.6\njel;21.8\njel;14.3\njel;25.8\njel;16.0\njel;32.1\njel;13.9\njel;24.2\njel;17.5\njel;12.4\njel;13.7\njel;32.9\njel;16.5\njel;7.3\njel;18.1\njel;-4.4\njel;13.2\njel;28.9\njel;32.6\njel;11.3\njel;11.4\njel;31.5\njel;24.8\njel;7.5\njel;12.5\njel;19.9\njel;10.1\njel;17.8\njel;13.0\njel;13.8\njel;15.6\njel;25.0\njel;12.4\njel;14.5\njel;10.2\njel;15.7\njel;24.1\njel;15.8\njel;16.1\njel;19.3\njel;12.7\njel;22.9\njel;14.9\njel;-0.3\njel;23.0\njel;7.6\njel;10.2\njel;-0.8\njel;17.0\njel;17.1\njel;16.0\njel;12.9\njel;24.4\njel;22.9\njel;14.3\njel;15.6\njel;16.8\njel;31.3\njel;28.3\njel;8.5\njel;23.8\njel;25.0\njel;21.5\njel;23.4\njel;4.5\njel;14.8\njel;24.1\njel;10.1\njel;9.9\njel;17.4\njel;26.8\njel;26.7\njel;14.7\njel;16.7\njel;15.4\njel;4.7\njel;19.2\njel;19.3\njel;24.9\njel;21.4\njel;21.2\njel;22.4\njel;21.7\njel;19.7\njel;19.1\njel;22.7\njel;21.0\njel;4.5\njel;28.8\njel;23.4\njel;18.4\njel;32.0\njel;27.9\njel;8.9\njel;11.9\njel;25.0\njel;12.0\njel;19.3\njel;19.0\njel;16.1\njel;14.0\njel;14.3\njel;25.0\njel;24.6\njel;13.7\njel;19.0\njel;10.3\njel;25.8\njel;14.9\njel;8.0\njel;12.1\njel;15.0\njel;28.7\njel;28.7\njel;12.9\njel;25.4\njel;11.0\njel;37.8\njel;9.2\njel;23.9\njel;28.4\njel;13.7\njel;15.8\njel;20.8\njel;19.4\njel;21.0\njel;8.9\njel;14.8\njel;27.0\njel;25.2\njel;32.1\njel;28.1\njel;5.7\njel;16.6\njel;22.7\njel;13.6\njel;9.9\njel;28.8\njel;14.0\njel;16.9\njel;14.0\njel;20.9\njel;23.1\njel;30.9\njel;21.9\njel;-1.5\njel;7.7\njel;27.8\njel;26.4\njel;21.8\njel;20.7\njel;28.7\njel;12.9\njel;5.3\njel;20.2\njel;24.8\njel;18.2\njel;25.1\njel;9.0\njel;7.3\njel;25.3\njel;11.2\njel;14.9\njel;9.3\njel;12.9\njel;23.6\njel;26.3\njel;5.2\njel;18.2\njel;35.8\njel;23.9\njel;30.0\njel;22.0\njel;20.1\njel;18.4\njel;15.6\njel;14.7\njel;27.1\njel;12.1\njel;12.6\njel;6.8\njel;13.9\njel;14.7\njel;15.9\njel;27.5\njel;25.7\njel;16.9\njel;22.8\njel;8.3\njel;20.2\njel;30.4\njel;17.9\njel;22.7\njel;20.8\njel;30.2\njel;3.9\njel;14.5\njel;12.4\njel;24.8\njel;26.5\njel;10.2\njel;13.6\njel;11.3\njel;16.2\njel;12.9\njel;23.7\njel;12.9\njel;22.8\njel;27.8\njel;28.3\njel;21.4\njel;10.0\njel;13.4\njel;11.1\njel;13.0\njel;17.4\njel;26.2\njel;12.8\njel;24.4\njel;23.5\njel;23.8\njel;15.0\njel;21.1\njel;15.6\njel;11.0\njel;22.4\njel;24.7\njel;24.8\njel;16.7\njel;-2.5\njel;5.7\njel;26.9\njel;24.3\njel;26.0\njel;16.8\njel;17.9\njel;18.2\njel;22.1\njel;12.1\njel;18.4\njel;29.0\njel;10.8\njel;26.7\njel;15.4\njel;17.8\njel;18.6\njel;6.7\njel;18.0\njel;19.7\njel;22.2\njel;17.3\njel;14.7\njel;6.5\njel;13.6\njel;11.0\njel;26.0\njel;20.8\njel;30.1\njel;7.0\njel;29.0\njel;2.9\njel;10.2\njel;10.6\njel;22.3\njel;16.3\njel;21.5\njel;8.4\njel;17.4\njel;24.5\njel;21.0\njel;19.6\njel;18.6\njel;32.5\njel;13.1\njel;6.1\njel;36.1\njel;14.4\njel;18.2\njel;14.0\njel;20.9\njel;21.5\njel;24.1\njel;9.3\njel;21.5\njel;14.9\njel;18.1\njel;18.3\njel;25.4\njel;15.0\njel;32.4\njel;12.9\njel;19.6\njel;28.2\njel;21.8\njel;7.0\njel;16.6\njel;17.8\njel;18.1\njel;5.8\njel;13.1\njel;22.8\njel;15.3\njel;34.1\njel;12.5\njel;14.8\njel;19.9\njel;15.4\njel;8.4\njel;7.0\njel;19.0\njel;29.3\njel;8.5\njel;11.4\njel;38.0\njel;8.1\njel;15.6\njel;26.4\njel;25.3\njel;27.3\njel;17.2\njel;13.7\njel;22.8\njel;33.8\njel;21.8\njel;17.6\njel;6.7\njel;10.4\njel;17.4\njel;18.2\njel;23.4\njel;22.6\njel;22.6\njel;24.1\njel;20.9\njel;20.4\njel;24.7\njel;22.1\njel;16.5\njel;20.9\njel;19.3\njel;17.4\njel;22.9\njel;18.8\njel;6.0\njel;7.3\njel;2.8\njel;18.9\njel;10.4\njel;21.9\njel;12.1\njel;7.0\njel;9.1\njel;10.6\njel;26.0\njel;8.2\njel;32.1\njel;24.4\njel;24.4\njel;12.3\njel;13.7\njel;8.7\njel;27.2\njel;28.1\njel;17.7\njel;14.4\njel;28.4\njel;19.8\njel;8.1\njel;29.9\njel;19.4\njel;26.1\njel;13.9\njel;20.5\njel;23.2\njel;16.7\njel;18.7\njel;19.9\njel;14.7\njel;12.8\njel;28.1\njel;16.8\njel;15.8\njel;15.6\njel;13.9\njel;33.5\njel;9.1\njel;18.7\njel;15.4\njel;9.1\njel;21.4\njel;21.3\njel;14.9\njel;24.6\njel;14.0\njel;22.7\njel;15.6\njel;14.9\njel;15.9\njel;15.0\njel;19.1\njel;11.0\njel;17.5\njel;9.7\njel;5.6\njel;17.0\njel;15.3\njel;18.5\njel;22.6\njel;22.2\njel;26.5\njel;22.4\njel;7.5\njel;17.3\njel;26.0\njel;17.3\njel;16.6\njel;11.3\njel;1.1\njel;16.5\njel;14.9\njel;14.9\njel;23.3\njel;5.7\njel;17.7\njel;19.4\njel;12.5\njel;2.4\njel;21.2\njel;21.0\njel;19.2\njel;28.3\njel;14.2\njel;23.6\njel;10.0\njel;18.7\njel;28.4\njel;10.6\njel;23.0\njel;17.6\njel;27.6\njel;16.8\njel;12.9\njel;26.0\njel;34.2\njel;22.3\njel;15.6\njel;25.0\njel;12.9\njel;10.3\njel;17.6\njel;21.2\njel;29.0\njel;26.8\njel;14.9\njel;14.0\njel;20.8\njel;26.4\njel;20.5\njel;21.1\njel;11.8\njel;28.6\njel;4.7\njel;15.6\njel;22.2\njel;19.9\njel;14.4\njel;16.9\njel;27.7\njel;10.3\njel;18.4\njel;29.3\njel;20.5\njel;15.7\njel;29.1\njel;20.0\njel;16.4\njel;19.0\njel;20.9\njel;11.9\njel;13.5\njel;24.2\njel;25.2\njel;11.5\njel;21.5\njel;6.0\njel;18.8\njel;22.8\njel;26.0\njel;14.8\njel;8.5\njel;6.4\njel;20.3\njel;10.3\njel;15.0\njel;2.9\njel;19.1\njel;10.0\njel;2.2\njel;14.3\njel;17.9\njel;10.2\njel;11.0\njel;21.6\njel;13.9\njel;11.9\njel;14.6\njel;15.4\njel;18.5\njel;11.4\njel;8.2\njel;9.4\njel;28.1\njel;6.0\njel;17.9\njel;19.7\njel;14.4\njel;31.6\njel;23.7\njel;32.6\njel;11.4\njel;9.9\njel;20.5\njel;18.4\njel;21.3\njel;10.4\njel;5.4\njel;13.7\njel;8.7\njel;24.2\njel;16.2\njel;20.9\njel;7.7\njel;22.3\njel;10.2\njel;23.6\njel;28.1\njel;9.7\njel;5.2\njel;24.5\njel;6.7\njel;16.6\njel;15.9\njel;12.6\njel;24.8\njel;7.0\njel;20.6\njel;29.7\njel;18.0\njel;22.4\njel;23.7\njel;19.9\njel;7.4\njel;6.1\njel;17.3\njel;20.6\njel;23.2\njel;14.9\njel;16.8\njel;22.9\njel;28.6\njel;23.9\njel;31.4\njel;28.4\njel;30.2\njel;24.7\njel;16.8\njel;7.2\njel;18.3\njel;15.4\njel;14.6\njel;16.6\njel;15.3\njel;22.6\njel;13.1\njel;23.5\njel;25.5\njel;18.7\njel;21.3\njel;17.1\njel;20.9\njel;28.0\njel;19.8\njel;11.4\njel;25.5\njel;19.5\njel;4.8\njel;24.8\njel;23.3\njel;26.7\njel;9.7\njel;16.2\njel;26.6\njel;24.3\njel;10.9\njel;26.6\njel;9.9\njel;22.8\njel;15.7\njel;20.0\njel;13.7\njel;18.5\njel;26.7\njel;15.1\njel;23.2\njel;20.8\njel;14.0\njel;20.2\njel;10.7\njel;19.5\njel;17.0\njel;18.5\njel;35.1\njel;10.3\njel;28.6\njel;18.0\njel;21.5\njel;13.8\njel;1.1\njel;14.7\njel;21.4\njel;17.8\njel;39.2\njel;10.4\njel;23.4\njel;28.2\njel;12.9\njel;29.3\njel;21.2\njel;14.6\njel;18.0\njel;12.9\njel;19.5\njel;14.4\njel;30.7\njel;40.9\njel;22.2\njel;7.4\njel;24.7\njel;17.1\njel;19.3\njel;13.7\njel;25.9\njel;24.2\njel;16.8\njel;25.3\njel;11.4\njel;10.5\njel;27.9\njel;15.9\njel;32.5\njel;-2.9\njel;19.3\njel;26.8\njel;15.6\njel;21.9\njel;19.1\njel;4.9\njel;17.3\njel;25.9\njel;19.5\njel;2.7\njel;20.2\njel;7.6\njel;15.6\njel;15.2\njel;26.3\njel;31.0\njel;22.6\njel;21.3\njel;10.5\njel;18.0\njel;16.4\njel;15.3\njel;19.6\njel;25.9\njel;29.2\njel;19.0\njel;21.4\njel;17.5\njel;2.2\njel;26.0\njel;18.8\njel;16.5\njel;10.6\njel;27.7\njel;28.4\njel;5.8\njel;22.1\njel;12.2\njel;19.8\njel;20.3\njel;36.5\njel;23.8\njel;10.7\njel;20.8\njel;31.0\njel;22.8\njel;12.6\njel;21.7\njel;16.8\njel;18.6\njel;20.1\njel;11.3\njel;18.3\njel;12.8\njel;12.2\njel;21.6\njel;11.0\njel;-0.5\njel;27.0\njel;27.4\njel;27.6\njel;8.4\njel;12.3\njel;21.6\njel;21.4\njel;19.4\njel;23.8\njel;19.5\njel;28.9\njel;29.1\njel;15.3\njel;14.4\njel;4.6\njel;17.2\njel;25.9\njel;22.1\njel;10.1\njel;19.8\njel;24.6\njel;7.0\njel;13.5\njel;19.9\njel;17.1\njel;16.6\njel;25.0\njel;30.1\njel;14.9\njel;7.0\njel;17.7\njel;15.0\njel;30.7\njel;10.9\njel;18.5\njel;20.9\njel;4.0\njel;28.6\njel;17.6\njel;25.8\njel;18.9\njel;14.1\njel;29.4\njel;25.5\njel;13.2\njel;14.3\njel;20.6\njel;23.6\njel;24.0\njel;16.8\njel;5.9\njel;16.2\njel;39.0\njel;22.5\njel;28.0\njel;8.8\njel;21.0\njel;8.7\njel;4.2\njel;22.1\njel;8.9\njel;22.9\njel;17.4\njel;12.7\njel;9.8\njel;10.8\njel;9.3\njel;25.0\njel;17.1\njel;16.2\njel;16.2\njel;27.5\njel;16.5\njel;26.8\njel;8.1\njel;13.6\njel;25.1\njel;15.5\njel;19.3\njel;8.6\njel;18.8\njel;6.7\njel;21.1\njel;13.6\njel;12.4\njel;29.4\njel;20.6\njel;24.9\njel;11.9\njel;27.9\njel;25.3\njel;8.3\njel;23.3\njel;20.1\njel;12.0\njel;32.2\njel;15.7\njel;14.1\njel;22.8\njel;21.1\njel;9.7\njel;-1.7\njel;16.7\njel;25.6\njel;14.9\njel;16.8\njel;10.7\njel;8.3\njel;16.1\njel;17.1\njel;10.7\njel;2.3\njel;15.0\njel;10.1\njel;17.4\njel;25.6\njel;10.7\njel;23.4\njel;18.1\njel;26.6\njel;9.1\njel;31.0\njel;31.2\njel;19.4\njel;11.0\njel;16.3\njel;18.3\njel;29.3\njel;18.8\njel;14.8\njel;19.2\njel;16.5\njel;29.5\njel;20.7\njel;23.6\njel;17.9\njel;8.2\njel;20.2\njel;17.9\njel;37.7\njel;19.4\njel;12.8\njel;13.3\njel;18.4\njel;1.7\njel;13.7\njel;7.8\njel;16.1\njel;9.4\njel;19.4\njel;18.7\njel;15.9\njel;22.7\njel;20.3\njel;15.9\njel;-4.7\njel;24.7\njel;20.1\njel;20.5\njel;16.3\njel;14.2\njel;29.5\njel;15.3\njel;1.4\njel;15.5\njel;21.2\njel;15.5\njel;26.0\njel;15.0\njel;23.3\njel;20.2\njel;13.7\njel;30.1\njel;28.0\njel;24.0\njel;17.0\njel;27.9\njel;12.4\njel;5.3\njel;27.9\njel;14.8\njel;23.3\njel;8.3\njel;8.8\njel;16.1\njel;22.2\njel;10.6\njel;12.1\njel;24.0\njel;20.8\njel;14.7\njel;17.0\njel;17.7\njel;19.0\njel;11.2\njel;27.0\njel;25.0\njel;20.3\njel;18.4\njel;18.1\njel;28.4\njel;28.7\njel;18.0\njel;19.9\njel;18.1\njel;24.5\njel;19.4\njel;19.6\njel;20.6\njel;7.3\njel;24.3\njel;19.8\njel;17.8\njel;12.1\njel;24.8\njel;16.5\njel;27.4\njel;16.4\njel;22.2\njel;20.7\njel;13.4\njel;15.3\njel;15.3\njel;23.5\njel;15.4\njel;15.8\njel;22.3\njel;14.3\njel;14.9\njel;11.6\njel;16.5\njel;14.5\njel;14.0\njel;17.6\njel;10.5\njel;9.8\njel;23.5\njel;20.0\njel;21.6\njel;9.6\njel;20.9\njel;16.4\njel;22.3\njel;4.2\njel;30.4\njel;28.2\njel;17.7\njel;15.9\njel;16.6\njel;33.5\njel;13.9\njel;14.7\njel;5.5\njel;22.1\njel;24.0\njel;25.7\njel;17.2\njel;15.9\njel;14.8\njel;22.2\njel;12.5\njel;25.5\njel;21.4\njel;24.1\njel;16.5\njel;20.4\njel;11.8\njel;27.0\njel;19.8\njel;21.2\njel;20.6\njel;29.1\njel;9.7\njel;14.1\njel;17.2\njel;18.7\njel;10.6\njel;13.9\njel;15.3\njel;31.0\njel;22.1\njel;26.6\njel;20.0\njel;3.8\njel;12.7\njel;20.3\njel;16.4\njel;9.3\njel;11.8\njel;23.1\njel;13.1\njel;15.1\njel;20.9\njel;2.6\njel;18.2\njel;19.4\njel;16.2\njel;17.8\njel;26.2\njel;14.4\njel;13.9\njel;20.7\njel;7.4\njel;19.5\njel;15.9\njel;13.4\njel;18.8\njel;23.6\njel;16.3\njel;19.6\njel;14.5\njel;17.6\njel;20.0\njel;20.6\njel;22.1\njel;11.3\njel;10.6\njel;33.0\njel;24.9\njel;28.2\njel;12.7\njel;7.0\njel;12.6\njel;20.2\njel;20.2\njel;14.0\njel;17.4\njel;26.8\njel;17.9\njel;15.0\njel;24.2\njel;5.5\njel;18.7\njel;15.9\njel;20.1\njel;26.8\njel;15.5\njel;16.0\njel;14.9\njel;9.9\njel;12.3\njel;13.0\njel;28.0\njel;19.6\njel;14.5\njel;18.9\njel;15.8\njel;19.2\njel;19.4\njel;17.6\njel;25.9\njel;20.8\njel;10.7\njel;15.8\njel;6.5\njel;14.8\njel;18.5\njel;18.8\njel;7.8\njel;21.2\njel;8.4\njel;3.0\njel;8.6\njel;14.3\njel;29.4\njel;25.0\njel;17.5\njel;27.5\njel;32.5\njel;34.3\njel;23.2\njel;18.8\njel;19.3\njel;11.1\njel;19.5\njel;22.0\njel;21.1\njel;23.3\njel;10.5\njel;20.1\njel;27.6\njel;21.9\njel;17.5\njel;23.4\njel;24.3\njel;27.1\njel;19.6\njel;21.6\njel;17.7\njel;16.3\njel;24.1\njel;10.9\njel;3.6\njel;7.8\njel;22.8\njel;9.5\njel;20.6\njel;20.6\njel;20.0\njel;10.6\njel;23.2\njel;14.1\njel;27.8\njel;12.6\njel;1.3\njel;17.7\njel;20.3\njel;31.1\njel;22.0\njel;23.4\njel;26.6\njel;21.3\njel;22.9\njel;8.3\njel;18.2\njel;15.2\njel;15.5\njel;9.1\njel;16.6\njel;10.8\njel;17.9\njel;21.7\njel;21.1\njel;20.8\njel;26.8\njel;23.7\njel;14.4\njel;19.3\njel;10.1\njel;8.9\njel;12.6\njel;19.2\njel;26.0\njel;24.6\njel;26.7\njel;21.5\njel;23.0\njel;23.6\njel;20.0\njel;21.1\njel;10.6\njel;19.4\njel;10.1\njel;14.8\njel;21.8\njel;18.1\njel;20.2\njel;15.6\njel;20.0\njel;11.6\njel;16.4\njel;11.4\njel;19.4\njel;24.6\njel;10.2\njel;19.6\njel;8.5\njel;24.8\njel;18.2\njel;26.1\njel;24.0\njel;13.8\njel;19.0\njel;25.6\njel;10.4\njel;21.3\njel;23.0\njel;22.6\njel;26.7\njel;9.5\njel;0.3\njel;13.0\njel;19.0\njel;16.7\njel;16.7\njel;8.1\njel;19.7\njel;20.0\njel;20.1\njel;24.1\njel;23.4\njel;25.8\njel;13.7\njel;12.1\njel;9.3\njel;8.0\njel;27.6\njel;19.8\njel;8.6\njel;28.2\njel;9.5\njel;11.3\njel;12.7\njel;21.8\njel;14.5\njel;27.4\njel;6.3\njel;3.8\njel;5.9\njel;16.4\njel;22.5\njel;21.6\njel;22.9\njel;12.8\njel;12.1\njel;21.3\njel;22.0\njel;20.2\njel;25.1\njel;8.0\njel;18.8\njel;19.9\njel;16.6\njel;20.3\njel;30.1\njel;18.5\njel;28.6\njel;17.4\njel;17.0\njel;2.9\njel;5.4\njel;21.8\njel;25.3\njel;7.3\njel;29.9\njel;24.8\njel;19.0\njel;25.3\njel;17.0\njel;17.6\njel;14.1\njel;22.6\njel;18.6\njel;25.8\njel;18.7\njel;16.9\njel;29.7\njel;11.2\njel;15.0\njel;17.8\njel;13.0\njel;12.2\njel;13.8\njel;16.3\njel;17.0\njel;14.3\njel;17.8\njel;27.5\njel;9.6\njel;10.2\njel;37.0\njel;24.4\njel;18.6\njel;-1.7\njel;35.8\njel;18.9\njel;15.2\njel;4.2\njel;27.9\njel;17.8\njel;16.2\njel;16.0\njel;22.2\njel;20.2\njel;15.1\njel;13.9\njel;11.8\njel;24.3\njel;12.7\njel;13.6\njel;12.7\njel;27.5\njel;18.0\njel;19.1\njel;20.3\njel;21.3\njel;22.4\njel;3.7\njel;9.1\njel;10.7\njel;14.7\njel;11.8\njel;10.0\njel;8.3\njel;12.5\njel;16.1\njel;29.7\njel;32.4\njel;15.1\njel;15.3\njel;25.7\njel;27.2\njel;23.1\njel;22.5\njel;17.4\njel;25.5\njel;21.4\njel;21.9\njel;12.2\njel;17.7\njel;17.8\njel;3.6\njel;17.9\njel;23.0\njel;17.2\njel;14.9\njel;7.7\njel;20.8\njel;19.3\njel;14.3\njel;13.3\njel;22.7\njel;17.2\njel;30.3\njel;19.2\njel;8.2\njel;19.0\njel;5.2\njel;13.8\njel;28.1\njel;11.7\njel;11.4\njel;22.4\njel;17.0\njel;20.2\njel;15.9\njel;27.8\njel;23.2\njel;17.9\njel;8.1\njel;16.5\njel;11.8\njel;21.5\njel;22.1\njel;31.5\njel;14.6\njel;19.5\njel;34.6\njel;19.2\njel;17.6\njel;25.1\njel;24.3\njel;21.1\njel;7.0\njel;17.5\njel;27.8\njel;16.8\njel;23.5\njel;23.3\njel;25.9\njel;13.0\njel;12.9\njel;21.3\njel;14.3\njel;22.3\njel;9.5\njel;11.0\njel;28.0\njel;28.0\njel;23.7\njel;17.8\njel;15.9\njel;26.3\njel;20.2\njel;17.3\njel;14.9\njel;25.1\njel;26.3\njel;16.5\njel;17.1\njel;23.8\njel;18.9\njel;6.5\njel;15.1\njel;4.2\njel;18.3\njel;22.8\njel;12.8\njel;16.4\njel;20.0\njel;31.1\njel;9.3\njel;13.5\njel;20.6\njel;24.8\njel;18.0\njel;17.4\njel;14.3\njel;17.5\njel;16.9\njel;18.6\njel;19.2\njel;15.5\njel;15.0\njel;14.3\njel;20.2\njel;20.1\njel;21.9\njel;20.1\njel;21.6\njel;21.1\njel;28.5\njel;3.3\njel;14.9\njel;14.4\njel;28.0\njel;14.8\njel;5.0\njel;15.2\njel;14.6\njel;23.0\njel;20.2\njel;8.6\njel;15.4\njel;15.5\njel;16.9\njel;34.3\njel;9.5\njel;27.8\njel;20.4\njel;29.8\njel;18.1\njel;15.4\njel;12.7\njel;19.1\njel;20.6\njel;26.9\njel;9.5\njel;5.9\njel;22.9\njel;18.0\njel;22.7\njel;23.3\njel;15.4\njel;25.7\njel;30.1\njel;23.2\njel;28.8\njel;24.8\njel;19.2\njel;14.2\njel;4.8\njel;19.7\njel;16.3\njel;27.0\njel;6.7\njel;23.3\njel;28.6\njel;27.8\njel;39.6\njel;9.2\njel;25.0\njel;15.6\njel;19.0\njel;20.6\njel;23.6\njel;27.7\njel;17.9\njel;12.7\njel;15.8\njel;12.5\njel;22.2\njel;20.3\njel;13.3\njel;26.5\njel;31.5\njel;23.3\njel;21.2\njel;15.5\njel;18.2\njel;5.8\njel;35.2\njel;18.9\njel;12.2\njel;11.3\njel;9.4\njel;31.9\njel;14.0\njel;18.3\njel;20.3\njel;14.4\njel;26.9\njel;28.3\njel;16.7\njel;20.5\njel;22.4\njel;15.0\njel;12.3\njel;25.4\njel;5.6\njel;8.1\njel;11.0\njel;6.3\njel;33.4\njel;22.5\njel;18.5\njel;32.1\njel;22.0\njel;19.8\njel;19.2\njel;20.5\njel;24.4\njel;6.2\njel;10.4\njel;22.5\njel;10.1\njel;17.8\njel;24.6\njel;18.7\njel;6.8\njel;26.0\njel;23.1\njel;0.7\njel;29.8\njel;31.3\njel;22.6\njel;22.8\njel;15.8\njel;25.7\njel;16.5\njel;10.9\njel;18.6\njel;27.8\njel;27.4\njel;10.4\njel;20.8\njel;23.6\njel;8.6\njel;12.5\njel;22.7\njel;22.2\njel;27.6\njel;13.0\njel;16.1\njel;10.1\njel;19.8\njel;18.2\njel;13.9\njel;29.0\njel;25.2\njel;12.0\njel;9.3\njel;23.5\njel;18.4\njel;22.3\njel;19.9\njel;13.5\njel;5.1\njel;14.2\njel;17.7\njel;12.5\njel;23.7\njel;12.6\njel;20.0\njel;16.1\njel;22.7\njel;11.9\njel;11.3\njel;15.1\njel;28.9\njel;15.2\njel;16.5\njel;13.4\njel;25.5\njel;30.3\njel;8.6\njel;24.7\njel;18.1\njel;24.2\njel;19.9\njel;23.0\njel;18.7\njel;19.6\njel;16.7\njel;25.4\njel;14.3\njel;9.0\njel;8.3\njel;20.0\njel;4.9\njel;21.2\njel;23.7\njel;17.9\njel;38.3\njel;16.5\njel;7.3\njel;10.2\njel;15.5\njel;28.1\njel;5.7\njel;27.5\njel;20.0\njel;16.2\njel;15.6\njel;13.8\njel;8.2\njel;11.6\njel;14.4\njel;18.3\njel;34.0\njel;24.0\njel;15.1\njel;23.6\njel;12.4\njel;16.5\njel;19.6\njel;11.1\njel;12.7\njel;13.4\njel;11.9\njel;18.4\njel;19.9\njel;20.3\njel;12.3\njel;7.3\njel;23.4\njel;20.6\njel;32.0\njel;14.8\njel;14.6\njel;10.9\njel;9.6\njel;19.7\njel;9.6\njel;17.3\njel;16.5\njel;18.0\njel;16.3\njel;12.7\njel;23.0\njel;17.5\njel;13.0\njel;7.1\njel;9.0\njel;7.8\njel;19.9\njel;24.7\njel;-0.1\njel;28.2\njel;15.5\njel;23.2\njel;11.9\njel;7.9\njel;20.2\njel;19.3\njel;28.5\njel;9.8\njel;2.6\njel;11.8\njel;33.3\njel;4.5\njel;17.7\njel;12.9\njel;9.3\njel;16.0\njel;16.8\njel;17.7\njel;15.0\njel;9.5\njel;15.6\njel;15.9\njel;5.0\njel;10.7\njel;28.4\njel;11.0\njel;8.6\njel;22.4\njel;17.6\njel;12.9\njel;18.3\njel;16.1\njel;24.3\njel;20.9\njel;19.4\njel;1.8\njel;29.2\njel;16.0\njel;18.2\njel;20.5\njel;11.7\njel;15.4\njel;15.2\njel;19.7\njel;23.7\njel;15.8\njel;23.7\njel;20.4\njel;14.7\njel;22.8\njel;13.7\njel;33.1\njel;15.7\njel;16.4\njel;21.9\njel;16.4\njel;22.5\njel;19.9\njel;4.0\njel;29.2\njel;17.7\njel;22.9\njel;18.8\njel;18.5\njel;21.8\njel;13.3\njel;11.1\njel;8.4\njel;17.7\njel;21.6\njel;28.6\njel;21.7\njel;12.0\njel;14.1\njel;9.5\njel;16.1\njel;20.3\njel;19.8\njel;10.7\njel;14.4\njel;8.5\njel;35.7\njel;16.4\njel;8.7\njel;23.1\njel;7.7\njel;24.7\njel;11.9\njel;9.6\njel;7.6\njel;27.4\njel;24.2\njel;14.3\njel;18.8\njel;13.0\njel;24.0\njel;14.5\njel;24.1\njel;20.9\njel;19.9\njel;19.1\njel;20.1\njel;16.2\njel;14.8\njel;15.8\njel;10.4\njel;23.6\njel;11.9\njel;23.6\njel;15.2\njel;10.7\njel;30.1\njel;27.7\njel;23.5\njel;29.1\njel;15.0\njel;15.6\njel;15.9\njel;12.8\njel;11.6\njel;17.6\njel;23.4\njel;18.5\njel;2.7\njel;10.5\njel;10.1\njel;14.8\njel;15.9\njel;20.7\njel;8.4\njel;16.4\njel;26.6\njel;8.9\njel;24.2\njel;25.5\njel;12.6\njel;21.7\njel;14.0\njel;20.5\njel;12.0\njel;16.2\njel;17.7\njel;18.1\njel;20.6\njel;9.7\njel;7.5\njel;17.3\njel;19.1\njel;24.8\njel;21.6\njel;18.4\njel;21.8\njel;17.2\njel;8.0\njel;32.5\njel;25.0\njel;17.1\njel;18.5\njel;23.3\njel;26.1\njel;24.1\njel;28.4\njel;13.1\njel;21.0\njel;16.4\njel;8.5\njel;12.3\njel;28.5\njel;22.4\njel;21.4\njel;9.3\njel;20.9\njel;17.1\njel;19.6\njel;23.0\njel;12.1\njel;15.9\njel;28.6\njel;10.1\njel;18.0\njel;14.7\njel;21.1\njel;28.2\njel;13.4\njel;15.9\njel;12.2\njel;16.1\njel;22.0\njel;32.2\njel;19.7\njel;20.6\njel;17.1\njel;14.9\njel;15.7\njel;14.5\njel;27.8\njel;13.3\njel;10.2\njel;8.4\njel;9.1\njel;13.0\njel;23.8\njel;26.1\njel;23.1\njel;2.4\njel;7.1\njel;14.0\njel;27.6\njel;24.7\njel;20.0\njel;3.7\njel;16.0\njel;26.3\njel;19.3\njel;33.2\njel;19.7\njel;20.2\njel;39.0\njel;9.7\njel;10.3\njel;27.9\njel;8.1\njel;17.0\njel;20.3\njel;19.6\njel;19.3\njel;12.4\njel;14.7\njel;18.3\njel;11.8\njel;11.0\njel;7.7\njel;19.5\njel;33.6\njel;18.5\njel;16.8\njel;26.8\njel;20.2\njel;20.7\njel;23.8\njel;16.5\njel;28.7\njel;24.4\njel;10.9\njel;30.1\njel;11.0\njel;5.8\njel;10.5\njel;26.2\njel;18.6\njel;15.2\njel;17.7\njel;1.1\njel;15.1\njel;21.2\njel;26.0\njel;28.2\njel;21.1\njel;31.8\njel;15.6\njel;14.9\njel;24.9\njel;30.3\njel;18.6\njel;16.6\njel;24.4\njel;6.7\njel;17.2\njel;20.7\njel;14.6\njel;11.9\njel;17.6\njel;22.0\njel;13.6\njel;7.8\njel;11.9\njel;22.2\njel;23.8\njel;16.4\njel;21.6\njel;13.6\njel;26.0\njel;16.4\njel;15.8\njel;25.6\njel;6.5\njel;26.1\njel;12.9\njel;19.5\njel;21.0\njel;11.3\njel;11.8\njel;24.6\njel;10.5\njel;0.1\njel;27.9\njel;15.8\njel;15.8\njel;23.4\njel;21.1\njel;7.7\njel;7.0\njel;19.7\njel;15.9\njel;22.6\njel;15.0\njel;11.9\njel;15.2\njel;13.5\njel;4.4\njel;24.9\njel;31.3\njel;28.2\njel;16.4\njel;14.4\njel;17.8\njel;9.6\njel;22.1\njel;18.0\njel;28.2\njel;18.2\njel;10.1\njel;17.1\njel;30.4\njel;12.3\njel;14.4\njel;10.7\njel;28.4\njel;14.5\njel;30.2\njel;14.0\njel;12.9\njel;18.3\njel;14.6\njel;11.3\njel;16.6\njel;8.1\njel;18.0\njel;21.7\njel;7.9\njel;15.5\njel;11.2\njel;18.9\njel;22.0\njel;19.7\njel;16.8\njel;10.0\njel;13.2\njel;20.5\njel;25.2\njel;18.2\njel;19.9\njel;21.9\njel;18.2\njel;20.5\njel;24.0\njel;31.1\njel;20.7\njel;19.0\njel;23.0\njel;11.9\njel;16.3\njel;29.4\njel;18.8\njel;11.9\njel;21.1\njel;10.9\njel;14.4\njel;11.8\njel;12.3\njel;21.0\njel;22.9\njel;18.5\njel;22.0\njel;12.3\njel;12.5\njel;23.3\njel;26.0\njel;26.6\njel;11.7\njel;18.4\njel;15.0\njel;7.5\njel;21.5\njel;9.4\njel;21.2\njel;24.5\njel;29.3\njel;-2.4\njel;15.8\njel;10.7\njel;13.1\njel;25.5\njel;20.7\njel;16.1\njel;14.9\njel;15.2\njel;25.4\njel;15.2\njel;11.9\njel;13.9\njel;19.6\njel;17.9\njel;10.0\njel;16.2\njel;16.7\njel;16.7\njel;16.1\njel;30.7\njel;17.7\njel;5.6\njel;17.4\njel;5.1\njel;27.0\njel;15.8\njel;22.7\njel;4.4\njel;25.8\njel;22.8\njel;17.5\njel;11.0\njel;29.7\njel;21.3\njel;30.5\njel;11.6\njel;8.6\njel;15.2\njel;13.7\njel;11.8\njel;22.4\njel;18.2\njel;14.2\njel;1.0\njel;20.5\njel;19.0\njel;14.1\njel;20.8\njel;18.1\njel;11.9\njel;21.8\njel;22.7\njel;12.8\njel;35.2\njel;23.7\njel;24.2\njel;11.2\njel;14.1\njel;22.8\njel;15.3\njel;20.7\njel;26.5\njel;26.3\njel;26.0\njel;18.2\njel;25.6\njel;12.8\njel;14.4\njel;14.3\njel;18.9\njel;4.6\njel;24.3\njel;20.3\njel;8.0\njel;18.4\njel;22.1\njel;25.3\njel;17.6\njel;19.6\njel;12.1\njel;27.8\njel;25.9\njel;14.5\njel;13.3\njel;17.9\njel;21.0\njel;14.9\njel;19.0\njel;20.1\njel;9.6\njel;13.2\njel;27.8\njel;12.5\njel;20.7\njel;8.0\njel;11.9\njel;22.7\njel;22.5\njel;17.4\njel;13.3\njel;6.6\njel;8.2\njel;16.1\njel;15.5\njel;22.4\njel;13.8\njel;27.4\njel;8.1\njel;11.1\njel;31.7\njel;19.7\njel;27.9\njel;9.9\njel;11.8\njel;21.4\njel;22.7\njel;24.9\njel;21.7\njel;11.0\njel;13.5\njel;11.3\njel;15.0\njel;29.0\njel;23.8\njel;16.6\njel;13.4\njel;15.4\njel;22.2\njel;22.2\njel;9.9\njel;22.3\njel;14.7\njel;19.5\njel;18.4\njel;23.7\njel;12.5\njel;13.8\njel;14.4\njel;13.5\njel;12.0\njel;28.9\njel;16.2\njel;19.1\njel;10.4\njel;11.6\njel;18.1\njel;27.4\njel;17.1\njel;15.0\njel;27.8\njel;24.3\njel;21.2\njel;14.5\njel;9.1\njel;12.0\njel;15.5\njel;23.6\njel;16.5\njel;9.4\njel;24.9\njel;12.5\njel;8.3\njel;24.0\njel;8.3\njel;15.9\njel;13.8\njel;19.1\njel;34.2\njel;18.6\njel;15.4\njel;16.2\njel;21.4\njel;23.4\njel;23.7\njel;30.1\njel;15.0\njel;24.1\njel;22.1\njel;29.6\njel;9.1\njel;15.5\njel;1.2\njel;10.3\njel;25.4\njel;20.4\njel;25.7\njel;29.0\njel;27.6\njel;14.3\njel;24.9\njel;20.6\njel;21.9\njel;24.6\njel;9.4\njel;13.2\njel;23.3\njel;21.8\njel;19.0\njel;18.5\njel;23.9\njel;19.5\njel;20.8\njel;19.6\njel;27.6\njel;15.5\njel;15.4\njel;14.2\njel;9.7\njel;15.9\njel;30.8\njel;11.4\njel;20.3\njel;7.0\njel;8.8\njel;23.7\njel;30.3\njel;14.5\njel;17.7\njel;15.7\njel;17.5\njel;12.1\njel;23.6\njel;16.9\njel;27.7\njel;0.5\njel;13.6\njel;10.4\njel;17.2\njel;17.1\njel;32.1\njel;10.7\njel;20.6\njel;12.1\njel;13.7\njel;21.5\njel;15.0\njel;18.4\njel;25.8\njel;19.6\njel;19.3\njel;25.3\njel;18.1\njel;20.0\njel;20.2\njel;12.4\njel;22.2\njel;33.3\njel;13.0\njel;17.2\njel;31.8\njel;8.6\njel;20.1\njel;24.5\njel;10.9\njel;17.8\njel;15.4\njel;8.1\njel;2.4\njel;14.2\njel;22.0\njel;14.2\njel;19.9\njel;18.6\njel;18.7\njel;21.6\njel;25.8\njel;20.2\njel;20.4\njel;20.5\njel;23.0\njel;19.3\njel;25.6\njel;9.0\njel;14.0\njel;23.2\njel;12.6\njel;12.3\njel;15.5\njel;23.6\njel;0.8\njel;11.3\njel;24.0\njel;24.9\njel;12.5\njel;17.1\njel;29.9\njel;22.9\njel;18.5\njel;13.8\njel;10.4\njel;20.4\njel;25.4\njel;19.7\njel;17.0\njel;25.3\njel;21.6\njel;19.2\njel;16.4\njel;19.2\njel;11.2\njel;17.2\njel;14.9\njel;21.1\njel;21.1\njel;17.4\njel;16.0\njel;30.5\njel;15.5\njel;18.2\njel;12.5\njel;20.9\njel;19.1\njel;19.2\njel;19.8\njel;27.2\njel;18.7\njel;19.7\njel;18.5\njel;18.7\njel;27.7\njel;27.0\njel;17.1\njel;20.8\njel;12.0\njel;10.9\njel;20.8\njel;23.0\njel;20.5\njel;26.8\njel;13.2\njel;15.2\njel;24.0\njel;28.5\njel;15.1\njel;25.9\njel;16.9\njel;21.1\njel;21.2\njel;13.7\njel;12.9\njel;28.9\njel;29.6\njel;19.0\njel;25.1\njel;15.1\njel;15.0\njel;25.0\njel;19.2\njel;27.2\njel;17.1\njel;28.3\njel;22.3\njel;27.2\njel;17.8\njel;28.0\njel;17.2\njel;13.8\njel;20.8\njel;10.7\njel;25.9\njel;20.5\njel;17.1\njel;14.9\njel;12.7\njel;7.9\njel;10.4\njel;27.9\njel;19.3\njel;19.5\njel;20.9\njel;15.5\njel;24.4\njel;17.3\njel;8.2\njel;18.8\njel;37.6\njel;22.3\njel;12.6\njel;16.3\njel;14.8\njel;23.6\njel;16.8\njel;11.6\njel;1.3\njel;8.6\njel;28.2\njel;11.4\njel;13.9\njel;21.6\njel;18.1\njel;24.3\njel;22.5\njel;5.9\njel;22.0\njel;15.7\njel;27.1\njel;17.7\njel;26.0\njel;5.5\njel;11.5\njel;16.4\njel;22.0\njel;13.4\njel;21.9\njel;24.7\njel;11.5\njel;9.0\njel;21.4\njel;16.6\njel;5.4\njel;15.4\njel;17.5\njel;21.2\njel;19.4\njel;12.9\njel;19.6\njel;21.6\njel;15.4\njel;11.0\njel;18.8\njel;8.0\njel;18.3\njel;17.1\njel;17.1\njel;15.1\njel;13.2\njel;21.8\njel;25.6\njel;21.0\njel;18.8\njel;28.9\njel;12.0\njel;19.8\njel;16.8\njel;20.2\njel;14.3\njel;18.0\njel;28.8\njel;11.8\njel;12.8\njel;19.8\njel;11.5\njel;30.8\njel;7.7\njel;17.3\njel;25.4\njel;15.0\njel;29.4\njel;6.8\njel;21.5\njel;4.3\njel;19.9\njel;22.5\njel;31.8\njel;12.8\njel;6.2\njel;9.9\njel;11.8\njel;13.8\njel;26.1\njel;15.3\njel;5.4\njel;6.4\njel;12.6\njel;13.5\njel;31.0\njel;25.4\njel;24.2\njel;11.5\njel;6.2\njel;16.5\njel;28.4\njel;23.5\njel;23.0\njel;17.4\njel;18.6\njel;16.1\njel;13.2\njel;18.1\njel;17.6\njel;36.6\njel;17.0\njel;21.8\njel;29.1\njel;21.1\njel;18.0\njel;20.4\njel;17.1\njel;5.5\njel;21.7\njel;12.8\njel;15.5\njel;20.3\njel;20.4\njel;22.1\njel;25.0\njel;25.0\njel;13.8\njel;17.6\njel;25.3\njel;27.0\njel;18.9\njel;14.5\njel;10.3\njel;1.9\njel;20.1\njel;2.3\njel;20.4\njel;30.2\njel;20.1\njel;32.0\njel;10.8\njel;21.3\njel;22.5\njel;25.8\njel;12.4\njel;10.3\njel;13.3\njel;9.8\njel;27.2\njel;22.4\njel;16.2\njel;12.1\njel;16.9\njel;31.3\njel;14.4\njel;23.9\njel;23.3\njel;32.1\njel;7.9\njel;26.9\njel;14.5\njel;8.2\njel;14.7\njel;23.3\njel;15.2\njel;28.0\njel;21.6\njel;26.6\njel;20.0\njel;17.1\njel;2.0\njel;9.7\njel;12.3\njel;17.8\njel;16.6\njel;22.2\njel;16.1\njel;16.1\njel;33.5\njel;18.6\njel;10.5\njel;17.9\njel;27.0\njel;8.3\njel;32.1\njel;27.4\njel;13.9\njel;25.2\njel;23.5\njel;25.1\njel;9.0\njel;0.9\njel;25.4\njel;17.6\njel;0.2\njel;31.8\njel;16.0\njel;11.8\njel;7.1\njel;16.3\njel;18.3\njel;19.4\njel;2.4\njel;15.3\njel;13.5\njel;24.5\njel;12.6\njel;23.9\njel;6.4\njel;18.2\njel;24.5\njel;11.8\njel;16.5\njel;24.4\njel;20.8\njel;25.2\njel;14.7\njel;20.8\njel;7.9\njel;18.8\njel;3.8\njel;27.0\njel;20.2\njel;13.8\njel;8.0\njel;19.1\njel;24.2\njel;29.6\njel;24.4\njel;20.5\njel;22.1\njel;26.2\njel;9.0\njel;31.9\njel;18.4\njel;10.9\njel;18.0\njel;14.7\njel;27.1\njel;19.9\njel;15.3\njel;8.0\njel;23.5\njel;22.6\njel;18.4\njel;14.9\njel;29.2\njel;23.8\njel;19.3\njel;26.0\njel;16.5\njel;26.0\njel;15.3\njel;16.5\njel;16.9\njel;5.1\njel;2.8\njel;22.5\njel;26.8\njel;16.0\njel;13.9\njel;15.8\njel;17.5\njel;9.1\njel;26.7\njel;21.1\njel;17.1\njel;26.5\njel;27.1\njel;13.8\njel;23.3\njel;27.9\njel;17.7\njel;16.0\njel;26.9\njel;22.7\njel;18.0\njel;27.7\njel;13.7\njel;30.5\njel;22.5\njel;15.7\njel;20.0\njel;29.5\njel;16.3\njel;27.1\njel;25.9\njel;16.8\njel;14.0\njel;27.3\njel;22.0\njel;18.0\njel;27.2\njel;21.5\njel;29.4\njel;15.3\njel;13.9\njel;17.5\njel;9.5\njel;17.9\njel;14.4\njel;12.0\njel;8.3\njel;20.0\njel;14.4\njel;16.2\njel;-2.3\njel;8.1\njel;21.5\njel;5.4\njel;15.8\njel;32.8\njel;1.2\njel;10.5\njel;17.2\njel;22.7\njel;21.8\njel;26.3\njel;14.5\njel;21.0\njel;36.1\njel;20.1\njel;19.4\njel;27.9\njel;26.1\njel;14.6\njel;21.1\njel;6.7\njel;12.2\njel;21.6\njel;14.7\njel;17.4\njel;14.2\njel;19.0\njel;18.4\njel;14.8\njel;22.2\njel;10.4\njel;28.9\njel;21.4\njel;28.9\njel;9.8\njel;20.7\njel;22.5\njel;32.7\njel;21.8\njel;27.6\njel;20.1\njel;26.7\njel;11.2\njel;20.0\njel;15.8\njel;20.2\njel;24.1\njel;23.5\njel;24.0\njel;40.0\njel;27.9\njel;19.1\njel;16.1\njel;10.3\njel;7.6\njel;16.0\njel;11.1\njel;20.0\njel;4.8\njel;10.3\njel;16.8\njel;10.1\njel;18.1\njel;10.1\njel;13.7\njel;25.7\njel;17.5\njel;24.1\njel;15.6\njel;17.2\njel;13.3\njel;21.4\njel;20.4\njel;9.9\njel;11.5\njel;20.8\njel;11.9\njel;22.0\njel;20.0\njel;1.8\njel;23.2\njel;23.3\njel;13.8\njel;16.1\njel;38.0\njel;6.6\njel;36.8\njel;0.8\njel;16.6\njel;22.6\njel;11.1\njel;31.6\njel;14.7\njel;32.5\njel;13.3\njel;9.2\njel;19.5\njel;29.0\njel;10.7\njel;11.7\njel;9.8\njel;13.7\njel;23.4\njel;18.5\njel;9.0\njel;18.3\njel;19.3\njel;21.3\njel;24.8\njel;37.4\njel;19.4\njel;22.9\njel;20.5\njel;24.0\njel;12.7\njel;18.8\njel;26.1\njel;18.5\njel;20.5\njel;17.5\njel;17.2\njel;9.4\njel;19.0\njel;29.8\njel;10.9\njel;25.0\njel;31.8\njel;24.0\njel;11.1\njel;22.6\njel;20.4\njel;5.0\njel;12.7\njel;24.1\njel;10.1\njel;16.2\njel;11.1\njel;17.9\njel;14.1\njel;7.0\njel;18.0\njel;19.9\njel;14.7\njel;17.3\njel;32.1\njel;18.8\njel;6.2\njel;22.1\njel;7.4\njel;19.6\njel;14.4\njel;10.4\njel;29.4\njel;17.7\njel;22.9\njel;9.7\njel;17.5\njel;14.8\njel;17.7\njel;16.0\njel;15.1\njel;22.5\njel;40.9\njel;34.7\njel;9.1\njel;7.9\njel;23.3\njel;10.1\njel;12.6\njel;22.1\njel;22.7\njel;13.9\njel;8.3\njel;17.9\njel;2.5\njel;19.0\njel;21.5\njel;16.9\njel;13.6\njel;20.7\njel;13.9\njel;6.8\njel;18.7\njel;13.3\njel;9.7\njel;21.1\njel;24.5\njel;24.5\njel;21.2\njel;15.2\njel;13.0\njel;24.3\njel;26.2\njel;30.1\njel;14.7\njel;25.3\njel;10.8\njel;11.3\njel;19.6\njel;24.2\njel;18.4\njel;11.1\njel;32.9\njel;15.1\njel;21.3\njel;33.5\njel;34.1\njel;10.6\njel;24.8\njel;22.4\njel;23.5\njel;22.2\njel;13.5\njel;18.4\njel;18.0\njel;29.0\njel;14.3\njel;19.5\njel;9.8\njel;20.7\njel;32.1\njel;8.5\njel;11.5\njel;24.4\njel;27.8\njel;18.6\njel;11.0\njel;13.8\njel;10.8\njel;25.0\njel;13.7\njel;19.8\njel;15.8\njel;16.1\njel;20.0\njel;13.2\njel;17.7\njel;11.1\njel;7.1\njel;31.9\njel;20.4\njel;19.3\njel;17.0\njel;20.7\njel;11.9\njel;13.9\njel;23.7\njel;26.4\njel;12.1\njel;25.7\njel;13.1\njel;22.3\njel;3.3\njel;25.7\njel;10.4\njel;27.1\njel;20.9\njel;22.9\njel;17.2\njel;27.2\njel;10.4\njel;21.0\njel;13.0\njel;24.2\njel;17.7\njel;18.4\njel;14.0\njel;28.0\njel;13.0\njel;23.4\njel;7.4\njel;27.2\njel;24.5\njel;14.3\njel;12.4\njel;10.6\njel;8.1\njel;16.9\njel;33.4\njel;20.5\njel;19.9\njel;11.3\njel;3.9\njel;-1.1\njel;9.6\njel;14.1\njel;18.0\njel;15.2\njel;27.4\njel;7.0\njel;19.1\njel;18.0\njel;17.2\njel;19.3\njel;19.8\njel;17.1\njel;26.2\njel;15.0\njel;37.3\njel;18.7\njel;2.4\njel;28.1\njel;15.7\njel;26.5\njel;21.2\njel;20.5\njel;10.1\njel;16.5\njel;22.3\njel;20.7\njel;20.7\njel;30.0\njel;31.9\njel;18.4\njel;13.5\njel;9.9\njel;11.3\njel;13.1\njel;19.0\njel;3.5\njel;22.6\njel;18.3\njel;14.8\njel;0.9\njel;15.1\njel;15.7\njel;11.2\njel;23.4\njel;18.0\njel;12.1\njel;12.3\njel;12.6\njel;30.3\njel;8.2\njel;20.7\njel;21.6\njel;15.1\njel;24.5\njel;20.5\njel;14.3\njel;21.7\njel;24.8\njel;26.5\njel;23.5\njel;13.6\njel;8.2\njel;15.4\njel;20.2\njel;25.7\njel;8.9\njel;17.9\njel;17.4\njel;13.4\njel;13.3\njel;4.5\njel;29.4\njel;22.8\njel;21.5\njel;2.8\njel;25.1\njel;10.2\njel;20.1\njel;16.7\njel;20.7\njel;22.2\njel;19.5\njel;26.7\njel;24.6\njel;34.4\njel;19.5\njel;27.7\njel;28.6\njel;7.4\njel;5.1\njel;16.4\njel;23.9\njel;17.8\njel;17.2\njel;16.4\njel;27.1\njel;12.5\njel;15.9\njel;20.2\njel;12.8\njel;13.2\njel;26.8\njel;5.9\njel;16.6\njel;17.3\njel;25.3\njel;1.8\njel;7.8\njel;19.7\njel;11.5\njel;29.9\njel;19.5\njel;19.8\njel;11.5\njel;4.9\njel;23.4\njel;16.6\njel;6.0\njel;24.5\njel;17.0\njel;22.1\njel;29.3\njel;16.7\njel;21.3\njel;6.2\njel;27.2\njel;10.6\njel;7.6\njel;19.5\njel;7.2\njel;12.1\njel;24.1\njel;22.8\njel;15.4\njel;13.3\njel;21.4\njel;11.8\njel;18.7\njel;19.1\njel;15.3\njel;14.2\njel;2.4\njel;17.3\njel;31.8\njel;13.0\njel;29.6\njel;15.9\njel;17.0\njel;17.5\njel;38.7\njel;14.6\njel;13.3\njel;13.0\njel;11.5\njel;21.6\njel;5.9\njel;19.9\njel;12.9\njel;13.8\njel;9.3\njel;24.6\njel;22.7\njel;32.6\njel;13.8\njel;21.0\njel;14.4\njel;22.3\njel;11.9\njel;28.7\njel;26.5\njel;16.3\njel;10.9\njel;25.5\njel;19.2\njel;14.9\njel;11.1\njel;8.2\njel;19.1\njel;17.4\njel;17.7\njel;24.1\njel;27.0\njel;4.2\njel;19.3\njel;20.8\njel;15.2\njel;30.7\njel;7.7\njel;17.1\njel;14.0\njel;18.1\njel;20.5\njel;13.2\njel;25.9\njel;15.5\njel;30.0\njel;14.2\njel;7.6\njel;28.5\njel;16.9\njel;10.5\njel;24.3\njel;13.6\njel;20.2\njel;22.9\njel;13.8\njel;15.2\njel;23.2\njel;27.0\njel;18.6\njel;24.5\njel;26.3\njel;17.4\njel;10.0\njel;19.1\njel;12.4\njel;21.0\njel;18.1\njel;18.5\njel;32.3\njel;14.6\njel;27.4\njel;23.3\njel;17.9\njel;18.7\njel;18.1\njel;15.4\njel;26.9\njel;21.1\njel;22.5\njel;19.6\njel;17.2\njel;15.5\njel;22.6\njel;29.3\njel;27.9\njel;21.5\njel;31.9\njel;18.0\njel;10.7\njel;5.1\njel;19.0\njel;23.8\njel;14.5\njel;15.0\njel;17.6\njel;7.4\njel;18.8\njel;21.6\njel;6.7\njel;19.6\njel;18.5\njel;26.5\njel;11.6\njel;28.8\njel;20.1\njel;21.4\njel;19.2\njel;6.6\njel;9.6\njel;14.3\njel;23.8\njel;26.7\njel;32.5\njel;17.8\njel;27.0\njel;21.5\njel;20.8\njel;1.8\njel;15.9\njel;14.0\njel;6.9\njel;17.2\njel;14.5\njel;12.5\njel;8.9\njel;21.6\njel;20.1\njel;10.9\njel;7.9\njel;6.7\njel;16.2\njel;28.6\njel;11.4\njel;14.7\njel;23.4\njel;15.1\njel;-1.4\njel;16.2\njel;9.5\njel;21.1\njel;24.1\njel;14.6\njel;27.9\njel;17.9\njel;26.9\njel;10.8\njel;10.5\njel;11.5\njel;34.0\njel;33.4\njel;20.9\njel;15.4\njel;3.7\njel;22.6\njel;18.4\njel;13.1\njel;6.7\njel;26.5\njel;19.6\njel;21.5\njel;20.7\njel;20.9\njel;27.0\njel;12.1\njel;9.0\njel;20.7\njel;17.5\njel;18.1\njel;8.9\njel;3.0\njel;15.6\njel;13.4\njel;9.9\njel;23.9\njel;8.9\njel;17.3\njel;26.7\njel;24.6\njel;20.4\njel;9.8\njel;17.3\njel;12.8\njel;17.0\njel;16.8\njel;13.1\njel;11.5\njel;20.1\njel;10.3\njel;22.1\njel;2.3\njel;24.1\njel;5.9\njel;13.9\njel;16.6\njel;21.1\njel;7.8\njel;15.3\njel;17.2\njel;27.1\njel;29.8\njel;17.1\njel;19.4\njel;24.9\njel;22.2\njel;15.8\njel;13.2\njel;5.2\njel;13.2\njel;19.1\njel;19.5\njel;17.3\njel;20.0\njel;17.9\njel;15.4\njel;12.5\njel;18.2\njel;21.6\njel;15.5\njel;18.3\njel;11.1\njel;29.1\njel;21.0\njel;13.5\njel;17.7\njel;8.0\njel;20.6\njel;26.0\njel;5.0\njel;19.4\njel;28.4\njel;12.6\njel;18.9\njel;15.4\njel;7.7\njel;15.0\njel;8.4\njel;22.2\njel;5.3\njel;20.6\njel;34.6\njel;14.9\njel;6.5\njel;9.3\njel;15.1\njel;23.3\njel;10.1\njel;22.8\njel;12.8\njel;31.1\njel;26.8\njel;14.0\njel;13.7\njel;13.4\njel;14.9\njel;21.2\njel;19.1\njel;22.1\njel;25.4\njel;25.4\njel;25.9\njel;27.1\njel;16.8\njel;7.3\njel;18.8\njel;13.1\njel;5.1\njel;6.2\njel;19.1\njel;10.4\njel;22.2\njel;19.0\njel;16.7\njel;27.4\njel;17.8\njel;28.6\njel;23.7\njel;21.0\njel;21.3\njel;24.6\njel;22.3\njel;19.6\njel;16.2\njel;33.2\njel;14.6\njel;23.5\njel;16.1\njel;32.4\njel;20.4\njel;9.2\njel;20.4\njel;12.5\njel;21.8\njel;15.9\njel;20.6\njel;20.8\njel;18.1\njel;16.0\njel;13.5\njel;15.5\njel;23.1\njel;9.6\njel;40.7\njel;13.2\njel;22.7\njel;27.7\njel;23.5\njel;17.9\njel;12.4\njel;21.9\njel;22.3\njel;12.0\njel;16.3\njel;20.5\njel;28.2\njel;18.4\njel;12.3\njel;14.9\njel;14.7\njel;17.6\njel;14.4\njel;4.7\njel;19.4\njel;13.8\njel;24.8\njel;12.0\njel;19.7\njel;21.1\njel;28.3\njel;22.6\njel;8.3\njel;19.2\njel;22.8\njel;9.6\njel;11.6\njel;27.2\njel;16.6\njel;8.6\njel;19.0\njel;18.4\njel;5.3\njel;12.9\njel;10.1\njel;25.2\njel;27.3\njel;13.4\njel;18.6\njel;7.6\njel;15.5\njel;8.5\njel;18.1\njel;24.9\njel;15.8\njel;33.0\njel;11.5\njel;13.3\njel;22.3\njel;16.2\njel;18.8\njel;13.6\njel;20.1\njel;7.6\njel;22.4\njel;15.2\njel;13.7\njel;22.9\njel;18.7\njel;19.0\njel;26.4\njel;21.1\njel;19.5\njel;14.0\njel;22.3\njel;12.3\njel;22.2\njel;7.3\njel;23.1\njel;23.2\njel;30.4\njel;16.7\njel;17.7\njel;15.6\njel;23.5\njel;29.8\njel;16.6\njel;15.1\njel;25.9\njel;22.5\njel;16.3\njel;21.0\njel;21.7\njel;21.3\njel;14.2\njel;14.8\njel;20.1\njel;19.8\njel;12.8\njel;6.7\njel;20.4\njel;31.5\njel;14.1\njel;14.4\njel;11.7\njel;-1.8\njel;7.3\njel;22.0\njel;17.5\njel;19.7\njel;12.9\njel;31.2\njel;25.5\njel;14.1\njel;12.6\njel;25.2\njel;16.0\njel;6.2\njel;12.2\njel;16.6\njel;6.9\njel;3.3\njel;9.6\njel;25.5\njel;25.7\njel;16.5\njel;27.0\njel;20.0\njel;6.1\njel;25.4\njel;16.5\njel;22.9\njel;24.7\njel;2.0\njel;10.2\njel;21.1\njel;25.6\njel;24.2\njel;21.5\njel;14.1\njel;16.5\njel;24.1\njel;25.1\njel;17.3\njel;20.5\njel;28.1\njel;29.3\njel;16.9\njel;29.3\njel;24.8\njel;18.6\njel;15.0\njel;6.5\njel;15.7\njel;7.7\njel;13.9\njel;22.6\njel;31.9\njel;17.1\njel;28.9\njel;12.4\njel;4.5\njel;21.0\njel;21.5\njel;23.7\njel;10.5\njel;9.5\njel;21.8\njel;15.7\njel;10.5\njel;17.4\njel;14.0\njel;17.0\njel;8.2\njel;12.2\njel;17.6\njel;29.0\njel;8.1\njel;8.6\njel;13.4\njel;21.5\njel;10.6\njel;10.1\njel;34.4\njel;23.1\njel;26.0\njel;16.3\njel;22.1\njel;8.2\njel;22.3\njel;14.3\njel;18.1\njel;7.0\njel;-0.5\njel;7.5\njel;19.6\njel;7.3\njel;19.6\njel;28.4\njel;29.2\njel;17.4\njel;17.4\njel;9.6\njel;23.4\njel;15.2\njel;20.7\njel;18.0\njel;21.0\njel;14.8\njel;3.4\njel;22.3\njel;16.7\njel;25.6\njel;4.3\njel;11.8\njel;4.2\njel;11.6\njel;23.2\njel;4.8\njel;20.6\njel;15.2\njel;15.7\njel;29.5\njel;12.9\njel;20.8\njel;7.2\njel;11.9\njel;16.4\njel;19.0\njel;29.0\njel;19.5\njel;27.5\njel;-0.9\njel;19.2\njel;25.8\njel;21.1\njel;18.3\njel;12.7\njel;13.2\njel;23.2\njel;21.9\njel;19.7\njel;31.3\njel;14.9\njel;27.3\njel;15.3\njel;13.5\njel;19.9\njel;15.2\njel;27.7\njel;23.4\njel;14.3\njel;12.6\njel;24.0\njel;23.1\njel;25.6\njel;16.0\njel;22.3\njel;8.5\njel;24.2\njel;15.0\njel;26.5\njel;11.8\njel;16.2\njel;18.9\njel;18.7\njel;13.7\njel;12.1\njel;24.5\njel;25.0\njel;20.2\njel;15.2\njel;17.8\njel;18.2\njel;16.7\njel;12.9\njel;19.9\njel;28.2\njel;13.6\njel;26.1\njel;15.6\njel;21.4\njel;20.9\njel;18.6\njel;12.4\njel;14.8\njel;9.9\njel;22.8\njel;11.1\njel;12.4\njel;17.4\njel;11.0\njel;24.6\njel;26.3\njel;22.3\njel;20.7\njel;21.8\njel;28.5\njel;16.7\njel;4.5\njel;7.8\njel;15.1\njel;28.8\njel;25.8\njel;15.8\njel;32.8\njel;25.9\njel;5.6\njel;9.3\njel;11.7\njel;4.7\njel;20.4\njel;24.0\njel;16.8\njel;5.0\njel;19.0\njel;33.9\njel;28.0\njel;21.5\njel;8.8\njel;15.8\njel;21.9\njel;10.9\njel;24.9\njel;11.7\njel;29.9\njel;22.7\njel;20.6\njel;27.5\njel;18.4\njel;15.7\njel;16.9\njel;14.8\njel;-0.6\njel;18.4\njel;27.4\njel;6.2\njel;27.6\njel;17.1\njel;11.3\njel;16.7\njel;21.3\njel;8.2\njel;17.7\njel;19.8\njel;21.1\njel;16.9\njel;18.3\njel;12.0\njel;16.1\njel;28.9\njel;11.3\njel;25.4\njel;9.5\njel;28.7\njel;27.1\njel;20.5\njel;5.8\njel;13.1\njel;9.2\njel;29.7\njel;22.9\njel;10.1\njel;9.5\njel;16.6\njel;14.1\njel;16.5\njel;12.9\njel;22.6\njel;7.6\njel;17.6\njel;28.5\njel;17.3\njel;23.2\njel;17.3\njel;7.2\njel;27.0\njel;8.3\njel;25.4\njel;24.5\njel;23.3\njel;15.3\njel;17.5\njel;21.8\njel;21.7\njel;19.0\njel;17.2\njel;29.5\njel;16.3\njel;20.8\njel;9.9\njel;14.7\njel;17.3\njel;15.8\njel;18.0\njel;27.9\njel;25.5\njel;22.5\njel;10.2\njel;26.5\njel;18.1\njel;6.8\njel;30.4\njel;17.7\njel;15.3\njel;22.4\njel;18.3\njel;12.8\njel;3.0\njel;12.5\njel;12.9\njel;8.2\njel;12.5\njel;19.8\njel;22.4\njel;14.4\njel;17.4\njel;15.2\njel;25.8\njel;12.4\njel;19.0\njel;10.6\njel;26.2\njel;27.4\njel;5.0\njel;15.9\njel;14.3\njel;27.8\njel;8.5\njel;17.2\njel;30.5\njel;21.6\njel;17.6\njel;12.2\njel;27.1\njel;23.6\njel;16.7\njel;13.7\njel;15.1\njel;18.1\njel;16.8\njel;28.0\njel;18.7\njel;17.1\njel;14.9\njel;28.1\njel;6.2\njel;18.8\njel;22.2\njel;20.3\njel;31.7\njel;13.6\njel;20.4\njel;15.5\njel;28.0\njel;6.5\njel;2.2\njel;8.8\njel;15.0\njel;12.4\njel;25.4\njel;22.9\njel;15.1\njel;25.9\njel;16.1\njel;11.7\njel;1.5\njel;20.3\njel;21.5\njel;15.1\njel;21.2\njel;21.1\njel;18.0\njel;17.6\njel;22.0\njel;27.1\njel;12.5\njel;15.8\njel;19.9\njel;28.1\njel;16.3\njel;9.5\njel;22.2\njel;21.2\njel;17.1\njel;12.6\njel;15.6\njel;9.3\njel;20.7\njel;13.3\njel;4.3\njel;34.1\njel;27.3\njel;26.9\njel;7.3\njel;15.6\njel;13.2\njel;20.4\njel;4.6\njel;9.7\njel;26.7\njel;19.9\njel;12.1\njel;16.6\njel;19.0\njel;25.5\njel;29.7\njel;14.8\njel;22.6\njel;15.2\njel;17.9\njel;8.9\njel;27.2\njel;15.9\njel;19.6\njel;18.7\njel;29.7\njel;24.0\njel;24.4\njel;18.1\njel;12.4\njel;27.7\njel;21.2\njel;15.9\njel;17.4\njel;16.1\njel;13.9\njel;34.2\njel;20.0\njel;19.5\njel;25.8\njel;16.4\njel;15.5\njel;26.6\njel;21.9\njel;25.5\njel;15.5\njel;5.2\njel;17.3\njel;30.4\njel;15.4\njel;37.9\njel;10.3\njel;21.4\njel;27.5\njel;14.5\njel;21.6\njel;15.9\njel;20.5\njel;0.3\njel;14.8\njel;16.0\njel;18.2\njel;10.5\njel;25.0\njel;28.3\njel;24.5\njel;19.2\njel;9.2\njel;29.3\njel;19.6\njel;14.3\njel;25.6\njel;17.4\njel;25.6\njel;24.8\njel;21.2\njel;19.2\njel;16.2\njel;10.0\njel;7.6\njel;11.9\njel;19.4\njel;17.7\njel;13.8\njel;19.7\njel;13.9\njel;24.1\njel;17.8\njel;26.1\njel;4.7\njel;18.7\njel;18.1\njel;8.2\njel;18.1\njel;27.1\njel;12.2\njel;22.2\njel;30.1\njel;27.3\njel;24.6\njel;20.8\njel;4.5\njel;-0.5\njel;23.9\njel;17.2\njel;17.9\njel;24.1\njel;28.7\njel;20.9\njel;13.9\njel;18.7\njel;19.5\njel;12.0\njel;13.3\njel;10.5\njel;27.8\njel;20.8\njel;17.2\njel;6.6\njel;18.4\njel;8.5\njel;9.6\njel;5.3\njel;21.7\njel;27.0\njel;25.8\njel;24.4\njel;8.9\njel;17.1\njel;24.9\njel;21.5\njel;20.7\njel;21.7\njel;16.9\njel;19.2\njel;8.4\njel;21.1\njel;13.9\njel;23.8\njel;16.7\njel;12.5\njel;14.8\njel;23.1\njel;21.1\njel;15.8\njel;28.7\njel;11.9\njel;27.3\njel;16.7\njel;18.8\njel;0.4\njel;25.2\njel;11.2\njel;19.9\njel;35.0\njel;20.3\njel;10.9\njel;23.5\njel;13.7\njel;17.4\njel;25.2\njel;30.8\njel;29.5\njel;17.9\njel;20.4\njel;19.6\njel;16.7\njel;10.8\njel;25.8\njel;18.4\njel;15.1\njel;7.3\njel;16.5\njel;20.9\njel;26.5\njel;30.8\njel;11.2\njel;15.8\njel;21.1\njel;23.1\njel;26.5\njel;13.4\njel;19.4\njel;14.6\njel;18.0\njel;13.1\njel;2.5\njel;18.0\njel;18.7\njel;18.1\njel;28.3\njel;19.8\njel;27.2\njel;17.4\njel;25.7\njel;18.3\njel;16.9\njel;15.8\njel;32.4\njel;22.1\njel;25.5\njel;22.1\njel;22.4\njel;24.3\njel;21.5\njel;13.0\njel;23.1\njel;25.5\njel;12.9\njel;18.3\njel;17.4\njel;26.0\njel;15.8\njel;22.4\njel;29.2\njel;9.3\njel;26.0\njel;45.4\njel;15.9\njel;11.7\njel;17.9\njel;17.2\njel;18.9\njel;12.6\njel;28.1\njel;25.8\njel;19.6\njel;15.6\njel;14.2\njel;16.0\njel;17.8\njel;17.0\njel;20.6\njel;21.0\njel;15.3\njel;16.3\njel;7.9\njel;30.2\njel;21.5\njel;29.0\njel;23.2\njel;4.9\njel;15.7\njel;41.9\njel;6.6\njel;8.9\njel;14.7\njel;23.6\njel;21.2\njel;8.7\njel;27.6\njel;22.8\njel;14.7\njel;10.1\njel;10.8\njel;23.4\njel;22.1\njel;18.5\njel;14.2\njel;10.9\njel;15.5\njel;16.8\njel;13.6\njel;21.8\njel;10.0\njel;15.0\njel;25.2\njel;9.6\njel;12.6\njel;22.8\njel;21.6\njel;23.5\njel;17.8\njel;6.3\njel;3.9\njel;8.2\njel;18.4\njel;23.3\njel;20.5\njel;26.9\njel;12.7\njel;21.5\njel;24.6\njel;24.7\njel;21.8\njel;28.5\njel;15.5\njel;17.8\njel;24.0\njel;21.1\njel;10.9\njel;9.3\njel;27.6\njel;28.9\njel;15.7\njel;23.2\njel;11.1\njel;15.7\njel;37.8\njel;27.1\njel;32.4\njel;22.5\njel;11.5\njel;24.8\njel;22.3\njel;24.0\njel;11.4\njel;23.0\njel;-0.9\njel;18.8\njel;22.9\njel;16.5\njel;30.2\njel;15.1\njel;6.5\njel;24.0\njel;13.9\njel;32.6\njel;21.6\njel;21.9\njel;20.0\njel;4.4\njel;31.6\njel;14.7\njel;24.5\njel;15.1\njel;14.9\njel;20.1\njel;18.4\njel;9.8\njel;17.9\njel;23.3\njel;15.9\njel;19.5\njel;19.5\njel;20.9\njel;28.0\njel;19.5\njel;19.8\njel;14.8\njel;17.3\njel;25.0\njel;20.2\njel;14.8\njel;14.7\njel;30.6\njel;10.3\njel;20.5\njel;17.3\njel;5.7\njel;16.8\njel;21.8\njel;31.0\njel;13.8\njel;31.8\njel;20.9\njel;17.8\njel;15.8\njel;32.8\njel;31.7\njel;13.0\njel;19.9\njel;25.7\njel;15.9\njel;26.2\njel;13.9\njel;28.1\njel;15.5\njel;10.8\njel;14.7\njel;21.2\njel;11.2\njel;22.5\njel;17.6\njel;15.1\njel;13.7\njel;30.9\njel;17.2\njel;22.0\njel;9.0\njel;11.4\njel;10.2\njel;17.8\njel;19.5\njel;15.6\njel;18.1\njel;27.9\njel;22.9\njel;25.3\njel;22.6\njel;7.0\njel;22.4\njel;21.9\njel;25.3\njel;18.3\njel;15.5\njel;20.0\njel;22.4\njel;22.0\njel;8.5\njel;14.8\njel;6.9\njel;34.5\njel;23.7\njel;23.4\njel;13.3\njel;9.6\njel;16.0\njel;10.2\njel;21.6\njel;22.6\njel;12.0\njel;16.2\njel;26.7\njel;27.4\njel;-1.0\njel;14.0\njel;10.2\njel;14.7\njel;17.3\njel;13.2\njel;11.0\njel;20.9\njel;13.8\njel;14.4\njel;25.3\njel;18.2\njel;8.4\njel;8.7\njel;12.4\njel;31.2\njel;30.8\njel;22.7\njel;17.1\njel;25.5\njel;11.7\njel;34.4\njel;22.3\njel;5.5\njel;13.7\njel;13.9\njel;12.2\njel;18.6\njel;25.5\njel;33.1\njel;19.3\njel;15.2\njel;14.1\njel;17.1\njel;15.0\njel;5.4\njel;15.8\njel;23.6\njel;13.6\njel;24.1\njel;29.3\njel;16.5\njel;28.3\njel;4.6\njel;23.9\njel;19.7\njel;22.4\njel;15.2\njel;7.2\njel;23.1\njel;11.8\njel;27.6\njel;20.4\njel;23.3\njel;17.3\njel;25.9\njel;21.6\njel;9.3\njel;18.9\njel;18.2\njel;35.6\njel;22.9\njel;5.1\njel;14.3\njel;10.7\njel;12.5\njel;25.8\njel;13.4\njel;20.7\njel;-1.1\njel;21.3\njel;21.9\njel;11.9\njel;26.0\njel;18.5\njel;10.0\njel;23.6\njel;22.5\njel;21.4\njel;15.7\njel;26.9\njel;15.1\njel;23.0\njel;22.4\njel;15.7\njel;23.2\njel;4.0\njel;18.0\njel;23.9\njel;30.7\njel;13.5\njel;11.4\njel;19.3\njel;9.6\njel;7.2\njel;19.3\njel;23.5\njel;11.6\njel;24.8\njel;14.0\njel;14.1\njel;30.0\njel;13.4\njel;14.2\njel;17.0\njel;31.3\njel;5.6\njel;22.6\njel;32.5\njel;21.9\njel;11.1\njel;15.5\njel;23.7\njel;12.0\njel;13.7\njel;13.2\njel;13.7\njel;22.5\njel;22.2\njel;29.0\njel;5.2\njel;6.2\njel;14.5\njel;22.5\njel;21.5\njel;22.8\njel;16.8\njel;10.2\njel;13.5\njel;15.0\njel;9.9\njel;12.1\njel;23.2\njel;20.7\njel;17.2\njel;21.8\njel;26.1\njel;22.2\njel;26.2\njel;16.5\njel;25.1\njel;21.6\njel;12.5\njel;12.6\njel;23.4\njel;14.4\njel;11.6\njel;23.8\njel;24.2\njel;15.5\njel;26.3\njel;28.6\njel;21.8\njel;20.8\njel;33.4\njel;29.8\njel;29.5\njel;38.3\njel;10.7\njel;21.0\njel;6.5\njel;11.1\njel;19.8\njel;19.2\njel;16.9\njel;9.6\njel;16.9\njel;20.7\njel;27.6\njel;12.3\njel;11.1\njel;14.1\njel;28.3\njel;21.7\njel;28.6\njel;23.9\njel;14.9\njel;27.9\njel;19.6\njel;7.7\njel;17.2\njel;15.2\njel;15.0\njel;10.2\njel;12.6\njel;24.4\njel;20.5\njel;25.9\njel;17.5\njel;21.5\njel;33.0\njel;29.7\njel;26.6\njel;12.0\njel;15.2\njel;12.7\njel;12.6\njel;20.6\njel;22.7\njel;15.6\njel;20.4\njel;25.4\njel;8.8\njel;18.7\njel;18.2\njel;27.3\njel;7.7\njel;25.2\njel;11.4\njel;20.2\njel;15.1\njel;14.4\njel;19.6\njel;22.8\njel;17.7\njel;25.6\njel;9.3\njel;8.8\njel;9.6\njel;18.0\njel;19.7\njel;13.5\njel;17.4\njel;30.0\njel;31.2\njel;17.9\njel;4.8\njel;20.1\njel;17.3\njel;2.2\njel;19.6\njel;28.0\njel;7.7\njel;15.9\njel;28.0\njel;15.1\njel;14.0\njel;12.7\njel;15.0\njel;30.8\njel;7.7\njel;11.5\njel;10.1\njel;15.9\njel;17.7\njel;32.2\njel;12.7\njel;22.4\njel;26.8\njel;18.2\njel;4.7\njel;14.0\njel;18.5\njel;15.2\njel;9.6\njel;12.3\njel;14.7\njel;24.5\njel;14.3\njel;11.8\njel;33.9\njel;25.5\njel;6.6\njel;33.3\njel;14.1\njel;14.1\njel;21.2\njel;23.0\njel;28.7\njel;7.2\njel;10.8\njel;15.4\njel;20.7\njel;21.4\njel;15.4\njel;13.5\njel;12.4\njel;16.3\njel;10.1\njel;15.8\njel;22.2\njel;6.5\njel;14.7\njel;17.1\njel;23.5\njel;21.3\njel;28.3\njel;33.9\njel;21.3\njel;15.6\njel;19.5\njel;17.6\njel;16.6\njel;12.1\njel;15.1\njel;15.0\njel;19.2\njel;12.8\njel;12.8\njel;18.2\njel;16.2\njel;13.7\njel;8.5\njel;20.2\njel;20.7\njel;24.1\njel;16.8\njel;22.0\njel;19.2\njel;19.7\njel;30.5\njel;12.6\njel;20.5\njel;12.6\njel;13.7\njel;16.0\njel;25.4\njel;6.0\njel;19.8\njel;29.1\njel;23.2\njel;23.0\njel;19.0\njel;19.7\njel;17.0\njel;22.1\njel;26.6\njel;10.4\njel;11.3\njel;3.9\njel;25.1\njel;19.0\njel;20.5\njel;21.9\njel;13.7\njel;25.9\njel;21.5\njel;19.6\njel;26.0\njel;14.7\njel;30.2\njel;26.0\njel;15.6\njel;13.0\njel;4.8\njel;17.0\njel;7.3\njel;-0.8\njel;11.7\njel;26.0\njel;13.4\njel;22.0\njel;7.4\njel;11.4\njel;15.7\njel;23.7\njel;7.6\njel;19.2\njel;5.0\njel;15.7\njel;19.9\njel;16.8\njel;9.2\njel;11.6\njel;16.1\njel;9.4\njel;4.7\njel;16.3\njel;8.7\njel;14.2\njel;19.2\njel;26.5\njel;26.0\njel;28.5\njel;7.9\njel;20.0\njel;15.1\njel;20.9\njel;20.7\njel;20.0\njel;22.3\njel;19.3\njel;10.6\njel;35.2\njel;8.2\njel;13.7\njel;28.2\njel;13.9\njel;9.0\njel;26.3\njel;21.7\njel;9.1\njel;28.5\njel;17.2\njel;7.9\njel;10.0\njel;26.2\njel;15.2\njel;17.7\njel;27.4\njel;13.7\njel;28.5\njel;22.1\njel;22.9\njel;12.7\njel;27.1\njel;20.6\njel;20.9\njel;6.6\njel;4.9\njel;6.8\njel;23.4\njel;20.0\njel;27.4\njel;19.7\njel;19.4\njel;14.5\njel;9.9\njel;22.1\njel;10.9\njel;12.1\njel;14.2\njel;14.7\njel;16.0\njel;25.0\njel;18.2\njel;21.6\njel;24.6\njel;25.1\njel;17.0\njel;23.6\njel;28.5\njel;22.0\njel;10.8\njel;10.3\njel;21.6\njel;16.9\njel;18.5\njel;12.3\njel;32.3\njel;6.8\njel;31.3\njel;22.8\njel;23.1\njel;27.5\njel;30.2\njel;20.7\njel;35.5\njel;6.9\njel;7.6\njel;19.7\njel;18.8\njel;23.6\njel;4.7\njel;26.3\njel;19.5\njel;20.4\njel;12.7\njel;19.7\njel;25.4\njel;16.7\njel;19.0\njel;19.9\njel;24.3\njel;13.3\njel;20.7\njel;19.8\njel;30.2\njel;16.2\njel;29.4\njel;17.4\njel;18.8\njel;20.0\njel;6.5\njel;19.3\njel;26.7\njel;7.6\njel;11.4\njel;15.9\njel;7.3\njel;15.3\njel;12.2\njel;26.1\njel;17.5\njel;15.4\njel;21.2\njel;16.6\njel;33.3\njel;15.4\njel;8.4\njel;16.0\njel;24.0\njel;26.7\njel;11.6\njel;13.7\njel;12.0\njel;16.4\njel;13.1\njel;7.5\njel;10.1\njel;18.8\njel;9.0\njel;21.0\njel;18.5\njel;14.5\njel;10.1\njel;11.6\njel;37.4\njel;20.3\njel;-1.2\njel;11.8\njel;11.4\njel;16.9\njel;21.2\njel;17.0\njel;16.5\njel;19.9\njel;22.6\njel;23.8\njel;10.4\njel;14.7\njel;9.8\njel;21.5\njel;17.7\njel;20.7\njel;13.2\njel;16.1\njel;24.6\njel;13.8\njel;27.3\njel;16.6\njel;24.3\njel;12.6\njel;13.1\njel;17.4\njel;12.1\njel;13.9\njel;16.6\njel;19.5\njel;16.8\njel;9.3\njel;17.7\njel;20.5\njel;22.5\njel;13.9\njel;15.7\njel;4.3\njel;35.6\njel;8.3\njel;9.4\njel;9.1\njel;22.1\njel;19.2\njel;24.5\njel;13.7\njel;18.5\njel;21.2\njel;16.8\njel;34.7\njel;4.1\njel;19.7\njel;23.1\njel;15.0\njel;14.9\njel;7.3\njel;5.4\njel;16.8\njel;16.2\njel;11.8\njel;23.3\njel;11.6\njel;18.4\njel;10.1\njel;16.2\njel;16.4\njel;25.7\njel;18.8\njel;9.2\njel;8.6\njel;31.7\njel;17.9\njel;16.0\njel;18.3\njel;4.1\njel;32.3\njel;7.8\njel;11.0\njel;17.0\njel;0.5\njel;11.8\njel;31.7\njel;25.2\njel;26.4\njel;26.2\njel;18.7\njel;25.3\njel;18.8\njel;19.9\njel;19.7\njel;20.0\njel;24.2\njel;7.8\njel;18.0\njel;25.6\njel;29.3\njel;22.0\njel;15.7\njel;13.3\njel;18.9\njel;17.2\njel;17.6\njel;13.4\njel;23.4\njel;19.7\njel;11.3\njel;19.2\njel;20.8\njel;10.7\njel;18.7\njel;21.8\njel;22.9\njel;21.6\njel;5.0\njel;13.4\njel;25.6\njel;20.2\njel;18.1\njel;18.3\njel;14.0\njel;24.0\njel;18.3\njel;24.7\njel;22.9\njel;24.4\njel;17.2\njel;13.5\njel;29.1\njel;9.9\njel;14.3\njel;24.2\njel;13.8\njel;15.1\njel;8.5\njel;12.3\njel;27.4\njel;3.4\njel;4.4\njel;20.1\njel;34.2\njel;25.3\njel;13.3\njel;29.7\njel;17.8\njel;9.7\njel;30.1\njel;6.1\njel;28.0\njel;22.9\njel;19.3\njel;23.0\njel;15.1\njel;21.2\njel;12.7\njel;17.5\njel;19.4\njel;29.4\njel;17.6\njel;16.1\njel;5.9\njel;14.4\njel;23.7\njel;27.7\njel;18.1\njel;28.7\njel;22.3\njel;9.9\njel;22.6\njel;24.1\njel;23.4\njel;10.9\njel;3.6\njel;19.7\njel;22.6\njel;24.0\njel;18.9\njel;34.4\njel;20.5\njel;18.9\njel;9.8\njel;21.3\njel;13.1\njel;24.0\njel;20.3\njel;20.2\njel;18.7\njel;18.8\njel;28.7\njel;24.8\njel;20.5\njel;25.8\njel;18.4\njel;15.3\njel;16.3\njel;33.1\njel;5.7\njel;13.4\njel;23.8\njel;20.2\njel;24.7\njel;31.3\njel;18.0\njel;18.4\njel;16.1\njel;40.0\njel;17.6\njel;23.6\njel;20.1\njel;4.9\njel;14.9\njel;27.4\njel;23.4\njel;18.5\njel;16.7\njel;20.2\njel;26.2\njel;25.9\njel;29.6\njel;15.9\njel;28.9\njel;34.1\njel;15.3\njel;18.8\njel;17.2\njel;25.9\njel;25.1\njel;11.5\njel;12.2\njel;5.3\njel;6.9\njel;9.5\njel;14.4\njel;24.5\njel;5.3\njel;32.9\njel;26.3\njel;10.3\njel;16.1\njel;9.2\njel;19.0\njel;22.2\njel;16.0\njel;25.3\njel;3.8\njel;17.2\njel;25.2\njel;23.5\njel;17.0\njel;12.5\njel;27.5\njel;19.1\njel;12.0\njel;14.1\njel;21.5\njel;37.5\njel;23.6\njel;23.1\njel;33.7\njel;16.8\njel;6.0\njel;8.2\njel;22.6\njel;14.4\njel;18.6\njel;21.8\njel;8.7\njel;7.3\njel;13.5\njel;14.3\njel;27.1\njel;29.9\njel;21.2\njel;9.0\njel;21.4\njel;8.7\njel;19.8\njel;28.7\njel;25.3\njel;27.2\njel;15.9\njel;26.9\njel;22.8\njel;5.5\njel;22.7\njel;24.4\njel;27.1\njel;25.3\njel;24.9\njel;19.6\njel;18.4\njel;18.4\njel;13.5\njel;20.8\njel;21.0\njel;17.2\njel;17.0\njel;16.4\njel;15.5\njel;16.9\njel;14.8\njel;6.5\njel;16.0\njel;18.9\njel;22.9\njel;25.6\njel;8.1\njel;32.9\njel;18.5\njel;15.3\njel;23.5\njel;24.0\njel;24.3\njel;20.7\njel;18.0\njel;15.6\njel;16.4\njel;13.3\njel;20.2\njel;8.1\njel;19.6\njel;12.4\njel;12.2\njel;24.1\njel;15.5\njel;15.9\njel;22.3\njel;17.4\njel;21.9\njel;6.0\njel;36.0\njel;10.3\njel;19.0\njel;19.4\njel;25.6\njel;23.4\njel;19.5\njel;9.5\njel;27.8\njel;23.5\njel;24.1\njel;19.2\njel;12.6\njel;26.9\njel;16.2\njel;12.7\njel;13.8\njel;18.8\njel;13.7\njel;14.1\njel;19.6\njel;28.4\njel;31.7\njel;19.5\njel;23.1\njel;14.9\njel;26.2\njel;6.7\njel;23.6\njel;25.1\njel;23.3\njel;14.2\njel;13.1\njel;17.1\njel;17.3\njel;13.8\njel;20.1\njel;8.9\njel;16.7\njel;20.0\njel;10.5\njel;5.8\njel;14.9\njel;11.0\njel;14.4\njel;11.6\njel;24.1\njel;26.0\njel;19.1\njel;16.1\njel;20.9\njel;22.8\njel;19.4\njel;23.4\njel;16.6\njel;21.7\njel;13.4\njel;15.9\njel;29.5\njel;21.4\njel;9.5\njel;19.6\njel;13.4\njel;19.8\njel;16.2\njel;20.1\njel;16.6\njel;11.6\njel;24.0\njel;16.5\njel;6.3\njel;17.0\njel;-1.6\njel;26.4\njel;10.8\njel;17.4\njel;27.3\njel;13.3\njel;30.8\njel;24.0\njel;21.4\njel;19.3\njel;24.7\njel;29.4\njel;24.1\njel;10.6\njel;7.0\njel;23.6\njel;25.0\njel;23.3\njel;25.3\njel;30.4\njel;15.1\njel;21.1\njel;22.7\njel;14.0\njel;24.2\njel;1.5\njel;15.0\njel;17.0\njel;14.7\njel;16.5\njel;12.9\njel;9.4\njel;8.3\njel;3.8\njel;23.4\njel;22.8\njel;15.5\njel;20.7\njel;14.7\njel;9.5\njel;16.4\njel;23.2\njel;12.2\njel;14.3\njel;16.5\njel;20.1\njel;15.7\njel;12.1\njel;10.4\njel;22.8\njel;28.0\njel;39.9\njel;13.3\njel;17.3\njel;23.2\njel;13.1\njel;8.6\njel;21.5\njel;12.4\njel;18.6\njel;11.0\njel;8.8\njel;5.2\njel;27.8\njel;16.6\njel;10.8\njel;16.6\njel;18.1\njel;24.2\njel;24.6\njel;17.2\njel;11.8\njel;25.8\njel;27.1\njel;16.6\njel;24.7\njel;12.1\njel;27.5\njel;14.4\njel;31.6\njel;14.5\njel;32.3\njel;25.0\njel;6.6\njel;10.0\njel;19.0\njel;8.2\njel;9.6\njel;33.1\njel;21.5\njel;17.9\njel;15.8\njel;20.9\njel;17.2\njel;8.5\njel;19.5\njel;31.2\njel;11.2\njel;22.4\njel;26.5\njel;9.1\njel;19.8\njel;17.4\njel;16.8\njel;12.4\njel;31.1\njel;13.9\njel;21.4\njel;18.0\njel;16.3\njel;14.4\njel;15.5\njel;17.1\njel;26.5\njel;27.0\njel;20.0\njel;10.1\njel;11.9\njel;20.8\njel;12.7\njel;13.8\njel;23.6\njel;19.2\njel;19.2\njel;18.3\njel;28.0\njel;24.1\njel;20.3\njel;16.6\njel;16.1\njel;11.6\njel;25.8\njel;10.3\njel;11.4\njel;31.7\njel;19.8\njel;10.2\njel;10.1\njel;18.9\njel;17.2\njel;19.9\njel;16.5\njel;24.0\njel;14.9\njel;6.9\njel;10.8\njel;26.0\njel;17.7\njel;25.3\njel;17.8\njel;29.2\njel;25.2\njel;23.6\njel;18.9\njel;18.2\njel;21.9\njel;11.9\njel;16.8\njel;8.3\njel;17.0\njel;0.3\njel;20.2\njel;18.8\njel;18.5\njel;23.1\njel;10.5\njel;12.0\njel;13.8\njel;23.3\njel;18.7\njel;18.0\njel;16.0\njel;20.4\njel;21.2\njel;5.6\njel;23.3\njel;20.5\njel;20.9\njel;13.5\njel;15.5\njel;23.1\njel;24.1\njel;11.0\njel;19.6\njel;11.3\njel;17.0\njel;19.9\njel;28.4\njel;24.8\njel;12.7\njel;20.7\njel;31.9\njel;15.4\njel;20.7\njel;25.2\njel;17.1\njel;25.1\njel;10.8\njel;20.2\njel;1.1\njel;14.4\njel;17.0\njel;21.8\njel;11.6\njel;9.1\njel;20.9\njel;22.2\njel;3.3\njel;7.0\njel;9.1\njel;9.3\njel;21.2\njel;13.9\njel;13.3\njel;28.4\njel;26.7\njel;11.7\njel;4.1\njel;10.1\njel;20.2\njel;17.3\njel;25.6\njel;22.4\njel;21.7\njel;25.7\njel;16.1\njel;8.5\njel;12.0\njel;16.2\njel;25.6\njel;22.0\njel;25.5\njel;29.1\njel;10.2\njel;20.8\njel;20.1\njel;15.6\njel;5.0\njel;23.3\njel;15.2\njel;6.1\njel;15.9\njel;19.9\njel;19.6\njel;9.9\njel;11.6\njel;18.0\njel;28.0\njel;32.1\njel;22.5\njel;24.8\njel;22.4\njel;23.4\njel;18.1\njel;15.2\njel;-2.6\njel;17.5\njel;23.4\njel;11.2\njel;28.8\njel;19.4\njel;8.1\njel;19.5\njel;17.2\njel;25.5\njel;15.1\njel;24.3\njel;24.4\njel;11.3\njel;17.3\njel;13.3\njel;19.8\njel;9.9\njel;21.3\njel;17.0\njel;28.2\njel;7.5\njel;18.4\njel;16.1\njel;29.0\njel;19.9\njel;13.0\njel;16.2\njel;20.8\njel;21.1\njel;20.6\njel;11.5\njel;35.7\njel;24.5\njel;16.2\njel;23.7\njel;21.7\njel;12.7\njel;22.2\njel;18.0\njel;18.9\njel;18.1\njel;4.6\njel;20.7\njel;20.0\njel;18.8\njel;13.1\njel;12.6\njel;19.4\njel;15.8\njel;31.6\njel;22.0\njel;2.6\njel;20.6\njel;18.7\njel;23.7\njel;24.8\njel;13.8\njel;16.7\njel;27.9\njel;35.6\njel;21.8\njel;19.3\njel;13.4\njel;31.4\njel;9.0\njel;27.1\njel;13.3\njel;16.2\njel;26.0\njel;22.4\njel;25.6\njel;32.0\njel;26.4\njel;11.7\njel;19.8\njel;33.1\njel;28.6\njel;22.1\njel;13.2\njel;25.2\njel;19.2\njel;13.9\njel;19.2\njel;16.6\njel;22.1\njel;28.4\njel;17.2\njel;16.2\njel;20.6\njel;22.4\njel;16.4\njel;13.1\njel;9.3\njel;24.9\njel;10.4\njel;37.9\njel;14.5\njel;5.8\njel;18.7\njel;1.9\njel;27.0\njel;14.8\njel;15.1\njel;12.5\njel;22.3\njel;19.2\njel;13.3\njel;14.7\njel;20.7\njel;23.1\njel;-1.6\njel;22.1\njel;10.9\njel;5.7\njel;27.5\njel;21.7\njel;6.2\njel;25.5\njel;20.9\njel;17.3\njel;10.2\njel;7.7\njel;30.9\njel;3.3\njel;21.4\njel;25.7\njel;20.5\njel;9.2\njel;4.0\njel;14.9\njel;17.8\njel;16.7\njel;15.3\njel;21.6\njel;22.4\njel;21.5\njel;25.6\njel;19.4\njel;23.3\njel;18.9\njel;24.4\njel;10.7\njel;19.0\njel;8.0\njel;6.8\njel;9.1\njel;20.6\njel;18.9\njel;9.6\njel;15.6\njel;22.3\njel;18.0\njel;25.2\njel;17.8\njel;24.4\njel;23.2\njel;22.1\njel;20.5\njel;29.7\njel;18.2\njel;14.2\njel;18.8\njel;15.5\njel;20.9\njel;32.2\njel;20.8\njel;22.4\njel;7.6\njel;18.0\njel;19.7\njel;12.7\njel;15.6\njel;15.8\njel;18.4\njel;14.7\njel;14.4\njel;16.8\njel;13.3\njel;16.1\njel;19.9\njel;26.0\njel;14.0\njel;19.6\njel;15.0\njel;6.5\njel;24.5\njel;17.7\njel;17.5\njel;14.5\njel;12.8\njel;18.4\njel;29.7\njel;18.1\njel;22.0\njel;6.7\njel;18.8\njel;10.1\njel;9.5\njel;18.9\njel;18.0\njel;24.2\njel;17.3\njel;7.2\njel;27.9\njel;26.0\njel;4.6\njel;17.2\njel;20.3\njel;10.5\njel;17.6\njel;16.2\njel;22.5\njel;15.9\njel;13.6\njel;14.9\njel;22.9\njel;25.1\njel;18.0\njel;15.5\njel;9.1\njel;17.2\njel;21.6\njel;27.7\njel;18.6\njel;14.9\njel;10.9\njel;11.7\njel;22.7\njel;7.8\njel;23.8\njel;16.7\njel;22.8\njel;17.8\njel;21.7\njel;13.6\njel;8.7\njel;21.4\njel;23.7\njel;14.5\njel;17.3\njel;18.0\njel;13.7\njel;24.6\njel;28.8\njel;16.3\njel;10.2\njel;22.5\njel;27.1\njel;14.9\njel;16.3\njel;15.1\njel;24.2\njel;13.4\njel;14.6\njel;28.4\njel;16.2\njel;22.5\njel;18.5\njel;22.8\njel;15.1\njel;33.6\njel;13.1\njel;21.9\njel;12.7\njel;10.6\njel;28.4\njel;17.4\njel;15.9\njel;35.2\njel;15.9\njel;19.6\njel;19.4\njel;25.7\njel;0.0\njel;6.6\njel;9.5\njel;22.8\njel;20.5\njel;16.7\njel;29.7\njel;9.5\njel;10.9\njel;20.0\njel;23.3\njel;22.7\njel;19.9\njel;11.2\njel;7.2\njel;18.2\njel;10.0\njel;16.5\njel;14.5\njel;18.5\njel;17.1\njel;17.8\njel;17.6\njel;13.6\njel;9.5\njel;15.0\njel;14.9\njel;4.8\njel;24.2\njel;26.9\njel;8.1\njel;23.8\njel;26.6\njel;12.2\njel;8.3\njel;20.8\njel;16.7\njel;24.4\njel;15.3\njel;26.6\njel;20.6\njel;17.6\njel;10.4\njel;25.3\njel;28.4\njel;16.1\njel;23.2\njel;9.1\njel;12.4\njel;14.6\njel;25.2\njel;17.4\njel;23.6\njel;21.5\njel;31.6\njel;-0.7\njel;15.0\njel;7.5\njel;12.6\njel;21.0\njel;24.2\njel;17.6\njel;21.6\njel;18.1\njel;17.3\njel;11.0\njel;19.9\njel;19.2\njel;8.3\njel;18.8\njel;15.1\njel;28.9\njel;17.7\njel;17.5\njel;27.7\njel;12.2\njel;21.3\njel;13.2\njel;18.8\njel;25.9\njel;13.6\njel;14.5\njel;21.8\njel;7.6\njel;31.2\njel;11.7\njel;14.4\njel;19.6\njel;10.7\njel;28.5\njel;17.3\njel;10.6\njel;7.5\njel;19.5\njel;13.0\njel;10.3\njel;12.7\njel;11.1\njel;30.0\njel;24.9\njel;16.7\njel;23.1\njel;11.3\njel;6.9\njel;6.8\njel;24.1\njel;26.6\njel;14.3\njel;22.9\njel;26.3\njel;25.4\njel;20.0\njel;18.0\njel;9.8\njel;15.9\njel;26.7\njel;16.7\njel;19.3\njel;14.2\njel;14.2\njel;13.7\njel;15.4\njel;19.4\njel;24.2\njel;19.0\njel;10.3\njel;12.6\njel;15.0\njel;20.8\njel;14.3\njel;16.0\njel;12.4\njel;29.0\njel;21.0\njel;20.1\njel;24.9\njel;29.6\njel;16.1\njel;2.2\njel;14.8\njel;28.2\njel;10.8\njel;6.0\njel;11.0\njel;11.1\njel;26.7\njel;18.2\njel;19.1\njel;13.0\njel;17.0\njel;30.7\njel;14.3\njel;18.9\njel;24.4\njel;19.4\njel;13.1\njel;10.3\njel;27.7\njel;20.3\njel;12.6\njel;9.6\njel;8.3\njel;14.7\njel;11.2\njel;14.3\njel;31.8\njel;20.5\njel;21.5\njel;17.9\njel;8.8\njel;19.5\njel;28.0\njel;28.1\njel;11.9\njel;14.8\njel;18.1\njel;13.4\njel;18.6\njel;15.2\njel;11.6\njel;17.5\njel;22.2\njel;9.0\njel;13.9\njel;20.5\njel;14.6\njel;34.0\njel;21.3\njel;13.2\njel;23.3\njel;28.1\njel;22.6\njel;18.8\njel;4.7\njel;14.4\njel;26.8\njel;16.7\njel;22.9\njel;9.2\njel;13.9\njel;22.6\njel;36.3\njel;19.6\njel;17.0\njel;11.4\njel;18.7\njel;15.7\njel;25.0\njel;27.6\njel;16.6\njel;25.4\njel;15.2\njel;15.9\njel;17.2\njel;21.3\njel;16.8\njel;21.1\njel;11.3\njel;21.6\njel;12.5\njel;12.5\njel;10.3\njel;23.9\njel;32.3\njel;28.9\njel;20.1\njel;18.1\njel;16.1\njel;14.3\njel;9.8\njel;24.1\njel;3.4\njel;19.8\njel;15.3\njel;18.5\njel;13.9\njel;27.2\njel;18.6\njel;21.3\njel;13.3\njel;21.5\njel;18.7\njel;22.1\njel;9.2\njel;8.4\njel;9.4\njel;30.9\njel;24.9\njel;27.6\njel;10.7\njel;15.5\njel;28.6\njel;23.8\njel;12.0\njel;14.4\njel;17.9\njel;28.9\njel;18.1\njel;18.7\njel;19.2\njel;24.0\njel;23.0\njel;19.9\njel;16.2\njel;5.1\njel;19.4\njel;21.5\njel;24.2\njel;16.5\njel;19.4\njel;11.0\njel;21.1\njel;15.0\njel;2.0\njel;18.2\njel;21.3\njel;10.2\njel;21.4\njel;12.7\njel;27.9\njel;17.2\njel;17.0\njel;14.2\njel;33.8\njel;17.7\njel;13.2\njel;24.1\njel;21.0\njel;16.2\njel;18.2\njel;16.8\njel;12.4\njel;14.1\njel;17.8\njel;7.0\njel;15.7\njel;28.4\njel;13.5\njel;21.1\njel;10.7\njel;12.0\njel;33.2\njel;16.7\njel;19.2\njel;23.0\njel;12.7\njel;22.2\njel;20.9\njel;26.2\njel;9.5\njel;25.6\njel;26.5\njel;16.9\njel;19.8\njel;25.5\njel;18.6\njel;16.6\njel;9.3\njel;17.5\njel;22.0\njel;23.3\njel;9.8\njel;0.4\njel;17.4\njel;11.9\njel;22.2\njel;19.4\njel;20.2\njel;21.8\njel;17.2\njel;14.8\njel;25.5\njel;20.1\njel;13.5\njel;18.3\njel;22.6\njel;21.2\njel;28.0\njel;18.4\njel;15.4\njel;8.5\njel;23.8\njel;1.2\njel;28.9\njel;15.3\njel;14.4\njel;29.2\njel;30.5\njel;17.1\njel;18.2\njel;15.9\njel;23.1\njel;35.7\njel;13.9\njel;13.8\njel;8.6\njel;12.9\njel;9.4\njel;10.9\njel;15.7\njel;9.4\njel;23.7\njel;14.9\njel;21.1\njel;23.0\njel;16.4\njel;20.5\njel;19.1\njel;27.0\njel;16.1\njel;27.1\njel;7.6\njel;18.5\njel;9.9\njel;7.8\njel;16.4\njel;26.6\njel;9.0\njel;14.1\njel;21.7\njel;17.0\njel;19.1\njel;14.9\njel;14.6\njel;16.8\njel;23.0\njel;30.0\njel;33.8\njel;26.4\njel;16.5\njel;12.8\njel;28.7\njel;12.3\njel;21.5\njel;17.8\njel;8.2\njel;27.5\njel;17.7\njel;22.5\njel;14.4\njel;17.8\njel;11.5\njel;14.9\njel;19.9\njel;23.0\njel;-0.2\njel;15.1\njel;28.2\njel;21.2\njel;25.9\njel;27.0\njel;18.9\njel;15.9\njel;12.1\njel;10.1\njel;10.6\njel;17.9\njel;13.8\njel;16.3\njel;21.0\njel;23.4\njel;20.9\njel;15.8\njel;21.1\njel;3.9\njel;11.6\njel;22.5\njel;24.1\njel;-0.4\njel;22.3\njel;4.2\njel;18.4\njel;15.0\njel;17.2\njel;12.2\njel;25.4\njel;8.6\njel;25.8\njel;14.1\njel;18.8\njel;9.4\njel;14.7\njel;25.4\njel;23.6\njel;29.6\njel;22.1\njel;24.7\njel;14.0\njel;24.6\njel;20.1\njel;19.7\njel;22.1\njel;19.4\njel;17.4\njel;25.6\njel;7.2\njel;4.8\njel;25.0\njel;18.3\njel;10.8\njel;22.9\njel;13.8\njel;22.7\njel;21.4\njel;17.4\njel;6.3\njel;24.0\njel;17.1\njel;23.5\njel;32.8\njel;34.5\njel;7.1\njel;26.5\njel;11.1\njel;31.3\njel;9.8\njel;14.2\njel;7.4\njel;17.8\njel;15.4\njel;21.4\njel;21.4\njel;28.3\njel;20.0\njel;21.6\njel;37.9\njel;11.9\njel;15.7\njel;17.5\njel;28.8\njel;20.8\njel;13.4\njel;14.8\njel;31.6\njel;27.3\njel;1.4\njel;31.3\njel;24.4\njel;15.7\njel;25.7\njel;18.9\njel;15.2\njel;17.4\njel;16.4\njel;12.0\njel;21.5\njel;17.2\njel;24.2\njel;20.7\njel;19.5\njel;23.1\njel;24.6\njel;16.4\njel;19.3\njel;14.6\njel;22.3\njel;17.1\njel;19.4\njel;16.9\njel;5.0\njel;15.0\njel;17.6\njel;9.7\njel;18.3\njel;20.9\njel;28.9\njel;26.4\njel;6.8\njel;11.9\njel;12.3\njel;9.3\njel;14.8\njel;16.7\njel;25.6\njel;12.5\njel;5.8\njel;18.9\njel;15.4\njel;18.8\njel;21.5\njel;12.3\njel;12.3\njel;24.1\njel;27.0\njel;20.6\njel;13.9\njel;15.9\njel;27.3\njel;8.2\njel;13.8\njel;15.2\njel;10.0\njel;20.9\njel;13.5\njel;14.2\njel;17.5\njel;11.4\njel;18.6\njel;21.2\njel;20.3\njel;25.5\njel;-6.4\njel;9.2\njel;8.7\njel;17.3\njel;29.0\njel;16.4\njel;4.1\njel;15.0\njel;17.4\njel;22.6\njel;5.2\njel;28.1\njel;9.5\njel;10.3\njel;17.0\njel;17.7\njel;15.2\njel;5.9\njel;18.5\njel;21.6\njel;1.9\njel;13.6\njel;22.5\njel;17.6\njel;19.5\njel;11.7\njel;19.1\njel;14.6\njel;25.4\njel;29.1\njel;10.2\njel;17.9\njel;31.3\njel;18.2\njel;12.7\njel;14.1\njel;19.5\njel;22.7\njel;6.1\njel;5.7\njel;15.0\njel;19.7\njel;11.4\njel;13.2\njel;12.4\njel;23.5\njel;24.5\njel;19.2\njel;3.5\njel;24.3\njel;13.9\njel;11.8\njel;30.8\njel;12.8\njel;28.3\njel;8.3\njel;29.8\njel;8.0\njel;25.2\njel;22.4\njel;11.7\njel;26.8\njel;7.7\njel;20.6\njel;10.8\njel;13.6\njel;21.9\njel;29.4\njel;-3.0\njel;21.1\njel;31.7\njel;21.2\njel;16.0\njel;26.3\njel;17.6\njel;20.6\njel;24.3\njel;19.9\njel;20.4\njel;14.1\njel;24.4\njel;22.1\njel;10.0\njel;22.5\njel;19.3\njel;16.5\njel;24.9\njel;13.6\njel;16.3\njel;25.9\njel;30.8\njel;20.4\njel;24.6\njel;18.5\njel;12.8\njel;28.1\njel;15.4\njel;14.8\njel;15.5\njel;15.5\njel;16.7\njel;10.2\njel;23.9\njel;18.4\njel;12.9\njel;18.4\njel;24.8\njel;17.4\njel;23.4\njel;9.5\njel;15.4\njel;27.0\njel;18.4\njel;17.7\njel;9.2\njel;19.5\njel;16.6\njel;26.1\njel;6.8\njel;32.3\njel;17.6\njel;20.9\njel;17.5\njel;1.1\njel;21.4\njel;7.7\njel;25.0\njel;13.8\njel;5.1\njel;22.7\njel;23.4\njel;26.7\njel;17.3\njel;4.1\njel;17.0\njel;17.0\njel;13.2\njel;26.1\njel;19.8\njel;16.4\njel;8.7\njel;19.0\njel;20.6\njel;23.3\njel;20.6\njel;16.9\njel;20.3\njel;24.7\njel;9.3\njel;13.7\njel;19.2\njel;8.8\njel;14.0\njel;17.0\njel;6.8\njel;7.8\njel;24.0\njel;11.6\njel;25.6\njel;24.5\njel;12.8\njel;18.0\njel;22.6\njel;7.4\njel;28.7\njel;15.2\njel;22.6\njel;11.4\njel;14.0\njel;14.0\njel;14.7\njel;6.2\njel;27.0\njel;7.7\njel;26.6\njel;16.3\njel;24.4\njel;22.8\njel;9.5\njel;19.4\njel;15.9\njel;17.7\njel;9.3\njel;13.7\njel;25.4\njel;23.3\njel;17.8\njel;18.5\njel;13.3\njel;8.4\njel;21.3\njel;21.9\njel;4.5\njel;23.5\njel;29.8\njel;10.2\njel;17.0\njel;18.4\njel;15.5\njel;21.3\njel;19.2\njel;12.7\njel;21.3\njel;25.7\njel;7.3\njel;7.2\njel;7.2\njel;6.0\njel;9.7\njel;3.0\njel;10.6\njel;15.3\njel;16.3\njel;10.4\njel;19.8\njel;22.0\njel;20.5\njel;30.1\njel;14.7\njel;13.5\njel;19.7\njel;20.0\njel;18.3\njel;13.5\njel;39.1\njel;18.1\njel;16.9\njel;12.6\njel;9.4\njel;16.8\njel;31.2\njel;24.1\njel;11.9\njel;15.5\njel;0.7\njel;21.6\njel;10.6\njel;5.2\njel;11.5\njel;23.9\njel;22.3\njel;22.1\njel;18.6\njel;11.2\njel;17.5\njel;30.5\njel;16.7\njel;16.4\njel;21.3\njel;24.5\njel;16.5\njel;27.3\njel;27.8\njel;21.7\njel;13.4\njel;7.2\njel;13.0\njel;12.3\njel;19.0\njel;17.9\njel;25.6\njel;10.3\njel;11.5\njel;25.4\njel;9.0\njel;20.2\njel;16.2\njel;41.2\njel;15.3\njel;3.4\njel;27.3\njel;18.5\njel;4.4\njel;17.0\njel;12.8\njel;22.5\njel;16.7\njel;17.4\njel;12.4\njel;6.8\njel;26.6\njel;11.7\njel;18.2\njel;19.3\njel;19.9\njel;23.6\njel;14.9\njel;19.8\njel;20.9\njel;16.8\njel;15.7\njel;20.4\njel;28.7\njel;13.2\njel;16.8\njel;9.3\njel;15.8\njel;15.7\njel;15.1\njel;7.3\njel;23.0\njel;17.1\njel;16.9\njel;10.5\njel;20.1\njel;31.5\njel;23.7\njel;7.5\njel;12.9\njel;17.0\njel;15.4\njel;12.5\njel;13.8\njel;14.6\njel;13.0\njel;40.8\njel;14.6\njel;23.5\njel;15.5\njel;26.4\njel;23.0\njel;18.2\njel;9.6\njel;23.3\njel;20.7\njel;20.8\njel;17.2\njel;29.5\njel;26.6\njel;24.0\njel;22.9\njel;14.3\njel;24.1\njel;21.9\njel;11.9\njel;17.0\njel;29.4\njel;21.0\njel;22.3\njel;16.5\njel;9.5\njel;6.8\njel;42.5\njel;12.9\njel;13.6\njel;15.9\njel;3.3\njel;19.5\njel;17.9\njel;26.3\njel;1.3\njel;27.9\njel;8.8\njel;18.1\njel;18.1\njel;19.3\njel;8.4\njel;22.5\njel;16.8\njel;21.7\njel;14.4\njel;13.5\njel;29.3\njel;16.4\njel;16.8\njel;14.8\njel;16.1\njel;25.6\njel;11.4\njel;23.0\njel;17.8\njel;20.4\njel;15.8\njel;16.9\njel;23.0\njel;14.7\njel;26.7\njel;8.5\njel;13.7\njel;12.0\njel;12.9\njel;11.7\njel;17.9\njel;25.2\njel;20.2\njel;11.4\njel;7.2\njel;37.8\njel;14.3\njel;20.7\njel;26.8\njel;15.8\njel;25.7\njel;15.6\njel;21.4\njel;12.6\njel;9.9\njel;10.4\njel;17.2\njel;19.5\njel;9.7\njel;23.4\njel;16.5\njel;15.8\njel;20.0\njel;11.8\njel;33.1\njel;13.5\njel;13.2\njel;25.9\njel;16.7\njel;12.5\njel;15.9\njel;24.2\njel;27.7\njel;11.8\njel;15.3\njel;19.1\njel;6.9\njel;19.1\njel;18.9\njel;15.5\njel;19.8\njel;14.9\njel;15.5\njel;7.1\njel;1.3\njel;16.1\njel;17.1\njel;6.6\njel;10.6\njel;26.6\njel;9.6\njel;21.4\njel;18.9\njel;19.6\njel;23.7\njel;9.0\njel;8.5\njel;13.3\njel;17.3\njel;16.7\njel;15.9\njel;28.6\njel;18.0\njel;24.5\njel;-2.6\njel;14.7\njel;23.8\njel;19.5\njel;17.2\njel;15.6\njel;13.6\njel;17.9\njel;1.6\njel;13.5\njel;17.6\njel;20.6\njel;13.3\njel;13.3\njel;19.6\njel;18.7\njel;24.9\njel;23.7\njel;21.5\njel;20.4\njel;17.6\njel;22.9\njel;16.2\njel;24.1\njel;21.7\njel;21.7\njel;4.5\njel;27.0\njel;2.7\njel;22.4\njel;15.7\njel;17.9\njel;19.2\njel;26.8\njel;31.9\njel;11.4\njel;18.8\njel;22.8\njel;21.6\njel;25.3\njel;17.3\njel;6.0\njel;30.5\njel;29.5\njel;31.9\njel;11.7\njel;20.2\njel;15.7\njel;16.8\njel;15.1\njel;30.3\njel;0.7\njel;8.5\njel;24.2\njel;20.8\njel;36.7\njel;23.1\njel;9.9\njel;13.0\njel;16.5\njel;17.7\njel;33.0\njel;14.2\njel;11.5\njel;25.0\njel;23.3\njel;20.2\njel;22.0\njel;34.1\njel;19.3\njel;24.9\njel;27.5\njel;36.5\njel;23.1\njel;35.8\njel;19.9\njel;10.4\njel;-2.1\njel;19.3\njel;11.7\njel;20.7\njel;19.8\njel;28.3\njel;26.4\njel;15.0\njel;11.1\njel;12.0\njel;9.6\njel;21.0\njel;11.9\njel;16.4\njel;27.5\njel;21.1\njel;27.3\njel;19.5\njel;14.1\njel;24.8\njel;18.1\njel;22.8\njel;14.1\njel;13.1\njel;9.8\njel;22.6\njel;18.5\njel;17.1\njel;21.2\njel;22.3\njel;11.6\njel;3.3\njel;13.5\njel;23.1\njel;23.0\njel;23.1\njel;31.3\njel;25.3\njel;13.5\njel;22.6\njel;15.8\njel;13.6\njel;5.2\njel;16.3\njel;22.3\njel;19.0\njel;9.1\njel;20.7\njel;17.1\njel;11.1\njel;10.1\njel;19.8\njel;13.0\njel;19.5\njel;27.7\njel;24.4\njel;27.1\njel;18.3\njel;6.1\njel;29.0\njel;24.7\njel;16.7\njel;18.7\njel;15.1\njel;19.2\njel;10.0\njel;14.9\njel;27.1\njel;14.3\njel;18.9\njel;18.0\njel;22.0\njel;14.2\njel;14.4\njel;13.6\njel;12.8\njel;14.3\njel;19.4\njel;24.4\njel;11.9\njel;18.5\njel;24.1\njel;26.6\njel;27.3\njel;9.4\njel;18.2\njel;20.5\njel;25.5\njel;14.6\njel;22.2\njel;14.0\njel;26.4\njel;12.5\njel;19.3\njel;25.1\njel;16.1\njel;17.3\njel;23.3\njel;13.1\njel;6.6\njel;26.1\njel;17.7\njel;8.3\njel;25.0\njel;21.1\njel;19.5\njel;20.1\njel;15.8\njel;12.6\njel;14.7\njel;11.2\njel;22.2\njel;17.5\njel;30.1\njel;13.1\njel;18.4\njel;11.5\njel;19.0\njel;7.9\njel;21.5\njel;10.1\njel;19.2\njel;27.0\njel;39.9\njel;11.3\njel;15.6\njel;21.5\njel;10.0\njel;19.3\njel;26.5\njel;10.7\njel;22.6\njel;26.0\njel;13.3\njel;16.0\njel;21.4\njel;31.9\njel;18.8\njel;19.2\njel;14.4\njel;14.8\njel;10.5\njel;19.9\njel;17.0\njel;19.6\njel;24.1\njel;21.8\njel;18.7\njel;25.9\njel;11.6\njel;20.6\njel;27.3\njel;25.5\njel;19.1\njel;16.8\njel;21.8\njel;22.4\njel;13.7\njel;21.6\njel;2.6\njel;22.2\njel;15.6\njel;21.7\njel;14.3\njel;17.9\njel;12.5\njel;21.2\njel;19.0\njel;18.6\njel;17.0\njel;17.6\njel;23.5\njel;26.2\njel;27.2\njel;14.3\njel;11.3\njel;16.9\njel;22.7\njel;3.1\njel;18.0\njel;16.2\njel;15.6\njel;20.6\njel;14.1\njel;22.7\njel;15.8\njel;22.3\njel;26.7\njel;10.9\njel;28.3\njel;12.7\njel;22.8\njel;19.2\njel;19.5\njel;23.5\njel;28.8\njel;28.4\njel;24.3\njel;16.1\njel;11.1\njel;8.1\njel;16.8\njel;20.7\njel;23.8\njel;19.1\njel;15.9\njel;23.2\njel;22.2\njel;16.1\njel;21.1\njel;12.8\njel;16.9\njel;20.6\njel;25.7\njel;12.2\njel;14.0\njel;9.0\njel;17.1\njel;20.1\njel;25.3\njel;16.8\njel;20.9\njel;23.1\njel;20.6\njel;21.2\njel;14.2\njel;24.6\njel;28.9\njel;15.6\njel;8.5\njel;6.2\njel;19.3\njel;9.7\njel;10.7\njel;13.3\njel;31.9\njel;23.6\njel;12.0\njel;26.1\njel;8.3\njel;17.4\njel;12.7\njel;19.4\njel;22.8\njel;28.8\njel;15.9\njel;12.2\njel;24.2\njel;25.5\njel;16.6\njel;23.8\njel;17.4\njel;14.0\njel;20.7\njel;12.0\njel;24.1\njel;16.6\njel;23.3\njel;15.8\njel;7.1\njel;18.8\njel;13.6\njel;10.5\njel;21.4\njel;17.1\njel;20.5\njel;13.2\njel;12.1\njel;25.7\njel;23.0\njel;12.9\njel;23.4\njel;29.4\njel;14.7\njel;30.2\njel;3.0\njel;13.1\njel;8.3\njel;11.2\njel;19.3\njel;23.7\njel;11.0\njel;16.6\njel;9.6\njel;15.3\njel;11.3\njel;20.5\njel;23.6\njel;19.0\njel;20.5\njel;23.6\njel;19.1\njel;12.9\njel;2.8\njel;21.1\njel;26.5\njel;11.2\njel;15.7\njel;15.7\njel;9.9\njel;20.5\njel;7.4\njel;19.6\njel;27.7\njel;11.3\njel;26.7\njel;33.4\njel;25.9\njel;21.5\njel;14.0\njel;13.9\njel;23.2\njel;33.7\njel;15.6\njel;25.1\njel;15.1\njel;4.4\njel;21.5\njel;10.0\njel;18.0\njel;21.4\njel;22.6\njel;35.8\njel;7.0\njel;8.1\njel;7.1\njel;28.2\njel;17.0\njel;2.9\njel;19.3\njel;15.3\njel;13.4\njel;18.1\njel;15.4\njel;12.6\njel;17.9\njel;21.3\njel;9.5\njel;16.7\njel;17.1\njel;12.1\njel;23.2\njel;16.4\njel;23.2\njel;11.0\njel;19.9\njel;16.6\njel;14.6\njel;17.9\njel;28.9\njel;21.9\njel;31.3\njel;6.7\njel;11.5\njel;19.5\njel;22.5\njel;15.2\njel;22.9\njel;14.5\njel;6.3\njel;19.9\njel;11.6\njel;10.4\njel;17.9\njel;19.5\njel;9.9\njel;12.2\njel;13.4\njel;11.5\njel;23.1\njel;5.8\njel;16.0\njel;13.0\njel;15.8\njel;21.8\njel;20.7\njel;15.9\njel;19.9\njel;22.3\njel;10.2\njel;32.9\njel;22.4\njel;18.5\njel;23.7\njel;13.2\njel;18.5\njel;15.1\njel;22.4\njel;14.5\njel;12.2\njel;1.8\njel;22.0\njel;21.9\njel;8.7\njel;19.6\njel;21.4\njel;10.8\njel;15.4\njel;21.6\njel;15.2\njel;14.8\njel;9.4\njel;21.5\njel;27.2\njel;26.7\njel;23.5\njel;16.8\njel;18.5\njel;22.8\njel;13.8\njel;16.6\njel;25.5\njel;17.1\njel;12.8\njel;18.1\njel;34.6\njel;16.9\njel;13.5\njel;16.0\njel;23.3\njel;20.6\njel;20.3\njel;9.8\njel;6.8\njel;26.7\njel;10.7\njel;20.4\njel;27.1\njel;20.9\njel;19.1\njel;19.8\njel;13.6\njel;13.7\njel;30.7\njel;18.6\njel;11.7\njel;11.9\njel;18.4\njel;14.7\njel;10.5\njel;16.0\njel;21.1\njel;21.4\njel;21.7\njel;9.3\njel;25.5\njel;25.3\njel;11.5\njel;27.9\njel;23.9\njel;21.1\njel;10.6\njel;15.6\njel;15.5\njel;10.7\njel;15.8\njel;23.1\njel;28.8\njel;25.5\njel;27.7\njel;23.1\njel;31.7\njel;27.1\njel;15.1\njel;15.5\njel;19.9\njel;15.9\njel;20.6\njel;12.8\njel;10.9\njel;13.4\njel;15.1\njel;-0.9\njel;12.2\njel;8.0\njel;18.6\njel;21.7\njel;26.2\njel;19.9\njel;23.1\njel;10.7\njel;24.2\njel;23.1\njel;18.1\njel;17.3\njel;20.8\njel;15.6\njel;29.3\njel;15.8\njel;19.1\njel;28.6\njel;16.9\njel;11.1\njel;13.2\njel;19.4\njel;16.6\njel;23.4\njel;7.3\njel;30.5\njel;30.7\njel;12.4\njel;14.4\njel;20.6\njel;29.8\njel;13.8\njel;17.1\njel;15.5\njel;-3.5\njel;9.8\njel;15.9\njel;5.4\njel;22.1\njel;14.7\njel;25.7\njel;34.1\njel;14.4\njel;29.3\njel;30.7\njel;0.9\njel;35.5\njel;20.8\njel;31.3\njel;11.4\njel;3.1\njel;16.5\njel;1.7\njel;2.1\njel;19.3\njel;14.3\njel;31.5\njel;27.2\njel;6.8\njel;15.3\njel;32.1\njel;20.7\njel;9.9\njel;23.6\njel;17.7\njel;21.1\njel;22.1\njel;24.7\njel;25.7\njel;26.4\njel;18.6\njel;13.1\njel;23.5\njel;5.6\njel;19.7\njel;12.5\njel;26.7\njel;29.8\njel;15.6\njel;14.1\njel;11.6\njel;17.0\njel;20.7\njel;18.5\njel;22.0\njel;21.8\njel;21.9\njel;8.9\njel;21.7\njel;30.8\njel;14.7\njel;9.1\njel;26.8\njel;10.4\njel;13.6\njel;20.2\njel;12.3\njel;14.0\njel;30.1\njel;24.1\njel;20.0\njel;11.4\njel;16.2\njel;13.5\njel;16.5\njel;18.3\njel;18.5\njel;17.8\njel;27.1\njel;21.5\njel;11.3\njel;8.8\njel;19.6\njel;17.7\njel;18.0\njel;7.3\njel;20.0\njel;15.8\njel;4.4\njel;14.9\njel;18.0\njel;11.9\njel;12.7\njel;12.6\njel;15.6\njel;20.1\njel;20.2\njel;4.9\njel;16.7\njel;17.3\njel;12.4\njel;5.9\njel;24.4\njel;19.7\njel;17.4\njel;34.1\njel;22.4\njel;21.4\njel;27.5\njel;33.8\njel;16.6\njel;20.8\njel;32.4\njel;15.9\njel;22.4\njel;17.5\njel;13.9\njel;24.2\njel;27.1\njel;17.5\njel;30.1\njel;18.3\njel;15.1\njel;9.9\njel;22.3\njel;24.9\njel;22.6\njel;10.7\njel;6.7\njel;14.5\njel;27.9\njel;20.0\njel;29.4\njel;18.1\njel;4.8\njel;18.1\njel;9.4\njel;12.2\njel;12.1\njel;12.2\njel;8.8\njel;17.5\njel;19.6\njel;16.0\njel;18.4\njel;0.1\njel;27.5\njel;22.1\njel;23.9\njel;11.4\njel;21.2\njel;17.2\njel;32.0\njel;22.4\njel;16.2\njel;15.4\njel;20.0\njel;26.5\njel;18.5\njel;32.0\njel;29.3\njel;31.8\njel;13.6\njel;15.4\njel;21.7\njel;8.6\njel;24.3\njel;12.2\njel;14.5\njel;21.2\njel;22.2\njel;15.2\njel;14.3\njel;16.2\njel;24.9\njel;17.8\njel;13.9\njel;22.0\njel;27.2\njel;17.1\njel;23.7\njel;19.0\njel;16.7\njel;28.1\njel;17.2\njel;25.7\njel;17.5\njel;28.7\njel;25.4\njel;17.3\njel;11.7\njel;12.6\njel;26.6\njel;3.9\njel;14.5\njel;29.3\njel;15.6\njel;13.2\njel;31.3\njel;19.9\njel;13.9\njel;13.8\njel;6.3\njel;21.6\njel;17.4\njel;22.7\njel;19.7\njel;17.6\njel;11.8\njel;22.8\njel;27.0\njel;9.3\njel;6.1\njel;16.7\njel;12.4\njel;23.4\njel;4.4\njel;21.0\njel;16.3\njel;23.3\njel;13.4\njel;30.2\njel;29.6\njel;0.8\njel;19.0\njel;1.6\njel;12.7\njel;19.1\njel;27.6\njel;28.5\njel;13.0\njel;8.2\njel;25.2\njel;9.4\njel;14.3\njel;25.2\njel;21.5\njel;34.1\njel;17.1\njel;20.9\njel;9.3\njel;23.8\njel;12.2\njel;19.8\njel;19.5\njel;15.1\njel;27.2\njel;26.9\njel;30.2\njel;20.5\njel;19.9\njel;20.6\njel;20.5\njel;22.3\njel;10.8\njel;11.8\njel;14.3\njel;19.5\njel;13.3\njel;17.7\njel;14.9\njel;13.9\njel;22.4\njel;20.1\njel;18.6\njel;19.6\njel;13.4\njel;17.7\njel;6.0\njel;12.1\njel;19.4\njel;18.7\njel;7.6\njel;21.1\njel;13.6\njel;28.8\njel;12.0\njel;13.6\njel;22.7\njel;20.0\njel;5.1\njel;18.3\njel;23.6\njel;15.5\njel;15.2\njel;20.5\njel;21.2\njel;2.5\njel;21.7\njel;20.9\njel;22.3\njel;10.6\njel;18.3\njel;31.3\njel;10.8\njel;10.4\njel;16.9\njel;27.8\njel;10.8\njel;-4.9\njel;26.8\njel;23.0\njel;21.6\njel;10.7\njel;18.9\njel;21.2\njel;20.9\njel;24.0\njel;17.1\njel;17.0\njel;23.5\njel;15.2\njel;7.6\njel;27.4\njel;11.2\njel;20.6\njel;19.5\njel;26.7\njel;24.7\njel;10.5\njel;17.3\njel;13.6\njel;29.9\njel;7.8\njel;36.4\njel;21.4\njel;14.4\njel;23.6\njel;13.2\njel;18.5\njel;10.5\njel;10.7\njel;7.3\njel;22.1\njel;21.2\njel;21.6\njel;14.3\njel;10.7\njel;17.3\njel;4.9\njel;21.2\njel;21.2\njel;18.4\njel;15.1\njel;21.4\njel;12.6\njel;11.2\njel;24.8\njel;13.9\njel;15.1\njel;19.0\njel;26.4\njel;19.3\njel;10.3\njel;16.8\njel;29.4\njel;18.0\njel;8.0\njel;19.9\njel;15.9\njel;10.8\njel;12.2\njel;22.1\njel;13.9\njel;17.1\njel;12.5\njel;15.7\njel;20.8\njel;24.1\njel;20.6\njel;34.5\njel;29.9\njel;24.6\njel;6.6\njel;27.6\njel;25.8\njel;10.8\njel;20.2\njel;16.1\njel;17.5\njel;35.6\njel;9.9\njel;22.7\njel;24.7\njel;23.6\njel;10.2\njel;19.0\njel;8.2\njel;12.6\njel;19.6\njel;3.0\njel;22.5\njel;11.4\njel;18.1\njel;16.5\njel;27.9\njel;11.2\njel;16.7\njel;21.5\njel;2.0\njel;20.4\njel;18.7\njel;19.2\njel;10.6\njel;11.4\njel;9.5\njel;26.9\njel;23.2\njel;24.9\njel;15.3\njel;21.6\njel;13.1\njel;17.0\njel;19.4\njel;26.7\njel;16.4\njel;5.4\njel;18.3\njel;14.4\njel;25.4\njel;13.8\njel;4.8\njel;17.9\njel;24.6\njel;23.6\njel;11.2\njel;23.8\njel;17.2\njel;11.6\njel;13.6\njel;20.4\njel;29.4\njel;16.8\njel;11.6\njel;16.4\njel;19.2\njel;17.5\njel;19.5\njel;32.6\njel;30.6\njel;15.9\njel;18.7\njel;22.7\njel;9.1\njel;29.4\njel;16.2\njel;17.0\njel;27.4\njel;15.7\njel;23.6\njel;20.3\njel;11.2\njel;12.7\njel;11.3\njel;18.1\njel;24.6\njel;17.8\njel;15.7\njel;15.9\njel;21.1\njel;3.6\njel;1.5\njel;13.3\njel;22.6\njel;29.4\njel;23.9\njel;26.6\njel;18.9\njel;12.9\njel;15.3\njel;15.5\njel;13.7\njel;25.2\njel;5.6\njel;2.5\njel;22.6\njel;9.3\njel;41.1\njel;25.4\njel;18.6\njel;29.7\njel;16.4\njel;9.1\njel;31.1\njel;20.3\njel;25.6\njel;20.7\njel;14.3\njel;35.5\njel;21.4\njel;12.4\njel;14.7\njel;26.0\njel;16.7\njel;17.0\njel;25.1\njel;21.4\njel;27.0\njel;18.9\njel;15.6\njel;26.3\njel;22.9\njel;17.7\njel;17.8\njel;16.5\njel;11.9\njel;20.7\njel;17.4\njel;7.5\njel;23.0\njel;10.0\njel;17.7\njel;19.4\njel;23.2\njel;23.7\njel;18.0\njel;20.6\njel;23.1\njel;22.0\njel;14.0\njel;27.5\njel;26.7\njel;26.9\njel;19.8\njel;23.8\njel;16.3\njel;24.7\njel;21.4\njel;11.3\njel;19.0\njel;9.5\njel;21.7\njel;23.1\njel;29.2\njel;23.5\njel;9.5\njel;14.3\njel;20.2\njel;18.8\njel;11.9\njel;18.2\njel;21.0\njel;15.5\njel;25.9\njel;24.6\njel;8.5\njel;11.2\njel;24.1\njel;19.0\njel;4.3\njel;19.3\njel;19.8\njel;19.1\njel;13.3\njel;21.4\njel;26.8\njel;13.2\njel;23.7\njel;13.1\njel;15.1\njel;25.6\njel;21.3\njel;17.2\njel;9.2\njel;21.1\njel;20.7\njel;20.5\njel;31.7\njel;20.7\njel;10.6\njel;28.3\njel;17.7\njel;19.8\njel;33.6\njel;9.3\njel;10.0\njel;19.9\njel;11.9\njel;32.0\njel;15.9\njel;14.7\njel;19.4\njel;9.8\njel;18.7\njel;24.5\njel;15.3\njel;27.2\njel;20.8\njel;27.6\njel;12.9\njel;10.0\njel;22.7\njel;13.1\njel;15.8\njel;15.5\njel;17.3\njel;14.7\njel;8.1\njel;24.4\njel;13.1\njel;12.2\njel;19.6\njel;32.6\njel;18.2\njel;20.1\njel;13.1\njel;21.9\njel;22.0\njel;21.7\njel;21.0\njel;28.1\njel;9.5\njel;17.4\njel;15.8\njel;19.3\njel;8.6\njel;13.8\njel;23.4\njel;16.5\njel;29.0\njel;27.9\njel;14.8\njel;12.6\njel;20.8\njel;17.1\njel;15.4\njel;22.1\njel;11.5\njel;15.5\njel;13.4\njel;9.4\njel;9.1\njel;24.7\njel;5.6\njel;6.6\njel;23.1\njel;16.5\njel;25.7\njel;16.7\njel;21.2\njel;15.8\njel;13.1\njel;14.4\njel;16.4\njel;19.7\njel;16.1\njel;13.2\njel;2.0\njel;16.0\njel;20.3\njel;21.6\njel;26.8\njel;27.8\njel;12.2\njel;19.4\njel;23.9\njel;21.7\njel;10.3\njel;16.4\njel;11.1\njel;13.7\njel;19.1\njel;15.0\njel;16.7\njel;29.1\njel;19.0\njel;21.4\njel;14.0\njel;11.6\njel;11.1\njel;17.7\njel;8.2\njel;12.6\njel;25.2\njel;19.8\njel;12.3\njel;16.9\njel;16.9\njel;18.9\njel;10.3\njel;19.0\njel;7.8\njel;7.5\njel;8.2\njel;19.1\njel;21.5\njel;21.5\njel;6.6\njel;12.4\njel;14.3\njel;18.5\njel;14.0\njel;21.8\njel;25.3\njel;22.1\njel;22.7\njel;11.7\njel;12.1\njel;20.6\njel;23.1\njel;11.2\njel;15.9\njel;23.4\njel;27.3\njel;31.9\njel;16.7\njel;12.1\njel;9.7\njel;19.6\njel;14.1\njel;28.7\njel;19.8\njel;11.9\njel;10.9\njel;7.4\njel;3.4\njel;11.5\njel;27.6\njel;21.3\njel;7.4\njel;28.7\njel;17.6\njel;17.2\njel;14.7\njel;28.3\njel;10.8\njel;9.1\njel;35.4\njel;21.6\njel;26.2\njel;20.4\njel;26.4\njel;26.1\njel;12.2\njel;9.2\njel;24.4\njel;24.9\njel;24.1\njel;16.3\njel;20.3\njel;22.7\njel;20.4\njel;1.7\njel;0.6\njel;28.3\njel;16.8\njel;23.4\njel;12.5\njel;9.7\njel;17.9\njel;26.9\njel;15.8\njel;29.2\njel;27.3\njel;4.6\njel;4.4\njel;19.8\njel;13.5\njel;12.0\njel;18.0\njel;18.6\njel;11.2\njel;18.8\njel;20.7\njel;8.6\njel;30.9\njel;11.9\njel;16.7\njel;18.0\njel;4.3\njel;19.3\njel;13.0\njel;9.7\njel;11.7\njel;24.6\njel;21.1\njel;17.0\njel;17.4\njel;21.1\njel;20.3\njel;15.2\njel;25.6\njel;19.8\njel;12.0\njel;17.3\njel;21.0\njel;4.1\njel;23.1\njel;18.4\njel;9.4\njel;24.2\njel;10.8\njel;26.7\njel;15.4\njel;19.9\njel;12.5\njel;22.5\njel;6.5\njel;28.4\njel;28.8\njel;11.1\njel;17.6\njel;26.5\njel;11.5\njel;5.0\njel;14.8\njel;26.9\njel;17.2\njel;12.5\njel;5.8\njel;16.9\njel;17.8\njel;16.8\njel;14.9\njel;17.0\njel;11.7\njel;14.4\njel;11.2\njel;24.3\njel;13.3\njel;26.3\njel;6.3\njel;12.3\njel;8.9\njel;15.0\njel;20.3\njel;18.8\njel;28.6\njel;8.8\njel;3.5\njel;15.4\njel;14.4\njel;15.0\njel;15.1\njel;20.0\njel;17.4\njel;10.0\njel;11.3\njel;23.8\njel;13.7\njel;21.5\njel;8.3\njel;6.2\njel;21.4\njel;32.1\njel;29.0\njel;20.1\njel;13.6\njel;20.0\njel;16.3\njel;8.9\njel;19.3\njel;7.6\njel;21.7\njel;23.3\njel;14.9\njel;21.3\njel;3.8\njel;35.7\njel;7.3\njel;21.3\njel;19.3\njel;12.3\njel;19.8\njel;24.1\njel;12.6\njel;23.1\njel;22.9\njel;7.2\njel;11.1\njel;28.7\njel;14.6\njel;23.6\njel;24.1\njel;25.8\njel;18.6\njel;29.0\njel;21.2\njel;19.6\njel;15.8\njel;18.7\njel;18.9\njel;22.7\njel;9.7\njel;22.4\njel;22.9\njel;19.0\njel;16.2\njel;14.1\njel;21.2\njel;25.8\njel;23.6\njel;20.0\njel;21.9\njel;14.8\njel;19.3\njel;20.1\njel;8.3\njel;23.5\njel;5.5\njel;30.0\njel;26.2\njel;19.3\njel;21.8\njel;11.4\njel;13.0\njel;1.2\njel;25.3\njel;18.2\njel;15.9\njel;16.4\njel;27.8\njel;24.1\njel;21.9\njel;30.5\njel;11.3\njel;23.6\njel;28.5\njel;22.3\njel;31.8\njel;18.4\njel;16.4\njel;19.0\njel;6.1\njel;26.2\njel;19.5\njel;5.9\njel;12.1\njel;16.3\njel;23.5\njel;15.6\njel;6.2\njel;14.3\njel;19.6\njel;15.2\njel;27.1\njel;20.8\njel;21.7\njel;16.8\njel;14.1\njel;17.9\njel;26.6\njel;22.9\njel;25.6\njel;19.7\njel;22.6\njel;13.2\njel;14.5\njel;15.3\njel;20.8\njel;20.1\njel;4.4\njel;19.4\njel;35.1\njel;14.7\njel;23.9\njel;15.7\njel;18.1\njel;14.7\njel;24.9\njel;15.9\njel;28.5\njel;31.5\njel;8.9\njel;13.3\njel;17.7\njel;13.2\njel;13.6\njel;7.8\njel;8.4\njel;20.1\njel;3.3\njel;21.7\njel;12.2\njel;3.2\njel;15.4\njel;16.9\njel;27.8\njel;24.4\njel;13.9\njel;26.3\njel;24.2\njel;7.5\njel;13.5\njel;18.0\njel;21.4\njel;17.8\njel;24.2\njel;13.5\njel;19.3\njel;17.6\njel;7.5\njel;13.1\njel;9.6\njel;21.9\njel;10.6\njel;11.6\njel;24.1\njel;17.3\njel;17.8\njel;21.4\njel;12.2\njel;4.0\njel;20.5\njel;22.1\njel;6.3\njel;6.7\njel;13.0\njel;12.8\njel;17.9\njel;17.1\njel;18.8\njel;24.8\njel;2.8\njel;22.0\njel;20.6\njel;27.9\njel;18.4\njel;16.5\njel;21.1\njel;25.6\njel;14.5\njel;16.7\njel;16.2\njel;15.0\njel;17.7\njel;23.0\njel;13.7\njel;23.6\njel;17.6\njel;16.2\njel;9.2\njel;13.0\njel;20.4\njel;18.7\njel;18.5\njel;24.5\njel;20.5\njel;25.3\njel;6.8\njel;21.6\njel;15.0\njel;14.1\njel;15.7\njel;15.2\njel;21.3\njel;17.4\njel;21.0\njel;25.0\njel;13.2\njel;21.6\njel;23.8\njel;19.1\njel;17.3\njel;15.2\njel;29.1\njel;23.7\njel;15.7\njel;24.6\njel;8.3\njel;7.4\njel;7.7\njel;24.5\njel;12.8\njel;24.1\njel;16.2\njel;18.5\njel;17.7\njel;22.7\njel;7.2\njel;15.8\njel;14.0\njel;13.8\njel;14.5\njel;12.0\njel;9.2\njel;20.8\njel;14.7\njel;4.5\njel;19.9\njel;9.3\njel;21.5\njel;18.3\njel;16.6\njel;18.2\njel;14.9\njel;12.4\njel;20.3\njel;21.8\njel;19.2\njel;19.8\njel;19.5\njel;21.7\njel;9.4\njel;24.3\njel;13.8\njel;21.6\njel;17.4\njel;23.5\njel;7.2\njel;9.7\njel;14.7\njel;16.6\njel;23.7\njel;11.5\njel;12.9\njel;17.1\njel;21.9\njel;19.9\njel;27.1\njel;20.3\njel;6.2\njel;12.4\njel;14.4\njel;20.4\njel;20.5\njel;28.0\njel;7.6\njel;11.6\njel;25.0\njel;12.2\njel;23.7\njel;15.2\njel;19.5\njel;23.9\njel;9.2\njel;20.9\njel;10.5\njel;22.9\njel;-2.2\njel;15.5\njel;23.0\njel;11.4\njel;19.9\njel;17.8\njel;14.0\njel;11.9\njel;23.5\njel;26.4\njel;17.6\njel;15.4\njel;8.8\njel;8.6\njel;9.6\njel;8.0\njel;5.9\njel;9.3\njel;21.0\njel;19.7\njel;22.6\njel;27.6\njel;11.3\njel;17.0\njel;29.2\njel;18.8\njel;9.1\njel;18.3\njel;12.2\njel;17.6\njel;28.1\njel;5.6\njel;13.0\njel;-2.1\njel;19.0\njel;12.9\njel;25.1\njel;18.7\njel;24.8\njel;27.2\njel;19.8\njel;23.9\njel;17.7\njel;22.9\njel;20.0\njel;22.5\njel;15.6\njel;24.3\njel;24.2\njel;13.5\njel;19.2\njel;16.8\njel;6.0\njel;8.9\njel;15.5\njel;25.9\njel;17.0\njel;9.8\njel;24.2\njel;13.4\njel;21.1\njel;14.1\njel;31.0\njel;15.8\njel;16.8\njel;22.4\njel;18.8\njel;19.3\njel;18.4\njel;20.4\njel;17.7\njel;26.7\njel;15.5\njel;3.4\njel;19.8\njel;9.4\njel;18.1\njel;16.1\njel;16.4\njel;27.0\njel;19.9\njel;14.2\njel;25.9\njel;24.6\njel;16.3\njel;14.3\njel;33.0\njel;19.8\njel;0.9\njel;27.3\njel;13.8\njel;20.4\njel;22.7\njel;25.7\njel;19.1\njel;16.5\njel;28.9\njel;6.0\njel;32.5\njel;12.2\njel;10.6\njel;15.7\njel;17.8\njel;13.5\njel;13.0\njel;20.3\njel;35.2\njel;27.9\njel;14.6\njel;11.6\njel;8.5\njel;12.5\njel;20.8\njel;16.3\njel;6.6\njel;13.6\njel;9.6\njel;22.4\njel;25.6\njel;22.9\njel;21.2\njel;14.8\njel;22.5\njel;21.9\njel;16.7\njel;13.2\njel;35.0\njel;26.5\njel;15.3\njel;13.6\njel;11.9\njel;24.9\njel;15.0\njel;21.0\njel;14.1\njel;14.8\njel;13.9\njel;22.4\njel;17.2\njel;13.1\njel;23.4\njel;9.6\njel;16.3\njel;15.9\njel;9.8\njel;15.0\njel;26.1\njel;25.6\njel;20.9\njel;11.3\njel;5.9\njel;7.9\njel;26.9\njel;14.8\njel;11.1\njel;11.5\njel;24.4\njel;5.3\njel;16.3\njel;9.9\njel;18.6\njel;10.0\njel;13.1\njel;9.3\njel;13.3\njel;29.7\njel;22.4\njel;14.0\njel;10.7\njel;11.5\njel;17.0\njel;15.1\njel;19.3\njel;16.9\njel;3.9\njel;19.2\njel;16.3\njel;13.1\njel;31.0\njel;20.1\njel;12.2\njel;20.0\njel;19.1\njel;22.5\njel;18.7\njel;27.2\njel;5.3\njel;29.3\njel;19.8\njel;20.1\njel;19.2\njel;11.2\njel;34.1\njel;25.0\njel;19.6\njel;12.7\njel;24.0\njel;25.7\njel;16.6\njel;24.7\njel;5.7\njel;21.4\njel;9.6\njel;14.6\njel;23.1\njel;21.0\njel;16.3\njel;22.7\njel;12.2\njel;13.8\njel;28.7\njel;23.8\njel;24.5\njel;14.4\njel;18.5\njel;2.4\njel;10.5\njel;10.2\njel;13.9\njel;10.4\njel;20.7\njel;16.9\njel;19.9\njel;11.2\njel;20.1\njel;18.1\njel;12.0\njel;12.9\njel;15.9\njel;14.6\njel;26.7\njel;24.3\njel;32.8\njel;29.7\njel;14.9\njel;32.0\njel;10.7\njel;18.0\njel;20.2\njel;27.1\njel;12.0\njel;23.1\njel;12.2\njel;15.7\njel;16.0\njel;2.7\njel;31.2\njel;9.5\njel;27.6\njel;17.7\njel;12.5\njel;18.0\njel;7.3\njel;28.8\njel;13.4\njel;5.4\njel;19.7\njel;17.2\njel;11.5\njel;17.2\njel;10.9\njel;10.5\njel;15.3\njel;7.8\njel;16.3\njel;11.2\njel;17.8\njel;18.4\njel;18.0\njel;10.2\njel;18.2\njel;12.3\njel;35.3\njel;20.5\njel;11.1\njel;25.2\njel;16.0\njel;22.3\njel;5.4\njel;32.0\njel;20.8\njel;21.3\njel;13.7\njel;21.9\njel;11.5\njel;6.7\njel;18.2\njel;11.3\njel;33.0\njel;9.5\njel;5.3\njel;10.8\njel;15.7\njel;18.3\njel;22.0\njel;16.6\njel;21.5\njel;16.2\njel;29.4\njel;19.6\njel;29.6\njel;24.3\njel;11.3\njel;28.4\njel;17.8\njel;10.9\njel;20.7\njel;16.1\njel;14.3\njel;20.3\njel;16.8\njel;19.5\njel;22.9\njel;20.2\njel;11.0\njel;13.4\njel;16.6\njel;12.0\njel;11.9\njel;15.0\njel;16.3\njel;13.8\njel;22.4\njel;22.5\njel;20.0\njel;18.3\njel;13.9\njel;22.0\njel;16.1\njel;16.1\njel;18.4\njel;9.0\njel;20.1\njel;12.4\njel;22.1\njel;18.4\njel;24.3\njel;18.1\njel;21.2\njel;11.3\njel;14.7\njel;31.5\njel;10.5\njel;22.1\njel;16.7\njel;17.6\njel;18.9\njel;19.5\njel;14.0\njel;18.0\njel;20.3\njel;22.7\njel;25.9\njel;20.7\njel;26.7\njel;20.3\njel;17.6\njel;3.7\njel;22.7\njel;18.2\njel;24.6\njel;21.6\njel;24.8\njel;29.6\njel;17.5\njel;17.2\njel;19.1\njel;11.5\njel;8.0\njel;14.8\njel;18.3\njel;21.8\njel;19.9\njel;11.4\njel;21.8\njel;29.7\njel;7.7\njel;18.9\njel;18.4\njel;6.1\njel;25.5\njel;24.3\njel;21.7\njel;18.6\njel;18.9\njel;8.7\njel;17.7\njel;25.3\njel;17.3\njel;18.6\njel;22.3\njel;22.4\njel;21.3\njel;16.4\njel;10.6\njel;23.8\njel;27.1\njel;8.7\njel;25.9\njel;18.1\njel;19.6\njel;13.9\njel;25.6\njel;16.6\njel;14.4\njel;9.7\njel;16.0\njel;18.6\njel;24.4\njel;15.9\njel;24.1\njel;21.4\njel;20.7\njel;19.8\njel;23.5\njel;12.8\njel;16.0\njel;12.8\njel;17.1\njel;17.1\njel;16.1\njel;20.0\njel;27.0\njel;10.3\njel;15.2\njel;14.5\njel;22.1\njel;18.3\njel;19.5\njel;13.4\njel;11.6\njel;18.2\njel;29.4\njel;10.6\njel;21.1\njel;17.5\njel;16.2\njel;36.7\njel;24.0\njel;28.3\njel;18.7\njel;19.1\njel;24.5\njel;13.1\njel;25.5\njel;21.5\njel;23.0\njel;22.0\njel;18.5\njel;20.5\njel;21.9\njel;18.9\njel;31.3\njel;25.5\njel;6.5\njel;26.4\njel;0.4\njel;36.5\njel;17.8\njel;14.5\njel;21.0\njel;38.3\njel;24.1\njel;22.9\njel;5.6\njel;19.6\njel;11.2\njel;13.4\njel;34.2\njel;5.2\njel;23.4\njel;25.0\njel;15.8\njel;-2.8\njel;12.1\njel;16.8\njel;12.7\njel;22.2\njel;20.1\njel;11.2\njel;12.8\njel;16.6\njel;18.0\njel;35.3\njel;23.1\njel;12.6\njel;27.4\njel;9.5\njel;16.0\njel;7.0\njel;11.4\njel;11.5\njel;19.6\njel;16.7\njel;15.0\njel;32.0\njel;19.3\njel;14.2\njel;13.1\njel;19.3\njel;18.7\njel;19.7\njel;16.0\njel;16.0\njel;30.1\njel;16.7\njel;21.0\njel;21.1\njel;5.8\njel;20.2\njel;24.3\njel;11.7\njel;-1.8\njel;20.9\njel;14.0\njel;21.4\njel;13.1\njel;10.5\njel;18.3\njel;13.9\njel;22.6\njel;18.1\njel;22.0\njel;23.9\njel;29.3\njel;16.7\njel;23.3\njel;22.2\njel;15.3\njel;21.3\njel;22.5\njel;16.0\njel;14.0\njel;10.2\njel;32.6\njel;13.4\njel;7.9\njel;11.3\njel;17.1\njel;21.8\njel;16.2\njel;25.5\njel;3.0\njel;24.4\njel;15.1\njel;11.2\njel;23.7\njel;13.6\njel;16.6\njel;18.6\njel;19.4\njel;14.7\njel;18.6\njel;15.0\njel;18.0\njel;22.8\njel;20.7\njel;29.7\njel;8.7\njel;20.5\njel;13.3\njel;17.0\njel;18.5\njel;14.7\njel;12.4\njel;11.9\njel;14.6\njel;11.2\njel;24.1\njel;17.8\njel;13.4\njel;22.0\njel;15.2\njel;21.2\njel;14.8\njel;7.2\njel;19.8\njel;20.5\njel;16.6\njel;21.9\njel;20.6\njel;12.7\njel;15.7\njel;7.9\njel;21.7\njel;24.0\njel;27.5\njel;21.4\njel;24.6\njel;12.6\njel;4.2\njel;19.0\njel;4.2\njel;3.7\njel;27.4\njel;4.5\njel;15.5\njel;21.1\njel;16.4\njel;13.7\njel;12.6\njel;31.5\njel;18.6\njel;25.2\njel;8.8\njel;12.1\njel;23.1\njel;21.5\njel;7.2\njel;14.6\njel;16.8\njel;7.7\njel;21.4\njel;3.6\njel;13.8\njel;7.6\njel;17.2\njel;29.7\njel;19.6\njel;8.9\njel;5.1\njel;21.0\njel;17.7\njel;28.6\njel;25.9\njel;6.3\njel;6.9\njel;7.0\njel;24.2\njel;9.8\njel;18.8\njel;13.8\njel;11.9\njel;12.9\njel;22.0\njel;14.8\njel;15.0\njel;21.5\njel;20.4\njel;24.6\njel;24.6\njel;35.5\njel;19.1\njel;26.7\njel;28.1\njel;28.4\njel;21.4\njel;15.4\njel;24.9\njel;10.0\njel;15.5\njel;3.9\njel;15.3\njel;29.3\njel;16.4\njel;27.3\njel;11.1\njel;17.8\njel;24.3\njel;14.7\njel;11.8\njel;29.0\njel;20.8\njel;15.6\njel;22.0\njel;19.7\njel;18.9\njel;16.6\njel;19.1\njel;22.9\njel;19.1\njel;5.7\njel;26.5\njel;37.3\njel;42.4\njel;20.9\njel;11.8\njel;25.6\njel;26.5\njel;16.4\njel;34.8\njel;14.5\njel;26.6\njel;21.7\njel;36.0\njel;22.6\njel;18.5\njel;5.6\njel;24.0\njel;14.7\njel;9.9\njel;24.8\njel;24.6\njel;18.1\njel;14.6\njel;20.4\njel;28.8\njel;7.9\njel;9.6\njel;11.7\njel;17.9\njel;15.2\njel;13.9\njel;21.6\njel;24.9\njel;10.6\njel;7.6\njel;13.6\njel;11.2\njel;22.9\njel;15.5\njel;15.1\njel;16.1\njel;13.9\njel;15.7\njel;14.1\njel;22.6\njel;13.6\njel;18.4\njel;22.3\njel;18.5\njel;13.9\njel;16.8\njel;28.4\njel;27.2\njel;10.1\njel;11.1\njel;16.4\njel;14.2\njel;32.9\njel;11.3\njel;21.2\njel;16.6\njel;11.6\njel;20.4\njel;15.9\njel;10.7\njel;7.6\njel;19.3\njel;28.1\njel;22.7\njel;28.3\njel;9.5\njel;8.0\njel;21.1\njel;3.7\njel;18.4\njel;11.6\njel;22.4\njel;18.9\njel;24.2\njel;17.8\njel;25.0\njel;23.2\njel;17.0\njel;12.8\njel;17.2\njel;7.6\njel;20.4\njel;18.3\njel;21.6\njel;22.0\njel;22.3\njel;18.6\njel;18.0\njel;19.9\njel;12.5\njel;11.8\njel;19.7\njel;12.9\njel;9.3\njel;6.4\njel;34.0\njel;17.1\njel;26.8\njel;28.4\njel;9.6\njel;15.1\njel;5.9\njel;34.5\njel;17.4\njel;17.2\njel;7.4\njel;29.4\njel;29.4\njel;21.8\njel;19.1\njel;13.7\njel;11.1\njel;20.9\njel;22.1\njel;12.2\njel;14.6\njel;31.1\njel;21.7\njel;20.3\njel;37.0\njel;2.8\njel;26.3\njel;17.6\njel;35.3\njel;21.4\njel;18.9\njel;5.6\njel;13.2\njel;0.9\njel;18.2\njel;16.9\njel;13.1\njel;22.3\njel;9.3\njel;21.7\njel;27.1\njel;10.4\njel;20.0\njel;16.7\njel;14.5\njel;9.8\njel;16.1\njel;23.0\njel;19.2\njel;21.3\njel;15.0\njel;20.2\njel;10.7\njel;13.5\njel;21.6\njel;22.7\njel;20.3\njel;16.3\njel;4.0\njel;22.6\njel;0.4\njel;18.6\njel;25.3\njel;30.6\njel;20.9\njel;19.1\njel;26.3\njel;21.0\njel;25.6\njel;27.4\njel;14.1\njel;10.4\njel;12.4\njel;20.3\njel;16.7\njel;16.8\njel;5.7\njel;22.6\njel;14.6\njel;25.6\njel;24.1\njel;20.2\njel;20.0\njel;16.6\njel;12.0\njel;17.4\njel;18.6\njel;21.3\njel;24.2\njel;18.8\njel;13.2\njel;17.9\njel;13.1\njel;30.7\njel;8.9\njel;18.6\njel;24.1\njel;14.4\njel;18.4\njel;24.3\njel;19.3\njel;22.6\njel;25.6\njel;18.6\njel;6.7\njel;13.7\njel;11.7\njel;6.6\njel;21.3\njel;22.8\njel;17.6\njel;14.3\njel;28.3\njel;20.2\njel;29.2\njel;16.4\njel;15.8\njel;11.1\njel;15.9\njel;14.5\njel;21.4\njel;19.1\njel;14.5\njel;12.4\njel;21.4\njel;21.2\njel;17.2\njel;16.3\njel;17.3\njel;27.2\njel;18.4\njel;11.3\njel;6.0\njel;32.3\njel;20.6\njel;27.1\njel;8.4\njel;26.4\njel;24.7\njel;16.7\njel;11.8\njel;17.7\njel;22.4\njel;16.7\njel;21.7\njel;17.9\njel;16.8\njel;29.3\njel;26.4\njel;10.9\njel;31.0\njel;19.7\njel;17.4\njel;13.6\njel;25.6\njel;18.0\njel;15.1\njel;11.7\njel;19.7\njel;23.9\njel;18.6\njel;17.7\njel;20.8\njel;14.9\njel;18.8\njel;19.7\njel;24.2\njel;23.4\njel;2.2\njel;7.3\njel;18.3\njel;17.6\njel;16.3\njel;19.5\njel;16.9\njel;17.6\njel;13.3\njel;10.2\njel;7.9\njel;16.0\njel;14.2\njel;12.7\njel;20.6\njel;14.6\njel;30.8\njel;26.9\njel;16.2\njel;8.4\njel;19.1\njel;21.9\njel;31.1\njel;23.5\njel;14.4\njel;22.4\njel;26.3\njel;12.6\njel;18.8\njel;20.8\njel;19.8\njel;13.8\njel;5.7\njel;12.9\njel;10.2\njel;8.8\njel;13.1\njel;10.0\njel;18.1\njel;19.3\njel;13.1\njel;17.7\njel;13.4\njel;0.3\njel;23.3\njel;23.0\njel;26.0\njel;13.0\njel;19.5\njel;24.6\njel;11.4\njel;22.3\njel;14.5\njel;21.3\njel;12.5\njel;17.1\njel;10.2\njel;23.8\njel;16.9\njel;15.7\njel;7.0\njel;31.9\njel;14.2\njel;18.2\njel;9.7\njel;13.7\njel;8.6\njel;22.7\njel;15.7\njel;20.8\njel;30.7\njel;29.6\njel;1.0\njel;14.7\njel;8.9\njel;23.8\njel;12.7\njel;19.2\njel;25.7\njel;16.5\njel;23.7\njel;16.8\njel;18.7\njel;28.4\njel;12.8\njel;24.3\njel;13.2\njel;27.7\njel;17.0\njel;18.8\njel;19.7\njel;11.8\njel;9.3\njel;23.0\njel;25.1\njel;11.8\njel;8.0\njel;10.4\njel;21.8\njel;23.6\njel;18.7\njel;7.6\njel;26.1\njel;7.8\njel;16.5\njel;1.9\njel;14.6\njel;11.3\njel;23.8\njel;16.1\njel;7.1\njel;9.1\njel;15.6\njel;26.8\njel;13.6\njel;6.3\njel;23.2\njel;19.7\njel;26.1\njel;10.5\njel;20.9\njel;18.9\njel;26.2\njel;11.2\njel;14.5\njel;15.2\njel;17.1\njel;11.9\njel;13.3\njel;5.3\njel;21.7\njel;29.2\njel;12.3\njel;18.5\njel;10.0\njel;8.2\njel;27.6\njel;22.1\njel;22.7\njel;24.2\njel;4.3\njel;20.1\njel;13.3\njel;17.9\njel;21.1\njel;14.0\njel;19.4\njel;18.1\njel;13.6\njel;17.1\njel;17.4\njel;21.2\njel;8.8\njel;16.6\njel;36.5\njel;21.1\njel;28.5\njel;20.1\njel;27.3\njel;18.2\njel;17.3\njel;10.6\njel;20.2\njel;8.2\njel;24.7\njel;17.4\njel;23.4\njel;12.7\njel;10.8\njel;14.2\njel;21.0\njel;11.5\njel;11.8\njel;28.5\njel;-0.4\njel;20.2\njel;14.2\njel;13.9\njel;27.3\njel;16.6\njel;23.4\njel;23.5\njel;16.6\njel;15.4\njel;19.3\njel;17.4\njel;23.8\njel;26.4\njel;27.6\njel;5.1\njel;23.4\njel;17.9\njel;29.2\njel;26.7\njel;10.6\njel;19.9\njel;22.8\njel;29.0\njel;9.7\njel;24.8\njel;34.4\njel;18.8\njel;7.8\njel;21.1\njel;19.0\njel;14.9\njel;15.0\njel;17.3\njel;16.0\njel;18.5\njel;19.6\njel;10.8\njel;13.5\njel;23.6\njel;41.1\njel;-1.3\njel;16.6\njel;1.9\njel;13.6\njel;17.4\njel;22.0\njel;18.3\njel;6.6\njel;18.6\njel;20.9\njel;10.6\njel;21.9\njel;22.1\njel;19.7\njel;19.3\njel;13.2\njel;31.1\njel;26.9\njel;27.5\njel;10.4\njel;21.6\njel;25.5\njel;25.6\njel;16.3\njel;9.9\njel;7.6\njel;25.0\njel;23.1\njel;24.0\njel;36.1\njel;9.2\njel;24.3\njel;15.8\njel;15.9\njel;31.4\njel;28.5\njel;21.3\njel;3.2\njel;21.7\njel;22.1\njel;19.6\njel;17.9\njel;11.8\njel;35.6\njel;24.1\njel;15.1\njel;20.6\njel;17.1\njel;12.7\njel;24.9\njel;20.0\njel;17.3\njel;10.8\njel;27.5\njel;10.8\njel;11.9\njel;26.9\njel;14.0\njel;28.4\njel;18.1\njel;13.4\njel;16.6\njel;17.5\njel;16.5\njel;12.7\njel;11.9\njel;23.2\njel;12.9\njel;10.6\njel;25.6\njel;24.2\njel;19.1\njel;12.8\njel;11.9\njel;15.7\njel;15.8\njel;34.6\njel;17.0\njel;20.4\njel;23.1\njel;24.5\njel;28.7\njel;20.8\njel;17.6\njel;17.4\njel;14.4\njel;21.7\njel;17.6\njel;11.5\njel;17.9\njel;33.0\njel;12.0\njel;17.1\njel;9.1\njel;24.5\njel;20.2\njel;21.5\njel;4.6\njel;22.5\njel;12.9\njel;16.6\njel;11.9\njel;18.8\njel;18.2\njel;11.2\njel;13.2\njel;0.3\njel;12.0\njel;10.7\njel;10.2\njel;15.3\njel;19.8\njel;16.4\njel;23.6\njel;5.4\njel;8.0\njel;16.4\njel;5.6\njel;20.0\njel;22.7\njel;25.6\njel;19.4\njel;28.2\njel;17.3\njel;29.5\njel;26.2\njel;18.1\njel;12.4\njel;28.9\njel;10.7\njel;23.2\njel;14.9\njel;25.2\njel;17.6\njel;12.3\njel;12.5\njel;7.9\njel;34.9\njel;20.1\njel;16.7\njel;23.0\njel;23.2\njel;21.2\njel;23.2\njel;19.7\njel;4.6\njel;17.8\njel;25.1\njel;12.3\njel;11.6\njel;21.0\njel;28.1\njel;26.9\njel;9.1\njel;14.2\njel;13.9\njel;9.7\njel;16.8\njel;29.4\njel;13.5\njel;23.2\njel;22.6\njel;3.2\njel;15.8\njel;7.9\njel;24.5\njel;13.2\njel;0.7\njel;30.3\njel;4.8\njel;16.5\njel;16.5\njel;26.6\njel;14.1\njel;17.6\njel;17.3\njel;17.1\njel;10.0\njel;15.7\njel;13.1\njel;19.1\njel;30.6\njel;23.0\njel;11.0\njel;18.9\njel;25.5\njel;10.1\njel;21.2\njel;15.3\njel;12.3\njel;21.8\njel;22.0\njel;17.6\njel;26.5\njel;20.2\njel;9.9\njel;15.3\njel;13.7\njel;5.0\njel;10.8\njel;12.5\njel;29.7\njel;23.7\njel;17.4\njel;16.1\njel;15.6\njel;13.8\njel;21.3\njel;25.8\njel;6.1\njel;14.5\njel;15.7\njel;33.9\njel;13.3\njel;13.9\njel;11.5\njel;13.6\njel;21.7\njel;32.3\njel;21.4\njel;15.0\njel;6.2\njel;24.8\njel;16.5\njel;22.3\njel;20.2\njel;12.5\njel;10.2\njel;16.8\njel;16.0\njel;25.8\njel;11.4\njel;14.4\njel;9.8\njel;17.8\njel;21.7\njel;20.7\njel;33.6\njel;18.9\njel;16.3\njel;27.9\njel;19.1\njel;26.0\njel;33.8\njel;20.8\njel;19.0\njel;16.1\njel;9.9\njel;16.1\njel;6.0\njel;8.1\njel;11.3\njel;5.4\njel;10.5\njel;18.7\njel;13.3\njel;15.9\njel;26.0\njel;18.5\njel;19.1\njel;28.3\njel;17.7\njel;27.0\njel;11.2\njel;14.6\njel;16.3\njel;19.3\njel;11.5\njel;20.4\njel;7.3\njel;18.9\njel;22.1\njel;17.0\njel;9.3\njel;19.7\njel;18.0\njel;25.2\njel;19.9\njel;30.2\njel;8.5\njel;7.3\njel;7.8\njel;18.0\njel;30.2\njel;5.1\njel;19.5\njel;27.1\njel;11.8\njel;20.8\njel;19.1\njel;22.4\njel;27.9\njel;19.3\njel;4.1\njel;18.5\njel;2.4\njel;15.9\njel;8.2\njel;11.2\njel;18.9\njel;24.2\njel;29.2\njel;19.9\njel;14.6\njel;24.4\njel;23.8\njel;19.4\njel;14.2\njel;26.3\njel;20.5\njel;17.7\njel;25.1\njel;21.5\njel;20.1\njel;18.7\njel;10.6\njel;15.6\njel;26.1\njel;24.0\njel;23.8\njel;13.3\njel;23.9\njel;21.4\njel;18.1\njel;23.5\njel;22.5\njel;14.6\njel;19.5\njel;16.7\njel;6.2\njel;9.0\njel;19.7\njel;17.9\njel;19.9\njel;27.1\njel;16.1\njel;17.6\njel;12.7\njel;19.0\njel;3.3\njel;10.0\njel;14.4\njel;20.8\njel;24.3\njel;16.6\njel;11.3\njel;25.2\njel;18.3\njel;2.8\njel;26.0\njel;17.8\njel;13.9\njel;25.7\njel;7.8\njel;16.3\njel;13.6\njel;18.6\njel;15.7\njel;11.2\njel;21.6\njel;17.2\njel;19.7\njel;15.7\njel;9.2\njel;8.4\njel;10.7\njel;20.1\njel;18.0\njel;9.8\njel;23.4\njel;23.8\njel;13.8\njel;18.9\njel;25.8\njel;15.1\njel;33.4\njel;11.0\njel;19.7\njel;16.0\njel;16.1\njel;29.4\njel;19.9\njel;19.8\njel;16.3\njel;8.4\njel;13.4\njel;16.9\njel;19.6\njel;12.0\njel;6.9\njel;15.7\njel;20.2\njel;17.7\njel;28.6\njel;17.6\njel;16.6\njel;16.4\njel;12.3\njel;13.7\njel;15.4\njel;21.4\njel;19.5\njel;18.2\njel;32.5\njel;15.7\njel;20.4\njel;19.8\njel;20.7\njel;13.6\njel;19.8\njel;12.8\njel;13.7\njel;24.8\njel;4.7\njel;11.4\njel;22.3\njel;10.5\njel;8.7\njel;6.4\njel;17.0\njel;17.3\njel;28.5\njel;13.9\njel;9.4\njel;23.0\njel;14.2\njel;12.9\njel;22.3\njel;26.7\njel;17.2\njel;14.2\njel;9.5\njel;24.1\njel;19.4\njel;22.7\njel;11.2\njel;10.3\njel;13.2\njel;13.1\njel;10.5\njel;12.9\njel;24.6\njel;11.4\njel;18.8\njel;17.4\njel;23.8\njel;9.6\njel;17.4\njel;24.4\njel;6.8\njel;22.2\njel;14.6\njel;16.9\njel;17.4\njel;17.9\njel;14.7\njel;17.3\njel;20.0\njel;11.3\njel;28.5\njel;21.7\njel;8.4\njel;15.9\njel;18.4\njel;18.3\njel;10.5\njel;25.9\njel;24.9\njel;18.8\njel;35.2\njel;21.0\njel;20.8\njel;20.2\njel;17.2\njel;26.0\njel;13.6\njel;22.5\njel;14.0\njel;25.3\njel;7.5\njel;8.1\njel;18.2\njel;7.4\njel;17.8\njel;4.6\njel;19.9\njel;13.2\njel;11.0\njel;28.2\njel;8.4\njel;11.7\njel;20.7\njel;16.6\njel;7.4\njel;26.0\njel;19.4\njel;14.3\njel;12.6\njel;20.0\njel;22.0\njel;15.5\njel;22.5\njel;22.3\njel;20.2\njel;22.0\njel;14.2\njel;10.4\njel;14.5\njel;22.9\njel;18.7\njel;18.7\njel;15.4\njel;9.6\njel;10.8\njel;24.8\njel;14.7\njel;25.4\njel;12.1\njel;19.5\njel;10.0\njel;10.5\njel;23.3\njel;24.1\njel;16.5\njel;23.9\njel;32.6\njel;5.6\njel;19.4\njel;23.3\njel;22.0\njel;22.5\njel;7.1\njel;9.5\njel;19.7\njel;23.3\njel;8.6\njel;12.9\njel;7.5\njel;22.9\njel;23.7\njel;12.6\njel;7.6\njel;17.9\njel;10.3\njel;14.5\njel;21.5\njel;26.9\njel;17.3\njel;19.2\njel;19.1\njel;12.0\njel;8.1\njel;22.9\njel;8.9\njel;15.0\njel;19.7\njel;20.0\njel;20.2\njel;3.3\njel;12.3\njel;11.4\njel;28.8\njel;10.3\njel;15.7\njel;21.1\njel;20.3\njel;18.8\njel;7.6\njel;6.2\njel;21.7\njel;19.8\njel;19.0\njel;20.9\njel;10.4\njel;11.7\njel;14.2\njel;16.7\njel;9.2\njel;21.7\njel;30.9\njel;11.8\njel;17.6\njel;26.0\njel;25.9\njel;24.7\njel;4.5\njel;17.9\njel;20.0\njel;15.4\njel;16.8\njel;10.5\njel;6.8\njel;27.2\njel;15.2\njel;19.9\njel;18.0\njel;25.9\njel;12.3\njel;7.4\njel;18.7\njel;23.6\njel;25.1\njel;20.1\njel;17.9\njel;24.6\njel;31.4\njel;25.4\njel;29.7\njel;27.1\njel;18.6\njel;10.3\njel;11.1\njel;9.7\njel;23.7\njel;8.2\njel;26.4\njel;5.2\njel;20.5\njel;7.9\njel;13.6\njel;34.4\njel;13.0\njel;11.4\njel;24.0\njel;18.9\njel;5.4\njel;13.4\njel;20.0\njel;16.1\njel;14.6\njel;27.0\njel;24.6\njel;5.0\njel;15.4\njel;11.9\njel;11.4\njel;18.7\njel;6.2\njel;19.9\njel;19.0\njel;30.5\njel;17.1\njel;4.1\njel;22.0\njel;24.9\njel;9.9\njel;15.9\njel;13.7\njel;20.5\njel;29.4\njel;18.0\njel;24.7\njel;19.5\njel;10.7\njel;17.8\njel;5.2\njel;25.3\njel;15.4\njel;7.8\njel;32.5\njel;9.0\njel;21.3\njel;20.6\njel;17.1\njel;18.6\njel;19.1\njel;18.4\njel;20.7\njel;10.8\njel;12.2\njel;11.5\njel;12.0\njel;9.4\njel;22.6\njel;24.5\njel;17.1\njel;17.2\njel;15.8\njel;22.0\njel;8.8\njel;18.7\njel;16.4\njel;21.0\njel;26.0\njel;23.2\njel;15.8\njel;12.7\njel;20.6\njel;4.4\njel;15.1\njel;21.3\njel;0.8\njel;20.8\njel;27.5\njel;20.9\njel;18.4\njel;12.1\njel;14.5\njel;10.0\njel;22.5\njel;7.2\njel;12.7\njel;12.8\njel;30.4\njel;19.6\njel;25.8\njel;25.1\njel;6.0\njel;16.9\njel;23.3\njel;23.1\njel;24.1\njel;15.4\njel;19.3\njel;21.3\njel;13.6\njel;2.3\njel;26.1\njel;13.5\njel;14.4\njel;8.0\njel;4.7\njel;18.3\njel;23.8\njel;22.6\njel;24.0\njel;18.5\njel;18.5\njel;17.0\njel;20.6\njel;16.7\njel;12.2\njel;-2.5\njel;20.6\njel;21.9\njel;26.4\njel;5.6\njel;25.4\njel;25.7\njel;18.4\njel;17.3\njel;26.4\njel;29.1\njel;25.7\njel;16.8\njel;11.2\njel;15.8\njel;29.3\njel;24.3\njel;30.6\njel;16.2\njel;18.2\njel;24.5\njel;17.5\njel;30.2\njel;29.0\njel;13.2\njel;30.4\njel;14.1\njel;26.2\njel;9.6\njel;18.1\njel;23.7\njel;10.3\njel;21.3\njel;21.1\njel;28.3\njel;23.1\njel;4.0\njel;15.7\njel;14.2\njel;18.9\njel;24.8\njel;16.4\njel;14.2\njel;15.6\njel;21.8\njel;14.4\njel;25.8\njel;18.5\njel;23.9\njel;24.3\njel;15.9\njel;16.7\njel;30.4\njel;19.3\njel;25.3\njel;16.6\njel;10.2\njel;20.1\njel;13.2\njel;9.6\njel;26.6\njel;12.3\njel;17.0\njel;22.9\njel;26.1\njel;33.4\njel;20.3\njel;10.5\njel;15.4\njel;14.1\njel;28.2\njel;12.7\njel;21.7\njel;17.0\njel;17.7\njel;17.5\njel;14.3\njel;12.2\njel;18.9\njel;19.6\njel;13.0\njel;23.5\njel;28.2\njel;28.3\njel;28.1\njel;19.8\njel;18.9\njel;14.4\njel;26.9\njel;18.6\njel;10.2\njel;21.8\njel;18.8\njel;19.7\njel;14.7\njel;13.4\njel;-0.6\njel;12.9\njel;2.7\njel;24.6\njel;24.9\njel;25.6\njel;12.4\njel;1.0\njel;25.3\njel;17.5\njel;23.2\njel;18.9\njel;27.2\njel;15.8\njel;24.4\njel;22.8\njel;11.6\njel;14.9\njel;23.4\njel;17.4\njel;13.1\njel;2.5\njel;22.0\njel;26.9\njel;24.9\njel;12.5\njel;15.8\njel;15.4\njel;22.3\njel;28.3\njel;20.8\njel;19.8\njel;17.7\njel;18.5\njel;12.4\njel;19.4\njel;18.7\njel;17.4\njel;6.6\njel;13.5\njel;12.8\njel;7.7\njel;3.9\njel;5.6\njel;4.8\njel;11.9\njel;18.3\njel;17.7\njel;16.6\njel;20.2\njel;12.3\njel;22.0\njel;10.5\njel;18.0\njel;8.2\njel;8.3\njel;22.1\njel;14.3\njel;15.6\njel;22.4\njel;14.2\njel;22.4\njel;27.7\njel;20.2\njel;23.1\njel;16.5\njel;6.5\njel;-0.4\njel;22.1\njel;10.1\njel;18.2\njel;16.7\njel;13.9\njel;13.6\njel;16.6\njel;8.5\njel;21.0\njel;23.8\njel;15.7\njel;22.7\njel;13.1\njel;18.6\njel;5.6\njel;20.2\njel;7.2\njel;13.6\njel;16.9\njel;24.2\njel;11.7\njel;26.8\njel;14.2\njel;19.2\njel;19.0\njel;8.5\njel;14.4\njel;10.7\njel;11.2\njel;22.0\njel;23.5\njel;26.7\njel;13.7\njel;17.2\njel;15.6\njel;32.3\njel;24.3\njel;13.0\njel;22.4\njel;22.4\njel;27.2\njel;25.4\njel;21.0\njel;14.2\njel;12.8\njel;13.7\njel;16.6\njel;27.0\njel;16.1\njel;19.1\njel;40.6\njel;34.6\njel;30.6\njel;24.4\njel;22.0\njel;17.6\njel;12.4\njel;29.9\njel;27.8\njel;15.2\njel;18.9\njel;18.0\njel;18.6\njel;19.8\njel;12.4\njel;11.8\njel;19.9\njel;20.0\njel;23.7\njel;21.8\njel;17.3\njel;15.4\njel;15.2\njel;20.8\njel;13.0\njel;8.7\njel;21.3\njel;9.5\njel;24.8\njel;23.5\njel;11.9\njel;24.4\njel;-0.9\njel;1.2\njel;8.7\njel;6.7\njel;14.5\njel;17.9\njel;32.3\njel;6.5\njel;12.9\njel;25.2\njel;11.6\njel;26.5\njel;9.9\njel;26.4\njel;10.0\njel;26.0\njel;19.0\njel;12.0\njel;29.0\njel;11.0\njel;9.6\njel;30.4\njel;2.3\njel;19.3\njel;9.5\njel;27.2\njel;28.6\njel;11.3\njel;17.0\njel;13.9\njel;26.1\njel;9.7\njel;19.0\njel;15.0\njel;13.5\njel;22.6\njel;7.6\njel;11.6\njel;7.2\njel;15.9\njel;22.0\njel;4.3\njel;23.7\njel;19.3\njel;18.6\njel;11.6\njel;28.1\njel;11.9\njel;18.7\njel;27.7\njel;15.6\njel;10.0\njel;13.2\njel;12.4\njel;29.1\njel;12.1\njel;23.8\njel;21.0\njel;16.2\njel;23.2\njel;10.8\njel;19.4\njel;15.3\njel;4.5\njel;24.7\njel;20.9\njel;26.5\njel;21.9\njel;22.8\njel;22.3\njel;30.1\njel;8.6\njel;21.3\njel;20.1\njel;30.0\njel;24.3\njel;10.0\njel;1.7\njel;18.4\njel;16.2\njel;19.7\njel;4.4\njel;18.9\njel;28.7\njel;8.7\njel;25.3\njel;7.4\njel;12.2\njel;28.3\njel;33.1\njel;15.3\njel;11.3\njel;19.7\njel;29.5\njel;14.1\njel;21.4\njel;11.8\njel;28.1\njel;19.1\njel;14.9\njel;26.9\njel;23.8\njel;13.7\njel;19.4\njel;14.4\njel;16.7\njel;13.4\njel;8.3\njel;14.6\njel;19.7\njel;33.3\njel;17.2\njel;10.0\njel;21.9\njel;9.7\njel;9.9\njel;14.5\njel;11.4\njel;15.0\njel;9.1\njel;1.2\njel;18.3\njel;19.1\njel;15.2\njel;23.6\njel;18.2\njel;24.6\njel;11.1\njel;1.2\njel;19.7\njel;20.4\njel;6.5\njel;25.9\njel;11.7\njel;13.9\njel;18.9\njel;10.3\njel;14.2\njel;8.5\njel;11.6\njel;11.4\njel;9.4\njel;14.9\njel;5.9\njel;12.8\njel;20.0\njel;18.7\njel;22.5\njel;6.4\njel;21.4\njel;16.5\njel;6.9\njel;24.5\njel;17.1\njel;24.7\njel;11.1\njel;10.9\njel;34.6\njel;11.0\njel;16.6\njel;23.7\njel;19.7\njel;13.7\njel;25.2\njel;18.0\njel;17.8\njel;15.1\njel;10.5\njel;23.7\njel;26.5\njel;5.3\njel;9.8\njel;13.4\njel;13.6\njel;15.3\njel;19.1\njel;30.4\njel;26.1\njel;12.3\njel;10.7\njel;14.3\njel;11.7\njel;17.4\njel;18.2\njel;9.9\njel;28.2\njel;21.5\njel;16.9\njel;26.7\njel;23.8\njel;16.8\njel;7.0\njel;23.4\njel;13.8\njel;11.1\njel;12.4\njel;3.4\njel;13.1\njel;34.4\njel;4.7\njel;22.4\njel;17.7\njel;21.0\njel;28.2\njel;19.3\njel;23.6\njel;19.5\njel;13.7\njel;18.5\njel;31.9\njel;22.3\njel;11.1\njel;6.9\njel;13.2\njel;24.9\njel;25.6\njel;9.6\njel;15.5\njel;23.1\njel;21.6\njel;12.6\njel;24.2\njel;18.7\njel;25.7\njel;20.9\njel;21.2\njel;31.9\njel;24.9\njel;11.9\njel;22.3\njel;11.9\njel;18.0\njel;24.2\njel;17.9\njel;25.0\njel;9.5\njel;19.7\njel;10.1\njel;8.3\njel;24.4\njel;21.1\njel;24.3\njel;19.6\njel;28.3\njel;19.6\njel;17.4\njel;21.6\njel;30.8\njel;17.6\njel;9.3\njel;16.1\njel;16.6\njel;17.0\njel;14.9\njel;12.8\njel;10.8\njel;6.9\njel;18.6\njel;13.7\njel;14.2\njel;24.0\njel;20.2\njel;17.8\njel;0.7\njel;28.8\njel;15.0\njel;29.2\njel;18.6\njel;19.2\njel;29.5\njel;23.8\njel;21.7\njel;11.6\njel;20.2\njel;14.5\njel;26.0\njel;9.9\njel;17.9\njel;26.2\njel;28.6\njel;19.8\njel;24.3\njel;13.6\njel;25.5\njel;17.5\njel;25.5\njel;12.7\njel;7.5\njel;3.7\njel;19.6\njel;33.0\njel;13.1\njel;17.6\njel;35.0\njel;13.9\njel;18.6\njel;18.6\njel;15.1\njel;17.5\njel;28.9\njel;16.2\njel;13.6\njel;14.4\njel;16.4\njel;17.8\njel;27.0\njel;22.7\njel;9.2\njel;12.5\njel;20.3\njel;28.4\njel;16.0\njel;18.9\njel;4.3\njel;15.0\njel;16.0\njel;14.2\njel;25.7\njel;21.0\njel;30.3\njel;17.8\njel;11.0\njel;5.8\njel;23.7\njel;18.2\njel;22.4\njel;4.0\njel;18.3\njel;29.8\njel;10.6\njel;11.6\njel;17.6\njel;23.2\njel;20.2\njel;19.9\njel;14.2\njel;20.0\njel;18.3\njel;23.1\njel;30.8\njel;24.1\njel;19.5\njel;7.1\njel;23.5\njel;15.2\njel;10.8\njel;19.9\njel;24.7\njel;23.0\njel;18.7\njel;29.4\njel;15.3\njel;26.4\njel;19.4\njel;7.3\njel;20.8\njel;26.4\njel;25.3\njel;19.4\njel;13.2\njel;18.4\njel;7.6\njel;18.8\njel;13.1\njel;22.0\njel;27.1\njel;18.7\njel;8.0\njel;6.4\njel;7.7\njel;24.5\njel;26.4\njel;19.2\njel;17.0\njel;6.1\njel;24.2\njel;23.2\njel;20.9\njel;18.8\njel;11.9\njel;20.9\njel;20.1\njel;29.3\njel;15.4\njel;20.6\njel;22.9\njel;20.1\njel;22.5\njel;24.6\njel;14.0\njel;16.5\njel;13.5\njel;20.4\njel;19.3\njel;20.1\njel;22.1\njel;8.7\njel;7.9\njel;16.5\njel;16.6\njel;26.2\njel;17.8\njel;22.9\njel;18.9\njel;22.1\njel;22.5\njel;21.0\njel;41.1\njel;17.1\njel;32.7\njel;24.4\njel;-1.5\njel;17.9\njel;14.6\njel;20.5\njel;11.0\njel;18.1\njel;20.3\njel;24.1\njel;24.5\njel;25.4\njel;10.5\njel;15.4\njel;15.1\njel;20.6\njel;15.5\njel;14.2\njel;19.7\njel;10.6\njel;17.5\njel;15.4\njel;3.3\njel;29.2\njel;23.8\njel;18.5\njel;9.1\njel;11.4\njel;19.7\njel;13.5\njel;16.9\njel;13.8\njel;11.8\njel;22.5\njel;18.3\njel;19.1\njel;17.0\njel;15.0\njel;24.5\njel;17.3\njel;15.8\njel;17.5\njel;21.3\njel;10.3\njel;26.3\njel;25.0\njel;23.7\njel;23.8\njel;10.2\njel;12.9\njel;26.3\njel;14.4\njel;14.1\njel;26.0\njel;20.6\njel;21.6\njel;16.7\njel;18.9\njel;6.6\njel;19.4\njel;14.6\njel;29.5\njel;13.7\njel;17.5\njel;16.5\njel;14.5\njel;12.0\njel;19.0\njel;23.4\njel;22.0\njel;11.0\njel;21.7\njel;16.5\njel;30.3\njel;24.2\njel;29.8\njel;16.0\njel;13.6\njel;10.9\njel;12.6\njel;6.3\njel;19.4\njel;19.9\njel;21.3\njel;26.1\njel;12.7\njel;22.0\njel;20.0\njel;5.9\njel;11.8\njel;22.1\njel;33.1\njel;18.3\njel;38.2\njel;12.4\njel;17.7\njel;19.2\njel;19.0\njel;24.4\njel;15.9\njel;31.1\njel;25.7\njel;24.6\njel;20.7\njel;6.5\njel;19.9\njel;12.9\njel;21.7\njel;8.7\njel;16.3\njel;18.7\njel;22.1\njel;16.3\njel;24.9\njel;18.7\njel;20.6\njel;3.2\njel;25.2\njel;21.2\njel;10.3\njel;16.7\njel;15.4\njel;28.1\njel;20.0\njel;24.3\njel;17.6\njel;23.3\njel;21.0\njel;18.0\njel;23.6\njel;25.5\njel;25.2\njel;32.4\njel;10.9\njel;21.2\njel;8.5\njel;25.7\njel;20.1\njel;8.7\njel;14.2\njel;26.3\njel;12.7\njel;18.0\njel;21.3\njel;18.4\njel;16.6\njel;20.0\njel;15.3\njel;25.0\njel;24.3\njel;33.3\njel;14.1\njel;21.9\njel;19.8\njel;12.4\njel;11.6\njel;20.4\njel;15.2\njel;17.4\njel;15.2\njel;20.8\njel;9.4\njel;9.0\njel;33.0\njel;1.9\njel;13.7\njel;22.4\njel;16.6\njel;9.8\njel;12.6\njel;17.1\njel;13.8\njel;14.5\njel;13.7\njel;21.2\njel;12.9\njel;7.8\njel;18.9\njel;2.2\njel;16.7\njel;8.7\njel;15.0\njel;-1.5\njel;11.5\njel;9.9\njel;19.0\njel;16.5\njel;12.5\njel;4.8\njel;11.8\njel;21.8\njel;10.8\njel;29.1\njel;12.4\njel;8.1\njel;13.7\njel;16.1\njel;20.2\njel;25.7\njel;7.8\njel;35.8\njel;30.5\njel;13.3\njel;25.3\njel;12.6\njel;11.5\njel;8.6\njel;8.3\njel;9.5\njel;8.9\njel;17.6\njel;16.2\njel;23.5\njel;20.3\njel;13.6\njel;13.9\njel;15.4\njel;17.4\njel;16.1\njel;13.9\njel;21.3\njel;32.9\njel;18.2\njel;20.4\njel;7.0\njel;16.9\njel;8.2\njel;9.9\njel;9.3\njel;29.3\njel;13.4\njel;23.0\njel;17.4\njel;26.8\njel;17.3\njel;24.7\njel;18.7\njel;7.8\njel;12.6\njel;18.1\njel;7.7\njel;8.6\njel;24.2\njel;3.9\njel;-4.1\njel;11.9\njel;10.9\njel;15.8\njel;12.7\njel;23.3\njel;20.8\njel;14.5\njel;15.4\njel;27.2\njel;28.1\njel;18.7\njel;25.7\njel;15.0\njel;28.5\njel;15.8\njel;20.5\njel;22.0\njel;14.2\njel;28.2\njel;21.2\njel;11.4\njel;10.8\njel;11.0\njel;26.7\njel;24.6\njel;18.0\njel;23.6\njel;26.0\njel;14.4\njel;11.3\njel;13.5\njel;17.5\njel;27.8\njel;11.8\njel;12.3\njel;24.2\njel;13.5\njel;15.7\njel;14.8\njel;30.0\njel;14.3\njel;6.5\njel;18.7\njel;25.5\njel;8.6\njel;22.2\njel;18.0\njel;24.9\njel;17.7\njel;19.9\njel;21.8\njel;16.6\njel;31.4\njel;26.7\njel;25.6\njel;9.2\njel;21.4\njel;22.2\njel;15.6\njel;15.8\njel;13.9\njel;14.8\njel;20.2\njel;19.3\njel;23.9\njel;12.3\njel;16.6\njel;11.3\njel;26.7\njel;19.5\njel;18.3\njel;13.6\njel;23.2\njel;20.0\njel;15.2\njel;14.0\njel;15.2\njel;26.5\njel;17.8\njel;14.8\njel;23.9\njel;17.0\njel;34.9\njel;9.4\njel;6.5\njel;17.4\njel;6.3\njel;21.3\njel;15.5\njel;7.8\njel;10.0\njel;22.5\njel;19.3\njel;25.3\njel;13.9\njel;33.6\njel;9.2\njel;8.9\njel;8.8\njel;7.7\njel;19.3\njel;21.5\njel;19.5\njel;17.4\njel;21.1\njel;25.7\njel;10.8\njel;15.5\njel;10.9\njel;15.4\njel;17.6\njel;21.9\njel;19.9\njel;17.5\njel;16.5\njel;26.5\njel;17.3\njel;18.1\njel;15.8\njel;27.2\njel;21.7\njel;13.9\njel;20.5\njel;14.7\njel;8.0\njel;24.0\njel;24.9\njel;18.2\njel;21.8\njel;22.2\njel;28.7\njel;13.1\njel;17.4\njel;19.6\njel;24.0\njel;11.5\njel;8.8\njel;30.8\njel;15.4\njel;17.2\njel;14.1\njel;9.8\njel;14.7\njel;14.2\njel;25.0\njel;11.4\njel;17.3\njel;16.0\njel;14.8\njel;21.1\njel;22.9\njel;10.5\njel;14.0\njel;12.0\njel;17.2\njel;9.6\njel;14.5\njel;5.1\njel;26.7\njel;7.0\njel;18.2\njel;13.4\njel;17.3\njel;8.6\njel;1.6\njel;17.7\njel;10.8\njel;12.9\njel;24.3\njel;26.2\njel;28.0\njel;24.1\njel;19.4\njel;20.7\njel;17.2\njel;12.6\njel;7.5\njel;21.8\njel;19.9\njel;13.7\njel;27.0\njel;16.7\njel;12.7\njel;12.8\njel;5.3\njel;20.1\njel;6.6\njel;7.4\njel;23.2\njel;20.6\njel;17.0\njel;25.4\njel;15.7\njel;11.3\njel;11.9\njel;21.1\njel;6.2\njel;17.0\njel;29.4\njel;23.1\njel;21.6\njel;2.0\njel;21.9\njel;10.6\njel;21.2\njel;15.2\njel;21.0\njel;15.4\njel;20.4\njel;11.5\njel;18.3\njel;22.6\njel;13.6\njel;15.4\njel;15.8\njel;12.5\njel;14.0\njel;21.9\njel;18.1\njel;26.2\njel;13.8\njel;10.4\njel;20.3\njel;27.9\njel;31.5\njel;17.6\njel;11.7\njel;6.8\njel;10.3\njel;21.0\njel;16.7\njel;15.0\njel;27.2\njel;9.4\njel;14.9\njel;8.4\njel;24.9\njel;6.6\njel;28.0\njel;13.4\njel;14.2\njel;17.9\njel;20.2\njel;20.3\njel;3.5\njel;24.8\njel;19.4\njel;17.4\njel;25.2\njel;16.2\njel;17.2\njel;16.8\njel;17.7\njel;13.4\njel;20.3\njel;16.6\njel;4.4\njel;15.1\njel;15.3\njel;13.7\njel;8.1\njel;26.2\njel;26.6\njel;22.8\njel;17.4\njel;13.3\njel;28.9\njel;17.8\njel;15.2\njel;27.4\njel;16.4\njel;28.3\njel;24.8\njel;20.1\njel;25.7\njel;12.8\njel;3.6\njel;21.0\njel;21.5\njel;7.6\njel;21.2\njel;24.4\njel;27.4\njel;11.5\njel;24.5\njel;13.1\njel;11.6\njel;16.0\njel;17.9\njel;18.7\njel;17.0\njel;14.4\njel;13.8\njel;10.1\njel;21.0\njel;28.8\njel;29.2\njel;17.1\njel;23.7\njel;18.1\njel;14.0\njel;21.9\njel;19.5\njel;20.4\njel;22.6\njel;3.2\njel;13.5\njel;21.2\njel;9.2\njel;26.8\njel;5.0\njel;22.2\njel;15.8\njel;11.5\njel;12.5\njel;19.3\njel;22.0\njel;20.2\njel;16.4\njel;7.6\njel;19.4\njel;16.8\njel;23.7\njel;14.3\njel;17.1\njel;14.8\njel;5.6\njel;1.3\njel;18.8\njel;2.4\njel;10.8\njel;7.1\njel;25.0\njel;13.7\njel;13.1\njel;15.2\njel;13.9\njel;19.8\njel;13.0\njel;11.9\njel;16.4\njel;19.8\njel;18.1\njel;27.5\njel;24.1\njel;19.8\njel;31.1\njel;11.2\njel;20.6\njel;4.6\njel;14.7\njel;16.6\njel;24.6\njel;22.0\njel;27.5\njel;16.8\njel;33.7\njel;16.4\njel;14.7\njel;16.7\njel;18.5\njel;21.8\njel;16.9\njel;15.0\njel;18.6\njel;7.1\njel;17.0\njel;23.6\njel;25.3\njel;17.9\njel;16.2\njel;14.6\njel;24.5\njel;20.8\njel;17.5\njel;24.1\njel;12.0\njel;14.1\njel;15.8\njel;12.9\njel;16.2\njel;5.5\njel;10.5\njel;12.8\njel;18.6\njel;24.6\njel;15.1\njel;11.6\njel;14.9\njel;10.8\njel;14.6\njel;16.4\njel;14.0\njel;5.7\njel;12.0\njel;24.7\njel;18.0\njel;17.8\njel;27.2\njel;21.2\njel;22.2\njel;25.6\njel;19.8\njel;2.0\njel;15.0\njel;8.5\njel;31.6\njel;16.1\njel;29.2\njel;23.7\njel;13.2\njel;32.0\njel;15.5\njel;7.4\njel;18.3\njel;19.4\njel;16.2\njel;11.3\njel;12.0\njel;13.8\njel;18.5\njel;18.9\njel;21.1\njel;12.1\njel;15.3\njel;17.1\njel;28.3\njel;27.9\njel;19.6\njel;15.1\njel;12.8\njel;12.0\njel;20.1\njel;24.2\njel;26.2\njel;24.7\njel;23.8\njel;18.9\njel;35.6\njel;3.1\njel;16.4\njel;28.9\njel;14.2\njel;23.5\njel;21.0\njel;28.7\njel;14.9\njel;21.2\njel;8.1\njel;10.4\njel;29.5\njel;14.8\njel;0.2\njel;26.5\njel;10.2\njel;6.6\njel;9.8\njel;27.6\njel;22.4\njel;13.6\njel;15.2\njel;23.1\njel;30.9\njel;23.3\njel;23.2\njel;23.6\njel;16.9\njel;14.8\njel;28.7\njel;20.0\njel;27.8\njel;18.2\njel;15.3\njel;21.8\njel;16.7\njel;10.7\njel;13.1\njel;24.4\njel;13.8\njel;20.9\njel;25.6\njel;11.8\njel;13.7\njel;14.9\njel;11.2\njel;20.6\njel;22.5\njel;17.8\njel;16.8\njel;20.2\njel;15.5\njel;5.0\njel;12.8\njel;20.3\njel;10.3\njel;30.4\njel;12.5\njel;20.9\njel;25.7\njel;28.1\njel;7.0\njel;9.4\njel;26.6\njel;23.6\njel;29.6\njel;15.9\njel;8.9\njel;11.9\njel;29.5\njel;13.6\njel;19.2\njel;23.7\njel;30.1\njel;19.8\njel;20.5\njel;17.9\njel;18.3\njel;17.7\njel;13.3\njel;11.8\njel;11.4\njel;13.2\njel;10.3\njel;7.8\njel;21.5\njel;34.5\njel;25.7\njel;17.8\njel;19.1\njel;16.0\njel;1.0\njel;21.4\njel;5.8\njel;11.1\njel;15.5\njel;21.9\njel;17.8\njel;17.2\njel;22.9\njel;24.4\njel;24.9\njel;12.9\njel;26.6\njel;5.6\njel;20.9\njel;13.6\njel;20.6\njel;29.6\njel;15.6\njel;29.8\njel;30.7\njel;17.8\njel;26.4\njel;14.0\njel;8.1\njel;15.6\njel;18.3\njel;23.8\njel;22.5\njel;13.8\njel;26.9\njel;7.9\njel;15.2\njel;14.8\njel;13.3\njel;20.5\njel;15.9\njel;21.2\njel;14.8\njel;15.5\njel;21.5\njel;21.5\njel;16.3\njel;13.6\njel;24.6\njel;10.3\njel;11.4\njel;9.5\njel;8.1\njel;15.1\njel;18.5\njel;20.1\njel;22.0\njel;11.1\njel;21.6\njel;18.9\njel;23.3\njel;7.0\njel;16.7\njel;21.2\njel;24.1\njel;39.6\njel;20.6\njel;22.6\njel;20.6\njel;17.2\njel;22.5\njel;18.4\njel;30.2\njel;17.0\njel;21.7\njel;15.4\njel;31.4\njel;18.9\njel;30.3\njel;13.4\njel;20.9\njel;14.1\njel;18.0\njel;13.9\njel;5.9\njel;3.7\njel;17.6\njel;28.4\njel;25.0\njel;11.8\njel;15.9\njel;20.5\njel;-0.1\njel;21.0\njel;12.5\njel;5.6\njel;22.3\njel;17.0\njel;8.0\njel;24.9\njel;9.7\njel;31.4\njel;20.6\njel;14.7\njel;27.6\njel;35.3\njel;15.0\njel;9.1\njel;11.5\njel;16.2\njel;32.1\njel;17.1\njel;15.1\njel;11.0\njel;14.0\njel;23.8\njel;17.5\njel;25.9\njel;18.1\njel;15.8\njel;21.3\njel;21.4\njel;21.6\njel;3.2\njel;21.3\njel;22.0\njel;3.6\njel;18.3\njel;34.6\njel;13.2\njel;15.4\njel;20.8\njel;17.6\njel;23.8\njel;30.5\njel;25.0\njel;20.4\njel;14.5\njel;24.8\njel;18.9\njel;21.0\njel;8.6\njel;12.6\njel;22.1\njel;11.3\njel;20.9\njel;12.1\njel;19.1\njel;14.8\njel;17.1\njel;29.5\njel;21.9\njel;15.2\njel;19.4\njel;20.5\njel;15.4\njel;14.7\njel;24.2\njel;28.2\njel;14.5\njel;20.8\njel;10.2\njel;24.3\njel;14.5\njel;23.6\njel;15.8\njel;23.3\njel;15.8\njel;12.5\njel;10.2\njel;22.2\njel;21.7\njel;18.0\njel;25.8\njel;23.7\njel;27.4\njel;27.7\njel;18.7\njel;5.8\njel;17.9\njel;19.2\njel;19.4\njel;14.1\njel;28.7\njel;13.5\njel;11.0\njel;11.4\njel;30.4\njel;22.0\njel;23.1\njel;16.0\njel;25.4\njel;12.7\njel;25.5\njel;25.6\njel;17.7\njel;14.5\njel;16.8\njel;12.4\njel;20.8\njel;18.5\njel;30.5\njel;15.2\njel;19.3\njel;24.6\njel;21.5\njel;18.1\njel;23.1\njel;12.3\njel;27.0\njel;11.5\njel;23.3\njel;12.1\njel;20.6\njel;36.2\njel;17.7\njel;21.2\njel;15.2\njel;17.8\njel;8.7\njel;16.0\njel;10.6\njel;16.2\njel;32.5\njel;24.4\njel;8.5\njel;19.8\njel;18.9\njel;16.3\njel;18.3\njel;27.8\njel;6.7\njel;15.5\njel;24.8\njel;27.9\njel;24.5\njel;16.0\njel;17.6\njel;13.6\njel;7.6\njel;8.8\njel;11.3\njel;15.6\njel;20.7\njel;15.2\njel;15.1\njel;22.2\njel;20.8\njel;12.6\njel;7.5\njel;13.4\njel;15.8\njel;17.8\njel;24.0\njel;10.7\njel;10.1\njel;4.6\njel;3.5\njel;31.1\njel;25.4\njel;25.3\njel;18.8\njel;7.6\njel;20.3\njel;29.0\njel;11.9\njel;27.0\njel;30.2\njel;9.8\njel;8.1\njel;21.6\njel;25.5\njel;18.0\njel;19.2\njel;14.7\njel;21.6\njel;1.2\njel;26.8\njel;20.5\njel;13.1\njel;7.6\njel;15.3\njel;22.1\njel;17.7\njel;31.6\njel;27.2\njel;12.0\njel;6.2\njel;18.8\njel;30.8\njel;23.0\njel;19.0\njel;11.8\njel;11.1\njel;18.4\njel;15.1\njel;12.7\njel;23.6\njel;9.7\njel;19.6\njel;29.6\njel;14.9\njel;15.6\njel;21.2\njel;27.7\njel;17.3\njel;27.6\njel;10.0\njel;20.9\njel;11.8\njel;23.1\njel;25.4\njel;20.3\njel;32.4\njel;25.7\njel;24.7\njel;14.7\njel;10.4\njel;16.7\njel;9.6\njel;22.4\njel;22.6\njel;14.4\njel;14.3\njel;21.9\njel;23.6\njel;20.5\njel;24.8\njel;21.2\njel;11.3\njel;12.4\njel;24.6\njel;16.3\njel;21.5\njel;21.8\njel;13.8\njel;29.2\njel;19.1\njel;20.2\njel;16.9\njel;21.6\njel;11.6\njel;29.0\njel;20.8\njel;7.5\njel;30.9\njel;27.1\njel;18.1\njel;21.5\njel;26.1\njel;18.2\njel;17.2\njel;12.4\njel;12.2\njel;18.3\njel;10.1\njel;6.4\njel;23.0\njel;15.8\njel;14.9\njel;25.7\njel;20.1\njel;20.1\njel;19.0\njel;19.7\njel;13.1\njel;11.1\njel;17.6\njel;26.4\njel;23.3\njel;34.3\njel;15.2\njel;27.5\njel;10.9\njel;30.0\njel;7.7\njel;27.9\njel;14.0\njel;23.1\njel;15.3\njel;15.1\njel;16.5\njel;12.9\njel;12.6\njel;19.3\njel;26.6\njel;14.5\njel;15.2\njel;21.6\njel;19.7\njel;22.8\njel;20.5\njel;7.6\njel;8.0\njel;26.8\njel;3.0\njel;16.6\njel;8.5\njel;28.1\njel;20.9\njel;17.1\njel;14.3\njel;7.6\njel;9.4\njel;16.8\njel;30.1\njel;21.6\njel;5.8\njel;26.7\njel;22.4\njel;20.3\njel;19.3\njel;20.7\njel;20.2\njel;22.3\njel;7.2\njel;26.5\njel;19.8\njel;17.5\njel;14.8\njel;18.1\njel;14.1\njel;19.3\njel;16.7\njel;9.0\njel;20.9\njel;15.3\njel;32.3\njel;22.8\njel;13.0\njel;17.4\njel;17.4\njel;17.0\njel;14.9\njel;10.8\njel;15.3\njel;27.3\njel;28.3\njel;7.4\njel;21.6\njel;16.5\njel;17.3\njel;19.8\njel;14.5\njel;20.1\njel;17.9\njel;13.1\njel;26.1\njel;7.9\njel;21.2\njel;12.6\njel;14.0\njel;28.4\njel;16.0\njel;28.4\njel;10.3\njel;37.8\njel;27.5\njel;22.3\njel;5.6\njel;12.3\njel;13.3\njel;37.2\njel;21.7\njel;19.8\njel;8.1\njel;19.0\njel;19.5\njel;17.9\njel;19.8\njel;11.6\njel;34.5\njel;18.0\njel;12.9\njel;16.8\njel;13.2\njel;11.3\njel;9.3\njel;24.6\njel;20.1\njel;14.5\njel;8.4\njel;5.0\njel;13.5\njel;23.3\njel;22.7\njel;14.4\njel;12.8\njel;17.5\njel;23.1\njel;18.6\njel;24.0\njel;9.9\njel;14.5\njel;17.4\njel;20.8\njel;6.0\njel;15.1\njel;13.9\njel;17.6\njel;16.1\njel;16.9\njel;19.3\njel;16.0\njel;21.0\njel;20.8\njel;14.5\njel;21.0\njel;16.0\njel;14.7\njel;28.1\njel;17.1\njel;18.1\njel;16.3\njel;15.2\njel;9.4\njel;6.0\njel;10.8\njel;9.2\njel;15.8\njel;30.6\njel;12.8\njel;14.7\njel;15.9\njel;10.7\njel;15.1\njel;24.3\njel;16.9\njel;19.2\njel;21.8\njel;14.3\njel;21.8\njel;18.8\njel;16.2\njel;15.3\njel;20.5\njel;8.4\njel;14.9\njel;34.1\njel;8.3\njel;25.9\njel;17.3\njel;7.9\njel;23.7\njel;18.3\njel;4.0\njel;25.5\njel;8.9\njel;20.0\njel;18.7\njel;23.3\njel;14.7\njel;22.1\njel;8.2\njel;14.4\njel;15.1\njel;22.0\njel;12.1\njel;22.9\njel;16.3\njel;20.3\njel;22.6\njel;27.1\njel;16.8\njel;22.2\njel;16.3\njel;8.6\njel;12.8\njel;28.7\njel;19.5\njel;21.2\njel;15.4\njel;17.7\njel;11.7\njel;19.3\njel;19.2\njel;10.6\njel;10.2\njel;13.8\njel;17.1\njel;11.4\njel;28.4\njel;23.1\njel;27.3\njel;19.4\njel;13.8\njel;14.6\njel;8.3\njel;22.6\njel;25.4\njel;24.3\njel;20.2\njel;26.8\njel;30.1\njel;30.3\njel;7.2\njel;4.5\njel;16.2\njel;32.2\njel;20.1\njel;4.9\njel;13.6\njel;11.1\njel;14.8\njel;17.1\njel;15.7\njel;24.6\njel;14.7\njel;31.4\njel;19.8\njel;15.8\njel;8.5\njel;12.8\njel;25.8\njel;35.1\njel;10.9\njel;26.3\njel;20.3\njel;13.5\njel;3.0\njel;17.1\njel;21.3\njel;21.4\njel;22.5\njel;7.3\njel;12.9\njel;4.6\njel;25.2\njel;22.4\njel;14.1\njel;31.7\njel;14.7\njel;25.8\njel;29.2\njel;24.1\njel;16.4\njel;5.2\njel;16.4\njel;22.5\njel;26.3\njel;17.1\njel;25.1\njel;4.1\njel;3.7\njel;18.1\njel;24.1\njel;13.6\njel;15.5\njel;24.4\njel;16.5\njel;28.1\njel;26.6\njel;5.9\njel;10.8\njel;20.3\njel;16.0\njel;5.1\njel;16.3\njel;21.2\njel;19.1\njel;26.3\njel;16.5\njel;14.7\njel;24.0\njel;18.7\njel;20.1\njel;4.5\njel;16.4\njel;13.6\njel;16.6\njel;17.0\njel;17.1\njel;22.5\njel;25.8\njel;25.2\njel;19.0\njel;23.0\njel;15.7\njel;26.3\njel;2.6\njel;21.9\njel;10.6\njel;12.8\njel;12.4\njel;24.9\njel;23.5\njel;22.9\njel;12.1\njel;9.9\njel;0.2\njel;23.2\njel;8.4\njel;12.4\njel;5.7\njel;18.4\njel;9.8\njel;35.1\njel;16.5\njel;16.1\njel;13.0\njel;17.8\njel;17.6\njel;11.8\njel;18.3\njel;6.0\njel;3.6\njel;23.1\njel;29.5\njel;14.5\njel;10.0\njel;16.5\njel;32.5\njel;16.5\njel;15.6\njel;19.8\njel;27.1\njel;25.4\njel;16.3\njel;23.6\njel;9.2\njel;21.2\njel;26.6\njel;15.7\njel;22.6\njel;18.2\njel;15.1\njel;16.7\njel;22.5\njel;7.7\njel;18.0\njel;21.2\njel;27.9\njel;13.2\njel;22.0\njel;24.8\njel;18.5\njel;11.3\njel;12.2\njel;17.2\njel;17.9\njel;16.2\njel;13.1\njel;23.4\njel;20.4\njel;21.0\njel;20.8\njel;21.8\njel;22.2\njel;17.1\njel;17.6\njel;30.9\njel;19.9\njel;16.2\njel;22.9\njel;20.1\njel;24.8\njel;26.6\njel;19.5\njel;15.2\njel;16.0\njel;11.8\njel;27.7\njel;13.8\njel;27.8\njel;16.6\njel;25.7\njel;16.5\njel;13.9\njel;14.5\njel;18.9\njel;22.5\njel;30.8\njel;21.6\njel;20.3\njel;6.7\njel;32.3\njel;11.4\njel;15.1\njel;24.1\njel;16.9\njel;8.3\njel;14.3\njel;9.9\njel;16.5\njel;22.5\njel;22.3\njel;12.0\njel;11.8\njel;11.5\njel;25.6\njel;31.0\njel;26.1\njel;19.6\njel;14.6\njel;2.1\njel;27.1\njel;26.8\njel;16.3\njel;15.0\njel;18.3\njel;24.9\njel;27.2\njel;19.1\njel;19.9\njel;22.7\njel;25.1\njel;8.9\njel;16.5\njel;15.9\njel;23.2\njel;22.9\njel;16.1\njel;19.0\njel;26.5\njel;12.9\njel;24.6\njel;13.1\njel;3.2\njel;29.4\njel;10.5\njel;20.2\njel;15.8\njel;13.4\njel;11.5\njel;21.6\njel;20.8\njel;20.7\njel;28.7\njel;10.7\njel;13.6\njel;1.9\njel;23.8\njel;12.4\njel;21.7\njel;30.6\njel;32.2\njel;20.8\njel;27.8\njel;30.8\njel;30.1\njel;16.3\njel;22.3\njel;19.4\njel;20.7\njel;9.9\njel;10.8\njel;18.4\njel;7.9\njel;8.5\njel;31.1\njel;14.7\njel;23.1\njel;31.0\njel;12.7\njel;15.8\njel;16.9\njel;26.9\njel;9.5\njel;14.2\njel;18.2\njel;24.6\njel;17.8\njel;15.3\njel;5.4\njel;18.9\njel;28.4\njel;12.2\njel;15.1\njel;19.2\njel;23.9\njel;36.0\njel;23.9\njel;26.1\njel;15.3\njel;12.1\njel;9.8\njel;7.0\njel;19.9\njel;12.7\njel;-4.9\njel;19.4\njel;17.9\njel;18.7\njel;8.2\njel;29.2\njel;15.4\njel;17.2\njel;18.1\njel;15.8\njel;8.1\njel;14.9\njel;19.0\njel;24.4\njel;13.2\njel;20.3\njel;5.6\njel;14.8\njel;22.4\njel;19.0\njel;12.6\njel;12.5\njel;6.0\njel;16.9\njel;10.5\njel;15.0\njel;9.4\njel;20.7\njel;14.0\njel;23.0\njel;14.4\njel;11.4\njel;17.3\njel;18.8\njel;1.8\njel;22.9\njel;9.0\njel;19.4\njel;32.4\njel;4.0\njel;21.2\njel;8.2\njel;18.0\njel;16.6\njel;33.4\njel;27.4\njel;20.5\njel;28.2\njel;25.0\njel;13.3\njel;20.3\njel;21.0\njel;13.5\njel;17.0\njel;7.0\njel;20.6\njel;13.0\njel;18.4\njel;15.5\njel;17.8\njel;8.1\njel;19.6\njel;13.5\njel;11.7\njel;8.5\njel;5.8\njel;22.3\njel;4.3\njel;7.8\njel;-6.1\njel;23.6\njel;13.2\njel;24.2\njel;24.6\njel;19.1\njel;14.2\njel;18.2\njel;22.4\njel;15.4\njel;5.7\njel;15.5\njel;26.0\njel;16.0\njel;16.8\njel;13.3\njel;15.2\njel;16.5\njel;19.8\njel;7.5\njel;13.9\njel;24.4\njel;18.9\njel;17.1\njel;25.9\njel;16.0\njel;12.2\njel;18.7\njel;30.1\njel;7.3\njel;18.7\njel;18.2\njel;22.2\njel;33.6\njel;22.0\njel;6.4\njel;13.7\njel;16.0\njel;11.0\njel;15.3\njel;15.0\njel;22.8\njel;1.6\njel;19.2\njel;16.2\njel;7.6\njel;21.3\njel;19.6\njel;13.7\njel;8.6\njel;23.5\njel;28.8\njel;9.1\njel;18.1\njel;13.0\njel;17.0\njel;17.8\njel;27.2\njel;18.2\njel;13.6\njel;15.4\njel;17.4\njel;3.5\njel;26.4\njel;28.0\njel;23.3\njel;19.2\njel;25.3\njel;38.9\njel;15.3\njel;22.4\njel;26.3\njel;18.6\njel;25.6\njel;14.8\njel;36.0\njel;18.4\njel;13.6\njel;24.2\njel;8.4\njel;16.8\njel;19.9\njel;8.9\njel;21.6\njel;15.2\njel;12.4\njel;20.3\njel;20.7\njel;16.2\njel;24.8\njel;15.5\njel;18.6\njel;15.0\njel;10.8\njel;28.8\njel;19.0\njel;10.0\njel;4.8\njel;13.7\njel;21.5\njel;28.0\njel;21.5\njel;11.1\njel;9.6\njel;19.1\njel;19.6\njel;27.9\njel;19.3\njel;26.2\njel;21.3\njel;26.3\njel;22.1\njel;18.5\njel;19.7\njel;27.1\njel;9.6\njel;15.6\njel;10.7\njel;27.3\njel;17.8\njel;13.2\njel;9.2\njel;26.8\njel;26.1\njel;15.5\njel;24.8\njel;19.9\njel;19.7\njel;21.5\njel;19.3\njel;17.1\njel;7.5\njel;11.5\njel;12.4\njel;8.1\njel;26.9\njel;13.6\njel;9.5\njel;15.6\njel;12.1\njel;14.9\njel;24.9\njel;19.2\njel;20.4\njel;15.7\njel;31.3\njel;26.9\njel;11.6\njel;19.9\njel;19.0\njel;19.1\njel;25.9\njel;-0.7\njel;5.6\njel;24.8\njel;15.5\njel;13.7\njel;13.1\njel;28.6\njel;24.1\njel;12.8\njel;12.7\njel;13.7\njel;24.6\njel;9.6\njel;18.9\njel;21.8\njel;14.0\njel;22.5\njel;10.4\njel;13.0\njel;10.8\njel;24.0\njel;12.0\njel;20.8\njel;26.0\njel;8.3\njel;14.1\njel;21.5\njel;2.2\njel;11.2\njel;2.1\njel;33.5\njel;15.2\njel;19.1\njel;18.6\njel;19.2\njel;12.6\njel;18.5\njel;18.6\njel;26.6\njel;24.0\njel;23.5\njel;12.6\njel;12.1\njel;8.1\njel;20.9\njel;17.7\njel;9.4\njel;9.2\njel;16.3\njel;14.2\njel;16.8\njel;5.2\njel;8.9\njel;18.8\njel;19.9\njel;19.2\njel;10.1\njel;26.3\njel;14.2\njel;9.5\njel;10.4\njel;13.3\njel;21.8\njel;11.3\njel;15.2\njel;18.8\njel;15.4\njel;25.6\njel;26.9\njel;20.1\njel;7.0\njel;30.5\njel;18.3\njel;21.6\njel;13.1\njel;4.9\njel;28.1\njel;7.3\njel;15.1\njel;27.2\njel;21.6\njel;15.6\njel;14.9\njel;25.1\njel;16.4\njel;3.2\njel;9.5\njel;20.2\njel;12.8\njel;12.3\njel;10.3\njel;19.4\njel;18.7\njel;19.8\njel;28.7\njel;23.5\njel;22.4\njel;15.2\njel;15.1\njel;23.0\njel;21.5\njel;13.3\njel;26.9\njel;25.2\njel;13.2\njel;27.9\njel;13.1\njel;27.7\njel;-1.3\njel;30.6\njel;16.8\njel;20.2\njel;16.8\njel;20.3\njel;26.5\njel;17.7\njel;22.3\njel;26.5\njel;16.4\njel;15.6\njel;10.6\njel;15.1\njel;21.3\njel;35.6\njel;12.4\njel;-1.2\njel;14.3\njel;24.3\njel;25.1\njel;18.5\njel;25.3\njel;11.8\njel;11.6\njel;18.7\njel;1.5\njel;10.7\njel;22.9\njel;27.7\njel;15.6\njel;27.4\njel;23.5\njel;0.7\njel;13.1\njel;22.6\njel;16.3\njel;15.6\njel;9.6\njel;11.5\njel;17.0\njel;17.9\njel;13.8\njel;22.1\njel;7.1\njel;8.9\njel;17.7\njel;30.7\njel;28.5\njel;22.0\njel;6.0\njel;23.1\njel;17.4\njel;31.7\njel;20.9\njel;10.4\njel;20.1\njel;16.3\njel;17.7\njel;19.2\njel;28.8\njel;20.6\njel;20.4\njel;18.6\njel;8.4\njel;13.6\njel;11.3\njel;6.3\njel;17.0\njel;13.8\njel;14.3\njel;22.7\njel;24.3\njel;21.6\njel;25.7\njel;16.2\njel;17.5\njel;21.2\njel;24.8\njel;12.8\njel;12.7\njel;11.2\njel;15.5\njel;3.0\njel;22.3\njel;21.0\njel;23.1\njel;9.3\njel;12.3\njel;12.2\njel;24.0\njel;13.3\njel;15.7\njel;5.2\njel;16.5\njel;19.7\njel;11.4\njel;17.7\njel;6.6\njel;12.9\njel;26.0\njel;26.3\njel;10.2\njel;19.8\njel;19.7\njel;20.2\njel;19.7\njel;14.8\njel;17.9\njel;29.6\njel;15.1\njel;8.9\njel;18.4\njel;16.6\njel;23.7\njel;18.6\njel;27.5\njel;30.2\njel;26.2\njel;19.8\njel;23.1\njel;9.3\njel;18.8\njel;1.8\njel;21.7\njel;24.3\njel;5.6\njel;22.4\njel;22.3\njel;28.4\njel;15.9\njel;35.6\njel;16.7\njel;20.6\njel;16.5\njel;16.1\njel;16.7\njel;12.3\njel;0.8\njel;20.5\njel;9.4\njel;14.6\njel;12.6\njel;21.6\njel;20.0\njel;19.6\njel;29.5\njel;5.1\njel;7.7\njel;5.1\njel;19.8\njel;24.7\njel;26.3\njel;11.8\njel;5.8\njel;19.7\njel;14.6\njel;17.9\njel;25.8\njel;19.6\njel;14.6\njel;30.9\njel;26.3\njel;20.8\njel;4.7\njel;15.9\njel;21.5\njel;11.3\njel;15.6\njel;17.2\njel;25.0\njel;21.3\njel;15.7\njel;23.0\njel;22.6\njel;20.6\njel;14.5\njel;23.3\njel;22.9\njel;10.3\njel;18.0\njel;7.9\njel;14.1\njel;10.1\njel;27.9\njel;19.4\njel;23.6\njel;19.1\njel;26.5\njel;22.8\njel;19.2\njel;22.7\njel;21.1\njel;25.1\njel;28.6\njel;17.6\njel;7.5\njel;20.8\njel;24.3\njel;29.0\njel;18.1\njel;19.9\njel;21.7\njel;24.0\njel;13.0\njel;16.5\njel;22.9\njel;13.4\njel;9.5\njel;27.0\njel;15.4\njel;16.2\njel;16.5\njel;13.7\njel;10.5\njel;18.5\njel;29.5\njel;34.5\njel;19.3\njel;20.4\njel;14.0\njel;19.3\njel;10.2\njel;29.7\njel;12.0\njel;15.3\njel;18.4\njel;17.3\njel;16.1\njel;17.8\njel;22.7\njel;2.2\njel;22.2\njel;21.1\njel;10.7\njel;15.1\njel;22.6\njel;12.8\njel;12.8\njel;15.5\njel;6.8\njel;9.9\njel;25.3\njel;18.9\njel;13.8\njel;-3.7\njel;7.6\njel;11.9\njel;11.3\njel;7.8\njel;20.9\njel;18.7\njel;10.6\njel;25.3\njel;11.4\njel;18.5\njel;20.6\njel;14.6\njel;12.7\njel;10.3\njel;18.6\njel;21.4\njel;26.9\njel;18.1\njel;14.5\njel;4.3\njel;33.2\njel;20.2\njel;8.3\njel;17.4\njel;18.4\njel;16.5\njel;20.6\njel;18.3\njel;10.1\njel;32.5\njel;23.1\njel;14.3\njel;22.3\njel;14.7\njel;25.8\njel;30.7\njel;21.6\njel;9.6\njel;13.0\njel;11.8\njel;13.3\njel;19.1\njel;8.5\njel;22.5\njel;13.8\njel;16.6\njel;14.6\njel;14.3\njel;26.5\njel;12.2\njel;12.3\njel;40.4\njel;12.6\njel;22.2\njel;19.8\njel;13.4\njel;17.4\njel;10.6\njel;19.7\njel;17.2\njel;17.7\njel;3.0\njel;16.1\njel;18.7\njel;17.4\njel;5.4\njel;10.4\njel;20.3\njel;22.1\njel;10.9\njel;11.5\njel;15.6\njel;21.4\njel;6.4\njel;12.8\njel;24.5\njel;17.5\njel;9.4\njel;22.0\njel;5.4\njel;7.1\njel;5.4\njel;31.0\njel;5.7\njel;31.3\njel;27.3\njel;21.0\njel;9.2\njel;16.4\njel;24.3\njel;6.3\njel;18.9\njel;19.0\njel;15.0\njel;12.2\njel;21.1\njel;15.8\njel;14.9\njel;14.9\njel;28.6\njel;15.6\njel;18.8\njel;26.3\njel;23.3\njel;10.5\njel;15.6\njel;22.5\njel;24.5\njel;14.2\njel;13.5\njel;19.1\njel;14.6\njel;17.8\njel;10.6\njel;16.9\njel;19.1\njel;25.2\njel;22.6\njel;22.6\njel;11.2\njel;25.0\njel;11.6\njel;19.1\njel;13.5\njel;10.6\njel;22.4\njel;16.5\njel;19.6\njel;12.1\njel;13.4\njel;14.2\njel;30.2\njel;17.3\njel;14.2\njel;15.6\njel;11.7\njel;12.1\njel;24.1\njel;19.2\njel;17.3\njel;10.6\njel;11.7\njel;25.4\njel;3.7\njel;33.4\njel;17.6\njel;10.7\njel;29.9\njel;22.4\njel;16.0\njel;19.1\njel;20.0\njel;2.5\njel;22.6\njel;16.1\njel;4.8\njel;15.9\njel;11.3\njel;10.1\njel;22.4\njel;17.8\njel;34.8\njel;5.3\njel;13.6\njel;18.1\njel;25.4\njel;16.7\njel;15.6\njel;12.2\njel;19.2\njel;20.5\njel;12.6\njel;16.3\njel;18.9\njel;20.3\njel;15.8\njel;15.7\njel;20.5\njel;19.0\njel;15.4\njel;11.1\njel;21.7\njel;14.8\njel;22.7\njel;14.5\njel;16.1\njel;22.3\njel;26.7\njel;21.3\njel;30.7\njel;6.3\njel;11.7\njel;18.0\njel;13.3\njel;18.0\njel;25.7\njel;11.6\njel;36.4\njel;28.4\njel;21.1\njel;19.8\njel;30.4\njel;13.5\njel;8.0\njel;12.7\njel;11.3\njel;11.9\njel;20.8\njel;17.7\njel;20.8\njel;19.8\njel;9.6\njel;15.8\njel;24.9\njel;10.9\njel;15.9\njel;18.1\njel;5.9\njel;18.8\njel;19.7\njel;21.3\njel;22.3\njel;23.6\njel;29.5\njel;22.4\njel;16.4\njel;16.0\njel;31.4\njel;23.5\njel;10.3\njel;31.2\njel;16.0\njel;27.3\njel;23.5\njel;13.2\njel;17.4\njel;20.2\njel;16.8\njel;23.0\njel;18.5\njel;21.4\njel;22.8\njel;20.9\njel;22.2\njel;19.8\njel;12.5\njel;31.2\njel;21.8\njel;14.8\njel;24.7\njel;11.9\njel;14.5\njel;11.1\njel;20.2\njel;14.3\njel;26.2\njel;22.7\njel;16.0\njel;14.5\njel;25.8\njel;12.0\njel;20.8\njel;26.9\njel;17.3\njel;16.5\njel;24.9\njel;10.1\njel;20.9\njel;7.1\njel;7.9\njel;17.8\njel;18.9\njel;23.8\njel;9.8\njel;8.9\njel;16.0\njel;11.2\njel;14.2\njel;19.2\njel;19.9\njel;18.7\njel;9.7\njel;23.2\njel;31.4\njel;16.9\njel;13.2\njel;16.1\njel;21.5\njel;8.3\njel;21.7\njel;3.9\njel;5.7\njel;13.5\njel;12.1\njel;17.3\njel;11.0\njel;31.0\njel;11.1\njel;21.3\njel;13.0\njel;16.5\njel;7.2\njel;14.4\njel;24.3\njel;14.3\njel;21.1\njel;14.2\njel;16.1\njel;24.7\njel;16.6\njel;25.4\njel;25.4\njel;21.9\njel;20.5\njel;19.0\njel;1.7\njel;13.2\njel;25.5\njel;13.1\njel;18.2\njel;18.5\njel;14.1\njel;13.2\njel;20.7\njel;17.9\njel;32.1\njel;23.3\njel;25.7\njel;16.9\njel;11.3\njel;12.2\njel;16.9\njel;10.3\njel;13.6\njel;11.5\njel;25.0\njel;11.8\njel;14.2\njel;15.6\njel;30.3\njel;8.9\njel;23.1\njel;11.7\njel;32.1\njel;20.1\njel;21.4\njel;31.1\njel;16.5\njel;22.3\njel;8.7\njel;27.1\njel;10.9\njel;18.6\njel;11.6\njel;5.0\njel;18.3\njel;20.4\njel;26.8\njel;15.3\njel;15.5\njel;6.2\njel;14.2\njel;21.5\njel;13.0\njel;30.8\njel;19.2\njel;14.8\njel;7.9\njel;13.8\njel;10.1\njel;15.7\njel;21.8\njel;11.3\njel;27.5\njel;16.8\njel;23.5\njel;21.4\njel;16.3\njel;16.7\njel;18.9\njel;11.6\njel;21.6\njel;21.1\njel;25.8\njel;18.0\njel;7.4\njel;24.6\njel;29.0\njel;18.9\njel;23.0\njel;22.4\njel;21.7\njel;13.6\njel;22.8\njel;17.9\njel;12.5\njel;17.6\njel;22.1\njel;10.0\njel;12.9\njel;17.6\njel;26.4\njel;23.1\njel;23.5\njel;24.3\njel;14.5\njel;24.6\njel;21.6\njel;21.0\njel;46.5\njel;26.3\njel;20.2\njel;9.3\njel;19.7\njel;12.3\njel;23.1\njel;17.9\njel;20.0\njel;0.4\njel;15.7\njel;14.0\njel;23.0\njel;16.7\njel;5.3\njel;24.8\njel;14.5\njel;21.9\njel;19.5\njel;24.1\njel;6.7\njel;16.2\njel;21.0\njel;15.5\njel;1.0\njel;17.8\njel;20.3\njel;8.4\njel;7.4\njel;11.0\njel;14.8\njel;25.2\njel;26.3\njel;8.4\njel;12.3\njel;19.4\njel;21.1\njel;16.3\njel;12.6\njel;21.4\njel;20.6\njel;21.0\njel;24.9\njel;21.0\njel;13.8\njel;24.5\njel;21.4\njel;9.7\njel;17.2\njel;24.9\njel;18.5\njel;12.6\njel;15.7\njel;17.1\njel;12.5\njel;33.4\njel;19.4\njel;6.4\njel;11.3\njel;22.5\njel;17.2\njel;25.5\njel;11.5\njel;12.6\njel;11.5\njel;17.0\njel;14.3\njel;20.0\njel;19.1\njel;15.8\njel;15.0\njel;25.8\njel;9.9\njel;15.0\njel;13.4\njel;4.8\njel;27.6\njel;10.5\njel;27.2\njel;13.8\njel;20.1\njel;23.7\njel;13.5\njel;21.0\njel;25.5\njel;21.9\njel;20.4\njel;28.4\njel;31.5\njel;24.2\njel;23.9\njel;19.3\njel;4.7\njel;-1.5\njel;13.8\njel;18.0\njel;22.4\njel;22.0\njel;15.1\njel;17.6\njel;13.7\njel;22.2\njel;19.9\njel;27.7\njel;28.9\njel;23.3\njel;12.9\njel;25.7\njel;19.6\njel;8.0\njel;14.7\njel;20.0\njel;13.1\njel;26.8\njel;17.1\njel;32.3\njel;16.6\njel;23.2\njel;18.4\njel;17.9\njel;15.5\njel;24.7\njel;18.5\njel;10.7\njel;15.5\njel;18.4\njel;26.2\njel;22.2\njel;18.0\njel;25.4\njel;29.2\njel;5.3\njel;19.8\njel;24.7\njel;21.8\njel;17.1\njel;21.5\njel;26.0\njel;18.0\njel;16.2\njel;26.8\njel;19.0\njel;23.0\njel;11.1\njel;21.4\njel;19.5\njel;22.0\njel;17.2\njel;18.3\njel;6.1\njel;13.9\njel;10.4\njel;21.6\njel;25.7\njel;18.0\njel;23.0\njel;25.3\njel;11.1\njel;14.6\njel;10.1\njel;19.8\njel;11.3\njel;15.3\njel;26.8\njel;12.2\njel;23.4\njel;9.0\njel;16.4\njel;11.6\njel;19.7\njel;16.4\njel;23.0\njel;9.7\njel;25.4\njel;15.6\njel;23.7\njel;25.5\njel;22.7\njel;12.1\njel;7.6\njel;28.5\njel;26.0\njel;6.8\njel;28.3\njel;17.7\njel;15.4\njel;11.5\njel;7.5\njel;15.9\njel;22.7\njel;21.1\njel;-0.1\njel;24.6\njel;20.2\njel;11.3\njel;20.4\njel;11.5\njel;18.2\njel;24.9\njel;6.1\njel;25.0\njel;12.1\njel;21.0\njel;19.9\njel;19.9\njel;22.1\njel;14.2\njel;14.4\njel;15.9\njel;21.1\njel;21.8\njel;9.2\njel;13.8\njel;16.4\njel;20.1\njel;25.0\njel;26.3\njel;12.4\njel;19.0\njel;19.4\njel;6.8\njel;4.7\njel;8.5\njel;13.5\njel;11.8\njel;22.3\njel;16.0\njel;35.3\njel;25.5\njel;35.3\njel;7.9\njel;20.7\njel;17.3\njel;13.5\njel;10.6\njel;21.6\njel;19.0\njel;18.2\njel;14.7\njel;15.6\njel;19.5\njel;13.5\njel;22.1\njel;23.1\njel;23.9\njel;28.1\njel;2.1\njel;15.4\njel;12.9\njel;17.6\njel;15.3\njel;24.1\njel;30.1\njel;6.9\njel;21.0\njel;24.9\njel;7.5\njel;21.2\njel;22.3\njel;14.4\njel;8.5\njel;14.7\njel;17.8\njel;20.5\njel;13.8\njel;11.9\njel;12.9\njel;11.3\njel;41.5\njel;11.6\njel;19.0\njel;19.5\njel;12.8\njel;23.6\njel;13.5\njel;17.1\njel;35.1\njel;8.2\njel;24.3\njel;12.6\njel;18.5\njel;12.9\njel;23.5\njel;18.0\njel;18.8\njel;7.8\njel;2.9\njel;2.0\njel;25.0\njel;10.7\njel;19.7\njel;31.0\njel;15.5\njel;15.4\njel;10.7\njel;9.2\njel;26.1\njel;13.0\njel;12.2\njel;22.6\njel;19.2\njel;18.2\njel;26.5\njel;28.5\njel;13.2\njel;15.3\njel;17.3\njel;6.0\njel;15.7\njel;13.7\njel;22.0\njel;12.9\njel;24.3\njel;13.4\njel;7.0\njel;9.8\njel;13.1\njel;17.8\njel;22.3\njel;12.6\njel;14.7\njel;16.2\njel;8.6\njel;28.8\njel;11.0\njel;24.2\njel;25.3\njel;0.8\njel;20.6\njel;13.3\njel;19.7\njel;0.3\njel;22.5\njel;14.0\njel;30.2\njel;14.3\njel;18.8\njel;15.0\njel;16.9\njel;6.0\njel;18.4\njel;16.8\njel;18.5\njel;20.8\njel;11.5\njel;15.7\njel;17.7\njel;12.6\njel;22.7\njel;3.5\njel;14.8\njel;25.4\njel;15.6\njel;13.8\njel;22.4\njel;10.4\njel;28.3\njel;17.8\njel;19.9\njel;18.8\njel;25.1\njel;9.0\njel;8.8\njel;18.4\njel;14.3\njel;14.0\njel;12.7\njel;18.5\njel;13.5\njel;22.8\njel;23.9\njel;24.3\njel;22.4\njel;19.1\njel;21.1\njel;13.4\njel;25.7\njel;20.2\njel;26.4\njel;25.6\njel;27.4\njel;25.0\njel;31.2\njel;28.5\njel;29.8\njel;14.0\njel;16.6\njel;14.9\njel;21.3\njel;22.9\njel;19.7\njel;20.3\njel;14.3\njel;13.6\njel;24.5\njel;15.0\njel;16.7\njel;21.1\njel;28.4\njel;10.6\njel;15.4\njel;14.6\njel;18.0\njel;13.2\njel;27.0\njel;19.3\njel;15.0\njel;23.8\njel;16.8\njel;15.9\njel;19.0\njel;15.4\njel;31.0\njel;8.3\njel;26.9\njel;16.4\njel;21.2\njel;18.4\njel;15.4\njel;9.8\njel;24.1\njel;13.4\njel;23.7\njel;21.9\njel;18.7\njel;2.6\njel;23.1\njel;7.4\njel;15.6\njel;6.2\njel;10.9\njel;22.2\njel;18.2\njel;8.1\njel;18.5\njel;12.8\njel;27.7\njel;20.0\njel;12.3\njel;20.6\njel;14.8\njel;19.5\njel;17.9\njel;26.9\njel;24.9\njel;26.4\njel;25.3\njel;28.0\njel;15.6\njel;18.3\njel;27.3\njel;17.6\njel;15.7\njel;16.8\njel;13.8\njel;25.1\njel;15.8\njel;25.8\njel;20.6\njel;11.7\njel;32.5\njel;17.9\njel;19.1\njel;17.3\njel;16.2\njel;25.6\njel;11.3\njel;18.4\njel;24.0\njel;-3.2\njel;32.6\njel;23.1\njel;19.5\njel;12.9\njel;15.5\njel;20.2\njel;20.7\njel;15.8\njel;17.5\njel;18.0\njel;17.6\njel;21.8\njel;26.8\njel;28.8\njel;15.4\njel;18.7\njel;1.3\njel;17.8\njel;14.1\njel;7.9\njel;19.1\njel;10.5\njel;11.7\njel;5.9\njel;13.5\njel;26.4\njel;11.8\njel;2.2\njel;16.8\njel;20.4\njel;25.1\njel;27.6\njel;13.8\njel;20.6\njel;18.3\njel;23.8\njel;30.3\njel;12.6\njel;32.3\njel;15.9\njel;8.4\njel;16.4\njel;24.9\njel;16.1\njel;19.5\njel;12.7\njel;28.5\njel;14.1\njel;10.9\njel;28.3\njel;13.9\njel;32.6\njel;20.0\njel;9.4\njel;7.3\njel;6.5\njel;23.5\njel;13.7\njel;19.7\njel;20.7\njel;14.3\njel;20.1\njel;25.3\njel;26.9\njel;17.2\njel;18.9\njel;21.7\njel;6.6\njel;25.9\njel;21.4\njel;17.5\njel;20.2\njel;20.3\njel;12.5\njel;37.5\njel;18.9\njel;13.1\njel;21.0\njel;17.2\njel;10.7\njel;23.3\njel;24.1\njel;16.5\njel;14.7\njel;21.9\njel;22.9\njel;17.0\njel;27.8\njel;8.7\njel;19.7\njel;17.9\njel;10.9\njel;19.4\njel;19.7\njel;3.9\njel;36.7\njel;21.5\njel;24.8\njel;14.5\njel;11.6\njel;18.9\njel;4.4\njel;26.2\njel;26.1\njel;21.7\njel;21.1\njel;24.2\njel;24.5\njel;12.3\njel;36.1\njel;23.2\njel;16.2\njel;18.2\njel;21.3\njel;6.4\njel;16.8\njel;18.8\njel;25.3\njel;9.4\njel;15.1\njel;14.0\njel;16.1\njel;31.1\njel;11.4\njel;24.0\njel;30.8\njel;14.2\njel;15.6\njel;16.7\njel;23.0\njel;33.2\njel;19.9\njel;21.7\njel;17.7\njel;21.4\njel;10.1\njel;27.6\njel;11.4\njel;24.8\njel;14.8\njel;25.2\njel;22.6\njel;38.2\njel;19.0\njel;22.7\njel;18.6\njel;22.2\njel;12.9\njel;23.8\njel;12.4\njel;14.0\njel;-4.8\njel;29.2\njel;23.3\njel;26.5\njel;22.2\njel;12.7\njel;10.7\njel;12.4\njel;19.4\njel;21.9\njel;3.9\njel;18.9\njel;10.4\njel;14.9\njel;22.8\njel;13.6\njel;12.4\njel;7.7\njel;26.3\njel;22.6\njel;12.8\njel;18.6\njel;16.4\njel;16.4\njel;28.5\njel;20.3\njel;30.0\njel;20.7\njel;13.5\njel;18.1\njel;13.2\njel;6.1\njel;18.8\njel;17.6\njel;22.9\njel;4.8\njel;30.4\njel;11.1\njel;19.6\njel;21.3\njel;23.8\njel;21.2\njel;19.7\njel;18.8\njel;17.7\njel;21.9\njel;17.3\njel;12.9\njel;18.6\njel;15.2\njel;15.7\njel;16.0\njel;17.9\njel;18.7\njel;22.1\njel;23.8\njel;18.9\njel;26.6\njel;12.7\njel;22.0\njel;22.3\njel;27.5\njel;27.8\njel;11.9\njel;0.2\njel;18.7\njel;19.2\njel;13.4\njel;14.0\njel;16.2\njel;22.2\njel;24.5\njel;20.1\njel;16.6\njel;11.6\njel;25.3\njel;15.4\njel;11.0\njel;19.6\njel;19.6\njel;23.3\njel;21.8\njel;8.4\njel;22.5\njel;19.6\njel;21.1\njel;20.9\njel;28.7\njel;17.8\njel;18.9\njel;21.8\njel;28.3\njel;19.8\njel;11.9\njel;15.1\njel;32.3\njel;13.1\njel;30.5\njel;14.5\njel;25.2\njel;16.0\njel;17.2\njel;12.4\njel;21.0\njel;25.0\njel;9.5\njel;25.0\njel;10.7\njel;25.2\njel;24.6\njel;20.6\njel;30.5\njel;15.6\njel;15.1\njel;29.9\njel;12.7\njel;25.2\njel;12.2\njel;14.4\njel;1.4\njel;16.2\njel;33.0\njel;23.0\njel;14.7\njel;8.3\njel;26.4\njel;16.0\njel;10.2\njel;1.8\njel;13.0\njel;6.4\njel;5.7\njel;19.1\njel;32.8\njel;13.7\njel;14.2\njel;8.4\njel;21.0\njel;16.3\njel;29.6\njel;26.9\njel;23.1\njel;14.9\njel;14.8\njel;14.0\njel;10.6\njel;12.8\njel;29.6\njel;10.7\njel;13.0\njel;17.2\njel;27.7\njel;12.9\njel;16.1\njel;16.5\njel;6.0\njel;11.0\njel;21.6\njel;12.9\njel;13.2\njel;9.7\njel;-5.0\njel;8.2\njel;31.3\njel;17.0\njel;19.9\njel;26.9\njel;17.8\njel;18.1\njel;23.1\njel;2.8\njel;19.7\njel;21.6\njel;18.8\njel;21.3\njel;12.7\njel;26.2\njel;13.1\njel;4.5\njel;23.7\njel;27.3\njel;9.5\njel;23.7\njel;10.7\njel;12.8\njel;27.8\njel;14.6\njel;30.2\njel;31.6\njel;29.8\njel;27.5\njel;28.6\njel;21.6\njel;22.2\njel;26.8\njel;20.4\njel;19.3\njel;22.5\njel;22.4\njel;11.1\njel;21.1\njel;9.8\njel;9.9\njel;22.8\njel;7.5\njel;7.5\njel;28.4\njel;21.5\njel;16.6\njel;20.2\njel;19.6\njel;22.1\njel;27.8\njel;11.9\njel;25.0\njel;1.0\njel;26.9\njel;19.4\njel;23.0\njel;25.8\njel;14.5\njel;10.5\njel;13.0\njel;17.1\njel;19.2\njel;29.8\njel;14.8\njel;6.5\njel;12.4\njel;23.7\njel;23.9\njel;23.2\njel;26.7\njel;21.3\njel;13.3\njel;15.2\njel;18.9\njel;19.7\njel;2.8\njel;15.5\njel;18.4\njel;21.9\njel;16.9\njel;21.1\njel;1.7\njel;6.5\njel;18.0\njel;28.1\njel;14.8\njel;21.7\njel;16.8\njel;26.5\njel;26.7\njel;25.4\njel;36.8\njel;13.1\njel;11.6\njel;28.0\njel;26.8\njel;24.0\njel;19.3\njel;13.9\njel;25.5\njel;30.3\njel;9.7\njel;18.2\njel;15.3\njel;8.4\njel;9.3\njel;12.2\njel;27.3\njel;12.0\njel;21.4\njel;16.2\njel;15.8\njel;28.1\njel;27.6\njel;14.5\njel;17.4\njel;1.8\njel;22.7\njel;17.6\njel;21.7\njel;20.9\njel;28.0\njel;11.1\njel;11.8\njel;19.3\njel;14.4\njel;22.0\njel;24.2\njel;23.2\njel;7.0\njel;15.8\njel;6.7\njel;19.0\njel;25.2\njel;21.4\njel;10.3\njel;16.5\njel;15.3\njel;15.3\njel;21.4\njel;9.6\njel;21.3\njel;27.9\njel;10.9\njel;20.1\njel;22.9\njel;22.8\njel;35.0\njel;10.7\njel;24.2\njel;26.6\njel;19.0\njel;24.6\njel;21.3\njel;18.1\njel;16.6\njel;6.0\njel;37.8\njel;23.7\njel;20.6\njel;18.7\njel;26.0\njel;13.2\njel;11.6\njel;19.5\njel;28.3\njel;27.8\njel;7.3\njel;20.3\njel;29.8\njel;25.8\njel;20.0\njel;33.0\njel;27.6\njel;16.8\njel;28.2\njel;33.2\njel;20.1\njel;18.0\njel;11.0\njel;19.2\njel;24.6\njel;13.6\njel;10.4\njel;13.7\njel;22.7\njel;14.8\njel;25.8\njel;16.1\njel;15.1\njel;15.4\njel;7.4\njel;19.6\njel;18.8\njel;16.1\njel;20.0\njel;19.7\njel;5.3\njel;16.1\njel;23.0\njel;22.0\njel;28.7\njel;8.3\njel;12.5\njel;19.9\njel;32.0\njel;16.8\njel;24.0\njel;18.3\njel;16.9\njel;28.0\njel;8.7\njel;9.3\njel;23.0\njel;10.5\njel;10.8\njel;12.6\njel;23.5\njel;18.8\njel;12.4\njel;14.2\njel;17.9\njel;12.1\njel;19.7\njel;25.5\njel;19.9\njel;16.7\njel;15.4\njel;20.4\njel;22.4\njel;18.4\njel;27.7\njel;28.8\njel;1.6\njel;4.3\njel;13.8\njel;6.7\njel;13.9\njel;23.7\njel;12.7\njel;12.9\njel;19.1\njel;17.6\njel;9.6\njel;11.1\njel;23.3\njel;5.9\njel;14.6\njel;21.3\njel;26.9\njel;16.7\njel;27.3\njel;23.0\njel;8.0\njel;18.5\njel;23.1\njel;12.6\njel;26.3\njel;21.0\njel;10.1\njel;19.8\njel;25.7\njel;17.9\njel;24.4\njel;19.1\njel;28.5\njel;15.3\njel;8.7\njel;13.7\njel;10.5\njel;24.3\njel;7.7\njel;13.9\njel;25.7\njel;15.5\njel;13.2\njel;11.9\njel;19.8\njel;14.1\njel;19.9\njel;15.9\njel;21.8\njel;13.8\njel;13.1\njel;27.8\njel;16.4\njel;16.4\njel;17.7\njel;24.0\njel;22.3\njel;21.7\njel;9.6\njel;23.6\njel;0.4\njel;17.4\njel;21.3\njel;14.9\njel;11.6\njel;19.3\njel;17.6\njel;-1.8\njel;20.8\njel;19.2\njel;25.4\njel;12.1\njel;13.1\njel;19.7\njel;14.2\njel;20.0\njel;23.5\njel;14.0\njel;10.5\njel;12.1\njel;19.6\njel;21.3\njel;19.5\njel;26.1\njel;9.8\njel;30.8\njel;19.4\njel;23.6\njel;18.4\njel;12.0\njel;19.0\njel;18.3\njel;11.3\njel;5.6\njel;10.8\njel;19.2\njel;15.7\njel;14.3\njel;9.0\njel;7.5\njel;4.4\njel;13.1\njel;25.0\njel;16.1\njel;15.6\njel;9.2\njel;22.3\njel;16.6\njel;17.1\njel;18.2\njel;23.9\njel;6.9\njel;15.5\njel;16.5\njel;22.9\njel;19.8\njel;26.5\njel;17.8\njel;28.3\njel;19.5\njel;22.6\njel;9.7\njel;18.1\njel;28.5\njel;10.0\njel;23.9\njel;26.1\njel;21.1\njel;28.2\njel;16.8\njel;13.3\njel;28.8\njel;21.5\njel;15.0\njel;24.8\njel;13.9\njel;10.5\njel;18.8\njel;23.3\njel;32.4\njel;11.4\njel;2.0\njel;30.2\njel;9.3\njel;13.8\njel;12.7\njel;15.2\njel;22.0\njel;16.7\njel;18.1\njel;18.1\njel;17.3\njel;10.4\njel;23.6\njel;12.3\njel;14.3\njel;15.6\njel;-0.6\njel;-1.7\njel;10.8\njel;7.9\njel;16.0\njel;15.2\njel;22.0\njel;29.4\njel;19.2\njel;10.0\njel;21.9\njel;27.4\njel;31.2\njel;22.7\njel;16.5\njel;26.0\njel;19.3\njel;28.2\njel;7.9\njel;21.9\njel;13.8\njel;17.1\njel;25.3\njel;7.8\njel;7.8\njel;19.4\njel;11.2\njel;21.6\njel;36.5\njel;12.7\njel;18.3\njel;23.0\njel;17.5\njel;26.1\njel;10.4\njel;13.4\njel;26.2\njel;24.0\njel;17.2\njel;16.3\njel;18.5\njel;12.1\njel;26.9\njel;7.8\njel;21.2\njel;18.0\njel;28.2\njel;16.2\njel;24.0\njel;21.5\njel;20.7\njel;14.4\njel;21.7\njel;5.5\njel;19.7\njel;21.8\njel;9.2\njel;24.2\njel;13.2\njel;14.0\njel;20.1\njel;6.8\njel;20.6\njel;0.3\njel;17.9\njel;34.8\njel;14.5\njel;33.3\njel;20.2\njel;21.9\njel;26.9\njel;21.2\njel;20.6\njel;21.9\njel;17.1\njel;31.7\njel;20.7\njel;20.3\njel;26.3\njel;30.6\njel;23.6\njel;0.8\njel;22.2\njel;22.5\njel;15.3\njel;14.3\njel;7.9\njel;11.4\njel;23.8\njel;13.7\njel;33.1\njel;35.5\njel;27.8\njel;14.4\njel;21.6\njel;17.3\njel;16.0\njel;22.7\njel;15.6\njel;26.8\njel;26.6\njel;24.5\njel;10.0\njel;16.5\njel;13.1\njel;14.6\njel;9.9\njel;18.5\njel;19.3\njel;13.8\njel;18.8\njel;23.1\njel;15.6\njel;18.8\njel;20.4\njel;-3.1\njel;7.7\njel;16.8\njel;26.3\njel;17.7\njel;21.7\njel;25.0\njel;21.6\njel;7.3\njel;9.0\njel;21.9\njel;16.0\njel;13.4\njel;19.9\njel;30.7\njel;20.3\njel;12.4\njel;17.4\njel;17.3\njel;26.2\njel;10.5\njel;21.0\njel;14.5\njel;38.1\njel;14.3\njel;24.5\njel;22.2\njel;20.1\njel;15.9\njel;11.8\njel;11.2\njel;36.8\njel;23.6\njel;14.8\njel;11.8\njel;19.7\njel;15.6\njel;28.3\njel;9.9\njel;10.7\njel;18.6\njel;15.6\njel;16.7\njel;5.2\njel;23.5\njel;13.5\njel;14.5\njel;15.7\njel;26.4\njel;13.5\njel;24.9\njel;7.1\njel;30.8\njel;5.0\njel;23.7\njel;21.2\njel;22.5\njel;15.7\njel;18.9\njel;6.5\njel;4.5\njel;16.9\njel;22.4\njel;22.2\njel;20.8\njel;16.0\njel;11.8\njel;23.1\njel;14.9\njel;24.8\njel;15.6\njel;19.1\njel;15.0\njel;14.2\njel;33.2\njel;18.8\njel;26.8\njel;26.9\njel;6.8\njel;18.4\njel;23.8\njel;19.6\njel;-0.6\njel;31.5\njel;29.4\njel;18.0\njel;9.8\njel;5.3\njel;17.8\njel;16.4\njel;32.9\njel;19.7\njel;27.6\njel;24.7\njel;19.9\njel;22.4\njel;12.8\njel;28.5\njel;34.2\njel;8.0\njel;13.3\njel;25.4\njel;16.6\njel;12.7\njel;18.4\njel;2.9\njel;18.6\njel;31.3\njel;10.7\njel;22.9\njel;16.7\njel;16.8\njel;27.5\njel;26.7\njel;16.7\njel;29.8\njel;12.1\njel;24.0\njel;18.1\njel;18.5\njel;15.7\njel;9.1\njel;7.1\njel;4.5\njel;7.4\njel;26.3\njel;5.5\njel;14.2\njel;16.0\njel;18.4\njel;26.3\njel;20.2\njel;21.2\njel;22.1\njel;13.8\njel;25.5\njel;13.4\njel;33.3\njel;23.6\njel;18.4\njel;23.6\njel;13.6\njel;21.9\njel;19.7\njel;12.0\njel;30.4\njel;31.2\njel;19.0\njel;31.0\njel;24.1\njel;7.7\njel;16.3\njel;11.3\njel;24.0\njel;22.3\njel;25.4\njel;19.6\njel;24.3\njel;11.1\njel;18.4\njel;20.4\njel;14.5\njel;18.9\njel;13.2\njel;9.3\njel;20.7\njel;14.1\njel;5.9\njel;27.7\njel;22.8\njel;17.0\njel;22.5\njel;8.1\njel;15.5\njel;20.5\njel;15.4\njel;21.5\njel;10.4\njel;17.2\njel;23.5\njel;18.9\njel;22.9\njel;18.8\njel;19.0\njel;21.1\njel;18.0\njel;12.6\njel;14.7\njel;26.4\njel;21.9\njel;18.2\njel;17.4\njel;20.1\njel;14.7\njel;20.4\njel;17.6\njel;16.8\njel;23.3\njel;23.5\njel;22.3\njel;9.1\njel;24.7\njel;5.6\njel;15.3\njel;16.3\njel;16.8\njel;26.0\njel;25.4\njel;18.9\njel;29.4\njel;11.8\njel;10.6\njel;32.6\njel;7.4\njel;14.8\njel;12.8\njel;8.0\njel;33.2\njel;6.6\njel;20.1\njel;0.1\njel;18.5\njel;31.9\njel;26.5\njel;11.8\njel;22.7\njel;11.1\njel;19.7\njel;26.3\njel;20.8\njel;18.0\njel;24.4\njel;16.4\njel;11.0\njel;1.9\njel;18.6\njel;27.4\njel;13.5\njel;17.6\njel;15.3\njel;22.7\njel;10.1\njel;16.3\njel;16.6\njel;24.8\njel;24.4\njel;20.3\njel;15.0\njel;26.0\njel;17.2\njel;22.5\njel;13.5\njel;12.0\njel;29.3\njel;16.7\njel;15.7\njel;16.9\njel;31.2\njel;14.7\njel;34.7\njel;18.8\njel;17.3\njel;9.5\njel;17.5\njel;7.4\njel;15.7\njel;5.1\njel;18.4\njel;8.1\njel;17.0\njel;7.9\njel;12.3\njel;28.2\njel;14.8\njel;13.3\njel;18.7\njel;14.9\njel;19.9\njel;16.4\njel;24.6\njel;8.1\njel;25.0\njel;16.0\njel;10.6\njel;22.4\njel;22.6\njel;24.2\njel;8.6\njel;11.9\njel;12.8\njel;16.4\njel;20.6\njel;19.7\njel;19.1\njel;6.3\njel;12.0\njel;6.0\njel;17.7\njel;19.5\njel;10.7\njel;24.8\njel;17.9\njel;14.9\njel;22.4\njel;-1.4\njel;25.3\njel;18.1\njel;25.9\njel;17.9\njel;18.1\njel;18.7\njel;13.3\njel;14.5\njel;12.1\njel;13.5\njel;15.6\njel;23.3\njel;22.8\njel;22.4\njel;7.3\njel;2.4\njel;23.7\njel;22.2\njel;22.4\njel;14.7\njel;16.0\njel;22.6\njel;21.8\njel;19.9\njel;22.8\njel;0.4\njel;14.0\njel;11.0\njel;9.4\njel;11.9\njel;6.3\njel;29.0\njel;20.3\njel;10.2\njel;15.6\njel;19.7\njel;27.2\njel;18.1\njel;15.4\njel;19.7\njel;27.3\njel;11.0\njel;19.9\njel;13.9\njel;26.7\njel;9.6\njel;10.3\njel;25.5\njel;23.3\njel;20.5\njel;21.4\njel;13.1\njel;20.4\njel;25.5\njel;20.2\njel;4.2\njel;21.5\njel;29.0\njel;14.6\njel;17.0\njel;32.7\njel;5.0\njel;25.4\njel;13.1\njel;19.3\njel;32.4\njel;22.5\njel;25.1\njel;25.5\njel;16.9\njel;13.2\njel;25.0\njel;21.2\njel;14.7\njel;17.3\njel;11.5\njel;20.0\njel;11.3\njel;18.0\njel;23.1\njel;20.5\njel;13.4\njel;20.3\njel;22.8\njel;21.7\njel;13.4\njel;19.4\njel;5.2\njel;8.5\njel;18.2\njel;15.7\njel;11.6\njel;1.2\njel;24.9\njel;18.8\njel;-1.2\njel;23.8\njel;14.6\njel;21.8\njel;21.8\njel;24.0\njel;12.2\njel;11.2\njel;23.7\njel;14.6\njel;15.1\njel;11.7\njel;24.9\njel;12.8\njel;25.0\njel;12.1\njel;23.1\njel;20.2\njel;11.6\njel;11.3\njel;20.1\njel;15.8\njel;13.9\njel;20.2\njel;9.5\njel;17.1\njel;17.1\njel;15.9\njel;17.5\njel;17.4\njel;8.7\njel;21.5\njel;7.2\njel;21.4\njel;15.5\njel;20.8\njel;7.7\njel;15.2\njel;17.5\njel;23.1\njel;24.9\njel;8.4\njel;23.4\njel;17.8\njel;21.6\njel;22.2\njel;12.9\njel;15.4\njel;39.4\njel;23.1\njel;8.8\njel;21.7\njel;16.4\njel;11.4\njel;14.6\njel;20.9\njel;11.5\njel;18.9\njel;16.3\njel;11.4\njel;19.8\njel;18.4\njel;4.4\njel;26.1\njel;22.0\njel;7.0\njel;18.7\njel;24.4\njel;-0.2\njel;22.0\njel;16.5\njel;11.0\njel;16.6\njel;3.9\njel;24.4\njel;12.2\njel;13.5\njel;9.8\njel;9.6\njel;12.6\njel;14.7\njel;16.5\njel;13.0\njel;14.1\njel;18.5\njel;20.5\njel;33.5\njel;19.0\njel;19.1\njel;16.1\njel;20.4\njel;16.9\njel;19.7\njel;-0.4\njel;15.6\njel;24.9\njel;29.9\njel;21.4\njel;13.5\njel;19.8\njel;17.0\njel;30.3\njel;28.7\njel;16.3\njel;21.1\njel;8.3\njel;12.7\njel;19.0\njel;33.1\njel;19.9\njel;18.9\njel;22.7\njel;1.4\njel;10.5\njel;17.4\njel;26.8\njel;22.4\njel;17.5\njel;21.5\njel;17.1\njel;20.8\njel;13.1\njel;7.0\njel;14.0\njel;24.4\njel;14.9\njel;11.0\njel;24.1\njel;11.5\njel;13.1\njel;14.0\njel;21.9\njel;27.0\njel;28.2\njel;27.0\njel;4.5\njel;20.3\njel;14.1\njel;18.5\njel;1.4\njel;10.6\njel;0.6\njel;29.6\njel;15.6\njel;7.5\njel;24.2\njel;35.0\njel;26.9\njel;13.4\njel;10.2\njel;12.0\njel;16.0\njel;21.9\njel;17.7\njel;8.1\njel;11.0\njel;11.5\njel;12.6\njel;13.3\njel;12.5\njel;15.7\njel;10.0\njel;8.0\njel;8.3\njel;30.9\njel;22.3\njel;37.6\njel;15.0\njel;6.4\njel;15.6\njel;14.6\njel;18.0\njel;21.7\njel;19.7\njel;23.8\njel;8.3\njel;18.2\njel;18.8\njel;15.2\njel;14.9\njel;24.0\njel;8.7\njel;16.1\njel;17.8\njel;19.1\njel;16.1\njel;27.0\njel;17.9\njel;7.5\njel;4.9\njel;10.3\njel;15.7\njel;16.1\njel;22.2\njel;14.6\njel;0.4\njel;10.8\njel;27.4\njel;23.8\njel;24.8\njel;15.8\njel;9.2\njel;13.1\njel;27.1\njel;20.1\njel;17.3\njel;17.0\njel;11.4\njel;20.3\njel;8.1\njel;31.4\njel;17.5\njel;16.1\njel;8.6\njel;16.2\njel;19.8\njel;21.8\njel;17.7\njel;14.4\njel;20.3\njel;9.2\njel;25.3\njel;31.1\njel;24.0\njel;8.3\njel;17.3\njel;24.4\njel;17.2\njel;18.4\njel;20.1\njel;6.8\njel;19.8\njel;17.1\njel;11.3\njel;18.1\njel;25.4\njel;26.6\njel;18.2\njel;21.2\njel;10.4\njel;23.4\njel;22.9\njel;11.6\njel;8.4\njel;2.0\njel;14.0\njel;28.2\njel;22.2\njel;19.7\njel;33.6\njel;14.7\njel;6.7\njel;24.3\njel;13.7\njel;13.2\njel;2.4\njel;3.9\njel;17.6\njel;27.7\njel;16.1\njel;1.0\njel;18.3\njel;11.6\njel;16.7\njel;13.3\njel;38.4\njel;17.9\njel;18.8\njel;8.4\njel;16.2\njel;12.0\njel;16.8\njel;31.2\njel;18.9\njel;27.7\njel;11.0\njel;13.8\njel;36.6\njel;2.0\njel;20.2\njel;21.2\njel;6.9\njel;12.6\njel;11.1\njel;15.6\njel;5.6\njel;22.5\njel;16.9\njel;20.1\njel;25.8\njel;18.0\njel;10.5\njel;17.7\njel;17.0\njel;14.5\njel;9.4\njel;6.1\njel;20.6\njel;12.6\njel;18.0\njel;10.4\njel;17.6\njel;21.8\njel;9.6\njel;18.9\njel;15.0\njel;26.8\njel;23.8\njel;21.6\njel;16.4\njel;13.6\njel;17.2\njel;17.9\njel;21.2\njel;30.1\njel;20.5\njel;16.9\njel;21.1\njel;7.7\njel;28.6\njel;35.5\njel;22.8\njel;4.1\njel;17.3\njel;20.1\njel;18.5\njel;19.5\njel;13.7\njel;18.7\njel;10.1\njel;23.9\njel;27.5\njel;19.7\njel;21.3\njel;24.0\njel;27.6\njel;13.9\njel;24.8\njel;12.3\njel;19.3\njel;17.3\njel;25.3\njel;14.1\njel;8.2\njel;22.2\njel;20.6\njel;21.9\njel;21.1\njel;0.2\njel;10.5\njel;11.3\njel;18.2\njel;12.9\njel;23.9\njel;14.2\njel;16.1\njel;0.2\njel;15.0\njel;6.1\njel;11.1\njel;17.6\njel;12.3\njel;9.0\njel;14.8\njel;25.8\njel;22.2\njel;20.9\njel;17.2\njel;17.9\njel;1.5\njel;7.1\njel;12.4\njel;25.1\njel;22.7\njel;27.7\njel;8.5\njel;26.8\njel;25.0\njel;15.3\njel;20.2\njel;16.6\njel;16.9\njel;21.7\njel;27.2\njel;19.4\njel;16.0\njel;33.8\njel;30.8\njel;29.8\njel;25.4\njel;22.4\njel;16.2\njel;26.4\njel;15.5\njel;1.3\njel;18.1\njel;16.5\njel;20.1\njel;10.1\njel;9.2\njel;23.9\njel;15.3\njel;18.4\njel;12.9\njel;-1.9\njel;11.2\njel;13.6\njel;24.0\njel;14.5\njel;22.0\njel;11.6\njel;8.4\njel;31.6\njel;21.0\njel;23.3\njel;16.9\njel;21.0\njel;15.4\njel;23.0\njel;17.0\njel;22.0\njel;6.4\njel;22.9\njel;5.2\njel;15.5\njel;17.0\njel;12.4\njel;11.7\njel;16.3\njel;14.5\njel;23.6\njel;26.2\njel;22.7\njel;20.3\njel;11.7\njel;20.2\njel;16.1\njel;24.9\njel;21.3\njel;19.7\njel;24.2\njel;16.3\njel;9.7\njel;24.0\njel;4.6\njel;18.9\njel;22.4\njel;14.6\njel;8.2\njel;17.3\njel;19.5\njel;20.1\njel;14.2\njel;17.4\njel;26.6\njel;24.6\njel;17.6\njel;13.1\njel;8.4\njel;8.8\njel;15.8\njel;14.1\njel;16.9\njel;10.5\njel;16.2\njel;30.0\njel;18.2\njel;22.1\njel;5.2\njel;12.9\njel;9.6\njel;14.7\njel;14.7\njel;25.9\njel;22.1\njel;22.0\njel;17.0\njel;9.0\njel;16.8\njel;9.1\njel;16.4\njel;25.2\njel;17.3\njel;18.5\njel;15.3\njel;18.2\njel;20.0\njel;29.7\njel;13.2\njel;9.0\njel;23.1\njel;9.9\njel;17.7\njel;24.6\njel;19.2\njel;22.2\njel;19.9\njel;21.8\njel;21.2\njel;12.5\njel;20.6\njel;17.2\njel;23.3\njel;8.9\njel;15.6\njel;20.3\njel;21.3\njel;20.4\njel;30.7\njel;27.0\njel;24.1\njel;11.1\njel;20.7\njel;20.1\njel;10.6\njel;22.7\njel;6.7\njel;13.5\njel;19.5\njel;17.9\njel;15.0\njel;11.1\njel;2.9\njel;21.6\njel;13.4\njel;24.0\njel;16.1\njel;16.9\njel;13.4\njel;15.2\njel;9.8\njel;34.3\njel;27.4\njel;8.7\njel;24.3\njel;17.9\njel;16.9\njel;14.0\njel;14.8\njel;21.9\njel;15.8\njel;19.1\njel;25.2\njel;10.5\njel;14.7\njel;9.5\njel;35.3\njel;10.8\njel;26.5\njel;25.7\njel;22.9\njel;-0.6\njel;9.7\njel;16.8\njel;6.3\njel;11.6\njel;20.5\njel;11.5\njel;13.3\njel;25.7\njel;20.2\njel;16.9\njel;23.3\njel;13.2\njel;4.2\njel;23.5\njel;8.4\njel;21.4\njel;15.3\njel;18.1\njel;11.0\njel;17.9\njel;30.9\njel;23.7\njel;16.5\njel;18.6\njel;15.6\njel;21.4\njel;27.9\njel;2.4\njel;16.7\njel;20.4\njel;18.1\njel;11.5\njel;20.0\njel;15.8\njel;10.0\njel;6.7\njel;20.9\njel;13.0\njel;20.2\njel;20.3\njel;23.0\njel;31.3\njel;14.8\njel;18.2\njel;10.6\njel;19.9\njel;20.1\njel;25.0\njel;18.3\njel;23.8\njel;24.7\njel;22.8\njel;11.1\njel;10.0\njel;23.6\njel;27.0\njel;17.3\njel;14.0\njel;7.8\njel;18.8\njel;24.8\njel;9.3\njel;10.2\njel;22.7\njel;12.8\njel;18.4\njel;25.8\njel;34.0\njel;14.5\njel;13.3\njel;14.2\njel;15.7\njel;19.0\njel;15.1\njel;24.2\njel;21.9\njel;12.7\njel;11.3\njel;20.3\njel;14.6\njel;17.3\njel;20.6\njel;16.8\njel;19.1\njel;16.5\njel;27.5\njel;12.3\njel;13.0\njel;14.5\njel;20.6\njel;11.6\njel;11.5\njel;12.8\njel;16.9\njel;25.8\njel;16.5\njel;24.7\njel;12.5\njel;25.4\njel;3.9\njel;24.0\njel;24.6\njel;26.9\njel;10.4\njel;7.9\njel;22.7\njel;17.3\njel;18.4\njel;6.3\njel;26.0\njel;28.2\njel;15.7\njel;15.9\njel;23.3\njel;14.9\njel;19.6\njel;11.7\njel;10.7\njel;20.2\njel;7.3\njel;18.5\njel;19.6\njel;10.0\njel;20.1\njel;26.1\njel;17.0\njel;30.4\njel;21.2\njel;19.4\njel;20.5\njel;29.2\njel;24.5\njel;11.2\njel;16.6\njel;18.2\njel;24.3\njel;22.2\njel;11.7\njel;20.4\njel;14.8\njel;19.2\njel;18.5\njel;19.2\njel;22.8\njel;13.0\njel;10.1\njel;20.4\njel;29.1\njel;15.5\njel;29.6\njel;14.0\njel;21.6\njel;14.2\njel;19.8\njel;28.6\njel;26.2\njel;19.5\njel;9.9\njel;20.8\njel;19.5\njel;16.9\njel;11.5\njel;17.7\njel;10.6\njel;10.7\njel;14.9\njel;26.2\njel;15.5\njel;9.5\njel;9.8\njel;18.1\njel;5.4\njel;14.2\njel;17.1\njel;27.8\njel;25.5\njel;25.0\njel;15.0\njel;15.9\njel;22.7\njel;16.3\njel;20.0\njel;4.2\njel;19.9\njel;22.1\njel;19.7\njel;17.1\njel;14.6\njel;27.2\njel;13.7\njel;16.9\njel;25.6\njel;16.1\njel;9.1\njel;10.1\njel;16.6\njel;29.6\njel;21.6\njel;16.9\njel;22.3\njel;13.3\njel;21.3\njel;25.1\njel;21.5\njel;14.4\njel;10.1\njel;5.4\njel;10.7\njel;22.7\njel;11.7\njel;9.5\njel;27.1\njel;19.3\njel;15.3\njel;13.4\njel;26.4\njel;7.7\njel;23.1\njel;19.4\njel;25.7\njel;30.1\njel;21.3\njel;14.5\njel;11.9\njel;20.8\njel;17.7\njel;17.0\njel;15.1\njel;21.8\njel;17.2\njel;21.1\njel;20.6\njel;17.4\njel;19.9\njel;14.4\njel;2.8\njel;17.1\njel;10.1\njel;14.4\njel;21.9\njel;14.5\njel;18.8\njel;21.4\njel;20.5\njel;19.3\njel;16.9\njel;18.6\njel;24.0\njel;17.7\njel;6.6\njel;13.7\njel;11.0\njel;8.1\njel;18.9\njel;17.1\njel;17.9\njel;12.0\njel;17.9\njel;11.3\njel;18.3\njel;17.7\njel;23.9\njel;37.8\njel;15.4\njel;18.8\njel;19.2\njel;24.9\njel;26.8\njel;15.4\njel;16.0\njel;21.5\njel;20.4\njel;22.1\njel;20.3\njel;28.8\njel;0.0\njel;14.4\njel;17.0\njel;18.3\njel;12.9\njel;6.1\njel;12.5\njel;15.5\njel;15.5\njel;-0.3\njel;21.8\njel;2.5\njel;8.1\njel;16.0\njel;13.0\njel;20.4\njel;19.2\njel;23.7\njel;10.6\njel;18.7\njel;8.9\njel;20.4\njel;9.0\njel;15.8\njel;15.5\njel;19.1\njel;6.7\njel;14.9\njel;12.9\njel;23.2\njel;13.5\njel;27.0\njel;20.6\njel;29.9\njel;14.7\njel;26.1\njel;17.7\njel;27.6\njel;22.0\njel;8.0\njel;13.3\njel;33.2\njel;22.1\njel;20.9\njel;20.5\njel;20.5\njel;16.2\njel;19.0\njel;22.0\njel;28.2\njel;22.3\njel;23.0\njel;19.1\njel;13.2\njel;22.2\njel;23.8\n"
  },
  {
    "path": "src/test/resources/samples/measurements-short.out",
    "content": "{a=1.0/1.0/1.0, b=1.0/1.5/2.0}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-short.txt",
    "content": "a;1.0\nb;1.0\nb;2.0\n"
  },
  {
    "path": "src/test/resources/samples/measurements-shortest.out",
    "content": "{a=1.0/1.0/1.0}\n"
  },
  {
    "path": "src/test/resources/samples/measurements-shortest.txt",
    "content": "a;1.0\n"
  },
  {
    "path": "test.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -euo pipefail\n\nDEFAULT_INPUT=\"src/test/resources/samples/*.txt\"\nFORK=${1:-\"\"}\nINPUT=${2:-$DEFAULT_INPUT}\n\nif [ \"$#\" -eq 0 ] || [ \"$#\" -gt 2 ] || [ \"$FORK\" = \"-h\" ]; then\n  echo \"Usage: ./test.sh <fork name> [input file pattern]\"\n  echo\n  echo \"For each test sample matching <input file pattern> (default '$DEFAULT_INPUT')\"\n  echo \"runs <fork name> implementation and diffs the result with the expected output.\"\n  echo \"Note that optional <input file pattern> should be quoted if contains wild cards.\"\n  echo\n  echo \"Examples:\"\n  echo \"./test.sh baseline\"\n  echo \"./test.sh baseline src/test/resources/samples/measurements-1.txt\"\n  echo \"./test.sh baseline 'src/test/resources/samples/measurements-*.txt'\"\n  exit 1\nfi\n\nif [ -f \"./prepare_$FORK.sh\" ]; then\n  \"./prepare_$FORK.sh\"\nfi\n\nfor sample in $(ls $INPUT); do\n  echo \"Validating calculate_average_$FORK.sh -- $sample\"\n\n  rm -f measurements.txt\n  ln -s $sample measurements.txt\n\n  diff --color=always <(\"./calculate_average_$FORK.sh\" | ./tocsv.sh) <(./tocsv.sh < ${sample%.txt}.out)\ndone\n\nrm measurements.txt\n"
  },
  {
    "path": "test_all.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -euo pipefail\n\nINPUT=${1:-\"\"}\n\nif [ \"$INPUT\" = \"-h\" ] || [ \"$#\" -gt 1 ]; then\n  echo \"Usage: ./test_all.sh [input file pattern]\"\n  echo\n  echo \"For each available fork run ./test.sh <fork name> [input file pattern].\"\n  echo \"Note that optional <input file pattern> should be quoted if contains wild cards.\"\n  echo\n  echo \"Examples:\"\n  echo \"./test_all.sh\"\n  echo \"./test_all.sh 2>/dev/null\"\n  echo \"./test_all.sh src/test/resources/samples/measurements-1.txt\"\n  echo \"./test_all.sh 'src/test/resources/samples/measurements-*.txt'\"\n  exit 1\nfi\n\nif [ -t 1 ]; then\n  GREEN='\\033[0;32m'\n  RED='\\033[0;31m'\n  RESET='\\033[0m'\nelse\n  GREEN=\"\"\n  RED=\"\"\n  RESET=\"\"\nfi\n\nWITH_TIMEOUT=\"\"\nif [ -x \"$(command -v timeout)\" ]; then\n  WITH_TIMEOUT=\"timeout -s KILL 5s\"\nelif [ -x \"$(command -v gtimeout)\" ]; then # MacOS from `brew install coreutils`\n  WITH_TIMEOUT=\"gtimeout -s KILL 5s\"\nelse\n  echo \"$0: timeout command not available, tests may run indefinitely long.\" 1>&2\nfi\n\nfor impl in $(ls calculate_average_*.sh | sort); do\n  noext=\"${impl%%.sh}\"\n  fork=${noext##calculate_average_}\n\n  # ./test.sh calls ./prepare_$fork.sh e.g. to build native image\n  # which may take some time.\n  # Here we run it upfront, assuming that prepare result is cached\n  # to avoid timeout due to long preparation.\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    if ! output=$(\"./prepare_$fork.sh\" 2>&1); then\n      echo \"$output\" 1>&2\n      echo \"FAIL $fork\"\n      continue\n    fi\n  fi\n\n  if output=$($WITH_TIMEOUT ./test.sh \"$fork\" \"$INPUT\" 2>&1); then\n    echo -e \"${GREEN}PASS${RESET} $fork\"\n  elif [ $? -eq 137 ]; then\n    echo -e \"${RED}TIME${RESET} $fork\"\n  else\n    echo \"$output\" 1>&2\n    echo -e \"${RED}FAIL${RESET} $fork\"\n  fi\ndone\n"
  },
  {
    "path": "test_ci.sh",
    "content": "#!/bin/bash\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nset -eo pipefail\n\nif [ -z \"$1\" ]\n  then\n    echo \"Usage: test_ci.sh <fork name> (<fork name 2> ...)\"\n    echo \" for each fork, there must be a 'calculate_average_<fork name>.sh' script and an optional 'prepare_<fork name>.sh'.\"\n    exit 1\nfi\n\nBOLD_WHITE='\\033[1;37m'\nCYAN='\\033[0;36m'\nGREEN='\\033[0;32m'\nPURPLE='\\033[0;35m'\nBOLD_RED='\\033[1;31m'\nRED='\\033[0;31m'\nBOLD_YELLOW='\\033[1;33m'\nRESET='\\033[0m' # No Color\n\nMEASUREMENTS_FILE=\"measurements_10M.txt\"\nRUNS=5\nDEFAULT_JAVA_VERSION=\"21.0.1-open\"\nRUN_TIME_LIMIT=300 # seconds\n\nTIMEOUT=\"\"\nif [ \"$(uname -s)\" == \"Linux\" ]; then\n  TIMEOUT=\"timeout -v $RUN_TIME_LIMIT\"\nelse # MacOs\n  if [ -x \"$(command -v gtimeout)\" ]; then\n    TIMEOUT=\"gtimeout -v $RUN_TIME_LIMIT\" # from `brew install coreutils`\n  else\n    echo -e \"${BOLD_YELLOW}WARNING${RESET} gtimeout not available, benchmark runs may take indefinitely long.\"\n  fi\nfi\n\nfunction check_command_installed {\n  if ! [ -x \"$(command -v $1)\" ]; then\n    echo \"Error: $1 is not installed.\" >&2\n    exit 1\n  fi\n}\n\nfunction print_and_execute() {\n  echo \"+ $@\" >&2\n  \"$@\"\n}\n\ncheck_command_installed java\n\n# Validate that ./calculate_average_<fork>.sh exists for each fork\nfor fork in \"$@\"; do\n  if [ ! -f \"./calculate_average_$fork.sh\" ]; then\n    echo -e \"${BOLD_RED}ERROR${RESET}: ./calculate_average_$fork.sh does not exist.\" >&2\n    exit 1\n  fi\ndone\n\n## SDKMAN Setup\n# 1. Custom check for sdkman installed; not sure why check_command_installed doesn't detect it properly\nif [ ! -f \"$HOME/.sdkman/bin/sdkman-init.sh\" ]; then\n     echo -e \"${BOLD_RED}ERROR${RESET}: sdkman is not installed.\" >&2\n    exit 1\nfi\n\n# 2. Init sdkman in this script\nsource \"$HOME/.sdkman/bin/sdkman-init.sh\"\n\n# 3. make sure the default java version is installed\nif [ ! -d \"$HOME/.sdkman/candidates/java/$DEFAULT_JAVA_VERSION\" ]; then\n  print_and_execute sdk install java $DEFAULT_JAVA_VERSION\nfi\n\n# 4. Install missing SDK java versions in any of the prepare_*.sh scripts for the provided forks\nfor fork in \"$@\"; do\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    grep -h \"^sdk use\" \"./prepare_$fork.sh\" | cut -d' ' -f4 | while read -r version; do\n      if [ ! -d \"$HOME/.sdkman/candidates/java/$version\" ]; then\n        print_and_execute sdk install java $version\n      fi\n    done || true # grep returns exit code 1 when no match, `|| true` prevents the script from exiting early\n  fi\ndone\n## END - SDKMAN Setup\n\n# Run tests and benchmark for each fork\nfiletimestamp=$(date  +\"%Y%m%d%H%M%S\") # same for all fork.out files from this run\nfailed=()\nfor fork in \"$@\"; do\n  set +e # we don't want prepare.sh, test.sh or hyperfine failing on 1 fork to exit the script early\n\n  # Run prepare script\n  if [ -f \"./prepare_$fork.sh\" ]; then\n    print_and_execute source \"./prepare_$fork.sh\"\n  else\n    print_and_execute sdk use java $DEFAULT_JAVA_VERSION\n  fi\n\n  # Run the test suite\n  print_and_execute $TIMEOUT ./test.sh $fork\n  if [ $? -ne 0 ]; then\n    failed+=(\"$fork\")\n    echo \"\"\n    echo -e \"${BOLD_RED}FAILURE${RESET}: ./test.sh $fork failed\"\n\n    exit 1\n  fi\n  echo \"\"\ndone\n"
  },
  {
    "path": "tocsv.sh",
    "content": "#!/bin/sh\n#\n#  Copyright 2023 The original authors\n#\n#  Licensed under the Apache License, Version 2.0 (the \"License\");\n#  you may not use this file except in compliance with the License.\n#  You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n#  Unless required by applicable law or agreed to in writing, software\n#  distributed under the License is distributed on an \"AS IS\" BASIS,\n#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n#  See the License for the specific language governing permissions and\n#  limitations under the License.\n#\n\nexec sed '\n#\n# Transform calculate_average*.sh output into semicolon-separated values, one per line.\n#\n\n# 1. remove \"{\" and \"}\"\ns/[{}]//g;\n\n# 2. replace \"=\" and \"/\" with semicolon\ns/[=/]/;/g;\n\n# 3. id may contain comma, e.g. \"Washington, D.C.;-15.1;14.8;44.8, Wau;-2.1;27.4;53.4\"\n# so replace \", \" with a newline only if it is preceded by a digit\ns/\\([0-9]\\), /\\1\\n/g\n'\n"
  }
]