diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bae96d5f25..2632c68833 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,8 +49,10 @@ variables: CI_AUTO_TEST_SCRIPT_REPO_URL: "https://gitlab-ci-token:${BOT_TOKEN}@${CI_SERVER_HOST}:${CI_SERVER_PORT}/qa/auto_test_script.git" CI_AUTO_TEST_SCRIPT_REPO_BRANCH: "ci/v3.1" - # Versioned esp-idf-doc env image to use for all document building jobs - ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v5" +# Versioned esp-idf-doc env image to use for all document building jobs + ESP_IDF_DOC_ENV_IMAGE: "$CI_DOCKER_REGISTRY/esp-idf-doc-env:v7" + + # before each job, we need to check if this job is filtered by bot stage/job filter .apply_bot_filter: &apply_bot_filter @@ -284,25 +286,18 @@ build_examples_cmake: - mkdir -p ${LOG_PATH} - ${IDF_PATH}/tools/ci/build_examples_cmake.sh -build_docs: + +.build_docs_template: &build_docs_template stage: build - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + image: $ESP_IDF_DOC_ENV_IMAGE tags: - build_docs artifacts: when: always paths: - # English version of documentation - - docs/en/doxygen-warning-log.txt - - docs/en/sphinx-warning-log.txt - - docs/en/sphinx-warning-log-sanitized.txt - - docs/en/_build/html - - docs/sphinx-err-* - # Chinese version of documentation - - docs/zh_CN/doxygen-warning-log.txt - - docs/zh_CN/sphinx-warning-log.txt - - docs/zh_CN/sphinx-warning-log-sanitized.txt - - docs/zh_CN/_build/html + - docs/*/*.txt + - docs/_build/*/html/* + - docs/_build/*/latex/* expire_in: 4 days only: variables: @@ -310,17 +305,32 @@ build_docs: - $BOT_LABEL_BUILD - $BOT_LABEL_BUILD_DOCS - $BOT_LABEL_REGULAR_TEST + dependencies: [] script: + # Active python 3.6.10 env as this is where Sphinx is installed + - source /opt/pyenv/activate && pyenv global 3.6.10 + # Setup a build dir with both languages to simplify deployment - cd docs + - mkdir -p _build/$DOCLANG - ./check_lang_folder_sync.sh - - cd en + - cd $DOCLANG - make gh-linkcheck - make html - ../check_doc_warnings.sh - - cd ../zh_CN - - make gh-linkcheck - - make html + - make latexpdf LATEXMKOPTS="--f --interaction=nonstopmode --quiet --outdir=build" - ../check_doc_warnings.sh + - mv -f _build/* ../_build/$DOCLANG + +build_docs_en: + extends: .build_docs_template + variables: + DOCLANG: "en" + +build_docs_zh_CN: + extends: .build_docs_template + variables: + DOCLANG: "zh_CN" + .check_job_template: &check_job_template stage: check @@ -614,45 +624,67 @@ push_to_github: - git remote add github git@github.com:espressif/esp-idf.git - tools/ci/push_to_github.sh -deploy_docs: +.deploy_docs_template: + extends: .before_script_lesser stage: deploy - image: $CI_DOCKER_REGISTRY/esp32-ci-env$BOT_DOCKER_IMAGE_TAG + image: $ESP_IDF_DOC_ENV_IMAGE tags: - deploy - shiny + dependencies: + - build_docs_en + - build_docs_zh_CN + variables: + DOCS_BUILD_DIR: "${IDF_PATH}/docs/_build/" + PYTHONUNBUFFERED: 1 + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_PRIVATEKEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_DEPLOY_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_DEPLOY_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + + - ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh -p 3.6.10 ${IDF_PATH}/tools/ci/deploy_docs.py + + +# deploys docs to CI_DOCKER_REGISTRY webserver, for internal review +deploy_docs_preview: + extends: .deploy_docs_template only: refs: - - master - - /^release\/v/ - - /^v\d+\.\d+(\.\d+)?($|-)/ - triggers variables: - $BOT_TRIGGER_WITH_LABEL == null - $BOT_LABEL_BUILD_DOCS - dependencies: - - build_docs - <<: *before_script_lesser - script: - - mkdir -p ~/.ssh - - chmod 700 ~/.ssh - - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 - - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa - - chmod 600 ~/.ssh/id_rsa - - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config - - export GIT_VER=$(git describe --always) - - cd docs/en/_build/ - - mv html $GIT_VER - - tar czvf $GIT_VER.tar.gz $GIT_VER - - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/en - - ssh $DOCS_SERVER -x "cd $DOCS_PATH/en && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" - - cd ../../zh_CN/_build/ - - mv html $GIT_VER - - tar czvf $GIT_VER.tar.gz $GIT_VER - - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH/zh_CN - - ssh $DOCS_SERVER -x "cd $DOCS_PATH/zh_CN && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" - # add link to preview doc - - echo "[document preview][en] $CI_DOCKER_REGISTRY/docs/esp-idf/en/${GIT_VER}/index.html" - - echo "[document preview][zh_CN] $CI_DOCKER_REGISTRY/docs/esp-idf/zh_CN/${GIT_VER}/index.html" + variables: + TYPE: "preview" + # older branches use DOCS_DEPLOY_KEY, DOCS_SERVER, DOCS_SERVER_USER, DOCS_PATH for preview server so we keep these names for 'preview' + DOCS_DEPLOY_PRIVATEKEY: "$DOCS_DEPLOY_KEY" + DOCS_DEPLOY_SERVER: "$DOCS_SERVER" + DOCS_DEPLOY_SERVER_USER: "$DOCS_SERVER_USER" + DOCS_DEPLOY_PATH: "$DOCS_PATH" + DOCS_DEPLOY_URL_BASE: "https://$CI_DOCKER_REGISTRY/docs/esp-idf" + +# deploy docs to production webserver +deploy_docs_production: + extends: .deploy_docs_template + only: + refs: + # The DOCS_PROD_* variables used by this job are "Protected" so these branches must all be marked "Protected" in Gitlab settings + - master + - /^release\/v/ + - /^v\d+\.\d+(\.\d+)?($|-)/ + variables: + - $BOT_TRIGGER_WITH_LABEL == null + variables: + TYPE: "preview" + DOCS_DEPLOY_PRIVATEKEY: "$DOCS_PROD_DEPLOY_KEY" + DOCS_DEPLOY_SERVER: "$DOCS_PROD_SERVER" + DOCS_DEPLOY_SERVER_USER: "$DOCS_PROD_SERVER_USER" + DOCS_DEPLOY_PATH: "$DOCS_PROD_PATH" + DOCS_DEPLOY_URL_BASE: "https://docs.espressif.com/projects/esp-idf" check_doc_links: stage: host_test diff --git a/README.md b/README.md index bbb8d3a54b..7ce0f5d73d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # Espressif IoT Development Framework -[![Documentation Status](https://readthedocs.com/projects/espressif-esp-idf/badge/?version=latest)](https://docs.espressif.com/projects/esp-idf/en/latest/?badge=latest) - ESP-IDF is the official development framework for the [ESP32](https://espressif.com/en/products/hardware/esp32/overview) chip. # Developing With ESP-IDF diff --git a/docs/Doxyfile b/docs/Doxyfile index 7493f2956f..9fb2ae9613 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -167,6 +167,7 @@ MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES PREDEFINED = \ __attribute__(x)= \ + _Static_assert()= \ IRAM_ATTR= \ configSUPPORT_DYNAMIC_ALLOCATION=1 \ configSUPPORT_STATIC_ALLOCATION=1 \ diff --git a/docs/_static/espressif2.pdf b/docs/_static/espressif2.pdf new file mode 100644 index 0000000000..05d20ec86f --- /dev/null +++ b/docs/_static/espressif2.pdf @@ -0,0 +1,785 @@ +%PDF-1.5 % +1 0 obj <>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <>stream + + + + + Adobe Illustrator CC 2015 (Macintosh) + 2018-07-17T18:09:55+08:00 + 2018-07-17T18:09:55+08:00 + 2018-07-17T18:09:55+08:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEAkACQAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAAkAAAAAEA AQCQAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7F XYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FX Yq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY q7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq8Q/Pz8+Na8h6zp+i+X4bOe8lgNzftdq8nBWbjCqiOSOhP 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 2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV//2Q== + + + + 1 + False + False + + 56.333333 + 57.333333 + Pixels + + + + Black + + + + + + 默认色板组 + 0 + + + + application/pdf + + + 黑鱼白底 + + + proof:pdf + xmp.did:279a03ea-f3e7-40a3-ae53-771dd64b883e + uuid:c3a85fc4-4db4-b943-8504-bfeab2b33386 + uuid:f45c532c-a658-3748-b74d-0cf5e658e16a + + uuid:28112cc2-f74a-0b45-b4e8-5de3f55b3424 + uuid:f45c532c-a658-3748-b74d-0cf5e658e16a + uuid:f45c532c-a658-3748-b74d-0cf5e658e16a + proof:pdf + + + + + saved + xmp.iid:279a03ea-f3e7-40a3-ae53-771dd64b883e + 2018-07-17T18:09:54+08:00 + Adobe Illustrator CC 2015 (Macintosh) + / + + + + Adobe PDF library 15.00 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 7 0 obj <>/Resources<>/Properties<>>>/Thumb 11 0 R/TrimBox[0.0 0.0 56.3333 57.3333]/Type/Page>> endobj 8 0 obj <>stream +HDWˮ\W|olׁ 'q$RS>70Ul滿}x_?(_?}oo|r0櫵~oI10nGaո4U;Q@?[`nɅqN&`TяPۋpFSS'F(5k s*GO݂1ã_*8Cu5b  +!u6G:.N5Gf'l! ES@]C`we,ÍWSpn=v*mua7jSh kO Ɓy{(Axflt-8utɈQ7& އ`fΆfDQ5x%YK7]b~ۿX@w_GƆ&a!z:>鏻hXzli*jϫF#\{<؋Bz^Bp6jÃlʫAlTf};E;Uj~vצt8$nrpGg ثHJ?3q񘻙hqDD&:U.#m0I5LY#v Ql؆5Pf1_r}3za%GFĊ$H58>>D-ZA"ч EWϘС$!Gĩ93zab_MA <GkIuNID"R2Iti_4d9G3y餲M,'&8imsԥ${KD0|%G=DԜ{J0pM% T@,I3zG86ANq0ݧ6lBc561OK%D%E B9%g83ᄖF9fe_&*U碌)x v<|%@n-;mA-7PWirWkԢg!(#oƷ-םJt8jvoX'Whλj7}o=|{.0wf+A:˓!S0ad[Y|0PM8]eS+U0?ո {TUQ* ϣ);C|;6K8tMp{$̗sF6| d^˅GZ3^S{2; W("ym!*LV~HIX9dǵYjN 9!sՏ:*>SYn 0gu>5 1L7|Qtw\MW\+>{oW@z'2Ǖȁߧ c|H~hˌuʋF9ޒ-$nߔAa3ە#ߡ3xIRzzyUtO:P0cP& +uifu^0$)>'+^%F{[갡f)S|K]lkqG9a~vwG*Caֳ?J 꽤=R+Z %&| kf xencB }{C1V^_O!Z}]4)Y:5TP)ҭ}͎l:vhAf^A b|\"QWdy|ʌLClН84LẓoEVcτeq|DK!xNh_y|O#'7s%ᓌxYytG'CI̾=Ѵwf1!էK,Cg8v{xyO|zߘ2 h۵Lgh3 gT92n/Ȧ,1foZ|- +#EL0D]gH`qy38!Яm _unO-B&2oJ:° =r+|QPf;Z&]vFX$K`&d|%(J:e+ݢ/p_Skm~]#EoE\,17]CasXocSMp2 U $Oso˒& E"_jeɍs#y0*[ʯ\t'#_](3Eu G71C2Ssv9[6; ̾<g¢M\fx_FL`i%iS!v)DOAMr5o(A'aQTg/OR0|p{@\DM{[E*>tp*=˫wyS/. `wמojr؏nU'Z~*!dIGxPPQ6ߑ F +|_~:s4T]%^L?Fp ξNNBсŠxޥ@Tix2't1~CG[9S=Hxy2d8b0QV}^n$/SDwfi28GzqoT'n9yп)R  }5}T4KVB q5<] +Ď!O5ĵ踯4(,*TF,jXqj=uOnXz' + 4S ΆL̬*p;-) +djUQ3)5W酜LMFhF!]zD4!@-jb)=ߖaBrǨ0SJ4sTY))HIuAVxc2kSP?y  Ty#Sx~ҝgvȏ r=?uu6"H +CEcӐAһFHkְxa +l?Wx_LW]t K,Zp1*ZM: +1x^#jQd`'1j]!Yô1~eD 2#07ܻFQg80i&yӁ3h"Gt% +8N5 +^i͜ P +mSU<ÀכO(ÁaYvqAES%GѪWBDWH=*R+%$^4tU)$].%2J4tFTl?]#N}kĹ^UB:hxDWP1Ѻ},M *P1p=3OW|u>&i3j %p:_{VNywl6r*E)L)5 ݁>f + )`vr`]H L nvK"Nb.02sNWr[LQ{FtggƼ +ص0Á4!@Y5b-Jܡ9e=*<(;k&lBf#݇T & +tBTkk1!F%0X][VkӜLO]t ;&c`]Id3`~(]v&LV~Y\t0]KD!OJӺ/s.-{u7*ֵ6㗮)]bg3V {F]k]Tsˠr{b1Y.I2xzՌy-! k@ڮphQcm{lPb$)Z᎝cWbh<,!sAVFԢ|%e={ikHJ{^t 4T"롣/Wr9Kn^p'vPK} );\|e44>h6rDZW +m7Mp:5xY )\het[#7z7`3-6p +/Mܚ>Sv=4>F5֖ZEIU"t$Yp?yػ +ek|ex?pȒ~/UsS*]bD|w޳ddub#gj2V°-M'O [ӍaU8T' ]' Ku=]&'ю*Fw +8\ַE)}U9 h*\Q/*<+j<4|Q$4ܗ==7>!Yg#ql%bJVF%hP>%*ov L6z!LE"eo}8M΍Uuܶ[ʂT>hN +~\`@jّP _}b| __|~ݼ~t?/|AW5/m??φhbi߃_B {.vx,!RFBE0'aR&a*Ec?/M(~(8Hu6>\Zic uA:2<4_ 〉QڅuҰn4tJ5:KȰvຕ;T7PA?x]^FNVYS65~?ݰgbHdb٢0\^cןX,#r/jJ^RR4?u,T)8VZh U oAvMcwHEaOВ< Op8}~Ij|KNd)a/5QC1EAYɏ>99uIeuD ;:ͩH7vƱHJ.!b7>OɚNƤ8ᤘdlq”l*}x@<6{(ك}>&D'osQ_`FW1!Fi+@Q%pթ5g$ˎ)"rhD+5yz2X>OFf؍&P !X$aHb0t05<t7#T XCh<3H{f@&A׌km%RjCDzQ#i+/bneڦz\?{' \20PvJV7ӳ6o,:vE:^ɓ^AKE}H]b3o!B' +Ig{(Ecң"R5e2MS$>Բ[)Fӳ 9vt`}`OHCVL E ձt%{rttJrG\k* +`QVe^IlS#g5S)T]a;N}aTUv]²Z)񀪲-E|. :g1: N6yDgwGE0:5ˈN& 0:?k.?Q=l38viV'kV țANQs˲&uc6 7^e"΍ոBv5$$D`ՃZ NPJ\ڀ7l3|xh\}lXvx#$󈖽#͵r76RX mL9JFQް3:@!oUvN9M}_q[- |Xa¤Vx%-mCZ<;_Š)bu8ʟ%] RRMH٪:zZ̤0(ov{ǑG@MH:#plύ х es|I^1܅*, ,O8.Yx$D|Ҵ2H|ھr$nݔ7rO:vR w4])7~sm( 6!"sCZHOX"}zLF80F#5Zwpn1)αlS3[]W6r@uid uI{d7:Ih_ߑ ;G#\!9{v +eաCGB}f8aSP *enl|#3e4Q  ʆ'Z9nOCl<aWGBW zAHFBh8KV3Vj)حXkFbG n̛VjLCNHpIRyI2^|$mu<- ,eؙ]$Sm=cCVUndO {)Tpm- =Q]ʃn-hbN%5O{&kLafS8-ie?} +Y=nGSy+^2bFt6D\p< {ēÁ+"64b1p$%;qxjp+ap n|IGfEՔ +Bw]Uh '1Qjč0xpTt ^:Fl4;3#|KjC]G.qŢc&©i-x8nFDk*{C 8*;6&p*/,(ٳ^Jl6Id*lcrFMJָ(!׉)A푥 Gvp0nIVwa,1$Ds:IYrxձÑwC-FAS)3t+T\yN!<ŖcX3o ;IptMpDLDUk\F3XO˰qޢ'oK5 rEI)cfG cֈ~byʹ׍=[Ȍ +>i.c7]+4ł]װhk [Ƕ,HCrmzP 5W3I/1MM' Acx"Lr8WJ<bBFlzPuחaPF$6xUxdήMNbn{U/eeUw+S!%P4_P$;囹Ј"m&]吝WSJ'>BgՈ\OI7Hj=6nTӑdQ@FtKZ\B2]IKW3rNjwz?[ cT;[7%M2+Y7N*m~ԯ,M:hǕ:l(SVj X*+AӺ:W8,)JQk4"5&rǖ> }%@> +,}51UpχgYk +S1=%ev2n(&6rw=T:" +3Vp$p}p!b`|y^yI4zԯ?. SE01[٠h)'yᢚcu:)"PkRWXh`NV%x0sA7k _M=qw`2k[5m;b<gh)eyOLZ{|wePnz>$}TT&ȷY5ct ƗpL#,,M=kj.B=hpk"@ k#UϼO4Z/$bq[] dֈmxno3"aLOB[uf=>72cZ[~Ī&Z +=2xOuopZK?_c9pX#hb8j`G>!ֶ#& {Yu +sr* jEl9t]%;[v)٥4+{J)xX0_LRAw;4*w)j~)"LB<9u{A:RApߦcVF#cJ˖|DgHe3d 9 ۭQB~w?ؕ]>mi ;6g?}{Xp=eўYF(NK]{;BO@ 7sݝUl$g`#f)Hmj6c7=r@pڀ=B]. tKPq;I~DyDq&wJ;,o)NjҚ unv}\x_#?HiؑZH0s%xZ|^#^zIqG ݲ;t7;̾25՝.m*FtI=ovyM5w֧]"^$S<P_,``OdM֙2)Z_)~dc_z8MҏP!kg\߭@&s9*vw=K𻚒 ij T>Q5x" hm#FJ= f9 +`G+ ļ +@G#\ʺi 2ZL-ıG `}# ֔>C `Gy70M1zJsUuQbVi˂]V"S5e]ix; p^ב"cIp HA}gk1 +opyj%: '0׶dД +R!`>V,4 XGjѨ#jaNbz-GZ +%e9:ؖFN } uUMAU<&p4k" wlf4#0HC"kx;X-|\!MӗU|4嵀 +&XOk<%@8rrDt"+iA2S! 8lK}udkWoTBO!Zőzʓ C6=nȚ5eo$DUk<(2kks.qeAS|d֧ ,DsՈ~Xoz:(tB8MJyGߚ2ȑ]{e⼣m,Hrm`ݭ+l_mЌXMv6MRDe:Hl(ؓ +u۫h]#&^|j_n.,A DVBJ@q/N?iI<wMS/5GQEb*eMO[N YN|9$Ϊ)Noz26mp$#%Ⱥp"$mU#ԅd5Nfl6zvpҥ-*ǨvoK &dhWbnT(5)ͩ_oY7Vu$+unQUW uu`yfIWB|&p,-Y2Sƕߣh(E^k6M8-}$@$7e*<`J/#,!A& AH:/ҩ^ #Tҧx4 +G$9od1F̜27KҎvl7nИi#wTKLU(UXV6ڙ9"ѣ1/XCb|$ +=3+O涋E3CJ[dvt"Ff,_M rR"O; "NѫM3٪)ME%$ߙ83 oPڪ\бKiTO '˪}AF0b=S+ֶc +cH5ԚhDJ35`zA55 ͻa˿]#\ *F$TS^-fӍ^@OcDQ,؟L`nѰ+!?t LtS6AY5##HљFX/7a.|i{{9(p rH>. +{=x7>Z6NkuH:$F4l@<wӼ[۴}ЈylODGz}d)mm-O*Uђhg`{ze #?:=NֱsI ϱ?h,@lBO>EpHGI(zhCu +=x* ' +v'JvB4उ6=Ed_LR4};4BSuZSA=IH3)Ha҆(@IH(ٚM[7 "i"$M$PUSiBB?C}g=ͩǟOXl?6OO0 i!i_~Ǔ2rן_@ +C~~$ʮGtu桷!ߚ\oHD'}Qj֧[߫斿g;n^y˚OVxVi: C$#B!ɻ~i\s!\ NA%@TU#iS"4 c5HYlMȟ\nmj!O VyLSE$aUḢjW&ZCXvzr:|Svv~k2'3^l;wؓߞ/~v~`Ylx8<ʱH$9z 6+*K]yx C!O634%Azǚay>_~DI@HIa-Y3 +qkzD /ɳf^{JjE '3kRb'y7Rb9_r#x~8y7[ө$P=⵩`s{I ;P}dfl1x #Dϱm K鐝;9 L֠?_ZsI"9 1|)M3IЈrhgVl @n`(/cD-^ w;t$\~"68MqeM{&Q>謏Zt,j4wMРrus_ JH v1 şPaO + KfIIC;^I \$Y[)8ZOnxd j$M"u}t g9p^SТg:m[S-HAw#A[8p$B<Ǟعţ# ]d gU67(b >T[pL't08V + 8Ͼ[gl)<8d]e g8e4P)G GP= 8"@6qy&VSHYra+kG,- +vu'|M{>HT)8qlp߬جtџ͹5=R/qB#FVGд@:7|\F ɑB@c-2ԭo^kl3NcLte4:(Yv}XvMN Mfvt0NtxMh˱8֔ŪFhf셼d xy# 0iFA0)Ү78Z^AɦĘ5jR488I1h!ǎrx\{b2sM7Ǹp?!7vx[3FX{9p`(c;mEl٣iZQ, < +XL!.bhD=8qR\leVt#rj<嘫fԈnD)>A㗃4h$QH]490I4w1y8B*l}#CV@۾,ftSg?9R/^[FԒ}׌ѥAӀ޲NM3)S "rL eeR1uF7p7v^ZEvSBDCJn}#ZJ7SBSʹ6 GiԍkUǕL8`˖9tX+Gwx$lz+]LoLWM$ )3-#g ,rMH7xCS]DOoT(.7 gK8<ݶ~g@p&x2jfki&>byGژbk\n:b&>STwpo<r't"$2mynMR۱/W=ouGIM^+ĭ* 6E4.G bpy$̈́4dr`;J2Vr4UgH9UDjz8ES,2dթHLIL'*cJ!MΓlo.Z-x1o TV%]zqRᨾfc#M$ ':~ELVx{Qܶߟ'*>ESR߹2J?}߿(eU'=?_B ߨZK>gY?왕7*mP2WI?,U98>P9Ѯh[mC }=kwczOw|T B+&E?E*KQl1|O1 0lϯׯ}fGL>m[X=2ݏ&E,-^8P+Gȇp8~y "kOcEuq zkcCGe-ZϮ[: Jetxp)vsLͮ2;8pdh(sg)H{_)Ng/@ɝU s +ZGyx@Wx|+yf}^&3S~Q&݌q>˼F>}}Q.$Zao~2Ӟl״kspq5/3Z)ffaڨc8QeC໖SUb2X8Ç8NBui) S4%t+GrW2$X:j +׶I)9mv\Q*+B'l44#zQtԷscx=&On|h[~x)M!PN 'm餟)v!`4OyCVt$i=h3eKߴa!;U]fn?$4iBGaOƶZ +]#&k/BFW`M!;su>q* wKtcG:FeOꜘ71x`IÎv$WZY[`㓟+ pnn6L6̮L.MJ&K9AruٺPWu^ɩ`o1b;l  $㴥$W 2minˁq4IӳnxyԼ$b+='ENfrSUztM#I'E}mrӂe ޏk(M +*pcc= C` +\y<RCVg]=Sֆ8 +_ Rm!0=`Tvl _|%1pu5kϘ6P)l2MVmfq8Zq`cz \Ք#L+k$G,-6 ut 4E1SC59U +މScfzXӉ#GN@Z!pFDV`iŘ@VY7<\PD–ZZ^%V Z67sL};VM4̲S7£02oa o͉\ZPN30Μ#so$mF|4h)">}Z6:ޘp2yF4t. xNќ+p[L}Xuch}T/%K;R3*0ިV/kyw%^ L=XJ=)pH65ޮW6QUw5ÁrAy@+ӘM|$MBmS.n~Ct( +v$%iI8DU`Y_kOJfi|SzcgP^ +U߼#m6sO3"=XkTc{\cE,4`Q* >oaKk>Q>)MZZ2+ZQ`9<+&j`vW\5=ԃ_ rOM(Ѳt#vɀsnCI֐ o_1Cd+W ZtՍ/luJ@%BaNMw]9 h?ia-vzYM*fѡtf&\Wst7F% ,j۩2bg }ɭ[xRifw•6?4bMJ8|dR`|XvqK2$bUQMӻ.'ިP]n$ϖ.PIeZ=rc_4p{A;2V>[%U6l4Vi\6-6lI i +`-JcWwPdhw϶r2 ,pNYfSeLǫSn=O4T0I$C^' \ 77ZbP`7J 5>7?Q}'FH Ou: +m1@M?OT}jW!~seV!7v>}5uQVc ʪ?Ւ+˭潊lg[B dOII8I %;pUozJ gV\gT el=L "?X=Bh ڒyrc߁zY^T'H]fa]) +ҽh)Lx8PBƼtAh)A+""=2C>|{C,tݸP$A 2 Mek(k%D^ ?'FXu]AgOp]/v~WGf3H$YlvIA1n>= %a u *`ӠF'f )_؀\1o/F1ٟ\Cpi0z4K﹄`,{.>?gXbK:Xs>``g=V7F:4? rD{ӯ·UC-B͍GrmvEs#R^L'ufJaP," 3gYVeD Q.`˃B-r>5-يP<r%i6];~`+zޕ qB^C?{q`K>!ͧ_t̎^ = #XrCvgpC+#YsgDX*ۘG>LOfLi'NҬ+_ޕ|-ΔtO(O 0ق]tog&7JC|Lw{XA7\{(-,=dM&7XR!Mk65X٣܅^Pn\6tT9m Ya)GK.R;uTp퐵,dHpr~.(\{UߍkV4ĖΓ'%e;7Xг]"~.-j9ž{ +g ||~'Gģ : 뇺f>cTU'LVaYQeIo8u|z c9|{ߔf q[6˘QS˯y8h ߦ1Ƨö4Nmg/}l¸Xt,0w|"1m g.x<_\),#.]-E_)Vx%s+34$ +w#, xI, 4$%qb(i{kH[a$Yӏynm%r®Xw񅅻\^8ZB.g@c0")ϸS3NSg2ԁG˙"Y 8amXrqR@1K8?7ÛoKLUL]f8COHu*mȪ'!XvW*9Q_}HQc}7C!}^lA^);=e +N B 98(\e@fq^jE㡪"lIa;SyXVocThl)ξ&81R&=KM FV!e"1,`C:HY +\o085X]wH rX +hL5eEXfY5 QB܇<0+mL +ёI=V\ c2h2r1*zJ8&'+V̳XsC"*ɕ,:E^f182_F2"YwR J.ws@$zoCƘL.R翸=>}L2m']%IGo6Xqw/QN:DKL <&pDN1/ !}@rw9N LؕXkx(NYT|ݤ5O=u ^otJs?|ԝ6-8kX9P-}}'+vG WWM_|#%ssS +~K]ZIJ4Nd/}m59e8ib3T,L +6?wKxX +L>._ͶέBҠ4<`W "KM!Jߐb+}0GUa=0xT% iw +Dt~փg Jf7zh(%kCkl[vtSVxTûnpއ 6Pep/rҨؾӪe*(z O7lXh <f =lX5Gt㚢"P`:< NcCe]15{yC,"k{XVmɆQoH†zd4vGּհrnޫ0Yjօl5GmzhjT j+ c{@╹|Q4S؍ݗ+89_L{*>wY$Q0sb0`=k&&)iHJoM_r.yȣ=ioӆqduyDNVk;Yvv Vź[/,ryv|S΀t+x6")xR3nSfe3EӍͩ1 rrR%cGn7rx3R,bmz%Gϡ6ܩ:.@X_6 |x;?G%MđCFjr!`=s؂3*0%,Fka|XLU[Ce9ʋYaanAΗ1n9r]6"WfQs7S0d fo#-9]4LKxVn.GտvEwVXqUjqs71qa۬isƌn6X7uy .;xUtÒ*tY>,:! }NH<S#1W83'C#a.o_a>rK.*GaMg{?J9xLB;0JF=|+jX}* e +7C!\zezx)%S, +]m@*'6+TQ?T(b$[4+ZD-.`^yC2'SB*&~d'ع[zlX~|(AD`\Y#J߯I3K5qpVb%7ṫO+!TM]kSˡڷ +j_oϯ}BPПȰ_1n5]U3?HKTⴴٙB+t +' +I@Y]X&R)Ho )qOK!Ҁ{c{!&ץ-b)p%vC JY"_mdmvNJAe xnGѽR@8-xT@ӒxfCpn^ +7 tT`4&[pu<"6TL=̅aMe[$ +|wMf.M@cQCokP+6>Uۢ+po ++t8@\모Fif-$TxVd=8 + #Z]7O>kd*VBN + y+{nŘQ zĩs=e(Ƕ#A1V sݴ'^~v,k‡g s(xrQr̃p_²ĦOͥ^Ň'(VL] pc +LK, 0mf~o;R`IuB?CSһ2(.)SS?[®E%z)|6R[_bxbw^ؾfJ|iyZd^΄]jsޖ!qIu~C%:~P/ oTK |;Ù4iWsMeΰ%.qx>ڛrN73_4¤Km%B~Fƛ i&+!S;j!H0+&1s;tZt^1osVirR0m7WBa}U`9Vd+kJN"k]׬=WQe^᱊*#5(Q(L=s,L;- +x 7t%w@GG+0GMO= y( :@. z>-݅;&C ͸z^R?V=&jx=h@B-54,@a@ +\iRVihϳ: n-<mkCu1'Y|mkW4 + sXj&Jt2Ws,.6qEF8_n~Vz +-4A;Z (MuT"a0-*EtCuH\-eܑΝ=J$fZyhw=,P4yG7yq0XGOg۬cL Ӄ wyeSyt=lᅸ,b]aER ϷK;x +~{WuL䎦>kGz +ڡ{jz:w^r/g7QGl.5gVkiuO'&ݟXU1ƗI*1_~G*&j%?)XiN.8>.v4!ڕj/Denix- &E P)5Na'bG ly#5ɏm9`zMӔB;09YjK7_8ÚZTQcBPt`Ш5ʝctaqt5b0XNSb394ZI 3kI;,KȘXIf%[IlbJnNϯ߿ڷ~?9x?5Kq*e^^!&g1zzGP(c7W|NRƇXP'|z5(xNꗟ\l_2HI?8}XOMD;PД PQ!ߔE j 8s:@)75_:a ̄RG,6a ;\aD^aXdU]V%;b^`ˡE&C>AG`[L.̑}tB߆ iЄ0!y$)Lٽb,4Ű弻HWe6.<I>):yևjW+|9&|K%{ú]د{1IyTǼ;z)\584 ;̷ ܳw 6_ վy92 +~QkY}T^Te}Ґ]v|p-j?z/n9Qp<8\DMbC򀃗y$NOo1?\Ti%XUx?At7nH'"2) +oCCfx,1dIu# =X̮UE=1N I[ĮI+EZv~HĮ3)6vzC3=ysS.v9 !qUIu6LwyRJqTwygヵw/{p;>xֿ]~D;i ɾ*"'J7KM {&3;ss-vIo +wU69Ѕi;+M؇ݑ EzyY10iX{WU筛<]~x|V&+0޾*0qf3W k 6ܮy) ?_Yuj +ǪV9>Ze3 _ w༢kH]eAOQc It0Q}\s~K~y-%9zw?U(R~L?ʛ(֜z=NIv +wK'Kq56wrbYV!RG z+(؇t0wAhB%_sB$ڝ(j#KV5Q0VGdhK/ |`lY^ry{JYjFH5%*Wlncڐ] jti.i8<5ELh3L器VeɻGa`_^ cueZ3]PtoSoǶ5hG3u4tw!g8hC-E,>צb"tccwQ,+`%ѳ̉~@G-ϳ$C^PUܼŏY:zeftoY8qOL-Ҿ3Vb#tv֟}lqKlF>PJx>/ +vFiskh~{A:aO䊦 +_aQYov(M5]^CF/og5R+TM\`F8&ee-KL "OtMLx@e $_|F1Am_稽 +D'S=Å?lO]uv RKtK©HQ$Gq@վ lbܪ-RV䠸9y8WQQM)-(rsr˚YͱaiS^ skIR'QoG2]6-cKշS:?r.Bt&\?qɷՐQ1YS%ݡgZylVu HȘb9[ `hO?㿟!VNo"GGT3>ME4 w9-^ Hv;{G ;#oaaK G~Ox #]c?Rw3Mpŭ._^6.6Bz۝,sD%Hu&2C|A"jj;!=EJ n?9<5B=ټS+yo|;>;ҧ9m= ':J5="H9EoZd/wPQv{q^ +ohSauqo$":ph+Ƿp#,܈$ȕ[>'$t^ bwaϩ^{2ɚL?7iZj9t;CFRo+!cG1{=mI| XW-B?*+mH𴏸8w.ot[𤚕mYnxCh͡'BjjҼU!D8@k:ZC JLHfȚ"ɫO"ݲ9JGQb^&)Y2 D[hrslh E.h['{t홬3"_T/6 ,:&4`h CKWJИM<,atMh׋e܊{ =rU^t_Pm|0G4\Rr:ܲpF:w@g0+ںӝ1P*0Pe@F Mkrࣜ`DߓInC]:P1>T]e/G0) XQCo@zm>)\4R>g9IlA2nD5K!ST2HnU@1$œ+M.poz}l?/Jہ5G"ྋ38!)98ThЄ(Os>Uch3iĶFCM "V[2i]ߛ{1fh.WCK/|o1LĔFS-X>&$=”ⲇi3ir 6c2r^J*gC=[ܣ0 f^t_Lo]*ÇJYm`xNmF cՃ@A0HC}pn]`cԃ;ék)Þ6h7Ž. `YSz pEhM#\rum<8ߏed dOO>W˶DT3:T={6:]ra)pQ`o]\8:㊞:r0oAj/̷ =@X8JbQܞ^wv{wEjbFmK] i:-"~o.`">D?{g F]+=/cU2ԁUz0^',Մ , Nho7LT\5BD PWx;M}g9S)i܆`K"w߂tA,,;aAZ)>kKA[HC~Sj!ߦEJsl:Dս4y:z箒I-iN7PU3uތǰZVZh40RW4Y%W3lOi׆K:6M4Y:<5~.Խ"Se#׋닯Ohx*X^ma$S="NSdVng ԇ{QUV gH+Xum"3D2zT +kIw㕑P 6O81VSBQSs(gC*DAB4 KVnθ.2Lg~5;*x#~Q!>OJJ0(SJ4ӂ֎ Cbbw+ISF34_5a _ueb[E(¨3ª {@,s]mKX*g*\&M,_)V%쨰pI +RtyRB;_΄1;{ѭ-P ne +uɉcJP`N3 ~O@PԙගIPϿ~OՃASb5?\2/]Gܠnr7y)\yҥF/ȵ>k;7_fږHj%:οE%=,68Q.kM>T?oB"^e(4V<ӨGOwn8m v'} ݩaZ~} ~ȶEv;ǯJ¤ƣD=vMR_8%W"TDy(94 abAI^719d`hAgsf,nb|ČXG5B<b=ƖOS8 s3 4Litف4eڇ-{hNUl g(R%pz$p*fg_#MЖ lAUn'q6t#Yamډw%"|ZᖈTfRH5#FaA ݇hN8ڱ_(]V|{>G腵{#j[Y>Da9}d +++?i{!b ?^-'XxD +L޴;i)&ܖ:MYmf維 B$]#ٲ19A`$=x\D}i;~jV. {>^ƪPY$|p- iaVIѽO`Y AX"}>n3K2aM9u7zʊx;dYrS DmuڴY[.@ȥ޼d$İLGPNy9Z9!I$2OL^O<}9h9L (Tx>ۚ`w-ЇZ=goܻhTn';&XC*)0AB6z"7`jcS>P1yko .̤CPLMD3,8>%\Q!xH ꋷw5(USrMc{Bk#Y*1bm55$`#%6/jq,OQ^TEvF7s;b'ɞAB+ŤђL/+%,S1myI+D95uݺ)CٕЋb-\ S.CD.fSF!jDfndwIswL'ScUX#ɂS J)Pi_Iفr .7nC +H5P4=ٱ SAO[T׶_Kr(H1TC ˡ,ľˑyNWʩRuVPxJ4 1J&M9 >h,4ԯ(#=[/i;&fH6(["&$v$x0@ݗl8U^qP-> ("crC㮊A21[h[w%&^kE`8Pި3,y@ZSphmFLU94E +,#~(:xOaPN5+L X[6B^v# i=14 l-j_lq!bY {iz76fGW-ya/T<(! +1*Uzu:%)HaNC AFAJc>h{*{Kp+Iǁql2/j&VD$&m5M`R֨7h lJh'Gӟg 4 e@ʤֿ?RM7-dUS)Vh`Lg5Аli)^ J8[hߩÏXϣvh\ïMt_wcS**1A&-X;XI +w@Y6bHGk-XX6,ƙSQ!zaL[h6gxO4(ev \ FX;uE LD$LǵZ!$|~_0]Dnى%HT{U]D bc,+n9LXQM`'nzet2@rbHN~T=H!JEL?Ty .'=H"SJ񄋅Ī&X pM +R;b]¯k'Kalnc99(b_QŦ;X{ɩn2nOS F1$}Rܲվ)JĤok9p jx. %P6@a E-#*%`E+,Q!_/`°ozjmxsH]̧ |]h4r +EY ։ HQ{o3"Yא4i%㹩Lɏ Eډ;D4R?JLxzX<4k 0ƅct"xSN \TcfaysA:7|Ȕe҉gabSN4D&HDk҉Zeb։DJ̘F$ +0 +1DupLHDbǬ ڬ>D(u@:8^2>&P&Z'DЎ_^?` aֹ0}vAL;[ έyӼs+n޹wb޹f޹j޹7s[üs'xvyyOm`m ;&;$&;E&;f"̡N玺b炅碉⑉ià:\5\<6\6\D7\7\F0\0\N1\ 1^3-R,) *?GNED6jӇh oDZ@HT3N޺1O n$G1XrCK"Qbp&syi..މCht̮5[A)8ҐMy!Qt!b؁Ou⹅9U'.n g4$-2Q鼲A yኑH H \!؟#ts"q Sֈ۷in)ge+O& /w3Z* $ZF['<{T$rO1@S 2ނfOJNOHskFyH x񙳴@hh5/]HA~ +4H|1 @\;"9} IQ},)F)p 93tNH1k1`>a!J :36߀y?+X=S5VO|ss{lB%+WvT%ϡ$^I\4G5l$uIu+o=+~7 sZc6ƻj+WT~֐;<c5L(g %-C8ESiB؆1c}.)%[ &V](m~iҬ#|us6L!22 9ȂB# >Gn J}K[?9V)15r>-igǶw` }h/1ƸZπP{}(8:[+ +M ;vAHЗS-'~ Z9CBx x/ki\aJ2+]IPߛO1+A t0_8W .9۷jhpYdXp2YgW> ۅ_WINb+6|z ϗLͷ43i>eĊ_n\S+i1i TQkcԔ&|PC&*fFed U%n@h:TqW_l@pR 5884_ICAGl@HJ=&WM k 2\ըPB ׷'3j+xQo1j;P&bb͚&6̬-5kΞ5q(FMQj5FM$QeD5'AE_&2ܬ0kH (u&D5QbMX.ք5bMxXf#ք5aWbMX'؄# +6aMxhs:˕m.&m 6CE Dٴy߿~ן I endstream endobj 11 0 obj <>stream +8;S=C0`_7S%"\noO8`:`1K?(.gkjkgO>Z(g[7.,"GQA!K)E&9'~> endstream endobj 12 0 obj [/Indexed/DeviceRGB 255 13 0 R] endobj 13 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 5 0 obj <> endobj 14 0 obj [/View/Design] endobj 15 0 obj <>>> endobj 10 0 obj <> endobj 9 0 obj <> endobj 16 0 obj <> endobj 17 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 19.0.0 %%For: (Graphics) () %%Title: (黑鱼白底.ai) %%CreationDate: 2018/7/17 下午6:09 %%Canvassize: 16383 %%BoundingBox: 512 14 580 82 %%HiResBoundingBox: 512.519474100296 14.5993985160931 579.268412090863 81.3483365066604 %%DocumentProcessColors: Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 44 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%CMYKProcessColor: 1 1 1 1 ([套版色]) %AI3_Cropmarks: 516.333333333334 18 572.666666666666 75.3333333333339 %AI3_TemplateBox: 297.5 420.5 297.5 420.5 %AI3_TileBox: 265 -333.333333333332 824 449.666666666667 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: 504 120 6 1448 814 26 0 0 67 38 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: 504 120 6 1448 814 26 0 0 67 38 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:0 0 %AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 18 0 obj <>stream +%%BoundingBox: 512 14 580 82 %%HiResBoundingBox: 512.519474100296 14.5993985160931 579.268412090863 81.3483365066604 %AI7_Thumbnail: 128 128 8 %%BeginData: 17418 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDFCFFFDD6FF7D7D527D527D %527D7DA8A8FD74FFA827F8272027F8272027F8272052527DA8FD6FFF7DF8 %26F827F826F827F826F827F826F827F8527DFD6CFF272720272027202720 %272027202720272027202720527DFD6AFF7D52F827F826F827F826F827F8 %26F827F826F827F826207DA8FD69FFA852272027F8272027F8272027F827 %2027F8272027F82752FD52FF7D27F82727527DA8A8FD0FFFA87D2726F827 %F826F827F826F827F826F827F826F827F87DA8FD4EFF5227202720272027 %2027277D7DFD0FFF7D4B2027202720272027202720272027202720272027 %7DFD3DFF52A8FD0CFF7DF826F827F826F827F826F827F826F82752A8A8FD %0CFFA82726F827F826F827F826F827F826F827F827F82727A8FD3AFF7D20 %27A8FD09FFA852F8272027F8272027F8272027F8272027F827202752A8FD %0CFF7D27F8272027F8272027F8272027F8272027F827207DFD38FF52F827 %F827A8FD07FF7D27F826F827F826F827F826F827F826F827F826F827F826 %F8277DA8FD0AFFA852F827F826F827F826F827F826F827F826F827F852A8 %FD35FF7D20272027207DFD06FF5227202720272027202720272027202720 %2720272027202720272027207DA8FD0BFF27272027202720272027202720 %27202720272052A8FD33FFA8F826F827F852FD06FF5226F827F826F827F8 %26F827F826F827F826F827F826F827F826F827F826F82727A8FD0AFF7D26 %F827F826F827F826F827F826F827F827F827A8FD32FFF8272027F852FD06 %FFA8272027F8272027F8272027F8272027F8272027F8272027F8272027F8 %272027F82720527DFD09FFA852F8272027F8272027F8272027F8272027F8 %27A8FD30FF2726F827F827A8FD06FFA8F827F826F827F826F827F826F827 %F826F827F826F827F826F827F826F827F826F827F82627A8FD09FF7DF827 %F826F827F826F827F826F827F826F8277DFD2EFF522720272027A8FD07FF %A82720272027202720272027202720272027202720272027202720272027 %2027202720272027207DA8FD09FF27272027202720272027202720272027 %20277DFD2CFF7D27F826F8277DFD09FFF827F826F827F826F827F826F827 %F826F827F826F827F826F827F826F827F826F827F826F827F8267DFD09FF %5226F827F826F827F826F827F826F827F826A8FD2BFF27F827202752FD0A %FF27F8272027F8272027F8272027F8272027F8272027F8272027F8272027 %F8272027F8272027F827202727FD09FF7D27F8272027F8272027F8272027 %F8272027A8FD29FF7DF826F82727FD0BFF2026F827F826F827F826F827F8 %26F827F826F827F826F827F826F827F826F827F826F827F826F827F826F8 %7DFD08FF7D26F827F826F827F826F827F826F827F827A8FD27FFA9202720 %2720A8FD0BFF272027202720272027202720272027202720272027202720 %272027202720272027202720272027202720272052A8FD07FFA827202720 %27202720272027202720272052FD27FF2727F826F87DFD0CFF2727275227 %27F827F826F827F826F827F826F827F826F827F826F827F826F827F826F8 %27F826F827F826F827F8277DFD07FFA827F826F827F826F827F826F827F8 %26F87DFD25FF7D27F8272027FD13FFA8A8A87D7D27272027F8272027F827 %2027F8272027F8272027F8272027F8272027F8272027F82720277DFD07FF %A8522027F8272027F8272027F8272027F8FD24FFA827F826F8277DFD19FF %A8A87D522627F826F827F826F827F826F827F826F827F826F827F826F827 %F826F827F82652FD07FFA852F826F827F826F827F826F827F82627FD23FF %A82027202752FD1FFFA87D27272027202720272027202720272027202720 %272027202720272027202727FD08FF522027202720272027202720272027 %7DFD22FF2727F826F8A8FD22FFA87D2726F827F826F827F826F827F826F8 %27F826F827F826F827F826F82720A8FD07FF27F827F826F827F826F827F8 %26F827A8FD20FFA827F8272052FD26FFA852F8272027F8272027F8272027 %F8272027F8272027F8272027F82720A8FD07FF27F8272027F8272027F827 %2027F87DFD20FF52F826F827A8FD0DFFA8A87EA87D7D7DA8A8FD12FFA852 %27F826F827F826F827F826F827F826F827F826F827F826F827F8A8FD06FF %A827F827F826F827F826F827F826F8A8FD1FFF2027202727FD0BFFA87D52 %2720272027202720272752527D7DA8FD0EFFA87D20272027202720272027 %202720272027202720272027202720A9FD06FFA827202720272027202720 %27202752FD1EFF5227F826F8A8FD09FFA85227F826F827F826F827F826F8 %27F826F827F82752A8A8FD0CFFA82727F827F827F826F827F826F827F826 %F827F826F827F826F8A8FD06FF7D27F826F827F826F827F826F827A8FD1D %FF27F8272027AFFD07FFA87D2027F8272027F8272027F8272027F8272027 %F8272027F827277DA8FD0BFF7D272027F8272027F8272027F8272027F827 %2027F8272027F8FD07FF7D272027F8272027F8272027F87DFD1CFFA8F826 %F82752FD07FFA827F827F826F827F826F827F826F827F826F827F826F827 %F826F827F82627A8FD0AFFA852F826F827F826F827F826F827F826F827F8 %26F827F826F8FD07FF5227F826F827F826F827F826F8FD1CFF7D27202720 %A8FD06FF7D27202720272027202720272027202720272027202720272027 %202720272027204B7DFD0AFFA82727202720272027202720272027202720 %272027202727FD07FF2727202720272027202720277DFD1BFF27F826F827 %FD06FF7D27F827F827F826F827F826F827F826F827F826F827F826F827F8 %26F827F826F827F826277DFD0AFF4B27F827F827F826F827F826F827F826 %F827F826F82752FD06FFA8F826F827F826F827F826F852FD1AFFA8F82720 %2752FD05FFA827F8272027F8272027F8272027F8272027F8272027F82720 %27F8272027F8272027F8272027F8277DFD09FF7D272027F8272027F82720 %27F8272027F8272027F8277DFD06FF7D2027F8272027F8272027F8FD1AFF %7D26F827F8A8FD04FFA827F826F827F826F827F826F827F826F827F826F8 %27F826F827F826F827F826F827F826F827F826F82727A8FD08FF7D27F826 %F827F826F827F826F827F826F827F826F8277DFD06FF52F826F827F826F8 %27F8267DFD19FF5220272027A8FD04FF7D20272027202720272027202720 %272027202720272027202720272027202720272027202720272027202720 %7DFD08FFA8272027202720272027202720272027202720272027A8FD05FF %A8272027202720272027207DFD19FF2726F82727FD04FFA8F827F826F827 %F826F827F826F827F826F827F826F827F826F827F826F827F826F827F826 %F827F826F827F826F852A8FD07FFA827F827F826F827F826F827F826F827 %F826F827F852FD06FF7D26F827F826F827F826F8FD18FFA8272027F87DFD %04FF5227F8272027F8272027F8272027F8272027F8272027F8272027F827 %2027F8272027F8272027F8272027F8272027F8277DFD08FF4BF8272027F8 %272027F8272027F8272027F827207DFD06FF2727F8272027F8272027A8FD %17FFA8F827F8267DFFFFFFA827F826F827F826F827F826F827F826F827F8 %26F827F826F827F826F827F826F827F826F827F826F827F826F827F826F8 %2752FD07FFA827F827F826F827F826F827F826F827F826F827F8A8FD05FF %A8F826F827F826F827F87DFD17FF7D27202720FD04FFA820272027202720 %272027202720272027202720272027202720272027202720272027202720 %2720272027202720272027202752FD07FFA8522027202720272027202720 %2720272027202727FD06FF7D202720272027202752FD17FF52F827F827A8 %FFFFFF7D27F826F827F826F827F826F827F826F827F826F827F826F827F8 %26F827F826F827F826F827F826F827F826F827F826F827F82627FD07FFA8 %27F827F827F826F827F826F827F826F827F8267DFD05FFA827F827F826F8 %27F827FD17FF5227F82727FD04FF7DF8272027F8272027F8272027F82720 %27F8272727F8272027F8272027F8272027F8272027F8272027F8272027F8 %272027F827202726FD07FFA8272027F8272027F8272027F8272027F82720 %27A8FD05FF7D27F8272027F82720FD16FFA84BF826F852FD04FF5226F827 %F826F827F826F827F826F8277DFFA8FFA8A87D7D5227F827F826F827F826 %F827F826F827F826F827F826F827F826F827F826F8FD07FF7D27F826F827 %F826F827F826F827F826F827F852FD06FF2726F827F826F827A8FD16FF27 %27202752FD04FF2720272027202720272027202720277DFD0BFF7D522027 %20272027202720272027202720272027202720272027202727FD07FF7D27 %2027202720272027202720272027202720A8FD05FFA820272027202720A8 %FD15FFA827F826F87DFD04FF2026F827F826F827F826F827F826F8FD0FFF %7D52F826F827F826F827F826F827F826F827F826F827F826F82727FD07FF %5226F827F826F827F826F827F826F827F82627FD06FF27F827F826F8277D %FD15FFA8F82720277DFFFFFFA8272027F8272027F8272027F8272027A8FD %10FFA85227F8272027F8272027F8272027F8272027F8272027F82752FD07 %FF2727F8272027F8272027F8272027F82720277DFD05FF7D27F8272027F8 %7DFD15FFA826F827F8A8FD04FFF827F826F827F826F827F826F827F87DFD %12FFA852F827F826F827F826F827F826F827F826F827F826F82752FD06FF %A8F826F827F826F827F826F827F826F827F852FD06FF2726F827F82652FD %15FFA8202720277DFFFFFFA827202720272027202720272027202720A8FD %13FFA8272720272027202720272027202720272027202720277DFD06FF7D %2027202720272027202720272027202720A8FD05FFA820272027207DFD15 %FFA826F827F8A8FD04FFF827F826F827F826F827F826F827F826F8275252 %527D7DA8A8FD0DFF5226F827F826F827F826F827F826F827F826F827F826 %A8FD05FFA827F827F826F827F826F827F826F827F82627FD05FFA827F827 %F82652FD15FFA82027F8277DFD04FF52F8272027F8272027F8272027F827 %2027F8272027F827202752A8FD0CFFA827F8272027F8272027F8272027F8 %272027F8272052FD06FF7D27F8272027F8272027F8272027F8272027A8FD %05FF7D27F827207DFD15FF7D27F826F8A8FD04FF7D26F827F826F827F826 %F827F826F827F826F827F826F827F826F82752A8FD0AFFA827F827F826F8 %27F826F827F826F827F826F827F87DFD06FF2726F827F826F827F826F827 %F826F827F852FD05FFA8F826F82752FD16FF202720277DFD05FF20272027 %2027202720272027202720272027202720272027202720272052A8FD0AFF %5220272027202720272027202720272027202720FD06FFA8202720272027 %2027202720272027202720FD06FF522027207DFD15FFA827F826F8A8FD05 %FF52F827F826F827F826F827F826F827F826F827F826F827F826F827F826 %F82727A8FD09FF52F826F827F826F827F826F827F826F827F82627FD06FF %52F827F826F827F826F827F826F827F82659FD05FF7D26F8277DFD16FF20 %2720277DFD05FFA827F8272027F8272027F8272027F8272027F8272027F8 %272027F8272027F827207DFD09FF7D2027F8272027F8272027F8272027F8 %2720277DFD05FFA827F8272027F8272027F8272027F827204BFD06FF277D %A8FD17FF27F827F852FD06FF2726F827F826F827F826F827F826F827F826 %F827F826F827F826F827F826F827F827A8FD08FF52F826F827F826F827F8 %26F827F826F827F827A8FD05FF5226F827F826F827F826F827F826F827F8 %A8FD1FFF2727202752FD07FF202720272027202720272027202720272027 %20272027202720272027202720272027A8FD08FF52202720272027202720 %2720272027202720A8FD05FFA82027202720272027202720272027202752 %FD1FFF52F827F827FD07FF84F827F826F827F826F827F826F827F826F827 %F826F827F826F827F826F827F827F8277DFD07FFA827F827F826F827F826 %F827F826F827F82627FD06FF52F827F826F827F826F827F826F827F827A8 %FD1EFF7D27F82727FD08FF7DF8272027F8272027F8272027F8272027F827 %2027F8272027F8272027F8272027F8277DFD07FFA827F8272027F8272027 %F8272027F82720277DFD05FFA827F8272027F8272027F8272027F82720A8 %FD1EFFA8F826F827A8FD08FF7DF827F826F827F826F827F826F827F826F8 %27F826F827F826F827F826F827F826F8277DFD07FF5226F827F826F827F8 %26F827F826F827F827A8FD05FF2726F827F826F827F826F827F826F82752 %FD1EFFA827202720A8FD09FFA82027202720272027202720272027202720 %2720272027202720272027202720272027A8FD07FF272720272027202720 %2720272027202720A8FD05FF7D20272027202720272027202720272052FD %1FFFF826F82752FD0AFFA82726F827F826F827F826F827F826F827F826F8 %27F826F827F826F827F826F827F826A8FD06FFA8F827F826F827F826F827 %F826F827F82652FD05FFA826F827F826F827F826F827F826F827F8A8FD1E %FF522027F852FD0CFF7D4BF8272027F8272027F8272027F8272027F82720 %27F8272027F8272027F8272052FD07FF52F8272027F8272027F8272027F8 %272027A8FD05FF2727F8272027F8272027F8272027F8277DFD1EFF5227F8 %26F8A8FD0DFFA85227F826F827F826F827F826F827F826F827F826F827F8 %26F827F826F827F87DFD06FFA826F827F826F827F826F827F826F827F87D %FD05FF7DF826F827F826F827F826F827F826F852FD1EFFA8202720277DFD %11FF7DA87D7D525220272027202720272027202720272027202720272027 %20FD07FF5227202720272027202720272027202727FD05FFA82720272027 %2027202720272027202727FD1EFFA827F826F852FD17FFA87D27F827F826 %F827F826F827F826F827F826F827F82627FD06FFA8F827F826F827F826F8 %27F826F827F826A8FD05FF2726F827F826F827F826F827F826F827A8FD1E %FF2727202720FD1AFFA827272027F8272027F8272027F8272027F8272027 %7DFD06FF52F8272027F8272027F8272027F82720A8FD05FF7D2027F82720 %27F8272027F8272027F8A8FD1EFF7DF827F8267DFD1BFF5227F826F827F8 %26F827F826F827F826F827F84BFD06FF7D26F827F826F827F826F827F826 %F82752FD05FF7D27F826F827F826F827F826F827F8267DFD1EFFA8272027 %2052FD1CFF7D272027202720272027202720272027202720A8FD06FF2027 %202720272027202720272027204BFD05FFA9202720272027202720272027 %2027207DFD1FFF2727F826F8A9FD1CFFA826F827F826F827F826F827F826 %F827F82652FD06FF52F827F826F827F826F827F826F827F8A8FD04FFA827 %F826F827F826F827F826F827F82627FD1FFFA8F827202752FD1DFF7D27F8 %272027F8272027F8272027F8272027A8FD05FF7D27F8272027F8272027F8 %272027F8277DFD05FF27272027F8272027F8272027F8272027FD1FFFA827 %F827F827A8FD1DFF5226F827F826F827F826F827F826F827F87DFD06FFF8 %26F827F826F827F826F827F826F87DFD05FF52F827F826F827F826F827F8 %26F827F8A8FD1FFF5227202720A8FD0EFF7DA87DA8A8FD0BFF2727202720 %272027202720272027202752FD06FF272027202720272027202720272027 %52FD05FF7D27202720272027202720272027204BFD20FFA8F827F82627FD %0BFFA852F826F827F82627A8FD09FFA8F827F826F827F826F827F826F827 %F827A8FD05FF5226F827F826F827F826F827F826F852FD05FFA8F827F826 %F827F826F827F826F8277DFD21FF52F82720277DFD09FF7D27F8272027F8 %272027F87DFD09FF4BF8272027F8272027F8272027F82720FD06FF7D2027 %F8272027F8272027F827202727FD05FFA827F8272027F8272027F8272027 %4BFD22FFA826F827F827A8FD07FF7D27F826F827F826F827F826F87DFD08 %FF7D26F827F826F827F826F827F826F8277DFD05FF7D27F826F827F826F8 %27F826F827F826A8FD04FFA8F826F827F826F827F826F827F8A8FD23FF52 %272027207DFD06FFA82720272027202720272027202720A8FD08FF202720 %2720272027202720272027207DFD06FF2027202720272027202720272027 %20A8FD05FF2720272027202720272027207DFD24FFA8F827F826F8A8FD05 %FF52F827F826F827F826F827F826F82752FD08FF27F827F826F827F826F8 %27F826F82752FD05FFA827F826F827F826F827F826F827F8267DFD05FF27 %26F827F826F827F827F852FD26FF7DF827202727FD05FF2027F8272027F8 %272027F8272027F827A8FD07FF5227F8272027F8272027F8272027F876FD %06FF20272027F8272027F8272027F82720A8FD05FF522027F8272027F827 %2027A8FD26FFA827F827F8267DFFFFFF7D27F826F827F826F827F826F827 %F826F8A8FD07FF7DF826F827F826F827F826F827F82627FD05FFA827F827 %F826F827F826F827F826F8277DFD05FF2727F826F827F826F8277DFD28FF %7D2720272027A8FFFFA8202720272027202720272027202720277DFD07FF %7D272027202720272027202720272052FD06FF2727202720272027202720 %27202720A8FD05FF5220272027202720277DFD2AFF5227F827F827FFFF7D %27F826F827F826F827F826F827F826F87DFD07FF7DF826F827F826F827F8 %26F827F82652FD06FF27F827F826F827F826F827F826F8277DFD05FF2727 %2627F827F82652FD2CFF20272027F87DFFA8F8272027F8272027F8272027 %F82720277DFD07FF52272027F8272027F8272027F8272052FD06FF2727F8 %272027F8272027F8272027F8A8FD0AFFA8FFA8FD2DFFA8F827F826F87DA8 %26F827F826F827F826F827F826F827F8A8FD07FF52F827F826F827F826F8 %27F826F82752FD05FFA827F826F827F826F827F826F827F8267DFD3BFF7D %2027202720A852272027202720272027202720272052FD08FF2727202720 %272027202720272027207DFD06FF262720272027202720272027202720A8 %FD3CFF52F827F827207DF827F826F827F826F827F827F827A8FD07FFA826 %F827F826F827F826F827F826F8277DFD05FFA827F826F827F826F827F826 %F827F8267DFD3CFFA8272027F8272752F8272027F8272027F82720277DFD %08FF7D2027F8272027F8272027F8272027F8A8FD05FFA8F8272027F82720 %27F8272027F82720A8FD3DFFA827F826F8272052F827F826F827F826F827 %7DFD09FF2727F826F827F826F827F826F827F826A8FD05FF7D26F827F826 %F827F826F827F826F827A8FD0DFFA87DA8FD2EFFA82720272027277D5227 %202720272052A8FD09FF7D27202720272027202720272027202727FD06FF %7D202720272027202720272027202727FD0EFF522027A8FD2EFF7D26F827 %F82620A8A8A87D7D7DA8FD0BFF27F827F826F827F826F827F826F827F852 %FD06FF2726F827F826F827F826F827F826F852FD0CFFA852F827F827A8FD %2EFF8427F8272027F8A8FD0FFF7D2027F8272027F8272027F8272027F827 %7DFD05FFA8272027F8272027F8272027F82720277DFD0BFFA8272027F827 %2052FD2FFF7D26F827F826F852A8FD0CFF7DF827F826F827F826F827F826 %F827F826F8FD06FF7DF827F826F827F826F827F826F827F8A8FD0AFF7D26 %F827F826F852FD31FFA82720272027204BA8FD0BFFA82720272027202720 %27202720272027207DFD06FF52272027202720272027202720272027A8FD %09FF762720272027207DFD33FFA827F826F827F8267DFD0BFFA84BF826F8 %27F826F827F826F827F826A8FD05FFA826F827F826F827F826F827F826F8 %2752FD08FFA82727F827F827F87DFD35FFA8522027F827202727FD0CFF52 %2027F8272027F8272027F82727FD06FFA82727F8272027F8272027F82727 %7DA8FD08FF7D2027F8272027F8A8FD38FF7DF826F827F826F87DA8FD0AFF %7DF826F827F826F827F826F8A8FD08FF8452F827F826F827F8527DFD09FF %7D27F827F826F82727A8FD3AFFA820272027202720277DFD0BFF7D7D2727 %202720272052FD0CFF7D52277DA8FD0AFFA8522720272027202752FD3EFF %5227F826F827F826277DA8FD0BFFA87D527D2727A8FD19FFA852F827F826 %F827F8277DFD40FF7D272027F8272027F8277DFD28FFA827272027F82720 %27F87DFD43FFA87DF826F827F826F827F8527DFD22FFA85227F826F827F8 %26F82727A8FD47FF5227202720272027202727527DFD1BFFA8A8524B2027 %20272027202720527DFD4AFFA852F826F827F826F827F826F84B527D7DFD %12FFA87D7D2727F827F826F827F826F827277DFD4FFF7D27F8272027F827 %2027F8272027205252767DA87DA87DA87DA87D84525227272027F8272027 %F8272027F82720527DFD52FFA87D2727F826F827F826F827F826F827F826 %F827F826F827F826F827F826F827F826F827F826F827F82752A8FD57FFA8 %845227202720272027202720272027202720272027202720272027202720 %27202720527DA8FD5DFFA8A85252F827F826F827F826F827F826F827F826 %F827F826F827F82627527DA8FD65FFA8A87D52FD0427F8272027F8272027 %275252527DA8A8FD6EFFA8FFA8A87DA87DA87EA8A8FFA8FDFCFFFDFCFFFD %FCFFFDFCFFFD46FFFF %%EndData endstream endobj 19 0 obj <>stream +HWn X)l`=y+Y'n|,H=C\SC3C`E/ +h{ѻ@{U4-2My4>H$aIC~G|`#b&O8D +}Eegw g?8l ƤgŠ= +o;i^Ω| PXq[Ĕz'|O? >#Ag:jpʯXK`$Cv<<+~8V!VqcwB}qUqM0e"gNy4 GvPrϨL~w)$9K@t'=C$Jʯ%郃m\C"+l; XmF +3P5\ndil@ Pz]Un(_B2q1*z"!(%JfgG>ad39\"F5'h_:1>vCˇׅw s֡m9 8ށo}TJ•l(/O_/Hvq20av`_R#U@$Яs6*.!onzz,8c{ :mî ߰R/kP'gg4Z:fm^s1sE'[(mQ.Gt@׌'0ðZ;puO{NKŞgN~;G e6YV#~,NڨWW;[CwiZHV9zZap{fhEZ]޵B5!q$2舶q+Dhusg8ȓ8˜f$vcyg1MZX/ơafcios#Q ;2tbm_܄Bǒ=u:biF8ĆqaV}L9AFT Ӏ*TEͲ^<v[달͚7P64Lc"p4JXgU5A9Ы1>؂><t|*zf:jr3e**f|"${%'Nњ~]LߣIXzȒIBXʎ~.=ŤTΚ><_&VmC$ڡzвQ`cDw +fRϴvΩ,Z$ kYLm46L,с5;Nf--t'UK܈-u$>Bz]ಶ\'IzZʜt"T&$gi6Q/#iFe]{ANEd.EG&1h~lc@@HR@&g En"$CIIL3)Niz5ץ$%= Ri^cEW7g6CF#Ƴj)w{{[=J?Uua5 SQ@H+`vRj Sn#ijw{v[۸ninn23$I8?胫g%]`㼟[5ǍxG+ XY/"".:2e0wVЇ2iH$R˔-V{Pr4p0*ߙAkUA< X#?/D#yJCYsW  y-%!g,"XdsХ܊(Ȟ؛MH2Cܨ!\S&tpzuAq w SV= .Z>'!zӛVq k04 "[&Ꙃ,i&;PI F3T"bqx[p3Tg`Q4uI"~8I\d |!w+? 9&(}FЧN" + WA,9A8tBu`)e4w =s.饁nUAq+[Q9,tع >5!{'/CF DH5 J[z֯e5 9#r;(VOO"-,+SIdC4kq`)Ʊ9wR%h jbz8PR 5pF iKH_ؚu0x~qqg~Nդ[zؘ0hP0p Uj$Vl(ʢ[ј.5#VTSc4Z@.85h0/T_:_- I6BPa=oHod$8<&bF%@,uMuJ>9|U FY|f/Qdߨ ,DO&#(:c \|zS(ygQ Db XI10ʡuE쾰ңȣl B$ȮFFl.+FF#h*yGaYs1#e35=F:LkU쪡8X7 +[ڐ8DL0#J z-*Pm9GԂlr- E:l "#p4 ,>N 6$]@@US茌[ь&4M*d`!;gGzOƜ%FHUb"08צ[P1ÒA:!T!*W֖J[,L.zk |_t& =,vF=h?Cz&nA<}M/E.],r\% ^ӗ\S +T"b1)F>@J>{eVmY8uQY V1w% ظ( +&CCZ+ l.l8ȓmIwI@kFۅP+5Dz%pH 7@+txW$6 !~K9ne:)[*VU7Lِ4Sa)Z^iigp~`n^䳜;% Gn`2 P `P +MuCgo9ӧ,˦E|U")4JHC58h ;w}.fVxyѦ{2V$ȘVk<] H*A'arKwB ;'ŒFbH +^I5<X"΀W L,,"@]0('Ȓ *2w8`Yg3靳'cVy~)\,HZL ەl}Y$"w-߆ыc+4l@%JنwYq j\^[TO'ܨdg&7'4HJR~;UK +>8~(`M$65&u5V{iޫ|2™9LL~B~Ż~ 9p#:-cs[) Pӳsw2俙9h?"tCg97^@! n5 `A S[(Z,؜z9$dqy|[Ace!ھۣb='Ov@a@6{+;`r`"&XP I +q+BPuVO85*Q{B4ȋ>->ecĀFǁ3 +BG +k =h4h u hzh,TJ @',4tҩwL.TQƈߐjXpÀmz[I@ | 3o"zyu&YhvΩ /G/ƔC^º@ݥSC{c~o Byn$ZH,00-cm>aKA +@^5vhR~Q$+|kkِ/g>J#۹X +P$}1|&K4h%!ؕXu 9 oH~S}HqłɖۊM}D᪗Y=<eЙihg{4]҃ڏl AcǷREqVJ 6x2Lwi-~:hZ vZ [,{{ FoXA(wEjⷰnDk \͉ۗqTZvoj50 gXy*k >Dkd;KD nϊ-q_T&IΞPA&Z'(dZW>Z[p:Ke#?g;kqVJ.5V-QE.I8뛕;k dKQNj+駘>]o8eO^İ*2kMk6L{]ifN,78͸BN[H/gdi7]9 #M<{mGO|ŋ+- Y-XPQ@ɻ.^g7ߘj{ˠ0vjwXu'Oy&6.cpl ;MϝpZgzGb[)i&AR{gljˊCD"D/k>h,)?< + -ҏ.z^.2hj6q3׆;)&/'gׅIXAe)HR|4d!ZG +X74(݊LPBk"R ϩH9>t0VY?fEϟMeORQ۾A Puc+ʙ(v}^?,F*~üw zռ<~P\b9Ƚٟ }e +R9O=밠/iF@O7ג] y?<$W'5N]7\:%]Ykt%E]No mIn?Y|}aXk_"c؏σ1!cȘ~=^-4q&W)!ZCo)(orAsjB^~}Sߺ29CJ +Hd6"I2QdKPf7RVc- ء+#fO<#W\3L9ӖN[N.CFW<~l$Xу&4|.IKUk>(A )ܓ]lpZ–k(a#~hbՇ'pUS`l!?ʜPQB:M#GPX[o*x%!zd nzW^oq=~7xQmp0-qg Gg-+W%fDcQMQ}w +-ѨWZ2ڨM$zĵ:kLJ_˘!K +ȸS69% =/>N>u|N;ASSģ4lҠ&˽%QLhTw%JؗlhlEXGaɸ/ц7tWuKƽw? r-~d$d~H~ѡNY$;-{otL3sDL1?a^iP &LЬPHڐ!Bax+ɛ$$Y6QQ,3gT=<O;%%;l0`g~d "E@ɢ^EUyqE2kOޔkmFQq~sUo˝`P8Kk*ZBE#QE _,-}([aX47,Gl" +dG*dpxd͚6Q4. 1'*Zh*hPfWJAm|M}P5Irlhp6W4P4X8kaMƢ9v ~iߐGծ|u;mgϙdžn*3̧ƃY |)Y0$e bY.$( =Πj`eEc'g 7Q9zaN%'4,Y4_|_Yo|ßbϚp{E,(xקxM1X5Y/bgsP0C8BBqOᄟ܂! +4,YӰ6C#(BP䊪Kq| ;d'܎`/ԓ$:BIE4!WJ &:|^IaV`/3 +A'){Vח+~]q}炕ߺgᛘ,c|Tr :}V(-GIv;Yţ/7fZ,Lo,v9iF,twʍkӦxfL_Ք^:+'';q@|jo> YU7nܬV2pZ,ipˁw_5 ֝xcz̿K./r/Y{i^kg$v5vs:/URVb:mBJgՋ4;^ +{h,~p.K$^{ΥKA,ˍK3}AL/RY{ŸN~oNzo+WoK|7@-ec& _/ֈj"?|biJxr=LI=w> @Ov[F,u߻:9:eoyC+?U?[0MyX ?_Ň4y-p}w$~"9GܤK< 9%Q5.bHRZ}J5lb};il<Җb˕ֵ2CLYxHi2w_Vd7HY-wAjUUI{ӜIGϘgD? e&hl㭪V?mkY:EV\?ɂO>I +bΣ ޣNI{~Dgn[A~MO~/ +.&3meڍ2F*Zm4:a ` 6~^ISr 2z5 `gفx0xjC--qb>X/ìNJg^*B&6uc!֒;C٩4y:\'A5OSC`'Qp7eKxdM1Av?0Q5.bqFG(0vrBvHgk7=ց#E:4j|'/C dEO8r:WBt=Rh84x'iܺx *mGsɠY*^",ti(/%˟pz'1%&Q.QpNcMd,o,wiyPft%B5Ka>E %j *84%Qhe؟J +<%UءD܀uQ@0"qݍ*FnӲJ tDbAM2;OV(rWF}z1Hί\%׹yԙZWh5/jFNF[(|۹}ڹ=1ஙx)TgPqO^xXT v#fMJšxJ'$,pV[nA(Se%vqS9H `Z] Ś2ߧ{;Ŷ$ {U{Kx8`\R[lS[Ҧ6:ێ\_TM5VN PsŘ2D^t= Y4k!,> )[pAEBLCh1. GiaX5~⩤D"zDʐb8fYI=+r9%|-lVC_:*39XCjQ^eJK1nlCÕ怌lhs:Sb' {E~}Bٗ;;5n -Cb"G)GX0NE_z㯇9`( O^\ +R,_I>=e-VTZpCF`}Oxo[k`dA˧ 32n` +u\ 8cMo{%=>p*သm4I[R5dÚ_35`@kHv$2D0pB +!N%c5=`-Zk/A"mØQ<<51o]ʂqdF%.o/0n:p ƃ߂k'|7xϫFǏuj_X'խꋿ;ؾ;J+s:;"ncSN'KpIn /x3RUwgF`"Pʃ׹xwEGyJ[, 'fӆ˩SҐJz IT8b;O}wlj;vKOpngSh +45g'&?/ʠ?.C%JGUIA)uȔ rz{s;oo |wє *B3:qbst +6#&۩e|1ՌvL + .9 BBAJ}]$ay1ng%^G jn+xXmוEF:J\U`\Xwy qo Ɯ".sAۏ_V8M0@SHLfȪ ҂_\za +,]U}ȧ94(AC m U_-Dn^-2aDÍh q!ِ2=AhB$`@=DNB`P<3=\u)ͰAW7HStȌqW%"bE=I~FD,hpT{5q)m,vdhɪ_7'g`slb'"Cf[M}ZF4ۄ),;*^zTLϏJS{?"|_\R#*p@ˈ g\PB OI$0,l s +bTҹ_cĭ=VagvET;sws \Vԕ +oF,XTx[yO1کժ _jIF'C +# deuz!yj(}Bќߖ[CnoKLC9y; =K/hbl:s Zňy|B_gm~y +sO60`F?w 7Oŵ "$5rytvj'ijDےϼ*OTs#[kЄR%d% +oe{V0_OB 9d`~yB)˥¡S0wJNFMURbS_D0?r"MxVd ɑ'DKXΊFJ»%91C.K6ߜZˇtf~4>Cd,"ˌ1By# +$%$"%5>stream +HW^L}<@H $Vh HE,?dyofa&Lk6A-uYXZvbֹ`a{|h)T.Fe9jUrѾ&eI6MZe59YzeP +rŊiPsƽ*]fWqS֡,O&jNgQJku޵ןVdl E$f|e)>9Н{T= +XyN\|k< n'] d ov"m}|UƱ"dIJ1>%*%"Eg7\;Pg^^ZyOI2/e\WAott̎&ӆ%5$m5a5!JV^\Z{3\ckE%ơȉ٣|2]xIGO&ʒ ԂH* +J+aB'J:'R ȥɏҜfw!;rɳB^l8T}\l&<+dKwQ٩e-nbQ Bn'&{ࣀI%dLx0Syyhdپy"0Ur{ ۚ$3eKs>r^2z!X?a론8¶~Ycu<ϬZhU]]Gڑ$wcN9;9+{۟SSVG:YFpNzG!F[Sr0KSL㤿Y. ~6et,Q4kFQ*j>GǽR'σ IvЖ R's3͖ ɐ_xI:(aAGHy cp޹_ 艟]k2qH2J+Z=UZ4kN^xv'iǤ V$\/ZǹIt$Z ƙ?4" G< |y›c<%kh!.:"T\b4-?S!Kܽ +.)ןL^+ora,bw.Y-ڹrI%QxBҊNAzxR6 '?6v{z؂~sCd*8^hjph3f}>U҉] Tzy:Y$ֆ\ANRU1{abVC,aB]IR+kmZv;U-g1,#.cii+tdRr x OhmRt W(lqrc Pآm(}1KӁ5N(MD̑@)͋J*N'`q K-7dەVW1FVvY~A}'RcmVE1x<[ح1 +JWNxRс,GqI>łyA`  +(]%+O=MvNm͂rR$rYm.zeiNߦi!*eK+^KPífZXϔ4ox@+;o(+ #X#(O)`~}Q^> TkE._p}e3BPwGqBG1W\;{j sx+|6t(4jB +mH"jB4-`&DVm>ֆעqW\D8CX#7L5pLnr=ʢ&L4^R.6o^?Li|h 2*Xbslo9DcXm$"s$C9WRސQ ɜE͞fwå"X>ޠi qJ=^Vesq{=Y5urX}7/maa!WFiÒjrې#v72e@@9aΊgF!T^^ZEms>X X*j̀cu3Jˬ|(g>oY!Y^Y!1hiXf .dgO >GP9WH2o.TWQoHL@䪃XϘ5dBIWzJ}bQc&K{TM100{v[k> ёPĮnȁ5{zhD#?5 Xb,H/p+z|ƶx-l@i*Fp=]Ɉ|tjg)LSwA`p4|g$Z:_@*Ex:ecT- R:p ;`@_>4ˢ];Ja;n QqZH[t"!&8gF=0:*RmK֢1-s:#[+(kUy;87Z?Q V9C}uyqai'a\Qo/U $҃ĩq;j>9}_ã}hԩplAWÓb}-&Ppm_Ĝ_>E]qu贾3?OqܢP,|, pI`Omg.CzZ7ۍ4YGjBLlBN{ѻ [i턨6GN'ł2Vɞ 6q5Ft("_f!7 +g!/BHz[܋Vߣ4sܨv |ycNӔĆtwBxkd7ڂ 1ŏN7UmsGRGՙ^zѷQ>K.=ϺX.;X[% l춾{rNօypr^Uk8?SX0ۥ?j{4V'c271 R~ kg(lUsqɰRI;:BtC._%0+#$D 8Ԥ3w(? !JL_hxWNM~}۫MmSmСBN{\7=p?UȾ Y?ǾN^B`x99Mˇ,b{j=Н- JbǶXU6{͝,u׷i낼$RqOK;l"ЕN)ޘ Zk8'p j5\ DрڃKˉ{eiDOSU͗쉺TU)5&k!n:Q22}WmE E[ $u G1% K-Dg)a;yO:uw9aT:%6Q at!cPP{ʞK !nv6փxo4hfBCi7+AGy&N+!rgOu2 Bg+SVPy:rτtևN{RZm %ilTv'0>$.X߈e64eH ʅ䖃]9d s{?-g^epEqN&7=vr;ؘE"Z6]r6_󄏥kz@u'2!u/%4t3};0CRD-QjJWC Rh@hҵpy'$3*s&z"pߙhMu`Y9E{svq, 9Hʳ꾆gOhPYSm; -Ǐ+7Z3d8>ꮍv7TEPr<ө +`=@モY"T9`6Pc7-#LBLmggKA:!=_c駾[phyhɖ"TR4 ŚWo*ʛ_DV뷽*ًA hv@]I3Q?F\;#I \6KDa:˱Cw9H?Q7mO^mWD0Z$<,tuiݒE}mкv Lt(ٯ*iNC* ??.nno#̿1Ώ +9=ZxA{2kI> `$Kn5 YnY'*H!_qRh6$bvk̢+;<9A K@K +-,zw eUxBѻr[=\xPf]B{jJaQ`) |]Ci5F&^Ki&OgPUwEDUӀ8za^bӘEDՊpH3J{rqdXH!0^2Iк(kJLبOľ G%e lBݪa" FX8ހ_nۙPOhcxoؗ5y3Pɿn|u|-?T,FxJ=~>@ǬrPJj<)-Uzx8&GGJ)f<\I! r_JX[O;$HQHgN! ?YI&=of*ȧrvհz Jهta՝ˡ'O%=`S3|֊_l0L\''vԹC{Mɻ5 W|l)PFqS8/E~);מ(L|@q1\Tj1>vvbHɎuct+8}9gT>s!q:QQGP vy)x8o'yx〱9v +%E徍9RI kJb'b2ս)jj \dU;hoU{:P;Ѥ-q;&#OӰuQh=䶩1tYoVݕ2ZWK ;;a9+݅-oco^{<˥hoo:'O,f%\iG `)pW)`hyGgßP斊*,̱ygܕ^r2u-wSLɻ"-\-[e%r3"'Bsx-c jf34b|hfޗ-u_䳟~@ 0f䳌rA"ȰV'Y[+񾈌&ގYJ46Xpi3/<[@G+Q(ȚƷ\ˈ!f@3l4-LQϮL?c4dz5 B3If~3dhA { @5?BFf}g8H=kB2 !-?o lA"|e;MyG cNnjcXZU +>ZmT!6dH*LUVIx FUnFΕv/oqx`AZm+>(0 kQ{GȿAɆWYkّYaHj8:.7u *{^GDcFrjR ^c/@ LAƞ"X]K"`5AvE&~DŎ놪t0'PtY3 @;^0܈LRgR7W}S< *TMUKe:-#VSDa̰S2"޺0v̵+e@Qmxw +-> R*,BV* (Ŝ Sg= +_+FSjL/z3uhd5Cݼ\V/$n) aM6'd"gN˸_HE@WѺO"pyrkX[MYۑއ%3ۻKN(h5կrzȿzSݗ *˄=7K1\Au_ʘMp}o(k~li;n}3L-q=%Cg7U>x2\Y"^I$e䫐AkZ+/H-/u2JjdV{ͼxb/-YLG?QJr& +ѫ[ \I U^!NSytg6< MA$Etܩ Apwhq= +czakbHZFKet,oA: CH[%3T9z_F㡿f +3{ 1O<[^g`(,t? %D(/Yi>:aڨ7f~/u]|G_'!UQ..B9u̢B@s%#t,u'[K/A/b#nIe&VIuJo9I0]^@UY%KJٗ2+kYW-xb<_F'5QY؀ =IY_ZKF/1l *MN\I'f f1&l`m fs9\`n1bn BQYY_f~ 4 &2/(P:˸aW A_RY +$whax2GSN +3?C3&fBSXjoiMZzx>|ɕ.A^ Az0X>I PZ)2?fq])pWȘb=^+k +.g-MA]Ll-wiC8Y8`I|>F"%vXޛFWbqfxz(uKi +^ÚGEÛppg胍(;G#/W"QJ9jf5c'iLo.F{%S7kx+ɪ#0QotQ3gא[}*)Aŕdֱ{Z+PQ:[bݧ2g=ZIN#y`^N> ytk.ƪ|~GlvGxtPpO!@Y"`Rm *&'S2X]Q3|n;ߩ C-3]D&+g煇nMdrvDgmylխoU3:^\Ѷ0rd3?*;aR +x0ϒr1Y= +Tpk])3a{AFwL[j])hɛ,b.IHf}ZA,=:v̴ 5O_셴H8ZKƽ6>_+It)7)pL8׎+ b 7:T}ɴ#FA>OWxJݡ­*PBTWYwkJ#FLvF솽SVA$gyL7HpImH)|s5;᩾}eNאּA8Sɍu}BQF&iCcj2$Il0ۇlCA4^_:AC=iqN_neL+wh=Ga`~iAsB)!u#EA@k68D>Nɦk=@] 2:n?TCg,*eBG.ƎB&)DUyQ_d9Vs3©@pG6P>} N_ҙ5 + .hՑ}T1ȉ`'6TgW{W Q8o +ZRmp "›R"An{JTp wѭ;-e)b{OYdeVcί IJ QBRjoo^O3ƎQ:ӪlW7OlةE[iɀLgZ 'Aud9bGH?"i⚞~u"COR$S4X%qObvV-<^B{}JW=ka(ùQq> L)45s;ˈ<¢0FȌjӘٖ'jg/ASX5 +)ʁ͖Xk>a ku ud BDbL,Q4S|Cd\ȖU N-A)_C%LkS&2>B#"s1!@b2&ăSf1VM@W_'u0-#KoBv9tq7E)g͕ݪ1#QSO{0NSuUNgkCMjs11ha{օP +D{h&x?/f7̓nG*Zo-ސٗvwX)zN2 !'-A7x? &L:4^Ke&/dd5W3]@G#.HO@R{eDC e]S2Ehl>`7Ƹ/,/]JZnwx) } J j,lGZV5.iOLoCzoG<$ 5E}\Ը+;p5'U&K˒YrI;='Oo$ J +sy +g4W$/🶈<@#P 60" + +7%bĆ&9BAz!Uoj2*'ur{%H2!cFkD +;d/W])sRU@CMa IֳzuzX׺a`v6Al/K:1~"OHrD%Չ+}"'5bN/>MxI +:jeUOpޡ6.yWZ B5:3?*+322u~CPp;]ǟ_?G;/Σޮ?]{?~xivGm15f{2ͣóƯW*W{}|Iȏ$ۏgnwkY[2`ެoֽ2 i*=={Z~Yx[`{aP;[![zŲ=|Mo@zkz6Z :@okxi¸wѬj1oDI[3Zu*n}U kbXv̘Z]Vw>+CrFta=f!x\vE:9TC@%>FH-g{хsH]Tt3ACuNC + +$)DLgњa@#ސ`QH B 3u$9է0$Ci;VD6 +<$uCQr09G, 9v=`XwTgY&{v L ;1y&m #iE|4 2 &|$e/&IF4}-uy`rOcuXIc`qE 9g`fVu0 ̄|K`3 ybC4XH:8xAɴ_߅yR<ЗQ2EaBm`4=MB45sX(2z0HcBc1LT)K +:,#:@"Qa0Q(? HJ)aT]&1 ABR=6d7A6rn qҸT&b>0v*σAa;Rv4)/(|0fF3.;ͻ*B"_DݧN(f' *e\A)sqj()廾GoLC-t, &e6FZLjF1) ,%S{1QJrL-^1  jqS3 +huAFkŢ%j:G)` 4bCä2d09EmR#+\qp^yC<ڜ0p쥋Chbh9yjapg.OAh !bAI(^!&e:rEi*+<$~JǑ4 T^|!#hmLMCx|M:TAVSR Rln[Ţd~3 0HzYo e ,+kȏ0`UXGÍI&|Pu:F +EH{Jͧ{&(9t؍M(^"͐XgH3b!A5 KY8UQמR=Ӝ|YFkrV4Jy*xI+dAe93A# +l5"֙=uV7bTMj@hV`fvSZo䕕{?}G $ك~0w,SrXAaAL 0oi:+6Bx10U`.>aYp*r!xTWt*#r#AY˃A(g28ힰ'0Zn|#~>{-yav0C;7U#`0᥉Tyca!FIWd KQKMօ_8od0>|4(TALNSE?0[w[bDi +;#1l'ƍ;1qeWuA-1FcN1 }\KZPeZ;h-Y\Vjx7Cb458`UH:ϥ~u<]Ƀۼ@ G]΅MLsQA!M ߉beVrհCy +]>=6ԾPt +kR!<" x3\!dhq$൴հ k8;jڪj&%84uwq +f4]5 a.X^?hJ5GÆ2)Ewԩ0;9KS|j?70 }<Eϑt[&vpc} N֥]LwLչQs CF]@C!soio[H~`na}~_`!8e8Gu2SҷMοqC!`# +I .b7N` Ӣzmaȱܶb054^H-h +QB˭k$ +f,XclSUW$?4)8֎Ruw,]TϤJk|r.{_uXbX:-1ֆtù;{X;èH{^(wS"SjȈ3!8Mi7)7ͬI8JF?M:38eW.M>]'zd80]v W``:O[M16wi +@L_ +Yуc(E9iL,*,ʖb)hSt$yuyWU~!J3,FŮZ^!Oy8blbEFxųt&[f*55+[ "ƿE9}/DQ]}b&@QIͻ n?S`ac*؞pVa, +Iև`>'`%{m134?dF cN ^3-[}.&Meyb? c[ˑ[~W- ,W ނ +!-]h11}Gq#j6Cvszj6ca~z^ƋZ& bPȄ 2¿G3Pf}P=ƿaL̀e99"&\C,#r\p|:{4qLޚ:a +d0* V(X2BnFu +!J؉lPwʦ쑚/oa"Q? +_i ^1:fCpF_$gW0s,1ƗqZL-J<4M<RMC qgi<0(#Ϩpzf)) a; +ybbL&USc_K-3KMo$j_r11G.:^r#tW%1'72a= +{~m`W$1EK̕<=ʿ!/DcG>0틢ßP5dGD yԪ 6R [Wi=3P /b̀'hf(>T縫j@\=_  +(&@fbToXT0EC=9]YXR9OB^GT-DQdZ8 ND0Vy%r@Q_85-\'`Z ( ';ƕ)/% &L'C!۪U0Es; +8l'N(o濳igӺ5d?!EĦꋙe!(a%'0 aobU׭[\U A: KP3[*f*̜jh D|@2 MŽP5Ab\hgcIJ>+¡&] >u c`h@ab%ȄbR+|*=` `zNb`փa?N GIǠ-bܾٚzQYx3\b !2א{bx:]!!HN ;`u㈁옃ֵRKN9*! JvͿc -ܽ Q땆x" )a@<2j2^ul)e!b*-~lckb=}>›xzQzi/NbA"Ђ +MC[J5ũu.3bs}lPxK-01(y X ͆'ِ7:F!bnf,O(u_ 7 zJ(] &KmAdO!pM+-ϴ3vK=WxL95!WΘ&@Y_+TU~\d#Oxq2Bg|t +zE2|d`Hd_Bf CR ^dzĬ5 sq-O0Ou6!5 Ђj ÝAy1=>—qDoal_\t{YDIU}ߊɺ8 @dg3ro0hB0G*)f!pxHU^ $ATȬ,c]bPL rl1s>UW>гqaVI 3x'AHU3) O J|Ijݵ[aeFk)4+#} +YKWr +-T6BWuߧ} Q[`d( _ /myЄ&}L .c1,@wFD t C@xI}4b'%/`5}}9)1ɏʍ񦕄%Y1 'yesŷH11䉷q6IctznS"py_瘵Þ0}zɬ,95JkwVQ.Fݘ'Z30M[Er Ѫa0 eWs',zs[a,+׎g`4^^f)S">WԳkbPBcy;P}&*=ɛU? +e0L5IU"KDFU'/afIp9Ycbn<XJA 6b3 *FcxfFCOZ*v -^LxT^׍*։è*:0t*PfxPP +9{~3Pc,l},pXӺ1o^x5x,4#)Faұ{ƜnDQ=H oEFOJjHi ?X:M-Oa?EHk6FlNLX1 >´DؓXQdXV U3>Ql91WZ;:݁8et8EXX04дn Gʫ80)]1v Ưt~ʥkbm|o-5B={//@l8e"eJ<7 +Q|T(ו9+k7 " ݩ #ְSVriqЗ=0?~w~?ߎ_Guri{*+e[D)c0bq^B`9@W"K#qbh(Kpao l.;ロ-1s%ID(,*@#g%a-D +7gYʨX02d^YYsè5y<~+J+ Q;X73 '"{9S uwG,2g ,m>ܘƫ& .WaÙ +_!l<(ئK:pYd1Lm;96~_u0q|HJ20P:qɅb]$Υ4%#VϚɮNz: ZrmR1Eq :oވx׏I<:ogJcۂ$pN'*h/Xm8c%Fҭi~t cArD\[f a,!68[cOʾ.ɦ\gQWFM9ya"@M'diw~5k0x(ߔJ:S,yUJa0ù)f616nM["3;,mC543v9݊%o1)0IVN2!sÒޙdRrI;'=*leDG2D`3q׾2 +E7)^qQVl$V׏8xsu8:jϓ~{O8Ò[ Ay"}VQ|jO*5@usdqcʎ9*s| eqɥ FzrǮ3BcOF&11 8~%3 + +0H]O7*0 -?.%'[J`IQ>'fnRnlB&0y:+gKтSG9)*sǹH<!ϲ07fLR\>zCQ[ֿ.H(Ie2&ŵ0"ODI.w&=0Z"uaZ4Bd +[0TEW6PS kT]x`;}aF! 9UslN55(@V;'uNVaSNӏ^z1ag1LM%w.{$$C7>QXatԹxCFGنv%8x Ty{@d ++ {uԻ9#1X2q7s0/5D+E Ϣ]V=%LOw@dCʰJˀj:b$ v՘bNBMMKxv}vj8dȋ(b@s)}s4VT瀏ygMlrt[~:[?ztU*\H)V~rj53:56հVS3il7_1{EdoyLjrR\zLHM˶X$~o;zTYXW Z>X52v: (.{Y& $W5L|%0 mn(J$|RnmBNO[i@4J5"\53~`̆?DqRoF9σ_kM-߭2Cy=L1PIisX_(&YHړJO(`5{/;"LP_{3-]LK~`z"!\^i(9w.ru9]pB| }%EF7&5~\ pqIhG]Xb&2vj<@;/ZN>HΛ%⊃sB2?5ϡ|NZuc2e1s/Yr}WOVj{zfb7 JFc"RN% qSUj@CzA*_e9 endstream endobj 21 0 obj <>stream +HDݑe)-Xʂ~|ZKLLtW!R߶5}E<ǜsjbGHwf0?ձE06l07l\6;WZ.}7_W̱jq%LU͝O bHADVnkV]L$'$_$wrU^UmE|5|X Cfq?O߳g㕼W?kinjLcA0_LԊ 3+axhB^bfMF07EBnoyyj.q!ZkZׂMj> y!foqܼ)SU_47" %H0vbt+J*A'Rs*%Ȩ SQD 6ـoFﱮ.ŏ~mNs!Ra3?QZ_vFhb&TZn/ūIX~_XJNT[UavY %&5u! t/ߝCRHCu( I Bpu3AӔ@u] rMFC\߳JVH&n[ |S z)m3*$Դ(r1dg%G1bP!t oeՐ{s`) m70ǧ]Hë}T(&hf\}i8Dգ @ #nS`6mDc]KF).V04^/HI|RWJ 1=! nTDDe-^Bd<(97ƐފߣLMD +?Dk A#99xGQK `؅ ycYQw +IɽtfX0^& @絜؇]49n⼫[s7_ba`DI'd)s+.,0L ,a {8gdKOOZK0+8K` d@gS Y:0xU}!-31J0{R}9Ys4I$T%C!k $΄~!tPA-aA̦,fje'm0EsETY2[^Cn8*A,8E]~j +Cv]%>s0Wrgd+ESj2)WY]-+;吒cxt,gG+V jl0HYo>B./?ɘn||xBqr-!艺Ta0iI0-|trahC.Sұz;.tZW(.JsLa0  /im^ +DP'L of Gգ. U1=e!seh'VS]zΛE(UPaeG4ynK`ZE7I!7ADsƖ(*M[Ő>FD}>C}f #MZMQ @[Ԕt#DZ.PL|S{א8m pJEÊH8-Kbю:!{B6yzLV:8IU :"48 w\+ʥ`\},Qdz3ed "mM yi`%PD7l.|g +lr.ftK5/w&K;C>v\V@j6IX|o ;iF$ a>U`2B~YO{K.&j_DCclp0%ef|1kC8gH<Bq1ķ,aߠ#AӴVaaj]CA }L{"]/Tp/`x2 ZKYC4TeP1/t:Ydv;>kNZJe7p=#C\( Y8SVE~5ߢ|U!O`(V㞝%!1ؖS1=Ҍk CşOs|99 %RRJ)-`UæG|&鱁u9#dzb Px DOZO¢˕^v=|JWۘB33aFO8]zT!%vbaMwɊ&gz߰ LgFz^:wDiS&,-#,1~":0x4;t l9O#~yI;)Y򌒌دYҤd[2 c.4:NL56fF=7&fx-W07.̝SV0Nuw13`HCi>~M+Pq\ D]^'On6.WXoaƓUhju%/*`* m!o )IG`Fi^zZɐ~,\3 ϻ3E=sx,;\Œl}F| OA$͎1.u.#]6rOq-OؼҕY}a]{L\P +,lsH`FҊ(ތ c(7[ƾT +sJZˀqT®$/AE$rl0n1dy\u6q ';آTb)K%˖0*W<˦@0Bi +bl D4 '%`}la0+$ Ӣ"7oSP h @TwD彐 0'kwaQ`b0UpLt / s$(R[īOup{!DP/;; + + nSkaP ) q܅A:$ gWFqD|12X=vlxӝUd'T ~%Z.+B9#6d?,SjP` #b# 눳JĬ\j*f )x< Fw^L̍Fn~Hb9bM ++'ӓa:.MZ}ٌ;:jBtWG$!ô]j3θ= o)vy0-3xfg18nǼC^ԬBQJ0 @ydLX,!R#! eDˤ+W@;A fQK2-$6v'_]YE3AmJ11Y{Zzy]܎ʷ8ӟ2 +&)NS_Kk~0?|cO4:X2w$=1v#h[0Nz J5?tyŔ+j"Xgd4^=-$&ω25G0z_`Qg5{'9(II~LsG%&FN--wlL nȥZqs%7M4Q;QU<c0YKLWRq,0AFkYcE2l=(f\oړ( r?ʜ!9# ZXɯtFnwsyxzcu8b 13'bIaf0ka$4"q4zU%OXuzCPہ@\`٩ƥeG3K5*ƥ,k`L>}Ӑ&;6!ͧԭT-"g2wcHƘ%6֓& UZa=J{?JA[&ܾ~|L>ĎԽȰ9!#X][@$176o6$e,_1B+FU%uy(sAo JfbŒyZ;̦@<o[0ФC$o.6 IjM +*Rq*>W /<DBK sDlǽD f :d!R-&ȅq'J4(ՅQ$*EP&2DU Fdr[jdr, 1s?,HIŻ +UֵQ$~ϣ L +~[@24R%Bs8Uy,ٖxO&`NmKcmyWuaȊ:E1Q$iǷENr@0u4a3Zr1({fE y" +Y"hxZɁ=LMpM̘ 59>bAL:Q܎u.`FDDiD3r }CPS/Z[m`{&E- !)$ \s rhl; WYVF- y&F-0u4פ3Dezr/B9V\4@^Ȕ!1W3Տ]^R&KÜM A\6@(S,waLgks, N)O\&ZL o> "YxE4%Ls0‰qdB3Lh]åA+}(j +a|YmEka9kI$: r9$wF\+&Һ:rObӫ5ȴ)zc ~̨ѥ')XhX잡5J4 +|U_ -}xsAwLx]s6F?01jR=MQOa `O#~8.tv2mqS x7TCd +zýƯP#W:bAeGf*~/>陮:q,Kp

