
    jnH                       d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
ZddlmZmZ ddlmZmZ ddlmZ  ed      Z ed      Z ed	      Z ed
      Z ed      ZdZddhZddhZddhZh dZ ej:                  dej<                        Z ej:                  d      Z d Z!d Z"d Z#d Z$d%dZ%d Z&d Z'd&dZ(d Z)d Z*d  Z+d! Z,d" Z-d# Z.e/d$k(  r e.        yy)'zBAA-041 read-only staging reconciler. No productive writes/imports.    )annotationsN)Counterdefaultdict)datetimetimezone)Pathz2/opt/struktur/obsidian-graphiti-reconciler-stagingz/opt/obsidian-vaultzB/opt/struktur/obsidian-graphiti-import/obsidian_graphiti_import.dbz+/opt/struktur/youtube-research/knowledge.dbz_/opt/struktur/knowledge-pipeline-aggregator-staging/obsidian-graphiti-reconciliation-AA040.jsonzhttp://127.0.0.1:8644z.gitz	.obsidiancachez_pipeline.logzno-graphitizexclude-from-graphiti>   	07-Archiv
00-Staging
AG-CONTEXT
LP-CONTEXT
SYNC-LP-AG03-ProjekteAG-SPECIFICLP-SPECIFIC06-Daily-NotesYouTube ResearchYouTube-Researchdraftarchivbackuparchiveprivatevorlagetemplate05_SESSIONSzD(?:youtube\.com/(?:watch\?v=|shorts/)|youtu\.be/)([A-Za-z0-9_-]{6,})z6(?<![A-Za-z0-9_-])([A-Za-z0-9_-]{11})(?![A-Za-z0-9_-])c                 d    t        j                  t        j                        j	                         S N)r   nowr   utc	isoformat     !/opt/struktur/aa041_reconciler.pyr   r      s    (,,x||,6688r#   c                H    t        j                  |       j                         S r   )hashlibsha256	hexdigest)bs    r$   shar*      s    7>>!$..00r#   c                .   | j                  dd      j                  dd      j                  dd      }t        j                  dd|      j	                         j                         }t        j                  |j                               j                         S )Nutf-8replacez

z\s+ )
decoder-   resubstriplowerr&   r'   encoder(   )r)   ss     r$   normr8      sn    hhwy!))&6>>tDIAffVC  "((*A>>!((*%//11r#   c                N    t        j                  dt        |       z   dz   d      S )Nzfile:z?mode=roT)uri)sqlite3connectstr)paths    r$   dbr?      s     W__WSY%6z%AdKKr#   c                    t         j                  | _        | j                  ||      D cg c]  }t	        |       c}S c c}w r   )r;   Rowrow_factoryexecutedict)cqargsxs       r$   rowsrI      s/    ++AM		!D8I&J1tAw&JJ&Js   ?c                V   | sy| j                         j                  d      } t        j                  |       }|rd|j                  d      z   S t	        j
                  dd| t        j                        } t	        j
                  dd|       j                  d	      } | j                         S )
N z`<> https://www.youtube.com/watch?v=   z
^https?://zhttps://)flagsz[?#].*$/)	r4   
YOUTUBE_REsearchgroupr2   r3   Irstripr5   )ums     r$   canonical_urlrW      s    BggiooeAA21771:=	=ff]:abdd3AffZ1$$S)A779r#   c                \    t         j                  | xs d      }|r|j                  d      S y)NrK   rM   )rP   rQ   rR   )textrV   s     r$   
youtube_idrZ   '   s)    
#A
	r#   c                    t        |       }|rd|z   S t        j                  d| xs d      }|rdt        |d         z   S d|z   S )Nyoutube:zhttps?://[^\s`)>]+rK   zurl:r   z	obsidian:)rZ   r2   findallrW   )rY   r>   source_typeyurlss        r$   source_identityra   +   sN    A
