§
   —&Â6b–Óã                   óö  — d Z ddlZddlZddlZddlZdZdZdad„ Zd„ Z	dZ
dZd	Zd
Z G d„ dej        ¦  «        ZdHd„Zd„ Z G d„ d¦  «        ZdHd„Zd„ Zd„ ZdId„ZdJd„Zd„ Zd„ Zd„ Zd„ ZdHd„Zd„ ZdJd„Zd„ Zd„ Z dJd „Z!d!„ Z"d"„ Z#d#„ Z$dKd$„Z%dKd%„Z&dLd&„Z'dJd'„Z(dMd)„Z)d*„ Z*d+„ Z+d,„ Z,d-„ Z-dHd.„Z.dNd0„Z/dKd1„Z0dOd3„Z1dJd4„Z2d5„ Z3dLd6„Z4dHd7„Z5d8„ Z6d9„ Z7d:„ Z8d;Z9dHd<„Z:d=„ Z;d>„ Z<d?„ Z=d@„ Z>dAZ?dHdB„Z@dC„ ZAdD„ ZBdE„ ZCdF„ ZDdG„ ZEdS )PzÒSQLite store of the addon library (docs/plan/milionar-library/030).

The only module that runs SQL. One connection per call (plugin and service
processes both use it), WAL journal, every write one transaction.
é    Né   z
library.dbc                 ó
   — | a dS )z*Tests point the store at a temporary file.N)Ú_override_path©Úpaths    ú`/Users/chudy/Library/Application Support/Kodi/addons/plugin.video.milionar/wcs/library2/store.pyÚset_pathr	      s   € ð €N€N€Nó    c                  ó–   — t           rt           S dd l} t          j                             |                      d¦  «        t          ¦  «        S )Nr   z3special://profile/addon_data/plugin.video.milionar/)r   ÚxbmcvfsÚosr   ÚjoinÚtranslatePathÚDB_NAME)r   s    r   Údb_pathr      s?   € Ýð ÝÐØ€N€N€NÝŒ7�<Š<˜×-Ò-Ð.cÑdÔdÕfmÑnÔnÐnr
   a2  
CREATE TABLE titles(
  media_type TEXT NOT NULL CHECK(media_type IN ('movie','tv')),
  tmdb_id INTEGER NOT NULL,
  in_list INTEGER NOT NULL DEFAULT 0,
  list_added_at INTEGER,
  list_pos INTEGER,
  legacy_json TEXT,
  hidden_from_continue_at INTEGER,
  last_activity_at INTEGER,
  PRIMARY KEY(media_type, tmdb_id));
CREATE TABLE movie_state(
  tmdb_id INTEGER PRIMARY KEY,
  playcount INTEGER NOT NULL DEFAULT 0, last_played_at INTEGER,
  resume_pos REAL NOT NULL DEFAULT 0, resume_total REAL NOT NULL DEFAULT 0,
  last_ident TEXT, last_provider TEXT, last_file_name TEXT, mirrored_at INTEGER);
CREATE TABLE episode_state(
  show_id INTEGER NOT NULL, season INTEGER NOT NULL, episode INTEGER NOT NULL,
  playcount INTEGER NOT NULL DEFAULT 0, last_played_at INTEGER,
  resume_pos REAL NOT NULL DEFAULT 0, resume_total REAL NOT NULL DEFAULT 0,
  last_ident TEXT, last_provider TEXT, last_file_name TEXT, mirrored_at INTEGER,
  PRIMARY KEY(show_id, season, episode));
CREATE TABLE play_log(
  id INTEGER PRIMARY KEY, media_type TEXT, tmdb_id INTEGER, season INTEGER, episode INTEGER,
  started_at INTEGER, ended_at INTEGER, position REAL, total REAL, outcome TEXT);
CREATE TABLE meta(key TEXT PRIMARY KEY, json TEXT NOT NULL, fetched_at INTEGER NOT NULL, ttl INTEGER NOT NULL);
CREATE TABLE flags(key TEXT PRIMARY KEY, value TEXT);
zý
ALTER TABLE movie_state ADD COLUMN mirrored_playcount INTEGER;
ALTER TABLE movie_state ADD COLUMN mirrored_resume_pos REAL;
ALTER TABLE episode_state ADD COLUMN mirrored_playcount INTEGER;
ALTER TABLE episode_state ADD COLUMN mirrored_resume_pos REAL;
aÊ  
ALTER TABLE movie_state ADD COLUMN state_version INTEGER NOT NULL DEFAULT 0;
ALTER TABLE episode_state ADD COLUMN state_version INTEGER NOT NULL DEFAULT 0;
CREATE TABLE mirror_pending(
  media_type TEXT NOT NULL, tmdb_id INTEGER NOT NULL,
  season INTEGER NOT NULL, episode INTEGER NOT NULL,
  version INTEGER NOT NULL, attempts INTEGER NOT NULL DEFAULT 0,
  next_attempt REAL NOT NULL DEFAULT 0,
  PRIMARY KEY(media_type,tmdb_id,season,episode));
CREATE TABLE pending_marks(
  id INTEGER PRIMARY KEY, media_type TEXT NOT NULL, tmdb_id INTEGER NOT NULL,
  kind TEXT NOT NULL, season INTEGER, episode INTEGER, watched INTEGER NOT NULL,
  attempts INTEGER NOT NULL DEFAULT 0, next_attempt REAL NOT NULL DEFAULT 0);
zø
CREATE TABLE feedback(
  media_type TEXT NOT NULL CHECK(media_type IN ('movie','tv')),
  tmdb_id INTEGER NOT NULL,
  value TEXT NOT NULL CHECK(value IN ('like','dislike','hide','pick')),
  at INTEGER NOT NULL,
  PRIMARY KEY(media_type, tmdb_id));
c                   ó   — e Zd ZdS )Ú_ConnectionN)Ú__name__Ú
__module__Ú__qualname__© r
   r   r   r   \   s   € € € € € Ø€Dr
   r   c                 ó²  — | pt          ¦   «         } t          j                             | ¦  «        }|rt          j        |d¬¦  «         t          j        | dd t          ¬¦  «        }t          ¦   «         |_	        t
          j
        |_        |                     d¦  «         |                     d¦  «         |                     d¦  «         t          |¦  «         |S )NT)Úexist_okg      @)ÚtimeoutÚisolation_levelÚfactoryzPRAGMA busy_timeout=5000zPRAGMA journal_mode=WALzPRAGMA foreign_keys=ON)r   r   r   ÚdirnameÚmakedirsÚsqlite3Úconnectr   ÚsetÚwidget_rowsÚRowÚrow_factoryÚexecuteÚ_migrate)r   ÚfolderÚconns      r   r    r    `   s·   € ØÐ•7‘9”9€DÝŒW�_Š_˜TÑ"Ô"€FØð +Ý
Œ�F TÐ*Ñ*Ô*Ð*ÝŒ?˜4¨¸dÍKÐXÑXÔX€DÝ‘u”u€DÔÝ”{€DÔØ‡L‚LÐ+Ñ,Ô,Ð,Ø‡L‚LÐ*Ñ+Ô+Ð+Ø‡L‚LÐ)Ñ*Ô*Ð*ÝˆT�N„N€NØ€Kr
   c                 ó¼  — |                       d¦  «                             ¦   «         d         }|t          k    rd S |                       d¦  «         	 |                       d¦  «                             ¦   «         d         }|dk     rXt                               ¦   «                              d¦  «        D ]+}|                     ¦   «         r|                       |¦  «         Œ,|dk     rXt                               ¦   «                              d¦  «        D ]+}|                     ¦   «         r|                       |¦  «         Œ,|dk     rXt                               ¦   «                              d¦  «        D ]+}|                     ¦   «         r|                       |¦  «         Œ,|dk     rXt                               ¦   «                              d¦  «        D ]+}|                     ¦   «         r|                       |¦  «         Œ,|                       d	 	                    t          ¦  «        ¦  «         |                       d
¦  «         d S # t          $ r |                       d¦  «         ‚ w xY w)NzPRAGMA user_versionr   úBEGIN IMMEDIATEé   ú;é   é   r   zPRAGMA user_version={}ÚCOMMITÚROLLBACK)r%   ÚfetchoneÚSCHEMA_VERSIONÚ	SCHEMA_V1ÚstripÚsplitÚ	SCHEMA_V2Ú	SCHEMA_V3Ú	SCHEMA_V4ÚformatÚ	Exception)r(   ÚversionÚ	statements      r   r&   r&   o   s-  € Ø�lŠlÐ0Ñ1Ô1×:Ò:Ñ<Ô<¸QÔ?€GØ•.Ò Ð ØˆØ‡L‚LÐ"Ñ#Ô#Ð#ðØ—,’,Ð4Ñ5Ô5×>Ò>Ñ@Ô@ÀÔCˆØ�QŠ;ˆ;Ý&Ÿ_š_Ñ.Ô.×4Ò4°SÑ9Ô9ð ,ð ,�	Ø—?’?Ñ$Ô$ð ,Ø—L’L Ñ+Ô+Ð+øØ�QŠ;ˆ;Ý&Ÿ_š_Ñ.Ô.×4Ò4°SÑ9Ô9ð ,ð ,�	Ø—?’?Ñ$Ô$ð ,Ø—L’L Ñ+Ô+Ð+øØ�QŠ;ˆ;Ý&Ÿ_š_Ñ.Ô.×4Ò4°SÑ9Ô9ð ,ð ,�	Ø—?’?Ñ$Ô$ð ,Ø—L’L Ñ+Ô+Ð+øØ�QŠ;ˆ;Ý&Ÿ_š_Ñ.Ô.×4Ò4°SÑ9Ô9ð ,ð ,�	Ø—?’?Ñ$Ô$ð ,Ø—L’L Ñ+Ô+Ð+øØ�ŠÐ-×4Ò4µ^ÑDÔDÑEÔEÐEØ�Š�XÑÔÐÐÐøÝð ð ð Ø�Š�ZÑ Ô Ð Øðøøøs   ÁG'H: È:!Ic                   ó&   — e Zd ZdZdd„Zd„ Zd„ ZdS )Ú_Txz3with store.tx() as conn: one IMMEDIATE transaction.Nc                 ó.   — t          |¦  «        | _        d S ©N)r    r(   )Úselfr   s     r   Ú__init__z_Tx.__init__�   s   € Ý˜D‘M”MˆŒ	ˆ	ˆ	r
   c                 óD   — | j                              d¦  «         | j         S )Nr*   )r(   r%   )rA   s    r   Ú	__enter__z_Tx.__enter__“   s!   € ØŒ	×ÒÐ+Ñ,Ô,Ð,ØŒyÐr
   c                 óÚ  — |st          | j        j        ¦  «        nt          ¦   «         }	 |sB|D ]?}d|z   }| j                             d|f¦  «         | j                             d|f¦  «         Œ@| j                             |rdnd¦  «         | j                             ¦   «          n# | j                             ¦   «          w xY w|r$	 ddlm}  |d|¦  «         n# t          $ r Y nw xY wd	S )
