From 8e2d3712180476507213e469763956616bc64ef3 Mon Sep 17 00:00:00 2001 From: lennyaiko Date: Thu, 27 Mar 2025 11:29:36 +0100 Subject: [PATCH] initial commit --- .env | 0 .gitignore | 1 + .vscode/settings.json | 24 ++ Dockerfile | 21 ++ README.md | 0 __pycache__/app.cpython-310.pyc | Bin 0 -> 245 bytes __pycache__/wsgi.cpython-310.pyc | Bin 0 -> 203 bytes app.py | 6 + app/__init__.py | 27 ++ app/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 771 bytes app/__pycache__/config.cpython-310.pyc | Bin 0 -> 524 bytes app/config.py | 9 + app/errors/__init__.py | 1 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 204 bytes .../__pycache__/handlers.cpython-310.pyc | Bin 0 -> 819 bytes app/errors/handlers.py | 18 ++ .../response_helper.cpython-310.pyc | Bin 0 -> 9154 bytes app/helpers/response_helper.py | 251 ++++++++++++++++++ app/routes/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 216 bytes .../authentication.cpython-310.pyc | Bin 0 -> 838 bytes .../__pycache__/eligibility.cpython-310.pyc | Bin 0 -> 987 bytes app/routes/authentication.py | 19 ++ app/routes/eligibility.py | 42 +++ app/routes/loan.py | 0 app/routes/repayment.py | 0 app/utils/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 119 bytes app/utils/__pycache__/auth.cpython-310.pyc | Bin 0 -> 388 bytes app/utils/auth.py | 8 + app/utils/logger.py | 13 + docker-compose.yml | 30 +++ openapi.yml | 60 +++++ requirements.txt | 7 + wsgi.py | 7 + 35 files changed, 548 insertions(+) create mode 100644 .env create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 __pycache__/app.cpython-310.pyc create mode 100644 __pycache__/wsgi.cpython-310.pyc create mode 100644 app.py create mode 100644 app/__init__.py create mode 100644 app/__pycache__/__init__.cpython-310.pyc create mode 100644 app/__pycache__/config.cpython-310.pyc create mode 100644 app/config.py create mode 100644 app/errors/__init__.py create mode 100644 app/errors/__pycache__/__init__.cpython-310.pyc create mode 100644 app/errors/__pycache__/handlers.cpython-310.pyc create mode 100644 app/errors/handlers.py create mode 100644 app/helpers/__pycache__/response_helper.cpython-310.pyc create mode 100644 app/helpers/response_helper.py create mode 100644 app/routes/__init__.py create mode 100644 app/routes/__pycache__/__init__.cpython-310.pyc create mode 100644 app/routes/__pycache__/authentication.cpython-310.pyc create mode 100644 app/routes/__pycache__/eligibility.cpython-310.pyc create mode 100644 app/routes/authentication.py create mode 100644 app/routes/eligibility.py create mode 100644 app/routes/loan.py create mode 100644 app/routes/repayment.py create mode 100644 app/utils/__init__.py create mode 100644 app/utils/__pycache__/__init__.cpython-310.pyc create mode 100644 app/utils/__pycache__/auth.cpython-310.pyc create mode 100644 app/utils/auth.py create mode 100644 app/utils/logger.py create mode 100644 docker-compose.yml create mode 100644 openapi.yml create mode 100644 requirements.txt create mode 100644 wsgi.py diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70700a2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +./vscode \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f1682a3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,24 @@ +{ + "editor.lineNumbers": "off", + "editor.padding.top": 3, + "editor.padding.bottom": 3, + "editor.formatOnSave": true, + "editor.formatOnPaste": true, + "editor.fontSize": 14, + "editor.lineHeight": 4.5, + "editor.suggestFontSize": 15, + // "editor.suggestLineHeight": 4, + "breadcrumbs.enabled": false, + "workbench.tips.enabled": false, + "workbench.statusBar.visible": false, + // "workbench.editor.showTabs": "single", + "git.enableSmartCommit": true, + "workbench.editor.editorActionsLocation": "hidden", + // "workbench.activityBar.location": "hidden", + "workbench.editor.enablePreviewFromQuickOpen": false, + "editor.lightbulb.enabled": "off", + "editor.selectionHighlight": false, + "editor.overviewRulerBorder": false, + "editor.renderLineHighlight": "none", + "editor.occurrencesHighlight": "off" +} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3148809 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +# Use Python base image +FROM python:3.10 + +# Set working directory +WORKDIR /app + +# Copy files to container +COPY . /app + +# Install dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Expose port 5000 +EXPOSE 5000 + +# Set environment variables +ENV FLASK_APP=app.py +ENV FLASK_RUN_HOST=0.0.0.0 + +# Run the application +CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "wsgi:wsgi_app"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/__pycache__/app.cpython-310.pyc b/__pycache__/app.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..634fcf8c1e340b17da518394784c562dbc9e642f GIT binary patch literal 245 zcmYjLyN<#@477JQ5OGj}xNk_qA?g$23uvICSp~e}apa**Qh-E7L&JygNw+Pc;1_5( zZ>qC3V~spxIqP&kl+Fl44z>DMv(Xs_S3*lk|ad| zHLenYnzI^F_~aZ!=vpgl;?n3i&t0f>5^qzjkImtr?(L-uFps2Do2)3E$}?NKfXuR5 zPb1|dr>x*ZKAOgf(b`E{r8ltt{hD4MU+nT2g`kf~O)+(|dsQV-N=!FabFZKwPW_BvKes7;_kM8KW2(8B!UW8KM|cnNpat znTrHd8KRg|n1dNWSd--?P%VQd<1Mb_qSVBa)cC}Lf?FK%@wthadGYannk=`Nfg(j9 zqd~%XiMgrq@wYh2i_?%zu>+;R#4jFwpol(5O0S^u7Kcr4eoARhsvRRxK{3eX NJPd4196-qO4*+5JE_VO` literal 0 HcmV?d00001 diff --git a/app.py b/app.py new file mode 100644 index 0000000..031e1d7 --- /dev/null +++ b/app.py @@ -0,0 +1,6 @@ +from app import create_app + +app = create_app() + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000, debug=True) \ No newline at end of file diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..a98c30b --- /dev/null +++ b/app/__init__.py @@ -0,0 +1,27 @@ +from flask import Flask +from flask_cors import CORS +from app.config import Config +from app.routes import auth_bp, eligibility_bp +from app.errors import method_not_allowed, unsupported_media_type + + +def create_app(): + """Factory function to create a Flask app instance""" + app = Flask(__name__) + + # Load configuration + app.config.from_object(Config) + + CORS(app) + + # Register blueprints + app.register_blueprint(auth_bp) + # app.register_blueprint(loan_bp) + app.register_blueprint(eligibility_bp, url_prefix="/eligibility") + # app.register_blueprint(repayment_bp) + + # Error Handlers + app.register_error_handler(405, method_not_allowed) + app.register_error_handler(415, unsupported_media_type) + + return app diff --git a/app/__pycache__/__init__.cpython-310.pyc b/app/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..30e884ee10e5b534dd82ac8055e2585ad1d2937b GIT binary patch literal 771 zcmYjOJ#X7E5GD0(SvG>8$gH7@m-r79MFFE3+oIXH5VAD+HxhP6@YVpYv^F257%zslAG*$1 zkb*Z-sEWhBleHW4WE4S!zC!oHfB?OtpUHvT1P>uZk0=o01G&TVKpqlET?M-dWP*y| zOW^Ah5kmg>gd><9F$#-smseE{#_r3_(AJ<#TY@QTD=Uy?ReHH))pez6d#Ku4-WJOf zeGAI+!D`-Fxly0gS7fZdVOSK_ZDhvUfJ|?yQQEa-grr~CNBWtiuoDDIsb1S#1 z2Wk0Q53;kW1sl6=;<^|Ay3$%>`L1e(Mwq%cG7Pwh5LtdFw!rMqvn3|pIajR$&M&+D zm>*?v?746HGYnZ!gjtY>^Pq?d8U=Qa#W#x?i#Kl5UIoiN=C!f?k!_AwTpk5^4a^s; s89??Yw0+ex?*CKu6Fkk6FvF>1_M$Oj(DJ3*d+&r4q@V>o!>0)U0=MhFTmS$7 literal 0 HcmV?d00001 diff --git a/app/__pycache__/config.cpython-310.pyc b/app/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b2fd6e99994a3829c8a8ed46f7792c53ba567b34 GIT binary patch literal 524 zcmYjOJx{|h5Ov%%O{*3pMqr4<)TMzHAq0g`@u3Q}MF=mJiA@Qlaj=u3c7-1TBY!C? zV&E?@aZZuwNq4$;@BDl|%T}v_z&5wO#v2wwp9U;j1;7EgUWdRDw_-$44{^*ZuZUM( zFtNBbL~Z*Uc+?L~Ts9lP0l40VAP{sTg1JR1!hWk7m3K@WZj)MxtK0$X@*1gg7gXzo zb0m|yXgv42Obah8L9SR9$;7*p$~%dfe)L$H7L8$WGzdoYJh&k%I!}etB2*%K6tnrx zeU_zq*Y`uI1WTh17t@Z8Cbvq&F-yjsL}dPS#|O&SEM{s}tejns=#u2>Oy-I{JZE$v zJL`!ns+;4c>tAS* VwV+nGdy853;m46S7rST;{{oYfflmMc literal 0 HcmV?d00001 diff --git a/app/config.py b/app/config.py new file mode 100644 index 0000000..598d366 --- /dev/null +++ b/app/config.py @@ -0,0 +1,9 @@ +import os + +class Config: + """Base configuration for Flask app""" + + SECRET_KEY = os.getenv("SECRET_KEY", "supersecretkey") + API_BASE_URL = "https://coreapi.dev.simbrellang.net/v1/api/salary" + JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your_jwt_secret") + DEBUG = True \ No newline at end of file diff --git a/app/errors/__init__.py b/app/errors/__init__.py new file mode 100644 index 0000000..15c380c --- /dev/null +++ b/app/errors/__init__.py @@ -0,0 +1 @@ +from .handlers import method_not_allowed, unsupported_media_type \ No newline at end of file diff --git a/app/errors/__pycache__/__init__.cpython-310.pyc b/app/errors/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ca4fc6e0297f5dfe78841a1d93a5e0afbb70037 GIT binary patch literal 204 zcmYj~O$x#=5QURep$Oeb5y2C5V=o}m6S#5LO(@J@3;AP`B0Z8<%2r%>1y?4neDJ=R z$G|*WRU4MH+P`jHn$H~mB~s{;eVqUdxMG_3T#H_C2I9(^;?2{k5pk1^Rhjwu8XC$)ZTPY_q1u2hi RiRDRKm=&ILx6co1_61M>G8q5> literal 0 HcmV?d00001 diff --git a/app/errors/__pycache__/handlers.cpython-310.pyc b/app/errors/__pycache__/handlers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aed3a0e02ecb4bbfeaa0c48f751806ab5b0df59a GIT binary patch literal 819 zcmah{J8#=C5GM7oh=;Fos13}RTP;^Kh11L3W9^m(@~Lt8%d#{V8g3|irL9$G zdK@6X?shAGtEi1D)cvhkBO1IB$ld?kKTu8M#fR;|Qq@puw3B9yeYz2o-11js()<4e ziVy&G4acW>o4Ei1)fz<7_zY`V}CoCK#e991*gOS81q^9Gfix;J`ACaT; zed2Jk^mAkr(ZlJq4evX2Uhm*Dj-LqH`e+frL@$}+|kTWPCJwXHR^ zcCMLg=bQOnhKShD$`0zNi8XKj%qAN zb1YButiXz_#L6t+Qm3V9i5A!hEylU|mLl>>AdzPkOtmVsOh@kK?#RtifmacT=e9sX z{GHIsbd**FS{2X^mByfj3Oz5{hIKc$Z&2IH^f0Xnv_qn8M*!=>78uyFK{!P^PA3G; zn829?oQu1{IZCGl&SAir7JYken{gl9o@4a5z^MVw34wEIS2!o>V*=+0;5;sHey}SX zLQe^talm;(;QVk`IH&0ufinR(PYRqL?F#29`n15A1e_Ux^Zc%G>hu|ba};o%6*w>K z3TKv{6*yB=0lU5&Ru`GqaUGAn&g>53t3N9fc;?AXktC*VcphoFoGb^HO)cjJ@qELf z2B+34qvXviZ#4*yAv|I^WC3ctJ10;Y_dWq@5A#sN54^C@W}auS`i2*3~dYl@D{j z&iPUoyg^rOVNX@#ydp`WS=hmsu{XpR(3!b%Dm>3`c$d=@R*#xaW|m#ou3si^IMgx? zpLyi=P3GTZoIn7>aw}k-Pi`9?@dDF?-nRlf8X5$_Cms?qImyvM4&y zry}h6H2|I^fO;K=7IY+LC%yvR?f_|-<0s?0fye9JZ`5;q1Sr=mM}zPR^pjU0gO6fx z2m_!MOprn>Q&dgL!(w6{YZ9+PZtwItqtg*@WMtmCL_&`;<~l23RoI)Jl;AY)A*M2^ z$ckKrU;cijuzGTFgZa*FtQD58q`WgVsGU3*FTg8o3LE81f0n5XRwZ?nuKE|8^A+O@ zIb$)=Afw4dkg3%VG?aZKpKV3O1Uxa4flM5hFv9<= zdjNFOdqa?YGlfUevo7$-h;r*}TX(7Gk=7|E-0Y7rYYKwZ@jkMN?)T6Ux&b#CF*$>& zm?nM-rd)f)RH0__U_5bt-)wY#ROu>$ajNmRtr(X&Ju%rC>9>G^;^PAuxNig)mfFzD zofZ*~B$t-%eF`cSgj!QGK1@u{8@Ut~VtOn>jmUi+-sHYwkqoDT4k&L}PVp0f4GYe{ z55XXZB+v&G`ZgDOOB`2NfLKI!~(sEHyodFI0GS982=?~1zyFS z%}@?V>dF}h^v9v-1MBhVYhLsCiHQpl2y%bQmP#9qe@mPEG@Wv*`ky=JJRF*A?Sh2oCxlK z8nJ<9Y-2yE@%w?)D5ZM&DCNaeA1_joUJXj3wXx&+pwhtE*?D|03_DUdTo>=W06v&` z2-%ZksRir3!Sn#d=t9r`*p?otNN@bA)8Q^2Pa4ZMBX}z2Z@**uUuT!i&>0Kbe6o7L zkv-$cUk7qzJjiNYkF@@AN|)1p-efE3UhNlf+U-)(0Jk!4+wSclRwaKL#<8>`T=XwS zgd3eB9Z={0voQI?K2LMqV~3S&WvNd$UYg2EgRHduot~K}s*1&B!r1&%@ z@N10*3LO{O5IGe^`02QaKb=JCN#xliayE&aOClGd$aGlLb;oEkT@TB;-gaqVW4xm4 zw*teCOA5M9T@$nMK-e-PW``PH0){GFHE}#uT!%cfx%N4;CVWK27_4)<}f&q!9@(#w+14HC-LIo9>3$g4c1zeG+EK$2e(7oeF*=f zD9XRbROKP$J*eiC`{jJ4r<{abkN}wnW3h|^GF6Z%=PLJ=@%8d7Mt`~XFsWUI+GVZs zK&eGF2bCb=7_@40o$p%7*aI=Tje04}weUil>Fsw59 Dict[str, Any]: + """ + Build a standardized JSON response. + + Args: + status (bool): Indicates whether the request was successful. + message (str): A message describing the result of the request. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + status_code (int): The HTTP status code for the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + response = { + "status": status, + "statusCode": status_code, + "message": message, + "data": data if data is not None else {}, + "error": error if error is not None else {}, + } + return jsonify(response), status_code + + @staticmethod + def success( + data: Optional[Union[Dict, List, str]] = None, + message: str = "Successful", + status_code: int = 200, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a success response. + + Args: + data (Optional[Union[Dict, List, str]]): The data to return in the response. + message (str): A message describing the result of the request. + status_code (int): The HTTP status code for the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(True, message, data, status_code, error) + + @staticmethod + def error( + message: str = "An error occurred", + status_code: int = 400, + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return an error response. + + Args: + message (str): A message describing the error. + status_code (int): The HTTP status code for the response. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, status_code, error) + + @staticmethod + def created( + data: Optional[Union[Dict, List, str]] = None, + message: str = "Resource created successfully", + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a created resource. + + Args: + data (Optional[Union[Dict, List, str]]): The data to return in the response. + message (str): A message describing the result of the request. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(True, message, data, 201, error) + + @staticmethod + def updated( + data: Optional[Union[Dict, List, str]] = None, + message: str = "Resource updated successfully", + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for an updated resource. + + Args: + data (Optional[Union[Dict, List, str]]): The data to return in the response. + message (str): A message describing the result of the request. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(True, message, data, 200, error) + + @staticmethod + def internal_server_error( + message: str = "Internal Server Error", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for an internal server error. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 500, error) + + @staticmethod + def unauthorized( + message: str = "Unauthorized", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for an unauthorized request. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 401, error) + + @staticmethod + def forbidden( + message: str = "Forbidden", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a forbidden request. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 403, error) + + @staticmethod + def not_found( + message: str = "Resource not found", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a not found resource. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 404, error) + + @staticmethod + def unprocessable_entity( + message: str = "Unprocessable entity", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for an unprocessable entity. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 422, error) + + @staticmethod + def method_not_allowed( + message: str = "Method Not Allowed", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a method not allowed error. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 405, error) + + @staticmethod + def bad_request( + message: str = "Bad Request", + data: Optional[Union[Dict, List, str]] = None, + error: Optional[Union[Dict, str]] = None, + ) -> Dict[str, Any]: + """ + Return a response for a bad request error. + + Args: + message (str): A message describing the error. + data (Optional[Union[Dict, List, str]]): The data to return in the response. + error (Optional[Union[Dict, str]]): Any error details to include in the response. + + Returns: + Dict[str, Any]: A dictionary representing the JSON response. + """ + return ResponseHelper.build_response(False, message, data, 400, error) \ No newline at end of file diff --git a/app/routes/__init__.py b/app/routes/__init__.py new file mode 100644 index 0000000..d7d4421 --- /dev/null +++ b/app/routes/__init__.py @@ -0,0 +1,4 @@ +from .authentication import auth_bp +from .eligibility import eligibility_bp +# from .loan import loan_bp +# from .repayment import repayment_bp \ No newline at end of file diff --git a/app/routes/__pycache__/__init__.cpython-310.pyc b/app/routes/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be0688cb3ab3c4b179e77163adb2ea05f921c995 GIT binary patch literal 216 zcmd1j<>g`kf;^?C>AgVuF^GcsPMp9SA3=~<(P{abHz{D?U{ltO-FfPh3ElDlbkB`sH%PfhH*DI*J#bJ}1pHiBW PY6r5t7^I1ZL4Xke%4hznK0O^u++ekplAP9mS2;3+J>@?dfXpxdu<{l=w1}sRG()u5g zGJle9U>l_HFQm#0WgrRx&T{y=4bk!4)h!<2Ow@jp>_m%8u-uLys7~I!~ z;>gzrf}N3UbO%@@3taD=>SU|S+PXx`t4&GNZ!LWLkJcY6Re~=3h=?y#l~{mnVfxTGpbR8A4H>2 zKKyw;;ce@$ZaOQ?1fgYZ%Ne(2Q;*vl7w>5#hyc2hA=3!7jwh;Fl(h>_KcAidM+ylc zk|*^69+s@=7Km-BWvgIAH=y(_+p-N?g(A3Q`l*dJ>>K?Kii%(k%GpSSBEmJW2P;`T zUB6sf+nQIC$*j?mx8+#K>#-@T3oVu6^Bs4s|I@&i&+B(;c8%MD7fW$0&qpA75-w{rZ)1Q zx_aO-y-fJ@2E{C-Bi5(K^dZ$xaMaL6bH&Z2Ms@cj5JEqIkdMHhac4_q#%PU>py<+~ ysCgxe!X;QNE?O6P|GYDP>H!Pywx^Q5t{TxP`G&$2a}41zN$HUG88R9LBl;JXN6T;k literal 0 HcmV?d00001 diff --git a/app/routes/__pycache__/eligibility.cpython-310.pyc b/app/routes/__pycache__/eligibility.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8711c075d41c7c4a26e6d7cbd5a3bfa9b78c8bc GIT binary patch literal 987 zcmYjPJ8u**5VpO~dy)(922mj$MRIq6BuEI6ga{$fB}zi$X0=)SE_>M*wpSt%sX{@+ zF93c3CBK1&-{2Ne90fIkhVdp5=hb|kv1Z5L=b60Ksv}sfJ3q!>Y=pj>V0OV7dJHCa z02pF8K`Ev#%q&0bC^5E%zICm&uVYc zDW(lZc2T!Jg}SI~>)Lu!@LPtm{xOAC0(p#%L{#v$ZrY zGX-w=`ob+l&dNwZf}?nri|NSJ+Wrb~*M~CZJt*n*XnnVgA}-~qOu8PeN2OGGT2*c- z5oR)sRGeo}rxBS;#L-61ICWDQOP100SyvLiW#~v+7hIN!s&YDK{u3@E5f`S)^qV2? z3ey>Fo3;zbxNekZqj;>HYBGeG#;&Dp7OGHtVG#$VNVE^-iaeA2GZNPzx6eYHDYc zgz``jh$;~k)iVu1uNr5m+dylfRB<8~!crXw7qYb<1X-B!AkgPeRt<8nUudUdU)@mY dnt|)ppAS=LWx^j}h-4Gs2J&$e*Gb!Ig`k0vFMz=^*+sh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2BsKe3UCDHq0l& z{6i0OUN6hy1&JZZK736Bfc4(0vXVgtnB!)v#|2aAie;1uX`8p2kqIGq_$?eLeOo(% m-M36CsRzp{lXv}+{_vmwTa92qJ0}}X+lrmyKb(VH?2;c