fzlee / alipay

Python Alipay(支付宝) SDK with SHA1/SHA256 support
Other
1.29k stars 378 forks source link

我得验签出现问题 试了很多方法 想问问大佬 #126

Closed zhang54188 closed 3 years ago

zhang54188 commented 3 years ago

俺用的是python3.9 alipay包是在你clone你的 公钥和私钥匹配的 用官方软件验证了 接入支付宝的应用是沙箱 如果大佬有时间可以帮忙看看么 很感谢 大佬 你的这个alipay包在我工程的时候有个报错的地方我改了下 在init.py下的parse.py下的quote_plus这个方法里面string = str(string)

xshibiao commented 3 years ago

我测试了多次,return_urlnotify_url这两个参数要填,旧版本好像不用,具体原因我也不清楚

order_string = alipay.api_alipay_trade_page_pay(
        out_trade_no="2016211001000511",
        total_amount=0.01,
        subject=subject,
        return_url="http://127.0.0.1:8080/mark/", 
        notify_url=" ",    # 不能注释,注释掉后默认参数为None,会报错,不能为空串,空串会导致验签出错
    )
zhang54188 commented 3 years ago

你好 你能发我一个旧版本么 ? 我试试吧这两个参数填上会不会有问题 新版的 用把里面那个string强行从byte转成str也不报错 你试试?

zhang54188 commented 3 years ago

请问一下我如果没有异步或者同步回调的url怎么办? def quote_plus(string, safe='', encoding=None, errors=None): """Like quote(), but also replace ' ' with '+', as required for quoting HTML form values. Plus signs in the original string are escaped unless they are included in safe. It also does not have safe default to '/'. """

Check if ' ' in string, where string may either be a str or bytes. If

# there are no spaces, the regular quote will produce the right answer.
string = str(string) # 这句话我自己改变的 这样可以添空的 但是验签一直过不了
#print(string)
if ((isinstance(string, str) and ' ' not in string) or
    (isinstance(string, bytes) and b' ' not in string)):
    return quote(string, safe, encoding, errors)
if isinstance(safe, str):
    space = ' '
else:
    space = b' '
string = quote(string, safe + space, encoding, errors)
return string.replace(' ', '+')
zhang54188 commented 3 years ago

大佬 我把这两个参数设置成空的字符 以后验签还是过不了 如果可以 您留一下联系方式 我把我的工程给你瞧瞧? 由于我不是很懂这个接口 所以按照你的教程走的 没有遗漏 网页的提示是这个: 错误代码 invalid-signature 错误原因: 验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为:app_id=2021000117648452&biz_content={"subject":"20210507161433","out_trade_no":"20210507161433","total_amount":"23.58","product_code":"FAST_INSTANT_TRADE_PAY"}&charset=utf-8&method=alipay.trade.page.pay&sign_type=RSA2&timestamp=2021-05-09 19:20:32&version=1.0

xshibiao commented 3 years ago

那你私聊我吧 1963765870@qq.com

fzlee commented 3 years ago

你可以把示例代码贴上来看看。函数接受的参数不能为“”或者是null, 会导致签名报错

fzlee commented 3 years ago

旧版的可以试试 pip install python-alipay-sdk==2.3.0

zhang54188 commented 3 years ago

好的 大佬 你能给一个联系方式么? 我给你发我的代码 我确实没找到是哪儿错了 我把那两个参数写成百度的网址也不行 也是验签错误

zhang54188 commented 3 years ago

大佬 我用的python版本是3.9 用这个命令安装的时候报错ValueError: check_hostname requires server_hostname 我经过查看据说是urllibs太高了 我用 pip install requests==2.20 或者使用下面的命令降低版本: pip install urllib3==1.25.8 这两句都是报这个错误 你们有这个情况么?

zhang54188 commented 3 years ago

app_private_key_string = open(settings.APP_PRIVATE).read() alipay_public_key_string = open(settings.ALIPAY_PUBLIC).read()

print(app_private_key_string,alipay_public_key_string)

    alipay = AliPay(
        appid="2021000117648452",#沙箱appid
        app_notify_url=None,  # 默认回调url
        app_private_key_string=app_private_key_string,
        # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        alipay_public_key_string=alipay_public_key_string,
        sign_type="RSA2",# RSA 或者 RSA2
        debug = True, # 默认False 沙箱为true
        verbose = True ,  # 输出调试数据
        config = AliPayConfig(timeout=20)  # 可选, 请求超时时间
    )
    # 电脑网站支付,需要跳转到https://openapi.alipaydev.com/gateway.do? + order_string
    total_pay = order.total_price+order.transit_price#价格加运费
    subject =order_id
    order_string = alipay.client_api(
        "alipay.trade.page.pay",
        biz_content={
            "out_trade_no": order_id,
            "total_amount":str(total_pay),
            "subject":subject,
        },
        return_url="https://www.baidu.com/",  # this is optional
    )
    # order_string = alipay.api_alipay_trade_page_pay(
    #     out_trade_no=order_id,#订单id
    #     total_amount=str(total_pay),#支付总金额
    #     subject=subject,
    #     return_url="https://www.baidu.com/",#用户点击确认以后同步响应这个地址 返回支付结果
    #     notify_url="https://www.baidu.com/",  #用户点击确认以后同步响应这个地址 返回支付结果
    # )
    #返回应答
    pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string

这个是我的实例代码 然后我的回调添的百度 我解决那个填空或者none签名报错的情况了的 就是验签过不了 验签生成了的

2021-05-10 17:26:00,418 [DEBUG] python-alipay-sdk: data to be signed 2021-05-10 17:26:00,419 [DEBUG] python-alipay-sdk: {'app_id': '2021000117648452', 'method': 'alipay.trade.page.pay', 'charset': 'utf-8', 'sign_type': 'RSA2', 'timestamp': '2021-05-10 17:26:00', 'version': '1.0', 'biz_content': {'out_trade_no': '20210507161433', 'total_amount': '23.58', 'subject': '20210507161433'}, 'return_url': 'https://www.baidu.com/'} 2021-05-10 17:26:00,440 [DEBUG] python-alipay-sdk: signed srtring 2021-05-10 17:26:00,441 [DEBUG] python-alipay-sdk: app_id=2021000117648452&biz_content=%7B%22out_trade_no%22%3A%2220210507161433%22%2C%22total_amount%22%3A%2223.58%22%2C%22subject%22%3A%2220210507161433%22%7D&charset=utf-8&method=alipay.trade.page.pay&return_url=https%3A%2F%2Fwww.baidu.com%2F&sign_type=RSA2&timestamp=2021-05-10+17%3A26%3A00&version=1.0&sign=T%2FAgJE2U%2BA4dvl3a9SGDM5EXicbzDk%2FoyF6yWOGF%2FjM83LkttLUQzOUULLgEzmmiPCUV4WCK9m%2BX05sNeSmt%2BFVUKwT%2FQISgf9dD29vUZiYbu1BeYcuT943Vqk8zZemJGx%2Bh3Yo5G%2FOhEgeyHobvXzwCxYtdGxEJvI5TDkbBpLrQgUtth6CfsN7WEx8fHDfQRtSLLv4QicjD%2Fr5I4xfr7EpkvJdTx9l0Wpha9Pr%2F6vTb%2Bv5ueV42bf2l81XNWysDEPdT1R9zIdCYYb8GHFPUpwSihQNbj96zWc3HKzzdm58h%2BJXxmg4UFWQ44JRwd1k2k1Gg8npwBdod4hDRQRkI5w%3D%3D [10/May/2021 17:26:00] "POST /order/order_pay HTTP/1.1" 200 749 https://openapi.alipaydev.com/gateway.do?app_id=2021000117648452&biz_content=%7B%22out_trade_no%22%3A%2220210507161433%22%2C%22total_amount%22%3A%2223.58%22%2C%22subject%22%3A%2220210507161433%22%7D&charset=utf-8&method=alipay.trade.page.pay&return_url=https%3A%2F%2Fwww.baidu.com%2F&sign_type=RSA2&timestamp=2021-05-10+17%3A26%3A00&version=1.0&sign=T%2FAgJE2U%2BA4dvl3a9SGDM5EXicbzDk%2FoyF6yWOGF%2FjM83LkttLUQzOUULLgEzmmiPCUV4WCK9m%2BX05sNeSmt%2BFVUKwT%2FQISgf9dD29vUZiYbu1BeYcuT943Vqk8zZemJGx%2Bh3Yo5G%2FOhEgeyHobvXzwCxYtdGxEJvI5TDkbBpLrQgUtth6CfsN7WEx8fHDfQRtSLLv4QicjD%2Fr5I4xfr7EpkvJdTx9l0Wpha9Pr%2F6vTb%2Bv5ueV42bf2l81XNWysDEPdT1R9zIdCYYb8GHFPUpwSihQNbj96zWc3HKzzdm58h%2BJXxmg4UFWQ44JRwd1k2k1Gg8npwBdod4hDRQRkI5w%3D%3D

