[Mlir-commits] [clang] [clang-tools-extra] [compiler-rt] [flang] [libclc] [lld] [llvm] [mlir] [openmp] [polly] 同步 (PR #102810)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Sun Aug 11 04:48:03 PDT 2024
https://github.com/cratelschen created https://github.com/llvm/llvm-project/pull/102810
None
>From f3f998dfa78a87a0c895a9dab8cacf479a7a34d2 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Fri, 14 Jun 2024 22:15:26 +0800
Subject: [PATCH 01/21] add comments, time=2024-06-14 22:15:26
---
llvm/CMakeLists.txt | 79 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 75 insertions(+), 4 deletions(-)
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 3208147101c0d7..e0388db032e789 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -1,22 +1,36 @@
# See docs/CMake.html for instructions about how to build LLVM with CMake.
+# 设置当前工程要求的最低 cmake 版本
cmake_minimum_required(VERSION 3.20.0)
+# 设置变量LLVM_COMMON_CMAKE_UTILS,存储.cmake配置文件所在的路径
+# CMAKE_CURRENT_SOURCE_DIR:当前正在处理的源文件所在位置。
+# 这条命令向上找到项目顶层的cmake文件夹。cmake文件夹中一般定义了多个用于复用的cmake宏或者方法。
set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
+message(WARNING "找到项目最外层的cmake路径为===="${LLVM_COMMON_CMAKE_UTILS})
+
+# 将.cmake文件导入到当前文件
+# 可以将重复性的 cmake 语句书写在 cmake 后缀的文件中,在使用的位置通过 include 来引入,避免重复 cmake 代码
include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake
NO_POLICY_SCOPE)
# Builds with custom install names and installation rpath setups may not work
# in the build tree. Allow these cases to use CMake's default build tree
# behavior by setting `LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE` to do this.
+# 设置 option。在后续的 cmake 文件中可能根据 option 的不同值来控制构建过程
+# option 的值可以由用户输入
option(LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE "If set, use CMake's default build tree install name directory logic (Darwin only)" OFF)
+# 将当前 option 置为高级选项,只在 cmake GUI中的高级选项中展示
mark_as_advanced(LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE)
+
if(NOT LLVM_NO_INSTALL_NAME_DIR_FOR_BUILD_TREE)
set(CMAKE_BUILD_WITH_INSTALL_NAME_DIR ON)
endif()
+# 导入LLVM的版本设置cmake文件,引入一些变量供后续使用
include(${LLVM_COMMON_CMAKE_UTILS}/Modules/LLVMVersion.cmake)
+# 设置属性值
set_directory_properties(PROPERTIES LLVM_VERSION_MAJOR "${LLVM_VERSION_MAJOR}")
if (NOT PACKAGE_VERSION)
@@ -29,6 +43,12 @@ if(NOT DEFINED LLVM_SHLIB_SYMBOL_VERSION)
set(LLVM_SHLIB_SYMBOL_VERSION "LLVM_${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}")
endif()
+# 根据cmake的构建工具来做不同的逻辑处理
+# 常见的构建工具有四个:
+# Ninja — for generating Ninja build files. Most llvm developers use Ninja.
+# Unix Makefiles — for generating make-compatible parallel makefiles.
+# Visual Studio — for generating Visual Studio projects and solutions.
+# Xcode — for generating Xcode projects.
if ((CMAKE_GENERATOR MATCHES "Visual Studio") AND (MSVC_TOOLSET_VERSION LESS 142) AND (CMAKE_GENERATOR_TOOLSET STREQUAL ""))
message(WARNING "Visual Studio generators use the x86 host compiler by "
"default, even for 64-bit targets. This can result in linker "
@@ -42,24 +62,32 @@ if (CMAKE_GENERATOR STREQUAL "Xcode" AND NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES "x86_64")
endif()
+# 设置当前工程的工程名,版本信息以及实现语言
project(LLVM
VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}
LANGUAGES C CXX ASM)
+ # CMAKE_INSTALL_LIBDIRinstall的路径
if (NOT DEFINED CMAKE_INSTALL_LIBDIR AND DEFINED LLVM_LIBDIR_SUFFIX)
# Must go before `include(GNUInstallDirs)`.
set(CMAKE_INSTALL_LIBDIR "lib${LLVM_LIBDIR_SUFFIX}")
endif()
+# 设置环境变量,注意 cache 指定该值应该缓存使用
# Must go after `DEFINED LLVM_LIBDIR_SUFFIX` check.
set(LLVM_LIBDIR_SUFFIX "" CACHE STRING "Define suffix of library directory name (32/64)" )
+# cmake 官方功能导入
# Must go after `project(..)`.
include(GNUInstallDirs)
+# 设置工程使用语言的 C++标准
# This C++ standard is required to build LLVM.
set(LLVM_REQUIRED_CXX_STANDARD 17)
+# 如果缓存的语言版本小于当前最新的设置,对其值进行更新。
+# 所以cmake的cache是不是采用一种懒加载的方式?即一旦cache之后就不会主动更新,除非手动去更新,或者删除build目录再次触发configuration
+# 修改缓存变量时,一定要加FORCE选项,否则修改无效
# If we find that the cache contains CMAKE_CXX_STANDARD it means that it's a old CMakeCache.txt
# and we can just inform the user and then reset it.
if($CACHE{CMAKE_CXX_STANDARD} AND $CACHE{CMAKE_CXX_STANDARD} LESS ${LLVM_REQUIRED_CXX_STANDARD})
@@ -84,6 +112,8 @@ else()
set(CMAKE_CXX_EXTENSIONS NO)
endif()
+# build类型选择,在 configure 阶段必须从中选择一种,因为这里没有默认值且是fatal error
+# 根据项目的不同阶段来选择build类型
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(FATAL_ERROR "
No build type selected. You need to pass -DCMAKE_BUILD_TYPE=<type> in order to configure LLVM.
@@ -114,29 +144,43 @@ endif()
# LLVM_EXTERNAL_${project}_SOURCE_DIR using LLVM_ALL_PROJECTS
# This allows an easy way of setting up a build directory for llvm and another
# one for llvm+clang+... using the same sources.
+# 将LLVM支持的子项目都列出来
set(LLVM_ALL_PROJECTS "bolt;clang;clang-tools-extra;compiler-rt;cross-project-tests;libc;libclc;lld;lldb;mlir;openmp;polly;pstl")
+
+# flang项目暂未列入all中,先单独处理
# The flang project is not yet part of "all" projects (see C++ requirements)
set(LLVM_EXTRA_PROJECTS "flang")
+
+# 所有已知的项目列表
# List of all known projects in the mono repo
set(LLVM_KNOWN_PROJECTS "${LLVM_ALL_PROJECTS};${LLVM_EXTRA_PROJECTS}")
+
+# 预先设置LLVM_ENABLE_PROJECTS为空,注意其格式,多个项目之间使用分号隔开
set(LLVM_ENABLE_PROJECTS "" CACHE STRING
"Semicolon-separated list of projects to build (${LLVM_KNOWN_PROJECTS}), or \"all\".")
+
+# 如果LLVM_ENABLE_PROJECTS的值为all,将上面的LLVM_ALL_PROJECTS的值直接给LLVM_ENABLE_PROJECTS
# Make sure expansion happens first to not handle "all" in rest of the checks.
if( LLVM_ENABLE_PROJECTS STREQUAL "all" )
set( LLVM_ENABLE_PROJECTS ${LLVM_ALL_PROJECTS})
endif()
+
foreach(proj ${LLVM_ENABLE_PROJECTS})
+ message(WARNING "子项目名称===="${proj})
+ # 如果proj的值既不是llvm有不属于LLVM_KNOWN_PROJECTS中的任意一个,直接报错退出
if (NOT proj STREQUAL "llvm" AND NOT "${proj}" IN_LIST LLVM_KNOWN_PROJECTS)
MESSAGE(FATAL_ERROR "${proj} isn't a known project: ${LLVM_KNOWN_PROJECTS}. Did you mean to enable it as a runtime in LLVM_ENABLE_RUNTIMES?")
endif()
endforeach()
+# 判断flang是否在LLVM_ENABLE_PROJECTS中
if ("flang" IN_LIST LLVM_ENABLE_PROJECTS)
+ # 如果flang在而mlir不在列表里面,主动将nlir追加到列表内
if (NOT "mlir" IN_LIST LLVM_ENABLE_PROJECTS)
message(STATUS "Enabling MLIR as a dependency to flang")
list(APPEND LLVM_ENABLE_PROJECTS "mlir")
endif()
-
+ # 如果flang在而clang不在列表里面,直接报错
if (NOT "clang" IN_LIST LLVM_ENABLE_PROJECTS)
message(FATAL_ERROR "Clang is not enabled, but is required for the Flang driver")
endif()
@@ -146,6 +190,8 @@ endif()
#
# As we migrate runtimes to using the bootstrapping build, the set of default runtimes
# should grow as we remove those runtimes from LLVM_ENABLE_PROJECTS above.
+# 设置LLVM的运行时库
+# 运行时库是指C/C++标准库的实现。
set(LLVM_DEFAULT_RUNTIMES "libcxx;libcxxabi;libunwind")
set(LLVM_SUPPORTED_RUNTIMES "libc;libunwind;libcxxabi;pstl;libcxx;compiler-rt;openmp;llvm-libgcc;offload")
set(LLVM_ENABLE_RUNTIMES "" CACHE STRING
@@ -153,12 +199,15 @@ set(LLVM_ENABLE_RUNTIMES "" CACHE STRING
if(LLVM_ENABLE_RUNTIMES STREQUAL "all")
set(LLVM_ENABLE_RUNTIMES ${LLVM_DEFAULT_RUNTIMES})
endif()
+
+# 有点懒,这里临时变量竟然直接使用名字proj,最好是用runtime
foreach(proj IN LISTS LLVM_ENABLE_RUNTIMES)
if (NOT "${proj}" IN_LIST LLVM_SUPPORTED_RUNTIMES)
message(FATAL_ERROR "Runtime \"${proj}\" is not a supported runtime. Supported runtimes are: ${LLVM_SUPPORTED_RUNTIMES}")
endif()
endforeach()
+# 是否使用GPU加速,暂不深入。
# Set a shorthand option to enable the GPU build of the 'libc' project.
option(LIBC_GPU_BUILD "Enable the 'libc' project targeting the GPU" OFF)
if(LIBC_GPU_BUILD)
@@ -198,6 +247,9 @@ if(NEED_LIBC_HDRGEN)
endif()
unset(NEED_LIBC_HDRGEN)
+# LLVM_ENABLE_PROJECTS_USED在这里就已经有值为ON,后面将其设置为OFF的set且没有FORCE不知道意欲何为,可能只是一个定义
+message(WARNING "LLVM_ENABLE_PROJECTS_USED的值为===="${LLVM_ENABLE_PROJECTS_USED})
+
# LLVM_ENABLE_PROJECTS_USED is `ON` if the user has ever used the
# `LLVM_ENABLE_PROJECTS` CMake cache variable. This exists for
# several reasons:
@@ -218,20 +270,30 @@ mark_as_advanced(LLVM_ENABLE_PROJECTS_USED)
if (LLVM_ENABLE_PROJECTS_USED OR NOT LLVM_ENABLE_PROJECTS STREQUAL "")
set(LLVM_ENABLE_PROJECTS_USED ON CACHE BOOL "" FORCE)
foreach(proj ${LLVM_KNOWN_PROJECTS} ${LLVM_EXTERNAL_PROJECTS})
+ # 将proj转为大写
string(TOUPPER "${proj}" upper_proj)
+ message(WARNING "子项目名大写===="${upper_proj})
string(REGEX REPLACE "-" "_" upper_proj ${upper_proj})
+ message(WARNING "大写子项目名替换-为_后===="${upper_proj})
if ("${proj}" IN_LIST LLVM_ENABLE_PROJECTS)
message(STATUS "${proj} project is enabled")
set(SHOULD_ENABLE_PROJECT TRUE)
+
+ # 设置子工程的路径
set(PROJ_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")
+ message(WARNING "子工程路径===="${PROJ_DIR})
+
+ # 找不到路径指向的文件夹
if(NOT EXISTS "${PROJ_DIR}" OR NOT IS_DIRECTORY "${PROJ_DIR}")
message(FATAL_ERROR "LLVM_ENABLE_PROJECTS requests ${proj} but directory not found: ${PROJ_DIR}")
endif()
+
if( LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR STREQUAL "" )
set(LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}" CACHE PATH "" FORCE)
else()
set(LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}" CACHE PATH "")
endif()
+ message(WARNING "设置变量LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR的值为===="${LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR})
elseif ("${proj}" IN_LIST LLVM_EXTERNAL_PROJECTS)
message(STATUS "${proj} project is enabled")
set(SHOULD_ENABLE_PROJECT TRUE)
@@ -249,10 +311,15 @@ if (LLVM_ENABLE_PROJECTS_USED OR NOT LLVM_ENABLE_PROJECTS STREQUAL "")
CACHE
BOOL "Whether to build ${upper_proj} as part of LLVM" FORCE
)
+ message(WARNING "设置变量LLVM_TOOL_${upper_proj}_BUILD的值为===="${LLVM_TOOL_${upper_proj}_BUILD})
endforeach()
endif()
unset(SHOULD_ENABLE_PROJECT)
+# ccache == Compiler Cache.可以加速编译过程
+# 如果启用且ccache 程序可用,则 LLVM 将使用 ccache 构建,以加快 LLVM 及其组件的重建速度。默认为关闭。
+# ccache 所维护缓存的大小和位置可以通过 LLVM_CCACHE_MAXSIZE 和 LLVM_CCACHE_DIR 选项进行调整,
+# 这两个选项分别传递给 CCACHE_MAXSIZE 和 CCACHE_DIR 环境变量。
# Build llvm with ccache if the package is present
set(LLVM_CCACHE_BUILD OFF CACHE BOOL "Set to ON for a ccache enabled build")
if(LLVM_CCACHE_BUILD)
@@ -539,6 +606,8 @@ set(FFI_INCLUDE_DIR "" CACHE PATH "Additional directory, where CMake should sear
set(LLVM_TARGET_ARCH "host"
CACHE STRING "Set target to use for LLVM JIT or use \"host\" for automatic detection.")
+option(LLVM_ENABLE_TERMINFO "Use terminfo database if available." ON)
+
set(LLVM_ENABLE_LIBXML2 "ON" CACHE STRING "Use libxml2 if available. Can be ON, OFF, or FORCE_ON")
option(LLVM_ENABLE_LIBEDIT "Use libedit if available." ON)
@@ -903,8 +972,8 @@ set(LLVM_PROFDATA_FILE "" CACHE FILEPATH
"Profiling data file to use when compiling in order to improve runtime performance.")
if(LLVM_INCLUDE_TESTS)
- # All LLVM Python files should be compatible down to this minimum version.
- set(LLVM_MINIMUM_PYTHON_VERSION 3.8)
+ # Lit test suite requires at least python 3.6
+ set(LLVM_MINIMUM_PYTHON_VERSION 3.6)
else()
# FIXME: it is unknown if this is the actual minimum bound
set(LLVM_MINIMUM_PYTHON_VERSION 3.0)
@@ -1018,6 +1087,7 @@ endforeach(t)
# Provide an LLVM_ namespaced alias for use in #cmakedefine.
set(LLVM_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
+# def.in文件为模板文件,里面的@XXX@字段会被变量 XXX 的值替换掉
# Produce the target definition files, which provide a way for clients to easily
# include various classes of targets.
configure_file(
@@ -1097,6 +1167,7 @@ if (NOT TENSORFLOW_AOT_PATH STREQUAL "")
endif()
# Configure the three LLVM configuration header files.
+# configure_file,复制一份输入文件到输出文件,替换输入文件中被@VAR@或者${VAR}引用的变量值。也就是说,让普通文件,也能使用CMake中的变量
configure_file(
${LLVM_MAIN_INCLUDE_DIR}/llvm/Config/config.h.cmake
${LLVM_INCLUDE_DIR}/llvm/Config/config.h)
@@ -1229,7 +1300,7 @@ if( LLVM_INCLUDE_UTILS )
if( LLVM_INCLUDE_TESTS )
set(LLVM_SUBPROJECT_TITLE "Third-Party/Google Test")
add_subdirectory(${LLVM_THIRD_PARTY_DIR}/unittest ${CMAKE_CURRENT_BINARY_DIR}/third-party/unittest)
- set(LLVM_SUBPROJECT_TITLE)
+ set(LLVM_SUBPROJECT_TITLE)
endif()
else()
if ( LLVM_INCLUDE_TESTS )
>From 5d2e857c33cd02933daf7aae8a4c592d288649a8 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Fri, 14 Jun 2024 22:47:40 +0800
Subject: [PATCH 02/21] add comments, time=2024-06-14 22:47:40
---
LLVM_kickoff.md | 17 +++++++++++++++++
image.png | Bin 0 -> 72484 bytes
2 files changed, 17 insertions(+)
create mode 100644 LLVM_kickoff.md
create mode 100644 image.png
diff --git a/LLVM_kickoff.md b/LLVM_kickoff.md
new file mode 100644
index 00000000000000..d1b7530688e9d9
--- /dev/null
+++ b/LLVM_kickoff.md
@@ -0,0 +1,17 @@
+clang是 LLVM 项目中的重要子项目,是一个编译器,我们可以将它作为入口来学习。
+
+通过编译选项LLVM_ENABLE_PROJECTS=clang 来编译clang;通过编译选项CMAKE_BUILD_TYPE=Debug指定起编译类型为 debug,这样的话后续可以对其进行调试,也便于步进来学习 clang 代码。
+
+```
+ cmake -S llvm -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_PROJECTS=clang -DLLVM_TARGETS_TO_BUILD=X86
+```
+
+编译出来的 clang 位于 build/bin 目录中,我们可以切换到该目录并使用 lldb 对二进制 clang 进行调试。
+
+首先就是找出 clang 的入口文件。
+
+![alt text](image.png)
+
+可知 main 的位置在文件 clang-main.cpp中,接下来找到该文件即可。
+
+> 该文件由 cmake 在 generate 阶段通过模版替换生成在 build 目录中,而不在源码目录中。
diff --git a/image.png b/image.png
new file mode 100644
index 0000000000000000000000000000000000000000..798780197aaaa87cfc102cf2bf0bee7ed8251e43
GIT binary patch
literal 72484
zcmY&<1ymc+x^*Z;TC6R_wZ&T8p?Gn3*W&K(R-m{;aVt&;?oM$hxI4iM1c&gaz4yKK
z{<TQ5GGu1XoO3?gdw=1I@)8)Y310&M01PQfQDp!CWdi^}a6x?mKavS;oPmG5a*)(=
z1^{rW{=N{TlqvrJ0OSBE(XXl=na8W{KG?fNfIs^Q?6&E3QtsgP&mj#_%4Un at LSIu*
zKfVb1`1<2%AmWOksFLXWucD$toUEo4-YTEUz0Z<=Q5^aC>$d6ErWaX)doG{;+&OHw
zw{p$5THm*w at iQTm_#Q6V{{)r?yb(tI at cqAUgHH518i4=(`u87R#D)Q+|KE`s1oTOY
z|2gB|xtswAUjN^LL1bp3*#CQB)I|U?<n8~t6Y2*d@|J5Nv)*0<UgzJT681&gH=D-{
zIvOwj-3vkY%x8mozY1s_IJqs%{ZRSefkJ<DkwR05-XLUGHdMa+cfA)s+PQk7|J1uO
z{P%_>mdrx-UpNsG?_Y%39(j at f9U1?%ru21J=KjJr^P`A=M?QR4#Qql0p|wK%&BgwI
zZ_AzBa+N6ef3Ee4S!i8%$_Vn_>PY%O=LK}3to9C)HdG at 0_i@tD5TRpYfT#$hjsoCO
z;NMX|7mVM&d3H#k;9hR|_}}R@!9}0c2}C5KzN&Sl`p-}Sjs1p-2hRWJQX$4iulYW{
z_|BY5l-Xi-<i!^ueW~*PO4(|OEtf7MI=C|rH%x;>ST3kB3b>KR)lb1y(&{j(*4k;S
z_x8UlVD%Ci0xYse{k8v9J|1{<ZlN?Y(xEdGp1$`=)E>xCZR<O^4FK_cPk(7opwrD}
zuU-5Q?998)5X7#d@$2eMh^vV<M=7#;752eEt*h&Q=hUnl&^}xB3V$6<{TV|#8CZUS
zI at ETF#lQL-KCfldW~3C^TaL*gCAJwHm1Hc>*bx|y*xWY2a^l+BYD#IUwJTP-73WbI
zoCrLcrU&}$B at eeehV4f<*`bJ2d))TDp?8ZUt-OOTQNXCV`%4Cuz at 9l*OHbMwzp<0H
zWEu#PKAYG1`VYj10sagsx=#5lDk>vgNk5%Vqkmg!(zqP>jI-K-+RR)@cFb)GpEhAe
z5-kx0_d|}pP>!#$SZ#-Kck*`r&$kT<2aEImqYiFpHF~Z#1thDilu~w2Ub at 4DzB9*(
zk$z_@<}J46GsHm8J)Dd5-Af<q!sHnnmz-CLcqbN96xt!ig$@BO{f^x{@X6}?%vsD@
za0yVXI}eJbm^XC9(@`6`mMrl(&$-xkFKzDHRj3+3UT6^i&ki7f;v+%Isot3v<DSvs
z?Y_DZ-W)fE^0=avF-~;&pD=Tf5GRvgpx4^^Rvg_A<y<N=AqHf)Yo4*#FShVV_AaPt
z(0%^WaHWS$)bbz-CA<o)t{+<=u9tJ=z!`<`0akb}y*p`A7Rm%Try#-izZ=|5XQ==i
zB>31|HeaphL3uqDbS^HW08D$YRuxd`J%9IZy_y8fWA(S+y at KY}u~mqq0kGnDA;(??
z%<@!(B#O!EuLCykP}g>{iQG#wJ|oBH+eK^0@^vmt_qzm;WT6D?IP*%#PPn*XS&a+m
zNC;WUYTCrAZq)$krW0mN#%qEBU09bF_a at v6)x!dUdahIy{$mG|U$UgkSM47})9YX!
z4Se;ZjFWvGoq{g7OZn3bXYx3IuiLXb;5)#FM&A?4VfA~_=%8EGE2hfWnGcEB9-%nQ
zJP{jLk3RX-TWI3E<*th6rB-RmzZo99CyfL=1&T<hS3X{Eg<K}%-~b((l&a%2(32C?
zxo0R&*LJg at E)(%gOI6eiA0E~g%Llk#02Ii30KUtH$7L#mrl~QHMn=7V7V at Y+9{-(O
zCCbv;+zRH|Z{3{v>e at BFyX;<W({vf0FJjG3Yo}1IfVIoRucrazEfX&@P$0>!ta~<U
zmf6bs*8Aj>3`G at OzP)az9E-FFUde4K0&xbKK8Y`&MH6i`9iew`@1wm_&F3p}>SdM7
zYDJaP))`+w0dTLOtRx!x(nYX`BKT8TG4+aBp9mKoz#$D=!<7mVKwgZ@!y(yTxR#oA
zw`6zn*tl^s=WyyA4^&^CqflYpKSV1J*LKyBcPWqr(XP4mZO|I(Ry_;^4?3)dB?}0D
zoqO`p*>`<y=v77ZUx&O at CBes1C|!8Jv29v_EkXRnMUnp6GAo#;YIErO+?SbxDAn at u
zV=eiK(7u=&L(@s)7a*P)N=%>m+fC=6GFzd1_T|GrMGBJy+dPwC#md7O&Ao2!Be&mg
zc3+7?ZE{%9paqvF!bdrGG3VH6wfYE30w4Hw?sMmQfR6ae+{NckC#kh0SDmZ|VE*qF
zGvANDPUbRU#%qa4?4PuA1U{@V#lGR9-JAliCT~}qc${(+Xz0X at XQ;z>lP%Qi3Z at J0
z`_a=fZT>tLKK?H%<u#nWJ^T8+dx0||a37FP%HbtjPBI^fC9<{gb5ovqkUm69qg?v3
z<N!YYrZx%all4r>&z8d<dmQGR&dxLH7&#pu^JTWOWLkCGgLqxYj&K%M=Qym?PENm$
znJu^9`)aEXpGPFfc2;G>eOhqev1iZM#I;h8?H^j*>!-`+QVpHL^l0lRwh3&Hw)@rg
zhxzM0fi~hPUscWHk_JIZ`ot1N;xiuDJNHz$p?s7SSf={Wwl&)ONG9(kb+~Ztc4s|d
zp?=3H8U0Z(O+ at bdBa9vDLNRS>NimNgG`7jEpDJ;B-uK}}?6|VQC)FLP=IU(GD9M|`
zV$M(s+$QuNx#qiK?-tu%m<5h%xQE^g%JkzmuTS6>k1b8-bBO*k6owro%t;M(wa%OC
z4CwJnGjPeXOydpTU|?qc9N!+rZhz at I<e(DKY^m}igvDs9%-IdY<Er&RS}mA#pmD-Z
zp!&(#`Fdq^Oev$!)gj_X#+$cX-E%nA(bu=RZX2y`5SAeq0?q-y$;6xkdiue($L)+z
z#CzZbwfS0Kt4QnkZyZm1A at xz<M~iO5pdW-BX^eqF0^Dg=NEwQVN}3YV?@hw?FcWs}
z)rI at g!v1>K7wya at BWzukaZc?5Kv_1NGh~1XY7W^Rl?+3|z6KY|faily1ov-AK}HVS
z?H2YJd|EdGTDvMqv7V6WHuvj!JarYc*Xx2?_2#S)s%empC*5;cB9wk04e!tP?}P~j
zNxS`ei>!aKBu<TQ7~$S|zurIJ=jp^f{_Q5v(*+k{+q+vKEVrZMyeCEJ^HF3?WjPG(
z&hZ2(8&-W%E|I}<;Wc!JSYB$G*9uawU|OC-;m0IwKh$lba7p>W_hM|_pN&hR1lWyI
z50Bc7=rVHXgFbEwfA+6TY|%)9+SIZIjM)@}>;0HtdNmW#Ne!yj3sUWazF+{Z*Ty at F
z%?`tKGu$AkUm*<ymI`*iQeOfyg?0<fYhs}@va6**<HGs5 at +sOc0lFZ!w4;Nm0qR^(
z*!tRmmWaQa`uvN4V||2pWjRh_4FKThl&4`1^UX5`6 at L>@OXXk6Fhd-x8qlHrF<$bQ
zkv$V`BoY9NRNz;N|HWOZv)M$OD{lzp5J1oX4=;XbRWmvcO#vDRWJp9|rMR0+u`imF
zCfY%F#SWAAHZBe`kc}j+!7*LokyW at MXjkl<&1>P)p#mWS%wxZC>Lhw4Qw|M(9K*^w
zf{eOf7mbWqmz%1E0J>b?{1HPIr%)_UE^Ho3i14vgdmDDNK?%k63`rwJR0JkyB%3IM
z`OL9UB=8bc at l5qVpQOuaN8bJTZMTJrH^Ge3VT~==o+7PepqC;xaVX(|5TIIKCe22f
zd^c<Q<$~w)o9|tV;6(<Zowr737Eomnt&~Q25}>Qv-Noq~G2n1|bgOL{N9+JV?s9qg
zDjcurHce$nTgy_+u<RFKV-0<V@&3jZ!Pd^<{uaS-HCs6sX{kDnsR4Wxsp>c{;uy0(
z2;T_BOO#~suV;>_Mch9^BWH1%6E1u(=ermC2F8jDGMWm$EFW4x%W4 at y+QhXh<piw%
z808KgQPsRYkvShf4YY~jmr6*cD$S)v2w;L5RiCihk$tA~fo#1!UjNWNwTK3=GBwq5
zkI_gmYw-+w_<p^G)*emL!>UF_V3iz{j_Vovj=rHyUpc|Iyl%q}SU0*jJJAbD3?E39
zE-Yaj$}L*dMLE2#V4Pqalljc#gZgrF6FfCbH#!77H^WNK at 8G^Es{3f5taZEoM0&Vo
zS@$;8^IF!~4b5bEF at v!nY5x5$gR;ue)TDjq<KrwnAHBBT72kqaJr%c^+J*GP9qL+{
zQmd>VW52~q<W4gD905nq0|MF_q}2<36J?ZV$#sN1mCEurb4$||x;-k>znwEsd>)}4
zZ`adL>fc-NymfQBieYxFR(mgyOC81E9(YdF{dFUs?HH&Hte}<WYH&uO(I8#7K%I at 4
zp*2;L(zfh=stH1gk+);a&RhGsI_5KcP`fjV4FJrLXsF-js;h5qE>F$!3PW&BY at 7@8
z)s<6>ZT#suB_MB&wgT>Nynz*U+(+V`O6kJ-N2k~ahd9(w)DPNRPpQU*RsOqC{@(@b
zCt<r>9E}<D^`CtE%_gK)k&JmuWUP~s-ig_9RH5=3n8z%<Lj82R^=Xx+rK2kSQw2pI
z<`{pQdoX|1Bl_=^W=H)Q(fjY~xA8_i!LRLwYKfwx$ZM?F!5w at hapjCSbde@*Z!0TK
zPk&LM0e(~v?#>#yy0+^zp-uITxrlq at 3nOT;y5^~Bky9OivGF%gNu?lwpkDWb2ymo!
z at a=uyF2yqzW!s3#Gn7aI0N$LR8&Cir<;vti>U&bC*(5ZggRh;Gmp>lLMR3CmqK1Ax
z<8hR?>GaQ`O at bfw$%cI^DTeIygR%aVFjji8!U6h)%0S(EFL3{Qr2&{S>;%k}_uLgI
zUC3(KCFJe>K;m!f{hZYZx!9(W*KdJtk1M5o|C3JJL$bxwliaGl#voO81G}h^hbNfu
zgb23!(0P98-*|DZy&57SI0?@35-6=z2P!k>6yM1>Z8o~E_~w^bYMHKaq46q$r+lep
z_3MJyD0jE!vdVK%0uZ*>@ma6v_SRHs`|6F$W9{xFpM65bv4}ZOoQ<=vO_PzJo74=N
zXJl*cH|bvpKAXEl$oY8c$@a*O7`>rsWcpHn<c}=)77$07=6v=Wh7pOzYDc)@b6Z#F
z*sIUFAY8SXxM_-HIb%04w(MZ_fMR~_SFTcYQ*uXPR$)>dB|v48e3u$i!TR%82+bRQ
z7JIp{rf_Oblz^m2o$E(vJ}eC-Ae`y>-Rcbi?lQ!nht~9|Ph>rF>8=pAx3#hG>T=#2
z$&Jm?!nX*-li}@Pdozcl0Is!v{Ao%5&UgDalRwBncB121hbqI^Ai>#q_9z{j)$P<B
z4-52pSU%6p^TpJ0Y|OHwr(pYXh9~PjJukteVL<&M6L9e9p30W{>}kE+nJja)Y<?L3
z&7$=ZkvDM`-<2BxtMd5%^62x7OPC!+wr<<y<GKOqYK>~K=Hs6)y*aR at Z*_zvl>`3I
zXA5(t_vOF4t3`6O3D;aJU}amGM1pO0bGy*t;rG}lA{RVEX?i1&jPxNnVjib^ytj_n
za^DZshVMrtIs~hqRDv62x1yM~LOXu3?HuGqM^+Lqf3peeq$jX&xYMz|yc4eOR+E)$
zH`TP^^~~CVj>jsT!L-e1<37vWNBd5ETSk8RdGf{Q6!Jyz2rq742C|MC&ej3p-(%QY
zsw47$hV^+Es}b_vv^E){5duBg)NqSocUP2IC>#pp>Cg+1Kwe5ztyOn##5c$3L at c`}
zv-I&kaNhC{_>L<`hq&nSUvI;%Km^Nq8Qjq1<kJ4R!?iP_aur6KJU=uxu|68Av8TmD
z+rXkbGf^?I8wJB0yYQ@$N_LCsPiubl9<5s2xFss(;d>~MF(EgH*V-%s&gYDP+=5F4
z83_>sM1 at uA4?8AHe+)_v;02yZdq;+TU+jBt5K(c9a^~Hzyw?Y&uCe|3SHC&~8+`Jc
zI^4i|hgUC1h|ROtr$y&b4Vd2tP%FGIddBOU+wY{DIwerC2k%WRX=Ugk1MDbxB2%u*
z?~jEKvWa+1ee?+-%%Iv*@t~CM!wO#l;WQ?eg_>^1J*0{>RL7JXw6FitxrXV}0fwX@
zt0H;-y?QaU19&l*$?LrrsgTO>d~wNEEKkbs^t1Uj!0qIgu0>_0l+9eHI8>xSXl7+J
zzokrutrSw$aYVz#-`2s!fA{9nKxvL6!RDcvi=#}Mbvi*o8JstTn6(=0^15n)7zB`0
z>}a9S(AQVWKcP<ZI^uRtoPK<m`ED*`zIV}*9uYkfdi-D--yNW#eKEvw2JN_*xQU+A
z(pIbUJNWhlAKJ0z)ylf{K4%MxuP4?7E23wC*;B5{#?m>N|DD5+YWOdR7azM7&idzP
zRey3vNS7`&x>fqY{mM9*rmxK<QGaD-Lff)|z?n6Dh!?Q#Vq#apR!bm7wLFUC{v!UY
z!3Ri`Q+T4uu|Lq*GHhLr4u_6PZ(R?%M2OZ|nmoVukCClGvUA+N`X{qQ>$`H|z5f#T
zB_qY>x8_heP2Etb at x6SJc&ut^GPI}N8gF{a6Ht<@Zue|=KR#RQBEQEZgFH7ZouTK5
zkwy1`?Jfsn<lU9O&*BZE&Am at j{+dvu9Y?9jIO+05!`~q at lHBb+%;z6kqwC@)_mv8E
zEY5y|AAZeh2ZP-;1rzBjmnZX-Lt?tdl$0L-JoJ%Zi0>ohR*;{>KFh5=fMt{8jb~Ny
zo*wll5Q)~9-A0I4Zm%!yU^pQ+X=uq2Dbh7&-3%gcDtxW?4<+^yHsE%BBye1=s+r{R
zdnW_KDtSsm at o3Q3!K`m&^B(I^+j95JAWEU#Gq;qt?$|Kd?Pw#^v;fMK{V<OS(tR)0
zS=9AQUE6Q*XyvSN+-5R%98n04ix`aKXy6iIKpW#uZxS<e#nv*bF01~ak&TpI-J90-
z-?B-3bd^Hg=fkmD6=8;>A>^$Zim+=IGx&2_)s93Md=V;fZKNWV1m8cIF!Nvmh7XrU
z#dzuVNH~4A%b{-OZ<X_C{V$vTPS=G$w-!5$N!Tt6ks~m%;jB~JYNPv<4dlPEY0kp)
z4^W(uuYUkMm4iCZ=Tih37974k`?<O at q>yHJ#~>+C2Y8mEjTTbNi4prf`>ceThL8FS
zwoUntE$fvMGckNuEuX<a>8jHlrm{UN)~7IF)$C`Yk4gW;Gz~K}NbnBJu1r>+8y<!%
z<{vN5d~a2tY>%Uy^#}QWr71h5#@u~HXcD^E>SnlSThOgIoELqjn!JY)z|Gwt^IQry
zku+;2GChMh#~~=G%is~EPDh&XguK6Xm^@i8+`oGJSvfeteeNq`ygsa)-U@%MuS+p!
zMd{p%@Hyt1ut5T33%y at 87gqIo=X}ZL-P!JPOY{UhG}-N>mzvbVCrHI#H4mCxP1Scg
z8}2@$!GL;DNnMPd7C!iShBQwyRd`!Kh4!W*YgAzRH~D^O2=I9P#7Fax%?Tp~yI)Ke
z3&`TPN)i*xFzH^(pJhJmUB|QU!?V$j!7xufJweM`v9!Z!S+h^foQCONc$tRf4YL)N
z##A~vfhlIo&{<LAawiqgDa<j{FDdf?R^Pi1<6Lr5S4($47<A`B+r3Iy7a*~$uuOD=
zbsa{cpo_+3Na-^z-dcXVN at CtTJdb`p<(%}(Ri3feV_6inCN5OhZuY!;DV8;J5s^L?
zq_fw5ASlOY3%|!2_g&=dk);kirpAz&v7{<?QUn#SPfU=Mr}O!=n_|)JJ#g_ at 6(*x_
z(%Vd_Kf-M^U9;8yX#}_u7QnEN`8iXhuFL(KU6tLqyR&D#_>HHwUg$Mif=C#yXK=Tv
z(D(I>-s5%-CN?F+g%&FDhjx~v?TP~qrsgaOeL8bHF;&{yq65EjcY-&YocV0+bbu1>
zE1~9kB$NjRLBGbW8AQNFn5U<F_$BdrvZsrdmC{rHLw}<kf#=e-Ow581Z(Q#d<1ZrW
zEQ!CK*$TAe9+81kYH2-R(O|PoH($xi&7SaiLA&jinU56Hz$UAJKt0Zp?e4fpzd*n7
z)K04Y at cK@WkrWmmaf&2*eK^TbZN62m>wQ9oRWtlJBEcb8gt<Bp5xgyTtO!)kUIs;1
zAPqz at YmV|tVuvw|&0jyzNp_CYt7v8Rqq!9n)sk6^cMS6XWQ=p&hX8ArBnN&W9r0eJ
zi|=a2sqc|2U!2Zvr+3f6bXj(R^;Gl?r4M3|Q{JZ&Uws6<(nW2pgS>V9c0VU<4sR2%
z&IF at nkHgD>#txZ*3nT2J at 9to^DTn7neJ`)UBq~Rdy{W}Ci3xp`OmAy2p41HKsR1uN
za1{H8Pj{0e)8nM=B$_I<QN6U^B^1=^mni{U>V(xZKA9i=s#R!iiare|z{z3vx!3qO
z!AzSGtqpARc08K1FH*5~2c?mL&$KY-<C{H|=4Sml{Us-2((lw(s!~fcuYPG?{aGUA
z@$%k==CHg1_ZST at b4|23v)^SFQDhrv-V8;;e$|FyQO$nFYn;q0sh2_a`6D4$u=r=J
z?a-!jIXBH^VlgU-t>#d8PY5lkE;L#ykOYNjWi|+hYt@%Wj}JN)h+#j8X7KP~b!hem
zT3I;I=qt at IB*RAcCAcqPui`z5E0q-M&E{P&(RxuTP0sS7^X~%yMRKtxk|;*@W8NTJ
ziN1Q8kKNI3!O?-*vkk23VFT}HI4>iK_E6OL<;(m)>~+VRaMhU+WqVS?y}&O`=O-oE
z3a|O=CSIdtmmGB+ARpx>%};6+yyB5KV>A1@{)-DqxLO+cX{fpWGE57~i!so^c(h_(
zCZC<zn)*C#DNTGo6Xv(czi4A81zYv!WXd}m$Uja3x28;ox4qzjnwjCJ&P$!@E{IGZ
zOHlpbbH%1wynIO=3d&{QPhmN)`|IF}1yq0;?*-U7&w)8ab&)fYG93mheGy^Io7c^P
zkepTxp_!eK48G?F5+xPAx|{vx&#BiOmSJN)ngp%e at P*HGel`)>AvZI0cl<tX3iqsB
zT(cMEJ-<`uJyBfMJ|BV;VwwGsRyy6dZ(yIFLz!OHvn%B_rCMxxq7)n`(hCjFn(BbK
z^vB=a2`;*^Ma9q?>4_#MNbd+&Up8J_X9M85)W}jiV1tW?+cuyfOTWqK4d5l_D_NrE
z80~yn;07~~FCC_-l1Sc*fTN8VM*Hgzh$N*poWeMz0&$6V=|%Q_*I_8a*&YNQ7}{Dt
zU|W;^1{R9RuRXOBLKw!ruFHOlz9{IocPKm4Xr)dg{lRfl?k`Le5})5ca9D*q)UN|&
zrzuHB2LFfu0T%h9KvMnNdulLlP6Zd*t?8b8;r=0PhEH<Dw#{Tjs?~L-1;I-hc<<~v
z-A;#cKn2ehOx9Z+PJZ`m$;3>bt<Db)A9#>`t&&B7piMJQ2Og{y?6Dy}$(|a?sc+?1
zn0OiPwbuf=uz!?js%dp29%^23B+tCdhR^V1s9$B)ijcyDwi7eA7bQR4o4c5dn~XMj
z>5w(JkMy+Mf26q2D7lMrzwy4cY_-3<J(Y6ylkW5ly63hWqLHc}9{u{hRyihXxl_89
zEYM=6;_M2nY`)GbA=eZx@}O}0BW*kTTXp-3mYA&8`<saYC7IW(m7(q>=#I_q(Se
zd*E7n&c>r$yy4fR(`lb-&a%+Yu3tJQ?$qiW97v%xGH;*J;})x&6{GB~<khaLrkFH6
zxEa~`J^i`{?ZW*+7avczk;HGgpHG|dS7cblDJGO;;8&9d{CUy60(Xb%@nP4iK0)7H
z4>@da!3PpB&5QNDFjrd8#Ax~Wo^U?V%WYPb827`%<*%@Qe_LU|n+)c at Z?xBwkiZ$u
ziYecsDFiP^2YQ@@m=mtx4ns78o7CC%YY{^J!C(Giu+7zk4xL}^^2&@SR_sF0J$M>l
zh~*l=x#PXQ!YwCvccxypTARK+LLlYO<Hu9ik$5Nr<BuEou^`K?$U_c}qO+MRnfhX`
z-7QWtT4%g7RAXcBlBBDleZqtLGWDS}2{QJBtgi}w;&RTKHjWODD+)|LPeuR|lTOz?
z_ZEPnede*&_{xXN86<Ixa48SB-hp7q;6b7P+%&>Hyz<!!wd6`t-(x|9CgMF=wj7M(
zN7|<e7~}r*TT0rYJo+A<5#H-MV at Xaa%UQ3jaVTdSyqFjXGl>a2h8%M^Zl)w1$Pv*r
ze8HjvyX$&gC}pvct at -+R+#uWbVu4QYpGIEEl`)?Hb1ot3COMP(9eL+ODOA(em(!p+
zrvOqw4;geUT52eeHyV#4*2o;0?awOZmmK2PBqTG0{JByk+V at P(fqD||<(-`ym+5=j
zANw#LnVGb#-U4nrL3b%)$d at PWS*0va$#?JeFtq9oc&!p486POwVB^%9QV0TA58y at n
zA1j2cZJR<(e7Hl_lXsz2E)}Zh&c0d&PY|u?YzIwzineSW*V9fsu3Bp$$~v2UxdQ6s
z<>|;qy*#|CE&e6BCFy_orAhX6*47>*z8BYKw!j?35)NDyNfGP9=I`oAZaF5RE^pB0
zu^a~a`x}ezTf(dUPJfoA8g{gK1>4->R&<X!O%^;RIoXs`#R}CqB|XJf%t`1i-RKM@
z7O--XJ?f<>^cTe{rPLZX&@-Bc-HV)!M}g=*iL={lPETb>Ie#k=j;X#5J6iBg;?&io
zU|^|6(bkje+uKcqEDnJl$FV⁣)o7QKAFek?1i(M02L2339B51{R~A;AG3=jQKrU
zE7siJ7!%!$+#9~rkb1Pv=Jr1s%aOx-)3E>10%-8hyz*1}*b-AzOcz0VSRvQxtE}P~
zSaKwU7#<$XgW-&A?e`nYjvew&K7leBP7`f~O&G$TmOs=IEU;5(FvXPH``2P_h0oyJ
z7W8-woZ<3%unaBjslxc4VBCJ2Xi2ZO_j$_{@Mc*dQF&-lZ at ExgF!+m9!fVgy1OK90
zu%fuYB>@TDucil4swh3tiM=9 at i(s9qEozdiViy7^ADgMPsT4K8p3-eVn(srnryzLB
zQ(AF<lRwNFbhqO?cdVf^_XpzJ-<GEmV135!mD13Dw>FFHIRqymM|U_?aG&#>51X##
zxA#E>=5W%rX4t2EX65ge?^Y3*H5l|+Qhi^1glEy|q{5Nv=%D%nz6{mdJo0|KT<y`a
z)wiQG<F`Ff5{)F|dhYrTnmwSIfGvQW(u?xaQhg;sf-AI;`rUMP0}Y{P->{Eq28hGl
zdG_w3_3Uqa;mS$_*K!xK0;UGG*r;m1q_h)YbjIaJ_TGsl*W0sFnE>OaqN}7Nu3O(t
z*ulo+Q?1C&1SUU^M6o+xpJDDbR}znm(X2LCm(GHk`&$IN%Q`(-)x}u`cb9xs%*OH!
zpHe3o?I9KK8o>nx(CbGd`XR3JMwI^mZxZwe5_^Y-TOZ$jS#WOFWy~<GebcF%Hz?Ui
ziLhJCW`1xZVTTk${Br?|lgzsG$s0*jtS|Nw^SFm~T5dVpeAlnLaopnaJF at 8Y#h>t8
z=brbb#m5i3cW at wtM)O!¥jk^NOdct>JL`tsJHioSbm~=59=trH2SPXi0yKB9RKu
z`K{)-D#9jL8_U?4_5-O;yl4H(AA9QkwLTx#`D-D$9b5nTH0mI(Ce_f*`aUPl4mq{e
z%c^&vX86U^cgp*i$Bv&dyL}jGrC`s at y#qWc4#}M&ec-3Iv#r&y#elC>$LJyBuJBlb
zaoxSsY7zW-I^soEJv_++x4Jsbx{V~Oaap91OC^l&y~Sl)(A>)HPE6e?vhoWWO~v}z
z+wX;Ph}`z+I))J%`F=Mf`uD?V=iyS2oroDfoNP?*aNqrwRk0EXlEaKkoBn3A(-kv!
z94;HLx<j8+obg^vA~vr!G26hrMOG5Z{1hT!$PYP4Sn)2p**FDDnZL at g#UoA at +D9+_
zG!27Tml26}w7o!IsoK<&(C4d3NoS<1GjrQcr#+c!f02Jof?-m6{d%(D501$SrBnip
zzYyH8Pc|pv at 644W->vlOwI>D#9gub=JWM;juQBS2LWWa$w&${P`HqVp(OIrVu<6g<
zeD<<0SmhhzB2YZmGwv3KJgVE!t7!xLcl>dF={WlwPMwW!D!&Vs_*{R$TV+{b$fGvB
zaq-vSaeWnsr>?Bmm*#<BN6#2`s3EWNOJgCp6UWL(F)QM+v1uc6o5%Oj7Z>YA3P#5}
zA`xWvi}sK{$vF@$$Tn}@5PlkR1`4Xd2_4h0u;obmnIdf5k at i&wW+zuzHO<TV1;Y&b
z%5uB)_y2LHX+^%Z80hGzXiyx7Wzo)u9$~ar!n at l#)rB5)j~7!jeLDP)#t}94lF_j*
zbqtuAui$hXdBC4nC!5qUR^wl#5`I0`AqNngk!&vUx)MFEEZv|e%GhPXR0=C at Vj;dy
zNewxm3{9?>(IhXGWqWqRl_TnRJq}GVc3X<H*B?p;ogG|0GtIbw-EP9s4;Rk%(tvP)
zx1`HXES_3)>i`rDnVq-bt!wc>4*mc~^u3d$RYZ<ouVOqaootkx{48Rf1~#c{m)?VN
zocc*@8EvwK*nL{2x at n(!whl(;*Xg5<*~|j{MVaDta%;<T3MMngSZ+))nEZQF5!hmi
z6lc;Fg4-I(D9>WX(Xiib&wp at cHgqQ|m=|&BG%t7{fRGKNPx7|j5)x at o@{*??%IMQE
zaA^jZ!PMq)zq?qynIG@)X8kCi;TW`7+yTc0bWxUf4ol-Xvv<0O6mJ*8S>CbMjx-B^
z0zL%`evU^ec<9vS{iPo*szb%)Ski6w!JNys)&N+i3{0q9n0wX9&fVf(lCO^p5J~_D
zy-P>?X*<7R3#eC?j}AisTybFJd;8>RKEI*IHJ_8%!wg at M#a(CJ<Fh at qDnn1Pj7^e0
zLHjgb8QSRqiGtZ`JCmwMuQ^7?d|M%YAws4y=%FP6RIOW?(m_#L+3+psnn+yeeHzLz
zJ^p51pNjZF?JMxz!plEjC}WZ4X}hw;ZqG;7`NRhdkH8}puyiV=0(AqrcoJ!2YRSB2
z%J0tEtbcH|bv`Kdh`gHNY~p-RRo@?>^Ok88ym5gnwXfr1Vq71X^}vWf=v!F;b0WHM
z#b($42VbJ5b*}*0Yipfj7d{2 at 69FUx2%EJl6=#Qbtwh$zb;6{94K}@7TSiB7zhyb3
z7tZas`_iT1b*lSfXXC`vkZkTsNz(_mfsSvRC0fr at Fi2l_wd(gi!TjgjJHZoeAVD78
z-HLqHCbqAzSAZiP){~@y#I*(G6wu#;4~GXtI|lu8qMPZQq0Q)og^SXstflx1r&-=E
zux~NleP6G=r at r3&(Nrwj&g#v6Cw|&N1qpKEC;+hD7dHN3!@_5$H#UbeuGi~u3phGH
z#nXbGIYzv7wz9sC=%X;v5-w8Ut$=>SIxU#rc|eYtVZ8aqoL21V?#X~EXT4jtV at kDX
zV3p&?U2wrb0!N_5F+&cuo-5~o^Tm%SnO`b0 at E?hzK#r_ve||1DdWXK>Xi1 at oY*56)
zyJ0cFk(t~>$Gk)*gpK6pGPf7{@$17w(9t*U++1g-IIDLRvzj6nOiM{J56an=>Y}}S
zwvzCzfh%ZBiqP*TQ58kcRRZ@#W^0aPCVx_G3b6Lo$=wsO9Q3f}ZmDHT at C_o&uFVwC
zD>I)J?xtD+Z at er8K5qp`I=@r(uC3Ky#{hgFDsJ}Uulp#EolB#p4ineA*kl>9EjVG6
z*L$Ixibb`oeB=3ANnsAys^ST$gb}?0YM}5^G=?(hce#=*O<9_t$orEi&+Lg~j?mRo
zW>Ec$htuYB8tri#x#M{qFNLxaWJf-ajt;BS5-G5(O#AqvLqD<)bR#|({A62hNw!Q%
z|Gt`<r_YsBi!%z_SSai*hrGQWeJ{AR+mDtOJ%(EAM!?+2e7Ohb<*y>C#&3fNL#A_w
zw^Vt2-QfJlPbnMpcktDg+9?&q^|aL3=rsJs at 58|#H5^IG(~PuNXg%GN&h3SE{^x|x
z=AH}JW)S<w3toajgq}|uEba&4^<?<thRW)3Zch6eH12-0rSou at qk`)#q%kUAzhV2K
z)P*try1Z0FPiNA!3!UeU|K;f1ul;%DG2<`p3apWEb(KYUL9G_Cmj}Q&Q;&hbeTKFL
z(`Rj?1bI+<X`A8FqKnPm)e6^>8XD_0&BI?KMPrMNYH#yWGD#H<l+Fz8iUu`EH0*Tw
zTIFARAcHipK*ip;PmXT^3-aoxLiQhdn6ei$8k>j?Cim9xDXeC2B4d-uI+s1B1`q|6
z>9zUMyJ&%ubMCt>yL#;Z(fFxsBY4r!d at X)s at FKTN-Sc{yBP1W#7CKsA8+nZHdS)lB
z!nIOsy&tX9*!tVWE?k?ynF?jv3D~*ZETdqu#ydL$d7PPV^g!VdoZ@^-kg91wfdo(x
zw8hm6A{Q5E9cH434es4QH1^=^)_1&l@!x5OXFmHq>Rvp4w{7BB3g!}@$2ze9rHwI&
zLf=g6gUCho)6oy8Jlzp_FvsQErDwal6%Y3tO4YSJpD(TlZ-=OdZzV8&E{ika0-Lqg
zHm-+mvEa{N{{kCj<^osu`gC)0KxMmozW6WrmZ>lm{-=VUi0Ctt!}2HhIXGBW=+26Y
z6i6$w6}E?P*ZtC+bU1U&_m91#%SQlZ&U}pZlJ6h%;GvF;Sf&e4)56o-Zpir*sePIR
zVzy_wH at +h$N(Co3!{<rl)>ouNv~@!(gH~T^*IjMP_W0$+#27Bs$a&A^B&GN6Oftd8
znylZ~J*MW0DP{JLK`jYinH&@%s<B*Yj_a6oN at x$!{Jt1l82<~t-<PWU5uxoZ;<c!8
zL$fp!`Zgi2Iizgn?Qma05WYc6;x$0}m)ESBM$?B8CJs9ZSMI!qunDXBh;bU at B15pi
zDZXIgodgZ4(NYFV6fpnYkNIKgLYzAvbEfRX;)6iXS=!x$)scfm^2Drx&o1vfnAw`u
z)x|@K;lU9>2vRg;lab>GG_K!c+N}E79qmu6v++ul>FJDzBg^#+YCy*kKF`JEe{td}
z79(F&sT>$-aP#4^6)O!39*dF_BH9iwjxTy<YW+dKP-tYE>p<k&3EbRkzx~oFA5I;4
zc+RLXv!1$HXt-9DL<(`5fp2ni&QI5>7^QIS?YiNs at aOha>0AnWgyueOj}<PjIwMtz
zC;e&4H>XDFM3I8Wg^1;Dwv&*df2(c<5}aaP+&D at Bm}r|-^TN}0STG#puR)zS*Nb%5
zLjkyIbFiq6I_`Zgw?+scIUYTR9rH1_xfv4x{^au^<eqly=|uQ~aD8qh7idOJmDyWC
zcn3YU8NSsB0LGNbDNp@?jI;i5E3(y>0iuQ^-~OwB=652L0ubWkZw#82N;Y}$H at ni#
zP*RAqe>mb%@zd8gF$wF$BCfIXMOQ8{TqdByq7nm4!3DC9AMYz4EG)JQ3E;RXl;|Ow
zqul6S?Ahri-Ztdeln2g<G?$tmU~a&vfyG6xwZ=$N14fEnS<`B2{FB{v0zea{ys*20
zm71$3XT3D>Oi1&WZpo2?I3nNPEYj+@)r50a^G5PRgMEPs(VHnVTmk6v$4hskvrkSp
zC-2{7;d9w^2ic!ejoqc_CqMjYs|N14vIdVtV|2X!Yi*O at L_E9c*zt`1HvIQj9CAyz
zfPnahpQO6;thl<awxX%9iAiv3Y^BEM!%O7}7PMOlsQr~RN3^ivMv)5L?mZeXXw0Z%
zP06ZB`U;~=v<jH=7$|0u!)b$=YJD~X5!|!QPb||ZWcOL5!>NZ?lfwE1>@Ie|{Itd>
zBn2Ys!g#DoWj0149g`oNVcMqLEV;vN-AWnHRaU#amC-7Wy8~_hhM01OI6*_{fe;!0
zX3<YwHz#?3jTC%2adrqH)6aK(j(dyVyw2Fc8*Vr_2 at N-H)JDL}C`<tNINvjtL<sC5
zXgO4=f(7<VM#tu^U>24kqVPaZ1|-Y!_i6IuCU;q{nDnh}(}=Bh)%)iO6|F5Og~*O+
zkOP8P!$qfYB at oiN{WANO)z#Fq`Q0neoyOeQk!Y#Z*NO+(DxQC1`9GL=BsN^29SL0D
zxpI<yo6J3;nFE8To{BPRU(M at dhoA&REf18u(x^7WU+BX01;7bDAhQbi%PP1N+u7Ny
zC8Or?0U0Y#b#6+_>-#A%{!c3T52af5sah`i=d^5}Nl{N at O?vtLjwP_B`ZsnOscXbu
z`~I2PBrrHXG^f2nv6TzdRf)`%szyW-k=8edj4F%H><x{bSMPY&aFJYPAb2<twSG=q
z{~@ZTC#;{7D-1~^>s5VCg!(dH3HZ&Pjp1H0^w|yp at Pml8_JoU5a@Yxqr=DyI2KyO~
zDfAZh5i>WGu}^$MZLJZ_&<Lb?lZMaRQhF<V;>|p|qG-0oF*-(7%It8M6tPsOz{{91
zZorw<3AKcy&PTX2wMt`crlX!qf3jRrz_=&_%Gh_}q<GU2K3>|8z4aOGdSYH)39pv6
zPpjVuq(ZcY&eGva4~;31(C{PHJ*iT75lVEJPBlLJ+^Ym2Z;ofU+c1z1QW$&+=}8U_
z0Ozj$K*xKjn|<W&M4k3|EW0^c8*(#3IlVSKCi5uixKX<3rVtjNtv+tIE__&97yIIe
z6Q^#;akYioM?~TwOnDO&n(2u at KOq0|P{><jTA?!t<kOBLV8hQ!+j_RxGBYc4&Cfo(
zFQb$1S&UA-KNqFYq0m&kg?7B<>p;xdU+XsWcWJQ=J%KZI8nO1jidKK;=?AWkuEa(3
zAa;%Ua}0TgoPL;jNdj*6wd3X3+#=~-nH$emC}#3^*#6Od8r`SG1+m1NAZN3lmG#N<
z7~T?uECSbM%Ry5ZtF*fuoqjXVa3cHhRz3BI#*ej$jMN~*TTflj=-8otTDmk3RY?sF
zyD(r{y$NaDwknXP70c>g#Wm68a1;IZTc2!=Puswl+*P1dT~DB)1HSLzf8yHx$8t9N
z<hjLX2K<r<$Sp#&IQ8y~HbpQT6MT6l({r@}(awGZxKq+FO}?Xkt>fs7(m{7A7dfL7
z2FjV!XPfe^i0dsYgoDPy{+q$pOBGsqQ*)zIRBt%&Rr#J$>{{`p5;S5hjdT6-92s1o
z+LoqLrwmW5o~8TaXU`G$?nk4bQ8hjqtUa4yBt!xyr!%e}50_aO#r at Ns*d_GO`o^yF
zRxk$Rad7`hXSbLI!e%;D7m0w&+7vkmUO?B`o-nQ%$^nz_xZRc{wH)=g53W#gGhlK_
zmwytv at sKX2nYdcW%K0h?+qZvzt;RiW;2%blmx8N2^0JoY&@TPmUjp8rwPdIKQJKxh
zj)=w@^uO4&VbT2*a#^@D^zjO|(qeD-K4vjpz__-iB?WH-x8+HTRd^CIo-yp~XP>Z+
z`(T3KyJczM`tb;(b3L~S{DOh*KZVR<dMRlTTtf*cQAtoP-JG9Z4%#=HxZeVs;@aE}
zmxJ!^e-JUvqpLYBtQz at 3eS04mG#yn;`yUQ$Fz5T|G6}RStV!2yGqO)J>Pn`3xY^Hg
zf9jY&2R-u`p{@EhW2WN`@%!*vx%pjw;^;;XRrW&njUhB>{KUJv6wcu&VqjLOMtgMq
zSV8iGiL%A=jE-GGb)uNZW!d9-$?&g=fpq=aZ)=q7ClY+RPQ$!6Cu3P&u`Lp>!W>7*
zb0fn_>DiA22%G*ahmC^e6LzW at mQ*Dx1>#391U{@nT=w0W&VHN->X?Tm)KtJlT3mMs
zIl1DeNCDf+YeaX)v{_{L$pwOwcf>q5b0j)V&rN;BHx+;YIJxG|WE*){nqkj>cYFq2
zKsVm^GiQG8=+huc)DQ}8lagp`13!nm>$SO3L@`u*+Vp^j_T7}h0}Y%W$oK9RM|W@>
z?`~!MR0K0bH1=2ON_$;0OcbzzZ8Y|#d6Hs=j=b!X4z}v*d9O2@;2%7ct6Z~L+Pjco
zI*2(E;P-XToRh?Qz1KC{8R^ceIzx9$vC|YBg=yPL{;-K?sh?t?`r3Uq2@>v_J48?b
zq^fco64_8ezB_ at lq)q at Y(gOz_Sgld~f?)^6?!NImq at OO>=}K&qb&95nqa~S4Q#2IO
z`F*VhrsLT<j4Of3NyqvHw$^x_FLe~@*qXgU!Qg$YibEEk4`10Y2=nbFH4f)hl-#73
zfKP_i7&U4$s(2>`&)Nk8^}}iQ(3nf;kwv%Nau%V|tmTxrMKk^J%Z0JyH#}ctUHL#(
zH(6!1rKTv+ML%4~a2W6j`$_lAfgP77cEJ^nzl2xCRRjn&-|S*Mup8*9N;oZGyV{$p
z`{`Xj_#fHc41NgoAdfc~L;<v(u8Aha+3ZLK|BH1?{3-}u64{7=nPChXd0UDe;UEM3
zCW~43bx!@dygm@;ht@`<8Oq}pz}1*^yzT3+Z%F-EqEoH0#?R)Fb$R;bn3a^n!W4o7
zgdLJN84tE*$#*DSZg!WrBwwHbs-Mgi5xf8k50^nbqZ#}Xj1ErcDxVLfo$SxFcymb2
zXPGKmTNP+57+!Wud%^Y}F4+UiE>YCoPx(U#Tuq&i5kGpHuD1dJaNBRJ#3$qOh_M$X
z>!{@dz;&~WH}WTUQp+uG2#u{oyK92#Rt3lLFJ_A68DRhuSIfO>;F-!8;$PA%Q<u;r
z`kPzHdiCKKK#lX+feo)WK#}(7)L^msW<OQdzY8LuKz3*R>gj+sf-O|;VWp2P^V_o2
zh%+Mz3^uBNLPD};nl!#wjhI~sZ_udPJu2-j=06rN$qw$)Q(|HmYEJe#VrKicS{-KR
zW8kbS1LC3Xm|T`4mNuY)M}#&nABrb4<dCB-e at o9AkzRVLv30(xf=$f5^WJ?2d=Ph?
zDV%r_ze(F5nhWmR`nAd<ZQ%4CBxEhHjv6HCu@!x?ZkfMUKRryg9u*rU<8p<G81SHh
zH7STB?a^4x;0|4xDbJa>CcYar=L;;?E*x$1-h)GCqZj8C26Kxdpx;O?a5~5D*~rI1
zRoG&boVU{0uitfbER4vOlmhi5E93bZ&KTNDEPGPDbEhU4)y<L>;?oMyX#~zQp|1M!
zU)7k2UHLejO`w$=IQ#oEfs)bFq48aP3Z*3 at 3awSXa8=ZhK!L#?hfN^)UnZO&xve`=
zAUUdy5x#7!_GE#fKD`fwKFd+I<_bCO at P#_V6@$un&5rTv7HcY++gjVX<b2kMvCS>w
z@=IsmEUZ^*FLF4^QvIi*URF<^#WYD~!-`&YB=P3-P{lRX(|JCR3*`m0tiJ!NG!@7J
zKIo?3EQ)2N&Mv*@h~&e8>hLcr2eVH~3S=a|-$;1B at j^(IHdhz(HOFTSL_oJG9AeUK
z`o)HV3aHXHMsO@(wOyj#OBkJZL%GbMME2G>KxK#_Ds1<!U0cMHq;^aQDw#tQu2d%(
z8i5V&EGSWSB|BN%nn!*#fai2DyXsY~ym4_+4fpA4+rCaU at 0yym6*#l*!ydsl7G*Z$
zOm&Z_KP1B;#kt!z>(KD^^lJ||9=#FfP4q8f46+uzfa>z{0!o0^M~kF_S`9AyF`XBe
z>2YVf`>vhHw-5EY$$$-E>YexXkhi37cSCL<<1_FY$tOPcZn?!HjMcoadkHou+(^Dh
zYj&Kyw~5E*vouYSA((5%1lOKT#~YxNT3qyurMPO>{j9a_`hF(}ewu6qW;QtV at te7&
zb|(t1RME%(h0 at 7!*tTAYjsjkb5fdK~t<5h4mdI7+thhYwPzNIwF|L(eF2YN3v+MoU
zYOC=WHRrY$`EZyK!q~O7p^1IB8$#MG<*a`Cu#1y*e?-J;8V>J+$O?gbi{2vN$B8|x
z(#5}{^8djDx3Gl`oY~BBd5P&vH7Hh4{v`!GI1L|BBE$PA7gyGl-h<s)uaIA<?CU3H
zsQT;Vc_qPx6+_3pGDI*atHzn+)9%>Y)%~<2G~P5rJ7bO2sGDmRHqrXYDXb at 0Wp_fm
z#Mr#O4 at MN>lK0Fb+ at FADSe3`|WzE;&646r;+4?w)jO&nbl=;pbXk*P5gYlLno7*@o
zZ~GpV1kFUT{)6+#yh`aJ-2mt02YYHbdVD*i;DS4+idX6D9}qsQE6 at VFn7ZQms|nGw
z_(kIfw=n1;9i8OzWv!jcYk*Iinw%h8Fi$LG()K0E>-D?dl`O$g4ka?*Ii5>l_w}-A
zK4W*?oGGT(aH5 at Djq+q<&`av47wTkgvn{7$*|b4(<BO6J$3njcSEh|nX!Xko!bSON
zxi$yK418Y$oYq$GJS^>65Byh0R$UziF1FKW;<V0AgWUtk_6n2c=Ki+2+{GKg`+tIU
zYNdBe6^Q&A6eAi97}hE?{F$J)x(+rvXFpTy?U;W^_FZR?n!SX8&0&^Cwzh6s_Z1AI
zR9lO_9`-tyavcBgh#BIdj#?FeL&DMYr6Sa<te70`&+o$tnczLm_MMF;r^jgwS`?oW
zx~u6JyuM2eoH#ED;%|kf4M*lHEHD!U73VZ0@}};~VtqivFusv(Ph2DA-ju@*gQE%)
z{!UBOdM}J0CNN{9bBo{|S#Z%ffwQe7ba0W3cy3WtP`3yBN4B4HWB5x6k`^lJF_!xm
z!@oj0S-pdm;hxb8X3pgpJQtsT{JuY+rK2GGX=y>=GhE(H3fI3BjX;S78rQKyQPLoZ
zQ2Cw(as40yI2-S`y~fp4_C+HrCJqu`o1)1YXMf2RE5|(fGzSt1>Pxni!`8o_T_}U&
z$qz9c#BFw%L4DbOrq8NhMN>j at YHqQz_$Z4?Rn6)RvFWdG?}*YUQ1EA%4sf#GGp3Kd
zGP(uRdBvvNdtG9#ipy$Nh4*pJLg7_Dn`NM#WQ&q|vuXZ=tYqeSNOiq$KRxP^)oou$
z%(()l|B@;rFP9_4nJj1H!sVg=@P@{=C=T-5d~MCt&ohV|t}~kQ)Mn-IdeAvC<T$}V
zbo7*VQ0)njisp+ZLr7jjN^O$6U94vktygy9#RB-?VeGXp_ZlkMY-nr)gtYX~FfP~X
zEMGSHum<2w=K89pXp8=BuFGm)BQUW!YIsJ8O!Mf*7zZ%bthOQk>tFs(Kc~+#%bqXd
zv2aDiMI%2as!uJSU2`~)!>HGs;&cP6Z1?YcT1%*0Z9x;uhrd6!ID%=&8js2HU1=B0
zat$b0g$gSKA8w?*I6q0>gm{6EN%VdW5$LuP{vt&E0g+PhzU6=rNgCIlAPZjYUgl(;
zPWzXQ)55LI=$;1T<2}LD<M2Dtc7O8M(qYy9mkdUsss)8n1Br?31(>I+7Im!<oLdI@
zxpxjsF6tv73y>&~6FzUHbNLOs+ugDTV%AF&z+n$I`?F~&=MOG7S&zf^EKg>HD-mbM
zPt)^_5 at U}!urg8+^UgNDMK+;jq=oTrp&HbnZ&x{grXmgWX9O<+ZwUGS6z<N8Pu!)A
zHGmD!05%P)RR`;QH&cS~j^X##+o7Ynw__)8frlBhhzlEt$G3Zm0?*go{V~#-5Cf*|
z?)*g01<x{V4=u2v6Il=I4+Jk|cuUA*?d^KaRhm6Q+dHV~Xa%Iq at 8G(4 at d<sfg_Zq?
zgJ;hxrspr)?Y_uN8SpL$%|{WdVtqME1)P-s(E^MJFnzX<!{`sRzg2q$sB(WV=d}wu
zus=bKCN1e~c-SC7>yRRajW&*6PW*1DRmi;S%`~Mkz9;mM>S3yQ$c&AZ^FGRzkHHHz
zdS?dL!g%#8h`C^sW7k?HPLJw at cGNXt2EoOMIoJ1`PsL+!*BYI9o>iU0`?U(*uj&u)
z+~_e5JFI|53b<t7<KSpH8y2c#2xM$q#zs?L!RLRl4%UblFu%!7g}Il*ivXUHf~`dT
zr_&BD;|ioFi9#GQ^=!Xt5NI6k9>0%YY$`BiRPX%!k{bPmI|Zg)w|}sgTg%vNyvkzV
zYd^^U(ImZ%(MDqo1V|xLFjteIAc$oQDz>FIdF3)NhyX|taxSg9#SpKgUTqdYDY|br
z{We1eZ`FB%Wy_0Nb at EmdWB7|y;g2Y(5Ht{YQ+ucj at Qhiy;rac<;~0y5&pXCy4KR;!
z2Kzl6WqSUH`_vJg_Y+T48E}oha>d?BmICQ=rI+QWRc1|%JuS(;4oT?yxL|{bfSD|9
z>d-uU(uVA={eW|LO-r{6X^Cam*a$ecM^C#?#-J;Ro1c-EkxG`%D{*yk+CN{75*uD3
z4{0kZDytG#M+We9(5){nf5S9g8rJA3`L+C?78rOQZdF*vYM`8g2=K{Et at VBrX<A0c
z7@}HkMcFsI`{iXfyiv;4<)VfhFRo4hWBDK`KB?xo$%h6ja4 at XTu4g^EzJ^uHG*6fj
z5zsN2ake8y^_#0mPR}(KOG<0*Ssy*$d|gXp)cFDsaGxGgR#V}nRah_yUgVgBx>}1}
z at JL1f()<8IQtrcUy8M5%{bgKK-4{NLV;~4pq983IAT8aXpma$}3kXAZr%FkKNOyyD
z$1rrq(B0h(Ff<JF9B*&+{{EhSym_8^!)Jy$`|Q2Wj<v4qT5A#oLMrdYox=7F?fs~e
zUmc&;+1got)-VaE_#r`8d<)L3f#~U_M}iISlDntXNG5Pcjad;zNm1t0hpQ0cy+RlK
z690%yHSbYbpg>$^Y<m at c9V*{}c7l4Gs^|}uZ%3rShy6=@wU=@5Jk4c26*Z-I+VOdc
zba$UoeD2EeC2pOL_cGwldKhD&9Tc5OGeXsfhT>)gS}5*(=vc6v)tM`FLOG#x`!)E2
zEhCFY-4Me;4-5D1Qa{yP&0vFAy#>v~uPv at 9Pa%6VM`(o52D2Udf66xqJ|o6ys$_9=
z6cc{8^JYUSkd<%Yu3DHGJ5$?p0gKjnluu+6Lr~79Du<F-vWa(_c+ZZ}OPz5T2|A}Z
zn`#3<pFWgch_LFus5-AfX{vNuc6G8o-2X7OF3_ME$>vv`mybQgU*}9LIk=Dxz_wcc
zMh??}Ky+{1bNw7mkJY>1JazfLfb(sfAe?>&<8h`DWz|N*NppV8WUgt8Iq$?d?|9u1
zRk4yu*+Lg-fdW!eZPMH3)}2!dj+2Gr0svCX_-rwfbqa>m)_tD@?P}cz8(V{ep?6S%
z6x^(vy)l{MY8v;ReR@>=p`78D#Kere5(Q$R(ycepSXK1q>Ky}9t&IkIW|Z2i at 8IJ7
zny={UWI7IAx1|i{Aks5i>WYOw==<fQg_5J)zo|2No(C0bmq+{mQ*EL;5C}}^n#D9H
z(mAbZP_HI}yDnt-c|r!RZ(-Y|lXq@%{Srj(VF3jw#NM_PVWuii)sgRsdrnik)>#eb
z6J(0L&dodcAxfYy+FRvu6}-g;dANZpwq+#Yb$5};fWdh^LB9W862_%0Dh5zrL8Sy8
z97iV7=^IX at sE`-%ly=xVXz15M^_fNms%i93*>};EIZ#hW4NeY8S1(b7<*F>H_-lv&
z1sg<DE{De}jq#j&Coz&Q*1;o7&UgYkCTNm`{MI&~JK32Y{M%asptn?D3_0yzWjQLD
z)4(tvLa+Ow<R(8$g%H0u?5#IFs|G5O{96knq!k77cr@<=e|EC?p44z6EKB7r%HlSW
z=}uj0=NG{Rhv638E%i{r1-~d0dVV*d@*|WFpp6$t7zDMbyy&y6XXqjpA+x3XK39C2
z6TixxQ2O+Jxplez>=yRyUG)&4h=_uc&l}q5I*iT379hiVi+g0evIN(EWzdr$Y;Z+P
zwk7Lek5j?oPbrgd_4idpufQ={C{E<XcXR%UEi9B(+s1xYWBAkYb)e2c`S-Er8~C5v
zDd9CSh+ZVn`m0|ERvJwc3S>?Bxw$YVQ03!yF%u;_Wm?2U-YdO7H~d*UW!^T2{FO~@
zA;T}jpje8LGgHCMwK0D&S-7UeBsdRenDlBa7!D at uZeYSyMIvrvl?yL5)o%SP@^TN|
zLi^V5 at 6zwS{{LGrrU^yx*E9RoSIUofo}~Vxv;Xs{Im#U%kMrL)e|{Q{^_#o-{ptTx
z)oT_f>u&cyBqy(0PhgRKbZ+1NW2IBRVsL$ZXSNpJ!y=TO9hNL~cA=)rKCwS@<DcPu
z2W6EoN&r4vzfMu~*giBs(D9f8A5|xo+v^OvSEx$ypI+mdI!!x$(%EFR$K#885k3fx
z2|#ya=jKjH$j9_ZEm?e;RH=`{{WDWr3+xDAv378PA0NDY_hEE%=>M<?{>yf(Ki2s<
ze?Q*It~1Y<e29Yn#kjDCLtVqwRp(s*B#F!}t!pZvRj;~bJ*@mYfA<zq+$lD8pD+2o
z<*Xkq{%`C3V^dZjXmxNnL6JM1tx9mpN>6`gGCTqVM6p-1nC#gVKU*07_H8iyLz1tw
zkVf5cD>YZ%uT0Z_yHd%Ytq2gNrYKDfi05Me`v|8om7335()HN{nj(7Ft$C!f%Eq=w
zJ at 4QBg4gQb?ht~7eUSf6f+E}Sy4J!?M~7VUo9y(!Af at QNQyBj0M!s^M<${Ox`fhDd
z40E+YQXDB68DZn0>e>EW`~3Xf*8=Xbt|!}3b6`iK%$&-WA-9u#exu#VP%{2|sP{(4
z#umH|7CTOM_^XgnF$o6dktQP`9v&W)S0*Oi^K)R75A)KP_pnHx5EDO(9MfvBT{}qg
zMv at ARZl<B$&XJUtBjRwj&dCjBQ<pv3o7ow^aYsz6sHs)c(#T}?Xf-;XTvq0*UKad!
zhJIvwrK_vU5}AMZbayee$v>|UFWq9IgC at iUSsBA)ZgF!-UiwanHdx4Uy`{(lt#8UZ
z{<*iew;B^tW_L at BC3x$JkVVU8;&u8IoG>aXO1*I&IR!>8#<t=0QKBuc)CmfnbU*HG
z<nuf_UJbzS>DAocY!#=usd06Xu*S91OVK%eX>eK15DlC2vc4S6$y5xu at gw0b0F_Un
zD5x+I31*uQ?9W*iF&|IgATH~xjF-GeE1JFU#eF at Jk3SlvAn{tUt?k3ojX%2{!p~_y
zoF+J!d8HGO^Vom1U;b+3A@|=|t^YD=`5sDOZ$8S?uFi55`jJp3Ps3($E9Q at 48+3P@
z27PqObL2Tev_MIo^FtCN`{Z at lii7nP4NGzK<!h}Pduo$W34=SgamXhdb8}1VWXz>W
zU6<0^{c*?#1E3 at 5U!HIqDeLK_-3bHf(=vYHaX<K})eS<&?C+Bx4Dxtjc|KGokDNZD
z{i)#PGj7UBai2Cu{I at 7o7hA~PP4==fNfdEr2DWGQ0KH3ITT>&G at G`#kO`f8Pw4tpp
z4U58AZ0P!Kr+SmqGXHIq`%m-p3iApLj5?OACwql8O$+%(-ZMJ(K+pu;>_N=m86H(S
zIP~=ikYaC)cH@(VMxj05Bqv1f1+MX78kWWXFb#;eu at _o6+$_bXIbB(Oz6d9~^(s%9
zfZ%aVbW}cxsweXGodC;3-<Gp^&&b+0S&Ayks$*kgO68?PN%7~u&!m5*RF at Xe{VYXw
z)pyh=J{N9$e0)_>QPU|b!WUoLhZ6x`6k<9 at ad-zGjV2Vv={$;A+ at PtXIgtsWUXb47
zH#cwjYJ>0#BNH$>3i*z9{6h|pl9iQpynwF>EG at J-`FiHk7GYGD;`K=|W~XZfSdV-B
zP9ynR+FG7-HQjaMNXIp)x|xPI&pdA0V-gb+QExX$02>$qxxh7!c9|6{`E_%1_E{CI
ziIO~w_Vo0~+6jJm=+V^GJIcvb2P6*htsy7teJyRDN*-N}nemW@<_CT4w0pwiocrck
zWee at E!X^K%94g}bgLhsXC4n8JzRA8qCTnYHYip*-?aBEMzH+?;>v9z>9FPdQUGzkC
z4+vS^6iM|kq$Ke-7Rlj{6#w`Uk7(&dZJ%C+Wr$;&IeL&dAEH{EK(%W|3#A_<6+yDI
zjgHz5&Blu|Fppsq6LsRS`9e%VGJKM9$9_}3iF##vB2HUpS1}sx4>H3%_~4$t9wL6e
z2=e}#+>%tK&aU`rjk=~yR!P2u<6zip`QppN9A6fQ#6U8iO at Yz|w6CS(2>Gj$*srw_
zZb*zXm_N2%u4Xw-C+WsDRBhH-V_B-qjQ3^*PMUkaR^;L;yPwYt69a=qr_o})NXL0i
z7U8>toD`GyzkBb!vUrAo;B4OgZ_n|?u_ss#mf?2F^p83Bs7|Z)hc+PR!(Y^Nv=4gn
z*^QvkzOF%*5{oNr*E-$CyZB&Y4&zVIhgpiXo~>f8Rc_Ume5h|kD7C*4CFQJs1d;K&
z)|blvPklH7HioPkWqN+kQ`?1eOA+$U36;eeaDIhOmcoynRg6lFxx`l8TF-Lcglbfg
zv~Z}E5>pfrquma4E?JwOM5{ehHJ_cG{Uk;g;+T|tdTLvp87*ebL(11FUHL{sTg9+s
z at -Q-o|E<aJCjWu6L$Kvme}zq}>j-L*4n#!W&CQL7A^TF;?Tm=9eW>Y{bIl#>yk{?N
z(|<*!zV~)$QpsF0nAl@%(u}dxDWmjk9<0wD{oa84)N=HNSgF{%yKhl5DXiBJB`>RW
zRxF)r1s9Rm=P#@K_M!dIzCGwZ^hK2G)mgDFm}@h}Q>I2aPjS~v^0^{Eco#;V5}xW*
zu2!sVHhoUALU$La+xP3W*fGj0TwYcN)vaBEZKxFmSC`9dGe$m)`_40UIEyHp&3F$^
ze;YJxUG^FKl2$$?u8ht_EPH-!SH~?50wD_Mm3`;rL>w9v#QvzCEooHcOTOdwZ2Jg2
zk{{R8P{!5ZDU&Qx(EH#3%u&E87LuQkpiyW<;3*?B48DXMxO?5X|GOh71<`qA$H84O
zEL6G;#|JOgbt-cE=ArZRI`rKh;fXDxS&BQ_a%f`Qa)slKb%rl&J4#DS9_mmJq%<lt
zXrXu{C*6tqT%bgBqgYintmPjy&^J8GhIh94r~OyWty$6>%*;Z}%sK~|uPBwdQnk+K
zz|720ecHeFXd12&E`QJznV+E9=8cAp%~tnZh;nIf#!0<^5F1#eJs5&4MOz17(Eqf%
zN at hRkZA`$ZA>y_H1l3pANvE*6jK?`Hy{h8aWPL%9oGeqC2iA_Z!z4MjgCLH?9cP|D
z7o!+8-)Rx~CUvrrlaY~Ok}rM29J4xQH%p%t=(o4$lju4ANS2s0eQ63#uz3pI$g8N}
z;N$+3BhCu3G4=D)c=`5EOA0lq-pR$2lkbU{x3|-|<<^=4v(2SwMi$<ZKYH}0)nv=o
zPBA9v{G5lF`CZG1LPb~1I}BfuG=<EZUJDCUx1IF&rRf~?_J<-6n;)u$G^6|W)HKxW
zw}8SKX|3X>h>5AGto|@2xFziG9lIVkVPB4pau8!P>T(sU#q_RWWPQ62=HcD;n1&dg
zd{A<<5S3`Xcj6E;QK%i{r`uW2X{eOl+t;IiJM?X!av?!FN%PQ9sf>wko-%!ul!ZkW
z#yHBM#<z#~COnxMV_HuA^U9J|6cC$uE|YINjy!I-0B^D}kTg>1CVx3JGqbU9h4Zoi
z>raPPlWtGG_PSoBBQAQP&;f-q7puuj%7Shy=6$?ey{~~RBqAn$vItt9C+v?+9cyQa
zl5(>*78Mq9BR5&jmO0*?vLhC9+>L#cF4zYJoDmb at 6L?pQ7*{3yjEsX+k#llhD2CNe
zry($XiCQ{lOU!tr3K4^~O|*bcK{j2jls6_b357cDtcOr6FSjB+4vthtcQz+(JhR}I
z6My=Mf@=M3vZkiS-bD-#jfnEivj{DIkMripjRC5Rigei|Ud`Mw7VXBd^er`+bFkI6
z+hbiWgZcEXE(si*u;jTqdvgS2D<DSVIVf~Dq2a at nFD4=NL&?aFkd6mi8{zE7K;r2<
z#3^M<lfAuyh~05-vct!tUYdrQS{BH>f+cHH2-A2jT>DRz8%5J;2a3(ZJ9VfMTnVqZ
zI63>fyCZO)MM;ee4_nUGAr at czs8%#U$|;l^UH4oi#&(@BfxYRVuNISx|N5Bul!>x!
zW(MRj*#T>`pdYLrh4m-Ij+ss1>@LJGAHG=Mf7h4fd5ueGW$f(wcl62TBHJ5FxX<+C
zgj_`69atfqc^6|&J&9>1&PB`-63i)=Bh5|dM;iOHUb9y*&AZgq%!w~;h$ly4io%G5
zyT8ZQ(ykooa=0U4n!2L}5j*tq$q2&tY4wLZ300P`p~~_ at 9!E#VzD2I8s;a}o`@rJf
zMbbaQ2vDZ)b}<rWkk$jmc#v$hWHIP+78E~@i&N)jrK`<N$lq`HB9wo$c+)7ubG?8z
z_9cI_gNWnfBv69Sp>y2p;9#iU1zv5AVIV{<d_ic}n)*tW=+B@^>TmP3VNrfu9wqY9
zuD2{5Q=uOlb&*z~k4i)Lmrvq0<j*tN8n7oH%bD-=y0$p7A5k)_^E=rQay=S#POL74
zHRP)FI+Kb>3|MMA?y;T_dHISAWm{+#&O8T3QQ at SMrCN+RW4t`hqgiSmV3jxAc*Avg
zP>LUxEC9jxgoSya#d}_9N2T`cR^-{;YrXZSW4LdccT;J7f)N(OWhXP_!d`LA10_w{
zwDO3tGK1o3*h*z|PF8OYi&iaiAS0gIwpNvt??IhN9#Dhj6Xt}a*~wktP+tMDaGQ+@
zF at QwW^bC!RRIv+q96AcleeTX7vwPQ8Xk?C<w at z4JU(IZd9p+SJc#$Co=B!Wc!G4KC
z4rTURY)&n(t(%>>E1a}6&Z(8 at oXkw)_IG(@<vrgMC8fDzlbuSfHlXoCWfx9ScNkQQ
zRVzJaxV(}CUZY2Jf2_46_%oPK314{ILcWrck~Wx6rn<kHsyIHL0UDnh897O0P*a<T
zPvh)~!F+0Jy9Y~{<<cj0`$|&PBo#&CexXupyEZ&LOfD46b2XuRcxdwlrX3?1 at eGUD
zQ at vWp!&k&+<+2iR-1C($(VmuNuH}zExXhx!pGS1wVDBNtU$*_-V$koB9s7Py!*=};
zB!9lCGa7RLY=6XR#m at ow{7+Y(hTrA~uAw*~=5WWm2t0-2i=5t+YPS9T#;axn2FKed
zZ>pHhftm!`Q_{~L2FOC+R0glmBBi8cD$MKtG?w~F6ix7vV-a(aV&15PPtCbcw6MEX
z>3`ay{7h+y@<1_fY{qGyc}oS@)4wMDwc88hgS)`>3EWmk2QNBwzC}fyY#y%Us}%#!
zXWKxe{{8(szwh<w3l`b2!ekPU<7!(em4438BEP?07-SD@{(KF9 at o(D?{^#vi6w%p7
zil&tsyU$nE#z;6G^Zz~76>t~t|7ZQ9;7$6BT0L_l{@pV07lTaTHO}An|F_2fV_6iG
zXRpu%|9<xq`r!YsOJ8kkXD4oz&dttt1e2<61hEupL86^ZdYnG8sZVYjwuxPC9^#jd
z{2eFCg}1B(f+oAo>`)X=o-}<Cb6QHd>T%s^R5-oi&~t>RtGmz&=E4(UD}SVR(@<`F
z at ndt-xD+4tZ<kd2xh9 at iT3ULU&n#~38+{&Kbvkvd(w)e^aDd2Og(WAmf|4h@|1MIL
zov7X?$DW>^;>gMDG5%u3ydyTri!hDCagE_ at mz5}Kg0J76{B6FAFc`~5N$~l{{&e-K
zD#g0zth{T30p&Yf<}%XK2GPp73ZDJTwPKDh?S=x&K?6jWECXY*YFScIS$5fMOCyBE
z(B$fH#6qi^6AvE`u86+=g45nyO6#fjmoJ`MBjs`@1Jn=u1;aoQ at 5tPafh|nnAvTI?
z=iHnJtO`qphe>;WJEy46qW3f6s_G(*sQmgUWF|6a;Gt<4ff;>a;+h@#zg>MQPei)h
z(cG-pzpP$0ygTp0N$Hi$!|kwcUTADtWVvt2Eao_v3g~s_#01p1lf+q_>N1WD5tTPP
z+OytU at 2jhOJ^Cmh&z?QIheNTqr)@iT<lCUrUhcH2>v~f5)&mWDtx6VKj&yc!efbT#
zq>LQmv@?aVYT-7DI&HLjJiJ2C#>uX<v{bLfP%0+9S2W*)d2yd{Tv<aHb3@?YF1|`;
z<7w+(UGU6;z<t71NSpu<%R8FeYQD;N=3?*4xh_-8+7N&?f~cG3`rjH^v6NSH&&QzE
zg*)hXhw-L-`_^(JvGA?Ct1A`rv9kjW&eM&5pK9u-A!JhxkPZ~-SGm;*m{KpHYBS_w
z0lqO*3Nv(c-1U8{tvz{X<w>)h!_Fw^pi8vTpEYcC2A9pO$7=5C0WLqF6pbw?V1)Fp
z6<F%)bym at b%Tl9754il>^G^a<jozNyJ~sA at Cyc(!8=qUT3RA+v2h%M;g}#W(<Nb;L
z%rtuEBFm)oj0`o4Y2I9?)3YCndG(ErULQYZ<_6sUB+#5p$;YlV;!&XR;_j^UXLEX&
zG8q7c|Mgm>Lx|3D<Z37R<v=x~zkmOjcl-#Kgxksm?{TY-1v(M$UHQQ~k6y&j>s8Xc
zKz>Yp9Q77o+4!#ko({q9LcG22ka-AEvBM`1 at uOuQvOuBG{&=qYSa}*%GI?#Q-*b?V
z$y$(=y?up7A=JY#x+4VeFG`BM=yZJ*U64zW(rQKX=U3V4nv*piXU8^ER^;DLPq at sq
z at m2B^vqUazcd6}r-jI+aj0;x{YrjoXAQiG59lQrXOO56V#Ra-1R>jM}0nd_=P9cnd
z9Z!{)mckwsF0Zej_D|@tE{TVc3%eh8L7_#Uv!d6ZA4|KsbkIH*ay~zwZSTdy!|P}a
z%E&Mn=?D=qQ^q`Cpo#$rxZ$}h4o3Kgk#AWp3=#+k3cA|wE$e1~2eF>@6%<UKQCQA5
zfI%=JNCfHtUovn~)j4fx at s@l6m8Q3K(9rYIEFX at PZ!o_R7bnqpo0~{$WR%2Q9vHI7
zJHUQ8n>W_h;fLE|sVPKsf6iy4hL_aomQ5~f!RxG0hK9=Lx%;*A%{8is#1-IFi~fi{
zqN9rey%F$qUAqi1n<(0-Gt)WI{+fvP?*lA($VGXQV9fMGDd)7uWhC|h;xF%ZOlG_<
zHg$)El+Ok_J7vgQJYUw1gD-~talk?v{T;sT`tZpe|F9tzhmD(+`NjuEowW{2ciA)L
zZA~@8bp49ozw8D3_>XsF=<B;-Js}_ at 1nKKPf7sm*?~H?Xey=$8>pwmgII1v2{1{+}
z;x>ECNy$mfF{Z6kZJA_4b??IU at dUUhiv$^*!okGEBzx8vLc$r(ZODk<Ktyh{d|X>9
zdO0;?vT$DO09$I(%Xkn%F;^kEvb7>UIb~Yxz%H<SCU`|Kkl5v3 at 5<mlcra9#4+eva
zH5*<w6 at L$bHa?PCyR>i{_qQ0<VE!<ESZ%&E>sl#dk1vm2>j7KJJ&b&akMDq_mVnxI
z at o{0divgw7<D8Q%lZ7dxq|hm)vVN?qEwEvN?YDWBW0Gag_q}N$mpE)?sFs~cA$CgL
zwGAWLY at AFUUB!`v{fWEl%bAa9>1nE9;Spl47cS#YH at v@(un&UA4{Y$Y*4T*~$UGOm
z1S}c04K^!vJQ&(eqV<`?9j<x3r=!gmUxrty0dYCepPP3PkuaesUU92-bBTJ%Do7u-
zZD5Om?`R($R}=k$&uO<re_t5_aqz(<5h3<`hbR^W$I*g9UZ{>bw0yl)=h5a9KDgLJ
zi at iS#9{=R&u^~g8F{3Gto~O=f{2_(B!%3r7F$@37>HElpv^08Yl$6)jkj>zyn-1=0
z>3e!++a#M=)IOu=Medh_`xuXHw}#fE;R5Ayx%#ako1NN8?4uZ0y!-aGiGJmeF0BGz
z-sRn&MYmlvH#b-9ODLM*mq(}DTXFb!Hon|0cv93=-he;<*Agnn_JeASgs)mzt>!ge
zvd-3m!A_<li65NhD}HMMAaBx?X|ghnj10pZ6sT&-=w at sj9BplEpZnzAmz0&3myRhH
z?<lQ|VvgnPKUU7l%x1q8 at Md{?+w?M!<{Rka(Sn46!r<3ikP3qAUUtQi;VFdfThfna
zF)VBidA6QevE27!`v$tMGZXse#tc6o8#MBH`1#LvC;cD*5J{brJ#<HHzOf=gaC&O0
zP?IlaZYt(m^bOmk#jd}zuc9R3>Gq`2=t0`<W7KZGWMHy?PSX5Bf3Jj){!veGAERSl
zq!jf|On=Pwtc(6iI6SdDw7GT?{To~Wp9MXN{>tpf<Xqd<7Kco43Bj!}el(FWr_N{C
zK>vJjvlJgAS?O4LeIa$q^y&@Pq5B#FJ8n>V(my9?6ULTH at KC<bdUvN<aXMq{ll^sQ
zY|DfCSLpBPRr0xEvo$W5 at KPh=&1LmS(jcDLhDt9A!5waAA1!8DpPJfQreyAN4TZPs
zx+y9T(6O-_oM6dxGm>(0l=D;avuZ_;jQ3xh))EUDxmTL1Oi4!%#EI~m`iD%|vAoV2
zP8PB`F8O at SI$vRb at vSl;luWog*m7xelgDekf{*h{9P*x8(c;PqK0dy|b4k-m*Rkw{
zRxU%3=hzRGn7(8Yit at eTqOl&%oykLxd_r5W>T6(oDLXsp24D;}3Rzz3#!&L5)%QO4
z86Neh2dR-=!(YOOpis-hdUXfUa(IqX!upKof~5Z(?(-ez?UDQ(UAq3&yYf2q#C)y-
zks at el{zOVN?n=c3a27RC&Q>HXu&0c5jraAtK-D`Jwao8!yCeq?`e+mmV}#4+&~tJW
zgqL*AX|;@>^?EH32^rNZ<~{duc6IeB)KZ-847yNjFEjk1oM(%?p at n@oEPzch*!KTE
zYf%_7bG(yJ?eRqvPq0MIeQ)<(3>}nVX;xbxlRWEPc2vRp9%1`arpwttbhkSXLP5mF
z#!luhq-I<>4%=A8d(E`9VP7(ix7I6qi1HnLkB)Xc+2%Zb=&RT*pjx1sUwLCFk!5?s
zG20;S<>;lQp)n0?e%P?N*W#_`WqODt at adDO=_9NeZmT&lVLyL=ryG~WCGCV*^7nC&
zB;c at 1<b2W&`W*jSU=rf+X5n*2d4OUF$#~jQ9z2Fj&@s`oucrqHLyj93xMP_1S{aF0
zKMqbV&<quK2=6#w>h at ZhoG*wEOlHY3$An!vwD{N<OuH|{sy{q(VJ`j at oA5tV`YT+`
z>f$@&Yjl^Z{X5#{3tj_AkK^F`x^=Fiu)r2_C%gOa7Z&P+NZ4!{5$8*yS_yK3%qe`&
z%d0`r90h7>`QFJO50EwVuVtUR7ni<Bv`q&0^(mIPZ4g<_*F$VJZU`w=WTuoG(+unh
zEoVzNs+SsHE}=BC2`HL67_q4Dt*%O-OG-+PT~+MHVXA>E2a=b#p4S9MV1p~{dBI_^
zc=-76YZZImM#a8P)3F~qjYV5Rc8)!s*cy4trEWV<I&cz|=?y!mp7}g~PE+n?l6QY(
zefNE1 at O`x(xTz$s-|QDL%e<29YFcuYnhTzSdtRTCtoy~~xV at uFVB_An0405D@6b}U
zo$ZuOOa~vV^~UUCJ3;OW?31E9FJ3+%&#Qcsr+njb<PIj7V!u?y9wiq|k at v{q`Qvwf
zdQ6W_b_|3F$9c%i at 5&IHeL-hqDKv;wR$y at OsJ7=-3O|R|urzYj|6(-7KkP{u?%^gY
zmRk*&B;Z2mCS!iB*g)Te+eRTvsv_b2vxq at S4_?xmqqW{4Ynfd)hz+ at rYbK443$7Z>
zCt5#3D$BkgtfJ!h`}aqXA<MZS^n+gVC{3D3!;+4}5A1)2!?W*>?yv};aPv0^w=;@C
z?8}Gk!f_S}AdlZ3#fxwZ5j2mX^mu=nNUY;40hi0Z at 3KVk&EMwC<k75OIMXY?KzfvC
zznz<%#FSnSc8bWyvAORW<0T`LuE)<W8)4_ at m<`FL%ezEVVzXV8iW%;sCAzxtPTS%r
zFM9+;NItl3{QRvZ)f}gp%@mO*XTuLgE^)~9dVa2Iz4A~{DJx+pSmB(MM^tt#GDqIz
zy_pYj@(J0${!Z$vpEfn8kJ5nI`ikiFY at 1fzjA3#CnAr&fLDUhmo>^+~$Q$}QwP(8*
zL6bOBk&X?4uCg)GS&9g6neq~x#POjt`Dged4S8xi>n?(#NhRug%_?*ka>8bwP|R=#
zk;f!<OEvK4U7y*%=lf}VXaP6;_LUz=)Y=c0(+2zA?w*)%I?Eml<@G+_ at FnAS+MBFp
zfK}o6t!hIxQzu{PG=2VkO$og#-zGadrvah!BYfL~%@)5oOu)@%)R%f-<LEeFZ2=K9
zJBZBuK3d}g98;1pJiG*l%#_n5S6nm;&w5TwX8IT-=hI*K^!4-Q({u6cXP5uDlM}P`
z*Bl=PM_wbh9b~N6Fl1`%^Aw|H<v%YkXT~KREw%bT%Weyg5JelA=Zlg$*{Qh58Au!o
zgd4Wr3j)dg#H(|1My&DfgdGFo?U9m at kY+qKx#UJR%Vp)IZ>nFdyZCH^ut-9|>KHPA
zC&$ZUfui$+0HbJOBwLmP)qD2S^HKBA(9rC{A}<9aOHo7(&ttvY>KLe3L at GP)@?BqI
zS<QPWR97?0cdywRLSN2WGRwKHxU1%+r;U}rZ&m62$fh?EJ)unBf4)*x6`hRn1vDO@
zX>L8s+dJ`hl&^+IVD4x8g2Y8cN42Q<t?$gu8L<c*9EJd-JyjAR#1;pcUwi%fHAiAJ
zGq<4<IXSsp=oHy8UEWp)RZx4>m~557h9$&?UiC$a(|rlaUMLa2<_vQZ9{_g`4ISpY
za$*%;9dEG{Gw-b=5q9_T2LuFgXcgq%h)ARJR(VYnV$xb_^VlGESw)?~coyRvmI+8m
zouEe!f9(=}EYNasFhoUs%A~IKETSaklH;wZDKQpWG>e&Ke4n;9a}2|GDb2j^xXa6{
zx!ld1>S3Y8djFv2EIM at smGzc;8XVVr>xFa)+viIB#GVu>AA0Do0i16&TIzW=DbJ}L
zA~~7-{(aYBb)ce%_5IP)Wfl9%fuCi}wq}@E>9!6cGWt3J=Zw2p-ST62P;TyvpTjW(
zfnuVfvL1K#=C`%!inA|$6_-~l)CL)wts9YfVfYS at t4g6qOwFL(Q+2;S4^X{}hK5$W
z+#X9B{v+TMi{3#WpI%T%EicQiO|`(SFmSD`VMEa$W&riuO@!t*yGswiVM-)2!Z~#R
zA51<cELS?~8*pkHBdU#zjX!)!32 at WpF!(b5iAyoBLfoJ0c%^(JqSo>aO{9Y<{0`!Y
z=Yq(c!JPHrBgO~`PtygiiF2!k_MwAKJ#Pmp4uBiWluA|T9^rIce&isBR#>Ra=de3y
z*NJ^y>alWo2Q0Tcv!vb9dcJM7&<XGv{4>6GMw?=>f)0vvgFpIolQcS9$@}~HZqnzC
z=da%jd1ddvlp;}OPD4bomco4J_)`k-t0t|xT!3M&-FKetx1fi+{e8gBfc&4d3K6D<
zsAFI1z-q|VtcH%|Psl77YiViK31ocr4#ow3m!K#~=z6gmz7g?GV<;P%$TYegQ?y_@
zbj(0=J;!|l31mrNwR#7H=KlWT01C`kbu)k5CjI;yyZEWBZpm(oZ_vYlOvx271HWUt
zE}~1ZLRHv2m}MfQK&L9aC|%(NA)}6w>+SQeE?4t{pzxG;cf4*&UCO_T4+w=EIC at Od
zTpsGQWdz<bjI}nlUOQokx#2U>(9$BM%yhOHkX-2;$104^x$lX*X>G{xszjvGX)muY
zw~?ptvGTU}w@(djgHI{4Q7b(Q!x8+|eX-T6md-UPDZ2Rt{f$LuZ%rszh+P~e38?5;
zxp&TIN*p%&7R1=}<ejReX>ke{sy0Tq*y-r#PIkt~W~=>UK&-?U#h7Y$XE~Q*99jrS
zuz6V)|I8xK;=i*f>?aiGinLj3drg?L8=$gA6sOCL)D;u++nP!GFMZ%AX7$p^A>fTI
za9(2H6APcP{U?BRKRVt7mZ(hPz0>2Y9fJ;eHu9X4utJ(pQVHQ3oAcFO7fjhH9xqDD
zF)qdg(8t)X|HQBwLt%<}$1R6<Lf?{3+I*LadZTY(5D6jTbH^QuarjTnI%GBY61#hU
zG7a(d24YWp?t%BX+;C%_&cN>_Me$q%xAo+ULLM|n%R`2!t5>Tmx{W4trQitkb)%%G
zRsMzde>@2{tH_O=R26m@)94c3;02K(^;<ibHhlT^(--Y#D`Ur$kA$r&@?>PCtx}8m
zzB8!phxO;j9h7(Fo@%@8bSx<?{6-Nmo_Irs8Ct7GO1%3#fxK2D3#VUX1e8~Oy$Aq~
zv!R-%ACI?NbD#-jNuw3VAijYVMc9h)4VO#ZA=CNgWhlvXiYMTO^=X$(e%Hoah9-fp
zLKAxgb+EG(c}<693f+N7r=nU8P<aV>igi8TF1MRVwn9$0yqydMd}<dW#A!EN4aB_g
zgvV$Y$#?Q$p(V}Rpu_>j&2uVRf4C>!*<iJ>2U at WKPOR6*yTa#&_RLDeZC*0l)1cHt
zo>^-su%Td8ClYSg1c@}QSgI<iqipm4d$_;4Wl-YnIY8mIP;!s)ra-?bF5~L<9ftUZ
zt<pwWjVjNXl?|4WH6sDn0hg1=oEy`rQbMxCcq!=^dEFXYWQsVa^r~$k&yU39r at o3)
zCmXj2i{{3+i4^n4ItO$t$A3Wf?Z2BNJoh~|&t4kcljx``1T(#ydofc`i+L|N`3e3N
zCA)Om)dHjMY0D0fmNQY+8 at W+zPeuEj+G&gb_&jgKKEQIEnug{`j*Zf%t-al1w%)L-
ztF(~cerFJ|F|<OX19nWp)wfFN)x-n*)`iOb66B@{WNp<zvFAF9M5AKQ{JM!1Fw9L^
zS(%2 at W|iL6Jm443A&ov770%XV*aTGpm(?NHQsC}ofFm^2Lb-t|upiyIQM1FApSS9=
zI4NsbbOl7i#FvB{m)QSWO`+)t>9XHXLhsBRlR<OZAM)~4^g3Gm%4u&t^2}tVtGRip
z*AJ@)?K===H+s-s&qLfuxq#4GgS|rR!uHl1*&>9;$hp`@wyDG|rH0%aUbkQ}PD<$s
z%c(jKG=E5t2u-9)F}Whsxm}i`3+%?b5!qm}q>1SoLc;z-J7^a#-;PW-S1O7=MeRPl
zYQ+o6)uqUsrKPjj!%8 at +mlu+FOjPRXGP8G$<(ckJoKJyUSf-hGryy-|vBvHL7Mfg)
z`rnft<>mP6f%jm2$^IX&cd3Dy%LQ;!EJ{%Wz}zLDKk0rR4ZtQ7CUE(bZg}%E41rTE
z^bx`$0qcYCnyp)(>b?J1#aDKpJ>!&w!yFc&l>NXMCD^BJRmZzC)hRhAJls_LY%dc)
zTEZLUsHAUU(2P3$Ys(jj=CT1CX8T{%?Fj9+MoUE#2!wQ!U6QihrP7q=Ymv at dKO6we
zP(Oz{CGL8rhCsIQBTH$7gt<_N-QFn#@V%w8F;I?f|C!M!hKgu{23IitYGlJmXJ?Lk
z?WcNa1<yx>gxof#%fJs*XtX|sUPMGH;RUo!_L2s4=ZT7iR=x++;IPy`j;BH`j!gzI
z at 79;IdR-#EUrRH`PzXAbLf|g13sqBioU(w4BlV!{uEJp2?`vM^8Fb(uqqwXNWYErO
zX-`T&!Z2LTpIAc9H+rtXGBcl-KD>wWMfA_{mI~0d+<5$d`7aa{-_R-1*?-OQ&mXVN
z)ZZ}z at E-RT-{$Xa33&VF6ZZeGKdIio2?F4sukQZ8b?Jwn>>3J+&(KoNDf#}}xPz(%
zCu(ZyfQ00hJG?l)SUm#o$)(6XsVf+^DaP70y!1M2>Fe*e=xVwF5Mw(+#)te&sQxlE
znqc>#W-40j8<+RH74N_PJdgBqfYE(o`NadV>Ty!)dQJfB`rFy(j~{lqyf9Z-Z$47k
zM(O)PPZiyg2=~1J6KXJd8qa4a at gs+YxP0ovkdp-}Zly}f)`J*PaalD-XGw2+)!vGW
z2PNg!`_cl&OMUu;uY>|iT&#W3XHq{Lt}vO}=e?FT`dR%Nf#9#Qx*C`}0Jb at xkIP+7
zD%my}VwEDIj{8$*%k7w at BP~H|cJr=f%nMO`i>>|rdtnwN0&{b1auUrTE6|k#Bwlx7
zrUJRSMP#=gkd!F!T^bDnC{GFtnRNPqkuj(>syYzQm)RA6rK2<d&%L))8IyInE9faR
zwS%%FJ0BD-Q~<xY_K^QwbadE{;5W}|otIM$@X$mgW+>uykQ)oPM8yM>UhFf*!N;Q=
zE^<e2$paJ@|2PY%hg=0+b6Ow^Kt7@?Oy(!S9|JzOiUoWl2Y%P(H4I>S+QL6q=A-cw
z*p!r(QUWMocVAz<9rAEk#f(DOQ~&VI?N3$z%U&(CRRY0hqtT%j6`m2ZhRx|N at 2z39
z at C2)di_2;}@7ROh2`kqViZ(klY&JKV#JH?;_yJxadd|(YD18L3Nb*~;6A}&?C(QYI
z>gr<MZXc^_JFDx=JojNG=hb-lhoUb-3U*f!J%kvJaSJs at zPfZ)A`)6HoxmX+ltkKP
zlskH8&Ws^uc1HtH>h6r9XH$@UJO$*r^A&~(UnR at xwMb0!FC(@`z_j25SWq}UTO1=5
zl_*1eJH2 at ny-GB+TL??Y<8b?@H=;Yy!fT~Jt}aHNM4p;9PQ9!09BoWgWSlYH(2OBV
z`eCFJb`lTRvQ-Q-=glKHNWS>S1s7k){b={w8bkk_2tW;7Il#JnLK3Yz+S=^5xOZcO
z1b38?K;ZEb6X at A|Ia7f_Sc6p7H>IP(ct<pk4<FhK&7vo#Jj-VNaN{5zd)p}!8r9~L
z=UXwwTBRQ_Fk|r1oWQj_cp|{98xe=JrIB~C%dS7enfIGH6i*$E9w at J^Z?EsK>pvIq
z=Bvb<!4aTXR-L?_*Lq~fA|;&>X at Hlkc~xsBPTb&f)?j(}@=^~#Wn8NlH#gsmC^eW9
zC2!FQ*!ExCZq?^3`oJ+d>zR4v`$c=bH~P at V&W6V45vK-vbIXG$zU2P5&Bhk5f at Ek6
zl1nq_qj7K<SZN+!6LL-XP5<!B46O5Dd*c at pA{+3KIz2tTB3-?p#r2ULDCyx<LS>P!
z-F#a?d9VPV;49HW>B)QvJ6;~10(F62)%ZF7Vw%+f{0+b*w^;i4m70gA<{g4%v(t;>
zO)MA{z!@X%xDE+z5EchxF;L*)u{xg{Tfx5VM6(>9&_fv+VZX^pPN#`+`IZ}8Qqp>h
zJ;lQL3weF%=h7hg%k6v?xR9RjcW^>b- at J~Il~w)YduHBu)OZ5iX5nsm((*AQB^v!Z
z9<SnL2;M`(JhiG^$x;eGZ(*oFH_nLBzPwO2BrmutMHWj<NlCfg&wu$&wyR9V?5#`~
zoe#pd-$}*jqz-G>h7`aaALR$d(e`fCpM2DAU~ssI|D+Z{Ds!`^HVt6(>XkO)OIrZ{
z&=-HqfYtalkk{a*KP?N>XhaC)E5d8ucdn)80$;ZXs!CdD2+NT+y{mS5a`MlpMhIcs
z+r(Ao$;v;r%DgTv`!hf+fS=NXc8(SeH?VA*nVe)y<ZAF3m_Q=VQreX;QR=VHu3hYR
z-QtqS-1Oe55uRSDqeMqAPb32P+w`5jxV4Ssxvf_H`vKkZDMBkzY%hsyg;-M4s*GO1
zKe&iVkqxZhE|h&eRyfd<JO}oCm$5xFiIY$TbBC`NPSTa-x=$$3Qd2wZaqn)BYrEG=
z&DPslWqdyTTF}^{A+#ae$A{SkhFKyy=Z@~y2Xe&xFAe*i?bfpCp{N}Ni#$yM&BwNy
z?sdyFAPDXMkuns<&{CBk6l0sxOof9W at 2LM`Alg+x*XRIaZ<@XPo>vwPk*a$+JnvGe
zA?VsedYZrnAPXdFj30E~l$DkeapfWxmok_VRZ$k{C at It4&OkLVuTHk+iZyRYo}wOs
z0p%X?I&X$tJ}hDIU`fe$hfLmvasz&w*woCA4JR6u`Ewf?oPMMXfDF>ng}D5W)4Rj4
z9NxTX`#MWbRe6KKAO%hM=0Fhcv at m!1Pbm7>q$m%+W2kws{83;E8g}*S{9A5UYhB_7
z=e^V37?%FImU@%;X=3~<y`59C>|zo!GKlF2^fjbBUo=W;4S_&VQBn2FdUK8lupkZR
zG&t(72JaWz6abw2dhvUCVLx{Q<IiokP+q-m_vC%oy)xRfu#ghUQmmRkQ83fQZTNwB
zRp1fV&u8|+0mbNb6rQvm^rGc@?k(jgux(+Ps^tI}bTn}4s at uYri3JV_HxluXk1^JY
z at pEFqzN}RK?D%AOBBMSJ$oPk5napSF*WM~Wz^|hGxElWD>MkTGk_wAOt4xM_y8(gb
zNj4nj(vu98m#w at heT@Ir<7|I>%*@s4w4YlSTwC{0<e6?mz1;@$l`a6QF1RBe<9i-&
z9=3{y?e6ZnI>Lw_y)Vs-0lAATd;5nCXxEeCrFmi8PR=iPadkc3oNjNFp&QWOk5gAK
zg$d8rdpHfudx)uC+<>hN*@!5gFRgUKH&}2*rmM|Jh!rcp%S+Y at Pytjf!-N%(yrS*Y
zPOtJq`GsyM#HZnjp at D&D`FGiW$Y_oUtLBi}1&CbIG&Q6?_MmVE`Goke&~lDXhg$08
z(nN8F)qEXw*L)?ApJ5LhuC at JuI-vhHAVgN#UZ!m&2Q;AlHI$2I>+XgK!}(`SZ0wt|
z*N`$mtN;lF85u!>13j;g8%IC`9UTqq6 at f+nU)b}le7g>K(;;PKHz1<a%F{;$@VUT8
zHcw5DD1~meyjYlZ8jj8n at s+ARs4lk`mVAND0g6n~E5}=gz26Ux`?~sqUGUvj#x11f
zSOMxns?}Xbj+E_{9W8RIcfxj at Kg^}MB`cJ2)QS|@R&LYff{j)AsS##WS at C6}#(hrN
zmdCnIMu2nJup6I!#g++voVe6CWp^AeOCMEb4(Rwj;ir2iJKV<Cwrf48UOK){gm9Jy
z6)@i$J~%u+Hdbg9LO3rjQqJ+rN+s=oHXE;yY;|?Gmb$<dnXh;AI-l$YQe+aoNhE_*
z1$yg0oy at f~+K^V5A9^d(Q~T71gmCH<8u!x0^oFJIND38_fd-P0yXC2Jd(+MYc3wvd
zL6v$5akDq2hC#4+E?XN%*Ynk>aWXKEKrx7PK#}%C$cn;30+-3|>gq at La*pbd@>SpW
z$;t2Rir9>_B at cHmt?lj2$14KnE72*Df?hVTc|rWhet%%UDbJP_0VsMVC3--d1K1ew
z&49&MsA|W{R4oIA_wkj=;n?4|HEJjFPmxF~g8~*eSrJR){DFEN717I{4EZWxz1aoK
zUi%qEDiXYH`e7|>Y;61Ei{QRKgHCziWWwehxKI<D)O{Z(GhS&SeaULxIUgMSpu7Pb
zqZW{&;UO)YEa2ojle<My4NDeczH0X!ZkQ*n`p^&f^B`_(KvelbXS}OVar9>04N at vk
zJ}nBv8aJK{MihH7C+Xilq=+Q0HqHkZrKBu;-kTa&6b=eDU8v-~`v1V$Z^`X>?98_U
zKAfSUp$XGQEnh3376Rltw>-1V?QgOa=qIdZ%7x4$=O3GlXJu#MTsR!1$3 at 1O0KZYB
zuYZM2l&5l7RiJy~l6B--ZSplfoER%UzA}&w(0sr<accNLUL$~3q`1*4gCxgQqRY?F
zZmSc}BqF(7;-9*KG^?yFAsUo*`S>E13vN87*O_f?Z|1ygm at 96R*VH-e1e36Sm6Ir}
z{8xAog1{zxE3N%Mf(F$@0EN-H<JaEaP9#rq^|)4aUFJ0u*<?c#A<+>^Jal;_wo9Zj
z`AoMl?xjajL at y<F0AY0tMvW7oIaHBeS1VFbJp+S28X+2xT}M&*wKO9SgoK2|9j%O7
zZ0-jD_{2(8k{KwpXSdwnkd)iwrd!EtD<s;?gGH at qmLj3Nv1UK)5nkRX>p8OHP`;iS
z-!6H1Tmkdw3YwPnxTNF$u(GXLE-JvfW0P(uQE~OA#1et(`}q0!bp;wy?hj~|>P_qm
z%GBt2UrHOv>bC$=Q>=KC%j6bS7M#3?66h}QeNi~lLEkFGPPD(gCy~D@#igdZ3pO$2
z(dZU)FnSe&-l*6qWIcC at qgiQO1)y_<JQNQfdhHHs!}9RF;c<`K3;Wpb3UjhmXHg44
zcX$eP*f{{%i at MDFJms<LZB0>D&8l;~o>)qmSOOAx`7k9kM>fo2B-{#cCP&UOvTP4x
zCCR3%F3RMv>J+jRW#h|zL{q-v2}mbB6;_<xe*0+-h%TR^NWOWk>}DK7yc50ZX&pjA
z_^jif#g_2i&{^l_VvFUsBX)aY#)OkB0GkFkrXfw2v=)Bexuxr~23BQ!ID1SH1&_P=
zTKz8ODgPP8*^OZd9ZAJM%k3So+zv0I^sI&UulXs?KWdNAgye)#yrxCZvh)+bZU8MT
z$4w0==|Ub0b!|FNi)g=%&j&W`3e#D)^9u2W&)LPjyc at j89`q|r at CRtH)wW?+?GY>8
zTEe<(-A(Y7!BxjkrGd3ZUHwwEuq{cl#IuN50k6c`!h~<p^CfY~Zgm$iZ=531lz{N4
zTy at Wk!@T1<4os_=<Z3KYnqGu2_F$07?zf7gCuod8?T5WSGSv1`P8OZAN^y%tkPn+U
zyq6^_B&0vkWyB$Y{vX8%6}Xy!W#7adGkx)TPFy}w5~fyH%OigdWSu1XvU9=;pVQ<3
zk~a9j#XmZab6={zI*&en%)WVWw{LU;l#IV1mS4q+T^7BRGINP=49QoKP^)h76%dlw
zyO!?9VNqsQgiRbmW+3%a=#jJX_Z1C!W-1)tf(c}?w6F0+uBBb9v>~~+SyHY at 2FvAk
z6+myIgyw|01xA1F)3v+j>SzpMG7mvj{1*Si<@7VWH(<eICO8=vSTb?LcFl27-}x*X
zZ3OU(duI~~Gt<^j=TJ>d0GdaZ8gIGDMu at Yl3cp;d*Ih~~P%&=qJ1VMbYHwpMkyL9a
zZ}B~Lsdan1#=x787~*NfrpcgDS1b~?uRjI1VzP;8k6(w6cXV_Z!MEG%5Sc!>03z+d
z&ozwqq4J;@=H64kcry2`(PnnG-hqK#y4eRH+JY$JNdl+#J1LCMFNIynZ4A%Ia7E0s
zhTF?&%CE4|DIW%W?1 at ctOp%Lz at d%m~y6leEQ`j)GQ$Ga#%⋙rYWswbtvllVZH<v
zQ>J0?6Fz5PUDS1#P-fbAPebbLIh?!+dR>4W|62~4#+w4RFNqKBpmnzpm(Vy4v1+Ge
zT*Y$J!6qR=TjXutyS0I<Piq2=97krB&SZ7p<p$wFHyi}K^dJyvPwi?N1dqwM$ja8}
zi9s(x1#l^w;l3g?5-nHxM;IWp=;7mA?OsdxYRfx-`}QXjj==R*jQjpAKH{Pq>yDFJ
z3?Senejl~64XEXJqM?S|1au}_EEx+Oo?q2oMA_>VhgyhXQJ8+508sEip01w)Df$}&
zMSWY0D^%7z<udmrQb%_n5h$Wi{ay;p6Fy$3v{5`5R at i8@3WE&*KZJYz{`9HR9dTJ)
zYnTr%0L_2ch)xZ>wd;%F%SOc>gvgErR4<L at 4azm_l&`V1{tpdLd-hjv^Sz_DVpS{K
zyKTYpSv1c%nFN`%p*Q<Lat~^Gg;n4It#Z^-HXz;87?^wUy=M~V5QrysVL%Q+iz*}T
z%fn^W_peVaL7-~KEv-TdhbU;mXFvxN%j3z2oFnQ?F4gYtaVbCEoK5yCp2OZqplNNR
zcc|mJ?l_dG*U8?f|AfWq4};cbJ^s<Lwverudk3_ihbLNq&rT&n2dCo=6S{~Q((-Xv
zl^jvG5|ser_)T#qZbBMsVG%feHE{6&yQ#KeZ}i at D6)M7c{Rpe at GrEtd1t8OT!drcK
z#8_o8qA^$LoUDGx2zPn6z;sH|DemlJ)c4Ghr9QgJ){~>&a)kh5GrUFwh+fjsf`}A3
zshJS!A0G+c1q?uW$7?CU*rO(jkIRxU?OAecfCFW;6KIt5NAL?Z#bsM3C)ntEq??IM
zKo<855Xx~mC0sCXFuA)n;pW4>P%3ZSsV)HM`2DHFNDxqPQN`Ajn8{%cA)Roe{d3l(
z>ht!O2D!k;C1kkLY?BZ8i&x;7{9YZ8_;9Bp35%I^Ytu<O(fRqofS))Nh9|F^C}h`B
zz+^1>GuP%}K-<_@)IfHD?7Yy^zBr9Soyx7V64 at z`l}f&<Hk%s;M0O%eJ3q>7{C>@4
zafUcgX*PdsrSn*`Fb+G#-tI2JK!OSYGr>!LX at E?wLvns;b_7Nge=Bxq-BM2j4SRw7
zwzV6?F4&^AGq_l_klt->%`SV8p4+ at WdEt38C~y5 at 4v=VEwhtlRYA4;N<l^FDAcUsF
zjANKIPdj16L$PR~$>SbLaU1hj$J<+KQtZ2<!0`M+$p_kOtgT~N4R3p3b&gG$0J%de
zw6dK1-p6>WO(Eo5;q$zJER97SyanX?^_j^6G&dY1o3BI_dtn9e?ZDv=WSxqAJBDR|
z5ck49+^e^<v(pr?GOA1s>}wRte*&NcjJpbcEviIzmDg3QSmNz%Q0=-v?3>NS#lhMY
z`8%$T`q=*7eGQ%vR}EpxM0^%Y-^U+eKQ&W*uAXos=eG0ikvKw$or!#IM0Lb*=yccu
zr$)Uw_0_Jp_3j9r?>A{NUOv8P&|IKyRnH{sw!D56AEXZvvJ&U4ZM0Tjf>l|&kYp##
zpd8ZMD4SJ+20d1y at _SEf<QMyX9SHvoG~N|2$BW;Vc5y3R;mB3<-<OMqqwH3a#9LbG
zk^J0cHO86aq>Bf?DUEd8aH%tVDJcwzuuEt{X>4i=)M%Xo^n=Ul>!`)B=<ARb19+%5
zXTA}4Kvd7gPRK}2gi%+<>S#rde9BhGJAB1rNlX!m46BA at VFyxeXgy^9)T^))r+1(8
zyukKtvtn`UtYVID>)RI_mp22#PWM8_io8dM)g$BbR)TSNL>R-MxfjYrn7WcoT2;0S
zDW1F3k9%V%hI8^ifnVzH2h$xp07|<`S2#2zp<LR$e{c}k$$1HEUYdDF_W`mJsD2LG
zgVIapCoPUbu?Y_4IkM?Y-{Qjou`Dz>2Jwi?U$GNO|BZxYoW!SCXDh|)T}%n at z+Qdm
z0E_uaIIgRjq->WLi;l(n%D$0SK{{UQOWECI1X|_#<RGWjI!BzxDG{LO2SjW2hv&6Y
z|48qwCY1r{U0fU?Q!8-_ketJ~P?8kQD<a|S?7WeJHVhVIbK^%tGk82XI|d}Ni?%9l
zuw>-W_=Fb}6ufQ~ABp>NpOVV&0bAJ)H*DE2m{d9;7>8nc+I~ACBF{x8RS!}JXdQkj
z%qToG03N^$5p-cNz(j+7v*5AVb$Fbd;B<e$Qy7F(TCLyAIQ`J$E0V_mD$sm((-<9(
z_ZSd#6^K at +Yz1U!F;krE_#isvM$jo!5)h1^D8B$|15TMMa>Us_|0^^yX=!N^9&=>?
z=phDpq>}(WfR%BCv44^ikNhQo<A!mxo^m3`7q$3i(cc^Lq>@q4NByvf(b>(5TeWqW
z%x21AHjdu(bb|ilP?w#FVR3kKkqbFAEIjQ$2n8U>i_0snJd>&F3=8y&EZBeu^?W!O
zC;9qnbE+{cISJw%)w=EBwf`0zDD?cfn3xzwT#bBy%Jwna8FwgX*&!|p{(n*S)^Twq
zUDs%w03lci!G{psf;$9)Yk~#{5ZtwKjUd4Z(6~e6PH;<bch{heH_*8CSD9yKo_W9f
zyZ8Ry{+B+*={j|)_Fj9fwOhEy*1`D9MSpOy=<z`Bkn>h3hCVY$jw3QKh)1y=65ywC
z9N~y<MC^qOekl)dMt at Y;Wd$I%dAoiN7jUuQVD5BBIN6$JAzil&veaJ1vA*w~m9_Ay
zv(0FMHer$4f41<?lP+>M9S8QiGfrCRR at Si4rgJSG#T at 4%^D}_ixmP0*tvT|)K<4ZC
zJ at +f^VEm6yUwlR!wC7rNzWQ$eOdm66tL`|+LpapFM}*@dV_|PrFTC38aC$R2EC$p%
z4mFg)hN7jne{**a-z72ln!gwD56uyRl&kAS+Pig$rzQktRs)!EPBDT)AHI&e{KP3m
zetJFO^)%P5K5Sk<=?Kc70F&Hr2wL?Q8q&-k?zWn`*XP!9{Cgemj4etImts*adZ{#D
zz at a^7u4?E^lRE`<`n~JP!VQz1ot<w!191p(dB at 0fIs6X~_dt6?No#EF3L&fh!**n-
zk9`%>1R1e8dAO{#{=}4MY7EO_gHz%}3!p*5OE^`uEa#oz6 at cVwyioin;||oQ-n%5?
zXPYmK=BZM?;<+<!x-VTsEekswjDl}=_Iz?<PkYAm+4B?-?RSMdBfYO`<pcnc%iGI+
z6nAaR!l_x`eW7Qy*~MjY$E9`L_YrBa>AfqW3ixn=l+tNN9j-X1NB7n_BTt`Rt^VO0
z%-uFBr8e!n3?02VgXGf|kLsYyVvQj-7TOtf>6@}O*oGf(6x94?jwKOAW%pYxG?5^A
zAbYf|!@()8xH2&18Pn)*@my{fO!K_K>b6-+GwI{NX9}>xw-!uaoeJNLDSp?kfBaN|
ztMOJq*xGJa!-UEf at 0IwWOoJ}iZU2lUSU$*EvJ7jJq;%^1_#H}oBS?vhf47cU=yl^1
zHszfG{G52Hj^$+$cDXBAW4%^i^^$>m?Ck93iWswRkb;>e1 at H4lP~Jm*L$1p^#*NtW
z=u<OC{kwDi>o3|XnvnE=1`+2ZoueWsiw?7`F-35M?NE|U_-|4y(p)GoVdbnjPF-KV
zytH=$QSRbetn8u1mCa*VSZJ#RSdk|85n>?_XxTnAdLzk!Ty3CF*=qKte!^$5!OdeO
zjOdGHlxHIH&()=Ed{2;iJ;G@~QNqC>f2tAr2#f+(%c4e)LnaMw^P*ZFprMfv^QSVX
zj~$0ITVnMKl^UHq={KxL4`fvLVu#80n&_bcMsohMeF-kgl9oeO%ZAx~VK}j5?{?ff
z{<2qq*XVDPm00h7ez<0q^lYM^u?nn&Jam1Gm<4pUXFw=y3$1rSi2{111{d`^TcKdZ
zT!gU4LW{qX1$za93 at j3cG*LI2k6)~V4+Rsl-dn6!Wq=`MU@#bod;8@?<JViwJGlKo
z0tT2Q3uZB=@Fl7aDse$~`Bw712dM<gd8+P+ at x>b{<VR&0R!URar=>l1RD)d~bh|1m
zp*JN8+g_L0W)fXJJ?@4dRC$N-Su;L<Ea$vpVG*@WYF12*=VkX0cE3=sbjp8|E=bm-
zS)^_|m4*7ONB7UVV5xA>o$^m;bs@}$t-U&$@E^1%-2Xwu&xL_HZAw?6vJ_zBXzT+P
z17B7fsNREo3QU04bm?v6L33=0(A+#=-wV#o$5D$y%k`dn4_ZX{S?9W?ysapDpX<ha
z2xtYiQODR=OsbZKJ++|)11 at ltMYkBYpWF3*J}a&mv*ll!(ovcp_=->yB^u#jWhrq<
zk%T38Kq=iur&`{^5pU9kVtLkO*ZResYUNH7n^64Iw!)7(U+s(8W11uJViOZdyfAp_
zsnu+gJg~{VaSbd?HHG`#FjL8K7<1Y0{CSk(1^R|L&`9U?>fLL2hP&S|Aig5?Sl>q#
zKQb=*aMdj<u^`xop5j7K78h;$W>=qC;7D5fY_;0zRddr$EUQ!qp~G1Aoo-@*4UuQO
zqUUjO;;qgXCM at e!?wiU9=X3^(J})`Rq|{?R^VNQz<SAim9SY%5N)d)F&FM{+{c*e5
zW05iwdvEGTLs*-)JPrRzV|smp;ORih<Ie*tg$1Zzxc)cBLjRMp>Rb}3pF37I=(-W7
z_Zg>j$_}|ckH#O`XWQztIor503TI7ibag}hY at J12WgZu#NgTBWca?;!S54QS+Pkl0
zWo6~6GOV}Fi_#dC;m$?qaU#ToZxF`1iyjpz%AHHJkxG9bNrFn)XWze*eqET^=i38k
z(rXcArBw3==@b0FlU<I{UQc=XN7g`hgza{=@ix?Ax-sUIiu}IXBRhMC at 6{Dfc6JfH
zYu+%gc%R0vBZ8+dtX}u$^i1I_FMad+BxEu5he;Ks7y!~lGijgAWWFg1rH2DKbO(7R
zcXbnz2?-7>OaL_jLq~zl!$&4FuK*>E-^oG`kW_A}<pNN{`>^e5<n!B~J`rqY=J~Jk
zuRKR7oBrR6Km#y=;pI_Sj!@xY9ywpibI#uh#;d}@o>d9>mv6uGi|pzPW#!}WM~3Qo
zz0Iz=A^Qza*kemdZ2fNaYcrW|9;%ahl%wTt&Xu)xC7s(QlLlM8ugr4l+&gOC+XJ?&
zpIGP5XeVXJet<=wR#+P{og(Cedr5ie6{_*J#7`?($Y+4(*kWF=1b!{dUHNI3<UAHw
z8WPx}pUr1xWN`0H&F07noQOeX$2H*ha~r1Wdp<+HJnU+1HM|azfHlZX9mc`trK?tP
zZ)214R1h*_YiGxgq`8)5v<DLuk!V4`Tgp6qo2Lp`gL>zeCmAqC$H6FZrG~Fli#mDi
zyo*BD9odgiv>6G7r at y$ZX5%O8|NEHj2i$J3xT;6*ifU;+7Pqzb<=+#;CJp${i(Sx{
zlLg~2R9Agm`063O-bAXV_ijgj$=0O)gXmnnl7&qUQ`vPvy^~+*>)rJKiMM^o#*oI?
z<RbXE`gT9`(q+luTYpG<!QcFjv7g?At{_a#zWD1Ih0lx?8G3-a?syVC1v;f=E4MbU
ze)h`ZLuBp4%Bw)l+x0jr?~O4=@|tQNT|Z%vkNfelCx_4WeDsUb$#Z3B_vipxCfsS{
zJqfFG9;0ieGJqUX;7;pX6Sa4R?1<tucRh|wPXV^#yfe49wIz0Wt2g at aWPd-+{^?+{
zsE-*tdxd0pBAsdr#!JhcG#;bQ0UZJ7Jv>XNuJNtPZGrDLic%aed`U$-rjPXTF-QP~
zVm?tlkxP&7<sMK5T at L*Qt_x0^K?d2`TcHzdvdD8&zF4XkdPMc=W*jKhj=bF5B-f`a
z;D_$v6M9=AR~_hauAtyaAL4o1GB={-lip9*$BaY>w{egi^}QRX4ko1H8~xGbN}x6{
z7>lD^ZxT9cIxtk0!>U(n;_Bh{8A)H35TPlF7DiY-Mi6&llgwOXPr_}RLw2-7e!fLX
zc|<e?*g-(xE5wL=N=A0Q+RnIQZ?MqR8?2LfhcMlZSwublbNWlTXVc~0{dL+AS?Q3+
z`5h*ok_I#N;?sU$a5h|rzjhDc)@pS2ngzYf427m~Mw+Y>flC4hieYV6BC}t+Nf9w7
zo<=R=G^8zA?6S>X(N_aYYTm!v1587M-;>=`sI9^PWq>}QK*zO1oCjA_Ae*eWcQp|d
z)Ud1$>KEn6p6;@*E`gpem(%IcZ1z4&Oxj${*K6ls825G=owy^q1qkflRU0W at XETRd
z<-CE`ea`aetm5=MNBA&RjC$&9`N}rX at eRhSRenFes0o&v^PibxM=h&ya&%yF+$zX4
z#1;GcJ|$f_Z*Sgbsz%gWO!|Z0Er36p6h7jj#HJ8puajXkc-{4Rn!`Vw$n-_nJ6Q1_
z<EK~SBkX&N&8Z12rZlOJ5z_&_s)pIPd&981p^&|x51GprZdYeA0X8D=;SS6|PcPXd
ziURqcZ{i at rK3*;b7lC8F9jiAsxW*<H{-+0YCL?`n6RAkavlu3j1%;(@KH1$2j;(Z9
zprKdk(XdU*&7Dl=ve;mOpUB?6w2 at L)W)EO~$Lu)dv%GrFxI*)EBoNcp+eJ#Mb91Fq
zN*?0ORBm*$^ONeR?=8#D0y6nG8Qw$-XaV at GZ@}yKec5xm^yhN?#0`1GSF}AquOejC
zF=+uCVnKi^CPv|gUbgDm;mwhMl_72b0Md%zS12N$Vrb_vzD!C^zLvWj3J2QN%Bf<c
zQ{GCdD=s93WZT>vd2CM at TLW+<b{~YdIFJUTQx*>>g3_UWT~7QaMalbmVW2$p#aWD`
z&JR#ET+V^PFjH+PbJ2--m_14pCYYOYRI0r+b0h&uUTs4{BJ)04S>wZ&N0X&_9tmph
zGFz9KX08!}mi?s(1oGy-!1g#e@@1D=lQ8u_vl>k^V;^5CqN%<{<lE+Ef=cr92jnlX
z_fK>53&>25$G78t^-N<!V_DRCqSXrFtG;(Hj*67?Knw;;H>*b6$O&u&dpsE>F`bW`
z{!Am!VSe5kfPH_id;=)_NaDpz4;rR#_l+r8I2EMUZH2ay4~F$mYjPkO)I#Z@?ZkVs
zG*N+Zc)j at h^(8t at Ulo^=q9eDKciK1$jxE$L*Aq*Qn~?1g1OwD$hg(})w>p7I&&*N{
zJA0|W9(#*>G at C<JU%_X)=e_znV{#Gi-}OqGosEqeoA%{24CDB4CyViSwUYRw82Gkq
zM1>wVl1=sEkzTS!W)T9zSR0c8DV6QsUwKZw++H8g2Oi7W_V5f&!Um51ELh$qv3PvX
z%ABujvQua7uBnh_XFA9moRi~Odlv?(KtA2qLRg}UFQ(hznyy}8ZDsX7namvR`tmG%
zXS^ssUHEv?oW|~=ZyK``8;CUYg<0a*mI at GBi8Z)3MOXn4l9c0Q(|E$tp~I_C{NW1)
zZF4lQ&|iOuNw3L5Hw<k+rNz)tg2brfNsLJ5)9NPeLBD584N919WT&2!$3IQz4gk31
z9&3rq18?_JF{tQTbATzgNAvIy(l*))7pT5PI20W2caKsecy{|<_eOJ*$5Yx2AjN6#
zM#xfwnjy$2Z8=X=kbzI#Qs&#~FGD!x(qG!wgk6b^UeP;b=SL8w{L!RnHa at aIE$b0W
zx3&U1W|dHE8X9$BRuh@*OV>9`aepgltnf@{rc=8u`d!MK#YV4Ll$Sc&M{iPL at 2y1_
zPJGV6E9<N;Us42Mf~P5Qanh~rL3Pi9oUKsB+JuU8b#}`a(}r5`+s~hBX-u$=f-daG
z9eKd9g+7s8RUaglX24Xy$FL_9suBPF`**(Jn9*=*L1DMcz8?J4oT<fRMa5j0tG&`i
z-{;bH$ybY97Oz?XZpUuVtl-6((cI*76QAAV`Bm;Eqs)2T7?F}7Nk9^O at ePvlgIup@
zlkna$Iq!Bi|6^lecJ at f!LC^WL$M`iaBA1&fV~%{k-FL<cQ-oqCeZHkWO0rJIs+5Hh
zb4VaJq6#WTkGk=BtvZh;I-((o;ej$cK0p}wyUgqtGi#f~<qCE$fSckwGc3PJ7dy8}
z_Q^mAL54>l%yGf5^HyZ$E?6%7;@-Hb6WM4epI2{FadXG`2iI+h*g@|qY%vf}!;9`I
z2KGZEkxgmIMb@#3WWf4hW8+M%F~P0cC4H{ZBi!H8-_xdtAp<T*kynUuHecQUNCNXQ
zM%GfUnb67 at W^Zfj7w!i7JoO852Gax&7vS*ZAz&)@6^l|KkuzJV{|x~{bdIg5(dHwu
z*ytp!!dynmHg$#~tx5}5*BW)-5|Rnn(j_(pX0-QhaS4fGJ3!+HyZZblW<!Il{FM_Y
zewgc#<M>R2J64kLGfJrR3q15oNlRUv)p`$C*AU_?qLYKGN^O_DIkKk*`&VVxeH_Q^
z9+zCbPfs=k-t0FrK9Mzfr~yc2A3jK2e0{q1>(?)}hG!6UMm7ARS<5?5wIJA}0 at VM}
zuDIW|3{dB3!u7|Z#3C8XK}4!JSx#mwO|o at lZz=TGCOr4O7sHykP2OI_4$#%hYTFOw
zG<B%6X5H%tn;o at 2dJrG!?Nz0zHtm|0!#NLND3E}Y&F at -A=;Z9IC?f;3O)3KYc0mUe
z_<_gh7#I$aZf`n}*ZWz|7%T^M=a~b+pD&KKcHY8zhJGWf*;#i5e8)#qEsuk6uuUZi
zl4AP0Kj0%XGh1^9x(CpI<epQw;9 at 61lj7`Ika?R9rk&4yahjE><EaT9yfYU&sb8Y<
z-!G(U;@u!<@nKrluf29>jv1?4w*5>NHO`vsTNhn4Mu>&<awq)boNbW5hB;1}&n8`j
zjdgRydTYnZ;%DDKthpFZbV>ArdL7OcsRV5OOda;I{&l3o6!_2DdPV~0u((n4pM^#r
zJ9@=w>#sS~iscz~csbiUj3v%;X%1cyKUW{nzH7-#&3#&f=^@+qGgxDIT)4OCfFsMc
zx-BaUoTTg&!Gx!C4JNhF#}-KX6Z3G}?&YU at CuI#hWr$4 at Y%<j3;g6rM>+AvZ)JyJZ
z4#l9(*w_XUW~@i-n0Kjm at BWQYKbe2iiqfvxnO6f5_W1ZCtYkL(5I}cR&Z|4!-;DTX
z$idFuH&c1vEF~@6^^gKfiBw2@`<rQ?c)8Jl;|1Gc<w at wbxT#Z4LE9NyV9`a6r(9WX
zg7M3e$L3JFVt=72-1H7m2V%nehC*L at Y-QD@tHn3-S00w$WUYq`QvWFkns7A|-AC<h
zYcOR%8Mt(W-RH!`q$MRgj_xM}WPN7TFuOKn{CP@#EQx&h<M5orN$=}ysRO$8_Oyg5
z07Jzr_da=CDk5LB|65SB=g{~RxP%?g!<5a#A6sv9nhsKh7J6T0tylT9e`E(`v)aA4
zZ46N<DK at sImW<FDS(w_L-rD+Yx0_<^*a6O at q{!@Jz1#S<=NP>Z#P?qSmH=b{%j;^O
zxUt#gIzH+`xAeSkYv<Fy`{Qd4t2_cfq at QokH==g*d%!uPM)7+y(1fF9S0MGh*`F&B
z)y4r7q=Wtm*!tR9EL at 5;D>gQ-`%yK)uD`xI{kakm5Z#~p17Twp#{l$*qaM^VIsMwb
zQ*oKis#BX^SvSr-M%57#YibnUrT at BX#BH?l`NQ#<mkvVJwT`>|m(5q(0)y<V(&=mO
zx2AZLCebS|W=i`xuOveAQ`&>rmt5 at 8?d{c%aLOpxWB6~{iV(}XU(4);GoNPl*wsXq
zrxas9CWsM+0CdJtFChO<qqW#=$+jLh%MVyNZR_MN`bvR(&jjo-yqbs98It*(H);*h
zZl;<J&OYhTp6u?kq at xI$+nN0S<^nut6xVwaCH(?ovMTHpu)#OjIioOZR at 30KNf3N|
zC4Jqbf1kM<@Zxvsq3}VysanhM0}<Fr0~)C at yJilz$WS;anv#870Hp5m&qN at js|413
zC(c|24~lfFh6;7G{nybi)+{F`=Sx4Mg8-S=#|l*?gf^Jc92b+akfu8?Jnx;Mat}w0
z+h!J4nQmObGxP}+OvvbdvT>sstgc(<IXyaB;Sn2#vRv@(xWYjl0QE#$!p at A3>$~PX
z`I`SXsnkS-a6#+g{_TjkYQ#Kbfs2G|A5M|T6MS|g6B<`-I~ib&XBRHm?9nXTcr9nH
z8$`<E#Bv?T?|jv!WUb|`OMmH?Z2$T)Rmdgf+J+F-XggI0S+}K%FU_f+g+&ES*v>+>
zj^d-Eqc4uP9`DVz_Ns8mwCfQTn-#HqNas5JF(2%z%9i#B|1nl^gZJ8q9<72Qi%t;X
zX%eTm)qGOGm^|e-=>gJd9<QI}n1n2{FCu9|NkWN61}Wh`Ie}e;2SS*tptHRl*2 at 8k
z!f^^Z|HHa2&#h4hyb%!*5wJH?(=&L#3+GfGRl4<LO{c$>fOG~&?CR?3;$-V)ck<Zm
zYP)*R!dmo4n|2e}w1J>pYQv=j at 7-SCH?KsO-TLdn`3#Bq1kY==;B38-MGZf(TF7aN
zpe!E+*SpdFqUoCPBZ5g^YfW}bJbadw6{o|Y6zYOj;P0f~;Ceuz&54-0 at NgGPij46-
z at 1gDYQ-ktD4wMAHKn9Rjx#u`lu(dZUK(f8gJ$4md{}nClU1uN>oSovFp^nLNuf}M?
z(B_m}&`MPgSsn(Qn35fPEl9RN2_~@O=|C!f*!jlh9=FBW(EZ at pk%wZH+#&A=tRL3e
zEj<?yMqLb4^kFKS at x=m{5xA3B5jhc2d|XnGpdEa3Pck- at Kj%84(22cz?10wBi||w|
zBos+h`G=Z+EA&ZffpnlayTcStr;^lrrrm<tv=e$w&qLdl?<Y0-NcG0M$&lRA{~y_)
zt{#m!J~iC0pMRimDSB#dg=L4H4Gp-+Ot~DDREcoH<mTQdO|1;m(&P-C;uUI6orsuK
zOxOG*blRS%bswL)W%E1SAY{=Ek^^mQ&bdlRw2p`NtO-lz=Uny&0nWL|W35_Z!gbMx
zPHD7)@L6?=RA<$ePJ9TS&xZqcd=0DleAq-G3D^tKlXxl3_%{G)-{Bk~aBS)K5*RsI
zdAQij0;EJ>DgafNCU9$@XtsK~07!OIfD;U*VP!@hIuWl$!-sCdu8Ca%Egsvg*wNt~
zy&jL&@>+MpCeP~*SF9`GpGr2#IrHQ8l{w}U9HR0k;{F&xymq!q_TiB9oD`3x+JW8L
z!N${tC`iM=C}d>;)BX=d)q4^V)Y0rSO+NQtZ)8}{JlH?IJ_ at H@kx9u?N_n9a3D-Ao
zuTz+vU`pQ#boGrswPQql%Q+2HeOu?feK}=SpO`p1Bs{<Qa~3<bYuqCAnE?IjYI>43
z7yi$xW5)Vp^4yY2e6fKfp;M3QfhLiJ=IWP(VdNvGM>y2;grLG(Jp0EYemprxQI*f!
zvN7ZA1I}!Lf&90yWxth6YCQVX!Az2bED at 10UxfpMUK1rs@tYuD96X1WJ^0|cC%Nlp
z$GmetiHg2(s$Q)a-$gfu^+E>q(I}w}c6>#wt at GKiP_SQZspglNe&Vt0W?Yk=80o6L
zIcgr|@IaoM+r19E9w+x*EG8qpb4^TDJgwgNz%cb{+ at ro}?+lB7m>d|3P4~rlTlcP@
z&}sJ~6kf70+-S at jQwn4Kwsr-|Y|CArqqZG?upju&r<iKKsYqXpRIjE|3`f;h-RJ5>
zCAW%%*?D#0IJ at 0U2Y<~D$yPO7fru>DI$g3<j2TbNk7788k~wTTm{qeJ73c~HR13MD
z(N&~BI)P#N1!b(yte?f>)W$xYra&+u1ux}$X(qdet7?V}k4Ri7M(pX!TZWpjhUq8E
zI(H8Sc0-><*=UTp3mScIj52 at _YUU_fA47jRPqYhE*)Z at NF0@MJTf|oieJ~x=8_SUK
zs*5aeU&D|(wV0GA)$q_o)GMOhhey6EK<OZ$*!=HGT{Tw&!dLvURCkhj*%?euZ(4nn
zh^=cXw|i5(etvOx$z0UY<u=tCb=DdG9<7XXB1m$LdIk}66}XPAt>r~6R9+)=W*G;F
zPL_`syim_L*^&jE3fB{7Uw4#o5E5vcsI*UazqJYZR41WNKUl`*ezh8lSk+to2HBDC
zD&#{#6^T)kM_qJIUU#HnBTlm?>>gS4ychRF4HiV{3CKt$8xbFlk)=<FFV4E?4NuWv
z$SPZ%`VbcNHllb#nx0fm6&01(!g*Qj7$;VtQXdhoqGa|DQ at Pl~=VQXOFJMPR&lm3q
zOX$U`&x$BM|0W;Dr?<zi{l~A-OBI?ZGLg(-mqPQ5BOVN;UUPeNnNgE&AKzlLjvY6`
zV)N5smVkghaEsyeJEZN2K17rN0S^zo&ab)WMV%6LH)d_-5-l_+FjRx%OGv~os+{O5
zw$9qcdZ+AG4O@{R?u!j{m8SgNYc<KPO}R-{ow`EaykD#QWTi at iy+VWKX%q3}a#|VN
zxH+9Do!QR`*QkMU3aO=&mJo%M=BR3}FOwmxM~h8faz4unhZFN01goFj+ol5JMcgx%
z4_tvh+d$Dcb(?NcWwb?4DnG$pWaoVD{^9sncfJM9b+?%K7-N~<tX8MwrVQH|8ol6)
zwe9NYCtfE-7Ju-s@;AO5I#7gr9 at jMDW^OwBkM~k$B9o&BT)q+Ca3zeMe1yuvDq;)O
zkqvMFA8p0{7*CnJEFKm8S^HvQ%V!cnT{dt+!8=yBjo7Y2TdX0xpuFfUaG`i at Ge^c|
zZZfHR9Um?duOWMX=wkPBqqKI&YSw?;!i41y4_(vY;o;YvH&9!b{?pbJY~t*!+Y~|$
zPEN^(@R#l{IT$?-%ApBT%@C!gys}dZOuOPPk%p~l+pY_;pWTb2PfQ75!7k*y+3O=O
z7#RyJOK#*Qtb4oqq7z?Gt at dB$a(`-c*;^>!EPmfhJ7YkUj1w6dIg$+t&qV3S6EeD8
zL8Bw<9IvY$e`;p*5~sR;``O5HU;X~PXAT4AQ&tjTdr5gK&ulTJ2EaD3qNdUuv7Yrf
z-P$xtovqvG^J9eWB~eL*v!z}<+MayPYMBG*zD|3?F0)Oo^m(%E){-U@;4b?G?&a69
zeTXt&GrR1ZuZ2`Ad_ZU*gc$~s;tm^6heQUG2Co$*Uc|8C$JZ7Q{#pV{C0Zc7+o+r)
z*5>=xluj!=C at QD_eT5UE*M%bb1~=&4jXhJpPO0nO;c+1SB9vR3hHBORtf1;sBSG_V
z`UcxUhsX!bVj*g3nAe9AuK*<ma&~sH=a~lnp~-cg&}@oeqNwC#9iqv|qhG|ki&F~n
z@>cVk)yZgK#- at z)1^AK555kgob&l^cKZcN9LP!(aDi)De7#1<J1LaxJ%vrEJGnB#d
zG|o0gc9u1BF7LO57^nE);{Ft*5_!}=T5}so0}l<FG?;oa#)KWuWbBqG!}OF at tMVJU
zqm#4MbOs;fK}>B}3ml1dFSNn+I&8VJe}2eRl&X^<wEf1_)J?6MX0)6YOqcfi4MulI
zM at NGmm-RRfN)5GsCKDz>=z(b9$S9{5FQe}FZ9kh at MOL14|C*N^9KGgIT7}Lo_8wFn
zS-V6rYm}`win8G at -*(JBexwNaEKR1|ZEoupNyLQ(!&&rvjuuf4opev2NeDOYnnuAt
z+=Yz3#-QrS87U5RViOojY!{n$rz$;;&bpI5j&_G__uJ?>Y!;hdKV;)jnYQ&5g>3i)
zh;V4dl&tO&94_KgP}r&=E9Q{=sm4c6{#aOEq(kYm?b|NU6i>qy{PmK#XPgd&qRpF+
zhy^#=L}oX`H6BuGpOB7OgaQllW{Q&}7Hd!~P%mE0XSpNgdV{4+m;7sQPq#wSiAN(A
z#96k1GWz;Tab8d1y)!d)x<E0JLLMI<UyWG6#>Sph`5gLlaImC2)fQb_TdXTsqolPZ
z<w=lt=+Wm{Ytve1Ko%e#zXtl&k at n@TQ;NNX`Vuw!4z+9o48QS$ON|0$&F9|)-A;hu
z`LYgbGchqyX)!^kF%jI=wd-*jIz4)~dOBM*FY;zQzZU9D?dus7=0<uVUNHE~XMLp+
z{Go|}F(E#FdTI)o0-tPFnBFgCgv=Z@(>R&Os$d<RTYA<PH%>A2cXVWXH`W=?$>I~a
zJ-gsNIxsA1(q<j2Rh(_xb{VW-%5};viHr$tId1M<+6vEn<~F&>GgzTogJHopvtEa$
zF{sRJlM^^XQn at Alu<ZNyLhWirf at WFYh-$?1*DN|u1IL`0<%W9?2G|EJ6U{MIi!bvw
z7$-OVn!--2thELc`NJ at pQAf3MO6RO`(B%_Jd2M$Qqp3L=f`xo+2m}ctdnoeo2`oqC
z5!R?t0p?f=5BqyOl7VO${5q#D^YokLV}YpbfmLpyEzl|9wMR9F0O at nzwhr1IVY{P`
zTLWSk>nW2#si~>9?HG@#Wgp7lvt5)B_B at jApN!Z+_iK at Wpo&!*+2>ynQi at A<ZS~im
z?qE*ne~O8T(W!U5xZ*o8kiLCwA!>Xd*tx#?X}{LTW?7I_>^osKUvC-yO;`5Lj@#Mv
zAA=Byviu|Xr}v%EjM!~?1qD`=i?7Wg?`p?<po)oI;)~ZmC|jYaZiA at 4SsOErLGm0D
z=hS*nub)=dY6I&|1r}<@#$kbS(iY=o_4((b+Qr4iwAicWJW34E8!l7xPer<>N=<<z
zK+^lUW3idoOB7g)IC+>n=KqlrkcxFE_>97VY{T!%7cW$kS8=kC;^aWD5g^|<+a)sm
z`#-<Axf#C^C{Ha061(>`?|Ad|zDS1gd2Th(Sl at iqeL>?x!E2$6`}?nPcF91P{L#~K
zckI*S0KaAi$Hlu(b*GT~6{0C<E3b?1&d=35_ at gp&M9IT*ru^1#40EWc)J{CLU6&%3
zdIlTdKI_(#v6`dVj%L%oeEyyAUIOiE3Sk)q1um2PDG<+0e{Sz}Ki!(nltUvlMJtX{
z;WU<ekv^zfyif|msU*+l;QY(Umz2>xH1yR^ja<ll<~Dp>-i!Dkdof~3Qtr{MkM43$
z`^*<|ixY?<n{&7jIJs(_AMOVP2g}u#>rNIg{^F;U2&k=fdsUHbI*@YdmJ+ap^_R^1
zW5yrMI)WYtTN(4fh~Nn|d;HEERGY(OkTI(gxU2$FP+Z)zVwJa9U)z^aim6Nd1d at Ij
z|GD<pRJ<Hd66r2FB{0ia;b-2jpc|`YS?$o-URFQ)FjwtMJE%L?1mR&|2x?WmeT(iG
z;RClS4Cd%GGL>8Kxq5PPG at V?3s;sPBBm3;t?N2l|V50y2 at cw}F|4WvBON2`G-wwuh
zw+Q}gsC?@d>8szX@}Ccy>wDT;j=l?C{~ZB?tKr|q!#{5SZ-#sG|8?oBdJK06BzWE0
z`x+*peHWG;!Oq6EIc=M3YwS~u|1YazKmR~~q*|eBrEaSpX;PA#psuXL2oy61E1|HZ
zz5Lw)`(BFioRD at k;%a>@n32*{B@(|@@yS0w>edspbB&?IMD0hUC#Lq6Bve`1r5s#b
zMH?Eh3_WPTsg0iCCF^AOr<NSISFd&xZZ5IO0z*Pp`I&F|-Fi&)*D!Qrhk0q$%=(Ky
zUDD}8Nqou-QAF%Ae&HcqhzR1!ZOz#!a-o`lsH0c<ZE$2svXG6rzT!i4tHr~C%$!yf
z>7Y}_EesY?_P<7Zb1%0b&BdO1v|thElgyr=xp|&`_}*fzy&t(D;@4Ov;sX~ZpU2_G
z>?Ce}c6mrKA6&WklhEbcrF~QV*g;fh62H;vJ<y#)Oj=n?Y`<7xhULn`VPt^Wl9<~@
zccT7IYU*gAk6UWcbwJ2WqjjS^jd8N4lOp-!Do!3+-?p}nV<OJJv~316XDcnZZru~g
zRc!<1Q{gW)ijNszKfp at MC#HA0y7m>*my~=EAajSV%dYFM8-InHR{nXRt?j!8D*eu<
zkHpd4M(NlHU0yFS8*T`u9Am+<h59eG1t|qAf!>V-M)ksHjn8S}$_^^l*1NeuPWbo=
zBx|wA<6d}Xz=@Wo_UVqmcX4zNi!2Cz><`^*6k)^bNma|N=u9D~D~AdhzMiXFjC~os
zjl{#U%D1t>827ak1&gE)Tm at -qbAZ1SRpG_X!58lKU|ccq_Ezp4CE`xJv%Bh>)t$0;
z{ri at 0ZD8t+`^N0 at 5C48GdkF^_CI-GFjYUTnZ3E3F&5)sBV-I+I_Hi%hn7D1GJFMvG
zStz^B)Iy!P+x<*T#5g$WTTn at _wMCFsgwCYoe?P)o7a0wo7y5uW$brlK<q4$kdUi5;
zARY(BMY*IcE6a|g?H-u0J7&rxl)pT+ijsvSR4yI3?(#dWa0|Vm100$obYjTb$rlha
zKA_+m&-B5Wq`yNq^zWH&cpE*jTR&u-XKHGSSgco5yE<|lo^a}2m7Fl&?`6GR#HlIN
zyK!Gd)?pbMY?@eUC5Kf9Jt$?=PmS9TomCb6Nk~pEY%`)-taAH}*{_Jd-sz7misvLp
z3j~bAOQ<l49-QD%Xv*{Do8)c#GQHfF;hmQ-HxirCzx~_5bH5)N$+H2%$;}BkSaMV?
zsl+ at og>mudjb7J1H6B1=o)aulmTE{Y(vTRLL>IM25u2Cf((XXuNwz~qt!(Z%*4b6f
znkg)9QR%DA!{V|t6NM3LXE$bZyu*q8 at C;_}6+Titjn`d4SW*o5l&1?`Y8*gn&1rdo
zNf7qc_5Atsma#F%SIxpr!VA>NWO#T{sm-o#=QE-E`}>}g+rK_6HY?eNv%|<_r;JUE
z+dJA9ea_B?mZ*qn>VYK-=qa-A=)$<R6Bi$UOv&&&I|3!{AduZH;i<y%-?sW6{VH3j
z)uI1xJ*q|b1P|!{Ba7eH%04t7FPB((a6Bhhk0U1R6Dr_#F;}_G!>JhzgBgeK%{K`4
z^78Q-8JTo=hBaRPT7t>Nj!S`S{POdDM+a_);tG!KZ7ztX??#&~%wr=B>?O~7CxMq~
zqt|7afw+iB^Wj<#d*{BZApcOUic~w@^z<}nSCB))#*dHT$E?j+@=IqSQ{EgC6Y`wu
z03E$#QBt?w9=X=5k-#Kc at LnUWN{5FZg<t{^i=M#uoR(M?&|0LsTBDlfG4+maV<-^!
zYB)M_Qf7^okj;F5L}#P6(_X;i at fq9mY+tnhjuY=fEx*xUFZHcQ0Xe++AyU&RUT7*y
z;S|qL5epf+V)52vg6?)wvkS&fVW8wtY29hl*JO=O2 at bmRiqf2P?2S-&iu03S3)X#Z
zG>WN8T$@oTEHm|nhNrrBt#)O*n6I=w=S1qOzKZ7&)A)C;C?pA|=HKAw<do?0OSOI_
zKD3Qfd3*e8OOxSXaa0_D4fQtDpOqC)95?`q^q5q5eU^v1|MwbscX(>V;3>j%wbR}k
zC509r-y>4%w!hl`l?@;0^P_1%0~DLynKj)#7y(kHO1#_&kzO?Gl0O}DalEZS#4|Fk
z*=_iUh;kAkoWKtWlYXI`<bHniHgQ>f%!-S+QnhX$6?Uc4)BOqK<3)$QS0KlR(#q
zC}ks2XL59oKrOD|M+qEn<T&m=v9#RADu_{MLgdx#0-_L#RH)MVS`vm!IG8$`VXvbW
z>~*uHlPcP(ssNR{+GsW at iWBM0c4ez|0}{}HFmhInm0FK&{~m&#Jk9dwT=g2Jp29wd
zzV^wp58_sZKA0m!yi$Z+$`WW_^RL$3Dc`l)xN5Fg{q at 1;X3Cqv6FxjzH_kX3RZboG
zHp=AW;m$~wE|z<iDnoLu**Ktc5D>zU2Lt1jf4{sRcx4l6=-0L+14Np9EZf>jM`|<+
z9_zS2e8O<)Dwv|TX5mD_J!}M?XyM=wktddLbjp**VXd9=RSY&o`tC;T at pR0g7>Ve9
z#2p5&X`*&#YLv^IQ*eM~n&<kyu&F8Su^gSgrI6R0UHc61cJ5~&7$g at -<5X|QAQ&LW
zVksz0iN-N_j&n8K4DVWEU>xv9OdHNGPs>_vKco~CBc9Cj299UxikEhM8{Zsv1u2bM
zLfm>LTUP%0M;}ZfFI>^)slOxz5ilf)c>mDQ1YZ+3GvQB at f;Z0c(1#Y}8)#_ at lH1Nl
z)&{AC`r_~q!d1{tdHMP26qn})`nT(x%<@cVU87klO;>`zAauz+?2`nyNpBE+;FiAz
zzAAP2$z%cs^&Nzxgf^7`%2Zop6?U3>_0N9!Tt=ocvjRfT4?3k8wY6;ww6v5fUU&4d
z;RTAnkj-2?J2_$~>2_dZ4%U444o?is+PkEbZ<H}?#GSZtagIAPa!A#{_D$7~gK*6L
zey;Fb63YUE_Fzr$Ro|?@5s6I$lX_tqn$O0Vhi<{mg&yWxP?S~R3u-QADvrU+Ljd?m
zJtAQsYzMnw?^b&@O|8>KUd9pju%5vRemOOs`|6Jr9h#7975mVprlu8t>}ZmBmH}ye
z7{_UYU#%T-hF}Z7qzlw=ls=%jzXU<1n!@!vt+;||r-8 at RpIvO!LyRpf>VQ9YEu082
zf{XcJvJ1K#*@_d~2MHD5UjlR&PwWMrxtOx-;pv!Qy!sEldQV)4x4mTc5?*FHko0vm
zcBe3Z1Njn&{!RCUgj1V!((%n(o=+0^T2B&Mqg<|K2~8V<uB1zb-<wH3lp%mMyHQBc
zwzP at AbZ?{Rd-p(Sfva=3_ at 70qd|3RwG8BtUQTELUo$T$gCOPa2GEhc!;98x#7MRTY
zIbtk$$KwPaqcWEQbw+vU^HZRrqT(Ut`ufx4x>M)V{fjcr(?}LrbDQUg5#RFBoH}t*
zlAQT$P at _$XWCJ=emm<?se6ioY-YoHY{ga6as@<~%;HcP2G>_>vB5}T{@PgY|lmbKD
zf~PkM%@#BD+MUOVhn#LllWq3xOw74<&Q(S~d$2lDLNY+XolyL~Jk7g5f9yjE%kIfd
zg<kRQ*FZzbA=_8MBkcv;2tluP((yV!7;J6iK4fb=S4^QuxvT+X81nKV>-7f6{B}po
z6|eyUG)P&bIY9@$vbMLf!aT`vp at -k8c|GMU)^%OFpI5Q2y!(*LYUsn>_XAa=fNzAN
z^&RzM&D4a19Iq@;-=jF6Oy=vTe_uQN`ogT~lRVF!Usy7y+H>IhLrS^>?0(kPmy;^q
z4YC7wqQMlQ%m<x{30g&3Y9 at 1)!8h3yeIfDrtMp;24CBmd`ByV_d}LukfjSNDtwq|^
zd7>bTUi7%(_I$<4AhRx3;g3ZOJh`KYbl~qbaH at 2gIZ=zp(vs3&o{~MJyxpI`k}Tv$
zzF4Cs1qgJL11g=XW4#*r8~q_&hpzCgzhA3cFG;CwhmfwdR3NAbiF-B=b+CuE#<C=3
z|K5gDg_{<u>|yJ{vNDP@%^sL)z}f{jcochQIw3ml)!>`qlKi0D!#GwX`)U4C8}*B0
z685Bg0~+5Kw6xfdh|kY0_f%q>i`1OUq&4fUDRjWq=$M$7Ui%L(j+N8n^V}AcZYS^*
zO9hy+>b#ze!V?4Mh-6suGa{&VJGae|bnUnr-L_~z{V9d>Sr=Q~uK71<PJ=$*jVWGt
ze*h=og(@Tq{!I5}CWyghH|bg2vea5Z&N|(_Jc$X$8=|Y`+X23L_d@%u*H9h(i3+pM
zGWctrVn3-?!_&X4WpuW+&DA+2o_m}KqEcL;7gxu#8wXL;B8S?ZSJf<y7p6w*P0R~5
zqF($=c!8 at Ea;B>B at -#ew7XW0`sP at fU-iaH<0isf at 9ifQdc{WHdL3hX0<^%yrw$ZJm
zZH$(x?QiM;@e=YnNWk!YU&r)ql~jGHWZ~^6!%h at T?va#-fQfiar+`MlqrU=xk4w)o
zC#D{55Uzs$c;xf-)I3~V)N8v14}rz(AGWBn=)_6ZVSOoD)8rAeN1{H8%A~baXE<ah
z4y>6pb#yunmV>&r-+*!lAuKuirH?S;{+-+7?2jm4u$^D}<P6fWKrWKzI-WB`pGGFu
z*^PGq)-|(Ev-QOCxa?vWc5T9??S;mHN|b9h*q<G(Q)kQI({emwuPF+`**Tka;JPz@
zd at _IFywhIud=~-qDVBS8+BX=v_tILOEY(N<SmGyUw`iDq7ASs*sAW9*AVIO~F3H7N
z=R};Rn*ANV6c1Ui-d>2k=+{fifs&lm7I*#H@(I5ol?#v%NiheL6r^}}o<HVeYR<Up
zT`~keo#Q|A@<i?T`RUl#&%AMB9aq%zQbNjyX}hSQT81W1H6gc9Ep;Otu~`~g6j>~e
zc_&Zx0$577A7E4XjVwhDZ1IbP$h}!u`;ikjRlWzyE4B5*I1*@I>w&`Hf%**>Jx9-<
zi%C8lM~uG#z3u+v3sCH5P!fVl5rokQ`9|!2jdh$_7*Om_lHZPHP17EcmX%57W=!ok
z<(hVy5Sb}RcXe|cSt?n?gR-2ov_}xFNWIZdY#2V41}xg5ZD5w=R{fYyi9U%G>PXf{
zX)pO;TrxB;FwHV{Kq`zpDv^?raT^I|m0c+xbV`CaIn7rXhrW^+Y>h5CKnJ~9lsR7O
zUoB!eHdq$C+~fairO at REiQjL8QIjd6hI79r)x2ASdO3g??3A**u+r37K{G9P>sFNJ
zF%u_;N`<d00YSe^H@)Lj^e}C{wmA<!DG4Df&Z?VsObisNaGYgfVv%pM3w*^bXY*mq
znV9#)q-9K{xZauxitX$|7{+Kqh|DdMRY+K<j8 at w=&m|{~CgbB)r}<CWYpwNtLRA*j
zURzk?1I<ec`P)V_;?MbQ&F<F;kCD*>Ka&UbR(jo5jZ(}FQO{;d;M*<~3*z3cCs*yj
zZ3GV=3V$8s4I!iT^laEI3@%8O8h0MXSV0Z6t-G4$l_LK6xw05$Iu!#(;@OT3stj-W
zb%pEX-HyaQc`d^jV)oZ{jI2Brd$}nx9R#`v9y;jVwwXvfxn`6lCh6w!J2^Sgo-Cr%
z>FIvaOe}NELb_POdw3QfvA=(%oj0LB$yTkC!S6DRnO$EnE}#||D~oAkqFZCId%`8R
zA=-&o6-I5fJy|GQcMa@`Wnp^Dcs2_jH3r9ZA&<^&ULHkm2YqZgYsSAOLs&f-(fQk#
zP(oRl;HYDB<_Sj4uWPi=rxY*SB6W0hu=nQ7%=J at Hg)>pO<$u^B*WSGH^%oWf5-VFW
zZN}stI8rBx41`MKRc=vfY(D0PUtxBEVPW0`=WnkC+4P!-Y1ulAhE~Y_S_Nq at m6b(P
znY*(A1CpR-JrNT(UDHNLRnkAMHTs!UlWi(!a>0RCR9G0cGY?c+9JJJ2yV?fj;*pnP
z?rd_w%8FYv{Tg4Sy2|~K9f}DV+Kw-C+k4gLnmlaZEb6Wa^*;17k!@zBGtqA{9?$S+
z_ED=KwT9 at 3?jNodkb9v)k}(W9jt>5D|9nQDm!|YJoN*;(^mcYAGk?!$GT(~CaEYEU
zBo2>?*JW)zny8{Oi2Y{pt)q3aD#Nwqz(_D9r2~@Fe9mm`is+n0R<bLak53`nac`(9
ztXWU-$eqh#BKP3e((59;2OajHP;5DA`$nIF0<m>7?&;Ma)DvC&Zs5z_$@EBzXIp9d
zHjnk&x_e{}WOfqao&R{beoN2#EPNvOh^)%xrDUv^dz;2EO?Y6Qq>kg^c~7FmMA2<~
z2qq>&L~=57l#J86&+4kj3^J2WTRQ5_d-dI*x!LSSWr0R|YyD$#jl!bQo^wpXydUim
zavFoAj3)6F$k_hG8 at a@Rt(C3PZFY9ZWxQ&|uBW%+z}xXAkvF<cp2vr4j0{%h=C#K2
zvWtg&;pp4r#bw?qdr3?XaHGxtz0u*ctQ$7|t-E9=`wXTaz at _7&_Is?YMQ<CGV??i^
z at D#*{`Hl at LGKBm|-{==DVahQv>g(%#PHhJEbu at 3^;bA~UeD{x!VXYaCURB?b7sn+0
zJL}4_vl|ob5L6*phtPo)9o=nGI;bq|b>mAHX7%><frMh=Aewp>dOknCz}j7EGN_N)
z^2Ww1k(psc3hRvc^Wh8v%S};Q4}o>nnA*oR25J9YeQ#6_A9&48vN}!``wE43Mwy=<
z+L}n(5ID<7j#quk0BDKK3%o6AGYA9|hJLcoRM4I8CJ4&;h_33A)sA|Pb#)SI at 8C(J
zw>OnrL;CAf_ga^5M{3 at _uItCqx~{9-+|P+)754%5dK;yQ!4-LV=IZJ(bAkf{iX1ly
z(tfQ}y0%kEv+C#-yXI(Um%xRmU2UvLQzyW8zR3%|{-yK*SAp^u>qMR#_y<2iT-^M1
zux$y2yS64hAtPg^^3C^hDXpk1FPBwNfCk at aSHI#<iij?3^?!!uRrB!7Q#h3sN_=98
zO-LA<d0F*#@u{H4x$}o1>2|jiArHxbHS*NbJ|~BehFuYkR<eIAr2S$Kp9+qQO7KOU
zU!5e^S=JB5E-7u=$;6K2&tMN5I$jVseR?%i_nNRa57z4%?cg+Ow+jHpZZ5Odl>-t^
z8%b<$V7cN#Nkc<Zxy_Z0CgL43X1B{!6vv}eto9UK+AOvA7&z=SdQYBFvwXsciwDeg
zP9=MPzY5cd5>4pEctLW`$!_nYt)uI5+}j}gM6`Qnm**QXrS?(TK^zWR=}Wlf?%nT?
zk?{KM;>9K^LO;dkS3ed at E%N46rKAFy<^@K+<P1EWdmuD20(nd!oQl#ueRa%H5esOC
zCKe!xjC**`Ti6)*COm;}&R)9kUkRzb;DIU>M;WeKqvDB<T>stz>9V35L_sekH?AzV
z?Z>K9)ee=VLueF>&EuZw&)-^@NczXWk$$*@JYUJ~JAZP_Caicfzl)ipw83~$Ksb19
zx!zEw3)AXfo~R;Jq)?JSGch+;tFURU!y?8HJvhJmwvv-9Y=1VNsNpGG(hzPNTt(L3
z=diE@?KTRh=++oxz}VsX81}q-py{cDI`UrWPdM_mB3XRBRX;FGKlAhsUcVhBi58Cu
z!3WJYaj%OHehfz$e!h6S<X?FWAYdWe?)*-DeV_{?6Zmd9lNOd3%prvA*sYJZPxX~@
z^?;_ga22S|)p;N5alkz<PeO6PTk{gKwR$0<`)N{CU40_tesAnRiWnCE)U^DwOL#f7
zK&?M at u$XEU_{cfDeM~MOVOyW7G##NL<xIwVxIb*Dt)2K(!Dn-*99?H6HJN$ZXFp<Y
zt0SDq`aCoCPEewy%@<}CYBE!W#OKu=*7YZ#sh4F98Ydx=dSIZAmmuY(fgR9)w;;V)
zZ~#07xJ<{Db!}~Jg*#R%`1rpwY`d+Ylv(W7#}p!N at BtmMuk}Cy_32uR$NJTv5B#TL
zEp=)4Ukf^>)8o^BQK=&dxBJ(v9 at WI0=%uBlSr6(@HtL<H=d2_bL(Va<eU$r~pAxJi
z&jIugV92h1$U&csnof=d$#qLSJ~aPq)M+_Icg;U6Db3Ad?VZ+B%$;ea%`Es}%b|5i
zwlZ{Uk6icYS1X!JoVCESgul5+O&LLdagi>pfTeV~sh%C&nR#9gt{UYAFa+y<0~o~n
z?C5-=Xts|nIJU@&WN2!nC5gE3-~1*KgRU59`R`YEzC8Vl3nWncHy7yB6XNlAp$R%J
zSMpz%Q)|HZInK;N-d6R=3I}DP*U)UEr7Z;q>zuJXm3mWnl?9%ysZN98cD4f*LdetT
z>r4m1Hn+8Qh40LYpjeMb4fM1N*)Ee$r_&4_Gi6=e8OlH>sCr4rZTY4iP^28AMCAdp
zI+0wzDp~$}lACu$nExM>jL+j6!AJ<vyWr;FxGXyTP!!{_w>oU9B<7?TQ#EYNKApFM
zQW^Dj-1t(Tz$C?_7=BHfX<-3MFw;KR1$v(=Lv<2Qk~e>XVm2e8qGh?o$%y!-?E+(-
zS2jq at 6cV9I9ISPlgq#fA!lKuL!)5mKmp!JGfd8kz?pf=j04O?@P5 at FoBT{E>4S5Fi
zz>M&pc;TIZxcqHox+y2yuUUQi(eQOC970G}g4(6vWS~*kNxjD|_BlL>-}(KGA#SZn
zbPd68-cTO0<NeB?M4qdPAP-QCJv#3-G;C&I5rw~}?L3>k88vWgAk2OJ;IBC5m7c2l
zkO+EXYIK}7O06#Bvdeyylr&kbzht9%C4ePG;Fym;XnM0?DWf^ewaR=~*(8CUh-g`*
z6Lq?J at Y-EIrsdA2qA@jIcT+M6z{Pu<I2fb4Qv|(B?T-zP5iOH>D7m3r^gB^=2)tsw
zrZj89`kBa^civUvBc}WN1=SQiMM^YL$+eD|YMpyQUgmgWkx|pmx(Wa0vYh8cDk}pj
z<OJou3(T?^0=G&0u~4$$rJ5A|H_xP5Ivh8!-2rK2yoOW at c*mss-GWMJV{2!sTmsTQ
zedc-dG3^^+$>Q5NCzsc$_d`hwEY3lbg5A3wy8 at o<)LaTSks%RXxpDf2IV^gWl3vf9
zTCWz7$?-N}dQd?7#7gC*qTv=+nP%x9S>GnY`Y%O=8jpH#+{jn(vClYn=_!a#2y*b8
zYZb!|s*|y<Zx9Li948P9Et`^C)6=q%qB#J~Qo8ew9KmE?x&7Dt-x_;!s`xy-lj5ag
zbS6Y*y(=rLt)8b?*gI<&b2I5B8{07xd}U)bI{w=M{Z?yioDx5ixS7qKddKL(aC}!+
zz^UyRE7)qXbaM7|*E~14ogV at ylWBD>4;1w_OPv+Yc&ySbA}cGMiW0bbpvTYI9WEEH
zX_Zo*(P0Gvf-b}5c}!^~Fi><o=4aYLAMbE%0yVE=5aZ>m#z?<VN)c*yK{O>GD38{D
zj#sF18~_HHWD!4}7!xz|Ht>OJFTtZ+-L3D6kc*Xgeoii{Mz5BiW!oNPVqyX;ctDFM
zuZtZ`f5q@@Z!yr8^r%F=zvw$7<*JHf-%2U17MENGr1);JokPRl$k&rs=RCwiyQiOY
zje9vdvtH0zzb|TN4^NG%44tR&Q8Wkxc|hmmT at U1z-;#QM_Gfa=tatw^uzuiVNUTY}
zW_9iSQePc1-EXcRn{eTU2n&5sl>GPM2nzBo120gT57GHt*jMLdPzlEt<JKQES{8=P
z8L~hZlYmo1v47I}#Tv(?`G1SRA3rN*Vz|q0e3?zhwjr!81Hx?f_n$GS-fC?HQeEmX
zI5K1Y{YY=!N(*{Qa1 at Q`mRXF7dh{*2g;79&ak=(@-{8N!V?REBwT<Ea@%c(0j6^Z)
z#5W?gWYPX#t$fcm_iGeyZFDv3V-`pKcjQ}jE0Eu$g1<i>Q*jyo?ZM9b at vj2=f4=ZI
z?eo7p*gxJCJmSLm`_fytK6twR+oJvB-Q0h>yZ^fNzZv;|bLnqh#LKViw{KTkULZsq
zUjVt*HfR#Kp>X=6_{-%<8Zb7 at NVyI$F){+AkL2{U2Oq_5`w{%U?~kGfS0q)x__5NI
zJcUs+(<?Dg*T;S(ODP4Q_)=zH+`hFD{Dw}@<?3Ul8k@!b at n!Df#iM0z8U9zIShxJ{
zU at +byo0^^u6whe6ymR~GH+zq+()R)x5Q1b_s at p7PWk%z+!(y69l~1*kJ!3l`dqugj
z^5}w3$U^05DhOjG<r5EfroIm}I?{`E0Zq-GUukiGc~{!)Bd;fvSz*noZ|Iovr!@ep
zW+joQSP8qyje>yF;ZeXQTW(aq7v}zcbV{}|d#?vrEBt&P-hrHd_Paw_0ueCab=e#-
z&V&WLCL$v8@(&X(clkezePvjbTidpUC at 3g`h}1?Dq`ON=>FyGcj-innR6wLbI)?7<
zp=V2XcS<)S3^~Mn%e^0;_dSm9`|-_B9q#*{bzf_(Yn|75o>y?-8=x0QE^)gY`hgY5
z0mi&{*@snaz^Km)_b at f2_X1ug>eiFi4SxIcw|vpZSuGMj#|-V$%Ghs#y4rZKnd(yT
zq#cu9#hm?)s1X+bP%jqWg`)uvKkdRIVkR%`NArR~P7aNr=s(K^IGgtLUjP~F(?IdB
z(vZ&`6=m#Z+SnbMAgeL*z0hRbNH~pntY7C28LxlX-QA7lzV~fF-8pCg%f)E!1ckX)
z{ChIb^sp8ZD1?4E at nHaOZ?@WUxUV`ZN}Wx1{bPb0x5Ikl&`{@5ylL?I`Gxw}hlIpM
zkefp{YHC??=5RbFRTR{`174U15UdH!>2Q`@9L@(UV&4I}Et6M+?*w~mrwHLM{HA6I
zH~5)sre~&DvB7C3DoRyNE&8#B_sQAYq~-Q|RDd<9<A(0PXPpJ;TDvn<Up;z63%7S{
z`#7Iz(@A*>rz!%5n}nFUL~3YtC~RgVU%9DXL=mQ`rZ$#^AZAJx2;~>Tu7S8C-)^=?
zJPM1-eu#&={UQzE;x`}e4EZXi23R-T0XXnMD|TYyDq%__W#(}#ukX^Y2Zcn08j|k~
zTf!E)*93(g)H4%mq!D at RM^v(Gxcp6XAmr(s%4*EYf_z62Zmv340FoJb(uw^Ew|9Da
zjn at Rayk(3<A=(q4*+6nV-usj*PhH+lFub#p&Y%c<mB}Zca>}g>C|_`X&OC+{ZW6+9
zw_6(a at LairsADRsH4dAr$$&$fknUt1zd%7^I%p%+hl6%Z+23Z_wd_0P8yh;g9I$mT
z@|tlW*jZVFqBo%og_oF*KYKcuW<P}dsP%i9IWILmO-P)WaKFEgQ}F9?wnOIEjj+8q
zhMb#e_Zl46w!?n59{v16@&q(G;*|@p;bqJV{)EMW$!LvKW}}*!JSq9zoCr2J5F3)f
zsSXL`cvdn{_A5%v2rF at P<)6^gwIL8OJL(F=sYc07XtZAol@;1dSMbx~r at fwTa`82G
zA&v5{`_;8zd$+y@(E7wT==qH_m55IO0g9YdvoIgVbIW!RiDf=X67by(V(RA=*6-dj
zxPdAzW at KXQ+p@-^^=tqJ_SjWBRz-wgTmdr(eJ7M;4gn9Y9K9N%6>vqa at k@N=GTB}o
zu)S5Qfc43!$@`R<pIgDgs)x+dT7Rxh{M=ko#P>L<CK`2Ew1<>>c=zG92tZoxqO$5z
zi_<1DL0H%E3Md(oP=RyPi0gg8BrH;|CJ?H%yJ#L8Q)|jb<_5GBe0ytz^?c;NKbmr?
z+G)`aG2#ohWyVXFwjKDygvL0%dKM3;;nhHT6FqM39YyGUYO#5bfyOj8ZT=|Q-Ie9p
z|0?9E+%i#P$K)fDn!KR}N)FVX at XL{!LMW-a$^VScwyn>VaL<6w+AJU5E1Rt{IT}?i
z((HN!qQSa*?)<*Af^`4DfY|_QDf94@^@E?6>^qgpUmvSg>1I+E>zJ5%e*-jYo;nwQ
z8}zZ^;hhx5GX7#hN<W;@CWe4QYeMBlNaUL#gO4B2YFmB@|K$lf&$>7{<Y1fnk at 33L
z>jr4#-TU-{hK;RU>?hKZ+V|@NoNZlu-Fnt9<xx5Iusictf}oR>JQ-Iso?*k)FCZhI
zVK(Yco|~t5LW(dqEQ6}t^?O99A at LZ8p(_r`(ls52(lJUnqw at 9~SyEH>82sFtndy`y
zzcZbA(e{{+=@xFk9QMOaI4DjDy&_9f+MX|_CJze>-I*5o230g}H9PEOk&o?95v^XK
z=j0&e{xG!dLW(o+&!l0*-4<=yL*&~{d2g at Y|GcL=;#<hQ;RLmuXFt6!C92X>iZ~u`
z^dXe4$ujNSe?CwYRI}k`7mTZ5G1evzsuBygeKSl}HUZ_oic9PJ4bFDP91eDlfbi5B
z=XQF$-(-=m99C_V8nI8+cm;G1Cqod``Yl-pCi%?fV2u^MP8Jjk at 4kKGjBo4UOR_g#
zDN}4<?xI2TV|K^o2fvH2A26TA;1qttzF=iAiPQSj(%;`7YDc5{BJu?PInyc8N(_VM
zDW!lsehr?5p8Z7Frk(`tF3xsK^Iky+nQ(}<0K#Pvb8=N_=p8-6TvvRX`~unN+7wr4
z*(uNQ at 4K$ekU0I`J87%U=JuS()$uhI&p2SMYL6P`*^9UJg8eNgC+9Z$_~7_}d22T!
zBL4ESy|;JL&M#nNu{-=XD^j=#pnk5ejp7nwh)9WjFiR_90pS+$1HclU({k+Z(fQ)&
zN)t1)iGaLKkjxk~I at 58V6y_uqyigB)&YguFPA>8`V7A7Ri4f;LRiLyq&^^BLtFoHT
zaPalm&(;UdbBGR at p!fdFF==8^`^ZRz)Ty08ifJ+#89O_NiE!tF_b(-HH!DCYE!L?~
z;yMOtCrD)T0!!l0z$R#o)@0gKQDGdo2l^JQ!y4d_MdgsqjSbCay_6b4cR>pB&AI$c
z<7i+K5BjO7Mm>WyUH!^m9EzMFV#5KTL>%zOt+G4dx}FW2|H1O&#ZinPUw<N3b$Jbq
zAE+QDfB!BTN_g)M!qr02U&QC!5uD>at}9G?HS%|*?gd_<kHLAk;A!C!W$wEG>XM&i
zNdH7YnnWxhG>_<zN-eR!J}M8hErDJ#^<L`x`vY&BU(>rVGp}mt=+xLyC{;>wv7E9S
zJ9H#<opvfDdpv%e9$$J?k=^IJGqT1ILw|m<J<*=-H(v;kOoAgbPF!;V<;9XjX|7-@
zSQBz`hf)b6Xc(a1ss7gXugL*eTF`})rrm&UZ5uBGAVPcJa!PtUMd772JNOI+gF$zu
z5-9}T&evz*kmK0qON$s=oH3GEkUVG at z3S}gDNqM{&{d&FEFJ7p==gZH>nZ?GN=m8_
z<Cm~@KT+Q3*gD_ at Fy9^>zT(!n+RsLnX)$UXOEbfXX&JZdyUH4qhF1FT897Mz9sZ7V
z#gL?r#Kgq)JulWg6Gt*lI#YbM0jTd!zPrb1SQ}Yh=Q~kcW=zubX)ffRe at iS=qUJAV
zq;gJ`zdv7O<e8t}B!s$jz83g{F^EaAI2WiFiw20LA}&w%l9mN~HH){V>zIx;iu7{h
zj<?5|wvttq0Tqc_-8*Bf)NpXRI}pbQP3VpJal5IAe7G)XAWQ76{)ZY^zR#lYZBN&9
zZ2S~nz$u#WG8uMz;uqnDe0brKNJc(@ygTE9l?;-2d<wy=Rx@{9V$e6cK-;O~?6KMz
zRO at UyIF2?PkDcSH+)Ggf?y>e3fi3*;(6}xBzP7fujHVIrqBY%fWH}w_>*N5K-R<WS
z39OF4CYl0j>=yHB{Ev4gli2OD^m4Id7^1BgGrDV+ZkH~4bGodP!B|M#AO^ZUbh%Ag
zoXY%_U!VhqCV7I9G&0DGrIoKlxG)lYR<EX}ThAu~73KEFGE)<)b#-+iTGds??uvC%
zs`LC+eev8&shPPGC5w5S%SDzx)fRf1<Ho57k4f_(R<7B0xy#MfRU(x6G$D(mVzEYd
zgJztoGFZc<!s8l*lg>7N0dfwVeh$b%&F|8XP<fOJM?5C*I$I4Ix1MI%-kx4*cSNT!
z6AzUQ3}cuFbh9u)v_PU_TIn>i_6Wxx8;>HR<>B^Zrkf6+5GfbVq2oa73IK)v!y<#^
z7JUIZXyUpLS=4}(-do-U+y<^*VxGLc!8zB(!<1sEB`avJ(MrogBL_=JPPR!?-_cXs
z*3)CHwi))?A9HXfhN-pveZqtc at W(i9-h-9e3Ed;*bA8dvlnrwGkzm{5Du?;)nEW!h
zX2L}O^RPtDN~!m8G{;s-)C|!s$f<&@K8ZqwRKCL6*DyD7O|0tAL!}~Wr7F at _$sU|O
zClAm96QCDs|7;CNu3dVGhlz7CoDYr=8`~V-1zQoeI9(*MUs{4lhSU6seiO?SDMebu
zBQEw_iwl~C8me&Xpc_-&qgF2}1mEuHX^j_Xqma^>`DNlSijQTjvn!R8IvRf}7o}~S
zEc*$~<B`O=J at Kd`Ne4J}Q5>%0$(kUW-LgE1TU&;6`H1 at hYswvzdy(N=&Kt3AL;S=V
zjG0bQ4xlfgReUyCXM2O=AbLG?`x<bIE)-L92lb1#@89g*^pEx=0d>af!|DP69tGwh
z$=B#%PY051Y-60b6|Ylfs%(kdYsasyCYe&?@l)!YeM{2*lW|FGe5t=@(~vv>;}3g2
z5<ns7dA<$=jEAA^1mW`xNBqf)56gFOghLZ+)746Lr2-bAO4qgDRaz!I(6vi-wC}zq
zs?(<kLEl&w{U$33J=fz#-v4g)U;0xa>woA^1@$l2LA^oY7?&1L1rldr{eQEcMzohu
zw?x1B!ulhBl8<FqX8fT)rMsrQ;N&15%0w;fB}I3r3+C?tW?iu^dz?GAtdo<2u#0_o
zW~T4*OFN0q4y at 3GjJTO|khxveCJqi4Xp5<HR7NHy(nr3_FDq4a_wa)0aBY>Xh4-+?
zbW^$`O^%4$v9>Qe%LSJ$lF5)ZQ?s+cC&Tir5)S7Pe|}=SIL3;c7f=nQCt^wA)oN}$
z+~$itQc(k(gRj^R^*NmgDqDgz3JZ|msIE|pH(WPo+=Kq*SJk_wfcJ(;Im*p%;Y;Z+
zxk$jZYI?0+ at L?2Pz4;>nHx@*j0>bt6jzJ>DrRRZFzFI+QTfXT~@Du7cM%ldG_x#6e
zMWn8TEUS#`eo$w*XV%~LJXL!x8;M720mCi4z^C|Nwsyop^XQjAmF6^w8C+p+>laMw
z5JKkU>Ci%PAtt%eaKA~MmS3M>XYJo*IpqwWQg{gYF|JH~A<!`M>%&cZ8?P^T)@-k1
zUorKz1hrO#l`-48+8In1i^+1C=16U+cygEIX{CRm%BcLYR2;!aO)cTAaxS54rQ at OS
z8p%-{$gw^ul`QX2xaA|S64KxWwcGLUUR2HPPs}W>rsmfizTfbrz6{ck3|4tCZ@#2#
zfm%^Mhk0Re8m&zV%Z at 8_@}jl}20G6DhYP?!SoP5tIyUs#`D{B>*J?cr`ML5H0nn~m
zn9*?d7H^eRG7B3|4S}4UH8Vaj(N4Q5-kmy{UIr5zZ^O)439n37)CbEv8!=8?u^tm#
z64;PAv|{&!$`PBt%T|%abwY>o;W{m?S2LjT)epB5o~NXwc;6Bj@}=V0UubeO+)9oW
zDY<9r_f33DkYcc<C3%46U&h$}G~}BeqpIp?e<5+Nz6!V)Me1OmG05M|<Y0nsKa7hB
zO8NK?2m(3JJqzCa4X>e>MDl<Bgm6920Oi|JR4 at no!)Stjx)bqS4w1zmN0ZeO<ne3u
zXjJrIrktIvayCv~%(38a3H|Sq*Tb3VRlNfdT+PFnk{TZ}|Fy at RA1+s555dpzPO7%h
z;Z%=asEzqP at zS|t0~LM;=?v(-eCz at sca-VxliLzA`0FP`zmhY}I}H>SS7wgY)wW}I
z09bwZs1H>TtVS;{ON`s!mv^fyIe?U{(b++AY-8$>!cOf=zrUGZgqkusuJpiEXfDr|
zmF;l|#X;wxy7eaDto2$bz=aI&Fv3oGni5K1h%D5)s}^p8EHVo7AOpMAP|D!J{b6&o
z+7RC?p&th$4#WC0lcyTMO{1xPHGe)wp>$o8s`}))`f90`+VIkyeo3vfLLGJQe0vbQ
z>fR$usuM6g$aG|`7>6B;g4W0+Rp#uxUvtJ27<1sU<J*CX<lJW>2a5#X^UO8 at OWh}o
ztYk`T9;`#J`eI1wbqiMS^nQ;uHEOrj?yRUH87d8*3$O#F0C?L64pmj%q~)W>of{~4
zsjddX-SbM)+!v)wCI3#n%FY?{!xyD#SA%}Fk*>K>bMpd^%mZ^RB-9#`AC;j0Ff^W3
zKipc%8836Ed`2punmBnAWFGpwCNK2G1w%h_$Q(;01N(Dw9`<j19j*QTc;V+JO5r7k
z0X1qgNqlaR1s$2rIdP~4dd5?)x0%XVP5Jp-Ep?Uj(Wtb$QHWe}f$LKAYxV at 2)&ZYQ
z=yst-alO^j;t{D_Q-e#ifYddYgC3h?_)T05JKk%gw8tJp9Ag?Oa%Vhye!=IYmj}*H
zb4v9c5R$A=1Hb at Jd2v}=M~7LTHP;|C`EE#o8Y6Ofnc&Hj%<iwM+@(5l8 at Wi!jP6mh
z{8Wr(TT+_xN}DkoRU2rdu=f3Y+^Z>HTG(J;Sa`vasppEzA(?0;bnC)sN!7eRJ5kGO
zD(%Od<;vEmTrT%bhRLG19a5w7#AB&z7xS<KW=%WJl_X-&(Uh3qbwq7D<;Ra7&<nJ>
zb2!;TifMdxhY78GF|cvx*q at Q$!#1c9XE)m>%lMnOlwsR!c0eEGFdxE<PJ)UI4VRmh
zG5M7y`waK9W%)QZEXUF)nhO0zIq2;#N)Bno#FIqAS`NQ~5-6Aty1Jy^Ofo!Tck$jY
zG$Dd6&o<if$L=O3B at JG9dQ{%6&X)$r!|%HLqSP{)iN3nu1z61x-g7jVi+b#Mwp!;e
z>zI-{3DUf^FA1 at CJ?SN*9*?9+fJPob`y}hb$t`g&eP8HSgKG-^I=+=$cF;oKH^$#7
zgv+qf{Nm!|Y%osmJ$KS`huN=OcqguOi>jF-ofP~Yf}BU?=vRyhB2pHysu40TM?`29
zxNL%a{yQ(|Z7y4^4jK_#Zpp6*wmLx9*4>$6)J(O|+e*43S1igrbuL;bjn_Nr&ME6R
z>-PA(6rVIfufFod%mzP+J at V|b at Z?GF-0Wz4nN!ZPLD!*p`6Xs&OJN3mJ&~`))(h}M
zWnX~4&jBBts}%Xf*RX+5tp7bX&Z}LV_{oT#G<-b1Tc67MKTJooL<HbDcB#KB4;i?-
z0T*SIPhe{p at R7>z$Z;23K(FD>xa>*DA08d;j?sKdK~4D(2W#Dadn2kd<b4gbVSO}8
zL;!9xO)hsVL=D=W@~J;GBM>E%o#MaVTusim-HA<t(_8v{9o$$%e4o8xQzQQUQizL&
zdw-_Cq2Xj#J<7}*w&+73Bkag%X4z~q%D)W<ym3s}F2a4u5S_ at b`(jJz!-r<1bn$#m
zxchyAr%z8Vem-_qWD(_1bwUZ6&#i|#2~?*xIY0FN^3v~vsc9&g02 at 2~>6iC&n~{!%
zCJT3+ks`alB2AoS-CsmnfZV+=xRNHc+M at mgKnU<e*h at kp*i^4IeDKLqBgP<I_S;|L
zAAL_w7G$+p-6*XifBs;1R+m}kP3ByUuwn{=06 at L-H(NrJc#>-NzSH!aTLF3xrP$gc
zDkw0p&Si%ib-G&@mYXqXhzO++Nw{`eSwXmLjf+rooC-B}Jlq~NihTDHzOYOA*pxkC
z?&Wsp?pak at U~sUA)0U*9nZj-VMS`ff5{-pT5l_gXPu4AGY7f6h1wARyOU-GX4NplR
z(=B)q`}mNTQEuy2HG1VWV>mCLr0_zhbnAXG=j8F^oSA#7WaHMb8>@Fa%hO=mORlTU
zt>B{v*D+k)F7L!V80lTQTw=T&Ssup|8Tdtjl)`z3Cz_9Akd-oD$UAcMlYUorud|8j
ze|eM`ht5W!y7D;}J)$v*)?Lddo2=mx-2KlrO7+r1f-6CVT>~+;*lgC_9u=Ukr>7=y
zdVFl#XVGqPn!eI!@HIy+u?%vN<2}n$tY4>wq?`P+O#~g_GOXjSTi5KRTNg!_2pP_#
zq)iiQfD?VXTTx)(UuoK^?d~2fJ8}V#dHk59p1t<_vcMz4xi)FY#M#7vU{os>#koRz
z-4j!IB+^U$vdp{pLUX`Cz-<{__aql@&%upJS{|5YNXjLrd$7&D*B+^0EUIPN(Te3h
z($!GO=PWz at TQ@|ZrOo)@1lBNU*iSxMQtdT3%a}<TwE*!a3?&gdT*Z8GgUl--piP$>
zptayxzH_1sAK#sa6ypAqOuBDU!&jbs=iHT3n60MvxEVO0LN)JN$DkmPv`p0F4qEWo
zB2VO9UGF0O^g!`f1kiD#n)JC0k$||IEa31?-b4 at 0k5H}c=ax)cedzJzbDGX8Nc(|b
zgk~h=2BXen^5Tk{e+9kPFFGUq-4b}d(*k|F3Xru&c%p87PW#9vOP?Hnc?J5#5ytU(
z4`lo-<|}@v_8R$$$7QJ?v^@yW?p0Jrqnjm&9FH{?_xTL%&omEaeSSuu<<r!Pl+vv)
z=HRRY2KAB16<E3ty(NyV)UR|)6Q_k9XBHSO>i(Tu^|9R49M%(aSV6;@Hgj)JKdZvc
zxa3tzlBhB}dP6}RV^SJK5kV@$Qu>(*{^aB0`mJ{#8i<R(-g~KINFm}rQKL;QdhhBu
zJ2Uh4aRtQ{j1i`2rBSMY#m>&IE<`qR5^mzt#zunqXufie`fX8cDeRNge8B^+9B_{W
zRJCvAGC{%axN*)_^C2GDT|X4MO>DW3wA8kh^t6a7&)9OKwU;E$FVA~{{2s{ozEMf|
zgk`tBD39+6QZ#HtN3u#wnmrxg3<Zo=b*0-dQ|DimL}S36Q+b at 5x!AAx7~=}rAG3Y~
z(D~&tbzICqlaZ{P0h~%PfEiI^B}3FcJ&m?W_gAs62*p#<dK`wsP%jbISG3!7acxxT
zYO6T3E9CL~Ey8iOP&W=#M%T>J7BgP>*({`N*cyXWW@>bWDsyk%51RRe+JHcHDh?$l
zsQ?hbg_c*5ND;h!6zOqu4M-Y$W|P#Wf+s798BMv{l;4ywT53PlAd7X`l_jmWCHqb7
z#hwAw-cmqh!Npv87R;%|4p0BQ)Oa^A^yBu0>qX3?Wt|ZRK<{%&tm)_J3I6u2m3Gi&
zXDH}7*<8cyl1b<7250)U=*muDk3JONeOE^ygV=AAk*LWQDF0oS|1L3{aW<PEZgRh1
zW)Mg^rwIHsn2Y_2AV1`_`z1i(d=w8I!D_xgTTw5YnocR)MNEtqLO3PahKL1oZ{DW@
z8FP0x+oGcXGQs!gFbv at n*;Hz82DP-o$bSjI$_M1j!Qbvphf7HY!Mv|L52Mj9{iPbS
zT2G#f=;<H?PuXl#WKx7Bqrb~!%ak at z2={nPbfKj at xd>TU6!|ZYbu&iV4Qii>Y7Wh=
zhL%VH;l at _Xbd>qvR+1L2l&^EVcG at OfnlamMzF8K^nW<bZ`kRU-|C}e|?jrQ;1H>HA
zzIOK<g+-2vBT!Y03KAzu$DRH{-Z|U<4L)i<zJykK*3WO=@Fe|3klo9rDdG9+<y@~&
z?q`#9rTECm^wK+<g?VG?wLekk&XsrR at -1bEFILZS#WaU@`req6*peX977(5cmEq2O
zrh3Vx$$T_ChjVMBK`x2>N&HYwCnd>ujxyVYZb;jrV9#jRbV?_kc--*)*=y_Y>%c(w
zpq{0-VhO1~LX)gQ?4m8OUe0db at Fyags4D|LBL9$;Z6V2qD^KcANnY}dbaZ^RLw)vE
z&fmMA*tFN+yM=?65jI`R;kFt2wC_j<P9k$$9RHwn2NA<dcB0|K2_g2<az@$%45n3W
zPekYD=IXC!I&@sVIy0=14OMlYz>uM_FCUiE{SLgje**6}g<3T14~4qN5EnRucwb*i
zsDIH0DfFx^l?0HtHs7_jGFB-yn4g6sS4pjxzORMujAwYXKD~EV7}s}d<`q%CF%;O<
z^{%y;e3&nMKxJwEgsA~TXIR2W)t2+|pd!W8tEYZc at uG;4>1qFk=g3&XQD3;I*jhmu
zPl@(h;sOrhVnL at 9y=H5`TgdTQlX0Y$m%F2Y_lj)SW{ZK6A{=hk-57 at GhJVXjL<zvB
zJ9withiH8Uh2)=BvhuKX*C~V2YK`%J6%ncaZ^*n~bVYsaCC#hcAtP1E)I7Uvr;C}O
z&|u=c&3-`!hNSu;9u6*beldj?|I)OJ<x|$jW!6vUzP3>N?dN;7#7C;_nE5>-p`xZ;
zU+nx=U@#v~+;cRLRU6kW6z3JHdL1kEFG-u(xX*`Es>H2;0JD8;&96s at mSDbNY;3$K
zQYGnv0pZD2ur}8(j2r&z_=Mh|Z=`RmZEjAF at o7Utol4Y;%xIswjO}pGD;l`IW}S!v
zLW&ID>A7TVYbzfRrG~)cuo>f}e)&~iIbY1d$kbF~aU-kXBRhs3V$z27G)cen`vLB@
z<G$Tdb=(W#)IpnqV3nMz!sdzn?QNZf!UsaHWr*E&`97UXt|EmzLomZX^Z`+soK(YQ
ze>yzH%G|tjcN>MCmm;ef7&NLGzKO#S>mL&y&T}PPO)sP9Q&UsNqT!>dY?<x;ZvaZA
zr*ADkz;&XcYU at +GUdVR~FL6FY!vY)~>Y8|sq{9P3 at BsD|V&}!!>plQbQ}VgGNOxZv
zYH`K^aLgP!rg>#kEcM{B>5E%kpel|Y0}rRItWK;y5!{sgVq_gP`LQ1U>;J`UKlJ|E
z#_pl)xP~UDEKNo~0!WIx^_ZBHq98?Ms0Vrcxvhq?O|r3JzlR|x{gcA7K`GTS^&&ng
z38IS#8o=BP-R9?=>g?P>jk49TgeQP=GIxoA##ZOdyk4?ywT;96C6>qCrqso{e(sL+
z)fRBV*BPyWC71v?)dZvNyHi$HS1nBLU~8)yXMnt#Th_(DBzZRm%1q(ml>{CPu<dI0
zk?7Vmlaomj1<2B3y`99CiUJM2LizK0d%f<;fE9C5&Mg!10PdOiS?0)s%jOh=vd=T7
zGzCvsVxH#PMdE%_Q|4DMR3FY2q{>Rp#pb#`nZH1A7D;(KPnW&*1=Q|WK8 at 3-m+i9I
z!6QrIqrH#g8eTAmoxXTOzmzlhp@}ete~tfbv%e-dj5inljA$NUx4E>za#>vT9Ga$~
z<|y>U7&-0{-9d`Hx7GK0hqN1epD>cWySKOHuECrlMa&CypUGn(gnl-y1UL*59dt!%
zufErvc*Ulz-Pd8+4-kUr(dN1|13;96VY3ju&YfNdHj%n-a|X$qk9)<wnugJTGFLnX
zd0H~=LW-_HDpRD*qT5GQP4fORDA4>KMooh|oJFH6 at O^B&r)hC<fhjWJ<;NWK@}Fe)
zw-8ywOS^5Cleg{4f$S`6w$u;2X7nrOrS+x&28~ixboztdO^NOrSVO^?deN%t?`#G6
z!^C-m<UA-SXy&O`JTu8_m3-$s(FWJATK|T at i^@IY@>*oX5+IjnHg^F&be>Tw=)k(!
z_ at +23C+CEObN4b(?5MK`!C5d^ls0*B4x6<xA$#7$2hId at kgi{R9J$qyVZTQ$D+jTC
z2@?e-Znm0F8!>M{D<7R)<=eoG1l!GStf0`Xzx$qc*~bK`*asrTKxm?dB{crPLb{V+
zRf?w!a0+_r8wf<VCkh<cUiv`=jyw8i3*s~%k?eoOhLKd|G0s3|^oh}z*~{h^3n_dM
zu at 7dZ2+YexXjfCfA-TwQ-(;>J`NApUiOekhbS-e?4442aey|&h)?>SZe_-IsccwG<
zsCi`#e{H)yo(7$<X*DofbOB~n0KzFqrCsmUTzM%O`Brgg)^#tFVKag25MagrW_-u-
zf!&L!z2TlW_6{mTWsDnj<4wA0NwNchlJqgIVC9%*lm=@VQ2yq~Jy+z36#~=Xmik-6
zDcKn>@bvf(y}f?5O)v7-Xz<4jZZz-;IPVM<*rI6Onp~@R4ThT at WdMujkY^lJnDgl0
zPaZz7x4D1k9+f%s{7`}AU)=v-E|qH0HTuBM#dF_raDY#KTCG%P+5&K`Vo2eGsj(=v
zzRD0%r|%1c$T>68m7(R)0gxc^SZf9F`wL7>uL>Xr4!sYkIT!|4oI%9`RMZpMgmq=5
z<u796fkv!30<5{B@(lIc2lupV>=&k_Rh@(J(q12$a2^{`j~^9hXJb);^(jIoTQQ}{
zVj+*2sx7xME<c~{n4}^k0<7P6WkPDC^wJF)-uxBMwa4P*BoC1=7WUDuc5R|~@;8+j
zam?<)SPd}S{({(fV7~cHgh)!b9-4yl+mK>YV9MUwjcH3fKoO=qt+2e)g<oB`R+X1m
z at EMkur^sbJrbGs*C7$(Jw`o=RvFLLCRD;E^nSC=|IYP+ugpo;K&IMz^%!xWJmGt(V
zL%894r1bKjARtVGpRhg`ibZuy)<Vho8&^^@WvuTKGiy@}<r&=9wHE!B9|+Ew!6Py_
zD-36^iibBfW*7}>mQUtAebFcMNNvg2oT}(8bv9fSQ{huCoAbhj%$=gw^Eh1i_ufx{
zt_6u>rLP{{i+6vP*5!G|8&Z;X>g=W}Qn{dyaEOXX#_^B}5Y&$$+(rp#R#|%<0Piw-
zqTVN>9|aA at 3)IJ}9D%S{(@r5FU7yl!1w$rbs0+;T5bKOh&j?=dC`NUJY77iwW?f0B
zRM%I%>?Z2Obn9{bK{;ovNO|Rl*!ep9O=r}q_Q&83m-|!z-T{zlo;7<x+)q#^1?^gI
zP_<QOsk&gS#x7qd*MC;YXnm}iH)#Nj1h-}XdYBzFg1f7pU-SFu at RyJf558{RN6p^e
zR$n~Q5<V7k`-UB;*^zgg_=~GwOTGou6v9v$!zsR*I3 at nUSasav6v5*NTj#GW1!WBv
zo6^4lCVRx9rxMW-=<1qfK2>iLhkj-6>2RwftJ87etkH+_tL(k$T(tb&kU7h(=j&=~
zaO+X4ofFty#e}=|-!sbSY)inH?V%si at 2;%q&m$5`!{Jg1BSgLKL;62;bmGIGaXW*~
z4j$npNiUojK7h`tZUtVY6o7M37|Tq?Wk*0Oed}ji0DfJnP2yIy36(rpw|YLXZyU$&
zyZfu;4I=f1_c6hWU3=wOuKnBSg0w+nPF7k%oa#`61`i_s#+{!I?bf)($q4&M9K8p1
z;yfGT_q4eoXck-k!Z4|CLD$XqsJzA at I;J1iUDvYAX3sB^XGPTIci%2KqE5&Q#2#>{
zMgb&4m6}=v`od3KQc}e<xjN>R{#(kph$GC&J_mCU2ma5q%3c+Tw>KY?YAK6_Xc6d!
zl)qFqF%D*u%#0hI%eKtOiC<4}?6wRVmfh#1VLOo94Sd+3RsPqPCX=^s#qZ>|RGb>y
zPuZ9l#gaeuS;S{aNr0KJPaCZ#Bw&P5f_QWFEgS>c at RE{@jPFoO7k+a?VRBvdSakz~
z6a&MTF6b at u3Dcm}=BNEk1Dde<hJ6E?Q}p(FPE1FCO>Mk`b#O at E?7-^;ay at iedPTv5
zn3(E=1aB`d#(`47^{X-^ydk*tyv)7f3JKgg(ooVZ5<0r4^`{P7v$wHR*w;QL+P`<*
zaN6={mUJ<sGh%(l&cRX46zj|+p}+%~nVK<HSpPdw!^m{)vcBYnRg!A1LMp$Dj?Bf`
z*`?b+9AM~vrx6gEvMU*PcuF2Mul`Ik<{HXX#I(*7UT-6GbdU;Z{&n=4qLGJ#p`jka
zMW;8CEtW(fL@^Jfw5 at Oj*Xjy})saQ-o}DKRt~M<Fl<Zc??fd-R-rj3fCMN!3ck#XK
zrry(CE#-0)<Mmi&=LfayG}H%#>h!plPLvsZOK#SQ-EXoHFyR#U^sT4jj;-pd^_-Ik
z_NlCuLz&6<*3SSvP(EcWXKmq<u5AZ4a%Nzej*`r0qClO2&sH$8 at eJh_7jT>FF(Kh=
z_+U?W at fT{UIbQ%aui at +r2M9<9`eo8)iM!gRJQ6J&ceT(JEE%qAQ>m|Ddg5=MEDO0(
zxF&CE?z%<*42BZkLq$z3rZ9O}YG+&S!T=R|M()DOPj9xvZ>>19ru0 at l`>JBU`QCEL
zXy|jkmQ__s%G7;*ezm!Y7$xt?`O1n=W_RzDk8?A|#k&5zTfNdT89O(YmIEHf#6;Ue
zO=G^R5OkqRjob&}4@$ETracNUes2K*DH%=F3E*^XZJGykr`k;$xyzBeK=272f6}Rj
z<=)3Oa}$m$*>FMyVgDMl;C%R8YftO1x!12#lfUaMwO53<{C>6BcKVvb)$$4o10sks
z$&?~;rO}QSyg|F9`fyRr5`(DG$4t6fx_zaR4u6*q$(VDA1w4oiFnlU1=V6Y%uFX7L
z?HpYwn+gbTDUQ-F-o>dqazj3H_wkLGc_?bdlSew2F6J5RJ`1;{&Q&d0EUO80v>4^j
z__#w=?db}?T$isjlVAJQ=p`Thy0N*?b1E<UfxKW#OG~2P1mG)>i!9}d>NR_5D}XEQ
z?(f at Ok1E;Q at 0~6rzQ_(w6+|I1(Ty9XbG=&c- at ozjsAnB5_nvhmv_US!&ttDNRI%WF
zKiM1K^FdUX4HMN$ezU`Oi!oG>a at jviOBQxLEIN>qmX^Ltm1V+TmV*GTpMYdc`ow7P
zLF6b8#PnN_%yoB<eBroNb%%(1T~I^>{~#Wv>(*h6DT9WF^LeEc3aASGAEh7fymQJx
zQt*M^<|9%}NnfR%mcw}+o&WkbM&8 at l1nkF3eQ*qG5pCiu`IH+V_3@)qU3o}fZ!ZIH
zUaT5zEs0;K0bwQbtBBvDC3(`A`mLZs`aS0*6_uompwwyuauI%N4yWV9>X8phN<YIv
zD at 4nSz<+|KBs;4|K3?hpv}ZX_%E$<?;O}%t&ALYGeGy4KmVXC(k7DegY2vN<QlIX&
zYqWC7zzCwr)zLI2E)HxdvYj7}t%RRqCdq-{l!lHc9vQUJ^8oitrW77z7A<_9c`kDK
zfi1Wmj=j!b1;Gq^s#>GfCwGDg6q4PKLwQgrlr1ANPc?^3 at d;iZv(pSyd5g!wi(H~>
z4apq6v-~K7@~QH#U{pVdOMh5e-QuX3<b&)_rXL53btGk+UhV{!lBsE_;#lkW$HdgT
zz*=T<?B?qkpb0EZKcPosbq-GqxEI at oGhZDTN2T@?nrXh9mr9S4Br=(uU}9oMy at Lm=
zg|Rc%$UnGuFaFZ8`!&n#DMd)IfZ)Md;NFhLJKJp`A;IP(p`G&s7CzUV51I at OqRdzG
zgRcy}OEMFRKJX}5Oc8pT$a}OqA)!Di<j}KB(?iRAZLvs!FT2HzU!7!WnXokYAQsrl
z8n9izTRPUCZ<S;^sY%1fhg`QJ5S(_Mu=x1Rza3xZE<_Vh?AL2!F1x%wE9N2=>#lB(
z80KPQoJ%9Tgya<z6V8I%7YsmERMIbL5Z<|?y4c;zvhOcR-8PvzSk`n&Oxa|8h?fs6
zoKdaV-BALk9q}I`dy(roSErg7_H)kHukDY9a at V@Klw(fG&vzT<YpkkgjKl(_3~C8<
zt`U at z%-Xz;N(i_?Qkl<e{cvVV at lbzu4$&gE>}k$j-=!9R+>vAyaWL|^kWdh$%XNQY
zWvZBgZ$;00XS?3!C=tbjK~G)Apw68T-^D~UZMiFT5Js8Fb_=!X4Gj%@@|qUvmf<{$
z7fMhE at r`xvtNzKFV%@r<IIJDb>*v*8%I|D at OCPD<EkM?LPWV92z+8Q3&AK6r8`p*D
zPo++kB7s+i3M|ex3wa!r%GzMIj){mG9R4R9!QvL9e~EB)8cjqrOs9Ka*k{_6G8ALH
zFqz5Fy!qRot1q*Uj;oHUsyKVy=|}fIr=~6<%%Oy8y at ng>>sw0;OP at 6s2U1K0f^RD(
zI10-1vNqW7{}YSJ9JmONRt>&+u<88pmGcyHadX2gH9%GsKI0yvkCipBd!nl9SOm*r
z5l6%mWzBp3F-iub^hHHu#XHes+;w$z6#M+Jq@;m<rWcLU{fSR?YDp<S!Yds^L{#GE
zvtPY@*+sptQM%4?b!AC|3v~V7oCS~P9^Sa|+*Mlqt(t9xpgZez{JG3}|GB80P9!Xe
zXKnA)@6q}BIfq$nqw7$;Y31kJDcs$8_Wupfm1S9Ip=VXEZ?SIDwas)XB=xD=tTPUk
z>mJ=2+JFW$EQ=mZKi(D;Fs|*sC7;Mi@=F}w{qX%<YRLdjDRP^F+p2u%%ff806WCI-
zt0Xh?NeRewSh9?+9<8j47ETE8%3baRjX$9ci5$_V4ACn;%MBOCY}<QzSy*h2UR?;y
ztfk*|k$wKd`{F7!ap5JI$aJHF7~OocORu{V0=jeM^A5DOeES)RK$&ec$p7q3PfPpR
zq-b_!jh-F(@LnF#9c7SozBV}#J84y|JHeRB=H%*pgjcLF+n_m^U#jq{{-Oc?_S at zr
zIgK_{w@&hU|M8N1O_BEXN@=eNKKaS%>CTnK>2<i!3(5+Ae{?&7iEVn0^oil|!3lTD
z^xt{38TBq-gyT<Yx}R=fYFX*%x(9^bBMQ6oxsc5nyyw}(caJ<T&r)?a_2d;?cgx-(
zo4Lj>v5e{{#b8Mjs|~5bZgwCB{ayjKzx7yJiD3S?l at vZ{?XNfqJjUX{Hd*No-A3E7
zzgd^Gy0uh9 at A>|CZ=x1 at sO;ELhn^Vc@>yCA&n3clrqCLNY<ykZxN7{cvd#p6AYd5^
zHN8ar`20#N(<W%a)<oSBD7f9v7YtHF?-gq_xS_U9atBit8*M74j>3Z*whM*|Mkw<0
zd16cFIaj+oSNWjhg(PkV$qoX&rS+xRMf9q*JM`)jdyh7l4I&M$_ at nKs#{6TxEtGRG
z2~nrzq;gJ!H3oq>L4`G8$Cjcq9abd0DR-u`#YoQs<fz)dV3>-B4x<B226;COjq;1e
z3W{7i$aXPWZglgxQj<T^rYXIzCBVt|&6~fchBGA}?CQRqCBiE%0;vy&ow=+4)31Fx
zM!%`revR3U9w$%MUt76y==QLC5aa)uWuAO?fiZIt0yQaaj!VRsXQOAst*d7jRnk7B
z+`qcpdofdR%o`;oC3p!;3UAw7?`*RP+ZMiAstYeU_zZVKLP>EMvKn*LwY2lKChwb8
z%X at fuyfsQ6vr*kxuQBUxX(~VH)hG at NoTl}=_wXUPh+W^4 at YpKLP`-~-pQrWb2fWJ<
zo$N3R;eI at poL8d>v<fLlM at L>2hKt=SO at Ey-LLMy_^5rxk70-4ITejo$Vir=a6E2y%
z>W`IM?+Us21TRAq7NC3W#j`b}ry at CC|4hM_vhW?~=^BG(6FXFn3&KL>C;5$XePFJU
zdL3 at c0MZc(l4-NPE+c#i$u3;l+yz1CT;vsVR?b50$F;;ul}S<`%E?O4Ni1Aq%8*do
zg~s!Un^zad+cfYc=GTmuwp)%XyFH~yoYO{z5pmZ&rtA}lA!I{$L3!2{fok5;+Gz4P
zxx8%U$v*mgw(`UvMQb9XNbgeB;%emLQ^Uu#nZF;KglyE-)k%~Z(uE7X8r})6(h2pd
z?LrRSr&<n6LH90RkIB8CttT4sjeYyg6<>s=&kM81<A{69_Xq3GY2uK at 5P@gpuiA&!
z2CRypoyWRnUWW<imqfunIF&06gYjIGtL+gWvmCg(q|7$sWZPTOc0 at g_`!&s1hc9A>
z7N~rbAss~{>vO3glPcdRcvOeb(zX5YA?dtQ1YV9^;po_)JtJO6K2ukI<R1d|#a)4}
zBR7%mqtk^*<YQA?Ch`Yi?5=%IrH#Lm1>I>54#6RG;$tc<6_73UW53q84re$ep;Z%F
zEc|5Hj46pxh6hgQH76b(m2KFtaIE;cfuS_>Ou(DJc;{BqQz#RlMoj$`-}|cFVg2?O
z{aUZ%-1c7KWOM;%9S`?Xc3 at P$W1Q6c_kVZ91ZN+iiyLyhmGsOdrHa4bjl=An<_(%b
zsru(C-9ri6SxcA+_v>ZUl^c>hj<<_-j+&|;uZFaz@^Vb<x&RBO`3jACI0NID$eBgz
zA>lC2nt3uCm{?dbF{2C&ff|ML)d%=27idma%)SisP!9ux$vVc__fhx>sj&&8eELa$
z;BJ3+DZVFKvFVMLrzC66YP9khXZod)xJH<+u|Ll$UeN~3 at T^3?-s@@*e|PJIo=Irs
z;AX20_NLSWO8&L%@67`Bajwm;)BnsDX|O+yE~ZW(;FjTiPY0Vto0>6YY&6s+41N0}
zbMx~&r3Uo#pJ!`q`a2YbFI01%KYY%qRc+Di<&|jY1I}0QB7+xh?hgCQG3Jt?PGb|@
zCC0A)MAfoBrvos7{_{RgwAFy1jOG69v|-mxZ)+Y1&6h8?CYi3<Q*e(OQoYLUyraA2
z{3qS~8wQACY$LR&+A6q6`!i8^Y-TMCbUb!51~hc9TsAj}<;=E^(cMTN8^?wfaAw`H
z^Zk)l){T*k%IPZAwBSti at i|uv4xS(A5r(dRsg5E0CStbt_3Zq9sh)f}SBmf3ZxX$e
z at ouwO<?O~4^vlb5EQYEz1(k<qE?YQJd~kMo?A!K5@!r at Ww1dft(W4s!Fpg&rMfJDc
zm4(-YR|@_HtM*B|CNoV8d)G<7Zo=SI^^www=cvd`RqF!rbh48Aj0xBfQl4GzCL at XW
zW+>g*=+2MMWp!QmfTP=muaq!kj=Uh9J+!sNep0<4XlCu at t5>0^M;iG}I27MRPU47*
zCE at BzQydC0zjJH)7<Fak;iExB&Et06CWi(S_-iK{)8l!sQBD5urMWTBZHr#QvDq&0
z<NKr=_0WH3;qjUFTyZW%?23l!8e>nO23Rgj<{Ly3x!_~vTL4*M^V$v0cKx<^^7&%T
z+0FpkF0tWHZS^~04swBsOWUG;hzJ{4);RSsDEU4 at LIryT8%tOlWEoz+{&)?E3RxtF
zTTEW_qU>iIA!a?D<_6cWKvlWL&7Phf^ktI!;fJUp^hye5G at L=EM!}V+@}I-_U`i8i
z+_lk#U8Pbf#^%JwR%)Y{mg~49MB51m*H(Y!fhePX(+@#@7DB_taUmNuWr8#o`U*4)
z&$9>TZu?{c-q1trRGo`;8VG)j7*N%wes0w)nzvy;D_zwvn?S4&AVpTSQB-<<kJ#8Q
z&<{vl(3h`J;UgT7 at aLErbZF8VAD??pr__)6pAB5@?(Ue&f-DKArk`n at 9;fVva)skz
zuwRGkFgBWok at u{-!2<kCYtj=FsR;?^s}Ye1MqOA!jO}6M+i$pWrOmusFm1#B8vU+A
zx_ZxoS&r at UIdTM7suwp3sk+dR=(rM=t*@h`)dOWNtPp;(u~@Ei{e)KWIi-k)_wW}9
zqFMEpz$n_#UP{uq_m}w&Os*%5{@1qAn3d>chwT((Nl9AT`=7stQ9jyc&}Lk!LnL9J
zep#NTkLRph6W`v|Gzu#0a-GpGWGQN-zLmHAf{DrYN4Q86x+Cc}=$I|M?oS6nz}+Ar
zk6Kz=BQxK}M7LQCejw5R$+TeAW!RrpuT;B3=x8Ic=Lq8dbQjaN4!dBSSOT*PdbtJ%
z+k at JDDVpEsx>bgvv<gQL(^s=)4x_5n9o_mbdmSB7W_^hb%i-0pocfv at 4sok8LFi_i
zFL0++LS>!v>&BY+A|;Sh?tfj!d!@$u<o at ifL)n-<66M{DraK+=6RQYzoF`yFP`RlI
zmC7t>mY|yke=3*Xr)6Bw{4h75Q}$5;@q^knr1>xF=Mzc_acGlp#~v0H8F~i)X?34x
z2?yQg9A^FUgN?Qhtfan=fa+*p;KNvld{V!NddhsZeyx4F6yisc+kP*?#Aq>Rq49WW
z11N!3<fG0rCByQ_l|~FP7pYLo1H($M_8wKq!2y;qHgC^nFJ0P(`so<Wv672<|3`-X
zDWg7TQ{Y`EBC&mcJW8_9=!_a<)UKHmRggL}IZoWax{DO?8oQLb<@<=ZRF9PPkR=sr
z=aNkE at 7lE%?d+hMFD@=VM>$*&i$FYDZrkEGIJkc at Hww%yg at k5nLTyIT&?bXa`=hDr
zE9~T7ZFbi*)#2faoniRZVYQ0)Ky3{ezrxp6rv&O{- at SurFzI>#?b-P`OvrP;YdG`#
zJX at rvh3eL=Tj<lBBv;h>HkY-mVLcArDTyXlO-Ttb$#Au$CLJqGN{Vx%I#_N7H+iC~
zoL#^;KC4PAGKx48I_eiN$!SJ4*RPf5IquhcN`dDsjAgoIJ?=PK2NUq2IvJvhv(VPS
z!Xu?;Fi|KhYHVzz*gCNv?Fe;rbTV04enLPXGpOpH2lf29vcmCk=#%xN3O9rfMM`Qa
zWJ)M3&wFAdp64N3)R>}K{)>DDjt^M?aE}X2!EI?ddrHi~^tpoBY0mhFJ-O&Ne_70#
z)k$&?T at KwES8+>^%yGSfk?j)#71|2<q`SvEplj?)eIc?`r5sE{%Pun$dxd=AQ>M!+
zD~tI#0v3ZApP!#NkUNBSuw5%t&8}<&Xx50r7N|NcRHo*8WeVwo(oPZqa_Y|5!4Li)
zKS&Z1F7U|&UACPQDj5F3hj^u4JsfI?RcYYIx)Ck2PiUa^-0}7e`up?@yvZ%O_bDU`
zZWL>H{>3k|zwu$J7Lm&5G@${UBb5B3>+pe(I~fCeMgPoNaH!O$>8iRGf%v<hDl#f=
zDZK><2d&fw?y*M(>c)*ZRc9;W8#nCn&)?6?UQv3seGHQ<<RT%qhS-Q|XtalI- at Q?z
ztbNlyM}eI3`{*Pjt5A#J#*Lp|cYv;aK(#m#e)PPV3mkh3N8YjA&?Af?x?x_AFs)4%
zcFeFLzW^rbno`6(H$KVyc+V<sJ3C*9dDLW3>Z*O?Z+d!$8+dL4KzvWDiPj~pmfl+i
z67t*(tft#Vi}i)BN}nDrk0qe2;;?SeSBp&8{VG(R|EOS;E_^T&b4D#?a<Vtr*QZwa
z{>J-|9-M)!UzT42BI(~RN5jXM!CjR?X)3HC)xCe@^nVKlF#p$uUg_pdFh2i&)ZTph
zuLhs!(SH^8Z?K+M<9>29b~gOa_v|gJ{?~v0{`LQU{=csEzrOx<`qq(w!9o*SaJ<QF
z5r;lBcx1~Nv;%~=_+-ss{kdxG0~oBgx)J$VLB9ce0&l{CGl2wN1JTh;Z+B!89xvc|
zU^~WIHT*;oPtbF_?Sx4=fn>{y_>XyjQhp3Y+UemT#p$y3xb+!dI%mni{CtzC_)hHO
zVv|$kJlS!;O#7dEsTpM7*}SsG62wf#2?;fYm_H?XK&1V0(&SN&K-Ro3%<AmC^vpJ$
ze(k at 10DVrHI$k_!zZ#FI-;()qHa)F<5P;XVJ7b_^FO~S at k(TG#Cb3P?ORM7`Cvydz
z3pFFx3#@=KQg-8zXkjQPbhe|qBlY at tt($^^LiC$14}=+g(BN2vaD_#b%zJQIE{GN~
zZB2-*&5Wn64{|*VA|#wE=qhPqFs}a3px at XioB3jp>qL2e`H_c*#}aIhZSDKBRr_vH
z?TwAzUfzYXQ*TzxmbhQ+;#AI-f<~){U#+kM;=Q(!hN?J4JI*JrJ&<LO!)hW~=t;4%
zN!#W at wH4Mo4qvftJd*Rv5eeKLU911x>rG5{^~n#DtGivp?o at 3x{mSdZ?(tnceaSrL
z>%~V&hslzmNfW;c^Nl0_JX}oF+Kr}wfDP|ccqFZAiM~*oTR{6O$U-d?Wu{|h_VpmO
zxol{lpP|oykI8 at +k(XDiOByOU3i+F3JNAzchSGiQ{o%DhTI_D`eB!51nXlbbsxRy6
z_)zP8oC)Vjar^V0!ghn}L}sPQ>>ML-NZ9s)mZ4?E+t#wg>RTg_oP1sSKhK|ST!-b2
ziaqV#sxFLO-B{x*6jX2f91qK<>sHap9Ck*IOU)ntd3JhIT&7JIez&^Qa{;&gWI<?K
zorFqTYip%@;kU2pp|@}QI-wj at z;7aJVBw&ifB$;cBas_2T_sWY_ou(Sm6b=<WQhkr
zzn=rqgo!fq$(mg3 at Q9J>TfRLt?th*~-JI%;Asi~k2lE1bBmI>N)Z1=*r$ReE+RS#y
zC%Wv8>`e`yQ9EGoX#-3mkK_ at r^Qsmmv3fP(p%|&lHu~L6=oseeY%w{RQ2^Iz`|NRR
z+S2n-$$Lw>#U9$tf5tCuyK<;q{$0~uN3_Z^AMI1gNIM}4q=-eWgR?=#u*Hjg$Y}Wv
z^+{3Ndsac7eMrZ!yY`#+LyNS{Te?kOVQXy99`H?1tIV{Hjt=Pk=fOXD`uX4RwzvP5
zJkV9U*47f83WpDh!5T;ghj)(o_@=S2utq*)cJ%LRgFTZA0->bx`|-Z3x3_<AkmH$4
z*h<c*kkH4htL&cM-WUSV%5b!|_d4Xywdn^%iFvp#FISI>lPnb&<<5opENV4$FHL+6
zO2Zc_mfrL!SXMw=%c!V3K6=Db2}8G*{j-CiuNfI1i2^hZ{~13$XVJlYwf{uEuE_Z|
zk>^BIToQGzHFiLBHL>TPp(ip+$7+&PWk(Ibyl9{1Tmm9P)Tk~`aa1Ns^czDQ!G_O8
z_Elj|Uv2eSE=C5#ySRbDektz8ybOYlWr%(Grhuk;-ej-kO4FaE<_%Hc^WKN6xHvd?
zdy6KAmKtX3b)&R<dgG-cgFLBqo*No`<Z1%7dZu^&^9*U?>i32`-Q9byW}ltXn=sOC
zeHSXEr>B>Jj}<D8WQ+6dZ9t6fY5(WjH+r&U?reH{tvcH&l(d_wsD9tmR)710JQx+4
zd9u%sOMd#tn?{L7o$3vw at 2>|>H;9S0m<D+I?aGq>_(9(2q<{5ha46@`Rn_j`9-NAL
zrze+a6em8xRUQB6 at v(dB@=}mU_D@@nJR8P4n~;TfF{9Ayo8X10udL}4q#;tg<lDdh
zxeS;rH__3ng^v7xv33ReJKQLa5q5Xpr*Ji$tk+I19k%FEe#QcU&?#$aS+Ekum;ku+
zpU<a)9#LL_twRYu@`>7faDN5ugapT#&Pm5qK^M{O=}LMxH at 9Gv^<+LnE(*CiTS-qz
zX~<H#e8bzophW1uV{?iJZa=ou?O1PC{K=7%0ug0M&{ASTI8&0g>+g@{(PSV423nWV
zUMrL4#0E at tPOFhQFQ`T4cS`z^QM;+if-XG#Zp)R_M}L0Mqo=ozM8D0=C4*dgh8Ft)
z(~gWHxyXy$ov~u%x>?=gGi<ZCq`Zc at I-y~oi0<5D(y#tw*6%ka0z#gd5G+qxRO#0r
zN6?n$W<}Q%z!Xm3=h_{vX3G-q&i(N#{YjBt$?N8J6l<V(6gN`54|ziA_6tnV3(dr+
zC>L6h#nw^Pd+Fm=hCUaRn#_jvk%<6C%yB^o&|hpl>HI%ax-GsvBLD8P+OJaoW?x(D
zwSVTb$B%FCOTOM0yNh#o=GI%&@6Xuw?tAL<^YgA{nVvlq{q^1NE$!}w;@^N%10NR7
z2nsh!c at kmSy>COo at o5^r;YR}P5Rc%yaQxl<%TFiHyLZp-(vt at d7w?~Gxp>2d3;({#
z+0VP6wyAl_wXChY&WEMi+Ggr(uKb&o?Yw-N>F;G<_us#671Y;ho^_|>&*{l;_1ALB
z&(Csp>)H6@;>N`vmwpQ`j(@#vVPfyolQ)_Ti}-C|LG7VaUZ~u1W8cmt7q_>!AKwtD
zKP7Xobl7@}SpwnjlBSyOK9~@(IV&@8;?sit0!r^5*nx8N^w~vkS8eq-HqLYXyYb97
zsjMGY-+X at JP`L@%JNvz?^jnS;)c6AbjkoqzdjW6ZyOz6m&)%gcrRx4od}}q&zS>G%
z{r0)g`IePB`ugW at -@bkM@@e1ng)9HPlZ|dQu+aK_R{DDX5&0~!dtQ2*RqXBcv(BD6
z@;UwX7Tvr_^Jh(}c@)v~(P*yxJ765Of=2hb_x)ZK<`CeJko$Pv3tqOv6Mx(|%KcoD
zCyZOCrD8?#_k)M$8^1HLuR7hfL|Z&JMRWUvwldyoSjexKW3tWea>nt#dR2`beIL(6
zZ@={YZI at lmiFIr*S6z5{N7|H^e^u;nzq)@@Pm51pAE$ZT%VzH$DU%!#0TCUZM at f$&
zZ);zCS at M^SC-;s?%)4ZF4&b!@wwwsz-Sz&K+w%HBjfRY~upn38Ai7|>&F42efYprT
z`IBdMe0_U;erUwR7=PaVv+ApJSACoVoI{`LU1wSS%jIb96b9JMLpw}X*Iqb1O)sjT
z;J#d&<<|JHYj5X^*F-P82&>c at R&TzrefLgX>9G8p8>}|fF6WcoePxYkz{S*}z^c9f
zk{<nhq5FEhdVKJ19jI#>PObZ*m**4m{WCw$n%akVUUq4Knu2#`w{5p6{nPPQF-5i;
z-eNtlbgHF8zgH8&MO!ZYhBrqU_}p={VUgOMxSG5fO1r;>?S>t+&2XnU1Abyx0~ZJU
wW~K#9Oz>-&Ry4rf!Jwt!zz_2g{ggNTXD*OpXU&{-&kJO^r>mdKI;Vst043A_`~Uy|
literal 0
HcmV?d00001
>From 4a22c3dd611e12c55811cdb12c90dc76a80fd5af Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Sat, 15 Jun 2024 13:17:17 +0800
Subject: [PATCH 03/21] add comments, time=2024-06-15 13:17:17
---
LLVM_kickoff.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/LLVM_kickoff.md b/LLVM_kickoff.md
index d1b7530688e9d9..96ab3171f28675 100644
--- a/LLVM_kickoff.md
+++ b/LLVM_kickoff.md
@@ -14,4 +14,5 @@ clang是 LLVM 项目中的重要子项目,是一个编译器,我们可以将
可知 main 的位置在文件 clang-main.cpp中,接下来找到该文件即可。
+
> 该文件由 cmake 在 generate 阶段通过模版替换生成在 build 目录中,而不在源码目录中。
>From 6ea1545d4b6fa21ae5fce209325dc394a268c3e8 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Tue, 18 Jun 2024 22:59:44 +0800
Subject: [PATCH 04/21] add comments: the usage of -cc1-x options,
time=2024-06-18 22:59:44
---
clang/tools/driver/driver.cpp | 38 +++++++++++++++++++++-------
llvm/CMakeLists.txt | 2 +-
llvm/include/llvm/Support/InitLLVM.h | 4 +++
3 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 83b5bbb71f5212..61879e8959fb04 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -69,7 +69,7 @@ std::string GetExecutablePath(const char *Argv0, bool CanonicalPrefixes) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
- void *P = (void*) (intptr_t) GetExecutablePath;
+ void *P = (void *)(intptr_t)GetExecutablePath;
return llvm::sys::fs::getMainExecutable(Argv0, P);
}
@@ -102,10 +102,10 @@ static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
}
if (NameParts.TargetIsValid) {
- const char *arr[] = {"-target", GetStableCStr(SavedStrings,
- NameParts.TargetPrefix)};
- ArgVector.insert(ArgVector.begin() + InsertionPoint,
- std::begin(arr), std::end(arr));
+ const char *arr[] = {"-target",
+ GetStableCStr(SavedStrings, NameParts.TargetPrefix)};
+ ArgVector.insert(ArgVector.begin() + InsertionPoint, std::begin(arr),
+ std::end(arr));
}
}
@@ -226,10 +226,14 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
}
int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
+ // Cratels: 标记栈底位置
noteBottomOfStack();
+
llvm::setBugReportMsg("PLEASE submit a bug report to " BUG_REPORT_URL
" and include the crash backtrace, preprocessed "
"source, and associated run script.\n");
+
+ // Cratels: 存储参数
SmallVector<const char *, 256> Args(Argv, Argv + Argc);
if (llvm::sys::Process::FixupStandardFileDescriptors())
@@ -252,9 +256,25 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
// Handle -cc1 integrated tools.
+ // Cratels: 处理以-cc1 开头的 options
+ // -cc1开头的 option 将 clang 编译器或者叫 driver 退化为单纯的 clang
+ // fronted前端。用户不应该使用-cc1 option,因为该 option 并不承诺稳定 clang
+ // -cc1 is the frontend, clang is the driver. The driver invokes the frontend
+ // with options appropriate for your system.Some clang command line options
+ // are driver-only options, some are frontend-only options. Frontend-only
+ // options are intended to be used only by clang developers. Users should not
+ // run clang-cc1 directly, because -cc1 options are not guaranteed to be
+ // stable. If you want to use a frontend-only option (“a -cc1 option”), for
+ // example -ast-dump, then you need to take the clang-cc1 line generated by
+ // the driver and add the option you need. Alternatively, you can run
+ // clang-Xclang<option>... to force the driver pass <option> to clang-cc1
+ // Cratels: 如果只想使用前端 option,应该在第一个参数的位置
+ // Args[1]的位置直接写上-cc1开头的
+ // option,否则就不会进入ExecuteCC1Tool,而是直接作为 driver 执行
if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1"))
return ExecuteCC1Tool(Args, ToolContext);
+ // Cratels: 作为 driver,完整编译器开始执行
// Handle options that need handling before the real command line parsing in
// Driver::BuildCompilation()
bool CanonicalPrefixes = true;
@@ -316,8 +336,8 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
CreateAndPopulateDiagOpts(Args);
- TextDiagnosticPrinter *DiagClient
- = new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
+ TextDiagnosticPrinter *DiagClient =
+ new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
FixupDiagPrefixExeName(DiagClient, ProgName);
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -423,8 +443,8 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
if (::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
llvm::dbgs() << llvm::getBugReportMsg();
if (FailingCommand != nullptr &&
- TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel,
- *C, *FailingCommand))
+ TheDriver.maybeGenerateCompilationDiagnostics(CommandStatus, ReproLevel,
+ *C, *FailingCommand))
Res = 1;
Diags.getClient()->finish();
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index e0388db032e789..0873f5bc117a62 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -1087,7 +1087,7 @@ endforeach(t)
# Provide an LLVM_ namespaced alias for use in #cmakedefine.
set(LLVM_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS})
-# def.in文件为模板文件,里面的@XXX@字段会被变量 XXX 的值替换掉
+# // Cratels:def.in文件为模板文件,里面的@XXX@字段会被变量 XXX 的值替换掉
# Produce the target definition files, which provide a way for clients to easily
# include various classes of targets.
configure_file(
diff --git a/llvm/include/llvm/Support/InitLLVM.h b/llvm/include/llvm/Support/InitLLVM.h
index 172d13bf21a558..1febd4b0625c15 100644
--- a/llvm/include/llvm/Support/InitLLVM.h
+++ b/llvm/include/llvm/Support/InitLLVM.h
@@ -14,6 +14,10 @@
#include "llvm/Support/PrettyStackTrace.h"
#include <optional>
+/**
+ * @brief 所有 LLVM tools 中的库都是以初始化 InitLLVM 开始的
+ *
+ */
// The main() functions in typical LLVM tools start with InitLLVM which does
// the following one-time initializations:
//
>From fed048b31b3257b0520fb7828a20d68981f85ab9 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Tue, 18 Jun 2024 23:21:40 +0800
Subject: [PATCH 05/21] =?UTF-8?q?add=20comments:=20Clang=C2=A0=E5=AE=9E?=
=?UTF-8?q?=E4=BE=8B=E9=9E=8B=E6=90=BA=E5=B8=A6=E9=9C=80=E8=A6=81=E7=9A=84?=
=?UTF-8?q?=E5=85=A8=E9=83=A8=E4=BF=A1=E6=81=AF,=E9=9C=80=E8=A6=81?=
=?UTF-8?q?=E7=94=A8=E8=BF=99=E4=BA=9B=E4=BF=A1=E6=81=AF=E5=B9=B2=E4=BB=80?=
=?UTF-8?q?=E4=B9=88=E9=9C=80=E8=A6=81=E4=BD=BF=E7=94=A8=20Action=20?=
=?UTF-8?q?=E7=9A=84=E5=AD=90=E7=B1=BB=E6=9D=A5=E6=8C=87=E5=AE=9A=20,time?=
=?UTF-8?q?=3D2024-06-18=2023:21:40?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ExecuteCompilerInvocation.cpp | 125 ++++++++++++------
clang/tools/driver/cc1_main.cpp | 15 ++-
2 files changed, 91 insertions(+), 49 deletions(-)
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 7476b1076d1038..677f1e174013f8 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -43,26 +43,40 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
(void)Action;
switch (CI.getFrontendOpts().ProgramAction) {
- case ASTDeclList: return std::make_unique<ASTDeclListAction>();
- case ASTDump: return std::make_unique<ASTDumpAction>();
- case ASTPrint: return std::make_unique<ASTPrintAction>();
- case ASTView: return std::make_unique<ASTViewAction>();
+ case ASTDeclList:
+ return std::make_unique<ASTDeclListAction>();
+ case ASTDump:
+ return std::make_unique<ASTDumpAction>();
+ case ASTPrint:
+ return std::make_unique<ASTPrintAction>();
+ case ASTView:
+ return std::make_unique<ASTViewAction>();
case DumpCompilerOptions:
return std::make_unique<DumpCompilerOptionsAction>();
- case DumpRawTokens: return std::make_unique<DumpRawTokensAction>();
- case DumpTokens: return std::make_unique<DumpTokensAction>();
- case EmitAssembly: return std::make_unique<EmitAssemblyAction>();
- case EmitBC: return std::make_unique<EmitBCAction>();
+ case DumpRawTokens:
+ return std::make_unique<DumpRawTokensAction>();
+ case DumpTokens:
+ return std::make_unique<DumpTokensAction>();
+ case EmitAssembly:
+ return std::make_unique<EmitAssemblyAction>();
+ case EmitBC:
+ return std::make_unique<EmitBCAction>();
case EmitCIR:
llvm_unreachable("CIR suppport not built into clang");
- case EmitHTML: return std::make_unique<HTMLPrintAction>();
- case EmitLLVM: return std::make_unique<EmitLLVMAction>();
- case EmitLLVMOnly: return std::make_unique<EmitLLVMOnlyAction>();
- case EmitCodeGenOnly: return std::make_unique<EmitCodeGenOnlyAction>();
- case EmitObj: return std::make_unique<EmitObjAction>();
+ case EmitHTML:
+ return std::make_unique<HTMLPrintAction>();
+ case EmitLLVM:
+ return std::make_unique<EmitLLVMAction>();
+ case EmitLLVMOnly:
+ return std::make_unique<EmitLLVMOnlyAction>();
+ case EmitCodeGenOnly:
+ return std::make_unique<EmitCodeGenOnlyAction>();
+ case EmitObj:
+ return std::make_unique<EmitObjAction>();
case ExtractAPI:
return std::make_unique<ExtractAPIAction>();
- case FixIt: return std::make_unique<FixItAction>();
+ case FixIt:
+ return std::make_unique<FixItAction>();
case GenerateModule:
return std::make_unique<GenerateModuleFromModuleMapAction>();
case GenerateModuleInterface:
@@ -71,14 +85,20 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
return std::make_unique<GenerateReducedModuleInterfaceAction>();
case GenerateHeaderUnit:
return std::make_unique<GenerateHeaderUnitAction>();
- case GeneratePCH: return std::make_unique<GeneratePCHAction>();
+ case GeneratePCH:
+ return std::make_unique<GeneratePCHAction>();
case GenerateInterfaceStubs:
return std::make_unique<GenerateInterfaceStubsAction>();
- case InitOnly: return std::make_unique<InitOnlyAction>();
- case ParseSyntaxOnly: return std::make_unique<SyntaxOnlyAction>();
- case ModuleFileInfo: return std::make_unique<DumpModuleInfoAction>();
- case VerifyPCH: return std::make_unique<VerifyPCHAction>();
- case TemplightDump: return std::make_unique<TemplightDumpAction>();
+ case InitOnly:
+ return std::make_unique<InitOnlyAction>();
+ case ParseSyntaxOnly:
+ return std::make_unique<SyntaxOnlyAction>();
+ case ModuleFileInfo:
+ return std::make_unique<DumpModuleInfoAction>();
+ case VerifyPCH:
+ return std::make_unique<VerifyPCHAction>();
+ case TemplightDump:
+ return std::make_unique<TemplightDumpAction>();
case PluginAction: {
for (const FrontendPluginRegistry::entry &Plugin :
@@ -96,11 +116,12 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
}
CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name)
- << CI.getFrontendOpts().ActionName;
+ << CI.getFrontendOpts().ActionName;
return nullptr;
}
- case PrintPreamble: return std::make_unique<PrintPreambleAction>();
+ case PrintPreamble:
+ return std::make_unique<PrintPreambleAction>();
case PrintPreprocessedInput: {
if (CI.getPreprocessorOutputOpts().RewriteIncludes ||
CI.getPreprocessorOutputOpts().RewriteImports)
@@ -108,31 +129,42 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
return std::make_unique<PrintPreprocessedAction>();
}
- case RewriteMacros: return std::make_unique<RewriteMacrosAction>();
- case RewriteTest: return std::make_unique<RewriteTestAction>();
+ case RewriteMacros:
+ return std::make_unique<RewriteMacrosAction>();
+ case RewriteTest:
+ return std::make_unique<RewriteTestAction>();
#if CLANG_ENABLE_OBJC_REWRITER
- case RewriteObjC: return std::make_unique<RewriteObjCAction>();
+ case RewriteObjC:
+ return std::make_unique<RewriteObjCAction>();
#else
- case RewriteObjC: Action = "RewriteObjC"; break;
+ case RewriteObjC:
+ Action = "RewriteObjC";
+ break;
#endif
#if CLANG_ENABLE_ARCMT
case MigrateSource:
return std::make_unique<arcmt::MigrateSourceAction>();
#else
- case MigrateSource: Action = "MigrateSource"; break;
+ case MigrateSource:
+ Action = "MigrateSource";
+ break;
#endif
#if CLANG_ENABLE_STATIC_ANALYZER
- case RunAnalysis: return std::make_unique<ento::AnalysisAction>();
+ case RunAnalysis:
+ return std::make_unique<ento::AnalysisAction>();
#else
- case RunAnalysis: Action = "RunAnalysis"; break;
+ case RunAnalysis:
+ Action = "RunAnalysis";
+ break;
#endif
- case RunPreprocessorOnly: return std::make_unique<PreprocessOnlyAction>();
+ case RunPreprocessorOnly:
+ return std::make_unique<PreprocessOnlyAction>();
case PrintDependencyDirectivesSourceMinimizerOutput:
return std::make_unique<PrintDependencyDirectivesSourceMinimizerAction>();
}
-#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER \
- || !CLANG_ENABLE_OBJC_REWRITER
+#if !CLANG_ENABLE_ARCMT || !CLANG_ENABLE_STATIC_ANALYZER || \
+ !CLANG_ENABLE_OBJC_REWRITER
CI.getDiagnostics().Report(diag::err_fe_action_not_available) << Action;
return 0;
#else
@@ -140,8 +172,7 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
#endif
}
-std::unique_ptr<FrontendAction>
-CreateFrontendAction(CompilerInstance &CI) {
+std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &CI) {
// Create the underlying action.
std::unique_ptr<FrontendAction> Act = CreateFrontendBaseAction(CI);
if (!Act)
@@ -167,17 +198,15 @@ CreateFrontendAction(CompilerInstance &CI) {
Act = std::make_unique<arcmt::ModifyAction>(std::move(Act));
break;
case FrontendOptions::ARCMT_Migrate:
- Act = std::make_unique<arcmt::MigrateAction>(std::move(Act),
- FEOpts.MTMigrateDir,
- FEOpts.ARCMTMigrateReportOut,
- FEOpts.ARCMTMigrateEmitARCErrors);
+ Act = std::make_unique<arcmt::MigrateAction>(
+ std::move(Act), FEOpts.MTMigrateDir, FEOpts.ARCMTMigrateReportOut,
+ FEOpts.ARCMTMigrateEmitARCErrors);
break;
}
if (FEOpts.ObjCMTAction != FrontendOptions::ObjCMT_None) {
- Act = std::make_unique<arcmt::ObjCMigrateAction>(std::move(Act),
- FEOpts.MTMigrateDir,
- FEOpts.ObjCMTAction);
+ Act = std::make_unique<arcmt::ObjCMigrateAction>(
+ std::move(Act), FEOpts.MTMigrateDir, FEOpts.ObjCMTAction);
}
}
#endif
@@ -197,15 +226,18 @@ CreateFrontendAction(CompilerInstance &CI) {
// If there are any AST files to merge, create a frontend action
// adaptor to perform the merge.
if (!FEOpts.ASTMergeFiles.empty())
- Act = std::make_unique<ASTMergeAction>(std::move(Act),
- FEOpts.ASTMergeFiles);
+ Act =
+ std::make_unique<ASTMergeAction>(std::move(Act), FEOpts.ASTMergeFiles);
return Act;
}
bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
+ // Cratels: 如果参数是--help 的话其实就不用做其他处理,打印其 help 文档即可
// Honor -help.
if (Clang->getFrontendOpts().ShowHelp) {
+ llvm::outs()
+ << "打印出 clang 前端的 help 信息。注意:这些 option必须在 -cc1 后面\n";
driver::getDriverOptTable().printHelp(
llvm::outs(), "clang -cc1 [options] file...",
"LLVM 'Clang' Compiler: http://clang.llvm.org",
@@ -217,6 +249,8 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Honor -version.
//
// FIXME: Use a better -version message?
+
+ // Cratels: 打印 clang-cc1 的版本信息
if (Clang->getFrontendOpts().ShowVersion) {
llvm::cl::PrintVersionMessage();
return true;
@@ -230,7 +264,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// This should happen AFTER plugins have been loaded!
if (!Clang->getFrontendOpts().LLVMArgs.empty()) {
unsigned NumArgs = Clang->getFrontendOpts().LLVMArgs.size();
- auto Args = std::make_unique<const char*[]>(NumArgs + 2);
+ auto Args = std::make_unique<const char *[]>(NumArgs + 2);
Args[0] = "clang (LLVM option parsing)";
for (unsigned i = 0; i != NumArgs; ++i)
Args[i + 1] = Clang->getFrontendOpts().LLVMArgs[i].c_str();
@@ -274,6 +308,9 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
if (Clang->getDiagnostics().hasErrorOccurred())
return false;
// Create and execute the frontend action.
+ // Cratels: Clang
+ // 实例有需要的所有信息,但是开发者需要用这些信息做什么这需要使用前端 Action
+ // 来指定想要打印 ast 还是 token 等操作
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
return false;
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 2aebc6d3c01782..98aa9daa6536a5 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -63,7 +63,7 @@ using namespace llvm::opt;
static void LLVMErrorHandler(void *UserData, const char *Message,
bool GenCrashDiag) {
- DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+ DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine *>(UserData);
Diags.Report(diag::err_fe_error_backend) << Message;
@@ -139,7 +139,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
const llvm::ArrayRef<llvm::SubtargetFeatureKV> Features =
- MCInfo->getAllProcessorFeatures();
+ MCInfo->getAllProcessorFeatures();
llvm::StringMap<llvm::StringRef> DescMap;
for (const llvm::SubtargetFeatureKV &feature : Features)
@@ -164,6 +164,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
ensureSufficientStack();
+ // Cratels: 编译器实例,类似 clang 编译器的上下文
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
@@ -189,9 +190,12 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
Diags.setSeverity(diag::remark_cc1_round_trip_generated,
diag::Severity::Remark, {});
+ // Cratels: 解析参数,将参数解析之后塞进 Clang
+ // 实例中,可见后续Clang->getFrontendOpts(),Clang->getHeaderSearchOpts()等操作
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
Argv, Diags, Argv0);
+ // Cratels: 解析完参数后直接使用
if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
llvm::timeTraceProfilerInitialize(
Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
@@ -208,7 +212,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
Clang->getHeaderSearchOpts().ResourceDir.empty())
Clang->getHeaderSearchOpts().ResourceDir =
- CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+ CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Create the actual diagnostics engine.
Clang->createDiagnostics();
@@ -217,8 +221,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
- llvm::install_fatal_error_handler(LLVMErrorHandler,
- static_cast<void*>(&Clang->getDiagnostics()));
+ llvm::install_fatal_error_handler(
+ LLVMErrorHandler, static_cast<void *>(&Clang->getDiagnostics()));
DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
if (!Success) {
@@ -227,6 +231,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
}
// Execute the frontend actions.
+ // Cratels: 开始执行前端动作
{
llvm::TimeTraceScope TimeScope("ExecuteCompiler");
Success = ExecuteCompilerInvocation(Clang.get());
>From cd9bca096cb0e8695ca5696338ac9888cbbd9e19 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Wed, 19 Jun 2024 22:30:02 +0800
Subject: [PATCH 06/21] =?UTF-8?q?add=20comments:=20=E8=B7=9F=E8=B8=AA=20ll?=
=?UTF-8?q?vm=20=E4=B8=8B=E7=9A=84=20cmake=20=E6=96=87=E4=BB=B6=E7=9C=8B?=
=?UTF-8?q?=E7=9C=8B=E5=A6=82=E4=BD=95=E5=B0=86=20enable=20=E7=9A=84?=
=?UTF-8?q?=E5=AD=90=E9=A1=B9=E7=9B=AE=E5=8A=A0=E5=85=A5=E7=BC=96=E8=AF=91?=
=?UTF-8?q?=E7=8E=AF=E5=A2=83=E4=B8=AD=E7=9A=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
clang/include/clang/Frontend/FrontendAction.h | 11 ++++-----
llvm/CMakeLists.txt | 24 ++++++++++++++++---
llvm/cmake/modules/AddLLVM.cmake | 14 +++++++++--
llvm/tools/CMakeLists.txt | 1 +
4 files changed, 38 insertions(+), 12 deletions(-)
diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h
index 039f6f247b6d8c..2addc74a18774e 100644
--- a/clang/include/clang/Frontend/FrontendAction.h
+++ b/clang/include/clang/Frontend/FrontendAction.h
@@ -82,9 +82,7 @@ class FrontendAction {
///
/// \return True on success; on failure ExecutionAction() and
/// EndSourceFileAction() will not be called.
- virtual bool BeginSourceFileAction(CompilerInstance &CI) {
- return true;
- }
+ virtual bool BeginSourceFileAction(CompilerInstance &CI) { return true; }
/// Callback to run the program action, using the initialized
/// compiler instance.
@@ -132,9 +130,7 @@ class FrontendAction {
return (bool)CurrentASTUnit;
}
- const FrontendInputFile &getCurrentInput() const {
- return CurrentInput;
- }
+ const FrontendInputFile &getCurrentInput() const { return CurrentInput; }
StringRef getCurrentFile() const {
assert(!CurrentInput.isEmpty() && "No current file!");
@@ -256,6 +252,7 @@ class ASTFrontendAction : public FrontendAction {
class PluginASTAction : public ASTFrontendAction {
virtual void anchor();
+
public:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override = 0;
@@ -329,6 +326,6 @@ class WrapperFrontendAction : public FrontendAction {
bool hasCodeCompletionSupport() const override;
};
-} // end namespace clang
+} // end namespace clang
#endif
diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt
index 0873f5bc117a62..d2d3604f12a7e4 100644
--- a/llvm/CMakeLists.txt
+++ b/llvm/CMakeLists.txt
@@ -269,25 +269,31 @@ mark_as_advanced(LLVM_ENABLE_PROJECTS_USED)
if (LLVM_ENABLE_PROJECTS_USED OR NOT LLVM_ENABLE_PROJECTS STREQUAL "")
set(LLVM_ENABLE_PROJECTS_USED ON CACHE BOOL "" FORCE)
+ foreach(proj ${LLVM_KNOWN_PROJECTS} ${LLVM_EXTERNAL_PROJECTS})
+ message(WARNING ${proj})
+ endforeach()
+ # 遍历所有支持的子项目而不是 enable 的子项目
foreach(proj ${LLVM_KNOWN_PROJECTS} ${LLVM_EXTERNAL_PROJECTS})
# 将proj转为大写
string(TOUPPER "${proj}" upper_proj)
message(WARNING "子项目名大写===="${upper_proj})
string(REGEX REPLACE "-" "_" upper_proj ${upper_proj})
message(WARNING "大写子项目名替换-为_后===="${upper_proj})
+ # 判断 proj 是否在被打开的 projects 中
if ("${proj}" IN_LIST LLVM_ENABLE_PROJECTS)
message(STATUS "${proj} project is enabled")
+ # 如果 proj 在 enable 列表中,将变量SHOULD_ENABLE_PROJECT设置为 true,后面使用
set(SHOULD_ENABLE_PROJECT TRUE)
- # 设置子工程的路径
+ # 设置子工程的路径,通过相对路径找到 llvm 文件夹平级的子项目文件夹,比如这里可以找到 clang 文件夹
set(PROJ_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}")
message(WARNING "子工程路径===="${PROJ_DIR})
- # 找不到路径指向的文件夹
+ # 如果根据路径找不到指向的文件夹,直接报错
if(NOT EXISTS "${PROJ_DIR}" OR NOT IS_DIRECTORY "${PROJ_DIR}")
message(FATAL_ERROR "LLVM_ENABLE_PROJECTS requests ${proj} but directory not found: ${PROJ_DIR}")
endif()
-
+ # 设置环境变量LLVM_EXTERNAL_CLANG_SOURCE_DIR 指向外面的 clang 文件夹
if( LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR STREQUAL "" )
set(LLVM_EXTERNAL_${upper_proj}_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../${proj}" CACHE PATH "" FORCE)
else()
@@ -301,11 +307,14 @@ if (LLVM_ENABLE_PROJECTS_USED OR NOT LLVM_ENABLE_PROJECTS STREQUAL "")
message(STATUS "${proj} project is disabled")
set(SHOULD_ENABLE_PROJECT FALSE)
endif()
+
+
# Force `LLVM_TOOL_${upper_proj}_BUILD` variables to have values that
# corresponds with `LLVM_ENABLE_PROJECTS`. This prevents the user setting
# `LLVM_TOOL_${upper_proj}_BUILD` variables externally. At some point
# we should deprecate allowing users to set these variables by turning them
# into normal CMake variables rather than cache variables.
+ # 设置变量 LLVM_TOOL_CLANG_BUILD,类似变量被用来决定是否在编译的时候引入子项目
set(LLVM_TOOL_${upper_proj}_BUILD
${SHOULD_ENABLE_PROJECT}
CACHE
@@ -313,6 +322,14 @@ if (LLVM_ENABLE_PROJECTS_USED OR NOT LLVM_ENABLE_PROJECTS STREQUAL "")
)
message(WARNING "设置变量LLVM_TOOL_${upper_proj}_BUILD的值为===="${LLVM_TOOL_${upper_proj}_BUILD})
endforeach()
+
+ #
+ #
+ # 上面的遍历与判断最后就是生成了对应的 bool 变量,比如针对 clang 就生成了LLVM_TOOL_CLANG_BUILD为 true。待后续使用。
+ #
+ #
+
+
endif()
unset(SHOULD_ENABLE_PROJECT)
@@ -1323,6 +1340,7 @@ endforeach()
add_subdirectory(projects)
if( LLVM_INCLUDE_TOOLS )
+ # 此处加载 tools 下面的 cmake 文件
add_subdirectory(tools)
endif()
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 03f4e1f190fd98..33ed5a6674b45e 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -6,14 +6,14 @@ include(DetermineGCCCompatible)
# get_subproject_title(titlevar)
# Set ${outvar} to the title of the current LLVM subproject (Clang, MLIR ...)
-#
+#
# The title is set in the subproject's top-level using the variable
# LLVM_SUBPROJECT_TITLE. If it does not exist, it is assumed it is LLVM itself.
# The title is not semantically significant, but use to create folders in
# CMake-generated IDE projects (Visual Studio/XCode).
function(get_subproject_title outvar)
if (LLVM_SUBPROJECT_TITLE)
- set(${outvar} "${LLVM_SUBPROJECT_TITLE}" PARENT_SCOPE)
+ set(${outvar} "${LLVM_SUBPROJECT_TITLE}" PARENT_SCOPE)
else ()
set(${outvar} "LLVM" PARENT_SCOPE)
endif ()
@@ -1551,12 +1551,18 @@ endfunction(canonicalize_tool_name)
# Takes in a project name (i.e. LLVM), the subdirectory name, and an optional
# path if it differs from the name.
function(add_llvm_subdirectory project type name)
+ message(WARNING "将 LLVM 的子文件夹${project}加入到当前编译上下文中...")
set(add_llvm_external_dir "${ARGN}")
if("${add_llvm_external_dir}" STREQUAL "")
set(add_llvm_external_dir ${name})
endif()
canonicalize_tool_name(${name} nameUPPER)
+
+ message(WARNING ${nameUPPER})
+
set(canonical_full_name ${project}_${type}_${nameUPPER})
+
+ message(WARNING ${canonical_full_name})
get_property(already_processed GLOBAL PROPERTY ${canonical_full_name}_PROCESSED)
if(already_processed)
return()
@@ -1570,6 +1576,7 @@ function(add_llvm_subdirectory project type name)
mark_as_advanced(${project}_${type}_${name}_BUILD)
if(${canonical_full_name}_BUILD)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${add_llvm_external_dir} ${add_llvm_external_dir})
+ message(WARNING ${${CMAKE_CURRENT_SOURCE_DIR}/${add_llvm_external_dir}})
endif()
else()
set(LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR
@@ -1586,7 +1593,9 @@ function(add_llvm_subdirectory project type name)
"Whether to build ${name} as part of LLVM"
${${canonical_full_name}_BUILD_DEFAULT})
if (${canonical_full_name}_BUILD)
+ message(WARNING ${${canonical_full_name}_BUILD}"============")
if(EXISTS ${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR})
+ # Cratels: 从这里添加 clang 子文件夹到项目中
add_subdirectory(${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR} ${add_llvm_external_dir})
elseif(NOT "${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR}" STREQUAL "")
message(WARNING "Nonexistent directory for ${name}: ${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR}")
@@ -1601,6 +1610,7 @@ endfunction()
# enable or disable building it with everything else.
# Additional parameter can be specified as the name of directory.
macro(add_llvm_external_project name)
+ message(WARNING "尝试将子项目${name}加入编译中...")
add_llvm_subdirectory(LLVM TOOL ${name} ${ARGN})
endmacro()
diff --git a/llvm/tools/CMakeLists.txt b/llvm/tools/CMakeLists.txt
index db66dad5dc0dbd..5592fad954c8a5 100644
--- a/llvm/tools/CMakeLists.txt
+++ b/llvm/tools/CMakeLists.txt
@@ -41,6 +41,7 @@ add_llvm_external_project(lld)
add_llvm_external_project(mlir)
# ClangIR and Flang depend on mlir, lldb and Flang depend on clang, sort them
# accordingly so place them afterwards
+# 尝试将 clang 加入编译列表中
add_llvm_external_project(clang)
add_llvm_external_project(flang)
add_llvm_external_project(lldb)
>From 31024ea66d21d4f6a270b78491dfbbe629eb08c9 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Thu, 20 Jun 2024 21:39:29 +0800
Subject: [PATCH 07/21] add comments, time=2024-06-20 21:39:29
---
llvm/cmake/modules/AddLLVM.cmake | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake
index 33ed5a6674b45e..bc36cc2661e758 100644
--- a/llvm/cmake/modules/AddLLVM.cmake
+++ b/llvm/cmake/modules/AddLLVM.cmake
@@ -1596,6 +1596,7 @@ function(add_llvm_subdirectory project type name)
message(WARNING ${${canonical_full_name}_BUILD}"============")
if(EXISTS ${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR})
# Cratels: 从这里添加 clang 子文件夹到项目中
+ message(WARNING ${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR})
add_subdirectory(${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR} ${add_llvm_external_dir})
elseif(NOT "${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR}" STREQUAL "")
message(WARNING "Nonexistent directory for ${name}: ${LLVM_EXTERNAL_${nameUPPER}_SOURCE_DIR}")
>From b229fba9de7142fb3918591af225b4d7d965e651 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Thu, 20 Jun 2024 21:56:20 +0800
Subject: [PATCH 08/21] add comments, time=2024-06-20 21:56:20
---
clang/CMakeLists.txt | 6 ++++++
clang/tools/driver/CMakeLists.txt | 1 +
clang/tools/driver/driver.cpp | 2 ++
3 files changed, 9 insertions(+)
diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt
index c6496167d3828b..1f9174ce2f4234 100644
--- a/clang/CMakeLists.txt
+++ b/clang/CMakeLists.txt
@@ -1,14 +1,20 @@
cmake_minimum_required(VERSION 3.20.0)
+
+# 设置子项目的名称为 Clang
set(LLVM_SUBPROJECT_TITLE "Clang")
+# LLVM_COMMON_CMAKE_UTILS指当前子项目的 cmake 预定义属性
+# 每一个子项目该属性具体值各不相同
if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS)
set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake)
endif()
+
include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake
NO_POLICY_SCOPE)
# If we are not building as a part of LLVM, build Clang as an
# standalone project, using LLVM as an external library:
+# 如果不是在编译 LLVM 项目的时候编译子项目Clang,而是将 LLVM 项目作为外部库来单独编译 Clang时:
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
project(Clang)
set(CLANG_BUILT_STANDALONE TRUE)
diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt
index 290bf2a42536dd..1bb4ca6ca1553b 100644
--- a/clang/tools/driver/CMakeLists.txt
+++ b/clang/tools/driver/CMakeLists.txt
@@ -23,6 +23,7 @@ if(CLANG_PLUGIN_SUPPORT)
set(support_plugins SUPPORT_PLUGINS)
endif()
+# 用于生成 clang 二进制文件
add_clang_tool(clang
driver.cpp
cc1_main.cpp
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 61879e8959fb04..1b9447edae913b 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -225,6 +225,7 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
return 1;
}
+// Cratels: clang代码的真正入口
int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// Cratels: 标记栈底位置
noteBottomOfStack();
@@ -239,6 +240,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
if (llvm::sys::Process::FixupStandardFileDescriptors())
return 1;
+ // TODO: 初始化所有 target 的具体作用尚不清楚
llvm::InitializeAllTargets();
llvm::BumpPtrAllocator A;
>From 7c61214cdb113adeb2db31bc34be1ceb92549e5d Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Thu, 20 Jun 2024 22:52:07 +0800
Subject: [PATCH 09/21] add comments, time=2024-06-20 22:52:07
---
.../ExecuteCompilerInvocation.cpp | 15 +++++++++++---
clang/tools/driver/cc1_main.cpp | 10 +++++++++-
clang/tools/driver/driver.cpp | 20 +++++++++++++++----
3 files changed, 37 insertions(+), 8 deletions(-)
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 677f1e174013f8..f5677ff16e41cc 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -252,6 +252,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Cratels: 打印 clang-cc1 的版本信息
if (Clang->getFrontendOpts().ShowVersion) {
+ llvm::outs() << "打印版本信息......\n";
llvm::cl::PrintVersionMessage();
return true;
}
@@ -272,6 +273,9 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
+// clang-format off
+// Cratels: 是否打开 clang 的静态代码检测功能。只到 endif 的代码都在处理静态代码检测的问题,暂时不处理
+// clang-format on
#if CLANG_ENABLE_STATIC_ANALYZER
// These should happen AFTER plugins have been loaded!
@@ -308,13 +312,18 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
if (Clang->getDiagnostics().hasErrorOccurred())
return false;
// Create and execute the frontend action.
- // Cratels: Clang
- // 实例有需要的所有信息,但是开发者需要用这些信息做什么这需要使用前端 Action
- // 来指定想要打印 ast 还是 token 等操作
+ // clang-format off
+ // Cratels: Clang 实例有需要的所有信息,但是开发者需要用这些信息做什么这需要使用前端 Action 来指定想要打印 ast 还是 token 等操作
+ // clang-format on
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
return false;
+
+ // clang-format off
+ // Cratels: CreateFrontendAction创建出指定的 Action,然后调用ExecuteAction来执行 action
+ // clang-format on
bool Success = Clang->ExecuteAction(*Act);
+
if (Clang->getFrontendOpts().DisableFree)
llvm::BuryPointer(std::move(Act));
return Success;
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 98aa9daa6536a5..1783e545f7d517 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -165,7 +165,11 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
ensureSufficientStack();
// Cratels: 编译器实例,类似 clang 编译器的上下文
+ // clang-format off
+ // Cratels: 单例模式,此处创建后后续就可以直接使用 getCompilerInstance 来获得对象
+ // clang-format on
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
+
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Register the support for object-file-wrapped Clang modules.
@@ -191,6 +195,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
diag::Severity::Remark, {});
// Cratels: 解析参数,将参数解析之后塞进 Clang
+ // clang-format off
+ // Cratels: Invocation就是 option
+ // clang-format on
// 实例中,可见后续Clang->getFrontendOpts(),Clang->getHeaderSearchOpts()等操作
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
Argv, Diags, Argv0);
@@ -231,9 +238,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
}
// Execute the frontend actions.
- // Cratels: 开始执行前端动作
+ // Cratels: 开始执行真正的前端动作
{
llvm::TimeTraceScope TimeScope("ExecuteCompiler");
+ llvm::outs() << "开始执行真正的前端解析动作......\n";
Success = ExecuteCompilerInvocation(Clang.get());
}
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 1b9447edae913b..69e2735bddba76 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -201,9 +201,16 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
// Driver::CC1Main), we need to clean up the options usage count. The options
// are currently global, and they might have been used previously by the
// driver.
+
+ // clang-format off
+ // Cratels: cl就是代指 clang 相关代码的 namespace
+ // clang-format on
llvm::cl::ResetAllOptionOccurrences();
llvm::BumpPtrAllocator A;
+ // clang-format off
+ // Cratels:
+ // clang-format on
llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
llvm::errs() << toString(std::move(Err)) << '\n';
@@ -258,10 +265,10 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
// Handle -cc1 integrated tools.
- // Cratels: 处理以-cc1 开头的 options
- // -cc1开头的 option 将 clang 编译器或者叫 driver 退化为单纯的 clang
- // fronted前端。用户不应该使用-cc1 option,因为该 option 并不承诺稳定 clang
- // -cc1 is the frontend, clang is the driver. The driver invokes the frontend
+ // clang-format off
+ // Cratels: 处理以-cc1 开头的 options -cc1开头的 option 将 clang 编译器或者叫 driver 退化为单纯的 clang fronted前端。
+ // 用户不应该使用-cc1 option,因为该 option 并不承诺稳定
+ // clang -cc1 is the frontend, clang is the driver. The driver invokes the frontend
// with options appropriate for your system.Some clang command line options
// are driver-only options, some are frontend-only options. Frontend-only
// options are intended to be used only by clang developers. Users should not
@@ -270,10 +277,15 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// example -ast-dump, then you need to take the clang-cc1 line generated by
// the driver and add the option you need. Alternatively, you can run
// clang-Xclang<option>... to force the driver pass <option> to clang-cc1
+ // clang-format on
+
// Cratels: 如果只想使用前端 option,应该在第一个参数的位置
// Args[1]的位置直接写上-cc1开头的
// option,否则就不会进入ExecuteCC1Tool,而是直接作为 driver 执行
if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1"))
+ // clang-format off
+ // Cratels: ExecuteCC1Tool执行cc1工具,即只执行 clang 的前端而不作为整个编译器来使用
+ // clang-format on
return ExecuteCC1Tool(Args, ToolContext);
// Cratels: 作为 driver,完整编译器开始执行
>From e71822f35f79cb4b7e9839de1d22116c5cddcd06 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Fri, 21 Jun 2024 10:41:16 +0800
Subject: [PATCH 10/21] update comments
---
clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index f5677ff16e41cc..86fcd25d3855c9 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -172,12 +172,17 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
#endif
}
+// Cratels: 创建一个FontAction的智能指针,具体是哪个action是怎样带进来的?
std::unique_ptr<FrontendAction> CreateFrontendAction(CompilerInstance &CI) {
// Create the underlying action.
std::unique_ptr<FrontendAction> Act = CreateFrontendBaseAction(CI);
if (!Act)
return nullptr;
+ // clang-format off
+ // Cratels: 获取前端的options,此时具体是使用哪种action会从option中获得。比如clang -cc1 -ast-dump demo.cpp执行时“-ast-dump”就会在这里。
+ // Cratels: 这个option会影响具体是哪种action
+ // clang-format on
const FrontendOptions &FEOpts = CI.getFrontendOpts();
if (FEOpts.FixAndRecompile) {
>From 8b3aa8c7dbdf2ebf05633fc743a5b8dc8cfe6a30 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Fri, 21 Jun 2024 14:41:56 +0800
Subject: [PATCH 11/21] update comments
---
.../clang/Frontend/CompilerInvocation.h | 22 +-
clang/lib/Frontend/CompilerInstance.cpp | 217 +++++++++---------
clang/lib/Frontend/FrontendAction.cpp | 62 ++---
.../ExecuteCompilerInvocation.cpp | 1 +
clang/tools/driver/cc1_main.cpp | 12 +-
5 files changed, 158 insertions(+), 156 deletions(-)
diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h
index 1a2a39411e58d8..d73e17bb2a8322 100644
--- a/clang/include/clang/Frontend/CompilerInvocation.h
+++ b/clang/include/clang/Frontend/CompilerInvocation.h
@@ -21,8 +21,8 @@
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
-#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <memory>
#include <string>
@@ -208,6 +208,10 @@ class CowCompilerInvocation;
/// This class is designed to represent an abstract "invocation" of the
/// compiler, including data such as the include paths, the code generation
/// options, the warning flags, and so on.
+
+// clang-format off
+// Cratels: 该类是一个辅助类,被用来持有调用一次编译器所需要的信息。包括头文件include的路径,编译options等信息
+// clang-format on
class CompilerInvocation : public CompilerInvocationBase {
public:
CompilerInvocation() = default;
@@ -229,19 +233,19 @@ class CompilerInvocation : public CompilerInvocationBase {
/// @{
// Note: These need to be pulled in manually. Otherwise, they get hidden by
// the mutable getters with the same names.
- using CompilerInvocationBase::getLangOpts;
- using CompilerInvocationBase::getTargetOpts;
- using CompilerInvocationBase::getDiagnosticOpts;
- using CompilerInvocationBase::getHeaderSearchOpts;
- using CompilerInvocationBase::getPreprocessorOpts;
using CompilerInvocationBase::getAnalyzerOpts;
- using CompilerInvocationBase::getMigratorOpts;
using CompilerInvocationBase::getAPINotesOpts;
using CompilerInvocationBase::getCodeGenOpts;
+ using CompilerInvocationBase::getDependencyOutputOpts;
+ using CompilerInvocationBase::getDiagnosticOpts;
using CompilerInvocationBase::getFileSystemOpts;
using CompilerInvocationBase::getFrontendOpts;
- using CompilerInvocationBase::getDependencyOutputOpts;
+ using CompilerInvocationBase::getHeaderSearchOpts;
+ using CompilerInvocationBase::getLangOpts;
+ using CompilerInvocationBase::getMigratorOpts;
+ using CompilerInvocationBase::getPreprocessorOpts;
using CompilerInvocationBase::getPreprocessorOutputOpts;
+ using CompilerInvocationBase::getTargetOpts;
/// @}
/// Mutable getters.
@@ -267,9 +271,9 @@ class CompilerInvocation : public CompilerInvocationBase {
/// Base class internals.
/// @{
+ using CompilerInvocationBase::DiagnosticOpts;
using CompilerInvocationBase::LangOpts;
using CompilerInvocationBase::TargetOpts;
- using CompilerInvocationBase::DiagnosticOpts;
std::shared_ptr<HeaderSearchOptions> getHeaderSearchOptsPtr() {
return HSOpts;
}
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 6242b5a7d9fe39..f534551c5ed4f3 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -96,7 +96,8 @@ void CompilerInstance::setVerboseOutputStream(raw_ostream &Value) {
VerboseOutputStream = &Value;
}
-void CompilerInstance::setVerboseOutputStream(std::unique_ptr<raw_ostream> Value) {
+void CompilerInstance::setVerboseOutputStream(
+ std::unique_ptr<raw_ostream> Value) {
OwnedVerboseOutputStream.swap(Value);
VerboseOutputStream = OwnedVerboseOutputStream.get();
}
@@ -161,9 +162,7 @@ llvm::vfs::FileSystem &CompilerInstance::getVirtualFileSystem() const {
return getFileManager().getVirtualFileSystem();
}
-void CompilerInstance::setFileManager(FileManager *Value) {
- FileMgr = Value;
-}
+void CompilerInstance::setFileManager(FileManager *Value) { FileMgr = Value; }
void CompilerInstance::setSourceManager(SourceManager *Value) {
SourceMgr = Value;
@@ -180,9 +179,7 @@ void CompilerInstance::setASTContext(ASTContext *Value) {
getASTConsumer().Initialize(getASTContext());
}
-void CompilerInstance::setSema(Sema *S) {
- TheSema.reset(S);
-}
+void CompilerInstance::setSema(Sema *S) { TheSema.reset(S); }
void CompilerInstance::setASTConsumer(std::unique_ptr<ASTConsumer> Value) {
Consumer = std::move(Value);
@@ -303,7 +300,7 @@ static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts,
// Chain in the diagnostic client which will log the diagnostics.
auto Logger = std::make_unique<LogDiagnosticPrinter>(*OS, DiagOpts,
- std::move(StreamOwner));
+ std::move(StreamOwner));
if (CodeGenOpts)
Logger->setDwarfDebugFlags(CodeGenOpts->DwarfDebugFlags);
if (Diags.ownsClient()) {
@@ -332,18 +329,16 @@ static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts,
void CompilerInstance::createDiagnostics(DiagnosticConsumer *Client,
bool ShouldOwnClient) {
- Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client,
- ShouldOwnClient, &getCodeGenOpts());
+ Diagnostics = createDiagnostics(&getDiagnosticOpts(), Client, ShouldOwnClient,
+ &getCodeGenOpts());
}
-IntrusiveRefCntPtr<DiagnosticsEngine>
-CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
- DiagnosticConsumer *Client,
- bool ShouldOwnClient,
- const CodeGenOptions *CodeGenOpts) {
+IntrusiveRefCntPtr<DiagnosticsEngine> CompilerInstance::createDiagnostics(
+ DiagnosticOptions *Opts, DiagnosticConsumer *Client, bool ShouldOwnClient,
+ const CodeGenOptions *CodeGenOpts) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
- IntrusiveRefCntPtr<DiagnosticsEngine>
- Diags(new DiagnosticsEngine(DiagID, Opts));
+ IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
+ new DiagnosticsEngine(DiagID, Opts));
// Create the diagnostic client for reporting errors or for
// implementing -verify.
@@ -363,8 +358,7 @@ CompilerInstance::createDiagnostics(DiagnosticOptions *Opts,
SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags);
if (!Opts->DiagnosticSerializationFile.empty())
- SetupSerializedDiagnostics(Opts, *Diags,
- Opts->DiagnosticSerializationFile);
+ SetupSerializedDiagnostics(Opts, *Diags, Opts->DiagnosticSerializationFile);
// Configure our handling of diagnostics.
ProcessWarningOptions(*Diags, *Opts);
@@ -594,7 +588,8 @@ struct ReadModuleNames : ASTReaderListener {
Stack.push_back(M);
while (!Stack.empty()) {
Module *Current = Stack.pop_back_val();
- if (Current->IsUnimportable) continue;
+ if (Current->IsUnimportable)
+ continue;
Current->IsAvailable = true;
auto SubmodulesRange = Current->submodules();
Stack.insert(Stack.end(), SubmodulesRange.begin(),
@@ -656,11 +651,9 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
ASTReader::ListenerScope ReadModuleNamesListener(*Reader,
std::move(Listener));
- switch (Reader->ReadAST(Path,
- Preamble ? serialization::MK_Preamble
- : serialization::MK_PCH,
- SourceLocation(),
- ASTReader::ARR_None)) {
+ switch (Reader->ReadAST(
+ Path, Preamble ? serialization::MK_Preamble : serialization::MK_PCH,
+ SourceLocation(), ASTReader::ARR_None)) {
case ASTReader::Success:
// Set the predefines buffer as suggested by the PCH reader. Typically, the
// predefines buffer will be empty.
@@ -688,16 +681,14 @@ IntrusiveRefCntPtr<ASTReader> CompilerInstance::createPCHExternalASTSource(
// Code Completion
-static bool EnableCodeCompletion(Preprocessor &PP,
- StringRef Filename,
- unsigned Line,
- unsigned Column) {
+static bool EnableCodeCompletion(Preprocessor &PP, StringRef Filename,
+ unsigned Line, unsigned Column) {
// Tell the source manager to chop off the given file at a specific
// line and column.
auto Entry = PP.getFileManager().getOptionalFileRef(Filename);
if (!Entry) {
PP.getDiagnostics().Report(diag::err_fe_invalid_code_complete_file)
- << Filename;
+ << Filename;
return true;
}
@@ -713,8 +704,8 @@ void CompilerInstance::createCodeCompletionConsumer() {
getPreprocessor(), Loc.FileName, Loc.Line, Loc.Column,
getFrontendOpts().CodeCompleteOpts, llvm::outs()));
return;
- } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName,
- Loc.Line, Loc.Column)) {
+ } else if (EnableCodeCompletion(getPreprocessor(), Loc.FileName, Loc.Line,
+ Loc.Column)) {
setCodeCompletionConsumer(nullptr);
return;
}
@@ -723,18 +714,13 @@ void CompilerInstance::createCodeCompletionConsumer() {
void CompilerInstance::createFrontendTimer() {
FrontendTimerGroup.reset(
new llvm::TimerGroup("frontend", "Clang front-end time report"));
- FrontendTimer.reset(
- new llvm::Timer("frontend", "Clang front-end timer",
- *FrontendTimerGroup));
-}
-
-CodeCompleteConsumer *
-CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP,
- StringRef Filename,
- unsigned Line,
- unsigned Column,
- const CodeCompleteOptions &Opts,
- raw_ostream &OS) {
+ FrontendTimer.reset(new llvm::Timer("frontend", "Clang front-end timer",
+ *FrontendTimerGroup));
+}
+
+CodeCompleteConsumer *CompilerInstance::createCodeCompletionConsumer(
+ Preprocessor &PP, StringRef Filename, unsigned Line, unsigned Column,
+ const CodeCompleteOptions &Opts, raw_ostream &OS) {
if (EnableCodeCompletion(PP, Filename, Line, Column))
return nullptr;
@@ -959,7 +945,7 @@ CompilerInstance::createOutputFileImpl(StringRef OutputPath, bool Binary,
// Initialization Utilities
-bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){
+bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input) {
return InitializeSourceManager(Input, getDiagnostics(), getFileManager(),
getSourceManager());
}
@@ -973,7 +959,8 @@ bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input,
Input.getKind().getFormat() == InputKind::ModuleMap
? Input.isSystem() ? SrcMgr::C_System_ModuleMap
: SrcMgr::C_User_ModuleMap
- : Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User;
+ : Input.isSystem() ? SrcMgr::C_System
+ : SrcMgr::C_User;
if (Input.isBuffer()) {
SourceMgr.setMainFileID(SourceMgr.createFileID(Input.getBuffer(), Kind));
@@ -1058,6 +1045,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
getSourceManager().clearIDTables();
if (Act.BeginSourceFile(*this, FIF)) {
+ // clang-format off
+ // Cratels: 在execute方法中真正开始执行操作
+ // clang-format on
if (llvm::Error Err = Act.Execute()) {
consumeError(std::move(Err)); // FIXME this drops errors on the floor.
}
@@ -1159,14 +1149,14 @@ static Language getLanguageFromOptions(const LangOptions &LangOpts) {
/// Compile a module file for the given module, using the options
/// provided by the importing compiler instance. Returns true if the module
/// was built without errors.
-static bool
-compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
- StringRef ModuleName, FrontendInputFile Input,
- StringRef OriginalModuleMapFile, StringRef ModuleFileName,
- llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
- [](CompilerInstance &) {},
- llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
- [](CompilerInstance &) {}) {
+static bool compileModuleImpl(
+ CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
+ StringRef ModuleName, FrontendInputFile Input,
+ StringRef OriginalModuleMapFile, StringRef ModuleFileName,
+ llvm::function_ref<void(CompilerInstance &)> PreBuildStep =
+ [](CompilerInstance &) {},
+ llvm::function_ref<void(CompilerInstance &)> PostBuildStep =
+ [](CompilerInstance &) {}) {
llvm::TimeTraceScope TimeScope("Module Compile", ModuleName);
// Never compile a module that's already finalized - this would cause the
@@ -1225,7 +1215,8 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
DiagOpts.VerifyDiagnostics = 0;
assert(ImportingInstance.getInvocation().getModuleHash() ==
- Invocation->getModuleHash() && "Module hash mismatch!");
+ Invocation->getModuleHash() &&
+ "Module hash mismatch!");
// Construct a compiler instance that will be used to actually create the
// module. Since we're sharing an in-memory module cache,
@@ -1236,9 +1227,9 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
auto &Inv = *Invocation;
Instance.setInvocation(std::move(Invocation));
- Instance.createDiagnostics(new ForwardingDiagnosticConsumer(
- ImportingInstance.getDiagnosticClient()),
- /*ShouldOwnClient=*/true);
+ Instance.createDiagnostics(
+ new ForwardingDiagnosticConsumer(ImportingInstance.getDiagnosticClient()),
+ /*ShouldOwnClient=*/true);
if (llvm::is_contained(DiagOpts.SystemHeaderWarningsModules, ModuleName))
Instance.getDiagnostics().setSuppressSystemWarnings(false);
@@ -1254,9 +1245,10 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
// Note that this module is part of the module build stack, so that we
// can detect cycles in the module graph.
SourceMgr.setModuleBuildStack(
- ImportingInstance.getSourceManager().getModuleBuildStack());
- SourceMgr.pushModuleBuildStack(ModuleName,
- FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
+ ImportingInstance.getSourceManager().getModuleBuildStack());
+ SourceMgr.pushModuleBuildStack(
+ ModuleName,
+ FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager()));
// Make sure that the failed-module structure has been allocated in
// the importing instance, and propagate the pointer to the newly-created
@@ -1273,7 +1265,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build)
- << ModuleName << ModuleFileName;
+ << ModuleName << ModuleFileName;
PreBuildStep(Instance);
@@ -1290,7 +1282,7 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc,
ImportingInstance.getDiagnostics().Report(ImportLoc,
diag::remark_module_build_done)
- << ModuleName;
+ << ModuleName;
// Propagate the statistics to the parent FileManager.
if (!FrontendOpts.ModulesShareFileManager)
@@ -1335,8 +1327,8 @@ static bool compileModule(CompilerInstance &ImportingInstance,
InputKind::ModuleMap);
// Get or create the module map that we'll use to build this module.
- ModuleMap &ModMap
- = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
+ ModuleMap &ModMap =
+ ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap();
SourceManager &SourceMgr = ImportingInstance.getSourceManager();
bool Result;
if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module);
@@ -1385,16 +1377,16 @@ static bool compileModule(CompilerInstance &ImportingInstance,
Result = compileModuleImpl(
ImportingInstance, ImportLoc, Module->getTopLevelModuleName(),
FrontendInputFile(FakeModuleMapFile, IK, +Module->IsSystem),
- ModMap.getModuleMapFileForUniquing(Module)->getName(),
- ModuleFileName,
+ ModMap.getModuleMapFileForUniquing(Module)->getName(), ModuleFileName,
[&](CompilerInstance &Instance) {
- std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
- llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
- FileEntryRef ModuleMapFile = Instance.getFileManager().getVirtualFileRef(
- FakeModuleMapFile, InferredModuleMapContent.size(), 0);
- Instance.getSourceManager().overrideFileContents(
- ModuleMapFile, std::move(ModuleMapBuffer));
- });
+ std::unique_ptr<llvm::MemoryBuffer> ModuleMapBuffer =
+ llvm::MemoryBuffer::getMemBuffer(InferredModuleMapContent);
+ FileEntryRef ModuleMapFile =
+ Instance.getFileManager().getVirtualFileRef(
+ FakeModuleMapFile, InferredModuleMapContent.size(), 0);
+ Instance.getSourceManager().overrideFileContents(
+ ModuleMapFile, std::move(ModuleMapBuffer));
+ });
}
// We've rebuilt a module. If we're allowed to generate or update the global
@@ -1435,7 +1427,7 @@ static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance,
// The ASTReader didn't diagnose the error, so conservatively report it.
if (ReadResult == ASTReader::Missing || !Diags.hasErrorOccurred())
Diags.Report(ModuleNameLoc, diag::err_module_not_built)
- << Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
+ << Module->Name << SourceRange(ImportLoc, ModuleNameLoc);
return false;
}
@@ -1585,29 +1577,29 @@ static void checkConfigMacro(Preprocessor &PP, StringRef ConfigMacro,
// This macro was defined on the command line, then #undef'd later.
// Complain.
PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
- << true << ConfigMacro << Mod->getFullModuleName();
+ << true << ConfigMacro << Mod->getFullModuleName();
auto LatestDef = LatestLocalMD->getDefinition();
assert(LatestDef.isUndefined() &&
"predefined macro went away with no #undef?");
PP.Diag(LatestDef.getUndefLocation(), diag::note_module_def_undef_here)
- << true;
+ << true;
return;
} else if (!CmdLineDefinition) {
// There was no definition for this macro in the predefines buffer,
// but there was a local definition. Complain.
PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
- << false << ConfigMacro << Mod->getFullModuleName();
+ << false << ConfigMacro << Mod->getFullModuleName();
PP.Diag(CurrentDefinition->getDefinitionLoc(),
diag::note_module_def_undef_here)
- << false;
+ << false;
} else if (!CurrentDefinition->isIdenticalTo(*CmdLineDefinition, PP,
/*Syntactically=*/true)) {
// The macro definitions differ.
PP.Diag(ImportLoc, diag::warn_module_config_macro_undef)
- << false << ConfigMacro << Mod->getFullModuleName();
+ << false << ConfigMacro << Mod->getFullModuleName();
PP.Diag(CurrentDefinition->getDefinitionLoc(),
diag::note_module_def_undef_here)
- << false;
+ << false;
}
}
@@ -1684,7 +1676,7 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// If the file has been used recently enough, leave it there.
time_t FileAccessTime = llvm::sys::toTimeT(StatBuf.getLastAccessedTime());
if (CurrentTime - FileAccessTime <=
- time_t(HSOpts.ModuleCachePruneAfter)) {
+ time_t(HSOpts.ModuleCachePruneAfter)) {
continue;
}
@@ -1699,7 +1691,8 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) {
// If we removed all of the files in the directory, remove the directory
// itself.
if (llvm::sys::fs::directory_iterator(Dir->path(), EC) ==
- llvm::sys::fs::directory_iterator() && !EC)
+ llvm::sys::fs::directory_iterator() &&
+ !EC)
llvm::sys::fs::remove(Dir->path());
}
}
@@ -1727,9 +1720,8 @@ void CompilerInstance::createASTReader() {
std::unique_ptr<llvm::Timer> ReadTimer;
if (FrontendTimerGroup)
- ReadTimer = std::make_unique<llvm::Timer>("reading_modules",
- "Reading modules",
- *FrontendTimerGroup);
+ ReadTimer = std::make_unique<llvm::Timer>(
+ "reading_modules", "Reading modules", *FrontendTimerGroup);
TheASTReader = new ASTReader(
getPreprocessor(), getModuleCache(), &getASTContext(),
getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions,
@@ -1743,7 +1735,7 @@ void CompilerInstance::createASTReader() {
TheASTReader->setDeserializationListener(
getASTConsumer().GetASTDeserializationListener());
getASTContext().setASTMutationListener(
- getASTConsumer().GetASTMutationListener());
+ getASTConsumer().GetASTMutationListener());
}
getASTContext().setExternalSource(TheASTReader);
if (hasSema())
@@ -1771,8 +1763,8 @@ bool CompilerInstance::loadModuleFile(
// ASTReader to diagnose it, since it can produce better errors that we can.
bool ConfigMismatchIsRecoverable =
getDiagnostics().getDiagnosticLevel(diag::warn_module_config_mismatch,
- SourceLocation())
- <= DiagnosticsEngine::Warning;
+ SourceLocation()) <=
+ DiagnosticsEngine::Warning;
auto Listener = std::make_unique<ReadModuleNames>(*PP);
auto &ListenerRef = *Listener;
@@ -1903,16 +1895,15 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
unsigned ARRFlags = Source == MS_ModuleCache
? ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing |
ASTReader::ARR_TreatModuleWithErrorsAsOutOfDate
- : Source == MS_PrebuiltModulePath
- ? 0
- : ASTReader::ARR_ConfigurationMismatch;
- switch (getASTReader()->ReadAST(ModuleFilename,
- Source == MS_PrebuiltModulePath
- ? serialization::MK_PrebuiltModule
- : Source == MS_ModuleBuildPragma
- ? serialization::MK_ExplicitModule
- : serialization::MK_ImplicitModule,
- ImportLoc, ARRFlags)) {
+ : Source == MS_PrebuiltModulePath
+ ? 0
+ : ASTReader::ARR_ConfigurationMismatch;
+ switch (getASTReader()->ReadAST(
+ ModuleFilename,
+ Source == MS_PrebuiltModulePath ? serialization::MK_PrebuiltModule
+ : Source == MS_ModuleBuildPragma ? serialization::MK_ExplicitModule
+ : serialization::MK_ImplicitModule,
+ ImportLoc, ARRFlags)) {
case ASTReader::Success: {
if (M)
return M;
@@ -2014,8 +2005,7 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST(
}
ModuleLoadResult
-CompilerInstance::loadModule(SourceLocation ImportLoc,
- ModuleIdPath Path,
+CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path,
Module::NameVisibilityKind Visibility,
bool IsInclusionDirective) {
// Determine what file we're searching from.
@@ -2171,8 +2161,8 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
// FIXME: Should we detect this at module load time? It seems fairly
// expensive (and rare).
getDiagnostics().Report(ImportLoc, diag::warn_missing_submodule)
- << Module->getFullModuleName()
- << SourceRange(Path.front().second, Path.back().second);
+ << Module->getFullModuleName()
+ << SourceRange(Path.front().second, Path.back().second);
return ModuleLoadResult(Module, ModuleLoadResult::MissingExpected);
}
@@ -2181,7 +2171,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc,
if (Preprocessor::checkModuleIsAvailable(getLangOpts(), getTarget(),
*Module, getDiagnostics())) {
getDiagnostics().Report(ImportLoc, diag::note_module_import_here)
- << SourceRange(Path.front().second, Path.back().second);
+ << SourceRange(Path.front().second, Path.back().second);
LastModuleImportLoc = ImportLoc;
LastModuleImportResult = ModuleLoadResult();
return ModuleLoadResult();
@@ -2225,7 +2215,7 @@ void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc,
FrontendInputFile Input(
ModuleMapFileName,
InputKind(getLanguageFromOptions(Invocation->getLangOpts()),
- InputKind::ModuleMap, /*Preprocessed*/true));
+ InputKind::ModuleMap, /*Preprocessed*/ true));
std::string NullTerminatedSource(Source.str());
@@ -2264,8 +2254,8 @@ void CompilerInstance::makeModuleVisible(Module *Mod,
TheASTReader->makeModuleVisible(Mod, Visibility, ImportLoc);
}
-GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
- SourceLocation TriggerLoc) {
+GlobalModuleIndex *
+CompilerInstance::loadGlobalModuleIndex(SourceLocation TriggerLoc) {
if (getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty())
return nullptr;
if (!TheASTReader)
@@ -2281,7 +2271,7 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() &&
hasPreprocessor()) {
llvm::sys::fs::create_directories(
- getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
+ getPreprocessor().getHeaderSearchInfo().getModuleCachePath());
if (llvm::Error Err = GlobalModuleIndex::writeIndex(
getFileManager(), getPCHContainerReader(),
getPreprocessor().getHeaderSearchInfo().getModuleCachePath())) {
@@ -2302,7 +2292,8 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
ModuleMap &MMap = getPreprocessor().getHeaderSearchInfo().getModuleMap();
bool RecreateIndex = false;
for (ModuleMap::module_iterator I = MMap.module_begin(),
- E = MMap.module_end(); I != E; ++I) {
+ E = MMap.module_end();
+ I != E; ++I) {
Module *TheModule = I->second;
OptionalFileEntryRef Entry = TheModule->getASTFile();
if (!Entry) {
@@ -2333,15 +2324,13 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex(
}
// Check global module index for missing imports.
-bool
-CompilerInstance::lookupMissingImports(StringRef Name,
- SourceLocation TriggerLoc) {
+bool CompilerInstance::lookupMissingImports(StringRef Name,
+ SourceLocation TriggerLoc) {
// Look for the symbol in non-imported modules, but only if an error
// actually occurred.
if (!buildingModule()) {
// Load global module index, or retrieve a previously loaded one.
- GlobalModuleIndex *GlobalIndex = loadGlobalModuleIndex(
- TriggerLoc);
+ GlobalModuleIndex *GlobalIndex = loadGlobalModuleIndex(TriggerLoc);
// Only if we have a global index.
if (GlobalIndex) {
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index a9c45e525c696c..86c9f1f57ea0a9 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -131,9 +131,8 @@ class DeserializedDeclsChecker : public DelegatingDeserializationListener {
void DeclRead(GlobalDeclID ID, const Decl *D) override {
if (const NamedDecl *ND = dyn_cast<NamedDecl>(D))
if (NamesToCheck.find(ND->getNameAsString()) != NamesToCheck.end()) {
- unsigned DiagID
- = Ctx.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error,
- "%0 was deserialized");
+ unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Error, "%0 was deserialized");
Ctx.getDiagnostics().Report(Ctx.getFullLoc(D->getLocation()), DiagID)
<< ND;
}
@@ -157,7 +156,7 @@ void FrontendAction::setCurrentInput(const FrontendInputFile &CurrentInput,
Module *FrontendAction::getCurrentModule() const {
CompilerInstance &CI = getCompilerInstance();
return CI.getPreprocessor().getHeaderSearchInfo().lookupModule(
- CI.getLangOpts().CurrentModule, SourceLocation(), /*AllowSearch*/false);
+ CI.getLangOpts().CurrentModule, SourceLocation(), /*AllowSearch*/ false);
}
std::unique_ptr<ASTConsumer>
@@ -217,7 +216,8 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
P->ParseArgs(
CI,
CI.getFrontendOpts().PluginArgs[std::string(Plugin.getName())])) {
- std::unique_ptr<ASTConsumer> PluginConsumer = P->CreateASTConsumer(CI, InFile);
+ std::unique_ptr<ASTConsumer> PluginConsumer =
+ P->CreateASTConsumer(CI, InFile);
if (ActionType == PluginASTAction::AddBeforeMainAction) {
Consumers.push_back(std::move(PluginConsumer));
} else {
@@ -303,16 +303,15 @@ static SourceLocation ReadOriginalFileName(CompilerInstance &CI,
return T.getLocation();
}
-static SmallVectorImpl<char> &
-operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) {
+static SmallVectorImpl<char> &operator+=(SmallVectorImpl<char> &Includes,
+ StringRef RHS) {
Includes.append(RHS.begin(), RHS.end());
return Includes;
}
static void addHeaderInclude(StringRef HeaderName,
SmallVectorImpl<char> &Includes,
- const LangOptions &LangOpts,
- bool IsExternC) {
+ const LangOptions &LangOpts, bool IsExternC) {
if (IsExternC && LangOpts.CPlusPlus)
Includes += "extern \"C\" {\n";
if (LangOpts.ObjC)
@@ -352,7 +351,7 @@ static std::error_code collectModuleHeaderIncludes(
if (!Module->MissingHeaders.empty()) {
auto &MissingHeader = Module->MissingHeaders.front();
Diag.Report(MissingHeader.FileNameLoc, diag::err_module_header_missing)
- << MissingHeader.IsUmbrella << MissingHeader.FileName;
+ << MissingHeader.IsUmbrella << MissingHeader.FileName;
return std::error_code();
}
@@ -504,7 +503,7 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
/*AllowSearch=*/true);
if (!M) {
CI.getDiagnostics().Report(diag::err_missing_module)
- << CI.getLangOpts().CurrentModule << ModuleMapFilename;
+ << CI.getLangOpts().CurrentModule << ModuleMapFilename;
return nullptr;
}
@@ -529,7 +528,7 @@ static Module *prepareToBuildModule(CompilerInstance &CI,
/*openFile*/ true);
if (!OriginalModuleMap) {
CI.getDiagnostics().Report(diag::err_module_map_not_found)
- << OriginalModuleMapName;
+ << OriginalModuleMapName;
return nullptr;
}
if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID(
@@ -575,7 +574,7 @@ getInputBufferForModule(CompilerInstance &CI, Module *M) {
if (Err) {
CI.getDiagnostics().Report(diag::err_module_cannot_create_includes)
- << M->getFullModuleName() << Err.message();
+ << M->getFullModuleName() << Err.message();
return nullptr;
}
@@ -616,10 +615,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics());
// The AST unit populates its own diagnostics engine rather than ours.
- IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(
- new DiagnosticsEngine(Diags->getDiagnosticIDs(),
- &Diags->getDiagnosticOptions()));
- ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/false);
+ IntrusiveRefCntPtr<DiagnosticsEngine> ASTDiags(new DiagnosticsEngine(
+ Diags->getDiagnosticIDs(), &Diags->getDiagnosticOptions()));
+ ASTDiags->setClient(Diags->getClient(), /*OwnsClient*/ false);
// FIXME: What if the input is a memory buffer?
StringRef InputFile = Input.getFile();
@@ -747,7 +745,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// Set up embedding for any specified files. Do this before we load any
// source files, including the primary module map for the compilation.
for (const auto &F : CI.getFrontendOpts().ModulesEmbedFiles) {
- if (auto FE = CI.getFileManager().getOptionalFileRef(F, /*openFile*/true))
+ if (auto FE = CI.getFileManager().getOptionalFileRef(F, /*openFile*/ true))
CI.getSourceManager().setFileIsTransient(*FE);
else
CI.getDiagnostics().Report(diag::err_modules_embed_file_not_found) << F;
@@ -926,7 +924,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
for (const auto &Filename : CI.getFrontendOpts().ModuleMapFiles) {
if (auto File = CI.getFileManager().getOptionalFileRef(Filename))
CI.getPreprocessor().getHeaderSearchInfo().loadModuleMapFile(
- *File, /*IsSystem*/false);
+ *File, /*IsSystem*/ false);
else
CI.getDiagnostics().Report(diag::err_module_map_not_found) << Filename;
}
@@ -961,7 +959,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// FIXME: should not overwrite ASTMutationListener when parsing model files?
if (!isModelParsingAction())
- CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener());
+ CI.getASTContext().setASTMutationListener(
+ Consumer->GetASTMutationListener());
if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) {
// Convert headers to PCH and chain them.
@@ -1045,9 +1044,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
// provides the layouts from that file.
if (!CI.getFrontendOpts().OverrideRecordLayoutsFile.empty() &&
CI.hasASTContext() && !CI.getASTContext().getExternalSource()) {
- IntrusiveRefCntPtr<ExternalASTSource>
- Override(new LayoutOverrideSource(
- CI.getFrontendOpts().OverrideRecordLayoutsFile));
+ IntrusiveRefCntPtr<ExternalASTSource> Override(new LayoutOverrideSource(
+ CI.getFrontendOpts().OverrideRecordLayoutsFile));
CI.getASTContext().setExternalSource(Override);
}
@@ -1071,11 +1069,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
llvm::Error FrontendAction::Execute() {
CompilerInstance &CI = getCompilerInstance();
+ // clang-format off
+ // Cratels:ExecuteAction是一个纯虚方法,具体实现由各个action来实现。
+ // clang-format on
if (CI.hasFrontendTimer()) {
llvm::TimeRegion Timer(CI.getFrontendTimer());
ExecuteAction();
- }
- else ExecuteAction();
+ } else
+ ExecuteAction();
// If we are supposed to rebuild the global module index, do so now unless
// there were any module-build failures.
@@ -1125,7 +1126,8 @@ void FrontendAction::EndSourceFile() {
}
if (CI.getFrontendOpts().ShowStats) {
- llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFileOrBufferName() << "':\n";
+ llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFileOrBufferName()
+ << "':\n";
CI.getPreprocessor().PrintStats();
CI.getPreprocessor().getIdentifierTable().PrintStats();
CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
@@ -1193,7 +1195,7 @@ void ASTFrontendAction::ExecuteAction() {
CI.getFrontendOpts().SkipFunctionBodies);
}
-void PluginASTAction::anchor() { }
+void PluginASTAction::anchor() {}
std::unique_ptr<ASTConsumer>
PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
@@ -1220,9 +1222,7 @@ bool WrapperFrontendAction::BeginSourceFileAction(CompilerInstance &CI) {
setCurrentInput(WrappedAction->getCurrentInput());
return Ret;
}
-void WrapperFrontendAction::ExecuteAction() {
- WrappedAction->ExecuteAction();
-}
+void WrapperFrontendAction::ExecuteAction() { WrappedAction->ExecuteAction(); }
void WrapperFrontendAction::EndSourceFile() { WrappedAction->EndSourceFile(); }
void WrapperFrontendAction::EndSourceFileAction() {
WrappedAction->EndSourceFileAction();
@@ -1252,4 +1252,4 @@ bool WrapperFrontendAction::hasCodeCompletionSupport() const {
WrapperFrontendAction::WrapperFrontendAction(
std::unique_ptr<FrontendAction> WrappedAction)
- : WrappedAction(std::move(WrappedAction)) {}
+ : WrappedAction(std::move(WrappedAction)) {}
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 86fcd25d3855c9..1a784e223140a4 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -319,6 +319,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// Create and execute the frontend action.
// clang-format off
// Cratels: Clang 实例有需要的所有信息,但是开发者需要用这些信息做什么这需要使用前端 Action 来指定想要打印 ast 还是 token 等操作
+ // Clang持有Action的信息,CreateFrontendAction会根据该action创建出正确的FrontedAction对象
// clang-format on
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 1783e545f7d517..4615777ea0e02f 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -167,6 +167,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Cratels: 编译器实例,类似 clang 编译器的上下文
// clang-format off
// Cratels: 单例模式,此处创建后后续就可以直接使用 getCompilerInstance 来获得对象
+ // 编译器实例最终会拥有一次编译过程的所有信息,包括源代码路径,用户输入的options等所有信息
// clang-format on
std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
@@ -197,8 +198,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Cratels: 解析参数,将参数解析之后塞进 Clang
// clang-format off
// Cratels: Invocation就是 option
- // clang-format on
// 实例中,可见后续Clang->getFrontendOpts(),Clang->getHeaderSearchOpts()等操作
+ // 这里CreateFromArgs实际返回值是bool是用来显示创建过程是否正确,实际代码的side effect是改变了Clang->getInvocation()
+ // 经过该方法调用后用户调用编译时的option等信息就写入到了Clang对象中,比如源码路径,include路径,options(包括Action种类)等信息。
+ // clang-format on
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
Argv, Diags, Argv0);
@@ -208,8 +211,10 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
}
// --print-supported-cpus takes priority over the actual compilation.
- if (Clang->getFrontendOpts().PrintSupportedCPUs)
+ if (Clang->getFrontendOpts().PrintSupportedCPUs) {
+ llvm::outs() << Clang->getTargetOpts().Triple;
return PrintSupportedCPUs(Clang->getTargetOpts().Triple);
+ }
// --print-supported-extensions takes priority over the actual compilation.
if (Clang->getFrontendOpts().PrintSupportedExtensions)
@@ -242,6 +247,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
{
llvm::TimeTraceScope TimeScope("ExecuteCompiler");
llvm::outs() << "开始执行真正的前端解析动作......\n";
+ // clang-format off
+ // Cratels: 上面的步骤初始化了Clang对象持有的CompilerInvocation对象,并且为其准备了一次编译的所有信息,在这里就是执行这个CompilerInvocation,即执行这一次编译。
+ // clang-format on
Success = ExecuteCompilerInvocation(Clang.get());
}
>From 1fa7efae0c688c462492a4f6651780e655a1e587 Mon Sep 17 00:00:00 2001
From: CratelsChen <cratels at 126.com>
Date: Sat, 22 Jun 2024 18:09:12 +0800
Subject: [PATCH 12/21] add comments, time=2024-06-22 18:09:12
---
clang/lib/Frontend/CompilerInstance.cpp | 7 +++++++
clang/lib/Frontend/FrontendAction.cpp | 8 ++++++++
clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp | 3 +--
3 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index f534551c5ed4f3..94258f95fff588 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1011,9 +1011,15 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
raw_ostream &OS = getVerboseOutputStream();
+ // clang-format off
+ // Cratels: 执行前的准备动作
+ // clang-format on
if (!Act.PrepareToExecute(*this))
return false;
+ // clang-format off
+ // Cratels: 创建 target 对象
+ // clang-format on
if (!createTarget())
return false;
@@ -1039,6 +1045,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
llvm::sort(getCodeGenOpts().NoTocDataVars);
for (const FrontendInputFile &FIF : getFrontendOpts().Inputs) {
+ llvm::outs() << "被编译的文件名: " << FIF.getFile() << "\n";
// Reset the ID tables if we are reusing the SourceManager and parsing
// regular files.
if (hasSourceManager() && !Act.isModelParsingAction())
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 86c9f1f57ea0a9..25a7a0e9233752 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -1168,10 +1168,18 @@ bool FrontendAction::shouldEraseOutputFiles() {
// Utility Actions
//===----------------------------------------------------------------------===//
+// clang-format off
+// Cratels: 所有的前端 Action 全部共用这个方法
+// clang-format on
void ASTFrontendAction::ExecuteAction() {
+ // clang-format off
+ // Cratels: 获取全局编译器实例对象
+ // clang-format on
CompilerInstance &CI = getCompilerInstance();
+
if (!CI.hasPreprocessor())
return;
+
// This is a fallback: If the client forgets to invoke this, we mark the
// current stack as the bottom. Though not optimal, this could help prevent
// stack overflow during deep recursion.
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 1a784e223140a4..a1c5f7690b9534 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -318,8 +318,7 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
return false;
// Create and execute the frontend action.
// clang-format off
- // Cratels: Clang 实例有需要的所有信息,但是开发者需要用这些信息做什么这需要使用前端 Action 来指定想要打印 ast 还是 token 等操作
- // Clang持有Action的信息,CreateFrontendAction会根据该action创建出正确的FrontedAction对象
+ // Cratels: Clang持有Action的信息,CreateFrontendAction会根据该action创建出正确的FrontedAction对象,然后根据该对象构建一个 unique_ptr,将其作用域交给系统。
// clang-format on
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
if (!Act)
>From b220b4413627d60dc902716a95f36a030f852024 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Mon, 24 Jun 2024 14:29:17 +0800
Subject: [PATCH 13/21] update comments
---
clang/tools/driver/driver.cpp | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 69e2735bddba76..bd9d2dab87e84e 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -256,6 +256,10 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
const char *ProgName =
ToolContext.NeedsPrependArg ? ToolContext.PrependArg : ToolContext.Path;
+ // clang-format off
+ // Cratels: 判断当前是否工作在CL mode
+ // clang-cl 是一个Clang驱动器的另一个命令行接口的选择,是被设计用来兼容Visual C++ 的编译器。
+ // clang-format on
bool ClangCLMode =
IsClangCL(getDriverMode(ProgName, llvm::ArrayRef(Args).slice(1)));
@@ -288,6 +292,14 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// clang-format on
return ExecuteCC1Tool(Args, ToolContext);
+ // clang-format off
+ // Cratels:
+ //
+ // 后面为clang作为完整编译器的执行代码
+ //
+ //
+ // clang-format on
+
// Cratels: 作为 driver,完整编译器开始执行
// Handle options that need handling before the real command line parsing in
// Driver::BuildCompilation()
@@ -335,6 +347,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);
+ llvm::outs() << Path << "\n";
// Whether the cc1 tool should be called inside the current process, or if we
// should spawn a new clang subprocess (old behavior).
>From 21890ebde0cea2feb1f1d1d88f25c3797e3fb6a0 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Fri, 5 Jul 2024 14:33:36 +0800
Subject: [PATCH 14/21] add comments for MLIR
---
llvm/include/llvm/Option/Arg.h | 25 +++++++++++-------------
llvm/lib/Option/Option.cpp | 16 ++++++++++-----
mlir/examples/toy/Ch1/toyc.cpp | 11 +++++++++++
mlir/examples/toy/Ch2/include/toy/Ops.td | 20 ++++++++++++++++---
mlir/examples/toy/Ch2/toyc.cpp | 5 +++++
5 files changed, 55 insertions(+), 22 deletions(-)
diff --git a/llvm/include/llvm/Option/Arg.h b/llvm/include/llvm/Option/Arg.h
index 5a718438bf4a3e..25170fa84c069b 100644
--- a/llvm/include/llvm/Option/Arg.h
+++ b/llvm/include/llvm/Option/Arg.h
@@ -27,6 +27,9 @@ namespace opt {
class ArgList;
+// clang-format off
+// Cratels: 驱动器option的混合类
+// clang-format on
/// A concrete instance of a particular driver option.
///
/// The Arg class encodes just enough information to be able to
@@ -72,10 +75,10 @@ class Arg {
public:
Arg(const Option Opt, StringRef Spelling, unsigned Index,
const Arg *BaseArg = nullptr);
- Arg(const Option Opt, StringRef Spelling, unsigned Index,
- const char *Value0, const Arg *BaseArg = nullptr);
- Arg(const Option Opt, StringRef Spelling, unsigned Index,
- const char *Value0, const char *Value1, const Arg *BaseArg = nullptr);
+ Arg(const Option Opt, StringRef Spelling, unsigned Index, const char *Value0,
+ const Arg *BaseArg = nullptr);
+ Arg(const Option Opt, StringRef Spelling, unsigned Index, const char *Value0,
+ const char *Value1, const Arg *BaseArg = nullptr);
Arg(const Arg &) = delete;
Arg &operator=(const Arg &) = delete;
~Arg();
@@ -96,15 +99,13 @@ class Arg {
///
/// This is either the argument itself or the argument it was
/// derived from during tool chain specific argument translation.
- const Arg &getBaseArg() const {
- return BaseArg ? *BaseArg : *this;
- }
+ const Arg &getBaseArg() const { return BaseArg ? *BaseArg : *this; }
Arg &getBaseArg() { return BaseArg ? const_cast<Arg &>(*BaseArg) : *this; }
void setBaseArg(const Arg *BaseArg) { this->BaseArg = BaseArg; }
/// Args are converted to their unaliased form. For args that originally
/// came from an alias, this returns the alias the arg was produced from.
- const Arg* getAlias() const { return Alias.get(); }
+ const Arg *getAlias() const { return Alias.get(); }
void setAlias(std::unique_ptr<Arg> Alias) { this->Alias = std::move(Alias); }
bool getOwnsValues() const { return OwnsValues; }
@@ -116,15 +117,11 @@ class Arg {
bool isIgnoredTargetSpecific() const {
return getBaseArg().IgnoredTargetSpecific;
}
- void ignoreTargetSpecific() {
- getBaseArg().IgnoredTargetSpecific = true;
- }
+ void ignoreTargetSpecific() { getBaseArg().IgnoredTargetSpecific = true; }
unsigned getNumValues() const { return Values.size(); }
- const char *getValue(unsigned N = 0) const {
- return Values[N];
- }
+ const char *getValue(unsigned N = 0) const { return Values[N]; }
SmallVectorImpl<const char *> &getValues() { return Values; }
const SmallVectorImpl<const char *> &getValues() const { return Values; }
diff --git a/llvm/lib/Option/Option.cpp b/llvm/lib/Option/Option.cpp
index 500768588bc9b3..0a22d48289ed32 100644
--- a/llvm/lib/Option/Option.cpp
+++ b/llvm/lib/Option/Option.cpp
@@ -6,12 +6,12 @@
//
//===----------------------------------------------------------------------===//
+#include "llvm/Option/Option.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
-#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
@@ -24,7 +24,10 @@ using namespace llvm;
using namespace llvm::opt;
Option::Option(const OptTable::Info *info, const OptTable *owner)
- : Info(info), Owner(owner) {
+ : Info(info), Owner(owner) {
+
+ llvm::outs() << info->getName() << "\n";
+
// Multi-level aliases are not supported. This just simplifies option
// tracking, it is not an inherent limitation.
assert((!Info || !getAlias().isValid() || !getAlias().getAlias().isValid()) &&
@@ -41,7 +44,10 @@ Option::Option(const OptTable::Info *info, const OptTable *owner)
void Option::print(raw_ostream &O, bool AddNewLine) const {
O << "<";
switch (getKind()) {
-#define P(N) case N: O << #N; break
+#define P(N) \
+ case N: \
+ O << #N; \
+ break
P(GroupClass);
P(InputClass);
P(UnknownClass);
@@ -235,8 +241,8 @@ std::unique_ptr<Arg> Option::accept(const ArgList &Args, StringRef CurArg,
bool GroupedShortOption,
unsigned &Index) const {
auto A(GroupedShortOption && getKind() == FlagClass
- ? std::make_unique<Arg>(*this, CurArg, Index)
- : acceptInternal(Args, CurArg, Index));
+ ? std::make_unique<Arg>(*this, CurArg, Index)
+ : acceptInternal(Args, CurArg, Index));
if (!A)
return nullptr;
diff --git a/mlir/examples/toy/Ch1/toyc.cpp b/mlir/examples/toy/Ch1/toyc.cpp
index fb7b484a92fb9f..4c1247016ba5bd 100644
--- a/mlir/examples/toy/Ch1/toyc.cpp
+++ b/mlir/examples/toy/Ch1/toyc.cpp
@@ -30,6 +30,10 @@ static cl::opt<std::string> inputFilename(cl::Positional,
cl::desc("<input toy file>"),
cl::init("-"),
cl::value_desc("filename"));
+
+// static cl::opt<std::string> userName("name", cl::desc("User name"),
+// cl::init("-"),
+// cl::value_desc("user name"));
namespace {
enum Action { None, DumpAST };
} // namespace
@@ -46,6 +50,7 @@ std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
llvm::errs() << "Could not open input file: " << ec.message() << "\n";
return nullptr;
}
+
auto buffer = fileOrErr.get()->getBuffer();
LexerBuffer lexer(buffer.begin(), buffer.end(), std::string(filename));
Parser parser(lexer);
@@ -55,6 +60,12 @@ std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "toy compiler\n");
+ llvm::outs() << inputFilename << "\n";
+
+ // if (userName != "Cratels") {
+ // return -1;
+ // }
+
auto moduleAST = parseInputFile(inputFilename);
if (!moduleAST)
return 1;
diff --git a/mlir/examples/toy/Ch2/include/toy/Ops.td b/mlir/examples/toy/Ch2/include/toy/Ops.td
index 1a1b136af71fb0..43e2c067f33247 100644
--- a/mlir/examples/toy/Ch2/include/toy/Ops.td
+++ b/mlir/examples/toy/Ch2/include/toy/Ops.td
@@ -20,16 +20,22 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
// Provide a definition of the 'toy' dialect in the ODS framework so that we
// can define our operations.
+
+// 定义一个名为toy的dialect并在其中定义自己的operation。
def Toy_Dialect : Dialect {
let name = "toy";
let cppNamespace = "::mlir::toy";
}
+
// Base class for toy dialect operations. This operation inherits from the base
// `Op` class in OpBase.td, and provides:
-// * The parent dialect of the operation.
-// * The mnemonic for the operation, or the name without the dialect prefix.
-// * A list of traits for the operation.
+// * The parent dialect of the operation.========================================父类所在的dialect:Toy_Dialect
+// * The mnemonic for the operation, or the name without the dialect prefix.=====mnemonic:助记符,或者不带dialect前缀的名字
+// * A list of traits for the operation.=========================================该operation的特征值列表
+
+// 定义toy dialect的Operation基类,这个operation从基类Op继承而来。
+//
class Toy_Op<string mnemonic, list<Trait> traits = []> :
Op<Toy_Dialect, mnemonic, traits>;
@@ -42,6 +48,7 @@ class Toy_Op<string mnemonic, list<Trait> traits = []> :
//===----------------------------------------------------------------------===//
// We define a toy operation by inheriting from our base 'Toy_Op' class above.
+// 通过继承Toy_Op来定义一个operation ConstantOp,用来表示常量。
// Here we provide the mnemonic and a list of traits for the operation. The
// constant operation is marked as 'Pure' as it is a pure operation
// and may be removed if dead.
@@ -59,10 +66,17 @@ def ConstantOp : Toy_Op<"constant", [Pure]> {
```
}];
+ // ins代表op的输入值列表。outs代表op的输出列表
+ // op是用来进行转换的,所谓转换就是将来源Source转为目标值Target。ins就是指这里的Source来源,outs就是输出
+ //
+ //
// The constant operation takes an attribute as the only input.
+ // 常量必须有值,这个op的唯一属性就是常量值。
+ // F64ElementsAttr为attribute的类型,参数名称为value
let arguments = (ins F64ElementsAttr:$value);
// The constant operation returns a single value of TensorType.
+ // 输出类型为F64Tensor,即元素类型为F64的tensar类型
let results = (outs F64Tensor);
// Indicate that the operation has a custom parser and printer method.
diff --git a/mlir/examples/toy/Ch2/toyc.cpp b/mlir/examples/toy/Ch2/toyc.cpp
index e33b49b41c5a1d..6484ddcce8b3ae 100644
--- a/mlir/examples/toy/Ch2/toyc.cpp
+++ b/mlir/examples/toy/Ch2/toyc.cpp
@@ -35,6 +35,11 @@
using namespace toy;
namespace cl = llvm::cl;
+/**
+ * @brief 解析option inputFilename
+ * 该option没有前缀,然后为其指定desc,init以及value_desc
+ *
+ */
static cl::opt<std::string> inputFilename(cl::Positional,
cl::desc("<input toy file>"),
cl::init("-"),
>From fcc069e2037dc985a540efa637d8fdeecbc01bb3 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Tue, 9 Jul 2024 13:54:37 +0800
Subject: [PATCH 15/21] add comments: try toy with MLIR
---
mlir/examples/toy/Ch2/include/toy/Ops.td | 14 +++++++++++---
mlir/examples/toy/Ch2/toyc.cpp | 2 ++
mlir/examples/toy/Ch4/mlir/MLIRGen.cpp | 1 +
mlir/test/Examples/Toy/Ch3/transpose_transpose.toy | 2 +-
4 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/mlir/examples/toy/Ch2/include/toy/Ops.td b/mlir/examples/toy/Ch2/include/toy/Ops.td
index 43e2c067f33247..d9d63d22bd8127 100644
--- a/mlir/examples/toy/Ch2/include/toy/Ops.td
+++ b/mlir/examples/toy/Ch2/include/toy/Ops.td
@@ -33,7 +33,6 @@ def Toy_Dialect : Dialect {
// * The parent dialect of the operation.========================================父类所在的dialect:Toy_Dialect
// * The mnemonic for the operation, or the name without the dialect prefix.=====mnemonic:助记符,或者不带dialect前缀的名字
// * A list of traits for the operation.=========================================该operation的特征值列表
-
// 定义toy dialect的Operation基类,这个operation从基类Op继承而来。
//
class Toy_Op<string mnemonic, list<Trait> traits = []> :
@@ -56,6 +55,7 @@ def ConstantOp : Toy_Op<"constant", [Pure]> {
// Provide a summary and description for this operation. This can be used to
// auto-generate documentation of the operations within our dialect.
let summary = "constant";
+
let description = [{
Constant operation turns a literal into an SSA value. The data is attached
to the operation as an attribute. For example:
@@ -123,7 +123,7 @@ def AddOp : Toy_Op<"add"> {
}
//===----------------------------------------------------------------------===//
-// FuncOp
+// FuncOp 方法定义的operation
//===----------------------------------------------------------------------===//
def FuncOp : Toy_Op<"func", [
@@ -147,11 +147,17 @@ def FuncOp : Toy_Op<"func", [
}];
let arguments = (ins
+ // 符号表中的方法名
SymbolNameAttr:$sym_name,
+ // 方法类型信息
TypeAttrOf<FunctionType>:$function_type,
+ // 入参列表
OptionalAttr<DictArrayAttr>:$arg_attrs,
+ // 返回值列表
OptionalAttr<DictArrayAttr>:$res_attrs
);
+
+ // 当前OP包含的子元素成为 region
let regions = (region AnyRegion:$body);
let builders = [OpBuilder<(ins
@@ -203,11 +209,13 @@ def GenericCallOp : Toy_Op<"generic_call"> {
let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<F64Tensor>:$inputs);
// The generic call operation returns a single value of TensorType.
+ // 为了简化,Toy中所有的方法返回值都是固定的为F64Tensor
let results = (outs F64Tensor);
// Specialize assembly printing and parsing using a declarative format.
+ // 指定当前op输出时候的格式。这里我为其添加了cratels,这后续再进行MLIR的输出中所有的方法调用中都会增加这个后缀(无意义,仅供测试)
let assemblyFormat = [{
- $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results)
+ $callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results)`cratels`
}];
// Add custom build methods for the generic call operation.
diff --git a/mlir/examples/toy/Ch2/toyc.cpp b/mlir/examples/toy/Ch2/toyc.cpp
index 6484ddcce8b3ae..aef2972138a6a4 100644
--- a/mlir/examples/toy/Ch2/toyc.cpp
+++ b/mlir/examples/toy/Ch2/toyc.cpp
@@ -91,6 +91,8 @@ int dumpMLIR() {
if (!module)
return 1;
+ llvm::outs() << module->getName() << "\n\n";
+
module->dump();
return 0;
}
diff --git a/mlir/examples/toy/Ch4/mlir/MLIRGen.cpp b/mlir/examples/toy/Ch4/mlir/MLIRGen.cpp
index 6c5474a9646bcc..d514ed764cb3be 100644
--- a/mlir/examples/toy/Ch4/mlir/MLIRGen.cpp
+++ b/mlir/examples/toy/Ch4/mlir/MLIRGen.cpp
@@ -68,6 +68,7 @@ class MLIRGenImpl {
// add them to the module.
theModule = mlir::ModuleOp::create(builder.getUnknownLoc());
+ // Toy中并不支持使用全局变量,因此AST的顶级单元只有方法定义,即FunctionAST
for (FunctionAST &f : moduleAST)
mlirGen(f);
diff --git a/mlir/test/Examples/Toy/Ch3/transpose_transpose.toy b/mlir/test/Examples/Toy/Ch3/transpose_transpose.toy
index 2f13a3fca3aee5..2584fbe1814341 100644
--- a/mlir/test/Examples/Toy/Ch3/transpose_transpose.toy
+++ b/mlir/test/Examples/Toy/Ch3/transpose_transpose.toy
@@ -19,4 +19,4 @@ def main() {
# CHECK-NEXT: [[VAL_1:%.*]] = toy.constant dense<{{\[\[}}1.000000e+00, 2.000000e+00, 3.000000e+00], [4.000000e+00, 5.000000e+00, 6.000000e+00]]> : tensor<2x3xf64>
# CHECK-NEXT: [[VAL_2:%.*]] = toy.generic_call @transpose_transpose([[VAL_1]]) : (tensor<2x3xf64>) -> tensor<*xf64>
# CHECK-NEXT: toy.print [[VAL_2]] : tensor<*xf64>
-# CHECK-NEXT: toy.return
\ No newline at end of file
+# CHECK-NEXT: toy.return
>From c43eeb5b7487466d6c3881314a04c229246e5d04 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Thu, 11 Jul 2024 09:23:03 +0800
Subject: [PATCH 16/21] read LLVM
---
bolt/README.md | 18 ++++++++++++++++++
clang-tools-extra/ README.md | 13 +++++++++++++
clang-tools-extra/README.txt | 1 +
compiler-rt/README.md | 14 ++++++++++++++
flang/README.md | 8 ++++++++
libclc/README.TXT | 9 +++++++++
lld/README.md | 18 ++++++++++++++++++
llvm-libgcc/README.md | 1 +
openmp/README.md | 5 +++++
polly/README | 6 ++++++
10 files changed, 93 insertions(+)
create mode 100644 clang-tools-extra/ README.md
create mode 100644 compiler-rt/README.md
create mode 100644 llvm-libgcc/README.md
create mode 100644 openmp/README.md
diff --git a/bolt/README.md b/bolt/README.md
index fe54bd82a356a0..df90f600818a8e 100644
--- a/bolt/README.md
+++ b/bolt/README.md
@@ -1,3 +1,21 @@
+# BOLT介绍
+LLVM BOLT(Binary Optimization and Layout Tool)是一个二进制优化工具,它旨在改进已经编译并链接的程序的性能。BOLT是由Facebook开发和维护的,它是LLVM项目的一部分。BOLT通过重写二进制代码来优化程序,这包括重新布局代码以减少指令缓存未命中(instruction cache misses)和优化指令级并行性(instruction-level parallelism)。
+以下是LLVM BOLT的一些关键特性:
+1. **二进制代码重写**:BOLT直接在二进制级别上工作,这意味着它可以对已经编译和链接的ELF(Executable and Linkable Format)二进制文件进行优化,而不需要源代码。
+2. **性能分析**:BOLT使用性能分析数据(如采样的指令地址)来确定代码的热点(hot spots),并专注于优化这些关键区域。
+3. **指令布局优化**:通过重新安排代码的布局,BOLT可以减少指令缓存未命中,从而提高性能。这包括将频繁执行的操作顺序放置在一起,以及优化分支预测。
+4. **指令级并行性**:BOLT可以识别并优化可以利用现代处理器指令级并行性的代码片段。
+5. **代码大小优化**:除了性能优化,BOLT还可以通过删除未使用的代码和合并相似代码来减小二进制文件的大小。
+6. **兼容性和安全性**:BOLT旨在保持二进制文件的兼容性和安全性,确保优化后的程序的行为与原始程序相同。
+使用LLVM BOLT的一般流程可能包括以下步骤:
+1. **收集性能数据**:使用性能分析工具(如perf)收集程序的运行时数据,特别是指令地址的采样数据。
+2. **优化二进制文件**:将收集到的性能数据提供给BOLT,让它对二进制文件进行优化。
+3. **生成优化后的二进制**:BOLT生成一个新的优化后的二进制文件,这个文件可以替换原始的二进制文件进行部署和运行。
+LLVM BOLT特别适合用于优化大型、复杂的程序,尤其是那些已经经过高度优化但仍需要进一步提升性能的应用。例如,它可以用于优化高性能服务器应用、数据库管理系统、大数据处理工具等。
+由于BOLT是一个相对较新的工具,它的使用可能需要一些专业知识和对底层系统架构的理解。因此,如果想要使用BOLT来优化程序,建议查阅最新的官方文档和社区资源来获取详细的安装指南和最佳实践。
+
+---
+
# BOLT
BOLT is a post-link optimizer developed to speed up large applications.
diff --git a/clang-tools-extra/ README.md b/clang-tools-extra/ README.md
new file mode 100644
index 00000000000000..2f717436f91bdf
--- /dev/null
+++ b/clang-tools-extra/ README.md
@@ -0,0 +1,13 @@
+`clang-tools-extra` 是一个项目,它包含了一些使用 Clang 工具化 API 构建的工具。这些工具被保存在一个单独的目录树中,即 `clang-tools-extra`。这样做是为了允许更轻量级地检出核心 Clang 代码库。这个存储库仅打算在完整的 LLVM+Clang 树内以及 Clang 检出中的 'tools/extra' 子目录中被检出。
+在这个项目中,你可以找到一些重要的工具,例如 `clang-tidy`、`clang-include-fixer` 和 `clang-rename`。这些工具的发布说明、用户手册和针对各种 IDE 和编辑器的集成指南都可以在项目中找到。
+`clang-tidy` 是一个用于检查 C++ 代码的工具,它可以集成到 IDE 或编辑器中。`clang-include-fixer` 则是一个用于自动修复包含指令的工具。而 `clang-rename` 是一个用于重命名 C++ 符号的工具。这些工具都是为了提高开发效率和代码质量而设计的。
+
+`clang-tools-extra` 项目中包括以下工具:
+1. **Clang-Tidy**: 用于检查 C++ 代码的工具,可以集成到 IDE 或编辑器中。
+2. **Clang-Include-Fixer**: 自动修复包含指令的工具。
+3. **Modularize**: 有关模块化的用户手册,包括模块映射覆盖检查和模块映射生成。
+4. **pp-trace**: 一个用户手册,包括使用方法、输出格式和构建指南。
+5. **Clang-Rename**: 用于重命名 C++ 符号的工具,支持 Vim 和 Emacs 集成。
+6. **clangd**: 一个用于 C++ 的语言服务器,提供代码补全、诊断、查找定义等功能。
+7. **Clang-Doc**: 生成 C++ 代码文档的工具,包括使用方法、输出和配置指南。
+这些工具都是为了提高开发效率和代码质量而设计的。
diff --git a/clang-tools-extra/README.txt b/clang-tools-extra/README.txt
index 6891e4078997fb..dac401488fc1cc 100644
--- a/clang-tools-extra/README.txt
+++ b/clang-tools-extra/README.txt
@@ -1,3 +1,4 @@
+
//===----------------------------------------------------------------------===//
// Clang Tools repository
//===----------------------------------------------------------------------===//
diff --git a/compiler-rt/README.md b/compiler-rt/README.md
new file mode 100644
index 00000000000000..86a34e16984dac
--- /dev/null
+++ b/compiler-rt/README.md
@@ -0,0 +1,14 @@
+Compiler-RT(runtime)项目为硬件不支持的低级功能提供目标特定的支持。举例来说,32位目标通常缺少64位除法指令。Compiler-RT提供一个目标特定的优化的函数,它用32位指令实现64位除法,从而解决这个问题。它是libgcc的LLVM等价物,提供相同的功能。
+
+libgcc是GCC的一部分。C语言不仅仅是由编译器构成,还包括了一个标准库。编译器在GCC包里,标准库则位于GNU C库里,即glibc包里。C编译器(cc1)肯定是要以来glibc库才能正常运行。
+
+但是编译器本身还使用了一个内部库,名为libgcc,这个库位于GCC包里,并不属于GNU C库。这个库实现了一些复杂指令,这些指令并不能由汇编器指令集提供,因此补充了汇编器的不足。但是这个libgcc库也需要链接到glibc库才能完全运行。
+注:GNU的标准C++库(libstdc++)也需要链接到glibc库。
+
+这样在交叉编译时就产生了一个“鸡与蛋”的问题。我们需要编译器来编译glibc,但是编译器又依赖glibc才能运行。解决办法如下:
+1)首先编译一个 “降级C/C++编译器”,这个降级编译器使用libgcc,但是缺少了一些功能,例如线程支持与异常处理。
+2)然后使用这个降级编译器编译glibc,glibc不降级,功能完备。
+3)然后编译libstdc++库,但是这个C++也是降级的。
+
+
+compile-rt与libgcc功能类似
diff --git a/flang/README.md b/flang/README.md
index 2d5435196bb9bc..c29376cc916e0d 100644
--- a/flang/README.md
+++ b/flang/README.md
@@ -40,3 +40,11 @@ If you are interested in writing new documentation, follow
Consult the [Getting Started with Flang](docs/GettingStarted.md)
for information on building and running flang.
+
+
+---
+`Flang` 是一个基于 LLVM 的新 Fortran 编译器,它支持 Fortran 2018 以及一些扩展。这个编译器的设计、实现和开发参与方式都是值得关注的。
+`Flang` 编译器的作用是将 Fortran 源代码转换成可执行文件。这个过程包括三个高级阶段:分析、降低(lowering)和代码生成/链接。在分析阶段,Fortran 源代码被转换成一个装饰过的解析树和符号表。
+总的来说,`Flang` 作为 LLVM 项目的一部分,为 Fortran 语言提供了现代化的编译支持,使得 Fortran 程序能够在不同的平台上高效运行。
+
+Fortan语言专注于科学计算,可能在量化中很有用。
diff --git a/libclc/README.TXT b/libclc/README.TXT
index 57b5242b9bbecb..199544666b855d 100644
--- a/libclc/README.TXT
+++ b/libclc/README.TXT
@@ -50,3 +50,12 @@ Website
-------
https://libclc.llvm.org/
+
+
+---
+OpenCL类比与英伟达的CUDA,是第一个面向异构系统(此系统中可由CPU,GPU或其它类型的处理器架构组成)的并行编程的开放式标准。
+
+OpenCL 是一个异构并行计算平台,用于编写可以在不同类型的计算设备上运行的程序。它支持将计算任务映射到 CPU、GPU、DSP 和 FPGA 等不同的硬件上。OpenCL 提供了一个底层硬件结构的抽象模型,并旨在提供一个通用的开发 API,使得开发人员可以编写在 GPU 上运行的通用计算程序,而无需将其算法映射到 OpenGL 或 DirectX 的 3D 图形 API 上。
+
+
+相较于CUDA只支持英伟达的GPU,OpenCL更加通用,但也因为需要通用而导致去实现复杂性较高,目前CUDA更加流行。
diff --git a/lld/README.md b/lld/README.md
index 3b693c9957ee85..b0c87debf245a2 100644
--- a/lld/README.md
+++ b/lld/README.md
@@ -17,3 +17,21 @@ same tests, we create a collection of self contained programs.
It is hosted at https://s3-us-west-2.amazonaws.com/linker-tests/lld-speed-test.tar.xz
The current sha256 is `10eec685463d5a8bbf08d77f4ca96282161d396c65bd97dc99dbde644a31610f`.
+---
+LLVM Linker(简称为lld)是一个现代化的、模块化的链接器,它是LLVM编译器基础设施项目的重要组成部分。旨在提供高速度、高可靠性和跨平台兼容性,lld已被设计成一个可替代传统链接器的优秀选择。它的源代码公开并遵循许可证协议,允许自由分发。
+
+2、项目技术分析
+lld的架构基于LLVM的理念,即组件化和模块化,这使得它易于维护和扩展。作为一款现代链接器,lld采用了先进的算法和数据结构以提高性能。它不仅能够处理C++名称修饰,还支持各种其他语言的特性,如Go的导出和Rust的crate关联。此外,其速度测试集合提供了标准化的基准,方便开发者评估不同版本或补丁的性能差异。
+
+3、项目及技术应用场景
+软件开发:在大型软件项目中,lld可以显著减少链接时间,提高整个构建流程的效率。
+嵌入式系统:由于其跨平台兼容性,lld适用于各种操作系统和硬件平台,特别是资源有限的环境。
+教学与研究:lld的开放源码性质使其成为理解和学习链接器工作原理的理想工具。
+优化:对于追求极致性能的项目,通过使用lld,可以减少最终可执行文件的大小,并优化内存占用。
+4、项目特点
+高性能:lld通过高效的实现减少了链接时间,尤其在大规模项目中表现出色。
+模块化设计:易于集成到现有编译流程,支持定制和扩展。
+跨平台支持:可在多种操作系统上运行,包括Linux、macOS和Windows等。
+社区驱动:作为LLVM项目的一部分,有活跃的开发社区进行持续维护和更新。
+标准化基准:提供的速度测试集确保了性能比较的一致性。
+总的来说,无论您是专业开发者还是对链接器感兴趣的学生,lld都是一个值得尝试的优秀工具。其开源、高性能和跨平台的优势,使得它在不同场景下都能发挥重要作用。我们鼓励您加入到这个项目中,体验它带来的便利和强大功能。
diff --git a/llvm-libgcc/README.md b/llvm-libgcc/README.md
new file mode 100644
index 00000000000000..8b54f5cf7bf27a
--- /dev/null
+++ b/llvm-libgcc/README.md
@@ -0,0 +1 @@
+`llvm-libgcc` 是 LLVM 项目中的一个编译器运行时库。这个库提供了一些函数的定义,这些函数是由编译器隐式调用的,以支持底层硬件不直接支持的操作,例如 128 位整数乘法。在这些情况下,操作的内联展开被认为是不合适的。对于 GCC 作为主要编译器的目标平台,Clang 默认使用 `libgcc_s`。而在大多数其他目标平台上,`compiler-rt` 是默认的运行时库。
diff --git a/openmp/README.md b/openmp/README.md
new file mode 100644
index 00000000000000..78e46b8153cee8
--- /dev/null
+++ b/openmp/README.md
@@ -0,0 +1,5 @@
+OpenMP 是由 OpenMP Architecture Review Board 提出并广泛接受的一套指导性编译处理方案,用于共享内存并行系统的多线程程序设计。它支持的编程语言包括 C、C++ 和 Fortran,而支持 OpenMP 的编译器包括 Sun 等。OpenMP 提供对并行算法的高层抽象描述,特别适合在多核 CPU 机器上的并行程序设计。编译器根据程序中添加的 pragma 指令,自动将程序并行处理,使用 OpenMP 降低了并行编程的难度和复杂度。OpenMP 的执行模式采用 fork-join 模式。
+OpenMP 的编程模型以线程为基础,通过编译制导指令(如 #pragma omp)引导并行化。它有三种编程要素可以实现并行化控制,包括编译制导、API 函数集和环境变量。编译制导指令以 #pragma omp 开始,后跟具体的功能指令,格式如:#pragma omp 指令 [子句 [,子句] …]。常用的功能指令包括 #pragma once 等,用于指定头文件只被编译一次等。
+OpenMP 还利用编译器指令 (#pragma)、库函数和环境变量来简化 C/C++/Fortran 多线程编程。它不是全自动并行编程语言,其并行行为仍需由用户定义及控制。例如,#pragma GCC poison printf 用于禁止使用 printf 函数,并声明其被污染,紧跟在该条语句后面的代码段不能使用 printf。
+
+https://www.cnblogs.com/lfri/p/10111315.html
diff --git a/polly/README b/polly/README
index 09a4a5461883c7..3d99b6d82a2431 100644
--- a/polly/README
+++ b/polly/README
@@ -10,3 +10,9 @@ optimal loop structure. These transformations can be used to do constant
propagation through arrays, remove dead loop iterations, optimize loops for
cache locality, optimize arrays, apply advanced automatic parallelization, drive
vectorization, or they can be used to do software pipelining.
+
+---
+
+Polly 是 LLVM 项目中的一个高阶循环和数据局部性优化器以及优化基础设施。它使用基于整数多面体的抽象数学表示来分析和优化程序的内存访问模式。Polly 可以在 LLVM 管道中使用,并与 Clang 集成,提供自动 OpenMP 代码生成和自动向量代码生成等功能。它允许手动使用 Polly 的各个部分,并执行单个 Polly 遍历。
+Polly 的一个关键特性是它能够自动检测和转换相关程序部分,这种转换是语言无关的和语法透明的。这使得 Polly 能够提供一种通用的优化方法,适用于多种编程语言和代码结构。
+要开始使用 Polly,你可以使用你偏好的生成器(如 Ninja、make、Visual Studio 等)来构建和安装 Polly。你还可以通过从 GitHub 克隆 LLVM 项目来获取 Polly 的代码。
>From d4e7fbb4965e0c37f222ea124dd9e1fadcaf3939 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Thu, 11 Jul 2024 09:34:24 +0800
Subject: [PATCH 17/21] =?UTF-8?q?=E6=96=B0=E5=A2=9Eclang=20main=E7=9A=84?=
=?UTF-8?q?=E8=AF=B4=E6=98=8E=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
clang/lib/Driver/Driver.cpp.md | 31 +++++++++++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 clang/lib/Driver/Driver.cpp.md
diff --git a/clang/lib/Driver/Driver.cpp.md b/clang/lib/Driver/Driver.cpp.md
new file mode 100644
index 00000000000000..bfcba38a839c3f
--- /dev/null
+++ b/clang/lib/Driver/Driver.cpp.md
@@ -0,0 +1,31 @@
+clang的入口文件路径为: `/home/chenshuang/llvm-project/build/tools/clang/tools/driver/clang-driver.cpp`
+
+与传统方法是不一样的是,这里的入口文件是在`cmake`生成阶段根据模板文件创建的。这是因为`LLVM`中有很多子项目,是否将这些子项目纳入编译范围是由用户使用宏定义来决定的。
+
+因此`LLVM`开发团队并没有直接就将`main`函数写出来,因为可能用不上。且子项目较多,`main`方法具有高度重复性,因此使用模板文件生成更有利于去除代码冗余。
+
+clang main方法的内容为:
+```C++
+//===-- driver-template.cpp -----------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/LLVMDriver.h"
+
+int clang_main(int argc, char **, const llvm::ToolContext &);
+
+// clang-format off
+// Cratels: clang的真正入口。这个文件是在cmake生成阶段自动生成的,因此不在源码目录中而在build目录中。
+// 其他项目也采用了类似的做法,只是为你避免重复工作而已。
+// clang-format on
+int main(int argc, char **argv) {
+ llvm::InitLLVM X(argc, argv);
+ return clang_main(argc, argv, {argv[0], nullptr, false});
+}
+```
>From a24bc21a60d8c679a5316300be3d0dc37890fb2b Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Thu, 11 Jul 2024 14:23:05 +0800
Subject: [PATCH 18/21] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=B3=A8=E9=87=8A?=
=?UTF-8?q?=EF=BC=9Aclang=E6=89=A7=E8=A1=8C=E6=B5=81=E7=A8=8B?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../include/clang/Frontend/CompilerInstance.h | 53 +++++++++++--------
clang/tools/driver/cc1_main.cpp | 8 +++
clang/tools/driver/driver.cpp | 53 ++++++++++++-------
3 files changed, 73 insertions(+), 41 deletions(-)
diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h
index 3464654284f199..559f038e217081 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -35,7 +35,7 @@ namespace llvm {
class raw_fd_ostream;
class Timer;
class TimerGroup;
-}
+} // namespace llvm
namespace clang {
class ASTContext;
@@ -76,11 +76,29 @@ enum class DisableValidationForModuleKind;
/// in to the compiler instance for everything. When possible, utility functions
/// come in two forms; a short form that reuses the CompilerInstance objects,
/// and a long form that takes explicit instances of any required objects.
+
+// clang-format off
+// Cratels: CompilerInstance - 用于管理 Clang 编译器单个实例的辅助类。
+// CompilerInstance 有两个作用:
+// (1) 它管理运行编译器所需的多个对象、例如预处理器对象、目标信息对象和 AST 上下文对象等
+// (2) 它提供了用于构建和操作常见 Clang 对象的的实用例程。
+// 编译器实例通常拥有它所管理的所有对象的实例。不过,客户端仍可通过手动设置对象来共享对象,并在销毁 CompilerInstance 之前重新获得所有权。
+// 编译器实例的目的是简化客户机,而不是将客户机与编译器实例锁定在一起。在可能的情况下,实用功能有两种形式:
+// 一种是重用 CompilerInstance 对象的简短形式、
+// 一种是获取任何所需对象的显式实例的长形式。
+// clang-format on
class CompilerInstance : public ModuleLoader {
/// The options used in this compiler instance.
std::shared_ptr<CompilerInvocation> Invocation;
+ // clang-format off
+ // Cratels: IntrusiveRefCntPtr 侵入性的引用计数智能指针
+ // clang-format on
+
/// The diagnostics engine instance.
+ // clang-format off
+ // Cratels: 诊断信息
+ // clang-format on
IntrusiveRefCntPtr<DiagnosticsEngine> Diagnostics;
/// The target being compiled for.
@@ -204,6 +222,7 @@ class CompilerInstance : public ModuleLoader {
CompilerInstance(const CompilerInstance &) = delete;
void operator=(const CompilerInstance &) = delete;
+
public:
explicit CompilerInstance(
std::shared_ptr<PCHContainerOperations> PCHContainerOps =
@@ -270,9 +289,7 @@ class CompilerInstance : public ModuleLoader {
/// Set the flag indicating whether we should (re)build the global
/// module index.
- void setBuildGlobalModuleIndex(bool Build) {
- BuildGlobalModuleIndex = Build;
- }
+ void setBuildGlobalModuleIndex(bool Build) { BuildGlobalModuleIndex = Build; }
/// @}
/// @name Forwarding Methods
@@ -280,9 +297,7 @@ class CompilerInstance : public ModuleLoader {
AnalyzerOptions &getAnalyzerOpts() { return Invocation->getAnalyzerOpts(); }
- CodeGenOptions &getCodeGenOpts() {
- return Invocation->getCodeGenOpts();
- }
+ CodeGenOptions &getCodeGenOpts() { return Invocation->getCodeGenOpts(); }
const CodeGenOptions &getCodeGenOpts() const {
return Invocation->getCodeGenOpts();
}
@@ -308,9 +323,7 @@ class CompilerInstance : public ModuleLoader {
return Invocation->getFileSystemOpts();
}
- FrontendOptions &getFrontendOpts() {
- return Invocation->getFrontendOpts();
- }
+ FrontendOptions &getFrontendOpts() { return Invocation->getFrontendOpts(); }
const FrontendOptions &getFrontendOpts() const {
return Invocation->getFrontendOpts();
}
@@ -350,9 +363,7 @@ class CompilerInstance : public ModuleLoader {
return Invocation->getPreprocessorOutputOpts();
}
- TargetOptions &getTargetOpts() {
- return Invocation->getTargetOpts();
- }
+ TargetOptions &getTargetOpts() { return Invocation->getTargetOpts(); }
const TargetOptions &getTargetOpts() const {
return Invocation->getTargetOpts();
}
@@ -394,9 +405,7 @@ class CompilerInstance : public ModuleLoader {
void setVerboseOutputStream(std::unique_ptr<raw_ostream> Value);
/// Get the current stream for verbose output.
- raw_ostream &getVerboseOutputStream() {
- return *VerboseOutputStream;
- }
+ raw_ostream &getVerboseOutputStream() { return *VerboseOutputStream; }
/// @}
/// @name Target Info
@@ -574,8 +583,8 @@ class CompilerInstance : public ModuleLoader {
void setASTReader(IntrusiveRefCntPtr<ASTReader> Reader);
std::shared_ptr<ModuleDependencyCollector> getModuleDepCollector() const;
- void setModuleDepCollector(
- std::shared_ptr<ModuleDependencyCollector> Collector);
+ void
+ setModuleDepCollector(std::shared_ptr<ModuleDependencyCollector> Collector);
std::shared_ptr<PCHContainerOperations> getPCHContainerOperations() const {
return ThePCHContainerOperations;
@@ -701,11 +710,9 @@ class CompilerInstance : public ModuleLoader {
/// used by some diagnostics printers (for logging purposes only).
///
/// \return The new object on success, or null on failure.
- static IntrusiveRefCntPtr<DiagnosticsEngine>
- createDiagnostics(DiagnosticOptions *Opts,
- DiagnosticConsumer *Client = nullptr,
- bool ShouldOwnClient = true,
- const CodeGenOptions *CodeGenOpts = nullptr);
+ static IntrusiveRefCntPtr<DiagnosticsEngine> createDiagnostics(
+ DiagnosticOptions *Opts, DiagnosticConsumer *Client = nullptr,
+ bool ShouldOwnClient = true, const CodeGenOptions *CodeGenOpts = nullptr);
/// Create the file manager and replace any existing one with it.
///
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 4615777ea0e02f..d828cfa992408d 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -174,6 +174,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
// Register the support for object-file-wrapped Clang modules.
+ // clang-format off
+ // Cratels: PCH是需要额外维护数据的。
+ // clang-format on
auto PCHOps = Clang->getPCHContainerOperations();
PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
@@ -186,6 +189,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// Buffer diagnostics from argument parsing so that we can output them using a
// well formed diagnostic object.
+ // clang-format off
+ // Cratels: 从参数中获取diagnostic的控制参数然后缓存下来交给诊断信息的引擎
+ // clang-format on
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
@@ -201,6 +207,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
// 实例中,可见后续Clang->getFrontendOpts(),Clang->getHeaderSearchOpts()等操作
// 这里CreateFromArgs实际返回值是bool是用来显示创建过程是否正确,实际代码的side effect是改变了Clang->getInvocation()
// 经过该方法调用后用户调用编译时的option等信息就写入到了Clang对象中,比如源码路径,include路径,options(包括Action种类)等信息。
+ // Clang是掌管整个流程,Invocation是一次调用的抽象类
+ // 这一步就是为了解析所有参数,后面的步骤中直接使用即可。
// clang-format on
bool Success = CompilerInvocation::CreateFromArgs(Clang->getInvocation(),
Argv, Diags, Argv0);
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index bd9d2dab87e84e..3b844b1076950c 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -202,16 +202,19 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
// are currently global, and they might have been used previously by the
// driver.
+ // clang-format off
+ // Cratels: 如果我们从 clangDriver 库(通过 Driver::CC1Main)调用 cc1 工具,我们需要清理选项使用计数。这些选项目前是全局性的,可能之前已被驱动程序使用过。
+ // clang-format on
+
// clang-format off
// Cratels: cl就是代指 clang 相关代码的 namespace
// clang-format on
llvm::cl::ResetAllOptionOccurrences();
llvm::BumpPtrAllocator A;
- // clang-format off
- // Cratels:
- // clang-format on
+
llvm::cl::ExpansionContext ECtx(A, llvm::cl::TokenizeGNUCommandLine);
+
if (llvm::Error Err = ECtx.expandResponseFiles(ArgV)) {
llvm::errs() << toString(std::move(Err)) << '\n';
return 1;
@@ -220,9 +223,18 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
void *GetExecutablePathVP = (void *)(intptr_t)GetExecutablePath;
if (Tool == "-cc1")
return cc1_main(ArrayRef(ArgV).slice(1), ArgV[0], GetExecutablePathVP);
+
if (Tool == "-cc1as")
+ // clang-format off
+ // Cratels: llvm cc1as 是 LLVM 项目中 Clang 编译器的一部分。Clang 是 LLVM 的 C/C++ 前端,它负责从源代码生成中间码(IR)。cc1as 是 Clang 的一个组件,用于处理汇编语言文件。
+ // clang-format on
return cc1as_main(ArrayRef(ArgV).slice(2), ArgV[0], GetExecutablePathVP);
+
if (Tool == "-cc1gen-reproducer")
+ // clang-format off
+ // Cratels: LLVM -cc1gen-reproducer 是 LLVM 编译器工具链中的一个选项,用于生成能够复现特定编译问题的最小测试用例。这个选项通常在你遇到编译错误或警告,并且希望向 LLVM 开发者报告问题时使用。
+ // 通过生成一个复现器(reproducer),你可以提供一个简洁的代码示例,这样开发者就能更容易地诊断和修复问题。
+ // clang-format on
return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
GetExecutablePathVP, ToolContext);
// Reject unknown tools.
@@ -232,7 +244,9 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
return 1;
}
-// Cratels: clang代码的真正入口
+// clang-format off
+// Cratels: clang代码在源码中的真实入口,main方法是自动生成的,在build目录中。
+// clang-format on
int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// Cratels: 标记栈底位置
noteBottomOfStack();
@@ -241,7 +255,9 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
" and include the crash backtrace, preprocessed "
"source, and associated run script.\n");
- // Cratels: 存储参数
+ // clang-format off
+ // Cratels: 用于存储clang的命令行参数
+ // clang-format on
SmallVector<const char *, 256> Args(Argv, Argv + Argc);
if (llvm::sys::Process::FixupStandardFileDescriptors())
@@ -270,22 +286,23 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// Handle -cc1 integrated tools.
// clang-format off
- // Cratels: 处理以-cc1 开头的 options -cc1开头的 option 将 clang 编译器或者叫 driver 退化为单纯的 clang fronted前端。
+ // Cratels: 处理以-cc1 开头的所有 options。
+ // -cc1开头的 option 将 clang 编译器或者叫 driver 退化为单纯的 clang fronted前端。
// 用户不应该使用-cc1 option,因为该 option 并不承诺稳定
- // clang -cc1 is the frontend, clang is the driver. The driver invokes the frontend
- // with options appropriate for your system.Some clang command line options
- // are driver-only options, some are frontend-only options. Frontend-only
- // options are intended to be used only by clang developers. Users should not
- // run clang-cc1 directly, because -cc1 options are not guaranteed to be
- // stable. If you want to use a frontend-only option (“a -cc1 option”), for
- // example -ast-dump, then you need to take the clang-cc1 line generated by
- // the driver and add the option you need. Alternatively, you can run
- // clang-Xclang<option>... to force the driver pass <option> to clang-cc1
+ // 可以认为-cc1 option只是clang开发者给自己留的一个后门,便于在开发中直接检测前端功能,但并不对外开放以及保证稳定。
+ // clang -cc1 is the frontend, clang is the driver. The driver invokes the frontend with options appropriate for your system.
+ // Some clang command line options are driver-only options, some are frontend-only options.
+ // Frontend-only options are intended to be used only by clang developers.
+ // Users should not run clang-cc1 directly, because -cc1 options are not guaranteed to be stable.
+ // If you want to use a frontend-only option (“a -cc1 option”), for example -ast-dump, then you need to take the clang-cc1 line
+ // generated by the driver and add the option you need.
+ // Alternatively, you can run clang -Xclang <option>... to force the driver pass <option> to clang-cc1
// clang-format on
- // Cratels: 如果只想使用前端 option,应该在第一个参数的位置
- // Args[1]的位置直接写上-cc1开头的
- // option,否则就不会进入ExecuteCC1Tool,而是直接作为 driver 执行
+ // clang-format off
+ // Cratels: 如果只想使用前端 option,应该在第一个参数Args[1]的位置直接写上-cc1开头的option,否则就不会进入ExecuteCC1Tool,而是直接作为 driver 执行
+ // 这里源代码直接就是根据位置来拿的参数,因此必须写在第一个参数位置
+ // clang-format on
if (Args.size() >= 2 && StringRef(Args[1]).starts_with("-cc1"))
// clang-format off
// Cratels: ExecuteCC1Tool执行cc1工具,即只执行 clang 的前端而不作为整个编译器来使用
>From f2eef54058185b7defb433997f05749af2b4d612 Mon Sep 17 00:00:00 2001
From: chenshuang <chenshuang at softsafe-tech.com>
Date: Thu, 1 Aug 2024 13:54:30 +0800
Subject: [PATCH 19/21] add cmts
---
clang/include/clang/Sema/Sema.h | 3 +++
clang/lib/Driver/Compilation.cpp | 19 +++++++--------
clang/lib/Frontend/CompilerInstance.cpp | 1 +
clang/lib/Frontend/FrontendAction.cpp | 8 +++++++
.../ExecuteCompilerInvocation.cpp | 16 ++++++++++---
clang/lib/Parse/ParseAST.cpp | 22 +++++++++--------
clang/tools/driver/cc1_main.cpp | 24 ++++++++++++++++---
clang/tools/driver/driver.cpp | 17 ++++++++++++-
8 files changed, 82 insertions(+), 28 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6be6f6725e5b75..54c23e8eb3b4c7 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -530,6 +530,9 @@ struct FunctionEffectDifferences : public SmallVector<FunctionEffectDiff> {
const FunctionEffectsRef &New);
};
+// clang-format off
+// Cratels: C语言的语法分析器
+// clang-format on
/// Sema - This implements semantic analysis and AST building for C.
/// \nosubgrouping
class Sema final : public SemaBase {
diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp
index ad077d5bbfa69a..be155ffce2652b 100644
--- a/clang/lib/Driver/Compilation.cpp
+++ b/clang/lib/Driver/Compilation.cpp
@@ -67,7 +67,8 @@ Compilation::getArgsForToolChain(const ToolChain *TC, StringRef BoundArch,
if (!Entry) {
SmallVector<Arg *, 4> AllocatedArgs;
DerivedArgList *OpenMPArgs = nullptr;
- // Translate OpenMP toolchain arguments provided via the -Xopenmp-target flags.
+ // Translate OpenMP toolchain arguments provided via the -Xopenmp-target
+ // flags.
if (DeviceOffloadKind == Action::OFK_OpenMP) {
const ToolChain *HostTC = getSingleOffloadToolChain<Action::OFK_Host>();
bool SameTripleAsHost = (TC->getTriple() == HostTC->getTriple());
@@ -131,8 +132,7 @@ bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
// so we don't need to check again.
if (IssueErrors)
- getDriver().Diag(diag::err_drv_unable_to_remove_file)
- << EC.message();
+ getDriver().Diag(diag::err_drv_unable_to_remove_file) << EC.message();
return false;
}
return true;
@@ -141,13 +141,12 @@ bool Compilation::CleanupFile(const char *File, bool IssueErrors) const {
bool Compilation::CleanupFileList(const llvm::opt::ArgStringList &Files,
bool IssueErrors) const {
bool Success = true;
- for (const auto &File: Files)
+ for (const auto &File : Files)
Success &= CleanupFile(File, IssueErrors);
return Success;
}
-bool Compilation::CleanupFileMap(const ArgStringMap &Files,
- const JobAction *JA,
+bool Compilation::CleanupFileMap(const ArgStringMap &Files, const JobAction *JA,
bool IssueErrors) const {
bool Success = true;
for (const auto &File : Files) {
@@ -163,8 +162,8 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files,
int Compilation::ExecuteCommand(const Command &C,
const Command *&FailingCommand,
bool LogOnly) const {
- if ((getDriver().CCPrintOptions ||
- getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) {
+ if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) &&
+ !getDriver().CCGenDiagnostics) {
raw_ostream *OS = &llvm::errs();
std::unique_ptr<llvm::raw_fd_ostream> OwnedStream;
@@ -302,9 +301,7 @@ void Compilation::initCompilationForDiagnostics() {
ForceKeepTempFiles = true;
}
-StringRef Compilation::getSysRoot() const {
- return getDriver().SysRoot;
-}
+StringRef Compilation::getSysRoot() const { return getDriver().SysRoot; }
void Compilation::Redirect(ArrayRef<std::optional<StringRef>> Redirects) {
this->Redirects = Redirects;
diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp
index 94258f95fff588..ff6d3f2d5a0baa 100644
--- a/clang/lib/Frontend/CompilerInstance.cpp
+++ b/clang/lib/Frontend/CompilerInstance.cpp
@@ -1013,6 +1013,7 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) {
// clang-format off
// Cratels: 执行前的准备动作
+ // 提供可能需要处理的接口,默认实现只是返回true
// clang-format on
if (!Act.PrepareToExecute(*this))
return false;
diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp
index 25a7a0e9233752..69043882eefb1b 100644
--- a/clang/lib/Frontend/FrontendAction.cpp
+++ b/clang/lib/Frontend/FrontendAction.cpp
@@ -1067,10 +1067,15 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
}
llvm::Error FrontendAction::Execute() {
+
+ // clang-format off
+ // Cratels: 获取全局唯一单例的Compliance对象,它拥有本次编译的全部信息
+ // clang-format on
CompilerInstance &CI = getCompilerInstance();
// clang-format off
// Cratels:ExecuteAction是一个纯虚方法,具体实现由各个action来实现。
+ // 此处我们可以以打印AST的Action为例进行进一步分析
// clang-format on
if (CI.hasFrontendTimer()) {
llvm::TimeRegion Timer(CI.getFrontendTimer());
@@ -1080,6 +1085,9 @@ llvm::Error FrontendAction::Execute() {
// If we are supposed to rebuild the global module index, do so now unless
// there were any module-build failures.
+ // clang-format off
+ // Cratels: 如果我们应该重建全局模块索引,那么现在就重建,除非有任何模块构建失败。
+ // clang-format on
if (CI.shouldBuildGlobalModuleIndex() && CI.hasFileManager() &&
CI.hasPreprocessor()) {
StringRef Cache =
diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index a1c5f7690b9534..d68316a9d6e683 100644
--- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -265,6 +265,8 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
Clang->LoadRequestedPlugins();
// Honor -mllvm.
+ // Additional arguments to forward to LLVM's option processing
+ // 处理额外的option并传递给LLVM
//
// FIXME: Remove this, one day.
// This should happen AFTER plugins have been loaded!
@@ -278,9 +280,9 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args.get());
}
-// clang-format off
-// Cratels: 是否打开 clang 的静态代码检测功能。只到 endif 的代码都在处理静态代码检测的问题,暂时不处理
-// clang-format on
+ // clang-format off
+ // Cratels: 是否打开 clang 的静态代码检测功能。只到 endif 的代码都在处理静态代码检测的问题,暂时不处理
+ // clang-format on
#if CLANG_ENABLE_STATIC_ANALYZER
// These should happen AFTER plugins have been loaded!
@@ -314,13 +316,17 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
#endif
// If there were errors in processing arguments, don't do anything else.
+ // 处理参数是报错的话就直接退出,不做任何事情
if (Clang->getDiagnostics().hasErrorOccurred())
return false;
+
// Create and execute the frontend action.
// clang-format off
// Cratels: Clang持有Action的信息,CreateFrontendAction会根据该action创建出正确的FrontedAction对象,然后根据该对象构建一个 unique_ptr,将其作用域交给系统。
+ // 比如这里用户传入--ast-dump的option,则这里就会创建一个打印出AST对应的Action,然后执行即可。
// clang-format on
std::unique_ptr<FrontendAction> Act(CreateFrontendAction(*Clang));
+
if (!Act)
return false;
@@ -329,6 +335,10 @@ bool ExecuteCompilerInvocation(CompilerInstance *Clang) {
// clang-format on
bool Success = Clang->ExecuteAction(*Act);
+ // Disable memory freeing on exit.
+ // clang-format off
+ // Cratels: 一般情况下调用结束后系统会回收此次调用的内存,但是clang提供了一个option来保持内存不被回收,无论是否执行成功
+ // clang-format on
if (Clang->getFrontendOpts().DisableFree)
llvm::BuryPointer(std::move(Act));
return Success;
diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp
index 77ab3b556da58c..930268578a4c80 100644
--- a/clang/lib/Parse/ParseAST.cpp
+++ b/clang/lib/Parse/ParseAST.cpp
@@ -41,14 +41,13 @@ class ResetStackCleanup
ResetStackCleanup(llvm::CrashRecoveryContext *Context, const void *Top)
: llvm::CrashRecoveryContextCleanupBase<ResetStackCleanup, const void>(
Context, Top) {}
- void recoverResources() override {
- llvm::RestorePrettyStackState(resource);
- }
+ void recoverResources() override { llvm::RestorePrettyStackState(resource); }
};
/// If a crash happens while the parser is active, an entry is printed for it.
class PrettyStackTraceParserEntry : public llvm::PrettyStackTraceEntry {
const Parser &P;
+
public:
PrettyStackTraceParserEntry(const Parser &p) : P(p) {}
void print(raw_ostream &OS) const override;
@@ -87,7 +86,7 @@ void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
}
}
-} // namespace
+} // namespace
//===----------------------------------------------------------------------===//
// Public interface to the file
@@ -97,9 +96,8 @@ void PrettyStackTraceParserEntry::print(raw_ostream &OS) const {
/// the file is parsed. This inserts the parsed decls into the translation unit
/// held by Ctx.
///
-void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer,
- ASTContext &Ctx, bool PrintStats,
- TranslationUnitKind TUKind,
+void clang::ParseAST(Preprocessor &PP, ASTConsumer *Consumer, ASTContext &Ctx,
+ bool PrintStats, TranslationUnitKind TUKind,
CodeCompleteConsumer *CompletionConsumer,
bool SkipFunctionBodies) {
@@ -138,8 +136,8 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
PrettyStackTraceParserEntry CrashInfo(P);
// Recover resources if we crash before exiting this method.
- llvm::CrashRecoveryContextCleanupRegistrar<Parser>
- CleanupParser(ParseOP.get());
+ llvm::CrashRecoveryContextCleanupRegistrar<Parser> CleanupParser(
+ ParseOP.get());
S.getPreprocessor().EnterMainSourceFile();
ExternalASTSource *External = S.getASTContext().getExternalSource();
@@ -149,6 +147,9 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
// If a PCH through header is specified that does not have an include in
// the source, or a PCH is being created with #pragma hdrstop with nothing
// after the pragma, there won't be any tokens or a Lexer.
+ // clang-format off
+ // Cratels: 词法分析在预处理过程中完成
+ // clang-format on
bool HaveLexer = S.getPreprocessor().getCurrentLexer();
if (HaveLexer) {
@@ -185,7 +186,8 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) {
std::swap(OldCollectStats, S.CollectStats);
if (PrintStats) {
llvm::errs() << "\nSTATISTICS:\n";
- if (HaveLexer) P.getActions().PrintStats();
+ if (HaveLexer)
+ P.getActions().PrintStats();
S.getASTContext().PrintStats();
Decl::PrintStats();
Stmt::PrintStats();
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index df397a17d9dd72..255a34d7b60d72 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -162,7 +162,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
return 0;
}
-static int PrintEnabledExtensions(const TargetOptions& TargetOpts) {
+static int PrintEnabledExtensions(const TargetOptions &TargetOpts) {
std::string Error;
const llvm::Target *TheTarget =
llvm::TargetRegistry::lookupTarget(TargetOpts.Triple, Error);
@@ -177,7 +177,9 @@ static int PrintEnabledExtensions(const TargetOptions& TargetOpts) {
llvm::TargetOptions BackendOptions;
std::string FeaturesStr = llvm::join(TargetOpts.FeaturesAsWritten, ",");
std::unique_ptr<llvm::TargetMachine> TheTargetMachine(
- TheTarget->createTargetMachine(TargetOpts.Triple, TargetOpts.CPU, FeaturesStr, BackendOptions, std::nullopt));
+ TheTarget->createTargetMachine(TargetOpts.Triple, TargetOpts.CPU,
+ FeaturesStr, BackendOptions,
+ std::nullopt));
const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
@@ -185,7 +187,7 @@ static int PrintEnabledExtensions(const TargetOptions& TargetOpts) {
// We do that by capturing the key from the set of SubtargetFeatureKV entries
// provided by MCSubtargetInfo, which match the '-target-feature' values.
const std::vector<llvm::SubtargetFeatureKV> Features =
- MCInfo->getEnabledProcessorFeatures();
+ MCInfo->getEnabledProcessorFeatures();
std::set<llvm::StringRef> EnabledFeatureNames;
for (const llvm::SubtargetFeatureKV &feature : Features)
EnabledFeatureNames.insert(feature.Key);
@@ -261,10 +263,17 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
Argv, Diags, Argv0);
// Cratels: 解析完参数后直接使用
+ // clang-format off
+ // Cratels: 是否跟踪执行时间
+ // clang-format on
if (!Clang->getFrontendOpts().TimeTracePath.empty()) {
llvm::timeTraceProfilerInitialize(
Clang->getFrontendOpts().TimeTraceGranularity, Argv0);
}
+
+ // clang-format off
+ // Cratels: 打印出目标支持的CPU的triple
+ // clang-format on
// --print-supported-cpus takes priority over the actual compilation.
if (Clang->getFrontendOpts().PrintSupportedCPUs) {
llvm::outs() << Clang->getTargetOpts().Triple;
@@ -279,6 +288,9 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
if (Clang->getFrontendOpts().PrintEnabledExtensions)
return PrintEnabledExtensions(Clang->getTargetOpts());
+ // clang-format off
+ // Cratels: 如果编译时指定了builtin include的路径,就是用该路径。如果没有指定,就是用默认的路径。
+ // clang-format on
// Infer the builtin include path if unspecified.
if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
Clang->getHeaderSearchOpts().ResourceDir.empty())
@@ -286,12 +298,18 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
// Create the actual diagnostics engine.
+ // clang-format off
+ // Cratels: 创建诊断引擎
+ // clang-format on
Clang->createDiagnostics();
if (!Clang->hasDiagnostics())
return 1;
// Set an error handler, so that any LLVM backend diagnostics go through our
// error handler.
+ // clang-format off
+ // Cratels: 设置错误处理程序,以便任何 LLVM 后端诊断都会通过我们的错误处理程序。
+ // clang-format on
llvm::install_fatal_error_handler(
LLVMErrorHandler, static_cast<void *>(&Clang->getDiagnostics()));
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 3b844b1076950c..19337bae52a0a7 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -317,7 +317,9 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
//
// clang-format on
- // Cratels: 作为 driver,完整编译器开始执行
+ // clang-format off
+ // Cratels: 作为完整编译器
+ // clang-format on
// Handle options that need handling before the real command line parsing in
// Driver::BuildCompilation()
bool CanonicalPrefixes = true;
@@ -363,6 +365,9 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
&llvm::errs());
}
+ // clang-format off
+ // Cratels: 获取当前执行clang的文件路径
+ // clang-format on
std::string Path = GetExecutablePath(ToolContext.Path, CanonicalPrefixes);
llvm::outs() << Path << "\n";
@@ -370,6 +375,11 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
// should spawn a new clang subprocess (old behavior).
// Not having an additional process saves some execution time of Windows,
// and makes debugging and profiling easier.
+ // clang-format off
+ // Cratels: 是在当前进程中调用 cc1 工具,还是生成一个新的 clang 子进程(旧行为)。
+ // 没有额外的进程可以节省 Windows 的一些执行时间,并使调试和剖析变得更容易。
+ // 这里是在说是否将编译器的前端和后端相对分开。
+ // clang-format on
bool UseNewCC1Process = CLANG_SPAWN_CC1;
for (const char *Arg : Args)
UseNewCC1Process = llvm::StringSwitch<bool>(Arg)
@@ -398,6 +408,9 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
ProcessWarningOptions(Diags, *DiagOpts, /*ReportDiags=*/false);
+ // clang-format off
+ // Cratels: Driver对象是整个编译流程的抽象表示,这里在构造这个对象的时候需要指定执行文件路径,硬件目标三元组的信息以及诊断信息引擎
+ // clang-format on
Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
auto TargetAndMode = ToolChain::getTargetAndModeFromProgramName(ProgName);
TheDriver.setTargetAndMode(TargetAndMode);
@@ -425,6 +438,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
std::unique_ptr<Compilation> C(TheDriver.BuildCompilation(Args));
Driver::ReproLevel ReproLevel = Driver::ReproLevel::OnCrash;
+
if (Arg *A = C->getArgs().getLastArg(options::OPT_gen_reproducer_eq)) {
auto Level =
llvm::StringSwitch<std::optional<Driver::ReproLevel>>(A->getValue())
@@ -440,6 +454,7 @@ int clang_main(int Argc, char **Argv, const llvm::ToolContext &ToolContext) {
}
ReproLevel = *Level;
}
+
if (!!::getenv("FORCE_CLANG_DIAGNOSTICS_CRASH"))
ReproLevel = Driver::ReproLevel::Always;
>From ec74b7a4054bb8ced47287e2c9cc5ef5a524d10d Mon Sep 17 00:00:00 2001
From: Cratels Chen <cratels at 126.com>
Date: Thu, 1 Aug 2024 20:03:54 +0800
Subject: [PATCH 20/21] add comments, time=2024-08-01 20:03:54
---
mlir/include/mlir/IR/BuiltinTypes.td | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mlir/include/mlir/IR/BuiltinTypes.td b/mlir/include/mlir/IR/BuiltinTypes.td
index 4cade83dd3c32a..7e43d08ab1a338 100644
--- a/mlir/include/mlir/IR/BuiltinTypes.td
+++ b/mlir/include/mlir/IR/BuiltinTypes.td
@@ -329,6 +329,9 @@ def Builtin_Index : Builtin_Type<"Index", "index"> {
//===----------------------------------------------------------------------===//
// IntegerType
//===----------------------------------------------------------------------===//
+// clang-format off
+// Cratels: 内置类型 Integer 的定义
+// clang-format on
def Builtin_Integer : Builtin_Type<"Integer", "integer"> {
let summary = "Integer type with arbitrary precision up to a fixed limit";
>From ff1d4ebf584d8bd59b8d692a2e1f73d14f998cee Mon Sep 17 00:00:00 2001
From: Cratels Chen <cratels at 126.com>
Date: Sat, 10 Aug 2024 09:13:01 +0800
Subject: [PATCH 21/21] add comments: toy ,time=2024-08-10 09:13:00
---
mlir/examples/toy/Ch1/toyc.cpp | 37 +++++++++---
mlir/examples/toy/Ch2/include/toy/Ops.td | 71 +++++++++++++++---------
toy_src/ast_1.toy | 6 ++
toy_src/ast_1.yaml | 20 +++++++
toy_src/ast_2.toy | 17 ++++++
toy_src/ast_2.yaml | 44 +++++++++++++++
6 files changed, 162 insertions(+), 33 deletions(-)
create mode 100644 toy_src/ast_1.toy
create mode 100644 toy_src/ast_1.yaml
create mode 100644 toy_src/ast_2.toy
create mode 100644 toy_src/ast_2.yaml
diff --git a/mlir/examples/toy/Ch1/toyc.cpp b/mlir/examples/toy/Ch1/toyc.cpp
index 4c1247016ba5bd..13740efbec8480 100644
--- a/mlir/examples/toy/Ch1/toyc.cpp
+++ b/mlir/examples/toy/Ch1/toyc.cpp
@@ -26,10 +26,15 @@
using namespace toy;
namespace cl = llvm::cl;
-static cl::opt<std::string> inputFilename(cl::Positional,
- cl::desc("<input toy file>"),
- cl::init("-"),
- cl::value_desc("filename"));
+// clang-format off
+// Cratels: 处理 option
+// clang-format on
+static cl::opt<std::string> inputFilename(
+ // clang-format off
+ // Cratels: 根据位置而不是根据前缀来进行 option 的解析。第一个不是根据前缀来解析的 option 会给它。这也意味着最多只能有一个 positional 的参数
+ // clang-format on
+ cl::Positional, cl::desc("<input toy file>"), cl::init("-"),
+ cl::value_desc("filename"));
// static cl::opt<std::string> userName("name", cl::desc("User name"),
// cl::init("-"),
@@ -38,12 +43,21 @@ namespace {
enum Action { None, DumpAST };
} // namespace
-static cl::opt<enum Action>
- emitAction("emit", cl::desc("Select the kind of output desired"),
- cl::values(clEnumValN(DumpAST, "ast", "output the AST dump")));
+static cl::opt<enum Action> emitAction(
+ // clang-format off
+ // Cratels: prefix 的前缀为 emit,解析--emit=后面的值给 emitAction
+ // clang-format on
+ "emit", cl::desc("Select the kind of output desired"),
+ cl::values(clEnumValN(DumpAST, "ast", "output the AST dump")));
/// Returns a Toy AST resulting from parsing the file or a nullptr on error.
+// clang-format off
+// Cratels: ModuleAST代指一个 EntryPoint,是一个 AST 的基本块
+// clang-format on
std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
+ // clang-format off
+ // Cratels: 接受输入文件路径或者直接输入文本内容
+ // clang-format on
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> fileOrErr =
llvm::MemoryBuffer::getFileOrSTDIN(filename);
if (std::error_code ec = fileOrErr.getError()) {
@@ -51,7 +65,13 @@ std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
return nullptr;
}
+ // clang-format off
+ // Cratels: 获得文件内容
+ // clang-format on
auto buffer = fileOrErr.get()->getBuffer();
+
+ llvm::outs() << "文件内容:" << buffer << "\n";
+
LexerBuffer lexer(buffer.begin(), buffer.end(), std::string(filename));
Parser parser(lexer);
return parser.parseModule();
@@ -60,6 +80,9 @@ std::unique_ptr<toy::ModuleAST> parseInputFile(llvm::StringRef filename) {
int main(int argc, char **argv) {
cl::ParseCommandLineOptions(argc, argv, "toy compiler\n");
+ // clang-format off
+ // Cratels: 文件名
+ // clang-format on
llvm::outs() << inputFilename << "\n";
// if (userName != "Cratels") {
diff --git a/mlir/examples/toy/Ch2/include/toy/Ops.td b/mlir/examples/toy/Ch2/include/toy/Ops.td
index d9d63d22bd8127..cba359e1f03d42 100644
--- a/mlir/examples/toy/Ch2/include/toy/Ops.td
+++ b/mlir/examples/toy/Ch2/include/toy/Ops.td
@@ -21,20 +21,24 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
// Provide a definition of the 'toy' dialect in the ODS framework so that we
// can define our operations.
-// 定义一个名为toy的dialect并在其中定义自己的operation。
+// Cratels: 定义一个名为Toy_Dialect的dialect并在其中定义自己的operation
+// Cratels: tablegen模块会自动将其转换为 C++源码形式,其名称会被转换为 ToyDialect
def Toy_Dialect : Dialect {
let name = "toy";
+ // Cratels: 指定C++源码的命名空间
let cppNamespace = "::mlir::toy";
}
// Base class for toy dialect operations. This operation inherits from the base
// `Op` class in OpBase.td, and provides:
-// * The parent dialect of the operation.========================================父类所在的dialect:Toy_Dialect
-// * The mnemonic for the operation, or the name without the dialect prefix.=====mnemonic:助记符,或者不带dialect前缀的名字
-// * A list of traits for the operation.=========================================该operation的特征值列表
-// 定义toy dialect的Operation基类,这个operation从基类Op继承而来。
+// * The parent dialect of the operation.===父类所在的dialect:Toy_Dialect
+// * The mnemonic for the operation, or the name without the dialect prefix.===mnemonic:助记符,或者不带dialect前缀的名字
+// * A list of traits for the operation.===该operation的特征值列表
//
+// Cratels: mnemonic助记符:
+// Cratels: trait 特征值:
+// Cratels: 定义toy dialect的Operation基类,这个operation从基类Op继承而来
class Toy_Op<string mnemonic, list<Trait> traits = []> :
Op<Toy_Dialect, mnemonic, traits>;
@@ -47,18 +51,20 @@ class Toy_Op<string mnemonic, list<Trait> traits = []> :
//===----------------------------------------------------------------------===//
// We define a toy operation by inheriting from our base 'Toy_Op' class above.
-// 通过继承Toy_Op来定义一个operation ConstantOp,用来表示常量。
+// Cratels: 通过继承Toy_Op来定义一个operation ConstantOp,用来表示常量。
// Here we provide the mnemonic and a list of traits for the operation. The
// constant operation is marked as 'Pure' as it is a pure operation
// and may be removed if dead.
+// Cratels: Pure 意味着没有side effect副作用,如果不会访问到就可以大胆的删除
def ConstantOp : Toy_Op<"constant", [Pure]> {
// Provide a summary and description for this operation. This can be used to
// auto-generate documentation of the operations within our dialect.
let summary = "constant";
let description = [{
- Constant operation turns a literal into an SSA value. The data is attached
- to the operation as an attribute. For example:
+ Constant operation turns a literal into an SSA value.
+ // Cratels: The data is attached to the operation as an attribute.
+ For example:
```mlir
%0 = toy.constant dense<[[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]]>
@@ -66,17 +72,17 @@ def ConstantOp : Toy_Op<"constant", [Pure]> {
```
}];
- // ins代表op的输入值列表。outs代表op的输出列表
- // op是用来进行转换的,所谓转换就是将来源Source转为目标值Target。ins就是指这里的Source来源,outs就是输出
+ // Cratels: ins代表op的输入值列表。outs代表op的输出列表
+ // Cratels: op是用来进行转换的,所谓转换就是将来源Source转为目标值Target。ins就是指这里的Source来源,outs就是输出
//
//
- // The constant operation takes an attribute as the only input.
- // 常量必须有值,这个op的唯一属性就是常量值。
- // F64ElementsAttr为attribute的类型,参数名称为value
+ // Cratels: The constant operation takes an attribute as the only input.
+ // Cratels: 常量必须有值,这个op的唯一属性就是常量值。
+ // Cratels: F64ElementsAttr为attribute的类型,参数名称为value
let arguments = (ins F64ElementsAttr:$value);
// The constant operation returns a single value of TensorType.
- // 输出类型为F64Tensor,即元素类型为F64的tensar类型
+ // Cratels: 输出类型为F64Tensor,即元素类型为F64的tensor类型
let results = (outs F64Tensor);
// Indicate that the operation has a custom parser and printer method.
@@ -103,14 +109,18 @@ def ConstantOp : Toy_Op<"constant", [Pure]> {
// AddOp
//===----------------------------------------------------------------------===//
+// Cratels:从 Toy_Op 中派生出 AddOp 代表加法二元表达式,别名为 add
def AddOp : Toy_Op<"add"> {
let summary = "element-wise addition operation";
let description = [{
The "add" operation performs element-wise addition between two tensors.
The shapes of the tensor operands are expected to match.
+ // Cratels:两个执行加法的 tensor 要求唯独完全一致
}];
+ // Cratels:输入为两个 tensor
let arguments = (ins F64Tensor:$lhs, F64Tensor:$rhs);
+ // Cratels:输出为一个 tensor
let results = (outs F64Tensor);
// Indicate that the operation has a custom parser and printer method.
@@ -125,7 +135,8 @@ def AddOp : Toy_Op<"add"> {
//===----------------------------------------------------------------------===//
// FuncOp 方法定义的operation
//===----------------------------------------------------------------------===//
-
+// Cratels:用户自定义方法的 op,别名即为 func,trait 特征值为FunctionOpInterface, IsolatedFromAbove,暂不清楚具体意义
+// Cratels:代表用户定义的方法
def FuncOp : Toy_Op<"func", [
FunctionOpInterface, IsolatedFromAbove
]> {
@@ -147,24 +158,28 @@ def FuncOp : Toy_Op<"func", [
}];
let arguments = (ins
- // 符号表中的方法名
+ // Cratels:符号表中的符号名称
SymbolNameAttr:$sym_name,
- // 方法类型信息
+ // Cratels:方法类型
TypeAttrOf<FunctionType>:$function_type,
- // 入参列表
+ // Cratels:入参列表
OptionalAttr<DictArrayAttr>:$arg_attrs,
- // 返回值列表
+ // Cratels:返回值列表
OptionalAttr<DictArrayAttr>:$res_attrs
);
- // 当前OP包含的子元素成为 region
+ // Cratels:方法体,其类型为 region
let regions = (region AnyRegion:$body);
+ // Cratels:CArg 的作用是指当前即为 C 类型,参数直接将其参数拷贝过去即可
let builders = [OpBuilder<(ins
"StringRef":$name, "FunctionType":$type,
CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)
>];
+
+ // Cratels:有些方法可能无法使用 tablegen 来生成,可以使用这个属性直接将其书写下来。
+ // Cratels:在进行tablegen 的时候,这里的代码会被原样拷贝进生成的 cpp 文件中
let extraClassDeclaration = [{
//===------------------------------------------------------------------===//
// FunctionOpInterface Methods
@@ -187,6 +202,7 @@ def FuncOp : Toy_Op<"func", [
// GenericCallOp
//===----------------------------------------------------------------------===//
+// Cratels:方法调用的 op
def GenericCallOp : Toy_Op<"generic_call"> {
let summary = "generic call operation";
let description = [{
@@ -203,17 +219,19 @@ def GenericCallOp : Toy_Op<"generic_call"> {
This is only valid if a function named "my_func" exists and takes two
arguments.
}];
-
+ // Cratels:当我们调用方法的时候,只需要知道其方法名以及参数列表就可以了
+ // Cratels:方法名
+ // Cratels:方法参数使用可变容器 dic 字典来实现
// The generic call operation takes a symbol reference attribute as the
// callee, and inputs for the call.
let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<F64Tensor>:$inputs);
// The generic call operation returns a single value of TensorType.
- // 为了简化,Toy中所有的方法返回值都是固定的为F64Tensor
+ // Cratels:为了简化,Toy中所有的方法返回值都是固定的为F64Tensor
let results = (outs F64Tensor);
// Specialize assembly printing and parsing using a declarative format.
- // 指定当前op输出时候的格式。这里我为其添加了cratels,这后续再进行MLIR的输出中所有的方法调用中都会增加这个后缀(无意义,仅供测试)
+ // Cratels: 指定当前op输出时候的格式。这里我为其添加了cratels,这后续再进行MLIR的输出中所有的方法调用中都会增加这个后缀(无意义,仅供测试)
let assemblyFormat = [{
$callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results)`cratels`
}];
@@ -227,7 +245,7 @@ def GenericCallOp : Toy_Op<"generic_call"> {
//===----------------------------------------------------------------------===//
// MulOp
//===----------------------------------------------------------------------===//
-
+// Cratels:乘法 op
def MulOp : Toy_Op<"mul"> {
let summary = "element-wise multiplication operation";
let description = [{
@@ -250,7 +268,7 @@ def MulOp : Toy_Op<"mul"> {
//===----------------------------------------------------------------------===//
// PrintOp
//===----------------------------------------------------------------------===//
-
+// Cratels:信息打印 op
def PrintOp : Toy_Op<"print"> {
let summary = "print operation";
let description = [{
@@ -267,7 +285,7 @@ def PrintOp : Toy_Op<"print"> {
//===----------------------------------------------------------------------===//
// ReshapeOp
//===----------------------------------------------------------------------===//
-
+// Cratels:reshape,重新塑造 tensor 维度
def ReshapeOp : Toy_Op<"reshape"> {
let summary = "tensor reshape operation";
let description = [{
@@ -335,6 +353,7 @@ def ReturnOp : Toy_Op<"return", [Pure, HasParent<"FuncOp">,
// TransposeOp
//===----------------------------------------------------------------------===//
+// Cratels:转置 tensor,将 M*N 的 tensor 转换为 N*M
def TransposeOp : Toy_Op<"transpose"> {
let summary = "transpose operation";
diff --git a/toy_src/ast_1.toy b/toy_src/ast_1.toy
new file mode 100644
index 00000000000000..737bf0a94d25d8
--- /dev/null
+++ b/toy_src/ast_1.toy
@@ -0,0 +1,6 @@
+def main(){
+ var a=[[1,2,3],[4,5,6]];
+ var b<2,3>=[1,2,3,4,5,6];
+
+ print(transpose(a)*transpose(b));
+}
diff --git a/toy_src/ast_1.yaml b/toy_src/ast_1.yaml
new file mode 100644
index 00000000000000..5a55036796421b
--- /dev/null
+++ b/toy_src/ast_1.yaml
@@ -0,0 +1,20 @@
+ Module:
+ Function
+ Proto 'main' @ast.toy:1:1
+ Params: []
+ Block {
+ VarDecl a<> @ast.toy:2:3
+ Literal: <2, 3>[ <3>[ 1.000000e+00, 2.000000e+00, 3.000000e+00], <3>[ 4.000000e+00, 5.000000e+00, 6.000000e+00]] @ast.toy:2:9
+ VarDecl b<2, 3> @ast.toy:3:3
+ Literal: <6>[ 1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00] @ast.toy:3:14
+ Print [ @ast.toy:5:3
+ BinOp: * @ast.toy:5:22
+ Call 'transpose' [ @ast.toy:5:9
+ var: a @ast.toy:5:19
+ ]
+ Call 'transpose' [ @ast.toy:5:22
+ var: b @ast.toy:5:32
+ ]
+ ]
+ } // Block
+ast.toy
diff --git a/toy_src/ast_2.toy b/toy_src/ast_2.toy
new file mode 100644
index 00000000000000..f2edcbc84ea049
--- /dev/null
+++ b/toy_src/ast_2.toy
@@ -0,0 +1,17 @@
+def multi_transpose(a,b){
+ return transpose(a)* trasnpose(b);
+}
+
+
+def main(){
+ var a=[[1,2,3],[4,5,6]];
+ var b<2,3>=[1,2,3,4,5,6];
+
+ var c= multi_transpose(a,b);
+
+ var d = multi_transpose(b,a);
+
+ var e = multi_transpose(c,d);
+
+ var f= multi_transpose(a,c);
+}
diff --git a/toy_src/ast_2.yaml b/toy_src/ast_2.yaml
new file mode 100644
index 00000000000000..e9add8610725f4
--- /dev/null
+++ b/toy_src/ast_2.yaml
@@ -0,0 +1,44 @@
+ Module:
+ Function
+ Proto 'multi_transpose' @ast_2.toy:1:1
+ Params: [a, b]
+ Block {
+ Return
+ BinOp: * @ast_2.toy:2:24
+ Call 'transpose' [ @ast_2.toy:2:10
+ var: a @ast_2.toy:2:20
+ ]
+ Call 'trasnpose' [ @ast_2.toy:2:24
+ var: b @ast_2.toy:2:34
+ ]
+ } // Block
+ Function
+ Proto 'main' @ast_2.toy:6:1
+ Params: []
+ Block {
+ VarDecl a<> @ast_2.toy:7:3
+ Literal: <2, 3>[ <3>[ 1.000000e+00, 2.000000e+00, 3.000000e+00], <3>[ 4.000000e+00, 5.000000e+00, 6.000000e+00]] @ast_2.toy:7:9
+ VarDecl b<2, 3> @ast_2.toy:8:3
+ Literal: <6>[ 1.000000e+00, 2.000000e+00, 3.000000e+00, 4.000000e+00, 5.000000e+00, 6.000000e+00] @ast_2.toy:8:14
+ VarDecl c<> @ast_2.toy:10:3
+ Call 'multi_transpose' [ @ast_2.toy:10:10
+ var: a @ast_2.toy:10:26
+ var: b @ast_2.toy:10:28
+ ]
+ VarDecl d<> @ast_2.toy:12:3
+ Call 'multi_transpose' [ @ast_2.toy:12:11
+ var: b @ast_2.toy:12:27
+ var: a @ast_2.toy:12:29
+ ]
+ VarDecl e<> @ast_2.toy:14:3
+ Call 'multi_transpose' [ @ast_2.toy:14:11
+ var: c @ast_2.toy:14:27
+ var: d @ast_2.toy:14:29
+ ]
+ VarDecl f<> @ast_2.toy:16:3
+ Call 'multi_transpose' [ @ast_2.toy:16:10
+ var: a @ast_2.toy:16:26
+ var: c @ast_2.toy:16:28
+ ]
+ } // Block
+ast_2.toy
More information about the Mlir-commits
mailing list