Chuyển đến nội dung chính Chuyển đến điều hướng tài liệu
Check
in English

Thẩm định

Cung cấp phản hồi hữu ích, có giá trị cho người dùng của bạn với xác thực biểu mẫu HTML5, thông qua các hành vi mặc định của trình duyệt hoặc kiểu tùy chỉnh và JavaScript.

Chúng tôi biết rằng hiện tại không thể truy cập các kiểu xác thực tùy chỉnh phía máy khách và chú giải công cụ, vì chúng không được tiếp xúc với các công nghệ hỗ trợ. Trong khi chúng tôi làm việc trên một giải pháp, chúng tôi khuyên bạn nên sử dụng tùy chọn phía máy chủ hoặc phương pháp xác thực trình duyệt mặc định.

Làm thế nào nó hoạt động

Đây là cách xác thực biểu mẫu hoạt động với Bootstrap:

  • Xác thực biểu mẫu HTML được áp dụng thông qua hai lớp giả của CSS :invalid:valid. Nó áp dụng cho <input>, <select><textarea>các phần tử.
  • Bootstrap mở rộng phạm vi :invalidvà các :validkiểu cho lớp cha .was-validated, thường được áp dụng cho <form>. Nếu không, bất kỳ trường bắt buộc nào không có giá trị sẽ hiển thị là không hợp lệ khi tải trang. Bằng cách này, bạn có thể chọn thời điểm kích hoạt chúng (thường là sau khi thử gửi biểu mẫu).
  • Để đặt lại giao diện của biểu mẫu (ví dụ: trong trường hợp gửi biểu mẫu động bằng AJAX), hãy xóa .was-validatedlớp khỏi lớp <form>đó sau khi gửi.
  • Là một dự phòng .is-invalid.is-validcác lớp có thể được sử dụng thay vì các lớp giả để xác thực phía máy chủ . Chúng không yêu cầu một .was-validatedlớp cha.
  • Do những hạn chế về cách hoạt động của CSS, chúng tôi (hiện tại) không thể áp dụng các kiểu cho một <label>điều khiển biểu mẫu trong DOM mà không có sự trợ giúp của JavaScript tùy chỉnh.
  • Tất cả các trình duyệt hiện đại đều hỗ trợ API xác thực ràng buộc , một loạt các phương pháp JavaScript để xác thực các điều khiển biểu mẫu.
  • Thông báo phản hồi có thể sử dụng các mặc định của trình duyệt (khác nhau đối với từng trình duyệt và không thể xóa thông qua CSS) hoặc các kiểu phản hồi tùy chỉnh của chúng tôi với HTML và CSS bổ sung.
  • Bạn có thể cung cấp thông báo hợp lệ tùy chỉnh bằng setCustomValidityJavaScript.

Với ý nghĩ đó, hãy xem xét các bản trình diễn sau cho các kiểu xác thực biểu mẫu tùy chỉnh của chúng tôi, các lớp phía máy chủ tùy chọn và mặc định của trình duyệt.

Phong cách tùy chỉnh

Đối với thông báo xác thực biểu mẫu Bootstrap tùy chỉnh, bạn sẽ cần thêm novalidatethuộc tính boolean vào của mình <form>. Thao tác này vô hiệu hóa chú giải công cụ phản hồi mặc định của trình duyệt, nhưng vẫn cung cấp quyền truy cập vào các API xác thực biểu mẫu trong JavaScript. Cố gắng gửi biểu mẫu dưới đây; JavaScript của chúng tôi sẽ chặn nút gửi và chuyển tiếp phản hồi cho bạn. Khi cố gắng gửi, bạn sẽ thấy các kiểu :invalid:validkiểu được áp dụng cho các điều khiển biểu mẫu của mình.

Kiểu phản hồi tùy chỉnh áp dụng màu tùy chỉnh, đường viền, kiểu tiêu điểm và biểu tượng nền để truyền đạt phản hồi tốt hơn. Biểu tượng nền cho <select>s chỉ khả dụng với .form-selectvà không .form-control.

