o
    Êujj  ã                   @  s¶  d Z ddlmZ ddlZddlZddlmZmZmZmZ ddl	m
Z
 ddlZddlZddlmZmZmZmZmZmZmZ ddlZejZejZejZejZejZeeddƒp[ej dd¡Zeed	dƒphej d	d¡Z eed
dƒpuej d
d¡Z!e"e!ƒ #d¡r„ej $dd¡ dd„ Z%ede&ƒZ'dZ(dZ)dZ*dZ+g d¢Z,dddddddgdœdddddd d!gdœd"d#ddd$d%d&gdœd'd(ddd)d*d+gdœd,d-ddd.d*d+gdœd/d0ddd/d/d1gdœd2d3ddd4g d5¢dœd6d7d8d9d:d;d<gdœd=d>d?d9d@d;gdœdAdBdCd9dAdDdEgdœdFdGdCd9dFdHdIgdœdJdKd8d9dJdLgdœgZ-dMdN„ e-D ƒZ.dOdP„ Z/d¹dQdR„Z0dºdUdV„Z1d»dXdY„Z2d¼d[d\„Z3ddddddd]œd½dgdh„Z4didj„ Z5d¾dldm„Z6dndo„ Z7dddpœd¿dwdx„Z8dÀdÁd{d|„Z9dÂdd€„Z:dÃd‚dƒ„Z;dÄd‡dˆ„Z<dÅdŽd�„Z=dÆd‘d’„Z>dÇd”d•„Z?dÈd—d˜„Z@e' Ad™¡dšd›„ ƒZBe' Adœ¡d�dž„ ƒZCe' AdŸ¡d d¡„ ƒZDe'jAd¢d£gd¤�d¥d¦„ ƒZEe' Ad§¡d¨d©„ ƒZFe' Adª¡d«d¬„ ƒZGe' Ad­¡d®d¯„ ƒZHe' Ad°¡d±d²„ ƒZIe' Ad³¡d´dµ„ ƒZJe' Ad¶¡d·d¸„ ƒZKdS )Éz†
Fitness Tracker: Google Health API explorer (OAuth + data probe UI).
Single-user personal server; tokens stored in MySQL shop_stats.
é    )ÚannotationsN)ÚdateÚdatetimeÚ	timedeltaÚtimezone)ÚAny)Ú	BlueprintÚjsonifyÚredirectÚrender_templateÚrequestÚsessionÚurl_forÚGOOGLE_HEALTH_CLIENT_IDÚ ÚGOOGLE_HEALTH_CLIENT_SECRETÚGOOGLE_HEALTH_REDIRECT_URIz6http://192.168.50.5:5000/fitnesstracker/oauth/callbackzhttp://ÚOAUTHLIB_INSECURE_TRANSPORTÚ1c               
   C  sV   zddl m}  ddlm} ddlm} W n ty% } ztdƒ|‚d}~ww | ||fS )zJLazy-import Google OAuth libs so missing packages don't break app startup.r   )ÚRequest)ÚCredentials)ÚFlowz_Google OAuth packages not installed. Run: pip install google-auth google-auth-oauthlib requestsN)Úgoogle.auth.transport.requestsr   Úgoogle.oauth2.credentialsr   Úgoogle_auth_oauthlib.flowr   ÚImportErrorÚRuntimeError)ÚGoogleAuthRequestr   r   Úexc© r   ú1/var/www/html/Server/blueprints/fitnesstracker.pyÚ_google_libs+   s   ÿý€ÿ