Nzwidget.rev.z2INSERT OR IGNORE INTO flags(key,value) VALUES(?,0)z;UPDATE flags SET value=CAST(value AS INTEGER)+1 WHERE key=?r0   r/   r   )ÚnotifyÚskin_rows_changedF)r!   r(   r"   r%   ÚcloseÚwcs.skin.refreshrF   r:   )rA   Úexc_typeÚexcÚtbÚchangedÚrowÚkeyrF   s           r   Ú__exit__z_Tx.__exit__—   s.  € Ø4<ÐG•#�d”iÔ+Ñ,Ô,Ð,Å#Á%Ä%ˆð	Øð mØ"ð mð m�CØ'¨#Ñ-�CØ”I×%Ò%Ð&ZÐ]`Ð\bÑcÔcÐcØ”I×%Ò%Ð&cÐfiÐekÑlÔlÐlÐlØŒI×Ò¨HÐB˜j˜j¸(ÑCÔCÐCàŒI�OŠOÑÔÐÐøˆDŒI�OŠOÑÔÐÐøøøØð 	ðØ3Ð3Ð3Ð3Ð3Ð3Ø�Ð*¨GÑ4Ô4Ð4Ð4øÝð ð ð Ø�ðøøøàˆus   «A"B' Â'CÃC Ã
C(Ã'C(r@   )r   r   r   Ú__doc__rB   rD   rP   r   r
   r   r>   r>   �   sL   € € € € € Ø=Ð=ð"ð "ð "ð "ðð ð ðð ð ð ð r
   r>   c                 ó    — t          | ¦  «        S r@   )r>   r   s    r   ÚtxrS   «   s   € Ýˆt‰9Œ9Ðr
   c                  óB   — t          t          j        ¦   «         ¦  «        S r@   )ÚintÚtimer   r
   r   Ú_nowrW   ¯   s   € Ý�tŒy‰{Œ{ÑÔÐr
   c                 ó:   — | j                              |¦  «         dS )zPCollect rows once per transaction; revisions commit with the corresponding data.N)r"   Úupdate©r(   Úrowss     r   Údirtyr\   ³   s   € àÔ×Ò˜DÑ!Ô!Ð!Ð!Ð!r
   Fc                 óF   — ddl m} t          |  |||¦  «        ¦  «         d S )Nr   )Ú
media_rows)rI   r^   r\   )r(   Ú
media_typeÚ
membershipr^   s       r   Ú_media_dirtyra   ¸   s6   € Ø+Ð+Ð+Ð+Ð+Ð+Ý	ˆ$�
�
˜: zÑ2Ô2Ñ3Ô3Ð3Ð3Ð3r
   c           
      ó˜  — t          ||||¦  «        \  }}}}}	|                      d                     ||¦  «        |¦  «         |                      d                     ||¦  «        |¦  «                             ¦   «         d         }