Có vẻ tốt!
Có vẻ tốt!
@
Vui lòng chọn một tên người dùng.
Vui lòng cung cấp một thành phố hợp lệ.
Vui lòng chọn một trạng thái hợp lệ.
Vui lòng cung cấp một mã zip hợp lệ.
Bạn phải đồng ý trước khi gửi.
html
<form class="row g-3 needs-validation" novalidate>
  <div class="col-md-4">
    <label for="validationCustom01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationCustom01" value="Mark" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationCustom02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationCustom02" value="Otto" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationCustomUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="inputGroupPrepend">@</span>
      <input type="text" class="form-control" id="validationCustomUsername" aria-describedby="inputGroupPrepend" required>
      <div class="invalid-feedback">
        Please choose a username.
      </div>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationCustom03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationCustom03" required>
    <div class="invalid-feedback">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationCustom04" class="form-label">State</label>
    <select class="form-select" id="validationCustom04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div class="invalid-feedback">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationCustom05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationCustom05" required>
    <div class="invalid-feedback">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="" id="invalidCheck" required>
      <label class="form-check-label" for="invalidCheck">
        Agree to terms and conditions
      </label>
      <div class="invalid-feedback">
        You must agree before submitting.
      </div>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>
// Example starter JavaScript for disabling form submissions if there are invalid fields
(() => {
  'use strict'

  // Fetch all the forms we want to apply custom Bootstrap validation styles to
  const forms = document.querySelectorAll('.needs-validation')

  // Loop over them and prevent submission
  Array.from(forms).forEach(form => {
    form.addEventListener('submit', event => {
      if (!form.checkValidity()) {
        event.preventDefault()
        event.stopPropagation()
      }

      form.classList.add('was-validated')
    }, false)
  })
})()

Mặc định của trình duyệt

Không quan tâm đến thông báo phản hồi xác thực tùy chỉnh hoặc viết JavaScript để thay đổi hành vi của biểu mẫu? Tất cả tốt, bạn có thể sử dụng mặc định của trình duyệt. Hãy thử gửi biểu mẫu bên dưới. Tùy thuộc vào trình duyệt và hệ điều hành của bạn, bạn sẽ thấy một kiểu phản hồi hơi khác nhau.

Mặc dù không thể tạo kiểu cho các kiểu phản hồi này bằng CSS, nhưng bạn vẫn có thể tùy chỉnh văn bản phản hồi thông qua JavaScript.

@
html
<form class="row g-3">
  <div class="col-md-4">
    <label for="validationDefault01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationDefault01" value="Mark" required>
  </div>
  <div class="col-md-4">
    <label for="validationDefault02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationDefault02" value="Otto" required>
  </div>
  <div class="col-md-4">
    <label for="validationDefaultUsername" class="form-label">Username</label>
    <div class="input-group">
      <span class="input-group-text" id="inputGroupPrepend2">@</span>
      <input type="text" class="form-control" id="validationDefaultUsername"  aria-describedby="inputGroupPrepend2" required>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationDefault03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationDefault03" required>
  </div>
  <div class="col-md-3">
    <label for="validationDefault04" class="form-label">State</label>
    <select class="form-select" id="validationDefault04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
  </div>
  <div class="col-md-3">
    <label for="validationDefault05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationDefault05" required>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input" type="checkbox" value="" id="invalidCheck2" required>
      <label class="form-check-label" for="invalidCheck2">
        Agree to terms and conditions
      </label>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

Phía máy chủ

Chúng tôi khuyên bạn nên sử dụng xác thực phía máy khách, nhưng trong trường hợp bạn yêu cầu xác thực phía máy chủ, bạn có thể chỉ ra các trường biểu mẫu không hợp lệ và hợp lệ với .is-invalid.is-valid. Lưu ý rằng .invalid-feedbackcũng được hỗ trợ với các lớp này.

Đối với các trường không hợp lệ, hãy đảm bảo rằng thông báo phản hồi / lỗi không hợp lệ được liên kết với trường biểu mẫu có liên quan bằng cách sử dụng aria-describedby(lưu ý rằng thuộc tính này cho phép nhiều hơn một idđược tham chiếu, trong trường hợp trường đã trỏ đến văn bản biểu mẫu bổ sung).

Để khắc phục sự cố với bán kính đường viền , các nhóm đầu vào yêu cầu một .has-validationlớp bổ sung.

