Spaces:
Runtime error
Runtime error
Delete app.py
Browse files
app.py
DELETED
@@ -1,385 +0,0 @@
|
|
1 |
-
import streamlit as st
|
2 |
-
import openai
|
3 |
-
import time
|
4 |
-
from PIL import Image
|
5 |
-
import stqdm
|
6 |
-
from stqdm import stqdm
|
7 |
-
from streamlit_option_menu import option_menu
|
8 |
-
import pandas as pd
|
9 |
-
from pandasai import PandasAI
|
10 |
-
from pandasai.llm.openai import OpenAI
|
11 |
-
|
12 |
-
# Load and set our key
|
13 |
-
openai.api_key = open("key.txt", "r").read().strip("\n")
|
14 |
-
|
15 |
-
st.set_page_config(page_title="Loan Eligibility and Repayment Strategy Advisor", page_icon="GH", initial_sidebar_state="expanded")
|
16 |
-
|
17 |
-
hide_streamlit_style = """
|
18 |
-
<style>
|
19 |
-
#MainMenu {visibility: hidden;}
|
20 |
-
footer {visibility: hidden;}
|
21 |
-
</style>
|
22 |
-
"""
|
23 |
-
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
|
24 |
-
|
25 |
-
css_style = {
|
26 |
-
"icon": {"color": "white"},
|
27 |
-
"nav-link": {"--hover-color": "grey"},
|
28 |
-
"nav-link-selected": {"background-color": "#FF4C1B"},
|
29 |
-
}
|
30 |
-
|
31 |
-
|
32 |
-
def home_page():
|
33 |
-
|
34 |
-
st.write(f"""# Loan Eligibility and Repayment Strategy Advisor""", unsafe_allow_html=True)
|
35 |
-
|
36 |
-
st.image("banner1.jpg", use_column_width=True)
|
37 |
-
|
38 |
-
st.write(f"""<h2>The Problem</h2>
|
39 |
-
<p>Access to credit and loans is a critical challenge in Ghana, impacting both individuals and businesses. Key factors and challenges include:</p>
|
40 |
-
<ul>
|
41 |
-
<li>Limited access to formal credit.</li>
|
42 |
-
<li>An informal economy with cash-based businesses.</li>
|
43 |
-
<li>A credit information gap.</li>
|
44 |
-
<li>High interest rates.</li>
|
45 |
-
<li>Collateral requirements.</li>
|
46 |
-
<li>Credit scoring challenges.</li>
|
47 |
-
<li>Income variability.</li>
|
48 |
-
<li>Lack of financial literacy.</li>
|
49 |
-
<li>Challenges in the regulatory framework.</li>
|
50 |
-
<li>Economic volatility.</li>
|
51 |
-
</ul>
|
52 |
-
<p>Addressing these challenges requires a multi-faceted approach, including improving financial inclusion, enhancing credit reporting systems, promoting financial education, and leveraging technology for alternative credit assessment.</p>
|
53 |
-
""", unsafe_allow_html=True)
|
54 |
-
|
55 |
-
st.write(f"""<h2>Project Goals</h2>
|
56 |
-
<p>The Loan Eligibility and Advisor App aims to address the loan eligibility problem in Ghana by:</p>
|
57 |
-
<ul>
|
58 |
-
<li>Providing Loan Eligibility Checks: Offering users a tool to assess their eligibility for loans based on various factors, including income, credit score, and employment history.</li>
|
59 |
-
<li>Offering Personalized Advice: Generating personalized loan repayment advice for users based on their loan type, amount, interest rate, salary, and repayment duration.</li>
|
60 |
-
<li>Promoting Financial Literacy: Educating users on responsible financial practices to improve their eligibility and financial well-being.</li>
|
61 |
-
<li>Enhancing Access to Credit: Empowering individuals and businesses with the information and tools they need to access credit and loans more effectively.</li>
|
62 |
-
</ul>
|
63 |
-
<p>By addressing these goals, the Loan Eligibility and Advisor App strives to make a positive impact on the financial landscape in Ghana, increasing access to credit and fostering financial stability.</p>
|
64 |
-
""", unsafe_allow_html=True)
|
65 |
-
|
66 |
-
def about_page():
|
67 |
-
st.write("""<h1>Project Background</h1>""", unsafe_allow_html=True)
|
68 |
-
st.image("about.jpg", use_column_width=True)
|
69 |
-
st.write("""
|
70 |
-
<p>The Loan Eligibility and Advisor App is a project born out of the Deep Learning Indaba 2023 Hackathon, organized by JP Morgan AI. This hackathon serves as a dynamic platform where knowledge converges with the power of generative AI to address Africa-specific financial challenges. We firmly believe that generative AI holds the key to innovative solutions and has the potential to fuel the growth of home-grown startups.</p>
|
71 |
-
|
72 |
-
<p>The objectives of the Deep Learning Indaba 2023 Hackathon are:</p>
|
73 |
-
|
74 |
-
<ul>
|
75 |
-
<li><strong>Unleash Innovation:</strong> Empower participants to leverage their ideas and local insights, harnessing generative AI to create solutions for the unique financial challenges that Africa faces.</li>
|
76 |
-
<li><strong>Nurture Entrepreneurship:</strong> Cultivate an environment where participants can conceive and kick-start startups based on the prototypes developed during the hackathon, fostering entrepreneurship in the AI domain.</li>
|
77 |
-
<li><strong>Upskill Participants:</strong> Enable participants to tap into the potential of the OpenAI ChatGPT API, enhancing their proficiency in AI and its diverse applications.</li>
|
78 |
-
</ul>
|
79 |
-
|
80 |
-
<p>The Loan Eligibility and Advisor App is one such innovative solution aiming to address the challenges surrounding loan eligibility and financial guidance. Developed by the GENZ team consisting of Alidu Abubakari and Abdulhaq Adetunji Salako, the app offers personalized loan eligibility checks and generates practical loan repayment advice. It aims to empower individuals and businesses in Ghana to make informed financial decisions and improve their access to credit.</p>
|
81 |
-
""", unsafe_allow_html=True)
|
82 |
-
|
83 |
-
|
84 |
-
def eligibility_test():
|
85 |
-
# Title and Description
|
86 |
-
st.write("<center><h1>Loan Eligibility Checker</h1></center>", unsafe_allow_html=True)
|
87 |
-
st.image("banner_image.jpg", use_column_width=True)
|
88 |
-
|
89 |
-
# Center the image
|
90 |
-
#st.image(
|
91 |
-
#img_banner,
|
92 |
-
#width=400,
|
93 |
-
#align="center",
|
94 |
-
#)
|
95 |
-
st.write("Determine your loan eligibility based on your financial information.")
|
96 |
-
|
97 |
-
# User Input: Monthly Salary
|
98 |
-
salary = st.number_input("Monthly Salary (GH₵)", min_value=0, step=100, value=5000)
|
99 |
-
|
100 |
-
# User Input: credit Card Payments
|
101 |
-
credit_card_payments = st.number_input("Monthly Credit Card Payments ($)", min_value=0, step=100, value=0)
|
102 |
-
|
103 |
-
# User Input: Credit Score
|
104 |
-
credit_score = st.slider("Credit Score", min_value=300, max_value=850, step=1, value=700)
|
105 |
-
|
106 |
-
# User Input: loan Payments
|
107 |
-
loan_payments = st.number_input("Monthly Loan Payments ($)", min_value=0, step=100, value=0)
|
108 |
-
|
109 |
-
# User Input: Mortgage Payments
|
110 |
-
mortgage_payments = st.number_input("Monthly Mortgage Payments ($)", min_value=0, step=100, value=0)
|
111 |
-
|
112 |
-
# User Input: Other Payments
|
113 |
-
other_debts = st.number_input("Monthly Other Debt Payments ($)", min_value=0, step=100, value=0)
|
114 |
-
|
115 |
-
# User Input: Employment History (in years)
|
116 |
-
employment_history = st.number_input("Employment History (Years)", min_value=0, step=1, value=2)
|
117 |
-
|
118 |
-
# User Input: Loan Type
|
119 |
-
loan_type = st.selectbox("Loan Type", ["Personal loans", "Cash advances", "Mortgage loans",
|
120 |
-
"Home-equity loans", "Student loans", "Debt Consolidation loans"
|
121 |
-
"Payday Loans", "Small business loans", "Mobile Money Loans", "Car Loans"])
|
122 |
-
|
123 |
-
# User Input: Loan Amount
|
124 |
-
loan_amount = st.number_input("Loan Amount (GH₵)", min_value=0, step=1000, value=10000)
|
125 |
-
|
126 |
-
# User Input: Loan Term (in months)
|
127 |
-
loan_term = st.slider("Loan Term (Months)", min_value=1, max_value=60, value=36)
|
128 |
-
|
129 |
-
# User input: Interest Rate
|
130 |
-
interest_rate = st.slider("Interest Rate (%)", min_value=1.0, max_value=20.0, value=5.5, step=0.5)
|
131 |
-
|
132 |
-
# Initialize eligibility status
|
133 |
-
eligible = None
|
134 |
-
|
135 |
-
# Check Eligibility Button
|
136 |
-
if st.button("Check Eligibility"):
|
137 |
-
# Calculate Monthly Payment
|
138 |
-
monthly_interest_rate = (interest_rate / 100) / 12
|
139 |
-
monthly_payment = (loan_amount * monthly_interest_rate) / (1 - (1 + monthly_interest_rate) ** -loan_term)
|
140 |
-
|
141 |
-
# Calculate Total Monthly Debt Payments
|
142 |
-
total_monthly_debt_payments = (
|
143 |
-
monthly_payment
|
144 |
-
+ credit_card_payments
|
145 |
-
+ loan_payments
|
146 |
-
+ mortgage_payments
|
147 |
-
+ other_debts
|
148 |
-
)
|
149 |
-
|
150 |
-
# Calculate Debt-to-Income Ratio (DTI)
|
151 |
-
dti = (total_monthly_debt_payments / salary) * 100
|
152 |
-
|
153 |
-
# Check Eligibility
|
154 |
-
eligible = False
|
155 |
-
if (
|
156 |
-
salary >= 3000
|
157 |
-
and dti <= 40
|
158 |
-
and credit_score >= 500
|
159 |
-
and employment_history >= 1
|
160 |
-
):
|
161 |
-
eligible = True
|
162 |
-
|
163 |
-
# Create columns for layout
|
164 |
-
col1, col2 = st.columns(2)
|
165 |
-
|
166 |
-
# Display Eligibility Result
|
167 |
-
if eligible is not None:
|
168 |
-
col1.subheader("Loan Eligibility Result:")
|
169 |
-
if eligible:
|
170 |
-
col1.success("🎉 Congratulations! You are eligible for the loan.")
|
171 |
-
col1.image("eligible_image.jpg", use_column_width=True)
|
172 |
-
col1.write("Based on your financial information, you meet the eligibility criteria -->.")
|
173 |
-
col2.write("💡 Here's why you are eligible:")
|
174 |
-
col2.write(f"✅ Your DTI (Debt-to-Income Ratio) is {dti:.2f}%, within an acceptable range (<= 40%).")
|
175 |
-
col2.write(f"✅ Your credit score is {credit_score}, which is good (>= 650).")
|
176 |
-
col2.write(f"✅ You have {employment_history} years of employment history, demonstrating stability (>= 2 years).")
|
177 |
-
col2.write(f"✅ Your monthly salary is GH₵ {salary}, above the minimum threshold (>= GH₵ 3000).")
|
178 |
-
col2.write("Here are some tips for managing your loan:")
|
179 |
-
col2.write("✅ Make on-time payments to maintain a good credit score.")
|
180 |
-
col2.write("💰 Create a budget to track your expenses and savings.")
|
181 |
-
else:
|
182 |
-
col1.error("❌ Sorry, you are not eligible for the loan.")
|
183 |
-
col1.image("not_eligible_image.jpg", use_column_width=True)
|
184 |
-
col1.write("Based on your financial information, you do not meet the eligibility criteria. --> ")
|
185 |
-
col2.write("❗️ Here's why you are not eligible:")
|
186 |
-
col2.write(f"❌ Your DTI (Debt-to-Income Ratio) is {dti:.2f}%, which exceeds the acceptable range (> 40%).")
|
187 |
-
col2.write(f"❌ Your credit score is {credit_score}, which is below the required level (< 650).")
|
188 |
-
col2.write(f"❌ You have {employment_history} years of employment history, which is limited (< 2 years).")
|
189 |
-
col2.write(f"❌ Your monthly salary is GH₵ {salary}, below the minimum threshold (< GH₵ 3000).")
|
190 |
-
col2.write("📌 You can work on improving these factors to become eligible in the future.")
|
191 |
-
|
192 |
-
col2.write("Here are some steps to improve your eligibility:")
|
193 |
-
col2.write("📈 Work on improving your credit score.")
|
194 |
-
col2.write("📉 Consider reducing your monthly debts.")
|
195 |
-
|
196 |
-
# Display Calculated DTI if eligibility is checked
|
197 |
-
st.subheader("Calculated Debt-to-Income Ratio (DTI):")
|
198 |
-
st.write(f"Your DTI is {dti:.2f}%")
|
199 |
-
st.write("Debt-to-Income Ratio (DTI) measures the percentage of your monthly income that goes toward paying debts.")
|
200 |
-
st.write("A lower DTI is generally better, as it indicates that you have more income available to cover your debts.")
|
201 |
-
st.write("Lenders often use DTI as a factor in loan approval.")
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
def repayment_advice():
|
206 |
-
# Title and Description
|
207 |
-
st.write("<center><h1>Loan Repayment Strategy Advisor</h1></center>", unsafe_allow_html=True)
|
208 |
-
st.image("Loan_repayment.jpg", use_column_width=True)
|
209 |
-
|
210 |
-
|
211 |
-
# Description
|
212 |
-
st.write("Welcome to the Financial Advisor App! Take control of your financial future with personalized guidance.")
|
213 |
-
st.write("Calculate loan eligibility, manage debts, and plan your financial journey.")
|
214 |
-
st.write("Let us help you make informed financial decisions.")
|
215 |
-
|
216 |
-
# User input: Loan Type
|
217 |
-
loan_type = st.selectbox("Select Loan Type", ["Personal loans", "Cash advances", "Mortgage loans",
|
218 |
-
"Home-equity loans", "Student loans", "Debt Consolidation loans"
|
219 |
-
"Payday Loans", "Small business loans", "Mobile Money Loans", "Car Loans"])
|
220 |
-
|
221 |
-
# User input: Loan Amount
|
222 |
-
loan_amount = st.slider("Loan Amount", min_value=100, max_value=10000, value=1000, step=100)
|
223 |
-
|
224 |
-
# User input: Interest Rate
|
225 |
-
interest_rate = st.slider("Interest Rate (%)", min_value=1.0, max_value=20.0, value=5.5, step=0.5)
|
226 |
-
|
227 |
-
# User input: Monthly Salary
|
228 |
-
salary = st.slider("Monthly Salary", min_value=0, max_value=20000, value=4000, step=50)
|
229 |
-
|
230 |
-
# Duration
|
231 |
-
repayment_duration = st.slider("Repayment Duration in Months", min_value=1, max_value=100, value=1, step=1)
|
232 |
-
|
233 |
-
# Check if the user has checked eligibility (Yes/No)
|
234 |
-
checked_eligibility = st.radio("Have you checked your eligibility?", ("Yes", "No"))
|
235 |
-
|
236 |
-
# Display advice when the user clicks the "Generate Advice" button
|
237 |
-
if st.button("Generate Advice"):
|
238 |
-
with st.spinner("Generating advice..."):
|
239 |
-
# Check eligibility and provide recommendations
|
240 |
-
if checked_eligibility == "Yes":
|
241 |
-
# Generate loan repayment advice
|
242 |
-
advice = generate_loan_repayment_advice(loan_type, loan_amount, interest_rate, repayment_duration , salary)
|
243 |
-
|
244 |
-
st.subheader("Loan Advisor:")
|
245 |
-
st.write(advice)
|
246 |
-
st.download_button(
|
247 |
-
label="Download response",
|
248 |
-
data=advice,
|
249 |
-
file_name='advice.txt',
|
250 |
-
mime='text/txt',
|
251 |
-
key=f"download_button", # Use a unique key based on the index
|
252 |
-
)
|
253 |
-
time.sleep(1) # Pause for 1 second between responses
|
254 |
-
else:
|
255 |
-
st.warning("Please check your eligibility first using the Loan Eligibility Checker.")
|
256 |
-
|
257 |
-
def generate_loan_repayment_advice(loan_type, loan_amount, interest_rate, repayment_duration, salary):
|
258 |
-
# Calculate the 50/30/20 split of the salary
|
259 |
-
essential_expenses = salary * 0.5
|
260 |
-
discretionary_spending = salary * 0.3
|
261 |
-
recommended_savings = salary * 0.2
|
262 |
-
|
263 |
-
# Calculate the monthly installment required for repayment
|
264 |
-
monthly_interest_rate = (interest_rate / 100) / 12
|
265 |
-
monthly_payments = {}
|
266 |
-
|
267 |
-
for num_months in range(1, repayment_duration):
|
268 |
-
monthly_payments[num_months] = (loan_amount * monthly_interest_rate) / (1 - (1 + monthly_interest_rate) ** -num_months)
|
269 |
-
|
270 |
-
# Define the prompt
|
271 |
-
prompt = (
|
272 |
-
"Provide practical and realistic loan repayment advice based on the given information. Avoid speculative or impractical suggestions.\n\n"
|
273 |
-
f"Please provide advice specifically related to managing a {loan_type} loan with a principal amount of GH₵{loan_amount}, an interest rate of {interest_rate}%, and a repayment duration of {repayment_duration} months.\n\n"
|
274 |
-
"Ensure that the suggested monthly installment does not exceed 30% of the monthly salary.\n\n"
|
275 |
-
"For instance, you might suggest strategies to balance loan repayment with other financial priorities, such as essential expenses and discretionary spending.\n\n"
|
276 |
-
f"Loan Type: {loan_type}\n"
|
277 |
-
f"Loan Amount: GH₵{loan_amount}\n"
|
278 |
-
f"Interest Rate: {interest_rate}%\n"
|
279 |
-
f"Monthly Salary: GH₵{salary}\n"
|
280 |
-
f"Repayment Duration: {repayment_duration} months\n\n"
|
281 |
-
"Consider the following budgeting breakdown based on the 50/30/20 rule:\n"
|
282 |
-
f"- Allocate 50% of your salary to essential expenses (e.g., rent, bills): GH₵{essential_expenses:.2f}\n"
|
283 |
-
f"- Allocate 30% to discretionary spending (e.g., dining out, entertainment): GH₵{discretionary_spending:.2f}\n"
|
284 |
-
f"- Allocate 20% to savings and debt repayment: GH₵{recommended_savings:.2f}\n"
|
285 |
-
"Please provide detailed guidance, along with explanations, to help manage this loan effectively based on the input information.")
|
286 |
-
|
287 |
-
# Use the prompt to generate advice using your OpenAI model
|
288 |
-
response = openai.ChatCompletion.create(
|
289 |
-
model="gpt-3.5-turbo",
|
290 |
-
messages=[
|
291 |
-
{"role": "assistant", "content": "You are an expert financial advisor with several years of experience in providing loan repayment plans."},
|
292 |
-
{"role": "user", "content": prompt}
|
293 |
-
]
|
294 |
-
)
|
295 |
-
|
296 |
-
return response.choices[0].message['content']
|
297 |
-
|
298 |
-
|
299 |
-
def chat_loan_data():
|
300 |
-
|
301 |
-
st.title("Get Insights from Loan Data Using PandasAI")
|
302 |
-
|
303 |
-
st.image("chatdata.jpg", use_column_width=True)
|
304 |
-
|
305 |
-
# Load your loan.csv data directly (handle errors gracefully)
|
306 |
-
try:
|
307 |
-
loan_data = pd.read_csv("Loan_Clean.csv")
|
308 |
-
st.write(loan_data.head(3))
|
309 |
-
except FileNotFoundError:
|
310 |
-
st.error("Error: 'Loan_Clean.csv' dataset not found.")
|
311 |
-
st.stop()
|
312 |
-
|
313 |
-
# User input: Enter a prompt
|
314 |
-
prompt = st.text_area("Enter your prompt:")
|
315 |
-
|
316 |
-
# Predefined prompts for users to choose from
|
317 |
-
available_prompts = [
|
318 |
-
"Show me the summary statistics of the dataset.",
|
319 |
-
"What is the total loan amount in the dataset?",
|
320 |
-
"Calculate the average loan amount.",
|
321 |
-
"Find the maximum term days for loans.",
|
322 |
-
"Compare the number of good loans to bad loans in the dataset.",
|
323 |
-
"Calculate the total due for approved loans.",
|
324 |
-
"What is the most common loan term (termdays) in the dataset?",
|
325 |
-
"What is the range of loan amounts offered?",
|
326 |
-
"Find the percentage of good loans in the dataset.",
|
327 |
-
"How many unique loan numbers are there in the dataset?",
|
328 |
-
"What is the earliest approved date in the dataset?",
|
329 |
-
"What is the latest approved date in the dataset?",
|
330 |
-
"Calculate the total loan amount for loans with more than 30 days term.",
|
331 |
-
"What is the average total due for approved loans?",
|
332 |
-
"Find the median loan amount.",
|
333 |
-
"Calculate the total loan amount for loans with good vs. bad flags.",
|
334 |
-
|
335 |
-
# Add more predefined prompts here
|
336 |
-
]
|
337 |
-
|
338 |
-
# Allow users to select predefined prompts
|
339 |
-
selected_prompt = st.selectbox("Select a predefined prompt:", available_prompts)
|
340 |
-
|
341 |
-
# Generate output based on user's selection or custom prompt
|
342 |
-
if st.button("Generate"):
|
343 |
-
if selected_prompt:
|
344 |
-
prompt = selected_prompt
|
345 |
-
if prompt:
|
346 |
-
# Load and set the OpenAI key
|
347 |
-
openai.api_key = open("key.txt", "r").read().strip("\n")
|
348 |
-
# Create an LLM by instantiating OpenAI object
|
349 |
-
llm = OpenAI(api_token=openai.api_key)
|
350 |
-
# Create PandasAI object, passing the LLM
|
351 |
-
pandas_ai = PandasAI(llm)
|
352 |
-
# Call pandas_ai.run(), passing the loan_data DataFrame and prompt
|
353 |
-
with st.spinner("Generating response..."):
|
354 |
-
response = pandas_ai.run(loan_data, prompt)
|
355 |
-
# Apply HTML formatting to make the response bold and larger
|
356 |
-
response_html = f"<p style='font-size: larger; font-weight: bold;'>{response}</p>"
|
357 |
-
# Display the formatted response
|
358 |
-
st.write(response_html, unsafe_allow_html=True)
|
359 |
-
else:
|
360 |
-
st.warning("Please enter a prompt or select a predefined prompt.")
|
361 |
-
|
362 |
-
|
363 |
-
with st.sidebar:
|
364 |
-
st.image("moneybag.png")
|
365 |
-
selected = option_menu(
|
366 |
-
menu_title=None,
|
367 |
-
options=["Home", "Check eligibity", "Repayment_advice",'chat with data', "About"],
|
368 |
-
icons=["house", "droplet", "people", "people", "info-circle"],
|
369 |
-
styles=css_style
|
370 |
-
)
|
371 |
-
|
372 |
-
if selected == "Home":
|
373 |
-
home_page()
|
374 |
-
|
375 |
-
elif selected == "Check eligibity":
|
376 |
-
eligibility_test()
|
377 |
-
|
378 |
-
elif selected == "Repayment_advice":
|
379 |
-
repayment_advice()
|
380 |
-
|
381 |
-
elif selected == "chat with data":
|
382 |
-
chat_loan_data()
|
383 |
-
|
384 |
-
elif selected == "About":
|
385 |
-
about_page()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|