Mac OS系统下Python多进程Debug卡死状态

介绍
TEMP.py用于启动多进程读取文件,并行处理并写入文件中.

首先利用ps aux | grep TEMP.py查找对应pid.

(virtualenv_3.6.5) localhost:other_requriment root$ ps aux | grep TEMP.py
root             10859   0.0  0.0  4286184    972 s000  S+    8:07PM   0:00.01 grep TEMP.py
root             10797   0.0  0.0  7846872   1300   ??  S     7:50PM   0:16.63 bin/python3.6 /TEMP.py
root             10796   0.0  0.1  7875000   4360   ??  S     7:50PM   0:30.04 bin/python3.6 /TEMP.py
root             10795   0.0  0.1  7875000   4256   ??  S     7:50PM   0:30.23 bin/python3.6 /TEMP.py
root             10794   0.0  0.1  7875256   4236   ??  S     7:50PM   0:29.77 bin/python3.6 /TEMP.py
root             10793   0.0  0.1  7875256   4236   ??  S     7:50PM   0:29.26 bin/python3.6 /TEMP.py
root             10792   0.0  0.0  7847908   1824   ??  S     7:50PM   0:00.10 bin/python3.6 /TEMP.py
root             10791   0.0  0.0  7853028   1336   ??  S     7:50PM   0:08.25 bin/python3.6 /TEMP.py
root             10782   0.0  0.3  7846080  24124   ??  S     7:50PM   0:01.77 bin/python3.6 /TEMP.py

(virtualenv_3.6.5) localhost:$ pstree 10782
-+- 10782 root bin/python3.6 PROJECT/TEMP.py
 |--- 10791 root bin/python3.6 PROJECT/TEMP.py
 |--- 10792 root bin/python3.6 PROJECT/TEMP.py
 |--- 10793 root bin/python3.6 PROJECT/TEMP.py
 |--- 10794 root bin/python3.6 PROJECT/TEMP.py
 |--- 10795 root bin/python3.6 PROJECT/TEMP.py
 |--- 10796 root bin/python3.6 PROJECT/TEMP.py
 \--- 10797 root bin/python3.6 PROJECT/TEMP.py

使用dtruss进行进程情况查看(类似Linux系统中的strace).

(virtualenv_3.6.5) localhost:$ sudo dtruss -p 10782
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return
gettimeofday(0x7000046A9C68, 0x0, 0x0)           = 0 0
gettimeofday(0x7000047AC538, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A178168, 0x100000100, 0x0)          = -1 Err#316
gettimeofday(0x7000046A9C68, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A178168, 0x100000100, 0x0)          = -1 Err#316

查询子进程10791 – 10797
发现除了10792报错和主进程一样之外, 其他子进程均和10793一样, 没有报错.

(virtualenv_3.6.5) localhost:other_requriment didi$ sudo dtruss -p 10792
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return
gettimeofday(0x7FFEE9E28BA8, 0x0, 0x0)           = 0 0
psynch_cvwait(0x7FE75A236A88, 0x100000100, 0x0)          = -1 Err#316

(virtualenv_3.6.5) localhost:other_requriment didi$ sudo dtruss -p 10793
dtrace: system integrity protection is on, some features will not be available

SYSCALL(args)            = return

Linux系统下可以进入/proc/$PID/ 下 cat status 或者进入fd进行查看, 但是Mac OS系统下没有/proc目录, 所以根据Mac OS X equivalent of VirtualQuery or /proc/pid/maps?的推荐, 使用**vmmap**进行查看(需要root权限). 命令输出的信息较多(看不太懂这里的内容输出).

Stack Overflow上有类似的问题
Interpret dtruss output like “psynch_cvwait(…) = -1 Err#316”
问题中的回答提到

/*
 *  psynch_cvwait: This system call is used for psynch cvar waiters to block in kernel.
 */
int
psynch_cvwait(__unused proc_t p,
              struct psynch_cvwait_args * uap,
              uint32_t * retval)

也就是说, psynch_cswait是用来允许psynch cvar waiters在内核中block的.

Linux上调试类似问题
调试卡死的Python进程
用strace查找进程卡死原因

Mac系统中配置字体