Có vẻ tốt!
Có vẻ tốt!
@
Vui lòng chọn một tên người dùng.
Vui lòng cung cấp một thành phố hợp lệ.
Vui lòng chọn một trạng thái hợp lệ.
Vui lòng cung cấp một mã zip hợp lệ.
Bạn phải đồng ý trước khi gửi.
html
<form class="row g-3">
  <div class="col-md-4">
    <label for="validationServer01" class="form-label">First name</label>
    <input type="text" class="form-control is-valid" id="validationServer01" value="Mark" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationServer02" class="form-label">Last name</label>
    <input type="text" class="form-control is-valid" id="validationServer02" value="Otto" required>
    <div class="valid-feedback">
      Looks good!
    </div>
  </div>
  <div class="col-md-4">
    <label for="validationServerUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="inputGroupPrepend3">@</span>
      <input type="text" class="form-control is-invalid" id="validationServerUsername" aria-describedby="inputGroupPrepend3 validationServerUsernameFeedback" required>
      <div id="validationServerUsernameFeedback" class="invalid-feedback">
        Please choose a username.
      </div>
    </div>
  </div>
  <div class="col-md-6">
    <label for="validationServer03" class="form-label">City</label>
    <input type="text" class="form-control is-invalid" id="validationServer03" aria-describedby="validationServer03Feedback" required>
    <div id="validationServer03Feedback" class="invalid-feedback">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationServer04" class="form-label">State</label>
    <select class="form-select is-invalid" id="validationServer04" aria-describedby="validationServer04Feedback" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div id="validationServer04Feedback" class="invalid-feedback">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3">
    <label for="validationServer05" class="form-label">Zip</label>
    <input type="text" class="form-control is-invalid" id="validationServer05" aria-describedby="validationServer05Feedback" required>
    <div id="validationServer05Feedback" class="invalid-feedback">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <div class="form-check">
      <input class="form-check-input is-invalid" type="checkbox" value="" id="invalidCheck3" aria-describedby="invalidCheck3Feedback" required>
      <label class="form-check-label" for="invalidCheck3">
        Agree to terms and conditions
      </label>
      <div id="invalidCheck3Feedback" class="invalid-feedback">
        You must agree before submitting.
      </div>
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

Các yếu tố được hỗ trợ

Các kiểu xác thực có sẵn cho các thành phần và điều khiển biểu mẫu sau:

  • <input>s và <textarea>s với .form-control(bao gồm tối đa một .form-controltrong các nhóm đầu vào)
  • <select>s với.form-select
  • .form-checkS
Vui lòng nhập một tin nhắn vào vùng văn bản.
Ví dụ văn bản phản hồi không hợp lệ
Thêm ví dụ về văn bản phản hồi không hợp lệ
Ví dụ về phản hồi lựa chọn không hợp lệ
Ví dụ về phản hồi tệp biểu mẫu không hợp lệ
html
<form class="was-validated">
  <div class="mb-3">
    <label for="validationTextarea" class="form-label">Textarea</label>
    <textarea class="form-control" id="validationTextarea" placeholder="Required example textarea" required></textarea>
    <div class="invalid-feedback">
      Please enter a message in the textarea.
    </div>
  </div>

  <div class="form-check mb-3">
    <input type="checkbox" class="form-check-input" id="validationFormCheck1" required>
    <label class="form-check-label" for="validationFormCheck1">Check this checkbox</label>
    <div class="invalid-feedback">Example invalid feedback text</div>
  </div>

  <div class="form-check">
    <input type="radio" class="form-check-input" id="validationFormCheck2" name="radio-stacked" required>
    <label class="form-check-label" for="validationFormCheck2">Toggle this radio</label>
  </div>
  <div class="form-check mb-3">
    <input type="radio" class="form-check-input" id="validationFormCheck3" name="radio-stacked" required>
    <label class="form-check-label" for="validationFormCheck3">Or toggle this other radio</label>
    <div class="invalid-feedback">More example invalid feedback text</div>
  </div>

  <div class="mb-3">
    <select class="form-select" required aria-label="select example">
      <option value="">Open this select menu</option>
      <option value="1">One</option>
      <option value="2">Two</option>
      <option value="3">Three</option>
    </select>
    <div class="invalid-feedback">Example invalid select feedback</div>
  </div>

  <div class="mb-3">
    <input type="file" class="form-control" aria-label="file example" required>
    <div class="invalid-feedback">Example invalid form file feedback</div>
  </div>

  <div class="mb-3">
    <button class="btn btn-primary" type="submit" disabled>Submit form</button>
  </div>
</form>

Chú giải công cụ

