docs: def set_pin(ctx, pin, new_pin, u2f):
      """
      Set or change the PIN code.
  
      The FIDO2 PIN must be at least 4 characters long, and supports any type
      of alphanumeric characters.
  
      On YubiKey FIPS, a PIN can be set for FIDO U2F. That PIN must be at least
      6 characters long.
      """
  
      controller = ctx.obj['controller']
      is_fips = controller.is_fips
  
      if is_fips and not u2f:
          ctx.fail('This is a YubiKey FIPS. To set the U2F PIN, pass the --u2f '
                   'option.')
  
      if u2f and not is_fips:
          ctx.fail('This is not a YubiKey FIPS, and therefore does not support a '
                   'U2F PIN. To set the FIDO2 PIN, remove the --u2f option.')
  
      def prompt_new_pin():
          return click.prompt(
                      'Enter your new PIN', default='', hide_input=True,
                      show_default=False, confirmation_prompt=True, err=True)
  
      def change_pin(pin, new_pin):
          if pin is not None:
              _fail_if_not_valid_pin(ctx, pin, is_fips)
          _fail_if_not_valid_pin(ctx, new_pin, is_fips)
          try:
              if is_fips:
                  try:
                      # Failing this with empty current PIN does not cost a retry
                      controller.change_pin(old_pin=pin or '', new_pin=new_pin)
                  except ApduError as e:
                      if e.code == SW.WRONG_LENGTH:
                          pin = _prompt_current_pin()
                          _fail_if_not_valid_pin(ctx, pin, is_fips)
                          controller.change_pin(old_pin=pin, new_pin=new_pin)
                      else:
                          raise
  
              else:
                  controller.change_pin(old_pin=pin, new_pin=new_pin)
  
          except CtapError as e:
              if e.code == CtapError.ERR.PIN_INVALID:
                  ctx.fail('Wrong PIN.')
              if e.code == CtapError.ERR.PIN_AUTH_BLOCKED:
                  ctx.fail(
                      'PIN authentication is currently blocked. '
                      'Remove and re-insert the YubiKey.')
              if e.code == CtapError.ERR.PIN_BLOCKED:
                  ctx.fail('PIN is blocked.')
              if e.code == CtapError.ERR.PIN_POLICY_VIOLATION:
                  ctx.fail('New PIN is too long.')
              logger.error('Failed to change PIN', exc_info=e)
              ctx.fail('Failed to change PIN.')
  
          except ApduError as e:
              if e.code == SW.VERIFY_FAIL_NO_RETRY:
                  ctx.fail('Wrong PIN.')
  
              if e.code == SW.AUTH_METHOD_BLOCKED:
                  ctx.fail('PIN is blocked.')
  
              logger.error('Failed to change PIN', exc_info=e)
              ctx.fail('Failed to change PIN.')
  
      def set_pin(new_pin):
          _fail_if_not_valid_pin(ctx, new_pin, is_fips)
          try:
              controller.set_pin(new_pin)
          except CtapError as e:
              if e.code == CtapError.ERR.PIN_POLICY_VIOLATION:
                  ctx.fail('PIN is too long.')
              logger.error('Failed to set PIN', exc_info=e)
              ctx.fail('Failed to set PIN')
  
      if pin and not controller.has_pin:
          ctx.fail('There is no current PIN set. Use --new-pin to set one.')
  
      if controller.has_pin and pin is None and not is_fips:
          pin = _prompt_current_pin()
  
      if not new_pin:
          new_pin = prompt_new_pin()
  
      if controller.has_pin:
          change_pin(pin, new_pin)
      else:
          set_pin(new_pin)