├── .gitignore ├── README.md ├── codestyle_guide.md └── config.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | test_* 3 | __pycache__ 4 | *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # codestyle-guide 2 | java 代码风格指导文档及相关工具 3 | 4 | 5 | ## 文件结构 6 | - `codestyle_guide.md` 代码风格指导文档 7 | - `config.xml` 对应文档的checkstyle配置文件 8 | - `README.md` 项目指南 9 | 10 | 11 | ## 更新日志 12 | - 2019/02/13 更新v1.0版本文档和v1.0版本的配置文件 13 | - 2019/02/14 基本完善项目版本,并完成配置文件的简单验证 14 | - 2019/02/25 修复常量命名的问题,改为建议规则。由于没有对应的常量检查规则,所以checkstyle检查到连续的大写字母命名时会报错,请大家以`config.xml`中实际配置为准。(这里感谢17373348刘宸同学) 15 | 16 | ## 分数计算方式 17 | 18 | - 每次作业代码风格部分默认总分为100分,采用扣分制 19 | - 对于设计风格类(即风格文档的第六节)部分 20 | - 类长度风格问题,**每个扣50分** 21 | - 可见性检查、方法长度问题,**每个扣20分** 22 | - 参数个数、循环嵌套、语句嵌套问题,**每个扣10分** 23 | - 嵌套内联条件、布尔表达式、参数赋值问题,**每个扣5分** 24 | - 对于命名约定类(即风格文档第五章)部分 25 | - 所有的问题,**每个扣5分** 26 | - 对于除此之外的问题,**每个扣2分** 27 | - **对于所有的问题扣分上不封顶,扣到0分为止** 28 | 29 | ## 常见问题 30 | 31 | ### Q:作业中会如何检查代码风格? 32 | 33 | A:我们会使用一个叫做`checkstyle`的Java代码风格检查工具进行代码风格的检查。其中配置文件使用本仓库内提供的`config.xml`文件,作为代码风格检查的依据。 34 | 35 | 值得注意的是,我们的检查对象为你的代码仓库内全部的`.java`文件,其他的文件会被系统自动忽略。 36 | 37 | ### Q:我们本地是否可以检查代码风格? 38 | 39 | A:当然可以。你们有以下几种方法检测自己的代码风格: 40 | 41 | * 从Checkstyle官网上下载checkstyle的jar文件,并在本机按照help里提供的命令行参数进行代码风格的检查。 42 | * 对于ubuntu(应该其他unix系统也行,但是只在ubuntu上试过)用户,可以使用我们封装的`pycheckstyle`Python包进行快速代码风格检测(目前仅支持Python3) 43 | 44 | * 【推荐】**对于IDEA用户,可以下载安装`Checkstyle-IDEA`插件(见下文),对ide内的代码进行实时风格检测。只需要安装好插件后在设置中将我们提供的`config.xml`载入即可。**(更详细的攻略可以自行百度) 45 | * 对于Eclipse用户,实际上也存在checkstyle支持,可以自行百度探索。 46 | 47 | ### Q:代码风格文档内是否会和配置文件等存在冲突?如果存在,如何处理? 48 | 49 | A:我们的文档主要是将官方文档中相关的部分进行一些较为通俗的解释,可能有些细节上确实不够,也有可能存在少量的偏差。对于这样的情况,我们以checkstyle的官方文档,以及`checkstyle`在使用`config.xml`时的实际检查结果为准。 50 | 51 | ### Q:我们如何去查看官方文档的对应规则? 52 | 53 | A:在我们提供的风格文档中,均将配置文件中的对应部分写了出来。可以根据`module`的`name`字段信息,在官方文档上查找对应的规则以及说明。 54 | 55 | ## 一些有用的资料 56 | 57 | * [Checkstyle官方文档(全英文版)](http://checkstyle.sourceforge.net/checks.html) 58 | * [Google官方代码规范(我们所使用的代码规范的原型)](https://google.github.io/styleguide/javaguide.html) 59 | * [Sun官方代码规范](http://java.sun.com/docs/books/jls/second_edition/html/index.html) 60 | * [【推荐】IDEA Checkstyle插件主页](http://plugins.jetbrains.com/plugin/1065-checkstyle-idea) 61 | * [【课程组提供】pycheckstyle封装包](https://github.com/OO-guide-2019/pycheckstyle) 62 | 63 | 64 | ## 关于作者 65 | * [PaParaZz1] 66 | * [HansBug](mailto:hansbug@questionor.cn),邮箱:hansbug@questionor.cn 67 | 68 | 如有问题或建议,欢迎联系作者。 69 | -------------------------------------------------------------------------------- /codestyle_guide.md: -------------------------------------------------------------------------------- 1 | # java codestyle guide(simplified version) 2 | 3 | ## 1 术语说明 4 | 5 | P.S.:本指南中带有“(建议)”标志的部分是作者对于某个问题的建议,不一定严格按照给出示例,只是建议的方式,满足要求的方式都可以。 6 | 7 | P.P.S.:在每条代码风格规则中我们会标注`config.xml`文件中对应的部分,一般紧跟着某个小标题之后。 8 | 9 | ### 1.1 块状结构 10 | 11 | 块状结构(block-like construct)指的是一个类,方法或构造函数的主体。 12 | 13 | ### 1.2 自动换行 14 | 15 | 一般情况下,一行长代码为了避免超出单行字符限制(80个字符)而被分为多行,我们称之为自动换行(line-wrapping)。 16 | 17 | ------ 18 | 19 | ## 2 源文件基础 20 | 21 | ### 2.1 文件名 22 | 23 | ```xml 24 | 25 | ``` 26 | 27 | 源文件使用其最顶层的类名来命名(一般一个文件只包含一个类),大小写敏感,文件扩展名为`.java` 28 | 29 | ### 2.2 文件编码格式 30 | 31 | ```xml 32 | 33 | ``` 34 | 35 | 源文件编码格式为UTF-8 36 | 37 | ### 2.3 特殊字符 38 | 39 | #### 2.3.1 ASCII字符 40 | 41 | 所有源代码中一律使用ASCII字符,如无特殊注明,使用的非ASCII字符无效(即尽量不要使用中文注释,学着开始使用英文注释)。 42 | 43 | #### 2.3.2 空白字符 44 | 45 | ```xml 46 | 47 | 48 | 49 | ``` 50 | 51 | 除了行结束符序列(换行),ASCII水平空格字符(0x20,即空格)是源代码中唯一允许出现的空白字符,这意味着 52 | 53 | - 制表符'\t'不用于缩进(源代码不能出现任何一个'\t') 54 | - 所有其他字符串中的空白字符都要进行转义 55 | 56 | 注:一般的缩进单位采取**4个空格** 57 | 58 | ------ 59 | 60 | ## 3 源文件结构 61 | 62 | 一个源文件结构应该如下 63 | 64 | 1. package语句。 65 | 2. import语句 66 | 3. 一个顶级类 67 | 68 | ### 3.1 package语句 69 | 70 | ```xml 71 | 72 | ``` 73 | 74 | 该语句独立一行。 75 | 76 | ### 3.2 import语句 77 | 78 | #### 3.2.1 import不要通配符 79 | 80 | ```xml 81 | 82 | ``` 83 | 84 | import中应该准确指明需要引入的模块,不要使用通配符(例如:`import java.util.*;`) 85 | 86 | #### 3.2.2 单独成行 87 | 88 | ```xml 89 | 90 | ``` 91 | 92 | 每个import语句单独成行。 93 | 94 | #### 3.2.3 无用的import 95 | 96 | ```xml 97 | 98 | ``` 99 | 100 | 禁止出现没有使用的import 101 | 102 | ### 3.3 类声明 103 | 104 | #### 3.3.1 只有一个顶级类 105 | 106 | ```xml 107 | 108 | ``` 109 | 110 | 每个源文件中顶级类声明有且只有一个,在一个与其同名的源文件中(即类ObjectOriented一定在ObjectOriented.java文件中) 111 | 112 | #### 3.3.2 类函数/方法顺序 113 | 114 | ```xml 115 | 116 | ``` 117 | 118 | 关于类中方法的顺序,建议选择**除时间顺序外一种有逻辑的顺序**。但要求**重载的方法必须不能分离**,即当一个类有多个构造函数,或者多个重载了的同名方法,这些函数/方法应该出现在一起,中间不许有其他函数/方法。 119 | 120 | ------ 121 | 122 | ## 4 格式 123 | 124 | ### 4.1 大括号 125 | 126 | #### 4.1.1 必须使用大括号 127 | 128 | ```xml 129 | 130 | ``` 131 | 132 | 大括号`{}`和`if, else, for, do, while,case,default`等语句一起使用,即使其中只有一条语句或是空语句,也必须写上大括号 133 | 134 | #### 4.1.2 空块使用简洁写法 135 | 136 | ```xml 137 | 138 | 139 | 141 | 142 | ``` 143 | 144 | 一个空的块状结构中没有语句,所以大括号要写成`{}`,不需要换行。但如果他是一个多块语句的一部分(if/else 或 try/catch/finally) ,即使大括号内没内容,右大括号也要换行。 145 | 146 | ```java 147 | void emptyBlock() {} 148 | 149 | if (x == 1) { 150 | 151 | } else if (x == 2) { 152 | 153 | } else { 154 | 155 | } 156 | ``` 157 | 158 | ### 4.2 缩进 159 | 160 | ```xml 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | ``` 170 | 171 | 每当开始一个新的块,缩进增加**4个空格**,当块结束时,缩进返回先前的缩进级别。该缩进级别适用于代码和注释 172 | 173 | ```java 174 | for (int i = 0; i < 10; ++i) { 175 | // when condition satisfied 176 | if (i > 5) { 177 | try { 178 | // func for deal with correct state 179 | something(); 180 | } catch (Exception e) { 181 | recover(); 182 | } 183 | } 184 | } 185 | ``` 186 | 187 | ### 4.3 一行一个语句 188 | 189 | ```xml 190 | 191 | ``` 192 | 193 | 每个语句之后必须换行 194 | 195 | ### 4.4 单行字符个数限制 196 | 197 | ```xml 198 | 199 | 200 | 202 | 203 | ``` 204 | 205 | 源代码中除了下述例外情况,单行必须满足**80**个字符的限制。如果某一行超过这个限制,必须自动换行。 206 | 207 | 例外: 208 | 209 | - 不可能满足列限制的行(如长URL) 210 | - packge和import语句 211 | - 注释中那些需要被复制粘贴到shell中使用的命令 212 | 213 | ### 4.5 自动换行准则(建议) 214 | 215 | 对于超出限制的行进行自动换行的方法有很多,在这里作者给出一些建议性的准则: 216 | 217 | 1. **合理**缩短命名长度(如image用img代替) 218 | 219 | 2. 在语句中提取方法或局部变量,从而使该行代码变短 220 | 221 | 3. 断开原则,此处的准则是更倾向于在更高的语法级别处断开 222 | 223 | - 如果在**非赋值运算符**处断开,那么在该符号前断开 224 | 225 | ```java 226 | variableNaive = (factorC + factorCpp + factorPython 227 | + factorRuby + factorJava) / 2 228 | ``` 229 | 230 | - 如果在**赋值运算符**处断开,那么在该符号后断开 231 | 232 | ```java 233 | handleNaive.arrayUint32Complicated[i * 10 + j] = 234 | (meanFirst + meanSecond + meanThird + meanFourth) 235 | ``` 236 | 237 | - 方法名或构造函数名与左括号留在同一行 238 | 239 | - 逗号`,`和其前面的内容留在同一行 240 | 241 | 4. 自动换行时,第一行后面的行**至少**比第一行多缩进**4个空格** 242 | 243 | ### 4.6 空白 244 | 245 | #### 4.6.1 垂直空白(空行) 246 | 247 | ```xml 248 | 249 | 250 | 251 | 252 | ``` 253 | 254 | 以下情况需要使用**一个空行**: 255 | 256 | 1. 类内连续的成员之间:字段,构造函数,方法,嵌套类,静态初始化块,实例初始化块。 257 | - **例外**:两个连续字段之间的空行是可选的,用于字段的空行主要用来对字段进行逻辑分组。 258 | 2. 在函数体内,语句的逻辑分组间使用空行。 259 | 3. 要满足本文档中其他节的空行要求。 260 | 4. 不允许连续多个空行 261 | 262 | #### 4.6.2 水平空白 263 | 264 | ```xml 265 | 266 | 268 | 270 | 272 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 283 | 284 | 285 | ``` 286 | 287 | 除了语言需求和其它规则,并且除了文字,注释和Javadoc用到单个空格,单个ASCII空格也出现在以下几个地方: 288 | 289 | 1. 分隔任何保留字与紧随其后的左括号`(`(如`if, for catch`等)。 290 | 2. 分隔任何保留字与其前面的右大括号`}`(如`else, catch`)。 291 | 3. 在任何左大括号`{`前,但有两种例外: 292 | - `@SomeAnnotation({a, b}) 包含关系的大括号不用空格。 293 | - `String[][] x = foo; ` 两个大括号间不用空格 294 | 4. 在任何二元或三元运算符的两侧。这也适用于以下“类运算符”符号: 295 | - 类型界限中的&(``)。 296 | - catch块中的管道符号(`catch (FooException | BarException e`)。 297 | - `foreach`语句中的分号。 298 | 5. 在`, : ;`及右括号(`)`)后 299 | 6. 如果在一条语句后做注释,则双斜杠(//)两边都要空格。 300 | 7. 类型和变量之间:List list。 301 | 302 | ### 4.7 用小括号来限定组,即显式地限定运算顺序(建议) 303 | 304 | 我们没有理由假设reviewer能够记住整个java运算符优先级表,所以要**适当地使用小括号**来显式的标出运算顺序。 305 | 306 | ### 4.8 具体结构 307 | 308 | #### 4.8.1 变量声明 309 | 310 | ```xml 311 | 312 | 313 | 314 | ``` 315 | 316 | - 每次只声明一个变量,不要使用组合声明 317 | 318 | ```java 319 | int a; // correct 320 | int a, b; // wrong 321 | ``` 322 | 323 | - 需要时才声明,并尽快进行初始化。 324 | 325 | 不要在代码块的开头一次性声明所有要用到的局部变量,而是在第一次需要使用它时才声明,并且在声明之后尽快进行初始化。 326 | 327 | - 数组声明风格 328 | 329 | 要把中括号看作类型的一部分,即 330 | 331 | ```java 332 | String[] args; // correct 333 | String args[]; // wrong 334 | ``` 335 | 336 | #### 4.8.2 switch语句 337 | 338 | ```xml 339 | 340 | 341 | ``` 342 | 343 | - 每个switch必须都要包含一个`default`语句组,即使里面什么代码也没有(对枚举类型使用switch时除外) 344 | 345 | - 在一个swtich块内,每个语句组要么通过`break, return`或抛出异常来终止,要么通过注释`// fall through`来表示继续执行到下一个语句组,这个注释不需要在`default`语句组中出现 346 | 347 | ```java 348 | switch (variable) { 349 | case 1: 350 | func1(); 351 | // fall through 352 | case 2: 353 | func2(); 354 | break; 355 | default: 356 | } 357 | ``` 358 | 359 | #### 4.8.3 注解(Annotations) 360 | 361 | ```xml 362 | 363 | 364 | 366 | 367 | ``` 368 | 369 | 注解紧跟在文档部分后面,一个注解独占一行,后续的缩进等级不变。 370 | 371 | ```java 372 | @Override 373 | public int naiveMethod() { 374 | // something 375 | } 376 | ``` 377 | 378 | ### 4.9 Modifiers 379 | 380 | ```xml 381 | 382 | ``` 383 | 384 | 类或成员的Modifiers如果存在,则需要按照如下规范顺序出现: 385 | 386 | ```java 387 | public protected private abstract static final transient volatile synchronized native strictfp 388 | ``` 389 | 390 | ### 4.10 注释 391 | 392 | ```xml 393 | 394 | ``` 395 | 396 | 块注释与其周围的代码在同一缩进级别。它们可以是`/* ... */`风格,也可以是`// ...`风格。对于多行的`/* ... */`注释,后续行必须从`*`开始, 并且与前一行的`*`对齐。以下三种示例注释都是OK的。 397 | 398 | ```java 399 | /* 400 | * This is 401 | * okay. 402 | */ 403 | 404 | // And so 405 | // is this 406 | 407 | /* Or you can 408 | * even do this. */ 409 | ``` 410 | 411 | ### 4.11 long型变量规范 412 | 413 | ```xml 414 | 415 | ``` 416 | 417 | long型整型变量的后缀必须使用`L`左右后缀,例如: 418 | 419 | ```java 420 | 10000000000000L 421 | ``` 422 | 423 | ------ 424 | 425 | ## 5 命名约定 426 | 427 | ### 5.1 标识符通用规则 428 | 429 | 标识符只能使用ASCII字母和数字,即标识符必须匹配正则表达式`\w+` 430 | 431 | ### 5.2 标识符类型规则 432 | 433 | #### 5.2.1 包名 434 | 435 | ```xml 436 | 437 | ``` 438 | 439 | 包名全部小写,连续的单词只是简单地连接起来,不使用下划线 440 | 441 | #### 5.2.2 类名 442 | 443 | ```xml 444 | 445 | 447 | 448 | ``` 449 | 450 | 类名使用大驼峰式命名法 451 | 452 | 测试类的命名以他要测试的类的名称开始,以`Test`结束,例如`Elevator`对应`ElevatorTest` 453 | 454 | 接口的命名以具体命名内容开始,以`Interface`结束,例如`ApplicationInterface` 455 | 456 | #### 5.2.3 方法名 457 | 458 | ```xml 459 | 460 | 461 | 463 | 464 | ``` 465 | 466 | 方法名使用小驼峰式命名法 467 | 468 | 方法名通常是动词或者动词短语 469 | 470 | #### 5.2.4 常量名(建议) 471 | 472 | 常量命名模式为`CONSTANT_NAME`,即全部字母大写,然后用下划线分割单词 473 | 474 | 常量名通常是名词或者名词短语 475 | 476 | #### 5.2.5 变量名(包括参数名) 477 | 478 | ```xml 479 | 480 | 481 | 483 | 484 | 485 | 486 | 488 | 489 | 490 | 491 | 493 | 494 | 495 | 496 | 497 | 499 | 500 | ``` 501 | 502 | 变量名使用小驼峰式命名法 503 | 504 | 除了临时变量和循环变量,避免使用单字符进行命名。 505 | 506 | #### 5.2.6 类型变量名 507 | 508 | ```xml 509 | 510 | 511 | 513 | 514 | 515 | 516 | 518 | 519 | 520 | 521 | 523 | 524 | ``` 525 | 526 | 类型变量使用单个的大写字母命名(如T, E, V),例如: 527 | 528 | ```java 529 | MyArrayList 530 | ``` 531 | 532 | ### 5.3 驼峰式命名法 533 | 534 | ```xml 535 | 536 | 537 | 538 | 539 | ``` 540 | 541 | 驼峰式命名法分为大驼峰式命名法`UpperCamelCase` 和小驼峰式命名法`lowerCamelCase`。有时命名会遇到缩略语或不寻常的结构(例如”IPv6”或”iOS”)。有以下的转换方案。 542 | 543 | 名字从`散文形式`(prose form)开始: 544 | 545 | 1. 把短语转换为纯ASCII码,并且移除任何单引号。例如:”Müller’s algorithm”将变成”Muellers algorithm”。 546 | 2. 把这个结果切分成单词,在空格或其它标点符号(通常是连字符)处分割开。 547 | - 推荐:如果某个单词已经有了常用的驼峰表示形式,按它的组成将它分割开(如”AdWords”将分割成”ad words”)。 需要注意的是”iOS”并不是一个真正的驼峰表示形式,因此该推荐对它并不适用。 548 | 3. 现在将所有字母都小写(包括缩写),然后将单词的第一个字母大写: 549 | - 每个单词的第一个字母都大写,来得到大驼峰式命名。 550 | - 除了第一个单词,每个单词的第一个字母都大写,来得到小驼峰式命名。 551 | 4. 最后将所有的单词连接起来得到一个标识符。 552 | 553 | 示例: 554 | 555 | ```java 556 | Prose form Correct Incorrect 557 | ------------------------------------------------------------------ 558 | "XML HTTP request" XmlHttpRequest XMLHTTPRequest 559 | "new customer ID" newCustomerId newCustomerID 560 | "inner stopwatch" innerStopwatch innerStopWatch 561 | "supports IPv6 on iOS?" supportsIpv6OnIos supportsIPv6OnIOS 562 | "YouTube importer" YouTubeImporter 563 | ``` 564 | 565 | ------ 566 | 567 | ## 6 设计规范 568 | 569 | ### 6.1 类长度 570 | 571 | ```xml 572 | 573 | 574 | 575 | ``` 576 | 577 | 一个顶级类(即一个文件)最多有500行。 578 | 579 | ### 6.2 方法长度 580 | 581 | ```xml 582 | 583 | 584 | 585 | 586 | 587 | ``` 588 | 589 | 一个方法总长度不得超过60行(不包括其中的空行)。 590 | 591 | ### 6.3 参数个数 592 | 593 | ```xml 594 | 595 | 596 | 597 | 598 | ``` 599 | 600 | 一个方法或者构造函数的参数数目不得超过8个。 601 | 602 | ### 6.4 类成员变量的可见性检查 603 | 604 | ```xml 605 | 606 | ``` 607 | 608 | 严格检查类成员变量的可见性。只有被static final修饰的不可变对象,或是被可以是特殊注解修饰的对象才可以为public,其他一律为private 609 | 610 | ### 6.5 布尔表达式复杂度 611 | 612 | ```xml 613 | 614 | 615 | 616 | ``` 617 | 618 | 禁止使用过于复杂的布尔表达式,会造成reviewer者阅读困难和更高的debug难度,最大的布尔表达式中运算符个数是6。 619 | 620 | ### 6.6 禁止嵌套内联条件语句(inline conditions) 621 | 622 | ```xml 623 | 624 | ``` 625 | 626 | 例如: 627 | 628 | ```java 629 | String a = "oo"; 630 | String b = (a==null || a.length<1) ? null : a.substring(1); 631 | ``` 632 | 633 | 简单来说,对于三目运算符,禁止任何嵌套。如果有类似的逻辑写成显示的if-else语句。 634 | 635 | ### 6.7 禁止对参数的赋值 636 | 637 | ```xml 638 | 639 | ``` 640 | 641 | 禁止对方法中参数的赋值操作。 642 | 643 | ### 6.8 循环嵌套重数限制 644 | 645 | ```xml 646 | 647 | 648 | 649 | ``` 650 | 651 | 对于各类循环语句,限制最大嵌套重数为4。 652 | 653 | ### 6.9 条件语句嵌套重数限制 654 | 655 | ```xml 656 | 657 | 658 | 659 | ``` 660 | 661 | 对于if-else语句,限制最大嵌套重数为4。 662 | 663 | ------ 664 | 665 | ## 7 编程实践 666 | 667 | ### 7.1 @Override的使用 668 | 669 | 只要合理,就尽可能地使用`@Override`注解,表明是重写 670 | 671 | ### 7.2 对于类的静态成员和方法,使用类名进行调用 672 | 673 | 对于类的静态成员和方法,使用类名进行调用,而不是使用对象名或表达式 674 | 675 | ```java 676 | NaiveClass handle_simple = new NaiveClass(); 677 | NaiveClass.staticMethod(); // corrrect 678 | handle_simple.staticMethod(); // wrong 679 | returnNaiveClassObjectMethod().staticMethod(); // wrong 680 | ``` 681 | 682 | ### 7.3 对于捕获的异常不能忽视 683 | 684 | ```xml 685 | 686 | 687 | 688 | ``` 689 | 690 | 对于捕获到的异常,不能ignore,必须进行相应处理,即不允许出现空的catch块,常见的做法有打印日志,或者是再抛出一个`AssertionError` 691 | 692 | ------ 693 | 694 | 本指南是基于主流java代码风格指南的简化版,我们基于实际需要进行了一些修改,如有任何建议和问题请联系作者。 695 | 696 | email: **niuyazhe@buaa.edu.cn、hansbug@questionor.cn** 697 | 698 | github repo: https://github.com/OO-guide-2019/codestyle-guide 699 | -------------------------------------------------------------------------------- /config.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 53 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 72 | 73 | 74 | 76 | 77 | 78 | 79 | 81 | 82 | 83 | 84 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 97 | 98 | 99 | 100 | 102 | 103 | 104 | 105 | 107 | 108 | 109 | 110 | 112 | 113 | 114 | 116 | 118 | 120 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 141 | 142 | 143 | 144 | 145 | 146 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | --------------------------------------------------------------------------------