1		)$*"	5D6-Q000tr#   c                 @   	 t         j                  j                  t        dz   d      5 } t	        j
                  | j                               cd d d        S # 1 sw Y   y xY w# t        $ r1}g t        |      j                  dz   t        |      z   dcY d }~S d }~ww xY w)N/episodes/inventoryZ   )timeout: )episodeserror)urllibrequesturlopenGRAPHITIjsonloadsread	Exceptiontype__name__r=   )res     r$   graphiti_inventoryru   2   s{    V^^##H-B$B2#NoRS[_[e[efgflflfn[ooooURQ8H8H8McRSf8T!UUUs:   (A# #A	A# A A#  A# #	B,&BBBc                    t        | t              r&dj                  d | j                         D              S t        | t              rdj                  d | D              S t        |       S )Nr0   c              3  2   K   | ]  }t        |        y wr   flatten.0vs     r$   	<genexpr>zflatten.<locals>.<genexpr>7   s     *J!71:*J   c              3  2   K   | ]  }t        |        y wr   rx   rz   s     r$   r}   zflatten.<locals>.<genexpr>8   s     *A!71:*Ar~   )
isinstancerD   joinvalueslistr=   )rH   s    r$   ry   ry   6   sM    !D#((*Jqxxz*J"JJ!D#((*Aq*A"AAq6Mr#   c                `   g }| j                  dg       D ]  }t        |      }t        t        j	                  |            }|j                  t        |j                  dd            t        |j                  dd            t        |j                  dd            |t        |      d        |S )Nrg   uuidrK   namesource_description)r   r   r   rY   youtube_ids)getry   setrP   r]   appendr=   sorted)invoutrt   rY   idss        r$   episode_infor   :   s    
CWWZ# oQZ
""4()

3quuVB/0AEE&<L8Mcfghglgl  nB  CE  hF  dG  OS  bh  il  bm  n  	o	o
 Jr#   c                   | j                  dd      j                  d      }| j                         }t        d |D              ryt        d |D              ry|t	        |       j
                  gz   D ]  t        fdt        D              s y t        D cg c]  }|j                         |v s| }}|rd d	d
j                  |      z   fS yc c}w )N\rO   c              3  ,   K   | ]  }|t         v   y wr   )	TECH_DIRS)r{   ps     r$   r}   z%classify_exclusion.<locals>.<genexpr>F   s     
)a1	>
)s   )TECHNICAL_EXCLUDEztechnical metadata directoryc              3  t   K   | ]0  }t         D ]%  }|j                         |j                         k(   ' 2 y wr   )TECH_PATTERNSr5   )r{   r   rH   s      r$   r}   z%classify_exclusion.<locals>.<genexpr>G   s.     
FA
F11779aggi
F
Fs   68)r   ztechnical cache/log patternc              3  ^   K   | ]$  }|j                         j                         v  & y wr   )r5   )r{   rH   r   s     r$   r}   z%classify_exclusion.<locals>.<genexpr>I   s"     8!qwwyAGGI%8s   *-)EXPLICIT_OPT_OUTzexplicit no-graphiti markerz1legacy/fachlicher pattern not used as exclusion: ,)NrK   )	r-   splitr5   anyr   stemEXPLICITFACH_PATTERNSr   )relpartslowrH   matchesr   s        @r$   classify_exclusionr   C   s    
++d3

%
%c
*E		C

)5
))2d

F
FF  PADINN## r8x88Aqr%:1c)9Q:G:dNsxxX_O```` ;s   C1Cc                    	 t        j                  t        j                               } | j	                  di       j	                  dg       D ci c]  }|j	                  d      | }}| |fS c c}w # t
        $ r i i fcY S w xY w)Nobsidianwithout_graphitirelative_path)rm   rn   AA40	read_textr   rp   )rH   rs   olds      r$   load_oldr   N   sy    "