%{!pî_U{2\>͓Qź]PJP)u\7A -y-cw;wByX>DK( : CfhT?2ű[EYg+Vg~:&9J0HьmJVsF gWЈkB% F b9n۶YR|ĆRHc[ `zmD;}Jh*4xJ@se9y+LSFG'AIT}-LcZmUmw5"8!VyOǽI@0;}̸oGv|ԓu,syPumhC:v&޾ 3*&56D1? nn{=1OR-T;'<ǽnB3I<؊ROXg;T$m7|:-nk`,QΜC)Tk]+W g&슛h>=L?80U{aUa>o0D9>}/kdzev0eC APPŢP>~.++0Te'>=mHUBٲ +b({a蘊*c,b8:"=KôHĸX40>B!& +kQ7$޽0FZ0(!֫m̠TNhJv0JYHzbt`ZhƁ`fAB_}hC/9XȘ {GAB$|P:1ݷ 'ӚcE 6i6@ DN@-sI$)i2{ 9% FREy_\ `b[f@m/l$U|Pv]vƭbĘ[q'x6v-1> 7T# õ2ee,hZգkrQ+*iz0 V^'A01 Fļt8MyT!uk-l5B7{/Kž( ]ѷ~F\c(|[G6\wJHH +Nggش'[LzZǥ`f&)pu8=0#p~=R`zjfrj"0J1>[pYO~<G xI7ALv=,݂qdgcI%L&t2]VP ѷo%q4YkHf#–q'~WќsaZ=}cՖO-YRGtt3щ #ow![ M_|ЉUtUIs{Cx9+[펛Jzq!+3y{c)pRX8Fj}G_R(mDt{W0.q[Rm0{I'{|-vb𐨩Mt` &xXJi5c0O3XKr6}9Io>'P={yq >"F/ y!I3+B!17&E$+sλ1j?b{D̼k ފ(0)Ĭi0ULǻ@gRMWѢ<тpyc^V=;(?Aⴭ}֑ B&@Aߪ]uơiHS껬K +K(\{mgu\wn,TT7Ɣƛ=QZ0:;w$G CKxQۊ#0T.~ö~vґw Yh1z!RF>X 31>mc249$gaj &:*sG>:#ʒy*7Bs:\mXc>6L杂pR;151gѕh-Xkg62J BU9|ӧ-dqOҐs,DuL'&Қ4]|w,Vԝ1{g”DM>^ rR<=GXp- [ӓqޥOlD쯷٩qT4yæ0$x焗G4hzw0-.Kt1_I3`i & ?ckaFb}0LL Y ucDu91q' *#9 :F*3=?L&'\Fx+X$}pU׺J" zTL)+ҔT: +P-Iט^Q7. $w.0;B~C9EQ4ze+rH|1@+׼龈@9s4oă gq|6>wq-LE0rXӢG>[b "_nj0Lq^+bt * v +kcI؀q]hm, Hz12bƙCh^Ս7O83 > >,3oz*t3*Eʞ!!jkaN SΤ(6-d~Ӓ( )JQ`(p;:ERKGİ^k+qsoP7&Q2Ns0{-*tZ`T3뜻'Y*~׸=5ĎPS3Wl3_;F< !jn\Nv<)C Y3rm|O2G$ʚs A5&<k!\϶sE!,O|49cA w2f*J="wU* zJ@ɔň3L3&`2ukP1)jK=Kq0D qY'5vr`h4ƶDMt Ƌ8 'h0yF>p[u~pEH`MHYs/e4L-K} mBʌ7F_jbNNV¢hHM @h+ +qyZXbb0ΎlL=AϹ1#E'\Icݘ$!#gc &iѕ +ka؀ 2ZΜ-uƖݣia$iOXOg!D;lmA 8HᙕJ#V=>Gg$QFչ$D`@$31mc7 o 1*k˯X$Ɠ+SaEȐƌzϕo f 9a\>x5Shf錹p! 3+#kx_wqH&76YFĭU5$g2wcӈύ1KdM53úl߬~N;;+UTu5f≊}yuj í2K- +:0;+!7Z eR׷BI{ß&-'gù5q/4l ps]-cjPݘMNZδb`DUT>9Q9gI&zc+7sZ)Ujͦc GڀM&n'ȕI5,E% ?U[Yӓ`WxaQKw?qzvBHu>+SK2?u7.Ko\SG Ew I=GUc)S 2\P qÁܜ>!LGgYT Dvϱbi'؛sM +13lk^ю4WO0:k X{!V={aC'JB)$g~Ƽ1̱` =QB;V4R#*ǀQ8s,S\WdF}k2]Ex`"E\s{0jBe[Egxxabya60oHۿTvIr0!!;]af[WGsjS?|~H蟩2YLVxIxҢ,N]&;\1r0KN;]lӨV6$apD?4˝<8p=<\Y_C6wxOz$ m}5줍ZCaϽ~^awa>c<Ԥ{">ddx9|#>Fq\8e8'poD=1RBo\-$, *sr!j00FgıRJ_/8.B*h |/LS@ՙ)f W(_ ov^Nfp]4wFoWC)AqŖxr=\T8i-cyW-4t. USWkSnnٓМ %/$p Yt^Fۿtj7NRr,=a`41=܂i)91^ I[g҄Zl=CNH[5Lhb;U:'3f#;Kc`Mx]]uf2ousaB Өc8Ѧ͝de)k0g`^|y&TrLH`.6͓ŔY{/\EM{X繓\K:Qu)BUkN9Čۍ`8br=^z ,5w\b*UZ&g>զG(9:Yuns{@ΘUSb޺[Xfbj"9H84434w%uD1za`,ٷ +8R#695p X׷}@*wҧB4^=}#LoamiqDrɤ:6V_1vW#Ut0D 8 +njnY'ȎzgF>G^=6^6:T$4l̡f `fOG^w̓T # qm@g~1]-Y< d 5׷NZa`0(gNڊd1<"*8ĕ`pe}2}vM4\~7` G^@$_27颜m',qe~0eC}eϡ!xs"Ǣ> SP~.++0Te'>}HUBٲ +b(ka蘊*c,b8:"=KHqǸX40>m +kQ7$$,{/da`ɣX[ߘAeP7Zsa0{#ҁ9Z[hƁ`fAB_}h|C/9XȘ {GAB$|P:1ݷ 'ӚcE <6i6@ DN@-sI$)7թd&X!>9% FREy_\ `b[f@m/l$U5;W[OcboŝnB <3 P$ ˔ᗱ0i]=^QOCplu`Dw3ƹ0lʭ wKka{AX* DqfEsY7Onap9k+ !)S;=<;Ʀ%d<7X.{ɤu\ fFmr ^ 3 3A./ $]V8@LN-òRFI7rm G[ǃ0ψ/f0Ty;}-K`8YřXRɞ^~ +&c:c.+4T04E&BC[d yM5rW^T aK޸~UќsaZ=}c՞O(Ҭ!UF!9UO F#Ō(sEx%U'R"b!20@a*z}G?޹o-)O+15qL+^|bf.*8vbbN#apC-W B a1ef=fJ\!Q0%^C)ۛp"y/DpDJc!LAbf# 6<3>2.Í ggO*pּ;~bs FRm_C ȸL.FJs1]V1kD ^9o^Lw{JLgOJ ixi!xx;0*/<M]{_7?>COS?cNi8F'i,q`SVу7c)#NaAcuI?^sŐ0@MI[<֋'1g1J.;4C;1j`欄n6#k~F scM̊"s},Qa$5ybZlAt ģ/&OC\dDȱO*U!:gGTwhp>|Hʜ^ZCu}.7HI($S󕻚_Ieb];tUkl ǎ 4HU|W W` +I=: L+pfRσYͲAc>s<7iv1}:)SX).B]"aЮO/(OS"tESqZs$f4`JspX -t#H-@HK[1:m]e5Sqծ\=H3ɠIBrx֎<+_q]C{$|oc2abW*J^Qq@W1I4ˀ9yk0)K#V>%+(ٴeh& Gkjr4ͷM:鈁8"dž3c4 - +E `q; ,}bh oU8De{!CnԝВ~guLv(W>_d V)0;sa1ABGt` sLQ#V/CW3aGΎs @Ũ#0zzF68D#f,5*'Zi~#@("2gAW[Y4RTGxU1:,$LTSՈadF8:÷dbJYm`4Zby6Ũn9>'ť~,מ]9Evfc{+H~bx? \;-fQĐNlZYH 4 ]@%CL v%f ũ1MGp#f=8G*~gyEhFW10auYB1c;WG8+1}G0kRr;m$A*qe?El +⊙L6`xbE= &͎`Ob8 1CoE;B󎠌H3}Մ!b40r#1;VѸS?(@Q1h6:AȲ•OHNLRo)Kƃuyd423P"U>,FW:2Aߏ`=:,2;YntM @? Ƣ) md= |.<56[ ǰ ;}H̲J|-cp>̊%~OaB31.FM-J/wx׺ĆofbMUȶ!*=11X= Q1`ޡ祈'pagk vao.%0=cʀY^b +Sb|x3P:䆴.m;;#{!zsi' ȗz0uq\6捁bQaj8 ck}@ HZR/Zq FøeoTXƑ*Ɔ_˔HYLJ5qbmYH׍Yf2\jy:'P̖<3%B{PL;nƬIEPKe`)]V3F (r {&f:tWYX:jWW|O^pcύu82 +>)/-cAhRx (᭎ቑKtrm}? HҦ@GG kKϣC06<HJbl =tI=mĨv~ୢ,T ^7=@sdii;Vq+1\8$q06#40TX&j[b3:"CMa{L+l *g5j^Sӎacyg'/ CY+> K 20ʉY؉ 0D] ۨ((`v3{ttE`'@ig +q;X5~iMB; otbx;hIs&{6^)MZKK G3daU !u3&;`LX*J@tzS TUutL<1`\]$w?+ &RhrW&CADC#+yk` ;!d+ 2 (|0Kb "cww`*Y`]sV(Ksyg;XwߓWQu"-8P<8;cEݧ৑f|aB|T6W|r RM IET#--Mzz*DxFF=*1M s2w7ođ1v><!sc11@shG:8a|3^wgYLlߝMd79/^K}tДa.b}Ś54PeraN0f0ocE)iA+x:> |f H:_9=UT +fg';)pfPr-N2$ +5H~c&W\:3M~v a0VF*``0׬;XDݡ ǁ4ew%"V?0qS#_҃kܹ($séxh?KzsF~λ8.iֈw } [A2i;a1^lfI5 R=?ep_ꀐv0s%s`;;aXt /-j GwW k/1ܥ2HgJT"Hח^2<seyX.BJ 5PU#TM녂&5Ix.rZ?Ԁpr+ +Pk| +Pa(>LS??1¬LaxfY 4 %0MO^nf$XLdA_ cf"'w:[0Q'/.-3bap|^0;$fޯ&f 1sT@z݅90v6EuaSda0LEg'>I =:$ + b +(>G Y`VaG4-k _/pqm(\utZsAJ)^0ǘXuCby;+k.6 NLԗAu( !:Lnq.L<opS|) MIIcXQt0W4'ZMmu_qOEx@z.TLg)7HkbX3^>$Ԥ㢙B8φ1cV-O^Z!Q/3/~בJ)Xz1szlaSc#C|\a0=Y>_Ә5'w(F7hcbhLˆng A(ފA +=\҃1l1f0}4tga$(|B+ KdI= SCUQE0Eٰ0a$S cDY c*`#@;>ұ'fT -VªVE3FHña:`X6s-LIu0T ^W."[SLa͆ )BFN5?Ydu \̭AH6ň]nMɖ"]?' бo1H1 ّQ%3܄Vp4(HT,=")Eha xc3j[(@ BI|DʉR+8f[NXI W>$1heD~)gÕSuY5~1N7g05:c7ƒfKBV)+KHgYt*Į?#n &&d%Vx3]t~M%pR027_u2Gʇ!q <2m,zIVvg1:K^GøcrX0zL3mm|Q]IE,N2M0gޘ'J]\YT~!EjW_.gb$'6JS3NEEjM2 +cNJ„@ ~:{B+i%yZ˼6gc2.#MVKl;^Œ^tD탱d&h%ڭ/ +sԚ2I_ 6Ng*1]1!|>8oMVտ+b]7s8_0l,<ƪey21F'sי0x}6Li NOe2s0Z鱿*QĶ0l/Sأ`zDpЪOs:T30gtUQԹf?#8m yFPC*+gLl 42#LH ^>=g1=QeD`8~&nLr0%౾#'c T ]gzěn-;Bgi$+0|NQ9=ox,*`08L'c'fa, Sgc=lcI"X*P awFdv7#5ɒa(۵&n^5uPodXGeE[_$ߞ^W:T'&Ci~>4 +3 KgL{ A:p_@숾'U P߷I{z04osssdzQz|x4&Lq~şϯ7?s~,.j9+?ԜMsbzHZ00u-/4]5#t d\>dN`2 QKU8wQ|~ƆK#h6=~ + gajzmͮ}cg&X(_O*Q#6瞋Jgc)6]|vЕ=PQ†/L;`]'u;](剧IFm34#e üqDSW34)sO|9Ҙgܜ+) +ݟ瞺qsWymOQG&cC]pC8NxcQ+97w}8;B0Ӿ)R9Fڞ702%Jܿe`69H>͸xי'9%I7&y6њl̝pP\}z.F@{º>@Y+}|#8F3<=MGXw]$4d+6CP@ܼE1s p]ɳ&q"-NY[jE5I)fkp#B1X?<))`dcGMٳ :ǜ{[IE\mYDZ,kL3=s?C!=cA$.,+^<1WU>M{[mKٟJB㴑xJr,R }x^AV0\b BO_f.Jab]fmۀQv"1F*@QLی=,cz~Z$tigA:V'ぅ\N8C #;qBFCvoHI&u|F9M]T:RrC0>ar!'e.|S{;0 @\}¯mcu[""Ư<&t0GWUȐ[OǿcAW ͡/tEGwX=ijhR +Q;kW3)Sz+35_4#JԾ%%C?o\pXMS) +?zi;xCNǺsvK@AԲ#(H->aݢy>!TşhiDk ?cb{Jƒ"_̘u&gT7m}_mٚJW| kj?@Ig{ st1%>&QwRk)Z>P盭b}㯳dQ; 0:{|Y( d&Rׄ&وVL)L +ճFc"o> Z|rO\_2}&Ynyr FMg>oѕ>߹CpO0W\?0Y7лu֥?"%h] e|CM^s˩Tz6!|ĜPy¤$oאַ+nP˝gw"B\)f$ax>R%UB> %ێ`qV(̑R%ٙ!2&v90涮 +&PY;-fiUaU3(da{)db(îhc<Ǩ8ͦ"afu9gV2rK&&a]>B*1K{PM>$gy6Q8B~ƾɾ TvG 0Ǒ2XٚUt;1)S=[G8C4~CG rN(IN>jW* ϖx51[! ;kĘC|1x~kd-q¨ :tNLєzv /wy6zVafeR_UEk00N K1Q&qd( GN_%YV90Fv}colnwE/15=AufobSa]?uC7TjU\&1vcޙE$UN KðǺ4.7f R0pA kРkb({̗qȅ/oӠǸvoQ]*a*c9#Snۖn`Τ*5_$o8t5W:a3 4, e_ w8TqVRٛvEyH= 3ۈXe܇2XJ~߱+p-S4aQt{N2W,&w޵c[X7(r؎VPKu: yI׀׋T^[ oT-&9+=Ajּ)oYe_G0v$<>0bҕYbK|x&.cTw$j'e#0VV,8J9mYe 5R åP61gs7:"aINVZ-Tp暚/맦;f\wWHĠ%F@LrRA H{> !]$pVyt5>?#] zzv&T(aٮ4+07yx+'6W+ 3e΂+M:<-6z&TcUaH]fg@@`;*Rm~LZZSwa'f{X%^]5!jE,ja 術 ,<w +DU{Bd74,2:LLAh.Xe;_׸1qP\cωE{# ">)ÕOR߉^eoWq'ޟoi2n쓡 +#13!yo̻Qoh|!5cS)1g +;Nt8 \qf_s^rLo:ot+=ya߯[lk{TT s1'+^0AzQF}) 4ɠ9kaqy0 ~.(jS%VJ0+znTN{D s_+#QԴ ka=4e7/wѵjygkXݦW`{Dxc4?%4Bs<{M7"UQEaz&AbHN%K5Q +L;11D" kBdF14l%IE!&ޑXHXH 1 0҈g5ƔU͌85FdW;IojQ/Sy%j^γTY9;5nfsPSAK_ңKZY&IA6wy*Z $d]$ ,-Ŕ@8x /A9Μq[:J7ʺ;9*i]^tc֌n -j!LM*o3:y`q 'S(ҰÇo-7T=sٙ!âs<yh UM\/p?ŜP(bm].鋤|,R$>ٮ9!ӘwseqiZ~!1pxDRLLEgN`xnV(0 Qj 9jgspE\~&NXhV ,*f&4CX|X.B85Pi"|v<"l +ⓩ=$)גSx!zPj@xs +J1 Pa(.oʟfaV&Sz]6C~a18~``I bStdOnfF0`m,+OUZL`&&Y#DB5ZQ6@ߌV*{y d{u敆0``n I-;N*y{X5pa췕3 +l)GwGnhSJ0rY*J`TW斤}wI j5Ii1QiH[9ԡgob D7]bV@JWCw(kat Csh3:ɰu= ڙ!2b0LEMI.bl˦]nAXtj6Tfߐ<e( U U`M|԰Ch5M=@p6(Xuzr }̡bdA4{N;h6h@I1 D-r0z ̛xSiDIð(tt0CMb %F~hӅ>zf!8b8*T0Dn`Tg`Uh5b*QH& Lv!ԎK$f2F <`GkdXxJ*D7םXOc"vLh@72if1pJ~$L?N'8PtfMc% sIa3~1U) +t3'\itMW2躍LJC3;9 SC9c9Fz+$Hr R.tBMm !t1 -;D`kJ6i^CO%j KL=S*BLjc) ^F3TB8fL}Q(TZ p,(-dQ DJ+b6iH'!  +s`ExjCwdKLGAx _A`(2$H#"b5쑘!tXTcuBQ垇-~+S{R#4N< /DPCTF_qA7Lu0(ZˋuSSb wT@X_b*#H{^sdX rჀ:Gx[|Y{$q_OSY7|4Rbb'0$LSY sasxG@A%`<3D:RSKJt`fw@ܝbݷI] Hp[SwLmXϞcC50} /=4FD,`C`pK:pwS\8ϾŠ|$rE}w= 14*jLRkߏ?O?;|O~~~rzˮH%qbSqX]!(%3US `I73 '_3KkaJGwu 3,je"6쫩j<ZaYS~d~=%7S$IT$_ݧ(Kؒ/Rl\N_q0 +҃JDQz2S5}4]DכKY-z\E\G@Cli_=_:Gl\9 #A%89]]#ȯ0Ry ‚/NxI϶W,JOgaMwr3g>0s*^֒sbQ!!b,4)+Jram^h4P8 B)I UQ +"Mؕ }NL7[ ʻc6 ^H +FM8ckA9dyw˰BEP)MNۣ=6Ku ^v%)p`BMڒ2:8EDiiw6S0JpDhʡ)׻ (F 02AE]~Z>̚Kָ8./`D)&ѻu ]NFJR&p.6n d(혰DR}?3=*tlŶ]sd\Wj endstream endobj 22 0 obj <>stream +HLc7 #p@E$oǧڵ[i{gϜs,o\3V_L(U{1b"X$2Wxm֎5Ŭme¤uW|1wF)k[񕕵bd0sG{9j,Lj_ճj^. Uq{E^Lw[- m6A^̴ms݂tof׸G 2nd;6t̜/f{6 zo>N2` rfOb*wE}0aكܓ)Pk0.ATT*F8.#L׏&Ni?rjP_P)8;P; ^ޓN~m2FZתE&'hL:TynS0179{74FYS_Sgd]XS3_> ˧v/L _ǩ6Tk/f6?n26`=p{ ?:Ks0L&5O*8p043AzWŀ3 `)6CÜ*96ý[ck2%R:(tM]KH\߁ЉbP_Jε㐊R͕r)F)Q<1֔)j閯BHIHiJ"6ue(+,F ƫ?gu Y0lpT=B(LAHm H_Y9®iF>qq Fr78 Lpa~ !2>؈-a0AT#b ZV 1EN!W0g3sDHγRpK_3Ec/Hy>s8abtN08t*n i +o0XgI7q1vd20R,݋; bL2Uc| '$jK؇biKFԆU×$_H;Q>czbO%~lǽAɤҶ`3zZ_u@q*Vc1)L S&3)͠ +p.8{KR &TE}9H 1ot^+mѕOma7*ZWBI԰5\%&Ä-N\z֝?Zxb& ˹9@oK,7&I5\?kn T|7x.LNZ_Q'Iڗ%85(Ԙ 6sW gr}GɜY.~^N;_c-롨a܆\g<ڣC68{$R l!%5-;dLYaal}-^` )1?LBQRB曱]~Dl ܨoCg]9 0n3uueOfC$:*j/}Si(:(:}J܍¨Qo0#jR7a.J S"k|`% N0N1 #nFکWVo%We%+-繂Y2Ӈi .<ϲΊ5YܸNgۄ1=ܣW{M0FC{R5yםЖ{ExW´8厶޸(ajY}׷0z):6q֞QzHE`32?-(y_DUuX0/3u)sKnci\Ϊq9eIºޕAZ"CgMY,i% _+J1mό?R] | "0, 3})C.-oX;U[ھF@P( cB܇MI8_RRf ,>g>`MaBP;*17ajڠ`?uWcK뢣`LUvVFoKBztDŽ#WHTۂZcJ>$J8#@ ҅$aN\Q3|[+X, fZ =Y +0(ݹB lcTrʁXEJfXR /!MIaa;E0H\m YB+Gj[ūp%EW$.#ۧkC +S; -Ȇ{curI(0#oP0fYV,.mcTfHZ2HS݅wdoL:~2\[U`UL_/>D}aujx9eY7m%6\y?zCfV𒑐Dd ԛ8 IP"FAG|Iw#k^*}wo0$ MK>v_<0vE:[IrGSZhJEz!l[`<\x2# +2%J'/nd,l Zgg嚼ɥӤv7*018]`f +*Yf;^2+`2Ky\Vè_}$_;f_Ĉvo>Djzc2: #1h!^6u{6.^7r wH8X@\",j.o0XAMcb.X3+f,Ag{s>`( Ǝ##;qK3WԸ2- \xŷ|K sN0O.(9PUrEL7FLLF`J:=GK95'`YrXi}EvYIE۝ú/im޲tmCPg$Oף+Tc#lk +iruZ}6&c`z? a21 +\T:2}ZBI0f3==(_<)pv9&mCT񇡃I(q*JS;EIO0'=6DIw-W_߉7a8`FT6svCh y0='{z g\)Ru a5Gyfl0y2,O!G3EB\}CM(t!)A Iz״zY%ĩf.:Ap  +M~UYxVXaZj i(͔oYΖmo<08cU0.;wۏpxM#ifSU$YsHY`&Բ\o/OQ0Eo}vIY)Ӆ_uL^lTA[vKZ 4mo۵>1TB |YgT\ȇ7%ǿ4I 3a\#xјhм՗b# 9àϙ{Xiu1wJKbtu~K)&L֢+9=Oͥ. -W{$ųC*[H4jXDy#ͪ-Iif0q˔WSUsbQlguݓ|L<0D:LYrdddY*٫* ؊8sR- zK:ߜ^I @&5}5o:zNx\PܟwbJbS1* -Nq/j d`$=lJ(GlL!vDtiM{x,@X*lXorkFm׉j輭Oɉ[\"6KNjua`dQń#ƾ%rsa1dD,$2ᑭumz|#.b<#]e}Pi]ؼ#!-J=Si2;n凟?ӏҏ~O퓘[OVKD UJ4~|×<(cXN+K +Q-V5U?}#&rLl$w,gď -?Ldz'G^4Zo%ّ:]&}'l 昢R2/w`PaHi3ջƷ[ 3VZ''a&&"ev\#c]c+12f l0W_\`Qt,03OK$W ɉvjcD +[i-OI`eOE#9d&EII0F#IǐiJEɭ5LM2]+// f'D?pWm3-S.ycZ̖nrXv s$TlXxNG/ y8;aF֡2T}}V$5c؍j!+gP)@g [/= `rf/5HL!%ȳ |f g0 .KF( zr*Dy `I!1Yd yur6vmk{lW,*$lgMЛX0_gzM-!^ɤ/Փ=AƠ~X빼Z9z0OL || Q:9$)|ɼ?㍁F˅e7n^Q aXu>qM%]T}C.yNf~|:e2#K~j A4N߉ᑾN/֧階O hoD fR=Y:'<H1`d[/7?1#Q+QmO`!|>$jƇ |{t bC]H`lZV垅h0٢HCxՑu,ZߊXO(R&1l&HncU:NLm3dH׌9%q Ts%$F]f1&# @'=^.[ <`8{cD`Jzi-=dP)CdYqhk'kbcCκ*ZַVfېZBЄȂРL6\3Z'erQ<޼fzrFۆA!:&!Uc!a[lZB]1WvuR~`0t%ٍ#A݊V\LPIN iDy7eJ)1g%= 1h0-c_{J=%b-V7!fQ6G|hPΕL ﲮ eEWTլdg=ٵA$b<bWpM^AH;yM1qF?It-!ff2^~Z=7`%c0:߬/^A5,A+AGe Gt%:FLRQ=;Lmھsd_ a +-Qsd>_-"| -)*"DxdCzu)Eo +ue"d1q3x9rTvpL X&9,ML!}0o:k:Cv211Q[Jψ7:erCZSo+_d$o/)O9=% Ču9˜Ww1i)?.래u"9ƉgG-݃ӅuYYl^bo|8Z$ͽ<c}:19yލp+:\Ͷ&HI2@Iq'80R?GS1*~e*ҹCTzVA'FbKӬgz7^B#a%=NW!a'c@xKwxWݪu. doϛ _wՇ8L1p>1{Ϲ^Aboya`̫ȉ珷:GG~Pa蚁lĘ !Z4p$>ʱ FeWb_݂q[ooTم4Nmv>t}tAXs8[3sa4r=bŔe&7T=TDNK<cp<_lZ>ٟ 2ot+M*)%׾QuyK()h50c]B'Y;\͸֯W<jpB 7ي%)ƅkͺf[28~]9>r=&'KaMŶ7Kth \3z\'ƃ[r[ɜ _ ΆwS٦mfux(jbؼӰc/Kc:/*>lS J̲VCjS< +a=֚EZ^`Xgb_LPen7c; {?513[kӗQ 8rc ͨ&4eOfB`כϳd 2^"} +˶~lFa#jSxY'f\*̒{]|̠V= CxsJkBq7 +ުZ7҈oJ㯴8s2哛{{e)G}w8Nsmh퓛縶ф!7h='[jgpV1Ww=0[No)m8.JakjcﱖVPakQE?{ר0Z_+h~MGǙs7'İA )S{52fP9\Ƚٸie,RrDkE 0`sbVÐ/.Z,Һo9ޙ21…m(O /Zだc w6rnJ s|IɚM P{x|ƃx9ݷa +qM:laey<B:k CGCˆ0 "oƽ'ly/SA92{_kI2aO/.;3ꄩ8TJ_ 2J(Lێ0(_d5 2Kpigƈ":P4B]Ee q$'cs#UiƮE^68 +SNczS6Sa׷He\ +naLFv_$6iQa.Kag ٺ)l1?6"L. +XTuQ@+;pP <w #m1-~!Q^]d&N~3۠aJX,^+3s[~!=ܹ+ +y19a61ZJ91!XR /!˛¬ fz*Fb@>u8Raxǽz^B+"k~Sūp%EgW۫kS фob1 :?;ƾXVb27ξߤ}0Ey`zۨfu=K6;T{z#h=+xHHwb,Œx^C=őg?1_N$\hc6:j;H>c=)̡Bѿ2]}P1i g31+ʵc=P4e6QVZI]g0-%q(՟DQz F{K玌 +yF~Y^ uTXgR:Ph =H$`zj;?xFJ +%霌, MwnZ@-W[:RzT-u6}[veFjM (܃}kř|vqk Kܰә0jtxQ=uϑ.4oi1 YhkgJr]): a #{tcsF@;zb)I,CelBB}'N=;@aΗ\.J(vddħX qL2OTtqm9(2X]&7[E82=TN'L](2g2m{mUJNJ;{:y=IoJI @ϾL7I-fY'}{%m9n%wJW#d[lUVfkj\p.=GlrZ}kcB ǢsKkb!i^TDZl[L?Ǫi}mDކc8,wJ'@N񃐅IG\3Lca2 n Y#Nry3DumۺC&Gk[;!, +{bD"W>'#YR~?Ͽo|[?>7?l> Œ4c}r3i;{P)ӣXaʯ-a[z F*e\Nnޓ8ѐL׹NȢSwbfOp(I0HC2n ʮALx޽Ԇj>s|q=$ʹYe(FDTo=W"!qWǍу,QaZzPniVt4XuxE> CΠܐns'< GtߘK$IE*$ tq_<&(^Lj đZ+Ǹ#_֦ة4K>+^ACVZhP. ˳Sm>r .˾06Q[XF!OzxUFX Im8!%a\NcO~s!%r( q)-o=n5:wAI*yf( 81(M1IhU:>+ȗǦr_2>U={<{rfc"k?F\{ $BU1_#WY>-P +Vgד4^t6VӧyNB.imnDM'W['LyC*rc 93 FT9Oiܵt[iea$jnM u\1NJL"iw< ks8fu:apLgߵ/{=EZ &ĉZ#jɓ"ub"ijZ'F$҄k~3uKQ/LZQ P# uވX0gy]bÝ0jo<px0̩٦o(gX,&:gյRq#(=1*@=b _9jl +"OA(h +T($/ic+\qٟu)[BD.*6_imvkQ(>{{Q +|IȣϟChRz*~m:ON`bTklA{pU->Xgi-&_ykޢp8"c̎p)oٯLVS:<ԙQ +B=(YHvaoAuM<60i흈RAoNֵ[ Jƭ=3ܾc[f|&]q>; >>0|ʛzx?K:aO_}*Fe2$.|'Kj:?=&QSZ$Xo!)VƐJ 鞈)Y$zz, c5T0ƥTnZ"dRXcyZ\2%@X71΄(( k/$f:MVH: :6;}`z? +x'g`gJh^i%t7b}0{Yi8丷`<)_CsY|I.}9L$c=O/W CKΈ;,:}ڦ)"eFȽ#]gٕ@@%cWA1wT~gz7y\O`B~ٳf.Nv(\5-#bּ8KFA1\v94wG%D ސ1zǾamOW0ʉ~q { kk. u EV?[T όbGc#wz)oPxS o$FK)N &K&E+Z}D{2S[_2GB0WQtcwab4i0"EL5覡|~NCV9F鯑j~g7!wv$+\` 6s.(k<ƅ_c􂚱;ns;,;:BE̵0w3cq41l˕^DYU5;%V^;tF]  oNM,!u#K=_{a#xO9y`">=Tc1~%f`U_1Kɕ6*k׳ZQ$h\ =oυ&7Xvsas)eEe+Džї|{_[\!YȌ?ŝ>`.CŽ8JKCS->h[p_C"A5/ 3Kp01 E;Y iéas -'M]4hxLbgFT\ +hS?´"22wAuT%!76-7\LiBr`|9r\}`ݾeLT{BĸY2~FQX+j^ XVH7"Y'~w_/l_T_laZ,L|OG< oczl^k(!93u:!q:9gQ+h}}y ̸|wY8ogcyd5;YuXδ~FaBUFW0W M.  \߳XLjj%ҘQW=~υ%e\NZS +cl#Pqm R&jd +M呚a懹Bg0ϑOe+̋;0d%s,qVKQҞY1 +_Sl'ama~J?1\q:QC7>L}`T;XeN8sЕNé Qj ǘOy¤" <佶F!h a, y.l֌1,x$r*^a8HS>uW)5濿8%Ų;g$h({υ$;ث_>k;fgD;GzXCG}TUf<##'`#j;8;FḴd␬vY|iZeokfO]qJI B*8n-BG7Rs:t1DiǻN%,@ݱn0M}(0eϗN`8WhYXf ėrD#חI>O?ً +TDezVnoQt5\gd)oeFhK^!;]eGLab`rmH™H%qJfUҝ%f[? 5z){{A%Duo3.߸GۇтY0_n?m>096scD9\ E9 ;-E-2M}ěr' +rbo3?[}SOV"r2 +{& u8퉫PeTqut;ZXOg<7ߘڬsLH5R}ejp*Yȼ^lDuglom'Ru{f^}1Xu7(XL}{z[ +5Y=U3{|!X~?XvPQcRK c8"t᜞յdcNndTVK[ y!% ;>όgu$|1<[GfFHXc E+ >6:whԃh`Ha_ ",wΤM_ݳFG7r(kg.9~М)Wrp7/ƃff yJ> ct1S {`azI$/F=_ꙶH<p++]Wwl/۩@:Z-DgޡCPaB")&B\8cD}֚Hg5 @E>@ Q↉/y+*& ;_{K{YAJ8ڮg#=՜؋F_t9{AX;9 'θuąJcEh5=)~ +X!C&: +v+KE ԕqJ]-*['d^Ӯ0ڴMxxgPLxS$50u3M CQ,zai&-9רqHLp.Fozh}ۏq)ka~<|=*K ύq~}Dzqa6/9xc x>艼U(^1"}ܐ ` *n(@k@4ba]8k28z=*OĢ;g-Mڼލ8XsCd`A'*M!F.uPLuv +T'1EBdupQb2Qq$JobsQm/@ +3CL0t`ˎ ;| +!gi0(IS,:LK)G`;Y$1^+~yt)sH~¼4-?Љ ) k鑊I ۜFŠv/05ֱf668 iC鐳r#Oi6m*:yl-U("CBc;WbO35z}!=9 OjMv3h4`_ҥ~Zf38O`[U +U̮\DQ<~U! MƲ&^Td?@4~OXBTxU`פjZr/IaB፧$iEFƃacJl阅wσW$n=֔/``oYit}#LLӢg}i}ECYx_4/q"Qnj=4p2XkjC|34Js,% :ρ/x g/ʆb:w1Nq)F3"o2ΌӃRP +xlddQʬ/YK*ϵ@-&6&PZ KJ4/Fꃢg +~N t6MP*@~]96$fu6\}Bsq0l2nX mX~NÕa RF0L MZNl1<; V'pP{2= +FFM4mo7KELbuƲ*}3Dɵ1yi\uiGO .gL)ď%$I4scS6d`f؂Їrirdy,3Bň_wT>3jV%V^;tFnLWi 7&zH"Ϻ%ՖW6tnUjS7 &csKu`#ïDBW+f)ZZWvzvK+{"4ƕ1DJS`˟Ю6f>gRf\l1ҿ8^6pzH 2#ϡtq'cQ l1(v5 (/ M +ԯ>:n]Hl̽3P\PgMOw0̷ch9nzŒFS1-Ɋ)hDť6nLM!"351 +M!JBd3o0l+Zn{c2 =-Gp}Qwn-ezM?.'͒qF3jl26M?`ظ9pbY-#gc[YMOz Qu[a'0y6&>[gG< `z½QC's0gṍu:!q:9gQ+}}y qVp_:'jɞ+jvw:7fi 47x`l#-N0t[:7j욅}wŘ{a\~bϷWodL>U +kC'.bZY0!TA#\qjPT0oȁ㢬 +V ^\1452[p}b25J1+$ K4ʸ4ZS +cl#P_`X52iĠBge]=v`$n JX8VKQҞ٣1 +_S%$]O{~bbt67>>0 ,2 +R69@'ԍfcLkcR S]LkqLޫ{Pimaȳwaga1#SJ9Jƌ70C=zM1؋I6[hc|f}}\e1))]9#DCyo &i^kۘ=Nbr?EuZe6uCȒ<^w11.1^CG_m%̗VU&6SW\GRGκe_XjN?CSH=xTB? ԌMvaoC$Œ>_:?B#ĒVh # +9mLcXLZ~żA+{T_ua/daZ/78vƲspU[{q?DK +jc,;sCg}+If8RB:WiofvӂZ!דgqbw>TzWφ#xdLQA[r^^6c8Y)ta̰08/pU|WJwΗno]r~jSoxkn"&K { %N3.߸%hA?l0_n?ҭ>`axv&rsyf^<~H+7|s[iRL?$6?b9G3>H*FA"}2rfGlY<5(Hxka8Y) 30!Ä}|S#eUA$Y$U>çcǫ] yawQ/]-zM5==(VI{S>N`4YC2aN~+ΐ>Ͻޅdl>?],x9_ďg1ֶ9sc Djp;s +z8|ƳxqӴ+o޸&xL沞hȀ F'5>(>`xim2_#N\$VNuDŞ+ >4G#52Uz;&d㊂J8vec#zkKY/:-Wg<7_keutgO5Rudjfy9oڔrQ'jMf߄:0Y#Pg0ޖЭ&s싆 ĈM DAMv MQK#R͠ lU<޹e`c}v*;JǤ|y  qD*9-yPg<&&Ŋ%Œ^GR=h}u["3sIGݰCjJ Ki"Z%ŒT/[T03@SQoϤ[28z5#1=w.u|2jM:#_Rߘ$}b |W̿Va !Y s-=r"maGPK AM gi\:aƸv: 6A[3/ ˮ{bTw'Fhwy{B%=PaKmF>CA? ; 0g:3 5%XEx L`y($A=Fҗsa&`bR{@0fGeL:N{bC̱{Dy'^u ൐7cL 7E:nLLCU_L`ұ:֑lszL%Q·®0$P! /iŦ~@*J0#0VZC a83̰ +\/3I# +9(A ?2SԒ+тE-V!&cANa+/ؐFU?GU]ūQvY[qeKoa'1F0#Ŵc`?Chus X RVWFra~zf鄳1*ԠmuBìGʩqPIFf]iNj y0Tޫ˩z%LzxN n? Br- gyӴ׶DӐ̙Cb̑d`Nj)n]ԓ6-sF3l,SHƴ['UuVΐuLw#!-uǷk0UfA\\G=$^^vٌ Q#u<>i_DH㭠aϏZ w-v8FNp ;CsI!T_$\gGxiO(jxRm9!:װW9:=9I2奞V"A0/h_I{!zꘖat6D^`fVs9)k$ +W$u\p*Wvg-\E'co|1\^ӿ(֮61<8:T333T{/ +qB}1fDz"7Fm|lj +$22~Gj0)8̑P^E,ݱ̩Ҥ={#k柉 gJ# +سR0=޹h0 ߅;!S05EZg6\8Rg}ə獎7HR4fr.նx +CZ n7qcxk)\k~<<ݶuNފya+&[ĉTck#C `+A D;#z  e yL"}aj&+u>:+5׻60*-_2=A:̈́[8'"3niSR`%bf|0nhd=#:?>yn[ Qҋ ++A-:̟2sսb<j\>Kj Hb˄m $ah%6O|,`6ambF;ɘϡ)<RX{MڵIf i&/R-sx LoWclΑ޺1~-KORJDŽ`@cO1KcYǧ~gʾ_У+>h~' c(!+]gM MI7h {E'DD؈yu' {.%y4,0=IxŃ=E cK+3#/A&'Co6bZ{̒˞5\FDzXyJHtV4švW {'f1P)_aSхټLoz"R Cxo1 4r;7GX_m:t2p TIGmE$ U`]E y=J9ЪOy0Xf7ЂVOaǴ`xHV] ѽ:O8!wQklѹcרG>wLnv={ +oB~G]*c[ܝIhyE G7sTJar#,jvx%D){RhxFn$Ĥ-5'UV8RNB}5M>!j1]0)A 9V{aZ-ugez`0/ &R@2yM a{ X:~,W%hbd &ybUO;3rP [ȚzbrTNQOdUM`=bD +:2걹% l@I +hKx?tQM=; Q3vcΧkmVf>2sv5ny%6ų/q»;E4Plik1h?ύ1~{֧2u>BTFm}3Zsu:O 5?Lv;YV0Ϊ[ғI$(L =nmM?Mk`|ܛ +Ĩ)sV짏Z̝{= +j|KS|@Ju&GD-om-;A-wQZ|[4;3 *chLh=C&ڷ $$:>ِ5lġ_6ٵ+k`ʱ3Y=ʕ(x{0b׻ǔ$ we܅cQ7 +>ރ0Y;fć!ԙ`̹, @. NZ4X%BǞc3JdƲ1bA7!J~<+'܇zJ@5` }J;aTˆϊFIQ@6`ƕlHq< R| w͍#̕1YOdF/m31^7&D7RE ;clSrm20-buknI ){O +X{`Mo*f~(j&.H K;[Duwhb䖍16/<Y`%F8mN< D5y~= )ď;x?SUgM;G[1 Dj¼1BL2zGR1ad(2L2x{V>+:ƴ+$0(qqı-T»E 3$Px[0L[?r0}R|V|Bi+o D&ce)ƠMڬ"o26bMdtDŽ-I |MR-, VMf}$-#o cRތU- WzSiq qٸQx[/#0,8Y; 1lSffcѸw]]X"cctm6̻l|l +lL[a辯Fc}p~F% ]Zύ dQ<0X%}a +*$RbA a|{&OqOۘd{>x+ &j+37(zWE<6*_W +E쏜RFXkAJ${ 0v3C$#= +-նզFHT{,ZQ fk: ' ~}淞4muº8(UFɠyh-R0}Ey.C*$jWv0l9<7i 1y7L$)%ٮoL^S'j0)ƷƄ|_IJ0FV>`//̝'1᧐$;E>e.&ouELz: ?sąښyIK"9%Z^k-f kˣِju,&kŸsdYՇ^B#wU\UBDy\3D$[7&#žːs'\OGc.2h19&-6/ğWA߲b2=lx./)['@^ʻU=d: ^GV1kQ#n`ؐ4S$ +gKdzrz>gp^Qao +:eU?繎 A^Ukg}Qo !WE?DfĖҥI_'ƲX1k ߺp`_~nwZLNtw\Q=#Ѯ?XP,smXzTWwզo=+ƔnX=zR:)@Lm'LGo[O`9 endstream endobj 23 0 obj <>stream +HD۵e'#89zӟ~ݫkJlQ>/20su19m:=n0Z2sV8bVV7l9*ﬖŜ5Yw/3w;3„6^/DHdp*qqP\HwnAf5cwLG) Ԫ bVE(),&i9-rƼV.bUcbaxu1` j1OU0R\Rv-O\vM0F$%#ofoAja:r{ ;zub,.@HQe{DY afwQE(,TR 銹=>ؤ60 Q\̞Q<'&0zPXJOQNB -dS)' TfBZ0t19܉SpRb*WaI*f]vxyb6]9~ؿA<$MG &\~tHbҐ<*gHb5)x>1S@d@ "\>/H sa3,dS}圃' +11ҼC XN/ǾeDc\BC׊p TrΉ{`ѩ%L1wHBGl17C +aHOŬsΠlʛ=Lcޘo ރ'a3a.q##q\~)|-Q b&c>V6ޛƫ EaăR/PT-Jɧ=h$$. ~Q%ل&L&NlEѿE8Tօ9ME(a#Da(6 +2q0#æIl~>sUQ;c[rTFE[X= C0~ h0N \>bwhCZ"(&1 %E?rG|o4$ iÔSJQ18xok.=ĥ1Dq̍ &s qa|9yq|W&Y5q9T$opOh<,2>NQIڇas a1wܖV6]?LB %^UJ=U!h3cIӯw9Q5ص(Y"q،4b3L] +9S<3mKm_'3\F6bLV=kt)Gu9HdAb9F{xks`nt:iD8֙ڲ!3>J-~],(GYzs8V8aIwJ)ra}h`Ȗ܅.3?`DlSc+VːWIaLEr6&1d%T^j`UǽӞvW0N4z 1Ug bd&7TL9UW15h‰|k8HM F)I`Y`!T|?F ;fv@% +w1j@0 x=zx40_Y-"°`a#Ab_}aR<$!DZ]9b1 ȵȎJ'e |?lC5 +M&A=5sd\xj0=#h"4{? ͇A!]8}T\O>zAj0gtK sC?K`ĿF9̻η`Jƪ&5~Uy3ń`B3EY{DEn;R~D0:'9[~kƨa,[H1N>"IaZ)ՄG[ofhFD9n-Rk[SL`kbE\)vmX:iU7KvJ]gDqt79Cey€P޼Ynywzn/ơ(dQ(b +%qU6m^^׬1p ǘˀar]@HIfǘPaR-* V|A@IywN0I<:l,f&n̝,=# qK+c,W7&q:Ǚw1lOr퉶8xIэ].0 &qOw5 E\nIDz^u1/C[>9;CtufdFH4SO@°-F9i^=Ls00-ĨCkRs ۏXQdbf@ s$iU]X5bX'$Z +3ŷW;B:;)uM >2gF5+ԞG-׋Ajgou.Ln *Of9"%!`8l}s33]F&Ӧp.,JN uZϚ{'"`0-]8Sfu MCeI㮮jR:ILњ2j`ݐB [q<1<$R){uKq"B5&T:g&"Ø5*EĶ$S aZf{ +oB~G]*ѱPKF 6G푾ar4ـۘ ZFj[q(ecbG:ǫ\xҏG +I`:D-F3!:-~0yU-ذLk %D +Hz0Ē^64\9_ H|'Z:^"J@L*Ū;+LAnE"k>Q9E>ߑU56suĈI[S[͍ .3yFp9w\t'|Ĝw&W?bی:ͼe$ e,Jl(gr kmwy@ Ι4O}=7X[%iDZB!*#F:rtim_]a w]BMN$e E3tg ']CϺ[zj:{]1ӥ0OJcs+MA{)*_{r3v:L&,a23+>q<g "Jo&yt׃Ce!X g}C&&ZT|y/TS`PxJo#cic&ƋcGgQʕ(sLa45V'M!iw!*$ +6oA }͈cCӽsYwt1f[jbZsJ{ QJ 33 b TOs\O>Sx6D?`.o9[] }6HxLHyZybhc 8W0Os$I[C/ Ax$='xy&nag1ӑ쥦„q04V6m\CBXZt>OL/u17$]Ez̹Z0m.|SǕ@3j }8vA]FTᎧ"=.X̙ܲ0ŘG p" 죤Elu%cZ9rB>K+y~i`ǝ$z'#|adՉ1£IE}aeׅ9}k``~m<`=י[&ID#'}|g1"nfY(E5Efk>)L6UQ2ua&m"߃˳ #3&3{x/K<¸bS}+[72_YrUl}KTY Kw1;NĨDB4T¼iX4n{'H0^m֪ + sW:#q1 +>JNژ .œy Q+& * L .<;Ih-u1f\{'2Lgp^a樰7`X2=h{ir\7uԉ0g +\q+smgpP_~LtbDh i*%IILE;25mCAk̚eOEMocᷭ=DS`(:crʹU=s) IKDR8?y#?qWqV#>xc'˳MBiԴq3D3Q {d/3q sDUY^B/{^×}HXKC~oEN1X^/签_1h;KBx5u}?{'i{ h=IJm<8Y}_VhrG^Tih{^~yzs4\ SehK!>UJuyٙu}%? Gӣ4Ll,&gcғxP&@;a~o3PAQ1H\WS0yYb24vL"ATia +֑{U~؉@˼2\@l;ic#u i&H?1:Wk L\pEw gwZw\v<c?l,}1bUrq_) m<ܷ <*:$ {i싩Mߘ>U\d4G&w'x)Mƶ+cRɑ{ D\ޅAW2#]CD6XzywZL f$Taߘw0$'$E'~SǸqҟLgW01e,Ŏ037LWX*jy9QypQw9lC%h|kaXW1r0і CPGR~۬.`*xF}fh  +H\GmՉLW]+2jX4o<((wjQ%*[}p QsoY@zk{Js~9ż91f + g$N{F{rMLX'{cHL.TBozm?Chr𔇠'wa~` 2co/ُ=n+-K?Vˆ&JeCٚVqmוmV1 +9KkOΡ(:Jc7hۯħXHuO(oSV^Ox:~vrڠe@dӗ]!R#syN?L/Yu'?uYRYM8?pxSZ'?dŗwȍkN+ +w"lhķw"2KE Mw2" X@Ї>V?mnxiqut)qu^ϧn.kJ &WylyH$g0g Q=/{a`ν[ϳ?DQ[`NIkz !Q'jNѤ% >TGQt8RdY+'ȯA߃a:T>e1jsT ~Hx0c4Ěfف`֣Ԟ9mpa& CcMD>|$(.j|;lw~=kZ?[sGh1pAGN( +2acL1 6\Lk6q0S@{-K@M1(:x>~QPc(s!τdxyqJI ˝NY'0$`JT?==p]3[n;qtq\]ܞ(_p=1'ɜ3 _vRaHpbD$i'0QxA~S +_Ĭ0Zu/,~, }f4"7;CiX + &S˗jyBh| 05W,[=sۂ˨CAO@;QQc c8:ׄ`+T?Z1ײ.S"7&9͒i Zu~0+3dޔ+nAV 06DWYboB1Dds++fڍQ +'ˍYa] 3YFXܿ'-;O{:vd6 `+5~[N"Ǯɱz~տ??/~?¯~//fY.e[~ ok9/Q6*AO!:Lx%ƄE)>{瘌jRTHs#aoXtL+#M/L%|uOeBD&/sXFG'Yƞ`>d}rH +OCm'w͙Ǽ`\&SBz\n?FZzy/7W}jr61%.a_kks^9C?ʇ1"g|ך||ۗ?~b4>"bOi&rr^e`ɆV/RP"ʳ 5꿍WsXg$c9b<&Ffc=OSB5qWĜi'qz[;7d٢kX.q1Li*(a3T?u? z0{ wq>'D>je6V;n; AyRnA7Yq`VEp5v%J UU&1`92 eޘ4)et<( +[7e'٥cW(\g+-TlEO($&"e4dV{֕x}u M%,Y@T>c=b U7]S {FEj R`غ$in<V˟3e%rӯߚHs17CG\XQ[2ꃱWB}렃 X0(fYR n2]ej#a5k,j'}BFgo Ѡzj>v?Z]o#"u6[^FcpGYPE4or~Wn־`ҹn4Tc6h<\Nje/ra>ca_l&]5ܲݫ\X'O/So U65rKD 4l΀\_iuPXM3ǎg,}Qga6SQόl$a{=o` wa>TlmL9ڍ@q 8Ѵ$LfHal1Tod,cr@G -J3( OZs˂8o `!=lJxkh":Xp!jfTYƘ'8 d4&k`n(?QM4gd7ߘ45 +6d{ӆ  IѮtC$*Id%ŏdqT΀]q=Iki똌vl'#k Wn>1ۺaeh0"vTĠj!"@ӧ&ao(t UFv=R~cөa4s0h(h<[8sVu93sV&=rG#:$i'-T*`07uNE9YfF.l s9&|ꨢ{5k#acL~Uy%1F%ޘLJw;n#f@8gᐾܤWӡ& +:H؟?{43\{e.vֿ #~T#<Ħ0Mh@oF +'JQNX 1E91CNq+ׅPs4ى#\j|?NN)ig! EoT[(~摖{l(9 kOd d_7R#LMmGN&ԉwĪ ._VQb_/NogFݩSzs. @vƂafUr >i$l#KRшChM*D&3ҵd_ 픑Oߣ<gtq.Vk%6\#f*{^E.R8mi˞KEkOii99k#%V:C(!٘5]׵.+gL_=j"e&KqMȜoVd$)t1,'Nn^vZfaVQaqA +%q| P\iy?(BhO!U*W|rV6Zt,c.]Ņjl/@"kG[q7&Ԧ?[uF;??-(#(pŪqM=׻H)mޞ}=X@Ae5לpY +=ڜ*f^2rw&YaFM{#^H_.jLޚW;K[Ns>kVވ)Dua8cM{Tb>#⌢pWL*mw m0Y}K&+5 䨁oZISCsiT`7B+e=+Ucwf4ܑH&5X<ڌ|npChFM6 +z49lYҽIyYjhb|a)2Tl\--:*WR%㛷8߬lAڒmD3KbOx*\E'^7޸(65:ofbWt'qi!.Ba5H2լJB̘(Ǭ\/nndwr}pݻqjZcnBV$rZ"?..w j^Y*y?Gf#2*Ov8kB].,&>b2T䂛Xg{R `Aݬ\WS,Q쳎<]bĄYZbp)]?ҕnyW}Y% +7:fKJ/I`&{:v<#9T&ܯ[R-ˎ=k.X-:u +ndN΍y6kӬIS'Pm_g C-,t$G&Gרop,BǬ\Q +o0jbs0Y^wi㔍;ҶUaI{~Wr% &꾶?G_ܹ.l~SWEYS+%g@k72 qf_b|$pQ 9tt`BW3z a0g8:+X¶;J~OA{vSz9)L@X}0%O-gi͎6}VcR~3mm6淽oRZF:ϬiKB9bj30W +"S =@kc]˱hcş2P.qqX~m2( t#bf61A,-r*:\\1 ڑ+rNykZ͚ *~&K8 sn9J^۾ç i|eDMos?T&jub Ù'Yp<\Q钟 J3B,79W\!IW[\phpBwrlRUle=x~4fI?\b0s3[^kgƥoO0êL"2rk .s)).f)PAmGgFl޸'HlUУQf{*5HBX1gK\ ;ʠ{0Vy6tV@J/7׬y\+ti_hRDMk PzOxϼf5~I gsvDr,a\MwEBiJ̚Oh8F b qh@Lt.@<(aGB.:|Y PgƩ@>j; CҊj> #հt45f +Xtpg=5R:/<h= a[GǗ%4W|.Q #lQbKBue"H%oͯI+5PZiF m5Vj\_/IxrTQ鵻KGA"A! }~85d{_}=&9LCiiYϡHY#8Y,C"zeY'ɂftQi Nu[4F5:l%9k +eo⨨p{pT @q]f% +nv"@Ԅ=*_vo&r[x5SM"ծpK moߓ1lVL:\5=p?y?4CFbLZin R3!YCp=_O5#6nNw%u;xƈ/[5;LOnщZ]#➅"^,R\,Jkac$sՅ;sC)0V/x^0>glu z=k܇spڑf&,D<Lh@2J($"{i*byu +!hs+G]-S8=[h2aq;k֒x5#4@uEN?]5Z!L3c7&`W8 L75Ĉ+g=(&4 %=cH|)kNTٍRkaO=qL37gru织W{R㈡3v SEfR̐RfW Z|LL% +\+4s]:ʵR Sa8h ѧ&K6N9o Vɦ{ +'Ơ{IdA&YEbhf}!G蓜P=Խh.n4;Zb]◁g?DqFt$]n9 ?^0L68wMgvEA1!Kh׾kķ?OR9Ԥa^䎒֙$k9D ){LwVێ;kozXއe-a;U3ԛ=DT]@` 11MGI"AiXlCk}kDT Uj\'9|O1vCPjs #o+ꤑn|@Y+9j?"ubvk5a+$i +ml#Jl"}U H D8=*)# @,xUԤ0 H6cSW5-f1nLDr/rw٠̖#X~L3!/0>E@[݋TH]ѵK(eSVSFm$-$` $skfr:|v&*P]`2?o #8,USuK<4rcl~dCYzr3yrF@0d艽&< dI6QܪzWf?ĥ+~Q85}%7y|^5jlN"$(s\(1}ᅭV-'% "}aHL oϧ#fެŞ?RpdgK;ٔ} +8twpVƵdw2S&=GmVW =S05iWueXsI4ߘ͔h(0jGaXy,/}J쯝t +5f&C{7\K|cOM>(F̠I\#!Z(wjxL/xc1L2dan+RNvM]!c`m]a߉ h?bQXiv)dgS +xq/4tOOSs/zi;I35A[GV ٌҔh@5ҧ_I1[""hƵkrq=#~J hghs#Z5.ayA'v-UjS#B|`Nf (!ΐUPLEXKU"_C;!09U?w<>IԸΠC-1{0]=K %6 CCJٙ3c%ڮДMيo y)Qc0 Sbt$C׮ n{$e:VlǴ8 + xB0@6^9k7?ˏ?o?;?|;?V>??^&+B1 1%yV`WA4Dkq2k./:dlH+ϵ0BcWjhTޝu֌nhlgy'yQ"SCɺ}5 ϮI|DyhKHHq0•+=ٌ& n M9lC y)[tE)9-LIXw߻X|'15$^ڻ XZR3aIlf芩 +|lmYX>ܬ5RS%TP275uңםIdog-KChQw|olJڂ(B/q &?:tXN K6K7of8X`fz\tx-zYia~`e:&XXkf`6t<"ް&a7sgEVvJSgTqw6ϭ%%*PZ5oKT"e~Nq2j6]&%Jt Yn@J`Bcs.E=1w5J ڌ]#p'FJcX%+;@p%{{5vG5"3NVu1GM;fjhI:y_r$۔d V,{--[Gjy$\7`˴2?[ɇx-1Otƞjm< +e +[5my P=!*.u \R2Xl7ON26&@dthU @qw!}IC-M|5^uԑX0Ls]Y60*:/3` Ma Hf4cyIWH*L$*{T,1M;•ta{A+T<3mu-ƪf)( +讉rcީ.Q_NWtuRO1M > q^(y"l(ο\H=6'Hwiw1/}EHQb05:P'%&ݫk~[F|4;kϢ>S$3s#D]:+lq(4/+[}L+)5<IZ_FnЖ㳚M7*D&3ҵd__ 픑O?溬gtq.Vk%6#3=p&s7)gδeOץߢ5~h'4\eVﺎC(!٘5]׵x ʝ<3i/52ݥ8&V]fdN7e$)t1,o'DBo-~ɰr+QaqA +%q| P\iy?(BhO!U*W|rV6Zt,c.]Ņjl/@"kG[q7&Ԧ?[uE;?v–w^~bոUTҞ] +mޞ}3X@Ae5לpY +=ڜ>*f^2rw&Y~aFM{#^H_.jLޚW;K[Ns>kVވ)Duc8cM{Tb>#⌢$1ls} T\ X`A2Faf1"&+Y 7w$I/-6#v1QMg[lR^F5mX + /+5wpK DʕTfb-7)$[Pd)̒S5 +W/t׍7. +4 ƞ6YM۬Y[P$9-`vw1q8dMh4=9޷PF ұzL5k﷼3918˨[3;ꮜs5\)c\V)Xۇe\경}!!p~~h~|?+yj6+i7j3,b1]S\+l/Z!,Ȼk5~jb%&O<|X)1a\iJ׏t%[U_|ox~fw $0[jh;~#9T&<[R-ˎ3k=kb8ܪ .^ ++YYƭī6EY d)Vɇy! W:#}v#kԷH8YZcg+ڸ<\2LVWSy8ecGŶmgX^2\C H5?>m+'w8"ȖZ7uE[4l5R Vr-.'Lj1M,W uȾN@ &zy:3GsV%lO~V2(`OβrJ/'?3DYf?~^I)_P6[snx+s%oPΠ&r +؃'L/va  還=Odݯt~2#x _SADr3cl40qq,*ePsVz^wX;T!vF`ztD.Li._(gjFb{8-qnAjݘJ=%߇+sVC?$.#NM¡Amނ0v- C1*HVp'_bGqGٱ+FBD6m.JWRc졆h\ ;A{Vjyڹ P6h җn߱j^e^A͑uOO׈wUT +$Kd#@ɣՈ{1 Oj`8%|x1"cѥt+)MK^s0AUBe-@!) Zr;ŰKC=zV160(AjW TGjKFgVwpB(,M^, ZF6F㩡4KnLw a jS+^#& \s\ ārͪyKiDG1VԜQ>&I'BzW161&9̅v2C=2q,!}>4Լ'ɂZ^bTQ\ YN= + is[[r4~CW* + ']34zh5. o]}ՔH&p^IFLP&1:-T{c@yHaVP%\s7NNW%y:x'Oùlּ?A˜DtbgȟxdHW+[[j @ixFxĝ!GӒf.='}]V1 z]5>8NMX0y. 0Ѐd-ΕPHD351<8RC9ÙΎWc;S8=7uwdW||Q)j=Кgj:|:kYZ!t3b7$]תy'Fp/F65b6kkUhdПU"x,IM+U?',A0}sdO;z~򐠛b(7ܫ +J"PTH-_LΙto)1B(u:*'\+頎vNTC> bXm!ԤyWwzajDy߯dRB#cP5R$S Wj"14ڳ 3p#IN4a7@A 1a*e {O5Q7Ul9 ?^i0L68VMm+CZBBA`Q ܹ\BN=~=jEA!KLkjķ?OR{qPBy3JqZG>wrlR 7\{6tzzLDՑ}kbj‚F7?ߒcD1Dt~d/(E&ՏFD=_T p4ϏQ3 -X@~33|| tce|MԑwՄ5쒜 RhF 7vU$^oHG[FxC6Ζ +ĄS)JM:d36uUsW3¬~ fDSN7Oj"1l{ JoقWK7SK iljбs +6R0#:W %lho=6t D`ntΠ*1֫e:&|0>Ȣ\%9إ>/Iyp˳}Rn̐f wgS#{ƑiV# ]Xj܉&< dK6Qܪzת/q錁rv$঑ Mᅁ_{FMéVdyc%'^Jcu'ĺ 2*fl- gL]V6ͮ'Yyce[6lNʸ +YKĺ盳+ua"tD>p]$R2obJ 4Q h 5G0WJr mAX5k&BҼ =kꃢj\)qvT'čp ++5B<ӱ&LsӟUlwQ5XpkcG8V"B`1ڭ,2m4. 4yjB>^$ 75\^#t+D )}##lFbiJ\@+}WRו.\59p iھb0W%gfƖ'dk9ң~Ss'WbdY5wBѰ7~lƔ3bT7ij4y uNQu@朗'%1ܔnv;@c=,a: aդ)J_rjDJA DO>p7 ^WdNQy8X%Z dWX5y,N8ΠCo.a:*=CZ(lԻ CCJ#c%UC)2_i 8w2RF Q&3 0\O!r-b?WMpM-&)P[}"8PhܦƋ+5\ٰGGӯ~~ok/~۾};nǾi@ti'\"RuRbӽU{s3^oIvZ@tJ*|\u*k6I2`yOIפ 眚ui]l'-W,zm3'j:tPףla$m\oӆ06ӌ9L-⊈۹ ,L,,1[K]ua{yJ GӺ}D2)@ jql?WFu>Zkbj\]zqXIkL=ML+ba>M%38Fɰ:s8pywt)dZDr |@RQSfp =c;$;%2fb0EBO -@+ +\RdO JSt*!R10n UB>?YwU9b#hYL_ vXvZM QX +&c-sH߉q`~0^CD +FP3e42s^ ?<0w`̥t6[cf'FJ)0'B0s e17 Wz"T֋J栾kǃ0ɵ1ʇζ?aᜆu{-a>>oh+֪*~o$$l#&p;W650v38N0F2i2lRTs0-Erl,w; +vQvØ-ƀjOR?W*vlP?.>-05NQ[JYJ^#fO{{,k,/w|tgnFo`o˚ԭnbwW2@OOuUZ!cu=?x0heČX{kWjVrmm c\It{jѤ-47a _^u5s0FŻ'\ٷv~?qƽ[;^&RSַ`Ҽsk/o%ݍ%UmH*|$ @Xdƾ% Ez\ƛ"[ݷ)i&&"l&l%hIvi6MpAp(?#W{!.m2cudduSzO3_t3}7?-mcEב́{/9тhƕ.xSLUjyEcEl&mv* C N.i0XlD0?.uA“+)DdNh}ylYzK4fD+͂c($k`Bv 0 ;wq:U h>̑rd5Q;O*oh10`ἡ0'ռ0t0k aRrs:#S 骆 G=-qD/ A5BZb Yg (۽ Vv:iA0:"K)qw?y~hf"Jt(y <%OQ"ߨ3gCwԙcdc;ϙ`$gpf~>J +\@ (} 3.Ys[g<ÆiZcaP\$ҬzW־ H" h0H2V 畟Wi3[3l0V3XR SS݊틉Z pX%6pVw[dc8l]sϢ.kBo1V3/,LY/i)+z݇9p +3c7Shh1!ŝ~#S %sI_yHv8rVmd*za6qR>3t?g-0-BMa!X4Dd7[n?+Vbs5 +گsw+g)^쀉Bt6Y 񌲫3Lo֗|^w_\s$<ܕMբvSx-粕iO1|Qi5b]ʼnO݀SȱnaO2όx씂=ώzȔJ#; +nwg?/*+jCnjzk9?/b?G7Pa|/c'ט-'[ˎ7-[V [I/b+:߸D`ʾc<`I٤#gX/{@N|~.}<{/kh%\{TX[2Y',SmXg4y/~nyWBH9noP=seO.PΠ qcqV07Kb廻zk+}1Ym.Xe+sUDa\~HJ\|vb35Bju5"jdz_js<3ݷѯ/~amsj TOXTRETB0d&–A1àyaKxFI{ Ӱ+Je\GT_ +u]upfOF¦zFCrsؙ\'aGա_E/2F h0&9OO"yޔ(anq-aٲobYht ҝg sHVd%Xވ#Kq$xM_Z+ʂv3dSlcY.F<~M_䤭AkE&>:Kvb(^A(N7e`bf7e,;eA1.^*QWweBz=9>^wBJ w9CH5nyqqS|*+? yP1b4|=R2 k lI_,>_gMS:ln_hD]{%=v<ȧ=\ z%c"/{vC!9v;bJso:;FޝgtO>ews >KI "Au-uw%4;GY sIO9s_s=>y켞h 9rHřWwd…8V4Y3G9M&*gf 휫l}-Nn-Y Z@иHs'iPS(rWNƊОc_F=_- Io!qLփΗ<ݫ ld}ʗ ҴkeY_3mY<ؕYVܶ-'bP/soY7e0 +NP'e†BD|VEŒ4zWWC]bglL5l{X%qf(}wF)^"jU2ȟ|A4neI)$RTa{{/j1oo/mXk'ULekY m?DYx`KiF}oiɼe/NnKpoXK|e.jiZn?|m5U96WƲڎhDg4ƻڲhDעvΩ<ַ'aq8:chpH{}fx=72R5>v%qc}J(Yc"g^,)#h3|M  7 < "%J$ZEӥ*E0@h۽m4HU;щ(Ys dQ(޼bnP -7EvÛec5z4=Ҍa18G,A4wX! $"dPgהVS7hz"_+M08öIă-Mۥ1Y +[֑zBMy-%fQMu̘oIÄ^*Rk~ +H$z2J'q#^:B4;jpT"wVErfϣ0ܫw%.l$ h̔`1 %}QrW\å{5˥bra$\"O}g+jrPaD#Lک ^n1P]=Zr{ߚa8У1ΣA5' 룉O;a:tOh6eݮH/gy We`K)Ҟ#W{' \){i"I]+[K4]}4-)3?^s_3Hܷꭎ8H^ 0׷}M%M=U}-ؗU2ި׏eh#`Tmž :L3ޕǹ/wk"+lx:)T.=w,b/)# u` q=^iq1*^4.0"8pK3 g)k@je4]:AZ;6VwFPt4A82եgMv+C;ȢYU`}]3UXFh c_F1 Lft2;HCh+. Y,cKє as.1el<&s,q&NV4"Ύ%}3y׻˒PjTIwUJiٔX7lư^;L4w/7 Sw`f&~ endstream endobj 24 0 obj <>stream +Hʥ9axMU% 7 "#:0 s>+ow{vϪU+ezx++ӺGX+`ódKV2k^󕖫blxG[mYo\|WσIY=F/+aՖ}ԁT8nܘ|{F1˹>`;궦0@**19g`Rk^m~/?~ן^竽['s_ҍ_˛ןB rhO8Ǡgi;x:݅ K1j|3) +"$]fZH䵄Ib|灘 u i[,? S3D kM*1""Tr\Ud@TO}pcU9jCh3x91 B]I9V $`xH^aNkv ()>H3#MdLtn$[nncPXp`1I'fҌ8Ϩ?l~6neXhxaRjFvw5Q9ccarqZ-3占HGdY~q!7C- g{.! ]KQFLz7JHvZ]D2mW΃A֙}ڗ߹;0WBya$f/#c(R}ڻf'IbWZYV``\`ȒtI}scH^~Bf608]dszF}0)Tk,SCc'Ck!T 76CfA2RUEH +j;ZcTJ3S˜̄|Q:aYAAgIZ@P1SAYqaI|0P2ɆL5bG9aL  f8B[)z'Ub 1  sOeKr95v+dQK?6~Maah߈aMmNR;ug=3䆴B8t%6b&xV[)ɸ1~Gvcu{Zl(ڪwa5Vܫ:juqVYcP\ *);CPaI>~e!T/fW6wCYAIE:`XHpuɚN5o3 +D˚D|u-ˮDHSL:_ L Uu(TU +` +y^%5&[MAp"U[E u`moP2<eފֱepB3!R־p>C;kZ[Xz,OȢ^lddFy+z}*WcV=2hsRv7a@pju5s`,$WONje[ְyT?|!.r`JS)Hjyq9oC\A +Ыw>(,"Cl"y{A_h]yWSJCՙWbhXc o&NG CE^`vQ[U&M^W`Щ9D_kU07s]=!,.LEZZ`&u^h8 )LJ*YD՟xiB UN2鴓`y#@@FWlHf.bQLN"^z%!RzHVX] x4+Ì$0ĕB0wNZRj9|0Ms4+d4FcΆԶۺ4NiA/ineؑŞgMLWt:gk9 :( "j~ W +nF Ol FT!Pl@#idTh!fe,&oV|f̒9֒C9 -_:^ LLaDDܘe:X>E xw=OL`l^T!g (}G^ +(8asf[ՃY4cG=R+Fӊ\Ex>t+#Qf#51 bh}]ElWo f@BJhSFߚv^dc:|(no)#Z°,8dc4b5I2‰2 +a~ Xrذ;?X+ 5AQ/RpyY &~sI7p\M̌6j +YC;x.[f 1wcegJٹX N|zYhN!U='RF\R9W.GT\QX,6Ce/*? +b5j9^17j2_~_8PJ&yRKl}Mˎ;V'͖R%0-rEWeg'SKa%eV#>gǃ؃oM'Z.}@pڴv1Slc,z#._䤭]7r O4r:eA3.pUloEBnwuctŸLvH䵃H:.m*<>J7q즒[}BHE +uyRm❉p{u_>WrE,tC:C!=+e ߈~'0ywD\x0n*;n9rb.bOv#bXc3{ +xU ;\˼3^s04Lw?k +$ lz;=_q6!`M; A}A\Q&ob &U(P{9-oLv.`s/*g׻ᮀG԰<iF=hn9Te?—` 8+ Fdc]i;NGŦFC uJq/L4)ߺ5"Jj 2#DWL͠:gV\gcgb-z C*ZV8rU{zխ&Z/Ceh_1X3hw[@2 3y,18-n^Ֆғ+< g6~:&.l-Vy {QbؗKs5y}Kl3*ZsI-o#"eNX%74XѕHq.]Soi渝dD7{U._]vQؐhӽl.ٖHj8A.}ir"y5:y-:c7`SG@B2:% tu[@JxyqC,B̘hH fJPdFXLE8+M=UBC\R*9GVOٜ4(@2q*Uw34dS$v*SC\'^VQX/UTFC}bRpo UA&L(Sh;ndK#yG!4#^4T45{gAD}K.\cR{լ7oH|>sܥt, +iQ<_wïf?4-OsåуK]Uzp `Ѿ>YB#~O!NQ2]S yv[~K'ߡkLbva( O۽Lc-xϷ˶,?e]we^uQݗ*S<:bU +q|{;`- endstream endobj 6 0 obj [5 0 R] endobj 25 0 obj <> endobj xref 0 26 0000000000 65535 f +0000000016 00000 n +0000000144 00000 n +0000025173 00000 n +0000000000 00000 f +0000065496 00000 n +0000216446 00000 n +0000025224 00000 n +0000025562 00000 n +0000065799 00000 n +0000065686 00000 n +0000064745 00000 n +0000064935 00000 n +0000064983 00000 n +0000065570 00000 n +0000065601 00000 n +0000065872 00000 n +0000066155 00000 n +0000067473 00000 n +0000085125 00000 n +0000098214 00000 n +0000119906 00000 n +0000150354 00000 n +0000180599 00000 n +0000210222 00000 n +0000216469 00000 n +trailer <<636425E0298441309A895498F62E903C>]>> startxref 216662 %%EOF \ No newline at end of file diff --git a/docs/_static/get-started-garbled-output.png b/docs/_static/get-started-garbled-output.png new file mode 100644 index 0000000000..2e6dd68ca3 Binary files /dev/null and b/docs/_static/get-started-garbled-output.png differ diff --git a/docs/conf_common.py b/docs/conf_common.py index 5fecc7a9fe..673d480ddd 100644 --- a/docs/conf_common.py +++ b/docs/conf_common.py @@ -19,16 +19,21 @@ from __future__ import unicode_literals import sys import os import subprocess +from sanitize_version import sanitize_version +from get_github_rev import get_github_rev + # Note: If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute -from local_util import run_cmd_get_output, copy_if_modified +from local_util import copy_if_modified # build_docs on the CI server sometimes fails under Python3. This is a workaround: sys.setrecursionlimit(3500) +config_dir = os.path.abspath(os.path.dirname(__file__)) + try: builddir = os.environ['BUILDDIR'] except KeyError: @@ -142,6 +147,7 @@ suppress_warnings = ['image.nonlocal_uri'] # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['breathe', + 'sphinx_idf_theme', 'link-roles', 'sphinxcontrib.blockdiag', 'sphinxcontrib.seqdiag', @@ -150,6 +156,7 @@ extensions = ['breathe', 'sphinxcontrib.rackdiag', 'sphinxcontrib.packetdiag', 'html_redirects', + 'latex_builder', ] # Set up font for blockdiag, nwdiag, rackdiag and packetdiag @@ -192,16 +199,14 @@ master_doc = 'index' # built documents. # -# Readthedocs largely ignores 'version' and 'release', and displays one of -# 'latest', tag name, or branch name, depending on the build type. -# Still, this is useful for non-RTD builds. -# This is supposed to be "the short X.Y version", but it's the only version +# This is the full exact version, canonical git version description # visible when you open index.html. -# Display full version to make things less confusing. -version = run_cmd_get_output('git describe') -# The full version, including alpha/beta/rc tags. -# If needed, nearest tag is returned by 'git describe --abbrev=0'. -release = version +version = subprocess.check_output(['git', 'describe']).strip().decode('utf-8') + +# The 'release' version is the same as version for non-CI builds, but for CI +# builds on a branch then it's replaced with the branch name +release = sanitize_version(version) + print('Version: {0} Release: {1}'.format(version, release)) # There are two options for replacing |today|: either, you set today to some @@ -232,6 +237,13 @@ exclude_patterns = ['_build','README.md'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' +# Extra options required by sphinx_idf_theme +project_slug = 'esp-idf' +versions_url = 'https://dl.espressif.com/dl/esp-idf/idf_versions.js' + +languages = ['en', 'zh_CN'] + + # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] @@ -257,7 +269,15 @@ html_redirect_pages = [('api-reference/ethernet/index', 'api-reference/network/i # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = 'sphinx_rtd_theme' +html_theme = 'sphinx_idf_theme' + +# context used by sphinx_idf_theme +html_context = { + "display_github": True, # Add 'Edit on Github' link instead of 'View page source' + "github_user": "espressif", + "github_repo": "esp-idf", + "github_version": get_github_rev(), +} # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -340,28 +360,41 @@ htmlhelp_basename = 'ReadtheDocsTemplatedoc' # -- Options for LaTeX output --------------------------------------------- -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - # - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - # - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} +latex_template_dir = os.path.join(config_dir, 'latex_templates') -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'ReadtheDocsTemplate.tex', u'Read the Docs Template Documentation', - u'Read the Docs', 'manual'), -] +preamble = '' +with open(os.path.join(latex_template_dir, 'preamble.tex')) as f: + preamble = f.read() + +titlepage = '' +with open(os.path.join(latex_template_dir, 'titlepage.tex')) as f: + titlepage = f.read() + + +latex_elements = { + 'papersize': 'a4paper', + + # Latex figure (float) alignment + 'figure_align':'htbp', + + 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + 'fncychap': '\\usepackage[Sonny]{fncychap}', + + 'preamble': preamble, + + 'maketitle': titlepage, +} # The name of an image file (relative to this directory) to place at the top of # the title page. -# latex_logo = None + +# The name of an image file (relative to this directory) to place at the bottom of +# the title page. +latex_logo = "../_static/espressif2.pdf" +latex_engine = 'xelatex' +latex_use_xindy = False # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. @@ -422,3 +455,24 @@ texinfo_documents = [ def setup(app): app.add_stylesheet('theme_overrides.css') generate_version_specific_includes(app) + + # Not all config variables are set when setup is called + app.connect('config-inited', setup_config_values) + app.connect('config-inited', setup_html_context) + + +def setup_config_values(app, config): + # Sets up global config values needed by other extensions + idf_target_title_dict = { + 'esp32': 'ESP32', + } + + app.add_config_value('idf_target_title_dict', idf_target_title_dict, 'env') + + pdf_name = "esp-idf-{}-{}-{}".format(app.config.language, app.config.version, "esp32") + app.add_config_value('pdf_file', pdf_name, 'env') + + +def setup_html_context(app, config): + # Setup path for 'edit on github'-link + app.config.html_context['conf_py_path'] = "/docs/{}/".format(app.config.language) diff --git a/docs/en/conf.py b/docs/en/conf.py index cb77736dd3..f30829d2e0 100644 --- a/docs/en/conf.py +++ b/docs/en/conf.py @@ -16,7 +16,7 @@ except ImportError: # General information about the project. project = u'ESP-IDF Programming Guide' -copyright = u'2016 - 2020, Espressif Systems (Shanghai) CO., LTD' +copyright = u'2016 - 2021, Espressif Systems (Shanghai) CO., LTD' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/en/get-started-cmake/index.rst b/docs/en/get-started-cmake/index.rst index 1d19dff7f0..c1467cfe78 100644 --- a/docs/en/get-started-cmake/index.rst +++ b/docs/en/get-started-cmake/index.rst @@ -82,14 +82,14 @@ If you have different board, move to sections below. Step 1. Set up Toolchain ======================== -The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow provided instructions. +The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow provided instructions. .. toctree:: :hidden: Windows - Linux - MacOS + Linux + MacOS +-------------------+-------------------+-------------------+ | |windows-logo| | |linux-logo| | |macos-logo| | @@ -298,12 +298,12 @@ This command will compile the application and all the ESP-IDF components, genera -- Building empty aws_iot component due to configuration -- Component names: ... -- Component paths: ... - + ... (more lines of build system output) - + [527/527] Generating hello-world.bin esptool.py v2.3.1 - + Project build complete. To flash, run this command: ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin or run 'idf.py -p PORT flash' @@ -352,7 +352,7 @@ This step will flash the binaries that you just built to your ESP32 board. Compressed 136672 bytes to 67544... Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... Hash of data verified. - + Leaving... Hard resetting via RTS pin... @@ -393,14 +393,13 @@ Several lines below, after start up and diagnostic log, you should see "Hello wo To exit the monitor use shortcut ``Ctrl+]``. -.. note:: +If instead of the messages above, you see a random garbage similar to what is shown below, or monitor fails shortly after upload, your board is likely using 26MHz crystal, while the ESP-IDF assumes default of 40MHz. Exit the monitor, go back to the :ref:`menuconfig `, change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz, then :ref:`build and flash ` the application again. This is found under ``make menuconfig`` under Component config --> ESP32-specific --> Main XTAL frequency. - If instead of the messages above, you see a random garbage similar to:: +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - - or monitor fails shortly after upload, your board is likely using 26MHz crystal. Most development board designs use 40MHz and the ESP-IDF uses this default value. Exit the monitor, go back to the :ref:`menuconfig `, change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz, then :ref:`build and flash ` the application again. This is found under ``idf.py menuconfig`` under Component config --> ESP32-specific --> Main XTAL frequency. .. note:: diff --git a/docs/en/get-started/index.rst b/docs/en/get-started/index.rst index db0bc0ce5a..cbb0cd8f8a 100644 --- a/docs/en/get-started/index.rst +++ b/docs/en/get-started/index.rst @@ -1,376 +1,375 @@ -*********** -Get Started -*********** -:link_to_translation:`zh_CN:[中文]` - -This document is intended to help users set up the software environment for development of applications using hardware based on the Espressif ESP32. Through a simple example we would like to illustrate how to use ESP-IDF (Espressif IoT Development Framework), including the menu based configuration, compiling the ESP-IDF and firmware download to ESP32 boards. - -.. include:: /_build/inc/version-note.inc - -Introduction -============ - -ESP32 integrates Wi-Fi (2.4 GHz band) and Bluetooth 4.2 solutions on a single chip, along with dual high performance cores, Ultra Low Power co-processor and several peripherals. Powered by 40 nm technology, ESP32 provides a robust, highly integrated platform to meet the continuous demands for efficient power usage, compact design, security, high performance, and reliability. - -Espressif provides the basic hardware and software resources that help application developers to build their ideas around the ESP32 series hardware. The software development framework by Espressif is intended for rapidly developing Internet-of-Things (IoT) applications, with Wi-Fi, Bluetooth, power management and several other system features. - - -What You Need -============= - -To develop applications for ESP32 you need: - -* **PC** loaded with either Windows, Linux or Mac operating system -* **Toolchain** to build the **Application** for ESP32 -* **ESP-IDF** that essentially contains API for ESP32 and scripts to operate the **Toolchain** -* A text editor to write programs (**Projects**) in C, e.g. `Eclipse `_ -* The **ESP32** board itself and a **USB cable** to connect it to the **PC** - -.. figure:: ../../_static/what-you-need.png - :align: center - :alt: Development of applications for ESP32 - :figclass: align-center - - Development of applications for ESP32 - -Preparation of development environment consists of three steps: - -1. Setup of **Toolchain** -2. Getting of **ESP-IDF** from GitHub -3. Installation and configuration of **Eclipse** - -You may skip the last step, if you prefer to use different editor. - -Having environment set up, you are ready to start the most interesting part - the application development. This process may be summarized in four steps: - -1. Configuration of a **Project** and writing the code -2. Compilation of the **Project** and linking it to build an **Application** -3. Flashing (uploading) of the **Application** to **ESP32** -4. Monitoring / debugging of the **Application** - -See instructions below that will walk you through these steps. - - -Guides -====== - -If you have one of ESP32 development boards listed below, click on provided links to get you up and running. - -.. toctree:: - :maxdepth: 1 - - ESP32 DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT - -If you have different board, move to sections below. - - -.. _get-started-setup-toolchain: - -Setup Toolchain -=============== - -The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow provided instructions. - -.. toctree:: - :hidden: - - Windows - Linux - MacOS - -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ - -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started/windows-setup.html - -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started/linux-setup.html - -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started/macos-setup.html - -.. _Windows: ../get-started/windows-setup.html -.. _Linux: ../get-started/linux-setup.html -.. _Mac OS: ../get-started/macos-setup.html - -.. note:: - - We are using ``~/esp`` directory to install the prebuilt toolchain, ESP-IDF and sample applications. You can use different directory, but need to adjust respective commands. - -Depending on your experience and preferences, instead of using a prebuilt toolchain, you may want to customize your environment. To set up the system your own way go to section :ref:`get-started-customized-setup`. - -Once you are done with setting up the toolchain then go to section :ref:`get-started-get-esp-idf`. - - -.. _get-started-get-esp-idf: - -Get ESP-IDF -=========== - -.. highlight:: bash - -Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository `_. - -To obtain a local copy: open terminal, navigate to the directory you want to put ESP-IDF, and clone the repository using ``git clone`` command: - -.. include:: /_build/inc/git-clone-bash.inc - -ESP-IDF will be downloaded into ``~/esp/esp-idf``. - -Consult :doc:`/versions` for information about which version of ESP-IDF to use in a given situation. - -.. include:: /_build/inc/git-clone-notes.inc - -.. note:: - - Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: - - cd esp-idf - git submodule update --init --recursive - -.. _get-started-setup-path: - -Setup Path to ESP-IDF -===================== - -The toolchain programs access ESP-IDF using ``IDF_PATH`` environment variable. This variable should be set up on your PC, otherwise projects will not build. Setting may be done manually, each time PC is restarted. Another option is to set up it permanently by defining ``IDF_PATH`` in user profile. To do so, follow instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in section :doc:`add-idf_path-to-profile`. - -.. _get-started-get-packages: - -Install the Required Python Packages -==================================== - -Python packages required by ESP-IDF are located in the ``$IDF_PATH/requirements.txt`` file. You can install them by running:: - - python -m pip install --user -r $IDF_PATH/requirements.txt - -.. note:: - - Please invoke that version of the Python interpreter which you will be using with ESP-IDF. The version of the - interpreter can be checked by running command ``python --version`` and depending on the result, you might want to - use ``python2``, ``python2.7`` or similar instead of ``python``, e.g.:: - - python2.7 -m pip install --user -r $IDF_PATH/requirements.txt - -.. _get-started-start-project: - -Start a Project -=============== - -Now you are ready to prepare your application for ESP32. To start off quickly, we will use :example:`get-started/hello_world` project from :idf:`examples` directory in IDF. - -Copy :example:`get-started/hello_world` to ``~/esp`` directory:: - - cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world . - -You can also find a range of example projects under the :idf:`examples` directory in ESP-IDF. These example project directories can be copied in the same way as presented above, to begin your own projects. - -.. important:: - - The esp-idf build system does not support spaces in paths to esp-idf or to projects. - - -.. _get-started-connect: - -Connect -======= - -You are almost there. To be able to proceed further, connect ESP32 board to PC, check under what serial port the board is visible and verify if serial communication works. If you are not sure how to do it, check instructions in section :doc:`establish-serial-connection`. Note the port number, as it will be required in the next step. - - -.. _get-started-configure: - -Configure -========= - -Being in terminal window, go to directory of ``hello_world`` application by typing ``cd ~/esp/hello_world``. Then start project configuration utility ``menuconfig``:: - - cd ~/esp/hello_world - make menuconfig - -If previous steps have been done correctly, the following menu will be displayed: - -.. figure:: ../../_static/project-configuration.png - :align: center - :alt: Project configuration - Home window - :figclass: align-center - - Project configuration - Home window - -In the menu, navigate to ``Serial flasher config`` > ``Default serial port`` to configure the serial port, where project will be loaded to. Confirm selection by pressing enter, save configuration by selecting ``< Save >`` and then exit application by selecting ``< Exit >``. - -.. note:: - - On Windows, serial ports have names like COM1. On MacOS, they start with ``/dev/cu.``. On Linux, they start with ``/dev/tty``. - (See :doc:`establish-serial-connection` for full details.) - -Here are couple of tips on navigation and use of ``menuconfig``: - -* Use up & down arrow keys to navigate the menu. -* Use Enter key to go into a submenu, Escape key to go out or to exit. -* Type ``?`` to see a help screen. Enter key exits the help screen. -* Use Space key, or ``Y`` and ``N`` keys to enable (Yes) and disable (No) configuration items with checkboxes "``[*]``" -* Pressing ``?`` while highlighting a configuration item displays help about that item. -* Type ``/`` to search the configuration items. - -.. note:: - - If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``. - - -.. attention:: - - When using ESP32-DevKitC board with ESP32-SOLO-1 module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing example applications. - - -.. _get-started-build-flash: - -Build and Flash -=============== - -Now you can build and flash the application. Run:: - - make flash - -This will compile the application and all the ESP-IDF components, generate bootloader, partition table, and application binaries, and flash these binaries to your ESP32 board. - -.. highlight:: none - -:: - - esptool.py v2.0-beta2 - Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... - esptool.py v2.0-beta2 - Connecting........___ - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 921600 - Changed. - Attaching SPI flash... - Configuring flash size... - Auto-detected Flash size: 4MB - Flash params set to 0x0220 - Compressed 11616 bytes to 6695... - Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... - Hash of data verified. - Compressed 408096 bytes to 171625... - Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... - Hash of data verified. - Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... - Hash of data verified. - - Leaving... - Hard resetting... - -If there are no issues, at the end of build process, you should see messages describing progress of loading process. Finally, the end module will be reset and "hello_world" application will start. - -If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. - - -.. _get-started-build-monitor: - -Monitor -======= - -To see if "hello_world" application is indeed running, type ``make monitor``. This command is launching :doc:`IDF Monitor ` application:: - - $ make monitor - MONITOR - --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- - ets Jun 8 2016 00:22:57 - - rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - ... - -Several lines below, after start up and diagnostic log, you should see "Hello world!" printed out by the application. :: - - ... - Hello world! - Restarting in 10 seconds... - I (211) cpu_start: Starting scheduler on APP CPU. - Restarting in 9 seconds... - Restarting in 8 seconds... - Restarting in 7 seconds... - -To exit the monitor use shortcut ``Ctrl+]``. - -.. note:: - - If instead of the messages above, you see a random garbage similar to:: - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - - or monitor fails shortly after upload, your board is likely using 26MHz crystal, while the ESP-IDF assumes default of 40MHz. Exit the monitor, go back to the :ref:`menuconfig `, change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz, then :ref:`build and flash ` the application again. This is found under ``make menuconfig`` under Component config --> ESP32-specific --> Main XTAL frequency. - -To execute ``make flash`` and ``make monitor`` in one go, type ``make flash monitor``. Check section :doc:`IDF Monitor ` for handy shortcuts and more details on using this application. - -That's all what you need to get started with ESP32! - -Now you are ready to try some other :idf:`examples`, or go right to developing your own applications. - - -Environment Variables -===================== - -Some environment variables can be specified whilst calling ``make`` allowing users to **override arguments without needing to reconfigure them using** ``make menuconfig``. - -+-----------------+--------------------------------------------------------------+ -| Variables | Description & Usage | -+=================+==============================================================+ -| ``ESPPORT`` | Overrides the serial port used in ``flash`` and ``monitor``. | -| | | -| | Examples: ``make flash ESPPORT=/dev/ttyUSB1``, | -| | ``make monitor ESPPORT=COM1`` | -+-----------------+--------------------------------------------------------------+ -| ``ESPBAUD`` | Overrides the serial baud rate when flashing the ESP32. | -| | | -| | Example: ``make flash ESPBAUD=9600`` | -+-----------------+--------------------------------------------------------------+ -| ``MONITORBAUD`` | Overrides the serial baud rate used when monitoring. | -| | | -| | Example: ``make monitor MONITORBAUD=9600`` | -+-----------------+--------------------------------------------------------------+ - -.. note:: - Users can export environment variables (e.g. ``export ESPPORT=/dev/ttyUSB1``). - All subsequent calls of ``make`` within the same terminal session will use - the exported value given that the variable is not simultaneously overridden. - -Updating ESP-IDF -================ - -After some time of using ESP-IDF, you may want to update it to take advantage of new features or bug fixes. The simplest way to do so is by deleting existing ``esp-idf`` folder and cloning it again, exactly as when doing initial installation described in sections :ref:`get-started-get-esp-idf`. - -If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts know where to find the ESP-IDF in its release specific location. - -Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. - - -Related Documents -================= - -.. toctree:: - :maxdepth: 1 - - add-idf_path-to-profile - establish-serial-connection - make-project - eclipse-setup - idf-monitor - toolchain-setup-scratch - -.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases - +*********** +Get Started +*********** +:link_to_translation:`zh_CN:[中文]` + +This document is intended to help users set up the software environment for development of applications using hardware based on the Espressif ESP32. Through a simple example we would like to illustrate how to use ESP-IDF (Espressif IoT Development Framework), including the menu based configuration, compiling the ESP-IDF and firmware download to ESP32 boards. + +.. include:: /_build/inc/version-note.inc + +Introduction +============ + +ESP32 integrates Wi-Fi (2.4 GHz band) and Bluetooth 4.2 solutions on a single chip, along with dual high performance cores, Ultra Low Power co-processor and several peripherals. Powered by 40 nm technology, ESP32 provides a robust, highly integrated platform to meet the continuous demands for efficient power usage, compact design, security, high performance, and reliability. + +Espressif provides the basic hardware and software resources that help application developers to build their ideas around the ESP32 series hardware. The software development framework by Espressif is intended for rapidly developing Internet-of-Things (IoT) applications, with Wi-Fi, Bluetooth, power management and several other system features. + + +What You Need +============= + +To develop applications for ESP32 you need: + +* **PC** loaded with either Windows, Linux or Mac operating system +* **Toolchain** to build the **Application** for ESP32 +* **ESP-IDF** that essentially contains API for ESP32 and scripts to operate the **Toolchain** +* A text editor to write programs (**Projects**) in C, e.g. `Eclipse `_ +* The **ESP32** board itself and a **USB cable** to connect it to the **PC** + +.. figure:: ../../_static/what-you-need.png + :align: center + :alt: Development of applications for ESP32 + :figclass: align-center + + Development of applications for ESP32 + +Preparation of development environment consists of three steps: + +1. Setup of **Toolchain** +2. Getting of **ESP-IDF** from GitHub +3. Installation and configuration of **Eclipse** + +You may skip the last step, if you prefer to use different editor. + +Having environment set up, you are ready to start the most interesting part - the application development. This process may be summarized in four steps: + +1. Configuration of a **Project** and writing the code +2. Compilation of the **Project** and linking it to build an **Application** +3. Flashing (uploading) of the **Application** to **ESP32** +4. Monitoring / debugging of the **Application** + +See instructions below that will walk you through these steps. + + +Guides +====== + +If you have one of ESP32 development boards listed below, click on provided links to get you up and running. + +.. toctree:: + :maxdepth: 1 + + ESP32 DevKitC + ESP-WROVER-KIT + ESP32-PICO-KIT + +If you have different board, move to sections below. + + +.. _get-started-setup-toolchain: + +Setup Toolchain +=============== + +The quickest way to start development with ESP32 is by installing a prebuilt toolchain. Pick up your OS below and follow provided instructions. + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ + +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started/macos-setup.html + +.. _Windows: ../get-started/windows-setup.html +.. _Linux: ../get-started/linux-setup.html +.. _Mac OS: ../get-started/macos-setup.html + +.. note:: + + We are using ``~/esp`` directory to install the prebuilt toolchain, ESP-IDF and sample applications. You can use different directory, but need to adjust respective commands. + +Depending on your experience and preferences, instead of using a prebuilt toolchain, you may want to customize your environment. To set up the system your own way go to section :ref:`get-started-customized-setup`. + +Once you are done with setting up the toolchain then go to section :ref:`get-started-get-esp-idf`. + + +.. _get-started-get-esp-idf: + +Get ESP-IDF +=========== + +.. highlight:: bash + +Besides the toolchain (that contains programs to compile and build the application), you also need ESP32 specific API / libraries. They are provided by Espressif in `ESP-IDF repository `_. + +To obtain a local copy: open terminal, navigate to the directory you want to put ESP-IDF, and clone the repository using ``git clone`` command: + +.. include:: /_build/inc/git-clone-bash.inc + +ESP-IDF will be downloaded into ``~/esp/esp-idf``. + +Consult :doc:`/versions` for information about which version of ESP-IDF to use in a given situation. + +.. include:: /_build/inc/git-clone-notes.inc + +.. note:: + + Do not miss the ``--recursive`` option. If you have already cloned ESP-IDF without this option, run another command to get all the submodules:: + + cd esp-idf + git submodule update --init --recursive + +.. _get-started-setup-path: + +Setup Path to ESP-IDF +===================== + +The toolchain programs access ESP-IDF using ``IDF_PATH`` environment variable. This variable should be set up on your PC, otherwise projects will not build. Setting may be done manually, each time PC is restarted. Another option is to set up it permanently by defining ``IDF_PATH`` in user profile. To do so, follow instructions specific to :ref:`Windows ` , :ref:`Linux and MacOS ` in section :doc:`add-idf_path-to-profile`. + +.. _get-started-get-packages: + +Install the Required Python Packages +==================================== + +Python packages required by ESP-IDF are located in the ``$IDF_PATH/requirements.txt`` file. You can install them by running:: + + python -m pip install --user -r $IDF_PATH/requirements.txt + +.. note:: + + Please invoke that version of the Python interpreter which you will be using with ESP-IDF. The version of the + interpreter can be checked by running command ``python --version`` and depending on the result, you might want to + use ``python2``, ``python2.7`` or similar instead of ``python``, e.g.:: + + python2.7 -m pip install --user -r $IDF_PATH/requirements.txt + +.. _get-started-start-project: + +Start a Project +=============== + +Now you are ready to prepare your application for ESP32. To start off quickly, we will use :example:`get-started/hello_world` project from :idf:`examples` directory in IDF. + +Copy :example:`get-started/hello_world` to ``~/esp`` directory:: + + cd ~/esp + cp -r $IDF_PATH/examples/get-started/hello_world . + +You can also find a range of example projects under the :idf:`examples` directory in ESP-IDF. These example project directories can be copied in the same way as presented above, to begin your own projects. + +.. important:: + + The esp-idf build system does not support spaces in paths to esp-idf or to projects. + + +.. _get-started-connect: + +Connect +======= + +You are almost there. To be able to proceed further, connect ESP32 board to PC, check under what serial port the board is visible and verify if serial communication works. If you are not sure how to do it, check instructions in section :doc:`establish-serial-connection`. Note the port number, as it will be required in the next step. + + +.. _get-started-configure: + +Configure +========= + +Being in terminal window, go to directory of ``hello_world`` application by typing ``cd ~/esp/hello_world``. Then start project configuration utility ``menuconfig``:: + + cd ~/esp/hello_world + make menuconfig + +If previous steps have been done correctly, the following menu will be displayed: + +.. figure:: ../../_static/project-configuration.png + :align: center + :alt: Project configuration - Home window + :figclass: align-center + + Project configuration - Home window + +In the menu, navigate to ``Serial flasher config`` > ``Default serial port`` to configure the serial port, where project will be loaded to. Confirm selection by pressing enter, save configuration by selecting ``< Save >`` and then exit application by selecting ``< Exit >``. + +.. note:: + + On Windows, serial ports have names like COM1. On MacOS, they start with ``/dev/cu.``. On Linux, they start with ``/dev/tty``. + (See :doc:`establish-serial-connection` for full details.) + +Here are couple of tips on navigation and use of ``menuconfig``: + +* Use up & down arrow keys to navigate the menu. +* Use Enter key to go into a submenu, Escape key to go out or to exit. +* Type ``?`` to see a help screen. Enter key exits the help screen. +* Use Space key, or ``Y`` and ``N`` keys to enable (Yes) and disable (No) configuration items with checkboxes "``[*]``" +* Pressing ``?`` while highlighting a configuration item displays help about that item. +* Type ``/`` to search the configuration items. + +.. note:: + + If you are **Arch Linux** user, navigate to ``SDK tool configuration`` and change the name of ``Python 2 interpreter`` from ``python`` to ``python2``. + + +.. attention:: + + When using ESP32-DevKitC board with ESP32-SOLO-1 module, enable single core mode (:ref:`CONFIG_FREERTOS_UNICORE`) in menuconfig before flashing example applications. + + +.. _get-started-build-flash: + +Build and Flash +=============== + +Now you can build and flash the application. Run:: + + make flash + +This will compile the application and all the ESP-IDF components, generate bootloader, partition table, and application binaries, and flash these binaries to your ESP32 board. + +.. highlight:: none + +:: + + esptool.py v2.0-beta2 + Flashing binaries to serial port /dev/ttyUSB0 (app at offset 0x10000)... + esptool.py v2.0-beta2 + Connecting........___ + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 921600 + Changed. + Attaching SPI flash... + Configuring flash size... + Auto-detected Flash size: 4MB + Flash params set to 0x0220 + Compressed 11616 bytes to 6695... + Wrote 11616 bytes (6695 compressed) at 0x00001000 in 0.1 seconds (effective 920.5 kbit/s)... + Hash of data verified. + Compressed 408096 bytes to 171625... + Wrote 408096 bytes (171625 compressed) at 0x00010000 in 3.9 seconds (effective 847.3 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 82... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 8297.4 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting... + +If there are no issues, at the end of build process, you should see messages describing progress of loading process. Finally, the end module will be reset and "hello_world" application will start. + +If you'd like to use the Eclipse IDE instead of running ``make``, check out the :doc:`Eclipse guide `. + + +.. _get-started-build-monitor: + +Monitor +======= + +To see if "hello_world" application is indeed running, type ``make monitor``. This command is launching :doc:`IDF Monitor ` application:: + + $ make monitor + MONITOR + --- idf_monitor on /dev/ttyUSB0 115200 --- + --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + ets Jun 8 2016 00:22:57 + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + ... + +Several lines below, after start up and diagnostic log, you should see "Hello world!" printed out by the application. :: + + ... + Hello world! + Restarting in 10 seconds... + I (211) cpu_start: Starting scheduler on APP CPU. + Restarting in 9 seconds... + Restarting in 8 seconds... + Restarting in 7 seconds... + +To exit the monitor use shortcut ``Ctrl+]``. + +If instead of the messages above, you see a random garbage similar to what is shown below, or monitor fails shortly after upload, your board is likely using 26MHz crystal, while the ESP-IDF assumes default of 40MHz. Exit the monitor, go back to the :ref:`menuconfig `, change :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` to 26MHz, then :ref:`build and flash ` the application again. This is found under ``make menuconfig`` under Component config --> ESP32-specific --> Main XTAL frequency. + +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center + + +To execute ``make flash`` and ``make monitor`` in one go, type ``make flash monitor``. Check section :doc:`IDF Monitor ` for handy shortcuts and more details on using this application. + +That's all what you need to get started with ESP32! + +Now you are ready to try some other :idf:`examples`, or go right to developing your own applications. + + +Environment Variables +===================== + +Some environment variables can be specified whilst calling ``make`` allowing users to **override arguments without needing to reconfigure them using** ``make menuconfig``. + ++-----------------+--------------------------------------------------------------+ +| Variables | Description & Usage | ++=================+==============================================================+ +| ``ESPPORT`` | Overrides the serial port used in ``flash`` and ``monitor``. | +| | | +| | Examples: ``make flash ESPPORT=/dev/ttyUSB1``, | +| | ``make monitor ESPPORT=COM1`` | ++-----------------+--------------------------------------------------------------+ +| ``ESPBAUD`` | Overrides the serial baud rate when flashing the ESP32. | +| | | +| | Example: ``make flash ESPBAUD=9600`` | ++-----------------+--------------------------------------------------------------+ +| ``MONITORBAUD`` | Overrides the serial baud rate used when monitoring. | +| | | +| | Example: ``make monitor MONITORBAUD=9600`` | ++-----------------+--------------------------------------------------------------+ + +.. note:: + Users can export environment variables (e.g. ``export ESPPORT=/dev/ttyUSB1``). + All subsequent calls of ``make`` within the same terminal session will use + the exported value given that the variable is not simultaneously overridden. + +Updating ESP-IDF +================ + +After some time of using ESP-IDF, you may want to update it to take advantage of new features or bug fixes. The simplest way to do so is by deleting existing ``esp-idf`` folder and cloning it again, exactly as when doing initial installation described in sections :ref:`get-started-get-esp-idf`. + +If downloading to a new path, remember to :doc:`add-idf_path-to-profile` so that the toolchain scripts know where to find the ESP-IDF in its release specific location. + +Another solution is to update only what has changed. :ref:`The update procedure depends on the version of ESP-IDF you are using `. + + +Related Documents +================= + +.. toctree:: + :maxdepth: 1 + + add-idf_path-to-profile + establish-serial-connection + make-project + eclipse-setup + idf-monitor + toolchain-setup-scratch + +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ +.. _Releases page: https://github.com/espressif/esp-idf/releases + diff --git a/docs/gen-version-specific-includes.py b/docs/gen-version-specific-includes.py index 6bd377c4b1..1e2ae4fbbc 100755 --- a/docs/gen-version-specific-includes.py +++ b/docs/gen-version-specific-includes.py @@ -189,34 +189,29 @@ def write_version_note(template, out_dir, version, ver_type, is_stable): def get_version(): """ - Returns a tuple of (name of branch/tag, type branch/tag, is_stable) + Returns a tuple of (name of branch/tag/commit-id, type branch/tag/commit, is_stable) """ - # Trust what RTD says our version is, if it is set - version = os.environ.get("READTHEDOCS_VERSION", None) - if version == "latest": - return ("master", "branch", False) - - # Otherwise, use git to look for a tag + # Use git to look for a tag try: - tag = subprocess.check_output(["git", "describe", "--exact-match"]).strip() + tag = subprocess.check_output(["git", "describe", "--exact-match"]).strip().decode('utf-8') is_stable = re.match(r"v[0-9\.]+$", tag) is not None return (tag, "tag", is_stable) except subprocess.CalledProcessError: pass - # No tag, look for a branch - refs = subprocess.check_output(["git", "for-each-ref", "--points-at", "HEAD", "--format", "%(refname)"]) - print("refs:\n%s" % refs) - refs = refs.split(b"\n") - # Note: this looks for branches in 'origin' because GitLab CI doesn't check out a local branch - branches = [r.replace(b"refs/remotes/origin/",b"").strip() for r in refs if r.startswith(b"refs/remotes/origin/")] - if len(branches) == 0: - # last resort, return the commit (may happen on Gitlab CI sometimes, unclear why) - return (subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip(), "commit", False) - if "master" in branches: - return ("master", "branch", False) - else: - return (branches[0], "branch", False) # take whatever the first branch is + # No tag, look at branch name from CI, this will give the correct branch name even if the ref for the branch we + # merge into has moved forward before the pipeline runs + branch = os.environ.get("CI_COMMIT_REF_NAME", None) + if branch is not None: + return (branch, "branch", False) + + # Try to find the branch name even if docs are built locally + branch = subprocess.check_output(["git", "rev-parse", "--abbrev-ref", "HEAD"]).strip().decode('utf-8') + if branch != "HEAD": + return (branch, "branch", False) + + # As a last resort we return commit SHA-1, should never happen in CI/docs that should be published + return (subprocess.check_output(["git", "rev-parse", "--short", "HEAD"]).strip().decode('utf-8'), "commit", False) if __name__ == "__main__": diff --git a/docs/get_github_rev.py b/docs/get_github_rev.py new file mode 100644 index 0000000000..7dc2da5635 --- /dev/null +++ b/docs/get_github_rev.py @@ -0,0 +1,15 @@ +import subprocess + + +# Get revision used for constructing github URLs +def get_github_rev(): + path = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip().decode('utf-8') + try: + tag = subprocess.check_output(['git', 'describe', '--exact-match']).strip().decode('utf-8') + except subprocess.CalledProcessError: + tag = None + print('Git commit ID: ', path) + if tag: + print('Git tag: ', tag) + return tag + return path diff --git a/docs/latex_builder.py b/docs/latex_builder.py new file mode 100644 index 0000000000..270eb594f1 --- /dev/null +++ b/docs/latex_builder.py @@ -0,0 +1,55 @@ +from sphinx.builders.latex import LaTeXBuilder +import os + + +# Overrides the default Sphinx latex build +class IdfLatexBuilder(LaTeXBuilder): + + def __init__(self, app): + + # Sets up the latex_documents config value, done here instead of conf.py since it depends on the runtime value 'idf_target' + self.init_latex_documents(app) + + super().__init__(app) + + def init_latex_documents(self, app): + + file_name = app.config.pdf_file + '.tex' + + if app.config.language == 'zh_CN': + latex_documents = [('index', file_name, u'ESP-IDF 编程指南', u'乐鑫信息科技', 'manual')] + else: + # Default to english naming + latex_documents = [('index', file_name, u'ESP-IDF Programming Guide', u'Espressif Systems', 'manual')] + + app.config.latex_documents = latex_documents + + def prepare_latex_macros(self, package_path, config): + + PACKAGE_NAME = "espidf.sty" + latex_package = '' + with open(package_path, 'r') as template: + + latex_package = template.read() + + idf_target_title = "ESP32" + latex_package = latex_package.replace('', idf_target_title) + + # Release name for the PDF front page, remove '_' as this is used for subscript in Latex + idf_release_name = "Release {}".format(config.version.replace('_', '-')) + latex_package = latex_package.replace('', idf_release_name) + + with open(os.path.join(self.outdir, PACKAGE_NAME), 'w') as package_file: + package_file.write(latex_package) + + def finish(self): + super().finish() + + TEMPLATE_PATH = "../latex_templates/espidf.sty" + self.prepare_latex_macros(os.path.join(self.confdir,TEMPLATE_PATH), self.config) + + +def setup(app): + app.add_builder(IdfLatexBuilder, override=True) + + return {'parallel_read_safe': True, 'parallel_write_safe': True, 'version': '0.1'} diff --git a/docs/latex_templates/espidf.sty b/docs/latex_templates/espidf.sty new file mode 100644 index 0000000000..a41f764060 --- /dev/null +++ b/docs/latex_templates/espidf.sty @@ -0,0 +1,7 @@ +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{espidf}[2020/03/25 v0.1.0 LaTeX package (ESP-IDF markup)] + +\newcommand{\idfTarget}{} +\newcommand{\idfReleaseName}{} + +\endinput \ No newline at end of file diff --git a/docs/latex_templates/preamble.tex b/docs/latex_templates/preamble.tex new file mode 100644 index 0000000000..67d4890599 --- /dev/null +++ b/docs/latex_templates/preamble.tex @@ -0,0 +1,129 @@ +% package with esp-idf specific macros +\usepackage{espidf} + +\setcounter{secnumdepth}{2} +\setcounter{tocdepth}{2} + +\usepackage{amsmath,amsfonts,amssymb,amsthm} +\usepackage{graphicx} +%%% reduce spaces for Table of contents, figures and tables +%%% it is used "\addtocontents{toc}{\vskip -1.2cm}" etc. in the document +\usepackage[notlot,nottoc,notlof]{} + +\usepackage{color} +\usepackage{transparent} +\usepackage{eso-pic} +\usepackage{lipsum} + +%%% Needed for displaying Chinese in English documentation +\usepackage{xeCJK} + +\usepackage{footnotebackref} %%link at the footnote to go to the place of footnote in the text + +%% spacing between line +\usepackage{setspace} +\singlespacing + + +\definecolor{myred}{RGB}{229, 32, 26} +\definecolor{mygrayy}{RGB}{127, 127, 127} +\definecolor{myblack}{RGB}{64, 64, 64} + + +%%%%%%%%%%% datetime +\usepackage{datetime} + +\newdateformat{MonthYearFormat}{% + \monthname[\THEMONTH], \THEYEAR} + + +%% RO, LE will not work for 'oneside' layout. +%% Change oneside to twoside in document class +\usepackage{fancyhdr} +\pagestyle{fancy} +\fancyhf{} + +% Header and footer +\makeatletter + \fancypagestyle{normal}{ + \fancyhf{} + \fancyhead[L]{\nouppercase{\leftmark}} + \fancyfoot[C]{\py@HeaderFamily\thepage \\ \href{https://www.espressif.com/en/company/documents/documentation_feedback?docId=4287§ions=&version=\idfReleaseName}{Submit Document Feedback}} + \fancyfoot[L]{Espressif Systems} + \fancyfoot[R]{\idfReleaseName} + \renewcommand{\headrulewidth}{0.4pt} + \renewcommand{\footrulewidth}{0.4pt} + } +\makeatother + +\renewcommand{\headrulewidth}{0.5pt} +\renewcommand{\footrulewidth}{0.5pt} + + +% Define a spacing for section, subsection and subsubsection +% http://tex.stackexchange.com/questions/108684/spacing-before-and-after-section-titles + +\titlespacing*{\section}{0pt}{6pt plus 0pt minus 0pt}{6pt plus 0pt minus 0pt} +\titlespacing*{\subsection}{0pt}{18pt plus 64pt minus 0pt}{0pt} +\titlespacing*{\subsubsection}{0pt}{12pt plus 0pt minus 0pt}{0pt} +\titlespacing*{\paragraph} {0pt}{3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex} +\titlespacing*{\subparagraph} {0pt}{3.25ex plus 1ex minus .2ex}{1.5ex plus .2ex} + +% Define the colors of table of contents +% This is helpful to understand http://tex.stackexchange.com/questions/110253/what-the-first-argument-for-lsubsection-actually-is +\definecolor{LochmaraColor}{HTML}{1020A0} + +% Hyperlinks +\hypersetup{ + colorlinks = true, + allcolors = {LochmaraColor}, +} + + +\RequirePackage{tocbibind} %%% comment this to remove page number for following +\addto\captionsenglish{\renewcommand{\contentsname}{Table of contents}} +\addto\captionsenglish{\renewcommand{\listfigurename}{List of figures}} +\addto\captionsenglish{\renewcommand{\listtablename}{List of tables}} +% \addto\captionsenglish{\renewcommand{\chaptername}{Chapter}} + + + + +%%reduce spacing for itemize +\usepackage{enumitem} +\setlist{nosep} + +%%%%%%%%%%% Quote Styles at the top of chapter +\usepackage{epigraph} +\setlength{\epigraphwidth}{0.8\columnwidth} +\newcommand{\chapterquote}[2]{\epigraphhead[60]{\epigraph{\textit{#1}}{\textbf {\textit{--#2}}}}} +%%%%%%%%%%% Quote for all places except Chapter +\newcommand{\sectionquote}[2]{{\quote{\textit{``#1''}}{\textbf {\textit{--#2}}}}} + +% Insert 22pt white space before roc title. \titlespacing at line 65 changes it by -22 later on. +\renewcommand*\contentsname{\hspace{0pt}Contents} + + +% Define section, subsection and subsubsection font size and color +\usepackage{sectsty} +\definecolor{AllportsColor}{HTML}{A02010} +\allsectionsfont{\color{AllportsColor}} + +\usepackage{titlesec} +\titleformat{\section} +{\color{AllportsColor}\LARGE\bfseries}{\thesection.}{1em}{} + +\titleformat{\subsection} +{\color{AllportsColor}\Large\bfseries}{\thesubsection.}{1em}{} + +\titleformat{\subsubsection} +{\color{AllportsColor}\large\bfseries}{\thesubsubsection.}{1em}{} + +\titleformat{\paragraph} +{\color{AllportsColor}\large\bfseries}{\theparagraph}{1em}{} + +\titleformat{\subparagraph} + {\normalfont\normalsize\bfseries}{\thesubparagraph}{1em}{} + +\titleformat{\subsubparagraph} + {\normalfont\normalsize\bfseries}{\thesubsubparagraph}{1em}{} diff --git a/docs/latex_templates/titlepage.tex b/docs/latex_templates/titlepage.tex new file mode 100644 index 0000000000..768362366f --- /dev/null +++ b/docs/latex_templates/titlepage.tex @@ -0,0 +1,39 @@ +\makeatletter +\newgeometry{left=0cm,right=0cm,bottom=2cm} + + +\cfoot{www.espressif.com} + +\renewcommand{\headrulewidth}{0pt} + +{\color{myred}\rule{30pt}{2.1cm}} + \hspace{0.2cm} + \begin{minipage}[b]{18cm} + {\fontsize{36pt}{48pt}\textbf{\idfTarget}}\\ + + {\fontsize{28pt}{18pt}\textbf{\color{mygrayy}\@title}} + \end{minipage} + \hspace{\stretch{1}} + +\vspace{48em} + + +\begin{flushright} + \setlength\parindent{8em} + \begin{minipage}[b]{2cm} + \sphinxlogo + \end{minipage} + \hspace{0.2cm} + \rule{3pt}{1.9cm} + \hspace{0.2cm} + \begin{minipage}[b]{7cm} + {\large{\idfReleaseName}}\smallskip\newline + {\large{\@author}}\smallskip\newline + {\large{\@date}}\smallskip + \end{minipage} + {\color{myred}\rule{30pt}{1.9cm}} +\end{flushright} + + +\restoregeometry +\makeatother \ No newline at end of file diff --git a/docs/link-roles.py b/docs/link-roles.py index e97eb2e6e9..f3bb2a6cb1 100644 --- a/docs/link-roles.py +++ b/docs/link-roles.py @@ -6,6 +6,7 @@ import re import os from docutils import nodes from local_util import run_cmd_get_output +from sphinx.transforms.post_transforms import SphinxPostTransform def get_github_rev(): @@ -34,17 +35,42 @@ def setup(app): app.add_role('example_raw', autolink('{}/raw/{}/examples/%s'.format(baseurl, rev))) # link to the current documentation file in specific language version - on_rtd = os.environ.get('READTHEDOCS', None) == 'True' - if on_rtd: - # provide RTD specific commit identification to be included in the link - tag_rev = 'latest' - if (run_cmd_get_output('git rev-parse --short HEAD') != rev): - tag_rev = rev - else: - # if not on the RTD then provide generic identification - tag_rev = run_cmd_get_output('git describe --always') + app.add_role('link_to_translation', link_to_translation) + app.add_node(translation_link) + app.add_post_transform(TranslationLinkNodeTransform) - app.add_role('link_to_translation', crosslink('%s../../%s/{}/%s.html'.format(tag_rev))) + +class translation_link(nodes.Element): + """Node for "link_to_translation" role.""" + + +# Linking to translation is done at the "writing" stage to avoid issues with the info being cached between builders +def link_to_translation(name, rawtext, text, lineno, inliner, options={}, content=[]): + node = translation_link() + node['expr'] = (rawtext, text, options) + return [node], [] + + +class TranslationLinkNodeTransform(SphinxPostTransform): + # Transform needs to happen early to ensure the new reference node is also transformed + default_priority = 0 + + def run(self, **kwargs): + + # Only output relative links if building HTML + for node in self.document.traverse(translation_link): + if 'html' in self.app.builder.name: + rawtext, text, options = node['expr'] + (language, link_text) = text.split(':') + env = self.document.settings.env + docname = env.docname + doc_path = env.doc2path(docname, None, None) + return_path = '../' * doc_path.count('/') # path back to the root from 'docname' + # then take off 2 more paths for language/release/ and build the new URL + url = '{}.html'.format(os.path.join(return_path, '../..', language, env.config.release, docname)) + node.replace_self(nodes.reference(rawtext, link_text, refuri=url, **options)) + else: + node.replace_self([]) def autolink(pattern): diff --git a/docs/requirements.txt b/docs/requirements.txt index 9b8810644d..76f0fde7ba 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,16 +1,14 @@ # This is a list of python packages used to generate documentation. This file is used with pip: # pip install --user -r requirements.txt # -sphinx>=1.8.4 -breathe==4.11.1 -sphinx-rtd-theme -sphinxcontrib-blockdiag>=1.5.5, <2.0.0 -sphinxcontrib-seqdiag>=0.8.5, <2.0.0 -sphinxcontrib-actdiag>=0.8.5, <2.0.0 -sphinxcontrib-nwdiag>=0.9.5, <2.0.0 -blockdiag>=1.5.4, <2.0.0 -seqdiag>=0.9.6, <2.0.0 -actdiag>=0.5.4, <2.0.0 -nwdiag>=1.0.4, <2.0.0 +sphinx==2.3.1 +breathe==4.14.1 +sphinxcontrib-blockdiag==2.0.0 +sphinxcontrib-seqdiag==2.0.0 +sphinxcontrib-actdiag==2.0.0 +sphinxcontrib-nwdiag==2.0.0 +sphinxcontrib-wavedrom==2.0.0 +nwdiag==2.0.0 recommonmark future>=0.16.0 # for ../tools/gen_esp_err_to_name.py +sphinx_idf_theme==0.2 diff --git a/docs/sanitize_version.py b/docs/sanitize_version.py new file mode 100644 index 0000000000..90e9101678 --- /dev/null +++ b/docs/sanitize_version.py @@ -0,0 +1,43 @@ +# Tiny Python module to sanitize a Git version into something that can be used in a URL +# +# (this is used in multiple places: conf_common.py and in tools/ci/docs_deploy +# +# Copyright 2020 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + + +def sanitize_version(original_version): + """ Given a version (probably output from 'git describe --always' or similar), return + a URL-safe sanitized version. (this is used as 'release' config variable when building + the docs.) + + Will override the original version with the Gitlab CI CI_COMMIT_REF_NAME environment variable if + this is present. + + Also follows the RTD-ism that master branch is named 'latest' + + """ + + try: + version = os.environ['CI_COMMIT_REF_NAME'] + except KeyError: + version = original_version + + if version == "master": + return "latest" + + version = version.replace('/', '-') + + return version diff --git a/docs/zh_CN/api-guides/unit-tests-cmake.rst b/docs/zh_CN/api-guides/unit-tests-cmake.rst index c5f8898b7d..d00eb3a251 100644 --- a/docs/zh_CN/api-guides/unit-tests-cmake.rst +++ b/docs/zh_CN/api-guides/unit-tests-cmake.rst @@ -32,7 +32,7 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test” 来声明主函数的区域, ``unity_platform.c`` 会自动调用 ``UNITY_BEGIN()``\ , 然后运行测试用例,最后调用 ``UNITY_END()``\ 。 -``test`` 子目录需要包含 :ref:`组件 CMakeLists.txt `,因为他们本身就是一种组件。ESP-IDF 使用了 +``test`` 子目录需要包含 :ref:`组件 CMakeLists.txt `,因为他们本身就是一种组件。ESP-IDF 使用了 ``unity`` 测试框架,需要将其指定为组件的依赖项。通常,组件 :ref:`需要手动指定待编译的源文件 `;但是,对于测试组件来说,这个要求被放宽了,仅仅是建议使用 “COMPONENT_SRCDIRS”。 @@ -103,14 +103,14 @@ DUT 进行写入和运行测试。 DUT1(master)终端: -.. code:: bash +.. code:: Waiting for signal: [output high level]! Please press "Enter" key once any board send this signal. DUT2(slave)终端: -.. code:: bash +.. code:: Send signal: [output high level]! @@ -179,7 +179,7 @@ DUT2(slave)终端: 当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目。 -.. code:: bash +.. code:: Here's the test menu, pick your combo: (1) "esp_ota_begin() verifies arguments" [ota] @@ -226,7 +226,7 @@ DUT2(slave)终端: 一旦选择了多设备测试用例,它会打印一个子菜单: -.. code:: bash +.. code:: Running gpio master/slave test example... gpio master/slave test example @@ -237,7 +237,7 @@ DUT2(slave)终端: 与多设备测试用例相似,多阶段测试用例也会打印子菜单: -.. code:: bash +.. code:: Running reset reason check for deepsleep... reset reason check for deepsleep diff --git a/docs/zh_CN/api-guides/unit-tests.rst b/docs/zh_CN/api-guides/unit-tests.rst index de8e52d3ef..44b78951e7 100644 --- a/docs/zh_CN/api-guides/unit-tests.rst +++ b/docs/zh_CN/api-guides/unit-tests.rst @@ -17,7 +17,7 @@ C 文件可以包含多个测试用例。测试文件的名字要以 “test” 测试用例需要通过 C 文件中特定的函数来添加,如下所示: -.. code:: c +.. code-block:: c TEST_CASE("test name", "[module name]" { @@ -187,7 +187,7 @@ DUT2 终端:: 当单元测试应用程序空闲时,输入回车键,它会打印出测试菜单,其中包含所有的测试项目。 -.. code:: bash +.. code:: Here's the test menu, pick your combo: (1) "esp_ota_begin() verifies arguments" [ota] @@ -234,7 +234,7 @@ DUT2 终端:: 一旦选择了多设备测试用例,它会打印一个子菜单: -.. code:: bash +.. code:: Running gpio master/slave test example... gpio master/slave test example @@ -245,7 +245,7 @@ DUT2 终端:: 与多设备测试用例相似,多阶段测试用例也会打印子菜单: -.. code:: bash +.. code:: Running reset reason check for deepsleep... reset reason check for deepsleep diff --git a/docs/zh_CN/conf.py b/docs/zh_CN/conf.py index 567585ffbd..b9f147546f 100644 --- a/docs/zh_CN/conf.py +++ b/docs/zh_CN/conf.py @@ -16,7 +16,7 @@ except ImportError: # General information about the project. project = u'ESP-IDF 编程指南' -copyright = u'2016 - 2020 乐鑫信息科技(上海)股份有限公司' +copyright = u'2016 - 2021 乐鑫信息科技(上海)股份有限公司' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/zh_CN/get-started-cmake/index.rst b/docs/zh_CN/get-started-cmake/index.rst index 7e4ac5de65..1192905d05 100644 --- a/docs/zh_CN/get-started-cmake/index.rst +++ b/docs/zh_CN/get-started-cmake/index.rst @@ -1,421 +1,421 @@ -******************************** -快速入门 (CMake) -******************************** - -:link_to_translation:`en:[英文]` - -.. include:: ../cmake-warning.rst - -.. include:: ../cmake-pending-features.rst - -本文档旨在指导用户创建 ESP32 的软件环境。本文将通过一个简单的例子,说明 ESP-IDF (Espressif IoT Development Framework) 的使用方法,包括配置、编译、下载固件到开发板等步骤。 - -.. include:: /_build/inc/version-note.inc - -概述 -============ - -ESP32 是一套 Wi-Fi (2.4 GHz) 和蓝牙 (4.2) 双模解决方案,集成了高性能的 CPU 内核、超低功耗协处理器和丰富的外设。ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用和不同功耗需求。 - -乐鑫为用户提供完整的软、硬件资源,支持 ESP32 设备的开发。我们的软件开发环境 ESP-IDF 能够帮助用户快速开发物联网 (IoT) 应用,满足用户对于 Wi-Fi、蓝牙、低功耗等性能的需求。 - - -准备工作 -==================== - -开发 ESP32 应用程序需要准备: - -* **电脑**:安装 Windows、Linux 或者 Mac 操作系统 -* **工具链**:用于编译 ESP32 代码 -* **编译工具**:用于编译 ESP32 完整**应用程序**的 CMake 和 Ninja -* **ESP-IDF**:包含 ESP32 API 和用于操作 **工具链** 的脚本 -* **文本编辑器**:编写 C 语言程序,例如 `Eclipse `_ -* **ESP32 开发板** 和将其连接到 **电脑** 的 **USB 线** - -.. figure:: ../../_static/what-you-need-cmake.png - :align: center - :alt: Development of applications for ESP32 - :figclass: align-center - - 开发应用程序 - -开发环境的准备工作包括以下两部分: - -1. 设置 **工具链** -2. 从 GitHub 上获取 **ESP-IDF** - -开发环境设置完成后,遵循以下步骤创建 ESP-IDF 应用程序: - -1. 配置**工程** 并编写代码 -2. 编译**工程** 并链接成一个**应用程序** -3. 通过 USB/串口连接,烧录(上传)预编译的**应用程序**到 **ESP32** -4. 通过 USB/串口,监视/调试**应用程序**输出 - - -.. The label below is placeholder to link a new section "Installation Step by Step" - -.. _get-started-step-by-step-cmake: - -开发板指南 -======================== - -如果你有下列任一 ESP32 开发板,请点击对应的链接进行硬件设置: - -.. toctree:: - :maxdepth: 1 - - ESP32 DevKitC - ESP-WROVER-KIT - ESP32-PICO-KIT - -如果你使用其它开发板,请查看下面的内容。 - - -.. _get-started-setup-toolchain-cmake: - -设置工具链 -====================== - -用 ESP32 进行开发最快的方法是安装预编译的工具链。请根据你的操作系,点击对应的链接,并按照链接中的指导进行安装。 - -.. toctree:: - :hidden: - - Windows - Linux - MacOS - -+-------------------+-------------------+-------------------+ -| |windows-logo| | |linux-logo| | |macos-logo| | -+-------------------+-------------------+-------------------+ -| `Windows`_ | `Linux`_ | `Mac OS`_ | -+-------------------+-------------------+-------------------+ - -.. |windows-logo| image:: ../../_static/windows-logo.png - :target: ../get-started-cmake/windows-setup.html - -.. |linux-logo| image:: ../../_static/linux-logo.png - :target: ../get-started-cmake/linux-setup.html - -.. |macos-logo| image:: ../../_static/macos-logo.png - :target: ../get-started-cmake/macos-setup.html - -.. _Windows: ../get-started-cmake/windows-setup.html -.. _Linux: ../get-started-cmake/linux-setup.html -.. _Mac OS: ../get-started-cmake/macos-setup.html - -.. note:: - - 我们使用用户名主目录下的 ``esp`` 子目录(Linux 和 MacOS 为 ``~/esp``,Windows 为 ``%userprofile%\esp``)来进行一切有关 ESP-IDF 的安装操作。你也可以使用其他目录,但是需要注意调整相应的指令。 - -你可以安装预编译的工具链或者自定义你的环境,这完全取决于个人经验和偏好。如果你要自定义环境,请参考 :ref:`get-started-customized-setup-cmake`。 - -工具链设置完成后,继续阅读 :ref:`get-started-get-esp-idf-cmake` 一节。 - -.. _get-started-get-esp-idf-cmake: - -获取 ESP-IDF -================== - -工具链(包括用于编译和构建应用程序的程序)安装完成后,你还需要 ESP32 相关的 API/库。你可在乐鑫提供的 `ESP-IDF 仓库 `_ 中获取 API/库本地副本。打开终端,切换到你要存放 ESP-IDF 的目录,然后使用 ``git clone`` 命令克隆远程仓库。 - -Linux 和 MacOS -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库: - -.. include:: /_build/inc/git-clone-bash.inc - -ESP-IDF 将会被下载到 ``~/esp/esp-idf`` 目录下。 - -有关在给定情况下使用哪个 ESP-IDF 版本的信息,请参阅 :doc:`/versions` 。 - -Windows Command Prompt -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. include:: /_build/inc/git-clone-windows.inc - -ESP-IDF 将会被下载到用户的 ``esp\esp-idf`` 目录下。 - -有关在给定情况下使用哪个 ESP-IDF 版本的信息,请参阅 :doc:`/versions` 。 - -.. include:: /_build/inc/git-clone-notes.inc - -.. highlight:: bash -.. note:: - - 注意这里有个 ``--recursive`` 选项。如果你克隆 ESP-IDF 时没有带这个选项,你还需要运行额外的命令来获取子模块:: - - cd esp-idf - git submodule update --init - -.. _get-started-setup-path-cmake: - -设置环境变量 -=========================== - -ESP-IDF 的正常运行需要设置两个环境变量: - -- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 -- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 - -你需在你的电脑中设置这两个变量,否则工程将不能编译。 - -你可以在每次 PC 重启时手动设置,你也可以在用户配置中进行永久设置,具体请参照 :doc:`add-idf_path-to-profile` 小节中的 :ref:`Windows `,:ref:`Linux 和 MacOS ` 相关指导进行操作。 - -.. _get-started-start-project-cmake: - -创建一个工程 -====================== - -现在可以开始创建 ESP32 应用程序了。为了快速开始,我们这里以 IDF 的 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程为例进行说明。 - -将 :example:`get-started/hello_world` 拷贝到 ``~/esp`` 目录: - -Linux 和 MacOS -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp - cp -r $IDF_PATH/examples/get-started/hello_world . - -Windows Command Prompt -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp - xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world - -ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。 - -你也可以在原有位置创建示例,无需事先拷贝这些示例。 - -.. important:: - - esp-idf 构建系统不支持在路径中存在空格。 - -.. _get-started-connect-cmake: - -连接 -======= - -还有几个步骤就完成了。在继续后续操作前,先将 ESP32 开发板连接到 PC,然后检查串口号,看看它能否正常通信。如果你不知道如何操作,请查看 :doc:`establish-serial-connection` 中的相关指导。请注意一下端口号,我们在下一步中会用到。 - -.. _get-started-configure-cmake: - -配置 -========= - -进入 ``hello_world`` 应用程序副本目录,运行 ``menuconfig`` 工程配置工具: - -Linux 和 MacOS -~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: bash - - cd ~/esp/hello_world - idf.py menuconfig - -Windows Command Prompt -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. code-block:: batch - - cd %userprofile%\esp\hello_world - idf.py menuconfig - -.. note:: 如果你收到未发现 ``idf.py`` 的报错信息,查看是否如上 :ref:`get-started-setup-path-cmake` 所述将 ``tools`` 目录添加到你的路径中。如果 ``tools`` 目录中没有 ``idf.py``,查看 :ref:`get-started-get-esp-idf-cmake` 中 CMake 预览所处的分支是否正确。 - -.. note:: 对于 Windows 用户而言,Python 2.7 安装器会尝试配置 Windows,关联扩展名为 ``.py`` 的 Python 2 文件。如果单独安装的程序(如 Visual Studio Python 工具)关联到其他 Python 版本,``idf.py`` 可能无法运行(而仅是在 Visual Studio 中打开此文件)。你可以每次运行 ``C:\Python27\python idf.py`` 或更改 Windows 中有关``.py`` 文件的关联设置。 - -.. note:: 对于 Linux 用户而言,如果默认为 Python 3.x 版本,你需要运行 ``python2 idf.py``。 - -如果之前的步骤都正确,则会显示下面的菜单: - -.. figure:: ../../_static/project-configuration.png - :align: center - :alt: Project configuration - Home window - :figclass: align-center - - 工程配置 - 主窗口 - -下面是一些使用 ``menuconfig`` 的小技巧: - -* 使用 up & down 组合键在菜单中上下移动 -* 使用 Enter 键进入一个子菜单,Escape 键进入上一层菜单或退出整个菜单 -* 输入 ``?`` 查看帮助信息,Enter 键退出帮助屏幕 -* 使用空格键或 ``Y`` 和 ``N`` 键来使能 (Yes) 和禁止 (No) 带有复选框 "``[*]``" 的配置项 -* 当光标在某个配置项上面高亮时,输入 ``?`` 可以直接查看该项的帮助信息 -* 输入 ``/`` 搜索配置项 - -.. attention:: - - 如果 ESP32-DevKitC 板载的是 ESP32-SOLO-1 模组,请务必在烧写示例程序之前在 menuconfig 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 - -.. _get-started-build-cmake: - -创建一个工程 -========================== - -.. highlight:: bash - -现在可以编译工程了,执行指令:: - - idf.py build - -这条命令会编译应用程序和所有的 ESP-IDF 组件,生成 bootloader、区分表和应用程序 bin 文件。 - -.. code-block:: none - - $ idf.py build - Running cmake in directory /path/to/hello_world/build - Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... - Warn about uninitialized values. - -- Found Git: /usr/bin/git (found version "2.17.0") - -- Building empty aws_iot component due to configuration - -- Component names: ... - -- Component paths: ... - - ... (more lines of build system output) - - [527/527] Generating hello-world.bin - esptool.py v2.3.1 - - Project build complete. To flash, run this command: - ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin - or run 'idf.py -p PORT flash' - -如果没有任何报错,将会生成 bin 文件,至此编译完成。 - -.. _get-started-flash-cmake: - -烧录到设备 -========================== - -现在可以将应用程序烧录到 ESP32 板子上,执行指令:: - - idf.py -p PORT flash - -将端口改为 ESP32 板子的串口名称。Windows 平台的端口名称类似 ``COM1``,而 MacOS 则以 ``/dev/cu.`` 开头,Linux 则是 ``/dev/tty``。详情请参照 :doc:`establish-serial-connection`。 - -该步骤旨在将此前编译的 bin 文件烧录到 ESP32 板子上。 - -.. note:: 无需在 ``idf.py flash`` 之前运行 ``idf.py build``,烧录这一步会按照烧录前编写的要求(如有)自动编写工程。 - -.. code-block:: none - - Running esptool.py in directory [...]/esp/hello_world - Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... - esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin - esptool.py v2.3.1 - Connecting.... - Detecting chip type... ESP32 - Chip is ESP32D0WDQ6 (revision 1) - Features: WiFi, BT, Dual Core - Uploading stub... - Running stub... - Stub running... - Changing baud rate to 460800 - Changed. - Configuring flash size... - Auto-detected Flash size: 4MB - Flash params set to 0x0220 - Compressed 22992 bytes to 13019... - Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... - Hash of data verified. - Compressed 3072 bytes to 82... - Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... - Hash of data verified. - Compressed 136672 bytes to 67544... - Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... - Hash of data verified. - - Leaving... - Hard resetting via RTS pin... - -如果没有任何问题,在烧录的最后阶段,板子将会复位,应用程序 "hello_world" 开始运行。 - -.. (目前暂不支持)如果你想使用 Eclipse IDE 而不是运行 ``idf.py``,请参考 :doc:`Eclipse guide `。 - - -.. _get-started-build-monitor-cmake: - -监视器 -================ - -如果要查看 "hello_world" 程序是否真的在运行,输入命令 ``idf.py -p PORT monitor``。这个命令会启动 :doc:`IDF Monitor ` 程序:: - - $ idf.py -p /dev/ttyUSB0 monitor - Running idf_monitor in directory [...]/esp/hello_world/build - Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... - --- idf_monitor on /dev/ttyUSB0 115200 --- - --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- - ets Jun 8 2016 00:22:57 - - rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) - ets Jun 8 2016 00:22:57 - ... - -在启动消息和诊断消息后,你就能看到 "Hello world!" 程序所打印的消息: - -.. code-block:: none - - ... - Hello world! - Restarting in 10 seconds... - I (211) cpu_start: Starting scheduler on APP CPU. - Restarting in 9 seconds... - Restarting in 8 seconds... - Restarting in 7 seconds... - -要退出监视器,请使用快捷键 ``Ctrl+]``。 - -.. note:: - - 如果串口打印的不是上面显示的消息而是类似下面的乱码:: - - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - - 或者监视器程序启动失败,那么可能你的开发板用的是 26 MHz 晶振,而大多数开发板用的是 40 MHz 晶振,并且 ESP-IDF 默认的也是这一数值。请退出监视器,回到 :ref:`menuconfig `,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 改为 26 MHz,然后再次 :ref:`编写和烧录 ` 程序。请在 ``idf.py menuconfig`` 的 Component config --> ESP32-specific --> Main XTAL frequency 中配置。 - -.. note:: - - 你可以将编写、烧录和监视整合到一步当中,如下所示:: - - idf.py -p PORT flash monitor - -有关监视器使用的快捷键和其他详情,请参阅 :doc:`IDF Monitor `。 - -有关 ``idf.py`` 的全部命令和选项,请参阅 :ref:`idf.py`。 - -你已完成 ESP32 的入门! - -现在你可以尝试其他的示例工程 :idf:`examples`,或者直接开发自己的应用程序。 - - -更新 ESP-IDF -============= - -使用 ESP-IDF 一段时间后,您可能想通过升级来获取新的功能或者修复 bug,最简单的升级方式就是删除已有的 ``esp-idf`` 文件夹然后重新克隆一个,即重复 :ref:`get-started-get-esp-idf` 里的操作。 - -然后 :doc:`添加 IDF 到工作路径 `,这样工具链脚本就能够知道这一版本的 ESP-IDF 的具体位置。 - -另外一种方法是只更新有改动的部分。:ref:`更新步骤取决于现在用的ESP-IDF版本 `。 - -相关文档 -================= - -.. toctree:: - :maxdepth: 1 - - add-idf_path-to-profile - establish-serial-connection - eclipse-setup - idf-monitor - toolchain-setup-scratch - -.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ -.. _Releases page: https://github.com/espressif/esp-idf/releases +******************************** +快速入门 (CMake) +******************************** + +:link_to_translation:`en:[英文]` + +.. include:: ../cmake-warning.rst + +.. include:: ../cmake-pending-features.rst + +本文档旨在指导用户创建 ESP32 的软件环境。本文将通过一个简单的例子,说明 ESP-IDF (Espressif IoT Development Framework) 的使用方法,包括配置、编译、下载固件到开发板等步骤。 + +.. include:: /_build/inc/version-note.inc + +概述 +============ + +ESP32 是一套 Wi-Fi (2.4 GHz) 和蓝牙 (4.2) 双模解决方案,集成了高性能的 CPU 内核、超低功耗协处理器和丰富的外设。ESP32 采用 40 nm 工艺制成,具有最佳的功耗性能、射频性能、稳定性、通用性和可靠性,适用于各种应用和不同功耗需求。 + +乐鑫为用户提供完整的软、硬件资源,支持 ESP32 设备的开发。我们的软件开发环境 ESP-IDF 能够帮助用户快速开发物联网 (IoT) 应用,满足用户对于 Wi-Fi、蓝牙、低功耗等性能的需求。 + + +准备工作 +==================== + +开发 ESP32 应用程序需要准备: + +* **电脑**:安装 Windows、Linux 或者 Mac 操作系统 +* **工具链**:用于编译 ESP32 代码 +* **编译工具**:用于编译 ESP32 完整**应用程序**的 CMake 和 Ninja +* **ESP-IDF**:包含 ESP32 API 和用于操作 **工具链** 的脚本 +* **文本编辑器**:编写 C 语言程序,例如 `Eclipse `_ +* **ESP32 开发板** 和将其连接到 **电脑** 的 **USB 线** + +.. figure:: ../../_static/what-you-need-cmake.png + :align: center + :alt: Development of applications for ESP32 + :figclass: align-center + + 开发应用程序 + +开发环境的准备工作包括以下两部分: + +1. 设置 **工具链** +2. 从 GitHub 上获取 **ESP-IDF** + +开发环境设置完成后,遵循以下步骤创建 ESP-IDF 应用程序: + +1. 配置**工程** 并编写代码 +2. 编译**工程** 并链接成一个**应用程序** +3. 通过 USB/串口连接,烧录(上传)预编译的**应用程序**到 **ESP32** +4. 通过 USB/串口,监视/调试**应用程序**输出 + + +.. The label below is placeholder to link a new section "Installation Step by Step" + +.. _get-started-step-by-step-cmake: + +开发板指南 +======================== + +如果你有下列任一 ESP32 开发板,请点击对应的链接进行硬件设置: + +.. toctree:: + :maxdepth: 1 + + ESP32 DevKitC + ESP-WROVER-KIT + ESP32-PICO-KIT + +如果你使用其它开发板,请查看下面的内容。 + + +.. _get-started-setup-toolchain-cmake: + +设置工具链 +====================== + +用 ESP32 进行开发最快的方法是安装预编译的工具链。请根据你的操作系,点击对应的链接,并按照链接中的指导进行安装。 + +.. toctree:: + :hidden: + + Windows + Linux + MacOS + ++-------------------+-------------------+-------------------+ +| |windows-logo| | |linux-logo| | |macos-logo| | ++-------------------+-------------------+-------------------+ +| `Windows`_ | `Linux`_ | `Mac OS`_ | ++-------------------+-------------------+-------------------+ + +.. |windows-logo| image:: ../../_static/windows-logo.png + :target: ../get-started-cmake/windows-setup.html + +.. |linux-logo| image:: ../../_static/linux-logo.png + :target: ../get-started-cmake/linux-setup.html + +.. |macos-logo| image:: ../../_static/macos-logo.png + :target: ../get-started-cmake/macos-setup.html + +.. _Windows: ../get-started-cmake/windows-setup.html +.. _Linux: ../get-started-cmake/linux-setup.html +.. _Mac OS: ../get-started-cmake/macos-setup.html + +.. note:: + + 我们使用用户名主目录下的 ``esp`` 子目录(Linux 和 MacOS 为 ``~/esp``,Windows 为 ``%userprofile%\esp``)来进行一切有关 ESP-IDF 的安装操作。你也可以使用其他目录,但是需要注意调整相应的指令。 + +你可以安装预编译的工具链或者自定义你的环境,这完全取决于个人经验和偏好。如果你要自定义环境,请参考 :ref:`get-started-customized-setup-cmake`。 + +工具链设置完成后,继续阅读 :ref:`get-started-get-esp-idf-cmake` 一节。 + +.. _get-started-get-esp-idf-cmake: + +获取 ESP-IDF +================== + +工具链(包括用于编译和构建应用程序的程序)安装完成后,你还需要 ESP32 相关的 API/库。你可在乐鑫提供的 `ESP-IDF 仓库 `_ 中获取 API/库本地副本。打开终端,切换到你要存放 ESP-IDF 的目录,然后使用 ``git clone`` 命令克隆远程仓库。 + +Linux 和 MacOS +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +获取本地副本:打开终端,切换到你要存放 ESP-IDF 的工作目录,使用 ``git clone`` 命令克隆远程仓库: + +.. include:: /_build/inc/git-clone-bash.inc + +ESP-IDF 将会被下载到 ``~/esp/esp-idf`` 目录下。 + +有关在给定情况下使用哪个 ESP-IDF 版本的信息,请参阅 :doc:`/versions` 。 + +Windows Command Prompt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. include:: /_build/inc/git-clone-windows.inc + +ESP-IDF 将会被下载到用户的 ``esp\esp-idf`` 目录下。 + +有关在给定情况下使用哪个 ESP-IDF 版本的信息,请参阅 :doc:`/versions` 。 + +.. include:: /_build/inc/git-clone-notes.inc + +.. highlight:: bash +.. note:: + + 注意这里有个 ``--recursive`` 选项。如果你克隆 ESP-IDF 时没有带这个选项,你还需要运行额外的命令来获取子模块:: + + cd esp-idf + git submodule update --init + +.. _get-started-setup-path-cmake: + +设置环境变量 +=========================== + +ESP-IDF 的正常运行需要设置两个环境变量: + +- ``IDF_PATH`` 应设置为 ESP-IDF 根目录的路径。 +- ``PATH`` 应包括同一 ``IDF_PATH`` 目录下的 ``tools`` 目录路径。 + +你需在你的电脑中设置这两个变量,否则工程将不能编译。 + +你可以在每次 PC 重启时手动设置,你也可以在用户配置中进行永久设置,具体请参照 :doc:`add-idf_path-to-profile` 小节中的 :ref:`Windows `,:ref:`Linux 和 MacOS ` 相关指导进行操作。 + +.. _get-started-start-project-cmake: + +创建一个工程 +====================== + +现在可以开始创建 ESP32 应用程序了。为了快速开始,我们这里以 IDF 的 :idf:`examples` 目录下的 :example:`get-started/hello_world` 工程为例进行说明。 + +将 :example:`get-started/hello_world` 拷贝到 ``~/esp`` 目录: + +Linux 和 MacOS +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp + cp -r $IDF_PATH/examples/get-started/hello_world . + +Windows Command Prompt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp + xcopy /e /i %IDF_PATH%\examples\get-started\hello_world hello_world + +ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照上面的方法进行创建。 + +你也可以在原有位置创建示例,无需事先拷贝这些示例。 + +.. important:: + + esp-idf 构建系统不支持在路径中存在空格。 + +.. _get-started-connect-cmake: + +连接 +======= + +还有几个步骤就完成了。在继续后续操作前,先将 ESP32 开发板连接到 PC,然后检查串口号,看看它能否正常通信。如果你不知道如何操作,请查看 :doc:`establish-serial-connection` 中的相关指导。请注意一下端口号,我们在下一步中会用到。 + +.. _get-started-configure-cmake: + +配置 +========= + +进入 ``hello_world`` 应用程序副本目录,运行 ``menuconfig`` 工程配置工具: + +Linux 和 MacOS +~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: bash + + cd ~/esp/hello_world + idf.py menuconfig + +Windows Command Prompt +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: batch + + cd %userprofile%\esp\hello_world + idf.py menuconfig + +.. note:: 如果你收到未发现 ``idf.py`` 的报错信息,查看是否如上 :ref:`get-started-setup-path-cmake` 所述将 ``tools`` 目录添加到你的路径中。如果 ``tools`` 目录中没有 ``idf.py``,查看 :ref:`get-started-get-esp-idf-cmake` 中 CMake 预览所处的分支是否正确。 + +.. note:: 对于 Windows 用户而言,Python 2.7 安装器会尝试配置 Windows,关联扩展名为 ``.py`` 的 Python 2 文件。如果单独安装的程序(如 Visual Studio Python 工具)关联到其他 Python 版本,``idf.py`` 可能无法运行(而仅是在 Visual Studio 中打开此文件)。你可以每次运行 ``C:\Python27\python idf.py`` 或更改 Windows 中有关``.py`` 文件的关联设置。 + +.. note:: 对于 Linux 用户而言,如果默认为 Python 3.x 版本,你需要运行 ``python2 idf.py``。 + +如果之前的步骤都正确,则会显示下面的菜单: + +.. figure:: ../../_static/project-configuration.png + :align: center + :alt: Project configuration - Home window + :figclass: align-center + + 工程配置 - 主窗口 + +下面是一些使用 ``menuconfig`` 的小技巧: + +* 使用 up & down 组合键在菜单中上下移动 +* 使用 Enter 键进入一个子菜单,Escape 键进入上一层菜单或退出整个菜单 +* 输入 ``?`` 查看帮助信息,Enter 键退出帮助屏幕 +* 使用空格键或 ``Y`` 和 ``N`` 键来使能 (Yes) 和禁止 (No) 带有复选框 "``[*]``" 的配置项 +* 当光标在某个配置项上面高亮时,输入 ``?`` 可以直接查看该项的帮助信息 +* 输入 ``/`` 搜索配置项 + +.. attention:: + + 如果 ESP32-DevKitC 板载的是 ESP32-SOLO-1 模组,请务必在烧写示例程序之前在 menuconfig 中使能单核模式(:ref:`CONFIG_FREERTOS_UNICORE`)。 + +.. _get-started-build-cmake: + +创建一个工程 +========================== + +.. highlight:: bash + +现在可以编译工程了,执行指令:: + + idf.py build + +这条命令会编译应用程序和所有的 ESP-IDF 组件,生成 bootloader、区分表和应用程序 bin 文件。 + +.. code-block:: none + + $ idf.py build + Running cmake in directory /path/to/hello_world/build + Executing "cmake -G Ninja --warn-uninitialized /path/to/hello_world"... + Warn about uninitialized values. + -- Found Git: /usr/bin/git (found version "2.17.0") + -- Building empty aws_iot component due to configuration + -- Component names: ... + -- Component paths: ... + + ... (more lines of build system output) + + [527/527] Generating hello-world.bin + esptool.py v2.3.1 + + Project build complete. To flash, run this command: + ../../../components/esptool_py/esptool/esptool.py -p (PORT) -b 921600 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x10000 build/hello-world.bin build 0x1000 build/bootloader/bootloader.bin 0x8000 build/partition_table/partition-table.bin + or run 'idf.py -p PORT flash' + +如果没有任何报错,将会生成 bin 文件,至此编译完成。 + +.. _get-started-flash-cmake: + +烧录到设备 +========================== + +现在可以将应用程序烧录到 ESP32 板子上,执行指令:: + + idf.py -p PORT flash + +将端口改为 ESP32 板子的串口名称。Windows 平台的端口名称类似 ``COM1``,而 MacOS 则以 ``/dev/cu.`` 开头,Linux 则是 ``/dev/tty``。详情请参照 :doc:`establish-serial-connection`。 + +该步骤旨在将此前编译的 bin 文件烧录到 ESP32 板子上。 + +.. note:: 无需在 ``idf.py flash`` 之前运行 ``idf.py build``,烧录这一步会按照烧录前编写的要求(如有)自动编写工程。 + +.. code-block:: none + + Running esptool.py in directory [...]/esp/hello_world + Executing "python [...]/esp-idf/components/esptool_py/esptool/esptool.py -b 460800 write_flash @flash_project_args"... + esptool.py -b 460800 write_flash --flash_mode dio --flash_size detect --flash_freq 40m 0x1000 bootloader/bootloader.bin 0x8000 partition_table/partition-table.bin 0x10000 hello-world.bin + esptool.py v2.3.1 + Connecting.... + Detecting chip type... ESP32 + Chip is ESP32D0WDQ6 (revision 1) + Features: WiFi, BT, Dual Core + Uploading stub... + Running stub... + Stub running... + Changing baud rate to 460800 + Changed. + Configuring flash size... + Auto-detected Flash size: 4MB + Flash params set to 0x0220 + Compressed 22992 bytes to 13019... + Wrote 22992 bytes (13019 compressed) at 0x00001000 in 0.3 seconds (effective 558.9 kbit/s)... + Hash of data verified. + Compressed 3072 bytes to 82... + Wrote 3072 bytes (82 compressed) at 0x00008000 in 0.0 seconds (effective 5789.3 kbit/s)... + Hash of data verified. + Compressed 136672 bytes to 67544... + Wrote 136672 bytes (67544 compressed) at 0x00010000 in 1.9 seconds (effective 567.5 kbit/s)... + Hash of data verified. + + Leaving... + Hard resetting via RTS pin... + +如果没有任何问题,在烧录的最后阶段,板子将会复位,应用程序 "hello_world" 开始运行。 + +.. (目前暂不支持)如果你想使用 Eclipse IDE 而不是运行 ``idf.py``,请参考 :doc:`Eclipse guide `。 + + +.. _get-started-build-monitor-cmake: + +监视器 +================ + +如果要查看 "hello_world" 程序是否真的在运行,输入命令 ``idf.py -p PORT monitor``。这个命令会启动 :doc:`IDF Monitor ` 程序:: + + $ idf.py -p /dev/ttyUSB0 monitor + Running idf_monitor in directory [...]/esp/hello_world/build + Executing "python [...]/esp-idf/tools/idf_monitor.py -b 115200 [...]/esp/hello_world/build/hello-world.elf"... + --- idf_monitor on /dev/ttyUSB0 115200 --- + --- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H --- + ets Jun 8 2016 00:22:57 + + rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) + ets Jun 8 2016 00:22:57 + ... + +在启动消息和诊断消息后,你就能看到 "Hello world!" 程序所打印的消息: + +.. code-block:: none + + ... + Hello world! + Restarting in 10 seconds... + I (211) cpu_start: Starting scheduler on APP CPU. + Restarting in 9 seconds... + Restarting in 8 seconds... + Restarting in 7 seconds... + +要退出监视器,请使用快捷键 ``Ctrl+]``。 + +如果串口打印的不是上面显示的消息而是类似下面的乱码: + +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center + +或者监视器程序启动失败,那么可能你的开发板用的是 26 MHz 晶振,而 ESP-IDF 默认的是 40 MHz 晶振。请退出监视器,回到 :ref:`配置 `,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 改为 26 MHz,然后再次 :ref:`编译和烧写 `。请在 ``make menuconfig`` 的 Component config --> ESP32-specific --> Main XTAL frequency 中配置。 + +.. note:: + + 你可以将编写、烧录和监视整合到一步当中,如下所示:: + + idf.py -p PORT flash monitor + +有关监视器使用的快捷键和其他详情,请参阅 :doc:`IDF Monitor `。 + +有关 ``idf.py`` 的全部命令和选项,请参阅 :ref:`idf.py`。 + +你已完成 ESP32 的入门! + +现在你可以尝试其他的示例工程 :idf:`examples`,或者直接开发自己的应用程序。 + + +更新 ESP-IDF +============= + +使用 ESP-IDF 一段时间后,您可能想通过升级来获取新的功能或者修复 bug,最简单的升级方式就是删除已有的 ``esp-idf`` 文件夹然后重新克隆一个,即重复 :ref:`get-started-get-esp-idf` 里的操作。 + +然后 :doc:`添加 IDF 到工作路径 `,这样工具链脚本就能够知道这一版本的 ESP-IDF 的具体位置。 + +另外一种方法是只更新有改动的部分。:ref:`更新步骤取决于现在用的ESP-IDF版本 `。 + +相关文档 +================= + +.. toctree:: + :maxdepth: 1 + + add-idf_path-to-profile + establish-serial-connection + eclipse-setup + idf-monitor + toolchain-setup-scratch + +.. _Stable version: https://docs.espressif.com/projects/esp-idf/en/stable/ +.. _Releases page: https://github.com/espressif/esp-idf/releases diff --git a/docs/zh_CN/get-started/index.rst b/docs/zh_CN/get-started/index.rst index ccc1061b01..3c72a2002c 100644 --- a/docs/zh_CN/get-started/index.rst +++ b/docs/zh_CN/get-started/index.rst @@ -294,14 +294,14 @@ ESP-IDF 的 :idf:`examples` 目录下有一系列示例工程,都可以按照 要退出监视器,请使用快捷键 ``Ctrl+]``。 -.. note:: +如果串口打印的不是上面显示的消息而是类似下面的乱码: - 如果串口打印的不是上面显示的消息而是类似下面的乱码: :: +.. figure:: ../../_static/get-started-garbled-output.png + :align: center + :alt: Garbled output + :figclass: align-center - e���)(Xn@�y.!��(�PW+)��Hn9a؅/9�!�t5��P�~�k��e�ea�5�jA - ~zY��Y(1�,1�� e���)(Xn@�y.!Dr�zY(�jpi�|�+z5Ymvp - - 或者监视器程序启动失败,那么可能你的开发板用的是 26 MHz 晶振,而 ESP-IDF 默认的是 40 MHz 晶振。请退出监视器,回到 :ref:`配置 `,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 改为 26 MHz,然后再次 :ref:`编译和烧写 `。请在 ``make menuconfig`` 的 Component config --> ESP32-specific --> Main XTAL frequency 中配置。 +或者监视器程序启动失败,那么可能你的开发板用的是 26 MHz 晶振,而 ESP-IDF 默认的是 40 MHz 晶振。请退出监视器,回到 :ref:`配置 `,将 :ref:`CONFIG_ESP32_XTAL_FREQ_SEL` 改为 26 MHz,然后再次 :ref:`编译和烧写 `。请在 ``make menuconfig`` 的 Component config --> ESP32-specific --> Main XTAL frequency 中配置。 要一次性执行 ``make flash`` 和 ``make monitor``,输入 ``make flash monitor``。参考文档 :doc:`IDF Monitor ` 里的快捷键和更多内容。 diff --git a/tools/ci/deploy_docs.py b/tools/ci/deploy_docs.py new file mode 100755 index 0000000000..6b9f2d000e --- /dev/null +++ b/tools/ci/deploy_docs.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python3 +# +# CI script to deploy docs to a webserver. Not useful outside of CI environment +# +# +# Copyright 2020 Espressif Systems (Shanghai) PTE LTD +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import glob +import os +import os.path +import re +import stat +import sys +import subprocess +import tarfile +import packaging.version + + +def env(variable, default=None): + """ Shortcut to return the expanded version of an environment variable """ + return os.path.expandvars(os.environ.get(variable, default) if default else os.environ[variable]) + + +# import sanitize_version from the docs directory, shared with here +sys.path.append(os.path.join(env("IDF_PATH"), "docs")) +from sanitize_version import sanitize_version # noqa + + +def main(): + # if you get KeyErrors on the following lines, it's probably because you're not running in Gitlab CI + git_ver = env("GIT_VER") # output of git describe --always + ci_ver = env("CI_COMMIT_REF_NAME", git_ver) # branch or tag we're building for (used for 'release' & URL) + + version = sanitize_version(ci_ver) + print("Git version: {}".format(git_ver)) + print("CI Version: {}".format(ci_ver)) + print("Deployment version: {}".format(version)) + + if not version: + raise RuntimeError("A version is needed to deploy") + + build_dir = env("DOCS_BUILD_DIR") # top-level local build dir, where docs have already been built + + if not build_dir: + raise RuntimeError("Valid DOCS_BUILD_DIR is needed to deploy") + + url_base = env("DOCS_DEPLOY_URL_BASE") # base for HTTP URLs, used to print the URL to the log after deploying + + docs_server = env("DOCS_DEPLOY_SERVER") # ssh server to deploy to + docs_user = env("DOCS_DEPLOY_SERVER_USER") + docs_path = env("DOCS_DEPLOY_PATH") # filesystem path on DOCS_SERVER + + if not docs_server: + raise RuntimeError("Valid DOCS_DEPLOY_SERVER is needed to deploy") + + if not docs_user: + raise RuntimeError("Valid DOCS_DEPLOY_SERVER_USER is needed to deploy") + + docs_server = "{}@{}".format(docs_user, docs_server) + + if not docs_path: + raise RuntimeError("Valid DOCS_DEPLOY_PATH is needed to deploy") + + print("DOCS_DEPLOY_SERVER {} DOCS_DEPLOY_PATH {}".format(docs_server, docs_path)) + + tarball_path, version_urls = build_doc_tarball(version, git_ver, build_dir) + + deploy(version, tarball_path, docs_path, docs_server) + + print("Docs URLs:") + doc_deploy_type = os.getenv('TYPE') + for vurl in version_urls: + language, _, = vurl.split('/') + tag = '{}'.format(language) + url = "{}/{}/index.html".format(url_base, vurl) # (index.html needed for the preview server) + url = re.sub(r"([^:])//", r"\1/", url) # get rid of any // that isn't in the https:// part + print('[document {}][{}] {}'.format(doc_deploy_type, tag, url)) + + # note: it would be neater to use symlinks for stable, but because of the directory order + # (language first) it's kind of a pain to do on a remote server, so we just repeat the + # process but call the version 'stable' this time + if is_stable_version(version): + print("Deploying again as stable version...") + tarball_path, version_urls = build_doc_tarball("stable", git_ver, build_dir) + deploy("stable", tarball_path, docs_path, docs_server) + + +def deploy(version, tarball_path, docs_path, docs_server): + def run_ssh(commands): + """ Log into docs_server and run a sequence of commands using ssh """ + print("Running ssh: {}".format(commands)) + subprocess.run(["ssh", "-o", "BatchMode=yes", docs_server, "-x", " && ".join(commands)], check=True) + + # copy the version tarball to the server + run_ssh(["mkdir -p {}".format(docs_path)]) + print("Running scp {} to {}".format(tarball_path, "{}:{}".format(docs_server, docs_path))) + subprocess.run(["scp", "-B", tarball_path, "{}:{}".format(docs_server, docs_path)], check=True) + + tarball_name = os.path.basename(tarball_path) + + run_ssh(["cd {}".format(docs_path), + "rm -rf ./*/{}".format(version), # remove any pre-existing docs matching this version + "tar -zxvf {}".format(tarball_name), # untar the archive with the new docs + "rm {}".format(tarball_name)]) + + # Note: deleting and then extracting the archive is a bit awkward for updating stable/latest/etc + # as the version will be invalid for a window of time. Better to do it atomically, but this is + # another thing made much more complex by the directory structure putting language before version... + + +def build_doc_tarball(version, git_ver, build_dir): + """ Make a tar.gz archive of the docs, in the directory structure used to deploy as + the given version """ + version_paths = [] + tarball_path = "{}/{}.tar.gz".format(build_dir, version) + + # find all the 'html/' directories under build_dir + html_dirs = glob.glob("{}/**/html/".format(build_dir), recursive=True) + print("Found %d html directories" % len(html_dirs)) + + pdfs = glob.glob("{}/**/latex/build/*.pdf".format(build_dir), recursive=True) + print("Found %d PDFs in latex directories" % len(pdfs)) + + # add symlink for stable and latest and adds them to PDF blob + symlinks = create_and_add_symlinks(version, git_ver, pdfs) + + def not_sources_dir(ti): + """ Filter the _sources directories out of the tarballs """ + if ti.name.endswith("/_sources"): + return None + + ti.mode |= stat.S_IWGRP # make everything group-writeable + return ti + + try: + os.remove(tarball_path) + except OSError: + pass + + with tarfile.open(tarball_path, "w:gz") as tarball: + for html_dir in html_dirs: + # html_dir has the form '//html/' + language_dirname = os.path.dirname(os.path.dirname(html_dir)) + language = os.path.basename(language_dirname) + + # when deploying, we want the top-level directory layout 'language/version' + archive_path = "{}/{}".format(language, version) + print("Archiving '{}' as '{}'...".format(html_dir, archive_path)) + tarball.add(html_dir, archive_path, filter=not_sources_dir) + version_paths.append(archive_path) + + for pdf_path in pdfs: + # pdf_path has the form '///latex/build' + latex_dirname = os.path.dirname(pdf_path) + pdf_filename = os.path.basename(pdf_path) + language_dirname = os.path.dirname(os.path.dirname(latex_dirname)) + language = os.path.basename(language_dirname) + + # when deploying, we want the layout 'language/version/pdf' + archive_path = "{}/{}/{}".format(language, version, pdf_filename) + print("Archiving '{}' as '{}'...".format(pdf_path, archive_path)) + tarball.add(pdf_path, archive_path) + + for symlink in symlinks: + os.unlink(symlink) + + return (os.path.abspath(tarball_path), version_paths) + + +def create_and_add_symlinks(version, git_ver, pdfs): + """ Create symbolic links for PDFs for 'latest' and 'stable' releases """ + + symlinks = [] + if 'stable' in version or 'latest' in version: + for pdf_path in pdfs: + symlink_path = pdf_path.replace(git_ver, version) + os.symlink(pdf_path, symlink_path) + symlinks.append(symlink_path) + + pdfs.extend(symlinks) + print("Found %d PDFs in latex directories after adding symlink" % len(pdfs)) + + return symlinks + + +def is_stable_version(version): + """ Heuristic for whether this is the latest stable release """ + if not version.startswith("v"): + return False # branch name + if "-" in version: + return False # prerelease tag + + git_out = subprocess.check_output(["git", "tag", "-l"]).decode("utf-8") + + versions = [v.strip() for v in git_out.split("\n")] + versions = [v for v in versions if re.match(r"^v[\d\.]+$", v)] # include vX.Y.Z only + + versions = [packaging.version.parse(v) for v in versions] + + max_version = max(versions) + + if max_version.public != version[1:]: + print("Stable version is v{}. This version is {}.".format(max_version.public, version)) + return False + else: + print("This version {} is the stable version".format(version)) + return True + + +if __name__ == "__main__": + main() diff --git a/tools/ci/executable-list.txt b/tools/ci/executable-list.txt index 594947413a..8752608250 100644 --- a/tools/ci/executable-list.txt +++ b/tools/ci/executable-list.txt @@ -24,6 +24,7 @@ tools/ci/check_idf_version.sh tools/ci/check-executable.sh tools/ci/check-line-endings.sh tools/ci/checkout_project_ref.py +tools/ci/deploy_docs.py tools/ci/envsubst.py tools/ci/mirror-submodule-update.sh tools/ci/push_to_github.sh