Ethereum中涉及各种类型的方法调用。一个编程中常用的call概念,可能为Ethereum Vitrual Machine(EVM)内的call,又可能为EVM外的call,又涉及诸如Message/Transaction等基本概念;同时还包括call/delegatecall/callcode/send/transfer/sendTransaction等等方法。
对这些调用机制及基本概念的说明散落在 solidity文档 、黄皮书、白皮书 中,初学者容易搞晕。这里对这些基本概念、调用机制及用法做一下整体梳理。
PDF版本:Ethereum调用机制总结
PNG版本:Ethereum调用机制总结
示例代码:测试代码下载
pragma solidity ^ 0.4.18;
contract A {
uint public var2;
uint public var1;
B b1;
address addrB;
function A() public {
b1 = new B();
addrB=address(b1);
}
function callSet(address addr, uint param) public returns(uint) {
//addr.call(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。
//使用address.call
addr.call(bytes4(keccak256(“set(uint256)”)), param); //call 使用的是被调用者的存储,因此改变的是B.var1值
//使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
/*
B b2 = B(addr);
uint result = b2.set(param);
return result;
*/
//使用 new B()方式方式调用
// uint b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);
return 1;
}
function delegatecallSet(address addr, uint param) {
//addr.delegatecall(bytes4(keccak256(“set(uint)”)), param); //使用了uint,调用不生效。应当使用uint256; uint是uint256的昵称,但在ABI调用时候,只能使用长类型。
addr.delegatecall(bytes4(keccak256(“set(uint256)”)), param); //delegatecall和callcode都是使用调用者的存储,特别要注意调用者和被调用者合约变量定义顺序,目前改变的是A.var2的值。
B b2 = B(addr); //使用实例方式,可以直接采用callee.method形式调用,从而直接获取函数返回值
uint result = b2.set(param);
// uint b1=b1.set(param);
// addrB.call(bytes4(keccak256(“set(uint256)”)), param);
}
function callcodeSet(address addr, uint param) {
addr.callcode(bytes4(keccak256(“set(uint256)”)), param);
}
function getVar1() public view returns(uint) {
return var1;
}
function getVar2() public view returns(uint) {
return var2;
}
function getAddr() public view returns(address) {
return addrB;
}
}
contract B {
uint public var1;
event MyEvent(uint param, uint result);
function set(uint param) public returns(uint) {
var1 = param;
MyEvent(param, 1);
return param;
}
}
为加深对各种常用统计分布的理解,更好掌握R语言对应的各类分布的概率函数(d、p、q、r族)以及广义线性模型的使用,研究了一下常用统计分布数据的模拟生成方法,收获颇多。
各类常用统计分布蒙特卡洛模拟数据生成的大致思路:
1、构造自变量x的均匀分布
2、根据对应分布的均值函数,构造x变量对应的均值。(广义线性模型的link 函数参考https://en.wikipedia.org/wiki/Generalized_linear_model#Link_function)
3、将均值代入,R中对应分布的随机变量生成函数,得到因变量y(例如正态分布为rnorm、泊松分布为rpois)
代码:
#norm distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0+beta1*runif(n=num,-1,1)
y=rnorm(num,mean=x,sd=1)
model=glm(y~x,,family=gaussian(link=’identity’))
#possion distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
lambda=exp(x)
y=rpois(n=num, lambda=lambda)
model = glm(y~x, family=poisson(link = log))
#Exponential/Gamma distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
y=rexp(num,rate=exp(-x))
model=glm(y~x,,family=Gamma(link=’log’))
#使用nls模拟
df=data.frame(x,y)
model=nls(y~exp(a+b*x),data=df,start = list(a=0,b=0))
#logistic/probit distribution simulation
set.seed(1234)
num=100
beta0=1
beta1=0.2
x=beta0 + beta1*runif(n=num, min=0, max=5)
#logistic distribution logit=log(odds)=log(p/(1-p))
odds=exp(x)
probs=odds/(1+odds)
#probit distribution probit=Cumulative normal pdf
#probs=pnorm(x)
y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link=”logit”))
#bionimal/Categorical/Multinomial distribution simulation
library(nnet)
y=rbinom(n=num,size=3,prob=probs)
model <- multinom(y ~ x1 + x2)
参考资料:《 Monte Carlo Simulation and Resampling Methods for Social Science》
https://www.sagepub.com/sites/default/files/upm-binaries/57233_Chapter_6.pdf
R文档对fitted()、predict()函数以及predict函数type参数取值的具体含义说得很不清楚,网上也没有清晰的解释。总结一下。
一、说明
目的一、R中fitted和predict的关系
目的二、以logistic为例,解析predict中type参数不同取值的关系
1、R中fitted和predict的关系
fitted对无link函数模型(例如线性回归),fitted值和predict的值相同
对有link函数的模型(例如logistic、Binomial),
fitted是link函数作用前(或者link逆函数inverse of the link function作用后)的预测值
predict是link函数作用后(或link逆函数inverse of the link function作用前)的预测值
link function https://en.wikipedia.org/wiki/Generalized_linear_modelLink_function
2、logistic中predict中type参数不同取值的关系
predict中type参数的可选项有:default, type="link",type="response",type="terms"
假设log(odds)=log(p/(1-p))=alpha+beta1*x1+beta2*x2+…+betan*xn
a.、type="link",type为缺省值
type="link"为缺省值,给出logit线性函数预测值,link=alpha+beta1*x1+beta2*x2+…+betan*xn
b、 type="response"
type="response" 给出概率预测值。
response=predict(model,type = "response"),则
log(response/(1-response))=alpha+beta1*x1+beta2*x2+…+betan*xn=link,或:link=exp(response)/(1+response)
c、type="terms"
type="terms"表示各个变量的预测值(包括前面参数在模型中的值)。
terms=predict(model, newdata = traindata,type = "terms")的结果为各个变量term的值
term1=beta1*x1,term2=beta2*x2, …
sum(term1,…,termn)+attr(terms,"constant")=log(odds)=log(response/(1-response))
attr(terms,"constant")的含义 http://blog.minitab.com/blog/adventures-in-statistics-2/regression-analysis-how-to-interpret-the-constant-y-intercept
二、代码
#fitted和predict的关系演示
#linear regression
#no link function
num=100
x1=rnorm(num)
x2=rnorm(num)
lr=1+2*x1+3*x2
model=lm(y~x+x2)
fit=fitted(model)
pred=predict(model)
print(all.equal(fit, pred))
#对无link函数的模型,fitted值与predict值相同
#possion
#link=log
num=100
x=rnorm(num)
y=rpois(num,lambda = exp(x))
model = glm(y~x, family="poisson")
fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit),pred))
print(all.equal(fit,exp(pred)))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值
#logistic
#link=logit=log(p/(1-p))
num=100
x1=rnorm(num)
x2=rnorm(num)
lo=1+2*x1+3*x2
odds=exp(lo)
probs=odds/(1+odds)
y=rbinom(n=num,size=1,prob=probs)
model=glm(y~x1+x2,family = binomial(link="logit"))
fit=fitted(model)
pred=predict(model)
print(all.equal(log(fit/(1-fit)),pred))
print(all.equal(fit,exp(pred)/(1+exp(pred))))
#对有link函数的模型,fitted值为link函数作用前的值,predict为link作用后的值
#以logistic模型为例子,验证predict中type为缺省值,type="link",type="response",type="terms"关系
#predict中type="link"时的fitted及predict
link=predict(model,type="link")
print(link)
print(all.equal(pred,link))
#type=link为缺省值
#predict中type="response"时的fitted及predict
response=predict(model,type="response")
print(response)
print(all.equal(fit,response))
print(all.equal(pred,log(response/(1-response))))
#type="terms"时的fitted及predict
terms<- predict(model,type="terms")
term=terms[,1]+terms[,2]+attr(terms,"constant")
print(term)
print(all.equal(link,term))
print(all.equal(response,exp(term)/(1+exp(term))))
参考资料:
我在知乎关于提问“资产端线上对接资金端系统?” https://www.zhihu.com/question/67426957/answer/277256804 的回答。
虽然最近现金贷整顿,但此问题涉及的内容的应用场景挺多的,简单说一下思路。
资产端平台接入资金端平台时候,需要重点考虑两大部分的内容:
1、交易结构设计
由于合作双方监管合规性问题,交易结构设计主要解决资金端资金怎样以合规、安全的形式流转到资产端。这里的合规性,不单纯只是资产端或资金端,双方都涉及合规性。
在交易结构设计时候,涉及很多因素,例如:
a、资产端的资质,例如是P2P平台、互联网小贷平台、消费金融公司、助贷机构等的资金合规来源渠道并不同。
b、资金端的资质,例如是金融机构(银行、保险公司、融资性担保公司等)、P2P、互联网小贷、消费金融公司、企业、股东等的资金。
c、资产方的资产质量
d、实际放款方,资产最终归属。涉及放款资质,是否需要债权转让、ABS等
e、担保方式
f、资金放款、还款流转流程,支付/代扣渠道
g、资产端的保证金、杠杆、资金成本等
交易结构设计是整个合作最核心的内容,也是最难的地方,需要双方一起就双方实际情况探讨合规的合作模式。
交易结构设计影响了资产端、资金端合作模式、金融产品设计、平台对接的业务流等内容。
2、平台化设计
低成本、稳定、多元化的资金来源是资产端平台的核心竞争力,因此一般情况下,资产端都会尽量接入更多的资金端平台,以保证资金的持续供给。因此从平台建设角度来说,需要在设计时候考虑平台的扩展性、可运营性等因素,以满足多个资金端接入的需求。
在合作之初以验证合作模式为主,因此平台功能平台功能没必要设计得过于复杂。但随着业务规模扩大,低成本的运营能力成为平台的核心能力之一,可以说每一个资产端的资金对接平台最终都会演变成资产端、资金端的撮合路由平台。
一张图供参考
在消费金融中,风险模型组(申请评分卡、行为评分卡、催收评分卡、失联概率、违约概率PD模型等)、营销模型组(客户分层模型、客户响应模型、客户流失模型)、反欺诈模型组等都涉及了信用评分卡模型的应用。关于信用评分卡模型的使用及代码实现,网上公开的完整资料较少,且大都写得语焉不详。基于R语言做了一个完整例子,算是对最近一段时间工作总结。
分为两部分:
1、评分卡模型使用总结脑图
2、评分卡模型R语言代码
1、评分卡模型使用总结脑图(完整脑图点击下载)
2、R语言代码
由于libreoffice的soffice不支持多进程,只允许同时有一个进程来转换docx文件为pdf文件,因此无法多线程并发执行转换操作。
为实现并发转换操作,有两种方案:
方案一:将转换代码部署到不同的服务器上,此种方案需要单独服务器,对资源要求较高,部署也麻烦;
方案二:利用docker对资源的隔离特性,把libreoffice 放到docker中,然后启用多个libreoffice容器,java代码调用不同容器的soffice命令来并发转换docx文件。
1、安装docker相关程序
CentOS7已经缺省支持docker
yum install docker
service docker start
chkconfig docker on
简单的安装使用可以参考 https://linux.cn/article-4340-1.html
2、把缺省的docker镜像仓库换成国内的网易镜像
echo "DOCKER_OPTS=\"\$DOCKER_OPTS –registry-mirror=http://hub-mirror.c.163.com\"" >> /etc/default/docker
service docker restart
3、下载centos docker镜像
docker pull centos
4、启动centos的docker镜像
docker run -it centos /bin/bash
5、进入docker容器
docker run -it centos -v /root/install:/root/install /bin/bash
由于生产镜像时候,可能需要与宿主主机共享一些文件,例如中文ttf文件,因此在run 时候使用了-v参数,用于宿主主机与docker container之间的共享目录。
假设docker 容器与宿主机的共享目录为/root/install 。
Docker容器和主机之间共享数据,可以参考 https://www.howtoing.com/how-to-share-data-between-the-docker-container-and-the-host/
6、安装libreoffice、中文字体库等所需的软件
yum install libreoffice-writer.x86_64
yum groupinstall "Fonts"
yum groupinstall "Input Methods"
7、生成安装了libreoffice、中文字体等软件的docker 镜像
docker commit CONTAINER_ID liang/libreoffice1
其中:
CONTAINER_ID是docker ps -a得到了容器id docker ps -a|grep "centos"|awk ‘{print $1}’
liang/libreoffice1 是我们生成的docker镜像
8、停掉刚才启动的centos容器
docker stop CONTAINER_ID
9、启动我们新生成的docker 镜像
根据并发转换docx为pdf文件的需要,基于我们自己生成的docker镜像,启动多个docker的容器,利用docker容器对资源的隔离,调用不同容器中的soffice来并发处理不同的pdf文件
docker run –name office1 -it -d -v /root/pdf1:/root/pdf1 liang/libreoffice1
docker run –name office2 -it -d -v /root/pdf1:/root/pdf1 liang/libreoffice1
镜像文件与宿主机的共享目录为/root/pdf1和/root/pdf2,在共享目录中放入要转换的docx文件
docker exec -it office1 /bin/bash
10、调用soffice命令行,将docx转为pdf
docker exec -it office1 /bin/soffice –headless –invisible –norestore –nodefault –nolockcheck –nofirststartwizard –convert-to pdf:writer_pdf_Export –outdir /root/pdf1 /root/pdf1/liang1.docx
docker exec -it office2 /bin/soffice –headless –invisible –norestore –nodefault –nolockcheck –nofirststartwizard –convert-to pdf:writer_pdf_Export –outdir /root/pdf2 /root/pdf2/liang2.docx
以上命令行放到java代码中,同时可以在多个线程中并发调用。
背景:
1、生产服务器采用了dnspod-sr作为内网DNS服务器,以方便应用的部署。
2、所有服务器都采用CentOS,IP采用IPv4,未禁用IPv6,但操作系统路由、路由器及防火墙皆未启用IPv6地址。
虽然以前也遇到过因为IPv6导致类似curl、wget之类的系统命令执行太慢的问题,但一直未对IPv6引起足够的重视。
最近接连出现了一堆与IPv6相关的问题。
1、先是APP上APP Store审核,被苹果因为IPv6的问题接连打回来几次。最终直接把服务器的IPv6禁用了事。
2、有一台Redis服务器作为缓存服务器,其他Spring Boot应用通过内部DNS连接Redia。比较诡异的是,每一次重启Spring Boot应用,初始化Redis连接池时候,至少需要15秒。
最终查明了是DNS解析惹的祸,直接采用IP连接就不存在问题。原因是应用通过内部域名连接Redis时,做域名解析时候,发送了两条AAAA(IPv6)、A(IPv4)域名解析请求,其中AAAA > A记录请求 。
而且CentOS下即便禁用了IPv6,采用TCPDUMP抓包发现似乎仍然也会发送AAAA域名解析请求,导致先AAAA请求超时后,再处理IPv4。
网上大部分资料都建议直接禁用掉IPv6,只不IPv6是趋势,IPv6 Ready还是有必要的,尤其是外部一些IPv6环境的访问服务器时候,服务器端获取IPv6相关信息还是挺有价值的。
有没有在不禁用IPv6的情况下,让操作系统优先使用IPv4而非IPv6呢?
按照RFC3484 的说法,在IPv6、IPv4共存的环境下,解析顺序为
1. IPv6
2. IPv4
3. 6to4-Traffic
如果能够采用 Prefer IPv4 over IPv6,则可以实现IPv4 和IPv6并存。
办法一:修改/etc/gai.conf
/etc/gai.conf是socket getaddrinfo(3)函数的配置文件,因此修改此配置文件,可以影响各种socket程序对IPv4、IPv6地址的处理顺序。
配置样例:
label ::1/128 0
label ::/0 1
label 2002::/16 2
label ::/96 3
label ::ffff:0:0/96 4
precedence ::1/128 50
precedence ::/0 40
precedence 2002::/16 30
precedence ::/96 20
precedence ::ffff:0:0/96 100
配置文件说明可以参考Linux MAN
http://man7.org/linux/man-pages/man5/gai.conf.5.html
http://man7.org/linux/man-pages/man3/getaddrinfo.3.html
方案2、在Java应用中,指定-Djava.net.preferIPv4Stack=true
可以参考官方文档 Networking Properties
由于在上线部署Java应用后需要重启tomcat等应用服务器,由于此时可能仍有用户登陆了需要重启的应用服务器,如果此时侯强制停止服务器,已经登陆用户的操作可能中断掉(例如正在做支付),用户体验并不好。为避免此类情况发生,服务器上线时候需要支持所谓的drain stop、soft stop或者Session Draining(nginx术语)。
所谓Session Draining指对已经登陆要上线服务器的用户,保持其session,直到其操作完成。但不允许新的request接入要上线的服务器。
借用nginx plus的图:
除了采用F5这样高大上的硬件方案外,可以选用的方案:
方案1、采用tomcat 7 支持的并行部署Parallel Deployment特征
http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Parallel_deployment
http://www.javacodegeeks.com/2011/06/zero-downtime-deployment-and-rollback.html
http://www.tomcatexpert.com/blog/2011/05/31/parallel-deployment-tomcat-7
要实现旧版本的session失效后,Tomcat自动卸载掉,使用undeployOldVersions参数。
<Host undeployOldVersions=”true” …>
…
</Host>
http://tomcat.apache.org/tomcat-8.0-doc/config/host.html#Standard_Implementation
如果应用服务器是tomcat,且技术栈皆为java,此种方案最为简单。
方案2:采用haproxy+nginx方案,haproxy作为负载均衡服务器,nginx作为反向代理服务器,利用haproxy对drain stop的支持
参考资料:https://github.com/haproxy/haproxy-1.5/blob/master/doc/architecture.txt 的4. Soft-stop for application maintenance部分内容.
haproxy 管理界面可以对各服务器的session进行监控。
命令行方式可以采用haproxyctl https://github.com/flores/haproxyctl
也可以采用haproxy原生命令 http://serverfault.com/questions/249316/how-can-i-remove-balanced-node-from-haproxy-via-command-line
此种方案也较为方便。
方案3、采用LVS
将需要部署的服务器权重设置为0或从池中移除,则LVS会对已有会话保持,但不允许新的请求分配到权重为0的服务。
对采用LVS集群的,可以考虑采用。
方案4、nginx
nginx plus(收费)支持所谓的Session Draining,原理上使用了ngx_http_upstream_conf_module的drain参数。
nginux plus关于session persistence的文章值得一看:https://www.nginx.com/products/session-persistence Session Draining部分内容。
对于开源的nginx,有两种方案:
1、proxy_next_upstream+proxy_pass
2、-quit 命令 kill -QUIT $( cat /usr/local/nginx/logs/nginx.pid )
以上两种方案都只能实现粗略功能,且无方便的管理界面(无法查看活跃session),没有haproxy方便,不采用。
一、目前对账的算法:
1、从上游渠道(银行、银联等金融机构)获取对账文件,程序逐行解析入库
2、在存储过程中,以上游对账文件的表为基准,程序逐行读取并与我们系统的交易记录/账务记录(有账务系统情况下,合理方案应该是于账务记录)对比,查找出差异记录。
3、以我们系统的交易记录/账务记录为基准,程序逐行读取与上游对账文件对比,查找出差异记录
二、目前对账算法问题:
1、使用存储过程,对账过程都在数据库端完成,对数据库性能影响较大,而且对账逻辑扩展极为麻烦
2、逐行比对算法效率较低,但算法上并无好的优化余地。如果采用数据库INTERSECT、MINUS对数据库压力也高。
3、在业务量大的情况下(例如有上百家上游渠道需要对,每一家都有几十万条交易记录),对账服务器及数据库服务器负荷较高。即便采用读写分离,对账时候使用读库,压力一样很大。
4、导入批量文件,逐行入库效率较为低下(每一次都需要建立网络连接、关闭连接)
三、对账算法优化思路:
1、涉及网络传输的,尽量采用批量方式操作,减少网络消耗及时间消耗
2、使用Redis等NOSQL数据库,降低数据库服务器的压力。同时在扩展上也容易,一台Redis服务器不够,可以无限制增加用于对账用的服务器。
3、使用Redis的set集合的sdiff功能,利用Redis sdiff算法的高性能,比对上游记录和我方记录的差异
四、对账算法说明:
1、利用Oracle/Mysql的load data infile将对账文件批量导入到数据库
2、程序读取上游账务记录表,对上游账户记录执行select concat(channel_id, ":" , order_id , ":" , HASH_MD5(channel_id , order_id , amount , status , timestamp1 , timestamp2 ,…) ) as hashid from table ,得到对应的SET集合。
这里思路是将需要对账的记录拼成格式为:channel_id:order_id:hashid形式的串,以便作为Redis SET集合的item。
其中channel_id和order_id用于标识对应的渠道及订单,只是例子,根据实际需要补充。之所以要在hashid前面带上channel_id和order_id,主要目的是在sdiff后,能够作为主键,根据set结合的item查找出对应的数据库记录。
3、对我方的交易记录表/账户历史表采用上一步的类似算法,得到对应的SET结合
4、采用Redis的pipeline功能(Redis的各种客户端,包括java客户端jedis 都提供此功能),将上游账务记录SET集合和我方的交易记录/账务历史记录SET集分别批量执行sadd插入Redis,得到两个SET集合。
由于单条记录sadd 插入Redis效率较差(每一次都涉及网络open、close、传输消耗),因此使用Redis的pipeline功能,已实现批量入库功能。
可以参考:http://redis.io/topics/mass-insert
5、利用redis的sdiff功能查找出上游账务集合与我方记录集合的差值
6、从sdiff 集合中channel_id:order_id:hash,定位对应的数据库记录,更新对账状态。
具体性能及实现可以在实现后测试对比一下,应该会有大幅的性能提升。
我在知乎就问题《POS签购单上的授权号,凭证号,参考号,批次号,分别是什么?有什么作用》做的回答。
下面定义及术语参考了《中国银联POS终端规范》及《中国银联银行卡联网联合技术规范V2.1 第2部分 报文接口规范》两个规范。
批次号(Batch NO.):POS从签到起至结算、签退为止的交易为一批次,交易批次号标识一批交易。POS中心为每个POS的每个批次分配一个批次号,在签到响应报文中下传给POS终端。
对应银联ISO8583报文的报文头域7: 批次号(Batch Number)
序号(Ref. NO.):POS中心为交易分配的流水号,在响应报文中下传给POS终端作为对账参考号,并用于事后查证。
对应银联ISO8583报文的域37:检索参考号(Retrieval Reference Number)
授权号(Auth Code):授权标识应答码,简称“授权码”。是发卡行返回或银联CUPS代授权时返回的授权序号。
对应银联ISO8583报文的域38:授权标识应答码 Authorization Identification Response
查询号(Trace NO.):POS机为每一笔交易产生的顺序编号。POS每上送一次交易此号码增加1。 POS流水号为6位数字,值从1至999999循环使用。在自动冲正时,POS中心依据POS流水号作为确定被冲正交易的要素之一。
交易发起方赋予交易的一组数字,与域7(交易传输时间 Transmission Date/Time)、域32(受理机构标识码 Acquiring Institution Identification Code)和域33(发送机构标识码 Forwarding Institution Identification Code)的组合值唯一标识一笔交易的编号。
凭证号(Voucher NO.):查询号(Trace NO. 也叫POS流水号)也作为交易凭证号(在签购单上打印为Voucher NO.),在进行撤销等交易时,输入原交易凭证号作为确定原交易的要素之一,并且必须上送原交易的凭证号。
要确认一笔交易,分为发卡行和收单方:
对发卡行来说:卡号+参考号+授权号,就能够确定一笔交易
对于收单方来说:凭证号+域7(对应签购单上的日期/时间)+域32(对应签购单上的收单机构)+33域(对应签购单上的发卡机构)能够唯一确定一笔交易
因此如果是向发卡行投诉,则需要提供卡号、参考号、授权号。
如果是向收单方投诉,则需要提供凭证号、交易日期时间、收单机构、发卡机构
知乎回答原文链接:http://www.zhihu.com/question/29519161/answer/45062087