这个是我打开debug之后输出的我的加签数据和生成的签名 如果大佬想 我可以把我的工程发一个给你 我用的是django框架

fzlee commented 3 years ago

你好, 我使用如下代码成功支付,

subject = "测试订单"
order_id = "12345:"
total_pay = 12.3
subject = order_id
order_string = alipay.client_api(
    "alipay.trade.page.pay",
    biz_content={
        "out_trade_no": order_id,
        "total_amount": total_pay,
        "subject": subject,
        "product_code": "FAST_INSTANT_TRADE_PAY"
    },
    return_url="https://www.baidu.com/",
)
fzlee commented 3 years ago

你的代码看起来没有太多问题, 我修改了两个地方, 第一个是订单金额我用的是数字而不是字符串, 并且添加了"product_code": "FAST_INSTANT_TRADE_PAY" 字段

fzlee commented 3 years ago

我怀疑是你传入的appid, 公钥私钥不匹配导致的

zhang54188 commented 3 years ago

公钥和私钥 我用官方给的软件验证了 确定匹配成功的呀 同时在项目中公钥txt中需要加那个-----END PUBLIC KEY-----这样子的头和尾吧?

zhang54188 commented 3 years ago

大佬你把初始化的部分也给我瞧瞧可以么? 我的 alipay = AliPay( appid="2021000117648452",#沙箱appid app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string,

支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

        alipay_public_key_string=alipay_public_key_string,
        sign_type="RSA2",
        debug = True, # 默认False 沙箱为true
        verbose = True ,  # 输出调试数据
        config = AliPayConfig(timeout=20)  # 可选, 请求超时时间
    )
zhang54188 commented 3 years ago

app_private_key_string = open(settings.APP_PRIVATE).read() alipay_public_key_string = open(settings.ALIPAY_PUBLIC).read()

print(app_private_key_string,alipay_public_key_string)

    alipay = AliPay(
        appid="2021000117648452",#沙箱appid
        app_notify_url=None,  # 默认回调url
        app_private_key_string=app_private_key_string,
        # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        alipay_public_key_string=alipay_public_key_string,
        sign_type="RSA2",
        debug = True, # 默认False 沙箱为true
        verbose = True ,  # 输出调试数据
        config = AliPayConfig(timeout=20)  # 可选, 请求超时时间
    )
fzlee commented 3 years ago

和你的一样,除了appid是我自己的

On Mon, 10 May 2021 at 20:09, zhang54188 @.***> wrote:

大佬你把初始化的部分也给我瞧瞧可以么? 我的 alipay = AliPay( appid="2021000117648452",#沙箱appid app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string,

支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

alipay_public_key_string=alipay_public_key_string, sign_type="RSA2", debug = True, # 默认False 沙箱为true verbose = True , # 输出调试数据 config = AliPayConfig(timeout=20) # 可选, 请求超时时间 )

You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/fzlee/alipay/issues/126#issuecomment-836618554, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOYLNP3HHKX7JYZRFIEP5DTM7EIPANCNFSM44OUDR7Q .

-- 顺颂时祺

Fazheng Li

fzlee commented 3 years ago

如果你的公钥私钥格式不对,代码会立即报错

所以和格式无关

On Mon, 10 May 2021 at 20:10, Fazheng Li @.***> wrote:

和你的一样,除了appid是我自己的

On Mon, 10 May 2021 at 20:09, zhang54188 @.***> wrote:

大佬你把初始化的部分也给我瞧瞧可以么? 我的 alipay = AliPay( appid="2021000117648452",#沙箱appid app_notify_url=None, # 默认回调url app_private_key_string=app_private_key_string,

支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,

alipay_public_key_string=alipay_public_key_string, sign_type="RSA2", debug = True, # 默认False 沙箱为true verbose = True , # 输出调试数据 config = AliPayConfig(timeout=20) # 可选, 请求超时时间 )

You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/fzlee/alipay/issues/126#issuecomment-836618554, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAOYLNP3HHKX7JYZRFIEP5DTM7EIPANCNFSM44OUDR7Q .

-- 顺颂时祺

Fazheng Li

-- 顺颂时祺

Fazheng Li

zhang54188 commented 3 years ago

QQ截图20210510202503 zhe'g 这个是我通过官方验证器验证的呀 匹配成功 然后我上传的沙箱就是这个公钥

zhang54188 commented 3 years ago

大佬 你能把你的公钥在txt文件中的格式看一下么? QQ截图20210510202838

zhang54188 commented 3 years ago

我的是自动换行 不然是一行的

zhang54188 commented 3 years ago

只有后面的那个-----END PUBLIC KEY-----换行了的

zhang54188 commented 3 years ago

我试了 不对-----END PUBLIC KEY-----换行的话在生成签名的时候就会报错

zhang54188 commented 3 years ago

大佬 我所有的数据都在服务器上 如果可以的话 我可以把工程给你 你瞧瞧?

zhang54188 commented 3 years ago

不换行会错 我少打字了

zhang54188 commented 3 years ago

可以了 大佬

zhang54188 commented 3 years ago

解决了 大佬

zhang54188 commented 3 years ago

谢谢 大佬 不是你们的问题 是我的问题

819262791 commented 4 months ago

怎么解决的大佬,我遇到的问题跟你一样

819262791 commented 4 months ago

from rest_framework.views import APIView from alipay import AliPay from django.conf import settings from rest_framework.response import Response from order.models import Order from rest_framework import status

import logging log = logging.getLogger("django")

class AlipayAPIView(APIView): def get(self, request): """获取支付宝的支付地址"""

获取订单号

    order_number = request.query_params.get("order_number")
    # 判断订单是否存在
    # 判断订单是否存在
    try:
        order = Order.objects.get(order_number=order_number)
    except Order.DoesNotExist:
        return Response({"message": "对不起,订单不存在!"}, status=status.HTTP_400_BAD_REQUEST)
    with open(r"C:\Users\Xing\Desktop\luffy\luffyapi\apps\payments\keys\app_private_key.pem", 'r') as file:
        app_private_key_string = file.read()
    with open(r"C:\Users\Xing\Desktop\luffy\luffyapi\apps\payments\keys\alipay_public_key.pem", 'r') as file:
        alipay_public_key_string = file.read()

    alipay = AliPay(
        appid=settings.ALIAPY_CONFIG["appid"],
        app_notify_url=settings.ALIAPY_CONFIG["app_notify_url"],  # 默认回调url
        app_private_key_string=app_private_key_string,
        alipay_public_key_string=alipay_public_key_string,
        sign_type=settings.ALIAPY_CONFIG["sign_type"],
        debug=settings.ALIAPY_CONFIG["debug"]  # 默认False
    )

    # 调用接口
    order_string = alipay.api_alipay_trade_page_pay(
        out_trade_no=order.order_number,
        total_amount=float(order.real_price),
        subject=order.order_title,
        return_url=settings.ALIAPY_CONFIG["return_url"],
        notify_url=settings.ALIAPY_CONFIG["notify_url"],  # 可选, 不填则使用默认notify url
    )

    url = settings.ALIAPY_CONFIG["gateway_url"] + order_string
    print(url)
    return Response(url)
    这是我的代码
    # 支付宝配置信息

ALIAPY_CONFIG = {

"gateway_url": "https://openapi.alipay.com/gateway.do?", # 真实支付宝网关地址

"gateway_url": "https://openapi-sandbox.dl.alipaydev.com/gateway.do?", # 沙箱支付宝网关地址
"appid": "9021000138662797",
"app_notify_url": None,
"sign_type": "RSA2",
"debug": True,
"return_url": "http://www.luffycity.cn:8080/payments/result", # 同步回调地址
"notify_url": "http://api.luffycity.cn:8000/payments/result", # 异步结果通知

}这是配置信息

https://openapi-sandbox.dl.alipaydev.com/gateway.do?app_id=9021000138662797&biz_content=%7B%22subject%22%3A%22%5Cu8def%5Cu98de%5Cu5b66%5Cu57ce%5Cu8bfe%5Cu7a0b%5Cu8d2d%5Cu4e70%22%2C%22out_trade_no%22%3A%2220240621181339000001000011%22%2C%22total_amount%22%3A109.2%2C%22product_code%22%3A%22FAST_INSTANT_TRADE_PAY%22%7D&charset=utf-8&method=alipay.trade.page.pay&notify_url=http%3A%2F%2Fapi.luffycity.cn%3A8000%2Fpayments%2Fresult&return_url=http%3A%2F%2Fwww.luffycity.cn%3A8080%2Fpayments%2Fresult&sign_type=RSA2&timestamp=2024-06-28+15%3A02%3A05&version=1.0&sign=WZ9WdkFp8EdCJpHDavz3ybqpNIf7gbSDeDfb8XK0B03v6ZIxyq10v3EmpTL%2F7DyYX7XW%2BJ30TpSgHbdmyG4rmw0v4knjaEYialCqIHGfktvhHGDBlgNgDQJ6aS5u%2BVJPA0KPuXt94ljK1SsAP4Vf41%2FwCkQKSnkBqlV6Tyk4DDccoomxu50RZB3srjHDxhvop726YX%2FbQZN4dsoqaRRAGE%2F1NCC6%2Bo1xr2bmPyfvrjQ9EngnJP4EyYPo1TXkD0Z6fRpjdC1SUvqHOxk9mvZk1j3aQ2CsdRwmh2z%2BA13z5sFNOXaYNAonymc%2BntAfUuDnUUjtVIleROauXcC0HX3ekQ%3D%3D 这个是打印出的url地址,我进入这个地址之后报错是 调试错误,请回到请求来源地,重新发起请求。 错误代码 invalid-signature 错误原因: 验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为:app_id=9021000138662797&biz_content={"subject":"\u8def\u98de\u5b66\u57ce\u8bfe\u7a0b\u8d2d\u4e70","out_trade_no":"20240621181339000001000011","total_amount":109.2,"product_code":"FAST_INSTANT_TRADE_PAY"}&charset=utf-8&method=alipay.trade.page.pay&notify_url=http://api.luffycity.cn:8000/payments/result&return_url=http://www.luffycity.cn:8080/payments/result&sign_type=RSA2&timestamp=2024-06-28 15:02:05&version=1.0

819262791 commented 4 months ago

from rest_framework.views import APIView from alipay import AliPay from django.conf import settings from rest_framework.response import Response from order.models import Order from rest_framework import status

import logging log = logging.getLogger("django")

class AlipayAPIView(APIView): def get(self, request): """获取支付宝的支付地址"""

获取订单号

    order_number = request.query_params.get("order_number")
    # 判断订单是否存在
    # 判断订单是否存在
    try:
        order = Order.objects.get(order_number=order_number)
    except Order.DoesNotExist:
        return Response({"message": "对不起,订单不存在!"}, status=status.HTTP_400_BAD_REQUEST)
    with open(r"C:\Users\Xing\Desktop\luffy\luffyapi\apps\payments\keys\app_private_key.pem", 'r') as file:
        app_private_key_string = file.read()
    with open(r"C:\Users\Xing\Desktop\luffy\luffyapi\apps\payments\keys\alipay_public_key.pem", 'r') as file:
        alipay_public_key_string = file.read()

    alipay = AliPay(
        appid=settings.ALIAPY_CONFIG["appid"],
        app_notify_url=settings.ALIAPY_CONFIG["app_notify_url"],  # 默认回调url
        app_private_key_string=app_private_key_string,
        alipay_public_key_string=alipay_public_key_string,
        sign_type=settings.ALIAPY_CONFIG["sign_type"],
        debug=settings.ALIAPY_CONFIG["debug"]  # 默认False
    )

    # 调用接口
    order_string = alipay.api_alipay_trade_page_pay(
        out_trade_no=order.order_number,
        total_amount=float(order.real_price),
        subject=order.order_title,
        return_url=settings.ALIAPY_CONFIG["return_url"],
        notify_url=settings.ALIAPY_CONFIG["notify_url"],  # 可选, 不填则使用默认notify url
    )

    url = settings.ALIAPY_CONFIG["gateway_url"] + order_string
    print(url)
    return Response(url)
    这是我的代码
    # 支付宝配置信息

ALIAPY_CONFIG = {

"gateway_url": "https://openapi.alipay.com/gateway.do?", # 真实支付宝网关地址

"gateway_url": "https://openapi-sandbox.dl.alipaydev.com/gateway.do?", # 沙箱支付宝网关地址
"appid": "9021000138662797",
"app_notify_url": None,
"sign_type": "RSA2",
"debug": True,
"return_url": "http://www.luffycity.cn:8080/payments/result", # 同步回调地址
"notify_url": "http://api.luffycity.cn:8000/payments/result", # 异步结果通知

}这是配置信息

https://openapi-sandbox.dl.alipaydev.com/gateway.do?app_id=9021000138662797&biz_content=%7B%22subject%22%3A%22%5Cu8def%5Cu98de%5Cu5b66%5Cu57ce%5Cu8bfe%5Cu7a0b%5Cu8d2d%5Cu4e70%22%2C%22out_trade_no%22%3A%2220240621181339000001000011%22%2C%22total_amount%22%3A109.2%2C%22product_code%22%3A%22FAST_INSTANT_TRADE_PAY%22%7D&charset=utf-8&method=alipay.trade.page.pay&notify_url=http%3A%2F%2Fapi.luffycity.cn%3A8000%2Fpayments%2Fresult&return_url=http%3A%2F%2Fwww.luffycity.cn%3A8080%2Fpayments%2Fresult&sign_type=RSA2&timestamp=2024-06-28+15%3A02%3A05&version=1.0&sign=WZ9WdkFp8EdCJpHDavz3ybqpNIf7gbSDeDfb8XK0B03v6ZIxyq10v3EmpTL%2F7DyYX7XW%2BJ30TpSgHbdmyG4rmw0v4knjaEYialCqIHGfktvhHGDBlgNgDQJ6aS5u%2BVJPA0KPuXt94ljK1SsAP4Vf41%2FwCkQKSnkBqlV6Tyk4DDccoomxu50RZB3srjHDxhvop726YX%2FbQZN4dsoqaRRAGE%2F1NCC6%2Bo1xr2bmPyfvrjQ9EngnJP4EyYPo1TXkD0Z6fRpjdC1SUvqHOxk9mvZk1j3aQ2CsdRwmh2z%2BA13z5sFNOXaYNAonymc%2BntAfUuDnUUjtVIleROauXcC0HX3ekQ%3D%3D 这个是打印出的url地址,我进入这个地址之后报错是 调试错误,请回到请求来源地,重新发起请求。 错误代码 invalid-signature 错误原因: 验签出错,建议检查签名字符串或签名私钥与应用公钥是否匹配,网关生成的验签字符串为:app_id=9021000138662797&biz_content={"subject":"\u8def\u98de\u5b66\u57ce\u8bfe\u7a0b\u8d2d\u4e70","out_trade_no":"20240621181339000001000011","total_amount":109.2,"product_code":"FAST_INSTANT_TRADE_PAY"}&charset=utf-8&method=alipay.trade.page.pay&notify_url=http://api.luffycity.cn:8000/payments/result&return_url=http://www.luffycity.cn:8080/payments/result&sign_type=RSA2&timestamp=2024-06-28 15:02:05&version=1.0