4>>#$a-.UU:b-A-E-EFXY[-\
]155!!#
]c
]sUl ^!BrE\!s$   AA1 A,&A1 ,A1 1B Bc                   < t         j                  dd       t               } t               \  }}t	        t
              }t	        t              }t        |d      }t        |d      }t        |d      }t        |d      }|D 	ci c]  }	|	d   |	
 }
}	t        t              }|D ])  }||j                  d      xs d	   j                  |       + t        t              }|D ])  }	||	j                  d
      xs d	   j                  |	       + t               }t        |      }t        t              }|D ]   }|d   D ]  }||   j                  |        " g }t        t              }t        t              }t        t        j!                  d            D ]f  }|j#                  t              j%                         }|j'                         }|j)                  dd      }t+        |      }t-        |      }t/        ||      }t1        |      }|}t3        |      \  }}|r|j                  |g       ng } |
j                  |i       x}!}"|j                  |g       }#|j                  |g       }$t5        |j                  di       j                  d      t6              r2|j                  di       j                  di       j                  |i       ni }%|r	|}&d}'d}(d})n||   j                  |       ||   j                  |       |%j                  d      dk(  xs |%j                  d      dk(  }*|*r	d}&d}'d}(d})n| r,t9        |      dk\  rdnd}&|&j;                  d      rdnd}'d }(d!})ns|!r|!j                  d"      |k(  r	d}&d}'d}(d#})nT|!r.|!j                  d"      r|!j                  d"      |k7  r	d$}&d}'d}(d%})n$|%j                  d      d&v r	d'}&d(}'d }(d)})nd*}&d+}'d }(d,})i d-t+        |j=                               d d. d/|d0|j>                  d1|d2|d3t9        |      d4tA        jB                  |jE                         jF                  tH        jJ                        jM                         d5|rd6ndd7|d8|d9|rd:|z   nd	d;|rd<nd=d>|!j                  d"d	      d?|!rd@tO        |!j                  dA            z   n#|$r dBtO        |$dC   j                  dA            z   nd	dD| s|%j                  d      dk(  rdEndFdG|)dH| r| dC   dI   n|!j                  dHd	      i dJt9        |       xs |!j                  dH      rdKndCdL|%j                  dMd	      dNtQ        |%j                  dN      xs dC      dOd	dP| r|nd	dQ*s|!r|!j                  d"      |k(  rdRn| rdSndTdU| dV|!j                  dWd	      dX|!j                  dXd	      dY|'dZ|xs | rd[nd	d\|(d]|&d^|xs |)d_|d`z   |z   da|!s|$s| rdEndb}+|j                  |+       i |D ]x  }	|	d]   dcvr)t9        ||	d2            dKkD  rdd|	d]<   d(|	dY<   d|	d\<   de|	d^<   3|	d]   dcvs;t9        ||	d7            dKkD  sP|	d7   jS                  df      sedg|	d]<   d(|	dY<   d |	d\<   dh|	d^<   z |rt        |dC         ng },t         diz  jU                  djd	dk      5 }-tW        jX                  |-|,l      }.|.j[                          |.j]                  |       d d d        t_        dm |D              <| dtO        t              tO        t
              tO        t              t`        dnz   tO        tb              dot7        <      |t7        t_        dp |D                    t7        t_        dq |D                    t9        |      |j                  drd	      te        ds |D              dtte        <jg                               t9        |      k(  t9        |      te        <jg                               ddudv	}/t         dwz  ji                  tk        jl                  |/dxdyz      d{       g d|}0to        jp                  d}tn        jr                        }1g }2|0D ]  }3tu        |3      }4|4jw                         s|4j!                  d~      D ]  }|jy                         s|jz                  dv s#|j}                  d      }5|1j                  |5      sG|2j                  |j>                  d|3z   tO        |      dd6tO        |      j                         v rd6nddSd|5v sd|5j                         v rdRnddSddRdd         |2D 6ci c]  }6|6d   |6
 }2}6t         dz  }7|7jU                  djd	dk      5 }-|2r9t        t        t        |2jg                                     j                               ndg}8tW        jX                  |-|8l      }.|.j[                          |.j]                  |2jg                                d d d        |D 	cg c]  }	|	d5   d6k(  s|	 c}	d d }9t         dz  ji                  tk        jl                  |9dxdyz      d{       dj                  <fddD              }:d|  dt         dt9        |       dt
         dt         dt`         d|: dte        <jg                                dt9        |       d};t         dz  ji                  |;d{       t        tk        jl                  | t9        |      t7        <      t9        |      t9        |2      te        <jg                               t9        |      k(  tO        t               ddx             y c c}	w # 1 sw Y   nxY w#  Y xY wc c}6w # 1 sw Y   }xY wc c}	w )NT)parentsexist_okzselect * from filesz#select * from graphiti_import_queuez(select * from source_processing_registryzselect * from videosr   obsidian_pathrK   artifact_pathr   z*.mdr,   r-   r   by_pathdo_not_importhighexcludedfinal_classificationEXACT_CURRENTgraphiti_current_hash_matchYESCURRENTnonecanonical_path_and_hashi,  &SOURCE_PRESENT_OBSIDIAN_ADDS_KNOWLEDGESOURCE_ALREADY_PRESENT	KNOWLEDGEupdate_candidatemediumcross_source_youtubecontent_hash
queue_hashCHANGEDqueue_changed_hash)PROBABLE_HISTORICALEXACT_OLDER_VERSIONHISTORICAL_MATCHreviewhistorical_old_baselineMISSINGimport_candidate	not_foundobsidian_id    canonical_relative_pathfilenamecontent_sha256normalized_content_sha256
size_bytesmtimer^   youtubera   external_source_idrW   rL   origin_pipelinezyoutube-researchzobsidian-vaultsource_content_hash
provenancezqueue:idz	registry:r   graphiti_match_statuspresentabsentgraphiti_match_typegraphiti_episode_uuidr   graphiti_episode_countrM   obsidian_document_idsobsidian_document_idobsidian_document_countgraphiti_content_hashgraphiti_source_identitycontent_equivalentyesunknownnolast_reconciled_atlast_imported_atimported_atlast_verified_atrecommended_actionreview_reasonz/cross-source identity; compare content versions
confidenceclassificationreasonimport_identity:provenance_statusmissing)r   r   	DUPLICATEz6identical normalized content at multiple current pathsr\   	AMBIGUOUSz=same stable YouTube source identity at multiple current pathsz*obsidian-graphiti-reconciliation-AA041.csvw)newlineencoding)
fieldnamesc              3  &   K   | ]	  }|d      yw)r   Nr"   r{   rs   s     r$   r}   zmain.<locals>.<genexpr>}   s     9AA&'9s   rc   )vault	import_dbknowledge_dbru   baselinec              3  @   K   | ]  }|j                  d d        yw)graphiti_statusrK   Nr   )r{   rF   s     r$   r}   zmain.<locals>.<genexpr>~   sE       Lx  mn  MN  MR  MR  Sd  eg  Mh  Lxs   c           	   3     K   | ]H  }d j                  |j                  dd      |j                  dd      |j                  dd      g       J yw)|artifact_statusrK   quality_statusr  N)r   r   r  s     r$   r}   zmain.<locals>.<genexpr>~   s       XE  |}  Y\  Ya  Ya  cd  ch  ch  iz  {}  c~  @  D  D  EU  VX  Y  Z[  Z_  Z_  `q  rt  Zu  bv  Yw  XEs   AArh   c              3  8   K   | ]  }t        |d            yw)r   N)bool)r{   rt   s     r$   r}   zmain.<locals>.<genexpr>~   s>       mR	  I	J	  nr  st  uB	  sC	  nD	  mR	s   )episode_countinventory_erroryoutube_episode_count)sum_equals_markdownmarkdown_totalclassified_totalnot_a_productive_import)	probe_time_utc	read_onlysourcessummaryrI   queue_statusregistry_statusgraphiti	integrityz+obsidian-graphiti-reconciliation-AA041.jsonF   )ensure_asciiindent)r   )z/opt/struktur/graphitiz&/opt/struktur/obsidian-graphiti-importz/opt/struktur/youtube-researchz/opt/struktur/runnersz/etc/systemd/systemzL(?:/episodes|graphiti_url|GRAPHITI|graphiti-import|graphiti_import|Graphiti)*)z.pyz.shz.servicez.timerz.ymlz.yamlignore)errorszdiscovered via z@systemd/timer/manual/importer/API (needs ownership confirmation)zobsidian/variousz	/episodesgraphiti_url	potentialzonly pipeline_writerz direct bypass or duplicate write)writer_nameservice	code_pathtriggerr^   writes_to_obsidian_firstdirect_graphiti_writecurrently_activetarget_statemigration_requiredriskr(  zgraphiti-writers-AA041.csvr&     z!youtube-representative-AA041.jsonr.   c              3  N   K   | ]  }d | dj                  |d         yw)z- rf   r   Nr  )r{   kr  s     r$   r}   zmain.<locals>.<genexpr>   s0       par!Bw{{1Q/01  ps   "%)
r   r   r   r   r   r   r   r   r   r   uM   # AA-041 – Reconciliation-/Single-Writer-Zielarchitektur

Prüfzeitpunkt: `uL  ` (UTC).

## A Executive Summary
AA-041 ist ein read-only Staging-Lauf. Der fachliche Eingang wird künftig Obsidian; der Import darf ausschließlich über einen logischen Pipeline-Writer erfolgen. Die Implementierung berechnet Aktionen, führt aber keinen Import und keine Mutation aus.

## B Ist-Architektur und Quellen
- Vault: `u#   `; vollständiger Markdown-Lauf: **z** Dateien.
- Importer-DB: `z%`, Tabelle `files`; Queue/Registry: `zY`, Tabellen `graphiti_import_queue`, `source_processing_registry`.
- Graphiti-Inventar: `uk  /episodes/inventory` (GET-only). Neo4j wurde für diesen Lauf nicht mutiert; direkte Passwortabfrage war nicht erfolgreich, daher sind Neo4j-Zahlen aus AA-040 historische Baseline und nicht live verifiziert.
- AA-040 bleibt historische Baseline, nicht Live-Status.

## C/D Graphiti-Writer
Die vollständige Pfadmatrix steht in `graphiti-writers-AA041.csv`. Gefundene direkte/potenzielle Schreiber umfassen Obsidian-Importer, allgemeine Graphiti-Importskripte, YouTube-Graphiti-Queue/-Batch-Importer, Runner, Service- und Containerpfade. Für jeden Eintrag sind Aktivität und letzte Nutzung separat zu verifizieren; `currently_active=unknown` ist bewusst kein Aktivitätsnachweis.

## E YouTube-Writer
Die 1.785 YouTube-Episoden aus AA-040 sind **historischer Teilstand**. Der Erzeuger ist anhand der vorhandenen Queue-/Batch-/Graphiti-Codepfade plausibel als YouTube-Graphiti-Queue/Batch-Importer dokumentiert; eine ID-genaue historische Kausalität ist aus dem read-only Staging-Lauf nicht vollständig nachgewiesen. Die aktuelle Graphiti-Inventory-Zahl ist separat in `obsidian-graphiti-reconciliation-AA041.json`.

## F–K Zielarchitektur / Single Writer
`Quelle → kanonischer ObsidianRecord → ReconciliationRecord → Importentscheidung → Business-/Wissenspipeline → pipeline_writer → Graphiti → Neo4j`.
`source_identity` priorisiert externe ID, kanonische URL, Provenance, Graphiti-ID, kanonischen Pfad, Hash. `import_identity = source_identity + ':' + normalized_content_sha256`. Der Writer benötigt Idempotenzprüfung, Provenance, Version, Auditlog, Fail-Stop und begrenzte Retry-Regel. Technische Durchsetzung: Graphiti loopback/internal, separater Writer-Service-Account/Credential-Pfad, Gateway mit Schreibroute nur für Writer, read-only Reader-Routen, Netzwerkpolicy, Docker-Netzwerkregeln und Auditlogs. Noch nicht produktiv umgesetzt.

## L Vollständige Klassifikation
u   

Summenprüfung: `z == u  ` → **{'JA' if sum(summary.values())==len(current) else 'NEIN'}**. Jede aktuelle Markdown-Datei hat exakt einen Hauptstatus; fachliche Ordner wurden nicht pauschal ausgeschlossen.

## W/X Cross-Source
Die frühere AA-040-Klasse `NOT_IN_GRAPHITI` wird nicht als endgültiges Fehlen übernommen. YouTube-IDs werden canonicalisiert und gegen Graphiti-Inventory abgeglichen. Die belastbare aktuelle Auswertung steht in der JSON-Matrix: `SOURCE_ALREADY_PRESENT` plus `SOURCE_PRESENT_OBSIDIAN_ADDS_KNOWLEDGE` sind cross-source Treffer; `MISSING` sind nicht nachgewiesen. Ohne inhaltliche Episodenpayloads bleibt Content-Äquivalenz bei Cross-Source-Treffern teilweise `unknown`; keine automatische Skip-Entscheidung daraus.

## Y YouTube-Stichprobe
20 Fälle (soweit vorhanden) liegen in `youtube-representative-AA041.json`; Felder für Video-ID, URL, Episode, Obsidian-Datei, Source Identity, Content-Äquivalenz, Zusatzwissen, Klassifikation und Aktion sind enthalten.

## Z Dubletten
AA-040: 928 aktuelle `DUPLICATE_OR_INCONSISTENT` und 929 Pfadgruppen sind **historische Teilstände**. AA-041 markiert nur belastbare identische normalisierte Inhalte bzw. kollidierende stabile YouTube-Identitäten als `DUPLICATE`/`AMBIGUOUS`; keine Löschung oder automatische Zusammenführung. Restursachen: `Ursache noch nicht nachgewiesen`.

## AA–AC Denylist
Technische/explizite Marker bleiben zulässig. Fachliche Ordnerpatterns wie YouTube-Research, Projekte, Daily Notes, Archiv und Sessions dürfen nach Einführung des Reconciliation-Layers nicht mehr als harte Wissensausschlüsse dienen; sie sind Legacy-/Review-Regeln. Keine produktive Regel wurde geändert.

## AD–AF Migration, Deployment, Rollback
Siehe `migration-plan-AA041.md`, `deployment-plan-AA041.md`, `rollback-plan-AA041.md`. Phasen: beobachten → Writer inventarisieren → Quellen nach Obsidian → Pipeline-Writer → Direct Writer sperren → kontrollierte Importe → Provenance-Lücken → Review-Dubletten → Monitoring. Jede Phase ist backup-, fail-stop- und rollback-gated.

## AG Tests / AH Risiken / AI Betreiberfreigaben
Unit-/Mock-Tests decken 25 verlangte Fälle ab. Risiken: unvollständige Neo4j-Live-Verbindung, historische Writer-Kausalität, Provenance-Lücken, Content-Vergleich ohne Episode-Rohpayload, kollidierende Pfade und bestehende Direct Writes. Betreiberfreigabe ist erforderlich für jede produktive Code-/Config-/Service-/Queue-/Datenänderung.

## AJ Sicherheit
Keine produktiven Daten, Queue-Status, Graphiti-/Neo4j-Daten, Dienste, Timer, Cronjobs, Konfigurationen oder Denylists verändert. Keine Recovery, kein Import, keine Episode erzeugt/gelöscht.

## Entscheidungsmatrix
- RECONCILIATION LAYER PRODUKTIV BEREIT: **NEIN** – Staging-only; Review und produktiver Pilot fehlen.
- SINGLE-WRITER-ARCHITEKTUR PRODUKTIV BEREIT: **NEIN** – Writer-Gateway/Credentials/Audit noch nicht eingeführt.
- DIRECT-WRITER-MIGRATION BEREIT: **NEIN** – vollständige Aktivitäts-/Kausalitätsbeweise und Betreiberfreigabe fehlen.
- AUTOMATISCHER IMPORT FEHLENDER OBSIDIAN-DATEN BEREIT: **NEIN** – Review, Provenance und kontrollierter Pilot fehlen.
- DUBLETTEN-BEREINIGUNG BEREIT: **NEIN** – 928/929 Fälle benötigen Review; keine automatische Mutation.

Arbeitsauftrag AA-041 erledigt.
z	AA-041.md)proberI   r  episodes_livewriterssum_okbase)r  )FBASEmkdirr   r   r?   IMPDBKDBrI   r   r   r   r   ru   r   r   VAULTrglobrelative_toas_posix
read_bytesr1   r*   r8   ra   rZ   r   r   rD   lenendswithr6   r   r   fromtimestampstatst_mtimer   r    r!   r=   int
startswithopencsv
DictWriterwriteheader	writerowsr   rl   r   sumr   
write_textrm   dumpsr2   compilerS   r   existsis_filesuffixr   rQ   r5   nextiterkeysr   print)=r3  
old_bundleold_missingicr2  impqueueregvidsrs   imp_by	q_by_pathrF   reg_by_pathr   epseps_by_yrt   r_   currenthash_groups
sid_groupsr   r   r)   rY   csnssidextexr   e_matchipimp_by_pathqsrsr   clsactionconfgtypesame_oldrowfieldsfr   datatargetspatternsr5  rootrpr7   rH   wffsytcountsreportr  s=                                                               @r$   mainr  U   s   JJtTJ*#%EPXPZ9OK	%yBBsG!R%&Cd15Z.[aefg  iS  bT]`  [_  `a  bx  [y  VZ*-.QAoq .F.+d:K	D9QUU?39r:AA!DDD!KDQUU?39r:AA!DDC,s"3ck$>OX 65! 2 21 556GK-+d:KzEKK'( 
--

'
'
)cQ\\^1!((7S\B]Tbefgbh_amqrsmtjl  {J  KO  PS  {Tvy  Xb  cg  Xh  VW  no  jm"3'ibqa1CbZZB''bIMM#b,AkooVYZ\F]2IST^TbTbcmnpTqTuTuv  UA  BF  JG*..B
'
+
+Ib
9
=
=c"
E  MOc	SOV&T
%Bs#Z_%;%;C%@/0/ArSWWMjEkmrErS6F4F_:=d)S.6Nf#  FI  FR  FR  S^  F_  pB  ekhn  rz  mq  BX  |ABFF>*B.IfvSYdam[`BFF>*rvvn/Er/Iy3asZ`  {Auy  I]  CHWW+,0]]cu_b  Gw}  NV  IM  ^w  X]c$6VX[u C=SZZ\*3B/  C0I#  CjYZY_Y_  C`pqs  C  uP  QS  C  T`  ad  ef  ag  C  ho  px  pF  pF  GH  GM  GM  GO  GX  GX  Ya  Ye  Ye  pf  pp  pp  pr  C  s@  NO  AJ  U_  C  `q  ru  C  vJ  KN  C  O^  HI  `B  CD  `D  OQ  C  Sd  {|  ew  BR  C  Sh  ik  io  io  p~  A  iB  C  CO  np  PX  Y\  ]_  ]c  ]c  dh  ]i  Yj  Pj  [	]	  wB	  C	F	  G	I	  J	K	  G	L	  G	P	  G	P	  Q	U	  G	V	  C	W	  wW	  c	e	  C  g	~	  L
S
  W
Z
  W
^
  W
^
  _
u
  W
v
  x
G  W
G  	H
  MU  C  Vk  lq  C  rI  `g  JQ  RS  JT  U[  J\  mo  ms  ms  tK  LN  mO  C  Ph  il  mt  iu  if  A  E  E  F]  ^  z{  de  C  g~  B  F  F  G]  ^`  a  C  b{  |  @C  @G  @G  Ha  @b  @g  fg  |h  C  i@  AC  C  D^  fm  _b  su  C  vJ  U]  bd  ik  io  io  p~  i  AC  iC  LQ  X_  KT  ei  C  k  @E  C  FX  Y[  Y_  Y_  `m  np  Yq  C  rD  EG  EK  EK  L^  _a  Eb  C  cw  x~  C  N  OU  O_  OV  ZK  \^  C  `l  mq  C  rB  CF  C  GO  PV  P_  Z_  C  `q  ru  vy  ry  z|  r|  C  }P  _a  eg  kr  QZ  yB  CcnnS%(  q	
	$L	LQTU`abc~a  VA  RB  CD  RD'
+?)@[a1\?  phcdemcn&NNSVWabcdubvWwSxyzSz  @A  BS  @T  @_  @_  `j  @k'
+?)@[c1\?  rqefgoep	q
  '4
BF
;
;	A	A#bZa	A	b SfgqF+aQ]]_akk'>RS999G TSZ\_`e\fvyz}v~  U]  ^s  Us  B  CG  H  =I  TX  Y`  Ta  ip  @D  EL  Lx  rw  Lx  Ex  @y  LP  QX  XE  AD  XE  QE  LF  cf  gj  ck  ~A  ~E  ~E  FM  NP  ~Q  jm  mR	  N	Q	  mR	  jR	  RS	  w	z	  {	B
  {	I
  {	I
  {	K
  w	L
  N
Q
  R
Y
  N
Z
  w	Z
  l
o
  p
w
  l
x
  LO  PW  P^  P^  P`  La  |@  `	A  
BD	
77CCDJJtafnoDp  {BC  C _GZZghjhlhlmHwyov O	dbYY[xx} O!
))+!((&VVkkk*A??1	qvv8I$8N[^_`[a  mo  KT  X[  \]  X^  Xd  Xd  Xf  Kf  ~G  l~  Zc  EP  TU  EU  Yg  kl  kr  kr  kt  Yt  |A  zE  Yb  rH  ^c  kM  N  
OOO (//!Q{^A/G/D9U4U	R	1 dQ6=d4()*//1	2M?bVYVdVdefrtVuTUvw  wD  wD  wF  GH  GR  GR  SZ  Sa  Sa  Sc  Gdd :aa.	9:3B?B	
--99$**RUZbc:dnu9v99  p  <o  p  pF^_d^e  fx  y~  x  b  cf  gn  co  bp  pM  NS  MT  Ty  z}  y~  ~X
  Y
a
  X
b
  b
[(  \(b(  [(c(  c(x(  y(|(  }(D)  }(K)  }(K)  }(M)  y(N)  x(O)  O)S)  T)W)  X)_)  T)`)  S)a)  a)U]  X]F	+!!&'!:	$**e3w<$w-`cdg`hsvw~s  JM  NU  N\  N\  N^  J_  ad  el  am  Jm  ux  y}  u~    MR  S  T} /DS S 	x 0d d ;s=   m&9m%m9m %Bm%6m2m2mm%m/__main__)r"   )r   )0__doc__
__future__r   rI  r&   rm   osr2   r;   
subprocessurllib.requestri   collectionsr   r   r   r   pathlibr   r8  r<  r:  r;  r   rl   r   r   r   r   rP  rS   rP   YOUTUBE_ID_REr   r*   r8   r?   rI   rW   rZ   ra   ru   ry   r   r   r   r  rr   r"   r#   r$   <module>r     s   H " F F F F , ' 	
>?
 !
OP	67	
kl	 +
	'
/	0 B2::]^`^b^bc
bjjRS 8 02 LKV	"BTF Zr#   