├── .editorconfig ├── .github ├── renovate.json5 └── workflows │ ├── .java-version │ └── build.yaml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── RELEASING.md ├── build.gradle ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── kotlin-js-store └── yarn.lock ├── settings.gradle └── src ├── commonMain └── kotlin │ └── com │ └── jakewharton │ └── crossword │ ├── canvas.kt │ └── text.kt └── commonTest └── kotlin └── com └── jakewharton └── crossword ├── TextCanvasTest.kt └── TextTest.kt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{kt,kts}] 2 | indent_size=2 3 | insert_final_newline=true 4 | -------------------------------------------------------------------------------- /.github/renovate.json5: -------------------------------------------------------------------------------- 1 | { 2 | $schema: 'https://docs.renovatebot.com/renovate-schema.json', 3 | extends: [ 4 | 'config:recommended', 5 | ], 6 | ignorePresets: [ 7 | // Ensure we get the latest version and are not pinned to old versions. 8 | 'workarounds:javaLTSVersions', 9 | ], 10 | customManagers: [ 11 | // Update .java-version file with the latest JDK version. 12 | { 13 | customType: 'regex', 14 | fileMatch: [ 15 | '\\.java-version$', 16 | ], 17 | matchStrings: [ 18 | '(?.*)\\n', 19 | ], 20 | datasourceTemplate: 'java-version', 21 | depNameTemplate: 'java', 22 | // Only write the major version. 23 | extractVersionTemplate: '^(?\\d+)', 24 | }, 25 | ], 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/.java-version: -------------------------------------------------------------------------------- 1 | 24 2 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | pull_request: {} 5 | workflow_dispatch: {} 6 | push: 7 | branches: 8 | - 'trunk' 9 | tags: 10 | - '**' 11 | 12 | jobs: 13 | build: 14 | runs-on: macos-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | - uses: actions/setup-java@v4 19 | with: 20 | distribution: 'zulu' 21 | java-version-file: .github/workflows/.java-version 22 | 23 | - uses: gradle/actions/wrapper-validation@v4 24 | - run: ./gradlew build 25 | 26 | - name: Extract release notes 27 | id: release_notes 28 | if: startsWith(github.ref, 'refs/tags/') 29 | uses: ffurrer2/extract-release-notes@v2 30 | 31 | - name: Create Release 32 | if: startsWith(github.ref, 'refs/tags/') 33 | uses: softprops/action-gh-release@v2 34 | with: 35 | body: ${{ steps.release_notes.outputs.release_notes }} 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | 39 | - name: Publish Artifacts 40 | run: ./gradlew publish 41 | if: github.ref == 'refs/heads/trunk' 42 | env: 43 | ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.SONATYPE_CENTRAL_USERNAME }} 44 | ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.SONATYPE_CENTRAL_PASSWORD }} 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IntelliJ IDEA 2 | /.idea 3 | *.iml 4 | 5 | # Gradle 6 | /.gradle 7 | build 8 | /reports 9 | 10 | # Kotlin 11 | .kotlin 12 | 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [Unreleased] 4 | [Unreleased]: https://github.com/JakeWharton/crossword/compare/0.4.0...HEAD 5 | 6 | ### Changed 7 | 8 | - In-development snapshots are now published to the Central Portal Snapshots repository at https://central.sonatype.com/repository/maven-snapshots/. 9 | 10 | 11 | ## [0.4.0] - 2024-12-16 12 | [0.4.0]: https://github.com/JakeWharton/crossword/releases/tag/0.4.0 13 | 14 | ### Added 15 | 16 | * New Kotlin targets: 17 | * `wasmJs` 18 | * `wasmWasi` 19 | 20 | ### Removed 21 | 22 | * Legacy `wasm` target has been removed. 23 | 24 | 25 | ## [0.3.0] - 2023-08-31 26 | [0.3.0]: https://github.com/JakeWharton/crossword/releases/tag/0.3.0 27 | 28 | ### Added 29 | 30 | * New Kotlin targets: 31 | * `androidNativeArm32` 32 | * `androidNativeArm64` 33 | * `androidNativeX86` 34 | * `androidNativeX64` 35 | * `linuxArm64` 36 | * `wasm` 37 | * `watchosDeviceArm64` 38 | 39 | ### Changed 40 | 41 | * Publish using a newer version of Kotlin to produce non-legacy artifacts. 42 | 43 | ### Removed 44 | 45 | * Deprecated `CharSequence.visualCodePointCount` extension removed. Use `CharSequence.visualWidth`. 46 | 47 | 48 | ## [0.2.0] - 2022-02-25 49 | [0.2.0]: https://github.com/JakeWharton/crossword/releases/tag/0.2.0 50 | 51 | ### Added 52 | 53 | * Library is now fully multiplatform supporting JS and native targets in addition to JVM/Android. 54 | 55 | ### Fixed 56 | 57 | * Properly measure combining diacritics as part of the previous glyph. 58 | * `visualCodePointCount` renamed to `visualWidth` since it does not simply count code points. 59 | 60 | 61 | 62 | ## [0.1.2] - 2020-10-10 63 | [0.1.2]: https://github.com/JakeWharton/crossword/releases/tag/0.1.2 64 | 65 | ### Fixed 66 | 67 | * Support a zero-sized `TextCanvas`. 68 | 69 | 70 | ## [0.1.1] - 2020-09-19 71 | [0.1.1]: https://github.com/JakeWharton/crossword/releases/tag/0.1.1 72 | 73 | ### Fixed 74 | 75 | * Set Java compatibility to 8. The bytecode targeted 8, but the Gradle module descriptor erroneously 76 | declared 15 (the deployment JDK) which prevented import into libraries with a lower JDK. 77 | 78 | 79 | ## [0.1.0] - 2020-09-18 80 | [0.1.0]: https://github.com/JakeWharton/crossword/releases/tag/0.1.0 81 | 82 | Initial release 83 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crossword 2 | 3 | A 2D canvas for rendering text, usually for console applications. 4 | 5 | ```kotlin 6 | val canvas = TextCanvas(40, 8) 7 | canvas.write(1, 20, "Such canvas") 8 | canvas.write(6, 30, "Very 2D") 9 | canvas.write(4, 7, "Much monospace") 10 | println(canvas) 11 | ``` 12 | ``` 13 | 14 | Such canvas 15 | 16 | 17 | Much monospace 18 | 19 | Very 2D 20 | 21 | ``` 22 | 23 | Not very impressive. However, `TextCanvas` automatically handles multi-`char` codepoints and ANSI 24 | control sequences. 25 | 26 | For example, rendering a red `X` at (0,0) and a blue `O` at (0, 2) means writing 10 characters each: 27 | ```kotlin 28 | canvas.write(0, 0, "\u001B[31mX\u001B[0m") 29 | canvas.write(0, 2, "\u001B[34mO\u001B[0m") 30 | ``` 31 | ``` 32 | X O 33 | Such canvas 34 | 35 | 36 | Much monospace 37 | 38 | Very 2D 39 | 40 | ``` 41 | 42 | _(Note: GitHub/markdown do not allow coloring text so use your imagination)_ 43 | 44 | If `TextCanvas` was a naive 2D `char[]` the `O` would have overwritten almost all of the `X`'s ANSI 45 | escape sequence. 46 | 47 | 48 | ## Download 49 | 50 | ```groovy 51 | repositories { 52 | mavenCentral() 53 | } 54 | dependencies { 55 | implementation 'com.jakewharton.crossword:crossword:0.4.0' 56 | } 57 | ``` 58 | 59 |
60 | Snapshots of the development version are available in the Central Portal Snapshots repository. 61 |

62 | 63 | ```groovy 64 | repositories { 65 | maven { 66 | url 'https://central.sonatype.com/repository/maven-snapshots/' 67 | } 68 | } 69 | dependencies { 70 | implementation 'com.jakewharton.crossword:crossword:0.5.0-SNAPSHOT' 71 | } 72 | ``` 73 | 74 |

75 |
76 | 77 | 78 | # License 79 | 80 | Copyright 2020 Jake Wharton 81 | 82 | Licensed under the Apache License, Version 2.0 (the "License"); 83 | you may not use this file except in compliance with the License. 84 | You may obtain a copy of the License at 85 | 86 | http://www.apache.org/licenses/LICENSE-2.0 87 | 88 | Unless required by applicable law or agreed to in writing, software 89 | distributed under the License is distributed on an "AS IS" BASIS, 90 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 91 | See the License for the specific language governing permissions and 92 | limitations under the License. 93 | -------------------------------------------------------------------------------- /RELEASING.md: -------------------------------------------------------------------------------- 1 | # Releasing 2 | 3 | 1. Update the `VERSION_NAME` in `gradle.properties` to the release version. 4 | 5 | 2. Update the `CHANGELOG.md`: 6 | 1. Change the `Unreleased` header to the release version. 7 | 2. Add a link URL to ensure the header link works. 8 | 3. Add a new `Unreleased` section to the top. 9 | 10 | 3. Update the `README.md` so the "Download" section reflects the new release version and the 11 | snapshot section reflects the next "SNAPSHOT" version. 12 | 13 | 4. Commit 14 | 15 | ``` 16 | $ git commit -am "Prepare version X.Y.X" 17 | ``` 18 | 19 | 5. Publish 20 | 21 | ``` 22 | $ ./gradlew clean publish 23 | ``` 24 | 25 | If this step fails, drop the Sonatype repo, fix, commit, and publish again. 26 | 27 | 6. Tag 28 | 29 | ``` 30 | $ git tag -am "Version X.Y.Z" X.Y.Z 31 | ``` 32 | 33 | 7. Update the `VERSION_NAME` in `gradle.properties` to the next "SNAPSHOT" version. 34 | 35 | 8. Commit 36 | 37 | ``` 38 | $ git commit -am "Prepare next development version" 39 | ``` 40 | 41 | 9. Push! 42 | 43 | ``` 44 | $ git push && git push --tags 45 | ``` 46 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 2 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 3 | 4 | buildscript { 5 | dependencies { 6 | classpath libs.kotlinPlugin 7 | classpath libs.spotlessPlugin 8 | classpath libs.dokkaPlugin 9 | classpath libs.animalSnifferPlugin 10 | classpath libs.publishPlugin 11 | } 12 | 13 | repositories { 14 | mavenCentral() 15 | gradlePluginPortal() 16 | } 17 | } 18 | 19 | apply plugin: 'org.jetbrains.kotlin.multiplatform' 20 | apply plugin: 'com.vanniktech.maven.publish' 21 | 22 | kotlin { 23 | androidNativeArm32() 24 | androidNativeArm64() 25 | androidNativeX86() 26 | androidNativeX64() 27 | iosArm64() 28 | iosX64() 29 | iosSimulatorArm64() 30 | js().nodejs() 31 | jvm() 32 | linuxArm64() 33 | linuxX64() 34 | macosX64() 35 | macosArm64() 36 | mingwX64() 37 | tvosArm64() 38 | tvosX64() 39 | tvosSimulatorArm64() 40 | wasmJs().nodejs() 41 | wasmWasi().nodejs() 42 | watchosArm32() 43 | watchosArm64() 44 | watchosDeviceArm64() 45 | watchosX64() 46 | watchosSimulatorArm64() 47 | 48 | sourceSets { 49 | commonTest { 50 | dependencies { 51 | implementation 'org.jetbrains.kotlin:kotlin-test' 52 | } 53 | } 54 | } 55 | } 56 | 57 | repositories { 58 | mavenCentral() 59 | } 60 | 61 | apply plugin: 'com.diffplug.spotless' 62 | spotless { 63 | kotlin { 64 | ktlint().editorConfigOverride([ 65 | 'ktlint_standard_filename': 'disabled', 66 | ]) 67 | } 68 | } 69 | 70 | tasks.withType(KotlinCompile).configureEach { 71 | compilerOptions { 72 | jvmTarget = JvmTarget.JVM_1_8 73 | freeCompilerArgs.addAll([ 74 | '-progressive', 75 | '-Xjvm-default=all', 76 | ]) 77 | } 78 | } 79 | 80 | tasks.withType(JavaCompile).configureEach { 81 | sourceCompatibility = JavaVersion.VERSION_1_8.toString() 82 | targetCompatibility = JavaVersion.VERSION_1_8.toString() 83 | } 84 | 85 | apply plugin: 'ru.vyarus.animalsniffer' 86 | 87 | dependencies { 88 | signature 'org.codehaus.mojo.signature:java18:1.0@signature' 89 | signature 'net.sf.androidscents.signature:android-api-level-21:5.0.1_r2@signature' 90 | } 91 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | GROUP=com.jakewharton.crossword 2 | VERSION_NAME=0.5.0-SNAPSHOT 3 | 4 | POM_ARTIFACT_ID=crossword 5 | POM_NAME=Crossword 6 | POM_DESCRIPTION=A 2D canvas for rendering text 7 | 8 | POM_URL=https://github.com/JakeWharton/crossword/ 9 | POM_SCM_URL=https://github.com/JakeWharton/crossword/ 10 | POM_SCM_CONNECTION=scm:git:git://github.com/JakeWharton/crossword.git 11 | POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/JakeWharton/crossword.git 12 | 13 | POM_LICENCE_NAME=The Apache Software License, Version 2.0 14 | POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt 15 | POM_LICENCE_DIST=repo 16 | 17 | POM_DEVELOPER_ID=jakewharton 18 | POM_DEVELOPER_NAME=Jake Wharton 19 | 20 | kotlin.mpp.stability.nowarn=true 21 | 22 | SONATYPE_HOST=CENTRAL_PORTAL 23 | SONATYPE_AUTOMATIC_RELEASE=true 24 | RELEASE_SIGNING_ENABLED=true 25 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [libraries] 2 | kotlinPlugin = "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.21" 3 | spotlessPlugin = 'com.diffplug.spotless:spotless-plugin-gradle:7.0.4' 4 | dokkaPlugin = "org.jetbrains.dokka:dokka-gradle-plugin:2.0.0" 5 | animalSnifferPlugin = "ru.vyarus:gradle-animalsniffer-plugin:2.0.1" 6 | publishPlugin = "com.vanniktech:gradle-maven-publish-plugin:0.32.0" 7 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeWharton/crossword/3b064a8b45dba153cc1f1d3752820302cba6ffa0/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # SPDX-License-Identifier: Apache-2.0 19 | # 20 | 21 | ############################################################################## 22 | # 23 | # Gradle start up script for POSIX generated by Gradle. 24 | # 25 | # Important for running: 26 | # 27 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 28 | # noncompliant, but you have some other compliant shell such as ksh or 29 | # bash, then to run this script, type that shell name before the whole 30 | # command line, like: 31 | # 32 | # ksh Gradle 33 | # 34 | # Busybox and similar reduced shells will NOT work, because this script 35 | # requires all of these POSIX shell features: 36 | # * functions; 37 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 38 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 39 | # * compound commands having a testable exit status, especially «case»; 40 | # * various built-in commands including «command», «set», and «ulimit». 41 | # 42 | # Important for patching: 43 | # 44 | # (2) This script targets any POSIX shell, so it avoids extensions provided 45 | # by Bash, Ksh, etc; in particular arrays are avoided. 46 | # 47 | # The "traditional" practice of packing multiple parameters into a 48 | # space-separated string is a well documented source of bugs and security 49 | # problems, so this is (mostly) avoided, by progressively accumulating 50 | # options in "$@", and eventually passing that to Java. 51 | # 52 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 53 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 54 | # see the in-line comments for details. 55 | # 56 | # There are tweaks for specific operating systems such as AIX, CygWin, 57 | # Darwin, MinGW, and NonStop. 58 | # 59 | # (3) This script is generated from the Groovy template 60 | # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 61 | # within the Gradle project. 62 | # 63 | # You can find Gradle at https://github.com/gradle/gradle/. 64 | # 65 | ############################################################################## 66 | 67 | # Attempt to set APP_HOME 68 | 69 | # Resolve links: $0 may be a link 70 | app_path=$0 71 | 72 | # Need this for daisy-chained symlinks. 73 | while 74 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 75 | [ -h "$app_path" ] 76 | do 77 | ls=$( ls -ld "$app_path" ) 78 | link=${ls#*' -> '} 79 | case $link in #( 80 | /*) app_path=$link ;; #( 81 | *) app_path=$APP_HOME$link ;; 82 | esac 83 | done 84 | 85 | # This is normally unused 86 | # shellcheck disable=SC2034 87 | APP_BASE_NAME=${0##*/} 88 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 89 | APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH="\\\"\\\"" 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | if ! command -v java >/dev/null 2>&1 137 | then 138 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 139 | 140 | Please set the JAVA_HOME variable in your environment to match the 141 | location of your Java installation." 142 | fi 143 | fi 144 | 145 | # Increase the maximum file descriptors if we can. 146 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 147 | case $MAX_FD in #( 148 | max*) 149 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 150 | # shellcheck disable=SC2039,SC3045 151 | MAX_FD=$( ulimit -H -n ) || 152 | warn "Could not query maximum file descriptor limit" 153 | esac 154 | case $MAX_FD in #( 155 | '' | soft) :;; #( 156 | *) 157 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 158 | # shellcheck disable=SC2039,SC3045 159 | ulimit -n "$MAX_FD" || 160 | warn "Could not set maximum file descriptor limit to $MAX_FD" 161 | esac 162 | fi 163 | 164 | # Collect all arguments for the java command, stacking in reverse order: 165 | # * args from the command line 166 | # * the main class name 167 | # * -classpath 168 | # * -D...appname settings 169 | # * --module-path (only if needed) 170 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 171 | 172 | # For Cygwin or MSYS, switch paths to Windows format before running java 173 | if "$cygwin" || "$msys" ; then 174 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 175 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 176 | 177 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 178 | 179 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 180 | for arg do 181 | if 182 | case $arg in #( 183 | -*) false ;; # don't mess with options #( 184 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 185 | [ -e "$t" ] ;; #( 186 | *) false ;; 187 | esac 188 | then 189 | arg=$( cygpath --path --ignore --mixed "$arg" ) 190 | fi 191 | # Roll the args list around exactly as many times as the number of 192 | # args, so each arg winds up back in the position where it started, but 193 | # possibly modified. 194 | # 195 | # NB: a `for` loop captures its iteration list before it begins, so 196 | # changing the positional parameters here affects neither the number of 197 | # iterations, nor the values presented in `arg`. 198 | shift # remove old arg 199 | set -- "$@" "$arg" # push replacement arg 200 | done 201 | fi 202 | 203 | 204 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 205 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 206 | 207 | # Collect all arguments for the java command: 208 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 209 | # and any embedded shellness will be escaped. 210 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 211 | # treated as '${Hostname}' itself on the command line. 212 | 213 | set -- \ 214 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 215 | -classpath "$CLASSPATH" \ 216 | -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ 217 | "$@" 218 | 219 | # Stop when "xargs" is not available. 220 | if ! command -v xargs >/dev/null 2>&1 221 | then 222 | die "xargs is not available" 223 | fi 224 | 225 | # Use "xargs" to parse quoted args. 226 | # 227 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 228 | # 229 | # In Bash we could simply go: 230 | # 231 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 232 | # set -- "${ARGS[@]}" "$@" 233 | # 234 | # but POSIX shell has neither arrays nor command substitution, so instead we 235 | # post-process each arg (as a line of input to sed) to backslash-escape any 236 | # character that might be a shell metacharacter, then use eval to reverse 237 | # that process (while maintaining the separation between arguments), and wrap 238 | # the whole thing up as a single "set" statement. 239 | # 240 | # This will of course break if any of these variables contains a newline or 241 | # an unmatched quote. 242 | # 243 | 244 | eval "set -- $( 245 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 246 | xargs -n1 | 247 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 248 | tr '\n' ' ' 249 | )" '"$@"' 250 | 251 | exec "$JAVACMD" "$@" 252 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH= 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /kotlin-js-store/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ansi-colors@^4.1.3: 6 | version "4.1.3" 7 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" 8 | integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== 9 | 10 | ansi-regex@^5.0.1: 11 | version "5.0.1" 12 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 13 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 14 | 15 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 16 | version "4.3.0" 17 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 18 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 19 | dependencies: 20 | color-convert "^2.0.1" 21 | 22 | anymatch@~3.1.2: 23 | version "3.1.2" 24 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 25 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 26 | dependencies: 27 | normalize-path "^3.0.0" 28 | picomatch "^2.0.4" 29 | 30 | argparse@^2.0.1: 31 | version "2.0.1" 32 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 33 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 34 | 35 | balanced-match@^1.0.0: 36 | version "1.0.2" 37 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 38 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 39 | 40 | binary-extensions@^2.0.0: 41 | version "2.2.0" 42 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 43 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 44 | 45 | brace-expansion@^2.0.1: 46 | version "2.0.1" 47 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" 48 | integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== 49 | dependencies: 50 | balanced-match "^1.0.0" 51 | 52 | braces@~3.0.2: 53 | version "3.0.2" 54 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 55 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 56 | dependencies: 57 | fill-range "^7.0.1" 58 | 59 | browser-stdout@^1.3.1: 60 | version "1.3.1" 61 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 62 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 63 | 64 | buffer-from@^1.0.0: 65 | version "1.1.2" 66 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 67 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 68 | 69 | camelcase@^6.0.0: 70 | version "6.3.0" 71 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" 72 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== 73 | 74 | chalk@^4.1.0: 75 | version "4.1.2" 76 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 77 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 78 | dependencies: 79 | ansi-styles "^4.1.0" 80 | supports-color "^7.1.0" 81 | 82 | chokidar@^3.5.3: 83 | version "3.6.0" 84 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" 85 | integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== 86 | dependencies: 87 | anymatch "~3.1.2" 88 | braces "~3.0.2" 89 | glob-parent "~5.1.2" 90 | is-binary-path "~2.1.0" 91 | is-glob "~4.0.1" 92 | normalize-path "~3.0.0" 93 | readdirp "~3.6.0" 94 | optionalDependencies: 95 | fsevents "~2.3.2" 96 | 97 | cliui@^7.0.2: 98 | version "7.0.4" 99 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 100 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 101 | dependencies: 102 | string-width "^4.2.0" 103 | strip-ansi "^6.0.0" 104 | wrap-ansi "^7.0.0" 105 | 106 | color-convert@^2.0.1: 107 | version "2.0.1" 108 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 109 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 110 | dependencies: 111 | color-name "~1.1.4" 112 | 113 | color-name@~1.1.4: 114 | version "1.1.4" 115 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 116 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 117 | 118 | debug@^4.3.5: 119 | version "4.4.0" 120 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" 121 | integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== 122 | dependencies: 123 | ms "^2.1.3" 124 | 125 | decamelize@^4.0.0: 126 | version "4.0.0" 127 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" 128 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 129 | 130 | diff@^5.2.0: 131 | version "5.2.0" 132 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" 133 | integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== 134 | 135 | emoji-regex@^8.0.0: 136 | version "8.0.0" 137 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 138 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 139 | 140 | escalade@^3.1.1: 141 | version "3.1.1" 142 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 143 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 144 | 145 | escape-string-regexp@^4.0.0: 146 | version "4.0.0" 147 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 148 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 149 | 150 | fill-range@^7.0.1: 151 | version "7.0.1" 152 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 153 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 154 | dependencies: 155 | to-regex-range "^5.0.1" 156 | 157 | find-up@^5.0.0: 158 | version "5.0.0" 159 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 160 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 161 | dependencies: 162 | locate-path "^6.0.0" 163 | path-exists "^4.0.0" 164 | 165 | flat@^5.0.2: 166 | version "5.0.2" 167 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" 168 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 169 | 170 | format-util@^1.0.5: 171 | version "1.0.5" 172 | resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" 173 | integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== 174 | 175 | fs.realpath@^1.0.0: 176 | version "1.0.0" 177 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 178 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 179 | 180 | fsevents@~2.3.2: 181 | version "2.3.2" 182 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 183 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 184 | 185 | get-caller-file@^2.0.5: 186 | version "2.0.5" 187 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 188 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 189 | 190 | glob-parent@~5.1.2: 191 | version "5.1.2" 192 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 193 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 194 | dependencies: 195 | is-glob "^4.0.1" 196 | 197 | glob@^8.1.0: 198 | version "8.1.0" 199 | resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" 200 | integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== 201 | dependencies: 202 | fs.realpath "^1.0.0" 203 | inflight "^1.0.4" 204 | inherits "2" 205 | minimatch "^5.0.1" 206 | once "^1.3.0" 207 | 208 | has-flag@^4.0.0: 209 | version "4.0.0" 210 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 211 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 212 | 213 | he@^1.2.0: 214 | version "1.2.0" 215 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 216 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 217 | 218 | inflight@^1.0.4: 219 | version "1.0.6" 220 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 221 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 222 | dependencies: 223 | once "^1.3.0" 224 | wrappy "1" 225 | 226 | inherits@2: 227 | version "2.0.4" 228 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 229 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 230 | 231 | is-binary-path@~2.1.0: 232 | version "2.1.0" 233 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 234 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 235 | dependencies: 236 | binary-extensions "^2.0.0" 237 | 238 | is-extglob@^2.1.1: 239 | version "2.1.1" 240 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 241 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 242 | 243 | is-fullwidth-code-point@^3.0.0: 244 | version "3.0.0" 245 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 246 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 247 | 248 | is-glob@^4.0.1, is-glob@~4.0.1: 249 | version "4.0.3" 250 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 251 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 252 | dependencies: 253 | is-extglob "^2.1.1" 254 | 255 | is-number@^7.0.0: 256 | version "7.0.0" 257 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 258 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 259 | 260 | is-plain-obj@^2.1.0: 261 | version "2.1.0" 262 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" 263 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 264 | 265 | is-unicode-supported@^0.1.0: 266 | version "0.1.0" 267 | resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" 268 | integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== 269 | 270 | js-yaml@^4.1.0: 271 | version "4.1.0" 272 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" 273 | integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== 274 | dependencies: 275 | argparse "^2.0.1" 276 | 277 | kotlin-web-helpers@2.0.0: 278 | version "2.0.0" 279 | resolved "https://registry.yarnpkg.com/kotlin-web-helpers/-/kotlin-web-helpers-2.0.0.tgz#b112096b273c1e733e0b86560998235c09a19286" 280 | integrity sha512-xkVGl60Ygn/zuLkDPx+oHj7jeLR7hCvoNF99nhwXMn8a3ApB4lLiC9pk4ol4NHPjyoCbvQctBqvzUcp8pkqyWw== 281 | dependencies: 282 | format-util "^1.0.5" 283 | 284 | locate-path@^6.0.0: 285 | version "6.0.0" 286 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 287 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 288 | dependencies: 289 | p-locate "^5.0.0" 290 | 291 | log-symbols@^4.1.0: 292 | version "4.1.0" 293 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" 294 | integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== 295 | dependencies: 296 | chalk "^4.1.0" 297 | is-unicode-supported "^0.1.0" 298 | 299 | minimatch@^5.0.1, minimatch@^5.1.6: 300 | version "5.1.6" 301 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" 302 | integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== 303 | dependencies: 304 | brace-expansion "^2.0.1" 305 | 306 | mocha@10.7.3: 307 | version "10.7.3" 308 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752" 309 | integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== 310 | dependencies: 311 | ansi-colors "^4.1.3" 312 | browser-stdout "^1.3.1" 313 | chokidar "^3.5.3" 314 | debug "^4.3.5" 315 | diff "^5.2.0" 316 | escape-string-regexp "^4.0.0" 317 | find-up "^5.0.0" 318 | glob "^8.1.0" 319 | he "^1.2.0" 320 | js-yaml "^4.1.0" 321 | log-symbols "^4.1.0" 322 | minimatch "^5.1.6" 323 | ms "^2.1.3" 324 | serialize-javascript "^6.0.2" 325 | strip-json-comments "^3.1.1" 326 | supports-color "^8.1.1" 327 | workerpool "^6.5.1" 328 | yargs "^16.2.0" 329 | yargs-parser "^20.2.9" 330 | yargs-unparser "^2.0.0" 331 | 332 | ms@^2.1.3: 333 | version "2.1.3" 334 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 335 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 336 | 337 | normalize-path@^3.0.0, normalize-path@~3.0.0: 338 | version "3.0.0" 339 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 340 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 341 | 342 | once@^1.3.0: 343 | version "1.4.0" 344 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 345 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 346 | dependencies: 347 | wrappy "1" 348 | 349 | p-limit@^3.0.2: 350 | version "3.1.0" 351 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 352 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 353 | dependencies: 354 | yocto-queue "^0.1.0" 355 | 356 | p-locate@^5.0.0: 357 | version "5.0.0" 358 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 359 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 360 | dependencies: 361 | p-limit "^3.0.2" 362 | 363 | path-exists@^4.0.0: 364 | version "4.0.0" 365 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 366 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 367 | 368 | picomatch@^2.0.4, picomatch@^2.2.1: 369 | version "2.3.1" 370 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 371 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 372 | 373 | randombytes@^2.1.0: 374 | version "2.1.0" 375 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 376 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 377 | dependencies: 378 | safe-buffer "^5.1.0" 379 | 380 | readdirp@~3.6.0: 381 | version "3.6.0" 382 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 383 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 384 | dependencies: 385 | picomatch "^2.2.1" 386 | 387 | require-directory@^2.1.1: 388 | version "2.1.1" 389 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 390 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 391 | 392 | safe-buffer@^5.1.0: 393 | version "5.2.1" 394 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 395 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 396 | 397 | serialize-javascript@^6.0.2: 398 | version "6.0.2" 399 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" 400 | integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== 401 | dependencies: 402 | randombytes "^2.1.0" 403 | 404 | source-map-support@0.5.21: 405 | version "0.5.21" 406 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" 407 | integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== 408 | dependencies: 409 | buffer-from "^1.0.0" 410 | source-map "^0.6.0" 411 | 412 | source-map@^0.6.0: 413 | version "0.6.1" 414 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 415 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 416 | 417 | string-width@^4.1.0, string-width@^4.2.0: 418 | version "4.2.3" 419 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 420 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 421 | dependencies: 422 | emoji-regex "^8.0.0" 423 | is-fullwidth-code-point "^3.0.0" 424 | strip-ansi "^6.0.1" 425 | 426 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 427 | version "6.0.1" 428 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 429 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 430 | dependencies: 431 | ansi-regex "^5.0.1" 432 | 433 | strip-json-comments@^3.1.1: 434 | version "3.1.1" 435 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 436 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 437 | 438 | supports-color@^7.1.0: 439 | version "7.2.0" 440 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 441 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 442 | dependencies: 443 | has-flag "^4.0.0" 444 | 445 | supports-color@^8.1.1: 446 | version "8.1.1" 447 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 448 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 449 | dependencies: 450 | has-flag "^4.0.0" 451 | 452 | to-regex-range@^5.0.1: 453 | version "5.0.1" 454 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 455 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 456 | dependencies: 457 | is-number "^7.0.0" 458 | 459 | typescript@5.5.4: 460 | version "5.5.4" 461 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" 462 | integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== 463 | 464 | workerpool@^6.5.1: 465 | version "6.5.1" 466 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" 467 | integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== 468 | 469 | wrap-ansi@^7.0.0: 470 | version "7.0.0" 471 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 472 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 473 | dependencies: 474 | ansi-styles "^4.0.0" 475 | string-width "^4.1.0" 476 | strip-ansi "^6.0.0" 477 | 478 | wrappy@1: 479 | version "1.0.2" 480 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 481 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 482 | 483 | y18n@^5.0.5: 484 | version "5.0.8" 485 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 486 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 487 | 488 | yargs-parser@^20.2.2, yargs-parser@^20.2.9: 489 | version "20.2.9" 490 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 491 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 492 | 493 | yargs-unparser@^2.0.0: 494 | version "2.0.0" 495 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" 496 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 497 | dependencies: 498 | camelcase "^6.0.0" 499 | decamelize "^4.0.0" 500 | flat "^5.0.2" 501 | is-plain-obj "^2.1.0" 502 | 503 | yargs@^16.2.0: 504 | version "16.2.0" 505 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 506 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 507 | dependencies: 508 | cliui "^7.0.2" 509 | escalade "^3.1.1" 510 | get-caller-file "^2.0.5" 511 | require-directory "^2.1.1" 512 | string-width "^4.2.0" 513 | y18n "^5.0.5" 514 | yargs-parser "^20.2.2" 515 | 516 | yocto-queue@^0.1.0: 517 | version "0.1.0" 518 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 519 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 520 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JakeWharton/crossword/3b064a8b45dba153cc1f1d3752820302cba6ffa0/settings.gradle -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/jakewharton/crossword/canvas.kt: -------------------------------------------------------------------------------- 1 | package com.jakewharton.crossword 2 | 3 | import kotlin.jvm.JvmName 4 | import kotlin.jvm.JvmStatic 5 | 6 | private class TextSurface( 7 | override val width: Int, 8 | override val height: Int, 9 | ) : TextCanvas { 10 | private val rowBuilders = Array(height) { 11 | StringBuilder(width).apply { 12 | repeat(width) { 13 | append(' ') 14 | } 15 | } 16 | } 17 | 18 | override fun write(row: Int, column: Int, char: Char) { 19 | val rowBuilder = rowBuilders[row] 20 | val writeIndex = rowBuilder.visualIndex(column) 21 | rowBuilder[writeIndex] = char 22 | } 23 | 24 | override fun write(row: Int, column: Int, string: String) { 25 | string.split('\n').forEachIndexed { lineIndex, line -> 26 | val rowBuilder = rowBuilders[row + lineIndex] 27 | val writeStartIndex = rowBuilder.visualIndex(column) 28 | val writeEndIndex = rowBuilder.visualIndex(column + line.visualWidth) 29 | 30 | rowBuilder.setRange(writeStartIndex, writeEndIndex, line) 31 | } 32 | } 33 | 34 | override fun toString(): String { 35 | if (height == 0) { 36 | return "" 37 | } 38 | val rowCharacterCount = rowBuilders.sumOf { it.length } 39 | val newLineCount = height - 1 40 | return buildString(rowCharacterCount + newLineCount) { 41 | rowBuilders.forEachIndexed { index, rowBuilder -> 42 | if (index > 0) { 43 | append('\n') 44 | } 45 | append(rowBuilder) 46 | } 47 | } 48 | } 49 | } 50 | 51 | interface TextCanvas { 52 | val width: Int 53 | val height: Int 54 | 55 | fun write(row: Int, column: Int, char: Char) 56 | fun write(row: Int, column: Int, string: String) 57 | 58 | fun clip(left: Int, top: Int, right: Int, bottom: Int): TextCanvas { 59 | return ClippedTextCanvas(this, left, right, top, bottom) 60 | } 61 | 62 | override fun toString(): String 63 | 64 | companion object { 65 | @JvmStatic 66 | @JvmName("ofSize") 67 | operator fun invoke(width: Int, height: Int): TextCanvas { 68 | return TextSurface(width, height) 69 | } 70 | } 71 | } 72 | 73 | private class ClippedTextCanvas( 74 | private val canvas: TextCanvas, 75 | private val left: Int, 76 | right: Int, 77 | private val top: Int, 78 | bottom: Int, 79 | ) : TextCanvas { 80 | override val width = right - left 81 | override val height = bottom - top 82 | 83 | override fun write(row: Int, column: Int, char: Char) { 84 | canvas.write(top + row, left + column, char) 85 | } 86 | 87 | override fun write(row: Int, column: Int, string: String) { 88 | canvas.write(top + row, left + column, string) 89 | } 90 | 91 | override fun toString(): String { 92 | throw UnsupportedOperationException("Rendering a clipped canvas is not supported") 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/commonMain/kotlin/com/jakewharton/crossword/text.kt: -------------------------------------------------------------------------------- 1 | package com.jakewharton.crossword 2 | 3 | import kotlin.DeprecationLevel.ERROR 4 | 5 | private val ansiColorEscape = Regex("""\u001B\[\d+(;\d+)*m""") 6 | 7 | fun CharSequence.visualIndex(index: Int): Int { 8 | var remaining = index 9 | forEachVisualCharacter { 10 | if (remaining == 0) { 11 | return it 12 | } 13 | remaining-- 14 | } 15 | if (remaining == 0) { 16 | return length 17 | } 18 | throw IndexOutOfBoundsException() 19 | } 20 | 21 | val CharSequence.visualWidth: Int get() { 22 | var count = 0 23 | forEachVisualCharacter { 24 | count++ 25 | } 26 | return count 27 | } 28 | 29 | private inline fun CharSequence.forEachVisualCharacter(block: (index: Int) -> Unit) { 30 | var index = 0 31 | 32 | // These values will force a code path that searches for the first real match below. 33 | var nextMatchStart = 0 34 | var nextMatchEnd = -1 35 | 36 | val length = length 37 | while (index < length) { 38 | if (index == nextMatchStart) { 39 | // Jump over ANSI control sequence. 40 | index = nextMatchEnd + 1 41 | 42 | // Find the next ANSI control sequence, if any. 43 | val match = ansiColorEscape.find(this, index) 44 | if (match != null) { 45 | nextMatchStart = match.range.first 46 | nextMatchEnd = match.range.last 47 | } else { 48 | // No future matches. Ensure we never take this conditional again. 49 | nextMatchStart = length 50 | } 51 | 52 | // Restart loop since there may be successive ANSI sequences. 53 | continue 54 | } 55 | 56 | block(index) 57 | 58 | val code = this[index].code 59 | index++ 60 | 61 | // Check for a surrogate pair which render as a single visual glyph. 62 | if (code.isHighSurrogate() && index < length && this[index].code.isLowSurrogate()) { 63 | index++ 64 | } 65 | 66 | // Consume combining diacritics which render on the preceding code point. 67 | while (index < length && this[index].code.isCombiningDiacritical()) { 68 | index++ 69 | } 70 | } 71 | } 72 | 73 | @Suppress("NOTHING_TO_INLINE") 74 | private inline fun Int.isLowSurrogate(): Boolean = this in 0xDC00..0xDFFF 75 | @Suppress("NOTHING_TO_INLINE") 76 | private inline fun Int.isHighSurrogate(): Boolean = this in 0xD800..0xDBFF 77 | @Suppress("NOTHING_TO_INLINE") 78 | private inline fun Int.isCombiningDiacritical(): Boolean = this in 0x0300..0x036F 79 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/com/jakewharton/crossword/TextCanvasTest.kt: -------------------------------------------------------------------------------- 1 | package com.jakewharton.crossword 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class TextCanvasTest { 7 | @Test fun zeroSized() { 8 | val canvas = TextCanvas(0, 0) 9 | assertEquals("", canvas.toString()) 10 | } 11 | 12 | @Test fun fourCorners() { 13 | val canvas = TextCanvas(10, 4).apply { 14 | write(0, 0, 'a') 15 | write(0, 9, 'b') 16 | write(3, 0, 'c') 17 | write(3, 9, 'd') 18 | } 19 | assertEquals(""" 20 | |a b 21 | | 22 | | 23 | |c d 24 | """.trimMargin(), canvas.toString()) 25 | } 26 | 27 | @Test fun ansiControlSequences() { 28 | val canvas = TextCanvas(5, 2).apply { 29 | write(0, 0, "\u001B[31mX\u001B[0m") 30 | write(0, 2, "\u001B[34mO\u001B[0m") 31 | write(0, 4, 'X') 32 | write(1, 0, 'Y') 33 | write(1, 2, 'Z') 34 | write(1, 4, 'Y') 35 | } 36 | assertEquals(""" 37 | |$esc[31mX$esc[0m $esc[34mO$esc[0m X 38 | |Y Z Y 39 | """.trimMargin(), canvas.toString()) 40 | } 41 | 42 | private val esc = "\u001B" 43 | } 44 | -------------------------------------------------------------------------------- /src/commonTest/kotlin/com/jakewharton/crossword/TextTest.kt: -------------------------------------------------------------------------------- 1 | package com.jakewharton.crossword 2 | 3 | import kotlin.test.Test 4 | import kotlin.test.assertEquals 5 | 6 | class TextTest { 7 | @Test fun visualIndex() { 8 | assertEquals(0, "AAAAA".visualIndex(0)) 9 | assertEquals(1, "AAAAA".visualIndex(1)) 10 | assertEquals(2, "AAAAA".visualIndex(2)) 11 | assertEquals(3, "AAAAA".visualIndex(3)) 12 | assertEquals(4, "AAAAA".visualIndex(4)) 13 | 14 | assertEquals(1, "\u0031a".visualIndex(1)) 15 | assertEquals(1, "\u00A3a".visualIndex(1)) 16 | assertEquals(1, "\u20ACa".visualIndex(1)) 17 | assertEquals(1, "\u5317a".visualIndex(1)) 18 | } 19 | 20 | @Test fun visualIndexSurrogates() { 21 | // High, low, ASCII 22 | assertEquals(2, "\uD83D\uDE03a".visualIndex(1)) 23 | 24 | // High, high, low, low --> ?😃? 25 | assertEquals(1, "\uD83D\uD83D\uDE03\uDE03".visualIndex(1)) 26 | assertEquals(3, "\uD83D\uD83D\uDE03\uDE03".visualIndex(2)) 27 | // Low, low, high, high --> ???? 28 | assertEquals(1, "\uDE03\uDE03\uD83D\uD83D".visualIndex(1)) 29 | assertEquals(2, "\uDE03\uDE03\uD83D\uD83D".visualIndex(2)) 30 | assertEquals(3, "\uDE03\uDE03\uD83D\uD83D".visualIndex(3)) 31 | } 32 | 33 | @Test fun visualIndexCombiningDiacritics() { 34 | assertEquals(3, "o\u032E\u0306".visualIndex(1)) 35 | 36 | // Leading diacritic will be displayed separately. That is, at least, unless there is a letter 37 | // preceding it in the final output. But we cannot control that here. 38 | assertEquals(1, "\u032Eo".visualIndex(1)) 39 | assertEquals(2, "\u032Eo".visualIndex(2)) 40 | } 41 | 42 | @Test fun visualIndexAnsiEscapes() { 43 | val singleAnsiEscape = "AAA\u001B[31;1;4mAA" 44 | assertEquals(0, singleAnsiEscape.visualIndex(0)) 45 | assertEquals(1, singleAnsiEscape.visualIndex(1)) 46 | assertEquals(2, singleAnsiEscape.visualIndex(2)) 47 | assertEquals(12, singleAnsiEscape.visualIndex(3)) 48 | assertEquals(13, singleAnsiEscape.visualIndex(4)) 49 | 50 | val dualAdjacentAnsiEscapes = "AAA\u001B[31;1;4m\u001B[0mAA" 51 | assertEquals(0, dualAdjacentAnsiEscapes.visualIndex(0)) 52 | assertEquals(1, dualAdjacentAnsiEscapes.visualIndex(1)) 53 | assertEquals(2, dualAdjacentAnsiEscapes.visualIndex(2)) 54 | assertEquals(16, dualAdjacentAnsiEscapes.visualIndex(3)) 55 | assertEquals(17, dualAdjacentAnsiEscapes.visualIndex(4)) 56 | 57 | val dualAnsiEscapes = "AAA\u001B[31;1;4mAA\u001B[31;1;4mAA" 58 | assertEquals(0, dualAnsiEscapes.visualIndex(0)) 59 | assertEquals(1, dualAnsiEscapes.visualIndex(1)) 60 | assertEquals(2, dualAnsiEscapes.visualIndex(2)) 61 | assertEquals(12, dualAnsiEscapes.visualIndex(3)) 62 | assertEquals(13, dualAnsiEscapes.visualIndex(4)) 63 | } 64 | 65 | @Test fun visualWidth() { 66 | assertEquals(0, "".visualWidth) 67 | assertEquals(1, "A".visualWidth) 68 | assertEquals(2, "AA".visualWidth) 69 | assertEquals(3, "AAA".visualWidth) 70 | 71 | assertEquals(2, "\u0031a".visualWidth) 72 | assertEquals(2, "\u00A3a".visualWidth) 73 | assertEquals(2, "\u20ACa".visualWidth) 74 | assertEquals(2, "\u5317a".visualWidth) 75 | } 76 | 77 | @Test fun visualWidthSurrogates() { 78 | // High, low, ASCII 79 | assertEquals(2, "\uD83D\uDE03a".visualWidth) 80 | 81 | // High, high, low, low --> ?😃? 82 | assertEquals(3, "\uD83D\uD83D\uDE03\uDE03".visualWidth) 83 | // Low, low, high, high --> ???? 84 | assertEquals(4, "\uDE03\uDE03\uD83D\uD83D".visualWidth) 85 | } 86 | 87 | @Test fun visualWidthCombiningDiacritics() { 88 | assertEquals(1, "o\u032E\u0306".visualWidth) 89 | 90 | // Leading diacritic will be displayed separately. That is, at least, unless there is a letter 91 | // preceding it in the final output. But we cannot control that here. 92 | assertEquals(2, "\u032Eo".visualWidth) 93 | } 94 | 95 | @Test fun visualWidthAnsiEscapes() { 96 | assertEquals(1, "\u001B[31;1;4mA\u001B[0m".visualWidth) 97 | assertEquals(3, "A\u001B[31;1;4mA\u001B[0mA".visualWidth) 98 | 99 | assertEquals(3, "\u001B[31;1;4mA\u001B[0m\u001B[31;1;4mA\u001B[0mA".visualWidth) 100 | } 101 | } 102 | --------------------------------------------------------------------------------