From f849738613abe479d08ea7cbe9b96401b46ba0ea Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Thu, 4 Dec 2025 00:24:51 +0530 Subject: [PATCH 1/6] Add Lambda Durable Functions - Human Approval Pattern --- lambda-durable-human-approval-sam/README.md | 267 ++++++++++++++++++ .../architecture.png | Bin 0 -> 120768 bytes .../example-pattern.json | 112 ++++++++ .../src/callback_handler.py | 148 ++++++++++ .../src/lambda_function.py | 128 +++++++++ .../src/requirements.txt | 1 + .../template.yaml | 176 ++++++++++++ 7 files changed, 832 insertions(+) create mode 100644 lambda-durable-human-approval-sam/README.md create mode 100644 lambda-durable-human-approval-sam/architecture.png create mode 100644 lambda-durable-human-approval-sam/example-pattern.json create mode 100644 lambda-durable-human-approval-sam/src/callback_handler.py create mode 100644 lambda-durable-human-approval-sam/src/lambda_function.py create mode 100644 lambda-durable-human-approval-sam/src/requirements.txt create mode 100644 lambda-durable-human-approval-sam/template.yaml diff --git a/lambda-durable-human-approval-sam/README.md b/lambda-durable-human-approval-sam/README.md new file mode 100644 index 000000000..5f07f395f --- /dev/null +++ b/lambda-durable-human-approval-sam/README.md @@ -0,0 +1,267 @@ +# Human-in-the-Loop Approval Workflow with Lambda Durable Functions + +This pattern demonstrates a human-in-the-loop approval workflow using AWS Lambda Durable Functions. The workflow pauses execution for up to 24 hours while waiting for human approval via email, automatically handling timeouts and resuming when decisions are received. + +**Important:** Lambda Durable Functions are currently available in the **us-east-2 (Ohio)** region only. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-hitl-approval-sam + +## Architecture + +![Architecture Diagram](architecture.png) + +The pattern uses Lambda Durable Functions to implement a cost-effective approval workflow that can wait up to 24 hours without incurring compute charges during the wait period. + +### Workflow Steps + +1. **User submits approval request** via API Gateway +2. **Durable Function validates request** and creates a callback +3. **UUID mapping stored in DynamoDB** (callback ID → UUID) +4. **Email notification sent via SNS** with approve/reject links +5. **Function pauses execution** (no compute charges during wait) +6. **Approver clicks link** in email +7. **Callback Handler retrieves callback ID** from DynamoDB +8. **Callback sent to Lambda** using `SendDurableExecutionCallbackSuccess` +9. **Durable Function resumes** and processes the decision + +## Key Features + +- ✅ **24-Hour Wait Time** - Can wait up to 24 hours for approval +- ✅ **No Compute Charges During Wait** - Function suspended during wait period +- ✅ **Email Notifications** - Sends approval requests with clickable links +- ✅ **Short, Clean URLs** - Uses UUID instead of long callback IDs +- ✅ **DynamoDB Mapping** - Stores UUID → callback ID mapping with TTL +- ✅ **Automatic Timeout** - Auto-rejects after 24 hours +- ✅ **HTML Response Pages** - Beautiful approval/rejection confirmation pages + +## Prerequisites + +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed +* Python 3.14 runtime (automatically provided by Lambda) + +## Deployment + +1. Navigate to the pattern directory: + ```bash + cd lambda-durable-hitl-approval-sam + ``` + +2. Build the SAM application: + ```bash + sam build + ``` + +3. Deploy the application (must use us-east-2 region): + ```bash + sam deploy --guided --region us-east-2 + ``` + + During the guided deployment: + - Stack Name: `lambda-durable-hitl-approval` + - AWS Region: `us-east-2` + - Parameter ApproverEmail: `your-email@example.com` + - Confirm changes: `N` + - Allow SAM CLI IAM role creation: `Y` + - Disable rollback: `N` + - Save arguments to config file: `Y` + +4. **Confirm SNS subscription**: Check your email and click the confirmation link from AWS SNS + +5. Note the `ApiEndpoint` from the outputs + +## Testing + +### Submit an Approval Request + +```bash +curl -X POST https://YOUR-API-ID.execute-api.us-east-2.amazonaws.com/prod/requests \ + -H "Content-Type: application/json" \ + -d '{ + "requestId": "REQ-001", + "amount": 5000, + "description": "New server purchase" + }' +``` + +Response: +```json +{ + "message": "Request accepted" +} +``` + +### Check Your Email + +You'll receive an email with: +- Request details (ID, amount, description) +- **APPROVE** link +- **REJECT** link +- Expiration time (24 hours) + +### Click Approve or Reject + +Click one of the links in the email. You'll see a confirmation page with: +- ✓ or ✗ icon +- "Request Approved!" or "Request Rejected!" message +- Confirmation that the workflow has been notified + +### Monitor the Workflow + +```bash +# View durable function logs +aws logs tail /aws/lambda/lambda-durable-hitl-approval-ApprovalFunction-XXXXX \ + --follow \ + --region us-east-2 +``` + +Look for: +- `Starting approval workflow for request: REQ-001` +- `Approval request sent. UUID: ` +- `Approval workflow completed: approved` (or `rejected`) + +## How It Works + +### Callback Creation + +The durable function creates a callback and stores the mapping: + +```python +from aws_durable_execution_sdk_python import DurableContext, durable_execution +from aws_durable_execution_sdk_python.config import CallbackConfig, Duration + +@durable_execution +def lambda_handler(event, context: DurableContext): + # Create callback with 24-hour timeout + callback = context.create_callback( + name='wait-for-approval', + config=CallbackConfig(timeout=Duration.from_hours(24)) + ) + + # Generate short UUID and store mapping in DynamoDB + request_uuid = str(uuid.uuid4()) + table.put_item(Item={ + 'uuid': request_uuid, + 'callbackId': callback.callback_id, + 'ttl': int(time.time()) + 86400 # 24 hours + }) + + # Send email with UUID-based URLs + approve_url = f"{api_base_url}/approve/{request_uuid}" + + # Wait for callback result + approval = callback.result() +``` + +### Callback Handler + +When user clicks approve/reject: + +```python +def lambda_handler(event, context): + # Get UUID from URL path + request_uuid = event['pathParameters']['uuid'] + + # Fetch callback ID from DynamoDB + response = table.get_item(Key={'uuid': request_uuid}) + callback_id = response['Item']['callbackId'] + + # Send callback to durable function + lambda_client.send_durable_execution_callback_success( + CallbackId=callback_id, + Result=json.dumps({'decision': 'approved'}) + ) +``` + +### Cost Efficiency + +**Traditional Lambda approach:** +- Cannot wait more than 15 minutes (Lambda max timeout) +- Would need Step Functions or polling mechanism +- Complex state management + +**Durable Functions approach:** +- Wait up to 24 hours +- No compute charges during wait +- Simple, clean code +- Automatic state management + +## Configuration + +### Adjust Timeout Duration + +Modify in `template.yaml`: + +```yaml +DurableConfig: + ExecutionTimeout: 86400 # 24 hours in seconds +``` + +And in `src/lambda_function.py`: + +```python +config=CallbackConfig(timeout=Duration.from_hours(24)) +``` + +### Change Email Address + +Update during deployment or redeploy with new email: + +```bash +sam deploy --parameter-overrides ApproverEmail=new-email@example.com +``` + +## Use Cases + +- **Expense Approvals** - Wait for manager approval on spending requests +- **Document Reviews** - Pause workflow while documents are reviewed +- **Deployment Approvals** - Require human approval before production deployments +- **Access Requests** - Pause while security team reviews access requests +- **Contract Approvals** - Wait for legal team approval on contracts + +## Monitoring + +### CloudWatch Logs + +Monitor the durable function: +```bash +aws logs tail /aws/lambda/lambda-durable-hitl-approval-ApprovalFunction-XXXXX \ + --region us-east-2 \ + --follow +``` + +Monitor the callback handler: +```bash +aws logs tail /aws/lambda/lambda-durable-hitl-approv-CallbackHandlerFunction-XXXXX \ + --region us-east-2 \ + --follow +``` + +### DynamoDB Table + +Check the callback mappings: +```bash +aws dynamodb scan \ + --table-name lambda-durable-hitl-approval-callbacks \ + --region us-east-2 +``` + +## Cleanup + +```bash +sam delete --stack-name lambda-durable-hitl-approval --region us-east-2 +``` + + +## Learn More + +- [Lambda Durable Functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) +- [Durable Execution SDK (Python)](https://github.com/aws/aws-durable-execution-sdk-python) +- [Callback Operations](https://docs.aws.amazon.com/lambda/latest/dg/durable-callback.html) +- [SendDurableExecutionCallbackSuccess API](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/send_durable_execution_callback_success.html) + +--- + +Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/lambda-durable-human-approval-sam/architecture.png b/lambda-durable-human-approval-sam/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..ee703671e582806763b2b436156d37babc1fac05 GIT binary patch literal 120768 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