苹果电脑上的字体存在的位置有两种:
1、/System/Library/Fonts路径下。
2、/Library/Fonts路径下。
这两种路径也就是所谓的字体安装方式,在Macintosh(苹果机)机上有两种方式安装字体,可以用Fonts文件夹或最新版本的ATM字体管理软件。相对而言Fonts文件夹简单明了一些:1、打开以上路径下的Fonts文件夹,将新字体手提箱(在苹果机上字体都是以一个手提箱的形式存在)拷贝到里面即可,新字体的名称就会显示在应用程序里的字体菜单中。
2、直接利用ATM字体管理软件进行字体导入管理即可。
字体:
1、文字的外在形式特征。就是文字的风格,是文字的外衣。 字体的艺术性体现在其完美的外在形式与丰富的内涵之中。 字体是文化的载体,是社会的缩影。
2、微机系统的字体font。这类字体是电脑必用字体,存在于“fonts”文件夹里。

苹果手机系统默认字体:

1、Heiti SC(黑体-简,黑体-简的英文名称为Heiti SC.Heiti为黑体的拼音,SC代表简体中文(Simplified Chinese)),是Mac OS X Snow Leopard(版本10.6)包含的简体中文字型,也是iPhone OS

2、3.0(版本4.0后改名为iOS)及iPod nano第五代以来的预设简体中文字型.

3、系统默认中文字体是华文细黑,英文字体是Myriad Pro.
Heiti SC(黑体-简,黑体-简的英文名称为Heiti SC。Heiti为黑体的拼音,SC代表简体中文(Simplified Chinese))是Mac OS X Snow Leopard(版本10.6)包含的简体中文字型,也是iPhone OS 3.0(版本4.0后改名为iOS)及iPod nano第五代以来的预设简体中文字型.

黑体-简系为黑体,取代华文黑体成为Mac OS X Snow Leopard的预设简体中文字型.在过去,华文黑体是Mac OS X的预设简体中文字型,因此以前并没有黑体-简.

黑体-简是全新的字型,与黑体-繁同以华文黑体为基础开发,成为Mac OS X Snow Leopard与iPhone OS 3.0(版本4.0后改名为iOS)之后内建并同时为预设的简体中文字型.虽与华文黑体为两套字型,但差异微小,仅排列上有差距,笔画的差距也十分微小.包含“细体”与“中黑”,黑体-简与黑体-繁皆使用.ttc(TrueType Collection)格式,可以在单一档案包含多套字型.

在ios中默认字体分为三类:

第一种:STHeiti-Light.ttc 和 STHeiti-Medium.ttc 代表的是中文字体 .

第二种:_H_Helvetica.ttc 和 _H_HelveticaNeue.ttc 代表的是英文以及数字字体

https://blog.csdn.net/gmr2453929471/article/details/78655834

KnowledgeGraph – 实体消歧, 实体对齐

实体消歧与实体对齐有什么区别与联系是:

实体消歧(也称语义消歧)是专门用于解决同名实体产生歧义问题的技术。在实际的 语言环境中,经常会遇到某个实体名称对应于多个命名实体对象的问题, 需要通过实体消歧来明确名称指代的具体实体.

实体(Entity)是指客观存在并可相互区别的事物,包括具体的人、事、物、抽象的概念或联系,知识库中包含多种类别的实体。
实体对齐(Entity Alignment)也被称作实体匹配(Entity Matching),是指对于异构数据源知识库中的各个实体,找出属于现实世界中的同一实体。是指多个异构数据源和实体,多源数据源的融合。
实体消歧: 是用于解决同个实体名称在不同语句不同意义的问题。

实体消歧问题是当下比较热点的研究问题,国内外的大多熟研究从两个角度解决实体歧义造成的影响,分别是通过寻求更高质量的特征和引入外部资源辅助消解。

在特征选取方面,何正焱[2]利用DNN(深度神经网络)方法,提出了一种文档和实体的相似度为框架的消歧模型;姜丽丽[3]提出了一种基于带权图结构的框架来实现人物实体的消歧工作,并使用实体标签对每个人物实体进行标注;Bagga和Baldwin[4]将不同文档间上下文的相似度作为特征实现实体消歧的;R.Bekkerman和A.McCallum[5]则结合了社交网络的链接信息和聚类两种非监督的框架对社交网络中的人物实体进行消歧。

给定的文档集中所包含的被査询人的信息往往是非常有限的,因此网络公共资源经常被用来挖掘更多的信息以提高同名消歧质量。其中,中科院的韩先培[6]使用了在线知识库信息来辅助解决实体歧义的,D.Bollegara[7]通过来对Web搜索引擎中的同名人物实体进行消歧;R.Bunescu[8]尝试使用在线百科全书(Wikipedia)的部分锚文本信息来扩充文档集,从而完成信息检测和同名消歧的任务。这些方法能够非常出色的完成实体消歧的任务,但是由于其需要花费大量的时间进行在线信息采集,因此更适合于服务器端的应用。

现在阶段的实体消歧研究集中在通用文本上,而专利文本上的实体,又与通用文本中的实体有本质的区别。因此,本文需要充分利用专利文本及专利实体的特点,并在通用的实体消歧方法的基础上进行优化。

https://wenku.baidu.com/view/299fbb117e21af45b207a857.html

一种用于专利实体的实体消歧方法

http://blog.csdn.net/caiyuanyuan_bjtu/article/details/40710311

ACL主席Gertjan van Noord等欧洲NLP科学家近日编撰了一篇非常棒的报告,汇总了大量的实体识别与消歧,词义消歧数据集,工具集

https://wenku.baidu.com/view/71afa8aecaaedd3383c4d3f3.html

浅析电子商务商品归一化方法

https://my.oschina.net/u/856502/blog/534670

知识图谱——数据实体化的手段 刘知远


实体(Entity)是指客观存在并可相互区别的事物,包括具体的人、事、物、抽象的概念或联系,知识库中包含多种类别的实体。实体对齐(Entity Alignment)也被称作实体匹配(Entity Matching),是指对于异构数据源知识库中的各个实体,找出属于现实世界中的同一实体。随着中文网络百科的不断完善,可以从网络百科页面抽取出实体,并对不同来源的实体进行对齐,构建高质量的中文异构百科RDF知识库。百度百科与互动百科所包含的实体信息覆盖面广,更新及时,因此,如何从网络百科数据中抽取出实体信息并进行实体对齐,是构建中文RDF知识库的关键问题。实体对齐常用的方法是利用实体的属性信息判定不同源实体是否可进行对齐,由于网络百科数据属于用户原创内容(User Generated Content,UGC)类型,不同用户编辑的数据质量参差不齐,仅通过用户编辑的实体属性信息难以准确判定是否为同一实体。

可以采用多种方法结合的方式:即分层使用。第一步,先用一种方法对齐,设定上界和下界。达到上界的就是。低于下界的就不是。在下界和上界之间的就递进的采取下一种方法进一步判断。

参考论文中文异构百科知识库实体对齐

知识库实体对齐技术综述

基于网络语义标签的多源知识库实体对齐算法

中科院电子所专利: 面向知识图谱构建的细粒度中文属性对齐方法   旨在识别来自单一或多个数据源的属性之间存在的对应关系,例如,识别“生日”和“出生日期”之间的同义关系。

Linear Algebra – Lesson 1. 方程组的集合解释

Introduction

课程代码 : MIT 18.06
课程配套教材 : Introduction to Linear Algebra
课程在线网址 : web.mit.edu/18.06
在线网址里有习题和matlab代码等资源.


N linear equations, N unknows – 方程式组和矩阵

方程式组和矩阵之间存在天然的联系. 即方程式组可以用矩阵的形式很优雅的表达出来.
举一个简单的方程式组的例子 : \begin{cases} 2x-y=0 \\\\ -x+y=3 \end{cases}

可以将未知变量的系数看作矩阵的元素,从而将原始方程式组转换为矩阵的形式表达出来, 如下所示 :
\begin{bmatrix}2 & -1 \\\\ -1 & 2 \end{bmatrix} * \begin{bmatrix}x \\\\ y \end{bmatrix} = \begin{bmatrix} 0 \\\\ 3 \end{bmatrix}
这里,我们将 \(\begin{bmatrix}2 & -1 \\ -1 & 2 \end{bmatrix} \)看作是矩阵\(A\), 将\( \begin{bmatrix}x \\ y \end{bmatrix}\)看作是向量(Vector) \(X\), 那么结果\(\begin{bmatrix} 0 \\ 3 \end{bmatrix}\)就是向量\(b\), 从而得出\(A*X=b\)
矩阵\(A\),也被称为 系数矩阵(coefficient matrix).
所以, 正如老师所说,