Nếu bố cục biểu mẫu của bạn cho phép, bạn có thể hoán đổi các .{valid|invalid}-feedbacklớp cho .{valid|invalid}-tooltipcác lớp để hiển thị phản hồi xác thực trong một chú giải công cụ được tạo kiểu. Đảm bảo có phụ huynh đi cùng position: relativeđể định vị chú giải công cụ. Trong ví dụ dưới đây, các lớp cột của chúng tôi đã có điều này, nhưng dự án của bạn có thể yêu cầu thiết lập thay thế.

Có vẻ tốt!
Có vẻ tốt!
@
Vui lòng chọn một tên người dùng hợp lệ và duy nhất.
Vui lòng cung cấp một thành phố hợp lệ.
Vui lòng chọn một trạng thái hợp lệ.
Vui lòng cung cấp một mã zip hợp lệ.
html
<form class="row g-3 needs-validation" novalidate>
  <div class="col-md-4 position-relative">
    <label for="validationTooltip01" class="form-label">First name</label>
    <input type="text" class="form-control" id="validationTooltip01" value="Mark" required>
    <div class="valid-tooltip">
      Looks good!
    </div>
  </div>
  <div class="col-md-4 position-relative">
    <label for="validationTooltip02" class="form-label">Last name</label>
    <input type="text" class="form-control" id="validationTooltip02" value="Otto" required>
    <div class="valid-tooltip">
      Looks good!
    </div>
  </div>
  <div class="col-md-4 position-relative">
    <label for="validationTooltipUsername" class="form-label">Username</label>
    <div class="input-group has-validation">
      <span class="input-group-text" id="validationTooltipUsernamePrepend">@</span>
      <input type="text" class="form-control" id="validationTooltipUsername" aria-describedby="validationTooltipUsernamePrepend" required>
      <div class="invalid-tooltip">
        Please choose a unique and valid username.
      </div>
    </div>
  </div>
  <div class="col-md-6 position-relative">
    <label for="validationTooltip03" class="form-label">City</label>
    <input type="text" class="form-control" id="validationTooltip03" required>
    <div class="invalid-tooltip">
      Please provide a valid city.
    </div>
  </div>
  <div class="col-md-3 position-relative">
    <label for="validationTooltip04" class="form-label">State</label>
    <select class="form-select" id="validationTooltip04" required>
      <option selected disabled value="">Choose...</option>
      <option>...</option>
    </select>
    <div class="invalid-tooltip">
      Please select a valid state.
    </div>
  </div>
  <div class="col-md-3 position-relative">
    <label for="validationTooltip05" class="form-label">Zip</label>
    <input type="text" class="form-control" id="validationTooltip05" required>
    <div class="invalid-tooltip">
      Please provide a valid zip.
    </div>
  </div>
  <div class="col-12">
    <button class="btn btn-primary" type="submit">Submit form</button>
  </div>
</form>

Sass

Biến

$form-feedback-margin-top:          $form-text-margin-top;
$form-feedback-font-size:           $form-text-font-size;
$form-feedback-font-style:          $form-text-font-style;
$form-feedback-valid-color:         $success;
$form-feedback-invalid-color:       $danger;

$form-feedback-icon-valid-color:    $form-feedback-valid-color;
$form-feedback-icon-valid:          url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/></svg>");
$form-feedback-icon-invalid-color:  $form-feedback-invalid-color;
$form-feedback-icon-invalid:        url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>");

Mixin

Hai mixin được kết hợp với nhau, thông qua vòng lặp của chúng tôi , để tạo ra các kiểu phản hồi xác thực biểu mẫu của chúng tôi.

@mixin form-validation-state-selector($state) {
  @if ($state == "valid" or $state == "invalid") {
    .was-validated #{if(&, "&", "")}:#{$state},
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  } @else {
    #{if(&, "&", "")}.is-#{$state} {
      @content;
    }
  }
}