|                      d|t	          |¦  «        |�|nd|�|nd|
t          j        ¦   «         dz   f¦  «         d S )Nz4UPDATE {} SET state_version=state_version+1 WHERE {}z%SELECT state_version FROM {} WHERE {}r   zqINSERT OR REPLACE INTO mirror_pending(media_type,tmdb_id,season,episode,version,next_attempt) VALUES(?,?,?,?,?,?)éÿÿÿÿg      à?)Ú_state_keysr%   r9   r1   rU   rV   )r(   r_   Útmdb_idÚseasonÚepisodeÚtableÚwhereÚargsÚ_colsÚ_valsr;   s              r   Ú_queue_mirrorrm   ½   sè   € Ý'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uØ‡L‚LÐG×NÒNÈuÐV[Ñ\Ô\Ð^bÑcÔcÐcØ�lŠlÐB×IÒIÈ%ÐQVÑWÔWÐY]Ñ^Ô^×gÒgÑiÔiÐjkÔl€GØ‡L‚Lð 'Ø)3µS¸±\´\ÈVÐM_À6À6ÐegØ4;Ð4G¨¨ÈRÐQXÕZ^ÔZcÑZeÔZeÐhkÑZkð)mñnô nð nð nð nr
   c                 óP   — |                       d|t          |¦  «        f¦  «         d S )Nz>INSERT OR IGNORE INTO titles(media_type, tmdb_id) VALUES(?, ?))r%   rU   )r(   r_   re   s      r   Ú_ensure_titlero   È   s-   € Ø‡L‚LÐQÐT^Õ`cÐdkÑ`lÔ`lÐSmÑnÔnÐnÐnÐnr
   c                 ó²  — t          ¦   «         }	 |                     d| f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY wg }|D ]k}	 |d         rt	          j        |d         ¦  «        ni }n# t          $ r i }Y nw xY w|                     d|d         ¦  «         |                     |¦  «         Œl|S )zELegacy dicts of My movies ('movie') / My series ('tv') in list order.zrSELECT legacy_json, tmdb_id FROM titles WHERE media_type=? AND in_list=1 ORDER BY list_pos, list_added_at, tmdb_idÚlegacy_jsonÚidre   )	r    r%   ÚfetchallrH   ÚjsonÚloadsÚ
ValueErrorÚ
setdefaultÚappend)r_   r(   r[   ÚresultrN   Úentrys         r   Úget_listr{   Ì   sø   € å‰9Œ9€DðØ�|Š|ð HØJTÈñXô XßX`ÒX`ÑXbÔXbð 	ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ€FØð ð ˆð	Ø69¸-Ô6HÐP•D”J˜s =Ô1Ñ2Ô2Ð2ÈbˆEˆEøÝð 	ð 	ð 	ØˆEˆEˆEð	øøøà×Ò˜˜s 9œ~Ñ.Ô.Ð.Ø�Š�eÑÔÐÐØ€Ms   �)A ÁA$Á.$BÂB"Â!B"c                 óæ   — t          ¦   «         }	 |                     d| f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY wd„ |D ¦   «         S )z`{tmdb_id: {'added', 'activity'}} (epoch seconds or None) of the titles in My movies / My series.z\SELECT tmdb_id, list_added_at, last_activity_at FROM titles WHERE media_type=? AND in_list=1c                 ó>   — i | ]}|d          |d         |d         dœ“ŒS )re   Úlist_added_atÚlast_activity_at)ÚaddedÚactivityr   ©Ú.0Úrs     r   ú
<dictcomp>zlist_times.<locals>.<dictcomp>ç   s2   € ÐiÐiÐiÐ_`ˆAˆiŒL A oÔ$6ÀAÐFXÔDYÐZÐZÐiÐiÐir
   ©r    r%   rs   rH   )r_   r(   r[   s      r   Ú
list_timesr‡   ß   so   € å‰9Œ9€DðØ�|Š|ÐzØ'˜Mñ+ô +ß+3ª8©:¬:ð 	ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØiÐiÐdhÐiÑiÔiÐió   �)A ÁA$c                 ó¬  — t          ¦   «         }t          ¦   «         5 }g }d}t          |¦  «        D ]{\  }}t          |d         ¦  «        }|                     |¦  «         t          || |¦  «         t          j        |d¬¦  «        }	||                     d||	|| |||	f¦  «        j	        z  }Œ||r[d 
                    dt          |¦  «        z  ¦  «        }
||                     d                     |
¦  «        | g|z   ¦  «        j	        z  }n||                     d	| f¦  «        j	        z  }|rt          || d
¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zLMake `entries` (legacy dicts with 'id') the whole list, keeping their order.r   rr   F©Úensure_asciiz¿UPDATE titles SET in_list=1, list_pos=?, legacy_json=?, list_added_at=COALESCE(list_added_at, ?) WHERE media_type=? AND tmdb_id=? AND (in_list!=1 OR list_pos IS NOT ? OR legacy_json IS NOT ?)ú,ú?zcUPDATE titles SET in_list=0, list_pos=NULL WHERE media_type=? AND in_list=1 AND tmdb_id NOT IN ({})zKUPDATE titles SET in_list=0, list_pos=NULL WHERE media_type=? AND in_list=1TN)rW   rS   Ú	enumeraterU   rx   ro   rt   Údumpsr%   Úrowcountr   Úlenr9   ra   )r_   ÚentriesÚnowr(   ÚkeeprM   Úposrz   re   ÚencodedÚmarkss              r   Úreplace_listr˜   ê   sÔ  € å
‰&Œ&€CÝ	‰Œð 1�ØˆØˆÝ# GÑ,Ô,ð 	Zð 	Z‰JˆC�Ý˜% œ+Ñ&Ô&ˆGØ�KŠK˜Ñ Ô Ð Ý˜$ 
¨GÑ4Ô4Ð4Ý”j °UÐ;Ñ;Ô;ˆGØ�t—|’|ð %Yð ˜w¨¨Z¸À#ÀwÐOñQô Qô RZñZˆGˆGð ð 	KØ—H’H˜S¥3 t¡9¤9™_Ñ-Ô-ˆEØ�t—|’|ð %3ß39²6¸%±=´=À:À,ÐQUÑBUñWô WÜW_ñ`ˆGˆGð �t—|’|Ð$qÐt~ð  tAñ  Bô  Bô  Kñ  KˆGØð 	1Ý˜˜z¨4Ñ0Ô0Ð0ð'1ð 1ð 1ñ 1ô 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1øøøð 1ð 1ð 1ð 1ð 1ð 1s   �DE	Å	EÅEc                 óú  — t          ¦   «         }t          ¦   «         5 }t          || |¦  «         |ru|                     d| f¦  «                             ¦   «         d         }|                     d|||rt          j        |d¬¦  «        nd| t          |¦  «        f¦  «        j        }n*|                     d| t          |¦  «        f¦  «        j        }|rt          || d¦  «         ddd¦  «         dS # 1 swxY w Y   dS )	zUAdd / remove one title. Added titles go to the end of the list (like the old append).úSSELECT COALESCE(MAX(list_pos), -1) + 1 FROM titles WHERE media_type=? AND in_list=1r   z�UPDATE titles SET in_list=1, list_pos=?, list_added_at=?, legacy_json=COALESCE(?, legacy_json) WHERE media_type=? AND tmdb_id=? AND in_list=0FrŠ   NzZUPDATE titles SET in_list=0, list_pos=NULL WHERE media_type=? AND tmdb_id=? AND in_list!=0T)
rW   rS   ro   r%   r1   rt   r�   rU   r�   ra   )r_   re   Úin_listÚlegacyr“   r(   ÚendrM   s           r   Úset_in_listrž     s[  € å
‰&Œ&€CÝ	‰Œð 1�Ý�d˜J¨Ñ0Ô0Ð0Øð 	>Ø—,’,ÐtØ *˜}ñ.ô .ß.6ªh©j¬j¸ô<ˆCà—l’lð $Jà˜sÈfÐ$^¥D¤J¨vÀEÐ$JÑ$JÔ$JÐ$JÐZ^Ð`jÕloÐpwÑlxÔlxÐyñ{ô {ô |Dð ˆGð —l’lÐ#Ø$¥c¨'¡l¤lÐ3ñ5ô 5Ü5=ð àð 	1Ý˜˜z¨4Ñ0Ô0Ð0ð1ð 1ð 1ñ 1ô 1ð 1ð 1ð 1ð 1ð 1ð 1ð 1øøøð 1ð 1ð 1ð 1ð 1ð 1s   �CC0Ã0C4Ã7C4c                 ó  — t          ¦   «         }	 |                     d| t          |¦  «        f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY wt          |o|d         ¦  «        S )Nz;SELECT in_list FROM titles WHERE media_type=? AND tmdb_id=?r›   )r    r%   rU   r1   rH   Úbool©r_   re   r(   rN   s       r   Ú
is_in_listr¢     sz   € Ý‰9Œ9€DðØ�lŠlÐXØ&­¨G©¬Ð5ñ7ô 7ß7?²x±z´zð 	ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøÝ�Ð&˜˜IœÑ'Ô'Ð'ó   �7A ÁA2c           	      ó
  — | dk    r#ddt          |¦  «        fdt          |¦  «        ffS ddt          |¦  «        t          |¦  «        t          |¦  «        fdt          |¦  «        t          |¦  «        t          |¦  «        ffS )NÚmovieÚmovie_statez	tmdb_id=?©re   Úepisode_statez$show_id=? AND season=? AND episode=?)Úshow_idrf   rg   )rU   )r_   re   rf   rg   s       r   rd   rd   !  s�   € Ø�WÒÐØ˜k­C°©L¬L¨?¸LÍ3ÈwÉ<Ì<È/ÐYÐYØÐCÅcÈ'ÁlÄlÕTWÐX^ÑT_ÔT_ÕadÐelÑamÔamÐEnØ,­s°7©|¬|½SÀ¹[¼[Í#ÈgÉ,Ì,Ð.WðYð Yr
   c                 óø   — t          ||||¦  «        \  }}}}}	|                      d                     |d                     |¦  «        d                     dt	          |¦  «        z  ¦  «        ¦  «        |	¦  «         d S )Nz'INSERT OR IGNORE INTO {}({}) VALUES({})rŒ   r�   )rd   r%   r9   r   r‘   )
r(   r_   re   rf   rg   rh   Ú_whereÚ_argsÚcolsÚvalss
             r   Ú_ensure_stater¯   (  sy   € Ý'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ6�5˜$ Ø‡L‚LÐ:×AÒAÀ%ÈÏÊÐRVÉÌÐY\×YaÒYaÐbeÕhkÐlpÑhqÔhqÑbqÑYrÔYrÑsÔsÐuyÑzÔzÐzÐzÐzr
   c                 ó”   — t          | ||¦  «         |                      d||t          |¦  «        f¦  «         t          | |¦  «         d S )NzcUPDATE titles SET last_activity_at=?, hidden_from_continue_at=NULL WHERE media_type=? AND tmdb_id=?)ro   r%   rU   ra   )r(   r_   re   Úwhens       r   Ú_touchr²   -  sS   € Ý�$˜
 GÑ,Ô,Ð,Ø‡L‚LÐvØ˜
¥C¨¡L¤LÐ1ñ3ô 3ð 3å��zÑ"Ô"Ð"Ð"Ð"r
   c                 óJ  — t          | |||¦  «        \  }}}}}t          ¦   «         }		 |	                     d                     ||¦  «        |¦  «                             ¦   «         }
|	                     ¦   «          n# |	                     ¦   «          w xY w|
rt          |
¦  «        nd S )NzSELECT * FROM {} WHERE {})rd   r    r%   r9   r1   rH   Údict)r_   re   rf   rg   rh   ri   rj   rk   rl   r(   rN   s              r   Ú	get_staterµ   4  s•   € Ý'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uÝ‰9Œ9€DðØ�lŠlÐ6×=Ò=¸eÀUÑKÔKÈTÑRÔR×[Ò[Ñ]Ô]ˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØÐ%�4�‰9Œ9ˆ9 Ð%s   ¨<A9 Á9Bc                  óâ   — t          ¦   «         } 	 |                      d¦  «                             ¦   «         }|                      ¦   «          n# |                      ¦   «          w xY wd„ |D ¦   «         S )z7{tmdb_id: movie_state row} of every movie with a state.zSELECT * FROM movie_statec                 ó:   — i | ]}|d          t          |¦  «        “ŒS r§   ©r´   r‚   s     r   r…   z$get_movie_states.<locals>.<dictcomp>E  s$   € Ð0Ð0Ð0 aˆAˆiŒL�$˜q™'œ'Ð0Ð0Ð0r
   r†   rZ   s     r   Úget_movie_statesr¹   >  sc   € å‰9Œ9€DðØ�|Š|Ð7Ñ8Ô8×AÒAÑCÔCˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ0Ð0¨4Ð0Ñ0Ô0Ð0ó   �'A ÁA"c                  óP  — t          ¦   «         } 	 |                      d¦  «                             ¦   «         }|                      ¦   «          n# |                      ¦   «          w xY wi }|D ]<}t	          |¦  «        |                     |d         i ¦  «        |d         |d         f<   Œ=|S )zM{show_id: {(season, episode): episode_state row}} for every show with states.zSELECT * FROM episode_stater©   rf   rg   )r    r%   rs   rH   r´   rw   )r(   r[   ry   r„   s       r   Úget_all_episode_statesr¼   H  sŸ   € å‰9Œ9€DðØ�|Š|Ð9Ñ:Ô:×CÒCÑEÔEˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ€FØð Sð SˆÝKOÐPQÉ7Ì7ˆ×Ò˜!˜Iœ,¨Ñ+Ô+¨Q¨x¬[¸!¸I¼,Ð,GÑHÐHØ€Mrº   c                 ó   — t          ¦   «         }	 |                     dt          | ¦  «        f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY wd„ |D ¦   «         S )NzDSELECT * FROM episode_state WHERE show_id=? ORDER BY season, episodec                 ó,   — g | ]}t          |¦  «        ‘ŒS r   r¸   r‚   s     r   ú
<listcomp>z&get_episode_states.<locals>.<listcomp>\  ó   € Ð"Ð"Ð"˜�D�‰GŒGÐ"Ð"Ð"r
   )r    r%   rU   rs   rH   )r©   r(   r[   s      r   Úget_episode_statesrÁ   U  st   € Ý‰9Œ9€DðØ�|Š|ÐbÝ  ™\œ\˜Oñ-ô -ß-5ªX©Z¬Zð 	ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ"Ð"˜TÐ"Ñ"Ô"Ð"ó   �6A ÁA1c                 óì  — |pt          ¦   «         }t          | |||¦  «        \  }}	}
}}|pi }t          ¦   «         5 }t          || |||¦  «         |                     d                     ||	¦  «        t          |¦  «        t          |¦  «        ||                     d¦  «        |                     d¦  «        |                     d¦  «        f|
z   t          |¦  «        t          |¦  «        |                     d¦  «        |                     d¦  «        |                     d¦  «        fz   ¦  «        j        }|r%t          || ||¦  «         t          || |||¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zcIn-progress position; also records the source file used (`source` = dict ident/provider/file_name).ax  UPDATE {} SET resume_pos=?, resume_total=?, last_played_at=?, last_ident=COALESCE(?, last_ident), last_provider=COALESCE(?, last_provider), last_file_name=COALESCE(?, last_file_name) WHERE {} AND (resume_pos!=? OR resume_total!=? OR COALESCE(?,last_ident) IS NOT last_ident OR COALESCE(?,last_provider) IS NOT last_provider OR COALESCE(?,last_file_name) IS NOT last_file_name)ÚidentÚproviderÚ	file_nameN)rW   rd   rS   r¯   r%   r9   ÚfloatÚgetr�   r²   rm   )r_   re   ÚpositionÚtotalrf   rg   Úsourcer±   rh   ri   rj   rk   rl   r(   rM   s                  r   Úsave_resumerÌ   _  sï  € àˆ>•4‘6”6€DÝ'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uØˆ\�r€FÝ	‰Œð F�Ý�d˜J¨°¸ÑAÔAÐAØ—,’,ð  ~÷ Eò  Eð  FKð  MRñ  Sô  SÝ˜H‘o”o¥u¨U¡|¤|°T¸6¿:º:ÀgÑ;NÔ;NÐPV×PZÒPZÐ[eÑPfÔPfØ—j’j Ñ-Ô-ð/Ø15ñ6Ý9>¸x¹¼Í%ÐPUÉ,Ì,ÐX^×XbÒXbÐcjÑXkÔXkØ8>¿
º
À:Ñ8NÔ8NÐPV×PZÒPZÐ[fÑPgÔPgð9iñiñ	jô jô ksð 	ð ð 	FÝ�4˜ W¨dÑ3Ô3Ð3Ý˜$ 
¨G°V¸WÑEÔEÐEðFð Fð Fñ Fô Fð Fð Fð Fð Fð Fð Fð Føøøð Fð Fð Fð Fð Fð Fs   »D!E)Å)E-Å0E-c           
      óð  — |pt          ¦   «         }t          | |||¦  «        \  }}}}	}
|pi }t          ¦   «         5 }t          || |||¦  «         |                     d                     ||¦  «        ||                     d¦  «        |                     d¦  «        |                     d¦  «        f|z   ¦  «         t          || ||¦  «         t          || |||¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z'Watched: playcount + 1, resume cleared.zÖUPDATE {} SET playcount=playcount+1, resume_pos=0, resume_total=0, last_played_at=?, last_ident=COALESCE(?, last_ident), last_provider=COALESCE(?, last_provider), last_file_name=COALESCE(?, last_file_name) WHERE {}rÄ   rÅ   rÆ   N)	rW   rd   rS   r¯   r%   r9   rÈ   r²   rm   )r_   re   rf   rg   r±   rË   rh   ri   rj   rk   rl   r(   s               r   Úmark_watchedrÎ   r  s^  € àˆ>•4‘6”6€DÝ'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uØˆ\�r€FÝ	‰Œð B�Ý�d˜J¨°¸ÑAÔAÐAØ�Šð KçKQÊ6ÐRWÐY^ÑK_ÔK_Ø˜FŸJšJ wÑ/Ô/°·²¸JÑ1GÔ1GÈÏÊÐT_ÑI`ÔI`ÐaÐdhÑhñ	jô 	jð 	jõ 	ˆt�Z ¨$Ñ/Ô/Ð/Ý�d˜J¨°¸ÑAÔAÐAðBð Bð Bñ Bô Bð Bð Bð Bð Bð Bð Bð Bøøøð Bð Bð Bð Bð Bð Bs   »B#C+Ã+C/Ã2C/c                 óh  — |pt          ¦   «         }t          | |||¦  «        \  }}}}}	t          ¦   «         5 }
t          |
| |||¦  «         |
                     d                     ||¦  «        |¦  «         t          |
| ||¦  «         t          |
| |||¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z*Unwatched: playcount 0 and resume cleared.z@UPDATE {} SET playcount=0, resume_pos=0, resume_total=0 WHERE {}N)rW   rd   rS   r¯   r%   r9   r²   rm   )r_   re   rf   rg   r±   rh   ri   rj   rk   rl   r(   s              r   Úmark_unwatchedrÐ   �  s  € àˆ>•4‘6”6€DÝ'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uÝ	‰Œð B�Ý�d˜J¨°¸ÑAÔAÐAØ�ŠÐW×^Ò^Ð_dÐfkÑlÔlÐnrÑsÔsÐsÝˆt�Z ¨$Ñ/Ô/Ð/Ý�d˜J¨°¸ÑAÔAÐAð	Bð Bð Bñ Bô Bð Bð Bð Bð Bð Bð Bð Bøøøð Bð Bð Bð Bð Bð Bs   ·A#B'Â'B+Â.B+c                 ó,  — t          | |||¦  «        \  }}}}}t          ¦   «         5 }	|	                     d                     ||¦  «        |¦  «        j        }
|
r#t          |	| ¦  «         t          |	| |||¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )NzZUPDATE {} SET resume_pos=0, resume_total=0 WHERE {} AND (resume_pos!=0 OR resume_total!=0))rd   rS   r%   r9   r�   ra   rm   )r_   re   rf   rg   rh   ri   rj   rk   rl   r(   rM   s              r   Úclear_resumerÒ   Œ  s  € Ý'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uÝ	‰Œð F�Ø—,’,ð  HßHNÊÈuÐV[ÑH\ÔH\Ð^bñdô dÜdlð 	àð 	FÝ˜˜zÑ*Ô*Ð*Ý˜$ 
¨G°V¸WÑEÔEÐEðFð Fð Fñ Fô Fð Fð Fð Fð Fð Fð Fð Føøøð Fð Fð Fð Fð Fð Fs   §AB	Â	BÂBTc           	      ó`  — |pt          ¦   «         }d}t          ¦   «         5 }|�7|                     d|f¦  «                             ¦   «         s	 ddd¦  «         dS | dk    rdnd}| dk    r.d„ |                     dt	          |¦  «        f¦  «        D ¦   «         n-d	„ |                     d
t	          |¦  «        f¦  «        D ¦   «         }	t          |¦  «        D �]\  }
}|	                     |
|f¦  «        pi }t	          |                     d¦  «        pd¦  «        dk    }|r|s(|s'|s%t          |                     d¦  «        pd¦  «        sŒtt          || ||
|¦  «         t          | ||
|¦  «        \  }}}}}|r/|                     d 
                    ||¦  «        |f|z   ¦  «         n*|                     d 
                    ||¦  «        |¦  «         t          || ||