A matrix is just a rectangular array of numbers.

Row Picture

Row Picture, 也就是从行的角度来考虑矩阵内在的含义.
以上面的方程式组为例, 对于方程式(1)\(2x-y=0\) 可以通过假设\(x=0\)和\(x=1\)分别得出y的对应值为\(y=0\)和\(y=2\). 即可以以\((0,0)\)和\((1,2)\)为线上两点确认方程式(1)在\(x,y\)平面上的直线. 同理可得方程式(2)在平面上所代表的线. 通过图像可以看出, 两条线条交于一点\((1,2)\).

Column Picture

从列的角度来看,上述方程式组可以看做列的线性组合(linear combination of columns)
x\begin{bmatrix} 2 \\\\ -1\end{bmatrix} + y\begin{bmatrix} -1 \\\\ 2\end{bmatrix} = \begin{bmatrix} 0 \\\\ 3\end{bmatrix}

现在从二维转换为三维, 有如下方程组:
2x-y=0\\\\-x+2y-z=-1\\\\-3y+4z=4
同理可以得出对应的矩阵\(A\)和向量\(b\) : \(A=\begin{bmatrix}2&-1&0\\-1&2&-1\\0&-3&4\end{bmatrix}\) \(b=\begin{bmatrix}0\\-1\\4\end{bmatrix} \)
同样,从column picture的角度来看上述方程式组,得出:
x\begin{bmatrix}2\\\\-1\\\\0\end{bmatrix} + y\begin{bmatrix}-1\\\\2\\\\-3\end{bmatrix}+z\begin{bmatrix}0\\\\-1\\\\4\end{bmatrix}=\begin{bmatrix}0\\\\-1\\\\4\end{bmatrix}
可以得出一个解为\(x=0,y=0,z=1\)

对于上述方程式组,如果\(b\)的值变为\(\begin{bmatrix}1\\1\\-3\end{bmatrix}\), 则可以得出一个解为\(x=1,y=1,z=0\)

以此类推,得出一个问题:

Can I solve \(Ax=b\) for every \(b\) ?
Or
Do the linear combinations of the columns fill three dimensional space?

是否对于任意的\(b\),\(Ax=b\)都有解?

对于上述方程式组,如果三个列向量均处在同一平面内,则无法通过线性组合方式生成不在这个平面内的向量,那么对于空间内其他不属于此平面的向量就无解.
这种情况被称为奇异(singular case),该矩阵非可逆(not invertible),不是对于所有的\(b\)都有解.

Matrix Form – 矩阵形式

矩阵乘以向量的形式(multiply a matrix by a vector) 表达为 \(Ax=b\).
e.g.
\begin{bmatrix}2&5\\\\1&3\end{bmatrix}*\begin{bmatrix}1\\\\2\end{bmatrix}
可以将其看作 1个列1 和 2个列 2 相加:
\begin{bmatrix}2&5\\\\1&3\end{bmatrix}*\begin{bmatrix}1\\\\2\end{bmatrix} = 1\begin{bmatrix}2\\\\1\end{bmatrix} + 2\begin{bmatrix}5\\\\3\end{bmatrix} = \begin{bmatrix}12\\\\7\end{bmatrix}
也可以通过点乘的方式求解:
\begin{bmatrix}2&5\\\\1&3\end{bmatrix}*\begin{bmatrix}1\\\\2\end{bmatrix} =\begin{bmatrix}2*1+5*2\\\\1*1+3*2\end{bmatrix} =\begin{bmatrix}12\\\\7\end{bmatrix}

\(Ax\) is a combination of the columns of \(A\).

HTTP中GET和POST的区别

根据 99%的人都理解错了HTTP中GET与POST的区别 的描述, GET和POST最直观的区别在于 : GET将参数包含在URL中, 而POST通过request body传递参数.

在被问到两者区别时, 往往会给出如下的”标准答案”:

GET在浏览器回退时是无害的, 而POST会再次提交请求.
GET产生的URL地址可以被Bookmark, 而POST不可以.
GET请求会被浏览器主动cache, 而POST不会, 除非手动设置.
GET请求只能进行url编码, 而POST支持多种编码方式.
GET请求参数会被完整保留在浏览器历史记录里, 而POST中的参数不会被保留.
GET请求在URL中传送的参数是有长度限制的, 而POST么有.
对参数的数据类型, GET只接受ASCII字符, 而POST没有限制.
GET比POST更不安全, 因为参数直接暴露在URL上, 所以不能用来传递敏感信息.
GET参数通过URL传递, POST放在Request body中.
(本标准答案参考自w3schools

但其实GET和POST在协议本质上并没有特别大的区别.

从根本上来说, GET和POST是HTTP协议中的两种发送请求的方法. 而HTTP是基于TCP/IP的关于数据如何在万维网中如何通信的协议, 其底层实现基于TCP/IP. 所以GET和POST的底层也是TCP/IP, 也就是说, GET/POST都是TCP链接. GET和POST能做的事情是一样一样的.你要给GET加上request body, 给POST带上url参数, 技术上是完全行的通的.

那么, “标准答案”里的那些区别是怎么回事?

在我大万维网世界中, TCP就像汽车, 我们用TCP来运输数据, 它很可靠, 从来不会发生丢件少件的现象.但是如果路上跑的全是看起来一模一样的汽车, 那这个世界看起来是一团混乱, 送急件的汽车可能被前面满载货物的汽车拦堵在路上, 整个交通系统一定会瘫痪.为了避免这种情况发生, 交通规则HTTP诞生了.HTTP给汽车运输设定了好几个服务类别, 有GET, POST, PUT, DELETE等等, HTTP规定, 当执行GET请求的时候, 要给汽车贴上GET的标签(设置method为GET), 而且要求把传送的数据放在车顶上(url中)以方便记录.如果是POST请求, 就要在车上贴上POST的标签, 并把货物放在车厢里.当然, 你也可以在GET的时候往车厢内偷偷藏点货物, 但是这是很不光彩;也可以在POST的时候在车顶上也放一些数据, 让人觉得傻乎乎的.HTTP只是个行为准则, 而TCP才是GET和POST怎么实现的基本.

但是, 我们只看到HTTP对GET和POST参数的传送渠道(url还是requrest body)提出了要求.“标准答案”里关于参数大小的限制又是从哪来的呢?

在我大万维网世界中, 还有另一个重要的角色:运输公司.不同的浏览器(发起http请求)和服务器(接受http请求)就是不同的运输公司. 虽然理论上, 你可以在车顶上无限的堆货物(url中无限加参数).但是运输公司可不傻, 装货和卸货也是有很大成本的, 他们会限制单次运输量来控制风险, 数据量太大对浏览器和服务器都是很大负担.业界不成文的规定是, (大多数)浏览器通常都会限制url长度在2K个字节, 而(大多数)服务器最多处理64K大小的url.超过的部分, 恕不处理.如果你用GET服务, 在request body偷偷藏了数据, 不同服务器的处理方式也是不同的, 有些服务器会帮你卸货, 读出数据, 有些服务器直接忽略, 所以, 虽然GET可以带request body, 也不能保证一定能被接收到哦.

好了, 现在你知道, GET和POST本质上就是TCP链接, 并无差别.但是由于HTTP的规定和浏览器/服务器的限制, 导致他们在应用过程中体现出一些不同.

除此之外, GET和POST还有一个重大区别, 即 : GET产生一个TCP数据包, 而POST产生两个TCP数据包.

对于GET方式的请求, 浏览器会把http header和data一并发送出去, 服务器响应200(返回数据);
而对于POST, 浏览器先发送header, 服务器响应100 continue, 浏览器再发送data, 服务器响应200 ok(返回数据).

也就是说, GET只需要汽车跑一趟就把货送到了, 而POST得跑两趟, 第一趟, 先去和服务器打个招呼“嗨, 我等下要送一批货来, 你们打开门迎接我”, 然后再回头把货送过去.

因为POST需要两步, 时间上消耗的要多一点, 看起来GET比POST更有效.因此Yahoo团队有推荐用GET替换POST来优化网站性能.但这是一个坑!跳入需谨慎.为什么?

  1. GET与POST都有自己的语义, 不能随便混用.
  2. 据研究, 在网络环境好的情况下, 发一次包的时间和发两次包的时间差别基本可以无视.而在网络环境差的情况下, 两次包的TCP在验证数据包完整性上, 有非常大的优点.
  3. 并不是所有浏览器都会在POST中发送两次包, Firefox就只发送一次.

而在GET和POST有什么区别?及为什么网上的多数答案都是错的.中则介绍了面试者自己的亲身经历. 同时对于上述的一些说法做了实验.
以上就是HTTP协议中GET和POST的真正区别.

社交网络分析 (SNA) 简介

Social Network Analysis for Startups是一本介绍如何使用python进行社交网络分析的入门书,主要使用了NetworkX、numpy等插件进行网络分析,前端可以使用Matplotlib进行可视化展示,一个展示效果图如下所示:

一些资源:
• Code&data used in this lecture: http://www.cl.cam.ac.uk/~ss824/stna-examples.tar.gz
• NodeXL: a graphical front-end that integrates network analysis intoMicrosoft Office and Excel.
(http://nodexl.codeplex.com/)
• Pajek: a program for network analysis for Windows(http://pajek.imfm.si/doku.php).
• Gephi: an interactive visualization and exploration platform(http://gephi.org/)
• Power-law Distributions in Empirical Data: tools for fittingheavy-tailed distributions to data
(http://www.santafe.edu/~aaronc/powerlaws/)
• GraphViz: graph visualization software (http://www.graphviz.org/)
• Matplotlib: full documentation for the plotting library (http://matplotlib.sourceforge.net/)
 
Pdf书:http://download.csdn.net/detail/u010736419/9779562
Ppt讲义:http://download.csdn.net/detail/u010736419/9779543

Pandas Tutorials – DataFrame数据选择

pandas中索引的使用

定义一个pandas的DataFrame对像

import pandas as pd
data = pd.DataFrame({‘A’:[1,2,3],’B’:[4,5,6],’C’:[7,8,9]},index=[“a”,”b”,”c”])
data

A   B   C

a 1 4 7
b 2 5 8
c 3 6 9123456789

.loc 的使用

.loc[],中括号里面是先行后列,以逗号分割,行和列分别是行标签和列标签,比如我要得到数字5,那么就就是:

data.loc[“b”,”B”]1

因为行标签为b,列标签为B,同理,那么4就是data[“a”,”B”]
上面只是选择某一个值,那么如果我要选择一个区域呢,比如我要选择5,8,6,9,那么可以这样做:

data.loc[‘b’:’c’,’B’:’C’]1

因为选择的区域,左上角的值是5,右下角的值是9,那么这个矩形区域的值就是这两个坐标之间,也就是对应5的行标签到9的行标签,5的列标签到9的列标签,行列标签之间用逗号隔开,行标签与行标签之间,列标签与列标签之间用冒号隔开,记住,.loc是用行列标签来进行选择数据的。那么,我们会想,那我们只知道要第几行,第几列的数据呢,这该怎么办,刚好,.iloc就是干这个事的

.iloc

.iloc[]与loc一样,中括号里面也是先行后列,行列标签用逗号分割,与loc不同的之处是,.iloc 是根据行数与列数来索引的,比如上面提到的得到数字5,那么用iloc来表示就是data.iloc[1,1],因为5是第2行第2列,注意索引从0开始的,同理4就是data.iloc[0,1],同样如果我们需要选择一个区域,比如我要选择5,8,6,9,那么用,iloc来选择就是

data.iloc[1:3,1:3]1

因为5在第二行第二列,9在第三行第三列,注意此处区间前闭后开,所以是1:3,与loc不同的是loc前闭后闭,以及loc是根据行列标签,而.iloc是根据行数与列数

.ix

.ix我发现,上面两种用法他都可以,它既可以根据行列标签又可以根据行列数,比如拿到5

data.ix[1,1]
data.ix[“b”,”B”]12

上面两种做法都可以的,同理选择一个区域

data.ix[1:3,1:3]
data.ix[‘b’:’c’,’B’:’C’]
123

以上两种方法都是取到5,6,7,8


作者:ML_BOY
来源:CSDN
原文:https://blog.csdn.net/qq1483661204/article/details/77587881?utm_source=copy
版权声明:本文为博主原创文章,转载请附上博文链接!