This is an automated email from the ASF dual-hosted git repository.

400Ping pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/mahout.git


The following commit(s) were added to refs/heads/main by this push:
     new 4d454cf3d [CI] Auto-merge gate for CI failures and PMC bypass ruleset 
for main (#1517)
4d454cf3d is described below

commit 4d454cf3d369126406b53fb425107640a4b6a05b
Author: Jie-Kai Chang <[email protected]>
AuthorDate: Wed Oct 14 02:42:00 2026 +0800

    [CI] Auto-merge gate for CI failures and PMC bypass ruleset for main (#1517)
    
    Signed-off-by: 400Ping <[email protected]>
---
 .asf.yaml                                         |  86 ++++++
 .github/pmc-members.txt                           |   3 +
 .github/scripts/automerge_gate.py                 | 337 ++++++++++++++++++++++
 .github/workflows/automerge-gate.yml              |  85 ++++++
 docs/community/pr-policy-and-review-guidelines.md |  30 +-
 5 files changed, 540 insertions(+), 1 deletion(-)

diff --git a/.asf.yaml b/.asf.yaml
index 1bfb5ec67..9736d574e 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -65,11 +65,97 @@ github:
       # GitHub's own required_approving_review_count (as used by Airflow) 
cannot
       # exempt PMC members, so the rule is enforced through this required 
status
       # check produced by .github/workflows/pr-approval-check.yml.
+      # "Auto-merge gate" (.github/workflows/automerge-gate.yml) keeps
+      # auto-merge (allow_auto_merge above) from merging a PR whose CI failed:
+      # GitHub auto-merge only waits for *required* checks, and the CI jobs
+      # themselves are deliberately not required so that a committer can still
+      # merge manually after a failure. The gate waits for all pull_request
+      # workflows, disables auto-merge on failure, and then passes.
+      #
+      # MIGRATION: the same rules are defined as the "main" ruleset below,
+      # which additionally lets PMC members bypass them. GitHub applies the
+      # most restrictive of classic protection and rulesets, so the bypass
+      # only works once this classic block is removed in a follow-up change
+      # (after confirming that the ruleset was created).
       required_status_checks:
         strict: false
         checks:
           - context: "Committer approval"
             app_id: 15368  # GitHub Actions
+          - context: "Auto-merge gate"
+            app_id: 15368  # GitHub Actions
+
+  # Branch rules for main, as a ruleset (raw Rulesets API payload) because
+  # only rulesets support bypass actors: PMC members can merge a pull request
+  # from the GitHub UI ("bypass rules") without waiting for the required
+  # checks, e.g. for urgent fixes or when the ASF runner queue is stuck.
+  # bypass_mode "pull_request" means they still have to open a pull request
+  # (no direct pushes) and every bypass is recorded in the audit log.
+  # The actor ids are the GitHub user ids of .github/pmc-members.txt; update
+  # both when the PMC roster changes (`gh api users/<login> -q .id`).
+  rulesets:
+    - name: "main"
+      target: branch
+      enforcement: active
+      conditions:
+        ref_name:
+          include:
+            - "~DEFAULT_BRANCH"
+          exclude: []
+      bypass_actors:
+        - actor_id: 692523  # andrewmusselman
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 7681565  # andrewpalumbo
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 105915352  # guan404ming
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 70953  # MaineC
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 43886578  # 400Ping
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 101171023  # rich7420
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 409707  # sscdotopen
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 135417  # magsol
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 176382  # sslavic
+          actor_type: User
+          bypass_mode: pull_request
+        - actor_id: 5852441  # rawkintrevo
+          actor_type: User
+          bypass_mode: pull_request
+      rules:
+        # Only bypass actors can delete or force-push main.
+        - type: deletion
+        - type: non_fast_forward
+        - type: required_linear_history
+        # Changes must come through a pull request. No review count here:
+        # committer approval is the status check below (with PMC exemption).
+        - type: pull_request
+          parameters:
+            required_approving_review_count: 0
+            dismiss_stale_reviews_on_push: false
+            require_code_owner_review: false
+            require_last_push_approval: false
+            required_review_thread_resolution: false
+        - type: required_status_checks
+          parameters:
+            strict_required_status_checks_policy: false
+            required_status_checks:
+              - context: "Committer approval"
+                integration_id: 15368  # GitHub Actions
+              - context: "Auto-merge gate"
+                integration_id: 15368  # GitHub Actions
+
   environments:
     pypi:
       required_reviewers:
diff --git a/.github/pmc-members.txt b/.github/pmc-members.txt
index 671dfbcca..99e464f90 100644
--- a/.github/pmc-members.txt
+++ b/.github/pmc-members.txt
@@ -28,6 +28,9 @@
 # their ASF id (https://gitbox.apache.org/boxer/) can merge; the others are 
listed
 # for completeness. Keep one username per line, case-insensitive.
 #
+# The same people are bypass actors (by numeric GitHub user id) of the "main"
+# ruleset in .asf.yaml; update both when the roster changes.
+#
 # GitHub username   # ASF id
 andrewmusselman     # akm
 andrewpalumbo       # apalumbo
diff --git a/.github/scripts/automerge_gate.py 
b/.github/scripts/automerge_gate.py
new file mode 100644
index 000000000..9c4a8887e
--- /dev/null
+++ b/.github/scripts/automerge_gate.py
@@ -0,0 +1,337 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Keep GitHub auto-merge from merging a pull request whose CI failed.
+
+This backs the ``Auto-merge gate`` required status check on ``main`` (see
+``.github/workflows/automerge-gate.yml`` and ``.asf.yaml``).
+
+Background: GitHub auto-merge only waits for *required* status checks. Making
+every CI job required would also block committers from merging manually when
+they decide a failure is acceptable (e.g. a flaky external check), which is
+not what the project wants. So instead a single required check waits for the
+``pull_request`` workflows of the head commit and then:
+
+* while any of them is still running -> exit 1 ("waiting"); the check is
+  re-evaluated every time one of them completes (``workflow_run`` trigger);
+* if every one of them passed (or was skipped) -> exit 0; auto-merge, if
+  enabled, merges the PR;
+* if any of them failed -> **disable auto-merge** on the PR (if it was
+  enabled) and leave a comment, then exit 0 so that a committer can still
+  merge manually. The failed CI job stays visible on the PR.
+
+Urgent changes do not go through this script at all: PMC members are bypass
+actors of the ``main`` ruleset in ``.asf.yaml`` and can merge a pull request
+from the GitHub UI without waiting for any required check.
+
+Only the Python standard library is used so the script runs in CI and locally:
+
+    GITHUB_TOKEN=$(gh auth token) DRY_RUN=1 python 
.github/scripts/automerge_gate.py \\
+        --repo apache/mahout --sha <head sha>
+
+``DRY_RUN=1`` performs no mutation (auto-merge is not disabled, no comment).
+"""
+
+from __future__ import annotations
+
+import argparse
+import json
+import os
+import sys
+import urllib.error
+import urllib.parse
+import urllib.request
+from typing import Any
+
+API_URL = os.environ.get("GITHUB_API_URL", "https://api.github.com";)
+GRAPHQL_URL = os.environ.get("GITHUB_GRAPHQL_URL", 
"https://api.github.com/graphql";)
+# Only workflows triggered by these events are CI for the pull request. In
+# particular this excludes "PR Approval Check" (pull_request_target), which is
+# its own required status check, and this gate itself (workflow_run).
+PR_EVENTS = {"pull_request"}
+# Conclusions that do not count as a CI failure.
+OK_CONCLUSIONS = {"success", "skipped", "neutral"}
+# A run that is waiting for a maintainer to approve it (fork PRs) is pending,
+# not failed.
+PENDING_CONCLUSIONS = {"action_required"}
+
+
+class GitHubError(RuntimeError):
+    """Raised when the GitHub API returns an unexpected response."""
+
+
+def _request(token: str, url: str, data: dict[str, Any] | None = None) -> Any:
+    body = json.dumps(data).encode("utf-8") if data is not None else None
+    request = urllib.request.Request(
+        url,
+        data=body,
+        method="POST" if body is not None else "GET",
+        headers={
+            "Accept": "application/vnd.github+json",
+            "Authorization": f"Bearer {token}",
+            "X-GitHub-Api-Version": "2022-11-28",
+            "User-Agent": "apache-mahout-automerge-gate",
+            **({"Content-Type": "application/json"} if body is not None else 
{}),
+        },
+    )
+    try:
+        with urllib.request.urlopen(request, timeout=30) as response:
+            return json.load(response)
+    except urllib.error.HTTPError as exc:
+        text = exc.read().decode("utf-8", errors="replace")
+        raise GitHubError(f"{request.method} {url} -> HTTP {exc.code}: 
{text}") from exc
+
+
+def _api(
+    token: str, path: str, params: dict[str, str] | None = None, data: Any = 
None
+) -> Any:
+    url = f"{API_URL}{path}"
+    if params:
+        url = f"{url}?{urllib.parse.urlencode(params)}"
+    return _request(token, url, data)
+
+
+def _graphql(token: str, query: str, variables: dict[str, Any]) -> dict[str, 
Any]:
+    result = _request(token, GRAPHQL_URL, {"query": query, "variables": 
variables})
+    if result.get("errors"):
+        raise GitHubError(f"GraphQL: {json.dumps(result['errors'])}")
+    return result["data"]
+
+
+def workflow_runs_for_sha(token: str, repo: str, sha: str) -> list[dict[str, 
Any]]:
+    runs: list[dict[str, Any]] = []
+    page = 1
+    while True:
+        chunk = _api(
+            token,
+            f"/repos/{repo}/actions/runs",
+            {"head_sha": sha, "per_page": "100", "page": str(page)},
+        )
+        runs.extend(chunk.get("workflow_runs") or [])
+        if len(chunk.get("workflow_runs") or []) < 100:
+            return runs
+        page += 1
+
+
+def latest_pr_runs(runs: list[dict[str, Any]]) -> dict[str, dict[str, Any]]:
+    """Map workflow name -> its most recent ``pull_request`` run for the 
commit.
+
+    A re-run reuses the run id (``run_attempt`` increases) and the API reports
+    the latest attempt, so keeping the newest run per workflow is enough.
+    """
+    latest: dict[str, dict[str, Any]] = {}
+    for run in runs:
+        if run.get("event") not in PR_EVENTS:
+            continue
+        name = run.get("name") or str(run.get("workflow_id"))
+        if name not in latest or run["id"] > latest[name]["id"]:
+            latest[name] = run
+    return latest
+
+
+def classify(run: dict[str, Any]) -> str:
+    """Return ``"pending"``, ``"ok"`` or ``"failed"`` for a workflow run."""
+    if run.get("status") != "completed":
+        return "pending"
+    conclusion = run.get("conclusion") or ""
+    if conclusion in PENDING_CONCLUSIONS:
+        return "pending"
+    if conclusion in OK_CONCLUSIONS:
+        return "ok"
+    return "failed"
+
+
+def open_prs_with_head(token: str, repo: str, sha: str) -> list[dict[str, 
Any]]:
+    prs = _api(token, f"/repos/{repo}/commits/{sha}/pulls", {"per_page": 
"100"})
+    # Only act on PRs whose *current* head is this commit: a failure on an
+    # already superseded commit must not touch the PR.
+    return [
+        pr
+        for pr in prs
+        if pr.get("state") == "open" and (pr.get("head") or {}).get("sha") == 
sha
+    ]
+
+
+def auto_merge_state(token: str, repo: str, number: int) -> tuple[str, str | 
None]:
+    """Return ``(node_id, enabled_by_login_or_None)`` for a pull request."""
+    owner, name = repo.split("/", 1)
+    data = _graphql(
+        token,
+        """
+        query($owner: String!, $name: String!, $number: Int!) {
+          repository(owner: $owner, name: $name) {
+            pullRequest(number: $number) {
+              id
+              autoMergeRequest { enabledBy { login } }
+            }
+          }
+        }
+        """,
+        {"owner": owner, "name": name, "number": number},
+    )
+    pr = data["repository"]["pullRequest"]
+    request = pr.get("autoMergeRequest")
+    enabled_by = ((request or {}).get("enabledBy") or {}).get("login")
+    return pr["id"], (enabled_by or "(unknown)") if request else None
+
+
+def disable_auto_merge(token: str, node_id: str) -> None:
+    _graphql(
+        token,
+        """
+        mutation($id: ID!) {
+          disablePullRequestAutoMerge(input: {pullRequestId: $id}) {
+            pullRequest { number }
+          }
+        }
+        """,
+        {"id": node_id},
+    )
+
+
+def comment(token: str, repo: str, number: int, body: str) -> None:
+    _api(token, f"/repos/{repo}/issues/{number}/comments", data={"body": body})
+
+
+def failure_comment(sha: str, failed: list[dict[str, Any]], enabled_by: str) 
-> str:
+    lines = [
+        f"**Auto-merge disabled** (it was enabled by @{enabled_by}): "
+        f"CI failed for {sha[:7]}.",
+        "",
+    ]
+    lines.extend(
+        f"- {run['name']}: {run.get('conclusion')} ({run.get('html_url')})"
+        for run in failed
+    )
+    lines.extend(
+        [
+            "",
+            "Push a fix and enable auto-merge again, or a committer can merge "
+            "manually if the failure is acceptable. Auto-merge is never "
+            "re-enabled automatically.",
+            "",
+            "_Posted by the `Auto-merge gate` workflow "
+            "(`.github/workflows/automerge-gate.yml`)._",
+        ]
+    )
+    return "\n".join(lines)
+
+
+def gate(token: str, repo: str, sha: str, dry_run: bool) -> tuple[bool, 
list[str]]:
+    """Evaluate the gate. Returns ``(ok, log_lines)``."""
+    lines: list[str] = []
+    runs = latest_pr_runs(workflow_runs_for_sha(token, repo, sha))
+    if not runs:
+        # Cannot happen when triggered by workflow_run, but be explicit.
+        lines.append(f"No pull_request workflow runs found for {sha[:7]}.")
+        return False, lines
+
+    pending: list[dict[str, Any]] = []
+    failed: list[dict[str, Any]] = []
+    for name in sorted(runs):
+        run = runs[name]
+        state = classify(run)
+        lines.append(
+            f"{name}: {run.get('status')}/{run.get('conclusion') or '-'} -> 
{state}"
+        )
+        if state == "pending":
+            pending.append(run)
+        elif state == "failed":
+            failed.append(run)
+
+    if pending:
+        names = ", ".join(run["name"] for run in pending)
+        lines.append(f"Waiting for: {names}. Re-evaluated when they complete.")
+        return False, lines
+
+    if not failed:
+        lines.append("All pull_request workflows passed or were skipped.")
+        return True, lines
+
+    names = ", ".join(run["name"] for run in failed)
+    lines.append(f"CI failed: {names}.")
+    for pr in open_prs_with_head(token, repo, sha):
+        number = int(pr["number"])
+        node_id, enabled_by = auto_merge_state(token, repo, number)
+        if enabled_by is None:
+            lines.append(f"PR #{number}: auto-merge not enabled; nothing to 
do.")
+            continue
+        if dry_run:
+            lines.append(
+                f"PR #{number}: auto-merge enabled by @{enabled_by}; "
+                "DRY_RUN set, would disable it and comment."
+            )
+            continue
+        disable_auto_merge(token, node_id)
+        comment(token, repo, number, failure_comment(sha, failed, enabled_by))
+        lines.append(
+            f"PR #{number}: auto-merge (enabled by @{enabled_by}) disabled; "
+            "comment posted."
+        )
+    lines.append(
+        "Passing the gate so that a committer can still merge manually; "
+        "the failed job remains visible on the PR."
+    )
+    return True, lines
+
+
+def main(argv: list[str] | None = None) -> int:
+    parser = argparse.ArgumentParser(
+        description=__doc__, 
formatter_class=argparse.RawDescriptionHelpFormatter
+    )
+    parser.add_argument(
+        "--repo",
+        default=os.environ.get("GITHUB_REPOSITORY"),
+        help="owner/name (default: $GITHUB_REPOSITORY)",
+    )
+    parser.add_argument(
+        "--sha",
+        default=os.environ.get("HEAD_SHA"),
+        help="pull request head commit (default: $HEAD_SHA)",
+    )
+    args = parser.parse_args(argv)
+
+    token = os.environ.get("GITHUB_TOKEN")
+    if not token or not args.repo or not args.sha:
+        parser.error(
+            "GITHUB_TOKEN, --repo/$GITHUB_REPOSITORY and --sha/$HEAD_SHA are 
required"
+        )
+    dry_run = os.environ.get("DRY_RUN", "") not in {"", "0", "false"}
+
+    try:
+        ok, lines = gate(token, args.repo, args.sha, dry_run)
+    except GitHubError as exc:
+        print(f"::error::{exc}")
+        return 1
+
+    verdict = (
+        "PASS" if ok else "WAITING: not all pull_request workflows have 
completed."
+    )
+    lines.append(verdict)
+    print("\n".join(lines))
+
+    summary_path = os.environ.get("GITHUB_STEP_SUMMARY")
+    if summary_path:
+        with open(summary_path, "a", encoding="utf-8") as summary:
+            summary.write("### Auto-merge gate\n\n")
+            summary.writelines(f"- {line}\n" for line in lines)
+    if not ok:
+        print(f"::notice::{verdict}")
+    return 0 if ok else 1
+
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/.github/workflows/automerge-gate.yml 
b/.github/workflows/automerge-gate.yml
new file mode 100644
index 000000000..9b8ea0d2e
--- /dev/null
+++ b/.github/workflows/automerge-gate.yml
@@ -0,0 +1,85 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Keeps GitHub auto-merge from merging a PR whose CI failed, without blocking
+# a committer from merging it manually 
(docs/community/pr-policy-and-review-guidelines.md).
+#
+# GitHub auto-merge only waits for *required* status checks, and a required
+# check blocks manual merges just the same. So the only required CI-related
+# check is the "Auto-merge gate" job below: it is re-run every time one of
+# the pull_request workflows finishes, stays red ("waiting") until all of
+# them have completed, and then
+#   * passes when everything succeeded (auto-merge proceeds), or
+#   * disables auto-merge on the PR, comments, and *still passes* when
+#     something failed, so the committer can merge manually.
+# Urgent PRs do not need this gate: PMC members are bypass actors of the main
+# ruleset (.asf.yaml) and can merge from the GitHub UI without waiting for it.
+# See .github/scripts/automerge_gate.py for the details.
+#
+name: Auto-merge Gate
+
+on:
+  workflow_run:
+    # Every workflow that runs on pull_request. A workflow missing from this
+    # list still counts for the gate (it lists all pull_request runs of the
+    # commit) but will not re-trigger the gate when it finishes, so the gate
+    # could stay in "waiting" until another workflow completes.
+    workflows:
+      - Pre-commit
+      - Python Testing
+      - CI for Jupyter Notebooks
+      - Wheel Build
+      - Website Build Check
+      - Links
+    types: [completed]
+
+permissions:
+  actions: read
+  # Both are needed by GITHUB_TOKEN to toggle auto-merge; pull-requests also
+  # covers the comment.
+  contents: write
+  pull-requests: write
+
+# Serialise gate runs per commit (no cancellation): the newest run always
+# finishes last, so the status reflects the latest state of CI.
+concurrency:
+  group: automerge-gate-${{ github.event.workflow_run.head_sha }}
+  cancel-in-progress: false
+
+jobs:
+  gate:
+    # This job name is the status check context referenced in .asf.yaml.
+    name: Auto-merge gate
+    # Only CI of pull requests matters (not pushes to main etc.).
+    if: github.event.workflow_run.event == 'pull_request'
+    runs-on: ubuntu-latest
+    timeout-minutes: 10
+
+    steps:
+      # workflow_run always runs the default-branch workflow; take the script
+      # from there as well. No code from the PR head is executed.
+      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
+        with:
+          persist-credentials: false
+          sparse-checkout: |
+            .github/scripts/automerge_gate.py
+          sparse-checkout-cone-mode: false
+
+      - name: Evaluate CI of the pull request head
+        env:
+          GITHUB_TOKEN: ${{ github.token }}
+          HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
+        run: python3 .github/scripts/automerge_gate.py
diff --git a/docs/community/pr-policy-and-review-guidelines.md 
b/docs/community/pr-policy-and-review-guidelines.md
index 7c4e5f5c8..17260c9ad 100644
--- a/docs/community/pr-policy-and-review-guidelines.md
+++ b/docs/community/pr-policy-and-review-guidelines.md
@@ -73,10 +73,38 @@ For non-trivial code contributions, contributors are 
expected to have an ASF ICL
 
 When deciding whether to merge, committers should verify all of the following:
 
-- Required CI checks are green.
+- Required CI checks are green (enforced automatically, see below).
 - At least one committer approves (enforced automatically, see below).
 - All blocking comments are resolved.
 
+#### Auto-merge and CI
+
+GitHub auto-merge only waits for *required* status checks, and the CI jobs are
+deliberately **not** required on `main`: a required check would also stop a
+committer from merging manually when a failure is judged acceptable. Instead
+the `Auto-merge gate` status check 
([`automerge-gate.yml`](https://github.com/apache/mahout/blob/main/.github/workflows/automerge-gate.yml))
+is required. It is re-evaluated every time a CI workflow of the PR finishes:
+
+- While any CI workflow is still running, the gate is red ("waiting"), so
+  auto-merge cannot fire early.
+- When every CI workflow passed (or was skipped), the gate passes and
+  auto-merge, if enabled, merges the PR.
+- When a CI workflow failed, the gate **disables auto-merge** on the PR, leaves
+  a comment, and then passes. The PR is not merged automatically, but a
+  committer can still merge it manually. Auto-merge has to be enabled again by
+  hand after a fix.
+- **Urgent changes (PMC only):** PMC members are bypass actors of the `main`
+  branch ruleset in 
[`.asf.yaml`](https://github.com/apache/mahout/blob/main/.asf.yaml).
+  On any pull request they can choose "Merge without waiting for requirements
+  to be met (bypass rules)" and merge immediately, without waiting for CI or
+  for the status checks above (for example when the ASF runner queue is
+  stuck). The change must still come as a pull request, and every bypass is
+  recorded in the repository's audit log. Use it deliberately.
+
+"Required CI checks are green" above therefore remains a committer
+responsibility: merging over a red CI job is possible and must be a deliberate
+decision.
+
 #### Enforced Committer Approval
 
 The `Committer approval` status check 
([`pr-approval-check.yml`](https://github.com/apache/mahout/blob/main/.github/workflows/pr-approval-check.yml))
 is required on `main` and re-runs whenever a review is submitted, edited, or 
dismissed:

Reply via email to