$(>VHF<+f0qYpjq)P=oP~d@Fg-eS% z&S}=JY&{iUmx6_lF%-yc;0|VVEZ)K&xU^zaqR55Mi%MV|O;6(atTtapeGrGK@`(XA znpg~*;5a?(b4kXk=?W6spJV-1A7KIP>>`=+528$9sU)~0!v^k?(4-Lu#QIDTQ3|(l zPt8_$%P;i#+4p!HY}JxKz9+|xlqBAm=^VHyZ12pwc);Zr`5Ydm4|zPn0y0v8$#`|i)1kBNFweShQ`hS=#(WNBH;(%EBvC6+XI z`gVKbY9``vUBpTwGZxLA*9MfzG?9xcLDlm!1MT-&Flg3wF`14nIC*$cm7fbf7OAJ; z0jN80#g)_8eq~C9DxRWFiKR5DFS-$O>;iwfKCw6Una2*>sYD-X%fvJ+PnAu-P1&erYNVzw=+~;-L2{Sx&`MVknhw?T|4MRRW@bcIAPY;lXDOGyGAIZJ_vNCu~ zW}e+kwOUx$-M*5r>NiiplP~s=S86f=?B6hh-O1xksX-NyZcC#KR{Gt7xEIF_@%7;n z4$A92`Q8f;!hD6+fTQW~R{xNEW@kpTwbaP%3ExU+-1SwFf|gsxS!CIU(fqPA_-%4U zy9dHY>nn)WV!JlnapnsG-9KJUO_yjX)9*l-(?u}4JcVhrzkU&ScQkSR96;?_7AT6) z2B~2@&%vqaaE7YV3g8k z_nm_Y>uL)!y7ejS0bD`Yz9u37hYM#@k_yuw&a!aZ3;B||tw)py{iQ$#cAN%D{>kSd2}ls@<@)4A+m~WRK&v7(fj=o_0i1mU7m0Ki zJxdL>J2ejn%WXJ&toJA-le`2U9!y-T*J`n}YV-&041L4Han?hZtcSmAymhIOdBF2!GYHs}2(`a8twg5R z+TQ{?SNHlO2aYi0OXklYUY|=;<>L9$8TNM!h|6(#Go}ATKg!vF1Y?QMU2Hlma=Gc7 zc*SOdapX|I@du!xbW#9+jMy5peWh}q;Bj~% z(T|03(zK#0yBdBem{&woHhvGolp}4G9z^QV@b^_;$0)7d57d5z*S5Ma`XD7Szh$W+ zciGa#$O|6YANR#1r~Y*pO2PKCkG=v6$(HmJS0J<~#K1lA5PV0dEO-OEqd|siQuH{rE z;+w;<5^a=}-hTe4GSRL<{y_~kyznc6n)CkWQ8Ug$+64g8BPVEjIax16&`nIR^;QY= zZHx#rbHQG4mtXDBkm;vU0_5*wTFJ#=*a&dJW^fWb+W9pObzePmwcakj96+~n92Q{A zP%t1x6Y~tF<|vA5ThRNwY>@jDO|-jWT=~ACZEv^}1Eh!j@vRNBPBTd$;1UN)0tFWr z?AXVfi#07nXps2}Cjw}?NKGavB*bW-_-9N##L=K9EYZid`_-MQ|>;W+v7X2U|8|+x8Cjn@>UdnNBco29hiZNVmZEd`62kehG zhd-A}bPHzw?C1E1H_$4o^cVj*{H_QxKMw-w8xmx3G260{E79Qs=Cq(#Zni}O zvIu||gMUI1D7q}w1ckl8;E=vxd4jHg_%{^$z=QjCCd@t#5|r-xh2c)V0i3g?0O=s zxZxmRlI~9qw$&l%g?k?_2 zws>KJK*xQCid>j_dO*D*XaC5pzaV$^JqZ6qAoe-!7{AdS72pnNg5f}VJq|djHF|wjD=l@_QVy+JEm-r#iobZ7o&e6^cL2 z2Xdiapg;s{`r?3Q_mdit(OaKH=H)+@B3x|}>NqeoR@9C?S8W8H?B@UK^p7P+;McRv z&hlAigD=4UzUuy#hlo0unDm{ty`aW3J`>Ubx;YDa6IyRrjs2L>7fbldw>vuR5J2Ok zV*+i4mWi|VbANIGa)?YH3>{D2jiES2Mt^TgcIlf9^ILuA7a3U@4Nndg`TcPC8nGcK z$^!9IUg19p6vgxQU>|ZkqiU$w>?1?Tdn{ntKQ9nZeF^R+ULVgA`~Jv?&CJx3l$JKyPN@R^^Dj@=n>&hDb8+uK*12>F z<(q~~2+wveW-*M7sW4{wlpY+=1BQ&G9kUYVaWaQ@0s;txX=w&a@vqksNWd%ed2%n_ z?kp`u{8#yNt_X|<)uxPwF*XYH9l~D9{UFY)=?c$3SqCH}@-(g_depgWzn*_BmzI$d zuTaJLgn)o6m1lm#Tbd-Ngs7Eb9G{wcM)`G!f{_zi4(W3^H$Nh9`x4I(YvO2HdjEkM#-p-5U%iWVuXuDp-zfW zz*$6q+tlibuLj}fvdIa4*faKXAmn11{Osfc!|bZWf0q_!XS?xr>jzQKjTuz$H(&=m z>gcgc^M4Iaiw`=Wkm$w71MF%DNX!vW0`}yA^_ekvZ9&q)*v*r!>&f!g|TsuWG=VArz{*(T@omrnbGqfWEOtCy+jJV!v#3XeD zQvs+nomPD9cbi?yt~t-;n?s0vz1CS^pekaFU4UPpsyMZi+1H?+IfNvI#W}6!k0G7L zEIZyk*pJBwCmu<~On+8Dd10IbCQW|Etv%6tv{Kdz=L0e3U%n1l?=8PT+DPUrhLCp< z(fh?EFbQyeZu|1J^~J&#sE=b2_T{YV?(C^l{{>V`?8Q@$grPAc{+bm)vXah~=@WmQ z%Gocf(vR#pk%>NKwK& zkBMiuq@GX5w6xe0WeF6_4@ih~w7=nUc>md-9Pw7qDk@!A1{EF=$M=4MKv<@)FrTGq zohlaky)mSn@2YcYCc{G>HI79;79o0`5?XlNf@rXVgs*65>NrNT9$~(B>ZO{uamAD* zt+aG0WNPQWK)C{H43cs{Ei%7@HM&J)-=t-cXM4qbnc9Oe^0J>W~HBe9RJ|@*1=Qy@R4BO20KV=5Ii*Y?5_ik8m?`xXoO9wVIo@ zj6^$FA$WUoWaY74`iFu4p&Hq8Lks}&@VQGguFm&x>2sR@>Fn{Y6QJ&YKxqI_j=J35 zSodOlk^dY92ymcr$!k+kDFbGn$1en6kN+uMtt>XGVpE z$U#nS{>0Et;3L{V)z%vs?Xz}5zDn=nV%swkNx@4r(V3z5+&Q6#{pPiri5njEAcfTC zK97B{S<_$X*hXDbfOyD17&P%&|MW<60AwI|L@8$^{5`=m4L4!g$MDXsq%QbKKVC4N za|Pu^2}j&eGTFy~gy}F6b3;nVaiBZdDe-A8o+&%E>jmpz*Ov_fDeQdl#ay1zN6Rk` z>sv18@OAf({ASohSOp%qHIPPXyH}n?h;vXiqalLn!TD_wKfb(ZXes9Fo+x{;G`J;m zM=0l&A53nR+2I7(W^zOm=ghbi!nFtkG)4>)(2pEn035lqW$>U|CI6lXEtA4-fK)ACoVBE#V-5=*q0XT5aj z{s@=vFXkU-&oEwXCQbSTDfP0i(hj~QS17lXtnzU??1Yqc)3fAKsH{pv0C_vg=@;?}{gc_QZs{f|DVDoNe} zwjKM%-OU)*4%%wId=4{d^R??8u$EEYcu7EeKZ+yJ?_^wH_peqWIVX1jN`Wwt@k6-= z$ZwccscEP1@n6aj^Vmq&kge6d{SoWDy_E0lJmrBN^WBbIJBwnBZi|f1&(Fti9XyGhGb+4VC6M-~;)ev&6^pVqchFBkvG0_)eq z7qORUx|D%*?|I5kG%i8R*&Wco$c1z=2-|Ho_=17S<^BgycvNOfQv2V#PU3<4@NF%4*+D}G=%FO3~E_Sey zzA3pyZEKq;;IC$M;Av&QVG-oq6MYzdK_3XWniK^5y)pu#D`j~S2n5c&$!*#DuU#k# zd5$%$VKM@Knhbi~{;RQhE2+Iwz8wlnTu?{NlXmI59{9+=NgxlUtxanuduDBL*oF+9 z-OdYme#~`5{n8?X4$QiCs}hq*?^@q)S(yo5pj~zwB7IJI4-H?XN%7nS6(?yC_CGwm zV_4-~yg%Gz+pftq*_b9zc1^Zz*PUIH?IvTgZP#Sm#vqRcSMnI$p}DX+j1gvk4It2{tbUl(4=S+=u?!|cC@C8ask$J} z)ulQSIu{tT!U(?zc!CvI$WQ9t`%hMhU67{>&T{$G4^F%4!F=r7MV!&49+)7;~I|8rxDqSJ{V^f#~7C&XNg%jZm!l zaitJf!in0-rwzvw7S@vbaNDg$z5Bh8b0&8nI(^&j25K2}+%I~t5GUI$Xyx$nH;Y#f zINfUrqBjd@qP)HbbXR5;MLx^S-Si};YESG!W3Ei5CX7=H@M-nFeiIMOB zD!}nB;}**KYYyZs&~?P^Bvt*5k?Wr+56$HDu5et^9X>%MB+FGCvxac`dA$ED{)XR z6sL7$^d5b_!ZYHN-GoOKTCy@h0aT-;W9Hq#45Xi9X5Zy2q8pQ6zSn4mn|QPae{9`3 zz!WvhLxnUtCHmSZP}FpD6Seyt6VFt=_re_1@c);&A5LK{ZUK%JSB>y1CqwkefgS1{ z@Y~PEabRR6Kfcb1@UJo5o>dA#u?*el@!)6o>Ih0ml}3NI^_XR7E6VMJSvQ(!p5ZNS z&Cq+9x<{0BHt6_UU0H)2JG*;H5jo4xOa#gu=mH%FjIpseD0jo14-%ri=t&)a7pxxs# z=(iHsg$RcLpP!oAzi?1K2&}^46(E&5neBKI^G<5zS`jC#mmwf(@O}yc11<`mcRiEc=mQ z$EId!&c+NL{K4UC9up1n-ZrUacUo#w=&2D~7)94-V#{4k8Z2 z5u1@%Aac?&U*p6ii^t89I`p?$CrE6qDPk<$lPIx+eRP0s9{Vc&lg`!`dp#yY#>o(S z5DWYz*VdLy8zF_>w)k|=@s79Hb5ZH-6Q*THH;Ndrk8W=<3C(EzO#zb^o+OAB1meiqEIFDVUzVaYral9RI+4<2e&b)52o`xbNvknN zGu<(anzfpZ-ju!}O`aT@T?O#q`0T-4u@MZyLXieZlv%+qICBa8Mmx~bNk2EBGAIcN zH`Kl+(et?Et^7ATLMpMa?!Zg@AB5q=)Ie9faIpV8u0=2h6+FZn3HfM@Lf8_O4ITWkMmr?7wJ>7YX~F!9NK8nij0TaP^br z9FCTq-r>sO@$i`^YQVr1J=yXp*UJprHt#H~M)SI#5nJRJD)_p!5LfMQ*8?cG_R_#a zysQ%B=*iQ{f_0DS=U4`cbsD5A-v;b6bGHJSrtlF}>g5n1sQs|-s46bx{rCh?r3GUc zW3B{ohkGq~U_v5da|wls@tL3EdRxfw3pbvzL3^eZP^~`!20@4T%32Uxmn5(pVJT`jzl;v zG#d94L?a=}*W8=0m}d*S$>(o06Hn-wP zpjbHD)9$Cvdi{Vyv-Bx*-WkzCG7in4u(`so0N+Je^peKab=0n#qm3vk-Xz zF=s#5Z`xUpuTBnjN^Fz(IHnI`V0x3;y8ge#sLoU2fz*V^n`Qk^B*ra5CpV7bito^? zSi+%31CljgMeSIkgA>%6rgyLbBg{xi_HYDXS>B+`o4;M~YLu&4ZdDO%z4mDSJ7A^J=jir|p`ilx z=%bZ@8}u;L$M}hVAqdLg;$H}&V_@h{+x9)@P5Vyuy-be?@JI+;Ht-^tQ&#R2Od&|I zh}4G(ZlvO(Wg+t}!Z1pqOIFnPrwVuD(qS$talwCgd2zKG2(-w2 zfz@8l262^3t%R2h)ad!5n=VHVKh$~ky1jQp{*P}x-d}pzBVG=~Mr`F}n8VvG&`wfo z_d=$29zx0NsFLWNM-pMJCiV;)|Dz0Z_eVFZLsW#Q!%1S;{Alpl3RF&hCi<9cwv|Tf z3d5B7Z`P;QxKAHlVkqn_SzzY=;Xxt5+avc-p$iJB5I%x)D2Vcp4_0xSk|@g0_A&eB znd|t?i>r&t68rB|;Mb%ak1Y_`e|v1Q^ZNely}vXbvQ<=f=N%6 zzDY6+C{6tYuzl;R zY8?C5ibOfJi!Cz$LdpxDN@vKT0$Ik7I*t*!-Eo6p^AG4Tj&tTlmEX4E2D)lPXVP!m zMG=P~xq|oMigem7WXkBj^V&n6j}4?dogg6CE;Ee@S0eY^z;AYRiiX&Ygo!lq;t_K% zL@K`xp=w@@16mRU&5$FL#?ewVaa}L7{usZLF{lqW-{Vhnw6U`_KD4n3C{MRZ+prn|e(L%wC*MRZy)i*NmfLQ@S`95*^-;8$LaQB^_Ar zrimOJzY1hkRWW69T8UPseo+P%DAy&R4-$B*QrCC18Nq=!(B{b8qzOK;Fm7)${41WJH3!_r?W;vqw%bM zCaM%&+qQK0Dr9FF^kz;8Xf-(r$P@mW?a;AkcT@P>?26-h^5ZuRv?N(hB{MDV0D|p* z`E%$#my4K2%8l!7Hy8IS%^#G%E=009p&yp#zJB z-}-vkRaj5h;s_%D9;=fxOim^DMINfP3My2EjJxdJK}$*r9Sve+Slm(k$!?W|mQ2YE zVf*9s+v{*W!X8e7NO*AeQd{lC^IPxAF>_Rle^|#(RW_E+U7dZF{Kf1@7lJiP-GIMT zpXQ8O7FOED8{+)Vh!Snfr*F&VbZbXKPPwZX-L_h8q53mFZB($bc{k>XB(MuSpF@wm zfX~EC*?&vb+D;cw2$HC2_xp$2%qhPJkYOKfw;7~6oci5#11`BPHhc0?r*xh`zw|jB zP-zBTEsHxfZH$NP&UcD5u1*IEGy4zWgRgRlH_B)L6yL2~imT{?>(z};GWoBviR>ZDrby>mX%&*O=7A2rO_9vD& zo*IoNQ&NhSB%?&z^TbV>ocKU@b7M7XW0GYD?T;$!9@pcHB^#X>hUDLfFa0ILxTK)! zmnv~BFCSFQr9vn`+~M`c?oV91TgSI7JCGuPateKvQZjs{p@}p3cy8^Ksr?b+ej-DM zf|ZkX?Nh>SU+TB6f$V;cO+%~nM7D$y$W~&e_;3jo%&d8ZP}PwNvD4{_JW(Sth~f_q zkwPE3(ubz<`@w6dJ*vew$m&L{%%qEv>p_n;-);lpI8Z9PJ3I%P-LoxtHf`wY%;NQM zrOx+nhQoElfy#MXi7Oa^Z+nJX2MrPC`lwRa;w3uwS+QO#Ym zG`HBH_NwV513P0x(YS83<>32ua>>sQ`@M%YBwtPsX}b;#4BL(Ftj@%I&_Jf$;&2y2HU$JeOzxLs);^u1EmL zIHyb!h9w1Aj<*7;^`Wzn?j@y3x!;c@1DK5?ZIdSS(j{~++N&!wd0jwNQ^ZB6Am zM;8-re~9fc<}bnEx#gA~RfiZ!C{kLI+NLnc-r*iEzd76;G((6%nsqKAjpwT1m|0M) z(o!I{3RK>9M{i&F`fh6RC?fOdhxXt81*y#AM?^X362dYu)8x#D=LqLRtxUGqb6*PI zXFGEIgv5rxdqecL9prdOT1!gH+#TU|OuRSz4g*0!gS+2bj?KKL?xvuN1Zje;ygpD8^hq>ra)HR zp=FevV4*uWD4%yd|D#+mco@E@-5)3>Wp+walpu+6c2pd!{fm-9p`GC&b588{;ylZ^ z`=!v}*1*X46m1#w&41d}|706o6|cW*XQgIq*GCv11b2-h#rz3W{yUZ&dcG`0dHnjZBved`(we&%R)T&!~80h#gTux%7k`eTJS`@~sU&&gYgRWPC z&DM$Kx*Vi_fgW3iuXt2Dcg1wuXieR`nA(1LOn$Z>oY%k4#Fq;uD=-}6=#Ei;Pz^~G zie^LgT~`j~US9Hd-nW_nwZ1?`GAYGuB|>2SeEuIBr>tLCkbRIv{I+FtH$NLyuIBA z02|a=i(>m>7SAMKI{&BBYV#>y4Pi`Lg>E*DnX#MocWc$0$&jHXMKrr-YO%yAYu^gITq{`LGhsWl|)^F^|7Dmq-pPY&6aewO?${CIhOpQOx7ipvZ+4e{AW11_eg zicIHmB@}G&1%JZUc8Bm=ekjhJ4hkM4O*R~-@)z_*z6Iy7^Ev5Z;!Ev|yN%c#s(VTl zw%^OGUI&EWSSMpi$r)mE4#s;Di|Fx}pwn*&A}L0$`kXkab{?w6Y}Sa)5`6lky4~^H z_6@m(Pe&t-ktI4&$iRfqQ5b?jjB@xLWTgM7LXce#=^sT&Eg(Fy0{XfTxm8B~qOfde zmmSC9Ac@cI zh-oCw;yLYT83$mxpyVh-f2Qk<8QC`)Izy3b^_KhMjoW+ba{TPJEu!U}r%$k`@ni!@ z7#ju6wwEaGYzEL3dCU25(@pd~G_YQ9!9DS@!P$&VQ3rui} z6sl$`57>AvyU%HkW)?}FGkWmdEAwlqUo6@8^_<@yJ(wz&pJZ9FJ#+{X1qetzJ=h*6D7^H32k<`4qDDK;+2U2mAIBrpz^XHl-P3R+p+Gm z1>F|6)L!ua#LX`Q3nK!&sv|so3l^B6!d+K*)~{}nl&MpBhG#+u>e-+!+Y^7JA)q*N z+x^xwnq0~oo~UPl&hto(4h>z6vHxGVQ}z}rsYQm_MCG|Nd<+Wb(BR^{MaA#3*2#P8 zCd7EDVy}5g*XwLaNpCngk;*Yyj5Scmy8}QcPbK~uUTz@((I}r7ak-uF>d-RQ%?taf zFaPsyh5jcUcUnB*Cye7z(IJZ(&hmp7)@ErQvpMMTwi0r9H)OH^fhYuIbeE+-l)h!{r zC6yr!vr{x>9AE5?W4Xxw0Eha)Z@tJWJK{X(4pGw1`m^h%Hr%UlD#;OFRcCMd0lJlv zVqSTDf1#-1U8hr#sn?1yjIMw`r-1vV*+sJ+txCNWaBc-kCDGwSiki#J<9Mc6Hy=rETp&HAzm7H-(9AorRpvawZ~Y3 z-Ue}Pr8G=V&T^s`s9J_s?lq#8-qZdNvGzs^VLQB{iw(=aUrNMuT@Ti~;a+WEEdr7x z{rAZiT5=b^0m0p%ucTrha8CXlu{(>=GG-H1|M%Q+|L3`fX#YA|yVZ1>M_EonH}GgK ziY|O9Qx2_=Esg604R7;0@+KjrIa}9PIAgS5OF64hmRD;#Qr(A8`At0PWlwY~ofjxe zC?AaEEsuAr;6eui8j#X|fKiU>bw?6pgD*?M1WXF~Y@wHGdx=N>n1gLk`b2D$!UCj- zUjTtA;z2RJuJ?*aLUHo;cln?6g7(fI_rkgs(+TXC^lII2ii^_HoW5@kmhS?={e1U* z`@_7p-~S^99+=QY3mlAi%pJ^G>G63=}RTd5hNn@b^l z;SxAL4$U3@JQl7!+DFPD8TsJwVQKr7&Kb>p`evA>37yegFH)bQ=l^8=HH*K7z7Pf6 zfBUFg*9~%e3(UVyoZJ#-zzGw{iO8A7gK!J>ObiHs;;UuuRaK*GJ6;^CqZ0B+GF>zq z%k&GmEUF-9mBjc@``7TL(*)>K4FnuIv&(QQ(quN1o?z%fhUr(m|F=85QeI~VnKOrDEnkne$9%wglSn;~;xV7Yo`uJU_WSCs zn>aHA6{PkS;39e)>Zx2S1bEUmG(SYfGTr{P?97Ju!6S29mXuf#D^l*xs`AjBAI$8N1+kMXq-2@WC6!2t7y>z+#5iI=Q z-O^#FV|t?Bw$T|60fd{bNlX{5^27YO{zzqCWObHs{|eY%tppYVpWS|_eOE}AFJp0k zuwa>k?#qD%kn@#kZy$+1%Ixq8%P4@%Tc(20XtSQ_Zl|+s%B3!4fpcLGB~IeM)b6iIwmzl6c=c=xv=O#{)* zS%DiB0u)P~W{6K}-cZ97A{5Hi)IXMG#h57J0m_n0h{W=$%R%P@VzYt!7~J>zu;@gC zMI8J?bg}4{`N}V>OD3Lzq#xpT!3W~r?&so?$EZ}Ha+nOC(*?mw!KUNjhC9fj5)mD_ zE+`{^!6nEjZrDd`gqjH_cb4X0VWSHt4v4dml0-imDmS29WbXzVzu1(aM1lH0`<&B z`puu85Jxpw!`z8vzQTYRua(4J3efY!=+7@nVbG=jiBh@A1x^hOnYORt7xd)=*`j*GSrD9Pu2)!us>jy}IcJ9gPnd+$;7T-9!*ehvstf@hb~H`p&b<(cWX5V6&goVZ5qzb*J^qods~?X16PRM zRcU+T)EH>lh$1|Toc%)pt;Kz)iR}Cf$Ot` zdXaHH>p_h2A59z1u)c>rsUhFj-O`b(h~ccjze+kzp5uMPU$j zp$6txPN}s|86zcMiJjJWl|aTe`ZNI22+-W`+jH>G&+olZ^yt|11@F(qkZ>hGHc>^j z>oRx08BrfMu#8W;U8gGCo4a`g{G>bhE)!8IwJamI5GHCAlK;Krn?h!PadP`(hnXx3Xt&i=XPDowPulJKFhtwS)=SyMcHAg!U2&hqU(IS zxuA4X0$xbMYHnwJuN<1GtO8k^c)#UZ-Ix1`)@d&>ASiZ>J1ejoC%h*#vboA( zY49O76Mj-4#=-9@dlZ~EI~q*E#fQOh3ceDHV0%tt(mCE?o@7qKIv0q$(?sVnWk~(f zfUf7Rr588fV<^xG2~?!OEJ@qw!jD#>a+`jBIm&Tw&+TJ)7Hkh4du`J5j%KL!K_)nq zRxuMPR$F>NsTL2UJ>i>apKB9Ve5J}R3|oyF{ef(jBM#Raa)|=Ri6y&EaL;M6$JGHI zVx7=53b>8Y3*x*&m)=fbeh2~@@m77DZBH;Urj6<_E35P3B7?G zf1wO+H})b}Q1#w_wXS;_sg$yy59DWL4xq?=Ily6%>xRQDt_iLDJZd4G81ZIFV{z@5 z-rr{6d^^Lke|!01)_%k=wwyLJ5%8E8`IBD|21eKS3T6@sH{tDO-`|LB$6V_Y*DMw* zI3Q(CGGX>Z#Op7e9;xzkVkF{nWz~as$X9~X*WEfFd;!~Uiy;yp!py9EEPQycs<)y@ zM(-9;!eW0ye}8luW}UT44x(ma@*Xqwb=rpo-S!sjPcq9q`jh>}*bZ3{L1S1x#Gv1L zz$g?V7bNuA3goYm?o|wJ7kx`E@tN?PT>a4!aHNRWC>aw>nj%o8)LiK1MK*;lS#J8Z z>O;nsRZj0OgdTtMaeVyd#8W~r!xyI1esE{<=D%l}yfsw_KeQh2cn9Ke%Bl{;V)*1% zMe5e63|NYaN41bp*sRG3GJA}6R7ntRJ0l= z#b=1L8u`KhMc93aOmE$jhvv=f|Jl|bF!}OHq}TPYI(#>Rp&)5gfOh$4-CFfvNom%k}OmFT*hWH7WW0&a=~p-5XLzdFU~3@1wVcKYJx7 zPhza*`Q23nFWPBGt!)6&j8RSVPOp! zkGsR>dwt}_@>#9}CJuS!mUiYVX>Q-&JRKlyKCsbrfLch|4NduHL&#Ms}n;#AK_hyfy zM5%v+weCl!Cem_j($=E7yV#jK6qVITUhwsvGsZ*Mtr(KzMB0)%ch3^cD=9M&dHx{f zsQo32XmxfT^?F0u=jY06xwD}q|pWv;5!fP1E`9&r1bwebO_z3LYoDp8M>lb#>I zkUaf`2#{t)ilK*JqS66F9U5z!Kp=&svak-L1wgCM;$;pA;O>l1AesoWMjGq?br{pk zs0$_&Wu-&<9oOJP&xgN~v_K@o#oAkino)0`6KRQd@yYgr4@2E};`cjTTD7I#mJ~-n zq=}G3jKVqCyUANAa}w#&NA!bd7kc>BOkmV^M=z>{^i%wu{7$FZXee61!QkhQp%fd` zJBn7sAq5#WJ?Oiht)LEa^7hgVu6}TvMaZnpmyQ}#Jid<~a#uD;PQ()$-C?9?k8h=|563g~*-e;imSjC;y+4FbT(#9O zJWKo;XUi6KIqa!o35!RkFE;}sypU4IhwZpfIyU?8qPurz6XaIgk`IdciHy0U=xWp! z5NT@?dw&FH^U~=BqC!$mHyn>XkLa}CcV%msu^SN*cFISjB%+8U5Q?tt3i^d@EPsS{ zl))2JOaixAb#Ks_f%tHcEA~uS_3Hv8ZB1D(zVIF!w4UK#<=fO5r>uqnd=P0AGn|CY zNA$_#mj!gSL6nTBe9f)nwcI9>^|_{Z6E|lYVA6qHuO*?t6!oLUpDB{k^hAh2U3XT0 zVe#-^7d2=O^iTyMAmJx~92EAaRk>)*T>@Y!#>)Hxe9;mTvnO`~p)&5r(OCDW|>nIquLnUtiZg-pPyR9CfrX}%o@b#OEWvVwC6k&buxq+PH& zncD@XqfY><&G`a2xnh%W&JU-$p`gvHoQZ}X)xi59YtSlSK^xC=J5yV^2iDEOO@qUG zwP|5fSkenNP8j(C*Q7CILb}{_8paLxXGGWa{`1WfN3sQN5dqyC!A<8aqtinpLw6e- z@y5sv6fW4BbU~8NDU_;8S5yw^<3G(SAu||U{wo*kV=CaMJmGi$w%(p19BsE;+sb?t z@>IHkI`qIknoKvPX5NmOp+ZM4UxC5?>nBgtcoFVsGRVR+P#I?#UNvtW%8P^=+b%m4 zzx}8F?xRcgX7uF=e?TTp9bd_oM+i0jQHleG?F#3K2(;dg&0R$zz2+8zj62IsDZ&eM z%-dBhL|-IgOphC#{88wmP{9Y0MBve;LcUEdn&w};-NbPm=RqI`e6F7hV_LYBQFH zzeq$tS};~P(LOoZw)#oEWCWHJ1_5xlnH3GyXgLQK?rA>iM(q1KZ&mpW)OH4&_p_W# zVMGgUh}?Q-|F$E#?5*_0lUqVoW>t(w<{X2J1X`J9OIl0ty%l1ZXi>XzDY%QWd7}&u zj*lCx?r|k!@%7hh)Zk%*13PH80J$g%MvZDFo*v+mzOK~St~6#CN4xsu9}0iS`T7z= zy~uzxT7Fc&zAMgfm@eScYzl-XXzES5@oe`84arhHd!rCfc6?+_W6j8!Jgro=g5Tlr zxy^~AyIVfNC$`+zR{(vu9~!~!>u&LdHC zH-xh-Y&4n40X`#&ghx`P`w2{jE@a=vm_V+Y_(+#PZ{=+^rnd5-l`OZ2vH+QJ_pXME zzYn_+OhdsMX}H;feBAc7#eVpcoNSF9Z?H;WI)wb#Jsq>{N7#*cOkU zY{Q{~If3booFC2Dn_Ah#dAuOXw}*%yEmMj9<*WA!3%By0WlMay3r#ChDGG1?x4h}E zHf+r64&e|$AM4AoIhs628q@2<7&#^GH0nFx8Uu?TD#*~lM^QdUbMMu84ur#Nb49kG zAuxY?O}~O~|MoP}*=FO2_ao(UtoBtE%P_^?u0oZWh|er;;< zsrG;GxDqq%BN|RocIy@SgXj`)$)hd)Wy=(b-)pn=E)+EzNn00(PR8M(g|TE5?S8uo z>ej|^8{z0!m7`oFrS68p7!lf~($Yh-Z#2@m3{J)^>l2YV-M7u;h9`b#464DS&U>@x z1jZcWkwtVv0B{BZ5MZj$&US+nV(*+IYEZ~w=BXXo->s-KapWbg(q}v*nb521p-e8A9nYmI?%F`sW${;Ur^Cej^GV0L`Aoz{(!{A@6tG1WO^4){Hj z>3h9hUu-m0$~=qKJ)Qr$SZ#?{6n^=S`u>>Bctz>Rmo4uN4(;W>^L@DI=?H8l_;!HB zl+6=fn&+GCvE@VNqKsiYy5wJ8Ud`wJ%Dalkoa}R15$(;wj2P4lh@E-eYzdedtOt2~ z42_g@jgE5>*-VBq4!y(xR~%k=j7VDopIeCt zvWS8HQ+yk|I7a+x%p%@9HKr-UWQ-l3sZ6FmO@_*ygg#ws8I_Psi8X1xjV=-}LQ`d6 zt=K2T6+aH@I+99s6PF& z2crM3wvB2otY^={2GNs@OwKH^$u{`FyyAcFHur88d!i7F(M#?)e2jfU;g|5Ykr(dR zIWEP7zp@F~_;ym$M*0mi0b45#)r}D}-@fbOA&q`G2N(N_!$`uYNf;)ts>+~U!kKly z$k4TyB$Hm&oe^bnTMafS3W*M2d+}b$@_BXMjQ0RQW*a8lXVQp-|EBCM9$$xmFS8B~ z#>EJ!X$J3)g#|_CY1|l*)&6zG2x=)<;W+p>yjMVTI=)#Nk3~DUPtO3WJeXtfZS2S{ zP-PMLemZ3;av;_z!g-JJQ&Vqbif0K;9YLMn^$nSit@-4+IeKUNZ(W5>2ZA_NfwvL1 zYOvw=9+|qTlX}(0m+eo}U&H-Ws=gNhlYaMdJdU>)>7fY*{!e+0nu& zM+}*O#uBY{llD~)i1aGc6And1`_KfMTTA#ItW7M_+_E&D1-tPh&>TW8p z=_7B<)1~5bc7`;!jc@;$@#fq)ibNtH2tJScajLD1P(?A4-HCj|0n{HQ$&H@HLq^qj zLlWsT)D6O-S>DJ>9omv)YhQEvS#Woz$56&qVMHrZwAAXn@0u*`JtXS3CT$sKiS&7~X9?wW6=MM>^lOq_A=DCZ4Ss*T&O3gv^GLXV>7mQMhas)R zkuKNX9o!w}73aHkK;C_}u|tf3bb`7PAz7Zyn`#HaW#h%uKau5P`DAlPEy;(I_p$mv z?ZfjY8EdWI#$vLm%$GrhDVX4pg2tVVc~YmyU|RVMFSrO&D3t9>+Ov5dyu((i@M+@^ zV>H?0%*`?J@T81`T+vig05xZ7=;KP6jEdgN=!^8V3Uxj{D12deCP44#@3mIz>v0Md z4b^Oqfq~YRm7>ttXSA=qX9RlQXR;zJT- z#_}}!o{tE_al{p#@5TzuEbrSu$F|a7yHXzvOsa|Ddzz50yrwsPW5 zoGGSMbp8cVHg=qv%fR6A#Bw@o_@-|qox(6`VN`ptn|ME(P8yB$K@^3uUhx(6qsd=f zgyP7RRn}WM!W063%k-H^q{Z%`kU@)AzUOET;C}>(AVM4P}#QRB+WJ_ zZTNZ?UE?txVdsehsb|w^Q5oAir7{3?G3K!`S%kJBFBhZGCj-RHTb*y>yiU|xJV0c0 zjy7{PrbdiC>GOI)4!!TD3K$+iXSaA*$H12mWdhb;QsKmlQhHeUi?^|nmppR@JtG<+ zUIQb6=%wr*1ArGy;2|%-(vNrh;$7%~m#&lIXxtIHCr<{}WI?q4Qqrf|Wn6sWR7*ws zwVTvpN#mogL>liQr&iUu?IoM{z&mU$#(D207E4Pj3Mp;RxU152%Dln2?av$1{{CKt zdIk~YL-k*6!UGt4}wpLwcjT$Ye-a8y&4)25S3yABKw%gB0s-*rQ=l0#9!ac8= zsb35f&RIpx8ABcGr!u(7~<)qJ1 zsa5M$x{=M~8<(U5mHSdf$E=ge5fz-Ilu^$RGay;rN#dK84Gr|br+O>wJYk@u8&etA zRkm7xynqvY5psLry=USN)i+Nz@haHeli6gsi)?%8;(suTln632Wto$=%WAqK;DfiK z(Xnbx+h0t_EsDlX8KSHUCPC(0(30^(VP1OVa#p$@ah8dYMp4${hRETwM2cG|(if62 zK&<R*>cw~jc4gP=exVXCAFn3?@oJ`!u02!#c1or5qX!p3VT%8sqh**{zb==DGR$s5QGi8*o9KCzJ(X7iqSGpzo*R!BJ- zBW?Gq_1*bK!LSgo?H+k5Y^WrBLFDkoRHbT_a_TozplztxCd@r!0PcITRZaA-i2Uda z1_V)4D~IDWCc)$90mpm4WSKIA12+}rBdM-*Fbx6W<0M1(NBk^Y6>4=DF~a&Gzr8#dI(~dDZnln7C>1N3%hxD(PPX0i<}eR=w)XvAC-LR?z-aS=(d9DdCD7x?z$4mpsnZw57C}cxKvW@z4C0|a zvAB`eYX7ik#fYfQ{b?O63;RoU9$f@GIhgJ{97`a7@jJ{j@gGTyPcS^bTH+x;qa>7* zyOJm5&=$~3g#HY}Y`_=GW)`@9g4U8g{K$AP*!in~4eusESVief=SNJn{DVmz9p`E+ zKMxU94EmrOf48Ww7dZ{$4jZhSf##!7`TaWevkO=3I`)riA4pK6NBe}}jJ0uM9{LgHhAW)beuK_5XND|K%gvDZd2gLn=b zqV{He;}WX{0FTTmo`tEwlYG^XoQUTtUWU84wa%8lK zfgUbb%R1k?jUXTxOpt+X?$MtM^-nq!Z;6c+j(&wR-Bkjrt$+d`k`O@+*==Up64oEA zkf+L7yqA21sA?r)eDCU%E3b?mnbU$d!*rX<1t|=BO4cYw!a_O~CCj5_K#J}6fdIGd zs}M7<^YD*P6~>0 zF<#%zbIe^2Z`R_0Xq;*?dmzh6TZNm#}m#9>7Je_ATv*qV{x{>kp)M}kl&VBx=XsCo)k;g3ncOa*cnHvmj*41&o?w=Y!`J`i zn|2O@Zu|vtLg=EfadgsK9O(fdbLOWv zZ>ROxWma3q51I9-J;ZOtFvCjs6n{t2Dy2$*We%-sz4Rg>xhgv9{@9!OsCR#hN7~D{79P_CLH@W zt!>AB2|43#H3Bgv4I^q!o+jN->+Tv<^z>(Dg9wtqxYOPi4`+e45 zjJ5*@E(9F$Z)*J2Di==vvaMXY>oW7WhZk+ca|}E;TVK)u)O%@=eNNl$nv<@_U(2E2 z)&G+ar2hXCW1Nn}*-UH2&BZc64OAX$t8g+t-6@gFB{ce%5|q~=O>E;4ED4KW8dl@% z2i<*ThhD`qu%Z=+j<~LqoJTsgGNEx0ib{S4uOs;bP6(|{(H*zWT+=`{eFJ6S^> z^mmQjFk%=0ka4yC!NncsV0Oeo)BxD^!0Rrs=n^#Tqi~Y40&yrFFt#VxNgg68 zL&m^?Kvn7W1jg9wJ)axsm$~YU#F9?+Y(4YH_JHHo9on>h9cj|mQn+*PcOubc9U0u^O z3IunT;O-XOAy{yC*Py}O-QC?S5G+`5C%C)2vvHSy<$2FH#<}1M#$d0td-klZuCAtV zrO&LXKg!IV0O)G1TK9;qn6B4ndSYLG71obqw(rxYcl9hkIRZTCnQ})vyRTDDAC0$_ z>*e!q?9jCdTLg%trEOB+Q?$|ca5A5+4jX|z0U@0oY%O*(wzuc&gh7I(uf0mTJmDl6 z%FiRr&WT*b+FvCJw*Mv zzREjd+anKs$d~k@r8bfaTO$GyR3%7YnW5*??6Q3sJ}i4$Xx(N-zz_jN^NBd^RV3k; zl*CU$?&8AYAM_HXKrOw^eS^@Ns=uwAG=uE(?6P$4t415B0<_C9)k1M!i=rQjggW3M zipu&$E_USDvs}r+o?{uq36~NIkpiZ~!7)S{Wq!ghQqv(sn>BHa4Sz$3zNYJa`3#V~ z5lj0@DD{e_G!!eoTCzM-mXbtxpE+>CYH(H2j~Z)gGrpr}HF zl@uUz9u#X&I>POD5`*aNak52oj&ckaInM*BD6tkxOdRFU7_O@I+pm!FUg&m01+h_a zM7#vy<(be$?QSnPh=1iU4K+;}Z`|dZ~MA$~(s9eWM3aHUJ@lQE_n1DL_ zbe-nE5v6+rS&_5ScCoNrtgIQ=Mca=!{0=O~TUK}e zvG7u2E|&n13-Ev*P!$2bhV$u#HTsB>v1V;3BJkTrvyP?nrUm=31FRKR3{_mA#jFS{ z-r#(A_mRvZr?l{9W6BI|L`?z)Zi+4(sM2uC=x7>R@1?XnnpZ3fW9SND$yXqtY^n6o zTO0u5KO@OAs2>d%_|>cQ4JuM18<7A=kuZkQ{<^}4c-EX6Rwi5M7FV4X;x36Mj;YpX zmw=I0QmdAXvDnaE9!}@9lRp^3MTmua3OlmX-$=@m>8T4;79`Gj=a1Mn8Cj-JBX<}) z27re6s~P;+%R$}2Hf?LMg$^cE6<-&HZ@)@8h7K6&tP$o)s*imxGW-LR*V^b|KQQDq zT6#>e@hS)l5vUzyd1CAjPp*+LJkYyjD(7h*UVX#r zkIo3-XV}ksH~93QL~E(dPY7^lC*fH>eJS*C;?8i1RAbSI&E>&~Ce?~De_Bww%yVMP<)NHOp6{bR`QK% z{4&{Jkt5*EmQt!K8N1&9_a}u~7@nri+o`8RChWMHb>^RR+|G99j-B@QN4dZl#eI!P z4H&dXMjG)wp6g!zSlwP8`9^Cnh>L~VY&TFvOf*;HUtIi;WJ@M#O1g>4k=Jz zj(}3A3km#lV`dxOaq+ofyri&o*Mcf_-rCHR?y842ADv?F+hUz)Modj=ce!B=Kbl%D z5jRe(Y>N0wAq}yaAcFKUhgd0OOlt5p3i%_K6Ao+52V|UGUf&6PG%$MfbqcCepKjxt z_J_5IX5o$lFH4PQ*52yo!=Gw0-&=MjB0WM9vPfIzJlSP7ja~jO6kE2M_@9<5SUzEO zOUQ5ehRlILnMqE^vcR59-AZBi#|l2WNhR&CUTespO1lBkAks;6g@zXcUo85wK~+;X zE`&>9!rp4wl;H?2J8i%lkyskO*pnA9JVlOGPinzIAxrReMvq*PD_U}@{FC?^5&zRb zde?^Z`&b^DZ7k3y7H^DC%9;cua)t}pP<#70sdztCfo^VgvhdKoE#6cOj)?@~_Sut- zxnEuI*e>;Or+tNVfxPIs+xc1ooJL%MN|>w7T5FOEezW757&Z>`{+28KYV-1W)pBh} zPTPay%lIPee)X!w981X##^t|`h}nQ$4hH^<)PvVZ76-m`^W+sC2l8is!J^9kKt5)a zo8FqQ1Q-!*`x5L(pTF6xJe&`;T1Ew9An-E6J;*`FJMM7)8ny8@g_2Nu|A>U7jxE%t zIn`>(hA7IPPhh!5liCld6cTpkD?rS}TTlpmEX==lG`1zd^qekLuwNZBdMaJj{xmS=JjvcaE5@^NQCH!S}?{c@~gkKCRJwW2BVU5#i!{K9n6kC7X$!EeRZto!ECk^Ugbt(64S-_NG5&0~T9d2$X_a&B z?6k({JU!fM5%7DnGYmt5M5q6V@>LV@0Un3Y@e52?ztj=BKP7>-Vza1gJyzv`p~|h7 z{Yvfxm(OLhSPS~)=Z`I#(D$d}T^j;NtMoz0mbOYSoyq4Lzu17{_DsM&T+N#6YIo9l zn3+bkVgD)|kXZIt+O-b>mDc5J!;odX@;wfe(yJ?)!5?_F zFNCC$_{X7_8`uvkmzRr&i?|Wd(coHvc(xez1`}6%y7=~wpv`H!H~iJ#gznjq%ak*N z%VR^b-s)VaF!|#>UW#yb#c@b((edbrb-`|BqCQXEf$TJTN3x)h#+ZrDd?7o8fZIL! zd#<~GE}kBpgE-J`j~or0=}g^ZqUHn+n}ed^TAt8@4FCNWim#Y#Uue8DNH5XxzE6@? z_c0|pjY76PC;e7Fu|348vl}>m%u#8;0VEt&5Gv*B$)Jy8~gepM@n(+p7lx z0|p~4P6WaAZo2zB&-*#6!qkVM>P8+T(wI*&ox7LbB>XamG8L|xcnX+CZFF3H#Mh>V zUJF!Bc%%PO7O`w?B`zV!^l=zo3_O}m-m<+eeh-euztCpmhaAjp#hv*~Imv+&T2uB_ zPf7R5VzCtIVS^(A<-2dMwcm@iZ5xI-Wqf+PuxFY4E2uB-(d?nd8MKf>o{{m|ZpAU1 z>p4S=J%8?cGyMIx$CZNL?Wq<=486WC0|SHcMsLYjW?Svpynh`PhQODZ4EIq;U_WKh zw8dqV?~Jzuz@3i(G@?sI*a;rg=IJV4@MA6lN+!y*$l} zlM=Io^@)Q7sU+^rsz_kjzeySIO$8ucY=(thw*!Re)GLH z(S%x__52D3?@KK+otm@qVPqh>C48E`$QLzrftfY<W64}Ou=+iv(e{`lt>b)4$7Dh2b9CS+z39&_W@T^s6h)M7s{S(`|F!bq}T7y)C58v zyk{R8z;tS-EnTy&AII(xA~husT8xA|mx(j4rwd3r?#J<($LZbDnJbh2h}r190kDyC;P0%J?H4d>fk#jVb(hmLyNrOoA@k4Ru8@g#M?)2rW?qjg{e~g_9iQI}` zC%_q}Tw#P0UqJ@)vi#9+c>lz|(A{p&{jnZ$NV{>*1Gk&|2~w5Sp&vOzdLxh;Rp7!3 zE}F87iOlt{NqLg?C)C*=keQ`;+>UKfjWM;NFf?N7xU@>hM(O=YzH&c1=sOT0 zYgdoVgifQ)M3M?)KD?y)k9>(l_--PeZXlX4XdQSV9mDT z3{C`q`?GOH?dZvj)@nHfC?(B7s7&g-4iRN#>@em99l?^dddcs?r{HsTf1kuC;RqKlLBF4O6pPU z&E+QtAB`iZC2}47ew0~8Vll_=^$Z=^OfZ;X5}V$Qi%b+1gYcmzvGMBSUUeVu>JcNU zZHOp-nGuZtZ1NeqVPxdIr}c^D0MxY2pA=PU1mUoF+rwUn5V*j%7k4}pS^OfAaI>Hc zdZEcyFe?eW4~ksmjHHL+Y|EjP@!QM!@Rju~;IZi(jQMPT_-oN=w{h2Ey4^Cwrc#wI zTH=#LQNUiY7%=;fL)#1v;>4sKmRjRC;_rib_U46; zlbi0zEDj}3e{1Ka$xQVk+3Ft24VbBihk+`laP*9E|^~)<>Z~ zz&c%_Bt(adj#eQHm6s=p`yCBK3dcv_qgSA9S}mF^oLW zfW-w9eRgk%;oTY&r0Jsil4WMUQz)b9HbMSlEDsD^tepX+!{FDx}BY2 zmGAE72B6G@rEtx!7vSKcZRIaEB4&o0R;|-}LV*jh5rYeh;u*27Vl%@yFyC z9XCV3&FosQ#XSN?{|N{1r?~$6=2kQdRFU-XXp}1O2Qt4^H4G8!bS?+JI=(-UK0b!> zQKuO~kU>1Lkkj`eZwtdruIkPEFXpd=~ksu&Qp+GeS|(^O`u9^!~)* z`hF2JgUp!)mr}(A;{DX?2}%MW;QELVwY6xBHy-gWcCr=ONIB`LSO)JqFkHTxeDIv+ z+S%)JGyKM>W^yy)OeHjkX91QkY%p`c2+3|7ON!j8${04BrT?oVfg}Kt4|2we$z9br zV2I`eL53g@b?e!e0xhh=N?F6Iu`wCU$oS3?D|tg_{Vz`UIW?9y2cN)>RyhlfF%}(8 zYHoT%$t$b6kLs2v0c?nA%PoArYM|nHBukQIOQUt=YT7~vM_`u^`X}#ETy&hO55^HroO#GRp0w=)waH(x!9rt% z-v>-2FTLWqZ|kan+C^1{=wHzu*+P)r0u4F17H6IybA2z#e?zf2$MwkMO1YN*;60g^O|{voF!#>IlThzcmXqHs*pn{zaB6{8dSab;l44Hu9_ zEQUmFe1hAAMMZ5M2plqo!-W4y&hA}K-zBV_6h})76d>+!AIme~)r_yXg7Z`=krHqj zEE3lr%2q`m8n|Du#OFyvi5@TV93KqDBKTEfWREjl2j|Eyu}a#wac%}D`@&fYI7hK@ zIpE~N&;8Q6{D<^qrw1q7jXMGb_FKgwx%{MUx`y9) zzo*3o39hD=za(dlKib@LJzk%JjGAvY!2reto5*WRKblBz=|*nALgJTlft05S|4Tpn z?eRPoXfi#fql?h=difmrwZ)N9w=jIsz?bTXYZVnziH)UCnh=iVd54YzW}%<51WRNH z9+SNe7JT9r!t#@JrY7cgi#J~G+z6@eb|{)#!pdU5a+egwB6}6p{dA)*y94*9=(=&Q zubUUVldW$jc**b2dctx9vi?e0D+CS#b`MLsW+61|oG_?*UpBGS>9d)ZSqL2jsD;hG zL4e_U%8Ct_#%;Ga26oA%^J1~rJ<&1nbqc?3m4N~7MhK0pwN$a^zFZ9Wo4ZZ>_hAsx zkRo$})5L0(WVzJXTy}@0Sna@9hHJ`R}Sg+tD3+%CFqYFK@4Em zxM}BrMKj+eV47c8-jbecSOrsyk!l}7yIDUYUTvXV4?|k&O`otab;NNQ99o5t%jxd3 zr`LaPUhxQR0`{;bry(ipz)N6EtktIQVL7A0_}EL`&4pV)LG+WUG*Lp3@(BP6&k9@h zn3toDr>e*-gLf^2naSq4clAM)h5~K)@dzqD9b)vW9Bh01{cx7L5l?|VzyEts2B9^|6OgFOe4jt zbx*%oCLM_b^0(9#%HMf$Zq24T<1XGy5^4i{Yt8d13yGpi5P<;{o&(>ubbQUZ;|AQN zF0S{-{veC_Lan*ZH*vUM>QSfF=TWY<+S`6?o!vA0l}5Bl8{P-be`>wwCl%o!1bV)q zDhZ3RJEVV#?o3hDz+hvGw3z8{M}B$iKP9IR`DATe=vkXJC%H&xvr`KNOt+y+@*lq~ zkogzp2?bVGr5mWLmwkX0`9F3h<;!2jt{w*<+{rM4@dy2!i?3ae`lU zfW)`s{FFARWOKX?WSYGpMQfxK@e=n56~$nisZ#9}0!hMA%QboiqSC6jKp!3kR}ljZ z$)@~oN2<|X`<@naC))Q+-sNg^&gW}rb|1S~ue;|cz+>5+Jr>L{+M*#4KCp; z-V;S@t1W}eYXG9XsK+dHzp?oSOH#TPW#g}8_D$?-UR%dJcNNVt|Ln~i896&dc*V>( z8|vow#0UBD3%7jJK4A6+Tk z2`W^;ukdno*(u~sASc1GXiw_){AtF{f9fg~#wrS75`Y`u$c|2mlMNH7;kK#y=A!c? z(w2$L@=SKb&T=~ufIdMMWne&<2EX+ZBQ8<~v~)gpkf3n!KX)oH@Dd?!LNVE=xz3)aZS|`&1^olw=$lD{8|@Rg-Io+J6k&x9#^fFJ`+OTjXPT`fOsC} z8ObM810+(7$cd}N^4I*F!Q|M-i(P?JCTm*h=84b;=;fc5JBfLllDctls0|lf?EQB+ zfr&`7+YEn-+kp(CWsoEOhvxBK3Aa_jKYzy{6Q`jrd>C(HsqbfmPZPBWsu;~&*49o+ zd!_qL&hb)h#7DnzmOA6*h?7FT!eq7L;&yi-GwpDM``r`ubiD_sVCECnh^gBe@G{z8 zwq-5Yt=4$nsemhSRCJEC9V5^_l2(1S7UP@vbg`*Mi#xNlj7M|=Jj)lK!w4!$FEG{t zQL+e#TP5x8ymYc&a6e`J-~le0g2(?eR9USQ)F!|jS=T9{XDnxtgubT z1v8c0&O=wpwr+QAc~Vh$HuYI^@;v2u%|}^%%?|SV55!v7c;2i7 zjxy(7iL>z0$wRd+rMNrsrPJL)G)reaPU>69x|Qoj2!PLWA~KGu^ydH?GeT^Wu?z zwuX*U8jnxvu|*iv2iL>Gw6RI)`ja?>t|r@~Ybh<8rT0#c=AkaaVBz=7;Bl2?3Am7l;kC zZPHg`=?bLk^c{ABsR({~Is)`8(6rqBh+1$osd|0Kr`aEWl~9T5>(IEd&^ zR3e0VJFHo5%mHsBw02&kkuYcwJFOcKww^k1|0fgKUgNI8$kDK^__~i6esAy10;_|zqF0$TB^` zm=b{n-oL;N8J!yWo>S>ZklCnF*J`HURj6O#78LF=OQqLqs~7Qx?+3=gY7m&AZ1|AO zq+sZkNllo9ik-f9A4{#DUHkhCo5couloWll_SIAN(^9PmU$(ru6FQ_)(515y1v@Jg zZU$!{kXoI{Ef3v&Oy7VTg#2+{odeYn6EeLz3tBDup(i}i)}Rj{fg`6+pm2A+Ho$GI z5ELAr>SAbw{`^|WT*`gHXLw2VJhL+4-J$F3`@2wa)>czf903{7Cx$0fv^ewN!MWD5;PGo>avzezZ0fjkSAM5mBR~>@(Qk3QF8CU zqN)T+!0hJ3P|9Qd@*&;;Nz*(L1*fCy(X8_#6wdPv4!X1<{R~D7;r;ZaVEpsF=g$-s zpM7yz{Ur=8;Q)5FyE89C*o5bG@!AXyaL*&kDf2HKaNLoQHC&f%p|c~fi3Rhz@sbLNLp;aBC+{i zBmDl;{;BD}pnW^e3kV;jX5gjleh5BdmdWRt%|ydpxj#?8u--p!Pg$MX8KQyBSz(1D zU&ILsJwVDzkSFQuDo6fHm%x_r*#FKgTp88rWcZ>ant4(FI!9FA4X4w zGXyYappxPU%T6?+SF6fPXk3>VC)7>bs_*Ms&Ts=+UCCA|J&;8UfMfM2{y%Zah{<_}!w(OG z=YxQn-+1KrgnreIuiIc1=U^sJ8T8zDXWwgcJI|UbAt^TJ@EJG#a9PJcJNPKya+I?s zxIrAQ?jO2)+>t`z>M`y4)nPA?Z-DwLcJ99A@)9hwz>YmzU2?@K}cqO(00?nvfOtdoU~9Vq|OM)7*4+A052nxyLwb^iqq*Z22+0T3o=p&WMWJs_`?5d`9>*d38`G zhH2#_z;0|GOM)chsux)-|6T3C0w-hwL2U5J@Do&5RxHE90}WY+&&Uj=rcc)2Wa~WE z{a){Me2wPU#oYUWnccm`YKl^KABtYtZYhr~z-ju_Sz&7)u7U-rbu-J9UUYi}W&H)C zd17lIIe(#-+nx@xaUn^$ep{twL?-YCBVZtT^jP?~RH0pg86INCQ!aRAspTFby3kKZ zN>&^h4gSzMR?m|T!Owr%@rWT--c#~AaxU2SJpN{$7;Tdp1~qug2g&OHvai0rk0Q9l zGT~NiyYZeN7Xr}arx;LmsGBmS5J|~*^9!r{@{wY!>v=4*BrkolsOg_jj$yO;2gV79 z!Tg7yY6WC80WT`b8W(sSD=XSH(-**jCz{wxfGWBxLdvOCSF`TqdzI#!(>b36DpG2s z1NT~{<{w(iwl92k@?^v4Msj2KI_7b7at!C$iB#&EBwvHupx&%1PhfC4XvYoD_fJ@Fc#L7q*i8d{ znZ(X2f|`&&A+ZrlAQ159#?OEKB7SL}4(msU1Llvm{ZLpBY>%BCME7l!xP05JRN0lM zwW!D2sG8%ua+ml_OqJFHxq>fvK{zVep+(~V`wGX?elnJl2(#c743F&1o&WC7c??;Q zBoh-Og=B?-#4y~8f&qu~0R>Z4L=4#o)_&eEdvO1)Dk?kBga_-B1x}Q8-fNWZr=!m? z9oB6;;%QDj66Xb)n=5V#E;!}()$+5IdaZe0&!i|VOtXMvNzLmBG*Q_Uy-F3$71K*H z-5c}8##2~>ZJbu5{uI4Zg~{&g%ikcUOtGPk_@>U#mo>6CVFs$Wh+_wEN*mPkysni2A418+$e-BTiO z8C<>GdQ4;4Y$t>>?g%9}A={uvv{{11YUe{-h$yUyyPq&1UH=}fo0|XcUU6`wL%Ue5#20l@2 zhZAh~fK%FTg5?7VsbH+i&uw6fGz`D@hd}iDzTHE>`a0(nVAW}tyHdZLmUH`kPIeAD_7?$|~lGe3|#Vj*S&(*Ndh z%wy_(MVt732|0^n*~rgI*{D$h*xb)4`X_`*TMO@?=79jyEE-@1fs;d^#!6Q@`kXc{ z%o>7-io>>sbAdZx_Mr{GMn)NJEbYvr^m_A>*d~PWtPnI3-_Lwn!zi_xGLVeUL0Wng z505g9ZrGql*Bv1#)IT4RMasLTU;?Mjk;%`2{Y%IL0?ubeoqrl9xF$O%k`Tj#+P+iI zH#SX!x$BI&-@>T1fI8FX9W#+yFHAxqE+l_e`ovL}aWF(^vM1x^Ba9xzAaPZ1VDz+) zE3JMZvGFo$|K4-_*XIOdiN5Ri->doEnmpTazD}BM&1S7uMG)lYR+yxgG?wG`?UFi3tj_T2#(&rG`7+aYRKVm-}WI<`Sd&Cz4tfE z?Gdt??mh>lQ09_>zf#@u%5=X?7uH!K1F6MMzt|DXt>_3nGnvV~Y&ubkL8{UQaqj;= zc!G-~L=jkiVkjGZ-s%vf<*lN5eM-8tFt%kthnBtX93I*iyBeI_qGR57?(NF^(IzB! zCOp0JAq|gT<26$>WKGsxE*4{9{2wLbL_CQqj+WK@76}+GuvoIP^76AhF|m)D=MhUPH8h)z2mm3l9v4FdhP zQS(o_O!+(VHXH6Nfm6opHrQKjUbGF~wNCnCytts$j8R;JUHRQNn^d-M(h+ z5hjg=Efk#1$@}W8@rFeD#NV+|wILu9O1R6$2HvoMo;RqYz(g>Eu4k=r=wc;3x&p3~ zbd277V2pK8Ai*qVv_&?rJk$L$M*kO{P!H2TYvnv1Z<0RRo@fzxi+kZ7vM1_f6c&vK ze8ECC6P-4a&o!@Ehm}kRkJGxumZx=1`8_b^9P0c@NIEs}8=i0BFd3Eu5J1c!Z(n^4 z4S05$_^8xx{qZI=|A9sLK+`-dsE3v!&>TSpN{qy7H!@(F2`1cI{^Q$<6Z(_W;^_1F z*QWqBni_Y?szrmILuR@`+|C*zzqfzcZ2#sI7=Tt37oheNisCWwLrIf)HUXxUqPw0v zZ%;PtJ9R*D$mc6too#kQS$2M4VUv|6IZQYQ`AQdw|EC3D){S)FiaF?H3?&I?QNhS; zY1dU2R;)x@?PN4wZ5BUC_A(T3`Amt=SztP^t$F_rJ$>Ow#F1z+gFDRo$;L0ORx^BfY(@u#dox&GLgUp2 ziIZe0i}xqVzfZ?7K)&Qh6lnVc6=ZWkX17$Mi1zfy>H$vTcD~xwo7`p>q+Yq7Y~>E%8i0IzZo3s> zr24NAnwJ9xFj!XBaND$?1{jcJ6i;5kc%=9@ziqsuHfP7peEhTQ;Kdm2h5l&f0xRPf z=x1M__~#Ruzq+@KpWhxfzv22JG>q3j1q@s}CXZ#IynxEEp8IC|XC|(mzp=%#sPrkY z{50N)=e`uQ3mlCIoF}F`Y5ZwnEb=R$?!z>X>nWUO`3pXiQ^2I)p22r@EsVD8Dk`FP zhWzV{npq5>rNK^evX>7MI(ddd`=j!Dd>_)l1kM8=y~&PdZtcw7>}LcU_uxfAP!v z)}*E7!P99_578Wr2OcB>DuX7Q36B?CM~iLa&?_;|_IUQ#dp|c|iTMmYi&SKEG>2xD zq@=7lb)0X#fLZad88!C;3VGY1#C&Uk7@$}0^Sq_WE-`-~G+hhDdfpvAI8`dqvkD5o z6zciQ-7kd+ruG%W`P>mz$dP*|6eWOnep02A2`77Cp!Qq{_C}%7=*i=g?!dtHi8Y870*_Hb96g~hOcv6A!p3!BIx#qoZjw2ILIZ8dftpyY&sMV z{yhu?H&|bEYAEmriZC~uttE8LU>{6=;SOOQil|L_z?yJ>1*+GRk7_NW~s;6tw;=|u*3-*81 z@PSVo?jf^oV)6Ng8`!GbMNfRd8`&Nq8Uui_z`7IMurv;Rqbi-c#ARn0`cckMX8&$a zxmm!-Y16Uw&6ILUoXib>%lQJgpwd<3yo-%lqZxADC%H|>6q>i%S&ZXnttBhP^waUp ziTWpoT)5>XvO`~}@MaB4gWT^Fs6v`vhbQ=|m-{|I zaw3BR2#s1hVQzCWrE-<4`h6=4*d<`(J!ad9SS`+!admDd zQ^+QExDy1UNQ5G&EI`GMNHhh5kX996oHN=HUP8a1XrDl06_7d8e~*wB&*jB*Z9XY( z6Lka3S@c+@R!by+tRYnqsE@LK&ez{J+#Z8trlmz{kDhRdUM8qFW%!RvSB5jz0TQD zG?RNQSPtXmNIREm0pF&n#0Ql_@5rN z+T7)kbaMf4u$3|SDYtf_)Q+g)Fxy6mXm2ZNS%6Dk`4k;UQ|NpMN8oqqlOF0S@%*U> zb+II*EIVI`yui;4Dpu%)I9MSP^S^W(qt659`}@j`y&1cx_f`1mu1L{3*RT*UFZ)hbn@E3y{g z5@epVGz`6wYC>$TL4w$B>w>B50T8@7*h$o}Ly1_{hRv&#mQiWHdR5{!;vTu*>i}NP z1&vaMqatEd;SKq;Vl&}me{ss(jI7!XC0!y;Sht4gqWSf)P?@yJ7QesAHYj-*!$`mZ zz9g$D-}&5giCI_iNZOQx)h?G20u>!SAG87GAX*dD>84=u`^$QbpIW!W@s|;|SBTNp zJDM~o%)YXSk|g|@ehy(x_PV(0l=-wN6NZME_DxDAz9uNMGS_RMqAkgfXguZ#Km9Uj z;*hE@9x{m!IGrT{bCn-bA%HDU&kO9yQou70gnW@E_W>}&TV9C5n{WfR);aZrN> z_3}dD7NHF2k;#Hfq{zqhlcKm^6k_TjV^+ODGFewtO-%JCJ9Kv_;G_r#PK|`QcDzJRFd+>aF81@0Caxqa!BFpMMHM8f04pTWq%H2xq# zjrxjDhrR)X8T9e21X;DUjFeU*E%H?dz~u756t07RuYazNpuqTC0B}bwzK@2lwcd^Wxdw{iSe1*r zO<6T@@!uhpy3hpttQ9c&j)Tu{@s{NCM79elr`WB6gTZ~)GapxcQH_l$1mXXI?q+eD zm!@xj+{g&B%leAMF-8xUPm0CZ^|(<^BrH+cM{Y1Q99S9f|GjU<5jRl4@7i+gf4Q!2 zj3+!EuI8UQCM8qTPHbn37L{&uZ@0F<@EkF`>5EoQf#pvBDN$(t)ds3sy9Z}BCDu?5 zF%oVy@XB@lfer@A(}EuaDv5;&+NRr=s-Xo@=M~Y}{;_TSwoKp#f)ok<3dGz24yMu2 zguqymTLrBY?w4BPhHJZ7RP--d?1TB>9S)a&SzElDwo7C*YOO)w&Zpi;s&t>f6(T9s zt9lv#oB_zxT7&lRKyewx$G$klp`jjbW148LXffTm3q^bk3O9D(9XKy*MfyZQvr>wn z=8x~Kr7K<`4O|!^ISk!fMl^^E9{2r411$-A)X!@*B-PGOXcI!By3qJhf z=V|hVri;o@)IX_8*@u_E9XXYi!E0!-0y;17@M@AbF-?eQGZ^)5*KIIoxoU8*{)V%- zCC(rvR|_oq$ghYj&qd}C(PA{=TLcm=B;BxJ)iaKm3?En_Lgy0RlMCP4oKT~KY61o^ zVIIdKAb&w;Vv@7dN*t|z_aea2D{Rw$y3o^71p*iHeS)q}?MK+%kq0KjMra{rSGSfj zRmI3AH+l+?z~}(e=B(zA$lgL@D%;yjk#DJ86@l^j>XockKnS&4;z!CzQ(9Ut+6|^F zi5A4gDACBFiv11mL_nMBcZE6o^XKo!y%(l;Gwz8PhAeqlk9*%Y+*a2E-y)@~l!~Pk zi`o7_iCy2jitI=`npE4(fElbx#U@)AF`0~F?{f>|LJt4z(sa;zOMcOZh;4~tAs(=N}lz}XF3fb66Ph>4ESER-`pf!&@< z3NJRmRFyS_R7X_S1|?BZ!IFJ0XG8mw)Ri~*E;@w!!a=xFppzDhc3J+T0C>9hgVTR~ zHX8Z|U!2inN2BxS@s^kSETedV1PL)1{sN^e;}NHT#r?pd7D%W~Mv0!@fvMsWviFsD zmUR~RP^O%GDLFWIaE{Ld$uMaMvF(*Kn;kd@^VUkh!(~H3B{D!jR?zbUvIrC{**bt% z7j+-NT=Sc=qKNYyx%njyM)PKiTI{}mD-(3?}g=n zx>L{!E|FG(N|_}nK5`BM3xp4p2n+6s>(TOtGd9alI{x$>gvHGS>z^NE_JSFhms?L! zYK1y|qrp2i7XwBvChW|s)cQsv-Ao+9IS#qoNEpxklMj(F>uXjnq{z4jV>*ejqJ|xe zBes?yUs~7>$BW|ijUA1UBXZ#^B_AQ2vH@-PH`Px-Yb2$Ti{-vp4C4oZ00RWkJR_ut zaLq-|G*cOt>)9H;6rb}gWNh9mVGeIYOuQSAWFqL~vJL!SYj8+DvY@8Si`zJ^(v_wR zW&>VgBubg%CuCmlrmbtl<-Gr0R_6g8cf6WSApc5DPf=;p|M1dm^d*|U90M3CX+Lf} z|BjMydAev6Q#wjj2vY}#qE_kW%q4dB&#InDL;Ce^_)9gp)q#1iGXB$AnPG{HdF01~ zi)$;w_z1i4)QYBTqE+pz>t)FAVV?Qr5o%Wzudiyiv$p=5=OU<(Xml=AEiER8`j`$E z^@P59e$SlW;@L+h`hjrSNz;3wxbJvD*`7(^Z?H%uB%KTw7K=*1mOT~kcA!KF+5GVD z6_?2$9Sbhd0IqN3kb>`SZuxZ(k{9BZ2K>H~60$r@x`~gwE#6T3d~QX~bCy6S8|qJW#;zkY$tPjoN; z;Xhpuf=Le*IRB%<#(BtFEHtX$fQ;X62oq6pBy7ZAp#nY_>GbbG{Elg2wOvioo_cwTsPk4b%Q`xym3pQZ0E^z*4f4oLbJ??QYceZ zPlYV$Km9t&j~gZk=aT*MIsHA8b;^J(lo6BZ8wLg>n%P{&*3JmW8Pup)5?avn!}cCk zGA^4HjqAk|5>uL+KTyIxddzadGfD7F)0C35+^kIG1f8#WV7}F2t_;SYE;i#JuDA7g zUb|s3Y5t9*irZ{tE`>iF3#zO_T&a>xeyhhY<8$lFaKp0q$ZOgGWRgwjP~Z}PuCGmb zsb5w1rRQ?3K&wv^`IqR^u^w1(qz|LJP#>D1bH;O^-C^d>`v|9tu zqlQ3$;`NEmyw`(+7+7;-xLl94|F5>;=t8zI&KpKj60p+6Se($*Y<-Z_bV4CjmD61Z zEBd|nMY`D=c{W@qv`n-|Q3YsX!jeIrh}pA(tiUI-N6pSUTHPcHhjGE)`zYAStx#O=};@gIk{r;R{{F6+{xz%vA1NNntlIGPnqKxjJWOcDN-4PSJ zVCy%tH#$^a*M^`(S^7_1vajN_->{fi)qFjP#mYVfwwi}&OzX$?HqL@;?1zm1g~XL< z@{SD-KoLn=`+szO1yt2vvo<0qB7z74l1hh^(kas2og&@cB`6&N(%s!1hYo3pLx)J` zp*y~P{J;16-uvGBxmZgU{LYUZvuB=pX7)^VBJYvkz!Ud$MSNsqTA*WYVg|VSgy0**! zii?u7X(ANKa<00oy>m>~X?Mo?IYS(l*<#TTkY4e~Q5uW;6R$gZZPkX{!QMw%<^4+^ zi}2;crdU?nMdelRn*<>&$?Guc$u7QV0#b4_9W2; zz}P5VImAfH=5S)G>LAE-m?&z0`JO@LcUj-ic*+R zVR4pkf>JU2x?%RP#V3{;_7}s$w~KWd@s#G{#@$Yb)F4gIn6_{afy@F&>*}{i*Sgl@ z5v(LWS5Tq3*|NV~-34c@*Zb^B{6SCtN2GhL0YZ_}*KK$|%93s4h_FB&<`rCCLG;Yd zHrBq%=r}jQBr)a{Tpnm+@Tbo9`jBuz=_}jK%_k1~(+nR|F@<=Ag>FZ?l5O8r2?lL#YH=f@w0ZCgS5?2*+bsBA{D--<3ja z+vRUzY6|UrqRuQ(`*TA5`hke(-K!r~NkgZjY4-@(h@$!%uRL$is^T+O3h|XJKJ*oQ zM-0UV>k%FjSN0m5kFde@YlAGKhvM~TDJBuhZbA6emk8+|I=H@uZK#c-@(VCRaaFl8_& zIr*q80@bQ5n$}r(xr26!K|-uU<4O4Q3Q_Mu209O4v9 zqn+n3t9z>+pN!Kh{J2pH#tl4z`OsR*>Lhls3q8CpEB5_(8l6vhH2$N*CDVa;_4f6V zJ;Wn)g{VkkLwcWMdqnk{{d?z|hN-A`bt!}ob z=N>HIxKHuv%5*e;5Uam_dDHj6^bd9VBrC{Ai@Di|1yP@Ze-axg zw*5kcyD5G$QXA}okqcW$NdX$_8dOtGzUG>#+OYprH^)g4Xp*55L?hEVN}4;}yw5LB zmTPjP>Y2&X_7nFATTiJluuI9|HK%$1`3fyhJD8NZHer*;+>ysxn&|Wuhi0{gER%u{ zb0Vhg_KA8=V#*BC;h{guh2pumw6uuCI|8k@w6yDHs=lu~9y`C?kb1OwjLcTX-!#=0 zUexavIi8%EGKEpF^yPZ9rV7j2sJ4@!gQjh|JOd$1KLwmV6kn9^d<=%fAwy~g8pGY8 z&6xZ*S>vXWqxG1dM+TZu^TzvV1ccD;nj7x||7{L$a!uB8iNQ{w$cyvH`N$WLzEB+f zvRX{T|5Cvx(liJJ$o;UF7?x@!R+#a)HA##^6nrX(|JXIyY#qJqS$x|R)FB!k_`zht zY`<<>k{$;ew`w-#b>Kk<(Ew-kgG-MuLpvk;tW1Ig$at<+E|Sd09(SwhZi(?IPr-^6 zSG6PK!DDW(!TQHmzS}<+7#mX{{Vjc)foXiL-JJZmsT1>oHA*YBHd!$vJdvw9kcO@7 zT6VP?8a&;`Awi(_*l7$E<96_(~E8&J8F+UVmZbr~bbV`i(GL5yr^z%vY-4{G2>J_XlI@WXMKyVo7> zgR4D~U#Hcqc!l(kwAYv^$Rr+ydK`Xu zAd(aO@ui}#%7`pEV&<6n!qY*oRo>B~;hJ5h&btrTdOx7u6$5paOf7Cjn1(wRB^i(K zzNyjAF%*T(S%tavUwQfmavE9tC9?cA*Y0F>buLH3MsT2^K zyFzCdc&;3Pjk(-z<$OS8CDdiY#$SMpNm(UFiZ+u*PlP#20Tu*sp`Y;N znY%9vT^Qxkp1RfZe^ySN+w{*babm87`?-hd2w72ScaFK4X&+LaFyUWGtx-Kk61e!{ z8}jT&PuTQS=IowRw>UB8D;63WIf70<}c z_~=A#QV!M~U^Y9q>)Yq%7Q#-QX|ISpcit+#ryS5p)n&13CKS{P3G26=nh1+0n>VyJ}I)l@>T7ot3g zp3)Xp#u$~|+#3|%gU86Y1k@rjHXVAu1Sx(oU`ls6?jdO#VV&uJ_WZZxD>F$cQ_b41 zwXW~2)Jd5@|2)h&@?OXbR(({kFlp8J=pbXHDt%zP$I=f)N-Ej_&%HV_l_=r%r};*T z`OGK(+fnK^>LN*7O?Nts|FTc4^j6P){8ui(G(y&_iBF5Mc`dzfzA<@Mm77G-=xa)m z-abIV^>nRTXff&A&I!tFfG?D`Q_4}Q)jRw4O(4&s@so0@KVkk-_Y7K8h4H9$#t z=Hd>cV)%tJsr|OtYRNneFZa9a$SDTSm$ac&&Bw3dsU!ov9E%O=QFFa-0FWq%;O}XO zIDhWB7TUBMuO`oLKUnT`$w7(w@q;deKdhQ>7{{OFP;?idUFCzNdqo5Rio`|k#sstn)y6OJ3; zTlHe4<~Dt7XPK7H+~r^Dy-!#<4ULs1SBVl!pUYYQ=!J6Uug1p{hvGJ|IQ7qf%|$r( z$|2N4`q3r07ff@mzktE?F)N@Hsy8X0DbZDD9UNb*q&Bi9J`xVpSdF63=zaY_c#tDi zn+e_orqBYYw<*oxx-FHxkYDvf0UlQi>%tVAZx>EqHq}RElCaqB3Cpk?5AKsx3j2ya z^)Y9>(~!=dAX5Y$07I6RdeHM4pr5?TGGD$|jkyqYQDDA&(}y47p6_zwnc|{kssvgt zyy&Y766GWi5YjT zvOJJy=kPq^kxAnvF=a>beT|q2`-Lt(6(Q7qls510p9}QxraF6gEAlqWSyCPRFW31N zjL=h0bBvgW;!E#lnZJY^KA>;l7xGrzq`q<$(Cm-{jQ#xA<1>^@^zWw~?*mPt9p>K$ z1%&z<$wR264@!geVucd46_ombd1pA-<+BXD5$gGGXUJ&W_1S*_>2EXT3QeV!1bBIi zy+eXZDb)mNA1!Kkx9}IOF<#@hw*M6VUr_XP3FfmUJ&@Qb(h(SUiT*;F(tMjb{;Kx4 zSaSI9E+7B3Rk$O~M6yXL0I{gbw#KFM?c3n-~k)Fq?3R(Z; zj0W!=>W3==XThmvOidC@TOenI(GnFwVF1s}kUV!{O%4}Z4P=Ec8Q2h{=f8tM zq>l)!^d+%KPr6ugVT98_U0$%|?BRz|l8*Fz;_%WGN*+ z`8cybqzrg3_|k(SDTTt~5vkiYspz{9$R@brtu8UDUrimPkbV>)Diht{^!A@7_mR5KG&w6HRFVJOjmng8D*NL3 zjkkAy+`moMU{~kfz*D}`{%W&kpxJ;eW$Lw~bS=cd^581}_amMHJ5{6yAEnR~bUiT- z*~30P#r%||cU;GDe@XIYb|B|T^AhoahxNy(o_&d%j%Jwj&!a;O)=2x%3xkyzUJ{60 z;a}f0Pc4t1pROZA`4CI5^;JeSud8V?Oq#kjXO#3XmmPEI{y__wkXrrG3M0qKg#*XX z;%5mvCxbJxvJ~f1!+=+3y=$rCoKBZ`z1%7k4GAmV_tRucstGWBmF}tZ9-+ISVBk(g{s`c8Tt2jHLh-`b66ixFZ=c zfA9I#-us^Y_ff)QHV~&x!l2<$noEq|s~glomM#u{|N7Lr>DJP^I8aoR zz1#oqf=R0{0b1L?$deYhiQkzS6q=@)KO$ma^u(P!7R`PFH#(?HSK?1UN|`EXzWH>3 z6}ZFw4TgZJaujBocy2_KUBno_i5L}q;% zP_E5I^DkL6Gyl`Gr$=~&hPD7(<^BMw0I*Wmi#>OIxznJP?0K8^Q@45oyzJkcB_@5^ z<#mF{o856as!?_vb1YGDJ_fH_d{j11GVoGnWI3Nv*+dfN9N0VbTxRPJ(L!aO1=7ju zcF8V#bjkPnHNBLae=W~2_f%ykS`*nQ*1zkU6&*3W$ycT$^P%zUVKdD@86wF`{vhHH zvbVl@iag+bginx2S(^7iWQAxY@@QA_IocyOEcwsVrK!E$);gl2XToD&0fGRxvz4(3 z++@C*4id=q<{c4G0v*GJtwkQ#D03O4$Z?)t<%1osPMJVQrN`O$jq<|*k| zu#y|mpVB=ak%$GKc*3h(LU<^K_XiPAsQtYcuCO_Ko3hH}0gEl~6Q;sHE0Ij=Zsfd2 z2oooLse$@UE{JhBw~xD|=LBa%TJ=ls+HN zRTS}XelJFjfo+8!ZiwlYli0RX&%TygqC1pm9BGh~3SC}iQS-YaP=F!0ZDBh*+mYFw zJ*5dI75*Ja;Qdnh$6*}W1sK&x-g-jq4bfcxDa|#BoD@yAYd`Wz#9Qg;_$PvKn(3DF z=(Chl7c^oMY_W>C@|D-*N8XE%2bQb8lW;UwF!Ia}lNT!Rnn8J52Jj#7`~LeECiZ)! z$TJ@>jQ{)!YC1pm+Xppa6-5AA>cVSu>g;JIG^^8_8Q=UVrJN zQ3k5VAiyKeZ?h@aRf;i^c>GdJ2KU{&dCw?oW1tu{^z$gkh=mBuCvQVJk6U`$9^6KL z|K65uJ=gLOCVl^$XtqvJ!^{kchdl5XH4RNW20w$Kg#}vAlHF7Gk;Nsi&bxV&sI=Xwc9o?A}l97o~q2|};5!G};cu$N%%}gxjn~_1Ap!UmoE%Gj^bjPAt zJm+II(C}RR$a1>+mGMZ5V1$+SXsM-UZtCY=S-sw}R{g|7V_bIj zoDmRG%C^3;mG~v?U?K?!(SfTx9YbIr4t9?j{~U~FiAhQegAN@PP75PyM=S3JQ;%QX z9k28Mf@n_BPF-(pRQ;-SwU1DVDQi7%ci_3)BzwSW&EaZ&C5p$r{>WixHb-JDmO(Q- zXCUtLZahJK`=sTZ^X~vK)b4qzNXCp3N?roQKFIYa#PvH8xg0&&*!PU@PYrz za%UH}si3ud{w%s%G8Qf=c8pqGQHBEtgVC}=vlKv3%>+Pf&_|)_RdlY5-@<+yxAiSn zX8`&G1W@V!rqUkw?&6Q6%h@;F3cW>DP?;>eybhdrAr`?UEi|%k-@Z*ZxU-|8qGBI& z5Q6KDZrHdCI;*)!^f+oIDhMBJZJ!J$^Qw}yym%JT|5ON}++gNit7~f#JFa`Jb$9BX z=HbA4m>SbL9U8=n35Q-i80M|^LgCu`V*FUG)fOw&>xS7vy$;9Tc&Muf%KvF`SKVYL zlk@JVXQ|wEXOecR$sMNSQD0L zQ}W)tr&q1cj`LhsLShw(0(RlG0##*lJX%F@6`H_SewDS&E$OA@zeeZX(K(*0fB6S? zxD_y7aWQAji5I?#Iy)7JpF#I6q#Lq zm*=X-$3=U+301}wU=dpFhxO)~qT&K9xt-F>^QrS|OH}AUiyDysShQ+ij&#&CVR1Id zJc#r3jD*AI&z~3FSKwxHGS4ZuGs8MY;tn_r<8n64XuGqJ$BHCgNK;{r#EQfocz&Yc zJw;`$4~nGPyiQNqH=P&c=55c(LmRh@LK_@;&TeaUqm2Ko(zqP+TdzR2Nc5+leP*)0 zyP4fZm6v^ThA2-#TZ2j)bFCXH6OhbSayUD{_`s(1DxGY!MH({`@&>rS4p0XL6`85q#K6G?z=c_dgWOgm#LCi}lBcifGNX^7EzLQpluUK}2R>pj*`y=EGs`=%gE2+i!bf;@Kt#!N0<)bsZDN@)0eFP^sOVk_`b z&>Pgu99;1)cBNxx9kgXdtPG2v|G7%C?!F2m;5F3sSYyOv@gTP^2HoV}q2X~6Hl6Jr zPK(813U&IiFq`Uk4Ee%vGhC~T@K`-K*l$a@t$OblT?u&I9nPo0a;JJO3u|#Za8Sym z`o763?G0P$`F!X6v}pb=rkMvml6j7OHmTIJ*N-Cbz5z=YyZWRSQd#+~`6h0PY4?iR z<)DJfX5r^({7su5hsR02{&heEad#jy`*KBI+NaVvl{mdyV*XF0i>@&5iz)8=fCqy9 zpZ<8BugrexJS=m*lZ_fNs#^Z0sv~^=M$mSE$XWkaVC02SyKlNjMgzLQ^BRC=ih>5# zI^HujBgiAQ+#39UT^PMA56}{^iBdX}j@MUzx06U(O}4%HLzaJpHc6`24cd%K1Z%LPl{iWPs5- zSC^1fq6;qjZDKeP^U5vA{tWxfQ>#a52#(A2t*uqj%ZL8xaq|NBCZwlFx;mYK1Xe## zvimT2zCI8PSlO&tA)YJd)P;A{r7o&ZCkoZIzTL3Y;!R zQKpWJMx-Vp-6hb=xn&(Z{E<6ZJC{3 zB9wXD-``(;|N0t|H`lWeT*j9cG)b@d&eYp$nG;Y)&4=s!6arH=wE`??$ud-MllLb4gOM?kv4Z0rTI=t?GPQ9DqI4|HwMBcZ>tC2ai<`dE8 z!#LG)(;>6B@z*akYAk~IdCn1Kl6jsW!0kP-ImL73Itoj{Xi+_>D%cc1t;yb@qh z62k%+i1XGM)NkJkHPv!P5e$0B7eVoO4m7F<`VOZT?+?h}fF^?fh-tD^&HvKgD9biW z)k7uyxD1@=xPN>q`aWc?r$R zGco`VgnC||f1acw`Mf-3Z@ZBGCH_6k91sgXqc_U#U9k8|bo}y&-LXT~z5QC7PhRld zIZ)bWU|wD#nVS&0?Yy;~Mq^{ofAuWdhvT#Eiq?P|W0WO0L zBPoZ@NUvW2#_(mTJ>R)qODgQ#WBAf*$@`qhbFnGzopC=o&HC0=n$e)#TJTF&w+klM z7&-jx5CMabK7%os_syH= zzU<(av>b$fY2H3Oyz?=f_Ul3e6ZtyQjBNSVmkX&PGZ)Od1+L?i{i}a6g^xE1)T866 zV7sPb5V^WxKlbD#%KVmpU3l>kso~nmdEB`y+?FAXp!QtrGOFEK1<^zlA7W+6~!H*M-hEK(rH)5TU z8B3PxN7sjn5igI;PYxKBa~({TsdaT$TJTGfIqf#%IPDdc7`$|;nW)7=;^?R780%E# zCQD+-M4en?&wiaRg-4T1Cvi$fP5l1m)*ngMG-)|)GBY)l#9m{( zfu?=Mnr-RH3qkOBr+Gku)`1#~q>1plhLjeI4i$3v2=pOHDy^9hG{E2&eXpy35RQ3IDffz%(0aAMKbX1%<|-ntj@D0n2DXu99* zTBulL$*gv~zbTI@|1+B$LKTS7x{N!U2h* z!0_0p(RC-b2h<>mLwsmC3A@m@=4d^W(5$gs(1`j0tndX9Kq6}%a>bDNxD+XDiAQBp^}=R2WW{a0F(NCR;Ux*4wC zZ>u%df1a=IDKFBtt2di4i;u-T7Q`bt;Uov@IX6tVa<_{QM%^w$zl)8jz69^2(G=+foLeloSrD<)h$-@l$bDXJPu3! zDYny7G>TX7`|+XJ*eOB#(ee3|dkS}vO~ywWtLE9c?{KZoBk8{B6A_U^rqtKuyFFQ2 zGGp%@J!3Js+$oCviDmm+qa*!wITeFndwT3p5)kD})F%xEJg#=;x4A=Lz09D^4T4J~ zV=4{~gRZ)jE{E8b)PaiioSNtbNa7b06GRyZuFq7xuQJO^^r6^S5u5RamXt9 zl)POwSvLv-S(=-~!x0w~sxmZ3m3Pl9=RM@Azboy;Cet z^*+7@Gr$z|-z;%n8ovuHRJ_G=X&1A zv}2RQ{;7Sh524d<9uM+?1p~hBjuG`Fx*0 zeOozgDuYb)bRkk&V{XOccc zrdq1iAM-vBkx`RfX8;(31b*q78$Qc*#>97)jceyW*mQ{gB9T%YdL7cLnPNal7Jjgo{= zF-CPsk&&^p zvr`EA)2*E8Vq4>$Q?kF*T1Mi1HFJ~;JQ&CY+}zc1x8&%0r{&d_Xw1AlF7Is{H$P3R z2@VaN0N19Ki}M}d*__QURhy3xFQA~;HfA^-PnIBEKS6&|K|Vo5kE^>&Q15m30B%^J zjaV&I%K35v1F)E8h;p+UGq6GOtc5D$?ScU;`kT)O+^!7Ussi|!J@wV>>C`2f&iA2v zzvR{iBgxvYc(2b)hpk(8RxlbhV#BW7LZv99aqgLQiTC%TvWc3UO!ux%(MkC4Y;vL; z=BHG@t!Rzxaq58P&@E=+dA(#fO>hsi?^`LRrneM1S zpm)!TREPW+bSERTdRLW8lMVB!(>eoKJx){;xlA*IacD?K#)yyJ?q$%amYQ4^LV;?r zbGDCe*ZVcO$6b8)IU+DnZc4VXNF@w^dvtH5`ZnE#GJEyWXx8s_6$#OB;&GrEVwRv# zqlD>fnc{z>3z&P&*1=2V0CbYkKE*uNbXk%Z`jrAg&Pwz9FMhLC)@grb!xo@AIa3U0 z_!>*=nq@<-&x@w=7NSERZ&_a!#=BzCl1FPbyU=_Jpk@wF9yoKT{v!bcg0&=QM?@jY zR-hRFmBE&{>yu76UiI?A~Hvt>7S!Vyp9q8f6xIPUgT(M+XB}$rv&WEdF*i;pdG^ARNQq#!0FC*Bw#Z;nYNx-KAj>4=+!}^)-DGXmp1>b3=;dB z5dGOxXsYM+$;hntsZ(#=+kpr|PTJ@`gDrNzC2q9|kU*x(zd+BlZCYDeP#L+3{N|{}ad3OfERTb|^&=yvwMjZyfTm+vdtLYK; zvs?XisOLyvAj(iYtLCfsMoI&Zr&O1s^RR7}eSuxFzI2xy1KLN?;pQQR|8*$uKES_g zB+vC+CC3(5V(2tQ6b5h7!~RrLS2TJ|NXyI1Z%;Ml<#8Guc{!8iLW^M9*?tx{bkKZ(F(R|qIe!*k1IU&O9WgJf zjRF1^zxloAs;$TL8n3Xhu<6*30wAAHCSm+8as+i26*t6l)b33yn&|BPf7r7B1Or*! zIBzmL8X12(K&x7uZ!uG8+Ox}PXKNb?ypLCCkD&P)(n+;e(25nRVt;R2meNUj4HM8A zRioM=fxJNZslT^t^6llhK8Oscmn5>+C7QpLE!Apt+bdL7PZJE-oz2VIkg^b^Q?U?* z19`RqZo3x#;($xyKOu9Nq2~P~;}Z>%s=^||vo&e;?8z&^kmcm*bN^mJ4XrG~0>5$Z zgdEnL$pRqdCF{DOF*qBVrOBM&_$VjUSt))EWA_v6>@Z-#S1vRNB0rDjv^RQ2z#{hm zmtpf9*_$Wo^Y1PDt3mb4RGu7w3Ff3$+4EIp6W$w70@JBR&+mFw-Q#f$S~NG4-}@k( zlJE#c%FADs54h9N;_6=787kK~S<>q?N)fPGPeRd`jLO`tdn8B#;*%?JRlSh*8iM))CC+ z88M#%Fpa<5t(~1VT?~17q2+f^H5xs>0q-uKPPNReJizMJh>r`iHPGrqNsS7# z8ec!ZQ?og?BOCkilDWE?&r?>nY}PG>s-BDQNQCA^)OQu5cGxVWeo@;yIjJo2xPpDJ zF&$7*F3{>5`+ju{>xOF}d{&d!X`P}h&Wk)L2fPLCx7V6~?7;IW8myDtgcT1xD9F0>o!QhzcoK6mfYar3{QPuK~xe>q`yv-e6eCs z6t3bCo(#j-`P33{@y7`%txQXO@nv(h>A)lsQTxRyw`%jJ&nt^Ir3wvE+Y`kF@GYE} z`fRyq)3ZWWQYwEo*}li^Y}Q}BMXOSs5AbGQ%)J_wtOlETtkH(%Qfk^($S2)x2nOF6 z6^SP`5T{pRBJimLqpuG4tT{b2Jsi!aR6>lTEf<-jOTeM1v@jg}|wh?At=! zveG;4Rsqn{yRLa*uGZ0j_uZM1PfaE$9_k1fXIfvwJv*1bkLc z1;_UKVP={~>Q!vJ)}{rLu^B9UiJ;kTpL z+SRUePLM_B+`Z)YqUg6Lo#(NU0)(84Q)Hqh2Vg|!-LD7k2qwJ+$o$d7U4B1?%lEo; zqDgll)C^jjusu;~xKS5dJ#m*xzO@rc28D$P;4``8XUAXSh+>fB((ud5+Hu33pU_u9 zKxrEBdwU-bFSrlBdGkg*7UIc0;qhzZyX(q2z0ndV{SDML+W>$^Y_NGq@2>qtIVUac zw*1#;@k2&cuHc{ZtAdh8rl)4y$IbjWiLiwxW3Lt`?c*m)(MDA>7COMQ zY>+>WjkQZ@a$tR|Rj=n&)2aFQReg1_7g?5*1e$LJzx?~b_eMjtZ;vrhnBaeUf3e8f_vozWWs!NE?BCJfYqz$S z!muMI1MfX89d%s5L#2lwAKKTAxFr~m+zxphuMZ*3X*IY(=g-2<{=N~ELtt^w`F8kytb zA}qsnhizS;(_hn)fSB0o(xalIqhm1bbkF$Zxv}SUg7p%5&5sJ@R$!n$?}P1^O!)r& z`EhUBY4z-gB)vug1`((JOFswzJlU)GhC9|APB+f${jBDi^m7gF5i?C1&yGQWA8eSX z<3SRPlKi6e&Au#fuVyS{nvN|GE7#V+uc-pFR@}7*AA6#!$Ls;AZ_vr=VLQhnB-AgR z%CCUGqzYD`NW=H&J05&W(YaEr@a6B8j2nE6eih%@(V?KlzzM+3Iyl9NBiEM{vrCn@ zfOXpvg|lu^IGC89_#Cf7T{rf5*9TNf$<^7oxMn>ze`4C(*aSi=?Kf`US{jOKp`x)| zr*g$?vQ9^?EHt~0dtCgKKL%KmD4eV&=j~L=%WIafPXj(R(cP z2V&fjk&#Cj_31n8R{2`5WCsXUYU8CSiFm!Vx`VN61_?gBOIRhb5dh94a8>Ui9-eF4 z$_?uS#;zX~f?dsyP7e^Awk{KrX}AZYXZV=#}Ov_b08m zHDFgezM&QX9id_$fDk^}zM9>AiSvo2pa1m-z$e8}*yFrpRAFh?ijeI9K(j~kNLo*p4dYXm~UDwA9k|`uaR@3wUB&7SFK#?6RX|SiMXqcJ1h_o z4kq3-pdg5$dg}8G$CfMg4AJ3;_W_ z45O^pRb6LoAV-4}p>5ocj~M|$mOUy2;Q)n$AQ@Wd`W`Y{8)mouGjeemJf7Vc+3BBa z_HU2+3nPP{!~gNT$HRGvK#ba%i5StOS!cBsP{42cv+V(}Pm{}8qK>;4K}c(Mt3NaB z40+a;_pR*tF)=Y`E6nRahD&L5-UvX1JhUrY1sim#Dh-u}7FJb&R<>MfPz2J|pGx1v zGruqa(v^#zY_MC-6s8ZvMc)zvzeuSdiULd9o1I5XGOp~`0KF!yX!vg5K1|(i|HidM zyH00;|Bf0W*#7WvCkNU%SGTshYA`k40K7>M<5y}&ME(JA)xZ(|oksRYm0FrzmC9sNlxB3@vSixi&vYbLXmx9g3zbTLP#$)dWznhJX91o%AMi@aU@5bs zvS$wfgE0=!xZ~NpD_}?EV(3(q)+Amk=j#a+*@aiXAvV;#Y))&fwOV2*J6cnQY#;X# zcgmlgk*weF$-aa%pLoRdYqZ$KWJ*&)rqf&O)&@;!1T`Na_~c>r3IAqhKkV%Tf*O)@ zT;+I;4jcmR(WA2Fc@46FXED*y(T3_aVu5@+x&=PIUsOke)YmNQXz5#!) zDw#jk%%|B($E4ibcaqjM-efbLynT~5O){WU=O}L4d6jz-;7iPg8c#udBpH8FHpKvo zSmwr!MjY;M06I-oPwqQ8O>0rn)#-Ktz#){4Y3i-RPz*)yu@QbLg_PNvw*x@QN-GyB ziObuKPI8`&pS(IM{e9X+iM!%Wxs61)wppVTwYW1+GX$8DolRgyR#hsq0VOhUiH`7r zwgT$k>Udo%as#8YoNpF}bCsGj>_j{cV(<|R4-a429lVCjt{Y0aiq1ZdCJGSv{BTBe|mjJi4%I%9uw9GZ~G>{uC$OGg=0%MA_( zT~tWh=UqV4YFv)sm*_Ndv^Tcm4#qWU(ugYP}w9sgHd1ecQuqhI@L@kXcH#zz<=8F1dICyW4){2#=}f|ZL-fmaFL^DDht z&BCA;?|pAPvQ^dM3HAQ<{I<#LTP472lwtQOqw=G%^|>->r47gH<{+g6xan1IM}G8C z^o=xrIyQo+-6Km{$kGAtzQ$$7E+8rd1TjdQTxCD^MyQtHLrWHI1ZS(18Sk}D>Uuo5 zbr@MK@>_WM6@RS_Xf#_iJVGbR1rEAq)S)dAualNyuC(mwg+wwSKp~ z5*dx#-(J2#e~$xn+!L3?r9(QEP5aqSYdYd3mXikB@S|5~%=`&jTC3`_f&eDPlJ6~6 zO)2cxAwR`-xP-H~WgxC%8q+)g+b-OS_ErL90|@ac0X+~!zBgN?s$OX@>Tca?dCK+~ z{0ahXfx!9g=sX$msCNzZ)aH|KW77bplZXO*fkh3^UHN-kVZ5+e5ZA(IwV0Y{h%xL^#r4N?(4*&C+`3_!?C6)M4B8$oeZVH23VShY-$v< z%t94mZ#Y-{v~i|Pn~u1)r2SfdPP6OL^i5ylY3u5r&dG$$O%oz++mG#U-mp#emSr8< zwmd{Qu(7Cl4A&KpJv=6EvoPS1H?^yNAd5O{{idtG-T;bSquRyP_jYF7-v!YY7t z?&p+vsL;ih63E&M^Q5lKUYH~S9Q98WO@#E60LLwr4dQ6*(x9(B;FA$#IYh(lMv>g+tIXB+}ygJc3D}aABTFjIOokryw zonfirDPkOPT|0X^(B_${Rm=_Xfq)wK5n@hG@fx$q@8pgibs;^W_cHuax8jU77CFe? zccwJlu!wJk3+0is&Tg7RI#xw0Wi7d6q7mwQBPJ}{z+)-&iZ(J^+OmX9H|GE^OGsL? zZj`ZVL#@BY?7UILlXuc=4g?De=khC5%CyaE=2KUQPdKwn7x?5mjp!%VvaHO0RX4N{ zvd%{R+C7qIzlAsykdl%r)yaRRS8wSk-6QYo?iPj?Dvf4RJmIbteclMtuj#l~Wr;+*D!LE56*)~}f$k7-7uXI=!aX3b_;<GsdB)_P&Ul))W-BXZYj{sDT&ed{OcGyMwj-|f$4FW`dkm~Q zy=-n~@jQw!8*fzB_-d+n(_-i1Qg5};La(Z-T4Z;2X1Pa?+iLk@uDA49pA0hA;WH(_~Z=T8jo$I0;;ZZv!I|mHh%^oklGDzeV!JqI?;2M?nIIazmzb zRA-pV(OE1x=vFEpHSwQ8?}Y|?(Wn!x$zouvaKZ z`GG9l_CV$Cuh0PN4Ch$;fCN><~h(os5er!Lf(t zw6!4}=M~>Jvf=#48dS&C^7bT{WOkAr$vH-Tn(&Dp0dS*F#H2@b~-FZ~UfFgglHqa#^< z^SSVp?L%>PORXvm?>jzKV7_v`eRO(N-4uJ*AlLaAW3oD->P0g$jW}ne zaa}|5UopX5*FqvzG#>7D@CnADH?zNGU!kI&vmX(U`k!HP@k$2^z@A5~RvfMNl>k;M zHt%Ut^MqJd0LJ)-<7vj%?(I& z(>R;@D5+1$bCc?o$Ser(;{=HOzFmVGd@xlg$Y^HCzuy4c5*%Bqmf_6ptZ+T08%_R_ zPD2U!K=|+UvpWxg3Hkm#$!xT`fMWf8$y1bpfuTQ{CYrp!r9vM>TH;n$$pOh9rGF>V zXNg;+6!aoWf6>7Lq%m}+A!7iuG8oUCwFY}NFtVg8=pXUDT~F>jg0K2*D>hz!Sx@-* z2E@Ik_7}LtDs1h zELnvn2gx~@03~P1l5>#Ml2KGLNX|hC4Kx`VB)?Ut=bZcQxMSQm-u?5&c=ZRh%dV2}V*sf`X?*CJwGnQ{Q2$b`<$pWhk3ErxMCdtF2d>JSZl zJ4IDjW-=H)>|0i(!^4V-ikvrTg5J486+!~i_P1}>vv-acqfscw@}OVSCthV^ejuF1 zP%Z`s*_9=9wx;oWwpw-;D6Dhqy)n-0rmB*P5v-hix026CoxOr^v7q>Bj7*vhm6r^b zTI2$Tw;g{MxIwet@s%xx$KsRt-u8}A>w#UV7~kFVMF;N!A)4Y|Iost%xWIMrU;E&B zE>KXUS)-ecmiCXTqJ2r&l9KE7yq*f%@4ie*PVUKgh7aOXNx;O1e$v^X#{Abt63NA} z-~}m>89!~CWpmP$_{q7{4x{d2r!}61NcEtvSYE|5JUlFK5$q*p7Q`X$w z2?z-~3rSe?2*60(L46nv{Bk!u*Iop>(b6U7G*S2m6A%%V?z->YE7;xL!|Pz%R2%Oi zZ{SiIGAqde%KnPQfCki-)n3?U4I`76RdQU_#j(r>kuf{5bpTg7vJm=7IV9UeYd@zUF{JVay`pv5kLPJzH9^hTmpPHUfsboc4Kz5LOB-0g{U^*m&R(cF5`(`_;N zDhD|oUcbJEfdv_F%e%XD@E74oPz zp~|-@mbv9^)9v+%z%VvV-sbHw(%ma#p^Q9FW*(Ujy;llh6^o??Zl&XDC=3Y`aO0AS z@x#5?f{%aOB!8NJbcdF+%!Z-z%H!)~=cuxJ76r&ID4k$&43~d!wZ>Eg$lEA=trgrO z#f2*KzgWHrx?|$}eT_Ux5qJ^HK9Y%X|OUnv@GV92E zt>CZ%kB}>3$IO)jM()sZv+_H|9!A-vk8o76d1s&+)B#{9bRu8Qo6JZTmn9S5-AX z;4v(eR%Lf(gULkn!1FILt^{D(?=%A8t9v5!PTVbP#R(0H!`GBtO-%=Ik>x zrtMp#&Xk;}k+pYm8R}^a_cb2_8qhfWfiM=E4&~3OCU4MFUx483T4t?LcS1;aV8II+zZhoBg3$0ih*Cro&tVqZr5E+cHb#F6q4sci?(JOR`EKT5xDTv(+C&^z3X!WqL-&HQ8vc z9s>{agO4v@;z(<}GXA2fJ228JdvtrfBaKbdZm%5wEoq}PTd8wDfa)Lapv$W^gB8^< z`-A<`NV@d1+fdojbb&A;u{+Ku7QfxF^ zc!3HNg28;MtHbY2GEofI)L2iqBu+58mbiCaRmoKD;G#GEk4oI)Ldsi4DQ?5I*m3jg zDO8&H)onZ_px_4+q`JkG$1bTss_zDc3EdEM<>T^ec6M^T{nob%QCw)LaI%R6z1OWg z*lRAhJO3uXsxYf5#zphk0VNG4ksKfzW}uE|-6>8dx{8nb9V12ecey)K+%v%r`tu8^ zlB?Oj>8hl2y}|T|X`-e*(1}j?CcQYQHxY?Jp>>DRlD?NZL$jhZn%7;DMKxFT>C*xo z^Pzjx78d2enAy({=8jFbs^PQR8Q)rJITxFsWLl}VozQ1p6x5r^+Xjw5hYHbB6 zUJ*n_gi2D$n#mR5F`b<+v-u;bzT0&Y6$K31ZIWm5`Y>uzB2hC-Bb*u7-w2P|V<0)w zec9oJ1O<2jfiHVE^wKtHc9)FnkfQ!}l`{o?>OuAuB~4z-w3EpSqB2og)NVQ6_wZ0z zaYccPdMNZ2xB}loMO@u*L1Yb*SjUJPBm#X`IGZ2zVJG$ zc5qva{!7cTjv9GO#NE)dFS3&ogK*8TL>e0#B}rJ6zr9tU!>f_aAL{(jd%q<3J8TidA=$CwY#eDN;le9NhK55L$UCMvfl$u{_vkU^_)Nb|HuLiXt136t?} zkDKBIBS-oi+n^f}c4FSB?e9od&XXaR-9bkjN|8F14;ApUTTz20=E>#$6pa1YWHYh* zuQ$W>Xyp7vFJ)FOn7A~5*~B*lBl6-IG9hI}85)=M<;Spn*Qc#(bxR{fQMM^;M?o0) z(r6YSDoE&A|Hbp87>P5ZjOf92CY23Ct|;4;PKLP6HMPX&$G|QfKQ5aEF5-J&U77(O zQ=xua(vL51L@vsc9|yesFQMg}8*TzV2i-o)&(IjG7%I6+@*^TMS&K9t`YPvOEB#7M?}x(zPKI9fz&duPLm+cvGY~Ik1VPDc3^20s5$qkLl#S}56pfToD@+e zEqgU|_b7V?c%LP8y!Cz&SRtlofl_J`9ej}dDiN&eW)Zl7B^%JRq-$EEjn(gI9uG`LoAR+ts%Dhi z8ikG~qH05p1Q2@PzO7w;L9i+plBycqXqR9tqXuw-NsV6^!SukWLfgq8zVv(d4V1M6oQUO3jYQQ6ZMHSt^1~1zX!$Z#jN_*B1-~k)u~6Lo7y!RQepofX;PL1$4*OY}`C#kp{P5P1)oV|}Cg4V6*C-AZ3H9}tkRBh38!|Se)6uoLg5)zWQ zwhrV3I2=Qu%0rElPuR?d(KB&zDWqAsLJw53Wl%v;QI%R1w7%>J(x#KU0 zL>+yJe}6uI+nN~VY1j~a-f+_FX#{1|2SK9!BU+2_@KA)sTq1sP^H&d)$ zo@H=-Ovu+DRK418x093k_xH%31H}#{M7PU+d=@mp9e!?Iu)|t7(rO<0eIXC1Vo=M3KD<%3^ONdPNq`V-tV044L=uP;exKvm z`Ri$)PVXMOD^6yf#~nkTphxKc`(7_Q9bV@6B@rtrx#L5TZbdBwgymT=n7YoJ|GZU- z!&{y51I1Q&f-$r)%!r)v#cc_<_LRr)E)I`)@x$+FiW8d1&&YUb!}b-;8#QS&uS{|G zuU}`3OWs9BE`6AItgA7CQ@Wh`Qj#g(9cs5*zdlFBKP2x2wFb3pWapl%@*J%z8=aYU z#w6Prop0-N^4CeVp>O!$_53;dUm*ki=cquQ^w05#6uId?$NU|*_MgKODgOTa1yvyJ zwN3ewRo6dd@8l6N+j zG}*ZS2uhP4Q;VY|VW-d5q<0y%HJR~h=8A$@6J#w@?&B_c$B@_CA91DXaFU{gMg^*e z?jnFRez*(|bfxoNj~Y_LN_K)x2XT+FHr7A6>ub`I5u7!n{jqQlvDI;zM-%--$dVBH zs#R;#Gh0vI0f@aHqEX_ajr5xICEt5kS^?xCaQuD1W+M1lveVSkUbzIDeGLp+h*s)% zFIj7Cs;mFNzc+8Bg2!~x64DN^rN8x3%Yg*p_lL_YCKbIc;T3<^0Dt)qPV3)>=#Cp!Ty57DbOh=x;jaA zBE`=*hr~=vSrPNX;$yWO_^6fkS%7!iXH z=1zz*co0a~6vaJuOYUPVMpR#Hfo23> zK0VXTo8oeX9ID8*Zms?fbRjAQw~l0w9ewefUeY&`y$kx`&WCa66lc(b>}J&FXAD(A zwd!8cz3kqcU?7isn8SG-Z+VnelrcEVBzG9uI4x?GooD4HBWw!#XiwTV`tUH!G}8SF zK2IOU3vr&RKC-tx=Wm~XRh<`rvdGei^qw=mJE{l^EhQKCxUgz&B1S$DtXe@c_P~z} zYAsGqhMBn<*fc#koYVBJL8HHdSG>@og#}Ec!E!h6o>kCi?c8g!uO0}=hD?I3ZLo4w z2Ru072|+0FxsBUuB_^XX;IIWQQZi(9vMDvYFHd8k8T&2qhCc~13_(J_Q-SwXbBr3e zA;bh7mXMN^H z@5|E#6MmF(mVTr1n8(YGYoel}l8VM>&%#iqZ*%^r0GmcqQqno?1n3qm`|v?%^(J+y z_f`ccUf__7peJca5S87(3bHrE>8D09X67(v6M@vY{c zd0JJ_Cy*i&#RbhhLX8nMpg&uTmNQ5;#V`hPp_|q-#9Wz$1F+K|*K1dT<~XTdzOF~C zq$RH;c)4T*6#c}+#E|&vgL)dnSu67s;NUuq{<+%mwR2*hE&% zGR5;Au{m6+(zyJsn)K~`j$_BO+^`Pxk}-XG3h_c^(0a9Ex6rE%GoHR&M9hm2=|u%{ z0{>)h+hqApl?1htiObuXq0BDB?#$+$kQAQg$Smkv3#1ii5xeKt-KJeZH8>4?MR&eh zyTk>BLBXfrBu1P!Lg>wZ8iqqem&W=~i&Bj(B!Tw@$kBi_x#+iMTe*Vv83*rRToOFq zrU;an3eWwWAQd=K=Ja!!SXxGq&-_8D*+3^ht?A)Y?^(|CX;c~H(t|pH#W%N$rrLzLMv;hmD;in4rzXB?uvLJov@LG43tHYw z^tT9L+UM{?A(qK)xL)^iDQxx>4LjZnI~OfK7D#ERHUJ@1N18ywN?q4dDq9X^GD4kW*3RPE=PTUhz6k7>n2+?JEUiuad#4 zmYErPH47S|LsE37ce8wad?f5E!Sfp@WG4j`_>k5?!Pv*T-H~%P;D4do#PLdcCLUb&86xpJA!|CCr^??o9m_kzuBfBUNM=@4L*O_b%b7J|! z_f`PQo+mbFgfhsB3`}A8Rhxke%$b&@$Od;Es2F!taln^mi|n0{3gOMy%=VAr#pQpI zMp6yPZs_Y|Ap1(6pQ%>$hn+8hyA>yfw%H81$Bv zuCCiRwrSaSR584}HC2LvzU6}lH}@%S>8ohnSJqPatfgpE#ugDBE$uwiJZCa!5wjp# z!i5{X$dcRLlDgX4)6L5Fw_5l8VXHcA8?=?$-+u>v->h%Y3L<~|xVm=Ny*eTAM4-2O zUy*Bjl#{EdP1_ZNRtk~bpGv?Q*G>eAd=j**v=Hv?;kssCH4qvZSzmL&{Q`(yt6gzg zCnqOICnqbtwUe+%hWcW%pmwJBuKmQ)Qu~`P!8zKPfcIm5*l)Vt;1LI9or2e>wgEGi zr02cCyW}yqZahl4cZHJIoc+R00;0S|?iVN48eW`z#1-Xe`t$z2pD*2-302Fs9eYi? z?k(Sod|V4dugwAi4JR`?P`j&3vXx!>H7yF78Q{kFfv>XnYq&d%1#ypkB%`sWEp z#|!(dY1vy9wzKDyJYw5g)Qe766+@!os&Za`^m)kg2M%Xiq%|Bx+)fxKtBaF5SZcD- zy5!PspgxL8*|5­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 literal 0 HcmV?d00001 diff --git a/lambda-durable-human-approval-sam/example-pattern.json b/lambda-durable-human-approval-sam/example-pattern.json new file mode 100644 index 000000000..2f83f0ddf --- /dev/null +++ b/lambda-durable-human-approval-sam/example-pattern.json @@ -0,0 +1,112 @@ +{ + "title": "Human-in-the-Loop Approval Workflow with Lambda Durable Functions", + "description": "Approval workflow that pauses execution while waiting for human decisions, with automatic timeout handling and callback-based resumption", + "language": "Python", + "level": "300", + "framework": "SAM", + "services": { + "from": "apigateway", + "to": "lambda" + }, + "introBox": { + "headline": "How it works", + "text": [ + "This pattern demonstrates a human-in-the-loop approval workflow using Lambda Durable Functions with callback operations.", + "The workflow pauses execution using create_callback() while waiting for human approval, incurring no compute charges during the wait period.", + "If no decision is received within 24 hours, the workflow automatically times out and rejects the request.", + "When an approver submits a decision via API, the durable function resumes from its checkpoint and processes the result.", + "The pattern uses DynamoDB to map short UUIDs to callback IDs for clean approval URLs, and SNS to send email notifications with approve/reject links." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-hitl-approval-sam", + "templateURL": "serverless-patterns/lambda-durable-hitl-approval-sam", + "projectFolder": "lambda-durable-hitl-approval-sam", + "templateFile": "lambda-durable-hitl-approval-sam/template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Lambda Durable Functions Documentation", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Durable Execution SDK for Python", + "link": "https://github.com/aws/aws-durable-execution-sdk-python" + }, + { + "text": "Callback Operations", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-callback.html" + } + ] + }, + "deploy": { + "text": [ + "Note: Lambda Durable Functions are currently available in us-east-2 (Ohio) region only.", + "sam build", + "sam deploy --guided --region us-east-2" + ] + }, + "testing": { + "text": [ + "See README.md for comprehensive testing instructions including:", + "- Creating approval requests", + "- Submitting approval decisions", + "- Testing timeout behavior", + "- Monitoring durable executions" + ] + }, + "cleanup": { + "text": [ + "sam delete --region us-east-2" + ] + }, + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "apigateway", + "label": "API Gateway" + }, + "icon2": { + "x": 50, + "y": 50, + "service": "lambda", + "label": "Durable Approval Function" + }, + "icon3": { + "x": 80, + "y": 30, + "service": "dynamodb", + "label": "DynamoDB" + }, + "icon4": { + "x": 80, + "y": 70, + "service": "sns", + "label": "SNS" + }, + "line1": { + "from": "icon1", + "to": "icon2" + }, + "line2": { + "from": "icon2", + "to": "icon3" + }, + "line3": { + "from": "icon2", + "to": "icon4" + } + }, + "authors": [ + { + "name": "Abhishek Agawane", + "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", + "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.", + "linkedin": "https://www.linkedin.com/in/agawabhi/" + } + ] +} diff --git a/lambda-durable-human-approval-sam/src/callback_handler.py b/lambda-durable-human-approval-sam/src/callback_handler.py new file mode 100644 index 000000000..4af1978a2 --- /dev/null +++ b/lambda-durable-human-approval-sam/src/callback_handler.py @@ -0,0 +1,148 @@ +import json +import os +import boto3 + +lambda_client = boto3.client('lambda', region_name='us-east-2') +dynamodb = boto3.resource('dynamodb', region_name='us-east-2') +table = dynamodb.Table(os.environ['CALLBACK_TABLE_NAME']) + +def lambda_handler(event, context): + """Handle approval/rejection via API Gateway""" + + print(f"Received event: {json.dumps(event)}") + + # Get UUID and decision from path parameters + request_uuid = event['pathParameters']['uuid'] + decision = event['pathParameters']['decision'] # 'approve' or 'reject' + + print(f"Processing {decision} for UUID: {request_uuid}") + + # Fetch callback ID from DynamoDB + try: + response = table.get_item(Key={'uuid': request_uuid}) + if 'Item' not in response: + return { + 'statusCode': 404, + 'headers': {'Content-Type': 'text/html; charset=utf-8'}, + 'body': """ + + + + + Not Found + + +

Request Not Found

+

This approval link is invalid or has expired.

+ + +""" + } + + callback_id = response['Item']['callbackId'] + request_id = response['Item'].get('requestId', 'Unknown') + print(f"Found callback ID: {callback_id} for request: {request_id}") + + except Exception as e: + print(f"Error fetching from DynamoDB: {str(e)}") + return { + 'statusCode': 500, + 'headers': {'Content-Type': 'text/html; charset=utf-8'}, + 'body': f""" + + + + + Error + + +

Error

+

{str(e)}

+ + +""" + } + + # Prepare callback result + result = { + 'decision': 'approved' if decision == 'approve' else 'rejected', + 'comments': f"{'Approved' if decision == 'approve' else 'Rejected'} via web link" + } + + try: + # Send callback using Lambda API + # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/send_durable_execution_callback_success.html + result_json = json.dumps(result) + + # Use the boto3 method (requires boto3 >= 1.35.9) + response = lambda_client.send_durable_execution_callback_success( + CallbackId=callback_id, + Result=result_json + ) + + print(f"Callback sent successfully: {response}") + + # Return HTML response + icon = '✓' if decision == 'approve' else '✗' # HTML entities for checkmark and X + return { + 'statusCode': 200, + 'headers': {'Content-Type': 'text/html; charset=utf-8'}, + 'body': f""" + + + + + Request {result['decision'].title()} + + + +
+
{icon}
+

+ Request {result['decision'].title()}! +

+

The workflow has been notified and will continue processing.

+
+ + +""" + } + + except Exception as e: + print(f"Error: {str(e)}") + return { + 'statusCode': 500, + 'headers': {'Content-Type': 'text/html; charset=utf-8'}, + 'body': f""" + + + + + Error + + +

Error Processing Request

+

{str(e)}

+ + +""" + } diff --git a/lambda-durable-human-approval-sam/src/lambda_function.py b/lambda-durable-human-approval-sam/src/lambda_function.py new file mode 100644 index 000000000..6120645f2 --- /dev/null +++ b/lambda-durable-human-approval-sam/src/lambda_function.py @@ -0,0 +1,128 @@ +import json +import os +import uuid +import time +from aws_durable_execution_sdk_python import DurableContext, durable_execution +from aws_durable_execution_sdk_python.config import CallbackConfig, Duration +import boto3 + +sns = boto3.client('sns') +dynamodb = boto3.resource('dynamodb') +table = dynamodb.Table(os.environ['CALLBACK_TABLE_NAME']) + +@durable_execution +def lambda_handler(event, context: DurableContext): + """Human-in-the-Loop Approval Pattern using Durable Functions""" + + # Parse input + body = event.get('body') + if body: + import json as json_module + body = json_module.loads(body) + else: + body = event + + print(f"Received event keys: {list(event.keys())}") + print(f"Body: {body}") + request_id = body.get('requestId', 'REQ-UNKNOWN') + amount = body.get('amount', 0) + description = body.get('description', 'No description') + + # Get API Gateway URL from environment or construct it + region = os.environ.get('AWS_REGION', 'us-east-2') + api_base_url = f"https://w8a9tempjb.execute-api.{region}.amazonaws.com/prod" + + print(f"Starting approval workflow for request: {request_id}") + print(f"API Base URL: {api_base_url}") + + # Step 1: Validate request + context.step( + lambda _: print(f"Request {request_id} validated: ${amount} - {description}"), + name='validate-request' + ) + + # Step 2: Wait for human approval + def send_approval_request(callback_id, ctx): + # Generate a short UUID for the URL + request_uuid = str(uuid.uuid4()) + + # Store callback ID in DynamoDB with TTL (24 hours from now) + ttl = int(time.time()) + 86400 # 24 hours + table.put_item( + Item={ + 'uuid': request_uuid, + 'callbackId': callback_id, + 'requestId': request_id, + 'ttl': ttl + } + ) + + # Construct API Gateway URLs using the UUID + approve_url = f"{api_base_url}/approve/{request_uuid}" + reject_url = f"{api_base_url}/reject/{request_uuid}" + + sns.publish( + TopicArn=os.environ['APPROVAL_TOPIC_ARN'], + Subject=f'⚠️ Approval Required: {request_id}', + Message=f""" +APPROVAL REQUEST + +Request ID: {request_id} +Amount: ${amount} +Description: {description} + +Click one of the links below to approve or reject: + +✅ APPROVE: {approve_url} + +❌ REJECT: {reject_url} + +This request expires in 24 hours. +""" + ) + print(f"Approval request sent. UUID: {request_uuid}, Callback ID: {callback_id}") + + # Create callback with 24-hour timeout + callback = context.create_callback( + name='wait-for-approval', + config=CallbackConfig(timeout=Duration.from_hours(24)) + ) + + # Send approval request with callback ID + send_approval_request(callback.callback_id, context) + + # Wait for callback result + approval = callback.result() + + # Step 3: Process decision + def process_decision(_): + if not approval: + return 'timeout' + # Parse if string (base64 decoded JSON) + if isinstance(approval, str): + import json + approval_data = json.loads(approval) + return approval_data.get('decision', 'unknown') + return approval.get('decision', 'unknown') + + decision = context.step(process_decision, name='process-decision') + + print(f"Approval workflow completed: {decision}") + + # Parse comments + comments = 'Timed out' + if approval: + if isinstance(approval, str): + import json + approval_data = json.loads(approval) + comments = approval_data.get('comments', '') + else: + comments = approval.get('comments', '') + + return { + 'requestId': request_id, + 'amount': amount, + 'description': description, + 'decision': decision, + 'comments': comments + } diff --git a/lambda-durable-human-approval-sam/src/requirements.txt b/lambda-durable-human-approval-sam/src/requirements.txt new file mode 100644 index 000000000..8f4105d97 --- /dev/null +++ b/lambda-durable-human-approval-sam/src/requirements.txt @@ -0,0 +1 @@ +boto3>=1.42.1 diff --git a/lambda-durable-human-approval-sam/template.yaml b/lambda-durable-human-approval-sam/template.yaml new file mode 100644 index 000000000..cbcc40fe8 --- /dev/null +++ b/lambda-durable-human-approval-sam/template.yaml @@ -0,0 +1,176 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Human-in-the-Loop Approval Pattern using Lambda Durable Functions + +Parameters: + ApproverEmail: + Type: String + Description: Email address to receive approval notifications + +Resources: + # DynamoDB Table for Callback Mapping + CallbackTable: + Type: AWS::DynamoDB::Table + Properties: + TableName: !Sub '${AWS::StackName}-callbacks' + BillingMode: PAY_PER_REQUEST + AttributeDefinitions: + - AttributeName: uuid + AttributeType: S + KeySchema: + - AttributeName: uuid + KeyType: HASH + TimeToLiveSpecification: + AttributeName: ttl + Enabled: true + + # SNS Topic for Notifications + ApprovalTopic: + Type: AWS::SNS::Topic + Properties: + Subscription: + - Protocol: email + Endpoint: !Ref ApproverEmail + + # Callback Handler Function + CallbackHandlerFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: src/ + Handler: callback_handler.lambda_handler + Runtime: python3.14 + Timeout: 30 + Environment: + Variables: + CALLBACK_TABLE_NAME: !Ref CallbackTable + Policies: + - DynamoDBReadPolicy: + TableName: !Ref CallbackTable + - Statement: + - Effect: Allow + Action: + - lambda:SendDurableExecutionCallbackSuccess + Resource: '*' + + # Durable Function + ApprovalFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: src/ + Handler: lambda_function.lambda_handler + Runtime: python3.14 + Timeout: 120 + AutoPublishAlias: live + DurableConfig: + ExecutionTimeout: 86400 # 24 hours - showcases durable functions benefit + RetentionPeriodInDays: 7 + Environment: + Variables: + APPROVAL_TOPIC_ARN: !Ref ApprovalTopic + CALLBACK_TABLE_NAME: !Ref CallbackTable + Policies: + - SNSPublishMessagePolicy: + TopicName: !GetAtt ApprovalTopic.TopicName + - DynamoDBWritePolicy: + TableName: !Ref CallbackTable + - Statement: + - Effect: Allow + Action: + - lambda:CheckpointDurableExecution + Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${AWS::StackName}-ApprovalFunction-*' + + # IAM Role for API Gateway to call Lambda service API + ApiGatewayRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: apigateway.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: LambdaDurableCallbackPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:SendDurableExecutionCallbackSuccess + - lambda:SendDurableExecutionCallbackFailure + Resource: '*' + + # Lambda Permission for API Gateway + ApprovalFunctionInvokePermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref ApprovalFunction.Alias + Action: lambda:InvokeFunction + Principal: apigateway.amazonaws.com + SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApprovalApi}/*/POST/requests' + + CallbackHandlerInvokePermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref CallbackHandlerFunction + Action: lambda:InvokeFunction + Principal: apigateway.amazonaws.com + SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApprovalApi}/*/*/{uuid}' + + # API Gateway + ApprovalApi: + Type: AWS::Serverless::Api + Properties: + StageName: prod + DefinitionBody: + openapi: 3.0.1 + paths: + /requests: + post: + responses: + '202': + description: Request accepted + x-amazon-apigateway-integration: + type: aws + httpMethod: POST + uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApprovalFunction.Arn}:live/invocations' + requestParameters: + integration.request.header.X-Amz-Invocation-Type: "'Event'" + responses: + default: + statusCode: '202' + responseTemplates: + application/json: '{"message": "Request accepted"}' + passthroughBehavior: when_no_match + + /{decision}/{uuid}: + get: + parameters: + - name: decision + in: path + required: true + schema: + type: string + - name: uuid + in: path + required: true + schema: + type: string + responses: + '200': + description: Callback processed + x-amazon-apigateway-integration: + type: aws_proxy + httpMethod: POST + uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${CallbackHandlerFunction.Arn}/invocations' + passthroughBehavior: when_no_match + +Outputs: + ApiEndpoint: + Description: API Gateway endpoint URL + Value: !Sub 'https://${ApprovalApi}.execute-api.${AWS::Region}.amazonaws.com/prod' + + ApprovalFunctionArn: + Description: Durable Function ARN + Value: !GetAtt ApprovalFunction.Arn From 71e56b5da9656a6d47b0dca616ea24b5ab370bc2 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Thu, 4 Dec 2025 18:47:27 +0530 Subject: [PATCH 2/6] Fix example-pattern.json to match serverless-patterns standard format --- .../example-pattern.json | 60 +++---------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/lambda-durable-human-approval-sam/example-pattern.json b/lambda-durable-human-approval-sam/example-pattern.json index 2f83f0ddf..76e513c20 100644 --- a/lambda-durable-human-approval-sam/example-pattern.json +++ b/lambda-durable-human-approval-sam/example-pattern.json @@ -3,11 +3,7 @@ "description": "Approval workflow that pauses execution while waiting for human decisions, with automatic timeout handling and callback-based resumption", "language": "Python", "level": "300", - "framework": "SAM", - "services": { - "from": "apigateway", - "to": "lambda" - }, + "framework": "AWS SAM", "introBox": { "headline": "How it works", "text": [ @@ -20,10 +16,10 @@ }, "gitHub": { "template": { - "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-hitl-approval-sam", - "templateURL": "serverless-patterns/lambda-durable-hitl-approval-sam", - "projectFolder": "lambda-durable-hitl-approval-sam", - "templateFile": "lambda-durable-hitl-approval-sam/template.yaml" + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-human-approval-sam", + "templateURL": "serverless-patterns/lambda-durable-human-approval-sam", + "projectFolder": "lambda-durable-human-approval-sam", + "templateFile": "template.yaml" } }, "resources": { @@ -51,56 +47,14 @@ }, "testing": { "text": [ - "See README.md for comprehensive testing instructions including:", - "- Creating approval requests", - "- Submitting approval decisions", - "- Testing timeout behavior", - "- Monitoring durable executions" + "See the GitHub repo for detailed testing instructions." ] }, "cleanup": { "text": [ - "sam delete --region us-east-2" + "Delete the stack: sam delete --region us-east-2." ] }, - "patternArch": { - "icon1": { - "x": 20, - "y": 50, - "service": "apigateway", - "label": "API Gateway" - }, - "icon2": { - "x": 50, - "y": 50, - "service": "lambda", - "label": "Durable Approval Function" - }, - "icon3": { - "x": 80, - "y": 30, - "service": "dynamodb", - "label": "DynamoDB" - }, - "icon4": { - "x": 80, - "y": 70, - "service": "sns", - "label": "SNS" - }, - "line1": { - "from": "icon1", - "to": "icon2" - }, - "line2": { - "from": "icon2", - "to": "icon3" - }, - "line3": { - "from": "icon2", - "to": "icon4" - } - }, "authors": [ { "name": "Abhishek Agawane", From 8bbcb789d096bffd87596c5f1381c4c06b707a43 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Thu, 4 Dec 2025 19:05:10 +0530 Subject: [PATCH 3/6] Remove incorrect callback operations link from resources --- lambda-durable-human-approval-sam/example-pattern.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lambda-durable-human-approval-sam/example-pattern.json b/lambda-durable-human-approval-sam/example-pattern.json index 76e513c20..c0aa4f7a9 100644 --- a/lambda-durable-human-approval-sam/example-pattern.json +++ b/lambda-durable-human-approval-sam/example-pattern.json @@ -31,10 +31,6 @@ { "text": "Durable Execution SDK for Python", "link": "https://github.com/aws/aws-durable-execution-sdk-python" - }, - { - "text": "Callback Operations", - "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-callback.html" } ] }, From f6282add4782e3222b1dbe3ec72aa68697cc8f5f Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Wed, 10 Dec 2025 08:09:14 +0530 Subject: [PATCH 4/6] Address PR review comments: fix service naming, remove duplicates, improve clarity - Use 'Lambda durable functions' (lowercase) throughout - Use full AWS service names (Amazon API Gateway, Amazon DynamoDB, Amazon SNS) - Update regional availability note to be future-proof - Remove duplicate monitoring sections - Remove unnecessary DynamoDB monitoring section - Make deployment instructions less prescriptive - Rewrite bullet points as full sentences - Add explanation for dual timeout configuration - Update LinkedIn format to username only --- lambda-durable-human-approval-sam/README.md | 67 +++++-------------- .../example-pattern.json | 10 +-- 2 files changed, 21 insertions(+), 56 deletions(-) diff --git a/lambda-durable-human-approval-sam/README.md b/lambda-durable-human-approval-sam/README.md index 5f07f395f..c9b773d4c 100644 --- a/lambda-durable-human-approval-sam/README.md +++ b/lambda-durable-human-approval-sam/README.md @@ -1,8 +1,8 @@ -# Human-in-the-Loop Approval Workflow with Lambda Durable Functions +# Human-in-the-Loop Approval Workflow with AWS Lambda durable functions -This pattern demonstrates a human-in-the-loop approval workflow using AWS Lambda Durable Functions. The workflow pauses execution for up to 24 hours while waiting for human approval via email, automatically handling timeouts and resuming when decisions are received. +This pattern demonstrates a human-in-the-loop approval workflow using AWS Lambda durable functions. The workflow pauses execution for up to 24 hours while waiting for human approval via email, automatically handling timeouts and resuming when decisions are received. -**Important:** Lambda Durable Functions are currently available in the **us-east-2 (Ohio)** region only. +**Important:** Lambda durable functions have limited regional availability. Please check the [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) for current regional support. Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-hitl-approval-sam @@ -10,13 +10,13 @@ Learn more about this pattern at Serverless Land Patterns: https://serverlesslan ![Architecture Diagram](architecture.png) -The pattern uses Lambda Durable Functions to implement a cost-effective approval workflow that can wait up to 24 hours without incurring compute charges during the wait period. +The pattern uses Lambda durable functions to implement a cost-effective approval workflow that can wait up to 24 hours without incurring compute charges during the wait period. ### Workflow Steps -1. **User submits approval request** via API Gateway +1. **User submits approval request** via Amazon API Gateway 2. **Durable Function validates request** and creates a callback -3. **UUID mapping stored in DynamoDB** (callback ID → UUID) +3. **UUID mapping stored in Amazon DynamoDB** (callback ID → UUID) 4. **Email notification sent via SNS** with approve/reject links 5. **Function pauses execution** (no compute charges during wait) 6. **Approver clicks link** in email @@ -57,16 +57,11 @@ The pattern uses Lambda Durable Functions to implement a cost-effective approval sam deploy --guided --region us-east-2 ``` - During the guided deployment: - - Stack Name: `lambda-durable-hitl-approval` - - AWS Region: `us-east-2` - - Parameter ApproverEmail: `your-email@example.com` - - Confirm changes: `N` - - Allow SAM CLI IAM role creation: `Y` - - Disable rollback: `N` - - Save arguments to config file: `Y` + During the guided deployment, provide the required values: + - **ApproverEmail**: Enter your email address to receive approval notifications + - Allow SAM CLI to create IAM roles when prompted -4. **Confirm SNS subscription**: Check your email and click the confirmation link from AWS SNS +4. **Confirm SNS subscription**: Check your email and click the confirmation link from Amazon SNS 5. Note the `ApiEndpoint` from the outputs @@ -101,24 +96,9 @@ You'll receive an email with: ### Click Approve or Reject -Click one of the links in the email. You'll see a confirmation page with: -- ✓ or ✗ icon -- "Request Approved!" or "Request Rejected!" message -- Confirmation that the workflow has been notified +Click one of the links in the email. You'll see a confirmation page that displays a checkmark or X icon along with either a "Request Approved!" or "Request Rejected!" message. The page will also confirm that the workflow has been notified of your decision. -### Monitor the Workflow -```bash -# View durable function logs -aws logs tail /aws/lambda/lambda-durable-hitl-approval-ApprovalFunction-XXXXX \ - --follow \ - --region us-east-2 -``` - -Look for: -- `Starting approval workflow for request: REQ-001` -- `Approval request sent. UUID: ` -- `Approval workflow completed: approved` (or `rejected`) ## How It Works @@ -173,23 +153,13 @@ def lambda_handler(event, context): ) ``` -### Cost Efficiency - -**Traditional Lambda approach:** -- Cannot wait more than 15 minutes (Lambda max timeout) -- Would need Step Functions or polling mechanism -- Complex state management - -**Durable Functions approach:** -- Wait up to 24 hours -- No compute charges during wait -- Simple, clean code -- Automatic state management ## Configuration ### Adjust Timeout Duration +To change the timeout duration, you need to update both the Lambda function configuration and the callback configuration: + Modify in `template.yaml`: ```yaml @@ -203,6 +173,8 @@ And in `src/lambda_function.py`: config=CallbackConfig(timeout=Duration.from_hours(24)) ``` +Both values must match: `ExecutionTimeout` sets the maximum runtime for the durable function, while `CallbackConfig.timeout` sets how long the callback will wait before timing out. + ### Change Email Address Update during deployment or redeploy with new email: @@ -237,14 +209,7 @@ aws logs tail /aws/lambda/lambda-durable-hitl-approv-CallbackHandlerFunction-XXX --follow ``` -### DynamoDB Table -Check the callback mappings: -```bash -aws dynamodb scan \ - --table-name lambda-durable-hitl-approval-callbacks \ - --region us-east-2 -``` ## Cleanup @@ -255,7 +220,7 @@ sam delete --stack-name lambda-durable-hitl-approval --region us-east-2 ## Learn More -- [Lambda Durable Functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) +- [Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) - [Durable Execution SDK (Python)](https://github.com/aws/aws-durable-execution-sdk-python) - [Callback Operations](https://docs.aws.amazon.com/lambda/latest/dg/durable-callback.html) - [SendDurableExecutionCallbackSuccess API](https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/lambda/client/send_durable_execution_callback_success.html) diff --git a/lambda-durable-human-approval-sam/example-pattern.json b/lambda-durable-human-approval-sam/example-pattern.json index c0aa4f7a9..1f25e0b6d 100644 --- a/lambda-durable-human-approval-sam/example-pattern.json +++ b/lambda-durable-human-approval-sam/example-pattern.json @@ -1,5 +1,5 @@ { - "title": "Human-in-the-Loop Approval Workflow with Lambda Durable Functions", + "title": "Human-in-the-Loop Approval Workflow with Lambda durable functions", "description": "Approval workflow that pauses execution while waiting for human decisions, with automatic timeout handling and callback-based resumption", "language": "Python", "level": "300", @@ -7,7 +7,7 @@ "introBox": { "headline": "How it works", "text": [ - "This pattern demonstrates a human-in-the-loop approval workflow using Lambda Durable Functions with callback operations.", + "This pattern demonstrates a human-in-the-loop approval workflow using Lambda durable functions with callback operations.", "The workflow pauses execution using create_callback() while waiting for human approval, incurring no compute charges during the wait period.", "If no decision is received within 24 hours, the workflow automatically times out and rejects the request.", "When an approver submits a decision via API, the durable function resumes from its checkpoint and processes the result.", @@ -25,7 +25,7 @@ "resources": { "bullets": [ { - "text": "Lambda Durable Functions Documentation", + "text": "Lambda durable functions Documentation", "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" }, { @@ -36,7 +36,7 @@ }, "deploy": { "text": [ - "Note: Lambda Durable Functions are currently available in us-east-2 (Ohio) region only.", + "Note: Lambda durable functions have limited regional availability. Please check the AWS documentation for current regional support.", "sam build", "sam deploy --guided --region us-east-2" ] @@ -56,7 +56,7 @@ "name": "Abhishek Agawane", "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.", - "linkedin": "https://www.linkedin.com/in/agawabhi/" + "linkedin": "agawabhi" } ] } From 6a2a751ad85c658ba1c8653a8444925d6d4a655d Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Thu, 11 Dec 2025 08:42:47 +0100 Subject: [PATCH 5/6] Add final pattern file --- .../lambda-durable-human-approval-sam.json | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 lambda-durable-human-approval-sam/lambda-durable-human-approval-sam.json diff --git a/lambda-durable-human-approval-sam/lambda-durable-human-approval-sam.json b/lambda-durable-human-approval-sam/lambda-durable-human-approval-sam.json new file mode 100644 index 000000000..953b6f28b --- /dev/null +++ b/lambda-durable-human-approval-sam/lambda-durable-human-approval-sam.json @@ -0,0 +1,92 @@ +{ + "title": "Human-in-the-Loop Approval Workflow with Lambda durable functions", + "description": "Approval workflow that pauses execution while waiting for human decisions, with automatic timeout handling and callback-based resumption", + "language": "Python", + "level": "300", + "framework": "AWS SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern demonstrates a human-in-the-loop approval workflow using Lambda durable functions with callback operations.", + "The workflow pauses execution using create_callback() while waiting for human approval, incurring no compute charges during the wait period.", + "If no decision is received within 24 hours, the workflow automatically times out and rejects the request.", + "When an approver submits a decision via API, the durable function resumes from its checkpoint and processes the result.", + "The pattern uses DynamoDB to map short UUIDs to callback IDs for clean approval URLs, and SNS to send email notifications with approve/reject links." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-human-approval-sam", + "templateURL": "serverless-patterns/lambda-durable-human-approval-sam", + "projectFolder": "lambda-durable-human-approval-sam", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Lambda durable functions Documentation", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Durable Execution SDK for Python", + "link": "https://github.com/aws/aws-durable-execution-sdk-python" + } + ] + }, + "deploy": { + "text": [ + "Note: Lambda durable functions have limited regional availability. Please check the AWS documentation for current regional support.", + "sam build", + "sam deploy --guided --region us-east-2" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: sam delete --region us-east-2." + ] + }, + "authors": [ + { + "name": "Abhishek Agawane", + "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk", + "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.", + "linkedin": "agawabhi" + } + ], + "patternArch": { + "icon1": { + "x": 15, + "y": 50, + "service": "apigw", + "label": "Amazon API Gateway" + }, + "icon2": { + "x": 50, + "y": 50, + "service": "lambda", + "label": "AWS Lambda durable functions" + }, + "icon3": { + "x": 85, + "y": 50, + "service": "dynamodb", + "label": "Amazon DynamoDB" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "" + }, + "line2": { + "from": "icon2", + "to": "icon3", + "label": "" + } + } +} From d0d1dc90b663dc600813f01cc241d849393d4e06 Mon Sep 17 00:00:00 2001 From: Abhishek Agawane Date: Thu, 11 Dec 2025 14:12:34 +0530 Subject: [PATCH 6/6] Fix feature naming to use correct 'AWS Lambda durable functions' format - Update README.md regional availability note to be more concise - Fix template.yaml description to use 'AWS Lambda durable functions' - Fix lambda_function.py docstring to use 'Lambda durable functions' - Ensure consistent lowercase 'durable functions' throughout --- lambda-durable-human-approval-sam/README.md | 2 +- lambda-durable-human-approval-sam/src/lambda_function.py | 2 +- lambda-durable-human-approval-sam/template.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lambda-durable-human-approval-sam/README.md b/lambda-durable-human-approval-sam/README.md index c9b773d4c..00acae675 100644 --- a/lambda-durable-human-approval-sam/README.md +++ b/lambda-durable-human-approval-sam/README.md @@ -2,7 +2,7 @@ This pattern demonstrates a human-in-the-loop approval workflow using AWS Lambda durable functions. The workflow pauses execution for up to 24 hours while waiting for human approval via email, automatically handling timeouts and resuming when decisions are received. -**Important:** Lambda durable functions have limited regional availability. Please check the [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) for current regional support. +**Important:** Please check the [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) for regions currently supported by AWS Lambda durable functions. Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-hitl-approval-sam diff --git a/lambda-durable-human-approval-sam/src/lambda_function.py b/lambda-durable-human-approval-sam/src/lambda_function.py index 6120645f2..8de2a3532 100644 --- a/lambda-durable-human-approval-sam/src/lambda_function.py +++ b/lambda-durable-human-approval-sam/src/lambda_function.py @@ -12,7 +12,7 @@ @durable_execution def lambda_handler(event, context: DurableContext): - """Human-in-the-Loop Approval Pattern using Durable Functions""" + """Human-in-the-Loop Approval Pattern using Lambda durable functions""" # Parse input body = event.get('body') diff --git a/lambda-durable-human-approval-sam/template.yaml b/lambda-durable-human-approval-sam/template.yaml index cbcc40fe8..0458f4eab 100644 --- a/lambda-durable-human-approval-sam/template.yaml +++ b/lambda-durable-human-approval-sam/template.yaml @@ -1,6 +1,6 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 -Description: Human-in-the-Loop Approval Pattern using Lambda Durable Functions +Description: Human-in-the-Loop Approval Pattern using AWS Lambda durable functions Parameters: ApproverEmail: