首页 技术 正文
技术 2022年11月11日
0 收藏 471 点赞 4,765 浏览 17858 个字

本文翻译自Contributing Code

—————————————–

Apache Flink是由自愿的代码贡献者维护、优化及扩展的。Apache Flink社区鼓励任何人贡献源代码。为了使得代码贡献者及复查者之便利,以及保存高质量的代码基础,我们遵循着一个贡献代码的过程,该过程将在本文档中详细描述。

本文包括有关向Flink贡献代码所需知晓的所有事宜,描述了从前期准备,测试以及代码提交的过程,同时解释了代码编写的准则以及Flink基础代码的代码风格,此外给出了部署开发环境的教程。

重要:请在进行代码贡献之前仔细阅读该文档,遵循下述的过程及准则十分重要。否则,你的 pull request可能不会被接受或需要大量返工。特别地,在开始一个实现新特性的 pull request时,你需要打开一个JIRA ticket,并且与开发社区在有关是否需要该特性达成一致。

一、贡献代码的过程

1.1 前期准备

请确定你的贡献与一个JIRA的issue相关,这是Flink社区贡献代码时遵循的一个普遍规定,除了修复琐碎bug(trivial hot fixes),该规定覆盖了包括bug修正、优化或新特性等等情况。如果你想要修复找到的bug,或是想要添加新特性,或是想优化Flink,请遵循Flie a bug reportPropose an improvement or a new feature准则,在实现之前,打开一个Flink的JIRA的issue。

如果JIRA的issue的描述表明其解决方案会涉及到基础代码的敏感部分、它足够复杂或是会添加大量新代码,Flink社区可能需要一份设计文档(大多数贡献的代码都不需要设计文档)。该文档的目的在于保证issue的整体解决方法是合理且经由社区同意的。需要文档的JIRA的issue将打上requires-design-doc的标签,该标签可以由任何觉得文档是必要的社区成员添加上去。一个好的issue描述可以帮助人们决定该issue是否需要一份设计文档。设计文档必须添加或链接到JIRA的issue中,且需要满足以下几个方面:

1. 总体方法的概述

2. API改变的列表(改变的接口,新的或过期的配置参数,改变的行为等等)

3. 涉及到的主体组件( main component)和类

4. 该方法已知的缺陷

任何人都可以添加设计文档,包括issue的提出者和解决者

JIRA issue的代码贡献中,那些需要文档的贡献需要其文档被社区以lazy consensus的方式接受后才可以添加到Flink的基础代码中。请在编写代码之前检查并确认是否需要设计文档。

1.2 代码编写准则

请尽可能遵循以下规则:

1. 请重视JIRA的issue中记录归档的讨论或需求。

2. 如果需要设计文档,则尽可能遵循该文档的设计。如果你的实现和文档设计偏差过大,请实时更新文档并与社区达成一致。少量的偏差是允许的,不过在提交代码时请指出这些变动之处。

3. 严格遵循coding guidelines and the code style

4. 不要在一次代码贡献中混淆入其他不相关的issue

请随时随意提问,不论发送邮件给dev mailing list还是在JIRA issue中评论都可。

有关部署开发环境,见下面第四部分所述。

1.3 验证代码的合规性(compliance)

提交前验证代码的合规性十分重要,主要验证以下几点:

1. 保证代码可以编译

2. 验证通过所有已存在的新的测试

3. 检查代码风格不违规

4. 保证没有不相关或不必要的格式上的变动

你可以通过以下命令编译代码、运行并测试、检查部分代码风格:

mvn clean verify

请注意,有些Flink的基础代码的测试比较奇诡(flaky)并可能意外地失败,Flink社区正在努力提升这些测试的质量,但有的测试无法继续优化,如包括外部依赖的测试等。我们将所有奇诡的测试维护在JIRA中,并加上了test-stability标签。如果你遇到似乎与你的改变无关的测试失败的情况,请查看或扩展已知奇诡测试的列表。

请注意,为了验证你贡献的代码,我们针对Java,Scala,Hadoop不同版本的组合形式运行不同的编译profile。我们鼓励每个贡献者使用continuous integration服务,它将在你每次push一个change时自动测试代码。Best practices一文中有如何将Travis集成到你的Github仓库的教程。