|¦  «         |dz  }�Œ|rt          || ||¦  «         |�|                     d|f¦  «         ddd¦  «         n# 1 swxY w Y   |S )zZManual mark: one transaction, no network/RPC, and no second playcount for a repeated mark.r   Nz&SELECT 1 FROM pending_marks WHERE id=?r¥   r¦   r¨   c                 ó.   — i | ]}d t          |¦  «        “ŒS )©NNr¸   r‚   s     r   r…   zmark_many.<locals>.<dictcomp>ž  s    € ÐÐÐ¨q�\¥4¨¡7¤7ÐÐÐr
   z)SELECT * FROM movie_state WHERE tmdb_id=?c                 óJ   — i | ] }|d          |d         ft          |¦  «        “Œ!S )rf   rg   r¸   r‚   s     r   r…   zmark_many.<locals>.<dictcomp>   s?   € ð Yð Yð Y¸a�a˜”k 1 Y¤<Ð0µ$°q±'´'ð Yð Yð Yr
   z+SELECT * FROM episode_state WHERE show_id=?Ú	playcountÚ
resume_poszOUPDATE {} SET playcount=1,resume_pos=0,resume_total=0,last_played_at=? WHERE {}z>UPDATE {} SET playcount=0,resume_pos=0,resume_total=0 WHERE {}r+   z$DELETE FROM pending_marks WHERE id=?)rW   rS   r%   r1   rU   r!   rÈ   rÇ   r¯   rd   r9   rm   r²   )r_   re   ÚtargetsÚwatchedr±   Ú
pending_idrM   r(   rh   Úexistingrf   rg   ÚstateÚplayedÚ_tableri   rj   rk   rl   s                      r   Ú	mark_manyrà   –  s4  € àˆ>•4‘6”6€DØ€GÝ	‰Œð P�ØÐ!¨$¯,ª,Ð7_ÐblÐanÑ*oÔ*o×*xÒ*xÑ*zÔ*zÐ!ØðPð Pð Pñ Pô Pð Pð Pð Pð ",¨wÒ!6Ð!6��¸Oˆà! WÒ,Ð,ð @Ð°D·L²LÐAlÕorÐszÑo{Ôo{Ðn}Ñ4~Ô4~ÐÑÔÐðYð YÀ4Ç<Â<ØEÍÈGÉÌÀñDXô DXð Yñ Yô Yð 	õ  # 7™|œ|ð 	ñ 	‰OˆF�GØ—L’L &¨'Ð!2Ñ3Ô3Ð9°rˆEÝ˜Ÿš ;Ñ/Ô/Ð4°1Ñ5Ô5¸Ò9ˆFØð ˜Fð ¨Gð ¸Fð Í5ÐQV×QZÒQZÐ[gÑQhÔQhÐQmÐlmÑKnÔKnð ØÝ˜$ 
¨G°V¸WÑEÔEÐEÝ0;¸JÈÐQWÐY`Ñ0aÔ0aÑ-ˆF�E˜4 ¨Øð zØ—’Ðn×uÒuÐv{ð  ~Cñ  Dô  Dð  GKð  FMð  PTñ  FTñ  Uô  Uð  Uð  Uà—’Ð]×dÒdÐejÐlqÑrÔrÐtxÑyÔyÐyÝ˜$ 
¨G°V¸WÑEÔEÐEØ�q‰LˆG‰GØð 	4Ý�4˜ W¨dÑ3Ô3Ð3ØÐ!Ø�LŠLÐ?À*ÀÑOÔOÐOð1Pð Pð Pñ Pô Pð Pð Pð Pð Pð Pð Pøøøð Pð Pð Pð Pð2 €Ns   ¡-H#ÁF<H#È#H'È*H'c	                 óÎ   — t          ¦   «         5 }	|	                     d| t          |¦  «        |||||||f	¦  «         t          |	dh¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nz|INSERT INTO play_log(media_type,tmdb_id,season,episode,started_at,ended_at,position,total,outcome) VALUES(?,?,?,?,?,?,?,?,?)Úrecent_played)rS   r%   rU   r\   )
r_   re   rf   rg   Ú
started_atÚended_atrÉ   rÊ   Úoutcomer(   s
             r   Úlog_playræ   ¶  s¿   € Ý	‰Œð '�Ø�Šð 1à ¥# g¡,¤,°¸ÀÈXÐW_ÐafÐhoÐpñ	rô 	rð 	rõ 	ˆd�_Ð%Ñ&Ô&Ð&ð	'ð 'ð 'ñ 'ô 'ð 'ð 'ð 'ð 'ð 'ð 'ð 'øøøð 'ð 'ð 'ð 'ð 'ð 's   �>AÁAÁ!Ac           	      óÒ   — t          ¦   «         5 }|                     d| t          |¦  «        |||f¦  «        }t          |dh¦  «         |j        cddd¦  «         S # 1 swxY w Y   dS )znOpen a play_log row (ended_at NULL); returns its id. An open row after a crash is closed by close_open_logs().zTINSERT INTO play_log(media_type,tmdb_id,season,episode,started_at) VALUES(?,?,?,?,?)râ   N)rS   r%   rU   r\   Ú	lastrowid)r_   re   rf   rg   rã   r(   Úcurs          r   Ú	log_startrê   ¾  s±   € å	‰Œð �Ø�lŠlÐqØ&­¨G©¬°f¸gÀzÐRñTô Tˆåˆd�_Ð%Ñ&Ô&Ð&ØŒ}ð	ð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   �A AÁA Á#A c                 ó†   — t          ¦   «         5 }|                     d||| f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nz2UPDATE play_log SET position=?, total=? WHERE id=?©rS   r%   )Úrow_idrÉ   rÊ   r(   s       r   Ú
log_updaterî   Ç  sž   € Ý	‰Œð f�Ø�ŠÐIÈHÐV[Ð]cÐKdÑeÔeÐeðfð fð fñ fô fð fð fð fð fð fð fð føøøð fð fð fð fð fð fó   �6¶:½:c           	      óŠ   — t          ¦   «         5 }|                     d||||| f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )NzIUPDATE play_log SET ended_at=?, position=?, total=?, outcome=? WHERE id=?rì   )rí   rä   rÉ   rÊ   rå   r(   s         r   Ú
log_finishrñ   Ì  sª   € Ý	‰Œð C�Ø�ŠÐ`Ø ¨%°¸&ÐAñ	Cô 	Cð 	CðCð Cð Cñ Cô Cð Cð Cð Cð Cð Cð Cð Cøøøð Cð Cð Cð Cð Cð Cs   �8¸<¿<c                 óª   — t          ¦   «         5 }|                     d| pt          ¦   «         f¦  «        }|j        cddd¦  «         S # 1 swxY w Y   dS )zfService start: rows left open by a crash / power loss get outcome 'crash' (their last position stays).zFUPDATE play_log SET ended_at=?, outcome='crash' WHERE ended_at IS NULLN)rS   r%   rW   r�   )r±   r(   ré   s      r   Úclose_open_logsró   Ò  s–   € å	‰Œð �Ø�lŠlÐcØ ˜N¥D¡F¤FÐ,ñ.ô .ˆàŒ|ðð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   �,AÁAÁAé   c                 óæ   — t          ¦   «         }	 |                     d| f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY wd„ |D ¦   «         S )Nz/SELECT * FROM play_log ORDER BY id DESC LIMIT ?c                 ó,   — g | ]}t          |¦  «        ‘ŒS r   r¸   r‚   s     r   r¿   zrecent_logs.<locals>.<listcomp>à  rÀ   r
   r†   )Úlimitr(   r[   s      r   Úrecent_logsrø   Ú  sh   € Ý‰9Œ9€DðØ�|Š|ÐMÐPUÈxÑXÔX×aÒaÑcÔcˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ"Ð"˜TÐ"Ñ"Ô"Ð"rˆ   c           	      óÜ  — t          | |||¦  «        \  }}	}
}}t          ¦   «         5 }|                     d                     ||	|�dnd¦  «        |pt	          ¦   «         t          |¦  «        t          |¦  «        f|
z   |�|fndz   ¦  «        j        }|r2|�0|                     d| t          |¦  «        |�|nd|�|nd|f¦  «         t          |¦  «        cddd¦  «         S # 1 swxY w Y   dS )z^Remember what was written into Kodi (so a later difference means the user changed it in Kodi).zSUPDATE {} SET mirrored_at=?, mirrored_playcount=?, mirrored_resume_pos=? WHERE {}{}Nz AND state_version=?Ú r   zdDELETE FROM mirror_pending WHERE media_type=? AND tmdb_id=? AND season=? AND episode=? AND version=?rc   )	rd   rS   r%   r9   rW   rU   rÇ   r�   r    )r_   re   r×   rØ   rf   rg   r±   r;   rh   ri   rj   rk   rl   r(   rM   s                  r   Úset_mirroredrû   ã  so  € å'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uÝ	‰Œð �Ø—,’,Ðt×{Ò{Ø˜E¸WÐ=PÐ#9Ð#9ÐVXñ Zô  Zà�n�d™fœf¥c¨)¡n¤nµe¸JÑ6GÔ6GÐHÈ4ÑOÐahÐatÐT[ÐS]ÐS]Ðz|Ñ}ñô ô @Hð 	ð ð 	L�wÐ*Ø�LŠLÐØ$¥c¨'¡l¤l¸fÐ>P°F°FÐVXØ%,Ð%8˜'˜'¸bÀ'ðKñLô Lð Lõ �G‰}Œ}ðð ð ð ñ ô ð ð ð ð ð ð øøøð ð ð ð ð ð s   §B-C!Ã!C%Ã(C%é   c                 óè   — t          ¦   «         }	 d„ |                     d|€t          j        ¦   «         n|| f¦  «        D ¦   «         |                     ¦   «          S # |                     ¦   «          w xY w)Nc                 ó,   — g | ]}t          |¦  «        ‘ŒS r   r¸   r‚   s     r   r¿   z#pending_mirrors.<locals>.<listcomp>ô  s0   € ð ~ð ~ð ~˜A•�Q‘”ð ~ð ~ð ~r
   zPSELECT * FROM mirror_pending WHERE next_attempt<=? ORDER BY next_attempt LIMIT ?)r    r%   rV   rH   )r÷   r“   r(   s      r   Úpending_mirrorsrÿ   ñ  s‡   € Ý‰9Œ9€Dðð~ð ~ §¢ð /NØ_bÐ_jÕPTÔPYÑP[ÔP[ÐP[ÐpsÐuzÐO{ñ"}ô "}ð ~ñ ~ô ~ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøørÂ   c                 ó   — t          ¦   «         }	 |                     d| t          |¦  «        |�|nd|�|ndf¦  «                             ¦   «         d u|                     ¦   «          S # |                     ¦   «          w xY w)NzXSELECT 1 FROM mirror_pending WHERE media_type=? AND tmdb_id=? AND season=? AND episode=?rc   )r    r%   rU   r1   rH   )r_   re   rf   rg   r(   s        r   Úmirror_pendingr  ú  s„   € Ý‰9Œ9€DðØ�|Š|ÐvØ'­¨W©¬ÀÐAS°v°vÐY[Ø(/Ð(;˜W˜WÀðEñFô FçFNÂhÁjÄjÐX\ð]ð 	�
Š
‰Œˆˆøˆ�
Š
‰Œˆˆøøøs   �AA' Á'A=c                 óD  — t          ddt          | d         dz   d¦  «        z  ¦  «        }t          ¦   «         5 }|                     dt          j        ¦   «         |z   | d         | d         | d	         | d
         | d         f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )NiX  r-   Úattemptsr+   é
   z†UPDATE mirror_pending SET attempts=attempts+1,next_attempt=? WHERE media_type=? AND tmdb_id=? AND season=? AND episode=? AND version=?r_   re   rf   rg   r;   )ÚminrS   r%   rV   )ÚpendingÚdelayr(   s      r   Úretry_mirrorr    sê   € Ý��Q�#˜g jÔ1°AÑ5°rÑ:Ô:Ñ:Ñ;Ô;€EÝ	‰Œð ?�Ø�Šð aå”i‘k”k EÑ)¨7°<Ô+@À'È)ÔBTÐV]Ð^fÔVgØ˜iÔ(¨'°)Ô*<ð>ñ	?ô 	?ð 	?ð?ð ?ð ?ñ ?ô ?ð ?ð ?ð ?ð ?ð ?ð ?ð ?øøøð ?ð ?ð ?ð ?ð ?ð ?s   ¹ABÂBÂBc           	      óÂ  — |pt          ¦   «         }t          | |||¦  «        \  }}	}
}}t          ¦   «         5 }t          || |||¦  «         |                     d                     ||	¦  «        t          |¦  «        t          |¦  «        t          |¦  «        f|
z   ¦  «         t          || ||¦  «         t          || |||¦  «         ddd¦  «         dS # 1 swxY w Y   dS )z[Apply a change the user made through Kodi (mark watched / unwatched / remove resume point).z@UPDATE {} SET playcount=?, resume_pos=?, resume_total=? WHERE {}N)
rW   rd   rS   r¯   r%   r9   rU   rÇ   r²   rm   )r_   re   r×   rØ   Úresume_totalrf   rg   r±   rh   ri   rj   rk   rl   r(   s                 r   Úadopt_from_kodir    s@  € àˆ>•4‘6”6€DÝ'2°:¸wÈÐPWÑ'XÔ'XÑ$€Eˆ5�$˜˜uÝ	‰Œð B�Ý�d˜J¨°¸ÑAÔAÐAØ�ŠÐW×^Ò^Ð_dÐfkÑlÔlÝ˜)‘n”n¥e¨JÑ&7Ô&7½¸|Ñ9LÔ9LÐMÐPTÑTñ	Vô 	Vð 	Våˆt�Z ¨$Ñ/Ô/Ð/Ý�d˜J¨°¸ÑAÔAÐAðBð Bð Bñ Bô Bð Bð Bð Bð Bð Bð Bð Bøøøð Bð Bð Bð Bð Bð Bs   ·BCÃCÃCc           	      óB  — t          ¦   «         5 }t          || |¦  «         |                     d                     |rdnd¦  «        |r|pt	          ¦   «         nd | t          |¦  «        f¦  «        j        }|rt          || ¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )NzrUPDATE titles SET hidden_from_continue_at=? WHERE media_type=? AND tmdb_id=? AND hidden_from_continue_at IS {}NULLrú   zNOT )rS   ro   r%   r9   rW   rU   r�   ra   )r_   re   Úhiddenr±   r(   rM   s         r   Úset_hidden_from_continuer    sò   € Ý	‰Œð +�Ý�d˜J¨Ñ0Ô0Ð0Ø—,’,ð  GßGMÂvÐTZÐNfÈbÈbÐ`fÑGgÔGgØ*0Ð:�t�~�t™vœvø°d¸JÍÈGÉÌÐUñWô WäW_ð 	ð ð 	+Ý˜˜zÑ*Ô*Ð*ð+ð +ð +ñ +ô +ð +ð +ð +ð +ð +ð +ð +øøøð +ð +ð +ð +ð +ð +s   �A8BÂBÂBc                  ó  — t          ¦   «         } 	 d„ |                      d¦  «        D ¦   «         }|d„ |                      d¦  «        D ¦   «         z  }|                      ¦   «          n# |                      ¦   «          w xY w|S )zX[('movie', id, None, None), ('tv', show, season, episode)] for every stored watch state.c                 ó&   — g | ]}d |d         ddf‘ŒS )r¥   r   Nr   r‚   s     r   r¿   z"all_state_keys.<locals>.<listcomp>'  s%   € ÐeÐeÐe°�˜!˜Aœ$  dÐ+ÐeÐeÐer
   zSELECT tmdb_id FROM movie_statec                 ó>   — g | ]}d |d         |d         |d         f‘ŒS )Útvr   r+   r-   r   r‚   s     r   r¿   z"all_state_keys.<locals>.<listcomp>(  s-   € ÐvÐvÐv¨a�$˜˜!œ˜a œd A a¤DÐ)ÐvÐvÐvr
   z2SELECT show_id, season, episode FROM episode_state)r    r%   rH   )r(   Úkeyss     r   Úall_state_keysr  #  s|   € å‰9Œ9€DðØeÐe°T·\²\ÐBcÑ5dÔ5dÐeÑeÔeˆØÐvÐv°4·<²<Ð@tÑ3uÔ3uÐvÑvÔvÑvˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ€Ks   �AA& Á&A<c                  ó$  — t          ¦   «         5 } |                      d¦  «                             ¦   «         d         |                      d¦  «                             ¦   «         d         |                      d¦  «                             ¦   «         d         dœ}dD ]*}|                      d                     |¦  «        ¦  «         Œ+|                      d¦  «         t	          | d	¦  «         t	          | d
¦  «         ddd¦  «         n# 1 swxY w Y   |S )zeDelete every watched / resume state and the play log; the lists stay. Returns the removed row counts.z SELECT COUNT(*) FROM movie_stater   z"SELECT COUNT(*) FROM episode_statezSELECT COUNT(*) FROM play_log)ÚmoviesÚepisodesÚplays)r¦   r¨   Úplay_logr  Úpending_markszDELETE FROM {}zEUPDATE titles SET last_activity_at=NULL, hidden_from_continue_at=NULLr¥   r  N)rS   r%   r1   r9   ra   )r(   Úcountsrh   s      r   Úreset_watch_stater  .  sB  € å	‰Œð !�Ø ŸLšLÐ)KÑLÔL×UÒUÑWÔWÐXYÔZØ"ŸlšlÐ+OÑPÔP×YÒYÑ[Ô[Ð\]Ô^ØŸ<š<Ð(GÑHÔH×QÒQÑSÔSÐTUÔVðXð Xˆð eð 	9ð 	9ˆEØ�LŠLÐ)×0Ò0°Ñ7Ô7Ñ8Ô8Ð8Ð8Ø�ŠÐ\Ñ]Ô]Ð]Ý�T˜7Ñ#Ô#Ð#Ý�T˜4Ñ Ô Ð ð!ð !ð !ñ !ô !ð !ð !ð !ð !ð !ð !øøøð !ð !ð !ð !ð €Ms   �C*DÄD	ÄD	c                 ó  — t          ¦   «         }	 |                     d| t          |¦  «        f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY w|rt          |¦  «        nd S )Nz5SELECT * FROM titles WHERE media_type=? AND tmdb_id=?)r    r%   rU   r1   rH   r´   r¡   s       r   Ú	get_titler  <  sx   € Ý‰9Œ9€DðØ�lŠlÐRØ&­¨G©¬Ð5ñ7ô 7ß7?²x±z´zð 	ð 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØÐ%�4�‰9Œ9ˆ9 Ð%r£   )ÚlikeÚdislikeÚhideÚpickc                 ó†  — |�+|t           vr"t          d                     |¦  «        ¦  «        ‚t          ¦   «         5 }|€&|                     d| t          |¦  «        f¦  «         nD|                     d| t          |¦  «        |t          |�|nt          ¦   «         ¦  «        f¦  «         ddd¦  «         dS # 1 swxY w Y   dS )zflike / dislike / hide (not interested) / pick (first-run favourite); None clears the title's feedback.NzUnknown feedback {!r}z5DELETE FROM feedback WHERE media_type=? AND tmdb_id=?zOINSERT OR REPLACE INTO feedback(media_type, tmdb_id, value, at) VALUES(?,?,?,?))ÚFEEDBACK_VALUESrv   r9   rS   r%   rU   rW   )r_   re   Úvaluer±   r(   s        r   Úset_feedbackr&  K  s   € àÐ˜U­/Ð9Ð9ÝÐ0×7Ò7¸Ñ>Ô>Ñ?Ô?Ð?Ý	‰Œð g�Øˆ=Ø�LŠLÐPÐS]Õ_bÐcjÑ_kÔ_kÐRlÑmÔmÐmÐmà�LŠLÐjØ$¥c¨'¡l¤l°E½3ÀtÐGW¸t¸tÕ]aÑ]cÔ]cÑ;dÔ;dÐeñgô gð gð	gð gð gñ gô gð gð gð gð gð gð gð gøøøð gð gð gð gð gð gs   ¼A-B6Â6B:Â=B:c                  ó†   — t          ¦   «         5 } |                      d¦  «        j        cddd¦  «         S # 1 swxY w Y   dS )zfDelete the likes and the first-run picks, so Pro tebe offers the pick again; dislikes and hidden stay.z4DELETE FROM feedback WHERE value IN ('like', 'pick')N)rS   r%   r�   ©r(   s    r   Úreset_taster)  W  s“   € å	‰Œð ]�Ø�|Š|ÐRÑSÔSÔ\ð]ð ]ð ]ð ]ñ ]ô ]ð ]ð ]ð ]ð ]ð ]ð ]øøøð ]ð ]ð ]ð ]ð ]ð ]rï   c                  óâ   — t          ¦   «         } 	 |                      d¦  «                             ¦   «         }|                      ¦   «          n# |                      ¦   «          w xY wd„ |D ¦   «         S )zB{(media_type, tmdb_id): (value, at)} of every title with feedback.z3SELECT media_type, tmdb_id, value, at FROM feedbackc                 óL   — i | ]!}|d          |d         f|d         |d         f“Œ"S )r_   re   r%  Úatr   r‚   s     r   r…   z get_feedback.<locals>.<dictcomp>d  s4   € ÐQÐQÐQÀqˆQˆ|Œ_˜a 	œlÐ+¨a°¬j¸!¸D¼'Ð-BÐQÐQÐQr
   r†   rZ   s     r   Úget_feedbackr-  ]  sc   € å‰9Œ9€DðØ�|Š|ÐQÑRÔR×[Ò[Ñ]Ô]ˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØQÐQÈDÐQÑQÔQÐQrº   c                 óæ   — t          ¦   «         }	 |                     d| f¦  «                             ¦   «         }|                     ¦   «          n# |                     ¦   «          w xY w|r|d         nd S )Nú#SELECT value FROM flags WHERE key=?r%  ©r    r%   r1   rH   )rO   r(   rN   s      r   Úget_flagr1  i  sf   € Ý‰9Œ9€DðØ�lŠlÐ@À3À&ÑIÔI×RÒRÑTÔTˆà�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØÐ(ˆ3ˆwŒ<ˆ< DÐ(rˆ   c                 óž   — t          ¦   «         5 }|                     d| t          |¦  «        f¦  «         d d d ¦  «         d S # 1 swxY w Y   d S )Nz5INSERT OR REPLACE INTO flags(key, value) VALUES(?, ?))rS   r%   Ústr)rO   r%  r(   s      r   Úset_flagr4  r  s¤   € Ý	‰Œð a�Ø�ŠÐLÈsÕTWÐX]ÑT^ÔT^ÐN_Ñ`Ô`Ð`ðað að añ aô að að að að að að að aøøøð að að að að að as   �&AÁAÁ	A))r¥   zwatchlist_movies.json)r  zwatchlist_series.jsonc                 ó  ‡— t          | ¦  «        }‰�!‰d         |d         k    rt          d¦  «        ‚|Š‰d         si S t          d¦  «        ‰d         k    ri S ‰d         D ]}t          |¦  «         Œt	          ¦   «         5 }|                     dd¦  «                             ¦   «         }|r |d         ‰d         k    ri cddd¦  «         S t          D ]¼\  }}|                     d	|f¦  «                             ¦   «         d
         }d}	‰d         |         D ]d}
