Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -32,6 +32,17 @@ except ImportError:
|
|
| 32 |
OPENCV_AVAILABLE = False
|
| 33 |
print("⚠️ OpenCV not available - using fallback")
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
# =============
|
| 36 |
# GEMMA 3 PRINCIPAL AI MANAGER
|
| 37 |
# =============
|
|
@@ -2091,325 +2102,3 @@ print("🔐 Configuração segura com secrets - zero tokens hardcoded")
|
|
| 2091 |
print("🧠 Prioriza Gemma 3 multimodal AI com sistemas de fallback inteligentes")
|
| 2092 |
print("🚀 Execute main() para lançar a aplicação aprimorada com Gemma 3")
|
| 2093 |
print("💡 Configure HF_TOKEN nas secrets do Space para ativar Gemma 3!")
|
| 2094 |
-
|
| 2095 |
-
# ==============================================================================
|
| 2096 |
-
# DEBUG COMPLETO - RESOLVER PROBLEMA HF_TOKEN NO HUGGING FACE SPACES
|
| 2097 |
-
# ==============================================================================
|
| 2098 |
-
|
| 2099 |
-
import os
|
| 2100 |
-
import requests
|
| 2101 |
-
import json
|
| 2102 |
-
from datetime import datetime
|
| 2103 |
-
|
| 2104 |
-
def debug_hf_token_complete():
|
| 2105 |
-
"""Debug completo do token HF para identificar o problema exato"""
|
| 2106 |
-
|
| 2107 |
-
print("🔍 INICIANDO DEBUG COMPLETO DO TOKEN HF...")
|
| 2108 |
-
print("=" * 60)
|
| 2109 |
-
|
| 2110 |
-
# 1. VERIFICAR TODAS AS FONTES DE TOKEN
|
| 2111 |
-
print("\n1️⃣ VERIFICANDO FONTES DE TOKEN:")
|
| 2112 |
-
|
| 2113 |
-
token_sources = {
|
| 2114 |
-
'HF_TOKEN': os.getenv("HF_TOKEN"),
|
| 2115 |
-
'HUGGINGFACE_HUB_TOKEN': os.getenv("HUGGINGFACE_HUB_TOKEN"),
|
| 2116 |
-
'HUGGING_FACE_TOKEN': os.getenv("HUGGING_FACE_TOKEN"),
|
| 2117 |
-
'HF_AUTH_TOKEN': os.getenv("HF_AUTH_TOKEN")
|
| 2118 |
-
}
|
| 2119 |
-
|
| 2120 |
-
found_tokens = {}
|
| 2121 |
-
|
| 2122 |
-
for name, value in token_sources.items():
|
| 2123 |
-
if value:
|
| 2124 |
-
# Mostrar informações do token (primeiros/últimos chars)
|
| 2125 |
-
preview = f"{value[:8]}...{value[-4:]}" if len(value) > 12 else value
|
| 2126 |
-
print(f" ✅ {name}: ENCONTRADO - {preview} ({len(value)} chars)")
|
| 2127 |
-
found_tokens[name] = value
|
| 2128 |
-
else:
|
| 2129 |
-
print(f" ❌ {name}: NÃO ENCONTRADO")
|
| 2130 |
-
|
| 2131 |
-
if not found_tokens:
|
| 2132 |
-
print("\n❌ PROBLEMA: Nenhum token encontrado!")
|
| 2133 |
-
print("🔧 SOLUÇÃO: Configure HF_TOKEN no secrets do Space")
|
| 2134 |
-
return False
|
| 2135 |
-
|
| 2136 |
-
# 2. VALIDAR FORMATO DOS TOKENS ENCONTRADOS
|
| 2137 |
-
print(f"\n2️⃣ VALIDANDO FORMATO DOS {len(found_tokens)} TOKENS ENCONTRADOS:")
|
| 2138 |
-
|
| 2139 |
-
valid_tokens = {}
|
| 2140 |
-
|
| 2141 |
-
for name, token in found_tokens.items():
|
| 2142 |
-
print(f"\n 🔍 Validando {name}:")
|
| 2143 |
-
|
| 2144 |
-
# Limpar token
|
| 2145 |
-
clean_token = token.strip() if token else ""
|
| 2146 |
-
|
| 2147 |
-
# Verificações detalhadas
|
| 2148 |
-
checks = {
|
| 2149 |
-
'não_vazio': bool(clean_token),
|
| 2150 |
-
'prefixo_hf': clean_token.startswith('hf_'),
|
| 2151 |
-
'comprimento_ok': 35 <= len(clean_token) <= 50,
|
| 2152 |
-
'caracteres_válidos': all(c.isalnum() or c == '_' for c in clean_token),
|
| 2153 |
-
'sem_espaços': ' ' not in clean_token and '\n' not in clean_token and '\t' not in clean_token
|
| 2154 |
-
}
|
| 2155 |
-
|
| 2156 |
-
for check, result in checks.items():
|
| 2157 |
-
status = "✅" if result else "❌"
|
| 2158 |
-
print(f" {status} {check}: {result}")
|
| 2159 |
-
|
| 2160 |
-
is_valid = all(checks.values())
|
| 2161 |
-
|
| 2162 |
-
if is_valid:
|
| 2163 |
-
print(f" 🎉 TOKEN {name} É VÁLIDO!")
|
| 2164 |
-
valid_tokens[name] = clean_token
|
| 2165 |
-
else:
|
| 2166 |
-
print(f" ❌ TOKEN {name} É INVÁLIDO")
|
| 2167 |
-
|
| 2168 |
-
# Sugestões específicas
|
| 2169 |
-
if not checks['prefixo_hf']:
|
| 2170 |
-
print(" 💡 Deve começar com 'hf_'")
|
| 2171 |
-
if not checks['comprimento_ok']:
|
| 2172 |
-
print(f" 💡 Deve ter 35-50 chars (atual: {len(clean_token)})")
|
| 2173 |
-
if not checks['caracteres_válidos']:
|
| 2174 |
-
print(" 💡 Apenas letras, números e underscore permitidos")
|
| 2175 |
-
if not checks['sem_espaços']:
|
| 2176 |
-
print(" 💡 Não pode ter espaços ou quebras de linha")
|
| 2177 |
-
|
| 2178 |
-
if not valid_tokens:
|
| 2179 |
-
print("\n❌ PROBLEMA: Nenhum token com formato válido!")
|
| 2180 |
-
print("🔧 SOLUÇÃO: Gere um novo token em https://huggingface.co/settings/tokens")
|
| 2181 |
-
return False
|
| 2182 |
-
|
| 2183 |
-
# 3. TESTAR AUTENTICAÇÃO COM TOKENS VÁLIDOS
|
| 2184 |
-
print(f"\n3️⃣ TESTANDO AUTENTICAÇÃO COM {len(valid_tokens)} TOKENS VÁLIDOS:")
|
| 2185 |
-
|
| 2186 |
-
working_tokens = {}
|
| 2187 |
-
|
| 2188 |
-
for name, token in valid_tokens.items():
|
| 2189 |
-
print(f"\n 🧪 Testando autenticação com {name}:")
|
| 2190 |
-
|
| 2191 |
-
try:
|
| 2192 |
-
# Teste básico com HF API
|
| 2193 |
-
response = requests.get(
|
| 2194 |
-
'https://api-inference.huggingface.co/models/gpt2',
|
| 2195 |
-
headers={
|
| 2196 |
-
'Authorization': f'Bearer {token}',
|
| 2197 |
-
'User-Agent': 'AdaptLearn/1.0'
|
| 2198 |
-
},
|
| 2199 |
-
timeout=10
|
| 2200 |
-
)
|
| 2201 |
-
|
| 2202 |
-
print(f" 📡 Status HTTP: {response.status_code}")
|
| 2203 |
-
print(f" 📡 Status Text: {response.reason}")
|
| 2204 |
-
|
| 2205 |
-
if response.status_code == 200:
|
| 2206 |
-
print(f" ✅ AUTENTICAÇÃO SUCESSO com {name}!")
|
| 2207 |
-
working_tokens[name] = token
|
| 2208 |
-
|
| 2209 |
-
# Testar acesso a modelo específico
|
| 2210 |
-
try:
|
| 2211 |
-
test_response = requests.post(
|
| 2212 |
-
'https://api-inference.huggingface.co/models/gpt2',
|
| 2213 |
-
headers={'Authorization': f'Bearer {token}'},
|
| 2214 |
-
json={'inputs': 'Test', 'parameters': {'max_new_tokens': 5}},
|
| 2215 |
-
timeout=15
|
| 2216 |
-
)
|
| 2217 |
-
|
| 2218 |
-
if test_response.status_code == 200:
|
| 2219 |
-
print(f" 🎉 GERAÇÃO DE TEXTO FUNCIONA com {name}!")
|
| 2220 |
-
else:
|
| 2221 |
-
print(f" ⚠️ Geração falhou: {test_response.status_code}")
|
| 2222 |
-
|
| 2223 |
-
except Exception as gen_error:
|
| 2224 |
-
print(f" ⚠️ Erro na geração: {gen_error}")
|
| 2225 |
-
|
| 2226 |
-
elif response.status_code == 401:
|
| 2227 |
-
print(f" ❌ FALHA DE AUTENTICAÇÃO: Token inválido ou expirado")
|
| 2228 |
-
print(f" 💡 Gere novo token em https://huggingface.co/settings/tokens")
|
| 2229 |
-
|
| 2230 |
-
elif response.status_code == 403:
|
| 2231 |
-
print(f" ❌ ACESSO NEGADO: Token sem permissões adequadas")
|
| 2232 |
-
print(f" 💡 Token precisa de permissão 'Read'")
|
| 2233 |
-
|
| 2234 |
-
elif response.status_code == 429:
|
| 2235 |
-
print(f" ⚠️ RATE LIMIT: Muitas requisições")
|
| 2236 |
-
print(f" 💡 Aguarde alguns minutos")
|
| 2237 |
-
|
| 2238 |
-
else:
|
| 2239 |
-
print(f" ❌ ERRO INESPERADO: {response.status_code}")
|
| 2240 |
-
try:
|
| 2241 |
-
error_detail = response.text[:200]
|
| 2242 |
-
print(f" Detalhes: {error_detail}")
|
| 2243 |
-
except:
|
| 2244 |
-
pass
|
| 2245 |
-
|
| 2246 |
-
except requests.exceptions.Timeout:
|
| 2247 |
-
print(f" ⏱️ TIMEOUT: Conexão muito lenta")
|
| 2248 |
-
|
| 2249 |
-
except requests.exceptions.ConnectionError:
|
| 2250 |
-
print(f" 🌐 ERRO DE CONEXÃO: Verifique internet")
|
| 2251 |
-
|
| 2252 |
-
except Exception as e:
|
| 2253 |
-
print(f" ❌ ERRO GERAL: {e}")
|
| 2254 |
-
|
| 2255 |
-
# 4. TESTAR ACESSO AO GEMMA ESPECIFICAMENTE
|
| 2256 |
-
if working_tokens:
|
| 2257 |
-
print(f"\n4️⃣ TESTANDO ACESSO AO GEMMA COM TOKENS FUNCIONAIS:")
|
| 2258 |
-
|
| 2259 |
-
gemma_models = [
|
| 2260 |
-
'google/gemma-2-2b-it',
|
| 2261 |
-
'google/gemma-2-9b-it',
|
| 2262 |
-
'google/gemma-1.1-7b-it'
|
| 2263 |
-
]
|
| 2264 |
-
|
| 2265 |
-
best_token = list(working_tokens.values())[0]
|
| 2266 |
-
best_token_name = list(working_tokens.keys())[0]
|
| 2267 |
-
|
| 2268 |
-
print(f" 🎯 Usando melhor token: {best_token_name}")
|
| 2269 |
-
|
| 2270 |
-
for model in gemma_models:
|
| 2271 |
-
print(f"\n 🧪 Testando {model}:")
|
| 2272 |
-
|
| 2273 |
-
try:
|
| 2274 |
-
response = requests.post(
|
| 2275 |
-
f'https://api-inference.huggingface.co/models/{model}',
|
| 2276 |
-
headers={'Authorization': f'Bearer {best_token}'},
|
| 2277 |
-
json={
|
| 2278 |
-
'inputs': 'Hello',
|
| 2279 |
-
'parameters': {'max_new_tokens': 10}
|
| 2280 |
-
},
|
| 2281 |
-
timeout=20
|
| 2282 |
-
)
|
| 2283 |
-
|
| 2284 |
-
if response.status_code == 200:
|
| 2285 |
-
print(f" 🎉 {model} FUNCIONANDO!")
|
| 2286 |
-
result = response.json()
|
| 2287 |
-
if result and len(result) > 0:
|
| 2288 |
-
generated = result[0].get('generated_text', '')[:50]
|
| 2289 |
-
print(f" 📝 Gerou: {generated}...")
|
| 2290 |
-
|
| 2291 |
-
elif response.status_code == 503:
|
| 2292 |
-
print(f" ⏳ {model} carregando (normal para modelos grandes)")
|
| 2293 |
-
|
| 2294 |
-
elif response.status_code == 404:
|
| 2295 |
-
print(f" ❌ {model} não encontrado ou sem acesso")
|
| 2296 |
-
|
| 2297 |
-
else:
|
| 2298 |
-
print(f" ⚠️ {model} status {response.status_code}")
|
| 2299 |
-
|
| 2300 |
-
except Exception as e:
|
| 2301 |
-
print(f" ❌ Erro: {e}")
|
| 2302 |
-
|
| 2303 |
-
# 5. RELATÓRIO FINAL E RECOMENDAÇÕES
|
| 2304 |
-
print(f"\n5️⃣ RELATÓRIO FINAL:")
|
| 2305 |
-
print("=" * 60)
|
| 2306 |
-
|
| 2307 |
-
if working_tokens:
|
| 2308 |
-
best_token_name = list(working_tokens.keys())[0]
|
| 2309 |
-
print(f"✅ STATUS: PROBLEMA RESOLVIDO!")
|
| 2310 |
-
print(f"🎉 Token funcionando: {best_token_name}")
|
| 2311 |
-
print(f"🔧 O sistema deveria funcionar com este token")
|
| 2312 |
-
|
| 2313 |
-
print(f"\n🚀 PRÓXIMOS PASSOS:")
|
| 2314 |
-
print(f"1. Reinicie o Space (Factory reboot)")
|
| 2315 |
-
print(f"2. Execute o teste novamente")
|
| 2316 |
-
print(f"3. O Gemma deveria carregar automaticamente")
|
| 2317 |
-
|
| 2318 |
-
return True, best_token_name, working_tokens[best_token_name]
|
| 2319 |
-
|
| 2320 |
-
else:
|
| 2321 |
-
print(f"❌ STATUS: PROBLEMA PERSISTE!")
|
| 2322 |
-
print(f"🔧 SOLUÇÃO DEFINITIVA:")
|
| 2323 |
-
print(f"1. Vá para https://huggingface.co/settings/tokens")
|
| 2324 |
-
print(f"2. DELETE o token atual: gemma3n-access")
|
| 2325 |
-
print(f"3. Crie NOVO token:")
|
| 2326 |
-
print(f" - Name: adaptlearn-fixed")
|
| 2327 |
-
print(f" - Type: Read")
|
| 2328 |
-
print(f" - Repositories: (deixe vazio)")
|
| 2329 |
-
print(f"4. COPIE o token EXATAMENTE como mostrado")
|
| 2330 |
-
print(f"5. Substitua o valor do secret HF_TOKEN")
|
| 2331 |
-
print(f"6. Factory reboot do Space")
|
| 2332 |
-
|
| 2333 |
-
return False, None, None
|
| 2334 |
-
|
| 2335 |
-
def fix_hf_token_in_code():
|
| 2336 |
-
"""Aplicar fix no código do Gemma3AIManager"""
|
| 2337 |
-
|
| 2338 |
-
print("\n🔧 APLICANDO FIX NO CÓDIGO...")
|
| 2339 |
-
|
| 2340 |
-
fix_code = '''
|
| 2341 |
-
def _setup_hf_token(self):
|
| 2342 |
-
"""Configurar token do Hugging Face - VERSÃO CORRIGIDA"""
|
| 2343 |
-
|
| 2344 |
-
print("🔐 Configurando autenticação Hugging Face...")
|
| 2345 |
-
|
| 2346 |
-
# Tentar obter token com limpeza rigorosa
|
| 2347 |
-
token_sources = [
|
| 2348 |
-
os.getenv("HF_TOKEN"),
|
| 2349 |
-
os.getenv("HUGGINGFACE_HUB_TOKEN"),
|
| 2350 |
-
os.getenv("HUGGING_FACE_TOKEN"),
|
| 2351 |
-
os.getenv("HF_AUTH_TOKEN"),
|
| 2352 |
-
]
|
| 2353 |
-
|
| 2354 |
-
for i, token in enumerate(token_sources):
|
| 2355 |
-
if token:
|
| 2356 |
-
# LIMPEZA RIGOROSA DO TOKEN
|
| 2357 |
-
token_clean = str(token).strip()
|
| 2358 |
-
|
| 2359 |
-
# Remover possíveis caracteres invisíveis
|
| 2360 |
-
token_clean = ''.join(char for char in token_clean if char.isprintable())
|
| 2361 |
-
|
| 2362 |
-
# Remover espaços, tabs, quebras de linha
|
| 2363 |
-
token_clean = token_clean.replace(' ', '').replace('\\t', '').replace('\\n', '')
|
| 2364 |
-
|
| 2365 |
-
print(f"🔍 Token fonte #{i+1}: comprimento {len(token_clean)}")
|
| 2366 |
-
print(f"🔍 Preview: {token_clean[:10]}...{token_clean[-4:]}")
|
| 2367 |
-
|
| 2368 |
-
# Validação rigorosa
|
| 2369 |
-
if (token_clean.startswith('hf_') and
|
| 2370 |
-
35 <= len(token_clean) <= 50 and
|
| 2371 |
-
all(c.isalnum() or c == '_' for c in token_clean)):
|
| 2372 |
-
|
| 2373 |
-
self.hf_token = token_clean
|
| 2374 |
-
print(f"✅ Token HF válido encontrado!")
|
| 2375 |
-
print(f"🎉 GEMMA 3 SERÁ DESBLOQUEADO!")
|
| 2376 |
-
|
| 2377 |
-
# Testar login imediatamente
|
| 2378 |
-
try:
|
| 2379 |
-
from huggingface_hub import login
|
| 2380 |
-
login(token=self.hf_token, add_to_git_credential=False)
|
| 2381 |
-
print("🎉 Login HF realizado com sucesso!")
|
| 2382 |
-
return True
|
| 2383 |
-
except Exception as e:
|
| 2384 |
-
print(f"⚠️ Erro no login: {e}")
|
| 2385 |
-
print("🔄 Token pode estar inválido")
|
| 2386 |
-
self.hf_token = None
|
| 2387 |
-
continue
|
| 2388 |
-
else:
|
| 2389 |
-
print(f"❌ Token #{i+1} formato inválido")
|
| 2390 |
-
if not token_clean.startswith('hf_'):
|
| 2391 |
-
print(" - Não começa com 'hf_'")
|
| 2392 |
-
if not (35 <= len(token_clean) <= 50):
|
| 2393 |
-
print(f" - Comprimento inválido: {len(token_clean)}")
|
| 2394 |
-
|
| 2395 |
-
print("❌ NENHUM TOKEN VÁLIDO ENCONTRADO")
|
| 2396 |
-
return False
|
| 2397 |
-
'''
|
| 2398 |
-
|
| 2399 |
-
print("📄 CÓDIGO CORRIGIDO:")
|
| 2400 |
-
print(fix_code)
|
| 2401 |
-
|
| 2402 |
-
return fix_code
|
| 2403 |
-
|
| 2404 |
-
# EXECUTAR DEBUG COMPLETO
|
| 2405 |
-
if __name__ == "__main__":
|
| 2406 |
-
print("🚀 EXECUTANDO DEBUG COMPLETO...")
|
| 2407 |
-
|
| 2408 |
-
success, token_name, token_value = debug_hf_token_complete()
|
| 2409 |
-
|
| 2410 |
-
if success:
|
| 2411 |
-
print(f"\n🎉 DEBUG CONCLUÍDO COM SUCESSO!")
|
| 2412 |
-
print(f"Token funcionando: {token_name}")
|
| 2413 |
-
else:
|
| 2414 |
-
print(f"\n🔧 CÓDIGO CORRIGIDO DISPONÍVEL")
|
| 2415 |
-
fix_hf_token_in_code()
|
|
|
|
| 32 |
OPENCV_AVAILABLE = False
|
| 33 |
print("⚠️ OpenCV not available - using fallback")
|
| 34 |
|
| 35 |
+
# DEBUG
|
| 36 |
+
import os
|
| 37 |
+
print("🔍 [DEBUG] Verificando secret:")
|
| 38 |
+
print(f"HF_TOKEN exists: {os.getenv('HF_TOKEN') is not None}")
|
| 39 |
+
print(f"HF_TOKEN value: {repr(os.getenv('HF_TOKEN'))}")
|
| 40 |
+
if os.getenv('HF_TOKEN'):
|
| 41 |
+
token = os.getenv('HF_TOKEN')
|
| 42 |
+
print(f"Token length: {len(token)}")
|
| 43 |
+
print(f"First 10 chars: {token[:10]}")
|
| 44 |
+
print(f"Last 4 chars: {token[-4:]}")
|
| 45 |
+
|
| 46 |
# =============
|
| 47 |
# GEMMA 3 PRINCIPAL AI MANAGER
|
| 48 |
# =============
|
|
|
|
| 2102 |
print("🧠 Prioriza Gemma 3 multimodal AI com sistemas de fallback inteligentes")
|
| 2103 |
print("🚀 Execute main() para lançar a aplicação aprimorada com Gemma 3")
|
| 2104 |
print("💡 Configure HF_TOKEN nas secrets do Space para ativar Gemma 3!")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|