除了自动测试之外,请检查你的修改,并移除诸如不必要的格式修改等无关的修改。

1.4准备和提交你的贡献

为了使得merge更加方便,请将这些新的修改rebase到主仓库master分支的最新版本。也请遵循下文代码编写引导(本文2.1),清除你的commit历史,且将你的所有提交 squash到一个合适的集合中。请在rebase以及commit squash后对你的代码进行多次验证。

Flink工程通过GitHub Mirror,以Pull request的形式接受代码贡献。Pull request是一个提供补丁的简单方法,它通过提供一个代码分支的指针的方式来包含修改。

通过将我们的贡献push回到我们fork的Flink仓库来启用一个pull request

git push origin myBrance

进入你的fork仓库网址(https://github.com/<your-user-name>/flink),并且使用“Create Pull Request”按钮来创建一个pull request。确保base fork是 apache/flink master并且head fork包括了你的修改的分支。给你的pull request一个有意义的描述并且发送过来。

当然,你也可以通过JIRA issue来添加一个补丁。

二、代码编写引导

2.1 Pull request和commit信息

1. 每个pull request仅负责一个修改。请不要将不同的无关改变混合到一个pull request中。相反地,请用多个独立pull request对应JIRA issue。这保证pull request是topic相关,从而可以更加方便地merge,并且通常只会引起与该topic有关的冲突。

2. 不要再pull request中包含WIP(仍在开发中)。我们认为pull request是要不做会任何改进地merge到当前稳定主分支上去的。因此,一个pull request不应当为“work in progress”的。仅在你确信该pull request可以顺利merge到当前主branch中时才开始一个pull request。而如果你想要对你的代码的意见,请发布你的工作分支的链接。

3. Commit信息。一个pull request必须与一个JIRA issue相关;如果你想解决一个JIRA上没有的问题,请创建一个issue。最新的commit信息应当引用该issue,例如,“[FLINK-633] Fix NullPointerException for empty UDF parameters”。如此,该pull request会自动给它的内容加上描述,如以何种方式修复了什么bug

4. 复核commit。如果你在pull request上得到要求修改的评论,commit这些修改。不要rebase以及squash这些commit。这样才能让他人独立查看cleanup的部分。否则复查者就需要再一次重新复查整个集合。

2.2 异常和错误信息

1. Exception swallowing不要swallow异常并打印堆栈轨迹,而应该查看类似的类是如何处理异常的并加以模仿。

2. 错误信息要有意义。给出的错误信息要有意义,试着猜测异常为何被抛出并且给出可以帮助到用户解决问题的信息。

2.3 测试

1. 需要通过所有测试。任何无法通过测试或无法编译的pull request不会再进一步进行审查。我们建议将你的GitHub私人账号与Travis CI连接(像Flink的Github仓库)。请注意之前有关奇诡测试的说明

2. 需要测试新特性。所有新特性都需要由测试来严格保证。在接下来的merge中抛出或是破坏某特性。如果没有该特性没有测试来保证,这些问题将无法被意识到。所有未被测试覆盖的东西都是浮于表面的。

3. 使用合适的测试机制。请使用单元测试来孤立测试功能,例如方法等。单元测试应当以亚秒级执行并且应当考虑所有情况。类的单元测试的名字应当是”*Test”。使用继承测试来实现long-running测试。

2.4 文档

1. 文档更新。许多系统中的改变同样会影响到文档(JavaDocs文档和在目录docs/下的用户文档)。 pull request和补丁需要更新对应的文档,否则提交的改变将不会被源码接受。有关如何更新文档见于贡献文档指导一文。

2. 公共方法的Javadocs。所有公共方法和类需要JavaDoc。请填写有意义的文档,一个好的文档应当是简明扼要而富含信息的。若你改变了签名或是已有文档的方法的行为,请务必同时更新JavaDoc。

2.5 代码格式

1. 不要重新排版。请不要对源码文件重新排版,若你或你的IDE自动移除/替换了空白字符,重新排版代码或是自动注释后,代码差别(diff)将不可辨识。同样的,其他影响相同文件的补丁将无法进行merge操作。请配置您的IDE使其不会自动重排版。我们可能会拒绝带有过多或不必要的代码重排版的pull request

三、代码风格

1. Apache license header。确保你的源码文件中包含Apache License header,RAT插件将会在你编译代码时检查是否含有该header。

2. Tabs 或是 space。我们使用tab(而不是space)作为缩进符号。这只是由于我们开始时就使用tab,但不要将它们混用十分重要,否则会引发merge或diff时的冲突。

3. Block。所有if,for,while,do等语句必须包含在大括号封装的代码块中(即使只有一行代码,同样需要大括号包围代码块),如下代码所示,这将有效避免诸如Apple的SSL library的goto bug等问题。

for(…){

}

4. 不要在import语句中使用通配符。不要再核心文件中的import语句中使用通配符,它们会在adding到代码(adding to the code)甚至有时在重构(refactoring)期间产生一些问题。在导入operator和function时,异常将出现在Tuple类,与Tuple相关的支持类以及Flink user程序。测试则是user程序的特殊用例。

5. 不要留下没用的import语句。请移除所有没用的import语句。

6. 使用Guava检测。为了增加代码的同质性,请一致使用Guava方法checkNotNull和checkArgument来检测,而不是使用Apache Commons Validate

7. Supress warnings:如果它们suppress warning无法避免(如”unchecked”或”serial”等),请添加声明注解(annotation)。

8. 注释。请为代码添加有关逻辑的注释。可以通过添加JavaDoc,或是通过不对方法做任何注释而继承原来的注释等方法添加。不要自动生成注释,避免诸如”i++; // increment by one”这样无用的注释

四、练习

1. Travis:Flink已经预先针对Travis CI做了配置,使其可以很方便地在你的私人fork的仓库中启用(它使用GitHub来进行身份认证,所以你不需要另一个账号来进行验证)。可以简单地添加Travis CI的hook到你的仓库(settings -> webhooks & services -> add service),并启用Travis上对flink仓库的测试。

五、部署开发环境

5.1 开发和编译FLink的环境需求:

1. 类Unix环境(我们使用Linux,Mac OS X, Cygwin)

2. git

3. Maven(至少为版本3.0.4)

4. Java 7或8

5.2 Clone仓库

Apache Flink的源代码存储在git仓库中,并镜像存储在Github。Github上交换代码一般讲仓库fork到你的私人Github账户仓库。为此,你需要一个Github账户或免费创建一个。Fork一个仓库意味着Github为你创建了一个仓库的副本,该操作可以通过点击仓库站点页面中右上角的fork按钮完成。一旦你将Flink仓库fork到你的私人账户,你就可以将该仓库clone到你的本地设备上。通过以下命令,源码将会下载到名为flink的目录下。

git clone https://github.com/<your-user-name>/flink.git

5.3 代理设置

如果你处于防火墙保护之下,你可能需要为Maven和你的IDE提供代理设置。例如WikipediaEditsSourceTest通过IRC通信,并且需要一个SOCKS proxy server来绕过。

5.4 部署IDE并导入源代码

Flink的提交者们使用IntelliJ IDEA和Eclipse IDE来开发Flink基础代码。

5.4.1 IDE的最低要求:

·     支持JAVA和Scala语言,同时支持二者的混合项目。

·     支持Java和Scala的Maven。

5.4.2 IntelliJ IDEA

IntelliJ IDE自带支持Maven,并且提供了Scala开发的插件

IntelliJ下载地址:https://www.jetbrains.com/idea/

IntelliJ Scala Plugin:http://plugins.jetbrains.com/plugin/?id=1347

有关IntelliJ的设置,请看Setting up IntelliJ一文指导

5.4.3 Eclipse Scala IDE

对于Eclipse用户,我们建议基于Eclipse Kepler,使用Scala IDE 3.0.3。尽管该版本有些旧,但我们发现这是Flink等复杂项目运行最为鲁棒的版本。

进一步细节以及更新的Scala IDE版本的指导在How to setup Eclipse文档中。

注意:在开始下列部署之前,确保通过使用该一次以下命令来运行编译程序(mvn clean install -DskipTests,详情见上文)

1. 下载Scala IDE(推荐)或是安装Eclipse Kepler的插件。下载链接和指令见于How to setup Eclipse

2. 向Scala编译器添加添加”macroparadise”编译器插件。打开”Winodw” -> “Preferences” -> “Scala” -> “Complier” -> “Advanced”,并添加”Xplugin”域和macroparadise的jar文件的路径(通常是”/home/-your-user-/.m2/repository/org/scalamacros/paradise_2.10.4/2.0.1/pardise_2.10.4-2.0.1.jar”)。注意:如果你没有jar文件,可能是由于你没有运行命令行来编译生成。

3. 导入Flink Maven工程(”File” -> “Import” -> “Maven” -> “Existing Maven Projects”)

4. 在导入期间,Eclipse将会自动询问是否自动安装额外Maven build helper插件。

5. 关闭”flink-java8″工程,由于Eclipse Kepler不支持Java 8,你无法开发此工程

5.4.4 导入源码

Apache Flink使用Apache Maven作为编译工具,大多数IDE都可以导入Maven工程。

5.5 编译源码

为了从源码编译Flink,我们可以打开一个终端,导航到Flink源码的根目录,并调用命令”mvn clean package”。该命令将编译Flink并运行所有测试,Flink最终将安装在目录build-target。

为了编译Flink时不运行测试,你可以调用命令”mvn -DskipTests clean package”

六、提交者如何使用Git

只有ASF的infrastructure team具有Github镜像的管理员访问权限,因此,提交者需要将修改push到ASF的git仓库。

Main source仓库

ASF writablehttps://git-wip-us.apache.org/repos/asf/flink.git

ASF read-onlygit://git.apache.org/repos/asf/flink.git

ASF read-onlyhttps://github.com/apache/flink.git

注意:Flink不使用Oracle JDK 6编译,但它可以使用Oracle JDK 6运行。

如果你想要为Hadoop1编译,通过命令”mvn clean package -DskipTests -Dhadoop.profile=1″来激活编译profile。

七、快照版本(每夜构建Nightly builds)

Apache Flink 1.1-SNAPSHOT是我们最新的开发版本。

你可以下载我们打包的每夜构建版本,它包括最新的开发代码,由此可以使用还未发布的新特性。仅有通过所有测试的编译版本才会发布在此处。

· Hadoop 1: flink-1.1-SNAPSHOT-bin-hadoop1.tgz

· Hadoop 2 YARN :flink-1.1-SNAPSHOT-bin-hadoop2.tgz

添加Apache Snapshot repository到你的Maven的pom.xml:

 <repositories>
  <repository>
    <id>apache.snapshots</id>
    <name>Apache Development Snapshot Repository</name>
    <url>https://repository.apache.org/content/repositories/snapshots/</url>
  <releases><enabled>false</enabled></releases>
  <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>

至此,你就可以将版本1.1-SNAPSHOT(或版本1.1-SNAPSHOT-hadoop1来兼容旧的1.x版本hadoop)的Apache Flink包括到一个Maven依赖中了。

<!–
/* Font Definitions */
@font-face
{font-family:宋体;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-alt:SimSun;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 680460288 22 0 262145 0;}
@font-face
{font-family:”Cambria Math”;
panose-1:2 4 5 3 5 4 6 3 2 4;
mso-font-charset:1;
mso-generic-font-family:roman;
mso-font-pitch:variable;
mso-font-signature:0 0 0 0 0 0;}
@font-face
{font-family:Calibri;
panose-1:2 15 5 2 2 2 4 3 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-536870145 1073786111 1 0 415 0;}
@font-face
{font-family:”Calibri Light”;
panose-1:2 15 3 2 2 2 4 3 2 4;
mso-font-charset:0;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-1610611985 1073750139 0 0 415 0;}
@font-face
{font-family:”Microsoft YaHei Light”;
panose-1:0 0 0 0 0 0 0 0 0 0;
mso-font-charset:0;
mso-generic-font-family:roman;
mso-font-format:other;
mso-font-pitch:auto;
mso-font-signature:0 0 0 0 0 0;}
@font-face
{font-family:微软雅黑;
panose-1:2 11 5 3 2 2 4 2 2 4;
mso-font-charset:134;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-2147483001 684670034 22 0 262175 0;}
@font-face
{font-family:”\@宋体”;
panose-1:2 1 6 0 3 1 1 1 1 1;
mso-font-charset:134;
mso-generic-font-family:auto;
mso-font-pitch:variable;
mso-font-signature:3 680460288 22 0 262145 0;}
@font-face
{font-family:”\@微软雅黑”;
mso-font-charset:134;
mso-generic-font-family:swiss;
mso-font-pitch:variable;
mso-font-signature:-2147483001 684670034 22 0 262175 0;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
{mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-parent:””;
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;}
h1
{mso-style-priority:9;
mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-link:”标题 1 字符”;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
mso-pagination:widow-orphan;
mso-outline-level:1;
font-size:24.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;
font-weight:bold;}
h2
{mso-style-priority:9;
mso-style-unhide:no;
mso-style-qformat:yes;
mso-style-link:”标题 2 字符”;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
mso-pagination:widow-orphan;
mso-outline-level:2;
font-size:18.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;
font-weight:bold;}
p.MsoHeader, li.MsoHeader, div.MsoHeader
{mso-style-priority:99;
mso-style-link:”页眉 字符”;
margin:0cm;
margin-bottom:.0001pt;
text-align:center;
mso-pagination:widow-orphan;
tab-stops:center 207.65pt right 415.3pt;
layout-grid-mode:char;
border:none;
mso-border-bottom-alt:solid windowtext .75pt;
padding:0cm;
mso-padding-alt:0cm 0cm 1.0pt 0cm;
font-size:9.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;}
p.MsoFooter, li.MsoFooter, div.MsoFooter
{mso-style-priority:99;
mso-style-link:”页脚 字符”;
margin:0cm;
margin-bottom:.0001pt;
mso-pagination:widow-orphan;
tab-stops:center 207.65pt right 415.3pt;
layout-grid-mode:char;
font-size:9.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;}
a:link, span.MsoHyperlink
{mso-style-noshow:yes;
mso-style-priority:99;
color:blue;
text-decoration:underline;
text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
{mso-style-noshow:yes;
mso-style-priority:99;
color:purple;
text-decoration:underline;
text-underline:single;}
p
{mso-style-noshow:yes;
mso-style-priority:99;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;}
p.msonormal0, li.msonormal0, div.msonormal0
{mso-style-name:msonormal;
mso-style-unhide:no;
mso-margin-top-alt:auto;
margin-right:0cm;
mso-margin-bottom-alt:auto;
margin-left:0cm;
mso-pagination:widow-orphan;
font-size:12.0pt;
font-family:宋体;
mso-bidi-font-family:宋体;}
span.1
{mso-style-name:”标题 1 字符”;
mso-style-priority:9;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:”标题 1″;
mso-ansi-font-size:22.0pt;
mso-bidi-font-size:22.0pt;
font-family:宋体;
mso-ascii-font-family:宋体;
mso-fareast-font-family:宋体;
mso-hansi-font-family:宋体;
mso-bidi-font-family:宋体;
mso-font-kerning:22.0pt;
font-weight:bold;}
span.2
{mso-style-name:”标题 2 字符”;
mso-style-noshow:yes;
mso-style-priority:9;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:”标题 2″;
mso-ansi-font-size:16.0pt;
mso-bidi-font-size:16.0pt;
font-family:”等线 Light”;
mso-ascii-font-family:”等线 Light”;
mso-ascii-theme-font:major-latin;
mso-fareast-font-family:”等线 Light”;
mso-fareast-theme-font:major-fareast;
mso-hansi-font-family:”等线 Light”;
mso-hansi-theme-font:major-latin;
mso-bidi-font-family:”Times New Roman”;
mso-bidi-theme-font:major-bidi;
font-weight:bold;}
span.a
{mso-style-name:”页眉 字符”;
mso-style-priority:99;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:页眉;
mso-ansi-font-size:9.0pt;
mso-bidi-font-size:9.0pt;
font-family:宋体;
mso-ascii-font-family:宋体;
mso-fareast-font-family:宋体;
mso-hansi-font-family:宋体;
mso-bidi-font-family:宋体;}
span.a0
{mso-style-name:”页脚 字符”;
mso-style-priority:99;
mso-style-unhide:no;
mso-style-locked:yes;
mso-style-link:页脚;
mso-ansi-font-size:9.0pt;
mso-bidi-font-size:9.0pt;
font-family:宋体;
mso-ascii-font-family:宋体;
mso-fareast-font-family:宋体;
mso-hansi-font-family:宋体;
mso-bidi-font-family:宋体;}
.MsoChpDefault
{mso-style-type:export-only;
mso-default-props:yes;
font-size:10.0pt;
mso-ansi-font-size:10.0pt;
mso-bidi-font-size:10.0pt;
mso-ascii-font-family:”Times New Roman”;
mso-hansi-font-family:”Times New Roman”;
mso-font-kerning:0pt;}
/* Page Definitions */
@page
{mso-page-border-surround-header:no;
mso-page-border-surround-footer:no;
mso-footnote-separator:url(“数据流容错机制.files/header.htm”) fs;
mso-footnote-continuation-separator:url(“数据流容错机制.files/header.htm”) fcs;
mso-endnote-separator:url(“数据流容错机制.files/header.htm”) es;
mso-endnote-continuation-separator:url(“数据流容错机制.files/header.htm”) ecs;}
@page WordSection1
{size:595.3pt 841.9pt;
margin:72.0pt 90.0pt 72.0pt 90.0pt;
mso-header-margin:42.55pt;
mso-footer-margin:49.6pt;
mso-paper-source:0;}
div.WordSection1
{page:WordSection1;}
/* List Definitions */
@list l0
{mso-list-id:232471696;
mso-list-template-ids:1028537260;}
@list l1
{mso-list-id:954825970;
mso-list-template-ids:1224644986;}
@list l2
{mso-list-id:1005788181;
mso-list-template-ids:-103259158;}
@list l3
{mso-list-id:1051997984;
mso-list-template-ids:-355565624;}
@list l4
{mso-list-id:1108693587;
mso-list-template-ids:98456540;}
@list l5
{mso-list-id:1154296080;
mso-list-template-ids:653804648;}
@list l5:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level2
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:72.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level3
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:108.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level4
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:144.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level5
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:180.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level6
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:216.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level7
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:252.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level8
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:288.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l5:level9
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:324.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l6
{mso-list-id:1246188709;
mso-list-template-ids:-82130282;}
@list l7
{mso-list-id:1336305802;
mso-list-template-ids:-1641877954;}
@list l8
{mso-list-id:1368793531;
mso-list-template-ids:1610938582;}
@list l9
{mso-list-id:1371295367;
mso-list-template-ids:-851019786;}
@list l10
{mso-list-id:1413820100;
mso-list-template-ids:-1949821018;}
@list l10:level1
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:36.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level2
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:72.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level3
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:108.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level4
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:144.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level5
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:180.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level6
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:216.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level7
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:252.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level8
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:288.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l10:level9
{mso-level-number-format:bullet;
mso-level-text:;
mso-level-tab-stop:324.0pt;
mso-level-number-position:left;
text-indent:-18.0pt;
mso-ansi-font-size:10.0pt;
font-family:Symbol;}
@list l11
{mso-list-id:1463577150;
mso-list-template-ids:1383221570;}
@list l12
{mso-list-id:1611011600;
mso-list-template-ids:445140192;}
@list l13
{mso-list-id:1653951458;
mso-list-template-ids:-789653608;}
@list l14
{mso-list-id:1670719355;
mso-list-template-ids:-901508264;}
@list l4:level1 lfo10
{mso-level-start-at:4;}
ol
{margin-bottom:0cm;}
ul
{margin-bottom:0cm;}
–>

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,493
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,907
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,740
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,495
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,133
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,297