|
d         }t          |||¦  «         |                     d|t          ¦   «         t          j        |
d¬¦  «        ||f¦  «        j        }|rd}	|dz  }Œe|	rt          ||d¦  «         Œ½|                     dd‰d         f¦  «         |                     ddt          t          ¦   «         ¦  «        f¦  «         ddd¦  «         n# 1 swxY w Y   ˆfd„t          D ¦   «         S )a>  Explicit, atomic append/merge. Originals and immutable backup copies stay.

    Return valid unique source counts ({} for an already committed fingerprint).
    A failed read/backup or a changed reviewed snapshot raises without importing.
    Existing membership, snapshots, order and watch state take precedence.
    NÚfingerprintz'Legacy lists changed after confirmationÚfilesúwatchlists.import.v2r/  )r8  r%  rš   r   Fr’   rr   z¦UPDATE titles SET in_list=1, list_pos=?, list_added_at=COALESCE(list_added_at, ?), legacy_json=COALESCE(legacy_json, ?) WHERE media_type=? AND tmdb_id=? AND in_list=0rŠ   Tr+   z3INSERT OR REPLACE INTO flags(key,value) VALUES(?,?)Úwatchlists_importedc                 óN   •— i | ]!\  }}|t          ‰d          |         ¦  «        “Œ"S )r’   )r‘   )rƒ   ÚkindÚ_nameÚsnapshots      €r   r…   z%import_watchlists.<locals>.<dictcomp>¤  s1   ø€ ÐQÐQÐQ±[°T¸5ˆD•#�h˜yÔ)¨$Ô/Ñ0Ô0ÐQÐQÐQr
   )Úinspect_watchlist_importrv   r1  Ú_import_backuprS   r%   r1   ÚLEGACY_FILESro   rW   rt   r�   r�   ra   r3  )Úprofile_dirr=  ÚcurrentrË   r(   Úflagr_   r<  r�   rM   rz   re   Úupdateds    `           r   Úimport_watchlistsrE  z  sÌ  ø€ õ ' {Ñ3Ô3€GØÐ ¨Ô 7¸7À=Ô;QÒ QÐ QÝÐBÑCÔCÐCØ€HØ�GÔð Øˆ	ÝÐ&Ñ'Ô'¨8°MÔ+BÒBÐBØˆ	Ø˜7Ô#ð ð ˆÝ�vÑÔÐÐÝ	‰Œð ;�Ø�|Š|ÐAÐC\Ñ]Ô]×fÒfÑhÔhˆØð 	�D˜”M X¨mÔ%<Ò<Ð<Øð;ð ;ð ;ð ;ñ ;ô ;ð ;ð ;õ ".ð 	5ð 	5ÑˆJ˜Ø—,’,ð  BØDNÀ=ñRô RßRZÒRZÑR\ÔR\Ð]^ô`ˆCàˆGØ! )Ô,¨ZÔ8ð 
ð 
�Ø œ+�Ý˜d J°Ñ8Ô8Ð8ØŸ,š,ð (Xð ),­T©V¬VµT´ZÀÐTYÐ5ZÑ5ZÔ5ZÐ\fÐhoÐ'pñ	rô rô s{ð	 ð
 ð Ø"�GØ˜1‘H�CøØð 5Ý˜T :¨tÑ4Ô4Ð4øØ�ŠÐJØ,¨h°}Ô.EÐFñ	Hô 	Hð 	Hà�ŠÐJØ+­Sµ±´©[¬[Ð9ñ	;ô 	;ð 	;ð/;ð ;ð ;ñ ;ô ;ð ;ð ;ð ;ð ;ð ;ð ;øøøð ;ð ;ð ;ð ;ð2 RÐQÐQÐQÅLÐQÑQÔQÐQs   Â>G-ÃDG-Ç-G1Ç4G1c                 óÒ   — t          | t          ¦  «        st          | t          t          f¦  «        sdS 	 t          | ¦  «        }d|cxk     rdk    rn n|ndS # t          $ r Y dS w xY w)zIOnly positive integer TMDb IDs; bool/fractional/overflow IDs are invalid.Nr   l   ÿÿÿÿ )Ú
isinstancer    rU   r3  rv   )r%  Únumbers     r   Ú
_import_idrI  §  sŒ   € å�%�ÑÔð ¥j°½½c¸
Ñ&CÔ&Cð ØˆtðÝ�U‘”ˆØ˜VÐ:Ð:Ò:Ð:Ð':Ò:Ð:Ð:Ð:Ð:ˆvˆvÀÐDøÝð ð ð Øˆtˆtðøøøs   µ"A Á
A&Á%A&c                 ó¤  ‡— ddl }|                     d¦  «        }i i g ddddœ}t          D �]d\  }}t          j                             | |¦  «        }t          j                             |¦  «        s|dz  }|                     |                     d¦  «        dz   ¦  «         g t          ¦   «         }}d}		 t          |d¦  «        5 }
|
                     ¦   «         }ddd¦  «         n# 1 swxY w Y   n# t          $ r d}Y nw xY w|��_|                     d	|                     |¦  «                             ¦   «         z   ¦  «         t          j        |                     d
¦  «        t"          ¬¦  «        }t%          |t&          ¦  «        st)          d|z   ¦  «        ‚t+          |¦  «        }	|d                              ||dœ¦  «         |D ]œ}t%          |t.          ¦  «        r"t1          |                     d¦  «        ¦  «        nd}|€|dxx         dz  cc<   ŒN||v r|dxx         dz  cc<   Œc|                     |¦  «         |                     t/          ||¬¦  «        ¦  «         Œ�n|                     d¦  «         ||d         |<   |	|d         |<   �Œft7          ¦   «         }	 |d                              ¦   «         D ]O\  }}d„ |                     d|f¦  «        D ¦   «         Š|dxx         t=          ˆfd„|D ¦   «         ¦  «        z  cc<   ŒP	 |                     ¦   «          n# |                     ¦   «          w xY w|                      ¦   «         |d<   |S )zèRead-only reviewed snapshot; unreadable/malformed whole files raise.

    Fall back to old *.migrated files only when the original is absent. Invalid
    individual entries are counted and retained in the original/backup bytes.
    r   Ns   watchlists-import-v2 )r’   r  r7  Ú
duplicatesÚinvalidrÜ   ú	.migratedzutf-8ó    Úrbs   present z	utf-8-sig)Úparse_constantz&Legacy watchlist must be a JSON list: r7  )r   Úrawrr   rL  r+   rK  )rr   s   absent r’   r  c                 ó   — h | ]
}|d          ’ŒS )r   r   r‚   s     r   ú	<setcomp>z+inspect_watchlist_import.<locals>.<setcomp>ß  s.   € ð Að Að A ˜˜!œð Að Að Ar
   z;SELECT tmdb_id FROM titles WHERE media_type=? AND in_list=1rÜ   c              3   ó,   •K  — | ]}|d          ‰v V — ŒdS )rr   Nr   )rƒ   ÚerÜ   s     €r   ú	<genexpr>z+inspect_watchlist_import.<locals>.<genexpr>á  s,   øè è € Ð%KÐ%K¸a a¨¤g°Ð&9Ð%KÐ%KÐ%KÐ%KÐ%KÐ%Kr
   r6  )!ÚhashlibÚsha256r@  r   r   r   ÚexistsrY   Úencoder!   ÚopenÚreadÚFileNotFoundErrorÚdigestrt   ru   ÚdecodeÚ_import_bad_constantrG  Úlistrv   r‘   rx   r´   rI  rÈ   Úaddr    Úitemsr%   ÚsumrH   Ú	hexdigest)rA  rW  r^  ry   r_   Únamer   r’   ÚseenÚcountÚhandlerQ  Údatarz   re   r(   rÜ   s                   @r   r>  r>  ²  sÙ  ø€ ð €N€N€NØ�^Š^Ð5Ñ6Ô6€FØ r°BÀaÐTUÐcdÐeÐe€FÝ(ð  -ñ  -Ñˆ
�DÝŒw�|Š|˜K¨Ñ.Ô.ˆÝŒw�~Š~˜dÑ#Ô#ð 	 Ø�KÑˆDØ�Š�d—k’k 'Ñ*Ô*¨UÑ2Ñ3Ô3Ð3Ø�C™EœE�ˆØˆð	Ý�d˜DÑ!Ô!ð $ VØ—k’k‘m”m�ð$ð $ð $ñ $ô $ð $ð $ð $ð $ð $ð $øøøð $ð $ð $ð $øøå ð 	ð 	ð 	ØˆCˆCˆCð	øøøà‰?à�MŠM˜,¨¯ª¸Ñ)<Ô)<×)CÒ)CÑ)EÔ)EÑEÑFÔFÐFÝ”:˜cŸjšj¨Ñ5Ô5ÕFZÐ[Ñ[Ô[ˆDÝ˜d¥DÑ)Ô)ð RÝ Ð!IÈDÑ!PÑQÔQÐQÝ˜‘I”IˆEØ�7ŒO×"Ò"¨D¸Ð#=Ð#=Ñ>Ô>Ð>Øð <ð <�Ý9CÀEÍ4Ñ9PÔ9PÐZ�* U§Y¢Y¨t¡_¤_Ñ5Ô5Ð5ÐVZ�Ø�?Ø˜9Ð%Ð%Ô%¨Ñ*Ð%Ð%Ñ%Ð%Ø �_�_Ø˜<Ð(Ð(Ô(¨AÑ-Ð(Ð(Ñ(Ð(à—H’H˜WÑ%Ô%Ð%Ø—N’N¥4¨°'Ð#:Ñ#:Ô#:Ñ;Ô;Ð;Ð;ð<ð �MŠM˜+Ñ&Ô&Ð&Ø(/ˆˆyÔ˜*Ñ%Ø',ˆˆxÔ˜Ñ$Ñ$Ý‰9Œ9€DðØ#)¨)Ô#4×#:Ò#:Ñ#<Ô#<ð 	Lð 	LÑˆJ˜ðAð A d§l¢lÐ3pØ2<°ñ'@ô '@ð Añ Aô AˆHà�:ÐÐÔ¥#Ð%KÐ%KÐ%KÐ%KÀ7Ð%KÑ%KÔ%KÑ"KÔ"KÑKÐÐÑÐð	Lð
 	�
Š
‰Œˆˆøˆ�
Š
‰ŒˆˆøøøØ"×,Ò,Ñ.Ô.€Fˆ=ÑØ€MsC   Â3C0ÃC$ÃC0Ã$C(	Ã(C0Ã+C(	Ã,C0Ã0C?Ã>C?Ê A*L  Ì L6c                 ó&   — t          d| z   ¦  «        ‚)NzInvalid JSON number: )rv   )r%  s    r   r`  r`  è  s   € Ý
Ð,¨uÑ4Ñ
5Ô
5Ð5r
   c                  óÌ   — t          ¦   «         } 	 |                      d¦  «                             ¦   «         du |                      ¦   «          S # |                      ¦   «          w xY w)zHAutomatic migration is offered only before either new list is populated.z,SELECT 1 FROM titles WHERE in_list>0 LIMIT 1Nr0  r(  s    r   Úwatchlist_import_emptyrm  ì  sS   € å‰9Œ9€DðØ�|Š|ÐJÑKÔK×TÒTÑVÔVÐZ^Ð^à�
Š
‰Œˆˆøˆ�
Š
‰Œˆˆøøøs   �(A ÁA#c                 ó:  — ddl }| d         | d         }}|                     d¦  «        r|S |dz   }|dz   |                     |¦  «                             ¦   «         z   dz   }d}	 	 t	          |d	¦  «        5 }|                     |¦  «         |                     ¦   «          t          j        | 	                    ¦   «         ¦  «         ddd¦  «         n# 1 swxY w Y   n«# t          $ rœ t	          |d
¦  «        5 }|                     ¦   «         |k    r6t          j        | 	                    ¦   «         ¦  «         |cddd¦  «         cY S 	 ddd¦  «         n# 1 swxY w Y   |dk    r|n|dz   t          |¦  «        z   }|dz  }Y nw xY w�Œ$	 t          j        t          j                             |¦  «        pdt          j        ¦  «        }	 t          j        |¦  «         t          j        |¦  «         n# t          j        |¦  «         w xY wn# t"          $ r Y nw xY w|S )záNever overwrite an older backup; fsync before the database commit.

    A truncated copy left by a crash is kept; a new copy is retried. Exclusive
    creation works on Android/external storage without hard-link support.
    r   Nr   rQ  rM  z.migration-z.bakTÚxbrO  ú.r+   )rW  ÚendswithrX  re  r[  ÚwriteÚflushr   ÚfsyncÚfilenoÚFileExistsErrorr\  r3  r   r   ÚO_RDONLYrH   ÚOSError)	rË   rW  r   rQ  ÚtargetÚfallbackÚattemptri  r'   s	            r   r?  r?  õ  s¿  € ð €N€N€NØ�v”  u¤ˆ#€DØ‡}‚}�[Ñ!Ô!ð ØˆØ�KÑ€FØ�mÑ# g§n¢n°SÑ&9Ô&9×&CÒ&CÑ&EÔ&EÑEÈÑN€HØ€Gðð	Ý�f˜dÑ#Ô#ð * vØ—’˜SÑ!Ô!Ð!Ø—’‘”�Ý”˜Ÿš™œÑ)Ô)Ð)ð*ð *ð *ñ *ô *ð *ð *ð *ð *ð *ð *øøøð *ð *ð *ð *ð øÝð 	ð 	ð 	Ý�f˜dÑ#Ô#ð " vØ—;’;‘=”= CÒ'Ð'å”H˜VŸ]š]™_œ_Ñ-Ô-Ð-Ø!ð	"ð "ð "ð "ñ "ô "ð "ð "ð "ð "Ø'ð"ð "ð "ñ "ô "ð "ð "ð "ð "ð "ð "øøøð "ð "ð "ð "ð
 ")¨A¢ �X�X°8¸c±>ÅCÈÁLÄLÑ3PˆFØ�q‰LˆGˆGˆGð	øøøñð"Ý”�œŸš¨Ñ.Ô.Ð5°#µr´{ÑCÔCˆð	ÝŒH�VÑÔÐåŒH�VÑÔÐÐø�BŒH�VÑÔÐÐøøøÐøÝð ð ð Øˆðøøøà€MsŒ   Á%C Á5ACÃC ÃCÃC ÃCÃC ÃFÃ7A EÄ7FÅFÅE	ÅFÅE	Å%FÆFÆ	>H ÇG1 ÇH Ç1HÈH È
