diff --git a/.github/workflows/api-verification.yml b/.github/workflows/api-verification.yml
index e8cc9aa95a..af6bc682dc 100644
--- a/.github/workflows/api-verification.yml
+++ b/.github/workflows/api-verification.yml
@@ -23,6 +23,7 @@ jobs:
GIT_BRANCH: ${{ steps.environment_step.outputs.GIT_BRANCH }}
GIT_BASE_BRANCH: ${{ steps.environment_step.outputs.GIT_BASE_BRANCH }}
GIT_USER: ${{ steps.environment_step.outputs.GIT_USER }}
+ SKIP_API_CHECK: ${{ steps.environment_step.outputs.SKIP_API_CHECK }}
steps:
- name: Restore artifacts
@@ -40,7 +41,7 @@ jobs:
- name: Set pending status on PR builds
id: set_status
- if: steps.environment_step.outputs.IS_TEST_BUILD == 'true'
+ if: steps.environment_step.outputs.IS_TEST_BUILD == 'true' && steps.environment_step.outputs.SKIP_API_CHECK != 'true'
shell: bash
run: |
gh api \
@@ -53,6 +54,7 @@ jobs:
-f context="$STATUS_CONTEXT"
- name: Checkout
+ if: steps.environment_step.outputs.SKIP_API_CHECK != 'true'
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 #v4.2.2
with:
ref: '${{ steps.environment_step.outputs.GIT_SHA }}'
@@ -61,11 +63,13 @@ jobs:
path: ${{ github.workspace }}/keyman/
- name: Install devscripts
+ if: steps.environment_step.outputs.SKIP_API_CHECK != 'true'
uses: ./keyman/.github/actions/apt-install
with:
packages: devscripts equivs
- name: "Verify API for libkeymancore*.so (${{ steps.environment_step.outputs.GIT_BRANCH }}, branch ${{ steps.environment_step.outputs.GIT_BASE_BRANCH }}, by ${{ steps.environment_step.outputs.GIT_USER }})"
+ if: steps.environment_step.outputs.SKIP_API_CHECK != 'true'
run: |
echo "Verify API for libkeymancore*.so (${{ steps.environment_step.outputs.GIT_BRANCH }}, branch ${{ steps.environment_step.outputs.GIT_BASE_BRANCH }}, by ${{ steps.environment_step.outputs.GIT_USER }}):" >> $GITHUB_STEP_SUMMARY
@@ -79,17 +83,17 @@ jobs:
verify 2>> $GITHUB_STEP_SUMMARY
- name: Archive .symbols file
+ if: steps.environment_step.outputs.SKIP_API_CHECK != 'true' && always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: libkeymancore.symbols
path: ${{ github.workspace }}/keyman/linux/debian/tmp/DEBIAN/symbols
- if: always()
set_status:
name: Set result status on PR builds
needs: [api_verification]
runs-on: ubuntu-latest
- if: ${{ always() && needs.api_verification.outputs.IS_TEST_BUILD == 'true' }}
+ if: ${{ always() && needs.api_verification.outputs.IS_TEST_BUILD == 'true' && needs.api_verification.outputs.SKIP_API_CHECK != 'true' }}
steps:
- name: Set success
if: needs.api_verification.result == 'success'
diff --git a/.github/workflows/build-test-publish-docker.yml b/.github/workflows/build-test-publish-docker.yml
new file mode 100644
index 0000000000..7919d9ff81
--- /dev/null
+++ b/.github/workflows/build-test-publish-docker.yml
@@ -0,0 +1,90 @@
+# This workflow runs the build, test and publish steps for the
+# Keyman build Docker images.
+# It is triggered by a schedule and repository_dispatch event.
+
+name: "Build, test, and publish Docker images"
+run-name: "Build, test, and publish Docker images (branch ${{ github.ref_name }} on ${{ github.event_name }}/${{ github.event.action }} by ${{ github.actor }})"
+defaults:
+ run:
+ shell: bash
+
+on:
+ schedule:
+ #run every Fri, 3 pm UTC
+ - cron: '0 15 * * 5'
+
+ repository_dispatch:
+ types: ['build-test-publish-docker:*']
+
+env:
+ REGISTRY: ghcr.io
+ USERNAME: "${{ github.actor }}"
+ PASSWORD: "${{ github.token }}"
+
+jobs:
+
+ message:
+ name: Print message
+ runs-on: ubuntu-latest
+ if: ${{ github.event.act }}
+
+ steps:
+ - name: Print message
+ id: print-message
+ run: |
+ echo "Build, test, and publish Docker images (branch ${{ github.ref_name }} on ${{ github.event_name }}/${{ github.event.action }} by ${{ github.actor }})"
+
+ build:
+ name: Build Docker images
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ id: checkout
+ uses: actions/checkout@v4
+ - name: Build Docker images
+ id: build
+ run: |
+ if [ -z "${{ env.USERNAME }}" ]; then
+ resources/docker-images/build.sh build: --registry ${{ env.REGISTRY }}
+ else
+ echo ${{ env.PASSWORD }} | resources/docker-images/build.sh build: --registry ${{ env.REGISTRY }} --username ${{ env.USERNAME }}
+ fi
+
+ publish:
+ name: Publish Docker images
+ runs-on: ubuntu-latest
+ needs: build
+
+ steps:
+ - name: Checkout repository
+ id: checkout
+ uses: actions/checkout@v4
+
+ - name: Publish Docker images
+ id: publish
+ run: |
+ if [ -z "${{ env.USERNAME }}" ]; then
+ resources/docker-images/build.sh publish: --registry ${{ env.REGISTRY }}
+ else
+ echo ${{ env.PASSWORD }} | resources/docker-images/build.sh publish: --registry ${{ env.REGISTRY }} --username ${{ env.USERNAME }}
+ fi
+
+ test:
+ name: Test Docker images
+ runs-on: ubuntu-latest
+ needs: publish
+
+ steps:
+ - name: Checkout repository
+ id: checkout
+ uses: actions/checkout@v4
+
+ - name: Test Docker images
+ id: test
+ run: |
+ if [ -z "${{ env.USERNAME }}" ]; then
+ resources/docker-images/build.sh test: --registry ${{ env.REGISTRY }}
+ else
+ echo ${{ env.PASSWORD }} | resources/docker-images/build.sh test: --registry ${{ env.REGISTRY }} --username ${{ env.USERNAME }}
+ fi
diff --git a/.github/workflows/deb-packaging.yml b/.github/workflows/deb-packaging.yml
index a40fcb7259..472adf91b0 100644
--- a/.github/workflows/deb-packaging.yml
+++ b/.github/workflows/deb-packaging.yml
@@ -23,6 +23,7 @@ on:
# baseRef: The ref of the previous commit. For a PR the same as `baseBranch`.
# user: The user that triggered the build or created the PR
# isTestBuild: false for Releases, otherwise true
+# skipApiCheck: true to skip the API check, otherwise false
env:
COLOR_GREEN: "\e[32m"
@@ -332,6 +333,7 @@ jobs:
echo "GIT_BRANCH=${{ github.event.client_payload.branch }}" >> artifacts/env
echo "GIT_BASE_BRANCH=${{ github.event.client_payload.baseBranch }}" >> artifacts/env
echo "GIT_USER=${{ github.event.client_payload.user }}" >> artifacts/env
+ echo "SKIP_API_CHECK=${{ github.event.client_payload.skipApiCheck }}" >> artifacts/env
- name: Cache artifacts
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
diff --git a/.github/workflows/delete-build-containers.yml b/.github/workflows/delete-build-containers.yml
new file mode 100644
index 0000000000..d869831366
--- /dev/null
+++ b/.github/workflows/delete-build-containers.yml
@@ -0,0 +1,19 @@
+
+
+on:
+ schedule:
+ #run every Fri, 6 pm UTC
+ - cron: '0 18 * * 5' #
+
+jobs:
+ cleanup-images:
+ name: ghcr.io cleanup action
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: dataaxiom/ghcr-cleanup-action@cd0cdb900b5dbf3a6f2cc869f0dbb0b8211f50c4 # v1.0.16
+ with:
+ dry-run: true
+ expand-packages: true
+ packages: keyman-*-ci
+ delete-untagged: true
diff --git a/.github/workflows/pr-build-status.yml b/.github/workflows/pr-build-status.yml
index 236970f141..585a0b19b8 100644
--- a/.github/workflows/pr-build-status.yml
+++ b/.github/workflows/pr-build-status.yml
@@ -1,4 +1,4 @@
-# GENERATED FILE - DO NOT EDIT!
+# GENERATED FILE - DO NOT EDIT!
#
# Keyman is copyright (C) SIL Global. MIT License.
#
@@ -35,174 +35,194 @@ jobs:
id: run_pr_build_status_script
uses: actions/github-script@v7
with:
- script: |
- // This code is copied out of resources/build/pr-build-status/pr-build-status.mjs
- // where it is tested. It is copied inline here in order to avoid requiring the
- // repository to be checked out, which dramatically reduces the run time of the
- // check.
- //
- // Note: we don't currently look at check runs, only statuses
- //
- // Verify the following statuses:
- // 'user_testing'
- // 'API Verification' (github-actions[bot])
- //
- // At least 1 of the following statuses must be found:
- // 'Test*' (keyman-server), e.g. 'Test Build (Keyman)'
- // 'Ubuntu Packaging' (github-actions[bot])
- //
- // Ignore the following statuses:
- // check/web/file-size
- //
-
- function reduceStatuses(statuses) {
- const filtered_statuses = statuses.reduce((o, status) => {
- if(status.creator?.login == 'keyman-server' && status.context.startsWith('Test')) {
- if(!o[status.context]) o[status.context] = {type: 'build', state: status.state};
- } else if(status.creator?.login == 'keymanapp-test-bot[bot]' && status.context == 'user_testing') {
- if(!o[status.context]) o[status.context] = {type: 'user-test', state: status.state};;
- } else if(status.context == 'API Verification') {
- if(!o[status.context]) o[status.context] = {type: 'check', state: status.state};
- } else if(status.context == 'Ubuntu Packaging') {
- if(!o[status.context]) o[status.context] = {type: 'build', state: status.state};
- } else if(status.context == 'check/web/file-size') {
- // Ignore check/web/file-size -- we won't block automerge for this at this point
- } else {
- // We fail with an 'unknown status' response if we get a new status check
- // so we can be sure we are not skipping known status checks
- o[status.context] = {type: 'unknown', state: status.state};
- }
- return o;
-
- }, {});
- return filtered_statuses;
- }
-
- //
- // Given the collection of status checks we care about, return
- // an aggregate status -- error, failed, pending, or success,
- // and a summary description
- //
- function calculateFinalStatus(filtered_statuses) {
- const counts = {};
- let hasBuilds = false;
- for(const context of Object.keys(filtered_statuses)) {
- const { state, type } = filtered_statuses[context];
- if(type == 'unknown') {
- // We special-case for unknown status checks, and never permit them
- return [
- 'error', `An unknown context ${context} was found, cannot calculate build status.`
- ];
- }
- if(type == 'build') {
- hasBuilds = true;
- }
- counts[state] = counts[state] ? counts[state] + 1 : 1;
- }
-
- // If we do not have any statuses yet, we wait
- if(Object.keys(filtered_statuses).length == 0 || !hasBuilds) {
- return ['pending', 'Builds have not yet been triggered ⌛'];
- }
-
- const state =
- counts.error ? 'error' :
- counts.failed ? 'failed' :
- counts.pending ? 'pending' :
- 'success';
-
- let description = '';
- function appendDescription(count, state) {
- if(!count) return;
- if(description != '') description += '; ';
- description += `${count} check${count == 1 ? '' : 's'} ${state}`;
- }
- appendDescription(counts.error, 'in an error state ❌');
- appendDescription(counts.failed, 'failed ❌');
- appendDescription(counts.pending, 'pending ⌛');
- appendDescription(counts.success, 'completed successfully ✅');
-
- return [ state, description ];
- }
-
- async function getCommitStatuses(github, owner, repo, sha) {
- const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/statuses', {
- owner,
- repo,
- sha,
- headers: {
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- });
- return statuses;
- }
-
- async function getCommitCheckRuns(github, owner, repo, sha) {
- const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/check-runs', {
- owner,
- repo,
- sha,
- headers: {
- 'X-GitHub-Api-Version': '2022-11-28'
- }
- });
- return statuses;
- }
-
- function calculateCheckResult(statuses) {
- if(!Array.isArray(statuses)) {
- return ['error', 'Failed to retrieve status checks from GitHub ❌'];
- }
-
- const filtered_statuses = reduceStatuses(statuses);
-
- const result = calculateFinalStatus(filtered_statuses);
- return result;
- }
-
- async function test(github, owner, repo, sha) {
- // Get statuses from sha
- const statuses = await getCommitStatuses(github, owner, repo, sha);
- return calculateCheckResult(statuses);
- }
-
- async function createCheck(github, owner, repo, sha) {
- const check = await github.rest.checks.create({
- owner,
- repo,
- head_sha: sha,
- name: 'Build Outcome',
- status: 'in_progress',
- });
- return check.data.id;
- }
-
- async function updateCheck(github, owner, repo, checkRunId, status, description) {
- const checkStatus = status == 'pending' ? 'in_progress' : 'completed';
- const conclusion = checkStatus == 'in_progress' ? undefined : (status == 'success' ? 'success' : 'failure');
-
- await github.rest.checks.update({
- owner,
- repo,
- check_run_id: checkRunId,
- status: checkStatus,
- conclusion,
- output: {
- title: description,
- summary: ''
- }
- });
- }
-
- const { owner, repo } = context.repo;
- const sha =
- context.payload?.check_suite?.sha || /* check run completed */
- context.payload?.inputs?.commit || /* manual run */
- context.payload?.after || /* push */
- context.payload?.commit?.sha || /* status */
- context.sha; /* probably 'master'! */
-
- const checkRunId = await createCheck(github, owner, repo, sha);
- const res = await test(github, owner, repo, sha);
- await updateCheck(github, owner, repo, checkRunId, res[0], res[1]);
-
+ script: |
+ // This code is copied out of resources/build/pr-build-status/pr-build-status.mjs
+ // where it is tested. It is copied inline here in order to avoid requiring the
+ // repository to be checked out, which dramatically reduces the run time of the
+ // check.
+ //
+ // Note: we don't currently look at check runs, only statuses
+ //
+ // Verify the following statuses:
+ // 'user_testing'
+ // 'API Verification' (github-actions[bot])
+ //
+ // At least 1 of the following statuses must be found:
+ // 'Test*' (keyman-server), e.g. 'Test Build (Keyman)'
+ // 'Ubuntu Packaging' (github-actions[bot])
+ //
+ // Ignore the following statuses:
+ // check/web/file-size
+ //
+
+ function addLog(message) {
+ console.log(message);
+ return message + String.fromCharCode(10);
+ }
+
+ function addStatus(o, type, context, state) {
+ if(!o[context]) {
+ o[context] = {type, state};
+ return addLog(`Found ${context}: ${state}`);
+ } else {
+ return addLog(`Skipping repeated ${context}: ${state}`);
+ }
+ }
+
+ function reduceStatuses(statuses) {
+ let summary = '';
+ const filtered_statuses = statuses.reduce((o, status) => {
+ if(status.creator?.login == 'keyman-server' && status.context.startsWith('Test')) {
+ summary += addStatus(o, 'build', status.context, status.state);
+ } else if(status.creator?.login == 'keymanapp-test-bot[bot]' && status.context == 'user_testing') {
+ summary += addStatus(o, 'user-test', status.context, status.state);
+ } else if(status.context == 'API Verification') {
+ summary += addStatus(o, 'check', status.context, status.state);
+ } else if(status.context == 'Ubuntu Packaging') {
+ summary += addStatus(o, 'build', status.context, status.state);
+ } else if(status.context == 'check/web/file-size') {
+ // Ignore check/web/file-size -- we won't block automerge for this at this point
+ summary += addLog(`Skipping ${status.context}`);
+ } else {
+ // We fail with an 'unknown status' response if we get a new status check
+ // so we can be sure we are not skipping known status checks
+ summary += addLog(`Found unknown ${status.context}: ${status.state}`);
+ o[status.context] = {type: 'unknown', state: status.state};
+ }
+ return o;
+
+ }, {});
+ return { filtered_statuses, summary };
+ }
+
+ //
+ // Given the collection of status checks we care about, return
+ // an aggregate status -- error, failure, pending, or success,
+ // and a summary description
+ //
+ function calculateFinalStatus(filtered_statuses, summary) {
+ const counts = {};
+ let hasBuilds = false;
+ for(const context of Object.keys(filtered_statuses)) {
+ const { state, type } = filtered_statuses[context];
+ if(type == 'unknown') {
+ // We special-case for unknown status checks, and never permit them
+ console.error(`An unknown context ${context} was found, cannot calculate build status.`);
+ return [
+ 'error', `An unknown context ${context} was found, cannot calculate build status.`, summary
+ ];
+ }
+ if(type == 'build') {
+ hasBuilds = true;
+ }
+ counts[state] = counts[state] ? counts[state] + 1 : 1;
+ }
+
+ // If we do not have any statuses yet, we wait
+ if(Object.keys(filtered_statuses).length == 0 || !hasBuilds) {
+ console.log(`Builds not yet triggered`);
+ return ['pending', 'Builds have not yet been triggered ⌛', summary];
+ }
+
+ const state =
+ counts.error ? 'error' :
+ counts.failure ? 'failure' :
+ counts.pending ? 'pending' :
+ 'success';
+
+ let description = '';
+ function appendDescription(count, state) {
+ if(!count) return;
+ if(description != '') description += '; ';
+ description += `${count} check${count == 1 ? '' : 's'} ${state}`;
+ }
+ appendDescription(counts.error, 'in an error state ❌');
+ appendDescription(counts.failure, 'failed ❌');
+ appendDescription(counts.pending, 'pending ⌛');
+ appendDescription(counts.success, 'completed successfully ✅');
+
+ console.log(`Finished filtering and reviewing status checks: ${state}: ${description}`);
+ return [ state, description, summary ];
+ }
+
+ async function getCommitStatuses(github, owner, repo, sha) {
+ console.log(`Getting commit statuses for ${sha}`);
+ const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/statuses', {
+ owner,
+ repo,
+ sha,
+ headers: {
+ 'X-GitHub-Api-Version': '2022-11-28'
+ }
+ });
+ return statuses;
+ }
+
+ async function getCommitCheckRuns(github, owner, repo, sha) {
+ console.log(`Getting commit check runs for ${sha}`);
+ const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/check-runs', {
+ owner,
+ repo,
+ sha,
+ headers: {
+ 'X-GitHub-Api-Version': '2022-11-28'
+ }
+ });
+ return statuses;
+ }
+
+ function calculateCheckResult(statuses) {
+ if(!Array.isArray(statuses)) {
+ return ['error', 'Failed to retrieve status checks from GitHub ❌', 'statuses is not an array'];
+ }
+
+ const { filtered_statuses, summary } = reduceStatuses(statuses);
+ return calculateFinalStatus(filtered_statuses, summary);
+ }
+
+ async function test(github, owner, repo, sha) {
+ // Get statuses from sha
+ const statuses = await getCommitStatuses(github, owner, repo, sha);
+ return calculateCheckResult(statuses);
+ }
+
+ async function createCheck(github, owner, repo, sha) {
+ const check = await github.rest.checks.create({
+ owner,
+ repo,
+ head_sha: sha,
+ name: 'Build Outcome',
+ status: 'in_progress',
+ });
+ return check.data.id;
+ }
+
+ async function updateCheck(github, owner, repo, checkRunId, status, description, summary) {
+ const checkStatus = status == 'pending' ? 'in_progress' : 'completed';
+ const conclusion = checkStatus == 'in_progress' ? undefined : (status == 'success' ? 'success' : 'failure');
+
+ await github.rest.checks.update({
+ owner,
+ repo,
+ check_run_id: checkRunId,
+ status: checkStatus,
+ conclusion,
+ output: {
+ title: description,
+ summary
+ }
+ });
+ }
+
+ const { owner, repo } = context.repo;
+ const sha =
+ context.payload?.check_suite?.sha || /* check run completed */
+ context.payload?.inputs?.commit || /* manual run */
+ context.payload?.after || /* push */
+ context.payload?.commit?.sha || /* status */
+ context.sha; /* probably 'master'! */
+
+ const checkRunId = await createCheck(github, owner, repo, sha);
+ const res = await test(github, owner, repo, sha);
+ await updateCheck(github, owner, repo, checkRunId, res[0], res[1], res[2]);
+
diff --git a/HISTORY.md b/HISTORY.md
index e553e13395..9361b9a402 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,5 +1,50 @@
# Keyman Version History
+## 19.0.117 alpha 2025-09-11
+
+* fix(resources): ignore KEYMAN_VERSION_FOR_FILENAME in test (#14730)
+* fix(resources): pr build status - find 'failure' state in status checks and log (#14732)
+
+## 19.0.116 alpha 2025-09-10
+
+* fix(windows): kmshell continues when sm is in waitingrestart and returns to idle (#14644)
+* maint(linux): allow to skip API check (#14699)
+* maint(resources): adding GitHub actions workflow for Docker builds (#14674)
+* maint(developer): use versioned filenames for PR artifacts (#14701)
+* maint(windows): use versioned filenames for PR artifacts (#14702)
+* maint(android): use versioned filenames for PR artifacts (#14703)
+* maint(ios): use versioned filenames for PR artifacts (#14704)
+* maint(mac): use versioned filenames for PR artifacts (#14705)
+* maint(resources): rename KEYMAN_VERSION_FOR_PR_FILENAME (#14720)
+
+## 19.0.115 alpha 2025-09-09
+
+* fix(linux): don't crash if `kmp.json` is missing `keyboards` section (#14708)
+
+## 19.0.114 alpha 2025-09-08
+
+* docs(web): Improve empty What's New page for Web (#14660)
+* maint(linux): remove obsolete Makefile (#14694)
+* maint(resources): honor configure comment character in commit message (#14695)
+* fix(web): fix error trying to calculate style scaling effects (#14684)
+* refactor(resources): remove shellcheck warnings (#14698)
+
+## 19.0.113 alpha 2025-09-04
+
+* fix(android): Update KMSample1 layout when changing orientation (#14678)
+
+## 19.0.112 alpha 2025-09-03
+
+* fix(developer): add clear messages about validation failures to New LM Project Parameters form (#14659)
+* docs(developer): tweak get-started for kmc and add entry to HISTORY.md (#14667)
+* fix(android): Cleanup list layout in Engine and FirstVoices for edge to edge (#14655)
+* docs(common): update license date and owner (#14668)
+* maint(linux): skip tarball creation for `Build-bot: build` buildLevel (#14671)
+* docs(common): update docs Keyman Desktop → Keyman for Windows (#14669)
+* feat(web): adds transform cataloging methods to predictive-text worker (#14581)
+* feat(web): batch correction-search paths by related subsets (#14592)
+* refactor(web): simplify edit-distance calculation-object inputs (#14618)
+
## 19.0.111 alpha 2025-09-02
* change(developer): update SIL logo (#14656)
diff --git a/VERSION.md b/VERSION.md
index ee647f65c3..773f715f5c 100644
--- a/VERSION.md
+++ b/VERSION.md
@@ -1 +1 @@
-19.0.112
\ No newline at end of file
+19.0.118
\ No newline at end of file
diff --git a/android/KMAPro/build.sh b/android/KMAPro/build.sh
index 74fed10588..06370c06d2 100755
--- a/android/KMAPro/build.sh
+++ b/android/KMAPro/build.sh
@@ -46,7 +46,7 @@ MODEL_PACKAGE_ID="nrc.en.mtnt"
MODELS_TARGET="android/KMAPro/kMAPro/src/main/assets/${MODEL_PACKAGE_ID}.model.kmp"
builder_describe_outputs \
configure "/${MODELS_TARGET}" \
- build /android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${KEYMAN_VERSION}.apk
+ build /android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${KEYMAN_VERSION_FOR_FILENAME}.apk
#### Build
@@ -77,13 +77,15 @@ if builder_start_action build; then
# Copy Keyman Engine for Android
cp "${KEYMAN_ROOT}/android/KMEA/app/build/outputs/aar/keyman-engine-${CONFIG}.aar" "${KEYMAN_ROOT}/android/KMAPro/kMAPro/libs/keyman-engine.aar"
-
+
# Convert markdown to html for offline help
build_help_html android KMAPro/kMAPro/src/main/assets/info
echo "BUILD_FLAGS $BUILD_FLAGS"
./gradlew $DAEMON_FLAG clean $BUILD_FLAGS
+ mv "${KEYMAN_ROOT}/android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${KEYMAN_VERSION}.apk" "${KEYMAN_ROOT}/android/KMAPro/kMAPro/build/outputs/apk/$CONFIG/keyman-${KEYMAN_VERSION_FOR_FILENAME}.apk"
+
builder_finish_action success build
fi
diff --git a/android/Samples/KMSample1/app/src/main/java/com/keyman/kmsample1/MainActivity.java b/android/Samples/KMSample1/app/src/main/java/com/keyman/kmsample1/MainActivity.java
index 86e1f5af22..add6bc5d63 100644
--- a/android/Samples/KMSample1/app/src/main/java/com/keyman/kmsample1/MainActivity.java
+++ b/android/Samples/KMSample1/app/src/main/java/com/keyman/kmsample1/MainActivity.java
@@ -2,7 +2,9 @@ package com.keyman.kmsample1;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.Point;
import android.os.Bundle;
+import android.util.TypedValue;
import android.view.Menu;
import android.view.MenuItem;
@@ -25,6 +27,7 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
public static Context context;
private ConstraintLayout constraintLayout;
private KMTextView textView;
+ private int lastOrientation = Configuration.ORIENTATION_UNDEFINED;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -99,6 +102,18 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
protected void onResume() {
super.onResume();
KMManager.onResume();
+
+ // onConfigurationChanged() only triggers when device is rotated while app is in foreground
+ // This handles when device is rotated while app is in background
+ // using KMManager.getOrientation() since getConfiguration().orientation is unreliable #10241
+ int newOrientation = KMManager.getOrientation(context);
+ if (newOrientation != lastOrientation) {
+ lastOrientation = newOrientation;
+ Configuration newConfig = this.getResources().getConfiguration();
+ KMManager.onConfigurationChanged(newConfig);
+ }
+ resizeTextView(textView.isKeyboardVisible());
+
KMManager.addKeyboardEventListener(this);
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
}
@@ -116,6 +131,10 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ KMManager.onConfigurationChanged(newConfig);
+
+ resizeTextView(textView.isKeyboardVisible());
+ lastOrientation = newConfig.orientation;
}
@Override
@@ -131,11 +150,44 @@ public class MainActivity extends BaseActivity implements OnKeyboardEventListene
@Override
public void onKeyboardShown() {
// Handle Keyman keyboard shown event here if needed
+ resizeTextView(true);
}
@Override
public void onKeyboardDismissed() {
// Handle Keyman keyboard dismissed event here if needed
+ resizeTextView(false);
+ }
+
+ public void resizeTextView(boolean isKeyboardVisible) {
+ int bannerHeight = 0;
+ int keyboardHeight = 0;
+ if (isKeyboardVisible) {
+ bannerHeight = KMManager.getBannerHeight(this);
+ keyboardHeight = KMManager.getKeyboardHeight(this);
+ }
+
+ TypedValue outValue = new TypedValue();
+ getTheme().resolveAttribute(android.R.attr.actionBarSize, outValue, true);
+ int actionBarHeight = getResources().getDimensionPixelSize(outValue.resourceId);
+
+ // *** TO DO: Try to check if status bar is visible, set statusBarHeight to 0 if it is not visible ***
+ int statusBarHeight = 0;
+ int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceId > 0)
+ statusBarHeight = getResources().getDimensionPixelSize(resourceId);
+
+ // Navigation bar height
+ int navigationBarHeight = 0;
+ resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ navigationBarHeight = getResources().getDimensionPixelSize(resourceId);
+ }
+
+ Point size = KMManager.getWindowSize(context);
+ int screenHeight = size.y;
+ textView.setHeight(
+ screenHeight - statusBarHeight - actionBarHeight - bannerHeight - keyboardHeight - navigationBarHeight);
}
@Override
diff --git a/android/build.sh b/android/build.sh
index 9d48effbf1..54e61dd9a5 100755
--- a/android/build.sh
+++ b/android/build.sh
@@ -62,11 +62,12 @@ function do_test_help() {
function archive_artifacts() {
local UPLOAD_PATH KEYMAN_ENGINE_ANDROID_ZIP KEYMAN_APK FIRSTVOICES_APK
+ local KEYMAN_FULLY_VERSIONED_APK FIRSTVOICES_FULLY_VERSIONED_APK
UPLOAD_PATH="${KEYMAN_ROOT}/android/upload/${KEYMAN_VERSION}"
KEYMAN_ENGINE_ANDROID_ZIP="keyman-engine-android-${KEYMAN_VERSION}.zip"
- KEYMAN_APK="keyman-${KEYMAN_VERSION}.apk"
- FIRSTVOICES_APK="firstvoices-${KEYMAN_VERSION}.apk"
+ KEYMAN_APK="keyman-${KEYMAN_VERSION_FOR_FILENAME}.apk"
+ FIRSTVOICES_APK="firstvoices-${KEYMAN_VERSION_FOR_FILENAME}.apk"
rm -rf "${UPLOAD_PATH}"
mkdir -p "${UPLOAD_PATH}"
@@ -87,12 +88,12 @@ function archive_artifacts() {
)
# Copy release APK
- cp "${KEYMAN_ROOT}/android/KMAPro/kMAPro/build/outputs/apk/release/${KEYMAN_APK}" "${UPLOAD_PATH}"
+ cp "${KEYMAN_ROOT}/android/KMAPro/kMAPro/build/outputs/apk/release/${KEYMAN_APK}" "${UPLOAD_PATH}/${KEYMAN_APK}"
# FirstVoices app
if [[ "${RELEASE_OEM_FIRSTVOICES-false}" = true ]]; then
- cp "${KEYMAN_ROOT}/oem/firstvoices/android/app/build/outputs/apk/release/${FIRSTVOICES_APK}" "${UPLOAD_PATH}"
+ cp "${KEYMAN_ROOT}/oem/firstvoices/android/app/build/outputs/apk/release/${FIRSTVOICES_APK}" "${UPLOAD_PATH}/${FIRSTVOICES_APK}"
fi
#
diff --git a/developer/docs/help/index.md b/developer/docs/help/index.md
index 771bae620c..0b2f452087 100644
--- a/developer/docs/help/index.md
+++ b/developer/docs/help/index.md
@@ -8,7 +8,7 @@ and tutorials, and full reference information.
## Guides and Tutorials
- [What is Keyman Developer?](guides/intro)
-- [What's new in 19.0](whats-new)
+- [What's new in 19.0](whatsnew)
- [Developing Keyman keyboard layouts](guides/develop)
- [Testing Keyman keyboards](guides/test)
- [Distributing Keyman keyboards](guides/distribute)
@@ -35,4 +35,4 @@ and tutorials, and full reference information.
- [Keyman Engine for Windows](/developer/engine/windows/current-version/)
- [Keyman Engine for Web](/developer/engine/web/)
- [Keyman Engine for iPhone and iPad](/developer/engine/iphone-and-ipad/current-version/)
-- [Keyman Engine for Android](/developer/engine/android/current-version/)
\ No newline at end of file
+- [Keyman Engine for Android](/developer/engine/android/current-version/)
diff --git a/developer/docs/help/whats-new.md b/developer/docs/help/whatsnew.md
similarity index 100%
rename from developer/docs/help/whats-new.md
rename to developer/docs/help/whatsnew.md
diff --git a/developer/src/inst/build.sh b/developer/src/inst/build.sh
index 8b37048e1e..5d44f228eb 100755
--- a/developer/src/inst/build.sh
+++ b/developer/src/inst/build.sh
@@ -16,7 +16,7 @@ builder_describe "Installation files for Keyman Developer" \
# after all other builds complete
builder_describe_outputs \
- publish /developer/src/inst/keymandeveloper-${KEYMAN_VERSION}.exe
+ publish /developer/src/inst/keymandeveloper-${KEYMAN_VERSION_FOR_FILENAME}.exe
builder_parse "$@"
@@ -78,7 +78,7 @@ function do_publish() {
# Copy the installation archive
#
- copy-kmdev
+ copy-keymandeveloper-installer-to-artifacts
builder_if_release_build_level verify-installer-signatures
}
@@ -87,8 +87,8 @@ function do_test() {
verify-node-installer-version
}
-function copy-kmdev() {
- builder_heading copy-kmdev
+function copy-keymandeveloper-installer-to-artifacts() {
+ builder_heading copy-keymandeveloper-installer-to-artifacts
mkdir -p "$DEVELOPER_ROOT/release/${KEYMAN_VERSION}"
@@ -96,7 +96,7 @@ function copy-kmdev() {
make-kmc-install-zip
cp -f "$DEVELOPER_ROOT/src/inst/keymandeveloper.msi" "$DEVELOPER_ROOT/release/${KEYMAN_VERSION}/keymandeveloper.msi"
- cp -f "$DEVELOPER_ROOT/src/inst/keymandeveloper-${KEYMAN_VERSION}.exe" "$DEVELOPER_ROOT/release/${KEYMAN_VERSION}/keymandeveloper-${KEYMAN_VERSION}.exe"
+ cp -f "$DEVELOPER_ROOT/src/inst/keymandeveloper-${KEYMAN_VERSION_FOR_FILENAME}.exe" "$DEVELOPER_ROOT/release/${KEYMAN_VERSION}/keymandeveloper-${KEYMAN_VERSION_FOR_FILENAME}.exe"
}
function verify-program-signatures() {
@@ -234,8 +234,8 @@ function make-installer() {
echo "MSIFileName=keymandeveloper.msi" >> setup.inf
echo "Title=Keyman Developer ${KEYMAN_VERSION_WITH_TAG}" >>setup.inf
add_zip_files setup.zip keymandeveloper.msi setup.inf
- cat "$DEVELOPER_PROGRAM/setup.exe" setup.zip > "keymandeveloper-$KEYMAN_VERSION.exe"
- wrap-signcode //d "Keyman Developer" "keymandeveloper-$KEYMAN_VERSION.exe"
+ cat "$DEVELOPER_PROGRAM/setup.exe" setup.zip > "keymandeveloper-$KEYMAN_VERSION_FOR_FILENAME.exe"
+ wrap-signcode //d "Keyman Developer" "keymandeveloper-$KEYMAN_VERSION_FOR_FILENAME.exe"
#
# Zip the files we distribute as part of the standalone kmc distro into release\$Version\kmcomp-$Version.zip
@@ -251,7 +251,7 @@ function make-kmc-install-zip() {
cd "${DEVELOPER_ROOT}/bin"
# TODO: rename this to keyman-developer-cli-$Version.zip
- local KMCOMP_ZIP="${DEVELOPER_ROOT}/release/${KEYMAN_VERSION}/kmcomp-${KEYMAN_VERSION}.zip"
+ local KMCOMP_ZIP="${DEVELOPER_ROOT}/release/${KEYMAN_VERSION}/kmcomp-${KEYMAN_VERSION_FOR_FILENAME}.zip"
add_zip_files "${KMCOMP_ZIP}" -q -r \
kmconvert.exe \
diff --git a/docs/core-api-verification.md b/docs/core-api-verification.md
index fc3e0f629d..0bf266676f 100644
--- a/docs/core-api-verification.md
+++ b/docs/core-api-verification.md
@@ -99,6 +99,17 @@ the API version number in `CORE_API_VERSION.md`. If the API version
numbers in `CORE_API_VERSION.md` and in `libkeymancore.symbols` don't
match the API verification will fail.
+## Skipping the API check
+
+Sometimes we have a PR that intentionally does not change the API version
+number. To skip the API checks in this case, the trailer
+
+```text
+Keyman-Api-Check: skip
+```
+
+can be added to the PR description.
+
## How this works
`.github/workflows/api-verification.yml` contains a `Verify API` step
diff --git a/docs/minimum-versions.md b/docs/minimum-versions.md
index 96b6e820a5..19e0bf4420 100644
--- a/docs/minimum-versions.md
+++ b/docs/minimum-versions.md
@@ -73,6 +73,6 @@ https://help.keyman.com/developer/engine/android/latest-version/
| KEYMAN_VERSION_JAVA | 21 |
| KEYMAN_VERSION_LANGTAGS | 2025-02-18 |
| KEYMAN_VERSION_LANGUAGE_SUBTAG_REGISTRY | 2025-03-10 |
-| KEYMAN_VERSION_UNICODE | 16.0.0 |
+| KEYMAN_VERSION_UNICODE | 17.0.0 |
> ### This file is auto-generated by publish-minimum-versions.sh. Do not modify
diff --git a/ios/tools/prepRelease.sh b/ios/tools/prepRelease.sh
index 28adfbe1ff..8065aad2f8 100755
--- a/ios/tools/prepRelease.sh
+++ b/ios/tools/prepRelease.sh
@@ -29,8 +29,7 @@ fi
. $KEYMAN_ROOT/resources/build/history/history-utils.sh #includes the following
#. ../resources/build/utils.inc.sh
-BUILD_NUMBER=`cat ../VERSION.md`
-KEYMAN_TIER=`cat ../TIER.md`
+BUILD_NUMBER="${KEYMAN_VERSION}"
KEYMAN_CHANGELOG="changelog-${BUILD_NUMBER}-${KEYMAN_TIER}.txt"
CHANGELOG_PATH="upload/$BUILD_NUMBER/$KEYMAN_CHANGELOG"
@@ -59,7 +58,7 @@ mv -f "$CHANGELOG_PATH.1" "$CHANGELOG_PATH"
# Keyman Engine
#
-KMEI_DST_NAME="keyman-engine-ios-${BUILD_NUMBER}.zip"
+KMEI_DST_NAME="keyman-engine-ios-${KEYMAN_VERSION_FOR_FILENAME}.zip"
KMEI_DST="${WORK_DIR}/${UPLOAD_DIR}/${KMEI_DST_NAME}"
KMEI_FRAMEWORK_BASE="build/Build/Products/Release/"
@@ -87,14 +86,14 @@ cd "$WORK_DIR"
#
KEYMANAPP_IPA="build/Build/Products/Release-iphoneos/Keyman.ipa"
-KEYMANAPP_IPA_DST="keyman-ios-${BUILD_NUMBER}.ipa"
+KEYMANAPP_IPA_DST="keyman-ios-${KEYMAN_VERSION_FOR_FILENAME}.ipa"
echo "Copying Keyman IPA ${KEYMANAPP_IPA} => ${UPLOAD_DIR}/${KEYMANAPP_IPA_DST}..."
cp "${KEYMANAPP_IPA}" "${WORK_DIR}/${UPLOAD_DIR}/${KEYMANAPP_IPA_DST}"
KEYMANAPP_SIM_FOLDER="build/Build/Products/Release-iphonesimulator"
KEYMANAPP_SIM_APP="$KEYMANAPP_SIM_FOLDER/Keyman.app"
-KEYMANAPP_SIM_APP_DST="keyman-ios-simulator-${BUILD_NUMBER}.app.zip"
+KEYMANAPP_SIM_APP_DST="keyman-ios-simulator-${KEYMAN_VERSION_FOR_FILENAME}.app.zip"
echo "Zipping Keyman simulator artifact ${KEYMANAPP_SIM_APP} => ${UPLOAD_DIR}/${KEYMANAPP_SIM_APP_DST}..."
cd "${KEYMANAPP_SIM_FOLDER}"
@@ -108,14 +107,14 @@ cd "$WORK_DIR"
if [ "${RELEASE_OEM_FIRSTVOICES}" = true ]; then
FIRSTVOICESAPP_IPA="../oem/firstvoices/ios/build/Build/Products/Release-iphoneos/FirstVoices.ipa"
- FIRSTVOICESAPP_IPA_DST="firstvoices-ios-${BUILD_NUMBER}.ipa"
+ FIRSTVOICESAPP_IPA_DST="firstvoices-ios-${KEYMAN_VERSION_FOR_FILENAME}.ipa"
echo "Copying FirstVoices IPA ${FIRSTVOICESAPP_IPA} => ${UPLOAD_DIR}/${FIRSTVOICESAPP_IPA_DST}..."
cp "${FIRSTVOICESAPP_IPA}" "${WORK_DIR}/${UPLOAD_DIR}/${FIRSTVOICESAPP_IPA_DST}"
FIRSTVOICESAPP_SIM_FOLDER="../oem/firstvoices/ios/build/Build/Products/Release-iphonesimulator/"
FIRSTVOICESAPP_SIM_APP="$FIRSTVOICESAPP_SIM_FOLDER/FirstVoices.app"
- FIRSTVOICESAPP_SIM_APP_DST="firstvoices-ios-simulator-${BUILD_NUMBER}.app.zip"
+ FIRSTVOICESAPP_SIM_APP_DST="firstvoices-ios-simulator-${KEYMAN_VERSION_FOR_FILENAME}.app.zip"
echo "Zipping FirstVoices simulator artifact ${FIRSTVOICESAPP_SIM_APP} => ${UPLOAD_DIR}/${KEYMANAPP_SIM_APP_DST}..."
cd "${FIRSTVOICESAPP_SIM_FOLDER}"
diff --git a/linux/Makefile b/linux/Makefile
deleted file mode 100644
index 0df264e43d..0000000000
--- a/linux/Makefile
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/make
-
-default: # builds only
- BUILDONLY="yes" ./scripts/build.sh
-
-clean:
- rm -rf build-*
-
-reconf: clean
- ./scripts/reconf.sh
-
-configure:
- CONFIGUREONLY="yes" ./scripts/build.sh
-
-fullbuild: # configure and build
- ./scripts/build.sh
-
-tmpinstall: reconf
- INSTALLDIR="/tmp/keyman" ./scripts/build.sh
- INSTALLDIR="/tmp/keyman" ./scripts/install.sh
-
-install: # run as sudo
- SUDOINSTALL="yes" ./scripts/install.sh
-
-uninstall: # run as sudo
- SUDOINSTALL="uninstall" ./scripts/install.sh
-
-sources:
- ./scripts/dist.sh
-
-tmpsources:
- PKG_CONFIG_PATH="../../core/build/arch/release/meson-private" ./scripts/dist.sh
-
-origdist:
- ./scripts/dist.sh origdist
-
-sourcepackage: reconf origdist
- ./scripts/deb.sh
-
-nightlydist: reconf sources
- echo "Built nightly source release in dist/"
-
-check:
- cd keyman-config && ./run-tests.sh
- cd ibus-keyman && ./build.sh test
-
-tmpcheck: check
-
-tests: check
diff --git a/linux/keyman-config/keyman_config/install_kmp.py b/linux/keyman-config/keyman_config/install_kmp.py
index cb69d596af..8b47ed7857 100755
--- a/linux/keyman-config/keyman_config/install_kmp.py
+++ b/linux/keyman-config/keyman_config/install_kmp.py
@@ -178,9 +178,9 @@ class InstallKmp():
logging.info("Converting %s to LDML and installing both as as keyman file",
f['name'])
name, ext = os.path.splitext(f['name'])
- ldml = convert_kvk_to_ldml(name, fpath)
- ldmlfile = os.path.join(self.packageDir, f"{name}.ldml")
- output_ldml(ldmlfile, ldml)
+ if ldml := convert_kvk_to_ldml(name, fpath):
+ ldmlfile = os.path.join(self.packageDir, f"{name}.ldml")
+ output_ldml(ldmlfile, ldml)
elif ftype == KMFileTypes.KM_ICON:
# Special handling of icon to convert to PNG
logging.info("Converting %s to PNG and installing both as keyman files",
diff --git a/linux/keyman-config/keyman_config/kvk2ldml.py b/linux/keyman-config/keyman_config/kvk2ldml.py
index ddef89241a..35f5bcd908 100755
--- a/linux/keyman-config/keyman_config/kvk2ldml.py
+++ b/linux/keyman-config/keyman_config/kvk2ldml.py
@@ -366,14 +366,17 @@ def convert_ldml(keyboardName, kvkData, kmpJsonFilename):
info, system, options, keyboards, files = parsemetadata(kmpJsonFilename)
+ if not keyboards:
+ return None
+
ldml = etree.Element("keyboard", locale="zzz-keyman")
+
for keyboard in keyboards:
if keyboard['id'] != keyboardName:
continue
if 'oskFont' in keyboard:
fontFile = os.path.join(os.path.dirname(kmpJsonFilename), keyboard['oskFont'])
- font = _fontFacename(fontFile)
- if font:
+ if font := _fontFacename(fontFile):
ldml.set('keymanFacename', font)
break
diff --git a/linux/keyman-config/tests/kvk2ldml_tests.py b/linux/keyman-config/tests/kvk2ldml_tests.py
index fc8a34c28b..4bb9c337c0 100644
--- a/linux/keyman-config/tests/kvk2ldml_tests.py
+++ b/linux/keyman-config/tests/kvk2ldml_tests.py
@@ -8,31 +8,34 @@ import unittest
from keyman_config.kvk2ldml import KVKData, NFont, convert_ldml
class Kvk2LdmlTests(unittest.TestCase):
- def _createKmpJson(self, packagedir):
+ def _createKmpJson(self, packagedir, add_keyboards=True):
kmpJsonFilename = os.path.join(packagedir, 'kmp.json')
+ system = '''"system": {
+ "keymanDeveloperVersion": "18.0",
+ "fileVersion": "7.0"
+ }'''
+ files = '''"files": [ {
+ "name": "khmer_angkor.kmx",
+ "description": "Keyboard Khmer Angkor"
+ }, {
+ "name": "kmp.json",
+ "description": "Package information (JSON)"
+ } ]'''
+ if add_keyboards:
+ keyboards = '''"keyboards": [ {
+ "name": "Khmer Angkor",
+ "id": "khmer_angkor",
+ "version": "1.5",
+ "oskFont": "keymanweb-osk.ttf",
+ "languages": [ {
+ "name": "Central Khmer (Khmer, Cambodia)",
+ "id": "km"
+ } ]}
+ ]'''
+ else:
+ keyboards = ''
with open(kmpJsonFilename, 'w') as file:
- file.write('''{
- "system": {
- "keymanDeveloperVersion": "18.0",
- "fileVersion": "7.0"
- },
- "files": [ {
- "name": "khmer_angkor.kmx",
- "description": "Keyboard Khmer Angkor"
- }, {
- "name": "kmp.json",
- "description": "Package information (JSON)"
- } ],
- "keyboards": [ {
- "name": "Khmer Angkor",
- "id": "khmer_angkor",
- "version": "1.5",
- "oskFont": "keymanweb-osk.ttf",
- "languages": [ {
- "name": "Central Khmer (Khmer, Cambodia)",
- "id": "km"
- } ]}
- ]}''')
+ file.write(f'{{ {system}, {files}, {keyboards} }}')
return kmpJsonFilename
def test_convert_ldml__adds_keymanFacename(self):
@@ -56,3 +59,20 @@ class Kvk2LdmlTests(unittest.TestCase):
self.assertEqual(ldml.get('keymanFacename'), 'SymChar')
workdir.cleanup()
+
+ def test_convert_ldml__no_crash_without_keyboards(self):
+ # Setup
+ keyboardName = 'khmer_angkor'
+ kvkData = KVKData()
+ kvkData.AssociatedKeyboard = keyboardName
+
+ workdir = tempfile.TemporaryDirectory()
+ kmpJsonFilename = self._createKmpJson(workdir.name, add_keyboards=False)
+
+ # Execute
+ ldml = convert_ldml(keyboardName, kvkData, kmpJsonFilename)
+
+ # Verify
+ self.assertIsNone(ldml)
+
+ workdir.cleanup()
diff --git a/mac/Keyman4MacIM/make-km-dmg.sh b/mac/Keyman4MacIM/make-km-dmg.sh
index 0ee1d7395b..d949a96af3 100755
--- a/mac/Keyman4MacIM/make-km-dmg.sh
+++ b/mac/Keyman4MacIM/make-km-dmg.sh
@@ -212,7 +212,7 @@ if (( DETACH_SUCCESS < 999 )); then
fi
# Step 5 - Convert image to a compressed readonly DMG image
-DMG_FILE_PATH="$DEST_DIR/keyman-$KEYMAN_VERSION.dmg"
+DMG_FILE_PATH="$DEST_DIR/keyman-$KEYMAN_VERSION_FOR_FILENAME.dmg"
builder_echo info "Converting/compressing image to create \"$DMG_FILE_PATH\""
if [[ -e "$DMG_FILE_PATH" ]] ; then
if [[ "$VERBOSITY" != "-quiet" ]] ; then
diff --git a/mac/build.sh b/mac/build.sh
index 875e4b5013..e032db998a 100755
--- a/mac/build.sh
+++ b/mac/build.sh
@@ -293,7 +293,7 @@ do_publish() {
"${KM4MIM_BASE_PATH}/make-km-dmg.sh"
local UPLOAD_PATH="${KM4MIM_BASE_PATH}/output/upload/${KEYMAN_VERSION}"
- write_download_info "${UPLOAD_PATH}" "keyman-${KEYMAN_VERSION}.dmg" "Keyman4MacIM" dmg mac
+ write_download_info "${UPLOAD_PATH}" "keyman-${KEYMAN_VERSION_FOR_FILENAME}.dmg" "Keyman4MacIM" dmg mac
if builder_is_ci_build && builder_is_ci_build_level_release; then
do_sentry
diff --git a/oem/firstvoices/android/build.sh b/oem/firstvoices/android/build.sh
index 00de2d98ec..2d8d30141f 100755
--- a/oem/firstvoices/android/build.sh
+++ b/oem/firstvoices/android/build.sh
@@ -38,7 +38,7 @@ if builder_is_debug_build; then
TEST_FLAGS="-x assembleDebug lintDebug testDebug"
fi
-ARTIFACT="firstvoices-$KEYMAN_VERSION.apk"
+ARTIFACT="firstvoices-${KEYMAN_VERSION_FOR_FILENAME}.apk"
KEYBOARD_PACKAGE_ID="fv_all"
KEYBOARDS_TARGET="oem/firstvoices/android/app/src/main/assets/${KEYBOARD_PACKAGE_ID}.kmp"
@@ -76,6 +76,8 @@ if builder_start_action build; then
echo "BUILD_FLAGS: $BUILD_FLAGS"
./gradlew $DAEMON_FLAG clean $BUILD_FLAGS
+ mv "${KEYMAN_ROOT}/oem/firstvoices/android/app/build/outputs/apk/$CONFIG/firstvoices-${KEYMAN_VERSION}.apk" "${KEYMAN_ROOT}/oem/firstvoices/android/app/build/outputs/apk/$CONFIG/${ARTIFACT}"
+
builder_finish_action success build
fi
diff --git a/oem/firstvoices/windows/src/inst/build.sh b/oem/firstvoices/windows/src/inst/build.sh
index ac245b72aa..cad414d39b 100755
--- a/oem/firstvoices/windows/src/inst/build.sh
+++ b/oem/firstvoices/windows/src/inst/build.sh
@@ -16,7 +16,7 @@ builder_describe "Installation files for FirstVoices Keyboards" \
# after all other builds complete
builder_if_release_build_level builder_describe_outputs \
- publish /windows/release/${KEYMAN_VERSION}/firstvoices-${KEYMAN_VERSION}.exe
+ publish /windows/release/${KEYMAN_VERSION}/firstvoices-${KEYMAN_VERSION_FOR_FILENAME}.exe
builder_parse "$@"
@@ -103,7 +103,7 @@ function copy-installer() {
mkdir -p "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}"
cp firstvoices.msi "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/firstvoices.msi"
- cp firstvoices.exe "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/firstvoices-${KEYMAN_VERSION}.exe"
+ cp firstvoices.exe "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/firstvoices-${KEYMAN_VERSION_FOR_FILENAME}.exe"
verify-installer-signatures
}
diff --git a/resources/build/builder-basic.inc.sh b/resources/build/builder-basic.inc.sh
index 83f77c3134..94441617b2 100644
--- a/resources/build/builder-basic.inc.sh
+++ b/resources/build/builder-basic.inc.sh
@@ -13,6 +13,7 @@
# KEYMAN_VERSION_GIT_TAG: Git tag for the release, "release@$KEYMAN_VERSION_WITH_TAG", e.g. "release@14.0.1-alpha-test-1234"
# KEYMAN_ROOT: fully resolved root path of Keyman repository
# KEYMAN_VERSION_ENVIRONMENT: One of: local, test, alpha, beta, stable
+# KEYMAN_VERSION_FOR_FILENAME: KEYMAN_VERSION, for release builds, or KEYMAN_VERSION_WITH_TAG, for PR and local builds; see #10521
# UPLOAD_SENTRY: true - if KEYMAN_VERSION_ENVIRONMENT is one of alpha, beta, stable
# false - if local, test. Indicates if debug artifacts should be uploaded to Sentry
# BUILDER_OS: win|mac|linux -- current build environment
@@ -115,6 +116,16 @@ function _builder_basic_find_version() {
KEYMAN_VERSION_WITH_TAG="$KEYMAN_VERSION$KEYMAN_VERSION_TAG"
KEYMAN_VERSION_GIT_TAG="release@$KEYMAN_VERSION_WITH_TAG"
+ # For local builds, and for PR builds, we will use a filename including the tag
+ # but for release builds, we omit the tag for now. In the future, we may include
+ # the tag but that involves changing a number of other websites as dealing with
+ # the rename there too.
+ if builder_is_ci_release_build; then
+ KEYMAN_VERSION_FOR_FILENAME="${KEYMAN_VERSION}"
+ else
+ KEYMAN_VERSION_FOR_FILENAME="${KEYMAN_VERSION_WITH_TAG}"
+ fi
+
readonly KEYMAN_VERSION
readonly KEYMAN_VERSION_MAJOR
readonly KEYMAN_VERSION_MINOR
@@ -125,6 +136,7 @@ function _builder_basic_find_version() {
readonly KEYMAN_VERSION_WITH_TAG
readonly KEYMAN_VERSION_ENVIRONMENT
readonly KEYMAN_VERSION_GIT_TAG
+ readonly KEYMAN_VERSION_FOR_FILENAME
# Export version strings so places like version.gradle can access them
export KEYMAN_VERSION
@@ -137,6 +149,7 @@ function _builder_basic_find_version() {
export KEYMAN_VERSION_WITH_TAG
export KEYMAN_VERSION_ENVIRONMENT
export KEYMAN_VERSION_GIT_TAG
+ export KEYMAN_VERSION_FOR_FILENAME
}
function _builder_basic_find_tier() {
@@ -163,18 +176,19 @@ function _builder_basic_print_build_number_for_teamcity() {
}
function _builder_basic_print_version_utils_debug() {
- echo "KEYMAN_ROOT: $KEYMAN_ROOT"
- echo "KEYMAN_VERSION: $KEYMAN_VERSION"
- echo "KEYMAN_VERSION_WIN: $KEYMAN_VERSION_WIN"
- echo "KEYMAN_VERSION_RELEASE: $KEYMAN_VERSION_RELEASE"
- echo "KEYMAN_VERSION_MAJOR: $KEYMAN_VERSION_MAJOR"
- echo "KEYMAN_VERSION_MINOR: $KEYMAN_VERSION_MINOR"
- echo "KEYMAN_VERSION_PATCH: $KEYMAN_VERSION_PATCH"
- echo "KEYMAN_TIER: $KEYMAN_TIER"
- echo "KEYMAN_VERSION_TAG: $KEYMAN_VERSION_TAG"
- echo "KEYMAN_VERSION_WITH_TAG: $KEYMAN_VERSION_WITH_TAG"
- echo "KEYMAN_VERSION_GIT_TAG: $KEYMAN_VERSION_GIT_TAG"
- echo "KEYMAN_VERSION_ENVIRONMENT: $KEYMAN_VERSION_ENVIRONMENT"
+ echo "KEYMAN_ROOT: $KEYMAN_ROOT"
+ echo "KEYMAN_VERSION: $KEYMAN_VERSION"
+ echo "KEYMAN_VERSION_WIN: $KEYMAN_VERSION_WIN"
+ echo "KEYMAN_VERSION_RELEASE: $KEYMAN_VERSION_RELEASE"
+ echo "KEYMAN_VERSION_MAJOR: $KEYMAN_VERSION_MAJOR"
+ echo "KEYMAN_VERSION_MINOR: $KEYMAN_VERSION_MINOR"
+ echo "KEYMAN_VERSION_PATCH: $KEYMAN_VERSION_PATCH"
+ echo "KEYMAN_TIER: $KEYMAN_TIER"
+ echo "KEYMAN_VERSION_TAG: $KEYMAN_VERSION_TAG"
+ echo "KEYMAN_VERSION_WITH_TAG: $KEYMAN_VERSION_WITH_TAG"
+ echo "KEYMAN_VERSION_GIT_TAG: $KEYMAN_VERSION_GIT_TAG"
+ echo "KEYMAN_VERSION_ENVIRONMENT: $KEYMAN_VERSION_ENVIRONMENT"
+ echo "KEYMAN_VERSION_FOR_FILENAME: $KEYMAN_VERSION_FOR_FILENAME"
}
# TODO: consolidate with buildLevel, see #14285
@@ -209,6 +223,7 @@ replaceVersionStrings() {
s/\$KEYMAN_VERSION_GIT_TAG/$KEYMAN_VERSION_GIT_TAG/g;
s/\$KEYMAN_VERSION_ENVIRONMENT/$KEYMAN_VERSION_ENVIRONMENT/g;
s/\$KEYMAN_VERSION/$KEYMAN_VERSION/g;
+ s/\$KEYMAN_VERSION_FOR_FILENAME/$KEYMAN_VERSION_FOR_FILENAME/g;
" "$infile" > "$outfile"
}
@@ -249,6 +264,7 @@ replaceVersionStrings_Mkver() {
s/\$KEYMAN_VERSION_WITH_TAG/$KEYMAN_VERSION_WITH_TAG/g;
s/\$KEYMAN_VERSION_GIT_TAG/$KEYMAN_VERSION_GIT_TAG/g;
s/\$KEYMAN_VERSION_ENVIRONMENT/$KEYMAN_VERSION_ENVIRONMENT/g;
+ s/\$KEYMAN_VERSION_FOR_FILENAME/$KEYMAN_VERSION_FOR_FILENAME/g;
s/\$KEYMAN_VERSION/$KEYMAN_VERSION_WIN/g;
diff --git a/resources/build/ci/trigger-build-bot.inc.sh b/resources/build/ci/trigger-build-bot.inc.sh
index f7cdc815f8..d9fd38294f 100644
--- a/resources/build/ci/trigger-build-bot.inc.sh
+++ b/resources/build/ci/trigger-build-bot.inc.sh
@@ -39,6 +39,34 @@ function test_bot_check_pr_body() {
fi
}
+#
+# Check the Keyman-Api-Check command whether or not to run API checks.
+# Any value other than 'skip' or no Keyman-Api-Check command will run
+# the API checks.
+#
+# Parameters:
+# 1: PR number (not currently used)
+# 2: PR JSON data from api.github.com/repos/keymanapp/keyman/pulls/#
+#
+function is_skip_keyman_api_check() {
+ local PRNUM=$1
+ local prinfo="$2"
+ local prbody prApiCheck
+
+ set -o noglob
+ IFS=$'\n'
+ prbody="$(echo "${prinfo}" | "${JQ}" -r '.body')"
+ prApiCheck="$(echo -e "${prbody}" | grep '^Keyman-Api-Check:' | cut -d: -f 2 - | tr -d '[:space:]')"
+ unset IFS
+ set +o noglob
+
+ if [[ "${prApiCheck}" == "skip" ]]; then
+ echo "true"
+ else
+ echo "false"
+ fi
+}
+
#
# Check PR commit messages for Build-bot commands. Later commands override
# earlier ones. Also checks PR body for any overriding commands. Note, only
diff --git a/resources/build/ci/trigger-builds.inc.sh b/resources/build/ci/trigger-builds.inc.sh
index 0d54971b15..d1110a19a1 100644
--- a/resources/build/ci/trigger-builds.inc.sh
+++ b/resources/build/ci/trigger-builds.inc.sh
@@ -84,31 +84,34 @@ function triggerTeamCityBuild() {
# 2: 'skip' - don't run build; 'build' - run build and unit tests; 'test' - run build, unit tests, and deploy
# 3: Action name
# 4: branch name in git
+# 5: 'true' to skip API checks, 'false' to run them (optional, default 'false')
#
function triggerGitHubActionsBuild() {
local IS_TEST_BUILD="$1"
local BUILD_LEVEL="$2"
local GITHUB_ACTION="$3"
local GIT_BRANCH="$4"
+ local SKIP_API_CHECK="${5:-"false"}"
local GIT_BASE_BRANCH="${GIT_BRANCH}"
local GIT_USER="keyman-server"
local GIT_BUILD_SHA GIT_BASE_REF JSON
local GITHUB_SERVER=https://api.github.com/repos/keymanapp/keyman
- if [ "${action:-""}" == "commit" ]; then
+ if [[ "${action:-""}" == "commit" ]]; then
# This will only be true if we created and pushed a tag
- GIT_BUILD_SHA="$(git rev-parse "refs/tags/release@$KEYMAN_VERSION_WITH_TAG")"
+ GIT_BUILD_SHA="$(git rev-parse "refs/tags/release@${KEYMAN_VERSION_WITH_TAG}")"
GIT_BASE_REF="$(git rev-parse "${GIT_BUILD_SHA}^")"
GIT_EVENT_TYPE="${GITHUB_ACTION}: release@${KEYMAN_VERSION_WITH_TAG}"
- elif [[ $GIT_BRANCH =~ ^[0-9]+$ ]]; then
+ elif [[ ${GIT_BRANCH} =~ ^[0-9]+$ ]]; then
# pull request
- local JSON=$(call_curl "${GITHUB_SERVER}/pulls/${GIT_BRANCH}" --header "Authorization: token $GITHUB_TOKEN")
- GIT_BUILD_SHA="$(echo "$JSON" | $JQ -r '.head.sha')"
+ local JSON
+ JSON=$(call_curl "${GITHUB_SERVER}/pulls/${GIT_BRANCH}" --header "Authorization: token ${GITHUB_TOKEN}")
+ GIT_BUILD_SHA="$(echo "${JSON}" | ${JQ} -r '.head.sha')"
GIT_EVENT_TYPE="${GITHUB_ACTION}: PR #${GIT_BRANCH}"
- GIT_USER="$(echo "$JSON" | $JQ -r '.user.login')"
- GIT_BASE_BRANCH="$(echo "$JSON" | $JQ -r '.base.ref')"
- GIT_BASE_REF="$(echo "$JSON" | $JQ -r '.base.sha')"
+ GIT_USER="$(echo "${JSON}" | ${JQ} -r '.user.login')"
+ GIT_BASE_BRANCH="$(echo "${JSON}" | ${JQ} -r '.base.ref')"
+ GIT_BASE_REF="$(echo "${JSON}" | ${JQ} -r '.base.sha')"
GIT_BRANCH="PR-${GIT_BRANCH}"
else
# another branch: stable-x.y, beta, or master
@@ -118,20 +121,21 @@ function triggerGitHubActionsBuild() {
fi
local DATA="{
- \"event_type\": \"$GIT_EVENT_TYPE\", \
+ \"event_type\": \"${GIT_EVENT_TYPE}\", \
\"client_payload\": { \
- \"buildSha\": \"$GIT_BUILD_SHA\", \
- \"branch\": \"$GIT_BRANCH\", \
- \"baseBranch\": \"$GIT_BASE_BRANCH\", \
- \"baseRef\": \"$GIT_BASE_REF\", \
- \"user\": \"$GIT_USER\", \
- \"isTestBuild\": \"$IS_TEST_BUILD\", \
- \"buildLevel\": \"$BUILD_LEVEL\" \
+ \"buildSha\": \"${GIT_BUILD_SHA}\", \
+ \"branch\": \"${GIT_BRANCH}\", \
+ \"baseBranch\": \"${GIT_BASE_BRANCH}\", \
+ \"baseRef\": \"${GIT_BASE_REF}\", \
+ \"user\": \"${GIT_USER}\", \
+ \"isTestBuild\": \"${IS_TEST_BUILD}\", \
+ \"buildLevel\": \"${BUILD_LEVEL}\", \
+ \"skipApiCheck\": \"${SKIP_API_CHECK}\" \
}}"
- echo "GitHub Action Data: $DATA"
+ echo "GitHub Action Data: ${DATA}"
- if [[ "$GIT_BUILD_SHA" == null ]]; then
+ if [[ "${GIT_BUILD_SHA}" == null ]]; then
echo "Invalid GIT_BUILD_SHA"
exit 1
fi
@@ -141,8 +145,8 @@ function triggerGitHubActionsBuild() {
call_curl "${GITHUB_SERVER}/dispatches" \
--request POST \
--header "Accept: application/vnd.github+json" \
- --header "Authorization: token $GITHUB_TOKEN" \
- --data "$DATA"
+ --header "Authorization: token ${GITHUB_TOKEN}" \
+ --data "${DATA}"
echo
}
@@ -157,31 +161,32 @@ function call_curl() {
local curl_result
local http_code
- local output_file=$(mktemp)
+ local output_file
+ output_file=$(mktemp)
set +e
if [[ $# -gt 0 ]]; then
- http_code=$(curl --silent --output $output_file --no-progress-meter --write-out "%{http_code}" "$@" "$url")
+ http_code=$(curl --silent --output "${output_file}" --no-progress-meter --write-out "%{http_code}" "$@" "${url}")
else
- http_code=$(curl --silent --output $output_file --no-progress-meter --write-out "%{http_code}" "$url")
+ http_code=$(curl --silent --output "${output_file}" --no-progress-meter --write-out "%{http_code}" "${url}")
fi
curl_result=$?
if [[ ${curl_result} != 0 ]]; then
echo "curl call to '${url}' failed with code '${curl_result}'" >& 2
- >&2 cat $output_file
- rm -f $output_file
- exit $curl_result
+ >&2 cat "${output_file}"
+ rm -f "${output_file}"
+ exit ${curl_result}
fi
if [[ ${http_code} -lt 200 || ${http_code} -gt 299 ]] ; then
echo "curl call to '${url}' failed with HTTP error code '${http_code}'" >& 2
- >&2 cat $output_file
- rm -f $output_file
+ >&2 cat "${output_file}"
+ rm -f "${output_file}"
exit 22
fi
set -e
- cat $output_file
- rm -f $output_file
+ cat "${output_file}"
+ rm -f "${output_file}"
}
diff --git a/resources/build/ci/trigger-definitions.inc.sh b/resources/build/ci/trigger-definitions.inc.sh
index 74380e7311..0666e05487 100644
--- a/resources/build/ci/trigger-definitions.inc.sh
+++ b/resources/build/ci/trigger-definitions.inc.sh
@@ -112,7 +112,7 @@ vcs_test=HttpsGithubComKeymanappKeymanPRs
bc_master_android=(KeymanAndroid_Build)
bc_master_ios=(Keyman_iOS_Master)
-bc_master_linux=(KeymanLinux_Master deb-release-packaging_GitHub)
+bc_master_linux=(KeymanLinux_Master deb-release-packaging_GitHub build-test-publish-docker_GitHub)
bc_master_mac=(KeymanMac_Master)
bc_master_windows=(Keyman_Build)
bc_master_web=(Keymanweb_Build)
diff --git a/resources/build/minimum-versions.inc.sh b/resources/build/minimum-versions.inc.sh
index 5bcbf3cc12..8320c80954 100644
--- a/resources/build/minimum-versions.inc.sh
+++ b/resources/build/minimum-versions.inc.sh
@@ -3,7 +3,7 @@
# This is a list of minimum, maximum, and specific versions of any external
# components or dependencies found in Keyman.
#
-# Original (outdated) reference
+# Original (outdated) reference
# https://docs.google.com/document/d/1Uy3U2YXeA4rCEbUbT7O6QzUGJDZBeViFecL8fjUOLkE/edit?usp=sharing
# NOTE: After changing any values, you should run publish-minimum-versions.sh.
@@ -50,4 +50,4 @@ KEYMAN_VERSION_CLDR=46 # LDML Keyboards version
KEYMAN_VERSION_ISO639_3=2024-05-22 # Date of last import
KEYMAN_VERSION_LANGTAGS=2025-02-18 # _version value
KEYMAN_VERSION_LANGUAGE_SUBTAG_REGISTRY=2025-03-10 # Date from first line of language-subtag-registry
-KEYMAN_VERSION_UNICODE=16.0.0 # UCD + related data
+KEYMAN_VERSION_UNICODE=17.0.0 # UCD + related data
diff --git a/resources/build/pr-build-status/build.sh b/resources/build/pr-build-status/build.sh
index ca87de813d..42683bc3bc 100755
--- a/resources/build/pr-build-status/build.sh
+++ b/resources/build/pr-build-status/build.sh
@@ -19,7 +19,7 @@ function do_build() {
local YML_PREFIX=$(cat "$YML_PREFIX_FILE")
local SCRIPT_CLONE=$(sed -n '/CLONE:START/,/CLONE:END/{//!p}' < "$MJS_FILE")
local SCRIPT_SUFFIX=$(sed -n '/CLONE-COMMENTED:START/,/CLONE-COMMENTED:END/{//!p}' < "$MJS_FILE" | sed 's/\/\/ //g')
- echo -e "# GENERATED FILE - DO NOT EDIT!\n$YML_PREFIX\n$SCRIPT_CLONE\n$SCRIPT_SUFFIX\n" > "$YML_FILE"
+ echo $'# GENERATED FILE - DO NOT EDIT!\n'"$YML_PREFIX"$'\n'"$SCRIPT_CLONE"$'\n'"$SCRIPT_SUFFIX"$'\n' > "$YML_FILE"
}
builder_run_action build do_build
diff --git a/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-check-runs.json b/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-check-runs.json
new file mode 100644
index 0000000000..2544408133
--- /dev/null
+++ b/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-check-runs.json
@@ -0,0 +1,660 @@
+[
+ {
+ "id": 50109411782,
+ "name": "Build Outcome",
+ "node_id": "CR_kwDOAY2xT88AAAALqsDxxg",
+ "head_sha": "390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "external_id": "",
+ "url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50109411782",
+ "html_url": "https://github.com/keymanapp/keyman/runs/50109411782",
+ "details_url": "https://github.com/keymanapp/keyman/runs/50109411782",
+ "status": "completed",
+ "conclusion": "success",
+ "started_at": "2025-09-11T05:29:44Z",
+ "completed_at": "2025-09-11T05:29:45Z",
+ "output": {
+ "title": "21 checks completed successfully ✅",
+ "summary": "",
+ "text": null,
+ "annotations_count": 0,
+ "annotations_url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50109411782/annotations"
+ },
+ "check_suite": {
+ "id": 45240794914
+ },
+ "app": {
+ "id": 15368,
+ "client_id": "Iv1.05c79e9ad1f6bdfa",
+ "slug": "github-actions",
+ "node_id": "MDM6QXBwMTUzNjg=",
+ "owner": {
+ "login": "github",
+ "id": 9919,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github",
+ "html_url": "https://github.com/github",
+ "followers_url": "https://api.github.com/users/github/followers",
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
+ "organizations_url": "https://api.github.com/users/github/orgs",
+ "repos_url": "https://api.github.com/users/github/repos",
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github/received_events",
+ "type": "Organization",
+ "user_view_type": "public",
+ "site_admin": false
+ },
+ "name": "GitHub Actions",
+ "description": "Automate your workflow from idea to production",
+ "external_url": "https://help.github.com/en/actions",
+ "html_url": "https://github.com/apps/github-actions",
+ "created_at": "2018-07-30T09:30:17Z",
+ "updated_at": "2025-03-07T16:35:00Z",
+ "permissions": {
+ "actions": "write",
+ "administration": "read",
+ "attestations": "write",
+ "checks": "write",
+ "contents": "write",
+ "deployments": "write",
+ "discussions": "write",
+ "issues": "write",
+ "merge_queues": "write",
+ "metadata": "read",
+ "models": "read",
+ "packages": "write",
+ "pages": "write",
+ "pull_requests": "write",
+ "repository_hooks": "write",
+ "repository_projects": "write",
+ "security_events": "write",
+ "statuses": "write",
+ "vulnerability_alerts": "read"
+ },
+ "events": [
+ "branch_protection_rule",
+ "check_run",
+ "check_suite",
+ "create",
+ "delete",
+ "deployment",
+ "deployment_status",
+ "discussion",
+ "discussion_comment",
+ "fork",
+ "gollum",
+ "issues",
+ "issue_comment",
+ "label",
+ "merge_group",
+ "milestone",
+ "page_build",
+ "project",
+ "project_card",
+ "project_column",
+ "public",
+ "pull_request",
+ "pull_request_review",
+ "pull_request_review_comment",
+ "push",
+ "registry_package",
+ "release",
+ "repository",
+ "repository_dispatch",
+ "status",
+ "watch",
+ "workflow_dispatch",
+ "workflow_run"
+ ]
+ },
+ "pull_requests": [
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/pulls/14728",
+ "id": 2817549354,
+ "number": 14728,
+ "head": {
+ "ref": "chore/common/unicode-17",
+ "sha": "ebeacc83d0b5cfd7ab523874631e5740721f1f2f",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ },
+ "base": {
+ "ref": "master",
+ "sha": "898cd340a33f29b766b08da66a519be7e3d79fe6",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "id": 50107239504,
+ "name": "GitGuardian Security Checks",
+ "node_id": "CR_kwDOAY2xT88AAAALqp_MUA",
+ "head_sha": "390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "external_id": "",
+ "url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107239504",
+ "html_url": "https://github.com/keymanapp/keyman/runs/50107239504",
+ "details_url": "https://dashboard.gitguardian.com",
+ "status": "completed",
+ "conclusion": "success",
+ "started_at": "2025-09-11T04:38:47Z",
+ "completed_at": "2025-09-11T04:38:48Z",
+ "output": {
+ "title": "No secrets detected ✅",
+ "summary": "**2** commits were scanned without uncovering any secrets.\n",
+ "text": "Commits scanned: **2**\n\n\n\n- Pull request #14728: `chore/common/unicode-17` 👉 `master`\n \n\n🦉 [GitGuardian](https://dashboard.gitguardian.com/auth/login/?utm_medium=checkruns&utm_source=github&utm_campaign=cr1) detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
\n",
+ "annotations_count": 0,
+ "annotations_url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107239504/annotations"
+ },
+ "check_suite": {
+ "id": 45240794052
+ },
+ "app": {
+ "id": 46505,
+ "client_id": "Iv1.ec3c001966b4cc5a",
+ "slug": "gitguardian",
+ "node_id": "MDM6QXBwNDY1MDU=",
+ "owner": {
+ "login": "GitGuardian",
+ "id": 27360172,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjI3MzYwMTcy",
+ "avatar_url": "https://avatars.githubusercontent.com/u/27360172?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/GitGuardian",
+ "html_url": "https://github.com/GitGuardian",
+ "followers_url": "https://api.github.com/users/GitGuardian/followers",
+ "following_url": "https://api.github.com/users/GitGuardian/following{/other_user}",
+ "gists_url": "https://api.github.com/users/GitGuardian/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/GitGuardian/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/GitGuardian/subscriptions",
+ "organizations_url": "https://api.github.com/users/GitGuardian/orgs",
+ "repos_url": "https://api.github.com/users/GitGuardian/repos",
+ "events_url": "https://api.github.com/users/GitGuardian/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/GitGuardian/received_events",
+ "type": "Organization",
+ "user_view_type": "public",
+ "site_admin": false
+ },
+ "name": "GitGuardian",
+ "description": "# 🦉 What is GitGuardian?\r\n\r\nGitGuardian Secrets Detection detects and fixes vulnerabilities in source code at every step of the software development lifecycle, covering 350+ types of secrets like API keys, database connection strings, private keys, certificates, and more. The platform’s policy engine enables security teams to monitor and enforce rules across their VCS, DevOps tools, and infrastructure-as-code configurations. Our automated remediation playbooks and collaboration features bring security and development teams together to resolve incidents fast and in full.\r\n\r\n## 1. Scan your codebase for 350+ types of secrets\r\nGitGuardian scans your GitHub repositories and raises alerts only for critical secrets, such as API keys or other credentials. At scale, GitGuardian’s detection algorithm has been battle-tested on over three years of activity in all public GitHub repositories – totaling over 1 billion scanned commits!\r\n\r\n## 2. Quickly remediate your hard-coded secrets\r\nIf you ever experience a leak involving a credential, we have a complete remediation guide used by 100k+ developers each year. We’ll show you how to revoke the secret and remove it from your git history.\r\n\r\n## 3. Prevent secrets from reaching GitHub\r\nInstall ggshield, the GitGuardian CLI, and add secrets detection to your local development workflow using pre-commit and pre-push git hooks integrations.\r\n\r\n# 🙋♂️ FAQ\r\n\r\n**What is your pricing?**\r\nGitGuardian is free for teams under 25 developers and offers a 30-day trial for larger teams.\r\n\r\n**How can I be sure that GitGuardian won’t raise too many false positives?**\r\nWe have scanned billions of commits, sent millions of alerts since 2018, and integrated each feedback to improve our algorithm. Our alerts currently receive 91% “true positive” feedback from developers.\r\n\r\n**My repositories are private; why should I install automated secret detection?**\r\nImagine if there were a plain text file with all your credit card numbers inside, you wouldn’t put this file inside your company’s git repository. Secrets are just as sensitive and should be handled with special care.\r\n\r\n**Is GitGuardian available to be installed on-premise?**\r\nYes, you can contact one of our security specialists to look over the possibility of installing GitGuardian on-premise on your repositories.\r\n\r\n# ⚒️ Installation notes \r\n\r\nYou should install GitGuardian directly through your [GitGuardian](https://dashboard.gitguardian.com/) workspace on the Integration settings page. \r\n\r\nSo that you know, your GitHub organization or GitHub account can only be associated with a single GitGuardian workspace.\r\n\r\n# 👋 Support\r\n\r\nIf you experience any difficulties or have any questions, please reach out to us by email ([support@gitguardian.com](mailto:support@gitguardian.com)).",
+ "external_url": "https://dashboard.gitguardian.com",
+ "html_url": "https://github.com/apps/gitguardian",
+ "created_at": "2019-11-12T15:44:31Z",
+ "updated_at": "2023-07-18T09:06:22Z",
+ "permissions": {
+ "checks": "write",
+ "contents": "read",
+ "emails": "read",
+ "issues": "write",
+ "members": "read",
+ "metadata": "read",
+ "organization_hooks": "write",
+ "pull_requests": "write"
+ },
+ "events": [
+ "check_run",
+ "check_suite",
+ "commit_comment",
+ "create",
+ "delete",
+ "organization",
+ "public",
+ "pull_request",
+ "pull_request_review",
+ "pull_request_review_comment",
+ "push",
+ "repository"
+ ]
+ },
+ "pull_requests": [
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/pulls/14728",
+ "id": 2817549354,
+ "number": 14728,
+ "head": {
+ "ref": "chore/common/unicode-17",
+ "sha": "ebeacc83d0b5cfd7ab523874631e5740721f1f2f",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ },
+ "base": {
+ "ref": "master",
+ "sha": "898cd340a33f29b766b08da66a519be7e3d79fe6",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "id": 50107238217,
+ "name": "build",
+ "node_id": "CR_kwDOAY2xT88AAAALqp_HSQ",
+ "head_sha": "390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "external_id": "584213e9-9caa-5e7a-be2b-4a4fb7afc574",
+ "url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107238217",
+ "html_url": "https://github.com/keymanapp/keyman/actions/runs/17634180116/job/50107238217",
+ "details_url": "https://github.com/keymanapp/keyman/actions/runs/17634180116/job/50107238217",
+ "status": "completed",
+ "conclusion": "skipped",
+ "started_at": "2025-09-11T04:38:46Z",
+ "completed_at": "2025-09-11T04:38:45Z",
+ "output": {
+ "title": null,
+ "summary": null,
+ "text": null,
+ "annotations_count": 0,
+ "annotations_url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107238217/annotations"
+ },
+ "check_suite": {
+ "id": 45240899113
+ },
+ "app": {
+ "id": 15368,
+ "client_id": "Iv1.05c79e9ad1f6bdfa",
+ "slug": "github-actions",
+ "node_id": "MDM6QXBwMTUzNjg=",
+ "owner": {
+ "login": "github",
+ "id": 9919,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github",
+ "html_url": "https://github.com/github",
+ "followers_url": "https://api.github.com/users/github/followers",
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
+ "organizations_url": "https://api.github.com/users/github/orgs",
+ "repos_url": "https://api.github.com/users/github/repos",
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github/received_events",
+ "type": "Organization",
+ "user_view_type": "public",
+ "site_admin": false
+ },
+ "name": "GitHub Actions",
+ "description": "Automate your workflow from idea to production",
+ "external_url": "https://help.github.com/en/actions",
+ "html_url": "https://github.com/apps/github-actions",
+ "created_at": "2018-07-30T09:30:17Z",
+ "updated_at": "2025-03-07T16:35:00Z",
+ "permissions": {
+ "actions": "write",
+ "administration": "read",
+ "attestations": "write",
+ "checks": "write",
+ "contents": "write",
+ "deployments": "write",
+ "discussions": "write",
+ "issues": "write",
+ "merge_queues": "write",
+ "metadata": "read",
+ "models": "read",
+ "packages": "write",
+ "pages": "write",
+ "pull_requests": "write",
+ "repository_hooks": "write",
+ "repository_projects": "write",
+ "security_events": "write",
+ "statuses": "write",
+ "vulnerability_alerts": "read"
+ },
+ "events": [
+ "branch_protection_rule",
+ "check_run",
+ "check_suite",
+ "create",
+ "delete",
+ "deployment",
+ "deployment_status",
+ "discussion",
+ "discussion_comment",
+ "fork",
+ "gollum",
+ "issues",
+ "issue_comment",
+ "label",
+ "merge_group",
+ "milestone",
+ "page_build",
+ "project",
+ "project_card",
+ "project_column",
+ "public",
+ "pull_request",
+ "pull_request_review",
+ "pull_request_review_comment",
+ "push",
+ "registry_package",
+ "release",
+ "repository",
+ "repository_dispatch",
+ "status",
+ "watch",
+ "workflow_dispatch",
+ "workflow_run"
+ ]
+ },
+ "pull_requests": [
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/pulls/14728",
+ "id": 2817549354,
+ "number": 14728,
+ "head": {
+ "ref": "chore/common/unicode-17",
+ "sha": "ebeacc83d0b5cfd7ab523874631e5740721f1f2f",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ },
+ "base": {
+ "ref": "master",
+ "sha": "898cd340a33f29b766b08da66a519be7e3d79fe6",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "id": 50107238052,
+ "name": "triage",
+ "node_id": "CR_kwDOAY2xT88AAAALqp_GpA",
+ "head_sha": "390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "external_id": "90e392c4-1805-5238-9d01-622e4d746355",
+ "url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107238052",
+ "html_url": "https://github.com/keymanapp/keyman/actions/runs/17634180101/job/50107238052",
+ "details_url": "https://github.com/keymanapp/keyman/actions/runs/17634180101/job/50107238052",
+ "status": "completed",
+ "conclusion": "success",
+ "started_at": "2025-09-11T04:38:47Z",
+ "completed_at": "2025-09-11T04:38:52Z",
+ "output": {
+ "title": null,
+ "summary": null,
+ "text": null,
+ "annotations_count": 0,
+ "annotations_url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107238052/annotations"
+ },
+ "check_suite": {
+ "id": 45240899080
+ },
+ "app": {
+ "id": 15368,
+ "client_id": "Iv1.05c79e9ad1f6bdfa",
+ "slug": "github-actions",
+ "node_id": "MDM6QXBwMTUzNjg=",
+ "owner": {
+ "login": "github",
+ "id": 9919,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github",
+ "html_url": "https://github.com/github",
+ "followers_url": "https://api.github.com/users/github/followers",
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
+ "organizations_url": "https://api.github.com/users/github/orgs",
+ "repos_url": "https://api.github.com/users/github/repos",
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github/received_events",
+ "type": "Organization",
+ "user_view_type": "public",
+ "site_admin": false
+ },
+ "name": "GitHub Actions",
+ "description": "Automate your workflow from idea to production",
+ "external_url": "https://help.github.com/en/actions",
+ "html_url": "https://github.com/apps/github-actions",
+ "created_at": "2018-07-30T09:30:17Z",
+ "updated_at": "2025-03-07T16:35:00Z",
+ "permissions": {
+ "actions": "write",
+ "administration": "read",
+ "attestations": "write",
+ "checks": "write",
+ "contents": "write",
+ "deployments": "write",
+ "discussions": "write",
+ "issues": "write",
+ "merge_queues": "write",
+ "metadata": "read",
+ "models": "read",
+ "packages": "write",
+ "pages": "write",
+ "pull_requests": "write",
+ "repository_hooks": "write",
+ "repository_projects": "write",
+ "security_events": "write",
+ "statuses": "write",
+ "vulnerability_alerts": "read"
+ },
+ "events": [
+ "branch_protection_rule",
+ "check_run",
+ "check_suite",
+ "create",
+ "delete",
+ "deployment",
+ "deployment_status",
+ "discussion",
+ "discussion_comment",
+ "fork",
+ "gollum",
+ "issues",
+ "issue_comment",
+ "label",
+ "merge_group",
+ "milestone",
+ "page_build",
+ "project",
+ "project_card",
+ "project_column",
+ "public",
+ "pull_request",
+ "pull_request_review",
+ "pull_request_review_comment",
+ "push",
+ "registry_package",
+ "release",
+ "repository",
+ "repository_dispatch",
+ "status",
+ "watch",
+ "workflow_dispatch",
+ "workflow_run"
+ ]
+ },
+ "pull_requests": [
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/pulls/14728",
+ "id": 2817549354,
+ "number": 14728,
+ "head": {
+ "ref": "chore/common/unicode-17",
+ "sha": "ebeacc83d0b5cfd7ab523874631e5740721f1f2f",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ },
+ "base": {
+ "ref": "master",
+ "sha": "898cd340a33f29b766b08da66a519be7e3d79fe6",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ }
+ }
+ ]
+ },
+ {
+ "id": 50107108425,
+ "name": "Summarize build status checks",
+ "node_id": "CR_kwDOAY2xT88AAAALqp3MSQ",
+ "head_sha": "390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "external_id": "7e5f7f3d-df60-5a09-9991-ce263cfb45c6",
+ "url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107108425",
+ "html_url": "https://github.com/keymanapp/keyman/actions/runs/17634132698/job/50107108425",
+ "details_url": "https://github.com/keymanapp/keyman/actions/runs/17634132698/job/50107108425",
+ "status": "completed",
+ "conclusion": "success",
+ "started_at": "2025-09-11T04:35:52Z",
+ "completed_at": "2025-09-11T04:35:55Z",
+ "output": {
+ "title": null,
+ "summary": null,
+ "text": null,
+ "annotations_count": 0,
+ "annotations_url": "https://api.github.com/repos/keymanapp/keyman/check-runs/50107108425/annotations"
+ },
+ "check_suite": {
+ "id": 45240794914
+ },
+ "app": {
+ "id": 15368,
+ "client_id": "Iv1.05c79e9ad1f6bdfa",
+ "slug": "github-actions",
+ "node_id": "MDM6QXBwMTUzNjg=",
+ "owner": {
+ "login": "github",
+ "id": 9919,
+ "node_id": "MDEyOk9yZ2FuaXphdGlvbjk5MTk=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/9919?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github",
+ "html_url": "https://github.com/github",
+ "followers_url": "https://api.github.com/users/github/followers",
+ "following_url": "https://api.github.com/users/github/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github/subscriptions",
+ "organizations_url": "https://api.github.com/users/github/orgs",
+ "repos_url": "https://api.github.com/users/github/repos",
+ "events_url": "https://api.github.com/users/github/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github/received_events",
+ "type": "Organization",
+ "user_view_type": "public",
+ "site_admin": false
+ },
+ "name": "GitHub Actions",
+ "description": "Automate your workflow from idea to production",
+ "external_url": "https://help.github.com/en/actions",
+ "html_url": "https://github.com/apps/github-actions",
+ "created_at": "2018-07-30T09:30:17Z",
+ "updated_at": "2025-03-07T16:35:00Z",
+ "permissions": {
+ "actions": "write",
+ "administration": "read",
+ "attestations": "write",
+ "checks": "write",
+ "contents": "write",
+ "deployments": "write",
+ "discussions": "write",
+ "issues": "write",
+ "merge_queues": "write",
+ "metadata": "read",
+ "models": "read",
+ "packages": "write",
+ "pages": "write",
+ "pull_requests": "write",
+ "repository_hooks": "write",
+ "repository_projects": "write",
+ "security_events": "write",
+ "statuses": "write",
+ "vulnerability_alerts": "read"
+ },
+ "events": [
+ "branch_protection_rule",
+ "check_run",
+ "check_suite",
+ "create",
+ "delete",
+ "deployment",
+ "deployment_status",
+ "discussion",
+ "discussion_comment",
+ "fork",
+ "gollum",
+ "issues",
+ "issue_comment",
+ "label",
+ "merge_group",
+ "milestone",
+ "page_build",
+ "project",
+ "project_card",
+ "project_column",
+ "public",
+ "pull_request",
+ "pull_request_review",
+ "pull_request_review_comment",
+ "push",
+ "registry_package",
+ "release",
+ "repository",
+ "repository_dispatch",
+ "status",
+ "watch",
+ "workflow_dispatch",
+ "workflow_run"
+ ]
+ },
+ "pull_requests": [
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/pulls/14728",
+ "id": 2817549354,
+ "number": 14728,
+ "head": {
+ "ref": "chore/common/unicode-17",
+ "sha": "ebeacc83d0b5cfd7ab523874631e5740721f1f2f",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ },
+ "base": {
+ "ref": "master",
+ "sha": "898cd340a33f29b766b08da66a519be7e3d79fe6",
+ "repo": {
+ "id": 26063183,
+ "url": "https://api.github.com/repos/keymanapp/keyman",
+ "name": "keyman"
+ }
+ }
+ }
+ ]
+ }
+]
\ No newline at end of file
diff --git a/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-statuses.json b/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-statuses.json
new file mode 100644
index 0000000000..213931a7ed
--- /dev/null
+++ b/resources/build/pr-build-status/fixtures/390a5bc6dba73cd32bc8c7290ac73321f6504deb-statuses.json
@@ -0,0 +1,3038 @@
+[
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175572529,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwvMMQ",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T05:29:36Z",
+ "updated_at": "2025-09-11T05:29:36Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175567982,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwu6bg",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Developer_Test/576932",
+ "context": "Test - Windows (Keyman - Developer)",
+ "created_at": "2025-09-11T05:29:14Z",
+ "updated_at": "2025-09-11T05:29:14Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175162089,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwWI6Q",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T05:00:11Z",
+ "updated_at": "2025-09-11T05:00:11Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175160705,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwWDgQ",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_Windows/576928",
+ "context": "Test: Keyman Core - Windows (Common)",
+ "created_at": "2025-09-11T05:00:07Z",
+ "updated_at": "2025-09-11T05:00:07Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175159732,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwV_tA",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Developer_Mac/576933",
+ "context": "Test - macOS (Keyman - Developer)",
+ "created_at": "2025-09-11T05:00:02Z",
+ "updated_at": "2025-09-11T05:00:02Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175118416,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwTeUA",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:56:41Z",
+ "updated_at": "2025-09-11T04:56:41Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175115406,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwTSjg",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_WASM/576918",
+ "context": "Test: Keyman Core - WASM (Common)",
+ "created_at": "2025-09-11T04:56:27Z",
+ "updated_at": "2025-09-11T04:56:27Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175107216,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSykA",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:55:44Z",
+ "updated_at": "2025-09-11T04:55:44Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "id": 39175106689,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSwgQ",
+ "state": "success",
+ "description": "API verification succeeded",
+ "target_url": "https://github.com/keymanapp/keyman/actions/runs/17634394358",
+ "context": "API Verification",
+ "created_at": "2025-09-11T04:55:42Z",
+ "updated_at": "2025-09-11T04:55:42Z",
+ "creator": {
+ "login": "github-actions[bot]",
+ "id": 41898282,
+ "node_id": "MDM6Qm90NDE4OTgyODI=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github-actions%5Bbot%5D",
+ "html_url": "https://github.com/apps/github-actions",
+ "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175098588,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSQ3A",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:55:00Z",
+ "updated_at": "2025-09-11T04:55:00Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175098146,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSPIg",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:54:58Z",
+ "updated_at": "2025-09-11T04:54:58Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175098035,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSOsw",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Linux_Test_Integration/576920",
+ "context": "Test:Integration (Keyman - Linux)",
+ "created_at": "2025-09-11T04:54:58Z",
+ "updated_at": "2025-09-11T04:54:58Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175097199,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSLbw",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_macOS/576925",
+ "context": "Test: Keyman Core - macOS (Common)",
+ "created_at": "2025-09-11T04:54:54Z",
+ "updated_at": "2025-09-11T04:54:54Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175096032,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSG4A",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:54:47Z",
+ "updated_at": "2025-09-11T04:54:47Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175095550,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSE_g",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Developer_Mac/576933",
+ "context": "Test - macOS (Keyman - Developer)",
+ "created_at": "2025-09-11T04:54:45Z",
+ "updated_at": "2025-09-11T04:54:45Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175095475,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwSEsw",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestPullRequests/576915",
+ "context": "Test (Keyman - iOS)",
+ "created_at": "2025-09-11T04:54:44Z",
+ "updated_at": "2025-09-11T04:54:44Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175080948,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwRL9A",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:53:36Z",
+ "updated_at": "2025-09-11T04:53:36Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175080759,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwRLNw",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:53:35Z",
+ "updated_at": "2025-09-11T04:53:35Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175078800,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwRDkA",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanAndroid_TestSamplesAndTestProjects/576931",
+ "context": "Test: Samples and Test projects (Keyman - Android)",
+ "created_at": "2025-09-11T04:53:25Z",
+ "updated_at": "2025-09-11T04:53:25Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "id": 39175078429,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwRCHQ",
+ "state": "pending",
+ "description": "API verification started",
+ "target_url": "https://github.com/keymanapp/keyman/actions/runs/17634394358",
+ "context": "API Verification",
+ "created_at": "2025-09-11T04:53:23Z",
+ "updated_at": "2025-09-11T04:53:23Z",
+ "creator": {
+ "login": "github-actions[bot]",
+ "id": 41898282,
+ "node_id": "MDM6Qm90NDE4OTgyODI=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github-actions%5Bbot%5D",
+ "html_url": "https://github.com/apps/github-actions",
+ "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "id": 39175076234,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwQ5ig",
+ "state": "success",
+ "description": "Package build succeeded",
+ "target_url": "https://github.com/keymanapp/keyman/actions/runs/17634187943",
+ "context": "Ubuntu Packaging",
+ "created_at": "2025-09-11T04:53:11Z",
+ "updated_at": "2025-09-11T04:53:11Z",
+ "creator": {
+ "login": "github-actions[bot]",
+ "id": 41898282,
+ "node_id": "MDM6Qm90NDE4OTgyODI=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github-actions%5Bbot%5D",
+ "html_url": "https://github.com/apps/github-actions",
+ "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175068238,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwQaTg",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Linux_Test_Integration/576920",
+ "context": "Test:Integration (Keyman - Linux)",
+ "created_at": "2025-09-11T04:52:31Z",
+ "updated_at": "2025-09-11T04:52:31Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175063216,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwQGsA",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:52:10Z",
+ "updated_at": "2025-09-11T04:52:10Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175058340,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwPzpA",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Developer_Linux/576934",
+ "context": "Test - Linux (Keyman - Developer)",
+ "created_at": "2025-09-11T04:51:48Z",
+ "updated_at": "2025-09-11T04:51:48Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175051151,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwPXjw",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Linux/576935",
+ "context": "Test: Common - Linux (Common)",
+ "created_at": "2025-09-11T04:51:21Z",
+ "updated_at": "2025-09-11T04:51:21Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175051020,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwPXDA",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Linux/576935",
+ "context": "Test: Common - Linux (Common)",
+ "created_at": "2025-09-11T04:51:21Z",
+ "updated_at": "2025-09-11T04:51:21Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175049448,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwPQ6A",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:51:13Z",
+ "updated_at": "2025-09-11T04:51:13Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175048733,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwPOHQ",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:51:09Z",
+ "updated_at": "2025-09-11T04:51:09Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175044363,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwO9Cw",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Linux/576935",
+ "context": "Test: Common - Linux (Common)",
+ "created_at": "2025-09-11T04:50:47Z",
+ "updated_at": "2025-09-11T04:50:47Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175044256,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwO8oA",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanAndroid_TestPullRequests/576930",
+ "context": "Test (Keyman - Android)",
+ "created_at": "2025-09-11T04:50:46Z",
+ "updated_at": "2025-09-11T04:50:46Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175038088,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwOkiA",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:50:14Z",
+ "updated_at": "2025-09-11T04:50:14Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175033010,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwOQsg",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_macOS/576925",
+ "context": "Test: Keyman Core - macOS (Common)",
+ "created_at": "2025-09-11T04:49:50Z",
+ "updated_at": "2025-09-11T04:49:50Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175032935,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwOQZw",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_KeymanMac_PullRequests/576924",
+ "context": "Test (Keyman - macOS)",
+ "created_at": "2025-09-11T04:49:49Z",
+ "updated_at": "2025-09-11T04:49:49Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175026018,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwN1Yg",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:49:12Z",
+ "updated_at": "2025-09-11T04:49:12Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175005335,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMklw",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:47:30Z",
+ "updated_at": "2025-09-11T04:47:30Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39175005126,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMjxg",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:47:29Z",
+ "updated_at": "2025-09-11T04:47:29Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175001040,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMT0A",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanAndroid_TestSamplesAndTestProjects/576931",
+ "context": "Test: Samples and Test projects (Keyman - Android)",
+ "created_at": "2025-09-11T04:47:09Z",
+ "updated_at": "2025-09-11T04:47:09Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39175000940,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMTbA",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPullRequests/576926",
+ "context": "Test (Keyman - Windows)",
+ "created_at": "2025-09-11T04:47:09Z",
+ "updated_at": "2025-09-11T04:47:09Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174999511,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMN1w",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Developer_Test/576932",
+ "context": "Test - Windows (Keyman - Developer)",
+ "created_at": "2025-09-11T04:47:02Z",
+ "updated_at": "2025-09-11T04:47:02Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174999409,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwMNcQ",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Web/576929",
+ "context": "Test: Common - Web (Common)",
+ "created_at": "2025-09-11T04:47:02Z",
+ "updated_at": "2025-09-11T04:47:02Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174993947,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwL4Gw",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_KeymanMac_PullRequests/576924",
+ "context": "Test (Keyman - macOS)",
+ "created_at": "2025-09-11T04:46:36Z",
+ "updated_at": "2025-09-11T04:46:36Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174993870,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwL3zg",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Mac/576922",
+ "context": "Test: Common - macOS (Common)",
+ "created_at": "2025-09-11T04:46:35Z",
+ "updated_at": "2025-09-11T04:46:35Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174993783,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwL3dw",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Mac/576922",
+ "context": "Test: Common - macOS (Common)",
+ "created_at": "2025-09-11T04:46:35Z",
+ "updated_at": "2025-09-11T04:46:35Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39174990184,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLpaA",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:46:18Z",
+ "updated_at": "2025-09-11T04:46:18Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39174989998,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLorg",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:46:17Z",
+ "updated_at": "2025-09-11T04:46:17Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39174989781,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLn1Q",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:46:16Z",
+ "updated_at": "2025-09-11T04:46:16Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39174989098,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLlKg",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:46:12Z",
+ "updated_at": "2025-09-11T04:46:12Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985891,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLYow",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Developer_Linux/576934",
+ "context": "Test - Linux (Keyman - Developer)",
+ "created_at": "2025-09-11T04:45:56Z",
+ "updated_at": "2025-09-11T04:45:56Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985810,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLYUg",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keymanweb_TestPullRequests/576917",
+ "context": "Test (Keyman - Web)",
+ "created_at": "2025-09-11T04:45:56Z",
+ "updated_at": "2025-09-11T04:45:56Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985723,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLX-w",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanAndroid_TestPullRequests/576930",
+ "context": "Test (Keyman - Android)",
+ "created_at": "2025-09-11T04:45:55Z",
+ "updated_at": "2025-09-11T04:45:55Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985645,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLXrQ",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_Linux/576921",
+ "context": "Test: Keyman Core - Linux (Common)",
+ "created_at": "2025-09-11T04:45:55Z",
+ "updated_at": "2025-09-11T04:45:55Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985556,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLXVA",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Mac/576922",
+ "context": "Test: Common - macOS (Common)",
+ "created_at": "2025-09-11T04:45:54Z",
+ "updated_at": "2025-09-11T04:45:54Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174985505,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLXIQ",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestSamplesAndTestProjects/576916",
+ "context": "Test: Samples and Test Projects (Keyman - iOS)",
+ "created_at": "2025-09-11T04:45:54Z",
+ "updated_at": "2025-09-11T04:45:54Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174984029,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwLRXQ",
+ "state": "success",
+ "description": "⚠️ Warning: keymanweb.js is 170 bytes (0%) larger than 19.0.116, now 432,283 bytes",
+ "target_url": null,
+ "context": "check/web/file-size",
+ "created_at": "2025-09-11T04:45:46Z",
+ "updated_at": "2025-09-11T04:45:46Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174958855,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwJvBw",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Web/576929",
+ "context": "Test: Common - Web (Common)",
+ "created_at": "2025-09-11T04:43:34Z",
+ "updated_at": "2025-09-11T04:43:34Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174958775,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwJutw",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Windows/576923",
+ "context": "Test: Common - Windows (Common)",
+ "created_at": "2025-09-11T04:43:33Z",
+ "updated_at": "2025-09-11T04:43:33Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174958372,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwJtJA",
+ "state": "failure",
+ "description": "TeamCity build failed",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Windows/576923",
+ "context": "Test: Common - Windows (Common)",
+ "created_at": "2025-09-11T04:43:31Z",
+ "updated_at": "2025-09-11T04:43:31Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174938339,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwIe4w",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_Linux/576921",
+ "context": "Test: Keyman Core - Linux (Common)",
+ "created_at": "2025-09-11T04:41:54Z",
+ "updated_at": "2025-09-11T04:41:54Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174938237,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwIefQ",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanLinux_TestPullRequests/576919",
+ "context": "Test (Keyman - Linux)",
+ "created_at": "2025-09-11T04:41:53Z",
+ "updated_at": "2025-09-11T04:41:53Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174932962,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwIJ4g",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_Windows/576928",
+ "context": "Test: Keyman Core - Windows (Common)",
+ "created_at": "2025-09-11T04:41:25Z",
+ "updated_at": "2025-09-11T04:41:25Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174932882,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwIJkg",
+ "state": "success",
+ "description": "TeamCity build finished",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPrRenderOnScreenKeyboards/576927",
+ "context": "Test: Render On Screen Keyboards (Keyman - Windows)",
+ "created_at": "2025-09-11T04:41:24Z",
+ "updated_at": "2025-09-11T04:41:24Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "id": 39174908967,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGsJw",
+ "state": "pending",
+ "description": "Ubuntu packaging started",
+ "target_url": "https://github.com/keymanapp/keyman/actions/runs/17634187943",
+ "context": "Ubuntu Packaging",
+ "created_at": "2025-09-11T04:39:26Z",
+ "updated_at": "2025-09-11T04:39:26Z",
+ "creator": {
+ "login": "github-actions[bot]",
+ "id": 41898282,
+ "node_id": "MDM6Qm90NDE4OTgyODI=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/15368?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/github-actions%5Bbot%5D",
+ "html_url": "https://github.com/apps/github-actions",
+ "followers_url": "https://api.github.com/users/github-actions%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/github-actions%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/github-actions%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/github-actions%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/github-actions%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/github-actions%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/github-actions%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/github-actions%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/github-actions%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908607,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGqvw",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanLinux_TestPullRequests/576919",
+ "context": "Test (Keyman - Linux)",
+ "created_at": "2025-09-11T04:39:24Z",
+ "updated_at": "2025-09-11T04:39:24Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908507,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGqWw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576935",
+ "context": "Test: Common - Linux (Common)",
+ "created_at": "2025-09-11T04:39:24Z",
+ "updated_at": "2025-09-11T04:39:24Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908427,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGqCw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576934",
+ "context": "Test - Linux (Keyman - Developer)",
+ "created_at": "2025-09-11T04:39:23Z",
+ "updated_at": "2025-09-11T04:39:23Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908273,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGpcQ",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576933",
+ "context": "Test - macOS (Keyman - Developer)",
+ "created_at": "2025-09-11T04:39:22Z",
+ "updated_at": "2025-09-11T04:39:22Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908169,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGpCQ",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576932",
+ "context": "Test - Windows (Keyman - Developer)",
+ "created_at": "2025-09-11T04:39:22Z",
+ "updated_at": "2025-09-11T04:39:22Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174908061,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGonQ",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576931",
+ "context": "Test: Samples and Test projects (Keyman - Android)",
+ "created_at": "2025-09-11T04:39:22Z",
+ "updated_at": "2025-09-11T04:39:22Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907908,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGoBA",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576930",
+ "context": "Test (Keyman - Android)",
+ "created_at": "2025-09-11T04:39:21Z",
+ "updated_at": "2025-09-11T04:39:21Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907798,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGnlg",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576929",
+ "context": "Test: Common - Web (Common)",
+ "created_at": "2025-09-11T04:39:20Z",
+ "updated_at": "2025-09-11T04:39:20Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907673,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGnGQ",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576928",
+ "context": "Test: Keyman Core - Windows (Common)",
+ "created_at": "2025-09-11T04:39:20Z",
+ "updated_at": "2025-09-11T04:39:20Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907586,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGmwg",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPrRenderOnScreenKeyboards/576927",
+ "context": "Test: Render On Screen Keyboards (Keyman - Windows)",
+ "created_at": "2025-09-11T04:39:19Z",
+ "updated_at": "2025-09-11T04:39:19Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907492,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGmZA",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPrRenderOnScreenKeyboards/576927",
+ "context": "Test: Render On Screen Keyboards (Keyman - Windows)",
+ "created_at": "2025-09-11T04:39:19Z",
+ "updated_at": "2025-09-11T04:39:19Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907382,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGl9g",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPullRequests/576926",
+ "context": "Test (Keyman - Windows)",
+ "created_at": "2025-09-11T04:39:19Z",
+ "updated_at": "2025-09-11T04:39:19Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907255,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGldw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/KeymanDesktop_TestPullRequests/576926",
+ "context": "Test (Keyman - Windows)",
+ "created_at": "2025-09-11T04:39:18Z",
+ "updated_at": "2025-09-11T04:39:18Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907127,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGk9w",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576925",
+ "context": "Test: Keyman Core - macOS (Common)",
+ "created_at": "2025-09-11T04:39:17Z",
+ "updated_at": "2025-09-11T04:39:17Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174907022,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGkjg",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576924",
+ "context": "Test (Keyman - macOS)",
+ "created_at": "2025-09-11T04:39:17Z",
+ "updated_at": "2025-09-11T04:39:17Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906933,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGkNQ",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Windows/576923",
+ "context": "Test: Common - Windows (Common)",
+ "created_at": "2025-09-11T04:39:16Z",
+ "updated_at": "2025-09-11T04:39:16Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906844,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGj3A",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Test_Common_Windows/576923",
+ "context": "Test: Common - Windows (Common)",
+ "created_at": "2025-09-11T04:39:16Z",
+ "updated_at": "2025-09-11T04:39:16Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906746,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGjeg",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576922",
+ "context": "Test: Common - macOS (Common)",
+ "created_at": "2025-09-11T04:39:16Z",
+ "updated_at": "2025-09-11T04:39:16Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906635,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGjCw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576921",
+ "context": "Test: Keyman Core - Linux (Common)",
+ "created_at": "2025-09-11T04:39:15Z",
+ "updated_at": "2025-09-11T04:39:15Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906548,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGitA",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576920",
+ "context": "Test:Integration (Keyman - Linux)",
+ "created_at": "2025-09-11T04:39:14Z",
+ "updated_at": "2025-09-11T04:39:14Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906463,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGiXw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/build/576919",
+ "context": "Test (Keyman - Linux)",
+ "created_at": "2025-09-11T04:39:14Z",
+ "updated_at": "2025-09-11T04:39:14Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906355,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGh8w",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_WASM/576918",
+ "context": "Test: Keyman Core - WASM (Common)",
+ "created_at": "2025-09-11T04:39:14Z",
+ "updated_at": "2025-09-11T04:39:14Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906251,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGhiw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_Common_KPAPI_TestPullRequests_WASM/576918",
+ "context": "Test: Keyman Core - WASM (Common)",
+ "created_at": "2025-09-11T04:39:13Z",
+ "updated_at": "2025-09-11T04:39:13Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906139,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGhGw",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keymanweb_TestPullRequests/576917",
+ "context": "Test (Keyman - Web)",
+ "created_at": "2025-09-11T04:39:12Z",
+ "updated_at": "2025-09-11T04:39:12Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174906037,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGgtQ",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keymanweb_TestPullRequests/576917",
+ "context": "Test (Keyman - Web)",
+ "created_at": "2025-09-11T04:39:12Z",
+ "updated_at": "2025-09-11T04:39:12Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174905929,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGgSQ",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestPullRequests/576915",
+ "context": "Test (Keyman - iOS)",
+ "created_at": "2025-09-11T04:39:12Z",
+ "updated_at": "2025-09-11T04:39:12Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174905842,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGf8g",
+ "state": "pending",
+ "description": "TeamCity build started",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestSamplesAndTestProjects/576916",
+ "context": "Test: Samples and Test Projects (Keyman - iOS)",
+ "created_at": "2025-09-11T04:39:11Z",
+ "updated_at": "2025-09-11T04:39:11Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174905756,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGfnA",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestSamplesAndTestProjects/576916",
+ "context": "Test: Samples and Test Projects (Keyman - iOS)",
+ "created_at": "2025-09-11T04:39:11Z",
+ "updated_at": "2025-09-11T04:39:11Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "id": 39174905667,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGfQw",
+ "state": "pending",
+ "description": "TeamCity build was queued",
+ "target_url": "https://build.palaso.org/buildConfiguration/Keyman_iOS_TestPullRequests/576915",
+ "context": "Test (Keyman - iOS)",
+ "created_at": "2025-09-11T04:39:10Z",
+ "updated_at": "2025-09-11T04:39:10Z",
+ "creator": {
+ "login": "keyman-server",
+ "id": 7018967,
+ "node_id": "MDQ6VXNlcjcwMTg5Njc=",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7018967?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keyman-server",
+ "html_url": "https://github.com/keyman-server",
+ "followers_url": "https://api.github.com/users/keyman-server/followers",
+ "following_url": "https://api.github.com/users/keyman-server/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keyman-server/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keyman-server/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keyman-server/subscriptions",
+ "organizations_url": "https://api.github.com/users/keyman-server/orgs",
+ "repos_url": "https://api.github.com/users/keyman-server/repos",
+ "events_url": "https://api.github.com/users/keyman-server/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keyman-server/received_events",
+ "type": "User",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ },
+ {
+ "url": "https://api.github.com/repos/keymanapp/keyman/statuses/390a5bc6dba73cd32bc8c7290ac73321f6504deb",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "id": 39174900789,
+ "node_id": "SC_kwDOAY2xT88AAAAJHwGMNQ",
+ "state": "success",
+ "description": "User tests are not required",
+ "target_url": "https://github.com/keymanapp/keyman/pull/14728#issuecomment-3277442589",
+ "context": "user_testing",
+ "created_at": "2025-09-11T04:38:46Z",
+ "updated_at": "2025-09-11T04:38:46Z",
+ "creator": {
+ "login": "keymanapp-test-bot[bot]",
+ "id": 89363325,
+ "node_id": "MDM6Qm90ODkzNjMzMjU=",
+ "avatar_url": "https://avatars.githubusercontent.com/in/133554?v=4",
+ "gravatar_id": "",
+ "url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D",
+ "html_url": "https://github.com/apps/keymanapp-test-bot",
+ "followers_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/followers",
+ "following_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/following{/other_user}",
+ "gists_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/gists{/gist_id}",
+ "starred_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/starred{/owner}{/repo}",
+ "subscriptions_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/subscriptions",
+ "organizations_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/orgs",
+ "repos_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/repos",
+ "events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/events{/privacy}",
+ "received_events_url": "https://api.github.com/users/keymanapp-test-bot%5Bbot%5D/received_events",
+ "type": "Bot",
+ "user_view_type": "public",
+ "site_admin": false
+ }
+ }
+]
\ No newline at end of file
diff --git a/resources/build/pr-build-status/pr-build-status.mjs b/resources/build/pr-build-status/pr-build-status.mjs
index 091377d942..f8f1b62c1c 100644
--- a/resources/build/pr-build-status/pr-build-status.mjs
+++ b/resources/build/pr-build-status/pr-build-status.mjs
@@ -27,43 +27,61 @@
// check/web/file-size
//
+ function addLog(message) {
+ console.log(message);
+ return message + String.fromCharCode(13);
+ }
+
+ function addStatus(o, type, context, state) {
+ if(!o[context]) {
+ o[context] = {type, state};
+ return addLog(`Found ${context}: ${state}`);
+ } else {
+ return addLog(`Skipping repeated ${context}: ${state}`);
+ }
+ }
+
function reduceStatuses(statuses) {
+ let summary = '';
const filtered_statuses = statuses.reduce((o, status) => {
if(status.creator?.login == 'keyman-server' && status.context.startsWith('Test')) {
- if(!o[status.context]) o[status.context] = {type: 'build', state: status.state};
+ summary += addStatus(o, 'build', status.context, status.state);
} else if(status.creator?.login == 'keymanapp-test-bot[bot]' && status.context == 'user_testing') {
- if(!o[status.context]) o[status.context] = {type: 'user-test', state: status.state};;
+ summary += addStatus(o, 'user-test', status.context, status.state);
} else if(status.context == 'API Verification') {
- if(!o[status.context]) o[status.context] = {type: 'check', state: status.state};
+ summary += addStatus(o, 'check', status.context, status.state);
} else if(status.context == 'Ubuntu Packaging') {
- if(!o[status.context]) o[status.context] = {type: 'build', state: status.state};
+ summary += addStatus(o, 'build', status.context, status.state);
} else if(status.context == 'check/web/file-size') {
// Ignore check/web/file-size -- we won't block automerge for this at this point
+ summary += addLog(`Skipping ${status.context}`);
} else {
// We fail with an 'unknown status' response if we get a new status check
// so we can be sure we are not skipping known status checks
+ summary += addLog(`Found unknown ${status.context}: ${status.state}`);
o[status.context] = {type: 'unknown', state: status.state};
}
return o;
}, {});
- return filtered_statuses;
+ return { filtered_statuses, summary };
}
//
// Given the collection of status checks we care about, return
- // an aggregate status -- error, failed, pending, or success,
+ // an aggregate status -- error, failure, pending, or success,
// and a summary description
//
- function calculateFinalStatus(filtered_statuses) {
+ function calculateFinalStatus(filtered_statuses, summary) {
const counts = {};
let hasBuilds = false;
for(const context of Object.keys(filtered_statuses)) {
const { state, type } = filtered_statuses[context];
if(type == 'unknown') {
// We special-case for unknown status checks, and never permit them
+ console.error(`An unknown context ${context} was found, cannot calculate build status.`);
return [
- 'error', `An unknown context ${context} was found, cannot calculate build status.`
+ 'error', `An unknown context ${context} was found, cannot calculate build status.`, summary
];
}
if(type == 'build') {
@@ -74,12 +92,13 @@
// If we do not have any statuses yet, we wait
if(Object.keys(filtered_statuses).length == 0 || !hasBuilds) {
- return ['pending', 'Builds have not yet been triggered ⌛'];
+ console.log(`Builds not yet triggered`);
+ return ['pending', 'Builds have not yet been triggered ⌛', summary];
}
const state =
counts.error ? 'error' :
- counts.failed ? 'failed' :
+ counts.failure ? 'failure' :
counts.pending ? 'pending' :
'success';
@@ -90,14 +109,16 @@
description += `${count} check${count == 1 ? '' : 's'} ${state}`;
}
appendDescription(counts.error, 'in an error state ❌');
- appendDescription(counts.failed, 'failed ❌');
+ appendDescription(counts.failure, 'failed ❌');
appendDescription(counts.pending, 'pending ⌛');
appendDescription(counts.success, 'completed successfully ✅');
- return [ state, description ];
+ console.log(`Finished filtering and reviewing status checks: ${state}: ${description}`);
+ return [ state, description, summary ];
}
async function getCommitStatuses(github, owner, repo, sha) {
+ console.log(`Getting commit statuses for ${sha}`);
const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/statuses', {
owner,
repo,
@@ -110,6 +131,7 @@
}
async function getCommitCheckRuns(github, owner, repo, sha) {
+ console.log(`Getting commit check runs for ${sha}`);
const statuses = await github.paginate('GET /repos/{owner}/{repo}/commits/{sha}/check-runs', {
owner,
repo,
@@ -123,13 +145,11 @@
function calculateCheckResult(statuses) {
if(!Array.isArray(statuses)) {
- return ['error', 'Failed to retrieve status checks from GitHub ❌'];
+ return ['error', 'Failed to retrieve status checks from GitHub ❌', 'statuses is not an array'];
}
- const filtered_statuses = reduceStatuses(statuses);
-
- const result = calculateFinalStatus(filtered_statuses);
- return result;
+ const { filtered_statuses, summary } = reduceStatuses(statuses);
+ return calculateFinalStatus(filtered_statuses, summary);
}
async function test(github, owner, repo, sha) {
@@ -149,7 +169,7 @@
return check.data.id;
}
- async function updateCheck(github, owner, repo, checkRunId, status, description) {
+ async function updateCheck(github, owner, repo, checkRunId, status, description, summary) {
const checkStatus = status == 'pending' ? 'in_progress' : 'completed';
const conclusion = checkStatus == 'in_progress' ? undefined : (status == 'success' ? 'success' : 'failure');
@@ -161,7 +181,7 @@
conclusion,
output: {
title: description,
- summary: ''
+ summary
}
});
}
@@ -179,7 +199,7 @@
// const checkRunId = await createCheck(github, owner, repo, sha);
// const res = await test(github, owner, repo, sha);
- // await updateCheck(github, owner, repo, checkRunId, res[0], res[1]);
+ // await updateCheck(github, owner, repo, checkRunId, res[0], res[1], res[2]);
// CLONE-COMMENTED:END
diff --git a/resources/build/pr-build-status/pr-build-status.tests.mjs b/resources/build/pr-build-status/pr-build-status.tests.mjs
index bfb49fe64b..fae7f65628 100644
--- a/resources/build/pr-build-status/pr-build-status.tests.mjs
+++ b/resources/build/pr-build-status/pr-build-status.tests.mjs
@@ -1,6 +1,7 @@
import * as fs from 'node:fs';
import 'mocha';
import { assert } from 'chai';
+import sinon from 'sinon';
import { unitTestEndpoints } from './pr-build-status.mjs';
@@ -9,9 +10,10 @@ import { getOctokit } from '@actions/github';
import * as process from 'node:process';
const commits = {
+ '390a5bc6dba73cd32bc8c7290ac73321f6504deb': [ 'failure', '3 checks failed ❌; 21 checks completed successfully ✅'],
'825f7d2df0069fa56a8f2a534b42a49ee1f21ca1': [ 'success', '24 checks completed successfully ✅' ],
- '870d37f56b489ef5067b4352a06505369d9038e0': [ 'error', '6 checks in an error state ❌; 17 checks completed successfully ✅' ],
- '11a558e926370253db37026c95b7ff5a6aa1e8fc': [ 'success', '22 checks completed successfully ✅' ],
+ '870d37f56b489ef5067b4352a06505369d9038e0': [ 'error', '6 checks in an error state ❌; 1 check failed ❌; 17 checks completed successfully ✅' ],
+ '11a558e926370253db37026c95b7ff5a6aa1e8fc': [ 'failure', '2 checks failed ❌; 22 checks completed successfully ✅' ],
'8fd5ccc9026b85d6a780d8bcf862380e7a89aefb': [ 'pending', 'Builds have not yet been triggered ⌛' ],
'153683cfb007c6066c9dcf71d25afa4c66efa17f': [ 'pending', 'Builds have not yet been triggered ⌛' ],
};
@@ -32,13 +34,23 @@ if(debug) {
}
describe('pr-build-status', function () {
+ beforeEach(() => {
+ // just silencing the logging from pr-build-status bot
+ // in order to make the test results clearer
+ sinon.stub(console, 'log');
+ });
+
+ afterEach(() => {
+ console.log.restore();
+ });
+
for(const sha of Object.keys(commits)) {
it(`should return '${commits[sha][1]}' for sha ${sha}`, function () {
const json = JSON.parse(fs.readFileSync(`fixtures/${sha}-statuses.json`,'utf-8'));
const status = unitTestEndpoints.calculateCheckResult(json);
assert.isNotNull(status);
assert.isArray(status);
- assert.deepStrictEqual(status, commits[sha]);
+ assert.deepStrictEqual(status.splice(0, 2), commits[sha]);
});
}
});
diff --git a/resources/build/publish-minimum-versions.sh b/resources/build/publish-minimum-versions.sh
index 5da012737a..a9d6098c72 100755
--- a/resources/build/publish-minimum-versions.sh
+++ b/resources/build/publish-minimum-versions.sh
@@ -35,7 +35,7 @@ generate_table() {
KEYMAN_VERSION | KEYMAN_VERSION_MAJOR | KEYMAN_VERSION_MINOR | \
KEYMAN_VERSION_PATCH | KEYMAN_VERSION_RELEASE | KEYMAN_VERSION_WIN | \
KEYMAN_VERSION_TAG | KEYMAN_VERSION_WITH_TAG | \
- KEYMAN_VERSION_ENVIRONMENT | KEYMAN_VERSION_GIT_TAG)
+ KEYMAN_VERSION_ENVIRONMENT | KEYMAN_VERSION_GIT_TAG | KEYMAN_VERSION_FOR_FILENAME)
# ignore the variables that contain the Keyman version
;;
*)
diff --git a/resources/build/test/build-bot/trigger-build-bot.test.sh b/resources/build/test/build-bot/trigger-build-bot.test.sh
index a39b8361ae..f7ca8f91bd 100755
--- a/resources/build/test/build-bot/trigger-build-bot.test.sh
+++ b/resources/build/test/build-bot/trigger-build-bot.test.sh
@@ -216,7 +216,25 @@ _do_test_test_bot_check_pr_body() {
#----------------------------------------------------------------------------------------------------
+test_is_skip_keyman_api_check() {
+ builder_echo start test_is_skip_keyman_api_check 'START TEST: test_is_skip_keyman_api_check'
+ result=$(is_skip_keyman_api_check 1 '{ "body": "Keyman-Api-Check: skip" }')
+ assert-equal "${result}" "true" "PR #1: 'Keyman-Api-Check: skip' should return true"
+ result=$(is_skip_keyman_api_check 2 '{ "body": "PR message" }')
+ assert-equal "${result}" "false" "PR #2: omitted 'Keyman-Api-Check' should return false"
+ result=$(is_skip_keyman_api_check 3 '{ "body": "Keyman-Api-Check: invalid" }')
+ assert-equal "${result}" "false" "PR #3: invalid data for 'Keyman-Api-Check' should return false"
+ result=$(is_skip_keyman_api_check 4 '{ "body": "Some message\nKeyman-Api-Check: skip" }')
+ assert-equal "${result}" "true" "PR #4: 'Keyman-Api-Check: skip' at start of line should return true"
+ result=$(is_skip_keyman_api_check 5 '{ "body": "Here Keyman-Api-Check: skip\nis in the middle of the line" }')
+ assert-equal "${result}" "false" "PR #5: 'Keyman-Api-Check: skip' in the middle of the line should return false"
+ builder_echo end test_is_skip_keyman_api_check success 'SUCCESS: test_is_skip_keyman_api_check'
+}
+
+#----------------------------------------------------------------------------------------------------
+
test_build_bot_verify_platforms
test_build_bot_update_commands
test_build_bot_check_messages
test_test_bot_check_pr_body
+test_is_skip_keyman_api_check
diff --git a/resources/docker-images/README.md b/resources/docker-images/README.md
index cc1b9f1b38..6c962b407c 100644
--- a/resources/docker-images/README.md
+++ b/resources/docker-images/README.md
@@ -107,3 +107,38 @@ Running tests locally with the `run.sh` looks like:
resources/docker-images/run.sh :web --registry 'myregistry:5678' --username 'user' --password 'password' -- web/build.sh test
```
+## Running GitHub Actions locally
+
+There exist [GitHub actions for building the Docker images](../../.github/workflows/build-test-publish-docker.yml).
+For testing and developing the workflow can be started locally.
+As a prerequisite [act](https://nektosact.com/) must be installed.
+
+This is an exmaple for running the workflow with act:
+
+```bash
+#!/bin/bash
+# runs GitHub workflow locally for building, testing and publishing Docker images
+# requires act (https://nektosact.com/)
+# requires a GitHub token with repo permissions (e.g. GITHUB_TOKEN from a personal access token)
+# requires Docker with buildx support
+
+tempfile=/tmp/event.json
+
+cat > ${tempfile} <' \
+ -s GITHUB_TOKEN='' \
+ --container-options "--user runner:$(getent group docker | cut -d: -f3)" \
+ -W '.github/workflows/build-test-publish-docker.yml'
+
+rm -f ${tempfile}
+```
diff --git a/resources/docker-images/build.sh b/resources/docker-images/build.sh
index 49735071a5..bd2323332c 100755
--- a/resources/docker-images/build.sh
+++ b/resources/docker-images/build.sh
@@ -69,7 +69,7 @@ publish_action() {
local platform=$1
local version_list=("${build_version}")
- builder_echo debug "publishing image for ${platform}"
+ builder_echo debug "publishing image for ${platform}."
if is_default_values; then
version_list+=("default")
diff --git a/resources/docker-images/docker-build.inc.sh b/resources/docker-images/docker-build.inc.sh
index 711d6bdb53..b020559b45 100644
--- a/resources/docker-images/docker-build.inc.sh
+++ b/resources/docker-images/docker-build.inc.sh
@@ -96,16 +96,11 @@ setup_container_registry() {
local password=${REGISTRY_PASSWORD:-}
registry_slash=''
- builder_echo debug "Setting up container registry."
+ builder_echo debug "Setting up container registry '${registry}'."
- if [[ "${registry:-}" == "docker.io" ]]; then
- builder_echo debug "Container registry is 'docker.io'."
- registry=
- else
- registry_slash="${registry}/"
- registry_parameters="--registry ${registry}"
- build_args+=("--build-arg=REGISTRY=${registry_slash}")
- fi
+ registry_slash="${registry}/"
+ registry_parameters="--registry ${registry}"
+ build_args+=("--build-arg=REGISTRY=${registry_slash}")
if [[ -n ${username:-} ]] ; then
if [[ -z ${password:-} ]] ; then
diff --git a/resources/git-hooks/prepare-commit-msg b/resources/git-hooks/prepare-commit-msg
index 4fd7bdffea..0db32abff3 100755
--- a/resources/git-hooks/prepare-commit-msg
+++ b/resources/git-hooks/prepare-commit-msg
@@ -114,18 +114,25 @@ function prepend_scope() {
fi
fi
+ commentchar="#"
+ if [[ -n "$(git config core.commentString)" ]]; then
+ commentchar="$(git config core.commentString)"
+ elif [[ -n "$(git config core.commentChar)" ]]; then
+ commentchar="$(git config core.commentChar)"
+ fi
+
postfix=$(
cat <
-# - Use imperative, present tense ('attach' not 'attaches', 'attached' etc)
-# - Don't include a period at the end of the title
-# - Always include a blank line before trailers
-# - More: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
+\n${commentchar} Keyman Conventional Commit suggestions:
+${commentchar}
+${commentchar} - Link to a Sentry issue with git trailer:
+${commentchar} Fixes: _MODULE_-_ID_
+${commentchar} - Give credit to co-authors:
+${commentchar} Co-authored-by: _Name_ <_email_>
+${commentchar} - Use imperative, present tense ('attach' not 'attaches', 'attached' etc)
+${commentchar} - Don't include a period at the end of the title
+${commentchar} - Always include a blank line before trailers
+${commentchar} - More: https://github.com/keymanapp/keyman/wiki/Pull-Request-and-Commit-workflow-notes
EOF
)
@@ -170,4 +177,4 @@ case $COMMIT_SOURCE in
# Known possibilities: message (-m), template (-t)
exit 0
;;
-esac
\ No newline at end of file
+esac
diff --git a/resources/standards-data/readme.md b/resources/standards-data/readme.md
index 51d2079929..caeff56d19 100644
--- a/resources/standards-data/readme.md
+++ b/resources/standards-data/readme.md
@@ -57,13 +57,9 @@ See also [ldml-keyboards/readme.md](ldml-keyboards/readme.md).
### unicode-character-database
-Data from :
+Data from :
-```bash
-UNICODE_VERSION=15.1.0
-wget https://www.unicode.org/Public/${UNICODE_VERSION}/ucd/Blocks.txt -O unicode-character-database/Blocks.txt
-wget https://www.unicode.org/Public/${UNICODE_VERSION}/ucd/UnicodeData.txt -O unicode-character-database/UnicodeData.txt
-```
+See [download.sh](./unicode-character-database/download.sh)
### windows-lcid-to-bcp-47
diff --git a/resources/standards-data/unicode-character-database/Blocks.txt b/resources/standards-data/unicode-character-database/Blocks.txt
index 1517dde0ce..5c24ab60cb 100644
--- a/resources/standards-data/unicode-character-database/Blocks.txt
+++ b/resources/standards-data/unicode-character-database/Blocks.txt
@@ -1,6 +1,6 @@
-# Blocks-16.0.0.txt
-# Date: 2024-02-02
-# © 2024 Unicode®, Inc.
+# Blocks-17.0.0.txt
+# Date: 2025-08-01
+# © 2025 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
@@ -228,6 +228,7 @@ FFF0..FFFF; Specials
108E0..108FF; Hatran
10900..1091F; Phoenician
10920..1093F; Lydian
+10940..1095F; Sidetic
10980..1099F; Meroitic Hieroglyphs
109A0..109FF; Meroitic Cursive
10A00..10A5F; Kharoshthi
@@ -279,11 +280,13 @@ FFF0..FFFF; Specials
11AB0..11ABF; Unified Canadian Aboriginal Syllabics Extended-A
11AC0..11AFF; Pau Cin Hau
11B00..11B5F; Devanagari Extended-A
+11B60..11B7F; Sharada Supplement
11BC0..11BFF; Sunuwar
11C00..11C6F; Bhaiksuki
11C70..11CBF; Marchen
11D00..11D5F; Masaram Gondi
11D60..11DAF; Gunjala Gondi
+11DB0..11DEF; Tolong Siki
11EE0..11EFF; Makasar
11F00..11F5F; Kawi
11FB0..11FBF; Lisu Supplement
@@ -304,12 +307,14 @@ FFF0..FFFF; Specials
16B00..16B8F; Pahawh Hmong
16D40..16D7F; Kirat Rai
16E40..16E9F; Medefaidrin
+16EA0..16EDF; Beria Erfe
16F00..16F9F; Miao
16FE0..16FFF; Ideographic Symbols and Punctuation
17000..187FF; Tangut
18800..18AFF; Tangut Components
18B00..18CFF; Khitan Small Script
18D00..18D7F; Tangut Supplement
+18D80..18DFF; Tangut Components Supplement
1AFF0..1AFFF; Kana Extended-B
1B000..1B0FF; Kana Supplement
1B100..1B12F; Kana Extended-A
@@ -318,6 +323,7 @@ FFF0..FFFF; Specials
1BC00..1BC9F; Duployan
1BCA0..1BCAF; Shorthand Format Controls
1CC00..1CEBF; Symbols for Legacy Computing Supplement
+1CEC0..1CEFF; Miscellaneous Symbols Supplement
1CF00..1CFCF; Znamenny Musical Notation
1D000..1D0FF; Byzantine Musical Symbols
1D100..1D1FF; Musical Symbols
@@ -336,6 +342,7 @@ FFF0..FFFF; Specials
1E2C0..1E2FF; Wancho
1E4D0..1E4FF; Nag Mundari
1E5D0..1E5FF; Ol Onal
+1E6C0..1E6FF; Tai Yo
1E7E0..1E7FF; Ethiopic Extended-B
1E800..1E8DF; Mende Kikakui
1E900..1E95F; Adlam
@@ -367,6 +374,7 @@ FFF0..FFFF; Specials
2F800..2FA1F; CJK Compatibility Ideographs Supplement
30000..3134F; CJK Unified Ideographs Extension G
31350..323AF; CJK Unified Ideographs Extension H
+323B0..3347F; CJK Unified Ideographs Extension J
E0000..E007F; Tags
E0100..E01EF; Variation Selectors Supplement
F0000..FFFFF; Supplementary Private Use Area-A
diff --git a/resources/standards-data/unicode-character-database/UnicodeData.txt b/resources/standards-data/unicode-character-database/UnicodeData.txt
index 64258a3739..fca68e3e15 100644
--- a/resources/standards-data/unicode-character-database/UnicodeData.txt
+++ b/resources/standards-data/unicode-character-database/UnicodeData.txt
@@ -659,7 +659,7 @@
0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7
0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;
0294;LATIN LETTER GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
-0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
+0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Lo;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;
0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;
@@ -2121,6 +2121,7 @@
088C;ARABIC LETTER TAH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
088D;ARABIC LETTER KEHEH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;
088E;ARABIC VERTICAL TAIL;Lo;0;AL;;;;;N;;;;;
+088F;ARABIC LETTER NOON WITH RING ABOVE;Lo;0;AL;;;;;N;;;;;
0890;ARABIC POUND MARK ABOVE;Cf;0;AN;;;;;N;;;;;
0891;ARABIC PIASTRE MARK ABOVE;Cf;0;AN;;;;;N;;;;;
0897;ARABIC PEPET;Mn;230;NSM;;;;;N;;;;;
@@ -2862,6 +2863,7 @@
0C58;TELUGU LETTER TSA;Lo;0;L;;;;;N;;;;;
0C59;TELUGU LETTER DZA;Lo;0;L;;;;;N;;;;;
0C5A;TELUGU LETTER RRRA;Lo;0;L;;;;;N;;;;;
+0C5C;TELUGU ARCHAIC SHRII;Lo;0;L;;;;;N;;;;;
0C5D;TELUGU LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;;
0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
@@ -2958,6 +2960,7 @@
0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;
0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CDC;KANNADA ARCHAIC SHRII;Lo;0;L;;;;;N;;;;;
0CDD;KANNADA LETTER NAKAARA POLLU;Lo;0;L;;;;;N;;;;;
0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;
0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
@@ -6137,6 +6140,33 @@
1ACC;COMBINING LATIN SMALL LETTER INSULAR G;Mn;230;NSM;;;;;N;;;;;
1ACD;COMBINING LATIN SMALL LETTER INSULAR R;Mn;230;NSM;;;;;N;;;;;
1ACE;COMBINING LATIN SMALL LETTER INSULAR T;Mn;230;NSM;;;;;N;;;;;
+1ACF;COMBINING DOUBLE CARON;Mn;230;NSM;;;;;N;;;;;
+1AD0;COMBINING VERTICAL-LINE-ACUTE;Mn;230;NSM;;;;;N;;;;;
+1AD1;COMBINING GRAVE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;
+1AD2;COMBINING VERTICAL-LINE-GRAVE;Mn;230;NSM;;;;;N;;;;;
+1AD3;COMBINING ACUTE-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;
+1AD4;COMBINING VERTICAL-LINE-MACRON;Mn;230;NSM;;;;;N;;;;;
+1AD5;COMBINING MACRON-VERTICAL-LINE;Mn;230;NSM;;;;;N;;;;;
+1AD6;COMBINING VERTICAL-LINE-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;
+1AD7;COMBINING VERTICAL-LINE-GRAVE-ACUTE;Mn;230;NSM;;;;;N;;;;;
+1AD8;COMBINING MACRON-ACUTE-GRAVE;Mn;230;NSM;;;;;N;;;;;
+1AD9;COMBINING SHARP SIGN;Mn;230;NSM;;;;;N;;;;;
+1ADA;COMBINING FLAT SIGN;Mn;230;NSM;;;;;N;;;;;
+1ADB;COMBINING DOWN TACK ABOVE;Mn;230;NSM;;;;;N;;;;;
+1ADC;COMBINING DIAERESIS WITH RAISED LEFT DOT;Mn;230;NSM;;;;;N;;;;;
+1ADD;COMBINING DOT-AND-RING BELOW;Mn;220;NSM;;;;;N;;;;;
+1AE0;COMBINING LEFT TACK ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE1;COMBINING RIGHT TACK ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE2;COMBINING MINUS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE3;COMBINING INVERTED BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE4;COMBINING SQUARE ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE5;COMBINING SEAGULL ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE6;COMBINING DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;;;;;
+1AE7;COMBINING DOUBLE ARCH ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE8;COMBINING EQUALS SIGN ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AE9;COMBINING LEFT ANGLE CENTRED ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AEA;COMBINING UPWARDS ARROW ABOVE;Mn;230;NSM;;;;;N;;;;;
+1AEB;COMBINING DOUBLE RIGHTWARDS ARROW ABOVE;Mn;234;NSM;;;;;N;;;;;
1B00;BALINESE SIGN ULU RICEM;Mn;0;NSM;;;;;N;;;;;
1B01;BALINESE SIGN ULU CANDRA;Mn;0;NSM;;;;;N;;;;;
1B02;BALINESE SIGN CECEK;Mn;0;NSM;;;;;N;;;;;
@@ -7545,6 +7575,7 @@
20BE;LARI SIGN;Sc;0;ET;;;;;N;;;;;
20BF;BITCOIN SIGN;Sc;0;ET;;;;;N;;;;;
20C0;SOM SIGN;Sc;0;ET;;;;;N;;;;;
+20C1;SAUDI RIYAL SIGN;Sc;0;ET;;;;;N;;;;;
20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
@@ -10239,6 +10270,7 @@
2B93;NEWLINE RIGHT;So;0;ON;;;;;N;;;;;
2B94;FOUR CORNER ARROWS CIRCLING ANTICLOCKWISE;So;0;ON;;;;;N;;;;;
2B95;RIGHTWARDS BLACK ARROW;So;0;ON;;;;;N;;;;;
+2B96;EQUALS SIGN WITH INFINITY ABOVE;So;0;ON;;;;;N;;;;;
2B97;SYMBOL FOR TYPE A ELECTRONICS;So;0;ON;;;;;N;;;;;
2B98;THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
2B99;THREE-D RIGHT-LIGHTED UPWARDS EQUILATERAL ARROWHEAD;So;0;ON;;;;;N;;;;;
@@ -14274,10 +14306,14 @@ A7CA;LATIN SMALL LETTER S WITH SHORT STROKE OVERLAY;Ll;0;L;;;;;N;;;A7C9;;A7C9
A7CB;LATIN CAPITAL LETTER RAMS HORN;Lu;0;L;;;;;N;;;;0264;
A7CC;LATIN CAPITAL LETTER S WITH DIAGONAL STROKE;Lu;0;L;;;;;N;;;;A7CD;
A7CD;LATIN SMALL LETTER S WITH DIAGONAL STROKE;Ll;0;L;;;;;N;;;A7CC;;A7CC
+A7CE;LATIN CAPITAL LETTER PHARYNGEAL VOICED FRICATIVE;Lu;0;L;;;;;N;;;;A7CF;
+A7CF;LATIN SMALL LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;;;A7CE;;A7CE
A7D0;LATIN CAPITAL LETTER CLOSED INSULAR G;Lu;0;L;;;;;N;;;;A7D1;
A7D1;LATIN SMALL LETTER CLOSED INSULAR G;Ll;0;L;;;;;N;;;A7D0;;A7D0
-A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;;;
-A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;;;
+A7D2;LATIN CAPITAL LETTER DOUBLE THORN;Lu;0;L;;;;;N;;;;A7D3;
+A7D3;LATIN SMALL LETTER DOUBLE THORN;Ll;0;L;;;;;N;;;A7D2;;A7D2
+A7D4;LATIN CAPITAL LETTER DOUBLE WYNN;Lu;0;L;;;;;N;;;;A7D5;
+A7D5;LATIN SMALL LETTER DOUBLE WYNN;Ll;0;L;;;;;N;;;A7D4;;A7D4
A7D6;LATIN CAPITAL LETTER MIDDLE SCOTS S;Lu;0;L;;;;;N;;;;A7D7;
A7D7;LATIN SMALL LETTER MIDDLE SCOTS S;Ll;0;L;;;;;N;;;A7D6;;A7D6
A7D8;LATIN CAPITAL LETTER SIGMOID S;Lu;0;L;;;;;N;;;;A7D9;
@@ -14285,6 +14321,7 @@ A7D9;LATIN SMALL LETTER SIGMOID S;Ll;0;L;;;;;N;;;A7D8;;A7D8
A7DA;LATIN CAPITAL LETTER LAMBDA;Lu;0;L;;;;;N;;;;A7DB;
A7DB;LATIN SMALL LETTER LAMBDA;Ll;0;L;;;;;N;;;A7DA;;A7DA
A7DC;LATIN CAPITAL LETTER LAMBDA WITH STROKE;Lu;0;L;;;;;N;;;;019B;
+A7F1;MODIFIER LETTER CAPITAL S;Lm;0;L; 0053;;;;N;;;;;
A7F2;MODIFIER LETTER CAPITAL C;Lm;0;L; 0043;;;;N;;;;;
A7F3;MODIFIER LETTER CAPITAL F;Lm;0;L; 0046;;;;N;;;;;
A7F4;MODIFIER LETTER CAPITAL Q;Lm;0;L; 0051;;;;N;;;;;
@@ -15925,6 +15962,22 @@ FBBF;ARABIC SYMBOL RING;Sk;0;AL;;;;;N;;;;;
FBC0;ARABIC SYMBOL SMALL TAH ABOVE;Sk;0;AL;;;;;N;;;;;
FBC1;ARABIC SYMBOL SMALL TAH BELOW;Sk;0;AL;;;;;N;;;;;
FBC2;ARABIC SYMBOL WASLA ABOVE;Sk;0;AL;;;;;N;;;;;
+FBC3;ARABIC LIGATURE JALLA WA-ALAA;So;0;ON;;;;;N;;;;;
+FBC4;ARABIC LIGATURE DAAMAT BARAKAATUHUM;So;0;ON;;;;;N;;;;;
+FBC5;ARABIC LIGATURE RAHMATU ALLAAHI TAAALAA ALAYH;So;0;ON;;;;;N;;;;;
+FBC6;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIM;So;0;ON;;;;;N;;;;;
+FBC7;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHIMAA;So;0;ON;;;;;N;;;;;
+FBC8;ARABIC LIGATURE RAHIMAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;
+FBC9;ARABIC LIGATURE RAHIMAHUMAA ALLAAH;So;0;ON;;;;;N;;;;;
+FBCA;ARABIC LIGATURE RAHIMAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;
+FBCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUM;So;0;ON;;;;;N;;;;;
+FBCC;ARABIC LIGATURE HAFIZAHU ALLAAH;So;0;ON;;;;;N;;;;;
+FBCD;ARABIC LIGATURE HAFIZAHU ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;
+FBCE;ARABIC LIGATURE HAFIZAHUM ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;
+FBCF;ARABIC LIGATURE HAFIZAHUMAA ALLAAHU TAAALAA;So;0;ON;;;;;N;;;;;
+FBD0;ARABIC LIGATURE SALLALLAAHU TAAALAA ALAYHI WA-SALLAM;So;0;ON;;;;;N;;;;;
+FBD1;ARABIC LIGATURE AJJAL ALLAAHU FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;;
+FBD2;ARABIC LIGATURE ALAYHI AR-RAHMAH;So;0;ON;;;;;N;;;;;
FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL; 06AD;;;;N;;;;;
FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL; 06AD;;;;N;;;;;
FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL; 06AD;;;;N;;;;;
@@ -16370,6 +16423,8 @@ FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL; 0645
FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062C 0645;;;;N;;;;;
FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL; 0645 062E 062C;;;;N;;;;;
FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL; 0645 062E 0645;;;;N;;;;;
+FD90;ARABIC LIGATURE RAHMATU ALLAAHI ALAYH;So;0;ON;;;;;N;;;;;
+FD91;ARABIC LIGATURE RAHMATU ALLAAHI ALAYHAA;So;0;ON;;;;;N;;;;;
FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL; 0645 062C 062E;;;;N;;;;;
FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL; 0647 0645 062C;;;;N;;;;;
FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0647 0645 0645;;;;N;;;;;
@@ -16424,6 +16479,13 @@ FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0639
FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL; 0635 0645 0645;;;;N;;;;;
FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL; 0633 062E 064A;;;;N;;;;;
FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL; 0646 062C 064A;;;;N;;;;;
+FDC8;ARABIC LIGATURE RAHIMAHU ALLAAH TAAALAA;So;0;ON;;;;;N;;;;;
+FDC9;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANH;So;0;ON;;;;;N;;;;;
+FDCA;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHAA;So;0;ON;;;;;N;;;;;
+FDCB;ARABIC LIGATURE RADI ALLAAHU TAAALAA ANHUMAA;So;0;ON;;;;;N;;;;;
+FDCC;ARABIC LIGATURE SALLALLAHU ALAYHI WA-ALAA AALIHEE WA-SALLAM;So;0;ON;;;;;N;;;;;
+FDCD;ARABIC LIGATURE AJJAL ALLAAHU TAAALAA FARAJAHU ASH-SHAREEF;So;0;ON;;;;;N;;;;;
+FDCE;ARABIC LIGATURE KARRAMA ALLAAHU WAJHAH;So;0;ON;;;;;N;;;;;
FDCF;ARABIC LIGATURE SALAAMUHU ALAYNAA;So;0;ON;;;;;N;;;;;
FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0635 0644 06D2;;;;N;;;;;
FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL; 0642 0644 06D2;;;;N;;;;;
@@ -18708,6 +18770,32 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10938;LYDIAN LETTER NN;Lo;0;R;;;;;N;;;;;
10939;LYDIAN LETTER C;Lo;0;R;;;;;N;;;;;
1093F;LYDIAN TRIANGULAR MARK;Po;0;R;;;;;N;;;;;
+10940;SIDETIC LETTER N01;Lo;0;R;;;;;N;;;;;
+10941;SIDETIC LETTER N02;Lo;0;R;;;;;N;;;;;
+10942;SIDETIC LETTER N03;Lo;0;R;;;;;N;;;;;
+10943;SIDETIC LETTER N04;Lo;0;R;;;;;N;;;;;
+10944;SIDETIC LETTER N05;Lo;0;R;;;;;N;;;;;
+10945;SIDETIC LETTER N06;Lo;0;R;;;;;N;;;;;
+10946;SIDETIC LETTER N07;Lo;0;R;;;;;N;;;;;
+10947;SIDETIC LETTER N08;Lo;0;R;;;;;N;;;;;
+10948;SIDETIC LETTER N09;Lo;0;R;;;;;N;;;;;
+10949;SIDETIC LETTER N10;Lo;0;R;;;;;N;;;;;
+1094A;SIDETIC LETTER N11;Lo;0;R;;;;;N;;;;;
+1094B;SIDETIC LETTER N12;Lo;0;R;;;;;N;;;;;
+1094C;SIDETIC LETTER N13;Lo;0;R;;;;;N;;;;;
+1094D;SIDETIC LETTER N14;Lo;0;R;;;;;N;;;;;
+1094E;SIDETIC LETTER N15;Lo;0;R;;;;;N;;;;;
+1094F;SIDETIC LETTER N16;Lo;0;R;;;;;N;;;;;
+10950;SIDETIC LETTER N17;Lo;0;R;;;;;N;;;;;
+10951;SIDETIC LETTER N18;Lo;0;R;;;;;N;;;;;
+10952;SIDETIC LETTER N19;Lo;0;R;;;;;N;;;;;
+10953;SIDETIC LETTER N20;Lo;0;R;;;;;N;;;;;
+10954;SIDETIC LETTER N21;Lo;0;R;;;;;N;;;;;
+10955;SIDETIC LETTER N22;Lo;0;R;;;;;N;;;;;
+10956;SIDETIC LETTER N23;Lo;0;R;;;;;N;;;;;
+10957;SIDETIC LETTER N24;Lo;0;R;;;;;N;;;;;
+10958;SIDETIC LETTER N25;Lo;0;R;;;;;N;;;;;
+10959;SIDETIC LETTER N26;Lo;0;R;;;;;N;;;;;
10980;MEROITIC HIEROGLYPHIC LETTER A;Lo;0;R;;;;;N;;;;;
10981;MEROITIC HIEROGLYPHIC LETTER E;Lo;0;R;;;;;N;;;;;
10982;MEROITIC HIEROGLYPHIC LETTER I;Lo;0;R;;;;;N;;;;;
@@ -19541,6 +19629,20 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10EC2;ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;
10EC3;ARABIC LETTER TAH WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;
10EC4;ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW;Lo;0;AL;;;;;N;;;;;
+10EC5;ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW;Lm;0;AL;;;;;N;;;;;
+10EC6;ARABIC LETTER THIN NOON;Lo;0;AL;;;;;N;;;;;
+10EC7;ARABIC LETTER YEH WITH FOUR DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+10ED0;ARABIC BIBLICAL END OF VERSE;Po;0;ON;;;;;N;;;;;
+10ED1;ARABIC LIGATURE ALAYHAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;
+10ED2;ARABIC LIGATURE ALAYHIM AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;
+10ED3;ARABIC LIGATURE ALAYHIMAA AS-SALAATU WAS-SALAAM;So;0;ON;;;;;N;;;;;
+10ED4;ARABIC LIGATURE QADDASA ALLAAHU SIRRAH;So;0;ON;;;;;N;;;;;
+10ED5;ARABIC LIGATURE QUDDISA SIRRUHUM;So;0;ON;;;;;N;;;;;
+10ED6;ARABIC LIGATURE QUDDISA SIRRUHUMAA;So;0;ON;;;;;N;;;;;
+10ED7;ARABIC LIGATURE QUDDISAT ASRAARUHUM;So;0;ON;;;;;N;;;;;
+10ED8;ARABIC LIGATURE NAWWARA ALLAAHU MARQADAH;So;0;ON;;;;;N;;;;;
+10EFA;ARABIC DOUBLE VERTICAL BAR BELOW;Mn;220;NSM;;;;;N;;;;;
+10EFB;ARABIC SMALL LOW NOON;Mn;220;NSM;;;;;N;;;;;
10EFC;ARABIC COMBINING ALEF OVERLAY;Mn;0;NSM;;;;;N;;;;;
10EFD;ARABIC SMALL LOW WORD SAKTA;Mn;220;NSM;;;;;N;;;;;
10EFE;ARABIC SMALL LOW WORD QASR;Mn;220;NSM;;;;;N;;;;;
@@ -21521,6 +21623,14 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11B07;DEVANAGARI SIGN WESTERN NINE-LIKE BHALE;Po;0;L;;;;;N;;;;;
11B08;DEVANAGARI SIGN REVERSED NINE-LIKE BHALE;Po;0;L;;;;;N;;;;;
11B09;DEVANAGARI SIGN MINDU;Po;0;L;;;;;N;;;;;
+11B60;SHARADA VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
+11B61;SHARADA VOWEL SIGN OOE;Mc;0;L;;;;;N;;;;;
+11B62;SHARADA VOWEL SIGN UE;Mn;0;NSM;;;;;N;;;;;
+11B63;SHARADA VOWEL SIGN UUE;Mn;0;NSM;;;;;N;;;;;
+11B64;SHARADA VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+11B65;SHARADA VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+11B66;SHARADA VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+11B67;SHARADA VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
11BC0;SUNUWAR LETTER DEVI;Lo;0;L;;;;;N;;;;;
11BC1;SUNUWAR LETTER TASLA;Lo;0;L;;;;;N;;;;;
11BC2;SUNUWAR LETTER EKO;Lo;0;L;;;;;N;;;;;
@@ -21868,6 +21978,60 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11DB0;TOLONG SIKI LETTER I;Lo;0;L;;;;;N;;;;;
+11DB1;TOLONG SIKI LETTER E;Lo;0;L;;;;;N;;;;;
+11DB2;TOLONG SIKI LETTER U;Lo;0;L;;;;;N;;;;;
+11DB3;TOLONG SIKI LETTER O;Lo;0;L;;;;;N;;;;;
+11DB4;TOLONG SIKI LETTER A;Lo;0;L;;;;;N;;;;;
+11DB5;TOLONG SIKI LETTER AA;Lo;0;L;;;;;N;;;;;
+11DB6;TOLONG SIKI LETTER P;Lo;0;L;;;;;N;;;;;
+11DB7;TOLONG SIKI LETTER PH;Lo;0;L;;;;;N;;;;;
+11DB8;TOLONG SIKI LETTER B;Lo;0;L;;;;;N;;;;;
+11DB9;TOLONG SIKI LETTER BH;Lo;0;L;;;;;N;;;;;
+11DBA;TOLONG SIKI LETTER M;Lo;0;L;;;;;N;;;;;
+11DBB;TOLONG SIKI LETTER T;Lo;0;L;;;;;N;;;;;
+11DBC;TOLONG SIKI LETTER TH;Lo;0;L;;;;;N;;;;;
+11DBD;TOLONG SIKI LETTER D;Lo;0;L;;;;;N;;;;;
+11DBE;TOLONG SIKI LETTER DH;Lo;0;L;;;;;N;;;;;
+11DBF;TOLONG SIKI LETTER N;Lo;0;L;;;;;N;;;;;
+11DC0;TOLONG SIKI LETTER TT;Lo;0;L;;;;;N;;;;;
+11DC1;TOLONG SIKI LETTER TTH;Lo;0;L;;;;;N;;;;;
+11DC2;TOLONG SIKI LETTER DD;Lo;0;L;;;;;N;;;;;
+11DC3;TOLONG SIKI LETTER DDH;Lo;0;L;;;;;N;;;;;
+11DC4;TOLONG SIKI LETTER NN;Lo;0;L;;;;;N;;;;;
+11DC5;TOLONG SIKI LETTER C;Lo;0;L;;;;;N;;;;;
+11DC6;TOLONG SIKI LETTER CH;Lo;0;L;;;;;N;;;;;
+11DC7;TOLONG SIKI LETTER J;Lo;0;L;;;;;N;;;;;
+11DC8;TOLONG SIKI LETTER JH;Lo;0;L;;;;;N;;;;;
+11DC9;TOLONG SIKI LETTER NY;Lo;0;L;;;;;N;;;;;
+11DCA;TOLONG SIKI LETTER K;Lo;0;L;;;;;N;;;;;
+11DCB;TOLONG SIKI LETTER KH;Lo;0;L;;;;;N;;;;;
+11DCC;TOLONG SIKI LETTER G;Lo;0;L;;;;;N;;;;;
+11DCD;TOLONG SIKI LETTER GH;Lo;0;L;;;;;N;;;;;
+11DCE;TOLONG SIKI LETTER NG;Lo;0;L;;;;;N;;;;;
+11DCF;TOLONG SIKI LETTER Y;Lo;0;L;;;;;N;;;;;
+11DD0;TOLONG SIKI LETTER R;Lo;0;L;;;;;N;;;;;
+11DD1;TOLONG SIKI LETTER L;Lo;0;L;;;;;N;;;;;
+11DD2;TOLONG SIKI LETTER V;Lo;0;L;;;;;N;;;;;
+11DD3;TOLONG SIKI LETTER NNY;Lo;0;L;;;;;N;;;;;
+11DD4;TOLONG SIKI LETTER S;Lo;0;L;;;;;N;;;;;
+11DD5;TOLONG SIKI LETTER H;Lo;0;L;;;;;N;;;;;
+11DD6;TOLONG SIKI LETTER X;Lo;0;L;;;;;N;;;;;
+11DD7;TOLONG SIKI LETTER RR;Lo;0;L;;;;;N;;;;;
+11DD8;TOLONG SIKI LETTER RRH;Lo;0;L;;;;;N;;;;;
+11DD9;TOLONG SIKI SIGN SELA;Lm;0;L;;;;;N;;;;;
+11DDA;TOLONG SIKI SIGN HECAKA;Lo;0;L;;;;;N;;;;;
+11DDB;TOLONG SIKI UNGGA;Lo;0;L;;;;;N;;;;;
+11DE0;TOLONG SIKI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11DE1;TOLONG SIKI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11DE2;TOLONG SIKI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11DE3;TOLONG SIKI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11DE4;TOLONG SIKI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11DE5;TOLONG SIKI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11DE6;TOLONG SIKI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11DE7;TOLONG SIKI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11DE8;TOLONG SIKI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11DE9;TOLONG SIKI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;;
11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;;
11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;;
@@ -22088,8 +22252,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
12035;CUNEIFORM SIGN ARAD TIMES KUR;Lo;0;L;;;;;N;;;;;
12036;CUNEIFORM SIGN ARKAB;Lo;0;L;;;;;N;;;;;
12037;CUNEIFORM SIGN ASAL2;Lo;0;L;;;;;N;;;;;
-12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;;N;;;;;
-12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;;N;;;;;
+12038;CUNEIFORM SIGN ASH;Lo;0;L;;;;1;N;;;;;
+12039;CUNEIFORM SIGN ASH ZIDA TENU;Lo;0;L;;;;1;N;;;;;
1203A;CUNEIFORM SIGN ASH KABA TENU;Lo;0;L;;;;;N;;;;;
1203B;CUNEIFORM SIGN ASH OVER ASH TUG2 OVER TUG2 TUG2 OVER TUG2 PAP;Lo;0;L;;;;;N;;;;;
1203C;CUNEIFORM SIGN ASH OVER ASH OVER ASH;Lo;0;L;;;;;N;;;;;
@@ -22153,7 +22317,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
12076;CUNEIFORM SIGN DIM2;Lo;0;L;;;;;N;;;;;
12077;CUNEIFORM SIGN DIN;Lo;0;L;;;;;N;;;;;
12078;CUNEIFORM SIGN DIN KASKAL U GUNU DISH;Lo;0;L;;;;;N;;;;;
-12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;;N;;;;;
+12079;CUNEIFORM SIGN DISH;Lo;0;L;;;;1;N;;;;;
1207A;CUNEIFORM SIGN DU;Lo;0;L;;;;;N;;;;;
1207B;CUNEIFORM SIGN DU OVER DU;Lo;0;L;;;;;N;;;;;
1207C;CUNEIFORM SIGN DU GUNU;Lo;0;L;;;;;N;;;;;
@@ -22582,12 +22746,12 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
12223;CUNEIFORM SIGN MA2;Lo;0;L;;;;;N;;;;;
12224;CUNEIFORM SIGN MAH;Lo;0;L;;;;;N;;;;;
12225;CUNEIFORM SIGN MAR;Lo;0;L;;;;;N;;;;;
-12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;;N;;;;;
+12226;CUNEIFORM SIGN MASH;Lo;0;L;;;;1/2;N;;;;;
12227;CUNEIFORM SIGN MASH2;Lo;0;L;;;;;N;;;;;
12228;CUNEIFORM SIGN ME;Lo;0;L;;;;;N;;;;;
12229;CUNEIFORM SIGN MES;Lo;0;L;;;;;N;;;;;
1222A;CUNEIFORM SIGN MI;Lo;0;L;;;;;N;;;;;
-1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;;N;;;;;
+1222B;CUNEIFORM SIGN MIN;Lo;0;L;;;;2;N;;;;;
1222C;CUNEIFORM SIGN MU;Lo;0;L;;;;;N;;;;;
1222D;CUNEIFORM SIGN MU OVER MU;Lo;0;L;;;;;N;;;;;
1222E;CUNEIFORM SIGN MUG;Lo;0;L;;;;;N;;;;;
@@ -22811,9 +22975,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
12308;CUNEIFORM SIGN TUM;Lo;0;L;;;;;N;;;;;
12309;CUNEIFORM SIGN TUR;Lo;0;L;;;;;N;;;;;
1230A;CUNEIFORM SIGN TUR OVER TUR ZA OVER ZA;Lo;0;L;;;;;N;;;;;
-1230B;CUNEIFORM SIGN U;Lo;0;L;;;;;N;;;;;
+1230B;CUNEIFORM SIGN U;Lo;0;L;;;;1;N;;;;;
1230C;CUNEIFORM SIGN U GUD;Lo;0;L;;;;;N;;;;;
-1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;;N;;;;;
+1230D;CUNEIFORM SIGN U U U;Lo;0;L;;;;3;N;;;;;
1230E;CUNEIFORM SIGN U OVER U PA OVER PA GAR OVER GAR;Lo;0;L;;;;;N;;;;;
1230F;CUNEIFORM SIGN U OVER U SUR OVER SUR;Lo;0;L;;;;;N;;;;;
12310;CUNEIFORM SIGN U OVER U U REVERSED OVER U REVERSED;Lo;0;L;;;;;N;;;;;
@@ -22953,7 +23117,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
12396;CUNEIFORM SIGN SAG TIMES IGI GUNU;Lo;0;L;;;;;N;;;;;
12397;CUNEIFORM SIGN TI2;Lo;0;L;;;;;N;;;;;
12398;CUNEIFORM SIGN UM TIMES ME;Lo;0;L;;;;;N;;;;;
-12399;CUNEIFORM SIGN U U;Lo;0;L;;;;;N;;;;;
+12399;CUNEIFORM SIGN U U;Lo;0;L;;;;2;N;;;;;
12400;CUNEIFORM NUMERIC SIGN TWO ASH;Nl;0;L;;;;2;N;;;;;
12401;CUNEIFORM NUMERIC SIGN THREE ASH;Nl;0;L;;;;3;N;;;;;
12402;CUNEIFORM NUMERIC SIGN FOUR ASH;Nl;0;L;;;;4;N;;;;;
@@ -30124,6 +30288,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;;
16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;;
16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;;
+16EA0;BERIA ERFE CAPITAL LETTER ARKAB;Lu;0;L;;;;;N;;;;16EBB;
+16EA1;BERIA ERFE CAPITAL LETTER BASIGNA;Lu;0;L;;;;;N;;;;16EBC;
+16EA2;BERIA ERFE CAPITAL LETTER DARBAI;Lu;0;L;;;;;N;;;;16EBD;
+16EA3;BERIA ERFE CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;16EBE;
+16EA4;BERIA ERFE CAPITAL LETTER FITKO;Lu;0;L;;;;;N;;;;16EBF;
+16EA5;BERIA ERFE CAPITAL LETTER GOWAY;Lu;0;L;;;;;N;;;;16EC0;
+16EA6;BERIA ERFE CAPITAL LETTER HIRDEABO;Lu;0;L;;;;;N;;;;16EC1;
+16EA7;BERIA ERFE CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16EC2;
+16EA8;BERIA ERFE CAPITAL LETTER DJAI;Lu;0;L;;;;;N;;;;16EC3;
+16EA9;BERIA ERFE CAPITAL LETTER KOBO;Lu;0;L;;;;;N;;;;16EC4;
+16EAA;BERIA ERFE CAPITAL LETTER LAKKO;Lu;0;L;;;;;N;;;;16EC5;
+16EAB;BERIA ERFE CAPITAL LETTER MERI;Lu;0;L;;;;;N;;;;16EC6;
+16EAC;BERIA ERFE CAPITAL LETTER NINI;Lu;0;L;;;;;N;;;;16EC7;
+16EAD;BERIA ERFE CAPITAL LETTER GNA;Lu;0;L;;;;;N;;;;16EC8;
+16EAE;BERIA ERFE CAPITAL LETTER NGAY;Lu;0;L;;;;;N;;;;16EC9;
+16EAF;BERIA ERFE CAPITAL LETTER OI;Lu;0;L;;;;;N;;;;16ECA;
+16EB0;BERIA ERFE CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;16ECB;
+16EB1;BERIA ERFE CAPITAL LETTER ERIGO;Lu;0;L;;;;;N;;;;16ECC;
+16EB2;BERIA ERFE CAPITAL LETTER ERIGO TAMURA;Lu;0;L;;;;;N;;;;16ECD;
+16EB3;BERIA ERFE CAPITAL LETTER SERI;Lu;0;L;;;;;N;;;;16ECE;
+16EB4;BERIA ERFE CAPITAL LETTER SHEP;Lu;0;L;;;;;N;;;;16ECF;
+16EB5;BERIA ERFE CAPITAL LETTER TATASOUE;Lu;0;L;;;;;N;;;;16ED0;
+16EB6;BERIA ERFE CAPITAL LETTER UI;Lu;0;L;;;;;N;;;;16ED1;
+16EB7;BERIA ERFE CAPITAL LETTER WASSE;Lu;0;L;;;;;N;;;;16ED2;
+16EB8;BERIA ERFE CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;16ED3;
+16EBB;BERIA ERFE SMALL LETTER ARKAB;Ll;0;L;;;;;N;;;16EA0;;16EA0
+16EBC;BERIA ERFE SMALL LETTER BASIGNA;Ll;0;L;;;;;N;;;16EA1;;16EA1
+16EBD;BERIA ERFE SMALL LETTER DARBAI;Ll;0;L;;;;;N;;;16EA2;;16EA2
+16EBE;BERIA ERFE SMALL LETTER EH;Ll;0;L;;;;;N;;;16EA3;;16EA3
+16EBF;BERIA ERFE SMALL LETTER FITKO;Ll;0;L;;;;;N;;;16EA4;;16EA4
+16EC0;BERIA ERFE SMALL LETTER GOWAY;Ll;0;L;;;;;N;;;16EA5;;16EA5
+16EC1;BERIA ERFE SMALL LETTER HIRDEABO;Ll;0;L;;;;;N;;;16EA6;;16EA6
+16EC2;BERIA ERFE SMALL LETTER I;Ll;0;L;;;;;N;;;16EA7;;16EA7
+16EC3;BERIA ERFE SMALL LETTER DJAI;Ll;0;L;;;;;N;;;16EA8;;16EA8
+16EC4;BERIA ERFE SMALL LETTER KOBO;Ll;0;L;;;;;N;;;16EA9;;16EA9
+16EC5;BERIA ERFE SMALL LETTER LAKKO;Ll;0;L;;;;;N;;;16EAA;;16EAA
+16EC6;BERIA ERFE SMALL LETTER MERI;Ll;0;L;;;;;N;;;16EAB;;16EAB
+16EC7;BERIA ERFE SMALL LETTER NINI;Ll;0;L;;;;;N;;;16EAC;;16EAC
+16EC8;BERIA ERFE SMALL LETTER GNA;Ll;0;L;;;;;N;;;16EAD;;16EAD
+16EC9;BERIA ERFE SMALL LETTER NGAY;Ll;0;L;;;;;N;;;16EAE;;16EAE
+16ECA;BERIA ERFE SMALL LETTER OI;Ll;0;L;;;;;N;;;16EAF;;16EAF
+16ECB;BERIA ERFE SMALL LETTER PI;Ll;0;L;;;;;N;;;16EB0;;16EB0
+16ECC;BERIA ERFE SMALL LETTER ERIGO;Ll;0;L;;;;;N;;;16EB1;;16EB1
+16ECD;BERIA ERFE SMALL LETTER ERIGO TAMURA;Ll;0;L;;;;;N;;;16EB2;;16EB2
+16ECE;BERIA ERFE SMALL LETTER SERI;Ll;0;L;;;;;N;;;16EB3;;16EB3
+16ECF;BERIA ERFE SMALL LETTER SHEP;Ll;0;L;;;;;N;;;16EB4;;16EB4
+16ED0;BERIA ERFE SMALL LETTER TATASOUE;Ll;0;L;;;;;N;;;16EB5;;16EB5
+16ED1;BERIA ERFE SMALL LETTER UI;Ll;0;L;;;;;N;;;16EB6;;16EB6
+16ED2;BERIA ERFE SMALL LETTER WASSE;Ll;0;L;;;;;N;;;16EB7;;16EB7
+16ED3;BERIA ERFE SMALL LETTER AY;Ll;0;L;;;;;N;;;16EB8;;16EB8
16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;;
16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;;
16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;;
@@ -30280,8 +30494,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16FE4;KHITAN SMALL SCRIPT FILLER;Mn;0;NSM;;;;;N;;;;;
16FF0;VIETNAMESE ALTERNATE READING MARK CA;Mc;6;L;;;;;N;;;;;
16FF1;VIETNAMESE ALTERNATE READING MARK NHAY;Mc;6;L;;;;;N;;;;;
+16FF2;CHINESE SMALL SIMPLIFIED ER;Lm;0;L;;;;;N;;;;;
+16FF3;CHINESE SMALL TRADITIONAL ER;Lm;0;L;;;;;N;;;;;
+16FF4;YANGQIN SIGN SLOW ONE BEAT;Nl;0;L;;;;1;N;;;;;
+16FF5;YANGQIN SIGN SLOW THREE HALF BEATS;Nl;0;L;;;;3/2;N;;;;;
+16FF6;YANGQIN SIGN SLOW TWO BEATS;Nl;0;L;;;;2;N;;;;;
17000;;Lo;0;L;;;;;N;;;;;
-187F7;;Lo;0;L;;;;;N;;;;;
+187FF;;Lo;0;L;;;;;N;;;;;
18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;
18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;;
18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;;
@@ -31522,7 +31741,122 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
18CD5;KHITAN SMALL SCRIPT CHARACTER-18CD5;Lo;0;L;;;;;N;;;;;
18CFF;KHITAN SMALL SCRIPT CHARACTER-18CFF;Lo;0;L;;;;;N;;;;;
18D00;;Lo;0;L;;;;;N;;;;;
-18D08;;Lo;0;L;;;;;N;;;;;
+18D1E;;Lo;0;L;;;;;N;;;;;
+18D80;TANGUT COMPONENT-769;Lo;0;L;;;;;N;;;;;
+18D81;TANGUT COMPONENT-770;Lo;0;L;;;;;N;;;;;
+18D82;TANGUT COMPONENT-771;Lo;0;L;;;;;N;;;;;
+18D83;TANGUT COMPONENT-772;Lo;0;L;;;;;N;;;;;
+18D84;TANGUT COMPONENT-773;Lo;0;L;;;;;N;;;;;
+18D85;TANGUT COMPONENT-774;Lo;0;L;;;;;N;;;;;
+18D86;TANGUT COMPONENT-775;Lo;0;L;;;;;N;;;;;
+18D87;TANGUT COMPONENT-776;Lo;0;L;;;;;N;;;;;
+18D88;TANGUT COMPONENT-777;Lo;0;L;;;;;N;;;;;
+18D89;TANGUT COMPONENT-778;Lo;0;L;;;;;N;;;;;
+18D8A;TANGUT COMPONENT-779;Lo;0;L;;;;;N;;;;;
+18D8B;TANGUT COMPONENT-780;Lo;0;L;;;;;N;;;;;
+18D8C;TANGUT COMPONENT-781;Lo;0;L;;;;;N;;;;;
+18D8D;TANGUT COMPONENT-782;Lo;0;L;;;;;N;;;;;
+18D8E;TANGUT COMPONENT-783;Lo;0;L;;;;;N;;;;;
+18D8F;TANGUT COMPONENT-784;Lo;0;L;;;;;N;;;;;
+18D90;TANGUT COMPONENT-785;Lo;0;L;;;;;N;;;;;
+18D91;TANGUT COMPONENT-786;Lo;0;L;;;;;N;;;;;
+18D92;TANGUT COMPONENT-787;Lo;0;L;;;;;N;;;;;
+18D93;TANGUT COMPONENT-788;Lo;0;L;;;;;N;;;;;
+18D94;TANGUT COMPONENT-789;Lo;0;L;;;;;N;;;;;
+18D95;TANGUT COMPONENT-790;Lo;0;L;;;;;N;;;;;
+18D96;TANGUT COMPONENT-791;Lo;0;L;;;;;N;;;;;
+18D97;TANGUT COMPONENT-792;Lo;0;L;;;;;N;;;;;
+18D98;TANGUT COMPONENT-793;Lo;0;L;;;;;N;;;;;
+18D99;TANGUT COMPONENT-794;Lo;0;L;;;;;N;;;;;
+18D9A;TANGUT COMPONENT-795;Lo;0;L;;;;;N;;;;;
+18D9B;TANGUT COMPONENT-796;Lo;0;L;;;;;N;;;;;
+18D9C;TANGUT COMPONENT-797;Lo;0;L;;;;;N;;;;;
+18D9D;TANGUT COMPONENT-798;Lo;0;L;;;;;N;;;;;
+18D9E;TANGUT COMPONENT-799;Lo;0;L;;;;;N;;;;;
+18D9F;TANGUT COMPONENT-800;Lo;0;L;;;;;N;;;;;
+18DA0;TANGUT COMPONENT-801;Lo;0;L;;;;;N;;;;;
+18DA1;TANGUT COMPONENT-802;Lo;0;L;;;;;N;;;;;
+18DA2;TANGUT COMPONENT-803;Lo;0;L;;;;;N;;;;;
+18DA3;TANGUT COMPONENT-804;Lo;0;L;;;;;N;;;;;
+18DA4;TANGUT COMPONENT-805;Lo;0;L;;;;;N;;;;;
+18DA5;TANGUT COMPONENT-806;Lo;0;L;;;;;N;;;;;
+18DA6;TANGUT COMPONENT-807;Lo;0;L;;;;;N;;;;;
+18DA7;TANGUT COMPONENT-808;Lo;0;L;;;;;N;;;;;
+18DA8;TANGUT COMPONENT-809;Lo;0;L;;;;;N;;;;;
+18DA9;TANGUT COMPONENT-810;Lo;0;L;;;;;N;;;;;
+18DAA;TANGUT COMPONENT-811;Lo;0;L;;;;;N;;;;;
+18DAB;TANGUT COMPONENT-812;Lo;0;L;;;;;N;;;;;
+18DAC;TANGUT COMPONENT-813;Lo;0;L;;;;;N;;;;;
+18DAD;TANGUT COMPONENT-814;Lo;0;L;;;;;N;;;;;
+18DAE;TANGUT COMPONENT-815;Lo;0;L;;;;;N;;;;;
+18DAF;TANGUT COMPONENT-816;Lo;0;L;;;;;N;;;;;
+18DB0;TANGUT COMPONENT-817;Lo;0;L;;;;;N;;;;;
+18DB1;TANGUT COMPONENT-818;Lo;0;L;;;;;N;;;;;
+18DB2;TANGUT COMPONENT-819;Lo;0;L;;;;;N;;;;;
+18DB3;TANGUT COMPONENT-820;Lo;0;L;;;;;N;;;;;
+18DB4;TANGUT COMPONENT-821;Lo;0;L;;;;;N;;;;;
+18DB5;TANGUT COMPONENT-822;Lo;0;L;;;;;N;;;;;
+18DB6;TANGUT COMPONENT-823;Lo;0;L;;;;;N;;;;;
+18DB7;TANGUT COMPONENT-824;Lo;0;L;;;;;N;;;;;
+18DB8;TANGUT COMPONENT-825;Lo;0;L;;;;;N;;;;;
+18DB9;TANGUT COMPONENT-826;Lo;0;L;;;;;N;;;;;
+18DBA;TANGUT COMPONENT-827;Lo;0;L;;;;;N;;;;;
+18DBB;TANGUT COMPONENT-828;Lo;0;L;;;;;N;;;;;
+18DBC;TANGUT COMPONENT-829;Lo;0;L;;;;;N;;;;;
+18DBD;TANGUT COMPONENT-830;Lo;0;L;;;;;N;;;;;
+18DBE;TANGUT COMPONENT-831;Lo;0;L;;;;;N;;;;;
+18DBF;TANGUT COMPONENT-832;Lo;0;L;;;;;N;;;;;
+18DC0;TANGUT COMPONENT-833;Lo;0;L;;;;;N;;;;;
+18DC1;TANGUT COMPONENT-834;Lo;0;L;;;;;N;;;;;
+18DC2;TANGUT COMPONENT-835;Lo;0;L;;;;;N;;;;;
+18DC3;TANGUT COMPONENT-836;Lo;0;L;;;;;N;;;;;
+18DC4;TANGUT COMPONENT-837;Lo;0;L;;;;;N;;;;;
+18DC5;TANGUT COMPONENT-838;Lo;0;L;;;;;N;;;;;
+18DC6;TANGUT COMPONENT-839;Lo;0;L;;;;;N;;;;;
+18DC7;TANGUT COMPONENT-840;Lo;0;L;;;;;N;;;;;
+18DC8;TANGUT COMPONENT-841;Lo;0;L;;;;;N;;;;;
+18DC9;TANGUT COMPONENT-842;Lo;0;L;;;;;N;;;;;
+18DCA;TANGUT COMPONENT-843;Lo;0;L;;;;;N;;;;;
+18DCB;TANGUT COMPONENT-844;Lo;0;L;;;;;N;;;;;
+18DCC;TANGUT COMPONENT-845;Lo;0;L;;;;;N;;;;;
+18DCD;TANGUT COMPONENT-846;Lo;0;L;;;;;N;;;;;
+18DCE;TANGUT COMPONENT-847;Lo;0;L;;;;;N;;;;;
+18DCF;TANGUT COMPONENT-848;Lo;0;L;;;;;N;;;;;
+18DD0;TANGUT COMPONENT-849;Lo;0;L;;;;;N;;;;;
+18DD1;TANGUT COMPONENT-850;Lo;0;L;;;;;N;;;;;
+18DD2;TANGUT COMPONENT-851;Lo;0;L;;;;;N;;;;;
+18DD3;TANGUT COMPONENT-852;Lo;0;L;;;;;N;;;;;
+18DD4;TANGUT COMPONENT-853;Lo;0;L;;;;;N;;;;;
+18DD5;TANGUT COMPONENT-854;Lo;0;L;;;;;N;;;;;
+18DD6;TANGUT COMPONENT-855;Lo;0;L;;;;;N;;;;;
+18DD7;TANGUT COMPONENT-856;Lo;0;L;;;;;N;;;;;
+18DD8;TANGUT COMPONENT-857;Lo;0;L;;;;;N;;;;;
+18DD9;TANGUT COMPONENT-858;Lo;0;L;;;;;N;;;;;
+18DDA;TANGUT COMPONENT-859;Lo;0;L;;;;;N;;;;;
+18DDB;TANGUT COMPONENT-860;Lo;0;L;;;;;N;;;;;
+18DDC;TANGUT COMPONENT-861;Lo;0;L;;;;;N;;;;;
+18DDD;TANGUT COMPONENT-862;Lo;0;L;;;;;N;;;;;
+18DDE;TANGUT COMPONENT-863;Lo;0;L;;;;;N;;;;;
+18DDF;TANGUT COMPONENT-864;Lo;0;L;;;;;N;;;;;
+18DE0;TANGUT COMPONENT-865;Lo;0;L;;;;;N;;;;;
+18DE1;TANGUT COMPONENT-866;Lo;0;L;;;;;N;;;;;
+18DE2;TANGUT COMPONENT-867;Lo;0;L;;;;;N;;;;;
+18DE3;TANGUT COMPONENT-868;Lo;0;L;;;;;N;;;;;
+18DE4;TANGUT COMPONENT-869;Lo;0;L;;;;;N;;;;;
+18DE5;TANGUT COMPONENT-870;Lo;0;L;;;;;N;;;;;
+18DE6;TANGUT COMPONENT-871;Lo;0;L;;;;;N;;;;;
+18DE7;TANGUT COMPONENT-872;Lo;0;L;;;;;N;;;;;
+18DE8;TANGUT COMPONENT-873;Lo;0;L;;;;;N;;;;;
+18DE9;TANGUT COMPONENT-874;Lo;0;L;;;;;N;;;;;
+18DEA;TANGUT COMPONENT-875;Lo;0;L;;;;;N;;;;;
+18DEB;TANGUT COMPONENT-876;Lo;0;L;;;;;N;;;;;
+18DEC;TANGUT COMPONENT-877;Lo;0;L;;;;;N;;;;;
+18DED;TANGUT COMPONENT-878;Lo;0;L;;;;;N;;;;;
+18DEE;TANGUT COMPONENT-879;Lo;0;L;;;;;N;;;;;
+18DEF;TANGUT COMPONENT-880;Lo;0;L;;;;;N;;;;;
+18DF0;TANGUT COMPONENT-881;Lo;0;L;;;;;N;;;;;
+18DF1;TANGUT COMPONENT-882;Lo;0;L;;;;;N;;;;;
+18DF2;TANGUT COMPONENT-883;Lo;0;L;;;;;N;;;;;
1AFF0;KATAKANA LETTER MINNAN TONE-2;Lm;0;L;;;;;N;;;;;
1AFF1;KATAKANA LETTER MINNAN TONE-3;Lm;0;L;;;;;N;;;;;
1AFF2;KATAKANA LETTER MINNAN TONE-4;Lm;0;L;;;;;N;;;;;
@@ -32629,6 +32963,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1CCF7;OUTLINED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;;
1CCF8;OUTLINED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;;
1CCF9;OUTLINED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;;
+1CCFA;SNAKE SYMBOL;So;0;ON;;;;;N;;;;;
+1CCFB;FLYING SAUCER SYMBOL;So;0;ON;;;;;N;;;;;
+1CCFC;NOSE SYMBOL;So;0;ON;;;;;N;;;;;
1CD00;BLOCK OCTANT-3;So;0;ON;;;;;N;;;;;
1CD01;BLOCK OCTANT-23;So;0;ON;;;;;N;;;;;
1CD02;BLOCK OCTANT-123;So;0;ON;;;;;N;;;;;
@@ -33065,6 +33402,46 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1CEB1;KEYHOLE;So;0;ON;;;;;N;;;;;
1CEB2;OLD PERSONAL COMPUTER WITH MONITOR IN PORTRAIT ORIENTATION;So;0;ON;;;;;N;;;;;
1CEB3;BLACK RIGHT TRIANGLE CARET;So;0;ON;;;;;N;;;;;
+1CEBA;FRAGILE SYMBOL;So;0;ON;;;;;N;;;;;
+1CEBB;OFFICE BUILDING SYMBOL;So;0;ON;;;;;N;;;;;
+1CEBC;TREE SYMBOL;So;0;ON;;;;;N;;;;;
+1CEBD;APPLE SYMBOL;So;0;ON;;;;;N;;;;;
+1CEBE;CHERRY SYMBOL;So;0;ON;;;;;N;;;;;
+1CEBF;STRAWBERRY SYMBOL;So;0;ON;;;;;N;;;;;
+1CEC0;HEBE;So;0;ON;;;;;N;;;;;
+1CEC1;IRIS;So;0;ON;;;;;N;;;;;
+1CEC2;FLORA;So;0;ON;;;;;N;;;;;
+1CEC3;METIS;So;0;ON;;;;;N;;;;;
+1CEC4;PARTHENOPE;So;0;ON;;;;;N;;;;;
+1CEC5;VICTORIA;So;0;ON;;;;;N;;;;;
+1CEC6;EGERIA;So;0;ON;;;;;N;;;;;
+1CEC7;IRENE;So;0;ON;;;;;N;;;;;
+1CEC8;EUNOMIA;So;0;ON;;;;;N;;;;;
+1CEC9;PSYCHE;So;0;ON;;;;;N;;;;;
+1CECA;THETIS;So;0;ON;;;;;N;;;;;
+1CECB;MELPOMENE;So;0;ON;;;;;N;;;;;
+1CECC;FORTUNA;So;0;ON;;;;;N;;;;;
+1CECD;ASTRONOMICAL SYMBOL FOR ASTEROID PROSERPINA;So;0;ON;;;;;N;;;;;
+1CECE;BELLONA;So;0;ON;;;;;N;;;;;
+1CECF;AMPHITRITE;So;0;ON;;;;;N;;;;;
+1CED0;LEUKOTHEA;So;0;ON;;;;;N;;;;;
+1CEE0;GEOMANTIC FIGURE POPULUS;So;0;ON;;;;;N;;;;;
+1CEE1;GEOMANTIC FIGURE TRISTITIA;So;0;ON;;;;;N;;;;;
+1CEE2;GEOMANTIC FIGURE ALBUS;So;0;ON;;;;;N;;;;;
+1CEE3;GEOMANTIC FIGURE FORTUNA MAJOR;So;0;ON;;;;;N;;;;;
+1CEE4;GEOMANTIC FIGURE RUBEUS;So;0;ON;;;;;N;;;;;
+1CEE5;GEOMANTIC FIGURE ACQUISITIO;So;0;ON;;;;;N;;;;;
+1CEE6;GEOMANTIC FIGURE CONJUNCTIO;So;0;ON;;;;;N;;;;;
+1CEE7;GEOMANTIC FIGURE CAPUT DRACONIS;So;0;ON;;;;;N;;;;;
+1CEE8;GEOMANTIC FIGURE LAETITIA;So;0;ON;;;;;N;;;;;
+1CEE9;GEOMANTIC FIGURE CARCER;So;0;ON;;;;;N;;;;;
+1CEEA;GEOMANTIC FIGURE AMISSIO;So;0;ON;;;;;N;;;;;
+1CEEB;GEOMANTIC FIGURE PUELLA;So;0;ON;;;;;N;;;;;
+1CEEC;GEOMANTIC FIGURE FORTUNA MINOR;So;0;ON;;;;;N;;;;;
+1CEED;GEOMANTIC FIGURE PUER;So;0;ON;;;;;N;;;;;
+1CEEE;GEOMANTIC FIGURE CAUDA DRACONIS;So;0;ON;;;;;N;;;;;
+1CEEF;GEOMANTIC FIGURE VIA;So;0;ON;;;;;N;;;;;
+1CEF0;MEDIUM SMALL WHITE CIRCLE WITH HORIZONTAL BAR;Sm;0;ON;;;;;N;;;;;
1CF00;ZNAMENNY COMBINING MARK GORAZDO NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;;
1CF01;ZNAMENNY COMBINING MARK NIZKO S KRYZHEM ON LEFT;Mn;0;NSM;;;;;N;;;;;
1CF02;ZNAMENNY COMBINING MARK TSATA ON LEFT;Mn;0;NSM;;;;;N;;;;;
@@ -36004,6 +36381,61 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1E5F9;OL ONAL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
1E5FA;OL ONAL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
1E5FF;OL ONAL ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+1E6C0;TAI YO LETTER LOW KO;Lo;0;L;;;;;N;;;;;
+1E6C1;TAI YO LETTER HIGH KO;Lo;0;L;;;;;N;;;;;
+1E6C2;TAI YO LETTER LOW KHO;Lo;0;L;;;;;N;;;;;
+1E6C3;TAI YO LETTER HIGH KHO;Lo;0;L;;;;;N;;;;;
+1E6C4;TAI YO LETTER GO;Lo;0;L;;;;;N;;;;;
+1E6C5;TAI YO LETTER NGO;Lo;0;L;;;;;N;;;;;
+1E6C6;TAI YO LETTER CO;Lo;0;L;;;;;N;;;;;
+1E6C7;TAI YO LETTER LOW XO;Lo;0;L;;;;;N;;;;;
+1E6C8;TAI YO LETTER HIGH XO;Lo;0;L;;;;;N;;;;;
+1E6C9;TAI YO LETTER LOW NYO;Lo;0;L;;;;;N;;;;;
+1E6CA;TAI YO LETTER HIGH NYO;Lo;0;L;;;;;N;;;;;
+1E6CB;TAI YO LETTER DO;Lo;0;L;;;;;N;;;;;
+1E6CC;TAI YO LETTER LOW TO;Lo;0;L;;;;;N;;;;;
+1E6CD;TAI YO LETTER HIGH TO;Lo;0;L;;;;;N;;;;;
+1E6CE;TAI YO LETTER THO;Lo;0;L;;;;;N;;;;;
+1E6CF;TAI YO LETTER NO;Lo;0;L;;;;;N;;;;;
+1E6D0;TAI YO LETTER BO;Lo;0;L;;;;;N;;;;;
+1E6D1;TAI YO LETTER LOW PO;Lo;0;L;;;;;N;;;;;
+1E6D2;TAI YO LETTER HIGH PO;Lo;0;L;;;;;N;;;;;
+1E6D3;TAI YO LETTER PHO;Lo;0;L;;;;;N;;;;;
+1E6D4;TAI YO LETTER LOW FO;Lo;0;L;;;;;N;;;;;
+1E6D5;TAI YO LETTER HIGH FO;Lo;0;L;;;;;N;;;;;
+1E6D6;TAI YO LETTER MO;Lo;0;L;;;;;N;;;;;
+1E6D7;TAI YO LETTER YO;Lo;0;L;;;;;N;;;;;
+1E6D8;TAI YO LETTER LO;Lo;0;L;;;;;N;;;;;
+1E6D9;TAI YO LETTER VO;Lo;0;L;;;;;N;;;;;
+1E6DA;TAI YO LETTER LOW HO;Lo;0;L;;;;;N;;;;;
+1E6DB;TAI YO LETTER HIGH HO;Lo;0;L;;;;;N;;;;;
+1E6DC;TAI YO LETTER QO;Lo;0;L;;;;;N;;;;;
+1E6DD;TAI YO LETTER LOW KVO;Lo;0;L;;;;;N;;;;;
+1E6DE;TAI YO LETTER HIGH KVO;Lo;0;L;;;;;N;;;;;
+1E6E0;TAI YO LETTER AA;Lo;0;L;;;;;N;;;;;
+1E6E1;TAI YO LETTER I;Lo;0;L;;;;;N;;;;;
+1E6E2;TAI YO LETTER UE;Lo;0;L;;;;;N;;;;;
+1E6E3;TAI YO SIGN UE;Mn;230;NSM;;;;;N;;;;;
+1E6E4;TAI YO LETTER U;Lo;0;L;;;;;N;;;;;
+1E6E5;TAI YO LETTER AE;Lo;0;L;;;;;N;;;;;
+1E6E6;TAI YO SIGN AU;Mn;230;NSM;;;;;N;;;;;
+1E6E7;TAI YO LETTER O;Lo;0;L;;;;;N;;;;;
+1E6E8;TAI YO LETTER E;Lo;0;L;;;;;N;;;;;
+1E6E9;TAI YO LETTER IA;Lo;0;L;;;;;N;;;;;
+1E6EA;TAI YO LETTER UEA;Lo;0;L;;;;;N;;;;;
+1E6EB;TAI YO LETTER UA;Lo;0;L;;;;;N;;;;;
+1E6EC;TAI YO LETTER OO;Lo;0;L;;;;;N;;;;;
+1E6ED;TAI YO LETTER AUE;Lo;0;L;;;;;N;;;;;
+1E6EE;TAI YO SIGN AY;Mn;230;NSM;;;;;N;;;;;
+1E6EF;TAI YO SIGN ANG;Mn;230;NSM;;;;;N;;;;;
+1E6F0;TAI YO LETTER AN;Lo;0;L;;;;;N;;;;;
+1E6F1;TAI YO LETTER AM;Lo;0;L;;;;;N;;;;;
+1E6F2;TAI YO LETTER AK;Lo;0;L;;;;;N;;;;;
+1E6F3;TAI YO LETTER AT;Lo;0;L;;;;;N;;;;;
+1E6F4;TAI YO LETTER AP;Lo;0;L;;;;;N;;;;;
+1E6F5;TAI YO SIGN OM;Mn;230;NSM;;;;;N;;;;;
+1E6FE;TAI YO SYMBOL MUEANG;Lo;0;L;;;;;N;;;;;
+1E6FF;TAI YO XAM LAI;Lm;0;L;;;;;N;;;;;
1E7E0;ETHIOPIC SYLLABLE HHYA;Lo;0;L;;;;;N;;;;;
1E7E1;ETHIOPIC SYLLABLE HHYU;Lo;0;L;;;;;N;;;;;
1E7E2;ETHIOPIC SYLLABLE HHYI;Lo;0;L;;;;;N;;;;;
@@ -38079,6 +38511,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6D5;HINDU TEMPLE;So;0;ON;;;;;N;;;;;
1F6D6;HUT;So;0;ON;;;;;N;;;;;
1F6D7;ELEVATOR;So;0;ON;;;;;N;;;;;
+1F6D8;LANDSLIDE;So;0;ON;;;;;N;;;;;
1F6DC;WIRELESS;So;0;ON;;;;;N;;;;;
1F6DD;PLAYGROUND SLIDE;So;0;ON;;;;;N;;;;;
1F6DE;WHEEL;So;0;ON;;;;;N;;;;;
@@ -38228,6 +38661,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F774;LOT OF FORTUNE;So;0;ON;;;;;N;;;;;
1F775;OCCULTATION;So;0;ON;;;;;N;;;;;
1F776;LUNAR ECLIPSE;So;0;ON;;;;;N;;;;;
+1F777;VESTA FORM TWO;So;0;ON;;;;;N;;;;;
+1F778;ASTRAEA FORM TWO;So;0;ON;;;;;N;;;;;
+1F779;HYGIEA FORM TWO;So;0;ON;;;;;N;;;;;
+1F77A;PARTHENOPE FORM TWO;So;0;ON;;;;;N;;;;;
1F77B;HAUMEA;So;0;ON;;;;;N;;;;;
1F77C;MAKEMAKE;So;0;ON;;;;;N;;;;;
1F77D;GONGGONG;So;0;ON;;;;;N;;;;;
@@ -38498,6 +38935,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F8BB;SOUTH WEST ARROW FROM BAR;So;0;ON;;;;;N;;;;;
1F8C0;LEFTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;
1F8C1;RIGHTWARDS ARROW FROM DOWNWARDS ARROW;So;0;ON;;;;;N;;;;;
+1F8D0;LONG RIGHTWARDS ARROW OVER LONG LEFTWARDS ARROW;Sm;0;ON;;;;;N;;;;;
+1F8D1;LONG RIGHTWARDS HARPOON OVER LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;
+1F8D2;LONG RIGHTWARDS HARPOON ABOVE SHORT LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;
+1F8D3;SHORT RIGHTWARDS HARPOON ABOVE LONG LEFTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;
+1F8D4;LONG LEFTWARDS HARPOON ABOVE SHORT RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;
+1F8D5;SHORT LEFTWARDS HARPOON ABOVE LONG RIGHTWARDS HARPOON;Sm;0;ON;;;;;N;;;;;
+1F8D6;LONG RIGHTWARDS ARROW THROUGH X;Sm;0;ON;;;;;N;;;;;
+1F8D7;LONG RIGHTWARDS ARROW WITH DOUBLE SLASH;Sm;0;ON;;;;;N;;;;;
+1F8D8;LONG LEFT RIGHT ARROW WITH DEPENDENT LOBE;Sm;0;ON;;;;;N;;;;;
1F900;CIRCLED CROSS FORMEE WITH FOUR DOTS;So;0;ON;;;;;N;;;;;
1F901;CIRCLED CROSS FORMEE WITH TWO DOTS;So;0;ON;;;;;N;;;;;
1F902;CIRCLED CROSS FORMEE;So;0;ON;;;;;N;;;;;
@@ -38838,6 +39284,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FA51;BLACK CHESS KNIGHT-QUEEN;So;0;ON;;;;;N;;;;;
1FA52;BLACK CHESS KNIGHT-ROOK;So;0;ON;;;;;N;;;;;
1FA53;BLACK CHESS KNIGHT-BISHOP;So;0;ON;;;;;N;;;;;
+1FA54;WHITE CHESS FERZ;So;0;ON;;;;;N;;;;;
+1FA55;WHITE CHESS ALFIL;So;0;ON;;;;;N;;;;;
+1FA56;BLACK CHESS FERZ;So;0;ON;;;;;N;;;;;
+1FA57;BLACK CHESS ALFIL;So;0;ON;;;;;N;;;;;
1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;;
1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;;
1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;;
@@ -38875,6 +39325,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FA87;MARACAS;So;0;ON;;;;;N;;;;;
1FA88;FLUTE;So;0;ON;;;;;N;;;;;
1FA89;HARP;So;0;ON;;;;;N;;;;;
+1FA8A;TROMBONE;So;0;ON;;;;;N;;;;;
+1FA8E;TREASURE CHEST;So;0;ON;;;;;N;;;;;
1FA8F;SHOVEL;So;0;ON;;;;;N;;;;;
1FA90;RINGED PLANET;So;0;ON;;;;;N;;;;;
1FA91;CHAIR;So;0;ON;;;;;N;;;;;
@@ -38931,6 +39383,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FAC4;PREGNANT PERSON;So;0;ON;;;;;N;;;;;
1FAC5;PERSON WITH CROWN;So;0;ON;;;;;N;;;;;
1FAC6;FINGERPRINT;So;0;ON;;;;;N;;;;;
+1FAC8;HAIRY CREATURE;So;0;ON;;;;;N;;;;;
+1FACD;ORCA;So;0;ON;;;;;N;;;;;
1FACE;MOOSE;So;0;ON;;;;;N;;;;;
1FACF;DONKEY;So;0;ON;;;;;N;;;;;
1FAD0;BLUEBERRIES;So;0;ON;;;;;N;;;;;
@@ -38957,6 +39411,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FAE7;BUBBLES;So;0;ON;;;;;N;;;;;
1FAE8;SHAKING FACE;So;0;ON;;;;;N;;;;;
1FAE9;FACE WITH BAGS UNDER EYES;So;0;ON;;;;;N;;;;;
+1FAEA;DISTORTED FACE;So;0;ON;;;;;N;;;;;
+1FAEF;FIGHT CLOUD;So;0;ON;;;;;N;;;;;
1FAF0;HAND WITH INDEX FINGER AND THUMB CROSSED;So;0;ON;;;;;N;;;;;
1FAF1;RIGHTWARDS HAND;So;0;ON;;;;;N;;;;;
1FAF2;LEFTWARDS HAND;So;0;ON;;;;;N;;;;;
@@ -39215,14 +39671,15 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1FBF7;SEGMENTED DIGIT SEVEN;Nd;0;EN; 0037;7;7;7;N;;;;;
1FBF8;SEGMENTED DIGIT EIGHT;Nd;0;EN; 0038;8;8;8;N;;;;;
1FBF9;SEGMENTED DIGIT NINE;Nd;0;EN; 0039;9;9;9;N;;;;;
+1FBFA;ALARM BELL SYMBOL;So;0;ON;;;;;N;;;;;
20000;;Lo;0;L;;;;;N;;;;;
2A6DF;;Lo;0;L;;;;;N;;;;;
2A700;;Lo;0;L;;;;;N;;;;;
-2B739;;Lo;0;L;;;;;N;;;;;
+2B73F;;Lo;0;L;;;;;N;;;;;
2B740;;Lo;0;L;;;;;N;;;;;
2B81D;;Lo;0;L;;;;;N;;;;;
2B820;;Lo;0;L;;;;;N;;;;;
-2CEA1;;Lo;0;L;;;;;N;;;;;
+2CEAD;;Lo;0;L;;;;;N;;;;;
2CEB0;;Lo;0;L;;;;;N;;;;;
2EBE0;;Lo;0;L;;;;;N;;;;;
2EBF0;;Lo;0;L;;;;;N;;;;;
@@ -39773,6 +40230,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
3134A;;Lo;0;L;;;;;N;;;;;
31350;;Lo;0;L;;;;;N;;;;;
323AF;;Lo;0;L;;;;;N;;;;;
+323B0;;Lo;0;L;;;;;N;;;;;
+33479;;Lo;0;L;;;;;N;;;;;
E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
diff --git a/resources/standards-data/unicode-character-database/WordBreakProperty.txt b/resources/standards-data/unicode-character-database/WordBreakProperty.txt
index e557c3d0de..20fa24e375 100644
--- a/resources/standards-data/unicode-character-database/WordBreakProperty.txt
+++ b/resources/standards-data/unicode-character-database/WordBreakProperty.txt
@@ -1,6 +1,6 @@
-# WordBreakProperty-16.0.0.txt
-# Date: 2024-07-29, 16:27:36 GMT
-# © 2024 Unicode®, Inc.
+# WordBreakProperty-17.0.0.txt
+# Date: 2025-06-30, 06:20:49 GMT
+# © 2025 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
@@ -283,7 +283,8 @@ FB46..FB4F ; Hebrew_Letter # Lo [10] HEBREW LETTER TSADI WITH DAGESH..HEBREW
1A7F ; Extend # Mn TAI THAM COMBINING CRYPTOGRAMMIC DOT
1AB0..1ABD ; Extend # Mn [14] COMBINING DOUBLED CIRCUMFLEX ACCENT..COMBINING PARENTHESES BELOW
1ABE ; Extend # Me COMBINING PARENTHESES OVERLAY
-1ABF..1ACE ; Extend # Mn [16] COMBINING LATIN SMALL LETTER W BELOW..COMBINING LATIN SMALL LETTER INSULAR T
+1ABF..1ADD ; Extend # Mn [31] COMBINING LATIN SMALL LETTER W BELOW..COMBINING DOT-AND-RING BELOW
+1AE0..1AEB ; Extend # Mn [12] COMBINING LEFT TACK ABOVE..COMBINING DOUBLE RIGHTWARDS ARROW ABOVE
1B00..1B03 ; Extend # Mn [4] BALINESE SIGN ULU RICEM..BALINESE SIGN SURANG
1B04 ; Extend # Mc BALINESE SIGN BISAH
1B34 ; Extend # Mn BALINESE SIGN REREKAN
@@ -409,7 +410,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
10D69..10D6D ; Extend # Mn [5] GARAY VOWEL SIGN E..GARAY CONSONANT NASALIZATION MARK
10EAB..10EAC ; Extend # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
-10EFC..10EFF ; Extend # Mn [4] ARABIC COMBINING ALEF OVERLAY..ARABIC SMALL LOW WORD MADDA
+10EFA..10EFF ; Extend # Mn [6] ARABIC DOUBLE VERTICAL BAR BELOW..ARABIC SMALL LOW WORD MADDA
10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
10F82..10F85 ; Extend # Mn [4] OLD UYGHUR COMBINING DOT ABOVE..OLD UYGHUR COMBINING TWO DOTS BELOW
11000 ; Extend # Mc BRAHMI SIGN CANDRABINDU
@@ -544,6 +545,12 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11A8A..11A96 ; Extend # Mn [13] SOYOMBO FINAL CONSONANT SIGN G..SOYOMBO SIGN ANUSVARA
11A97 ; Extend # Mc SOYOMBO SIGN VISARGA
11A98..11A99 ; Extend # Mn [2] SOYOMBO GEMINATION MARK..SOYOMBO SUBJOINER
+11B60 ; Extend # Mn SHARADA VOWEL SIGN OE
+11B61 ; Extend # Mc SHARADA VOWEL SIGN OOE
+11B62..11B64 ; Extend # Mn [3] SHARADA VOWEL SIGN UE..SHARADA VOWEL SIGN SHORT E
+11B65 ; Extend # Mc SHARADA VOWEL SIGN SHORT O
+11B66 ; Extend # Mn SHARADA VOWEL SIGN CANDRA E
+11B67 ; Extend # Mc SHARADA VOWEL SIGN CANDRA O
11C2F ; Extend # Mc BHAIKSUKI VOWEL SIGN AA
11C30..11C36 ; Extend # Mn [7] BHAIKSUKI VOWEL SIGN I..BHAIKSUKI VOWEL SIGN VOCALIC L
11C38..11C3D ; Extend # Mn [6] BHAIKSUKI VOWEL SIGN E..BHAIKSUKI SIGN ANUSVARA
@@ -617,13 +624,17 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
1E2EC..1E2EF ; Extend # Mn [4] WANCHO TONE TUP..WANCHO TONE KOINI
1E4EC..1E4EF ; Extend # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
1E5EE..1E5EF ; Extend # Mn [2] OL ONAL SIGN MU..OL ONAL SIGN IKIR
+1E6E3 ; Extend # Mn TAI YO SIGN UE
+1E6E6 ; Extend # Mn TAI YO SIGN AU
+1E6EE..1E6EF ; Extend # Mn [2] TAI YO SIGN AY..TAI YO SIGN ANG
+1E6F5 ; Extend # Mn TAI YO SIGN OM
1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG
E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
-# Total code points: 2605
+# Total code points: 2647
# ================================================
@@ -679,6 +690,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK
0061..007A ; ALetter # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z
00AA ; ALetter # Lo FEMININE ORDINAL INDICATOR
00B5 ; ALetter # L& MICRO SIGN
+00B8 ; ALetter # Sk CEDILLA
00BA ; ALetter # Lo MASCULINE ORDINAL INDICATOR
00C0..00D6 ; ALetter # L& [23] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER O WITH DIAERESIS
00D8..00F6 ; ALetter # L& [31] LATIN CAPITAL LETTER O WITH STROKE..LATIN SMALL LETTER O WITH DIAERESIS
@@ -687,8 +699,8 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK
01BC..01BF ; ALetter # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN
01C0..01C3 ; ALetter # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK
01C4..0293 ; ALetter # L& [208] LATIN CAPITAL LETTER DZ WITH CARON..LATIN SMALL LETTER EZH WITH CURL
-0294 ; ALetter # Lo LATIN LETTER GLOTTAL STOP
-0295..02AF ; ALetter # L& [27] LATIN LETTER PHARYNGEAL VOICED FRICATIVE..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+0294..0295 ; ALetter # Lo [2] LATIN LETTER GLOTTAL STOP..LATIN LETTER PHARYNGEAL VOICED FRICATIVE
+0296..02AF ; ALetter # L& [26] LATIN LETTER INVERTED GLOTTAL STOP..LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
02B0..02C1 ; ALetter # Lm [18] MODIFIER LETTER SMALL H..MODIFIER LETTER REVERSED GLOTTAL STOP
02C2..02C5 ; ALetter # Sk [4] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER DOWN ARROWHEAD
02C6..02D1 ; ALetter # Lm [12] MODIFIER LETTER CIRCUMFLEX ACCENT..MODIFIER LETTER HALF TRIANGULAR COLON
@@ -745,7 +757,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK
0840..0858 ; ALetter # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
0860..086A ; ALetter # Lo [11] SYRIAC LETTER MALAYALAM NGA..SYRIAC LETTER MALAYALAM SSA
0870..0887 ; ALetter # Lo [24] ARABIC LETTER ALEF WITH ATTACHED FATHA..ARABIC BASELINE ROUND DOT
-0889..088E ; ALetter # Lo [6] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC VERTICAL TAIL
+0889..088F ; ALetter # Lo [7] ARABIC LETTER NOON WITH INVERTED SMALL V..ARABIC LETTER NOON WITH RING ABOVE
08A0..08C8 ; ALetter # Lo [41] ARABIC LETTER BEH WITH SMALL V BELOW..ARABIC LETTER GRAF
08C9 ; ALetter # Lm ARABIC SMALL FARSI YEH
0904..0939 ; ALetter # Lo [54] DEVANAGARI LETTER SHORT A..DEVANAGARI LETTER HA
@@ -813,7 +825,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK
0C2A..0C39 ; ALetter # Lo [16] TELUGU LETTER PA..TELUGU LETTER HA
0C3D ; ALetter # Lo TELUGU SIGN AVAGRAHA
0C58..0C5A ; ALetter # Lo [3] TELUGU LETTER TSA..TELUGU LETTER RRRA
-0C5D ; ALetter # Lo TELUGU LETTER NAKAARA POLLU
+0C5C..0C5D ; ALetter # Lo [2] TELUGU ARCHAIC SHRII..TELUGU LETTER NAKAARA POLLU
0C60..0C61 ; ALetter # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL
0C80 ; ALetter # Lo KANNADA SIGN SPACING CANDRABINDU
0C85..0C8C ; ALetter # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L
@@ -822,7 +834,7 @@ FF71..FF9D ; Katakana # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAK
0CAA..0CB3 ; ALetter # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA
0CB5..0CB9 ; ALetter # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA
0CBD ; ALetter # Lo KANNADA SIGN AVAGRAHA
-0CDD..0CDE ; ALetter # Lo [2] KANNADA LETTER NAKAARA POLLU..KANNADA LETTER FA
+0CDC..0CDE ; ALetter # Lo [3] KANNADA ARCHAIC SHRII..KANNADA LETTER FA
0CE0..0CE1 ; ALetter # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL
0CF1..0CF2 ; ALetter # Lo [2] KANNADA SIGN JIHVAMULIYA..KANNADA SIGN UPADHMANIYA
0D04..0D0C ; ALetter # Lo [9] MALAYALAM LETTER VEDIC ANUSVARA..MALAYALAM LETTER VOCALIC L
@@ -1002,11 +1014,8 @@ A788 ; ALetter # Lm MODIFIER LETTER LOW CIRCUMFLEX ACCENT
A789..A78A ; ALetter # Sk [2] MODIFIER LETTER COLON..MODIFIER LETTER SHORT EQUALS SIGN
A78B..A78E ; ALetter # L& [4] LATIN CAPITAL LETTER SALTILLO..LATIN SMALL LETTER L WITH RETROFLEX HOOK AND BELT
A78F ; ALetter # Lo LATIN LETTER SINOLOGICAL DOT
-A790..A7CD ; ALetter # L& [62] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN SMALL LETTER S WITH DIAGONAL STROKE
-A7D0..A7D1 ; ALetter # L& [2] LATIN CAPITAL LETTER CLOSED INSULAR G..LATIN SMALL LETTER CLOSED INSULAR G
-A7D3 ; ALetter # L& LATIN SMALL LETTER DOUBLE THORN
-A7D5..A7DC ; ALetter # L& [8] LATIN SMALL LETTER DOUBLE WYNN..LATIN CAPITAL LETTER LAMBDA WITH STROKE
-A7F2..A7F4 ; ALetter # Lm [3] MODIFIER LETTER CAPITAL C..MODIFIER LETTER CAPITAL Q
+A790..A7DC ; ALetter # L& [77] LATIN CAPITAL LETTER N WITH DESCENDER..LATIN CAPITAL LETTER LAMBDA WITH STROKE
+A7F1..A7F4 ; ALetter # Lm [4] MODIFIER LETTER CAPITAL S..MODIFIER LETTER CAPITAL Q
A7F5..A7F6 ; ALetter # L& [2] LATIN CAPITAL LETTER REVERSED HALF H..LATIN SMALL LETTER REVERSED HALF H
A7F7 ; ALetter # Lo LATIN EPIGRAPHIC LETTER SIDEWAYS I
A7F8..A7F9 ; ALetter # Lm [2] MODIFIER LETTER CAPITAL H WITH STROKE..MODIFIER LETTER SMALL LIGATURE OE
@@ -1115,6 +1124,7 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
108F4..108F5 ; ALetter # Lo [2] HATRAN LETTER SHIN..HATRAN LETTER TAW
10900..10915 ; ALetter # Lo [22] PHOENICIAN LETTER ALF..PHOENICIAN LETTER TAU
10920..10939 ; ALetter # Lo [26] LYDIAN LETTER A..LYDIAN LETTER C
+10940..10959 ; ALetter # Lo [26] SIDETIC LETTER N01..SIDETIC LETTER N26
10980..109B7 ; ALetter # Lo [56] MEROITIC HIEROGLYPHIC LETTER A..MEROITIC CURSIVE LETTER DA
109BE..109BF ; ALetter # Lo [2] MEROITIC CURSIVE LOGOGRAM RMT..MEROITIC CURSIVE LOGOGRAM IMN
10A00 ; ALetter # Lo KHAROSHTHI LETTER A
@@ -1142,6 +1152,8 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
10E80..10EA9 ; ALetter # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
10EB0..10EB1 ; ALetter # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
10EC2..10EC4 ; ALetter # Lo [3] ARABIC LETTER DAL WITH TWO DOTS VERTICALLY BELOW..ARABIC LETTER KAF WITH TWO DOTS VERTICALLY BELOW
+10EC5 ; ALetter # Lm ARABIC SMALL YEH BARREE WITH TWO DOTS BELOW
+10EC6..10EC7 ; ALetter # Lo [2] ARABIC LETTER THIN NOON..ARABIC LETTER YEH WITH FOUR DOTS BELOW
10F00..10F1C ; ALetter # Lo [29] OLD SOGDIAN LETTER ALEPH..OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL
10F27 ; ALetter # Lo OLD SOGDIAN LIGATURE AYIN-DALETH
10F30..10F45 ; ALetter # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
@@ -1232,6 +1244,9 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
11D67..11D68 ; ALetter # Lo [2] GUNJALA GONDI LETTER EE..GUNJALA GONDI LETTER AI
11D6A..11D89 ; ALetter # Lo [32] GUNJALA GONDI LETTER OO..GUNJALA GONDI LETTER SA
11D98 ; ALetter # Lo GUNJALA GONDI OM
+11DB0..11DD8 ; ALetter # Lo [41] TOLONG SIKI LETTER I..TOLONG SIKI LETTER RRH
+11DD9 ; ALetter # Lm TOLONG SIKI SIGN SELA
+11DDA..11DDB ; ALetter # Lo [2] TOLONG SIKI SIGN HECAKA..TOLONG SIKI UNGGA
11EE0..11EF2 ; ALetter # Lo [19] MAKASAR LETTER KA..MAKASAR ANGKA
11F02 ; ALetter # Lo KAWI SIGN REPHA
11F04..11F10 ; ALetter # Lo [13] KAWI LETTER A..KAWI LETTER O
@@ -1258,6 +1273,8 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
16D43..16D6A ; ALetter # Lo [40] KIRAT RAI LETTER A..KIRAT RAI VOWEL SIGN AU
16D6B..16D6C ; ALetter # Lm [2] KIRAT RAI SIGN VIRAMA..KIRAT RAI SIGN SAAT
16E40..16E7F ; ALetter # L& [64] MEDEFAIDRIN CAPITAL LETTER M..MEDEFAIDRIN SMALL LETTER Y
+16EA0..16EB8 ; ALetter # L& [25] BERIA ERFE CAPITAL LETTER ARKAB..BERIA ERFE CAPITAL LETTER AY
+16EBB..16ED3 ; ALetter # L& [25] BERIA ERFE SMALL LETTER ARKAB..BERIA ERFE SMALL LETTER AY
16F00..16F4A ; ALetter # Lo [75] MIAO LETTER PA..MIAO LETTER RTE
16F50 ; ALetter # Lo MIAO LETTER NASALIZATION
16F93..16F9F ; ALetter # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
@@ -1311,6 +1328,13 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
1E4EB ; ALetter # Lm NAG MUNDARI SIGN OJOD
1E5D0..1E5ED ; ALetter # Lo [30] OL ONAL LETTER O..OL ONAL LETTER EG
1E5F0 ; ALetter # Lo OL ONAL SIGN HODDOND
+1E6C0..1E6DE ; ALetter # Lo [31] TAI YO LETTER LOW KO..TAI YO LETTER HIGH KVO
+1E6E0..1E6E2 ; ALetter # Lo [3] TAI YO LETTER AA..TAI YO LETTER UE
+1E6E4..1E6E5 ; ALetter # Lo [2] TAI YO LETTER U..TAI YO LETTER AE
+1E6E7..1E6ED ; ALetter # Lo [7] TAI YO LETTER O..TAI YO LETTER AUE
+1E6F0..1E6F4 ; ALetter # Lo [5] TAI YO LETTER AN..TAI YO LETTER AP
+1E6FE ; ALetter # Lo TAI YO SYMBOL MUEANG
+1E6FF ; ALetter # Lm TAI YO XAM LAI
1E7E0..1E7E6 ; ALetter # Lo [7] ETHIOPIC SYLLABLE HHYA..ETHIOPIC SYLLABLE HHYO
1E7E8..1E7EB ; ALetter # Lo [4] ETHIOPIC SYLLABLE GURAGE HHWA..ETHIOPIC SYLLABLE HHWE
1E7ED..1E7EE ; ALetter # Lo [2] ETHIOPIC SYLLABLE GURAGE MWI..ETHIOPIC SYLLABLE GURAGE MWEE
@@ -1355,7 +1379,7 @@ FFDA..FFDC ; ALetter # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL
1F150..1F169 ; ALetter # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
1F170..1F189 ; ALetter # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
-# Total code points: 33791
+# Total code points: 33973
# ================================================
@@ -1467,6 +1491,7 @@ FF10..FF19 ; Numeric # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
11C50..11C59 ; Numeric # Nd [10] BHAIKSUKI DIGIT ZERO..BHAIKSUKI DIGIT NINE
11D50..11D59 ; Numeric # Nd [10] MASARAM GONDI DIGIT ZERO..MASARAM GONDI DIGIT NINE
11DA0..11DA9 ; Numeric # Nd [10] GUNJALA GONDI DIGIT ZERO..GUNJALA GONDI DIGIT NINE
+11DE0..11DE9 ; Numeric # Nd [10] TOLONG SIKI DIGIT ZERO..TOLONG SIKI DIGIT NINE
11F50..11F59 ; Numeric # Nd [10] KAWI DIGIT ZERO..KAWI DIGIT NINE
16130..16139 ; Numeric # Nd [10] GURUNG KHEMA DIGIT ZERO..GURUNG KHEMA DIGIT NINE
16A60..16A69 ; Numeric # Nd [10] MRO DIGIT ZERO..MRO DIGIT NINE
@@ -1482,7 +1507,7 @@ FF10..FF19 ; Numeric # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE
1E950..1E959 ; Numeric # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
1FBF0..1FBF9 ; Numeric # Nd [10] SEGMENTED DIGIT ZERO..SEGMENTED DIGIT NINE
-# Total code points: 774
+# Total code points: 784
# ================================================
diff --git a/resources/standards-data/unicode-character-database/emoji-data.txt b/resources/standards-data/unicode-character-database/emoji-data.txt
index ff99028248..450252c4df 100644
--- a/resources/standards-data/unicode-character-database/emoji-data.txt
+++ b/resources/standards-data/unicode-character-database/emoji-data.txt
@@ -1,11 +1,11 @@
# emoji-data.txt
-# Date: 2024-05-01, 21:25:24 GMT
-# © 2024 Unicode®, Inc.
+# Date: 2025-07-25, 17:54:31 GMT
+# © 2025 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use and license, see https://www.unicode.org/terms_of_use.html
#
# Emoji Data for UTS #51
-# Used with Emoji Version 16.0 and subsequent minor revisions (if any)
+# Version: 17.0
#
# For documentation and usage, see https://www.unicode.org/reports/tr51
#
@@ -340,6 +340,7 @@
1F6D1..1F6D2 ; Emoji # E3.0 [2] (🛑..🛒) stop sign..shopping cart
1F6D5 ; Emoji # E12.0 [1] (🛕) hindu temple
1F6D6..1F6D7 ; Emoji # E13.0 [2] (🛖..🛗) hut..elevator
+1F6D8 ; Emoji # E17.0 [1] () landslide
1F6DC ; Emoji # E15.0 [1] (🛜) wireless
1F6DD..1F6DF ; Emoji # E14.0 [3] (🛝..🛟) playground slide..ring buoy
1F6E0..1F6E5 ; Emoji # E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
@@ -408,6 +409,8 @@
1FA83..1FA86 ; Emoji # E13.0 [4] (🪃..🪆) boomerang..nesting dolls
1FA87..1FA88 ; Emoji # E15.0 [2] (🪇..🪈) maracas..flute
1FA89 ; Emoji # E16.0 [1] () harp
+1FA8A ; Emoji # E17.0 [1] () trombone
+1FA8E ; Emoji # E17.0 [1] () treasure chest
1FA8F ; Emoji # E16.0 [1] () shovel
1FA90..1FA95 ; Emoji # E12.0 [6] (🪐..🪕) ringed planet..banjo
1FA96..1FAA8 ; Emoji # E13.0 [19] (🪖..🪨) military helmet..rock
@@ -421,6 +424,8 @@
1FAC0..1FAC2 ; Emoji # E13.0 [3] (🫀..🫂) anatomical heart..people hugging
1FAC3..1FAC5 ; Emoji # E14.0 [3] (🫃..🫅) pregnant man..person with crown
1FAC6 ; Emoji # E16.0 [1] () fingerprint
+1FAC8 ; Emoji # E17.0 [1] () hairy creature
+1FACD ; Emoji # E17.0 [1] () orca
1FACE..1FACF ; Emoji # E15.0 [2] (🫎..🫏) moose..donkey
1FAD0..1FAD6 ; Emoji # E13.0 [7] (🫐..🫖) blueberries..teapot
1FAD7..1FAD9 ; Emoji # E14.0 [3] (🫗..🫙) pouring liquid..jar
@@ -430,10 +435,12 @@
1FAE0..1FAE7 ; Emoji # E14.0 [8] (🫠..🫧) melting face..bubbles
1FAE8 ; Emoji # E15.0 [1] (🫨) shaking face
1FAE9 ; Emoji # E16.0 [1] () face with bags under eyes
+1FAEA ; Emoji # E17.0 [1] () distorted face
+1FAEF ; Emoji # E17.0 [1] () fight cloud
1FAF0..1FAF6 ; Emoji # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
1FAF7..1FAF8 ; Emoji # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
-# Total elements: 1431
+# Total elements: 1438
# ================================================
@@ -640,6 +647,7 @@
1F6D1..1F6D2 ; Emoji_Presentation # E3.0 [2] (🛑..🛒) stop sign..shopping cart
1F6D5 ; Emoji_Presentation # E12.0 [1] (🛕) hindu temple
1F6D6..1F6D7 ; Emoji_Presentation # E13.0 [2] (🛖..🛗) hut..elevator
+1F6D8 ; Emoji_Presentation # E17.0 [1] () landslide
1F6DC ; Emoji_Presentation # E15.0 [1] (🛜) wireless
1F6DD..1F6DF ; Emoji_Presentation # E14.0 [3] (🛝..🛟) playground slide..ring buoy
1F6EB..1F6EC ; Emoji_Presentation # E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
@@ -704,6 +712,8 @@
1FA83..1FA86 ; Emoji_Presentation # E13.0 [4] (🪃..🪆) boomerang..nesting dolls
1FA87..1FA88 ; Emoji_Presentation # E15.0 [2] (🪇..🪈) maracas..flute
1FA89 ; Emoji_Presentation # E16.0 [1] () harp
+1FA8A ; Emoji_Presentation # E17.0 [1] () trombone
+1FA8E ; Emoji_Presentation # E17.0 [1] () treasure chest
1FA8F ; Emoji_Presentation # E16.0 [1] () shovel
1FA90..1FA95 ; Emoji_Presentation # E12.0 [6] (🪐..🪕) ringed planet..banjo
1FA96..1FAA8 ; Emoji_Presentation # E13.0 [19] (🪖..🪨) military helmet..rock
@@ -717,6 +727,8 @@
1FAC0..1FAC2 ; Emoji_Presentation # E13.0 [3] (🫀..🫂) anatomical heart..people hugging
1FAC3..1FAC5 ; Emoji_Presentation # E14.0 [3] (🫃..🫅) pregnant man..person with crown
1FAC6 ; Emoji_Presentation # E16.0 [1] () fingerprint
+1FAC8 ; Emoji_Presentation # E17.0 [1] () hairy creature
+1FACD ; Emoji_Presentation # E17.0 [1] () orca
1FACE..1FACF ; Emoji_Presentation # E15.0 [2] (🫎..🫏) moose..donkey
1FAD0..1FAD6 ; Emoji_Presentation # E13.0 [7] (🫐..🫖) blueberries..teapot
1FAD7..1FAD9 ; Emoji_Presentation # E14.0 [3] (🫗..🫙) pouring liquid..jar
@@ -726,10 +738,12 @@
1FAE0..1FAE7 ; Emoji_Presentation # E14.0 [8] (🫠..🫧) melting face..bubbles
1FAE8 ; Emoji_Presentation # E15.0 [1] (🫨) shaking face
1FAE9 ; Emoji_Presentation # E16.0 [1] () face with bags under eyes
+1FAEA ; Emoji_Presentation # E17.0 [1] () distorted face
+1FAEF ; Emoji_Presentation # E17.0 [1] () fight cloud
1FAF0..1FAF6 ; Emoji_Presentation # E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
1FAF7..1FAF8 ; Emoji_Presentation # E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
-# Total elements: 1212
+# Total elements: 1219
# ================================================
@@ -827,7 +841,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
21A9..21AA ; Extended_Pictographic# E0.6 [2] (↩️..↪️) right arrow curving left..left arrow curving right
231A..231B ; Extended_Pictographic# E0.6 [2] (⌚..⌛) watch..hourglass done
2328 ; Extended_Pictographic# E1.0 [1] (⌨️) keyboard
-2388 ; Extended_Pictographic# E0.0 [1] (⎈) HELM SYMBOL
23CF ; Extended_Pictographic# E1.0 [1] (⏏️) eject button
23E9..23EC ; Extended_Pictographic# E0.6 [4] (⏩..⏬) fast-forward button..fast down button
23ED..23EE ; Extended_Pictographic# E0.7 [2] (⏭️..⏮️) next track button..last track button
@@ -844,106 +857,63 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
2600..2601 ; Extended_Pictographic# E0.6 [2] (☀️..☁️) sun..cloud
2602..2603 ; Extended_Pictographic# E0.7 [2] (☂️..☃️) umbrella..snowman
2604 ; Extended_Pictographic# E1.0 [1] (☄️) comet
-2605 ; Extended_Pictographic# E0.0 [1] (★) BLACK STAR
-2607..260D ; Extended_Pictographic# E0.0 [7] (☇..☍) LIGHTNING..OPPOSITION
260E ; Extended_Pictographic# E0.6 [1] (☎️) telephone
-260F..2610 ; Extended_Pictographic# E0.0 [2] (☏..☐) WHITE TELEPHONE..BALLOT BOX
2611 ; Extended_Pictographic# E0.6 [1] (☑️) check box with check
-2612 ; Extended_Pictographic# E0.0 [1] (☒) BALLOT BOX WITH X
2614..2615 ; Extended_Pictographic# E0.6 [2] (☔..☕) umbrella with rain drops..hot beverage
-2616..2617 ; Extended_Pictographic# E0.0 [2] (☖..☗) WHITE SHOGI PIECE..BLACK SHOGI PIECE
2618 ; Extended_Pictographic# E1.0 [1] (☘️) shamrock
-2619..261C ; Extended_Pictographic# E0.0 [4] (☙..☜) REVERSED ROTATED FLORAL HEART BULLET..WHITE LEFT POINTING INDEX
261D ; Extended_Pictographic# E0.6 [1] (☝️) index pointing up
-261E..261F ; Extended_Pictographic# E0.0 [2] (☞..☟) WHITE RIGHT POINTING INDEX..WHITE DOWN POINTING INDEX
2620 ; Extended_Pictographic# E1.0 [1] (☠️) skull and crossbones
-2621 ; Extended_Pictographic# E0.0 [1] (☡) CAUTION SIGN
2622..2623 ; Extended_Pictographic# E1.0 [2] (☢️..☣️) radioactive..biohazard
-2624..2625 ; Extended_Pictographic# E0.0 [2] (☤..☥) CADUCEUS..ANKH
2626 ; Extended_Pictographic# E1.0 [1] (☦️) orthodox cross
-2627..2629 ; Extended_Pictographic# E0.0 [3] (☧..☩) CHI RHO..CROSS OF JERUSALEM
262A ; Extended_Pictographic# E0.7 [1] (☪️) star and crescent
-262B..262D ; Extended_Pictographic# E0.0 [3] (☫..☭) FARSI SYMBOL..HAMMER AND SICKLE
262E ; Extended_Pictographic# E1.0 [1] (☮️) peace symbol
262F ; Extended_Pictographic# E0.7 [1] (☯️) yin yang
-2630..2637 ; Extended_Pictographic# E0.0 [8] (☰..☷) TRIGRAM FOR HEAVEN..TRIGRAM FOR EARTH
2638..2639 ; Extended_Pictographic# E0.7 [2] (☸️..☹️) wheel of dharma..frowning face
263A ; Extended_Pictographic# E0.6 [1] (☺️) smiling face
-263B..263F ; Extended_Pictographic# E0.0 [5] (☻..☿) BLACK SMILING FACE..MERCURY
2640 ; Extended_Pictographic# E4.0 [1] (♀️) female sign
-2641 ; Extended_Pictographic# E0.0 [1] (♁) EARTH
2642 ; Extended_Pictographic# E4.0 [1] (♂️) male sign
-2643..2647 ; Extended_Pictographic# E0.0 [5] (♃..♇) JUPITER..PLUTO
2648..2653 ; Extended_Pictographic# E0.6 [12] (♈..♓) Aries..Pisces
-2654..265E ; Extended_Pictographic# E0.0 [11] (♔..♞) WHITE CHESS KING..BLACK CHESS KNIGHT
265F ; Extended_Pictographic# E11.0 [1] (♟️) chess pawn
2660 ; Extended_Pictographic# E0.6 [1] (♠️) spade suit
-2661..2662 ; Extended_Pictographic# E0.0 [2] (♡..♢) WHITE HEART SUIT..WHITE DIAMOND SUIT
2663 ; Extended_Pictographic# E0.6 [1] (♣️) club suit
-2664 ; Extended_Pictographic# E0.0 [1] (♤) WHITE SPADE SUIT
2665..2666 ; Extended_Pictographic# E0.6 [2] (♥️..♦️) heart suit..diamond suit
-2667 ; Extended_Pictographic# E0.0 [1] (♧) WHITE CLUB SUIT
2668 ; Extended_Pictographic# E0.6 [1] (♨️) hot springs
-2669..267A ; Extended_Pictographic# E0.0 [18] (♩..♺) QUARTER NOTE..RECYCLING SYMBOL FOR GENERIC MATERIALS
267B ; Extended_Pictographic# E0.6 [1] (♻️) recycling symbol
-267C..267D ; Extended_Pictographic# E0.0 [2] (♼..♽) RECYCLED PAPER SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
267E ; Extended_Pictographic# E11.0 [1] (♾️) infinity
267F ; Extended_Pictographic# E0.6 [1] (♿) wheelchair symbol
-2680..2685 ; Extended_Pictographic# E0.0 [6] (⚀..⚅) DIE FACE-1..DIE FACE-6
-2690..2691 ; Extended_Pictographic# E0.0 [2] (⚐..⚑) WHITE FLAG..BLACK FLAG
2692 ; Extended_Pictographic# E1.0 [1] (⚒️) hammer and pick
2693 ; Extended_Pictographic# E0.6 [1] (⚓) anchor
2694 ; Extended_Pictographic# E1.0 [1] (⚔️) crossed swords
2695 ; Extended_Pictographic# E4.0 [1] (⚕️) medical symbol
2696..2697 ; Extended_Pictographic# E1.0 [2] (⚖️..⚗️) balance scale..alembic
-2698 ; Extended_Pictographic# E0.0 [1] (⚘) FLOWER
2699 ; Extended_Pictographic# E1.0 [1] (⚙️) gear
-269A ; Extended_Pictographic# E0.0 [1] (⚚) STAFF OF HERMES
269B..269C ; Extended_Pictographic# E1.0 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
-269D..269F ; Extended_Pictographic# E0.0 [3] (⚝..⚟) OUTLINED WHITE STAR..THREE LINES CONVERGING LEFT
26A0..26A1 ; Extended_Pictographic# E0.6 [2] (⚠️..⚡) warning..high voltage
-26A2..26A6 ; Extended_Pictographic# E0.0 [5] (⚢..⚦) DOUBLED FEMALE SIGN..MALE WITH STROKE SIGN
26A7 ; Extended_Pictographic# E13.0 [1] (⚧️) transgender symbol
-26A8..26A9 ; Extended_Pictographic# E0.0 [2] (⚨..⚩) VERTICAL MALE WITH STROKE SIGN..HORIZONTAL MALE WITH STROKE SIGN
26AA..26AB ; Extended_Pictographic# E0.6 [2] (⚪..⚫) white circle..black circle
-26AC..26AF ; Extended_Pictographic# E0.0 [4] (⚬..⚯) MEDIUM SMALL WHITE CIRCLE..UNMARRIED PARTNERSHIP SYMBOL
26B0..26B1 ; Extended_Pictographic# E1.0 [2] (⚰️..⚱️) coffin..funeral urn
-26B2..26BC ; Extended_Pictographic# E0.0 [11] (⚲..⚼) NEUTER..SESQUIQUADRATE
26BD..26BE ; Extended_Pictographic# E0.6 [2] (⚽..⚾) soccer ball..baseball
-26BF..26C3 ; Extended_Pictographic# E0.0 [5] (⚿..⛃) SQUARED KEY..BLACK DRAUGHTS KING
26C4..26C5 ; Extended_Pictographic# E0.6 [2] (⛄..⛅) snowman without snow..sun behind cloud
-26C6..26C7 ; Extended_Pictographic# E0.0 [2] (⛆..⛇) RAIN..BLACK SNOWMAN
26C8 ; Extended_Pictographic# E0.7 [1] (⛈️) cloud with lightning and rain
-26C9..26CD ; Extended_Pictographic# E0.0 [5] (⛉..⛍) TURNED WHITE SHOGI PIECE..DISABLED CAR
26CE ; Extended_Pictographic# E0.6 [1] (⛎) Ophiuchus
26CF ; Extended_Pictographic# E0.7 [1] (⛏️) pick
-26D0 ; Extended_Pictographic# E0.0 [1] (⛐) CAR SLIDING
26D1 ; Extended_Pictographic# E0.7 [1] (⛑️) rescue worker’s helmet
-26D2 ; Extended_Pictographic# E0.0 [1] (⛒) CIRCLED CROSSING LANES
26D3 ; Extended_Pictographic# E0.7 [1] (⛓️) chains
26D4 ; Extended_Pictographic# E0.6 [1] (⛔) no entry
-26D5..26E8 ; Extended_Pictographic# E0.0 [20] (⛕..⛨) ALTERNATE ONE-WAY LEFT WAY TRAFFIC..BLACK CROSS ON SHIELD
26E9 ; Extended_Pictographic# E0.7 [1] (⛩️) shinto shrine
26EA ; Extended_Pictographic# E0.6 [1] (⛪) church
-26EB..26EF ; Extended_Pictographic# E0.0 [5] (⛫..⛯) CASTLE..MAP SYMBOL FOR LIGHTHOUSE
26F0..26F1 ; Extended_Pictographic# E0.7 [2] (⛰️..⛱️) mountain..umbrella on ground
26F2..26F3 ; Extended_Pictographic# E0.6 [2] (⛲..⛳) fountain..flag in hole
26F4 ; Extended_Pictographic# E0.7 [1] (⛴️) ferry
26F5 ; Extended_Pictographic# E0.6 [1] (⛵) sailboat
-26F6 ; Extended_Pictographic# E0.0 [1] (⛶) SQUARE FOUR CORNERS
26F7..26F9 ; Extended_Pictographic# E0.7 [3] (⛷️..⛹️) skier..person bouncing ball
26FA ; Extended_Pictographic# E0.6 [1] (⛺) tent
-26FB..26FC ; Extended_Pictographic# E0.0 [2] (⛻..⛼) JAPANESE BANK SYMBOL..HEADSTONE GRAVEYARD SYMBOL
26FD ; Extended_Pictographic# E0.6 [1] (⛽) fuel pump
-26FE..2701 ; Extended_Pictographic# E0.0 [4] (⛾..✁) CUP ON BLACK SQUARE..UPPER BLADE SCISSORS
2702 ; Extended_Pictographic# E0.6 [1] (✂️) scissors
-2703..2704 ; Extended_Pictographic# E0.0 [2] (✃..✄) LOWER BLADE SCISSORS..WHITE SCISSORS
2705 ; Extended_Pictographic# E0.6 [1] (✅) check mark button
2708..270C ; Extended_Pictographic# E0.6 [5] (✈️..✌️) airplane..victory hand
270D ; Extended_Pictographic# E0.7 [1] (✍️) writing hand
-270E ; Extended_Pictographic# E0.0 [1] (✎) LOWER RIGHT PENCIL
270F ; Extended_Pictographic# E0.6 [1] (✏️) pencil
-2710..2711 ; Extended_Pictographic# E0.0 [2] (✐..✑) UPPER RIGHT PENCIL..WHITE NIB
2712 ; Extended_Pictographic# E0.6 [1] (✒️) black nib
2714 ; Extended_Pictographic# E0.6 [1] (✔️) check mark
2716 ; Extended_Pictographic# E0.6 [1] (✖️) multiply
@@ -959,7 +929,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
2757 ; Extended_Pictographic# E0.6 [1] (❗) red exclamation mark
2763 ; Extended_Pictographic# E1.0 [1] (❣️) heart exclamation
2764 ; Extended_Pictographic# E0.6 [1] (❤️) red heart
-2765..2767 ; Extended_Pictographic# E0.0 [3] (❥..❧) ROTATED HEAVY BLACK HEART BULLET..ROTATED FLORAL HEART BULLET
2795..2797 ; Extended_Pictographic# E0.6 [3] (➕..➗) plus..divide
27A1 ; Extended_Pictographic# E0.6 [1] (➡️) right arrow
27B0 ; Extended_Pictographic# E0.6 [1] (➰) curly loop
@@ -973,19 +942,19 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
303D ; Extended_Pictographic# E0.6 [1] (〽️) part alternation mark
3297 ; Extended_Pictographic# E0.6 [1] (㊗️) Japanese “congratulations” button
3299 ; Extended_Pictographic# E0.6 [1] (㊙️) Japanese “secret” button
-1F000..1F003 ; Extended_Pictographic# E0.0 [4] (🀀..🀃) MAHJONG TILE EAST WIND..MAHJONG TILE NORTH WIND
1F004 ; Extended_Pictographic# E0.6 [1] (🀄) mahjong red dragon
-1F005..1F0CE ; Extended_Pictographic# E0.0 [202] (🀅..🃎) MAHJONG TILE GREEN DRAGON..PLAYING CARD KING OF DIAMONDS
+1F02C..1F02F ; Extended_Pictographic# E0.0 [4] (..) ..
+1F094..1F09F ; Extended_Pictographic# E0.0 [12] (..) ..
+1F0AF..1F0B0 ; Extended_Pictographic# E0.0 [2] (..) ..
+1F0C0 ; Extended_Pictographic# E0.0 [1] ()
1F0CF ; Extended_Pictographic# E0.6 [1] (🃏) joker
-1F0D0..1F0FF ; Extended_Pictographic# E0.0 [48] (..) ..
-1F10D..1F10F ; Extended_Pictographic# E0.0 [3] (🄍..🄏) CIRCLED ZERO WITH SLASH..CIRCLED DOLLAR SIGN WITH OVERLAID BACKSLASH
-1F12F ; Extended_Pictographic# E0.0 [1] (🄯) COPYLEFT SYMBOL
-1F16C..1F16F ; Extended_Pictographic# E0.0 [4] (🅬..🅯) RAISED MR SIGN..CIRCLED HUMAN FIGURE
+1F0D0 ; Extended_Pictographic# E0.0 [1] ()
+1F0F6..1F0FF ; Extended_Pictographic# E0.0 [10] (..) ..
1F170..1F171 ; Extended_Pictographic# E0.6 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
1F17E..1F17F ; Extended_Pictographic# E0.6 [2] (🅾️..🅿️) O button (blood type)..P button
1F18E ; Extended_Pictographic# E0.6 [1] (🆎) AB button (blood type)
1F191..1F19A ; Extended_Pictographic# E0.6 [10] (🆑..🆚) CL button..VS button
-1F1AD..1F1E5 ; Extended_Pictographic# E0.0 [57] (🆭..) MASK WORK SYMBOL..
+1F1AE..1F1E5 ; Extended_Pictographic# E0.0 [56] (..) ..
1F201..1F202 ; Extended_Pictographic# E0.6 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
1F203..1F20F ; Extended_Pictographic# E0.0 [13] (..) ..
1F21A ; Extended_Pictographic# E0.6 [1] (🈚) Japanese “free of charge” button
@@ -994,7 +963,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F23C..1F23F ; Extended_Pictographic# E0.0 [4] (..) ..
1F249..1F24F ; Extended_Pictographic# E0.0 [7] (..) ..
1F250..1F251 ; Extended_Pictographic# E0.6 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
-1F252..1F2FF ; Extended_Pictographic# E0.0 [174] (..) ..
+1F252..1F25F ; Extended_Pictographic# E0.0 [14] (..) ..
+1F266..1F2FF ; Extended_Pictographic# E0.0 [154] (..) ..
1F300..1F30C ; Extended_Pictographic# E0.6 [13] (🌀..🌌) cyclone..milky way
1F30D..1F30E ; Extended_Pictographic# E0.7 [2] (🌍..🌎) globe showing Europe-Africa..globe showing Americas
1F30F ; Extended_Pictographic# E0.6 [1] (🌏) globe showing Asia-Australia
@@ -1010,7 +980,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F31D..1F31E ; Extended_Pictographic# E1.0 [2] (🌝..🌞) full moon face..sun with face
1F31F..1F320 ; Extended_Pictographic# E0.6 [2] (🌟..🌠) glowing star..shooting star
1F321 ; Extended_Pictographic# E0.7 [1] (🌡️) thermometer
-1F322..1F323 ; Extended_Pictographic# E0.0 [2] (🌢..🌣) BLACK DROPLET..WHITE SUN
1F324..1F32C ; Extended_Pictographic# E0.7 [9] (🌤️..🌬️) sun behind small cloud..wind face
1F32D..1F32F ; Extended_Pictographic# E1.0 [3] (🌭..🌯) hot dog..burrito
1F330..1F331 ; Extended_Pictographic# E0.6 [2] (🌰..🌱) chestnut..seedling
@@ -1026,11 +995,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F37D ; Extended_Pictographic# E0.7 [1] (🍽️) fork and knife with plate
1F37E..1F37F ; Extended_Pictographic# E1.0 [2] (🍾..🍿) bottle with popping cork..popcorn
1F380..1F393 ; Extended_Pictographic# E0.6 [20] (🎀..🎓) ribbon..graduation cap
-1F394..1F395 ; Extended_Pictographic# E0.0 [2] (🎔..🎕) HEART WITH TIP ON THE LEFT..BOUQUET OF FLOWERS
1F396..1F397 ; Extended_Pictographic# E0.7 [2] (🎖️..🎗️) military medal..reminder ribbon
-1F398 ; Extended_Pictographic# E0.0 [1] (🎘) MUSICAL KEYBOARD WITH JACKS
1F399..1F39B ; Extended_Pictographic# E0.7 [3] (🎙️..🎛️) studio microphone..control knobs
-1F39C..1F39D ; Extended_Pictographic# E0.0 [2] (🎜..🎝) BEAMED ASCENDING MUSICAL NOTES..BEAMED DESCENDING MUSICAL NOTES
1F39E..1F39F ; Extended_Pictographic# E0.7 [2] (🎞️..🎟️) film frames..admission tickets
1F3A0..1F3C4 ; Extended_Pictographic# E0.6 [37] (🎠..🏄) carousel horse..person surfing
1F3C5 ; Extended_Pictographic# E1.0 [1] (🏅) sports medal
@@ -1045,11 +1011,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F3E0..1F3E3 ; Extended_Pictographic# E0.6 [4] (🏠..🏣) house..Japanese post office
1F3E4 ; Extended_Pictographic# E1.0 [1] (🏤) post office
1F3E5..1F3F0 ; Extended_Pictographic# E0.6 [12] (🏥..🏰) hospital..castle
-1F3F1..1F3F2 ; Extended_Pictographic# E0.0 [2] (🏱..🏲) WHITE PENNANT..BLACK PENNANT
1F3F3 ; Extended_Pictographic# E0.7 [1] (🏳️) white flag
1F3F4 ; Extended_Pictographic# E1.0 [1] (🏴) black flag
1F3F5 ; Extended_Pictographic# E0.7 [1] (🏵️) rosette
-1F3F6 ; Extended_Pictographic# E0.0 [1] (🏶) BLACK ROSETTE
1F3F7 ; Extended_Pictographic# E0.7 [1] (🏷️) label
1F3F8..1F3FA ; Extended_Pictographic# E1.0 [3] (🏸..🏺) badminton..amphora
1F400..1F407 ; Extended_Pictographic# E1.0 [8] (🐀..🐇) rat..rabbit
@@ -1086,7 +1050,6 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F4F8 ; Extended_Pictographic# E1.0 [1] (📸) camera with flash
1F4F9..1F4FC ; Extended_Pictographic# E0.6 [4] (📹..📼) video camera..videocassette
1F4FD ; Extended_Pictographic# E0.7 [1] (📽️) film projector
-1F4FE ; Extended_Pictographic# E0.0 [1] (📾) PORTABLE STEREO
1F4FF..1F502 ; Extended_Pictographic# E1.0 [4] (📿..🔂) prayer beads..repeat single button
1F503 ; Extended_Pictographic# E0.6 [1] (🔃) clockwise vertical arrows
1F504..1F507 ; Extended_Pictographic# E1.0 [4] (🔄..🔇) counterclockwise arrows button..muted speaker
@@ -1097,51 +1060,30 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F516..1F52B ; Extended_Pictographic# E0.6 [22] (🔖..🔫) bookmark..water pistol
1F52C..1F52D ; Extended_Pictographic# E1.0 [2] (🔬..🔭) microscope..telescope
1F52E..1F53D ; Extended_Pictographic# E0.6 [16] (🔮..🔽) crystal ball..downwards button
-1F546..1F548 ; Extended_Pictographic# E0.0 [3] (🕆..🕈) WHITE LATIN CROSS..CELTIC CROSS
1F549..1F54A ; Extended_Pictographic# E0.7 [2] (🕉️..🕊️) om..dove
1F54B..1F54E ; Extended_Pictographic# E1.0 [4] (🕋..🕎) kaaba..menorah
-1F54F ; Extended_Pictographic# E0.0 [1] (🕏) BOWL OF HYGIEIA
1F550..1F55B ; Extended_Pictographic# E0.6 [12] (🕐..🕛) one o’clock..twelve o’clock
1F55C..1F567 ; Extended_Pictographic# E0.7 [12] (🕜..🕧) one-thirty..twelve-thirty
-1F568..1F56E ; Extended_Pictographic# E0.0 [7] (🕨..🕮) RIGHT SPEAKER..BOOK
1F56F..1F570 ; Extended_Pictographic# E0.7 [2] (🕯️..🕰️) candle..mantelpiece clock
-1F571..1F572 ; Extended_Pictographic# E0.0 [2] (🕱..🕲) BLACK SKULL AND CROSSBONES..NO PIRACY
1F573..1F579 ; Extended_Pictographic# E0.7 [7] (🕳️..🕹️) hole..joystick
1F57A ; Extended_Pictographic# E3.0 [1] (🕺) man dancing
-1F57B..1F586 ; Extended_Pictographic# E0.0 [12] (🕻..🖆) LEFT HAND TELEPHONE RECEIVER..PEN OVER STAMPED ENVELOPE
1F587 ; Extended_Pictographic# E0.7 [1] (🖇️) linked paperclips
-1F588..1F589 ; Extended_Pictographic# E0.0 [2] (🖈..🖉) BLACK PUSHPIN..LOWER LEFT PENCIL
1F58A..1F58D ; Extended_Pictographic# E0.7 [4] (🖊️..🖍️) pen..crayon
-1F58E..1F58F ; Extended_Pictographic# E0.0 [2] (🖎..🖏) LEFT WRITING HAND..TURNED OK HAND SIGN
1F590 ; Extended_Pictographic# E0.7 [1] (🖐️) hand with fingers splayed
-1F591..1F594 ; Extended_Pictographic# E0.0 [4] (🖑..🖔) REVERSED RAISED HAND WITH FINGERS SPLAYED..REVERSED VICTORY HAND
1F595..1F596 ; Extended_Pictographic# E1.0 [2] (🖕..🖖) middle finger..vulcan salute
-1F597..1F5A3 ; Extended_Pictographic# E0.0 [13] (🖗..🖣) WHITE DOWN POINTING LEFT HAND INDEX..BLACK DOWN POINTING BACKHAND INDEX
1F5A4 ; Extended_Pictographic# E3.0 [1] (🖤) black heart
1F5A5 ; Extended_Pictographic# E0.7 [1] (🖥️) desktop computer
-1F5A6..1F5A7 ; Extended_Pictographic# E0.0 [2] (🖦..🖧) KEYBOARD AND MOUSE..THREE NETWORKED COMPUTERS
1F5A8 ; Extended_Pictographic# E0.7 [1] (🖨️) printer
-1F5A9..1F5B0 ; Extended_Pictographic# E0.0 [8] (🖩..🖰) POCKET CALCULATOR..TWO BUTTON MOUSE
1F5B1..1F5B2 ; Extended_Pictographic# E0.7 [2] (🖱️..🖲️) computer mouse..trackball
-1F5B3..1F5BB ; Extended_Pictographic# E0.0 [9] (🖳..🖻) OLD PERSONAL COMPUTER..DOCUMENT WITH PICTURE
1F5BC ; Extended_Pictographic# E0.7 [1] (🖼️) framed picture
-1F5BD..1F5C1 ; Extended_Pictographic# E0.0 [5] (🖽..🗁) FRAME WITH TILES..OPEN FOLDER
1F5C2..1F5C4 ; Extended_Pictographic# E0.7 [3] (🗂️..🗄️) card index dividers..file cabinet
-1F5C5..1F5D0 ; Extended_Pictographic# E0.0 [12] (🗅..🗐) EMPTY NOTE..PAGES
1F5D1..1F5D3 ; Extended_Pictographic# E0.7 [3] (🗑️..🗓️) wastebasket..spiral calendar
-1F5D4..1F5DB ; Extended_Pictographic# E0.0 [8] (🗔..🗛) DESKTOP WINDOW..DECREASE FONT SIZE SYMBOL
1F5DC..1F5DE ; Extended_Pictographic# E0.7 [3] (🗜️..🗞️) clamp..rolled-up newspaper
-1F5DF..1F5E0 ; Extended_Pictographic# E0.0 [2] (🗟..🗠) PAGE WITH CIRCLED TEXT..STOCK CHART
1F5E1 ; Extended_Pictographic# E0.7 [1] (🗡️) dagger
-1F5E2 ; Extended_Pictographic# E0.0 [1] (🗢) LIPS
1F5E3 ; Extended_Pictographic# E0.7 [1] (🗣️) speaking head
-1F5E4..1F5E7 ; Extended_Pictographic# E0.0 [4] (🗤..🗧) THREE RAYS ABOVE..THREE RAYS RIGHT
1F5E8 ; Extended_Pictographic# E2.0 [1] (🗨️) left speech bubble
-1F5E9..1F5EE ; Extended_Pictographic# E0.0 [6] (🗩..🗮) RIGHT SPEECH BUBBLE..LEFT ANGER BUBBLE
1F5EF ; Extended_Pictographic# E0.7 [1] (🗯️) right anger bubble
-1F5F0..1F5F2 ; Extended_Pictographic# E0.0 [3] (🗰..🗲) MOOD BUBBLE..LIGHTNING MOOD
1F5F3 ; Extended_Pictographic# E0.7 [1] (🗳️) ballot box with ballot
-1F5F4..1F5F9 ; Extended_Pictographic# E0.0 [6] (🗴..🗹) BALLOT SCRIPT X..BALLOT BOX WITH BOLD CHECK
1F5FA ; Extended_Pictographic# E0.7 [1] (🗺️) world map
1F5FB..1F5FF ; Extended_Pictographic# E0.6 [5] (🗻..🗿) mount fuji..moai
1F600 ; Extended_Pictographic# E1.0 [1] (😀) grinning face
@@ -1210,26 +1152,22 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F6BF ; Extended_Pictographic# E1.0 [1] (🚿) shower
1F6C0 ; Extended_Pictographic# E0.6 [1] (🛀) person taking bath
1F6C1..1F6C5 ; Extended_Pictographic# E1.0 [5] (🛁..🛅) bathtub..left luggage
-1F6C6..1F6CA ; Extended_Pictographic# E0.0 [5] (🛆..🛊) TRIANGLE WITH ROUNDED CORNERS..GIRLS SYMBOL
1F6CB ; Extended_Pictographic# E0.7 [1] (🛋️) couch and lamp
1F6CC ; Extended_Pictographic# E1.0 [1] (🛌) person in bed
1F6CD..1F6CF ; Extended_Pictographic# E0.7 [3] (🛍️..🛏️) shopping bags..bed
1F6D0 ; Extended_Pictographic# E1.0 [1] (🛐) place of worship
1F6D1..1F6D2 ; Extended_Pictographic# E3.0 [2] (🛑..🛒) stop sign..shopping cart
-1F6D3..1F6D4 ; Extended_Pictographic# E0.0 [2] (🛓..🛔) STUPA..PAGODA
1F6D5 ; Extended_Pictographic# E12.0 [1] (🛕) hindu temple
1F6D6..1F6D7 ; Extended_Pictographic# E13.0 [2] (🛖..🛗) hut..elevator
-1F6D8..1F6DB ; Extended_Pictographic# E0.0 [4] (..) ..
+1F6D8 ; Extended_Pictographic# E17.0 [1] () landslide
+1F6D9..1F6DB ; Extended_Pictographic# E0.0 [3] (..) ..
1F6DC ; Extended_Pictographic# E15.0 [1] (🛜) wireless
1F6DD..1F6DF ; Extended_Pictographic# E14.0 [3] (🛝..🛟) playground slide..ring buoy
1F6E0..1F6E5 ; Extended_Pictographic# E0.7 [6] (🛠️..🛥️) hammer and wrench..motor boat
-1F6E6..1F6E8 ; Extended_Pictographic# E0.0 [3] (🛦..🛨) UP-POINTING MILITARY AIRPLANE..UP-POINTING SMALL AIRPLANE
1F6E9 ; Extended_Pictographic# E0.7 [1] (🛩️) small airplane
-1F6EA ; Extended_Pictographic# E0.0 [1] (🛪) NORTHEAST-POINTING AIRPLANE
1F6EB..1F6EC ; Extended_Pictographic# E1.0 [2] (🛫..🛬) airplane departure..airplane arrival
1F6ED..1F6EF ; Extended_Pictographic# E0.0 [3] (..) ..
1F6F0 ; Extended_Pictographic# E0.7 [1] (🛰️) satellite
-1F6F1..1F6F2 ; Extended_Pictographic# E0.0 [2] (🛱..🛲) ONCOMING FIRE ENGINE..DIESEL LOCOMOTIVE
1F6F3 ; Extended_Pictographic# E0.7 [1] (🛳️) passenger ship
1F6F4..1F6F6 ; Extended_Pictographic# E3.0 [3] (🛴..🛶) kick scooter..canoe
1F6F7..1F6F8 ; Extended_Pictographic# E5.0 [2] (🛷..🛸) sled..flying saucer
@@ -1237,8 +1175,7 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F6FA ; Extended_Pictographic# E12.0 [1] (🛺) auto rickshaw
1F6FB..1F6FC ; Extended_Pictographic# E13.0 [2] (🛻..🛼) pickup truck..roller skate
1F6FD..1F6FF ; Extended_Pictographic# E0.0 [3] (..) ..
-1F774..1F77F ; Extended_Pictographic# E0.0 [12] (🝴..🝿) LOT OF FORTUNE..ORCUS
-1F7D5..1F7DF ; Extended_Pictographic# E0.0 [11] (🟕..) CIRCLED TRIANGLE..
+1F7DA..1F7DF ; Extended_Pictographic# E0.0 [6] (..) ..
1F7E0..1F7EB ; Extended_Pictographic# E12.0 [12] (🟠..🟫) orange circle..brown square
1F7EC..1F7EF ; Extended_Pictographic# E0.0 [4] (..) ..
1F7F0 ; Extended_Pictographic# E14.0 [1] (🟰) heavy equals sign
@@ -1247,7 +1184,10 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F848..1F84F ; Extended_Pictographic# E0.0 [8] (..) ..
1F85A..1F85F ; Extended_Pictographic# E0.0 [6] (..) ..
1F888..1F88F ; Extended_Pictographic# E0.0 [8] (..) ..
-1F8AE..1F8FF ; Extended_Pictographic# E0.0 [82] (..) ..
+1F8AE..1F8AF ; Extended_Pictographic# E0.0 [2] (..) ..
+1F8BC..1F8BF ; Extended_Pictographic# E0.0 [4] (..) ..
+1F8C2..1F8CF ; Extended_Pictographic# E0.0 [14] (..) ..
+1F8D9..1F8FF ; Extended_Pictographic# E0.0 [39] (..) ..
1F90C ; Extended_Pictographic# E13.0 [1] (🤌) pinched fingers
1F90D..1F90F ; Extended_Pictographic# E12.0 [3] (🤍..🤏) white heart..pinching hand
1F910..1F918 ; Extended_Pictographic# E1.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
@@ -1293,7 +1233,8 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1F9CD..1F9CF ; Extended_Pictographic# E12.0 [3] (🧍..🧏) person standing..deaf person
1F9D0..1F9E6 ; Extended_Pictographic# E5.0 [23] (🧐..🧦) face with monocle..socks
1F9E7..1F9FF ; Extended_Pictographic# E11.0 [25] (🧧..🧿) red envelope..nazar amulet
-1FA00..1FA6F ; Extended_Pictographic# E0.0 [112] (🨀..) NEUTRAL CHESS KING..
+1FA58..1FA5F ; Extended_Pictographic# E0.0 [8] (..) ..
+1FA6E..1FA6F ; Extended_Pictographic# E0.0 [2] (..) ..
1FA70..1FA73 ; Extended_Pictographic# E12.0 [4] (🩰..🩳) ballet shoes..shorts
1FA74 ; Extended_Pictographic# E13.0 [1] (🩴) thong sandal
1FA75..1FA77 ; Extended_Pictographic# E15.0 [3] (🩵..🩷) light blue heart..pink heart
@@ -1304,7 +1245,9 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1FA83..1FA86 ; Extended_Pictographic# E13.0 [4] (🪃..🪆) boomerang..nesting dolls
1FA87..1FA88 ; Extended_Pictographic# E15.0 [2] (🪇..🪈) maracas..flute
1FA89 ; Extended_Pictographic# E16.0 [1] () harp
-1FA8A..1FA8E ; Extended_Pictographic# E0.0 [5] (..) ..
+1FA8A ; Extended_Pictographic# E17.0 [1] () trombone
+1FA8B..1FA8D ; Extended_Pictographic# E0.0 [3] (..) ..
+1FA8E ; Extended_Pictographic# E17.0 [1] () treasure chest
1FA8F ; Extended_Pictographic# E16.0 [1] () shovel
1FA90..1FA95 ; Extended_Pictographic# E12.0 [6] (🪐..🪕) ringed planet..banjo
1FA96..1FAA8 ; Extended_Pictographic# E13.0 [19] (🪖..🪨) military helmet..rock
@@ -1318,7 +1261,10 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1FAC0..1FAC2 ; Extended_Pictographic# E13.0 [3] (🫀..🫂) anatomical heart..people hugging
1FAC3..1FAC5 ; Extended_Pictographic# E14.0 [3] (🫃..🫅) pregnant man..person with crown
1FAC6 ; Extended_Pictographic# E16.0 [1] () fingerprint
-1FAC7..1FACD ; Extended_Pictographic# E0.0 [7] (..) ..
+1FAC7 ; Extended_Pictographic# E0.0 [1] ()
+1FAC8 ; Extended_Pictographic# E17.0 [1] () hairy creature
+1FAC9..1FACC ; Extended_Pictographic# E0.0 [4] (..) ..
+1FACD ; Extended_Pictographic# E17.0 [1] () orca
1FACE..1FACF ; Extended_Pictographic# E15.0 [2] (🫎..🫏) moose..donkey
1FAD0..1FAD6 ; Extended_Pictographic# E13.0 [7] (🫐..🫖) blueberries..teapot
1FAD7..1FAD9 ; Extended_Pictographic# E14.0 [3] (🫗..🫙) pouring liquid..jar
@@ -1329,12 +1275,14 @@ E0020..E007F ; Emoji_Component # E0.0 [96] (..) tag space..c
1FAE0..1FAE7 ; Extended_Pictographic# E14.0 [8] (🫠..🫧) melting face..bubbles
1FAE8 ; Extended_Pictographic# E15.0 [1] (🫨) shaking face
1FAE9 ; Extended_Pictographic# E16.0 [1] () face with bags under eyes
-1FAEA..1FAEF ; Extended_Pictographic# E0.0 [6] (..) ..
+1FAEA ; Extended_Pictographic# E17.0 [1] () distorted face
+1FAEB..1FAEE ; Extended_Pictographic# E0.0 [4] (..) ..
+1FAEF ; Extended_Pictographic# E17.0 [1] () fight cloud
1FAF0..1FAF6 ; Extended_Pictographic# E14.0 [7] (🫰..🫶) hand with index finger and thumb crossed..heart hands
1FAF7..1FAF8 ; Extended_Pictographic# E15.0 [2] (🫷..🫸) leftwards pushing hand..rightwards pushing hand
1FAF9..1FAFF ; Extended_Pictographic# E0.0 [7] (..) ..
1FC00..1FFFD ; Extended_Pictographic# E0.0[1022] (..) ..
-# Total elements: 3537
+# Total elements: 2848
#EOF
diff --git a/resources/teamcity/ios/keyman-ios-test.sh b/resources/teamcity/ios/keyman-ios-test.sh
index 1c6f156238..63c48cc7dc 100755
--- a/resources/teamcity/ios/keyman-ios-test.sh
+++ b/resources/teamcity/ios/keyman-ios-test.sh
@@ -52,16 +52,14 @@ function __do_upload_to_testflight() {
local FASTLANE_ITC_PROVIDER="$1"
local FASTLANE_API_KEY_ID="$2"
local APP_IPA_DST
- local BUILD_NUMBER
export FASTLANE_ITC_TEAM_ID="$3"
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
- BUILD_NUMBER=$(cat ../VERSION.md)
- APP_IPA_DST="$4-ios-${BUILD_NUMBER}.ipa"
+ APP_IPA_DST="$4-ios-${KEYMAN_VERSION_FOR_FILENAME}.ipa"
- cd "upload/${BUILD_NUMBER}"
+ cd "upload/${KEYMAN_VERSION}"
command -v fastlane
# shellcheck disable=SC2154
fastlane pilot upload \
diff --git a/resources/teamcity/linux/keyman-linux-test.sh b/resources/teamcity/linux/keyman-linux-test.sh
index 950750b255..d89a57a75e 100755
--- a/resources/teamcity/linux/keyman-linux-test.sh
+++ b/resources/teamcity/linux/keyman-linux-test.sh
@@ -33,7 +33,7 @@ function make_source_tarball_action() {
if builder_is_ci_build_level_release; then
builder_echo start "make source tarball" "Make source tarball"
rm -rf dist
- make tmpsources
+ PKG_CONFIG_PATH="${KEYMAN_ROOT}/core/build/arch/release/meson-private" "${KEYMAN_ROOT}/linux/scripts/dist.sh"
builder_echo end "make source tarball" success "Finished making source tarball"
else
builder_echo "Skipping source tarball creation - not release build level"
diff --git a/resources/teamcity/triggers/trigger-test-builds.sh b/resources/teamcity/triggers/trigger-test-builds.sh
index 635f133687..cbd317ec8a 100755
--- a/resources/teamcity/triggers/trigger-test-builds.sh
+++ b/resources/teamcity/triggers/trigger-test-builds.sh
@@ -12,6 +12,7 @@ THIS_SCRIPT="$(readlink -f "${BASH_SOURCE[0]}")"
. "${THIS_SCRIPT%/*}/../../../resources/build/builder-full.inc.sh"
## END STANDARD BUILD SCRIPT INCLUDE
+# shellcheck disable=SC2154
. "${KEYMAN_ROOT}/resources/build/ci/trigger-definitions.inc.sh"
. "${KEYMAN_ROOT}/resources/build/ci/trigger-builds.inc.sh"
. "${KEYMAN_ROOT}/resources/build/ci/trigger-build-bot.inc.sh"
@@ -29,15 +30,15 @@ if ! builder_has_option --branch; then
builder_die "--branch parameter is required"
fi
-if [[ ! "$PRNUM" =~ ^([0-9]+|master|beta|stable-[0-9]+\.[0-9]+)$ ]]; then
- builder_die "Invalid parameter --branch '$PRNUM'; expected 'master', 'beta', 'stable-x.y', or PR number"
+if [[ ! "${PRNUM}" =~ ^([0-9]+|master|beta|stable-[0-9]+\.[0-9]+)$ ]]; then
+ builder_die "Invalid parameter --branch '${PRNUM}'; expected 'master', 'beta', 'stable-x.y', or PR number"
fi
#
# Debug logging
#
function debug_echo() {
- if [ ! -z ${DEBUG:-} ]; then
+ if [[ ! -z ${DEBUG:-} ]]; then
echo "DEBUG: $1"
fi
true
@@ -59,44 +60,45 @@ function triggerTestBuilds() {
# Cancel any already running builds for this branch
if builder_has_option --dry-run; then
- builder_echo "DRY RUN: cancel current builds for $branch"
+ builder_echo "DRY RUN: cancel current builds for ${branch}"
else
- node "$KEYMAN_ROOT/resources/build/ci/cancel-builds/cancel-test-builds.mjs" "$branch" "$TEAMCITY_TOKEN"
+ node "${KEYMAN_ROOT}/resources/build/ci/cancel-builds/cancel-test-builds.mjs" "${branch}" "${TEAMCITY_TOKEN}"
fi
for platform in "${!platforms[@]}"; do
- local platformBuildLevel=${platforms[$platform]}
- if [[ $platformBuildLevel == skip ]]; then
- builder_echo heading "$platform: skipping build"
+ local platformBuildLevel=${platforms[${platform}]}
+ if [[ ${platformBuildLevel} == skip ]]; then
+ builder_echo heading "${platform}: skipping build"
continue
fi
- builder_echo heading "$platform: checking for git changes"
- eval test_builds='(${'bc_test_$platform'[@]})'
+ builder_echo heading "${platform}: checking for git changes"
+ eval test_builds='(${'bc_test_${platform}'[@]})'
+ # shellcheck disable=SC2154
for test_build in "${test_builds[@]}"; do
- if [[ $test_build == "" ]]; then continue; fi
+ if [[ ${test_build} == "" ]]; then continue; fi
found_build=true
- if [ "${test_build:(-7)}" == "_GitHub" ]; then
+ if [[ "${test_build:(-7)}" == "_GitHub" ]]; then
local job=${test_build%_GitHub}
if builder_has_option --dry-run; then
- builder_echo "DRY RUN: Triggering GitHub action build $job/$branch, level = $platformBuildLevel"
+ builder_echo "DRY RUN: Triggering GitHub action build ${job}/${branch}, level = ${platformBuildLevel}"
else
- builder_echo "Triggering GitHub action build $job/$branch, level = $platformBuildLevel"
- triggerGitHubActionsBuild true $platformBuildLevel "$job" "$branch"
+ builder_echo "Triggering GitHub action build ${job}/${branch}, level = ${platformBuildLevel}"
+ triggerGitHubActionsBuild true "${platformBuildLevel}" "${job}" "${branch}" "${KEYMAN_API_CHECK_SKIP}"
fi
else
if builder_has_option --dry-run; then
- builder_echo "DRY RUN: Triggering build configuration $test_build on teamcity for $branch, level = $platformBuildLevel"
+ builder_echo "DRY RUN: Triggering build configuration ${test_build} on teamcity for ${branch}, level = ${platformBuildLevel}"
else
- builder_echo "Triggering build configuration $test_build on teamcity for $branch, level = $platformBuildLevel"
- triggerTeamCityBuild true $platformBuildLevel "$test_build" "$vcs_test" "$branch"
+ builder_echo "Triggering build configuration ${test_build} on teamcity for ${branch}, level = ${platformBuildLevel}"
+ triggerTeamCityBuild true "${platformBuildLevel}" "${test_build}" "${vcs_test}" "${branch}"
fi
fi
done
done
- if [[ $found_build == false ]]; then
+ if [[ ${found_build} == false ]]; then
postSkippedBuildsStatusResult
fi
}
@@ -111,7 +113,7 @@ function postSkippedBuildsStatusResult() {
curl --silent --write-out '\n' \
--request POST \
--header "Accept: application/vnd.github+json" \
- --header "Authorization: token $GITHUB_TOKEN" \
+ --header "Authorization: token ${GITHUB_TOKEN}" \
--data '{"state":"success","description":"Skipping since no platform builds necessary","context":"Test Build (Keyman)"}' \
"https://api.github.com/repos/keymanapp/keyman/statuses/${BUILD_VCS_NUMBER}"
fi
@@ -122,10 +124,10 @@ function postSkippedBuildsStatusResult() {
# branches as well as pull requests
#
-if [[ ! "$PRNUM" =~ ^[[:digit:]]+$ ]]; then
+if [[ ! "${PRNUM}" =~ ^[[:digit:]]+$ ]]; then
# branch name is 'master', 'beta', or 'stable-x.y'
- builder_echo "Branch $PRNUM needs to pass tests on all platforms."
- triggerTestBuilds main_branch_platform_build_levels $PRNUM
+ builder_echo "Branch ${PRNUM} needs to pass tests on all platforms."
+ triggerTestBuilds main_branch_platform_build_levels "${PRNUM}"
exit 0
fi
@@ -136,20 +138,20 @@ fi
# targeted by the PR other than to ask GitHub, anyway.)
#
-builder_echo grey "# Get information about pull request #$PRNUM from GitHub"
-prinfo=`curl -s -H "User-Agent: @keymanapp" -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/repos/keymanapp/keyman/pulls/$PRNUM`
-prbase=`echo ${prinfo} | "$JQ" -r '.base.ref'`
-prhead=`echo ${prinfo} | "$JQ" -r '.head.ref'`
-prbaserepo=`echo ${prinfo} | "$JQ" -r '.base.repo.html_url'`
-prheadrepo=`echo ${prinfo} | "$JQ" -r '.head.repo.html_url'`
+builder_echo grey "# Get information about pull request #${PRNUM} from GitHub"
+prinfo=$(curl -s -H "User-Agent: @keymanapp" -H "Authorization: Bearer ${GITHUB_TOKEN}" "https://api.github.com/repos/keymanapp/keyman/pulls/${PRNUM}")
+prbase=$(echo "${prinfo}" | "${JQ}" -r '.base.ref')
+prhead=$(echo "${prinfo}" | "${JQ}" -r '.head.ref')
+prbaserepo=$(echo "${prinfo}" | "${JQ}" -r '.base.repo.html_url')
+prheadrepo=$(echo "${prinfo}" | "${JQ}" -r '.head.repo.html_url')
-debug_echo "PRNUM: $PRNUM"
-debug_echo "BASE: $prbase ($prbaserepo)"
-debug_echo "HEAD: $prhead ($prheadrepo)"
+debug_echo "PRNUM: ${PRNUM}"
+debug_echo "BASE: ${prbase} (${prbaserepo})"
+debug_echo "HEAD: ${prhead} (${prheadrepo})"
prremote=origin
-if [ "$prbaserepo" != "https://github.com/keymanapp/keyman" ]; then
- echo "Unknown base repository $prbaserepo."
+if [[ "${prbaserepo}" != "https://github.com/keymanapp/keyman" ]]; then
+ echo "Unknown base repository ${prbaserepo}."
exit 1
fi
@@ -160,7 +162,7 @@ fi
# (Ensure we are within the repository before running git calls)
builder_echo grey "# Ensure our local branch is up to date"
-pushd "$KEYMAN_ROOT" > /dev/null
+pushd "${KEYMAN_ROOT}" > /dev/null
git fetch origin > /dev/null
#
@@ -169,10 +171,10 @@ git fetch origin > /dev/null
# on untrusted forks.
#
-if [ "$prheadrepo" != "https://github.com/keymanapp/keyman" ]; then
+if [[ "${prheadrepo}" != "https://github.com/keymanapp/keyman" ]]; then
prremote=external-rrtb
- git remote add "$prremote" "$prheadrepo"
- git fetch "$prremote" > /dev/null
+ git remote add "${prremote}" "${prheadrepo}"
+ git fetch "${prremote}" > /dev/null
fi
#
@@ -181,18 +183,18 @@ fi
#
builder_echo grey "# Get list of changed files in the pull request"
-prfiles=`git diff --name-only "origin/$prbase"..."$prremote/$prhead" || ( if [ $? == 128 ]; then echo abort; else exit $?; fi )`
-if [ "$prfiles" == "abort" ]; then
+prfiles=$(git diff --name-only "origin/${prbase}...${prremote}/${prhead}" || ( if [[ $? == 128 ]]; then echo abort; else exit $?; fi ))
+if [[ "${prfiles}" == "abort" ]]; then
# Don't trigger any builds, exit with success
- if [ "$prremote" != "origin" ]; then
- git remote remove "$prremote"
+ if [[ "${prremote}" != "origin" ]]; then
+ git remote remove "${prremote}"
fi
- echo "Remote branch origin/$prhead has gone away; probably an automatic pull request. Skipping build."
+ echo "Remote branch origin/${prhead} has gone away; probably an automatic pull request. Skipping build."
exit 0
fi
-if [ "$prremote" != "origin" ]; then
- git remote remove "$prremote"
+if [[ "${prremote}" != "origin" ]]; then
+ git remote remove "${prremote}"
fi
debug_echo "Files found: ${prfiles[*]}"
@@ -212,23 +214,23 @@ function find_platform_changes() {
while IFS= read -r line; do
# for each platform
for platform in "${available_platforms[@]}"; do
- if [[ ! " ${!build_platforms[@]} " =~ " $platform " ]]; then
+ if [[ ! " ${!build_platforms[*]} " =~ " ${platform} " ]]; then
# Which platform are we watching?
- eval watch='$'watch_$platform
+ eval watch="'$'watch_${platform}"
# Add common patterns to the watch list
- watch="^(${platform}|(oem/[^/]+/${platform})|resources/((?!teamcity)|teamcity/(${platform}|includes))|${watch})"
+ watch="^(${platform}|(oem/[^/]+/${platform})|resources/((?!teamcity|docker-images)|teamcity/(${platform}|includes)|docker-images/(${platform}|base))|${watch})"
# Since bash doesn't support negative look-aheads we use perl to test
# (grep has a --perl-regexp option, but not the version on macOS)
if perl -e 'exit($ARGV[0] =~ /$ARGV[1]/ ? 0 : 1)' "${line}" "${watch}"; then
# By default, we'll build a 'release' test build for touched platforms
- build_platforms[$platform]=$build_level_release
+ build_platforms[${platform}]=${build_level_release}
fi
fi
done
- done <<< "$prfiles"
+ done <<< "${prfiles}"
- builder_echo blue "Default build platforms: ${!build_platforms[@]}"
+ builder_echo blue "Default build platforms: ${!build_platforms[*]}"
}
find_platform_changes
@@ -238,7 +240,9 @@ find_platform_changes
# This will modify the build_platforms array
#
-if [ "$prremote" == "origin" ]; then
+KEYMAN_API_CHECK_SKIP="false"
+
+if [[ "${prremote}" == "origin" ]]; then
# We only accept Build-bot commands on trusted local origin PRs
cd "${KEYMAN_ROOT}/resources/build/ci/github"
npm ci
@@ -249,9 +253,10 @@ if [ "$prremote" == "origin" ]; then
NODE_WRAPPER=node
fi
# Note: we may move all of this into javascript at some point!
- prcommits=$(${NODE_WRAPPER} api-pull-commits.mjs $GITHUB_TOKEN $PRNUM)
- test_bot_check_pr_body "$PRNUM" "$prinfo"
- build_bot_check_messages $PRNUM "$prinfo" "$prcommits"
+ prcommits=$(${NODE_WRAPPER} api-pull-commits.mjs "${GITHUB_TOKEN}" "${PRNUM}")
+ test_bot_check_pr_body "${PRNUM}" "${prinfo}"
+ build_bot_check_messages "${PRNUM}" "${prinfo}" "${prcommits}"
+ KEYMAN_API_CHECK_SKIP="$(is_skip_keyman_api_check "${PRNUM}" "${prinfo}")"
fi
#
@@ -260,7 +265,7 @@ fi
if [[ ! -z "${build_platforms[*]:-}" ]] && (( ${#build_platforms[@]} > 0)); then
builder_echo heading "Start test builds"
- triggerTestBuilds build_platforms $PRNUM
+ triggerTestBuilds build_platforms "${PRNUM}"
else
builder_echo heading "No builds to start"
postSkippedBuildsStatusResult
diff --git a/web/docs/engine/index.md b/web/docs/engine/index.md
index 5515112f88..377b1ae66f 100644
--- a/web/docs/engine/index.md
+++ b/web/docs/engine/index.md
@@ -20,7 +20,7 @@ computer browsers.
-[What's New](whats-new)
+[What's New](whatsnew)
: What's new in Keyman Engine for Web 19.0
diff --git a/web/docs/engine/whats-new.md b/web/docs/engine/whats-new.md
deleted file mode 100644
index e220fb9c13..0000000000
--- a/web/docs/engine/whats-new.md
+++ /dev/null
@@ -1,3 +0,0 @@
----
-title: What's New in KeymanWeb 19.0
----
diff --git a/web/docs/engine/whatsnew.md b/web/docs/engine/whatsnew.md
new file mode 100644
index 0000000000..8828f3b81f
--- /dev/null
+++ b/web/docs/engine/whatsnew.md
@@ -0,0 +1,7 @@
+---
+title: What's New in KeymanWeb 19.0
+---
+
+## See also
+
+* [Keyman Engine for Web Documentation](index)
diff --git a/web/src/engine/osk/src/visualKeyboard.ts b/web/src/engine/osk/src/visualKeyboard.ts
index 1e9f88af03..ffded2c033 100644
--- a/web/src/engine/osk/src/visualKeyboard.ts
+++ b/web/src/engine/osk/src/visualKeyboard.ts
@@ -797,6 +797,7 @@ export default class VisualKeyboard extends EventEmitter implements Ke
if (this.usesFixedWidthScaling) {
let baseWidth = this.width;
baseWidth -= this._borderWidth * 2;
+ baseWidth = (isNaN(baseWidth) || baseWidth < 0) ? 0 : baseWidth;
return ParsedLengthStyle.inPixels(baseWidth);
} else {
return ParsedLengthStyle.forScalar(1);
@@ -821,7 +822,9 @@ export default class VisualKeyboard extends EventEmitter implements Ke
// Touch OSKs may apply internal padding to prevent row cropping at the edges.
// ... why not precompute both, rather than recalculate each time?
// - appears to contribute to layout reflow costs on layer swaps!
- return ParsedLengthStyle.inPixels(this.layoutHeight.val - this._borderWidth * 2 - this.layerGroup.verticalPadding);
+ let baseHeight = this.layoutHeight.val - this._borderWidth * 2 - this.layerGroup.verticalPadding;
+ baseHeight = (isNaN(baseHeight) || baseHeight < 0) ? 0 : baseHeight;
+ return ParsedLengthStyle.inPixels(baseHeight);
} else {
return ParsedLengthStyle.forScalar(1);
}
diff --git a/web/src/engine/predictive-text/worker-thread/src/main/correction/classical-calculation.ts b/web/src/engine/predictive-text/worker-thread/src/main/correction/classical-calculation.ts
index 6964673fad..7975f5eb8b 100644
--- a/web/src/engine/predictive-text/worker-thread/src/main/correction/classical-calculation.ts
+++ b/web/src/engine/predictive-text/worker-thread/src/main/correction/classical-calculation.ts
@@ -555,7 +555,6 @@ export class ClassicalDistanceCalculation<
return trimmedInstance;
}
- // Inputs add an extra row / first index entry.
// Inputs add an extra row / first index entry.
addInputChar(token: TUnit): this {
const returnBuffer = new ClassicalDistanceCalculation(this);
@@ -583,7 +582,7 @@ export class ClassicalDistanceCalculation<
}
addMatchChar(token: TUnit): this {
- let returnBuffer = new ClassicalDistanceCalculation(this);
+ const returnBuffer = new ClassicalDistanceCalculation(this);
returnBuffer._addMatchChar(token);
return returnBuffer as this;
}
diff --git a/web/src/test/auto/headless/engine/osk/visualKeyboard.tests.ts b/web/src/test/auto/headless/engine/osk/visualKeyboard.tests.ts
new file mode 100644
index 0000000000..991c4be98b
--- /dev/null
+++ b/web/src/test/auto/headless/engine/osk/visualKeyboard.tests.ts
@@ -0,0 +1,241 @@
+/*
+ * Keyman is copyright (C) SIL Global. MIT License.
+ */
+import { assert } from 'chai';
+import sinon from 'sinon';
+// @ts-ignore // Type info unavailable; doing a npm-install for it breaks things much worse in other ways.
+import { JSDOM } from 'jsdom';
+
+import { VisualKeyboard } from 'keyman/engine/osk';
+import { ActiveLayout, Keyboard, KeyboardProperties } from 'keyman/engine/keyboard';
+import { StylesheetManager } from 'keyman/engine/dom-utils';
+import { DeviceSpec } from "@keymanapp/web-utils";
+
+describe('VisualKeyboard', () => {
+ let dom: JSDOM;
+ let mockConfig: any;
+
+ beforeEach(() => {
+ dom = new JSDOM('Hello world
');
+ global.document = dom.window.document;
+ global.getComputedStyle = dom.window.getComputedStyle;
+
+ const mockDevice = { browser: DeviceSpec.Browser.Chrome, formFactor: DeviceSpec.FormFactor.Desktop, OS: DeviceSpec.OperatingSystem.Windows, touchable: false };
+ const mockLayout = sinon.createStubInstance(ActiveLayout) as any;
+
+ const keyboard = sinon.createStubInstance(Keyboard) as any;
+ keyboard.layout.returns(mockLayout);
+ sinon.stub(keyboard, 'isRTL').get(() => false);
+ sinon.stub(keyboard, 'id').get(() => 'test');
+ sinon.stub(keyboard, 'name').get(() => 'Test Keyboard');
+
+ mockConfig = {
+ device: mockDevice,
+ hostDevice: mockDevice,
+ pathConfig: { fonts: '', resources: '' },
+ keyboard: keyboard,
+ keyboardMetadata: sinon.createStubInstance(KeyboardProperties),
+ topContainer: document.createElement('div'),
+ styleSheetManager: sinon.createStubInstance(StylesheetManager),
+ };
+ });
+
+ function createVisualKeyboard(fixedScaling: boolean = true): VisualKeyboard {
+ const vk = new VisualKeyboard(mockConfig);
+ vk.usesFixedHeightScaling = fixedScaling;
+ vk.usesFixedWidthScaling = fixedScaling;
+ vk['_borderWidth'] = 3;
+ return vk;
+ }
+
+ describe('LayoutHeight', () => {
+ it('calculates LayoutHeight correctly for number', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = 100;
+ assert.equal(vk.layoutHeight.val, 94);
+ });
+
+ it('calculates LayoutHeight correctly for number string', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "100";
+ assert.equal(vk.layoutHeight.val, 94);
+ });
+
+ it('accepts small heights for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "5";
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('ignores non-number string for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "100px";
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('ignores invalid string for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "invalid";
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('ignores undefined value for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = undefined;
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('ignores null value for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = null;
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('calculates LayoutHeight correctly with fixed scaling', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_height'] = 100;
+ assert.equal(vk.layoutHeight.val, 94);
+ });
+
+ it('calculates LayoutHeight correctly with fixed scaling and string', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_height'] = "100px";
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+
+ it('ignores invalid borderWidth for LayoutHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = 100;
+ vk['_borderWidth'] = "3px";
+ assert.equal(vk.layoutHeight.val, 0);
+ });
+ });
+
+ describe('LayoutWidth', () => {
+ it('calculates LayoutWidth correctly for number', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = 100;
+ assert.equal(vk.layoutWidth.val, 94);
+ });
+
+ it('calculates LayoutWidth correctly for number string', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = "100";
+ assert.equal(vk.layoutWidth.val, 94);
+ });
+
+ it('accepts small heights for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = "5";
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('ignores non-number string for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = "100px";
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('ignores invalid string for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = "invalid";
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('ignores undefined value for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = undefined;
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('ignores null value for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = null;
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('calculates LayoutWidth correctly with fixed scaling', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_width'] = 100;
+ assert.equal(vk.layoutWidth.val, 94);
+ });
+
+ it('calculates LayoutWidth correctly with fixed scaling and string', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_width'] = "100px";
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ it('ignores invalid borderWidth for LayoutWidth', () => {
+ const vk = createVisualKeyboard();
+ vk['_width'] = 100;
+ vk['_borderWidth'] = "3px";
+ assert.equal(vk.layoutWidth.val, 0);
+ });
+
+ });
+
+ describe('InternalHeight', () => {
+ it('calculates InternalHeight correctly for number', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = 100;
+ assert.equal(vk.internalHeight.val, 88);
+ });
+
+ it('calculates InternalHeight correctly for number string', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "100";
+ assert.equal(vk.internalHeight.val, 88);
+ });
+
+ it('accepts small heights for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "5";
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('ignores non-number string for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "100px";
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('ignores invalid string for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = "invalid";
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('ignores undefined value for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = undefined;
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('ignores null value for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = null;
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('calculates InternalHeight correctly with fixed scaling', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_height'] = 100;
+ assert.equal(vk.internalHeight.val, 88);
+ });
+
+ it('calculates InternalHeight correctly with fixed scaling and string', () => {
+ const vk = createVisualKeyboard(true);
+ vk['_height'] = "100px";
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ it('ignores invalid borderWidth for InternalHeight', () => {
+ const vk = createVisualKeyboard();
+ vk['_height'] = 100;
+ vk['_borderWidth'] = "3px";
+ assert.equal(vk.internalHeight.val, 0);
+ });
+
+ });
+});
diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/alignment-helpers.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/alignment-helpers.tests.ts
index d25528a7fe..4872d31766 100644
--- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/alignment-helpers.tests.ts
+++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/alignment-helpers.tests.ts
@@ -188,8 +188,8 @@ describe('computeAlignment', () => {
canAlign: true,
editPath: [
{op: 'substitute', input: 0, match: 0},
- {op: 'insert', match: 1},
- {op: 'insert', match: 2}
+ {op: 'insert', match: 1},
+ {op: 'insert', match: 2}
],
leadTokenShift: 0,
leadEditLength: 0,
@@ -347,7 +347,7 @@ describe('computeAlignment', () => {
assert.deepEqual(computedAlignment, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
+ {op: 'insert', match: 0},
{op: 'match', input: 0, match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
@@ -399,7 +399,7 @@ describe('computeAlignment', () => {
assert.deepEqual(computedAlignment, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
+ {op: 'insert', match: 0},
{op: 'substitute', input: 0, match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
@@ -430,7 +430,7 @@ describe('computeAlignment', () => {
{op: 'match', input: 2, match: 1},
{op: 'match', input: 3, match: 2},
{op: 'match', input: 4, match: 3},
- {op: 'insert', match: 4}
+ {op: 'insert', match: 4}
],
leadTokenShift: -1,
leadEditLength: 0,
@@ -483,7 +483,7 @@ describe('computeAlignment', () => {
{op: 'match', input: 2, match: 2},
{op: 'match', input: 3, match: 3},
{op: 'substitute', input: 4, match: 4},
- {op: 'insert', match: 5}
+ {op: 'insert', match: 5}
],
leadTokenShift: 0,
leadEditLength: 1,
@@ -505,7 +505,7 @@ describe('computeAlignment', () => {
assert.deepEqual(computedAlignment, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
+ {op: 'insert', match: 0},
{op: 'match', input: 0, match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
@@ -532,7 +532,7 @@ describe('computeAlignment', () => {
assert.deepEqual(computedAlignment, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
+ {op: 'insert', match: 0},
{op: 'match', input: 0, match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
@@ -559,7 +559,7 @@ describe('computeAlignment', () => {
assert.deepEqual(computedAlignment, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
+ {op: 'insert', match: 0},
{op: 'match', input: 0, match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
@@ -608,7 +608,7 @@ describe('computeAlignment', () => {
canAlign: false,
editPath: [
{op: 'match', input: 0, match: 0},
- {op: 'insert', match: 1},
+ {op: 'insert', match: 1},
{op: 'match', input: 1, match: 2},
{op: 'match', input: 2, match: 3},
{op: 'match', input: 3, match: 4}
@@ -653,7 +653,7 @@ describe('computeAlignment', () => {
{op: 'match', input: 1, match: 1},
{op: 'match', input: 2, match: 2},
{op: 'match', input: 3, match: 3},
- {op: 'insert', match: 4},
+ {op: 'insert', match: 4},
{op: 'match', input: 4, match: 5}
]
});
@@ -715,8 +715,8 @@ describe('computeAlignment', () => {
{op: 'match', input: 8, match: 8},
{op: 'match', input: 9, match: 9},
{op: 'substitute', input: 10, match: 10},
- {op: 'insert', match: 11},
- {op: 'insert', match: 12}
+ {op: 'insert', match: 11},
+ {op: 'insert', match: 12}
],
leadTokenShift: 0,
leadEditLength: 0,
diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/context-tokenization.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/context-tokenization.tests.ts
index 6a79cae8ce..e88ac2ab28 100644
--- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/context-tokenization.tests.ts
+++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/context/context-tokenization.tests.ts
@@ -138,8 +138,8 @@ describe('ContextTokenization', function() {
{op: 'match', input: 4, match: 4},
{op: 'match', input: 5, match: 5},
{op: 'match', input: 6, match: 6},
- {op: 'insert', match: 7},
- {op: 'insert', match: 8}
+ {op: 'insert', match: 7},
+ {op: 'insert', match: 8}
],
leadTokenShift: 0,
leadEditLength: 0,
@@ -436,8 +436,8 @@ describe('ContextTokenization', function() {
targetTokens, {
canAlign: true,
editPath: [
- {op: 'insert', match: 0},
- {op: 'insert', match: 1},
+ {op: 'insert', match: 0},
+ {op: 'insert', match: 1},
{op: 'match', input: 0, match: 2},
{op: 'match', input: 1, match: 3},
{op: 'match', input: 2, match: 4},
@@ -614,8 +614,8 @@ describe('ContextTokenization', function() {
{op: 'match', input: 10, match: 9},
{op: 'match', input: 11, match: 10},
{op: 'match', input: 12, match: 11},
- {op: 'insert', match: 12},
- {op: 'insert', match: 13}
+ {op: 'insert', match: 12},
+ {op: 'insert', match: 13}
],
leadTokenShift: 1, // "'",
leadEditLength: 1, // "n't" / "t"
diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/classical-calculation.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/classical-calculation.tests.ts
index c61f4d89b9..5f53de43ea 100644
--- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/classical-calculation.tests.ts
+++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/classical-calculation.tests.ts
@@ -592,7 +592,7 @@ describe('Classical Damerau-Levenshtein edit-distance calculation', function() {
{ op: 'match', input: 1 /* 'c' */, match: 1 /* 'c' */},
{ op: 'match', input: 2 /* 'c' */, match: 2 /* 'c' */},
{ op: 'match', input: 3 /* 'o' */, match: 3 /* 'o' */},
- { op: 'insert', match: 4 /* 'm' */}, // insert is earlier
+ { op: 'insert', match: 4 /* 'm' */}, // insert is earlier
{ op: 'match', input: 4 /* 'm' */, match: 5 /* 'm' */}, // longer contiguous match sequence
{ op: 'match', input: 5 /* 'o' */, match: 6 /* 'o' */},
{ op: 'match', input: 6 /* 'd' */, match: 7 /* 'd' */},
@@ -605,7 +605,7 @@ describe('Classical Damerau-Levenshtein edit-distance calculation', function() {
{ op: 'match', input: 2 /* 'c' */, match: 2 /* 'c' */},
{ op: 'match', input: 3 /* 'o' */, match: 3 /* 'o' */},
{ op: 'match', input: 4 /* 'm' */, match: 4 /* 'm' */},
- { op: 'insert', match: 5 /* 'm' */}, // now inserting later.
+ { op: 'insert', match: 5 /* 'm' */}, // now inserting later.
{ op: 'match', input: 5 /* 'o' */, match: 6 /* 'o' */},
{ op: 'match', input: 6 /* 'd' */, match: 7 /* 'd' */},
{ op: 'match', input: 7 /* 'a' */, match: 8 /* 'a' */},
@@ -635,7 +635,7 @@ describe('Classical Damerau-Levenshtein edit-distance calculation', function() {
{ op: 'delete', input: 3},
{ op: 'match', input: 4, match: 3},
{ op: 'match', input: 5, match: 4},
- { op: 'insert', match: 5}
+ { op: 'insert', match: 5}
];
const viablePaths = buffer.editPath();
@@ -687,14 +687,14 @@ describe('Classical Damerau-Levenshtein edit-distance calculation', function() {
{ op: 'match', input: 1, match: 1}, // best sequence: continguous matches
{ op: 'match', input: 2, match: 2}, // + adjacent substitutes
{ op: 'substitute', input: 3, match: 3},
- { op: 'insert', match: 4},
+ { op: 'insert', match: 4},
];
let altSequence: EditTuple[] = [
{ op: 'match', input: 0, match: 0},
{ op: 'match', input: 1, match: 1},
{ op: 'match', input: 2, match: 2},
- { op: 'insert', match: 3},
+ { op: 'insert', match: 3},
{ op: 'substitute', input: 3, match: 4},
];
@@ -717,7 +717,7 @@ describe('Classical Damerau-Levenshtein edit-distance calculation', function() {
{ op: 'match', input: 5, match: 3},
{ op: 'match', input: 6, match: 4},
{ op: 'transpose-start', input: 7, match: 5},
- { op: 'transpose-insert', match: 6},
+ { op: 'transpose-insert', match: 6},
{ op: 'transpose-end', input: 8, match: 7}
];
diff --git a/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/segmentable-calculation.tests.ts b/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/segmentable-calculation.tests.ts
index 9b8df03e3c..1abdfa89e4 100644
--- a/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/segmentable-calculation.tests.ts
+++ b/web/src/test/auto/headless/engine/predictive-text/worker-thread/correction-search/segmentable-calculation.tests.ts
@@ -147,7 +147,6 @@ describe('Split/merge aware edit-distance calculation', () => {
assert.equal(calc.getFinalCost(), 4);
const editPaths = calc.editPath();
- assert.isAbove(editPaths.length, 3);
assert.sameDeepOrderedMembers(editPaths[0], [
{ op: 'split', input: 0, match: 0 },
{ op: 'split', input: 0, match: 1 },
@@ -156,6 +155,26 @@ describe('Split/merge aware edit-distance calculation', () => {
{ op: 'merge', input: 3, match: 4 },
{ op: 'merge', input: 4, match: 4 }
]);
+
+ // ('insert', 'substitute') can be reordered
+ // ('substitute', 'delete') can be reordered
+ // There also exist cases where one pair or the other, but not both,
+ // are considered for the edit path.
+ assert.includeDeepMembers(editPaths, [[
+ { op: 'insert', match: 0 }, // -> 'b'
+ { op: 'substitute', input: 0, match: 1 }, // 'abc' -> 'c'
+ { op: 'match', input: 1, match: 2 }, // 'd' == 'd'
+ { op: 'match', input: 2, match: 3 }, // 'e' == 'e'
+ { op: 'substitute', input: 3, match: 4 }, // 'f' -> 'fgh'
+ { op: 'delete', input: 4 } // 'g' ->
+ ]]);
+
+ // both split and merge: 1 variation
+ // split, but not merge: 2 variations
+ // merge, but not split: 2 variations
+ // neither: 2x2 = 4 variations
+ // sum: 9
+ assert.equal(editPaths.length, 9);
});
it("abcd,e,f,g -> b,c,d,efgh = 4", () => {
@@ -180,10 +199,10 @@ describe('Split/merge aware edit-distance calculation', () => {
]);
assert.sameDeepOrderedMembers(editPaths[1], [
- { op: 'substitute', input: 0, match: 0 },
- { op: 'substitute', input: 1, match: 1 },
- { op: 'substitute', input: 2, match: 2 },
- { op: 'substitute', input: 3, match: 3 }
+ { op: 'substitute', input: 0, match: 0 }, // 'abcd' -> 'b'
+ { op: 'substitute', input: 1, match: 1 }, // 'e' -> 'c'
+ { op: 'substitute', input: 2, match: 2 }, // 'f' -> 'd'
+ { op: 'substitute', input: 3, match: 3 } // 'g' -> 'efgh'
]);
});
});
\ No newline at end of file
diff --git a/windows/docs/help/common/unicode.md b/windows/docs/help/common/unicode.md
index 614934e72c..fd567c8ce4 100644
--- a/windows/docs/help/common/unicode.md
+++ b/windows/docs/help/common/unicode.md
@@ -3,5 +3,5 @@ title: Does Keyman support Unicode?
---
Yes, since Keyman 5, Keyman fully supports the Unicode Standard, up to
-and including Unicode 13.0. We also update Keyman with each new release
+and including Unicode 17.0. We also update Keyman with each new release
of the Unicode Standard.
diff --git a/windows/src/desktop/inst/build.sh b/windows/src/desktop/inst/build.sh
index aa581d5e04..8e64342a22 100755
--- a/windows/src/desktop/inst/build.sh
+++ b/windows/src/desktop/inst/build.sh
@@ -15,7 +15,7 @@ builder_describe "Installation files for Keyman for Windows" \
# after all other builds complete
builder_if_release_build_level builder_describe_outputs \
- publish /windows/release/${KEYMAN_VERSION}/keyman-${KEYMAN_VERSION}.exe
+ publish /windows/release/${KEYMAN_VERSION}/keyman-${KEYMAN_VERSION_FOR_FILENAME}.exe
builder_parse "$@"
@@ -104,7 +104,7 @@ function copy-installer() {
mkdir -p "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}"
cp keymandesktop.msi "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/keymandesktop.msi"
- cp keymandesktop.exe "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/keyman-${KEYMAN_VERSION}.exe"
+ cp keymandesktop.exe "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/keyman-${KEYMAN_VERSION_FOR_FILENAME}.exe"
cp "$WINDOWS_PROGRAM_APP/setup.exe" "$KEYMAN_ROOT/windows/release/${KEYMAN_VERSION}/setup.exe"
verify-installer-signatures
diff --git a/windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas b/windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas
index 7b831b97c4..d98e2c05f0 100644
--- a/windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas
+++ b/windows/src/desktop/kmshell/main/Keyman.System.UpdateStateMachine.pas
@@ -88,14 +88,19 @@ type
procedure HandleFirstRun;
function CurrentStateName: string;
(**
- * Checks if Keyman is the WaitingRestartState and that
- * Keyman has not run in this Windows session.
- * The sole purpose is for the calling code then produce
- * a UI to confirm the user wants to continue install.
+ * Checks if Keyman is the WaitingRestartState, the cache is valid
+ * and that Keyman has not run in this Windows session. It also confirms
+ * that automatic updates are still enabled #14295.
+ * The purpose is for the calling code can choose to produce
+ * a UI to confirm the user wants to install an update,
+ * if everything is ready to start a update.
+ *
+ * NOTE: If it finds the cache is invalid it will abort causing
+ * the State Machine to change state, returning to idle.
*
* @returns True if the Keyman is ready to install.
*)
- function ReadyToInstall: Boolean;
+ function ValidateReadyToInstall: Boolean;
function IsInstallingState: Boolean;
function GetAutomaticUpdates: Boolean;
@@ -558,14 +563,27 @@ begin
Result := CurrentState.ClassName;
end;
-function TUpdateStateMachine.ReadyToInstall: Boolean;
+function TUpdateStateMachine.ValidateReadyToInstall: Boolean;
begin
if not IsCurrentStateAssigned then
Exit(False);
- if (CurrentState is WaitingRestartState) and not HasKeymanRun then
- Result := True
- else
- Result := False;
+
+ if not (CurrentState is WaitingRestartState) then
+ Exit(False);
+
+ // Verify conditions since entering WaitingRestartState:
+ // If the cache is not valid or automatic updates have
+ // been disabled clear the cache and return to the idle state.
+ if not TUpdateCheckStorage.CheckMetaDataForUpdate or not Self.GetAutomaticUpdates then
+ begin
+ HandleAbort;
+ Exit(False);
+ end;
+
+ if not HasKeymanRun then
+ Exit(True);
+
+ Result := False;
end;
function TUpdateStateMachine.IsInstallingState: Boolean;
@@ -955,7 +973,7 @@ begin
// Return to Idle state and check for Updates state
ChangeState(IdleState);
bucStateContext.CurrentState.HandleCheck;
- Result := kmShellExit;
+ Result := kmShellContinue;
end
else
begin
diff --git a/windows/src/desktop/kmshell/main/initprog.pas b/windows/src/desktop/kmshell/main/initprog.pas
index 8a9e037de6..1f02c696e3 100644
--- a/windows/src/desktop/kmshell/main/initprog.pas
+++ b/windows/src/desktop/kmshell/main/initprog.pas
@@ -668,20 +668,11 @@ function ShouldSendToBUpdateSM(FSilent: Boolean; BUpdateSM: TUpdateStateMachine;
// UI elements from the state machine we have bring some of logic here.
var
frmStartInstall: TfrmStartInstall;
- ReadyToInstall: Boolean;
+ ValidateReadyToInstall: Boolean;
begin
- ReadyToInstall := BUpdateSM.ReadyToInstall;
- // The setting for automatic updates may have been set to disable
- // after updates were checked and downloaded. The user should
- // not be prompted for an update in this case and the update should
- // abort.
- if not BUpdateSM.GetAutomaticUpdates and ReadyToInstall then
- begin
- BUpdateSM.HandleAbort;
- Exit(False);
- end;
+ ValidateReadyToInstall := BUpdateSM.ValidateReadyToInstall;
- if not FSilent and ReadyToInstall and
+ if not FSilent and ValidateReadyToInstall and
(FMode in [fmStart, fmSplash, fmMain, fmAbout,
fmHelp, fmShowHelp, fmSettings, fmBoot]) then
begin
@@ -692,7 +683,7 @@ begin
frmStartInstall.Free;
end;
end
- else if FSilent and ReadyToInstall then
+ else if FSilent and ValidateReadyToInstall then
Result := False
else
Result := True;