From 1b6c131369ff6cda29b1d5bb1af78c3f1404461d Mon Sep 17 00:00:00 2001 From: PeterSthuka Date: Sun, 2 Aug 2026 19:18:17 +0300 Subject: [PATCH 1/4] Rebuild the PJSIP binary for iOS 15.0 and release 0.3.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The XCFramework carried minos 16.0 while Package.swift, the podspec and the build script all declare 15.0, so every consumer with a 15.x deployment target linked it with one `built for newer 'iOS' version` warning per object file. The floor had already been lowered in build-pjsip-xcframework.sh; the binary had simply never been rebuilt since. Rebuilt with MIN_IOS_VERSION=15.0. Every slice and every architecture now reports minos 15.0 — ios-arm64/arm64, and both arm64 and x86_64 inside ios-arm64_x86_64-simulator — with zero objects left at 16.x. The rebuild changes nothing else: exported symbols are identical (2241 before and after, none added, none removed), the headers are untouched, the XCFramework's Info.plist is byte-identical, and the file inventory is the same 336 files per slice. A link probe against the device slice went from 240 warnings to none, and the package's own test suite still passes 42/42. pod lib lint now passes without --allow-warnings, so the comments that justified that flag by the version mismatch are corrected rather than removed: the flag stays as a safety net, and the README section that told readers to rebuild the binary to silence the warnings is replaced with a per-slice verification snippet. --- .github/workflows/ci.yml | 5 +++-- CHANGELOG.md | 17 +++++++++++++++++ CallWaveKit.podspec | 2 +- README.md | 18 ++++++++++++------ RELEASING.md | 7 ++++--- Vendor/PJSIP.xcframework/ios-arm64/libPJSIP.a | Bin 3988080 -> 3988224 bytes .../ios-arm64_x86_64-simulator/libPJSIP.a | Bin 7729016 -> 7729328 bytes 7 files changed, 37 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3f8580..31231b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,8 @@ jobs: - uses: actions/checkout@v4 # Builds the pod into a synthetic application, which is what keeps the # CocoaPods integration honest now that the repository has no demo app. - # The bundled PJSIP binary is built for iOS 16 while the pod declares 15, - # which is a documented linker warning rather than a defect. + # --allow-warnings is a safety net, not a workaround: the lint passes + # clean since 0.3.1 realigned the PJSIP binary's minos with the declared + # platform. Drop the flag to make a new warning fail the build. - name: pod lib lint run: pod lib lint CallWaveKit.podspec --allow-warnings --skip-tests --platforms=ios diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f77e1c..18ca4a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to CallWaveKit are recorded here. The project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html); until 1.0 a minor bump may contain breaking changes, and each one is listed below. +## [0.3.1] — 2026-08-02 + +### Fixed + +- **The bundled PJSIP binary is built for iOS 15.0 again.** It carried + `minos 16.0` while the package declares iOS 15.0, so every application with a + 15.x deployment target linked it with a `built for newer 'iOS' version` + warning per object file — 199 of them in one real consumer. The build script + had already been lowered to 15.0; the XCFramework simply had not been rebuilt + since. Every slice now reports `minos 15.0`: `ios-arm64` (arm64) and + `ios-arm64_x86_64-simulator` (arm64 and x86_64). + + The rebuild is PJSIP 2.17 with the same options as before. The exported + symbols are unchanged — 2241 before and after, with no additions or + removals — the headers are untouched, and the XCFramework's `Info.plist` is + byte-identical. The public API of CallWaveKit did not change. + ## [0.3.0] — 2026-08-02 0.2.0 was staged during this work but never tagged or published, so it does diff --git a/CallWaveKit.podspec b/CallWaveKit.podspec index f3127ef..c6023ad 100644 --- a/CallWaveKit.podspec +++ b/CallWaveKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = 'CallWaveKit' - spec.version = '0.3.0' + spec.version = '0.3.1' spec.summary = 'Instance-owned incoming SIP calling for iOS with CallKit.' spec.description = <<-DESC CallWaveKit owns a PJSUA runtime, SIP registration, incoming audio calls, diff --git a/README.md b/README.md index 87da66f..edb3a19 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ To track the repository directly instead of the published pod — an unreleased fix, say — point at the tag: ```ruby -pod 'CallWaveKit', git: 'https://github.com/PetrShtuka/CallWaveKit.git', tag: '0.3.0' +pod 'CallWaveKit', git: 'https://github.com/PetrShtuka/CallWaveKit.git', tag: '0.3.1' ``` ## Host application settings @@ -184,19 +184,25 @@ The checked-in binary can be reproduced with: The script builds PJSIP 2.17 for iOS 15.0 or later. Override `PJSIP_VERSION`, `MIN_IOS_VERSION` or `BUILD_JOBS` when necessary. -The checked-in `PJSIP.xcframework` was built with a minimum of iOS 16.0. It -links into an application targeting iOS 15.0, but every object file produces a -`built for newer 'iOS' version` linker warning. Rebuild it to silence them: +The checked-in `PJSIP.xcframework` matches the package's own floor: every slice +reports `minos 15.0`, so an application with a 15.x deployment target links it +without `built for newer 'iOS' version` warnings. If you rebuild it, keep the +floor in step with `Package.swift` and the podspec, and check the result on +every slice rather than the first one: ```sh -MIN_IOS_VERSION=15.0 ./Scripts/build-pjsip-xcframework.sh +for a in Vendor/PJSIP.xcframework/*/libPJSIP.a; do + for arch in $(lipo -archs "$a"); do + echo "$a $arch $(otool -arch "$arch" -l "$a" | grep -A3 LC_BUILD_VERSION | grep minos | sort -u)" + done +done ``` The XCFramework is 21 MB and every clone pays for it. For a tagged release, attach the zip instead and point the binary target at its URL: ```sh -./Scripts/package-pjsip-release.sh 0.3.0 +./Scripts/package-pjsip-release.sh 0.3.1 ``` The script prints the archive's checksum and the `.binaryTarget(url:checksum:)` diff --git a/RELEASING.md b/RELEASING.md index 2b764c1..9014fb7 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -69,9 +69,10 @@ than from the working directory: pod spec lint CallWaveKit.podspec --allow-warnings --skip-tests --platforms=ios ``` -`--allow-warnings` is required: the bundled PJSIP binary is built for iOS 16 -while the pod declares 15, so every object file emits a -`built for newer 'iOS' version` linker warning. +`--allow-warnings` is kept as a safety net rather than to paper over a known +warning: since 0.3.1 the lint passes clean, because the PJSIP binary's `minos` +matches the platform the pod declares. Drop the flag if you would rather a new +warning fail the release. ### 5. Publish to CocoaPods diff --git a/Vendor/PJSIP.xcframework/ios-arm64/libPJSIP.a b/Vendor/PJSIP.xcframework/ios-arm64/libPJSIP.a index fe5e3283cb7b523f6139ba695e6a914bac16309b..e4625470df6a505d60002a7221fab6346d3feed4 100644 GIT binary patch delta 42743 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 z z8ld!c-CFI5R&B`^ee_m~S$mU$YuIV~<4zl^EZ2{&?K40bsW82pOBU2d{qv96{Id?OG9Z<)%dbXEUR`G ze&@u9fNA=0uEpfH3a**Dx&+ALRu>^afj52z}_(T09du-$& zyOs=5Z)Up=rY*n6t{h_j0}+xHP9%7 zzMO$`1ZSYh<;^^c6mBW!1mV4itGuK z((hJUZg)%$r$LrQA1}~5wmFyOyFHG){Cbh_4vXCl;w%!ZENTXEGYRKdoM8~JlHe0z zZM4&3cF{UeW!#+QNsFJybguD|$Dc&uVWQSDdDNs&np2yo_OZL^V=%?(e}(jP;efm8 zE%QX;uiS1E$?Y5k>Nrm(DcTfi)`_x7y9o1#RpGAAX8vW-E-J&+&D|WohLXrgcTe*M z3OA(QGxhK>Z>4Y(4!;&0H+jxpOSu0IQcQ&=pXNNy;tx{nik`XG5*Ypm1zou(o>xZS zR_x(di==%0mAw{oa#ITSW{<&KADM$1F5X;M)0-+!;d)bFyw}pyv_rqT*J9CjQ;JLU zc29KT98IbBRAd}QQd?55lHnhMh^E&M$(m$fevz+2T zr|9(0De?wKJZdDRZ=uK}j`-EcNbA2Db0lg z(eAUI(z$B&FpKFDF z@&`-2=^eeseoJ@L9=+FoOO_@ZF~dX$Ls=)eC#j~5qq*juf~G~pJw20LlG&0b<@zBPjd(6m#PG7IW&K2s&Drr}mE$c6 z$koMVh;rmpUseJgl=O3y|$qn7m%2{U+t zvWjM9k@22wOIi7X5%5Ta4^2?zEmakd#Y3dzB zhiIDoZMJw`-r@eqokG!rY@PN) zHg$0!Rr-|m@{g7;OimeQec>TXQk(9yHuF2HE|vKlm*Y!|arGb&S zij+dKK1=Uft!i+#rqtH9Na~9!Je)jJTk6F}EaB$rnb3i3Y7wp9Rqu7g655tca`cqY z;kj10QFdw|Rd6j;Jt|~9a!ydu{Hmn4sds(yH!YJ5^%XZ1_s%jacP0PiL9?DbV)@Jz zzLmWA{S^NKfnQ1VHuYXg(o%iJF-uW&b=_n;*0;6e)2i|29JiRutDWQl^pzGK%BI(4 zTjngG@xiZc^fvWw$yNJOR_!EB6Irz{W!2uL=GLs8k6YZFw4cd~-=SYb(a)hM;1TKi zfZ%Ehtt7>reyZ;k>FPspaSG)x5P=k|9T|FtjFA-dj&x06qkAYXL0J^^i3O;Zf9E_9sUgThs%=b12lV!ew25&%0 z=u!GxrNWEDsWRhG4yMVB6FHbJGtTE=hRpaW4rYd)q%xkPU?A0pf-h0foa9NpC9M2CjaDEX9vVNszPJFlm(d0=QZ$-5{R5hc_8!0HfBmtToR zkxA6aDEBy%=}c|#NVVwPxVp-2OINA~lf>Xwypu>W-m`X*F;2-oJM zI=lP5KzNxQ21}bqte^>B%E`L2`Ua`V!Z$|B>`~T}<-S~&Z=rIgPZyb@zwUL?5}G)a zJqB`4zR$Bq86QC8Ae-R#HVHHJW+yFCrUiN*N>lhDDN)byl#+WYUtSY@U8&tg8E}^_b&XVI{jQTKER344tNz?6i@A9$h08hK!d5-bPL#DG zHR@%VNp-2huRW=g*uRakp4J2`3Z$CK_O^>00zN)0yAzB@|wQFR4H znR~cie##P(=uOrT_UI^$syeYObgIr%xOUX1p0dzinvI~%V~%SC!Pz;K2T>hXa{bZ> z_2`{AoWCll?+c|*vW>1y#goDxqO>t9bdk!YG-IWeQEA0WTbqKU?MT)VPT6!(`U-ot zH!9s&8E8~0SQ%|pUT0;4Q5nL@IioU)6%VKCdZG>y<5*u|^YpEqK!+8>jaE8YKXuv? z7(atu=)7+`M4grCMrDy6dd3o_EoB4!Sg*|muwl~TezvX`ZbDv6attn@P~KeMvQsGQcXpRoisxx$9MM#FVh z4j7fYtc)`%|FAOAs5nLH&CgoQP2D5OlKWV*qgA}vmim}Yl=`!rX(xw7>T4)REt<`% zOmfb0Lx|EuR*o4<&t&C46Q3VZRv{}+P6nj`EA;zHTU$0_g|4mIlyX)U7?qYUv2@+U z>oT&I$~~jfnSH{Y0FlmACuJ>E~UT!E)sq>7O{+#+eT$ID{F0vuf|6vO4qZ##-Phpq;w0*zu06^ zx|0<*TLnbvK31BU46DW=R-QL1Ke6(HQ8~rROQ!8w)nbF={*CoBM$fCPylhl%vNG7H z&|j1n31f`P16IB^Do!*y5-u2(nxyF27cBn0yxI1#&4v~YWOA;)@_|k9y+j8pN;9MM&o0oY&SP_Dn^}}vSQ%zi>a()Ps5E4yn^9@P$|$4Kf|Z^| zr41{6jLOTr1xx5}l)AFA#i;aRCB&(^U(rE>SpLE2IEdap3ByBJL@9d=ORs-rELACI=iaV)h8@}s@4j5!K;*a*a<(`97XBZ ztO&I-C?ERk{vyHIsPHa0VZJfdL00BeDH?Yr{cV1cu&7F6T>R zeQ#3@L=11R{5~Mt$86tHy}m1R+2^co=cZ7bPMN6eD^|B&iq^BQSo}@fbnh#cP}6Qb zg`gc^+nzA`w53pYh8q9Grmwl?-oJ8ile+L&cAg?>g>q{xw|D#@ynko4NL|1zyTOry zY8O#YTxb`VGF!G$?JUYH#-Bc$JnPBwN2)f@`f}u$ij)O$ zWVvlC>K91@f15}-U})*|7(M29OOYvGf9ZGHE0wT)g=~2K5M>QmSS1^tKZIWy2`|z+ zaasknwy(`n)`4ADKEazTWl%LA3YHryMF^wtiI*9Bp z&SfLn?XYx{$Hz8NHcrpJN}V=UZ+g`dS7#3U%#}W}y`Ejl!Uoki@(cTC)|po=4W0gf z{du+D|F9g5weXz-y1*dcoOVJa$q2s=$jBED+F@jX;;e(}Y3 zu2@sjt17}5d)Vho`0zz|j#pKL?@c*6e!isTMCFTB)G(K5+rTfrD$9wv0DkeE8%J%= zw~^Ry6k3OGE^xf+==kmeS2UdRK7)$Mi$tXLL<{i6Qd4^pZlSRJ$C`|<|H(|z!F)lN z<5gWEuN+c57k0khDD8+Zls(*yuiJ55jK|5hADv0-PW3xS^?8bp|3kC^U(@7luHxAE zjvlAyYMP<(by@b|QNu5{K>Z)z;!ut6o3QVG%J(jgn=c--Z&g~pfX(r$w&UBN|En&1 zr{?i?l-B_%{RR4t&M&@CgEBp;3rz^n8<~seKgajSxUe|BTShOwN5=68x|7eZMX<}e zX%y$XYitjMKYa<7@lGt#tFbjFu=v>;8ehI+i7%&NzVQVumX<|VOMI(>CB6d#FTTXY z5?^T{m0x^)iY30v1F!XTKrHQ|4|wqvHI~LllNSwJe(@zk*7!;uQu5_PmiUSyosjs| z5y#9YC`i2Ou@^6MkoY3hA+0V#G61!e5;cszT}Hi_%0^>6MTP@y!Z|$4tX$T#m;*)rqn&@Ay)V&ujr@@W4TX5s6ah&ol9U>(8+yP0eZ7KPA1NPcM61@1rJWEeSS4(_toTY;{ zDTa#XHsE``fpq+Q+Y+_OLI!+kA9?cK0L~!RmccuiUb(g@$G3zz&qB(G5lmi$;7 zr*B1XbQxb-XNmWQfmo*HjV#jMw;jy`eQzYqPrho;-hW3|*NN{su++>Z@dIxx@q-!Y zbH3le(lDDB-|b+@$0qT;3YNOqB)-eQ(k7N@f5fj`y;oFmsC8mg@n~PubZgCQTITJZ zoYd)$SO;52d8L446G+w6w4olxV0>viU*^O zX-`DwhgdfcEcTUu9b#~C)h}0!KJ*jWVET!1@i4AKo5{shzmqliSRc$NE@pG#tm3L4 z8$4pxi{%5L6Xq4K!_(VFGyQN$KG}M4MKS(}<|B_kpI@sok6K?`_3*SYb(c-WKg;IX zQhW`6F2`sty;D4lkIwpM@l^cD0He88V2OOPRSznOaP(|ySc!Zt_FhDZ8BdNIQ-`ON z$OBuRTH=DAhZxP98mZLRpD9_0=k1N=1<#kr$7Z!wCHeSyv%#$XHq?opC6D~^P-DyJ zo0i4W@Te$><>O!6yQH^+C$z)+mdLJY)2}4oLEA4Fsj9eNEAi@YKYp&>EV;s&AG=** z#!r$ARkS{MP$HkuE__&W!9H_6&8zf(KB2Aet^I#7R`^Jx?XQIyO65O0|L9+|ddwK3 zAMr2cKQ?Cj^A`pWYkPC4?6ix4rTaSCA9Cg3QaPR$4=pWEvNu0iQYzcC@PpC|4w^e{ PX{mhT{j+7I+jIX9!yGSi delta 43106 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 z zxYe$2rrneTcI#>srQaxh-zyO)CrL5Jxt*NR^` zoG3HC$iXC;@of$!%ZwdpsQaeKj6FG+8gzon2&JGO)rW$y6g0*;n+enqd=+R!LH|f; zY(c?*aH&2+!NBmKU>YW)C>R_TWMSvA6gCbCYC!T#3WkKqbn{sq?(Xy{F*mfW@iQWK zKxjK*EUOB)cQlq)g`aUXR#b(bbvN#*3P0y*JWv(x;A=cq748^dJZq_nJa01oUKQ>X zZoExlKC;lxamIfs%uAZk7t%yCXF8)i=p8!Hld4h8f*Pdn1f=QvBwb3$?IA6 zC~VEb&}zZ^c@m1W&rX=b46kWFQktBBq=Y@g=agJjdGVy+n;p`siT=Md6`fZOut@ zVC-?SUSN-I(x|F)orR)@c?#zw?b=Cmj^zw3;$zaCuMiv^gLn}A!AgerUj(-hI#G$n3m=&%7|Z%Poi1mQg2^l&tCs06ue0J(T>()r zkCnCt-K?>Mm1p(Ja#o(#E2~*~(Xh=@HQ8Xs`I7b1de4olysTF?vocJtRIu`nUiqGt zul344R?h2{!=z{*oHzUQJb|vn(&y$*NVZu>5|tEDEl(GF`9G|9Bu`KCD)} zF42LCg33^>-US-f1{$g{J*v&3z?qeidc~cU-Fn5Fl~?tOKPzwPl@L~5*DF!1^w%qi zyabCGq?giJ*{oM`SqXG_*stiICt3bc@7SD`{d%PhEAQ%+=UAEaP@#)c!HX=#+vH!Q zHN0r1AMvs^*~Z#e8+egUnm5?G{b6=hm#Yyhf2QUNbsEV7{iWJb6ii?rp=JiShy=cW@%BC#LB0v+)y)v%9A1hG=PxZOn9xilWW4O#taJcd6Upv7;~$_eH=wl zTXHO5$NtToJQMm#M=m#^SUJjYKUa$g8cv>1v1JH*z9BvNs1pV$PZ=KUDhgY%)4b}5 zxUfA7^X0`uwsv7h78Y>UYGN*Yk%h&agA%-pNa(}jCY29wM0wq!8i)v9UwIE8+i2g$OrO;$)P12A z%h~ib*Sy}R94uEGkAL(tmW#CKSaF^tmdi>%)(6^$$sb}3M*JJOQBkQdQbSv z)Kd|K`^lOxOSVznG(m^yL!T{M{lfCcsy3~DmzMua{VFT{Smzu=l6*H2PC|M(d30=53K? zz8OGU7Q&a7-o5DEiJO65ypd!e4x=xD{F0kl#4_^d*C1_*cV4i=Ko@PZ5B)FKW3+7) zHS!%?2ePiF{eXS+=GR2+hIgKig|{a;!xG56?Z)vcH{Pt~cpU7!1I}?bRET#lIKGtD zS^VN1buNl;LR3|fH#FF18q)Ai3&(exXhWJ`ykpLZT9cuwBD_PxPG8c|^NV-RIbKzf zYp&`L9kri*^L(D>%~CdV7X0EnD)t(XZ||_*TeP3RFW&R#cvbxmXiJUMEONJoj!urLH_&yckt z@71!^h(x?!%<-x=x$z$bek0q*%N^yOr!T$y%9A-e-15+pPmdqAtyi10ZymQAXr-eUE z=|o<9HuGH}%8c*mpnmglWDO!7I`iftr{`q>O6Dz1mVT&iUcRMB|19$6A4=xighdhv<2_xu*3@zWcDrc=le16;># zw-Ac6#M|+XM0&~lpG3ZO%N;~7-bi9E7pg^7Lgeoh{!rr0WA=KXTH z==DD@%_A%?Ag_|b?B0Ri=po*(W{KBI$dsR3U}a3>i!OxC1(v_wZR7S?$Gl5Loi8mU#c4rJmIi@7%Lg&XPJ9`kMW3SYD8pJT%?K zY6{OQ@iG)y=Qg0p-sX8mjs8}6fYm)KZ#zGhxGy^oPv`3&InV$lGU^z+oPU>eDHEQ0vg-UH{nZFRfS=FabdM;l+j#{r{ zeinW^3IfV~}b+y}9IO{uR!=_w9Tme)+05m)_5pPd@K_kbmAbbFJK?pymU} zy0lu?djDap^pwVjf5W84VbfptukjbO9yLa2y?hJgA2+M|+pu~M>s4cc?6l$j1$(>M r9&(4_1#zFE*F&emMIv_Q7!&JPRD+iC9dWd-s{^2RF)wq^Vui`$Ye diff --git a/Vendor/PJSIP.xcframework/ios-arm64_x86_64-simulator/libPJSIP.a b/Vendor/PJSIP.xcframework/ios-arm64_x86_64-simulator/libPJSIP.a index a4d0f952f4e3d07cca340e357b7e5572c2129357..72829799e001d783fe55c258a4cbb377f4f4de51 100644 GIT binary patch delta 85161 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 HZux%zwiMm` delta 86225 zcmaf+2YeMp*T(0DG)O|~O(T``9+KQ7Kqw+jAcUsi3j!)ldX-{e0cj#l1Qsw-6a+OC z1-uBMDNUrefPjF2fTA=J&>-JAGf$EYH~QTlH~*REoGCjyGdnxG3F|KxS9$bfag{l~ zzTxYI5LHY{c=fMz`olK zGFl8K-uN_HOa$i<7w(D{8#fD02HvEMA61JH%c!77M`A=f6g&a?xvfI@kBSkK8VIre zO*gR&oc2VB@uxGyJa9R<2HXnn1ACcF;*qe3A>cTZri6DPEC5eF7NTL@3~>qxZ-9S+ z9{;F0{+T;|2w-BjZfSvoTxrHaoZ6894GWUijNA6 z5!Z;^e;@Wsh(8AFUeQzm-j`I(EnrKq zKR64_L&klTBEyUkK{C#i^bZrHMl@PWe-jkYEbW9iDKtBgQ0FS}%9$58fRbelR z^8v+zk{;n%4Th1U|fDz1sHFbn{*;E<1a3&dw3{sq__`WWK=cWQ~{;NDV_ z-~OOl;wIvz8_F*bJR|K|EpY>m4PkhMcn8GCQA>26oGx5ABg(KJ^i97}d_|f#PE7qg zP22#V63=W+6C3Xc5%yP_nD;yNg>Tcu7sN+<)5Q1SC8kEgLkO<7l|u~i()Vei5pn&| zG;s(SbzuEOn()6%1y@NIgDIYRCQVESSAsjiV(@p+k@8{x04k3wm`&6;kP9IM4i>N# z*aOTb-npA5W`aw=t3*E1f56wMf_J>q#dvTvxC4wOHgriBxp!&&$GWGBYzP5~nihp8^`1VsW zd|6Yp-$N5huLQ9X7ol#)X*p9hMGOYt1{Z;CcG2kB6eqUB-@7`Unz{}m8oY^$_~WA0 zj4JwQVqUyxBLnfG8#oZm2d${!K3c}C?i(XIp`f9l2F@XSoA+y13)T4AcnscCsU2>- z9xHD4rz_24Um*r4dVx`3ZLkHHfok5u;^{BYo(_)}Q;&C0ZN|ijYCEaav2mgXapCwl zk+_q_RM_M=QICY!8F3<)*k^W}n1yPtqxh(gGD)!V{eAu1F6bIHqXi1E{>@B*01HgPR_ZzZ{c+r5ES`sH3;mGsA zF5oyi@@Yje;$3h7vEer{;?8V3kwrnm4=wYe=0&TmO^)IeEmUJ~M2qv_74R1L04xE` zv>+bk5G}&M1TYh91Ugbr<$T>ie=q{na^d(A*bVFhZY55u87=k^??gt66U6bgqs0)| zFA>kwjTX1q-XdB&Ca&)sEyln;37i8u(gDnQBU&t0aZPlgrd(zhF9s5CIK+!F#7i#m z;vH}m&f$G(vV}j#h!WzZn=#@IG<7~W8~g}#q|TiBTa3scZvG=iG$Zn@Mt7n}i4|YS ze6={?1II|P0~`my@n8dWE3grrXFpYdZygp<1%+3<_!!&(?j|mLIbIwA&w;nVM_}Gz zAv$R($>J0;+=QC%1y6$^RPdQW@!}fdojD<;8&4JFY3nZZzd?8E{XDEAz<8t|yO$Qy z@rhz4SU}WRs0)YBU?>6)fhox7<6_FVeTwk?AGJt`mng!i38Mqxao!!%U_bCJa5lIM z{2bi6N2JMl^9Y0{2WXg_OcHZ4*(tjPYzOuN^T7f;lO{9z8p0{? z9_UJU!(31d*aSRW-6WPh%oGj1Ok&iVS)wiY8rXyU)@NJ9aPVz#!+kp8YtqGb@X&ot z30EQf2|E0t^dK+=tPkdbA#}?%t))d|f_Y$%Qo?T@RbYQTizozlgBLUe?t#vfkR691 z;S_K&ID#&eVr5M+6K&!Fe$R6)lGkpwmd|AM{hXUac7Q4{G9nu49c{@_G#HuxF%EqDsN z0d}DR`$R>Ek>E`5DeNmL-h4!a*eIz*h}{rQfWy&=!W^mdMP!QFU|}Im%wI)_YQ!)- zLWF^7U^DO)a0oaF?7E(=Alo9vNKj{8qm15%uogTBUIm|k-gNFb0}I$5912bcSA#pL zfJ+A=L^1dqXun43HHaEJ>_LLQ8~KtGCEf-nQ)lE2g?%M7KkUyCXTe{Z- zj?S9vL|ZkPnc{VD47if=U47Fc_WnW379NkqNN^K;3|4)hhM^xA2PQd~gojI}Xbk=j zEFwOtktq&?H^F~EcRH19PorU;x+Gm(yGP^Se_pzHa8L0$7}|giM7H~a-JuTz^T9~i zXCS@;wEIiVoSo2zPCcSw7my)tg3oI-rDlJWDW0b(c6E4$coCeBrVpkJ!Ww0W2N=ih z?rP>sf*y+afv0M-DGBj(I=B0OjS%(0Y_wcDPEi__vpFO~Xmg!SBDF=PSOx9`Pl3OI zRjVq$V6ZOO27Ch?2hIUkf?L2N;B`e!jHae(7@H}kf**o~U=jE|cn16xd<;5L=i+<< zz&Nl0IEY$ewTKk?;A}}PQY?qCiP*+DQhW;*gTH`3poy=7Pf7Rih!g>96*Iu*U>9%* zI0IY(?qF(^!D$G$!A&~VbZ>|_1l|Du0sR&#dji-3>;~q8AAlRd@4*}3Q=-NN`7Tl! zrhrYsZs0iLoUx%|0r&-Y5c~;z408x(v|C5F{$nGB4;Ty91zUr!gCoG{;37p$tcK7EO*eza>*hw8;sbCk zxEnkN{t0@~1jYWzU`wz&I2@b=nyRUZ%u7+e}GOdDqR4Wz|<(C`ViWHJ;9;iWN;DqIk*ix3jPFsO{b{go(!>>TDH&fNU;|@ z0ro~qk0NS(`F$V4=ioN*7uLP6&;r7CEDXK_PlH#$JKz(rKW<3g20s8l19yYxz+b_?!98yDFsakNOyN$;Wxlg% zOqa(t$1+3@FcNwlur1gV90^VXb#M(hm=+$qPpz|$nU|1V3d1zj|{uJ8XjQ-lx) z-^>&#U<0rX*c}`SP6QW%Yr*YcH7byoSp6Tgn>EL2;Ew~3f3*G`9HmZWmU^F-l2cUzi zz>VN;@R+2QF8+F?)@0SGsd#Nxk1`5t6eU`L{{w$U!aC^nJ8%wLD%fnf=_0o(@`gV(^1=r)@li9ST!f#Uo~^%G>g9W+Ca11F$DjS+u| zsByv%U|0w41dGAz;1kf#LoGrR!A4*wa0oaZTncUmkAc5?(EUH(#|vsgrZ*S^)&bjq zeZh&K5A}8)JwH>t&Ffjhjc(nTQQ%D6%IS0p?@W#o^AZ0TT_kz%UHQJj6SLeKZ7ygA>4+;9{@{6*vlhQmTXBfyLle@HY52 z=;)&=>m3fj^@_(-KwD5YQs2g^64U zJ;CcpI1cf7;1}Q_@K?}zsmeG8Yz)2%=7WpDHQ-LBMoo7T!d)9vXirDToiYTx zkEz@7p}GpT@HGi>KTEvgOXHsdqan-(H-O)P=fFQfH$Rmw5KIHxfPKJxFaQN7fc3yO z8Un9_Bf&Y~3a|(~30?)CfNpdV7cd*fpy>xa1~Z84{1^9|6!(Z zq9qg44@?5nxkc_|i9(tW+I*iSc7bQX+n~Ey*(1R^ikfH(p(i*ITnw%S4}f>Us#Gu+ z*qg?G!|mZ>0=NX+1fBqIfo`8D|0qc%NNRVt%kFbixCz6s6; z*MUD0vvX>SdrXZ2ZmX3L1J(oEfqlRUU;(%RJOcg%J_Oxp%asd?1RI0h!2?tQjhk*9 zog=;qP6gismw+8M(f+{7DA5ZX0~Ubmz;D5`;C;~TE0sP3%qEIkQR0QKX#8{Fe-QeC zqroZQLU0|p3oHh2fR8~Zt195?=d`377a<;idk4_+KFv?u1PfoI^8Nqu5jS3?1jl@Y z={3aw&;sUx1HqZ#Vd8i{vnZNR1?7i`)8KEQ>jI@mgZ06V;7|>Lcfn7i+)C`U$VYsDxOSu~Z3a7ei$f$dT=G584d>7ml665CkK;{8dq%AFl3+Ee_@Rz+3Dh z#=h$<&V#+EfQF~dVm!DM+zFlo{{sDcDgSz4H*ga83Ai2nk*QGucD+@?STGkH2HwXh zYC#pd)81S30>^_NfwRbej;pU&5AFl6gARR^Jpyb<)Hp$B2!p{X;A(I?cph|kLuHf- zz5u=fP6bzhJHZQJ3FzCG#y?jexv$EwC2`?uU(pMk2o``=@D%t5=+jT7%K^KCkLg_B zsp})AQ@qm_U$Fw*0iN!sDZ_6N9Q#wRJ>e^AfVIG;U>9&G_zrl4xbV8KScdpU&}E>S zaKgcCuoE~^Ltrjg2%ZG*gD!(qMxkI1*Z~{_z5{*=?gDQ!m-vY)G)kDkpq7n52XHv} zF1P~RL0tW{pEwClz(nIaohG8J8X|TsWjr}pRGURD>K!C%f|+1Tusb+LQ4@0^tN{;z zzktNFB z;PYTt@J(&Zf8-U%wF<^nD79e&)xCV*|Dq#%x0yqNH!M)&3&}E`Z7Y#a6 zOYo@)029IHU@xXd4t`W)Zjw}R0vrm!ZQu#;1u7u6U!dp-js+KhUw}uzn_!i`h9bbX)7We^J zL`+>7C{BYnK+_bZFD4%SGEi&;4}sS~r>V*w3DyTYgKtfxCg%(mL9l|y!TX^1H09?< z8FPhF!4_a|Z~~Z1Gu*W4{-QTH6SSX0b3VPc7y@Q%2;_l@RM4F(fg%%^)#em$XkSAN z2j_ubgXcinM3#QhU~{l7^63MP2N#3dCIk+H*TL%Vs_S|T*b3|kzFiteLDRuQGibTK zt%k57UJNdW|8DRHMNK?_Py$C+%77OX@!$(!Kk$9f3SJmQm)Vhi;#Z2VKVCyrnW-2A z)&)C&eZi@cS`D!j!glZ^c$+xQ6eMQh`n?7`1P;I{n*pu|FMtm3sdF6*wgQKN?=dy% z3~MQ{zDck+2>t?AovZX*;-hziMIUeyxE%ZzybLOom<7H}6p0~XG`JYt0-htrwhR$}fdTXB)aHhW6tL-h zdTo(~S0Ic4r-MttMLMkyHid{!m>WiCY3A_MnNcEQ6CK$6C{Y*udn1ib(mg4jx*;I< zsguSJbZT#NB8 zmP9cFECAPoyTF6sdGHPxbeL|5W0FPeVVd4Ju#sATU*m3$mT>+?Rlo-f17C(c4M*}L zk>Ak0Mh6fZ6(=5pZrfEn1k40GfW5&{8UpWtAA?_mr@>p`KcMFhRX`%x6nqUF4t6*| zEl2OUz6K5lOAb=Y+9wOm^N149A00ko3i{<}%y0C)|2;d^?e?Q)X%=UcKLj~AZ1 z730DBU~8~9m=7*c)WjMH`$~y|Pl4CLcvQ3jSOVRhD#Aw?4ZcbhZ2n7<7!LMCMQ0#h z2YzA?jnz(Cg7A@n1aXlnAetwLyWmnJxJ35xXA{Id(0Q+l$Ab;Q?%)OD{{D&LPcUGg ziq{3ZffJb;IWC3pHFy&I1$5Z2GKd791N(#X!S&#A@B!#Wy`C$S2(|=!6E!xxg(i9* z{1Pk%{{}mu>1$BS@VRdUj)A@aTn9#>Wi8-N>XiJl^?A^AfX4r&nn}Wk&LuMv%mlmc zq=n!7IMEv%1x^L$gG<3R#Z&;jHvaZe`sK6%$zndZ3fu?&c7*y&*JR;xR8xWLWN2QL zEaHf4Xa+up-V^cdC?M$=Rroadfjz)+;6kuBO*ES`lEox&5x5roRzu(-_y_1nHRObW zU?%ty*bme|9ozsOI8N7Q`n{lHRJijgnlG|b#6a+WC+PMlC`D+a5m*fF1b+e@Pb$Yy zuqpTkI1Aheo(2B|uc87zXVj^A4jiILzv%?wF!&Fcd{!ms3{C~V1b+gn|DgP8gKvO3 zxEs6&Mx0ar%_X%I(I3JwYMSv4Q^Zf;-{2V7XM>x-)8KEQ_j#3ZBv>2F1-pSw=+umQ zoGgl{j~vx5Q7=7BSK}5b;!|)dI0^~g1_Mav3eH1(JvfId+Pq$h_ypVn9)R723gXT^ zo^^?d0??(p{2Op;2lP1U5my*R9bgDnWD=5I}f;#d< zunyP?>{hDN0o-VkB3gr8Pt*8kVJL(t;6Wm{$Yt;z=s=x`^-!=b*cyBT91YF@-$VuC zaG=kD(=X8Y=Lusu9KHhW=m@z5yub)B9XtTPv*6#L*N-Z{c(5_p4IBZ^0#|7WSi$eX zOW6VR0=Cic5tq*gqc6z7#wL$ERC`0fL!F9rIEQQ*7aQg9>qtIEew)TV&{+wXL< zzSGUL!Ow&Kl0$~Y5*B7jtrZp)mKtVlHPV!3XY!b;jW$`e(RSuITbC6d*-4k;6?WF* z6;v2}@bvp-I`SRcCEZ~M!}tk2jG=x;q=%^^_wxH?=&w(+rEt?Mw6&Asb8ymG|W zeA3NPnmc+p4p>=aZReNdG`%RSwH<($C+Q-nln~9%{5W#eV;f5SGO_i z1wUs7=x&>w&YC>*BQf5=$|J+jiauXCaqXt+o1LusX6N8Kwl2HxIm;S8{KI)=7h7{- z+p6;TQaV&M``em3^sg#YPaRlwB~FpC{G5f#JZN!MOOkEsjr*#~!=HMf>WB`uX4lYa z^ea>z*4ts#Ho4oF^`K7&`CAXBR{Ms1W~WuVU~l7N&CjY9&+Wgeb~VcgTl1~8)nxTU zzo_PhPFSJ(`&9)(4^+G0YMa`%SY@7dw%XWO8?)ZOuq*X0lgpP}f!X#hr^0P~tiz*S zWb;0Zb$KPj*4*P27g;~Oo6ColoV&)0m3d@=%Y#Z%T^u}ZGar6drCxQ; zWld#ed$|6fMp92jqdpxIRJ0NH_Gnf`+cLY^{-N5<0%oTr|{G9@y>S zuIAb*bEDa3txElHoojA@t+~T@uCmpNzjqD(+}3PA(ye9{s(H*9ws=fdfPQF^2hT`PH~U~lGI&@| zE>^kkDDars*(P^umq#9|ZT|8Ij zF;%;O_(Mm1P-aYs-pR{5%xjX9a*9+CC#xyrYBsKZ#`p-vM{GO@<8Y)5a#1Opdy}!D zvr@meSDXXmLN>a%DX|HRojp{_!J|#p>C`;*_AYb`G0`7%s;PTAwcg+DmYom|_vuFf z9f3#QZ3;R5Nk4=`Iteea*xMj>AwgqNGl-K(_?*SL25}<^XR7E&&E7S%Xe!VY;+#Zq zG&xNr)aELLI6p^luya~OXhvWA5a&Er?43R*wC7-mb7zLL(>6j+`Z|U>4 z%Zy*)V1mrJF9#E4#v?hHBr~4O!DN~7`y5Ph+C*4RU)M0ForKTm>(bDXzxC-@rDjb!IQl0NRF@LmZ#W)}_$@o@pr?6H!w--z8$|Y_Jmfk6sxNES)=LiY83$Vn!B9d+=_`_$OH9kFX z<0fWlTzO`EW?8CHE^%LBiMtQ#%BP8?VdY-jWm)1*gY0F$rU4FQva<6KTYL!de4cTjHxx^!xr4jTal8&E0+#y-x{)hbA!)+N6wfGbg4;)B5s_7s7 z{(hNs36e*7kvxXjt53Pay__YD1IUbL0@iqPKrMKDvec~Hiw1?1u9izY53rX*xx@pC zB_3nQi$^s}+&@s_9+NffpwCP8`p%!-eQd8Pg;DaVQhqs3E59P?WUQgzj`qG-;gW9j zD2egD_pipFIB9f`FTMFNrp$@={)JNhtI=QYpWuD`Up@LK{(Exkq$KY#d=-D1;yobJ z=9sPd9lVdTIj^Jli&)wkYG&Q|u1cLU%ex6~ON{18Tao!T@0Ag@nQy$TuHyO??Md7)#U>w1CFY=DAGyGA3iTOV#U^w8)=Ii1Ev)HtfLCZEBYoDm*!sx(zT8wF zUS<7P>(=t&)-As?q+9FK`)gjQRXnXmaYfk&j&U?fbyz0q!D= zB^+E$6{OUwKJ)p|HnlDfqW>5F-4Oozj4%Jc!z|qJ?}w=uZhWRY7;4BTwPIf}8gG5| zA4b>B(pdT2llZmIzb|*yVQ(or>@c}QWGFa{KDAO)Gc)*xJv}vBpS0Ddi)VXJnj7g; zx;$==zWLO^ak+Ec09&>xKWLO?^Q?O)M9&^`V$*?@; zF2Is;dCX^?HN*0lo0uiT@|e#oONQk!_Z5~d(+@0z_%yL(SRQkiWy!ESmi_vfmJG{d8Wd8xN<_tY9$+uS@|Xt{ONQk! zk7||-%j5lWdECifpWL=8_IOhb3!#Fe&s@I@Mr+YAAGOhU!e<2b0gdL9|M>7yPtRKs zWVQyG%y+QgWbo00{LFmuEWZRAjMf}~a|^!qPYp09O;#%hgBh!-CFY77{5Bp>mj1hk z)qc5I9)kXnxuEFV5`^QV=XytmJ68T zGv=OHY}YDpU~4NkU%3_!_3*v6!1fsBg+6hWZ^eb4A%C?3YPI@5JkGZb@VEB=)K@N= zvp)A7>t7-&!PVIJr!b8f9v@`KUsl6L4Gs6ZOyK! zes$~|Jm?w{s4tHjR!d)&=9j1+-P*39ek08fw}pl>t*+^QYA4g;_hBR3{BlP5$&>0g z#_t+#uqvcps?67y`3=BEtkK+Ki{EtaRkyeLZL_nto;?-s{wZ0=J zjy8~A@ZVg?i0RNxm2kbg|0!qN3LJbxm9Va#f0Ihg_QU;U%gi3(zp|3d8^5bk$ISG< zkY$s(o|FAzfHi54|1oadr+fXQJZyb3iv778r=0QMW@{`teT?*FZR72@Zw0@)QRU*=G`s?{D!A0#?)PI1<3Ax@%MlS`6{*1 ze6?So>^36@1g@!Rletda#^2g%PN1A%{N@H$)_3U6U3RS_s{%`J+Kna9vu0UB=%&E2 z=(k35;Z9n%g)*v6g8!i)J=nB=1ZFgzf#ZE>^db_&QjN>25-aD-wK(}2$p5*vw~;Z zrq<6N3l7oS9SlB6Bcgn>!jOUT7<%ZxJ%aQ(hl5Z5R~|w7`Xkb#d=+3Ug&wK->j#fg zUH_vV|1qqNtE0SlGI#_YwHk7__HYQ19q*xI$fhXUCM-$}k!`dzImCkJb;i_JTZYu( zlOLKJl54U}o!>e{4$6mZLPk{5b@IoC$g}%Y3%O>yG|->jXUZ_X0pjyjh&;Eqtsy;C zx68;hEGv5K3pvgcQPzPFhmEpg70j*1h02nTj1L{~u`(MoZxtCP`;`_Q7Nwpu8q3zt z*Bef+7UYJF;X`kh7lwU4qmQ*izc5)s@qn#hu{}YOF$Rxo$jP*Yx_r*5hl z)mG)7VK{R|juEQIIY*38J+4CP$mj^!uB&1ra&v7{+rJs1E}$bLE;!km^R)7# z5ihD~wt~5bDN+qYyGRGM(O1FjT2+~sR*MXV+1O(bdPK@*$@7jp)YtaF630c#<8~S! z>837V6*7-AX>s0FN>mz?tTa*>L+tqE6va|Z_jC`?+D%)7K{Gcd# zVD2GN+tgaILhAF4qGWe)Y7&K|a|Lt%E>W^O(EAp-YDH0@=7m$DxaNAdW65S~t7%bl z)PwU1KC}xfE1=De!Uk*wbIyV&Ia-SKsIip{#U7ui)DKrhZE9?LbVavh1+2|}kGh~% z{uKsOhGVpBcz5UM0cbkoG&RE~x(<)jedg%Wsu|6bf|PkjaP$Zqn9!SyI=I!N-7XEAX=XJrvsyNF`SHe5O)sh0%K|N!{TanOdhe)6CYAZ==tk;~FZU&$yiI zZ!NhIU6W5i=r7U1l@!zJmO6%%-=iJW`yv%;(fE<7WbxzZLzqwuC0IAQ#K;ra%q`}E zZR_iaedB4_StDj5SKvrc4AwXmN+<}Ak&UQD#5Ad@datpBlZi2nD7D_;`wX)+F*#;G zdYRG3K10<)x5V_s2sD~qyQ&gycZ=zXxx;Ag(Jw|0@7V)lER~o~j*5|UhtpdzW7XS6 z6{fUu#B^@Vyzw@fTFCXs+#R#0k_v1*s?7TF zm^JD?*qB=HQYAjXI^cQ?{WUlb{o=1N!Pbp8V$M|3TMK@XEomj6CzY6Q{icdJayw>z zC2c(Xfiib|81n$Li19ePxW~$laN8qx8?H-6b5V*i=hccG5mw1bZW}940loJ$U)>QJ z57D}!M=bXN>-C+7W89R2JZP{0&;^h2Cx6Bqa zZ?++|eNLQAomD?BSS`VgRnv>EXVN|8TXAVzzjgU>SYsM}tghqYTJXtv8bMvSzZO@? z$bNsYQ4!FQo+8sj@gSJHE8V zjpj)w;?>ITRQ#Huw$(3co*>77-XdWe78u4;-s9y2*&~{DPPl*x%9wdZ?}X!gC*#yN zA!@M7+-T1EL7CkzB%H!}*l7MEK2f%8Oj2TQL)+Ao1|-UNVOI@Ke6fYC*>!88Ec@cN z#5Fx_%>@xjGV>!*Nx>NV#Q=BxQk^@`uQxbPD>+LH^4w&1GsqKGFl5?JZ zE9nA;qR~9*p2~dPA4!LBR*mKv4$1PAI5{V8!Z0(M5Bex`Gr!~kwyAab-2Qw_@;6++ zrE$qUvEnvlp%>*0^tUFaCf8&iz5rFyuZLTb<(bdRN}h}*j3Eo_)t8cG`}w_`e5#T| zEa{qDN8ZD}ntZB~V+b0UJe|v4H7L3CPRN+K{kCK|OHAF7JRfT_qdD=2Dw`J0Nw!C4 zrBNYkKJsj`LnQ-();^25?3gRb+c0++GymgivOM#l*OML8K5B*Gl<`;c0Y0#&CCL_y zXJhKd)l%euh;dC>X?t?4=YvvYtGS1!>`_}r#>{osC3MXw$xe~yZbzLIJhw3VSncbl z)ZywkXpr(-CDqS)PE{cE`IHg3QW)#EqNz%Kv02I!Ot41ttrp50(<xzHOaJ#}02JS|lo{JsgPV{vP5NUf_!9ZOOJxp}89OHD%a z8hos~*QCmB^>kgTIncI*$OEc`jt5f@W!joEs??Ha{)m08J-DebX1>BtnHvPuvS2_M z%zFRY7Jq9&a4mU3KN3=F8=BYPV=bszOSZtEs9Fw~bd2Un(`(5Vu+FHpM{V?G7|k>6 z(;D%?A8|};g0+y*92t`)558MmT5e6-qbq8eCcC|!n|7$Rt$BDsS|jc^)(_LR*`8Xp zATL;%Hj#ZoSEZFM$c+`a^?90{*0eQg4j7h3^Sq)o*}N&+)7&sDjpkOn)8w3~?@4n* z*E55_Bqo zuI8uGE>%*CTW3@;#XqF&!D7~!Md7`)kGK|jf257AzHM<#--+4N;AkyzNtfrUfm{0gN-BBPU7B@z21QFC&-Ct<_!N4ltD2hA zM_}=4Ea7Bay6lNgiRn#j$D*}M^YowiI2*J`A5h6KEb6FI-+nngIMKGN1x-<@pH5A$ zSIM%w)qCl(8(o~6ehsI|xG#HhUb^f?gBGL@!1Qf2-&&$lYs=CnqiTkCr>s6}Rn?lU zPmjW8k}-9DV1{g2YW;&o@#BHnMR>=_Z=NtkcV|0s3!w|6aQCaBKVjc_g)a#v|QuLzU59 zHjs5+hm5Epwk=e$N7Yf^mr;6`YOJH{+UNbPMc-vil>PSmjBOa71|O^IahZiqw-+=^ zoX8lAE@1SbXMu8L3_6=(!Ipu+tQW3-otE4tOFS3z(9SZVlGe<3vdG5nR@L$(#r8nx zLLwJG59?U)o@~VvS>GauhhIZWuxmKK9B4GtyMbjd2c}yxvNH7-TUk1LX5&Tu<_`3V z2z|2kU9Bv6rtwzKT+3{eX^y_UHSwTcE6>u*>%eQuX&#)t`WSwBrfVN%#EUxOlL5*o ze|csijQf?3H~^#k<(U?5C^e_5;@p8MrT>7yaQ~r73*%Q<=yP-=y@f{{uODk;$qHUQ zOsZmzi{hP8if5+MOE3DdEp@$h{w;I7DONR&epGvpl4erC-Y&zX4NnJ}t2+IxrMtgoG1sokLH2&gCZp3UrIwOR%0^l0a)w@`*`n_{Hq@^t zzvX4`_+D8Byid?Oqo(Q~@M(7MMrXxwo`9ir-@Q6_vXGDb0G@*DV1K^{ER?(FeV5 z33Qk(gR?kznu4La=ZT?#4sos=Oy%GZ3NF+0P7F1NuHztm9XHDo_%J=gWCL9w)m0De zVKHld^opu0eI2(v>(qo)nS5(m1%=n}Qn9GaU3h&|n#VSS=dn_8yTS7*iOJQev>ouI zFj~7d1(Wq%R40et6kMP;I62fDww#0Xb^N9*7x*6`^`GjxM^B4S?W*n^Ca>MkdS#KN z7kwS~pun>7hOkB7MTKZfDR`Kj_C4!#w$!r!nT)A#^9yhGjxl9j%ZIy`Fh3cZ9N>-e0k+I`9!9kU&&Z?mO|w5U=Sm5NQv+=bV7Bzo$zdQoo*bmXAt zY3f3+Qm{x*Jv}tC+Hnrj*Rh>`xwpk%UwV3|lS3lC5B-iF(%TYQZ8-<&>)6>~e?mf$ zKDf6fwAzc*5Hfuawg)(R6_W6d9#lLu)WMOC`yIU@1vNSLrpTkksC=jV(4oAm6j$!R z)cW?+iuMk}%39y=HOlz|6037SxG$%m!qo;^d!FjzWG}BT zhbd@Z<$o^ciS+--(@&GjZ4Qg@BC34N{q&;?HDMJ;ldA&W&^!!8dsdvI+{6I7K=jWjhiPb#6vK_9ZbU}}@pk0Qw& zX=NIfl%j_Xv&3jlq*W0OGnmFB!rfT#@--UCsi4KMWvCgroX(MU4Ime@E5phm3lS>?15~yioN+XFT|D=S{NRlZ` zgrA`@!;{I;F@SVuQ)+!e2AvAi^CZ^lNHOl+L0!D*cNt9)auD|>5y8PS$o*8Ljwnr; z|7^-q?|(@+ixSSHiO{sEG$BtRYTAh65=A)AlUnKya?E4L3#E?tN*x_WDo4JWrMl8V zNk0dgrQ|U@>zDd6xs=e{Z;CB-sYijJsU$nTqq5?4SL(YY%;gc%#+R1pGOwOxjti7y zZ?dO;O^&yCP>(9jaAuj`UFFBaJoQ|u-?D%6OQQpppZWCD^wJYbV0yPsnrJ7|S>_RF zdY1=a`fC(j9!}92TtNDEimv78Oc`~e;^g_6#pfseb&76g>+B{}LI(f-!yaq=NXu6y zlaGFRlqIfXE=|t-O^u*dZOg@&X*w?J10prMR8Oj)r!Av``O}cTrk8Tb%e0s(EYfRJ z%WT$P9c}5_s2^p_-|$_O)`8Dw{n~V~HXSX^>KX-t?o(RF=j3H3{1MflejoPvL;C2Z zF&6KBWj*pC7t@Ysr3NJ&?7#=zz@A#w^rBQ9IoMIE?i}pGK@lI!?M~ln9jdUKDWPt8 zB%y%{YjoL4sI6;bEJ5b70-qc7V)l>WGA`3Vh@M>I$s5g*(T4vMtF)HV1s zp1!7+YI9vT$huag5h3fkLDqGg1Fi6=vKPl%8rf+($&bH*abfiPTNH2!ar}wkXbP-L z%I_3(3vv9D;9wWXOZyTERu2j6L`HkM6?6}AbR{@A2l8~}OF@s&z!78&p`d4|V+_H` zPA*(BDd-g%IG2nKDCiyP*xa8+r;~GF2uYnu@(B)1rC=Wph6FaE;F}x_4a}wBBo2lJ zcB9~24u%KzrQk9S)(p(2;5rUQ1Wu*kb`D0$d=GIjR_1$_gK;w7pE(#Gn5&WVeGVtc zj0JUBpG29l8wZnQ#x*#YEHjSdU`k*II;B|@^riYxuptG_4ISGNs3G`*(2;_EHKp-Y z3i^jhwJ!w&!UE?~l6e%Y5gMqma{-0TGXhtWyoQ3op)%b@R%g39>?UT1v^MV}@(BpZ z6XwIE;WqZ>Q>Edy&gKiH;dZWO9+}d=y@&Z$X}E)rnTMs+U-UPZ(BI`&k(YwZ_B4E? zp<|fYjlz6nA)R8)eiY{QO~}isqDd%4qUjqlcq*BjCUS6SubOnOKcu+)Asj8F+B+o{rSuqUk&Ob8lM${oZ4bF0v%~ zLtYY_F4X7T8ye`hjEyfnYh0!8BBN=YzMV7pihW+@R`cYv@`q@;O}|Y>|2=H{-?PR; zfqM8Py5&AaR+HXfk|j`cu0eAMeZ$+7m&VCN(>kPvcI7%7^7m>)>R|ToSne;Y?lp?k z6>RBRZc#ZEk{UYT*_<|zdWrrxvk32Bol}SeB zGAq-{6zWkqH&}|X$^Z9YJ!G0CFyKC$6Ku?ngY~x4Xz%JNn|GFFSlZVdLr5+($sl-ZcR&JYkf=1_W z$jU>b(wvnbJ2^GW0iDx|l^W_$mC}}#>&BeBuo7C<99gCL_hvn^OfMaU!&r7V$f_~M z=^wmfsi93_>#xS_XRvbLsJze0#&X4z4@%?|u)N+N%h@Dn11tGpS$Wf_Twq0;Xq0|p zX^T<0!OAtGa+?)5yRv$s4i8xVtlZIaG7t2e5|%$P$f}L1gpxdqWa|CMz?r4F<(?wP zUC(=$<_9wy_LdvqAIS1+<+8{LWo3*}iDKn|QAuE>mr+S&Wt>sTWTkJZQkM^-9!mpD zB~}`vohVN4AaL^cEO|BV0q>Q zpi#!@UyzIcBzCFwj0;b=7s;x<$JVuKVvxIDISW}iYbJw(s z^jwDwu^xd1$+T3WVEh}+9Gv5OnOjkq2Sa>sVQyO*?qe?k_mJa@>^QKQgGYQn>BtjK ze1GLA!vmZ};P2$vg&l{p;}Ge{^LG4D|l>ATt)ZY94u1%i%k#csdK1RkCB#`t#%`u zp5{oVT=2GZQj%X=)ZRF!D?kR!#Y z(G!lWk_$%F7WUy(aaTSkM-6T0t)H1=scot;KXsV-GSOR=@wQE88p|&zenxfnvLtr3dbEo2fgq;OK9!RWOT4^ zO8;4|h(9TPWZiev;u`d2^$WS!-9mzDe${Hjbo;rM$cTLQSXkaZEvK`vSv7{dzn*Vx zIoHyn(!bSVr9Wl&L(ST}iBHcC#Pc-4FQe}s8h-rY{T~x?On{6ExdlbRP2|s?p8D@! zS!&q5kevOvwUUVrLMc*Ik%O8GtYDZj8H~S~(%O8Hi!CDU8E_b6Z ze|X!GiyQ|Z-cI9qX&T;y=6EdZytU2o!J+sYYeylRr*#&8c(a@f=|;y;dK|nx!HJy0 z=m&jxBZcD*NW)vY7g zBDIkG@a7xaSK_4dW-7-^&w$*vqd4zI@P{}1q#bd7O80MPxt8ziwnxto{Wt;N6sAyj zm`~ro(JgqJku#_NflYq+p&B0{S3Uq5@079+cOCxhlf6#kM;GjRkFrfgWAJV+yOt*9 z9c7M}HYh)P{I{y`vy*2VSMJYI`kQoT&7bz=WmYRI)K#yu#qvR0eq_aEMe+kI`tV~b zjtA3CDSsxxE+24Fd^qC1@aNYX*uOjfpiin6^*yhSPBU%`%5DNNrS`7Bz|j6!B%a<_;`s~`@1?Qyb68nkybH!seey=dc<+lOP3{^YCBGTLZoP@9 zEI+JcX(63Hdm?>!w~-~@fJDMTcy%Tj5lsMJbXY9$!$?THE6dV4N{GyOFPJ6XsfEOk zzggm^251Z3++m4t6HEWf>3QVO4{qT0B4xsEe1S%0ypPP%2r{7-yvNE?ukbQ2e%FX4 z-o3Xc(nmfhCGtaFK0);1eI;_x#5k%3^5@NIPMIH8Ch^uXOGnEk-V|mjHoVNM4p~{6 zQeIcy&t-}Cc}trIZNU$^aFBg@@0HznO#nCE17oRwdBxBz^+PZNSf7eMM8jj}cKDUu4j&JOkd5=L{B=OT#g|(q#r@qhX~F z_|_6om)`(m=MMD6`Qg26mU!b9)#UdZSXy3Q^PfERUEf;#HQpv?(~xp+-sWd%Pgq$7 z{B9Ua{9Xi3FmLd)bhq4#A1|=Pj{;CKKOA7`T)D*C`Yfe~la~_(=o6rK+ieN5j^Ax5 z!n^8**AT6(iY-6z8;CJyE%*-vj4ui5w{BSYFIm!GN(t8gxM^8v`x0WoFP1UlA(>H?yl1&FGP4fX?simW>8~&tQ)k3w z$`>Ga#AgOq@(S;*tW5cq?bO)IpJaR7 zE5>BXUtt(DHghK4u{Wls-@uUX2j?x#JXFccp@|=7$~QaRS7vU*yUE7X=hvtM>%A`X zl=^d0#V)xbLsbvE6N3uS4f7`4)bI zSF#>das-WgD051$tg-m5DMKaoq9Iuo{?xr$vKhuh?mse1c6EJp)`#uXAsfu<|GMaMFzXv`wa~*^durM=i%x%{%HQgG zH%qo`%Dt>jXnjLI)<5oN$=_)j`Da#Cq659wn^{}GToUK6e_b;>M!PXQQ8X^1t98{R z(H?BDjV{Z*l0@CFX${*tQM?8{k>aD8B#Mu%G)+uR5NnCcW+sT%o9VBEK1vW?#G|JZ zL;~2IILaeY3?_~@CyI&SJYvJ-M6q!*U4S_7CS}~GYob_21vQUL675j%1nB3sQbBtX z#iR!GrpI7+u?+0pDi^a{}H zwZ$eR+zifewN`@M}85qOch%;5~N2l2Xyr&D~| zN{c9l-UfQ>pQsD5;W`Yj!!QxFyP`7gjSTz|UkrQgdzA4XSz-+AYoN!%Zy)0C!+r_z z$6(znnkvBilB&4{Yzg)UXMuUhxG(qx^mE`JV9;fi-z4~DBAyHO1Q%=Mu==P)Yy`gp z>tCbS8tgO0Rm8{9k^0xm7EciOy{gh>f*s-C0`XVDzR=%7{4K=a2emmctbni*@ok9r zq=LKG$QIu~Uyh3G1{8gpbL?j&Q64wW0ity_~ghghG zT*SMA1HdfU^AT@>_$f3492;-d6S);`;en z;wh!m`i#vMjYzn$I7=Kt#vLdgwlqul-=!KJ%MybrzVPELF&zy4gW{93#Y)8MBEA#x zV(@qHW!N1lf6iw(;sL+Y_~#?arW!JH!4NoFz*gXFBp(PwTBHj)05r}^PZbrg0;86HY0Y3!y!T&P&5Bx)^g}7zvC~6`P z!fZB6ZtgdE}Uu+ zbHTQB3OBpb@LLYyK3&xwjY|~YeoCEbcZ_Jihcck;|Bbi`b~{d^;>UC`7Kh z_BgOMxPmI+zcx`6AfM^fKFdB$5lg@s-D#cr*jIemoyIN))XAGn)?dPMGjR%e<(0(L6fLNt~h; z@r~ya#d+`wcnf?0mVjnjdG{HaAi}@|FcWM9I`VRh@^uIO!3a>xh2u+LH?R-5mHB>x z*hdr#62uAOvK0wp2<(@L{;LwiE#mmE62xO-r#%T`4D6G@IiMpQz@rlhVzG*Aq6;PGb6=@R{$rid}bhOJV>JK!pu!~4`^3mYVf5~B0-N#YGObv`&7{0MZU&OEAV61^@= z`L<3H&4_$Y)1A0~a+3H$=1c!+tq&X{!47a70LOz3)IG;Wbe{cG0lr6BL=~LVE=7C{ zZUA=^$B#)7N5FI7E$|VTcbHZ++TUs76f)d|n(qZqgCSJ#rT0?AHN-n}LP|HDD#)|b zUFd&jc-;*tO36P&w%$p zv%T_51Dk?fz9yahTrsEne(wH_uBHZVto`H=2ZPt*b%fsM&;;rKeD z1Nb`l{sSId*vT1YHo9ZHf_7!A0O&u*jWS=J_0P3fzU3`tb`IY;VPj zJD~Vd#WfEEYJzG1SJ;`rWl{Wpd>`aePys;>Ih8{Z1P>Gy#S6R;6j8iUITaLmfV83> zOU)yX4sAV9tW3=`&7{ZjNK@0i%L7ZypQU+cnP!&C|NEW!JUojJ^?zPGyk|b&xproD zc6N53U9dMe49o-z!I#0~lrbNne*v98qMfNlOC=oa1O5$r{f#obr=&q?4lP!G-rH-LL7gGjqpN+oy)wB9WBW<&!AIEV<7x07L4s4^4Gq+ZNR7wezW#MP>c z@;P_}ya@gdT2;$%ucNbu*VoaCe^;e9I0~Fi>AumctFrD-nz!)&Xhei>!0*8u;6t$f zL%AC^q#w47$m*&Df?dEe;`A50Dj$R2fIotFK^NMs=dO)b4&JBzzsIs@6YK#!5gY?r6FGh!{IkHHFmgtt4^{k4NA1p?m2bcn1{zWe8pbFsDBz4X*?Wt{-wQi+!2R%@8P0&Oxlq;a94ge>D)4|2y7Vrdk1GFlW>3D-3z?3rD|G5Cg5SD`e*p1qNC(!0q zAYDQci@V)m{|o*W59I*m_m~D4LuaKOH~<_E7K3vPaI6HkfZu>WgMWjKpU8y$!Dz5Q zm?ghUE4Oie$Xbk5P2ZEi!p zLD>Ky3{{s$`|GlGU6mKXMc`U+CwLCL2R5RCiQ}~fdw?lm26!0*&^WApUl>tMVSW3H%J)3myT_fY-oBphH7S$3O}BvV#~2#(~LTCipz~I=Bkl z3VsDHrzSf8q_eVvYS!boR?64lX|OM9dIZtHhu)D|5+FSVKpWOAA+BO`@vJ-MKA#;BCM8_z1Aq3Ll(Y`?!r4MLL(`Y{9@dDd|abPN#15N`Mf`e(o!4s8S z@Wm!Ndag!{vIx9opn%uM#3)ZWLRyT{n2zU6KQI#P0VabJ!Rg>4a5Z?-R73yJMV0=Y zm7mdce}WDEk^_~&AC69761Wia`!(Rl;7-%LAFKj@2dzJqCl(%H8?Yys3QmZ$a1Ce#4}llKhoGa2PMn4}2cy9u z;AGGME(1RSPq@(eKcC0{55gay9aSmoUSK3R0GtTk$KLZb`|rjmcR(9Dg=7B|oXV-x zgr}~DDkbpG1Q)r|{?7{tDD8MQ3HRxsFhoBKW0Gv87 z9pD-8H?aPDbo}RxLde042Pc3pfGfc5;2H1^==8pf9|4X-!3LARpl7f$88m=P!L9Gp z@t*@6g77o=2y8@c&h}7nIud>d+y>20sLMg6F_H;NPH&r%Wdj><5kkA0cChNAj@i14bI)=nbZV1>h{O4BQSL055`f zKx;aP@s!RBi~#$9Bf!a^;bk}$gXQ2H%vdUEQfY4=qg(?Yf(>cL#Cj8|0cA-yWdV%` z*K@il?}DF$C&9a*wYv=GC23IFLWlz=f-iuJz>VOy;0-XF_J603gOyjn)nEm98oUiQ zTqnZ^2^xZx?hwX+&w)$9t>7{63TVAvCgcNl0*8XnflI+H;EzQA?jg!Orhyy{H%K7_ z>;@)-Ip8Z`8Tcu968s5#2sWf8SI#I9>;sMmk5B;&Ty^89ZTM)E4HkkggDDl1kV9)F z3w!}A1Gj+t!SBI8z=og6_`YB?@%rf2O8?Jj|7XW22)W?%;A`MAa0|E(tOT!vk3c)4 z%-{+w=|*mBsXPF`o6O00rz^ULu@B}fE z?hxL!lm?uu&6RWD9nkR|sRx7I!BkLhfa7&=9oU=-^u{W8Wgq-i;9sDtDidx8CW1L& z55&&|Uj}y)TdsFkR>E&MIgTzBopn==li*==SK6ghfNwmML0~3016&U71uMb7K-UZz zKa#lhiih&{EQKEL=c^1Qf58n8WfC|;(x9jiHiPHDhhXDO8L<`E9ZUwR##57dxhszg z=(tZ0vv4nz+)aA4tGn_bjjot{)KqaIKeH9+LHY*8&{SzB98Hyd#K^*?N)?zz87TEV zl^I|;xEH(t{tbF$$?)C4G;kKU4%`F&$TUy}R@pLQOK=ca1pa|08bAeG6WLVB0%w5l zfr}{o;W$raD|iUJ2HNCEdke4!(ZCT#Lnr`W12=$sz$(yYl1wNP><>-?=YVU$z2HUg zG1zo6?f+bWHj`z71Bp3*c`8}pt6&*u1kZx^LDyUvF9sYBJ{nJ_^IhDP`Q-O+S41lv3s59m2G&A_%`JU9l_gY&?X#0|Z?lr`{g2OXx$0Ve>A21kI?3~;;! zZUWDMe}E48G9f=O2226-!Fk|^;6Cs!)3=#YkMVm{BC3f9f2BFt5gZ7P2VamhC~ra73?2b*f(;hS1jE1~ zU?lD58?u`zao}jM2wVVu0PY4)gSQ3gmx6xyy-VwGC&97)(zguAaF7`7hFA^3VPaG`2su({th}mFYPVC zIB){^BB+Afo~Qkv6FdRo2H4;QsjorCpModA%isgBAr*iN-U5sU6TxC|9@vG_k96}< zk_~X=f-}M8;3wcw@E6ePMVWvfad3!_5(N$dv%uNl``|wCJZSh04u?{iP%zjV90xuJ zE(SM&hr!F>&6lYuD}0nk@VmVv(`^G%iwk?Q^waqt3=6@Jzyshla2Q1__{K*m0+)k( z!3*FM(0_&u9}A{|FMwr&^i-j}5UzsCD>7mT*dHtbRq$)@2I%mrj28^rQcZBvc!FVI zKQN1FpaAYvVy?1C@D&6o19yX`!TyxN-r>GVCioKg4)_Up61)M{nWt)AK?cj0n8fZ61+5^Gv;Ars0Ig~#qupELB{0{sBY%*7dbEky4K#|}8 zFdKXY97H3WM+a{u8(aulzd;k7-~1I{Fxmh|5*S7qjriGD>4?K>Kla=BDaGIt@N@72 zsLYe$g28^^5Tug>&Hz_{h6*@NfY-oAugl|l2$%q7f-_BiWHcWV?}81Y-E(xQUSi2e>$x`O{~r@er5XY!9Q-pG%x zwlnbUHl24;P0*d3MJ{xhrn`g>?V}B$+rv+T2QJg@P4}Z811rIwz&qeyV7;GY_(q^V z*lHJ*hi>59xtm7xz2VB?-88_l;~WIn3G#&G$9=K@`iAm`%n&-P^E~7M^jE$i|B1HB z0n2KY|yey9oiuVevSL4R;0?Cr26KN9&S z-K(?#bBo(3kHCg|q~90p2&RD9;B*5V^T7AP&%txxZSX1R{H4qw42%aSg2iCU5qYcY zM6eiqe2n(4qwN%f^Kt2z2SXY7DQKjCGrnl2909L_{f|=9tZ%10-A@I19HBTLkPHR8 zgNa}^SPH%)X;3ypIAkI+J_}w0Ls8IJ@GhoW_PxLtpuYod0fSJpQQ%(clzhK+6{tHx`~Qa4?G#sPOJ*S05gfOd z7O&`G9@*e@a1OW>EC)AN(f~$xj?X+r<48<>@LbJ z4+Fb^31FH@rw!QP*Fi}H$DQN-p9DRG*T7>$u93^&J7um6dup3D1-8a*#htr^h{sSwMQI-1@pxrte!j?@h}E5q5v#jo4zdig_Er}W zr1DM|W96N$QR^*(crT6N_bShcT^3`EUDoZQj||d5lTp}b-Nb`T(sp!P8fBS+^{?H& z<7dlM{?;w%Crh*A>F(l57>mz#uh?suc*;AmBJnxPVrSQpxc7-z5xe|U?Cd%c@9=34 z@no7q+k0%5FW}Wyk?K7#$x~f*um?X5q&jfmD$DEx5B1>m=dAyxhjINkJul{323Zo- zOBBI9x>sC|r8#enG~a!%S2y`?%_wc<#eCUIY+wGqUN3d9jQ#k5jBWU&l0@-voNHTp@_Mal)A1@6#BNd*2<2{yicC&bGEBx?ClP5qG;C|#tn+MH1|o7=4r#@9>_N`)+$=* zYjL9FX>;RN$%ie~GCQt}6YaftRa{AoW#XI=gvnRx#jk7c-te3GPK8!yYU}?5K8vmWx6OYFqJYZ?w z^j2SCHZ1M?(&v_D$E1FuQe%hotB@}=tyOaCY5hdWuTAfFTs~>3mifTCeqv8d-Oz8! zFw4ZxJdv@D)&0UtEX-=y1y4_7!;=2r@MCu>pX=WZJxW_Qfv@!!IT+{k-;7a8YcBqv zzbIeo`u>>}7C9J?jTt~sS#dIEj~j5Xj&_N8X@GdtQHWuHPfyF(DSM?k_NxIE6D-VX zUPy_j>JvEda;ff7nr2hF=t*FR%SgHgO2^(c(Rh&dBR@ov;ud#N6^ zmV5}~vL=*ggN9P<1LIdtGS7c`<*B`!d|I4`>TH|%x2=zk9ts}MMc#FRFe)cO_v9|kzuz_y6Q|kNKf5MWz-DJW6`Zn;fDQluuXl{3ooF43KVRxOJA?yqk>2_piOOb9b zcD54f8j{!@DiY>rZ8m5v5}w4)Fp=pWjIiTJk*=Yyqrcr=!iV&A zXlcKbK-Kacfz^i1?T-*>``CA$zK#5a@v@cTs5JJs51{t2(%AN9tCBpF3axdY;Hku{w^epj?fSBAtSUO}5RUcAYv&5Z`LzSB)-hWvt zp?`t2{rur>$Qmb#^m)H!X$}3uhHrqxy9*@Vm+4R8T?`WMe=Iqfv*bO8r5v-weVZl2 z_hyavf7W*-dT^?> z>J&0izR+HKSW&|~#4*QwtkxWl*w{?H>zR0|)}dY-qO@5eAL`BL8(O2ck1#g&O~lEF z*0{?zk)PxFuSO3w&p+|Ie+_Xv;NPPgXSGN?!pHff;6xux-!xepONS?ksj^lE+7Q&D9_pqcN!)1W4xtSZHdK_aZsW0(|1jna{|}?% zh-ZwN3RgFc6vn#iBw_S3b)t!ByfP-q#hQB2!|_R(X_oyUZ*P*AqF3)rdSGX1wmu@w z>d~Y@@-eg8rZV3DK1rNeoxG6rfxSg+ZVwN&>6I)cJ6!PnYr(4+PQD9XXd_tYv;ZV zpPBm}{O`H16Xw4D>L-6D{cY<{<9NM5IrsgQhI5+-^sgChTdlco6bU0()Xsg!k?;zO z+PUu>5;n7_o%?=9!Vj4HwxkSc?i)eC+_x(i!I$1F%!eH@_w7$kn)?o6Mb3SPvD4Rn zEJMzHv&l(w-+Th*zAurJ=Dx2nHedE}Pxi3%hF!xPkr=0udu~W`{ zpJ%6>`_5sfock_ir=0t~PfpBzH<6R(zIzCm`|c+v&3%s(F!#McPRxDjKriOLfz%!} z_ibe?{X5C~zvjMyw7v9KGxz1*!hX}-_gB;0ms4beX70;v#gb<3%iF_}X70Eecmn)Vf&D@vUlO@gEmwO0Hnz=7G4ojN3FLzXy zG;?3ko1dBcazEr?nz=8x6HA)8FL!R1G;?3>T`XzlzO7KNnz=9UCmc#M_ibiC`kJ{f z_Yw}Knfr35XXy|6hnXCA7nTkYG3#`Mq?!A2=i^Z2=1{!**wy`=As_6A6$C|t1%k$ z8VnY*wIs*EaqZ>dN^4#lJ6Nm;h4dPniFG!OSuGnck~SX)HAZ91#K8l2rD#t2;IXqU zl2&P|%PV-Y-&T35Hz^|yF=1Hoi z64cV|qdbh8GKX&C^R={`p>cK8#P<2JAd43aJ&Vg`nk0Zbc5 zlRD4rj0u0DlKx705^GUFV@&igQAzGyhDBi)*5*8Bz%X%fZBD|lDGMxPTYo=Hj4_=q z42wb~X=9h(9wv5y>R*TLo-bo-&BvY}E?PhB#o?<$EfaTKH(WID-SxvC)G>J8-zUwL z`-ktw1p{s3Yfs6}xQ6h4_)u;!(EF!D4lHseq6*uY(?G<%)SQ(;S z-~SHbt)A*Ps`lYoQwC1MTP+wMLYNOfnhVC6{GglL=)Q>lSDD80{w=J za*MXuNMoOQqeSPboIh%5D@!vCyP}G=d^YMLMqF*;W#5nL!iiV@Flq{pD_V0()hJQ@ z5kHP{!(LO%Y(HA`jLHV1k7HQVn7L*wSCTqJndfB2ltH6q`bnd0qzQB5^t1;>7I~|*6y~XhSEhYS-Ld9S zEv`03QsenY`WrW$PZO;&=ZCaG4P^oyG_7*wTACP;(r%{NjIlHq$B!4;r}i74*}~F% zEO)%9*QBZA$I46UwesGzf4n^W92|dD?(ntDF~`S?qPd?OUm*vZTIQxR&U=4@h~2n zI3bkxr-$hiqVRGdO&DX$qe#3Za3rY!xMYRn@DOU5p!vxsC~c76F1Ajq*nQ=9MVPcvm2)0v9a8` zj3()#01sW$v5s0R@l8JIE4XI+`lX+(W9!1&$k<;-qz5I*#I?o0|FX>6FeCjcI)-)} zDqfK;dR8DzUB+yA%2TUu5`L6*Gv`u9osy6#hLTQ+nPV|;(A14_?L?XQwe(D%I$G5=OPW)& z>om`rB+Z8=XAZ(3txY_zP?*&(muI;dOZA!O>*#eE^F;Ynx~0v{IOg@t92~2(>73ah zx52nEb8{VgMe&hLu~$?d%{~PkBJ;j> zHFMP`mWeM>v&5MgZ=yV#?GUYredW_E(Kyp8vclzQy0+h_36q2AKzK8&9rw)YTUjM_ z3<I%?AxI7#LpHnDVaotv1Duc?Mj1=;^YHE1`atVC{zVOsW+Aj=I|uu7Wq%d;2O zvBx`poGp)%Te6p0wwLktc41cU`Zu6z_$<3$9TmOgD_ISd`?C+qYpJ#R<)&lVVwdT3 zB74vfSw3y?m-yw#ULBA#JJ+)KDGPJNfh1yaj+?wuvsSNuJdXNP-s+qq+^ajS$qBEc zrHeP`yvpag54YsRjkPR5Lc>YIe6sPR%)XZ9KB<#rKN&gcNq zCy!3vjf0^kjIr#r%)xMW@{>Bu3ognW+%HYujOx|KKJ)8jQTtndn~XJxT1{JKl`Gor zkag~E%h>9%NglMg=$fnN#_?;KyQ+@fam+WD`=6TBwhgVL`scQ^?BQyuTO(@Zz}&Am zorvJvL2|jKR#6tj=ZcE{vS03146T|CQOERaPorN_ZgXy{yF+r_>gXq~X}O}d%g5)= z9$?uR9X`qx{lvIA_W|ZCnjDO~_R0d>{VLa{j*7NEk}GQR($UCY*%+gj#*EM%%^`RrCx*59j3{$Nr)zn(F;wzL)XWH}mQBr8F0RJKqNfCrub**|L1mY!NH+ zFXGUqHB%B?b?Qm)5SkKh%pXxl5?8i}Fvf^a@{i*PuT6qxJfikfEAmZ~9j$rSj(pK} zsbAzTtfTht@6H!}HsZ_tJ9Q);_LVH(m+OOl)-TzgUq=dSzm^%q9?oAXFP_xum{tF$e^ucd00e2Ke^UFlJPU$$t?D$U(Ij8zc@p`3(W+XB-BPFwuE z?ggUtt78k?a6r(QEiHJ- zG6&c^DV0DR`B0X#8G5T`jbBLxE_(z8ec3$ZId!_fH!W zb{2^Kb!}I{DwI!q{}>&9>G*o6;04Yh5T65lH5nJ7oTe#aY>(abJ(SD7m z7Mj*bw2}Md7k1%;wV|+Zn6pJ}dB^0FR|{+1F{!OQm2#)q(X2x5L;q5QC9f5V_MbMl zu&x)rZ(md>sz2$CLQ@CSlu)JnYdzKDtNx=1BE*#P|1U(tcb^H-UUOQvm#=|mN&j6c84AG-$q7w$byxp zLqpEj!He(waR{ORRt_ELe?5nu^xxVck^b8#jy5aVXZuS-&T1>U8)dhm|4L(9^4tFE z6yj3j`CWLNIiTXwkp4%ijVDIAb?(AW4*if#+CXDWmd70_8ENUt3A#*Yi@NVyy?f?% zQGhpV3ee;<-Mgx5w36Gs@i=NG+a*rUq7=gOj_{xqd1S8OAj?G7O(~eLIA>BFC@x=` z%q!Jz)1%y4*)^btr_tATb)CUSnauBs;6d+^{}u;dTW9bG!mJKSkMgwXMtx$onx7u! zWwS^)7qRm!Iek^<(|RwPmX7RZkZNGRnP#;o7^qn;YR9uQo;;x$Dip#sEGPJe`j@F9uqB`!ZzN!B!?4+-4XD6#?`rJX1 z>#LDjQEvSkQ5UXHU)!FdXn#=J=$J!DeU&Y7!Xk5BW)kCTf-5eENpw;dWl?YPv}LFB zIqE{=$+=UFJf{zA@GU#(Yn!ZI&W`d>%g^cUY+BQO*>hFj?5My7YuHI&+tC{PV-j|% z1=&%44N|BgMEnf4d)m5uM8aIvyHf9GV?*0LSM5PggV^_86I+YDa-Mn9p}Z~?NAAE> z`}L?6t!;{GYTtb#rM!Z~M(j`;uOX++b557I$~}Z%2Jb1~S?CD9z^6 zE#9Vt ze%6GYoVK^4P&pazrmFG0{-kS>Ck+Q)9#*Yr3{mR8Kt8{j>Wc66f21|?rVi*v|GLt* zc@pR4d@qnfxeO+uh{bG;_&f<^EE+W8dn6oY@hy$`EeQ|2jkkZ$yV)3eQCaM)#qs4h zIj!rBa=1WL9DbqyI)`7`tpx0%!Z$xm|3*_4*0a?)+OWf3_nO-j;*VTyb1B%*mu2r3w3MO5gC60xO`dpNzwm#^bIg@2{dI%GCzGcQdlGch z!`rC-MNuIJThi)PhS@Ot*M;TG#8LG+$3i`H*5?VHIY>4uAWlR^c7U@e60-w}x^_ zBcBJy_|VGUT*!~DoWf_R{eRX6H|aqE>UHsQrZC*(^<8X-sJ_KfLAoM!!_WF`-4@m9 ziayd{%PF?e(Z-OYrF~0TwSly|*@vQP;js^Qr68@?(weH4>sWZgbROZMCQrD|UkNx* zc?PthfVLi_+v_5`5js#)=z5dbb~yRCcYBX+LO+nywGcaT7Kw1?3nv#^i7Yn7EPXbn zDfGWYTu2cY(m<%IFh%4cL=GE4oTC!JAl=B}{Tj)(^JG#y?~3F;!27Fia8sJIi?lLp0=^>yW|KW~ z2L-&%JN0x^f(vWH{Vv1tZXWrADcqWW3)hY|SbUbyf8CVF6hZg;{kBT7(w=4B19h+S z4%mJodDjGxcL8V6eh+y!vv;BJdQoDUUxc-wVVg7c1ffN2pn}Bx)$4KS@CUz1#Q@H%Gh3rff&KKA@MmXoHIXCov4Y*^{ zgXR@)5B1F(dan*9zY^+A^-53qR~n?$;}mtRyO=$#yG!?r6ti`-dg+GV+pVUH_ad9_ zIg!Z#)#;|*YXqA_xA3Qe+veF(a-DoA{T7TI4!*XR3AQ?~2c+B~XG34x2Lu}{FP^ynL(WFNUM~JL zw9zSFV_#bbf{ncw4>oS(bn^3xAfpdCo&9Ws33gUuS`tN07eB8AGIl3t6F=L&9<=Y- z*?XO*oJNu4>f?2joZ0O3^?FRs5_bA|*-@OC?DY5YBI(J;u(KBHi=sY$ejY%Fa+PI|Bv2$L`i5;c9k z;J_=%?N;nHk>pL}^zjq%K4o>9qs@L|v~Qx@*FbE?o(|Ilyzm7DJ(wfGHep0IScFYEYb$ zh0G!1lUUB@yqt4nVES((Vx+REP?%;4(_A)*SYz2#%&9vIQ+x&sC1$~8DhbnBoMuba z?JQCet^vU{dBwj%0sInqrxUX*XC6zOIg}DVS53R8_i}%OLyQrz#XoU)j91k+*jUcS z;m;b^sr$&N`&g~wFclnTB-gPs#})sS_+9GVnNeOI2iQ33S>rJ;HDDH@6wahd=8lj!CGL6*t*)q;-ktuyds^64n zQ`$!AC3-c45|C$(AZy_ljv$*(n524#)f97`imelM>T;h<^wI^zFHMA(+1k+z-fw(O zwu)^Z60Gh0TddPHr4n+}_2R z(1N}pFY<|nJiCaYN6IU~3A(mHr0_o_CY+VQTBSWJDO#noT76&N)X;+sm$Zg>R>o+R zfvgm3l_9Lm&?>`O*`Za&u=2B3;n6@@TF}3 z|FJYz8|WGb*SgvAMN{`7a+e{~@j6JZ1A^n3by2BYo4+@3ZxS*{Z~R#EP9cM{xkAt2AQeJ+tEMDF#PZmcQ1> z_YAy96XVJHM6<5M__FeXRtaR~h*k+@B}=PBu=282iDG54R*7L{s!1_$_PtrsnVM4|_!pbA9@*OKaa)abBQOU{;Z8|@(62M_lgDArt z)`Ki6;}Ofw7P7VK_e9?;$kCsyceKg#2pRl9t9YtuPxMVgo3mk?*?aoIbbmdEEEB`)S-GAP`HZ{?3MU*R#%vZ;rJXDR*FN1oKj6; zp-c?sQqZ$d&PmAmq|0=2&QJ|c^8vqM7ec4MOs+2T&9da z%bt#6_9y0i@l`BzHctnI+W!iv;Q{eC{na(qdbggxlQ;AO*;WJpWKX5^#6M=wdh_(s zr5;tb16TMdO$E8Ae^%=|>%5jm7Bw^Yvvq^0E&iv(2eGh8)E56!Tw0URoxUN9S5YfD zn=SFZIOvD;atB2mX5_IZzAvkrpA9>R)vYz9z_?H!#yWoD(%*~RyeDzM zPs9wjxUH%3W$ozI=DMQ57B6y$Wg@BANGjpLc`WRZbs$c`ml!AMissk(d=QnMjpt#! z|8~?USK~+SMcIuy^MXE|?<*lRSDr!NS7`6z53dF3h|kd(Ab-Si6tRNB^Jl&~Fu16h zCtq0M=+!h;A3@PaBKk7bKxPA9L$xCFCR!CZNnif(g$~xD>128|efh(ykDOa6!tkmZ z`%Q6pEt>r;VdoWY_P0THC*l8sW?1~;C3DKdpp2&Cn>K;hF*wpbMB)V(_Ww-f<`1uk zbHR8m%v2Cwr{OTi5QZ1V*>5TcUm&V$`*}6Wit<+~sABk-${$`S<;a`?fB1q*U3JeF zb~xP2s2yIGVZUkXc*&m&>P>0$ISzlsdJb_WYJe9obz?}lhs?wU0rH!wj2GoN(Rb0n zyvWLaQ=mULN8Pua$Bb?lt_mE&7^)FJ5ra^OS5OY$mVga!^xLUQ=ejsp|OZy0cVMi z6p(m4W9j*}H4?A4v9!j&CM{kmW9cum#Oq@u8N|vG661R#I2fhLh`90`e6ZdsZ{5s?_L7qi5xxsdn*I7@sT2z9}$ zIV|yvg(s~1xq$Tf(hY*~#EXOR@fnHnS~E)#WI`!;9hN1Y2Ot#RZNw6m`J~)e~rY;&z#tNv&0L>Ed6AbI+K&79_F(0nlDSd7L4Ti zZUUD0QWrLI60gs)*3le{4+ty;n+qoH1t4j&IVRr&z@ZM3g!FjDesDE$?nTmRTfz-10EHXkmb*dC5F!{_^#r ztN1yHCTZjL)kWg=#lCBbOutdpns2W!>cRyJ`LM`z-+nFgCYoQ8dD_QC75K%0)*Q2| zNZj;Uxw{C@A+2?1<(Y3};*F0MnSSoBiLKH*Ht6Rx-xhr(YUXs&9sF8Q6UG=;zgYaD zWW7W2Li`L;V^(8&(l3w3v@Yg*YmIZlirwnEfitpL-2S<^U2!-3j#ZO{v8r3K*u?DE zVjKMCLTfG^T`X=r-7>b=^s^zYc}$i}JT|8|3cvK!nDH`>my7xCVDr-yv?1sb8y?1( z8O6kO%BEcyONunc&GX$ zrXT9oitSP&?r&CIORicbt}bX^QtRO(+M8e1u)zN?9t#r2nung$ib-z|sP#auXN>`B zRI8HOwWclfuFw+EXnn&>V+lYtt`zk#uBbiHR4_;H{*gGC8uyp Txi*QsFG|Gy>UVdQ>}&sjBRVyl From 32355b6cacebdd59db8254bd8529b79172f26b85 Mon Sep 17 00:00:00 2001 From: PeterSthuka Date: Sun, 2 Aug 2026 22:43:42 +0300 Subject: [PATCH 2/4] Reject a call that the user cancels before its INVITE arrives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A VoIP push routinely beats the INVITE by a second or more — the logs show "INVITE observed after 1840 ms" — and the two paths out of that window were asymmetric. Answering polls for the call until answerTimeout; rejecting did not. With no call id bound yet, -terminateCallWithUUID:declining:completion: sent nothing to SIP, deleted the pending record and returned CallWaveErrorNoActiveCall. Nothing then told the peer anything. The INVITE arrived to a registry with no pending call, on_incoming_call answered 180 Ringing before consulting any state, and handleIncomingSIPCall: took the host-owned branch and registered a second call under a fresh UUID. The intercom went on ringing until incomingCallTimeout, and the host saw .incoming again after .ended. The rejection is now remembered rather than discarded. A pending call that the user rejects is marked cancelled and kept, the state goes to .ended and the completion reports success — the user's intent did succeed, so an error there was wrong. on_incoming_call asks for such a cancellation before it rings and answers 603 Decline instead. This side is the callee, so it answers the INVITE rather than sending CANCEL. Two rules keep a stale cancellation from doing harm: it expires after answerTimeout, the same budget an INVITE gets to arrive, and a call still legitimately awaiting its INVITE always wins over a pending cancellation, so an INVITE that may belong to a live call is never refused. Both checks run on the PJSIP callback thread under the registry's own lock, like -canAcceptAnotherIncomingCall — a 180 or a 603 cannot wait for a queue hop. Nothing is reported to CallKit from this path: in host-owned mode the provider belongs to the application, which ends the call from the state stream. CallWaveCallRegistry sits behind a private header, so its tests are a small Objective-C target that reaches it through a header search path — 14 cases covering that a cancellation keeps the record, that a cancelled call is no longer offered as awaiting an INVITE, that an expired cancellation is equivalent to no record and is purged, and that a live pending call takes precedence. No public API was widened for testing, and the public headers are untouched. The end-to-end behaviour needs a real intercom and is not covered here. --- CHANGELOG.md | 23 +++ CallWaveKit/CallWaveCallRegistry.h | 28 ++- CallWaveKit/CallWaveCallRegistry.m | 74 +++++++- CallWaveKit/CallWaveClient.m | 55 +++++- Package.swift | 12 ++ .../CallWaveCallRegistryTests.m | 173 ++++++++++++++++++ 6 files changed, 358 insertions(+), 7 deletions(-) create mode 100644 Tests/CallWaveKitRegistryTests/CallWaveCallRegistryTests.m diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ca4a8..5a581e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,29 @@ bump may contain breaking changes, and each one is listed below. ### Fixed +- **Rejecting a call before its INVITE arrives now stops the caller ringing.** + A VoIP push routinely beats the INVITE by a second or more, and the reject + path — unlike the answer path, which polls for the call until `answerTimeout` + — sent nothing to SIP when there was no call id yet. It deleted the pending + record and returned `CallWaveErrorNoActiveCall`, so no `603`, `486` or `480` + ever left the device. The INVITE then arrived to an empty registry, was + answered `180 Ringing`, and became a *second* incoming call under a fresh + UUID: the intercom kept ringing until `incomingCallTimeout`, and the host saw + `.incoming` again after `.ended`. + + `-endCallWithUUID:completion:` and `-declineCallWithUUID:completion:` now + keep the record and mark it cancelled instead of deleting it, report + `CallWaveCallStateEnded` and complete without an error — the user's intent + succeeded, so it is not a failure. `on_incoming_call` checks for such a + cancellation before it rings, and answers `603 Decline` instead. Being the + callee, it answers the INVITE; it does not send CANCEL. + + A cancellation expires after `answerTimeout`, so one whose INVITE never + arrived cannot reject an unrelated later call, and a call still legitimately + waiting for its INVITE always takes precedence over a pending cancellation. + Nothing is reported to CallKit from this path: in host-owned mode the + application owns the provider and ends the call from the state stream. + - **The bundled PJSIP binary is built for iOS 15.0 again.** It carried `minos 16.0` while the package declares iOS 15.0, so every application with a 15.x deployment target linked it with a `built for newer 'iOS' version` diff --git a/CallWaveKit/CallWaveCallRegistry.h b/CallWaveKit/CallWaveCallRegistry.h index ea2bda9..d46adee 100644 --- a/CallWaveKit/CallWaveCallRegistry.h +++ b/CallWaveKit/CallWaveCallRegistry.h @@ -29,6 +29,13 @@ FOUNDATION_EXPORT const CallWaveSIPCallId CallWaveSIPCallIdInvalid; @property (nonatomic, assign) BOOL microphoneMuted; @property (nonatomic, strong, readonly) NSDate *createdAt; +/// Set when the user rejected the call before its INVITE arrived. The record is +/// kept rather than removed, so the INVITE that follows can be answered with a +/// final rejection instead of being rung as a fresh call. +@property (nonatomic, assign, readonly, getter=isCancelledBeforeInvite) BOOL cancelledBeforeInvite; +/// When the cancellation was recorded, for expiring it. +@property (nonatomic, strong, readonly, nullable) NSDate *cancelledAt; + - (instancetype)init NS_UNAVAILABLE; - (instancetype)initWithUUID:(NSUUID *)uuid NS_DESIGNATED_INITIALIZER; @@ -46,7 +53,8 @@ FOUNDATION_EXPORT const CallWaveSIPCallId CallWaveSIPCallIdInvalid; - (nullable CallWaveCall *)callForUUID:(nullable NSUUID *)uuid; - (nullable CallWaveCall *)callForCallId:(CallWaveSIPCallId)callId; /// The oldest call that was announced by a push but whose INVITE has not -/// arrived yet, so a fresh INVITE can be matched to it. +/// arrived yet, so a fresh INVITE can be matched to it. A call the user already +/// cancelled is never returned here — it is not waiting to be answered. - (nullable CallWaveCall *)callAwaitingInvite; /// The call `currentCallUUID` should point at: the most recently created call /// that has not ended. @@ -61,6 +69,24 @@ FOUNDATION_EXPORT const CallWaveSIPCallId CallWaveSIPCallIdInvalid; - (void)removeCallWithCallId:(CallWaveSIPCallId)callId; - (NSArray *)removeAllCalls; +/// Records that the user rejected `uuid` before its INVITE arrived, keeping the +/// record so the late INVITE can still be refused. +/// +/// Returns NO — and changes nothing — when there is no such call, or when the +/// call already has a SIP call id, because then there is a real INVITE to +/// reject through PJSUA and no reason to remember anything. +- (BOOL)markCallCancelledBeforeInvite:(nullable NSUUID *)uuid; + +/// Removes and returns the call whose late INVITE should be refused, or `nil` +/// when there is none. +/// +/// A cancellation older than `window` is dropped and not returned, so a +/// cancelled call whose INVITE never arrived cannot reject an unrelated later +/// one. A call that is still legitimately awaiting its INVITE takes precedence: +/// while one exists this returns `nil`, so the INVITE is matched to it rather +/// than consumed by a cancellation that may belong to a different call. +- (nullable CallWaveCall *)takeCallCancelledBeforeInviteWithin:(NSTimeInterval)window; + /// Runs `block` with the lock held, for a read-modify-write that has to be /// atomic. Do not call back into the registry from inside it. - (void)performLocked:(NS_NOESCAPE dispatch_block_t)block; diff --git a/CallWaveKit/CallWaveCallRegistry.m b/CallWaveKit/CallWaveCallRegistry.m index 5617a54..60f6615 100644 --- a/CallWaveKit/CallWaveCallRegistry.m +++ b/CallWaveKit/CallWaveCallRegistry.m @@ -4,6 +4,12 @@ const CallWaveSIPCallId CallWaveSIPCallIdInvalid = -1; +/// Only the registry may record a cancellation, and only under its lock. +@interface CallWaveCall () +@property (nonatomic, assign, readwrite, getter=isCancelledBeforeInvite) BOOL cancelledBeforeInvite; +@property (nonatomic, strong, readwrite, nullable) NSDate *cancelledAt; +@end + @implementation CallWaveCall - (instancetype)initWithUUID:(NSUUID *)uuid { @@ -15,6 +21,8 @@ - (instancetype)initWithUUID:(NSUUID *)uuid { _displayName = @""; _state = CallWaveCallStateIncoming; _createdAt = [NSDate date]; + _cancelledBeforeInvite = NO; + _cancelledAt = nil; } return self; } @@ -76,7 +84,9 @@ - (CallWaveCall *)callAwaitingInvite { os_unfair_lock_lock(&_lock); CallWaveCall *oldest = nil; for (CallWaveCall *call in _callsByUUID.objectEnumerator) { - if (call.callId != CallWaveSIPCallIdInvalid || call.state == CallWaveCallStateEnded) { + if (call.callId != CallWaveSIPCallIdInvalid || + call.state == CallWaveCallStateEnded || + call.isCancelledBeforeInvite) { continue; } if (oldest == nil || [call.createdAt compare:oldest.createdAt] == NSOrderedAscending) { @@ -172,6 +182,68 @@ - (void)removeCallWithCallId:(CallWaveSIPCallId)callId { os_unfair_lock_unlock(&_lock); } +- (BOOL)markCallCancelledBeforeInvite:(NSUUID *)uuid { + if (uuid == nil) { + return NO; + } + os_unfair_lock_lock(&_lock); + CallWaveCall *call = _callsByUUID[uuid]; + // A call that already has a SIP id has a real INVITE to answer, so there is + // nothing to defer; and re-marking must not extend an existing deadline. + BOOL marked = call != nil && + call.callId == CallWaveSIPCallIdInvalid && + !call.isCancelledBeforeInvite; + if (marked) { + call.cancelledBeforeInvite = YES; + call.cancelledAt = [NSDate date]; + } + os_unfair_lock_unlock(&_lock); + return marked; +} + +- (CallWaveCall *)takeCallCancelledBeforeInviteWithin:(NSTimeInterval)window { + os_unfair_lock_lock(&_lock); + + NSDate *now = [NSDate date]; + CallWaveCall *oldestCancelled = nil; + BOOL someoneIsStillWaiting = NO; + NSMutableArray *expired = [NSMutableArray array]; + + for (CallWaveCall *call in _callsByUUID.objectEnumerator) { + if (call.callId != CallWaveSIPCallIdInvalid) { + continue; + } + if (!call.isCancelledBeforeInvite) { + if (call.state != CallWaveCallStateEnded) { + someoneIsStillWaiting = YES; + } + continue; + } + if (call.cancelledAt == nil || + [now timeIntervalSinceDate:call.cancelledAt] > MAX(window, 0)) { + [expired addObject:call]; + continue; + } + if (oldestCancelled == nil || + [call.cancelledAt compare:oldestCancelled.cancelledAt] == NSOrderedAscending) { + oldestCancelled = call; + } + } + + // A cancellation whose INVITE never came is dead weight; drop it here so it + // cannot reject an unrelated call later. + for (CallWaveCall *call in expired) { + [_callsByUUID removeObjectForKey:call.uuid]; + } + + CallWaveCall *result = someoneIsStillWaiting ? nil : oldestCancelled; + if (result != nil) { + [_callsByUUID removeObjectForKey:result.uuid]; + } + os_unfair_lock_unlock(&_lock); + return result; +} + - (NSArray *)removeAllCalls { os_unfair_lock_lock(&_lock); NSArray *calls = _callsByUUID.allValues; diff --git a/CallWaveKit/CallWaveClient.m b/CallWaveKit/CallWaveClient.m index 8d6690f..66ec781 100644 --- a/CallWaveKit/CallWaveClient.m +++ b/CallWaveKit/CallWaveClient.m @@ -203,6 +203,7 @@ @interface CallWaveClient () - (BOOL)managesCallKit; - (NSString *)displayNameForCaller:(nullable NSString *)caller; - (BOOL)canAcceptAnotherIncomingCall; +- (nullable CallWaveCall *)takeCallCancelledBeforeInvite; - (void)handleIncomingSIPCall:(pjsua_call_id)callId caller:(NSString *)caller; - (void)handleSIPCallConfirmed:(pjsua_call_id)callId; - (void)handleSIPCallDisconnected:(pjsua_call_id)callId @@ -1064,12 +1065,20 @@ - (void)clearCallWithUUID:(nullable NSUUID *)uuid { return; } [self.registry removeCallWithUUID:uuid]; - if ([uuid isEqual:self.currentCallUUID]) { - CallWaveCall *next = self.registry.mostRecentCall; - self.currentCallUUID = next.uuid; - self.currentCaller = next.displayName; - self.microphoneMuted = next != nil ? next.microphoneMuted : NO; + [self detachCurrentCallIfItIs:uuid]; +} + +/// Moves `currentCallUUID` off `uuid` without touching the registry, for a call +/// whose record has to outlive the user's decision — a cancellation waiting for +/// its late INVITE. Must run on the main queue. +- (void)detachCurrentCallIfItIs:(nullable NSUUID *)uuid { + if (uuid == nil || ![uuid isEqual:self.currentCallUUID]) { + return; } + CallWaveCall *next = self.registry.mostRecentCall; + self.currentCallUUID = next.uuid; + self.currentCaller = next.displayName; + self.microphoneMuted = next != nil ? next.microphoneMuted : NO; } #pragma mark - Incoming-only calling @@ -1362,6 +1371,19 @@ - (void)terminateCallWithUUID:(NSUUID *)uuid NSUUID *target = call.uuid ?: uuid; pjsua_call_id callId = call != nil ? call.callId : CallWaveSIPCallIdInvalid; if (callId == CallWaveSIPCallIdInvalid) { + // A call the push announced but whose INVITE has not arrived yet. + // There is nothing to reject through PJSUA, so the rejection is + // remembered instead and applied to the INVITE when it lands. The + // user's intent succeeded; this is not an error. + if ([self.registry markCallCancelledBeforeInvite:target]) { + CWLogInfo(CallWaveLogCategoryCall, + @"call %@ %@ before its INVITE arrived; the INVITE will be refused", + target.UUIDString, declining ? @"declined" : @"ended"); + [self publishCallState:CallWaveCallStateEnded forUUID:target]; + [self detachCurrentCallIfItIs:target]; + [self complete:completion error:nil]; + return; + } [self clearCallWithUUID:target]; [self complete:completion error:CallWaveMakeError(CallWaveErrorNoActiveCall, @@ -1865,6 +1887,16 @@ - (void)refreshProviderConfiguration { self.provider.configuration = [self makeProviderConfiguration]; } +/// Called from a PJSIP callback thread, like `-canAcceptAnotherIncomingCall`: +/// the registry has its own lock, and a `180`/`603` cannot afford a queue hop. +/// +/// The cancellation is honoured for `answerTimeout` — the same budget the +/// client gives an INVITE to arrive — so it cannot outlive the call it belongs +/// to and reject a later, unrelated one. +- (CallWaveCall *)takeCallCancelledBeforeInvite { + return [self.registry takeCallCancelledBeforeInviteWithin:self.answerTimeout]; +} + - (BOOL)canAcceptAnotherIncomingCall { if ([self.registry callAwaitingInvite] != nil) { return YES; @@ -2431,6 +2463,19 @@ static void onIncomingCall(pjsua_acc_id accId, pjsua_call_id callId, pjsip_rx_da return; } + // The user may have rejected this call from the CallKit screen before its + // INVITE arrived — the push routinely beats the INVITE by a second or more. + // The peer is still waiting for a final response, so answer one now instead + // of ringing: `603` here, never CANCEL, because this side is the callee. + CallWaveCall *cancelled = [client takeCallCancelledBeforeInvite]; + if (cancelled != nil) { + pjsua_call_answer(callId, PJSIP_SC_DECLINE, NULL, NULL); + CWLogInfo(CallWaveLogCategoryCall, + @"INVITE for call %@ arrived after the user rejected it; answered 603", + cancelled.uuid.UUIDString); + return; + } + if (![client canAcceptAnotherIncomingCall]) { pjsua_call_answer(callId, PJSIP_SC_BUSY_HERE, NULL, NULL); return; diff --git a/Package.swift b/Package.swift index a0ecb9b..c72a3e2 100644 --- a/Package.swift +++ b/Package.swift @@ -56,6 +56,18 @@ let package = Package( name: "CallWaveKitTests", dependencies: ["CallWaveKit", "CallWaveKitAsync"], path: "Tests/CallWaveKitTests" + ), + // CallWaveCallRegistry is an implementation detail behind a private + // header, so its tests are Objective-C and reach it through a header + // search path rather than through the module. Keeping them out of the + // Swift target is what avoids widening the public API for testing. + .testTarget( + name: "CallWaveKitRegistryTests", + dependencies: ["CallWaveKit"], + path: "Tests/CallWaveKitRegistryTests", + cSettings: [ + .headerSearchPath("../../CallWaveKit") + ] ) ] ) diff --git a/Tests/CallWaveKitRegistryTests/CallWaveCallRegistryTests.m b/Tests/CallWaveKitRegistryTests/CallWaveCallRegistryTests.m new file mode 100644 index 0000000..f4020ee --- /dev/null +++ b/Tests/CallWaveKitRegistryTests/CallWaveCallRegistryTests.m @@ -0,0 +1,173 @@ +#import + +#import "CallWaveCallRegistry.h" + +/// `CallWaveCallRegistry` is a private header, so these live in an +/// Objective-C target that reaches it through a header search path rather than +/// through the module. Nothing here is public API. +@interface CallWaveCallRegistryCancellationTests : XCTestCase +@end + +@implementation CallWaveCallRegistryCancellationTests { + CallWaveCallRegistry *_registry; +} + +- (void)setUp { + [super setUp]; + _registry = [[CallWaveCallRegistry alloc] init]; +} + +/// A call announced by a push, with no INVITE yet — the state the bug happens in. +- (CallWaveCall *)pendingCall { + return [_registry registerCallWithUUID:[NSUUID UUID]]; +} + +#pragma mark - Marking a cancellation + +- (void)testCancellingAPendingCallKeepsTheRecord { + CallWaveCall *call = [self pendingCall]; + + XCTAssertTrue([_registry markCallCancelledBeforeInvite:call.uuid]); + + // Removing it is what used to let the late INVITE look like a fresh call. + XCTAssertNotNil([_registry callForUUID:call.uuid]); + XCTAssertEqual(_registry.count, (NSUInteger)1); + XCTAssertTrue([_registry callForUUID:call.uuid].isCancelledBeforeInvite); + XCTAssertNotNil([_registry callForUUID:call.uuid].cancelledAt); +} + +- (void)testCancellingAnUnknownCallChangesNothing { + XCTAssertFalse([_registry markCallCancelledBeforeInvite:[NSUUID UUID]]); + XCTAssertFalse([_registry markCallCancelledBeforeInvite:nil]); + XCTAssertEqual(_registry.count, (NSUInteger)0); +} + +- (void)testACallWithAnInviteIsNotMarked { + CallWaveCall *call = [self pendingCall]; + [_registry bindCallId:7 toUUID:call.uuid]; + + // There is a real INVITE to reject through PJSUA, so nothing is deferred. + XCTAssertFalse([_registry markCallCancelledBeforeInvite:call.uuid]); + XCTAssertFalse([_registry callForUUID:call.uuid].isCancelledBeforeInvite); +} + +- (void)testMarkingTwiceDoesNotExtendTheDeadline { + CallWaveCall *call = [self pendingCall]; + + XCTAssertTrue([_registry markCallCancelledBeforeInvite:call.uuid]); + NSDate *first = [_registry callForUUID:call.uuid].cancelledAt; + + XCTAssertFalse([_registry markCallCancelledBeforeInvite:call.uuid]); + XCTAssertEqualObjects([_registry callForUUID:call.uuid].cancelledAt, first); +} + +#pragma mark - A cancelled call is not awaiting an INVITE + +- (void)testCancelledCallIsNotReturnedAsAwaitingInvite { + CallWaveCall *call = [self pendingCall]; + XCTAssertEqualObjects([_registry callAwaitingInvite].uuid, call.uuid); + + [_registry markCallCancelledBeforeInvite:call.uuid]; + + // Matching an INVITE to it would ring a call the user already rejected. + XCTAssertNil([_registry callAwaitingInvite]); +} + +- (void)testCancellingOneCallLeavesAnotherAwaitingInvite { + CallWaveCall *cancelled = [self pendingCall]; + CallWaveCall *live = [self pendingCall]; + + [_registry markCallCancelledBeforeInvite:cancelled.uuid]; + + XCTAssertEqualObjects([_registry callAwaitingInvite].uuid, live.uuid); +} + +#pragma mark - Consuming a cancellation + +- (void)testTakingACancellationReturnsItAndRemovesTheRecord { + CallWaveCall *call = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:call.uuid]; + + CallWaveCall *taken = [_registry takeCallCancelledBeforeInviteWithin:60]; + + XCTAssertEqualObjects(taken.uuid, call.uuid); + XCTAssertNil([_registry callForUUID:call.uuid]); + XCTAssertEqual(_registry.count, (NSUInteger)0); + // Once consumed it must not reject a second INVITE. + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:60]); +} + +- (void)testNothingIsTakenWhenNoCallWasCancelled { + [self pendingCall]; + + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:60]); + XCTAssertEqual(_registry.count, (NSUInteger)1); +} + +- (void)testALiveCallAwaitingItsInviteTakesPrecedence { + CallWaveCall *cancelled = [self pendingCall]; + CallWaveCall *live = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:cancelled.uuid]; + + // The arriving INVITE may belong to `live`; refusing it would drop a call + // the user never rejected. + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:60]); + XCTAssertNotNil([_registry callForUUID:cancelled.uuid]); + XCTAssertNotNil([_registry callForUUID:live.uuid]); +} + +- (void)testTheOldestCancellationIsTakenFirst { + CallWaveCall *first = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:first.uuid]; + usleep(20000); + CallWaveCall *second = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:second.uuid]; + + XCTAssertEqualObjects([_registry takeCallCancelledBeforeInviteWithin:60].uuid, first.uuid); + XCTAssertEqualObjects([_registry takeCallCancelledBeforeInviteWithin:60].uuid, second.uuid); +} + +#pragma mark - Expiry + +- (void)testAnExpiredCancellationIsEquivalentToNoRecord { + CallWaveCall *call = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:call.uuid]; + usleep(20000); + + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:0.01]); + // And it is dropped, so it cannot reject some later, unrelated call. + XCTAssertNil([_registry callForUUID:call.uuid]); + XCTAssertEqual(_registry.count, (NSUInteger)0); +} + +- (void)testAFreshCancellationSurvivesTheSameWindow { + CallWaveCall *call = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:call.uuid]; + + XCTAssertEqualObjects([_registry takeCallCancelledBeforeInviteWithin:60].uuid, call.uuid); +} + +- (void)testExpiryDoesNotDisturbACallStillAwaitingItsInvite { + CallWaveCall *cancelled = [self pendingCall]; + [_registry markCallCancelledBeforeInvite:cancelled.uuid]; + usleep(20000); + CallWaveCall *live = [self pendingCall]; + + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:0.01]); + XCTAssertNil([_registry callForUUID:cancelled.uuid]); + XCTAssertNotNil([_registry callForUUID:live.uuid]); + XCTAssertEqualObjects([_registry callAwaitingInvite].uuid, live.uuid); +} + +#pragma mark - Calls with a SIP id are untouched + +- (void)testAnAnsweredCallIsNeverConsumedAsACancellation { + CallWaveCall *answered = [self pendingCall]; + [_registry bindCallId:3 toUUID:answered.uuid]; + answered.state = CallWaveCallStateActive; + + XCTAssertNil([_registry takeCallCancelledBeforeInviteWithin:60]); + XCTAssertEqualObjects([_registry callForCallId:3].uuid, answered.uuid); +} + +@end From 60b9bba9b4d8ade93b72b8156992ae8fd6b6958e Mon Sep 17 00:00:00 2001 From: PeterSthuka Date: Sun, 2 Aug 2026 22:46:30 +0300 Subject: [PATCH 3/4] Add a field-testing checklist and point the release process at it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The unit tests cover parsing and property contracts; they cover none of the answer path, the push path, the audio session or the registration lifecycle, which is where the decline-before-INVITE bug lived and why nothing caught it. FIELD-TESTING.md is the twelve-scenario pass that has to be run by hand on a device against a real intercom, and RELEASING.md now names it as step 0 — before the version bump, not after the tag. Three claims in the checklist did not match the code and are corrected here: the log categories are lower-case and are sip/call/audio/push/network/pjsip with no "Engine"; the decline-before-INVITE case failed in 0.3.0 and earlier rather than in 0.3.1, which is the release that fixes it; and scenario 4 now names the log line that proves the fix ran. --- FIELD-TESTING.md | 190 +++++++++++++++++++++++++++++++++++++++++++++++ README.md | 5 +- RELEASING.md | 17 +++++ 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 FIELD-TESTING.md diff --git a/FIELD-TESTING.md b/FIELD-TESTING.md new file mode 100644 index 0000000..40de6b1 --- /dev/null +++ b/FIELD-TESTING.md @@ -0,0 +1,190 @@ +# Field testing CallWaveKit + +`Scripts/run-package-tests.sh` covers URI construction, configuration equality, +caller-name formatting, DTMF normalization and the client's property contracts. +It cannot cover the part that actually breaks: a real PBX, a real VoIP push, a +real lock screen and a real audio session. Everything in this file has to be +done by hand, on a device, against an intercom. + +Run it before tagging a release, and after any change to the answer path, the +push path, the audio session or the registration lifecycle. + +## Setup + +- A physical iPhone. The Simulator has no PushKit and no usable audio route. +- An intercom (or PBX) that calls the account, and a door the DTMF code opens. +- A host application build with the library's logging opened up: + +```swift +CallWaveLog.level = .debug +CallWaveLog.redactsIdentifiers = false // never in a build you ship +``` + + Redaction is on by default, so without that second line every UUID, caller and + registrar reads `` and the scenarios below cannot be followed. At + `.debug` the PJSIP protocol trace includes `Authorization` headers — this is a + debugging build, not a TestFlight build. + +- Console output, filtered on the library's subsystem: + +```sh +log stream --predicate 'subsystem == "com.callwave.kit"' --info --debug +``` + + Categories are `sip`, `call`, `audio`, `push`, `network` and `pjsip`, and + they are lower-case — `--predicate 'category == "call"'` to narrow further. + +Record the log for every scenario. A failure with no log is a failure that has +to be reproduced from scratch. + +## Scenarios + +Each one lists what to do, what must happen, and the marker that proves it. + +### 1. Cold start, locked screen + +The single most fragile path: the application is not running, the phone is +locked, the call is answered from the lock screen. + +Force-quit the app, lock the phone, place the call, answer from the lock screen. + +- CallKit shows the branded name and icon. +- Two-way audio within a second of answering — **check both directions**, the + common failure is one-way. +- `[Call] INVITE for call … observed after N ms, settle delay 500 ms`, then + `[Call] answering call … after a 500 ms settle delay`, then + `[Call] 200 OK sent for call 0`. +- Note the `N`. If it creeps toward `answerTimeout`, the PBX or the push path + got slower and the timeout needs revisiting. +- `[Audio] CallKit did not activate the session, activating manually` is a + warning, not a failure — but if it appears on every call, CallKit is not + activating the session at all and that deserves an investigation of its own. + +### 2. Foreground and background + +Repeat scenario 1 with the app in the foreground, then backgrounded but running. +All three must behave identically; they exercise different wake-up paths. + +### 3. Opening the door + +Answer, then send the DTMF code. + +- The door opens. +- The call ends only **after** the digits have gone out — hanging up inside the + DTMF completion is the contract; ending the call earlier truncates the RTP + telephone-events and the door stays shut. +- If the PBX does not negotiate `telephone-event`, the log shows the RFC 2833 + attempt failing and the SIP INFO fallback being used. Both are acceptable; + silently no door is not. + +### 4. Declining + +Three separate cases, all of which must leave the intercom silent: + +1. Decline **after** the INVITE has arrived (roughly a second after the phone + starts ringing). +2. Decline **before** the INVITE has arrived — press it the instant CallKit + appears. The INVITE lands after the decline, and the intercom must still stop + ringing. There must be **no second** `call state … incoming` with a different + UUID afterwards, and no call left ringing on the PBX. +3. Ignore the call entirely and let CallKit time it out. + +Case 2 is a regression test: it failed in 0.3.0 and earlier, where the decline +was dropped because the SIP call did not exist yet, and the late INVITE then rang +as a second call. Fixed in 0.3.1 — the marker that proves the fix ran is +`[call] INVITE for call … arrived after the user rejected it; answered 603`. + +### 5. The intercom hangs up + +Answer, then hang up on the intercom side. + +- The CallKit screen disappears on its own; no stuck call in the UI. +- `didEndCallWithUUID:reason:` fires once, with the UUID of the call that + actually ended. + +### 6. Nobody answers + +Let the phone ring past `incomingCallTimeout` (60 s by default). + +- The call is rejected with `480`, `[Call] call … rang for 60s without an answer` + appears, and CallKit clears. +- The next call still arrives — the timeout must not leave the account in a bad + state. + +### 7. Several calls in a row + +Place five calls, answering some and declining others, with the app left running +between them. + +- Every call arrives. A call that does not arrive after a successful earlier one + means the registration was not restored — check `unregister()` / `login()` + ordering in the host. +- If the host receives credentials in the push, use an account whose credentials + actually change between calls, so the account swap is exercised rather than + the "identical configuration, just re-register" shortcut. +- Watch for `[SIP] registration started for … via …` per call and a `200` in + `[SIP] registration 200 …`. + +### 8. Two calls at once + +With `maximumCalls == 1` (the default), have a second intercom call while the +first is up: the second must be rejected `486 Busy Here` and the first must +survive untouched. + +With `maximumCalls > 1`, the second call is reported to CallKit, hold works, and +audio follows the active call. + +### 9. Network handover mid-call + +Answer, then switch Wi-Fi off during the conversation. + +- Audio recovers, or the call ends cleanly. What must not happen is a call that + looks alive with no audio in either direction. +- `pjsua_handle_ip_change()` runs — visible in the PJSIP trace at `.debug`. + +### 10. Push survival + +Twenty calls over a session, some answered, some declined, some ignored. + +- The process is never killed with `0xBAADCA11`. +- Pushes still arrive at call twenty. iOS stops delivering VoIP pushes to an + application that fails to run the PushKit completion handler, and the + punishment is delayed — which is exactly why this needs twenty calls and not + two. +- `[Push] acknowledging VoIP push (…)` appears once per push. + +### 11. Audio details + +During an answered call: + +- Mute, and confirm the **other side stops hearing you** — CallWaveKit mutes at + the RTP capture connection, so a mute that only changes the button is a bug. +- Speaker on and off. +- Plug in wired headphones, then a Bluetooth headset, mid-call. +- `statistics(forCallWithUUID:)` reports a sane codec, non-zero packet counts + and plausible loss and jitter. + +### 12. TLS, if the deployment uses it + +Certificate verification is on by default since 0.3.0. Register against the +intercom over TLS and confirm it succeeds; if the intercom carries a self-signed +certificate, confirm that the host's explicit opt-out is what makes it work, and +that removing the opt-out fails the registration rather than silently accepting +the certificate. + +## Reporting a field failure + +Attach the console log for the whole call, from the push to the end, and state: + +- which scenario number, and which of the three app states (cold, foreground, + background); +- the intercom or PBX model and the transport; +- the `N` from `INVITE … observed after N ms`; +- what the user saw, separately from what the log says. + +## Keeping this file honest + +Every bug found in the field becomes a numbered scenario here, in the same +release as the fix. A bug that is fixed without a scenario added is a bug that +comes back — the decline-before-INVITE case in scenario 4 is exactly that, and +it reached production because nothing on this list would have caught it. diff --git a/README.md b/README.md index edb3a19..a7481a7 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,10 @@ settings, call waiting and hold, DTMF, call statistics, the audio-session hooks, logging, the Swift concurrency layer and the threading contract. [CHANGELOG.md](CHANGELOG.md) records every release and every breaking change. -[RELEASING.md](RELEASING.md) is the maintainer's checklist for cutting one. +[RELEASING.md](RELEASING.md) is the maintainer's checklist for cutting one, and +[FIELD-TESTING.md](FIELD-TESTING.md) is the pass that has to be done by hand on a +device against a real intercom — the unit tests cover none of the answer path, +the push path or the audio session. ## What it does diff --git a/RELEASING.md b/RELEASING.md index 9014fb7..81677e5 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -24,6 +24,23 @@ shows who currently owns the pod name. ## Per release +### 0. Verify the behaviour + +Mechanics come later; this is the step that decides whether the release is +shippable at all. + +```sh +./Scripts/run-package-tests.sh +``` + +Then work through [FIELD-TESTING.md](FIELD-TESTING.md) on a device against a real +intercom. The unit tests cover none of the answer path, the push path, the audio +session or the registration lifecycle — those only break in the field, and +`pod spec lint` in step 4 checks packaging, not behaviour. + +For a release that only touches documentation or packaging, the field pass can be +skipped — say so in the release notes rather than leaving it ambiguous. + ### 1. Bump the version The version appears in five places; `spec.version` is the one that matters, the From c24665eb02176c6154673a7d94417e711b2e9e6e Mon Sep 17 00:00:00 2001 From: PeterSthuka Date: Mon, 3 Aug 2026 08:35:33 +0300 Subject: [PATCH 4/4] Check the field-testing markers against the code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every log line, default and behavioural claim in the checklist was verified against CallWaveKit/*.m and CallWaveKit/include/. The quoted message formats, the defaults (acceptDelay 0.5 s, incomingCallTimeout 60 s, answerTimeout 10 s, maximumCalls 1, redaction on), the 486/480 responses, the RFC 2833 to SIP INFO fallback, the RTP-level mute, pjsua_handle_ip_change() and TLS verification all matched and are left alone. So do the Swift spellings, including CallWaveLog.redactsIdentifiers, which reads as isRedactingIdentifiers but is still assignable under that name — confirmed by compiling it. What did not match: - the scenario markers used [Call], [Audio], [SIP] and [Push] while the categories the library registers are lower-case, contradicting the list in the same file. All markers are now lower-case, and the setup section says that the bracket stands for the category column rather than for something the library prints; - scenario 10 sent the reader into the PJSIP trace at .debug to confirm a network handover, when there is an Info-level line for exactly that; - scenario 3 described the DTMF fallback without naming the line that shows it. Two shipped bugs had no scenario. Un-REGISTER reporting the account as still registered — the 0.3.0 fix around PJSIP_EXPIRES_NOT_SPECIFIED — is now scenario 8, and ending one of two concurrent calls killing the wrong one is folded into scenario 9 rather than given a number of its own. Thirteen scenarios instead of twelve, still an evening: scenario 8 is a call to unregister() and a state read, and the addition to 9 reuses the two callers that scenario already needs. The remaining Fixed entries are thread races and a deadlock, which have no honest by-hand reproduction, so no scenarios were invented for them. --- FIELD-TESTING.md | 65 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/FIELD-TESTING.md b/FIELD-TESTING.md index 40de6b1..837a526 100644 --- a/FIELD-TESTING.md +++ b/FIELD-TESTING.md @@ -31,8 +31,13 @@ CallWaveLog.redactsIdentifiers = false // never in a build you ship log stream --predicate 'subsystem == "com.callwave.kit"' --info --debug ``` - Categories are `sip`, `call`, `audio`, `push`, `network` and `pjsip`, and - they are lower-case — `--predicate 'category == "call"'` to narrow further. + Categories are `sip`, `call`, `audio`, `push`, `network` and `pjsip`, all + lower-case. Narrow with `--predicate 'subsystem == "com.callwave.kit" AND + category == "call"'`. + +Markers below are written as `[category] message`, matching what `log stream` +prints for the subsystem and category. Only the message text is emitted by the +library; the bracket is shorthand for the category column. Record the log for every scenario. A failure with no log is a failure that has to be reproduced from scratch. @@ -51,12 +56,12 @@ Force-quit the app, lock the phone, place the call, answer from the lock screen. - CallKit shows the branded name and icon. - Two-way audio within a second of answering — **check both directions**, the common failure is one-way. -- `[Call] INVITE for call … observed after N ms, settle delay 500 ms`, then - `[Call] answering call … after a 500 ms settle delay`, then - `[Call] 200 OK sent for call 0`. +- `[call] INVITE for call … observed after N ms, settle delay 500 ms`, then + `[call] answering call … after a 500 ms settle delay`, then + `[call] 200 OK sent for call 0`. - Note the `N`. If it creeps toward `answerTimeout`, the PBX or the push path got slower and the timeout needs revisiting. -- `[Audio] CallKit did not activate the session, activating manually` is a +- `[audio] CallKit did not activate the session, activating manually` is a warning, not a failure — but if it appears on every call, CallKit is not activating the session at all and that deserves an investigation of its own. @@ -74,8 +79,9 @@ Answer, then send the DTMF code. DTMF completion is the contract; ending the call earlier truncates the RTP telephone-events and the door stays shut. - If the PBX does not negotiate `telephone-event`, the log shows the RFC 2833 - attempt failing and the SIP INFO fallback being used. Both are acceptable; - silently no door is not. + attempt failing and the SIP INFO fallback being used: + `[call] RFC 2833 DTMF failed (…), retrying with SIP INFO`. Both are + acceptable; silently no door is not. ### 4. Declining @@ -106,7 +112,7 @@ Answer, then hang up on the intercom side. Let the phone ring past `incomingCallTimeout` (60 s by default). -- The call is rejected with `480`, `[Call] call … rang for 60s without an answer` +- The call is rejected with `480`, `[call] call … rang for 60s without an answer` appears, and CallKit clears. - The next call still arrives — the timeout must not leave the account in a bad state. @@ -122,27 +128,48 @@ between them. - If the host receives credentials in the push, use an account whose credentials actually change between calls, so the account swap is exercised rather than the "identical configuration, just re-register" shortcut. -- Watch for `[SIP] registration started for … via …` per call and a `200` in - `[SIP] registration 200 …`. +- Watch for `[sip] registration started for … via …` per call and a `200` in + `[sip] registration 200 …`. + +### 8. Unregistering between calls + +A host that releases the account between calls does it through `unregister()`, +and the state that follows has to be believable: a client that claims to be +registered when it is not makes the host skip the re-registration, and the next +call simply never arrives. + +After a finished call, call `unregister()` and read the state back. + +- `registrationState` is `.stopped` and `isRegistered` is `false`. Reporting + `.registered` here is the 0.3.0 bug — PJSIP leaves `expires` at + `PJSIP_EXPIRES_NOT_SPECIFIED` rather than at zero, with the status still 200. +- `unregister()` a second time still succeeds instead of reporting an error. +- `refreshRegistration()` or `login(configuration:)` brings it back, and the + next call arrives. -### 8. Two calls at once +### 9. Two calls at once With `maximumCalls == 1` (the default), have a second intercom call while the first is up: the second must be rejected `486 Busy Here` and the first must survive untouched. With `maximumCalls > 1`, the second call is reported to CallKit, hold works, and -audio follows the active call. +audio follows the active call. With both calls up, end **one** of them: the +other must survive with its audio intact. Ending the wrong one is the 0.3.0 bug, +where a disconnect was resolved through `currentCallUUID` instead of the call id +PJSIP actually reported. -### 9. Network handover mid-call +### 10. Network handover mid-call Answer, then switch Wi-Fi off during the conversation. - Audio recovers, or the call ends cleanly. What must not happen is a call that looks alive with no audio in either direction. -- `pjsua_handle_ip_change()` runs — visible in the PJSIP trace at `.debug`. +- `[network] network path changed (0x… -> 0x…), rebuilding transports` — this + is the line that proves `pjsua_handle_ip_change()` ran. A failure logs + `[network] IP change handling failed (…)`. -### 10. Push survival +### 11. Push survival Twenty calls over a session, some answered, some declined, some ignored. @@ -151,9 +178,9 @@ Twenty calls over a session, some answered, some declined, some ignored. application that fails to run the PushKit completion handler, and the punishment is delayed — which is exactly why this needs twenty calls and not two. -- `[Push] acknowledging VoIP push (…)` appears once per push. +- `[push] acknowledging VoIP push (…)` appears once per push. -### 11. Audio details +### 12. Audio details During an answered call: @@ -164,7 +191,7 @@ During an answered call: - `statistics(forCallWithUUID:)` reports a sane codec, non-zero packet counts and plausible loss and jitter. -### 12. TLS, if the deployment uses it +### 13. TLS, if the deployment uses it Certificate verification is on by default since 0.3.0. Register against the intercom over TLS and confirm it succeeds; if the intercom carries a self-signed