HÈHr@   )FrÕ   )NNNN)NNN)TNN)rô   )rü   N)FrQ   rt   r   r   rV   r2   r   r   r	   r   r3   r6   r7   r8   Ú
Connectionr   r    r&   r>   rS   rW   r\   ra   rm   ro   r{   r‡   r˜   rž   r¢   rd   r¯   r²   rµ   r¹   r¼   rÁ   rÌ   rÎ   rÐ   rÒ   rà   ræ   rê   rî   rñ   ró   rø   rû   rÿ   r  r  r  r  r  r  r  r$  r&  r)  r-  r1  r4  r@  rE  rI  r>  r`  rm  r?  r   r
   r   ú<module>r}     s”  ððð ð
 €€€Ø 	€	€	€	Ø €€€Ø €€€à€Ø
€Ø€ðð ð ðoð oð oð€	ð<€	ð€	ð€	ð	ð 	ð 	ð 	ð 	�'Ô$ñ 	ô 	ð 	ðð ð ð ðð ð ð<ð ð ð ð ñ ô ð ð<ð ð ð ðð ð ð"ð "ð "ð
4ð 4ð 4ð 4ð
nð nð nð nðoð oð oðð ð ð&jð jð jð1ð 1ð 1ð21ð 1ð 1ð 1ð$(ð (ð (ðYð Yð Yð Yð{ð {ð {ð
#ð #ð #ð&ð &ð &ð &ð1ð 1ð 1ð
ð 
ð 
ð#ð #ð #ðFð Fð Fð Fð&Bð Bð Bð BðBð Bð Bð BðFð Fð Fð Fðð ð ð ð@'ð 'ð 'ðð ð ðfð fð fð
Cð Cð Cðð ð ð ð#ð #ð #ð #ðð ð ð ðð ð ð ðð ð ð ð?ð ?ð ?ð	Bð 	Bð 	Bð 	Bð+ð +ð +ð +ðð ð ðð ð ð&ð &ð &ð 6€ð	gð 	gð 	gð 	gð]ð ]ð ]ðRð Rð Rð)ð )ð )ðað að að
 U€ð*Rð *Rð *Rð *RðZð ð ð3ð 3ð 3ðl6ð 6ð 6ðð ð ð&ð &ð &ð &ð &r
   