r!   Úfitnesstrackerz https://health.googleapis.com/v4z#https://oauth2.googleapis.com/tokenz,https://accounts.google.com/o/oauth2/v2/authz$https://oauth2.googleapis.com/revoke)zJhttps://www.googleapis.com/auth/googlehealth.activity_and_fitness.readonlyzUhttps://www.googleapis.com/auth/googlehealth.health_metrics_and_measurements.readonlyz;https://www.googleapis.com/auth/googlehealth.sleep.readonlyz=https://www.googleapis.com/auth/googlehealth.profile.readonlyz>https://www.googleapis.com/auth/googlehealth.settings.readonlyÚopenidz.https://www.googleapis.com/auth/userinfo.emailz0https://www.googleapis.com/auth/userinfo.profileÚstepsÚStepsÚintervalÚdailyRollUpÚcountÚcountSum)ÚidÚlabelÚkindÚmethodÚfilter_stemÚ
value_keysÚdistanceÚDistanceÚdistanceMillimetersÚdistanceMillimetersSumúactive-minuteszActive MinutesÚactive_minutesÚminutesÚ
minutesSumzactive-energy-burnedzActive Energy BurnedÚactive_energy_burnedÚenergyKilocaloriesÚenergyKilocaloriesSumútotal-calorieszTotal CaloriesÚtotal_caloriesÚfloorsÚFloorsÚ	floorsSumzactive-zone-minuteszActive Zone MinutesÚactive_zone_minutes)ÚtotalMinutesÚtotalMinutesSumÚfatBurnMinutesSumú
heart-ratez
Heart RateÚsampleÚlistÚ
heart_rateÚbeatsPerMinuteÚbeatsPerMinuteAvgzdaily-resting-heart-ratezDaily Resting Heart RateÚdailyÚdaily_resting_heart_rateÚsleepÚSleepr   ÚminutesAsleepÚminutesInBedÚexerciseÚExerciseÚactivityNameÚcaloriesÚweightÚWeightÚweightKilogramsc                 C  s   i | ]}|d  |“qS )r*   r   ©Ú.0Údr   r   r    Ú
<dictcomp>¯   s    rZ   c                	   C  s   t jtttttt jjdd�S )NT)ÚhostÚportÚuserÚpasswordÚdatabaseÚcursorclassÚ
autocommit)	ÚpymysqlÚconnectÚ
MYSQL_HOSTÚ
MYSQL_PORTÚ
MYSQL_USERÚMYSQL_PASSWORDÚMYSQL_DATABASEÚcursorsÚ
DictCursorr   r   r   r    Ú	_get_conn²   s   ùrk   c                 C  sl   | d u }|r	t ƒ } z$|  ¡ �}| d¡ W d   ƒ n1 sw   Y  W |r,|  ¡  d S d S |r5|  ¡  w w )Na>  
                CREATE TABLE IF NOT EXISTS fitness_oauth_tokens (
                    id TINYINT NOT NULL PRIMARY KEY,
                    refresh_token TEXT,
                    access_token TEXT,
                    token_expiry DATETIME NULL,
                    scopes TEXT,
                    email VARCHAR(255) NULL,
                    profile_json MEDIUMTEXT NULL,
                    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
                        ON UPDATE CURRENT_TIMESTAMP
                ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
                )rk   ÚcursorÚexecuteÚclose)ÚconnÚownÚcurr   r   r    Úensure_fitness_tables¾   s   
ÿÿ€ÿ
ÿrr   ÚreturnÚboolc                   C  s   t totƒS ©N)rt   r   r   r   r   r   r    Ú_client_configuredØ   s   rv   Údictc                   C  s   dt ttttgdœiS )NÚweb)Ú	client_idÚclient_secretÚauth_uriÚ	token_uriÚredirect_uris)r   r   ÚAUTH_URIÚ	TOKEN_URIr   r   r   r   r    Ú_oauth_client_configÜ   s   ûÿr€   údict | Nonec                  C  sj   t ƒ  tƒ } z)|  ¡ �}| d¡ | ¡ W  d   ƒ W |  ¡  S 1 s$w   Y  W |  ¡  d S |  ¡  w )Nz/SELECT * FROM fitness_oauth_tokens WHERE id = 1)rr   rk   rl   rm   Úfetchonern   ©ro   rq   r   r   r    Ú_load_token_rowè   s   

þ
ür„   ©Úrefresh_tokenÚaccess_tokenÚexpiryÚscopesÚemailÚprofile_jsonr†   ú
str | Noner‡   rˆ   údatetime | Noner‰   úlist[str] | NonerŠ   r‹   c              
   C  s   t ƒ  tƒ pi }| du r| d¡} |du r| d¡}|du r#| d¡}|du r,| d¡}|dur6d |¡}n| d¡p<d}|durT|jdurQ| tj¡jdd	�}n|}n| d
¡}t	ƒ }	z.|	 
¡ �}
|
 d| |||||f¡ W d  ƒ n1 sxw   Y  W |	 ¡  dS W |	 ¡  dS |	 ¡  w )zEUpsert the single personal token row. None args keep existing values.Nr†   r‡   rŠ   r‹   ú r‰   r   ©ÚtzinfoÚtoken_expiryaO  
                INSERT INTO fitness_oauth_tokens
                    (id, refresh_token, access_token, token_expiry, scopes, email, profile_json)
                VALUES
                    (1, %s, %s, %s, %s, %s, %s)
                ON DUPLICATE KEY UPDATE
                    refresh_token = VALUES(refresh_token),
                    access_token = VALUES(access_token),
                    token_expiry = VALUES(token_expiry),
                    scopes = VALUES(scopes),
                    email = VALUES(email),
                    profile_json = VALUES(profile_json)
                )rr   r„   ÚgetÚjoinr‘   Ú
astimezoner   ÚutcÚreplacerk   rl   rm   rn   )r†   r‡   rˆ   r‰   rŠ   r‹   ÚrowÚ
scopes_strÚexpiry_naivero   rq   r   r   r    Ú_save_tokensó   sF   








úòÿçr›   c                  C  sf   t ƒ  tƒ } z'|  ¡ �}| d¡ W d   ƒ n1 sw   Y  W |  ¡  d S W |  ¡  d S |  ¡  w )Nz-DELETE FROM fitness_oauth_tokens WHERE id = 1)rr   rk   rl   rm   rn   rƒ   r   r   r    Ú_clear_tokens4  s   
ÿýrœ   r˜   c              	   C  s‚   | r|   d¡s	d S tƒ \}}}|   d¡}t|tƒr%|jd u r%|jtjd�}|   d¡p+d ¡ }||   d¡|   d¡t	t
t|p=t|d�S )Nr†   r’   r�   r‰   r   r‡   )Útokenr†   r|   ry   rz   r‰   rˆ   )r“   r!   Ú
isinstancer   r‘   r—   r   r–   Úsplitr   r   r   ÚOAUTH_SCOPES)r˜   Ú_r   rˆ   r‰   r   r   r    Ú_credentials_from_row>  s    
ùr¢   c                  C  s˜   t ƒ sd S tƒ } | rt| ƒnd }|sd S |jsJ|jrH|jrHztƒ \}}}| |ƒ ¡ W n
 ty5   Y d S w t	|j|j
|jt|jpBg ƒd� |S d S |S )N)r†   r‡   rˆ   r‰   )rv   r„   r¢   ÚvalidÚexpiredr†   r!   ÚrefreshÚ	Exceptionr›   r�   rˆ   rF   r‰   )r˜   Úcredsr   r¡   r   r   r    Ú_get_valid_credentialsQ  s.   ÿüÿr¨   )ÚparamsÚ	json_bodyr-   ÚstrÚpathr©   rª   ú*tuple[dict | list | None, int, str | None]c             
   C  sT  t ƒ }|r|js
dS t› d| d¡› �}d|j› �ddœ}ztj| ||||dd�}W n tjyE } zd dd	|› �fW  Y d }~S d }~ww |jd
ksN|jsTi |jd fS z| 	¡ }	W n t
yp   d |j|jd d… pldf Y S w |jdkr¤t|	tƒr�|	 di ¡ni }
t|
tƒr�|
 d¡nd }|sž|jd d… p�d|j› �}|	|j|fS |	|jd fS )N)Ni‘  zNot connected to Google Healthú/úBearer úapplication/json©ÚAuthorizationÚAccepté<   )Úheadersr©   ÚjsonÚtimeoutiö  zUpstream request failed: éÌ   éô  zNon-JSON responseé�  ÚerrorÚmessagezHTTP )r¨   r�   ÚHEALTH_API_BASEÚlstripÚrequestsr   ÚRequestExceptionÚstatus_codeÚcontentr¶   Ú
ValueErrorÚtextrž   rw   r“   )r-   r¬   r©   rª   r§   Úurlrµ   Úrespr   ÚdataÚerrr¼   r   r   r    Ú_health_requestj  sD   

þ
ú€ÿÿ
rÉ   rY   r   c                 C  s"   | j | j| jdœ|||ddœdœS )N©ÚyearÚmonthÚdayr   )Úhoursr6   ÚsecondsÚnanos)r   ÚtimerÊ   )rY   rÎ   r6   rÏ   r   r   r    Ú_civil_datetime–  s   þrÒ   ÚvalueÚdefaultc                 C  s4   | s|S z
t  | d d… ¡W S  ty   | Y S w )Né
   )r   ÚfromisoformatrÃ   )rÓ   rÔ   r   r   r    Ú_parse_date�  s   ÿr×   Údata_type_idc                 C  s   |   dd¡S )Nú-r¡   )r—   )rØ   r   r   r    Ú_camel_to_snake_stem¦  s   rÚ   ÚmetaÚstartÚend_exclusivec           	      C  s  |   d¡p
t| d ƒ}| d }| ¡ }| ¡ }|dkr)|› d|› d|› d|› d�S |d	krE|› d
�}|› d
�}|› d|› d|› d|› d�S |dkrW|› d|› d|› d|› d�S | d dkru|› d
�}|› d
�}|› d|› d|› d|› d�S |› d|› d|› d|› d�S )Nr.   r*   r,   r&   z.interval.civil_start_time >= "z" AND z.interval.civil_start_time < "ú"rE   z
T00:00:00Zz.sample_time.physical_time >= "z.sample_time.physical_time < "rJ   z
.date >= "z	.date < "rL   z.interval.end_time >= "z.interval.end_time < ")r“   rÚ   Ú	isoformat)	rÛ   rÜ   rÝ   Ústemr,   Ústart_sÚend_sÚstart_zÚend_zr   r   r    Ú_build_list_filter«  sJ   ÿÿÿ

ÿÿÿ

ÿÿÿÿÿÿrå   Úobjr   Úkeysú	list[str]úfloat | Nonec              
   C  sÜ   t | tƒsd S |D ]!}|| v r*| | d ur*z	t| | ƒW   S  ttfy)   Y q	w q	|  ¡ D ]<}t |ttfƒrCt |tƒsCt|ƒ  S t |tƒrYzt|ƒW   S  tyX   Y q/w t |tƒrkt	||ƒ}|d urk|  S q/d S ru   )
rž   rw   ÚfloatÚ	TypeErrorrÃ   ÚvaluesÚintrt   r«   Ú_first_numeric)ræ   rç   ÚkeyrÓ   Únestedr   r   r    rî   Í  s2   
ÿ€
ÿ

€rî   Úcivilc              
   C  s|   t | tƒsd S |  d¡pi }z"t|d ƒt|d ƒt|d ƒ}}}|d›d|d›d|d›�W S  tttfy=   Y d S w )Nr   rË   rÌ   rÍ   Ú04drÙ   Ú02d)rž   rw   r“   rí   ÚKeyErrorrë   rÃ   )rñ   rY   ÚyÚmrÍ   r   r   r    Ú_civil_labelå  s   
(ÿr÷   Úpointc                 C  s¾   d  dd„ t| d¡ƒD ƒ¡}|r#|d  ¡ r#|d  ¡ |dd …  }| dd¡}|||fD ]}|| v rAt| | tƒrA| |   S q.h d£}|  ¡ D ]\}}||v rSqJt|tƒr\|  S qJd S )	Nr   c                 s  s$   � | ]\}}|r|  ¡ n|V  qd S ru   )Ú
capitalize)rX   ÚiÚpartr   r   r    Ú	<genexpr>ò  s
   € ÿ
ÿz$_payload_for_type.<locals>.<genexpr>rÙ   r   é   r¡   >	   r   Únamer&   Ú
createTimeÚ
dataSourceÚ
sampleTimeÚ
updateTimeÚcivilEndTimeÚcivilStartTime)	r”   Ú	enumeraterŸ   ÚisupperÚlowerr—   rž   rw   Úitems)rø   rØ   ÚcamelÚsnakerï   ÚskiprÓ   r   r   r    Ú_payload_for_typeð  s$   
þ€
ÿr  Úrawc                 C  s  g }g }g }|   d¡pg }|dkrF|  d¡pg D ],}t|  d¡ƒp"d}t|| d ƒp+i }	t|	|ƒ}
| |¡ | |
¡ | ||
|	dœ¡ qny|  d¡pLg D ]q}t|| d ƒpWi }	d }|  d	¡p`i }|  d
¡pgi }t|  d¡ƒp�|  d¡p�t|  d¡ƒp�|  d¡p�td|  d¡iƒp�|  d¡p�d}t|  d¡tƒr¢td|d iƒp¡|}t|	|ƒ}
| t|ƒ¡ | |
¡ | t|ƒ|
|	dœ¡ qMdd„ |D ƒ}t|ƒt|ƒ|rÒt	|ƒnd |rÝt	|ƒt|ƒ nd |rät
|ƒnd |rët|ƒnd |rò|d nd dœ}|||||dk�rddœS ddœS )Nr/   r'   ÚrollupDataPointsr  ú?r*   )r+   rÓ   ÚpayloadÚ
dataPointsr&   r  Ú	startTimeÚ	civilTimeÚphysicalTimer   rþ   c                 S  s   g | ]}|d ur|‘qS ru   r   )rX   Úvr   r   r    Ú
<listcomp>5  s    z%_normalize_series.<locals>.<listcomp>r   )r(   ÚnumericCountÚsumÚavgÚminÚmaxÚlatestÚbarÚline)Úlabelsrì   ÚpointsÚsummaryÚ	chartType)r“   r÷   r  rî   Úappendrž   rw   r«   Úlenr  r  r  )rÛ   r  r-   r  rì   Ú
points_outr/   Úitemr+   r  Únumr&   rE   Únumericr!  r   r   r    Ú_normalize_series  sl   


úÿþýüûù	

ù
ûûr)  r®   c                   C  s   t ƒ  tdttƒ td�S )Nzfitnesstracker/index.html)Ú
data_typesÚclient_configuredÚredirect_uri)rr   r   Ú
DATA_TYPESrv   r   r   r   r   r    ÚindexH  s   ür.  z/oauth/startc               
   C  s‚   t ƒ sdS ztƒ \} } }W n ty% } zt|ƒdfW  Y d }~S d }~ww |jtƒ ttd�}|jdddd�\}}|t	d< t
|ƒS )	N)zqGoogle Health OAuth is not configured. Set GOOGLE_HEALTH_CLIENT_ID and GOOGLE_HEALTH_CLIENT_SECRET in config.env.r¹   r¹   )r‰   r,  ÚofflineÚtrueÚconsent)Úaccess_typeÚinclude_granted_scopesÚpromptÚfitness_oauth_state)rv   r!   r   r«   Úfrom_client_configr€   r    r   Úauthorization_urlr   r
   )r¡   r   r   ÚflowÚauth_urlÚstater   r   r    Úoauth_startS  s(   €ÿý
ýr;  z/oauth/callbackc               
   C  sº  t ƒ sdS tj d¡} | rd| › �dfS t dd ¡}|r$|tj d¡kr&dS ztƒ \}}}W n tyF } zt|ƒdfW  Y d }~S d }~ww |j	t
ƒ t|td	�}z	|jtjd
� W n tys } zd|› �dfW  Y d }~S d }~ww |j}d }ztjddd|j› �idd�}|jr’| ¡  d¡}W n
 tjy�   Y nw d }	ztjt› d�d|j› �ddœdd�}
|
jr¹|
j}	W n
 tjyÄ   Y nw t|j|j|jt|jpÑtƒ||	d� ttdƒƒS )N)zOAuth not configuredr¹   r»   zGoogle OAuth error: rº   r5  r:  )zInvalid OAuth staterº   r¹   )r‰   r:  r,  )Úauthorization_responsezToken exchange failed: z-https://www.googleapis.com/oauth2/v2/userinfor²   r¯   é   )rµ   r·   rŠ   z/users/me/profiler°   r±   r…   zfitnesstracker.index)rv   r   Úargsr“   r   Úpopr!   r   r«   r6  r€   r    r   Úfetch_tokenrÅ   r¦   Úcredentialsr¿   r�   Úokr¶   rÀ   r½   rÄ   r›   r†   rˆ   rF   r‰   r
   r   )rÈ   r:  r¡   r   r   r8  r§   rŠ   ÚinfoÚprofile_snippetÚprefr   r   r    Úoauth_callbackm  s|   €ÿü€ÿý€ÿý€ÿúrF  z/oauth/disconnectÚPOST)Úmethodsc                  C  sf   t ƒ } d }| r|  d¡p|  d¡}|r*ztjtd|idd� W n
 tjy)   Y nw tƒ  tddiƒS )Nr†   r‡   r�   é   )rÇ   r·   rB  T)r„   r“   r¿   ÚpostÚ
REVOKE_URIrÀ   rœ   r	   )r˜   r�   r   r   r    Úoauth_disconnect«  s   ÿrL  z/api/statusc                  C  sà   t ƒ  tƒ } tƒ }t|o| d¡ƒ}d}|rtƒ d u}d }|r;| d¡r;z	t |d ¡}W n tt	fy:   d }Y nw t
| |||rF| d¡nd |rR| d¡pOd ¡ ng |rc| d¡rc| d¡jdd	�nd t|d
d„ tD ƒdœ	ƒS )Nr†   Fr‹   rŠ   r‰   r   Ú
updated_atr�   )Úsepc                 S  s*   g | ]}|d  |d |d |d dœ‘qS )r*   r+   r-   r,   )r*   r+   r-   r,   r   rW   r   r   r    r  Õ  s    ÿÿzapi_status.<locals>.<listcomp>)	Ú
configuredÚ	connectedÚcredentialsValidrŠ   r‰   Ú	updatedAtÚredirectUriÚprofileÚ	dataTypes)rr   rv   r„   rt   r“   r¨   r¶   Úloadsrë   rÃ   r	   rŸ   rß   r   r-  )rO  r˜   rP  Úcreds_okrT  r   r   r    Ú
api_statusº  s@   
ÿÿÿþõÿrX  z/api/profilec                  C  sf   t ddƒ\} }}|rtd|| dœƒ|fS ztd d d d t | ¡d� W n	 ty+   Y nw td| dœƒS )NÚGETzusers/me/profileF©rB  r»   r  )r†   r‡   rˆ   r‰   r‹   T©rB  rÇ   )rÉ   r	   r›   r¶   Údumpsr¦   ©rÇ   ÚstatusrÈ   r   r   r    Úapi_profileÝ  s   
ûÿr_  z/api/settingsc                  C  ó6   t ddƒ\} }}|rtd|| dœƒ|fS td| dœƒS )NrY  zusers/me/settingsFrZ  Tr[  ©rÉ   r	   r]  r   r   r    Úapi_settingsð  ó   rb  z/api/identityc                  C  r`  )NrY  zusers/me/identityFrZ  Tr[  ra  r]  r   r   r    Úapi_identityø  rc  rd  z/api/explorec                  C  s  t j d¡pd ¡ } t | ¡}|stdd| › �dœƒdfS t ¡ }|tdd� }t	t j d	¡|ƒ}t	t j d
¡|ƒ}||k rC||}}|tdd� }t j d¡pS|d  ¡ }|dvrctdddœƒdfS || j
}| dv rndnd}	|dkrˆ||	krˆtdd| › d|	› d�dœƒdfS d| › �}
d }d}d }||
dœ}|dkr¹t|||ƒ}|ddœ}||d< td|
› d�|d�\}}}nt|ƒt|ƒd œddd!œ}||d"< td#|
› d$�|d%�\}}}|råtd|||| d&œƒ|fS t||pêi |ƒ}td'| |d( | ¡ | ¡ ||||d)œ	ƒS )*NÚdataTyper$   FzUnknown dataType: )rB  r»   rº   é   )ÚdaysrÜ   Úendrý   r-   )rF   r'   z"method must be list or dailyRollUp>   úcalories-in-heart-rate-zonerD   r4   r;   é   éZ   r'   zdailyRollUp max range for z is z dayszusers/me/dataTypes/éÈ   )r-   ÚparentrF   iè  )ÚfilterÚpageSizer©   rY  z/dataPoints)r©   )rÜ   rh  )ÚrangeÚwindowSizeDaysro  ÚbodyrG  z/dataPoints:dailyRollUp)rª   )rB  r»   r   r  re  Tr+   )	rB  re  r+   rÜ   rh  r-   r   Úseriesr  )r   r>  r“   ÚstripÚ_DATA_TYPE_BY_IDr	   r   Útodayr   r×   rg  rå   rÉ   rÒ   r)  rß   )Ú	data_typerÛ   rv  Údefault_startrÜ   Úend_inclusiverÝ   r-   Ú	span_daysÚmax_daysrm  r  r^  rÈ   Úrequest_infoÚfiltr©   rr  rs  r   r   r    Úapi_explore   s�   


ûþÿû


ÿþúÿûÿø
÷ÿr~  z/api/healthc                   C  s   t ddtƒ dœƒS )NTr"   )rB  ÚservicerO  )r	   rv   r   r   r   r    Ú
api_healthZ  s   ýÿr€  ru   )rs   rt   )rs   rw   )rs   r�   )r†   rŒ   r‡   rŒ   rˆ   r�   r‰   rŽ   rŠ   rŒ   r‹   rŒ   )r˜   rw   )
r-   r«   r¬   r«   r©   r�   rª   r�   rs   r­   )r   r   r   )rY   r   rs   rw   )rÓ   rŒ   rÔ   r   rs   r   )rØ   r«   rs   r«   )rÛ   rw   rÜ   r   rÝ   r   rs   r«   )ræ   r   rç   rè   rs   ré   )rñ   r�   rs   rŒ   )rø   rw   rØ   r«   rs   r�   )rÛ   rw   r  rw   r-   r«   rs   rw   )LÚ__doc__Ú
__future__r   r¶   Úosr   r   r   r   Útypingr   rb   r¿   Úflaskr   r	   r
   r   r   r   r   ÚconfigÚ_configrd   re   rh   rf   rg   ÚgetattrÚenvironr“   r   r   r   r«   Ú
startswithÚ
setdefaultr!   Ú__name__Úbpr½   r   r~   rK  r    r-  ru  rk   rr   rv   r€   r„   r›   rœ   r¢   r¨   rÉ   rÒ   r×   rÚ   rå   rî   r÷   r  r)  Úrouter.  r;  rF  rL  rX  r_  rb  rd  r~  r€  r   r   r   r    Ú<module>   s\   $ÿÿþýþü

ú	ú	ú	ú	ú	ú	ú	ú	ú	ú	ú	ú§c



ùA

û,

	

"


!7



=

"



Y