@mixin form-validation-state(
  $state,
  $color,
  $icon,
  $tooltip-color: color-contrast($color),
  $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),
  $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)
) {
  .#{$state}-feedback {
    display: none;
    width: 100%;
    margin-top: $form-feedback-margin-top;
    @include font-size($form-feedback-font-size);
    font-style: $form-feedback-font-style;
    color: $color;
  }

  .#{$state}-tooltip {
    position: absolute;
    top: 100%;
    z-index: 5;
    display: none;
    max-width: 100%; // Contain to parent when possible
    padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;
    margin-top: .1rem;
    @include font-size($form-feedback-tooltip-font-size);
    line-height: $form-feedback-tooltip-line-height;
    color: $tooltip-color;
    background-color: $tooltip-bg-color;
    @include border-radius($form-feedback-tooltip-border-radius);
  }

  @include form-validation-state-selector($state) {
    ~ .#{$state}-feedback,
    ~ .#{$state}-tooltip {
      display: block;
    }
  }

  .form-control {
    @include form-validation-state-selector($state) {
      border-color: $color;

      @if $enable-validation-icons {
        padding-right: $input-height-inner;
        background-image: escape-svg($icon);
        background-repeat: no-repeat;
        background-position: right $input-height-inner-quarter center;
        background-size: $input-height-inner-half $input-height-inner-half;
      }

      &:focus {
        border-color: $color;
        box-shadow: $focus-box-shadow;
      }
    }
  }

  // stylelint-disable-next-line selector-no-qualifying-type
  textarea.form-control {
    @include form-validation-state-selector($state) {
      @if $enable-validation-icons {
        padding-right: $input-height-inner;
        background-position: top $input-height-inner-quarter right $input-height-inner-quarter;
      }
    }
  }

  .form-select {
    @include form-validation-state-selector($state) {
      border-color: $color;

      @if $enable-validation-icons {
        &:not([multiple]):not([size]),
        &:not([multiple])[size="1"] {
          padding-right: $form-select-feedback-icon-padding-end;
          background-image: escape-svg($form-select-indicator), escape-svg($icon);
          background-position: $form-select-bg-position, $form-select-feedback-icon-position;
          background-size: $form-select-bg-size, $form-select-feedback-icon-size;
        }
      }

      &:focus {
        border-color: $color;
        box-shadow: $focus-box-shadow;
      }
    }
  }

  .form-control-color {
    @include form-validation-state-selector($state) {
      @if $enable-validation-icons {
        width: add($form-color-width, $input-height-inner);
      }
    }
  }

  .form-check-input {
    @include form-validation-state-selector($state) {
      border-color: $color;

      &:checked {
        background-color: $color;
      }

      &:focus {
        box-shadow: $focus-box-shadow;
      }

      ~ .form-check-label {
        color: $color;
      }
    }
  }
  .form-check-inline .form-check-input {
    ~ .#{$state}-feedback {
      margin-left: .5em;
    }
  }

  .input-group {
    > .form-control:not(:focus),
    > .form-select:not(:focus),
    > .form-floating:not(:focus-within) {
      @include form-validation-state-selector($state) {
        @if $state == "valid" {
          z-index: 3;
        } @else if $state == "invalid" {
          z-index: 4;
        }
      }
    }
  }
}

Bản đồ

Đây là bản đồ Sass xác nhận từ _variables.scss. Ghi đè hoặc mở rộng điều này để tạo ra các trạng thái khác hoặc bổ sung.

$form-validation-states: (
  "valid": (
    "color": $form-feedback-valid-color,
    "icon": $form-feedback-icon-valid
  ),
  "invalid": (
    "color": $form-feedback-invalid-color,
    "icon": $form-feedback-icon-invalid
  )
);

Bản đồ $form-validation-statescó thể chứa ba tham số tùy chọn để ghi đè chú giải công cụ và kiểu tiêu điểm.

Vòng

Được sử dụng để lặp lại $form-validation-statescác giá trị bản đồ nhằm tạo ra các kiểu xác thực của chúng tôi. Bất kỳ sửa đổi nào đối với bản đồ Sass ở trên sẽ được phản ánh trong CSS đã biên dịch của bạn thông qua vòng lặp này.

@each $state, $data in $form-validation-states {
  @include form-validation-state($state, $data...);
}

Tùy chỉnh

Trạng thái xác thực có thể được tùy chỉnh thông qua Sass với $form-validation-statesbản đồ. Nằm trong _variables.scsstệp của chúng tôi, bản đồ Sass này là cách chúng tôi tạo các trạng thái mặc định valid/ invalidxác thực. Bao gồm một bản đồ lồng nhau để tùy chỉnh màu sắc, biểu tượng, màu chú giải công cụ và bóng tiêu điểm của từng tiểu bang. Mặc dù không có trạng thái nào khác được trình duyệt hỗ trợ, những người sử dụng kiểu tùy chỉnh có thể dễ dàng thêm phản hồi biểu mẫu phức tạp hơn.