diff --git a/.github/ISSUE_TEMPLATE/canale-non-funzionante.md b/.github/ISSUE_TEMPLATE/canale-non-funzionante.md new file mode 100644 index 00000000..02a61257 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/canale-non-funzionante.md @@ -0,0 +1,26 @@ +--- +name: Segnala Problemi ad un Canale +about: Invio segnalazione per un canale non funzionante +title: 'Inserisci il nome del canale' +labels: Problema Canale +assignees: '' + +--- + +**Per poter scrivere o allegare file nella pagina devi:** + - cliccare sui [ ... ] in alto a destra della scheda + - Edit. Da questo momento puoi scrivere e/o inviare file. + + +Inserisci il nome del canale + + +- Il tipo di problema riscontrato, sii il più esauriente possibile. Che azione ha portato all'errore + +Es. non riesco ad aggiungere film nella videoteca, ne dal menu contestuale, ne dalla voce in fondo alla lista dei server. + +Se faccio ricerca globale, non riesco ad aggiungere film/serie/anime nella videoteca o a scaricare il video. + + +- Allega il file di log nella sua completezza. Non cancellarne delle parti. + diff --git a/.github/ISSUE_TEMPLATE/server-non-funzionante.md b/.github/ISSUE_TEMPLATE/server-non-funzionante.md new file mode 100644 index 00000000..7493aff5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/server-non-funzionante.md @@ -0,0 +1,19 @@ +--- +name: Segnala Problemi ad un Server +about: Invio segnalazione per un server non funzionante +title: 'Inserisci il nome del server' +labels: Problema Server +assignees: '' + +--- + +**Per poter scrivere o allegare file nella pagina devi:** + - cliccare sui [ ... ] in alto a destra della scheda + - Edit. Da questo momento puoi scrivere e/o inviare file. + + +Inserisci il nome del server che indica problemi e se il problema è circoscritto ad un solo canale, indicalo + + +- Allega il file di log nella sua completezza. Non cancellarne delle parti. + diff --git a/.github/ISSUE_TEMPLATE/test-canale.md b/.github/ISSUE_TEMPLATE/test-canale.md new file mode 100644 index 00000000..dbe53325 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/test-canale.md @@ -0,0 +1,286 @@ +--- +name: Test Canale +about: Pagina per il test di un canale +title: '' +labels: Test Canale +assignees: '' + +--- +Documento Template per il Test del canale + +Specifica, dove possibile, il tipo di problema che incontri, anche se non è presente alcuna voce per indicarlo. +Se hai **suggerimenti/consigli/dubbi sul test**...Proponili e/o Chiedi! Scrivendo un commento a questo stesso issue, che trovi in fondo, dopo questa pagina. + +**Avvertenze:** + +Per il test dei canali **DEVI**: +- utilizzare la versione **[BETA](https://kodiondemand.github.io/repo/KoD-installer-BETA.zip)** di KOD! +- **ABILITARE IL DEBUG PER I LOG** + +**Per eseguire il test, ricordati di titolarlo con il nome del canale da te scelto, e salvare la pagina cliccando sul bottone verde in basso "SUBMIT NEW ISSUE"** + +**Ogni volta che hai un ERRORE con avviso di LOG. Puoi scegliere se: + ALLEGARE IMMEDIATAMENTE il file kodi.log nel punto, della pagina, in cui sei nel test + Allegare il file kodi.log a fine pagina.** + +**Per poter scrivere o allegare file nella pagina devi:** + - cliccare sui [ ... ] in alto a destra della scheda + - Edit. Da questo momento puoi scrivere e/o inviare file. +Dopodiché clicca sul bottone verde "Update comment" per continuare il test nel modo consueto o per terminarlo! + +Se hai problemi non previsti dal test, segnalali aggiungendoli in fondo al test. + +**SE VEDI I QUADRATINI MA NON RIESCI A CLICCARLI... DEVI CLICCARE SUL BOTTONE VERDE "SUBMIT NEW ISSUE"** + +*** +I file relativi al canale li trovi: +- su browser: +[Apre la pagina dei Canali](https://github.com/kodiondemand/addon/tree/master/channels) +- sul device: +[nella specifica cartella](https://github.com/kodiondemand/addon/wiki/Percorsi-sui-diversi-S.O.) , .kodi/addons/channels. +Per aprirli non servono programmi particolari un semplice editor di testo è sufficiente. + +**Test N.1**: Controllo del file .json + +Occorrente: file .json + +**1. Indica la coerenza delle voci presenti in "language" con i contenuti presenti sul sito:** +valori: ita, sub-ita (sub-ita) + +- [ ] coerenti +- [ ] non coerenti + +Se non sono coerenti il test è FALLITO, continua comunque a revisionare il resto + +**2. Icone del canale** +Controlla sia presente qualcosa, tra le " " di thumbnail e banner, e che le immagini appaiano su KoD + +**in thumbnail:** +- [ ] Presente +- [ ] Assente + +**in banner:** +- [ ] Presente +- [ ] Assente + +**3. Verifica la coerenza delle voci presenti in "categories" con i contenuti presenti sul sito:** + +Riepilogo voci: + + movie, tvshow, anime, documentary, vos, adult + +(se il sito contiene film e serie, devono esserci sia movie che tvshow, se contiene solo film, solo movie) + +- [ ] Corrette +- [ ] 1 o più Errata/e +- [ ] Assenti - Non sono presenti voci in categories, in questo caso non puoi continuare il test. + +Se le voci sono: Assenti, dopo aver compilato la risposta, salva il test e **NON** proseguire. +**TEST FALLITO** + +*** + +**Test su KOD.** + +Entra in KOD -> Canali. Nella lista accedi al canale che stai testando. +**N.B.**: Il nome del canale è il campo **name** nel file .json. + +**Test N.2: Pagina Canale** + +**1. Cerca o Cerca Film...** +Cerca un titolo a caso in KOD e lo stesso titolo sul sito. Confronta i risultati. + +- [ ] OK +- indica il tipo di problema + +**Sezione FILM (se il sito non ha film elimina questa parte)** + +**TestN.3: Pagina dei Titoli** +*Test da effettuare mentre sei dentro un menu del canale (film, serietv, in corso ecc..)*. +Voci nel menu contestuale di KOD. Posizionati su di un titolo e controlla se hai le seguenti voci, nel menu contestuale (tasto c o tenendo enter premuto): + +**1. Aggiungi Film in videoteca** + +- [ ] Si +- [ ] No + +**2. Scarica Film (devi avere il download abilitato)** + +- [ ] Si +- [ ] No + +**Fine test menu contestuale** + +**Fondo pagina dei titoli** + +**3. Paginazione, controlla ci sia la voce "Successivo" (se non c'è controlla sul sito se è presente)** + +- [ ] Sì +- [ ] NO + +**Dentro un titolo + +**4. Entra nella pagina del titolo e verifica ci sia almeno 1 server:** + +- [ ] Si +- [ ] No + +**5. Eventuali problemi riscontrati** +- scrivi qui il problema/i + +**Sezione Serie TV (se il sito non ha serietv elimina questa parte)** + +Test da effettuare mentre sei nella pagina dei titoli. +Per ogni titolo verifica ci siano le voci nel menu contestuale. + +**1. Aggiungi Serie in videoteca** + +- [ ] Si +- [ ] No + +**2. Scarica Stagione (devi avere il download abilitato)** + +- [ ] Si +- [ ] No + +**3. Scarica Serie (devi avere il download abilitato)** + +- [ ] Si +- [ ] No + +**4. Cerca o Cerca Serie...** +Cerca un titolo a caso in KOD e lo stesso titolo sul sito. Confronta i risultati. + +- [ ] Ok +- indica il tipo di problema + +**5. Entra nella pagina della serie, verifica che come ultima voce ci sia "Aggiungi in videoteca":** + +- [ ] Si, appare +- [ ] Non appare + +**6. Entra nella pagina dell'episodio, **NON** deve apparire la voce "Aggiungi in videoteca":** + +- [ ] Si, appare +- [ ] Non appare + +**7. Eventuali problemi riscontrati** +- scrivi qui il problema/i + +**Sezione Anime (se il sito non ha anime elimina questa parte)** + +Test da effettuare mentre sei nella pagina dei titoli. Per ogni titolo verifica ci siano le voci nel menu contestuale. + +**1. Rinumerazione (se gli episodi non appaiono nella forma 1x01)** + +- [ ] Si +- [ ] No + +**2. Aggiungi Serie in videoteca** + +- [ ] Si +- [ ] No + +**3. Aggiungi 2-3 titoli in videoteca.** +- [ ] Aggiunti correttamente +- [Indica eventuali problemi] (copia-incolla per tutti i titoli con cui hai avuto il problema) + +- COPIA qui l'ERRORE dal LOG + +**4. Scarica Serie** + +- [ ] Si +- [ ] No + +**5. Cerca o Cerca Serie...** +Cerca un titolo a caso in KOD e lo stesso titolo sul sito. Confronta i risultati. + +- [ ] Ok +- indica il tipo di problema + +**6. Entra nella pagina della serie, verifica che come ultima voce ci sia "Aggiungi in videoteca":** + +- [ ] Appare +- [ ] Non appare + +**7. Entra nella pagina dell'episodio, NON ci deve essere la voce "Aggiungi in videoteca":** + +- [ ] Non appare +- [ ] Appare + +**8. Eventuali problemi riscontrati** +- scrivi qui il problema/i + +** TEST PER IL CONFRONTO TRA SITO E CANALE ** + +**TestN.4: Pagina Sito - Menu Canale** + +Occorrente: Browser, KOD! e il file canale.py ( da browser o da file ) +Avviso: +- Sul Browser disattiva eventuali componenti aggiuntivi che bloccano i JS (javascript), li riattivi alla fine del test. + +Entra in ogni menu e controlla che i risultati, delle prime 5-6 pagine, siano gli stessi che trovi sul sito, comprese le varie info (ita/sub-ita, qualità ecc..), inoltre entra, se ci sono, nei menu dei generi - anni - lettera, verifica che cliccando su una voce si visualizzino i titoli. + + *Copia questa sezione per ogni voce che presenta problemi:* + +- [ ] Voce menu ( del canale dove riscontri errori) + +Titoli non corrispondenti: + +- [ ] Il totale dei Titoli è diverso da quello del sito. Alcuni Titoli non compaiono. +- [ ] Appaiono titoli per pagine informative o link a siti esterni. Es: Avviso agli utenti. +- [ ] La lingua, del titolo, è diversa da quella riportata dal sito +- [ ] Non è indicato in 1 o più titoli che sono SUB-ITA +- [ ] Cliccando su "Successivo" non si visualizzano titoli +- [ ] Non è indicata la qualità: Hd-DVD/rip e altri, nonostante sul sito siano presenti + +- [ ] NO + + + *Fine Copia* + + +**Test.N5: Ricerca Globale** + +Per questo test ti consiglio di inserire come UNICO sito quello che stai testando, come canale incluso in: Ricerca Globale -> scegli i canali da includere +Il test è già compilato con le spunte, dato che devi copiarlo solo in caso di errori. Togli la spunta dove funziona. +Si consiglia di cercare almeno a fino 5 titoli. O perlomeno non fermarti al 1°. + +Cerca 5 FILM a tuo piacimento, se il titolo non esce controlla confrontando i risultati sul sito...: + + *Copia questa sezione per ogni voce che presenta problemi* + +controlla ci siano queste voci se titolo è un FILM: + +- [ ] inserisci il titolo cercato che da problemi +- [x] Aggiungi in videoteca +- [x] Scarica Film + + *Fine Copia* + +controlla ci siano queste voci se titolo è una SERIE/ANIME: + + *Copia questa sezione per ogni voce che presenta problemi* + +controlla ci siano queste voci se titolo è un FILM: + +- [ ] inserisci il titolo cercato che da problemi +- [x] Aggiungi in videoteca +- [x] Scarica Serie +- [x] Scarica Stagione + +- [ ] inserisci il titolo cercato che da problemi + + *Fine Copia* + + +Se il canale ha la parte Novità (questa stringa avvisa che NON è presente: "not_active": ["include_in_newest"]). + +**Test.N6: Novità.** +Per questo test ti consiglio di inserire come UNICO sito quello che stai testando, come canale incluso in: Novità -> categoria (film, serie o altro ) + +- [ ] Descrivere il problema + +Fine TEST! + +Grazie mille da parte di tutto il team KoD! diff --git a/LICENSE b/LICENSE index 818433ec..94a9ed02 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,674 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/addon.xml b/addon.xml index 3af6a6dc..5fc0fc3e 100644 --- a/addon.xml +++ b/addon.xml @@ -1,12 +1,12 @@ - - + + - + video @@ -19,7 +19,12 @@ resources/media/themes/ss/2.png resources/media/themes/ss/3.png - Benvenuto su KOD! + -Ridefinito il modo in cui vengono scritti i canali, per assicurare migliore stabilità, debuggabilità e coerenza + -Riscritti di conseguenza molti canali, corregendo di fatto moltissimi problemi che avete segnalato + -Quando aggiungi in videoteca da fonti in più lingue (ita/sub ita) o più qualità, ti viene chiesto quale tipo di fonte vuoi. + -Per gli amanti degli anime, aggiunto VVVVID (senza bisogno di account!) + -Aggiunti i server supervideo e hdload, fixato wstream + -migliorie varie Naviga velocemente sul web e guarda i contenuti presenti [COLOR red]The owners and submitters to this addon do not host or distribute any of the content displayed by these addons nor do they have any affiliation with the content providers.[/COLOR] [COLOR yellow]Kodi © is a registered trademark of the XBMC Foundation. We are not connected to or in any other way affiliated with Kodi, Team Kodi, or the XBMC Foundation. Furthermore, any software, addons, or products offered by us will receive no support in official Kodi channels, including the Kodi forums and various social networks.[/COLOR] @@ -29,6 +34,6 @@ https://t.me/kodiondemand https://github.com/kodiondemand/addon - + - + \ No newline at end of file diff --git a/channels.json b/channels.json index f1e8d571..b193e590 100644 --- a/channels.json +++ b/channels.json @@ -1,62 +1,52 @@ { - "altadefinizione01_club": "https://www.altadefinizione01.cc", - "altadefinizione01_link": "http://altadefinizione1.link", - "altadefinizione01": "https://www.altadefinizione01.cc", - "altadefinizioneclick": "https://altadefinizione.cloud", - "altadefinizionehd": "https://altadefinizionetv.best", - "animeforge": "https://ww1.animeforce.org", - "animeleggendari": "https://animepertutti.com", - "animestream": "https://www.animeworld.it", - "animespace": "https://www.animespace.tv", - "animesubita": "http://www.animesubita.org", - "animetubeita": "http://www.animetubeita.com", - "animevision": "https://www.animevision.it", - "animeworld": "https://www.animeworld.tv", - "asiansubita": "http://asiansubita.altervista.org", - "casacinema": "https://www.casacinema.site", - "casacinemainfo": "https://www.casacinema.info", - "cb01anime": "https://www.cineblog01.ink", - "cinemalibero": "https://www.cinemalibero.best", - "cinemastreaming": "https://cinemastreaming.icu", - "documentaristreamingda": "https://documentari-streaming-da.com", - "dreamsub": "https://www.dreamsub.stream", - "eurostreaming": "https://eurostreaming.pink", - "eurostreaming_video": "https://www.eurostreaming.best", - "fastsubita": "http://fastsubita.com", - "ffilms":"https://ffilms.org", - "filmigratis": "https://filmigratis.net", - "filmgratis": "https://www.filmaltadefinizione.net", - "filmontv": "https://www.comingsoon.it", - "filmpertutti": "https://www.filmpertutti.pub", - "filmsenzalimiti": "https://filmsenzalimiti.best", - "filmsenzalimiticc": "https://www.filmsenzalimiti.host", - "filmsenzalimiti_blue": "https://filmsenzalimiti.best", - "filmsenzalimiti_info": "https://www.filmsenzalimiti.host", - "filmstreaming01": "https://filmstreaming01.com", - "filmstreamingita": "http://filmstreamingita.live", - "guarda_serie": "https://guardaserie.site", + "altadefinizione01": "https://www.altadefinizione01.cc", + "altadefinizione01_club": "https://www.altadefinizione01.cc", + "altadefinizione01_link": "http://altadefinizione01.gift", + "altadefinizioneclick": "https://altadefinizione.cloud", + "animeforce": "https://ww1.animeforce.org", + "animeleggendari": "https://animepertutti.com", + "animespace": "http://www.animespace.tv", + "animestream": "https://www.animeworld.it", + "animesubita": "http://www.animesubita.org", + "animetubeita": "http://www.animetubeita.com", + "animeworld": "https://www.animeworld.tv", + "casacinema": "https://www.casacinema.uno", + "casacinemainfo": "https://www.casacinema.info", + "cb01anime": "https://www.cineblog01.ink", + "cinemalibero": "https://www.cinemalibero.best", + "documentaristreamingda": "https://documentari-streaming-da.com", + "dreamsub": "https://www.dreamsub.stream", + "eurostreaming": "https://eurostreaming.pink", + "fastsubita": "http://fastsubita.com", + "filmgratis": "https://www.filmaltadefinizione.net", + "filmigratis": "https://filmigratis.org", + "filmpertutti": "https://www.filmpertutti.link", + "filmsenzalimiti": "https://filmsenzalimiti.best", + "filmsenzalimiticc": "https://www.filmsenzalimiti.press", + "filmstreaming01": "https://filmstreaming01.com", "guardafilm": "http://www.guardafilm.top", - "guardarefilm": "https://www.guardarefilm.red", - "guardaseriecc": "https://guardaserie.site", - "guardaserieclick": "https://www.guardaserie.media", - "guardaserie_stream": "https://guardaserie.co", - "guardaserieonline": "http://www.guardaserie.media", - "guardogratis": "http://guardogratis.net", - "ilgeniodellostreaming": "https://ilgeniodellostreaming.se", - "italiafilm": "https://www.italia-film.pw", - "italiafilmhd": "https://italiafilm.info", - "italiaserie": "https://italiaserie.org", - "itastreaming": "https://itastreaming.film", - "majintoon": "https://toonitalia.org", - "mondolunatico": "http://mondolunatico.org", - "mondolunatico2": "http://mondolunatico.org/stream/", - "mondoserietv": "https://mondoserietv.com", - "piratestreaming": "https://www.piratestreaming.media", - "seriehd": "https://www.seriehd.zone", - "serietvonline": "https://serietvonline.tech", - "serietvsubita": "http://serietvsubita.xyz", - "serietvu": "https://www.serietvu.club", - "streamingaltadefinizione": "https://www.streamingaltadefinizione.best", - "tantifilm": "https://www.tantifilm.eu", - "toonitalia": "https://toonitalia.org" -} + "guardarefilm": "https://www.guardarefilm.red", + "guardaserie_stream": "https://guardaserie.co", + "guardaseriecc": "https://guardaserie.site", + "guardaserieclick": "https://www.guardaserie.media", + "guardogratis": "https://guardogratis.net", + "ilgeniodellostreaming": "https://igds.red", + "italiafilm": "https://www.italia-film.pw", + "italiaserie": "https://italiaserie.org", + "itastreaming": "https://itastreaming.film", + "mondolunatico": "http://mondolunatico.org", + "mondolunatico2": "https://mondolunatico.org:443/stream", + "mondoserietv": "https://mondoserietv.com", + "piratestreaming": "https://www.piratestreaming.media", + "polpotv": "https://polpo.tv", + "seriehd": "https://www.seriehd.moda", + "serietvonline": "https://serietvonline.best", + "serietvsubita": "http://serietvsubita.xyz", + "serietvu": "https://www.serietvu.club", + "streamingaltadefinizione": "https://www.popcornstream.best", + "streamtime": "https://t.me/s/StreamTime", + "tantifilm": "https://www.tantifilm.eu", + "toonitalia": "https://toonitalia.org", + "vedohd": "https://vedohd.video", + "vvvvid": "https://www.vvvvid.it" +} \ No newline at end of file diff --git a/channels/.cinemalibero.py b/channels/.cinemalibero.py new file mode 100644 index 00000000..7dea9140 --- /dev/null +++ b/channels/.cinemalibero.py @@ -0,0 +1,267 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per 'cinemalibero' + +""" + Questi sono commenti per i beta-tester. + + Su questo canale, nelle categorie: + -'Ricerca Globale' + - Novità, voce interna al canale + - Nella lista anime + non saranno presenti le voci: + - 'Aggiungi alla Videoteca' + - 'Scarica Film'/'Scarica Serie', + Inoltre nella lista Anime non è presente la voce rinumerazione! + dunque, la loro assenza, nel Test, NON dovrà essere segnalata come ERRORE. + + + Novità ( globale ), presenti solo i film: + - film ( 20 titoli ) della pagina https://www.cinemalibero.best/category/film/ + + Avvisi: + - Eventuali avvisi per i tester + + Ulteriori info: + +""" + +import re + +# per l'uso dei decoratori, per i log, e funzioni per siti particolari +from core import support +# se non si fa uso di findhost() +from platformcode import config + +# in caso di necessità +from core import scrapertoolsV2, httptools#, servertools +from core.item import Item # per newest +#from lib import unshortenit + +# se necessaria la variabile __channel__ +# da cancellare se non utilizzata +__channel__ = "cinemalibero" +# da cancellare se si utilizza findhost() +host = config.get_channel_url('cinemalibero') +headers = [['Referer', host]] + +list_servers = ['akstream', 'wstream', 'openload', 'streamango'] +list_quality = ['default'] + +### fine variabili + +#### Inizio delle def principali ### + +@support.menu +def mainlist(item): + support.log(item) + + film = ['/category/film/', + ('Generi', ['', 'genres', 'genres']), + ] + + # Voce SERIE, puoi solo impostare l'url + tvshow = ['/category/serie-tv/', + ('Novità', ['/aggiornamenti-serie-tv/', 'peliculas', 'update']) + ] + # Voce ANIME, puoi solo impostare l'url + Anime = [('Anime', ['/category/anime-giapponesi/', 'peliculas', 'anime', 'tvshow']), # url per la voce Anime, se possibile la pagina con titoli di anime +## #Voce Menu,['url','action','args',contentType] +## ('Novità', ['', '', '']), +## ('In Corso',['', '', '', '']), +## ('Ultimi Episodi',['', '', '', '']), +## ('Ultime Serie',['', '', '', '']) + ] + + + search = '' + + return locals() + + +@support.scrape +def peliculas(item): + support.log(item) + #support.dbg() # decommentare per attivare web_pdb + + if item.args == 'search': + patron = r'href="(?P[^"]+)".+?url\((?P[^\)]+)\)">.+?class="titolo">(?P[^<]+)<' + patronBlock = r'style="color: #2C3549 !important;" class="fon my-3"><small>.+?</small></h1>(?P<block>.*?)<div class="bg-dark ">' + action = 'select' + else: + if item.contentType == 'tvshow': + if item.args == 'update': + patron = r'<div class="card-body p-0">\s<a href="(?P<url>[^"]+)".+?url\((?P<thumb>.+?)\)">\s<div class="titolo">(?P<title>.+?)(?: – Serie TV)?(?:\([sSuUbBiItTaA\-]+\))?[ ]?(?P<year>\d{4})?</div>[ ]<div class="genere">(?:[\w]+?\.?\s?[\s|S]?[\dx\-S]+?\s\(?(?P<lang>[iItTaA]+|[sSuUbBiItTaA\-]+)\)?\s?(?P<quality>[HD]+)?|.+?\(?(?P<lang2>[sSuUbBiItTaA\-]+)?\)?</div>)' + action = 'select' + + def itemHook(item): + if item.lang2: + if len(item.lang2) <3: + item.lang2 = 'ITA' + item.contentLanguage = item.lang2 + item.title += support.typo(item.lang2, '_ [] color kod') + return item + + elif item.args == 'anime':# or 'anime' in item.url: + patron = r'<div class="card-body p-0"> <a href="(?P<url>[^"]+)".+?url\((?P<thumb>.+?)\)">[^>]+>[^>]+>[^>]+>(?:[ ](?P<rating>\d+.\d+))?[^>]+>[^>]+>(?P<title>.+?)(?:\([sSuUbBiItTaA\-]+\))?\s?(?:(?P<year>\d{4}|\(\d{4}\)|)?)?<[^>]+>(?:<div class="genere">.+?(?:\()?(?P<lang>ITA|iTA|Sub)(?:\))?)?' + action = 'select' + else: + patron = r'<div class="card-body p-0">\s?<a href="(?P<url>[^"]+)".+?url\((?P<thumb>.+?)\)">[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)</div>(?:<div class="genere">(?:[ |\w]+?(?:[\dx\-]+)?[ ](?:\()?(?P<lang>[sSuUbB]+|[iItTaA]+)(?:\))?\s?(?P<quality>[\w]+)?\s?|[\s|S]?[\dx\-]+\s[|]?\s?(?:[\w]+)?\s?\(?(\4[sSuUbB]+)?\)?)?.+?</div>)?' + action = 'episodios' + + elif item.contentType == 'movie': + action = 'findvideos' + patron = r'href="(?P<url>[^"]+)".+?url\((?P<thumb>.+?)\)">[^>]+>[^>]+>[^>]+>(?:[ ](?P<rating>\d+.\d+))?[^>]+>[^>]+>(?P<title>.+?)(?:\[(?P<lang>Sub-iTA|Sub-ITA|Sub)\])?[ ]\((?P<year>\d+)\)</div>(?:<div class="genere">(?P<quality>[^<]+)<)?' + + patronBlock = r'<h1(?: style="color: #2C3549 !important; text-transform: uppercase;"| style="text-transform: uppercase; color: #2C3549 !important;"| style="color: #2C3549 !important; text-transform: uppercase;" style="text-shadow: 1px 1px 1px #FF8C00; color:#FF8C00;"| style="text-shadow: 1px 1px 1px #0f0f0f;" class="darkorange"| style="color:#2C3549 !important;")>.+?</h1>(?P<block>.*?)<div class=(?:"container"|"bg-dark ")>' + + patronNext = '<a class="next page-numbers".*?href="([^"]+)">' + +## debug = True # True per testare le regex sul sito + return locals() + +@support.scrape +def episodios(item): + support.log(item) + #support.dbg() + + data = item.data1 + if item.args == 'anime': + item.contentType = 'tvshow' + blacklist = ['Clipwatching', 'Verystream', 'Easybytez'] + patron = r'(?:href="[ ]?(?P<url>[^"]+)"[^>]+>(?P<title>[^<]+)<|(?P<episode>\d+(?:×|×)?\d+\-\d+|\d+(?:×|×)\d+)[;]?(?:(\4[^<]+)(\2.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br />|</a></p>))' + #patron = r'<a target=.+?href="(?P<url>[^"]+)"[^>]+>(?P<title>(Epis|).+?(?P<episode>\d+)?)(?:\((?P<lang>Sub ITA)\))?</a>(?:<br />)?' + patronBlock = r'(?:class="txt_dow">Streaming:(?P<block>.*?)at-below-post)' + else: + patron = r'(?P<episode>\d+(?:×|×)?\d+\-\d+|\d+(?:×|×)\d+)[;]?[ ]?(?:(?P<title>[^<]+)(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br />|</a></p>)' +## patron = r'<a target=.+?href="(?P<url>[^"]+)"[^>]+>(?P<title>Epis.+?(\d+)?)(?:\((?P<lang>Sub ITA)\))?</a><br />' + patronBlock = r'<p><strong>(?P<block>(?:.+?[Ss]tagione.+?(?P<lang>iTA|ITA|Sub-ITA|Sub-iTA))?(?:|.+?|</strong>)(/?:</span>)?</p>.*?</p>)' + item.contentType = 'tvshow' + + action = 'findvideos' + + debug = True + return locals() + + +@support.scrape +def genres(item): + support.log(item) + #support.dbg() + + action = 'peliculas' + #blacklist = [''] + patron = r'<a class="dropdown-item" href="(?P<url>[^"]+)" title="(?P<title>[A-z]+)"' + + return locals() + +############## Fine ordine obbligato +## Def ulteriori + +def select(item): + support.log('select --->', item) + #support.dbg() + data = httptools.downloadpage(item.url, headers=headers).data + block = scrapertoolsV2.find_single_match(data, r'<div class="col-md-8 bg-white rounded-left p-5"><div>(.*?)<div style="margin-left: 0.5%; color: #FFF;">') + if re.findall('rel="category tag">serie', data, re.IGNORECASE): + support.log('select = ### è una serie ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + args='serie', + contentType='tvshow', + data1 = data + )) + elif re.findall('rel="category tag">anime', data, re.IGNORECASE): + if re.findall('episodio', block, re.IGNORECASE) or re.findall('stagione', data, re.IGNORECASE) or re.findall('numero stagioni', data, re.IGNORECASE): + support.log('select = ### è un anime ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + args='anime', + contentType='tvshow', + data1 = data + )) + else: + support.log('select = ### è un film ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + args = '', + contentType='movie', + #data = data + )) + else: + support.log('select = ### è un film ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + contentType='movie', + #data = data + )) + +############## Fondo Pagina +# da adattare al canale +def search(item, text): + support.log('search', item) + itemlist = [] + text = text.replace(' ', '+') + item.url = host + "/?s=" + text + item.contentType = item.contentType + try: + item.args = 'search' + item.contentType = 'episode' # non fa uscire le voci nel context menu + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + support.log('search log:', line) + return [] + + +# da adattare al canale +# inserire newest solo se il sito ha la pagina con le ultime novità/aggiunte +# altrimenti NON inserirlo +def newest(categoria): + support.log('newest ->', categoria) + itemlist = [] + item = Item() + try: + if categoria == 'peliculas': + item.url = host+'/category/film/' + item.contentType = 'movie' +## item.action = 'peliculas' +## itemlist = peliculas(item) + elif categoria == 'series': + item.contentType = 'tvshow' + item.args = 'update' + item.url = host+'/aggiornamenti-serie-tv/' + item.action = 'peliculas' + itemlist = peliculas(item) + + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log('newest log: ', {0}.format(line)) + return [] + + return itemlist + + +#support.server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True) +def findvideos(item): + support.log('findvideos ->', item) + #return support.server(item, headers=headers) + support.log(item) + if item.contentType == 'movie': + return support.server(item) + else: + return support.server(item, data= item.url) diff --git a/channels/0example.json.txt b/channels/0example.json.txt new file mode 100644 index 00000000..783193c6 --- /dev/null +++ b/channels/0example.json.txt @@ -0,0 +1,116 @@ +Rev:0.2 +Update: 03-10-2019 +##################### + +Promemoria da cancellare pena la non visibilità del canale in KOD!! + +##################### + + +le voci in settings sono state inserite per l'unico scopo +di velocizzare la scrittura del file +Vanno lasciate solo quelle voci il cui funzionamento sul +canale non vanno attivate. +"not_active": ["include_in_newest"], VA INSERITO nei canali che NON hanno nessuna voce newest. +Ovviamente va mantenuto tutto il codice di quell'id tra le {} +se vanno cancellati tutti deve rimanere la voce: +"settings": [] +##################### Cancellare fino a qui! +{ + "id": "nome del file .json", + "name": "Nome del canale visualizzato in KOD", + "language": ["ita", "sub-ita"], + "active": false, + "adult": false, + "thumbnail": "", + "banner": "", + "categories": ["movie", "tvshow", "anime", "vos", "documentary", "adult"], + "not_active": ["include_in_newest"], + "settings": [ + { + "id": "include_in_global_search", + "type": "bool", + "label": "@70728", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_series", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_italiano", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "checklinks", + "type": "bool", + "label": "Verifica se i link esistono", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "checklinks_number", + "type": "list", + "label": "Numero di link da verificare", + "default": 2, + "enabled": false, + "visible": "eq(-1,false)", + "lvalues": [ "3", "5", "10", "15", "20" ] + }, + { + "id": "filter_languages", + "type": "list", + "label": "@30019", + "default": 0, + "enabled": false, + "visible": false, + "lvalues": ["Non Filtrare"] + } + ], + + "renumber": [ + { + "id": "autorenumber", + "type": "bool", + "label": "@70712", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "autorenumber_mode", + "type": "bool", + "label": "@70688", + "default": false, + "enabled": false, + "visible": "eq(-1,false)" + } + ] +} diff --git a/channels/0example.py.txt b/channels/0example.py.txt new file mode 100644 index 00000000..f418da4a --- /dev/null +++ b/channels/0example.py.txt @@ -0,0 +1,286 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per 'idcanale nel json' +# By: pincopallo! +# Eventuali crediti se vuoi aggiungerli +# ------------------------------------------------------------ +# Rev: 0.2 +# Update 12-10-2019 +# fix: +# 1. aggiunto pagination e sistemate alcune voci +# 2. modificato problemi in eccezioni +# 3. aggiunta la def select +# 4. modifica alla legenda e altre aggiunte + +# Questo vuole solo essere uno scheletro per velocizzare la scrittura di un canale. +# La maggior parte dei canali può essere scritta con il decoratore. +# I commenti sono più un promemoria... che una vera e propria spiegazione! +# Niente di più. +# Ulteriori informazioni sono reperibili nel wiki: +# https://github.com/kodiondemand/addon/wiki/decoratori + +""" + Questi sono commenti per i beta-tester. + + Su questo canale, nella categoria 'Ricerca Globale' + non saranno presenti le voci 'Aggiungi alla Videoteca' + e 'Scarica Film'/'Scarica Serie', dunque, + la loro assenza, nel Test, NON dovrà essere segnalata come ERRORE. + + Novità. Indicare in quale/i sezione/i è presente il canale: + - Nessuna, film, serie, anime... + + Avvisi: + - Eventuali avvisi per i tester + + Ulteriori info: + +""" +# CANCELLARE Ciò CHE NON SERVE per il canale, lascia il codice commentato ove occorre, +# ma fare PULIZIA quando si è finito di testarlo + +# Qui gli import +#import re + +# per l'uso dei decoratori, per i log, e funzioni per siti particolari +from core import support +# se non si fa uso di findhost() +from platformcode import config + +# in caso di necessità +#from core import scrapertoolsV2, httptools, servertools, tmdb +from core.item import Item # per newest +#from lib import unshortenit + +##### fine import + +# impostazioni variabili o def findhost() + +# se necessaria la variabile __channel__ +# da cancellare se non utilizzata +__channel__ = "id nel json" +# da cancellare se si utilizza findhost() +host = config.get_channel_url('id nel json' OR __channel__) # <-- ATTENZIONE +headers = [['Referer', host]] + +# Inizio findhost() - da cancellare se usato l'altro metodo +#impostati dinamicamente da findhost() +host = "" +headers = "" + +def findhost(): + global host, headers + # da adattare alla bisogna... + permUrl = httptools.downloadpage('INSERIRE-URL-QUI', follow_redirects=False).headers + host = 'https://www.'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') + # cancellare host non utilizzato + host = scrapertoolsV2.find_single_match(permUrl, r'<div class="elementor-button-wrapper"> <a href="([^"]+)"') + headers = [['Referer', host]] + +findhost() # così le imposta una volta per tutte +### fine findhost + +# server di esempio... +list_servers = ['supervideo', 'streamcherry','rapidvideo', 'streamango', 'openload'] +# quality di esempio +list_quality = ['default', 'HD', '3D', '4K', 'DVD', 'SD'] + +### fine variabili + +#### Inizio delle def principali ### + +@support.menu +def mainlist(item): + support.log(item) + + # Ordine delle voci + # Voce FILM, puoi solo impostare l'url + film = ['', # url per la voce FILM, se possibile la pagina principale con le ultime novità + #Voce Menu,['url','action','args',contentType] + ('Al Cinema', ['', 'peliculas', '']), + ('Generi', ['', 'genres', 'genres']), + ('Per Lettera', ['', 'genres', 'letters']), + ('Anni', ['', 'genres', 'years']), + ('Qualità', ['', 'genres', 'quality']), + ('Mi sento fortunato', ['', 'genres', 'lucky']), + ('Popolari', ['', 'peliculas', '']), + ('Sub-ITA', ['', 'peliculas', '']) + ] + + # Voce SERIE, puoi solo impostare l'url + tvshow = ['', # url per la voce Serie, se possibile la pagina con titoli di serie + #Voce Menu,['url','action','args',contentType] + ('Novità', ['', '', '']), + ('Per Lettera', ['', 'genres', 'letters']), + ('Per Genere', ['', 'genres', 'genres']), + ('Per anno', ['', 'genres', 'years']) + ] + # Voce ANIME, puoi solo impostare l'url + anime = ['', # url per la voce Anime, se possibile la pagina con titoli di anime + #Voce Menu,['url','action','args',contentType] + ('Novità', ['', '', '']), + ('In Corso',['', '', '', '']), + ('Ultimi Episodi',['', '', '', '']), + ('Ultime Serie',['', '', '', '']) + ] + + """ + Eventuali Menu per voci non contemplate! + """ + + # se questa voce non è presente il menu genera una voce + # search per ogni voce del menu. Es. Cerca Film... + search = '' # se alla funzione search non serve altro + + # VOCE CHE APPARIRA' come prima voce nel menu di KOD! + # [Voce Menu,['url','action','args',contentType] + top = [ '' ['', '', '', '']) + + # Se vuoi creare un menu personalizzato o perchè gli altri non + # ti soddisfano + # [Voce Menu,['url','action','args',contentType] + nome = [( '' ['', '', '', '']) + return locals() + + # Legenda known_keys per i groups nei patron + # known_keys = ['url', 'title', 'title2', 'season', 'episode', 'thumb', 'quality', + # 'year', 'plot', 'duration', 'genere', 'rating', 'type', 'lang'] + # url = link relativo o assoluto alla pagina titolo film/serie + # title = titolo Film/Serie/Anime/Altro + # title2 = titolo dell'episodio Serie/Anime/Altro + # season = stagione in formato numerico + # episode = numero episodio, in formato numerico. + # thumb = linkrealtivo o assoluto alla locandina Film/Serie/Anime/Altro + # quality = qualità indicata del video + # year = anno in formato numerico (4 cifre) + # duration = durata del Film/Serie/Anime/Altro + # genere = genere del Film/Serie/Anime/Altro. Es: avventura, commedia + # rating = punteggio/voto in formato numerico + # type = tipo del video. Es. movie per film o tvshow per le serie. Di solito sono discrimanti usati dal sito + # lang = lingua del video. Es: ITA, Sub-ITA, Sub, SUB ITA. + # AVVERTENZE: Se il titolo è trovato nella ricerca TMDB/TVDB/Altro allora le locandine e altre info non saranno quelle recuperate nel sito.!!!! + + +@support.scrape +def peliculas(item): + support.log(item) + #support.dbg() # decommentare per attivare web_pdb + + action = '' + blacklist = [''] + patron = r'' + patronBlock = r'' + patronNext = '' + pagination = '' + + #debug = True # True per testare le regex sul sito + return locals() + +@support.scrape +def episodios(item): + support.log(item) + #support.dbg() + + action = '' + blacklist = [''] + patron = r'' + patronBlock = r'' + patronNext = '' + pagination = '' + + #debug = True + return locals() + +# Questa def è utilizzata per generare i menu del canale +# per genere, per anno, per lettera, per qualità ecc ecc +@support.scrape +def genres(item): + support.log(item) + #support.dbg() + + action = '' + blacklist = [''] + patron = r'' + patronBlock = r'' + patronNext = '' + pagination = '' + + #debug = True + return locals() + +############## Fine ordine obbligato +## Def ulteriori + +# per quei casi dove il sito non differenzia film e/o serie e/o anime +# e la ricerca porta i titoli mischiati senza poterli distinguere tra loro +# andranno modificate anche le def peliculas e episodios ove occorre +def select(item): + support.log('select --->', item) + #support.dbg() + data = httptools.downloadpage(item.url, headers=headers).data + # pulizia di data, in caso commentare le prossime 2 righe + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + block = scrapertoolsV2.find_single_match(data, r'') + if re.findall('', data, re.IGNORECASE): + support.log('select = ### è una serie ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + args='serie', + contentType='tvshow', + #data1 = data decommentando portiamo data nella def senza doverla riscaricare + )) + +############## Fondo Pagina +# da adattare al canale +def search(item, text): + support.log('search', item) + itemlist = [] + text = text.replace(' ', '+') + item.url = host + '/index.php?do=search&story=%s&subaction=search' % (text) + # bisogna inserire item.contentType per la ricerca globale + # se il canale è solo film, si può omettere, altrimenti bisgona aggiungerlo e discriminare. + item.contentType = item.contentType + try: + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + log('search log:', line) + return [] + + +# da adattare al canale +# inserire newest solo se il sito ha la pagina con le ultime novità/aggiunte +# altrimenti NON inserirlo +def newest(categoria): + support.log('newest ->', categoria) + itemlist = [] + item = Item() + try: + if categoria == 'peliculas': + item.url = host + item.action = 'peliculas' + itemlist = peliculas(item) + + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log('newest log: ', {0}.format(line)) + return [] + + return itemlist + +# da adattare... +# consultare il wiki sia per support.server che ha vari parametri, +# sia per i siti con hdpass +#support.server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True) +def findvideos(item): + support.log('findvideos ->', item) + return support.server(item, headers=headers) diff --git a/channels/altadefinizione01.json b/channels/altadefinizione01.json index ed51566e..8f0d698a 100644 --- a/channels/altadefinizione01.json +++ b/channels/altadefinizione01.json @@ -1,62 +1,11 @@ { "id": "altadefinizione01", "name": "Altadefinizione01", - "language": ["ita"], + "language": ["ita", "sub-ita"], "active": true, "adult": false, "thumbnail": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/altadefinizione01.png", "banner": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/altadefinizione01.png", - "categories": ["movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero di link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "categories": ["movie", "vos"], + "settings": [] } diff --git a/channels/altadefinizione01.py b/channels/altadefinizione01.py index 218d7e6d..be01b78f 100644 --- a/channels/altadefinizione01.py +++ b/channels/altadefinizione01.py @@ -2,61 +2,127 @@ # ------------------------------------------------------------ # Canale per altadefinizione01 # ------------------------------------------------------------ +""" + + Eccezioni note che non superano il test del canale: -from core import servertools, httptools, tmdb, scrapertoolsV2, support + Avvisi: + - L'url si prende da questo file. + - è presente nelle novità-> Film. + + Ulteriori info: + +""" +from core import scrapertoolsV2, httptools, support from core.item import Item -from platformcode import logger, config -from specials import autoplay +from platformcode import config, logger -#URL che reindirizza sempre al dominio corrente -#host = "https://altadefinizione01.to" +#impostati dinamicamente da findhost() +host = "" +headers = "" -__channel__ = "altadefinizione01" -host = config.get_channel_url(__channel__) +def findhost(): + global host, headers + data = httptools.downloadpage('https://altadefinizione01-nuovo.link/').data + host = scrapertoolsV2.find_single_match(data, '<div class="elementor-button-wrapper"> <a href="([^"]+)"') + headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['openload', 'streamango', 'rapidvideo', 'streamcherry', 'megadrive'] +list_servers = ['verystream','openload','rapidvideo','streamango'] list_quality = ['default'] -checklinks = config.get_setting('checklinks', 'altadefinizione01') -checklinks_number = config.get_setting('checklinks_number', 'altadefinizione01') - -headers = [['Referer', host]] -blacklist_categorie = ['Altadefinizione01', 'Altadefinizione.to'] - - +@support.menu def mainlist(item): - support.log() + findhost() + film = [ + ('Al Cinema', ['/cinema/', 'peliculas', 'pellicola']), + ('Ultimi Aggiornati-Aggiunti', ['','peliculas', 'update']), + ('Generi', ['', 'genres', 'genres']), + ('Lettera', ['/catalog/a/', 'genres', 'orderalf']), + ('Anni', ['', 'genres', 'years']), + ('Sub-ITA', ['/sub-ita/', 'peliculas', 'pellicola']) + ] - itemlist =[] + return locals() - support.menu(itemlist, 'Al Cinema','peliculas',host+'/cinema/') - support.menu(itemlist, 'Ultimi Film Inseriti','peliculas',host) - support.menu(itemlist, 'Film Sub-ITA','peliculas',host+'/sub-ita/') - support.menu(itemlist, 'Film Ordine Alfabetico ','AZlist',host+'/catalog/') - support.menu(itemlist, 'Categorie Film','categories',host) - support.menu(itemlist, 'Cerca...','search') +@support.scrape +def peliculas(item): + support.log('peliculas',item) + findhost() +## deflang = 'ITA' + action="findvideos" + + patron = r'<div class="cover boxcaption"> <h2>.<a href="(?P<url>[^"]+)">.*?<.*?src="(?P<thumb>[^"]+)"'\ + '.+?[^>]+>[^>]+<div class="trdublaj"> (?P<quality>[A-Z/]+)<[^>]+>(?:.[^>]+>(?P<lang>.*?)<[^>]+>).*?'\ + '<p class="h4">(?P<title>.*?)</p>[^>]+> [^>]+> [^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+> [^>]+> '\ + '[^>]+>[^>]+>(?P<year>\d{4})[^>]+>[^>]+> [^>]+>[^>]+>(?P<duration>\d+).+?>.*?<p>(?P<plot>[^<]+)<' + + if item.args == "search": + patronBlock = r'</script> <div class="boxgrid caption">(?P<block>.*)<div id="right_bar">' + + elif item.args == 'update': + patronBlock = r'<div class="widget-title">Ultimi Film Aggiunti/Aggiornati</div>(?P<block>.*?)<div id="alt_menu">' + patron = r'style="background-image:url\((?P<thumb>[^\)]+).+?<p class="h4">(?P<title>.*?)</p>[^>]+> [^>]+> [^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+> [^>]+> [^>]+>[^>]+>(?P<year>\d{4})[^>]+>[^>]+> [^>]+>[^>]+>(?P<duration>\d+).+?>.*?(?:>Film (?P<lang>Sub ITA)</a></p> )?<p>(?P<plot>[^<]+)<.*?href="(?P<url>[^"]+)' + else: + patronBlock = r'<div class="cover_kapsul ml-mask">(?P<block>.*)<div class="page_nav">' + + patronNext = '<span>\d</span> <a href="([^"]+)">' +## debug = True + return locals() + +@support.scrape +def genres(item): + support.log('genres',item) - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) + if item.args != 'orderalf': action = "peliculas" + else: action = 'orderalf' - return itemlist + blacklist = ['Altadefinizione01'] + if item.args == 'genres': + patronBlock = r'<ul class="kategori_list">(?P<block>.*?)<div class="tab-pane fade" id="wtab2">' + patron = '<li><a href="(?P<url>[^"]+)">(?P<title>.*?)</a>' + elif item.args == 'years': + patronBlock = r'<ul class="anno_list">(?P<block>.*?)</a></li> </ul> </div>' + patron = '<li><a href="(?P<url>[^"]+)">(?P<title>.*?)</a>' + elif item.args == 'orderalf': + patronBlock = r'<div class="movies-letter">(?P<block>.*?)<div class="clearfix">' + patron = '<a title=.*?href="(?P<url>[^"]+)"><span>(?P<title>.*?)</span>' + + #debug = True + return locals() + +@support.scrape +def orderalf(item): + support.log('orderalf',item) + + action= 'findvideos' + patron = r'<td class="mlnh-thumb"><a href="(?P<url>[^"]+)".*?src="(?P<thumb>[^"]+)"'\ + '.+?[^>]+>[^>]+ [^>]+[^>]+ [^>]+>(?P<title>[^<]+).*?[^>]+>(?P<year>\d{4})<'\ + '[^>]+>[^>]+>(?P<quality>[A-Z]+)[^>]+> <td class="mlnh-5">(?P<lang>.*?)</td>' + patronNext = r'<span>[^<]+</span>[^<]+<a href="(.*?)">' + + return locals() -def categories(item): - support.log(item) - itemlist = support.scrape(item,'<li><a href="([^"]+)">(.*?)</a></li>',['url','title'],headers,'Altadefinizione01',patron_block='<ul class="kategori_list">(.*?)</ul>',action='peliculas') - return support.thumb(itemlist) - -def AZlist(item): - support.log() - return support.scrape(item,r'<a title="([^"]+)" href="([^"]+)"',['title','url'],headers,patron_block=r'<div class="movies-letter">(.*?)<\/div>',action='peliculas_list') - +def search(item, text): + support.log(item, text) + findhost() + + itemlist = [] + text = text.replace(" ", "+") + item.url = host + "/index.php?do=search&story=%s&subaction=search" % (text) + item.args = "search" + try: + return peliculas(item) + # Cattura la eccezione così non interrompe la ricerca globle se il canale si rompe! + except: + import sys + for line in sys.exc_info(): + logger.error("search except: %s" % line) + return [] def newest(categoria): - # import web_pdb; web_pdb.set_trace() support.log(categoria) + findhost() itemlist = [] item = Item() try: @@ -64,10 +130,9 @@ def newest(categoria): item.url = host item.action = "peliculas" itemlist = peliculas(item) - if itemlist[-1].action == "peliculas": itemlist.pop() - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): @@ -76,75 +141,6 @@ def newest(categoria): return itemlist - -def search(item, texto): - support.log(texto) - item.url = "%s/index.php?do=search&story=%s&subaction=search" % ( - host, texto) - try: - return peliculas(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def peliculas(item): - support.log() - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - patron = r'<div class="cover_kapsul ml-mask".*?<a href="(.*?)">(.*?)<\/a>.*?<img .*?src="(.*?)".*?<div class="trdublaj">(.*?)<\/div>.(<div class="sub_ita">(.*?)<\/div>|())' - matches = scrapertoolsV2.find_multiple_matches(data, patron) - - for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedquality, subDiv, subText, empty in matches: - info = scrapertoolsV2.find_multiple_matches(data, r'<span class="ml-label">([0-9]+)+<\/span>.*?<span class="ml-label">(.*?)<\/span>.*?<p class="ml-cat".*?<p>(.*?)<\/p>.*?<a href="(.*?)" class="ml-watch">') - infoLabels = {} - for infoLabels['year'], duration, scrapedplot, checkUrl in info: - if checkUrl == scrapedurl: - break - - infoLabels['duration'] = int(duration.replace(' min', '')) * 60 # calcolo la durata in secondi - scrapedthumbnail = host + scrapedthumbnail - scrapedtitle = scrapertoolsV2.decodeHtmlentities(scrapedtitle) - fulltitle = scrapedtitle - if subDiv: - fulltitle += support.typo(subText + ' _ () color limegreen') - fulltitle += support.typo(scrapedquality.strip()+ ' _ [] color kod') - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType=item.contenType, - contentTitle=scrapedtitle, - contentQuality=scrapedquality.strip(), - plot=scrapedplot, - title=fulltitle, - fulltitle=scrapedtitle, - show=scrapedtitle, - url=scrapedurl, - infoLabels=infoLabels, - thumbnail=scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - support.nextPage(itemlist,item,data,'<span>[^<]+</span>[^<]+<a href="(.*?)">') - - return itemlist - -def peliculas_list(item): - support.log() - item.fulltitle = '' - block = r'<tbody>(.*)<\/tbody>' - patron = r'<a href="([^"]+)" title="([^"]+)".*?> <img.*?src="([^"]+)".*?<td class="mlnh-3">([0-9]{4}).*?mlnh-4">([A-Z]+)' - return support.scrape(item,patron, ['url', 'title', 'thumb', 'year', 'quality'], patron_block=block) - - - def findvideos(item): - support.log() - - itemlist = support.server(item, headers=headers) - - return itemlist + support.log('findvideos', item) + return support.server(item, headers=headers) diff --git a/channels/altadefinizione01_club.json b/channels/altadefinizione01_club.json deleted file mode 100644 index 34c36518..00000000 --- a/channels/altadefinizione01_club.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "id": "altadefinizione01_club", - "name": "Altadefinizione01 C", - "active": false, - "adult": false, - "language": ["ita"], - "fanart": "https://www.altadefinizione01.vision/templates/Darktemplate/images/logo.png", - "thumbnail": "https://www.altadefinizione01.vision/templates/Darktemplate/images/logo.png", - "banner": "https://www.altadefinizione01.vision/templates/Darktemplate/images/logo.png", - "categories": [ - "movie" - ], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://altadefinizione01.estate/", - "enabled": true, - "visible": true - }, - { - "id": "modo_grafico", - "type": "bool", - "label": "Cerca informazioni extra", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_film", - "type": "bool", - "label": "Includi in Novità", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "Non filtrare", - "IT" - ] - } - ] -} diff --git a/channels/altadefinizione01_club.py b/channels/altadefinizione01_club.py deleted file mode 100644 index 2895bb93..00000000 --- a/channels/altadefinizione01_club.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- -# -*- Channel Altadefinizione01C Film -*- -# -*- Riscritto per KOD -*- -# -*- By Greko -*- -# -*- last change: 04/05/2019 - - -from core import channeltools, servertools, support -from core.item import Item -from platformcode import config, logger -from specials import autoplay - -__channel__ = "altadefinizione01_club" -host = config.get_channel_url(__channel__) - -# ======== Funzionalità ============================= - -checklinks = config.get_setting('checklinks', __channel__) -checklinks_number = config.get_setting('checklinks_number', __channel__) - -headers = [['User-Agent', 'Mozilla/50.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'], - ['Referer', host]] - -parameters = channeltools.get_channel_parameters(__channel__) -fanart_host = parameters['fanart'] -thumbnail_host = parameters['thumbnail'] - -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['verystream','openload','supervideo','rapidvideo','streamango'] # per l'autoplay -list_quality = ['default'] - - -# =========== home menu =================== - -def mainlist(item): - """ - Creo il menu principale del canale - :param item: - :return: itemlist [] - """ - logger.info("%s mainlist log: %s" % (__channel__, item)) - itemlist = [] - - # Menu Principale - support.menu(itemlist, 'Film Ultimi Arrivi bold', 'peliculas', host, args='pellicola') - support.menu(itemlist, 'Genere', 'categorie', host, args='genres') - support.menu(itemlist, 'Per anno submenu', 'categorie', host, args=['Film per Anno','years']) - support.menu(itemlist, 'Per lettera', 'categorie', host + '/catalog/a/', args=['Film per Lettera','orderalf']) - support.menu(itemlist, 'Al Cinema bold', 'peliculas', host + '/cinema/', args='pellicola') - support.menu(itemlist, 'Sub-ITA bold', 'peliculas', host + '/sub-ita/', args='pellicola') - support.menu(itemlist, 'Cerca film submenu', 'search', host, args = 'search') - - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - support.channel_config(item, itemlist) - - return itemlist - -# ======== def in ordine di menu =========================== -# =========== def per vedere la lista dei film ============= - -def peliculas(item): - logger.info("%s mainlist peliculas log: %s" % (__channel__, item)) - itemlist = [] - - patron_block = r'<div id="dle-content">(.*?)<div class="page_nav">' - if item.args == "search": - patron_block = r'</table> </form>(.*?)<div class="search_bg">' - patron = r'<h2>.<a href="(.*?)".*?src="(.*?)".*?(?:|<div class="sub_ita">(.*?)</div>)[ ]</div>.*?<p class="h4">(.*?)</p>' - - listGroups = ['url', 'thumb', 'lang', 'title', 'year'] - - patronNext = '<span>[^<]+</span>[^<]+<a href="(.*?)">' - - itemlist = support.scrape(item, patron=patron, listGroups=listGroups, - headers= headers, patronNext=patronNext,patron_block=patron_block, - action='findvideos') - - return itemlist - -# =========== def pagina categorie ====================================== - -def categorie(item): - logger.info("%s mainlist categorie log: %s" % (__channel__, item)) - itemlist = [] - - # da qui fare le opportuni modifiche - patron = r'<li><a href="(.*?)">(.*?)</a>' - action = 'peliculas' - if item.args == 'genres': - bloque = r'<ul class="kategori_list">(.*?)</ul>' - elif item.args[1] == 'years': - bloque = r'<ul class="anno_list">(.*?)</ul>' - elif item.args[1] == 'orderalf': - bloque = r'<div class="movies-letter">(.*)<div class="clearfix">' - patron = r'<a title=.*?href="(.*?)"><span>(.*?)</span>' - action = 'orderalf' - - listGroups = ['url', 'title'] - patronNext = '' - - itemlist = support.scrape(item, patron=patron, listGroups=listGroups, - headers= headers, patronNext=patronNext, patron_block = bloque, - action=action) - - return itemlist - -# =========== def pagina lista alfabetica =============================== - -def orderalf(item): - logger.info("%s mainlist orderalf log: %s" % (__channel__, item)) - itemlist = [] - - listGroups = ['url', 'title', 'thumb', 'year', 'lang'] - patron = r'<td class="mlnh-thumb"><a href="(.*?)".title="(.*?)".*?src="(.*?)".*?mlnh-3">(.*?)<.*?"mlnh-5">.<(.*?)<td' #scrapertools.find_single_match(data, '<td class="mlnh-thumb"><a href="(.*?)".title="(.*?)".*?src="(.*?)".*?mlnh-3">(.*?)<.*?"mlnh-5">.<(.*?)<td') - patronNext = r'<span>[^<]+</span>[^<]+<a href="(.*?)">' - - itemlist = support.scrape(item, patron=patron, listGroups=listGroups, - headers= headers, patronNext=patronNext, - action='findvideos') - - return itemlist - -# =========== def pagina del film con i server per verderlo ============= - -def findvideos(item): - logger.info("%s mainlist findvideos_film log: %s" % (__channel__, item)) - itemlist = [] - return support.server(item, headers=headers) - -# =========== def per cercare film/serietv ============= -#http://altadefinizione01.link/index.php?do=search&story=avatar&subaction=search -def search(item, text): - logger.info("%s mainlist search log: %s %s" % (__channel__, item, text)) - itemlist = [] - text = text.replace(" ", "+") - item.url = host + "/index.php?do=search&story=%s&subaction=search" % (text) - #item.extra = "search" - try: - return peliculas(item) - # Cattura la eccezione così non interrompe la ricerca globle se il canale si rompe! - except: - import sys - for line in sys.exc_info(): - logger.error("%s Sono qua: %s" % (__channel__, line)) - return [] - -# =========== def per le novità nel menu principale ============= - -def newest(categoria): - logger.info("%s mainlist newest log: %s" % (__channel__, categoria)) - itemlist = [] - item = Item() - try: - item.url = host - item.action = "peliculas" - itemlist = peliculas(item) - if itemlist[-1].action == "peliculas": - itemlist.pop() - - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist diff --git a/channels/altadefinizione01_link.json b/channels/altadefinizione01_link.json index 579853b4..fe102b43 100644 --- a/channels/altadefinizione01_link.json +++ b/channels/altadefinizione01_link.json @@ -3,102 +3,9 @@ "name": "Altadefinizione01 L", "active": true, "adult": false, - "language": ["ita"], - "fanart": "https://altadefinizione01.estate/templates/Dark/img/nlogo.png", - "thumbnail": "https://altadefinizione01.estate/templates/Dark/img/nlogo.png", - "banner": "https://altadefinizione01.estate/templates/Dark/img/nlogo.png", - "fix" : "reimpostato url e modificato file per KOD", - "change_date": "2019-30-04", - "categories": [ - "movie", - "vosi" - ], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://altadefinizione01.estate/", - "enabled": true, - "visible": true - }, - { - "id": "modo_grafico", - "type": "bool", - "label": "Cerca informazioni extra", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "Non filtrare", - "ITA", - "vosi" - ] - }, - { - "id": "perfil", - "type": "list", - "label": "profilo dei colori", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "Sin color", - "Perfil 5", - "Perfil 4", - "Perfil 3", - "Perfil 2", - "Perfil 1" - ] - } - ] + "language": ["ita","sub-ita"], + "thumbnail": "altadefinizione01_L.png", + "banner": "altadefinizione01_L.png", + "categories": ["movie","vos"], + "settings" :[] } diff --git a/channels/altadefinizione01_link.py b/channels/altadefinizione01_link.py index 584e175b..6950f524 100644 --- a/channels/altadefinizione01_link.py +++ b/channels/altadefinizione01_link.py @@ -1,109 +1,97 @@ # -*- coding: utf-8 -*- -# -*- Channel Altadefinizione01L Film - Serie -*- -# -*- By Greko -*- +# -*- Channel altadefinizione01_link -*- +""" -import channelselector -from specials import autoplay -from core import servertools, support, jsontools + Eccezioni che non superano il test del canale: + - indicare i problemile eccezioni + + Novità. Indicare in quale/i sezione/i è presente il canale: + -film + + Avvisi: + - la voce 'Mi sento fortunato' è il rettangolino in basso nel sito + con scritto 'FILM RANDOM' + + Ulteriori info: + +""" + +from core import support from core.item import Item from platformcode import config, logger __channel__ = "altadefinizione01_link" # ======== def per utility INIZIO ============================ +host = config.get_channel_url(__channel__) +headers = [['Referer', host]] list_servers = ['supervideo', 'streamcherry','rapidvideo', 'streamango', 'openload'] list_quality = ['default'] -host = config.get_setting("channel_host", __channel__) - -headers = [['Referer', host]] # =========== home menu =================== - +@support.menu def mainlist(item): - """ - Creo il menu principale del canale - :param item: - :return: itemlist [] - """ - support.log() - itemlist = [] + support.log('mainlist',item) - # Menu Principale - support.menu(itemlist, 'Novità bold', 'peliculas', host) - support.menu(itemlist, 'Film per Genere', 'genres', host, args='genres') - support.menu(itemlist, 'Film per Anno submenu', 'genres', host, args='years') - support.menu(itemlist, 'Film per Qualità submenu', 'genres', host, args='quality') - support.menu(itemlist, 'Al Cinema bold', 'peliculas', host + '/film-del-cinema') - support.menu(itemlist, 'Popolari bold', 'peliculas', host + '/piu-visti.html') - support.menu(itemlist, 'Mi sento fortunato bold', 'genres', host, args='lucky') - support.menu(itemlist, 'Sub-ITA bold', 'peliculas', host + '/film-sub-ita/') - support.menu(itemlist, 'Cerca film submenu', 'search', host) - - # per autoplay - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - support.channel_config(item, itemlist) - - return itemlist + film = [ + ('Al Cinema', ['/film-del-cinema', 'peliculas', '']), + ('Generi', ['', 'genres', 'genres']), + ('Anni', ['', 'genres', 'years']), + ('Qualità', ['/piu-visti.html', 'genres', 'quality']), + ('Mi sento fortunato', ['/piu-visti.html', 'genres', 'lucky']), + ('Popolari', ['/piu-visti.html', 'peliculas', '']), + ('Sub-ITA', ['/film-sub-ita/', 'peliculas', '']) + ] + return locals() # ======== def in ordine di action dal menu =========================== +@support.scrape def peliculas(item): - support.log - itemlist = [] + support.log('peliculas',item) - patron = r'class="innerImage">.*?href="([^"]+)".*?src="([^"]+)"'\ - '.*?class="ml-item-title">([^<]+)</.*?class="ml-item-label"> (\d{4}) <'\ - '.*?class="ml-item-label">.*?class="ml-item-label ml-item-label-.+?"> '\ - '(.+?) </div>.*?class="ml-item-label"> (.+?) </' - listGroups = ['url', 'thumb', 'title', 'year', 'quality', 'lang'] - - patronNext = '<span>\d</span> <a href="([^"]+)">' - - itemlist = support.scrape(item, patron=patron, listGroups=listGroups, - headers= headers, patronNext=patronNext, - action='findvideos') - - return itemlist + patron = r'class="innerImage">.*?href="(?P<url>[^"]+)".*?src="(?P<thumb>[^"]+)"'\ + '[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+> (?P<year>\d{4})[^>]+>[^>]+> (?P<duration>\d+)'\ + '[^>]+>[^>]+> (?P<quality>[a-zA-Z]+) [^>]+>[^>]+> (?P<lang>[^>]+) [^>]+>' + patronNext = r'<span>\d</span> <a href="([^"]+)">' + #debug = True + return locals() # =========== def pagina categorie ====================================== - +@support.scrape def genres(item): - support.log - itemlist = [] - #data = httptools.downloadpage(item.url, headers=headers).data + support.log('genres',item) + action = 'peliculas' if item.args == 'genres': - bloque = r'<ul class="listSubCat" id="Film">(.*?)</ul>' + patronBlock = r'<ul class="listSubCat" id="Film">(?P<block>.*)<ul class="listSubCat" id="Anno">' elif item.args == 'years': - bloque = r'<ul class="listSubCat" id="Anno">(.*?)</ul>' + patronBlock = r'<ul class="listSubCat" id="Anno">(?P<block>.*)<ul class="listSubCat" id="Qualita">' elif item.args == 'quality': - bloque = r'<ul class="listSubCat" id="Qualita">(.*?)</ul>' - elif item.args == 'lucky': # sono i titoli random nella pagina, cambiano 1 volta al dì - bloque = r'FILM RANDOM.*?class="listSubCat">(.*?)</ul>' + patronBlock = r'<ul class="listSubCat" id="Qualita">(?P<block>.*)<blockquote' + elif item.args == 'lucky': # sono i titoli random nella pagina + patronBlock = r'FILM RANDOM.*?class="listSubCat">(?P<block>.*)</ul>' action = 'findvideos' - - patron = r'<li><a href="([^"]+)">(.*?)<' + patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<]+)<' - listGroups = ['url','title'] - itemlist = support.scrape(item, patron=patron, listGroups=listGroups, - headers= headers, patron_block = bloque, - action=action) - - return itemlist + #debug = True + return locals() # =========== def per cercare film/serietv ============= #host+/index.php?do=search&story=avatar&subaction=search def search(item, text): - support.log() + support.log('search', item) itemlist = [] text = text.replace(" ", "+") item.url = host+"/index.php?do=search&story=%s&subaction=search" % (text) try: return peliculas(item) - # Se captura la excepciÛn, para no interrumpir al buscador global si un canal falla + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla except: import sys for line in sys.exc_info(): @@ -113,7 +101,7 @@ def search(item, text): # =========== def per le novità nel menu principale ============= def newest(categoria): - support.log(categoria) + support.log('newest', categoria) itemlist = [] item = Item() try: @@ -124,7 +112,7 @@ def newest(categoria): if itemlist[-1].action == "peliculas": itemlist.pop() - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): @@ -134,14 +122,5 @@ def newest(categoria): return itemlist def findvideos(item): - support.log() - - itemlist = support.server(item, headers=headers) - - # Requerido para FilterTools - # itemlist = filtertools.get_links(itemlist, item, list_language) - - # Requerido para AutoPlay - autoplay.start(itemlist, item) - - return itemlist + support.log('findvideos', item) + return support.server(item, headers=headers) diff --git a/channels/altadefinizioneclick.json b/channels/altadefinizioneclick.json index b354fe12..d5190e8c 100644 --- a/channels/altadefinizioneclick.json +++ b/channels/altadefinizioneclick.json @@ -3,76 +3,9 @@ "name": "AltadefinizioneClick", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita","sub-ita"], "thumbnail": "https:\/\/raw.githubusercontent.com\/Zanzibar82\/images\/master\/posters\/altadefinizioneclick.png", "bannermenu": "https:\/\/raw.githubusercontent.com\/Zanzibar82\/images\/master\/posters\/altadefinizioneciclk.png", - "categories": ["movie","vosi"], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://altadefinizione.cloud", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "categories": ["movie","vos"], + "settings": [] } diff --git a/channels/altadefinizioneclick.py b/channels/altadefinizioneclick.py index e4db4965..8d7b4ba8 100644 --- a/channels/altadefinizioneclick.py +++ b/channels/altadefinizioneclick.py @@ -2,53 +2,108 @@ # ------------------------------------------------------------ # Canale per altadefinizioneclick # ---------------------------------------------------------- +""" -import re + Eccezioni che non superano il test del canale: + - indicare le eccezioni -from core import servertools, support + Novità. Indicare in quale/i sezione/i è presente il canale: + - film + + Avvisi: + - Eventuali avvisi per i tester + + Ulteriori info: + + +""" +from core import support from core.item import Item -from platformcode import logger, config -from specials import autoplay +from platformcode import config -#host = config.get_setting("channel_host", 'altadefinizioneclick') __channel__ = 'altadefinizioneclick' + host = config.get_channel_url(__channel__) - -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['verystream', 'openload', 'streamango', "vidoza", "thevideo", "okru", 'youtube'] -list_quality = ['1080p'] - -checklinks = config.get_setting('checklinks', 'altadefinizioneclick') -checklinks_number = config.get_setting('checklinks_number', 'altadefinizioneclick') - headers = [['Referer', host]] +list_servers = ['verystream', 'rapidvideo', 'openload', 'streamango', 'vidoza', + 'vidcloud', 'thevideo', 'okru', 'hdload', 'youtube'] +list_quality = ['1080p', '720', '360'] +@support.menu def mainlist(item): - support.log() - itemlist = [] + support.log() + film = ['', + ('Novità', ['/nuove-uscite/', 'peliculas', 'news']), + ('Al Cinema', ['/al-cinema/', 'peliculas', 'cinema']), + ('Generi', ['', 'genres', 'genres']), + ('Anni', ['', 'genres', 'years']), + ('Qualità', ['', 'genres', 'quality']), + ('Mi sento Fortunato',[ '', 'genres', 'lucky']), + ('Sub-ITA', ['/sub-ita/', 'peliculas', 'sub']) + ] + return locals() - support.menu(itemlist, 'Film', 'peliculas', host + "/nuove-uscite/") - support.menu(itemlist, 'Per Genere submenu', 'menu', host, args='Film') - support.menu(itemlist, 'Per Anno submenu', 'menu', host, args='Anno') - support.menu(itemlist, 'Sub-ITA', 'peliculas', host + "/sub-ita/") - support.menu(itemlist, 'Cerca...', 'search', host, 'movie') - support.aplay(item, itemlist,list_servers, list_quality) - support.channel_config(item, itemlist) +@support.scrape +def peliculas(item): + support.log() - return itemlist + patron = r'<div class="wrapperImage">[ ]?(?:<span class="hd">(?P<quality>[^<>]+))?.+?'\ + 'href="(?P<url>[^"]+)".+?src="(?P<thumb>[^"]+)".+?<h2 class="titleFilm">[^>]+>'\ + '(?P<title>.+?)[ ]?(?:|\[(?P<lang>[^\]]+)\])?(?:\((?P<year>\d{4})\))?</a>.*?'\ + '(?:IMDB\:</strong>[ ](?P<rating>.+?)<|</h2> )' + patronBlock = r'<h1 class="titleSection titleLastIns">.+?</h1>(?P<block>.*?)<div class="row ismobile">' + if item.args == 'genres': + patron = r'<div class="wrapperImage">[ ]?(?:<span class="hd">'\ + '(?P<quality>[^<>]+))?.+?href="(?P<url>[^"]+)".+?src="(?P<thumb>[^"]+)"'\ + '.+?<h2 class="titleFilm(?:Mobile)?">[^>]+>(?P<title>.+?)[ ]?'\ + '(?:|\[(?P<lang>[^\]]+)\])?(?:\((?P<year>\d{4})\))?</a>.*?'\ + '(IMDB\:[ ](?P<rating>.+?))<' + elif item.args == 'search': + patronBlock = r'<section id="lastUpdate">(?P<block>.*?)<div class="row ismobile">' + patron = r'<a href="(?P<url>[^"]+)">\s*<div class="wrapperImage">(?:<span class="hd">(?P<quality>[^<]+)'\ + '<\/span>)?<img[^s]+src="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)<[^<]+>'\ + '(?:.*?IMDB:\s(\2[^<]+)<\/div>)?' + elif not item.args: + patronBlock = r'ULTIMI INSERITI(?P<block>.*?)<div class="sliderLastUpdate ismobile ">' + + # nella pagina "CERCA", la voce "SUCCESSIVO" apre la maschera di inserimento dati + patronNext = r'<a class="next page-numbers" href="([^"]+)">' + + #debug = True + return locals() + +@support.scrape +def genres(item): + support.log('genres', item) + #debug = True + + action = 'peliculas' + patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<]+)<' + + if item.args == 'genres': + patronBlock = r'<ul class="listSubCat" id="Film">(?P<block>.*)<ul class="listSubCat" id="Anno">' + elif item.args == 'years': + patronBlock = r'<ul class="listSubCat" id="Anno">(?P<block>.*)<ul class="listSubCat" id="Qualita">' + elif item.args == 'quality': + patronBlock = r'<ul class="listSubCat" id="Qualita">(?P<block>.*)</li> </ul> </div> </div> </div> <a' + elif item.args == 'lucky': # sono i titoli random nella pagina + patronBlock = r'<h3 class="titleSidebox dado">FILM RANDOM</h3>(?P<block>.*)</section>' + patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<[]+)(?:\[(?P<lang>.+?)\])?<' + action = 'findvideos' + + item.args = 'genres' + + return locals() def search(item, texto): support.log("search ", texto) - item.extra = 'search' + item.args = 'search' item.url = host + "/?s=" + texto - try: return peliculas(item) - - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): @@ -61,6 +116,7 @@ def newest(categoria): item = Item() try: if categoria == "peliculas": + item.args = 'news' item.url = host + "/nuove-uscite/" item.action = "peliculas" itemlist = peliculas(item) @@ -68,7 +124,7 @@ def newest(categoria): if itemlist[-1].action == "peliculas": itemlist.pop() - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): @@ -77,36 +133,6 @@ def newest(categoria): return itemlist - -def menu(item): - support.log() - itemlist = support.scrape(item, '<li><a href="([^"]+)">([^<]+)</a></li>', ['url', 'title'], headers, patron_block='<ul class="listSubCat" id="'+ str(item.args) + '">(.*?)</ul>', action='peliculas') - return support.thumb(itemlist) - -def peliculas(item): - support.log() - if item.extra == 'search': - patron = r'<a href="([^"]+)">\s*<div class="wrapperImage">(?:<span class="hd">([^<]+)<\/span>)?<img[^s]+src="([^"]+)"[^>]+>[^>]+>[^>]+>([^<]+)<[^<]+>(?:.*?IMDB:\s([^<]+)<\/div>)?' - elements = ['url', 'quality', 'thumb', 'title', 'rating'] - - else: - patron = r'<img width[^s]+src="([^"]+)[^>]+><\/a>.*?<a href="([^"]+)">([^(?:\]|<)]+)(?:\[([^\]]+)\])?<\/a>[^>]+>[^>]+>[^>]+>(?:\sIMDB\:\s([^<]+)<)?(?:.*?<span class="hd">([^<]+)<\/span>)?\s*<a' - elements =['thumb', 'url', 'title','lang', 'rating', 'quality'] - itemlist = support.scrape(item, patron, elements, headers, patronNext='<a class="next page-numbers" href="([^"]+)">') - return itemlist - - def findvideos(item): - support.log() - - itemlist = support.hdpass_get_servers(item) - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # itemlist = filtertools.get_links(itemlist, item, list_language) - - autoplay.start(itemlist, item) - support.videolibrary(itemlist, item ,'color kod bold') - - return itemlist + support.log('findvideos', item) + return support.hdpass_get_servers(item) diff --git a/channels/altadefinizionehd.json b/channels/altadefinizionehd.json deleted file mode 100644 index 3efdad33..00000000 --- a/channels/altadefinizionehd.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "id": "altadefinizionehd", - "name": "AltadefinizioneHD", - "active": false, - "adult": false, - "language": ["ita"], - "thumbnail": "https://altadefinizione.doctor/wp-content/uploads/2019/02/logo.png", - "bannermenu": "https://altadefinizione.doctor/wp-content/uploads/2019/02/logo.png", - "categories": ["tvshow","movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] -} diff --git a/channels/altadefinizionehd.py b/channels/altadefinizionehd.py deleted file mode 100644 index 08757113..00000000 --- a/channels/altadefinizionehd.py +++ /dev/null @@ -1,264 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------ -# Canale per Altadefinizione HD -# ---------------------------------------------------------- -import re - -from channelselector import thumb -from core import httptools, scrapertools, servertools, tmdb -from core.item import Item -from platformcode import logger, config -from specials import autoplay - -__channel__ = 'altadefinizionehd' -host = config.get_channel_url(__channel__) - -headers = [['Referer', host]] - -list_servers = ['openload'] -list_quality = ['default'] - -def mainlist(item): - logger.info("[altadefinizionehd.py] mainlist") - - autoplay.init(item.channel, list_servers, list_quality) - - itemlist = [Item(channel=item.channel, - action="video", - title="[B]Film[/B]", - url=host + '/movies/', - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="menu", - title="[B] > Film per Genere[/B]", - url=host, - extra='GENERE', - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="menu", - title="[B] > Film per Anno[/B]", - url=host, - extra='ANNO', - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="video", - title="Film Sub-Ita", - url=host + "/genre/sub-ita/", - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="video", - title="Film Rip", - url=host + "/genre/dvdrip-bdrip-brrip/", - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="video", - title="Film al Cinema", - url=host + "/genre/cinema/", - thumbnail=NovitaThumbnail, - fanart=FilmFanart), - Item(channel=item.channel, - action="search", - extra="movie", - title="[COLOR blue]Cerca Film...[/COLOR]", - thumbnail=CercaThumbnail, - fanart=FilmFanart)] - - autoplay.show_option(item.channel, itemlist) - - itemlist = thumb(itemlist) - - return itemlist - - -def menu(item): - logger.info("[altadefinizionehd.py] menu") - itemlist = [] - data = httptools.downloadpage(item.url, headers=headers).data - logger.info("[altadefinizionehd.py] DATA"+data) - patron = r'<li id="menu.*?><a href="#">FILM PER ' + item.extra + r'<\/a><ul class="sub-menu">(.*?)<\/ul>' - logger.info("[altadefinizionehd.py] BLOCK"+patron) - block = scrapertools.find_single_match(data, patron) - logger.info("[altadefinizionehd.py] BLOCK"+block) - patron = r'<li id=[^>]+><a href="(.*?)">(.*?)<\/a><\/li>' - matches = re.compile(patron, re.DOTALL).findall(block) - for url, title in matches: - itemlist.append( - Item(channel=item.channel, - action='video', - title=title, - url=url)) - return itemlist - - - -def newest(categoria): - logger.info("[altadefinizionehd.py] newest" + categoria) - itemlist = [] - item = Item() - try: - if categoria == "peliculas": - item.url = host - item.action = "video" - itemlist = video(item) - - if itemlist[-1].action == "video": - itemlist.pop() - - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist - - -def video(item): - logger.info("[altadefinizionehd.py] video") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - logger.info("[altadefinizionehd.py] Data" +data) - if 'archive-content' in data: - regex = r'<div id="archive-content".*?>(.*?)<div class="pagination' - else: - regex = r'<div class="items".*?>(.*?)<div class="pagination' - block = scrapertools.find_single_match(data, regex) - logger.info("[altadefinizionehd.py] Block" +block) - - patron = r'<article .*?class="item movies">.*?<img src="([^"]+)".*?<span class="quality">(.*?)<\/span>.*?<a href="([^"]+)">.*?<h4>([^<]+)<\/h4>(.*?)<\/article>' - matches = re.compile(patron, re.DOTALL).findall(block) - - for scrapedthumb, scrapedquality, scrapedurl, scrapedtitle, scrapedinfo in matches: - title = scrapedtitle + " [" + scrapedquality + "]" - - patron = r'IMDb: (.*?)<\/span> <span>(.*?)<\/span>.*?"texto">(.*?)<\/div>' - matches = re.compile(patron, re.DOTALL).findall(scrapedinfo) - logger.info("[altadefinizionehd.py] MATCHES" + str(matches)) - for rating, year, plot in matches: - - infoLabels = {} - infoLabels['Year'] = year - infoLabels['Rating'] = rating - infoLabels['Plot'] = plot - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="movie", - title=title, - fulltitle=scrapedtitle, - infoLabels=infoLabels, - url=scrapedurl, - thumbnail=scrapedthumb)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - patron = '<a class='+ "'arrow_pag'" + ' href="([^"]+)"' - next_page = scrapertools.find_single_match(data, patron) - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="video", - title="[COLOR blue]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - thumbnail=thumb())) - - return itemlist - - -def search(item, texto): - logger.info("[altadefinizionehd.py] init texto=[" + texto + "]") - item.url = host + "/?s=" + texto - return search_page(item) - -def search_page(item): - itemlist = [] - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<img src="([^"]+)".*?.*?<a href="([^"]+)">(.*?)<\/a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumbnail, scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append( - Item(channel=item.channel, - action="findvideos", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - patron = '<a class='+ "'arrow_pag'" + ' href="([^"]+)"' - next_page = scrapertools.find_single_match(data, patron) - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="search_page", - title="[COLOR blue]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - thumbnail=thumb())) - - return itemlist - - -def findvideos(item): - data = httptools.downloadpage(item.url).data - patron = r"<li id='player-.*?'.*?class='dooplay_player_option'\sdata-type='(.*?)'\sdata-post='(.*?)'\sdata-nume='(.*?)'>.*?'title'>(.*?)</" - matches = re.compile(patron, re.IGNORECASE).findall(data) - - itemlist = [] - - for scrapedtype, scrapedpost, scrapednume, scrapedtitle in matches: - itemlist.append( - Item(channel=item.channel, - action="play", - fulltitle=item.title + " [" + scrapedtitle + "]", - show=scrapedtitle, - title=item.title + " [COLOR blue][" + scrapedtitle + "][/COLOR]", - url=host + "/wp-admin/admin-ajax.php", - post=scrapedpost, - server=scrapedtitle, - nume=scrapednume, - type=scrapedtype, - extra=item.extra, - folder=True)) - - autoplay.start(itemlist, item) - - return itemlist - -def play(item): - import urllib - payload = urllib.urlencode({'action': 'doo_player_ajax', 'post': item.post, 'nume': item.nume, 'type': item.type}) - data = httptools.downloadpage(item.url, post=payload).data - - patron = r"<iframe.*src='(([^']+))'\s" - matches = re.compile(patron, re.IGNORECASE).findall(data) - - url = matches[0][0] - url = url.strip() - data = httptools.downloadpage(url, headers=headers).data - - itemlist = servertools.find_video_items(data=data) - - return itemlist - - - -NovitaThumbnail = "https://superrepo.org/static/images/icons/original/xplugin.video.moviereleases.png.pagespeed.ic.j4bhi0Vp3d.png" -GenereThumbnail = "https://farm8.staticflickr.com/7562/15516589868_13689936d0_o.png" -FilmFanart = "https://superrepo.org/static/images/fanart/original/script.artwork.downloader.jpg" -CercaThumbnail = "http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search" -CercaFanart = "https://i.ytimg.com/vi/IAlbvyBdYdY/maxresdefault.jpg" -ListTxt = "[COLOR orange]Torna a video principale [/COLOR]" -AvantiTxt = config.get_localized_string(30992) -AvantiImg = "http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png" -thumbnail = "http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png" diff --git a/channels/animeforce.json b/channels/animeforce.json index e5cbc66e..386a6e61 100644 --- a/channels/animeforce.json +++ b/channels/animeforce.json @@ -4,17 +4,17 @@ "language": ["ita"], "active": true, "adult": false, - "thumbnail": "http://www.animeforce.org/wp-content/uploads/2013/05/logo-animeforce.png", - "banner": "http://www.animeforce.org/wp-content/uploads/2013/05/logo-animeforce.png", + "thumbnail": "animeforce.png", + "banner": "animeforce.png", "categories": ["anime"], "settings": [ { "id": "include_in_global_search", "type": "bool", - "label": "Incluir en busqueda global", + "label": "Includi in Ricerca Globale", "default": false, "enabled": false, - "visible": false + "visible": true }, { "id": "include_in_newest_anime", @@ -31,6 +31,39 @@ "default": true, "enabled": true, "visible": true - } + }, + { + "id": "checklinks", + "type": "bool", + "label": "Verifica se i link esistono", + "default": false, + "enabled": true, + "visible": true + }, + { + "id": "checklinks_number", + "type": "list", + "label": "Numero de link da verificare", + "default": 1, + "enabled": true, + "visible": "eq(-1,true)", + "lvalues": [ "1", "3", "5", "10" ] + }, + { + "id": "autorenumber", + "type": "bool", + "label": "@70712", + "default": false, + "enabled": true, + "visible": true + }, + { + "id": "autorenumber_mode", + "type": "bool", + "label": "@70688", + "default": false, + "enabled": true, + "visible": "eq(-1,true)" + } ] } diff --git a/channels/animeforce.py b/channels/animeforce.py index 54a14d80..8963c28d 100644 --- a/channels/animeforce.py +++ b/channels/animeforce.py @@ -1,505 +1,142 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew -# Canale per http://animeinstreaming.net/ +# Canale per AnimeForce # ------------------------------------------------------------ -import re -import urllib -import urlparse -from core import httptools, scrapertools, servertools, tmdb -from core.item import Item -from platformcode import config, logger from servers.decrypters import adfly +from core import support -__channel__ = "animeforge" -host = config.get_channel_url(__channel__) +__channel__ = "animeforce" +host = support.config.get_channel_url(__channel__) IDIOMAS = {'Italiano': 'IT'} list_language = IDIOMAS.values() +list_servers = ['directo', 'openload', 'vvvvid'] +list_quality = ['default'] + headers = [['Referer', host]] -PERPAGE = 20 - -# ----------------------------------------------------------------- +@support.menu def mainlist(item): - log("mainlist", "mainlist", item.channel) - itemlist = [Item(channel=item.channel, - action="lista_anime", - title="[COLOR azure]Anime [/COLOR]- [COLOR lightsalmon]Lista Completa[/COLOR]", - url=host + "/lista-anime/", - thumbnail=CategoriaThumbnail, - fanart=CategoriaFanart), - Item(channel=item.channel, - action="animeaggiornati", - title="[COLOR azure]Anime Aggiornati[/COLOR]", - url=host, - thumbnail=CategoriaThumbnail, - fanart=CategoriaFanart), - Item(channel=item.channel, - action="ultimiep", - title="[COLOR azure]Ultimi Episodi[/COLOR]", - url=host, - thumbnail=CategoriaThumbnail, - fanart=CategoriaFanart), - Item(channel=item.channel, - action="search", - title="[COLOR yellow]Cerca ...[/COLOR]", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search")] - - return itemlist + anime = ['/lista-anime/', + ('In Corso',['/lista-anime-in-corso/', 'peliculas', 'corso']), + ('Ultime Serie',['/category/anime/articoli-principali/','peliculas','last']) + ] + return locals() -# ================================================================= - -# ----------------------------------------------------------------- def newest(categoria): - log("newest", "newest" + categoria) + support.log(categoria) itemlist = [] - item = Item() + item = support.Item() try: if categoria == "anime": + item.contentType = 'tvshow' item.url = host - item.action = "ultimiep" - itemlist = ultimiep(item) - - if itemlist[-1].action == "ultimiep": - itemlist.pop() - # Continua la ricerca in caso di errore + item.args = 'newest' + return peliculas(item) + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.logger.error("{0}".format(line)) return [] return itemlist - -# ================================================================= - -# ----------------------------------------------------------------- +@support.scrape def search(item, texto): - log("search", "search", item.channel) - item.url = host + "/?s=" + texto - try: - return search_anime(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] + # debug = True + search = texto + item.contentType = 'tvshow' + patron = r'<a href="(?P<url>[^"]+)">\s*<strong[^>]+>(?P<title>[^<]+)<' + action = 'episodios' + return locals() -# ================================================================= +@support.scrape +def peliculas(item): + anime = True + action = 'episodios' -# ----------------------------------------------------------------- -def search_anime(item): - log("search_anime", "search_anime", item.channel) - itemlist = [] + if item.args == 'newest': + patron = r'<a href="(?P<url>[^"]+)">\s*<img src="(?P<thumb>[^"]+)" alt="(?P<title>.*?)(?: Sub| sub| SUB|")' + action = 'findvideos' - data = httptools.downloadpage(item.url).data + elif item.args == 'last': + patron = r'<a href="(?P<url>[^"]+)">\s*<img src="(?P<thumb>[^"]+)" alt="(?P<title>.*?)(?: Sub| sub| SUB|")' - patron = r'<a href="([^"]+)"><img.*?src="([^"]+)".*?title="([^"]+)".*?/>' - matches = re.compile(patron, re.DOTALL).findall(data) + elif item.args == 'corso': + pagination = '' + patron = r'<strong><a href="(?P<url>[^"]+)">(?P<title>.*?) [Ss][Uu][Bb]' + else: + pagination = '' + patron = r'<a href="(?P<url>[^"]+)">\s*<strong[^>]+>(?P<title>[^<]+)<' - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - if "Sub Ita Download & Streaming" in scrapedtitle or "Sub Ita Streaming": - if 'episodio' in scrapedtitle.lower(): - itemlist.append(episode_item(item, scrapedtitle, scrapedurl, scrapedthumbnail)) - else: - scrapedtitle, eptype = clean_title(scrapedtitle, simpleClean=True) - cleantitle, eptype = clean_title(scrapedtitle) + def itemHook(item): + if 'sub-ita' in item.url: + if item.args != 'newest': item.title = item.title + support.typo('Sub-ITA','_ [] color kod') + item.contentLanguage = 'Sub-ITA' + if item.args == 'newest': + url = support.match(item, '<a href="([^"]+)" title="[^"]+" target="[^"]+" class="btn', headers=headers)[0] + item.url = url[0] if url else '' + delete = support.scrapertoolsV2.find_single_match(item.fulltitle, r'( Episodi.*)') + episode = support.scrapertoolsV2.find_single_match(item.title, r'Episodi(?:o)? (?:\d+÷)?(\d+)') + item.title = support.typo(episode + ' - ','bold') + item.title.replace(delete,'') + item.fulltitle = item.show = item.title.replace(delete,'') + item.episode = episode + return item - scrapedurl, total_eps = create_url(scrapedurl, cleantitle) - - itemlist.append( - Item(channel=item.channel, - action="episodios", - text_color="azure", - contentType="tvshow", - title=scrapedtitle, - url=scrapedurl, - fulltitle=cleantitle, - show=cleantitle, - thumbnail=scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Next Page - next_page = scrapertools.find_single_match(data, r'<link rel="next" href="([^"]+)"[^/]+/>') - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="search_anime", - text_bold=True, - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png")) - - return itemlist + return locals() -# ================================================================= - -# ----------------------------------------------------------------- -def animeaggiornati(item): - log("animeaggiornati", "animeaggiornati", item.channel) - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<img.*?src="([^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="([^"]+)">([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumbnail, scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - if 'Streaming' in scrapedtitle: - cleantitle, eptype = clean_title(scrapedtitle) - - # Creazione URL - scrapedurl, total_eps = create_url(scrapedurl, scrapedtitle) - - itemlist.append( - Item(channel=item.channel, - action="episodios", - text_color="azure", - contentType="tvshow", - title=cleantitle, - url=scrapedurl, - fulltitle=cleantitle, - show=cleantitle, - thumbnail=scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - - -# ================================================================= - -# ----------------------------------------------------------------- -def ultimiep(item): - log("ultimiep", "ultimiep", item.channel) - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<img.*?src="([^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="([^"]+)">([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumbnail, scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - if 'Streaming' in scrapedtitle: - itemlist.append(episode_item(item, scrapedtitle, scrapedurl, scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - - -# ================================================================= - -# ----------------------------------------------------------------- -def lista_anime(item): - log("lista_anime", "lista_anime", item.channel) - - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - # Carica la pagina - data = httptools.downloadpage(item.url).data - - # Estrae i contenuti - patron = r'<li>\s*<strong>\s*<a\s*href="([^"]+?)">([^<]+?)</a>\s*</strong>\s*</li>' - matches = re.compile(patron, re.DOTALL).findall(data) - - scrapedplot = "" - scrapedthumbnail = "" - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - - # Pulizia titolo - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle).strip() - cleantitle, eptype = clean_title(scrapedtitle, simpleClean=True) - - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="episodios", - text_color="azure", - contentType="tvshow", - title=cleantitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=cleantitle, - show=cleantitle, - plot=scrapedplot, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - if len(matches) >= p * PERPAGE: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="lista_anime", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=scrapedurl, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png", - folder=True)) - - return itemlist - - -# ================================================================= - -# ----------------------------------------------------------------- +@support.scrape def episodios(item): - itemlist = [] - - data = httptools.downloadpage(item.url).data - - patron = '<td style="[^"]*?">\s*.*?<strong>(.*?)</strong>.*?\s*</td>\s*<td style="[^"]*?">\s*<a href="([^"]+?)"[^>]+>\s*<img.*?src="([^"]+?)".*?/>\s*</a>\s*</td>' - matches = re.compile(patron, re.DOTALL).findall(data) - - vvvvid_videos = False - for scrapedtitle, scrapedurl, scrapedimg in matches: - if 'nodownload' in scrapedimg or 'nostreaming' in scrapedimg: - continue - if 'vvvvid' in scrapedurl.lower(): - if not vvvvid_videos: vvvvid_videos = True - itemlist.append(Item(title='I Video VVVVID Non sono supportati', text_color="red")) - continue - - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'<[^>]*?>', '', scrapedtitle) - scrapedtitle = '[COLOR azure][B]' + scrapedtitle + '[/B][/COLOR]' - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title=scrapedtitle, - url=urlparse.urljoin(host, scrapedurl), - fulltitle=scrapedtitle, - show=scrapedtitle, - plot=item.plot, - fanart=item.fanart, - thumbnail=item.thumbnail)) - - # Comandi di servizio - if config.get_videolibrary_support() and len(itemlist) != 0 and not vvvvid_videos: - itemlist.append( - Item(channel=item.channel, - title=config.get_localized_string(30161), - text_color="yellow", - text_bold=True, - url=item.url, - action="add_serie_to_library", - extra="episodios", - show=item.show)) - - return itemlist + anime = True + patron = r'<td style[^>]+>\s*.*?(?:<span[^>]+)?<strong>(?P<title>[^<]+)<\/strong>.*?<td style[^>]+>\s*<a href="(?P<url>[^"]+)"[^>]+>' + def itemHook(item): + item.url = item.url.replace(host, '') + return item + action = 'findvideos' + return locals() -# ================================================================== - -# ----------------------------------------------------------------- def findvideos(item): - logger.info("kod.animeforce findvideos") + support.log(item) itemlist = [] - if item.extra: - data = httptools.downloadpage(item.url, headers=headers).data + if item.episode: + from lib import unshortenit + url, c = unshortenit.unshorten(item.url) + url = support.match(item, r'<a href="([^"]+)"[^>]*>', patronBlock=r'Episodio %s(.*?)</tr>' % item.episode ,url=url)[0] + item.url = url[0] if url else '' - blocco = scrapertools.find_single_match(data, r'%s(.*?)</tr>' % item.extra) - url = scrapertools.find_single_match(blocco, r'<a href="([^"]+)"[^>]*>') - if 'vvvvid' in url.lower(): - itemlist = [Item(title='I Video VVVVID Non sono supportati', text_color="red")] - return itemlist - if 'http' not in url: url = "".join(['https:', url]) - else: - url = item.url + if 'vvvvid' in item.url: + item.action = 'play' + itemlist.append(item) - if 'adf.ly' in url: - url = adfly.get_long_url(url) - elif 'bit.ly' in url: - url = httptools.downloadpage(url, only_headers=True, follow_redirects=False).headers.get("location") + if 'http' not in item.url: + if '//' in item.url[:2]: + item.url = 'http:' + item.url + elif host not in item.url: + item.url = host + item.url - if 'animeforce' in url: - headers.append(['Referer', item.url]) - data = httptools.downloadpage(url, headers=headers).data - itemlist.extend(servertools.find_video_items(data=data)) + if 'adf.ly' in item.url: + item.url = adfly.get_long_url(item.url) + elif 'bit.ly' in item.url: + item.url = support.httptools.downloadpage(item.url, only_headers=True, follow_redirects=False).headers.get("location") - for videoitem in itemlist: - videoitem.title = item.title + videoitem.title - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - videoitem.contentType = item.contentType + matches = support.match(item, r'button"><a href="([^"]+)"')[0] - url = url.split('&')[0] - data = httptools.downloadpage(url, headers=headers).data - patron = """<source\s*src=(?:"|')([^"']+?)(?:"|')\s*type=(?:"|')video/mp4(?:"|')>""" - matches = re.compile(patron, re.DOTALL).findall(data) - headers.append(['Referer', url]) - for video in matches: - itemlist.append(Item(channel=item.channel, action="play", title=item.title, - url=video + '|' + urllib.urlencode(dict(headers)), folder=False)) - else: - itemlist.extend(servertools.find_video_items(data=url)) + for video in matches: + itemlist.append( + support.Item(channel=item.channel, + action="play", + title='diretto', + url=video, + server='directo')) - for videoitem in itemlist: - videoitem.title = item.title + videoitem.title - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - videoitem.contentType = item.contentType - - return itemlist - - -# ================================================================== - -# ================================================================= -# Funzioni di servizio -# ----------------------------------------------------------------- -def scrapedAll(url="", patron=""): - data = httptools.downloadpage(url).data - MyPatron = patron - matches = re.compile(MyPatron, re.DOTALL).findall(data) - scrapertools.printMatches(matches) - - return matches - - -# ================================================================= - -# ----------------------------------------------------------------- -def create_url(url, title, eptype=""): - logger.info() - - if 'download' not in url: - url = url.replace('-streaming', '-download-streaming') - - total_eps = "" - if not eptype: - url = re.sub(r'episodio?-?\d+-?(?:\d+-|)[oav]*', '', url) - else: # Solo se è un episodio passa - total_eps = scrapertools.find_single_match(title.lower(), r'\((\d+)-(?:episodio|sub-ita)\)') # Questo numero verrà rimosso dall'url - if total_eps: url = url.replace('%s-' % total_eps, '') - url = re.sub(r'%s-?\d*-' % eptype.lower(), '', url) - url = url.replace('-fine', '') - - return url, total_eps - -# ================================================================= - -# ----------------------------------------------------------------- -def clean_title(title, simpleClean=False): - logger.info() - - title = title.replace("Streaming", "").replace("&", "") - title = title.replace("Download", "") - title = title.replace("Sub Ita", "") - cleantitle = title.replace("#038;", "").replace("amp;", "").strip() - - if '(Fine)' in title: - cleantitle = cleantitle.replace('(Fine)', '').strip() + " (Fine)" - eptype = "" - if not simpleClean: - if "episodio" in title.lower(): - eptype = scrapertools.find_single_match(title, "((?:Episodio?|OAV))") - cleantitle = re.sub(r'%s\s*\d*\s*(?:\(\d+\)|)' % eptype, '', title).strip() - - if 'episodio' not in eptype.lower(): - cleantitle = re.sub(r'Episodio?\s*\d+\s*(?:\(\d+\)|)\s*[\(OAV\)]*', '', cleantitle).strip() - - if '(Fine)' in title: - cleantitle = cleantitle.replace('(Fine)', '') - - return cleantitle, eptype - -# ================================================================= - -# ----------------------------------------------------------------- -def episode_item(item, scrapedtitle, scrapedurl, scrapedthumbnail): - scrapedtitle, eptype = clean_title(scrapedtitle, simpleClean=True) - cleantitle, eptype = clean_title(scrapedtitle) - - # Creazione URL - scrapedurl, total_eps = create_url(scrapedurl, scrapedtitle, eptype) - - epnumber = "" - if 'episodio' in eptype.lower(): - epnumber = scrapertools.find_single_match(scrapedtitle.lower(), r'episodio?\s*(\d+)') - eptype += ":? %s%s" % (epnumber, (r" \(%s\):?" % total_eps) if total_eps else "") - - extra = "<tr>\s*<td[^>]+><strong>(?:[^>]+>|)%s(?:[^>]+>[^>]+>|[^<]*|[^>]+>)</strong>" % eptype - item = Item(channel=item.channel, - action="findvideos", - contentType="tvshow", - title=scrapedtitle, - text_color="azure", - url=scrapedurl, - fulltitle=cleantitle, - extra=extra, - show=cleantitle, - thumbnail=scrapedthumbnail) - return item - -# ================================================================= - -# ----------------------------------------------------------------- -def scrapedSingle(url="", single="", patron=""): - data = httptools.downloadpage(url).data - paginazione = scrapertools.find_single_match(data, single) - matches = re.compile(patron, re.DOTALL).findall(paginazione) - scrapertools.printMatches(matches) - - return matches - - -# ================================================================= - -# ----------------------------------------------------------------- -def Crea_Url(pagina="1", azione="ricerca", categoria="", nome=""): - # esempio - # chiamate.php?azione=ricerca&cat=&nome=&pag= - Stringa = host + "/chiamate.php?azione=" + azione + "&cat=" + categoria + "&nome=" + nome + "&pag=" + pagina - log("crea_Url", Stringa) - return Stringa - - -# ================================================================= - -# ----------------------------------------------------------------- -def log(funzione="", stringa="", canale=""): - logger.debug("[" + canale + "].[" + funzione + "] " + stringa) - - -# ================================================================= - -# ================================================================= -# riferimenti di servizio -# ----------------------------------------------------------------- -AnimeThumbnail = "http://img15.deviantart.net/f81c/i/2011/173/7/6/cursed_candies_anime_poster_by_careko-d3jnzg9.jpg" -AnimeFanart = "https://i.ytimg.com/vi/IAlbvyBdYdY/maxresdefault.jpg" -CategoriaThumbnail = "http://static.europosters.cz/image/750/poster/street-fighter-anime-i4817.jpg" -CategoriaFanart = "https://i.ytimg.com/vi/IAlbvyBdYdY/maxresdefault.jpg" -CercaThumbnail = "http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search" -CercaFanart = "https://i.ytimg.com/vi/IAlbvyBdYdY/maxresdefault.jpg" -AvantiTxt = config.get_localized_string(30992) -AvantiImg = "http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png" + return support.server(item, itemlist=itemlist) diff --git a/channels/animeleggendari.json b/channels/animeleggendari.json index 6371a381..5fd0cf6b 100644 --- a/channels/animeleggendari.json +++ b/channels/animeleggendari.json @@ -3,76 +3,9 @@ "name": "AnimePerTutti", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita", "sub-ita"], "thumbnail": "animepertutti.png", "bannermenu": "animepertutti.png", - "categories": ["anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare", "IT"] - }, - { - "id": "autorenumber", - "type": "bool", - "label": "@70712", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "autorenumber_mode", - "type": "bool", - "label": "@70688", - "default": false, - "enabled": true, - "visible": "eq(-1,true)" - } - ] + "categories": ["anime", "vos"], + "settings": [] } diff --git a/channels/animeleggendari.py b/channels/animeleggendari.py index d5f4fe24..f95ecdff 100644 --- a/channels/animeleggendari.py +++ b/channels/animeleggendari.py @@ -3,184 +3,132 @@ # Canale per animeleggendari # ------------------------------------------------------------ -import re - -from core import servertools, httptools, scrapertoolsV2, tmdb, support -from core.item import Item -from core.support import log, menu +from core import support from lib.js2py.host import jsfunctions -from platformcode import logger, config -from specials import autoplay, autorenumber __channel__ = "animeleggendari" -host = config.get_channel_url(__channel__) +host = support.config.get_channel_url(__channel__) -# Richiesto per Autoplay -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['verystream', 'openload', 'streamango'] +headers = [['User-Agent', 'Mozilla/50.0 (Windows NT 10.0; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0'], + ['Referer', host]] + +list_servers = ['verystream','openload','rapidvideo','streamango'] list_quality = ['default'] -checklinks = config.get_setting('checklinks', 'animeleggendari') -checklinks_number = config.get_setting('checklinks_number', 'animeleggendari') +@support.menu def mainlist(item): - log() - itemlist = [] - menu(itemlist, 'Anime Leggendari', 'peliculas', host + '/category/anime-leggendari/') - menu(itemlist, 'Anime ITA', 'peliculas', host + '/category/anime-ita/') - menu(itemlist, 'Anime SUB-ITA', 'peliculas', host + '/category/anime-sub-ita/') - menu(itemlist, 'Anime Conclusi', 'peliculas', host + '/category/serie-anime-concluse/') - menu(itemlist, 'Anime in Corso', 'peliculas', host + '/category/anime-in-corso/') - menu(itemlist, 'Genere', 'genres', host) - menu(itemlist, 'Cerca...', 'search') - - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - support.channel_config(item, itemlist) + anime = [ + ('Leggendari', ['/category/anime-leggendari/', 'peliculas']), + ('ITA', ['/category/anime-ita/', 'peliculas']), + ('SUB-ITA', ['/category/anime-sub-ita/', 'peliculas']), + ('Conclusi', ['/category/serie-anime-concluse/', 'peliculas']), + ('in Corso', ['/category/serie-anime-in-corso/', 'peliculas']), + ('Genere', ['', 'genres']) + ] + + return locals() - return itemlist def search(item, texto): - log(texto) - + support.log(texto) + item.url = host + "/?s=" + texto try: return peliculas(item) - - # Continua la ricerca in caso di errore + + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] -def last_ep(item): - log('ANIME PER TUTTI') - return support.scrape(item, '<a href="([^"]+)">([^<]+)<', ['url','title'],patron_block='<ul class="mh-tab-content-posts">(.*?)<\/ul>', action='findvideos') - -def newest(categoria): - log('ANIME PER TUTTI') - log(categoria) - itemlist = [] - item = Item() - try: - if categoria == "anime": - item.url = host - item.action = "last_ep" - itemlist = last_ep(item) - - if itemlist[-1].action == "last_ep": - itemlist.pop() - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist +@support.scrape def genres(item): - itemlist = support.scrape(item, '<a href="([^"]+)">([^<]+)<', ['url', 'title'], action='peliculas', patron_block=r'Generi.*?<ul.*?>(.*?)<\/ul>', blacklist=['Contattaci','Privacy Policy', 'DMCA']) - return support.thumb(itemlist) + blacklist = ['Contattaci','Privacy Policy', 'DMCA'] + patronMenu = r'<a href="(?P<url>[^"]+)">(?P<title>[^<]+)<' + patronBlock = r'Generi</a>\s*<ul[^>]+>(?P<block>.*?)<\/ul>' + action = 'peliculas' + return locals() -def peliculas(item): - log() - itemlist = [] +@support.scrape +def peliculas(item): + anime = True blacklist = ['top 10 anime da vedere'] - matches, data = support.match(item, r'<a class="[^"]+" href="([^"]+)" title="([^"]+)"><img[^s]+src="([^"]+)"[^>]+') + if item.url != host: patronBlock = r'<div id="main-content(?P<block>.*?)<aside' + patron = r'<figure class="(?:mh-carousel-thumb|mh-posts-grid-thumb)"> <a class="[^"]+" href="(?P<url>[^"]+)" title="(?P<title>.*?)(?: \((?P<year>\d+)\))? (?:(?P<lang>SUB ITA|ITA))(?: (?P<title2>[Mm][Oo][Vv][Ii][Ee]))?[^"]*"><img[^s]+src="(?P<thumb>[^"]+)"[^>]+' + def itemHook(item): + if 'movie' in item.title.lower(): + item.title = support.re.sub(' - [Mm][Oo][Vv][Ii][Ee]|[Mm][Oo][Vv][Ii][Ee]','',item.title) + item.title += support.typo('Movie','_ () bold') + item.contentType = 'movie' + item.action = 'findvideos' + return item + patronNext = r'<a class="next page-numbers" href="([^"]+)">' + action = 'episodios' + return locals() - for url, title, thumb in matches: - title = scrapertoolsV2.decodeHtmlentities(title.strip()).replace("streaming", "") - lang = scrapertoolsV2.find_single_match(title, r"((?:SUB ITA|ITA))") - videoType = '' - if 'movie' in title.lower(): - videoType = ' - (MOVIE)' - if 'ova' in title.lower(): - videoType = ' - (OAV)' - - cleantitle = title.replace(lang, "").replace('(Streaming & Download)', '').replace('( Streaming & Download )', '').replace('OAV', '').replace('OVA', '').replace('MOVIE', '').strip() - - if not videoType : - contentType="tvshow" - action="episodios" - else: - contentType="movie" - action="findvideos" - - if not title.lower() in blacklist: - itemlist.append( - Item(channel=item.channel, - action=action, - contentType=contentType, - title=support.typo(cleantitle + videoType, 'bold') + support.typo(lang,'_ [] color kod'), - fulltitle=cleantitle, - show=cleantitle, - url=url, - thumbnail=thumb)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - autorenumber.renumber(itemlist) - support.nextPage(itemlist, item, data, r'<a class="next page-numbers" href="([^"]+)">') - - return itemlist +@support.scrape def episodios(item): - log() - itemlist = [] + data = support.match(item, headers=headers)[1] + if not any(x in data for x in ['Lista Episodi', 'Movie Parte']): + support.log('NOT IN DATA') + patron = r'(?:iframe src|str)="(?P<url>[^"]+)"' + title = item.title + def fullItemlistHook(itemlist): + url = '' + for item in itemlist: + url += item.url +'\n' + item = itemlist[0] + item.data = url + item.title = title + item.contentType = 'movie' + itemlist = [] + itemlist.append(item) + return itemlist + else: + url = item.url + anime = True + patronBlock = r'(?:<p style="text-align: left;">|<div class="pagination clearfix">\s*)(?P<block>.*?)</span></a></div>' + patron = r'(?:<a href="(?P<url>[^"]+)"[^>]+>)?<span class="pagelink">(?P<episode>\d+)' + def itemHook(item): + if not item.url: + item.url = url + if 'Movie Parte' in data: + item.title = support.typo(item.fulltitle + ' - Part ','bold') + item.title + item.contentType = 'movie' + else: + item.title = support.typo('Episodio ', 'bold') + item.title + return item + return locals() - data = httptools.downloadpage(item.url).data - block = scrapertoolsV2.find_single_match(data, r'(?:<p style="text-align: left;">|<div class="pagination clearfix">\s*)(.*?)</span></a></div>') +def check(item): + data = support.match(item, headers=headers)[1] + if 'Lista Episodi' not in data: + item.data = data + return findvideos(item) - itemlist.append( - Item(channel=item.channel, - action='findvideos', - contentType='episode', - title=support.typo('Episodio 1 bold'), - fulltitle=item.title, - url=item.url, - thumbnail=item.thumbnail)) - - if block: - matches = re.compile(r'<a href="([^"]+)".*?><span class="pagelink">(\d+)</span></a>', re.DOTALL).findall(data) - for url, number in matches: - itemlist.append( - Item(channel=item.channel, - action='findvideos', - contentType='episode', - title=support.typo('Episodio ' + number,'bold'), - fulltitle=item.title, - url=url, - thumbnail=item.thumbnail)) - - autorenumber.renumber(itemlist, item) - support.videolibrary - return itemlist + data = '' + return data def findvideos(item): - log() - data = '' - matches = support.match(item, 'str="([^"]+)"')[0] - if matches: - for match in matches: - data += str(jsfunctions.unescape(re.sub('@|g','%', match))) - data += str(match) - log('DATA',data) - if 'animepertutti' in data: - log('ANIMEPERTUTTI!') - + support.log() + if item.data: + data = item.data else: + matches = support.match(item, '(?:str="([^"]+)"|iframe src="([^"]+)")')[0] data = '' + if matches: + for match in matches: + try: data += str(jsfunctions.unescape(support.re.sub('@|g','%', match))) + except: data += '' + data += str(match) + else: + data = '' - itemlist = support.server(item,data) - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # itemlist = filtertools.get_links(itemlist, item, list_language) - autoplay.start(itemlist, item) - - return itemlist + return support.server(item,data) diff --git a/channels/animesaturn.json b/channels/animesaturn.json index d07baf12..c2e68a8a 100644 --- a/channels/animesaturn.json +++ b/channels/animesaturn.json @@ -8,6 +8,14 @@ "banner": "animesaturn.png", "categories": ["anime"], "settings": [ + { + "id": "modo_grafico", + "type": "bool", + "label": "Cerca informazioni extra", + "default": true, + "enabled": true, + "visible": true + }, { "id": "channel_host", "type": "text", @@ -57,15 +65,6 @@ "visible": "eq(-1,true)", "lvalues": [ "1", "3", "5", "10" ] }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - }, { "id": "autorenumber", "type": "bool", diff --git a/channels/animesaturn.py b/channels/animesaturn.py index 90edb519..08daea53 100644 --- a/channels/animesaturn.py +++ b/channels/animesaturn.py @@ -3,377 +3,119 @@ # Canale per AnimeSaturn # Thanks to 4l3x87 # ---------------------------------------------------------- -import re -import urlparse - -import channelselector -from core import httptools, tmdb, support, scrapertools, jsontools -from core.item import Item -from core.support import log -from platformcode import logger, config -from specials import autoplay, autorenumber +from core import support __channel__ = "animesaturn" -host = config.get_setting("channel_host", __channel__) -headers = [['Referer', host]] +host = support.config.get_setting("channel_host", __channel__) +headers={'X-Requested-With': 'XMLHttpRequest'} -IDIOMAS = {'Italiano': 'IT'} +IDIOMAS = {'Italiano': 'ITA'} list_language = IDIOMAS.values() list_servers = ['openload', 'fembed', 'animeworld'] list_quality = ['default', '480p', '720p', '1080p'] - +@support.menu def mainlist(item): - log() - itemlist = [] - support.menu(itemlist, 'Novità bold', 'ultimiep', "%s/fetch_pages.php?request=episodes" % host, 'tvshow') - support.menu(itemlist, 'Anime bold', 'lista_anime', "%s/animelist?load_all=1" % host) - support.menu(itemlist, 'Archivio A-Z submenu', 'list_az', '%s/animelist?load_all=1' % host, args=['tvshow', 'alfabetico']) - support.menu(itemlist, 'Cerca', 'search', host) - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) - return itemlist + anime = ['/animelist?load_all=1', + ('Più Votati',['/toplist','menu', 'top']), + ('In Corso',['/animeincorso','peliculas','incorso']), + ('Ultimi Episodi',['/fetch_pages.php?request=episodes','peliculas','updated'])] + + return locals() -# ---------------------------------------------------------------------------------------------------------------- -def cleantitle(scrapedtitle): - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle.strip()) - scrapedtitle = scrapedtitle.replace('[HD]', '').replace('’', '\'').replace('×', 'x').replace('"', "'") - year = scrapertools.find_single_match(scrapedtitle, '\((\d{4})\)') - if year: - scrapedtitle = scrapedtitle.replace('(' + year + ')', '') - - return scrapedtitle.strip() +@support.scrape +def search(item, texto): + search = texto + item.contentType = 'tvshow' + anime = True + patron = r'href="(?P<url>[^"]+)"[^>]+>[^>]+>(?P<title>[^<|(]+)(?:(?P<lang>\(([^\)]+)\)))?<|\)' + action = 'check' + return locals() -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def lista_anime(item): - log() - itemlist = [] - - PERPAGE = 15 - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - if '||' in item.url: - series = item.url.split('\n\n') - matches = [] - for i, serie in enumerate(series): - matches.append(serie.split('||')) - else: - # Estrae i contenuti - patron = r'<a href="([^"]+)"[^>]*?>[^>]*?>(.+?)<' - matches = support.match(item, patron, headers=headers)[0] - - scrapedplot = "" - scrapedthumbnail = "" - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - title = cleantitle(scrapedtitle).replace('(ita)', '(ITA)') - movie = False - showtitle = title - if '(ITA)' in title: - title = title.replace('(ITA)', '').strip() - showtitle = title - else: - title += ' ' + support.typo('Sub-ITA', '_ [] color kod') - - infoLabels = {} - if 'Akira' in title: - movie = True - infoLabels['year'] = 1988 - - if 'Dragon Ball Super Movie' in title: - movie = True - infoLabels['year'] = 2019 - - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="episodios" if movie == False else 'findvideos', - title=title, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=showtitle, - show=showtitle, - contentTitle=showtitle, - plot=scrapedplot, - contentType='episode' if movie == False else 'movie', - originalUrl=scrapedurl, - infoLabels=infoLabels, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - autorenumber.renumber(itemlist) - - # Paginazione - if len(matches) >= p * PERPAGE: - support.nextPage(itemlist, item, next_page=(item.url + '{}' + str(p + 1))) - - return itemlist - - -# ================================================================================================================ - - -# ---------------------------------------------------------------------------------------------------------------- -def episodios(item): - log() - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data - anime_id = scrapertools.find_single_match(data, r'\?anime_id=(\d+)') - # movie or series - movie = scrapertools.find_single_match(data, r'\Episodi:</b>\s(\d*)\sMovie') - - data = httptools.downloadpage( - host + "/loading_anime?anime_id=" + anime_id, - headers={ - 'X-Requested-With': 'XMLHttpRequest' - }).data - - patron = r'<td style="[^"]+"><b><strong" style="[^"]+">(.+?)</b></strong></td>\s*' - patron += r'<td style="[^"]+"><a href="([^"]+)"' - matches = scrapertools.find_multiple_matches(data, patron) - - for scrapedtitle, scrapedurl in matches: - scrapedtitle = cleantitle(scrapedtitle) - scrapedtitle = re.sub(r'<[^>]*?>', '', scrapedtitle) - scrapedtitle = '[B]' + scrapedtitle + '[/B]' - - itemlist.append( - Item( - channel=item.channel, - action="findvideos", - contentType="episode", - title=scrapedtitle, - url=urlparse.urljoin(host, scrapedurl), - fulltitle=scrapedtitle, - show=scrapedtitle, - plot=item.plot, - fanart=item.thumbnail, - thumbnail=item.thumbnail)) - - if ((len(itemlist) == 1 and 'Movie' in itemlist[0].title) or movie) and item.contentType != 'movie': - item.url = itemlist[0].url - item.contentType = 'movie' - return findvideos(item) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - autorenumber.renumber(itemlist, item) - support.videolibrary(itemlist, item, 'bold color kod') - - return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def findvideos(item): - log() - originalItem = item - - if item.contentType == 'movie': - episodes = episodios(item) - if len(episodes) > 0: - item.url = episodes[0].url - - itemlist = [] - data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data - data = re.sub(r'\n|\t|\s+', ' ', data) - patron = r'<a href="([^"]+)"><div class="downloadestreaming">' - url = scrapertools.find_single_match(data, patron) - data = httptools.downloadpage(url, headers=headers, ignore_response_code=True).data - data = re.sub(r'\n|\t|\s+', ' ', data) - itemlist = support.server(item, data=data) - - return itemlist - - -# ================================================================================================================ - - -# ---------------------------------------------------------------------------------------------------------------- - -def ultimiep(item): - log() - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - post = "page=%s" % p if p > 1 else None - - data = httptools.downloadpage( - item.url, post=post, headers={ - 'X-Requested-With': 'XMLHttpRequest' - }).data - - patron = r"""<a href='[^']+'><div class="locandina"><img alt="[^"]+" src="([^"]+)" title="[^"]+" class="grandezza"></div></a>\s*""" - patron += r"""<a href='([^']+)'><div class="testo">(.+?)</div></a>\s*""" - patron += r"""<a href='[^']+'><div class="testo2">(.+?)</div></a>""" - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumbnail, scrapedurl, scrapedtitle1, scrapedtitle2 in matches: - scrapedtitle1 = cleantitle(scrapedtitle1) - scrapedtitle2 = cleantitle(scrapedtitle2) - scrapedtitle = scrapedtitle1 + ' - ' + scrapedtitle2 + '' - - title = scrapedtitle - showtitle = scrapedtitle - if '(ITA)' in title: - title = title.replace('(ITA)', '').strip() - showtitle = title - else: - title += ' ' + support.typo('Sub-ITA', '_ [] color kod') - - - itemlist.append( - Item(channel=item.channel, - contentType="episode", - action="findvideos", - title=title, - url=scrapedurl, - fulltitle=scrapedtitle1, - show=showtitle, - thumbnail=scrapedthumbnail)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Pagine - patronvideos = r'data-page="(\d+)" title="Next">Pagina Successiva' - next_page = scrapertools.find_single_match(data, patronvideos) - if next_page: - support.nextPage(itemlist, item, next_page=(item.url + '{}' + next_page)) - - return itemlist - - -# ================================================================================================================ - - -# ---------------------------------------------------------------------------------------------------------------- def newest(categoria): - log(categoria) + support.log() itemlist = [] - item = Item() - item.url = host - item.extra = '' + item = support.Item() try: if categoria == "anime": - item.url = "%s/fetch_pages?request=episodios" % host - item.action = "ultimiep" - itemlist = ultimiep(item) - - if itemlist[-1].action == "ultimiep": - itemlist.pop() - + item.url = host + '/fetch_pages.php?request=episodes' + item.args = "updated" + return peliculas(item) # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.logger.error("{0}".format(line)) return [] return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def search_anime(item, texto): - log(texto) - itemlist = [] - - data = httptools.downloadpage(host + "/index.php?search=1&key=%s" % texto).data - jsondata = jsontools.load(data) - - for title in jsondata: - data = str(httptools.downloadpage("%s/templates/header?check=1" % host, post="typeahead=%s" % title).data) - - if 'Anime non esistente' in data: - continue - else: - title = title.replace('(ita)', '(ITA)') - showtitle = title - if '(ITA)' in title: - title = title.replace('(ITA)', '').strip() - showtitle = title - else: - title += ' ' + support.typo('Sub-ITA', '_ [] color kod') - - url = "%s/anime/%s" % (host, data) - - itemlist.append( - Item( - channel=item.channel, - contentType="episode", - action="episodios", - title=title, - url=url, - fulltitle=title, - show=showtitle, - thumbnail="")) - - return itemlist +@support.scrape +def menu(item): + patronMenu = r'u>(?P<title>[^<]+)<u>(?P<url>.*?)</div> </div>' + action = 'peliculas' + return locals() -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def search(item, texto): - log(texto) - itemlist = [] - - try: - return search_anime(item, texto) - - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] +@support.scrape +def peliculas(item): + anime = True + deflang= 'Sub-ITA' + if item.args == 'updated': + post = "page=" + str(item.page if item.page else 1) if item.page > 1 else None + page, data = support.match(item, r'data-page="(\d+)" title="Next">', post=post, headers=headers) + patron = r'<img alt="[^"]+" src="(?P<thumb>[^"]+)" [^>]+></div></a>\s*<a href="(?P<url>[^"]+)"><div class="testo">(?P<title>[^\(<]+)(?:(?P<lang>\(([^\)]+)\)))?</div></a>\s*<a href="[^"]+"><div class="testo2">[^\d]+(?P<episode>\d+)</div></a>' + if page: nextpage = page + item.contentType='episode' + action = 'findvideos' + elif item.args == 'top': + data = item.url + patron = r'<a href="(?P<url>[^"]+)">[^>]+>(?P<title>[^<\(]+)(?:\((?P<year>[0-9]+)\))?(?:\((?P<lang>[A-Za-z]+)\))?</div></a><div class="numero">(?P<title2>[^<]+)</div>.*?src="(?P<thumb>[^"]+)"' + action = 'check' + else: + pagination = '' + if item.args == 'incorso': patron = r'"slider_title" href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)"[^>]+>(?P<title>[^\(<]+)(?:\((?P<year>\d+)\))?</a>' + else: patron = r'href="(?P<url>[^"]+)"[^>]+>[^>]+>(?P<title>.+?)(?:\((?P<lang>ITA)\))?(?:(?P<year>\((\d+)\)))?</span>' + action = 'check' + return locals() -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- +def check(item): + movie, data = support.match(item, r'Episodi:</b> (\d*) Movie') + anime_id = support.match(data, r'anime_id=(\d+)')[0][0] + item.url = host + "/loading_anime?anime_id=" + anime_id + if movie: + item.contentType = 'movie' + episodes = episodios(item) + if len(episodes) > 0: item.url = episodes[0].url + return findvideos(item) + else: + item.contentType = 'tvshow' + return episodios(item) + + +@support.scrape +def episodios(item): + if item.contentType != 'movie': anime = True + patron = r'<strong" style="[^"]+">(?P<title>[^<]+)</b></strong></td>\s*<td style="[^"]+"><a href="(?P<url>[^"]+)"' + return locals() + + +def findvideos(item): + support.log() + url = support.match(item, r'<a href="([^"]+)"><div class="downloadestreaming">',headers=headers)[0] + if url: item.url = url[0] + return support.server(item) + -def list_az(item): - log() - itemlist = [] - alphabet = dict() - # Articoli - patron = r'<a href="([^"]+)"[^>]*?>[^>]*?>(.+?)<' - matches = support.match(item, patron, headers=headers)[0] - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - letter = scrapedtitle[0].upper() - if letter not in alphabet: - alphabet[letter] = [] - alphabet[letter].append(scrapedurl + '||' + scrapedtitle) - for letter in sorted(alphabet): - itemlist.append( - Item(channel=item.channel, - action="lista_anime", - url='\n\n'.join(alphabet[letter]), - title=letter, - fulltitle=letter)) - return itemlist -# ================================================================================================================ diff --git a/channels/animesubita.json b/channels/animesubita.json index 89d78fc6..aa00009f 100644 --- a/channels/animesubita.json +++ b/channels/animesubita.json @@ -3,35 +3,10 @@ "name": "AnimeSubIta", "active": true, "adult": false, - "language": ["ita"], + "language": ["sub-ita"], "thumbnail": "animesubita.png", "bannermenu": "animesubita.png", - "categories": ["anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "categories": ["anime", "vos", "movie"], + "settings": [] } diff --git a/channels/animesubita.py b/channels/animesubita.py index 93fc9f18..d2b492d0 100644 --- a/channels/animesubita.py +++ b/channels/animesubita.py @@ -1,65 +1,37 @@ # -*- coding: utf-8 -*- -# Ringraziamo Icarus crew # ------------------------------------------------------------ -# Ringraziamo Icarus crew # Canale per AnimeSubIta # ------------------------------------------------------------ -import re -import urllib -import urlparse -from core import httptools, scrapertools, tmdb, support -from core.item import Item -from platformcode import logger, config +from core import support __channel__ = "animesubita" -host = config.get_channel_url(__channel__) -PERPAGE = 20 +host = support.config.get_channel_url(__channel__) +headers = {'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0'} -# ---------------------------------------------------------------------------------------------------------------- +list_servers = ['directo'] +list_quality = ['default'] + + +@support.menu def mainlist(item): - logger.info() - itemlist = [Item(channel=item.channel, - action="lista_anime_completa", - title=support.color("Lista Anime", "azure"), - url="%s/lista-anime/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="ultimiep", - title=support.color("Ultimi Episodi", "azure"), - url="%s/category/ultimi-episodi/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="lista_anime", - title=support.color("Anime in corso", "azure"), - url="%s/category/anime-in-corso/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="categorie", - title=support.color("Categorie", "azure"), - url="%s/generi/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="search", - title=support.color("Cerca anime ...", "yellow"), - extra="anime", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search") - ] + anime = ['/lista-anime/', + ('Ultimi Episodi',['/category/ultimi-episodi/', 'peliculas', 'updated']), + ('in Corso',['/category/anime-in-corso/', 'peliculas', 'alt']), + ('Generi',['/generi/', 'genres', 'alt'])] + return locals() - return itemlist -# ================================================================================================================ -# ---------------------------------------------------------------------------------------------------------------- def newest(categoria): - logger.info() + support.log(categoria) itemlist = [] - item = Item() + item = support.Item() try: if categoria == "anime": item.url = host - item.action = "ultimiep" - itemlist = ultimiep(item) + item.args = "updated" + itemlist = peliculas(item) if itemlist[-1].action == "ultimiep": itemlist.pop() @@ -67,277 +39,92 @@ def newest(categoria): except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.logger.error("{0}".format(line)) return [] return itemlist -# ================================================================================================================ -# ---------------------------------------------------------------------------------------------------------------- + def search(item, texto): - logger.info() + support.log(texto) item.url = host + "/?s=" + texto + item.args = 'alt' try: - return lista_anime(item) + return peliculas(item) # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def categorie(item): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - patron = r'<li><a title="[^"]+" href="([^"]+)">([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item(channel=item.channel, - action="lista_anime", - title=scrapedtitle.replace('Anime', '').strip(), - text_color="azure", - url=scrapedurl, - thumbnail=item.thumbnail, - folder=True)) - - return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def ultimiep(item): - logger.info("ultimiep") - itemlist = lista_anime(item, False, False) - - for itm in itemlist: - title = scrapertools.decodeHtmlentities(itm.title) - # Pulizia titolo - title = title.replace("Streaming", "").replace("&", "") - title = title.replace("Download", "") - title = title.replace("Sub Ita", "").strip() - eptype = scrapertools.find_single_match(title, "((?:Episodio?|OAV))") - cleantitle = re.sub(r'%s\s*\d*\s*(?:\(\d+\)|)' % eptype, '', title).strip() - # Creazione URL - url = re.sub(r'%s-?\d*-' % eptype.lower(), '', itm.url) - if "-streaming" not in url: - url = url.replace("sub-ita", "sub-ita-streaming") - - epnumber = "" - if 'episodio' in eptype.lower(): - epnumber = scrapertools.find_single_match(title.lower(), r'episodio?\s*(\d+)') - eptype += ":? " + epnumber - - extra = "<tr>\s*<td[^>]+><strong>(?:[^>]+>|)%s(?:[^>]+>[^>]+>|[^<]*|[^>]+>)</strong>" % eptype - itm.title = support.color(title, 'azure').strip() - itm.action = "findvideos" - itm.url = url - itm.fulltitle = cleantitle - itm.extra = extra - itm.show = re.sub(r'Episodio\s*', '', title) - itm.thumbnail = item.thumbnail - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def lista_anime(item, nextpage=True, show_lang=True): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - blocco = scrapertools.find_single_match(data, r'<div class="post-list group">(.*?)</nav><!--/.pagination-->') - # patron = r'<a href="([^"]+)" title="([^"]+)">\s*<img[^s]+src="([^"]+)"[^>]+>' # Patron con thumbnail, Kodi non scarica le immagini dal sito - patron = r'<a href="([^"]+)" title="([^"]+)">' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'\s+', ' ', scrapedtitle) - # Pulizia titolo - scrapedtitle = scrapedtitle.replace("Streaming", "").replace("&", "") - scrapedtitle = scrapedtitle.replace("Download", "") - lang = scrapertools.find_single_match(scrapedtitle, r"([Ss][Uu][Bb]\s*[Ii][Tt][Aa])") - scrapedtitle = scrapedtitle.replace("Sub Ita", "").strip() - eptype = scrapertools.find_single_match(scrapedtitle, "((?:Episodio?|OAV))") - cleantitle = re.sub(r'%s\s*\d*\s*(?:\(\d+\)|)' % eptype, '', scrapedtitle) +@support.scrape +def genres(item): + blacklist= ['Anime In Corso','Ultimi Episodi'] + patronMenu=r'<li><a title="[^"]+" href="(?P<url>[^"]+)">(?P<title>[^<]+)</a>' + action = 'peliculas' + return locals() - cleantitle = cleantitle.replace(lang, "").strip() +@support.scrape +def peliculas(item): + anime = True + if item.args == 'updated': + #patron = r'<div class="post-thumbnail">\s*<a href="(?P<url>[^"]+)" title="(?P<title>.*?)\s*(?P<episode>Episodio \d+)[^"]+"[^>]*>\s*<img[^src]+src="(?P<thumb>[^"]+)"' + patron = r'<div class="post-thumbnail">\s*<a href="(?P<url>[^"]+)" title="(?P<title>.*?)\s*Episodio (?P<episode>\d+) (?P<lang>[a-zA-Z-\s]+)[^"]*"> <img[^src]+src="(?P<thumb>[^"]+)"' + patronNext = r'<link rel="next" href="([^"]+)"\s*/>' + action = 'findvideos' + elif item.args == 'alt': + patron = r'<div class="post-thumbnail">\s*<a href="(?P<url>[^"]+)" title="(?P<title>.*?)(?: [Oo][Aa][Vv])?(?:\s*(?P<lang>[Ss][Uu][Bb].[Ii][Tt][Aa]))[^"]+">\s*<img[^src]+src="(?P<thumb>[^"]+)"' + patronNext = r'<link rel="next" href="([^"]+)"\s*/>' + action = 'episodios' + else: + pagination = '' + patronBlock = r'<ul class="lcp_catlist"[^>]+>(?P<block>.*?)</ul>' + patron = r'<a href="(?P<url>[^"]+)"[^>]+>(?P<title>.*?)(?: [Oo][Aa][Vv])?(?:\s*(?P<lang>[Ss][Uu][Bb].[Ii][Tt][Aa])[^<]+)?</a>' + action = 'episodios' + return locals() - itemlist.append( - Item(channel=item.channel, - action="episodi", - contentType="tvshow" if 'oav' not in scrapedtitle.lower() else "movie", - title=scrapedtitle.replace(lang, "(%s)" % support.color(lang, "red") if show_lang else "").strip(), - fulltitle=cleantitle, - url=scrapedurl, - show=cleantitle, - folder=True)) - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) +@support.scrape +def episodios(item): + anime = True + patron = r'<td style="[^"]*?">\s*.*?<strong>(?P<episode>[^<]+)</strong>\s*</td>\s*<td[^>]+>\s*<a href="(?P<url>[^"]+)"[^>]+>\s*<img src="(?P<thumb>[^"]+?)"[^>]+>' + return locals() - if nextpage: - patronvideos = r'<link rel="next" href="([^"]+)"\s*/>' - matches = re.compile(patronvideos, re.DOTALL).findall(data) - - if len(matches) > 0: - scrapedurl = matches[0] - itemlist.append( - Item(channel=item.channel, - action="lista_anime", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=scrapedurl, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png", - folder=True)) - return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def lista_anime_completa(item): - logger.info() - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url).data - blocco = scrapertools.find_single_match(data, r'<ul class="lcp_catlist"[^>]+>(.*?)</ul>') - patron = r'<a href="([^"]+)"[^>]+>([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle.strip()) - cleantitle = scrapedtitle.replace("Sub Ita Streaming", "").replace("Ita Streaming", "") - - itemlist.append( - Item(channel=item.channel, - action="episodi", - contentType="tvshow" if 'oav' not in scrapedtitle.lower() else "movie", - title=support.color(scrapedtitle, 'azure'), - fulltitle=cleantitle, - show=cleantitle, - url=scrapedurl, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - if len(matches) >= p * PERPAGE: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="lista_anime_completa", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=scrapedurl, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png", - folder=True)) - - return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def episodi(item): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - - patron = '<td style="[^"]*?">\s*.*?<strong>(.*?)</strong>.*?\s*</td>\s*<td style="[^"]*?">\s*<a href="([^"]+?)"[^>]+>\s*<img.*?src="([^"]+?)".*?/>\s*</a>\s*</td>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedtitle, scrapedurl, scrapedimg in matches: - if 'nodownload' in scrapedimg or 'nostreaming' in scrapedimg: - continue - if 'vvvvid' in scrapedurl.lower(): - itemlist.append(Item(title='I Video VVVVID Non sono supportati')) - continue - - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'<[^>]*?>', '', scrapedtitle) - scrapedtitle = '[COLOR azure][B]' + scrapedtitle + '[/B][/COLOR]' - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title=scrapedtitle, - url=urlparse.urljoin(host, scrapedurl), - fulltitle=item.title, - show=scrapedtitle, - plot=item.plot, - fanart=item.thumbnail, - thumbnail=item.thumbnail)) - - # Comandi di servizio - if config.get_videolibrary_support() and len(itemlist) != 0: - itemlist.append( - Item(channel=item.channel, - title="[COLOR lightblue]%s[/COLOR]" % config.get_localized_string(30161), - url=item.url, - action="add_serie_to_library", - extra="episodios", - show=item.show)) - - return itemlist - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- def findvideos(item): - logger.info() + support.log(item) itemlist = [] - headers = {'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0'} + if item.args == 'updated': + ep = support.match(item.fulltitle,r'(Episodio\s*\d+)')[0][0] + item.url = support.re.sub(r'episodio-\d+-|oav-\d+-', '',item.url) + if 'streaming' not in item.url: item.url = item.url.replace('sub-ita','sub-ita-streaming') + item.url = support.match(item, r'<a href="([^"]+)"[^>]+>', ep + '(.*?)</tr>', )[0][0] - if item.extra: - data = httptools.downloadpage(item.url, headers=headers).data - blocco = scrapertools.find_single_match(data, r'%s(.*?)</tr>' % item.extra) - item.url = scrapertools.find_single_match(blocco, r'<a href="([^"]+)"[^>]+>') - - patron = r'http:\/\/link[^a]+animesubita[^o]+org\/[^\/]+\/.*?(episodio\d*)[^p]+php(\?.*)' - for phpfile, scrapedurl in re.findall(patron, item.url, re.DOTALL): - url = "%s/%s.php%s" % (host, phpfile, scrapedurl) + urls = support.match(item.url, r'(episodio\d*.php.*)')[0] + for url in urls: + url = host + '/' + url headers['Referer'] = url - data = httptools.downloadpage(url, headers=headers).data - # ------------------------------------------------ + data = support.match(item, headers=headers, url=url)[1] cookies = "" - matches = re.compile('(.%s.*?)\n' % host.replace("http://", "").replace("www.", ""), re.DOTALL).findall(config.get_cookie_data()) + matches = support.re.compile('(.%s.*?)\n' % host.replace("http://", "").replace("www.", ""), support.re.DOTALL).findall(support.config.get_cookie_data()) for cookie in matches: - name = cookie.split('\t')[5] - value = cookie.split('\t')[6] - cookies += name + "=" + value + ";" - headers['Cookie'] = cookies[:-1] - # ------------------------------------------------ - scrapedurl = scrapertools.find_single_match(data, r'<source src="([^"]+)"[^>]+>') - url = scrapedurl + '|' + urllib.urlencode(headers) - itemlist.append( - Item(channel=item.channel, - action="play", - text_color="azure", - title="[%s] %s" % (support.color("Diretto", "orange"), item.title), - fulltitle=item.fulltitle, - url=url, - thumbnail=item.thumbnail, - fanart=item.thumbnail, - plot=item.plot)) + cookies += cookie.split('\t')[5] + "=" + cookie.split('\t')[6] + ";" - return itemlist + headers['Cookie'] = cookies[:-1] + + url = support.match(data, r'<source src="([^"]+)"[^>]+>')[0][0] + '|' + support.urllib.urlencode(headers) + itemlist.append( + support.Item(channel=item.channel, + action="play", + title='diretto', + quality='', + url=url, + server='directo', + fulltitle=item.fulltitle, + show=item.show)) + + return support.server(item,url,itemlist) diff --git a/channels/animetubeita.json b/channels/animetubeita.json index a4374457..afb108c2 100644 --- a/channels/animetubeita.json +++ b/channels/animetubeita.json @@ -1,36 +1,11 @@ { "id": "animetubeita", - "name": "Animetubeita", + "name": "AnimeTubeITA", "active": true, "adult": false, - "language": ["ita"], - "thumbnail": "http:\/\/i.imgur.com\/rQPx1iQ.png", - "bannermenu": "http:\/\/i.imgur.com\/rQPx1iQ.png", - "categories": ["anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "language": ["sub-ita"], + "thumbnail": "animetubeita.png", + "bannermenu": "animetubeita.png", + "categories": ["anime","vos"], + "settings": [] } diff --git a/channels/animetubeita.py b/channels/animetubeita.py index d261c048..4f100a76 100644 --- a/channels/animetubeita.py +++ b/channels/animetubeita.py @@ -1,364 +1,138 @@ # -*- coding: utf-8 -*- -# ------------------------------------------------------------ -# Ringraziamo Icarus crew +# ---------------------------------------------------------- # Canale per animetubeita # ---------------------------------------------------------- import re import urllib - -from core import httptools, scrapertools, tmdb -from core.item import Item -from platformcode import logger, config +from core import support __channel__ = "animetubeita" -host = config.get_channel_url(__channel__) -hostlista = host + "/lista-anime/" -hostgeneri = host + "/generi/" -hostcorso = host + "/category/serie-in-corso/" +host = support.config.get_channel_url(__channel__) - -def mainlist(item): - log("animetubeita", "mainlist", item.channel) - itemlist = [Item(channel=item.channel, - action="lista_home", - title="[COLOR azure]Home[/COLOR]", - url=host, - thumbnail=AnimeThumbnail, - fanart=AnimeFanart), - # Item(channel=item.channel, - # action="lista_anime", - # title="[COLOR azure]A-Z[/COLOR]", - # url=hostlista, - # thumbnail=AnimeThumbnail, - # fanart=AnimeFanart), - Item(channel=item.channel, - action="lista_genere", - title="[COLOR azure]Genere[/COLOR]", - url=hostgeneri, - thumbnail=CategoriaThumbnail, - fanart=CategoriaFanart), - Item(channel=item.channel, - action="lista_in_corso", - title="[COLOR azure]Serie in Corso[/COLOR]", - url=hostcorso, - thumbnail=CategoriaThumbnail, - fanart=CategoriaFanart), - Item(channel=item.channel, - action="search", - title="[COLOR lime]Cerca...[/COLOR]", - url=host + "/?s=", - thumbnail=CercaThumbnail, - fanart=CercaFanart)] - return itemlist - - - -def lista_home(item): - log("animetubeita", "lista_home", item.channel) - - itemlist = [] - - patron = '<h2 class="title"><a href="(.*?)" rel="bookmark" title=".*?">.*?<img.*?src="(.*?)".*?<strong>Titolo</strong></td>.*?<td>(.*?)</td>.*?<td><strong>Trama</strong></td>.*?<td>(.*?)</' - for scrapedurl, scrapedthumbnail, scrapedtitle, scrapedplot in scrapedAll(item.url, patron): - title = scrapertools.decodeHtmlentities(scrapedtitle) - title = title.split("Sub")[0] - fulltitle = re.sub(r'[Ee]pisodio? \d+', '', title) - scrapedplot = scrapertools.decodeHtmlentities(scrapedplot) - itemlist.append( - Item(channel=item.channel, - action="dl_s", - contentType="tvshow", - title="[COLOR azure]" + title + "[/COLOR]", - fulltitle=fulltitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fanart=scrapedthumbnail, - show=fulltitle, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Paginazione - # =========================================================== - data = httptools.downloadpage(item.url).data - patron = '<link rel="next" href="(.*?)"' - next_page = scrapertools.find_single_match(data, patron) - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="lista_home", - title=AvantiTxt, - url=next_page, - thumbnail=AvantiImg, - folder=True)) - # =========================================================== - return itemlist - - - -# def lista_anime(item): -# log("animetubeita", "lista_anime", item.channel) - -# itemlist = [] - -# patron = '<li.*?class="page_.*?href="(.*?)">(.*?)</a></li>' -# for scrapedurl, scrapedtitle in scrapedAll(item.url, patron): -# title = scrapertools.decodeHtmlentities(scrapedtitle) -# title = title.split("Sub")[0] -# log("url:[" + scrapedurl + "] scrapedtitle:[" + title + "]") -# itemlist.append( -# Item(channel=item.channel, -# action="dettaglio", -# contentType="tvshow", -# title="[COLOR azure]" + title + "[/COLOR]", -# url=scrapedurl, -# show=title, -# thumbnail="", -# fanart="")) - -# tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - -# return itemlist - - - -def lista_genere(item): - log("lista_anime_genere", "lista_genere", item.channel) - itemlist = [] - - data = httptools.downloadpage(item.url).data - - bloque = scrapertools.find_single_match(data, - '<div class="hentry page post-1 odd author-admin clear-block">(.*?)<div id="disqus_thread">') - - patron = '<li class="cat-item cat-item.*?"><a href="(.*?)" >(.*?)</a>' - matches = re.compile(patron, re.DOTALL).findall(bloque) - scrapertools.printMatches(matches) - - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item(channel=item.channel, - action="lista_generi", - title='[COLOR lightsalmon][B]' + scrapedtitle + '[/B][/COLOR]', - url=scrapedurl, - fulltitle=scrapedtitle, - show=scrapedtitle, - thumbnail=item.thumbnail)) - - return itemlist - - - -def lista_generi(item): - log("animetubeita", "lista_generi", item.channel) - - itemlist = [] - patron = '<h2 class="title"><a href="(.*?)" rel="bookmark" title=".*?">.*?<img.*?src="(.*?)".*?<strong>Titolo</strong></td>.*?<td>(.*?)</td>.*?<td><strong>Trama</strong></td>.*?<td>(.*?)</' - for scrapedurl, scrapedthumbnail, scrapedtitle, scrapedplot in scrapedAll(item.url, patron): - title = scrapertools.decodeHtmlentities(scrapedtitle) - title = title.split("Sub")[0] - fulltitle = re.sub(r'[Ee]pisodio? \d+', '', title) - scrapedplot = scrapertools.decodeHtmlentities(scrapedplot) - itemlist.append( - Item(channel=item.channel, - action="dettaglio", - title="[COLOR azure]" + title + "[/COLOR]", - contentType="tvshow", - fulltitle=fulltitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - show=fulltitle, - fanart=scrapedthumbnail, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Paginazione - # =========================================================== - data = httptools.downloadpage(item.url).data - patron = '<link rel="next" href="(.*?)"' - next_page = scrapertools.find_single_match(data, patron) - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="lista_generi", - title=AvantiTxt, - url=next_page, - thumbnail=AvantiImg, - folder=True)) - # =========================================================== - - - return itemlist - - - -def lista_in_corso(item): - log("animetubeita", "lista_home", item.channel) - - itemlist = [] - - patron = '<h2 class="title"><a href="(.*?)" rel="bookmark" title="Link.*?>(.*?)</a></h2>.*?<img.*?src="(.*?)".*?<td><strong>Trama</strong></td>.*?<td>(.*?)</td>' - for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedplot in scrapedAll(item.url, patron): - title = scrapertools.decodeHtmlentities(scrapedtitle) - title = title.split("Sub")[0] - fulltitle = re.sub(r'[Ee]pisodio? \d+', '', title) - scrapedplot = scrapertools.decodeHtmlentities(scrapedplot) - itemlist.append( - Item(channel=item.channel, - action="dettaglio", - title="[COLOR azure]" + title + "[/COLOR]", - contentType="tvshow", - fulltitle=fulltitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - show=fulltitle, - fanart=scrapedthumbnail, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Paginazione - # =========================================================== - data = httptools.downloadpage(item.url).data - patron = '<link rel="next" href="(.*?)"' - next_page = scrapertools.find_single_match(data, patron) - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="lista_in_corso", - title=AvantiTxt, - url=next_page, - thumbnail=AvantiImg, - folder=True)) - # =========================================================== - return itemlist - - - -def dl_s(item): - log("animetubeita", "dl_s", item.channel) - - itemlist = [] - encontrados = set() - - # 1 - patron = '<p><center><a.*?href="(.*?)"' - for scrapedurl in scrapedAll(item.url, patron): - if scrapedurl in encontrados: continue - encontrados.add(scrapedurl) - title = "DOWNLOAD & STREAMING" - itemlist.append(Item(channel=item.channel, - action="dettaglio", - title="[COLOR azure]" + title + "[/COLOR]", - url=scrapedurl, - thumbnail=item.thumbnail, - fanart=item.thumbnail, - plot=item.plot, - folder=True)) - # 2 - patron = '<p><center>.*?<a.*?href="(.*?)"' - for scrapedurl in scrapedAll(item.url, patron): - if scrapedurl in encontrados: continue - encontrados.add(scrapedurl) - title = "DOWNLOAD & STREAMING" - itemlist.append(Item(channel=item.channel, - action="dettaglio", - title="[COLOR azure]" + title + "[/COLOR]", - url=scrapedurl, - thumbnail=item.thumbnail, - fanart=item.thumbnail, - plot=item.plot, - folder=True)) - - return itemlist - - - -def dettaglio(item): - log("animetubeita", "dettaglio", item.channel) - - itemlist = [] - headers = {'Upgrade-Insecure-Requests': '1', +headers = {'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0'} - episodio = 1 - patron = r'<a href="http:\/\/link[^a]+animetubeita[^c]+com\/[^\/]+\/[^s]+((?:stream|strm))[^p]+php(\?.*?)"' - for phpfile, scrapedurl in scrapedAll(item.url, patron): - title = "Episodio " + str(episodio) - episodio += 1 - url = "%s/%s.php%s" % (host, phpfile, scrapedurl) - headers['Referer'] = url - data = httptools.downloadpage(url, headers=headers).data - # ------------------------------------------------ - cookies = "" - matches = re.compile('(.animetubeita.com.*?)\n', re.DOTALL).findall(config.get_cookie_data()) - for cookie in matches: - name = cookie.split('\t')[5] - value = cookie.split('\t')[6] - cookies += name + "=" + value + ";" - headers['Cookie'] = cookies[:-1] - # ------------------------------------------------ - url = scrapertools.find_single_match(data, """<source src="([^"]+)" type='video/mp4'>""") - url += '|' + urllib.urlencode(headers) - itemlist.append(Item(channel=item.channel, - action="play", - title="[COLOR azure]" + title + "[/COLOR]", - url=url, - thumbnail=item.thumbnail, - fanart=item.thumbnail, - plot=item.plot)) +list_servers = ['directo'] +list_quality = ['default'] - return itemlist +@support.menu +def mainlist(item): + anime = [('Generi',['/generi', 'genres', 'genres']), + ('Ordine Alfabetico',['/lista-anime', 'peliculas', 'list']), + ('In Corso',['/category/serie-in-corso/', 'peliculas', 'in_progress']) + ] + return locals() + +@support.scrape +def genres(item): + blacklist = ['Ultimi Episodi', 'Serie in Corso'] + patronMenu = r'<li[^>]+><a href="(?P<url>[^"]+)" >(?P<title>[^<]+)</a>' + action = 'peliculas' + return locals() - -def search(item, texto): - log("animetubeita", "search", item.channel) - item.url = item.url + texto - +def search(item, text): + support.log(text) + item.url = host + '/lista-anime' + item.args = 'list' + item.search = text try: - return lista_home(item) + return peliculas(item) except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] - -def scrapedAll(url="", patron=""): - matches = [] - data = httptools.downloadpage(url).data - MyPatron = patron - matches = re.compile(MyPatron, re.DOTALL).findall(data) - scrapertools.printMatches(matches) - - return matches +def newest(categoria): + support.log(categoria) + item = support.Item() + try: + if categoria == "anime": + item.contentType='tvshow' + item.url = host + item.args = "last" + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("{0}".format(line)) + return [] +@support.scrape +def peliculas(item): + anime = True + if not item.search: pagination = '' + action = 'episodios' -def scrapedSingle(url="", single="", patron=""): - matches = [] - data = httptools.downloadpage(url).data - elemento = scrapertools.find_single_match(data, single) - matches = re.compile(patron, re.DOTALL).findall(elemento) - scrapertools.printMatches(matches) - - return matches + if item.args == 'list': + search = item.search + patronBlock = r'<ul class="page-list ">(?P<block>.*?)<div class="wprc-container' + patron = r'<li.*?class="page_.*?href="(?P<url>[^"]+)">(?P<title>.*?) Sub Ita' + elif item.args == 'last': + action = 'findvideos' + item.contentType='episode' + patronBlock = r'<div class="blocks">(?P<block>.*?)<div id="sidebar' + patron = r'<h2 class="title"><a href="(?P<url>[^"]+)" [^>]+>.*?<img.*?src="(?P<thumb>[^"]+)".*?<strong>Titolo</strong></td>.*?<td>(?P<title>.*?)\s*Episodio\s*(?P<episode>\d+)[^<]+</td>.*?<td><strong>Trama</strong></td>\s*<td>(?P<plot>[^<]+)<' + elif item.args in ['in_progress','genres']: + patronBlock = r'<div class="blocks">(?P<block>.*?)<div id="sidebar' + patron = r'<h2 class="title"><a href="(?P<url>[^"]+)"[^>]+>(?P<title>.*?)\s* Sub Ita[^<]+</a></h2>.*?<img.*?src="(?P<thumb>.*?)".*?<td><strong>Trama</strong></td>.*?<td>(?P<plot>[^<]+)<' + patronNext = r'href="([^"]+)" >»' + else: + patronBlock = r'<div class="blocks">(?P<block>.*?)<div id="sidebar' + patron = r'<img.*?src="(?P<thumb>[^"]+)".*?<strong>Titolo</strong></td>.*?<td>\s*(?P<title>.*?)\s*Episodio[^<]+</td>.*?<td><strong>Trama</strong></td>\s*<td>(?P<plot>[^<]+)<.*?<a.*?href="(?P<url>[^"]+)"' + patronNext = r'href="([^"]+)" >»' + return locals() - -def log(funzione="", stringa="", canale=""): - logger.debug("[" + canale + "].[" + funzione + "] " + stringa) +@support.scrape +def episodios(item): + patronBlock = r'<h6>Episodio</h6>(?P<block>.*?)(?:<!--|</table>)' + patron = r'<strong>(?P<title>[^<]+)</strong>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="http://link\.animetubeita\.com/2361078/(?P<url>[^"]+)"' + action = 'findvideos' + return locals() +def findvideos(item): + itemlist=[] + if item.args == 'last': + match = support.match(item, r'href="(?P<url>[^"]+)"[^>]+><strong>DOWNLOAD & STREAMING</strong>', url=item.url)[0] + if match: + patronBlock = r'<h6>Episodio</h6>(?P<block>.*?)(?:<!--|</table>)' + patron = r'<a href="http://link\.animetubeita\.com/2361078/(?P<url>[^"]+)"' + match = support.match(item, patron, patronBlock, headers, match[0])[0] + else: return itemlist -AnimeThumbnail = "http://img15.deviantart.net/f81c/i/2011/173/7/6/cursed_candies_anime_poster_by_careko-d3jnzg9.jpg" -AnimeFanart = "http://www.animetubeita.com/wp-content/uploads/21407_anime_scenery.jpg" -CategoriaThumbnail = "http://static.europosters.cz/image/750/poster/street-fighter-anime-i4817.jpg" -CategoriaFanart = "http://www.animetubeita.com/wp-content/uploads/21407_anime_scenery.jpg" -CercaThumbnail = "http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search" -CercaFanart = "https://i.ytimg.com/vi/IAlbvyBdYdY/maxresdefault.jpg" -AvantiTxt = config.get_localized_string(30992) -AvantiImg = "http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png" + if match: item.url = match[-1] + else: return itemlist + data = support.httptools.downloadpage(item.url, headers=headers).data + cookies = "" + matches = re.compile('(.animetubeita.com.*?)\n', re.DOTALL).findall(support.config.get_cookie_data()) + for cookie in matches: + name = cookie.split('\t')[5] + value = cookie.split('\t')[6] + cookies += name + "=" + value + ";" + + headers['Referer'] = item.url + headers['Cookie'] = cookies[:-1] + + url = support.scrapertoolsV2.find_single_match(data, """<source src="([^"]+)" type='video/mp4'>""") + if not url: url = support.scrapertoolsV2.find_single_match(data, 'file: "([^"]+)"') + if url: + url += '|' + urllib.urlencode(headers) + itemlist.append( + support.Item(channel=item.channel, + action="play", + title='diretto', + server='directo', + quality='', + url=url, + thumbnail=item.thumbnail, + fulltitle=item.fulltitle, + show=item.show, + contentType=item.contentType, + folder=False)) + return support.server(item, itemlist=itemlist) \ No newline at end of file diff --git a/channels/animeworld.json b/channels/animeworld.json index ac5f61d1..0aa9aa1d 100644 --- a/channels/animeworld.json +++ b/channels/animeworld.json @@ -1,86 +1,21 @@ { - "id": "animeworld", - "name": "AnimeWorld", - "active": true, - "adult": false, - "language": ["ita"], + "id": "animeworld", + "name": "AnimeWorld", + "active": true, + "adult": false, + "language": ["ita", "sub-ita"], "thumbnail": "animeworld.png", "banner": "animeworld.png", - "categories": ["anime"], + "categories": ["anime", "vos"], "settings": [ { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://www.animeworld.it", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", + "id": "order", "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", + "label": "Ordine di Visualizzazione", "default": 0, "enabled": true, "visible": true, - "lvalues": ["No filtrar","Italiano"] - }, - { - "id": "autorenumber", - "type": "bool", - "label": "@70712", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "autorenumber_mode", - "type": "bool", - "label": "@70688", - "default": false, - "enabled": true, - "visible": "eq(-1,true)" + "lvalues": [ "Standard", "Ultime Aggiunte", "Lista A-Z", "Data di Uscita" ] } ] } diff --git a/channels/animeworld.py b/channels/animeworld.py index 0890735c..f810fb02 100644 --- a/channels/animeworld.py +++ b/channels/animeworld.py @@ -2,320 +2,181 @@ # ------------------------------------------------------------ # Canale per animeworld # ---------------------------------------------------------- -import re -import time -import urllib -import urlparse -from core import httptools, scrapertoolsV2, servertools, tmdb, support, jsontools -from core.support import log -from core.item import Item -from platformcode import logger, config -from specials import autoplay, autorenumber +from core import support, jsontools __channel__ = "animeworld" -host = config.get_channel_url(__channel__) +host = support.config.get_channel_url(__channel__) headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'Italiano'} -list_language = IDIOMAS.values() list_servers = ['animeworld', 'verystream', 'streamango', 'openload', 'directo'] list_quality = ['default', '480p', '720p', '1080p'] +def order(): + # Seleziona l'ordinamento dei risultati + return str(support.config.get_setting("order", __channel__)) + +@support.menu def mainlist(item): - log() - - itemlist =[] - - support.menu(itemlist, 'ITA submenu bold', 'build_menu', host + '/filter?', args=["anime", 'language[]=1']) - support.menu(itemlist, 'Sub-ITA submenu bold', 'build_menu', host + '/filter?', args=["anime", 'language[]=0']) - support.menu(itemlist, 'Archivio A-Z submenu', 'alfabetico', host+'/az-list', args=["tvshow","a-z"]) - support.menu(itemlist, 'In corso submenu', 'video', host+'/ongoing', args=["in sala"]) - support.menu(itemlist, 'Generi submenu', 'generi', host+'/') - support.menu(itemlist, 'Ultimi Aggiunti bold', 'video', host+'/newest', args=["anime"]) - support.menu(itemlist, 'Ultimi Episodi bold', 'video', host+'/updated', args=["novita'"]) - support.menu(itemlist, 'Cerca...', 'search') - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) + anime=['/filter?sort=', + ('ITA',['/filter?language[]=1&sort=', 'build_menu', '1']), + ('SUB-ITA',['/filter?language[]=0&sort=', 'build_menu', '0']), + ('In Corso', ['/ongoing', 'peliculas','noorder']), + ('Ultimi Episodi', ['/updated', 'peliculas', 'updated']), + ('Nuove Aggiunte',['/newest', 'peliculas','noorder' ]), + ('Generi',['','genres',])] + return locals() + + +def genres(item): + support.log() + itemlist = [] + matches = support.match(item, r'<input.*?name="([^"]+)" value="([^"]+)"\s*>[^>]+>([^<]+)<\/label>' , r'<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown"> Generi <span.[^>]+>(.*?)</ul>', headers=headers)[0] + for name, value, title in matches: + support.menuItem(itemlist, __channel__, support.typo(title, 'bold'), 'peliculas', host + '/filter?' + name + '=' + value + '&sort=' + order(), 'tvshow', args='sub') return itemlist -# Crea menu dei generi ================================================= - -def generi(item): - log() - patron_block = r'</i>\sGeneri</a>\s*<ul class="sub">(.*?)</ul>' - patron = r'<a href="([^"]+)"\stitle="([^"]+)">' - - return support.scrape(item, patron, ['url','title'], patron_block=patron_block, action='video') - - -# Crea Menu Filtro ====================================================== def build_menu(item): - log() + support.log() itemlist = [] - support.menu(itemlist, 'Tutti bold submenu', 'video', item.url+item.args[1]) - matches, data = support.match(item,r'<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown"> (.*?) <span.*?>(.*?)<\/ul>',r'<form class="filters.*?>(.*?)<\/form>') - log('ANIME DATA =' ,data) + support.menuItem(itemlist, __channel__, 'Tutti bold', 'peliculas', item.url , 'tvshow' , args=item.args) + matches = support.match(item,r'<button class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown"> (.*?) <span.[^>]+>(.*?)</ul>',r'<form class="filters.*?>(.*?)</form>', headers=headers)[0] for title, html in matches: if title not in 'Lingua Ordine': - support.menu(itemlist, title + ' submenu bold', 'build_sub_menu', html, args=item.args) - log('ARGS= ', item.args[0]) - log('ARGS= ', html) + support.menuItem(itemlist, __channel__, title + ' submenu bold', 'build_sub_menu', html, 'tvshow', args=item.args) return itemlist -# Crea SottoMenu Filtro ====================================================== def build_sub_menu(item): - log() + support.log() itemlist = [] - matches = re.compile(r'<input.*?name="([^"]+)" value="([^"]+)"\s*>[^>]+>([^<]+)<\/label>', re.DOTALL).findall(item.url) + matches = support.re.compile(r'<input.*?name="([^"]+)" value="([^"]+)"\s*>[^>]+>([^<]+)<\/label>', support.re.DOTALL).findall(item.url) for name, value, title in matches: - support.menu(itemlist, support.typo(title, 'bold'), 'video', host + '/filter?' + '&' + name + '=' + value + '&' + item.args[1]) + support.menuItem(itemlist, __channel__, support.typo(title, 'bold'), 'peliculas', host + '/filter?' + name + '=' + value + '&language[]=' + item.args + '&sort=', 'tvshow', args='sub') return itemlist -# Novità ====================================================== def newest(categoria): - log() - itemlist = [] - item = Item() + support.log(categoria) + item = support.Item() try: if categoria == "anime": - item.url = host + '/newest' - item.action = "video" - itemlist = video(item) - - if itemlist[-1].action == "video": - itemlist.pop() - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist - - -# Cerca =========================================================== - -def search(item, texto): - log(texto) - item.url = host + '/search?keyword=' + texto - try: - return video(item) + item.url = host + '/updated' + item.args = "updated" + return peliculas(item) # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("{0}".format(line)) return [] -# Lista A-Z ==================================================== - -def alfabetico(item): - return support.scrape(item, '<a href="([^"]+)" title="([^"]+)">', ['url', 'title'], patron_block=r'<span>.*?A alla Z.<\/span>.*?<ul>(.*?)<\/ul>', action='lista_anime') - - -def lista_anime(item): - log() - itemlist = [] - matches ,data = support.match(item, r'<div class="item"><a href="([^"]+)".*?src="([^"]+)".*?data-jtitle="([^"]+)".*?>([^<]+)<\/a><p>(.*?)<\/p>') - for scrapedurl, scrapedthumb, scrapedoriginal, scrapedtitle, scrapedplot in matches: - - if scrapedoriginal == scrapedtitle: - scrapedoriginal='' - else: - scrapedoriginal = support.typo(scrapedoriginal,' -- []') - - year = '' - lang = '' - infoLabels = {} - if '(' in scrapedtitle: - year = scrapertoolsV2.find_single_match(scrapedtitle, r'(\([0-9]+\))') - lang = scrapertoolsV2.find_single_match(scrapedtitle, r'(\([a-zA-Z]+\))') - - infoLabels['year'] = year - title = scrapedtitle.replace(year,'').replace(lang,'').strip() - original = scrapedoriginal.replace(year,'').replace(lang,'').strip() - if lang: lang = support.typo(lang,'_ color kod') - longtitle = '[B]' + title + '[/B]' + lang + original - - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - contentType="episode", - action="episodios", - title=longtitle, - url=scrapedurl, - thumbnail=scrapedthumb, - fulltitle=title, - show=title, - infoLabels=infoLabels, - plot=scrapedplot, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - autorenumber.renumber(itemlist) - - # Next page - support.nextPage(itemlist, item, data, r'<a class="page-link" href="([^"]+)" rel="next"') - - return itemlist +def search(item, texto): + support.log(texto) + item.args = 'noorder' + item.url = host + '/search?keyword=' + texto + item.contentType = 'tvshow' + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("%s" % line) + return [] -def video(item): - log() - itemlist = [] +@support.scrape +def peliculas(item): + anime=True - matches, data = support.match(item, r'<a href="([^"]+)" class[^>]+><img src="([^"]+)"(.*?)data-jtitle="([^"]+)" .*?>(.*?)<\/a>', '<div class="widget-body">(.*?)<div id="sidebar"', headers=headers) + if item.args == 'updated': + patron=r'<div class="inner">\s*<a href="(?P<url>[^"]+)" class[^>]+>\s*<img src="(?P<thumb>[^"]+)" alt?="(?P<title>[^\("]+)(?:\((?P<lang>[^\)]+)\))?"[^>]+>[^>]+>\s*(?:<div class="[^"]+">(?P<type>[^<]+)</div>)?[^>]+>[^>]+>\s*<div class="ep">[^\d]+(?P<episode>\d+)[^<]*</div>' + action='findvideos' + else: + if item.args != 'noorder' and not item.url[-1].isdigit(): item.url += order() # usa l'ordinamento di configura canale + patron= r'<div class="inner">\s*<a href="(?P<url>[^"]+)" class[^>]+>\s*<img src="(?P<thumb>[^"]+)" alt?="(?P<title>[^\("]+)(?:\((?P<year>\d+)\) )?(?:\((?P<lang>[^\)]+)\))?"[^>]+>[^>]+>(?:\s*<div class="dub">[^>]+>)?\s*(?:<div class="[^"]+">(?P<type>[^<]+)</div>)?' + action='episodios' - for scrapedurl, scrapedthumb ,scrapedinfo, scrapedoriginal, scrapedtitle in matches: - # Cerca Info come anno o lingua nel Titolo - year = '' - lang = '' - if '(' in scrapedtitle: - year = scrapertoolsV2.find_single_match(scrapedtitle, r'( \([0-9]+\))') - lang = scrapertoolsV2.find_single_match(scrapedtitle, r'( \([a-zA-Z]+\))') - - # Rimuove Anno e Lingua nel Titolo - title = scrapedtitle.replace(year,'').replace(lang,'').strip() - original = scrapedoriginal.replace(year,'').replace(lang,'').strip() - - # Compara Il Titolo con quello originale - if original == title: - original='' - else: - original = support.typo(scrapedoriginal,'-- []') - - # cerca info supplementari - ep = '' - ep = scrapertoolsV2.find_single_match(scrapedinfo, '<div class="ep">(.*?)<') - if ep != '': - ep = ' - ' + ep.strip() - number = scrapertoolsV2.find_single_match(ep, '(\d+)') if ep else '' - ova = '' - ova = scrapertoolsV2.find_single_match(scrapedinfo, '<div class="ova">(.*?)<') - if ova != '': - ova = ' - (' + ova + ')' - - ona = '' - ona = scrapertoolsV2.find_single_match(scrapedinfo, '<div class="ona">(.*?)<') - if ona != '': - ona = ' - (' + ona + ')' - - movie = '' - movie = scrapertoolsV2.find_single_match(scrapedinfo, '<div class="movie">(.*?)<') - if movie != '': - movie = ' - (' + movie + ')' - - special = '' - special = scrapertoolsV2.find_single_match(scrapedinfo, '<div class="special">(.*?)<') - if special != '': - special = ' - (' + special + ')' + # Controlla la lingua se assente + patronNext=r'href="([^"]+)" rel="next"' + type_content_dict={'movie':['movie', 'special']} + type_action_dict={'findvideos':['movie', 'special']} + check_lang = item.url + def itemHook(item): + if not item.contentLanguage: + if 'language[]=1' in check_lang: + item.contentLanguage = 'ITA' + item.title += support.typo(item.contentLanguage,'_ [] color kod') + else: + item.contentLanguage = 'Sub-ITA' + item.title += support.typo(item.contentLanguage,'_ [] color kod') + return item - # Concatena le informazioni - - lang = support.typo('Sub-ITA', '_ [] color kod') if '(ita)' not in lang.lower() else '' - - info = ep + lang + year + ova + ona + movie + special - - # Crea il title da visualizzare - long_title = '[B]' + title + '[/B]' + info + original - - # Controlla se sono Episodi o Film - if movie == '': - contentType = 'tvshow' - action = 'episodios' - else: - contentType = 'movie' - action = 'findvideos' - - itemlist.append( - Item(channel=item.channel, - contentType=contentType, - action=action, - title=long_title, - url=scrapedurl, - fulltitle=title, - show=title, - thumbnail=scrapedthumb, - context = autoplay.context, - number= number)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - autorenumber.renumber(itemlist) - - # Next page - support.nextPage(itemlist, item, data, r'href="([^"]+)" rel="next"', resub=['&','&']) - return itemlist + return locals() +@support.scrape def episodios(item): - log() - itemlist = [] - patron_block = r'server active(.*?)server hidden ' - patron = r'<li><a [^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+" href="([^"]+)"[^>]+>([^<]+)<' - matches = support.match(item, patron, patron_block)[0] - - for scrapedurl, scrapedtitle in matches: - if scrapedtitle == item.number: - log('OK') - item.url = urlparse.urljoin(host, scrapedurl) - return findvideos(item) - else: - itemlist.append( - Item( - channel=item.channel, - action="findvideos", - contentType="episode", - title='[B] Episodio ' + scrapedtitle + '[/B]', - url=urlparse.urljoin(host, scrapedurl), - fulltitle=scrapedtitle, - show=scrapedtitle, - plot=item.plot, - fanart=item.thumbnail, - thumbnail=item.thumbnail, - number=scrapedtitle)) - - autorenumber.renumber(itemlist, item, 'bold') - support.videolibrary(itemlist, item) - return itemlist + anime=True + pagination = 50 + data = support.match(item, headers=headers)[1] + if 'VVVVID' in data: patronBlock= r'<div class="server\s*active\s*"(?P<block>.*?)</ul>' + else: patronBlock= r'server active(?P<block>.*?)server hidden ' + patron = r'<li><a [^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+"[^=]+="[^"]+" href="(?P<url>[^"]+)"[^>]+>(?P<episode>[^<]+)<' + def itemHook(item): + item.title += support.typo(item.fulltitle,'-- bold') + return item + action='findvideos' + return locals() def findvideos(item): - log() + import time + support.log(item) itemlist = [] - - matches, data = support.match(item, r'class="tab.*?data-name="([0-9]+)">([^<]+)</span', headers=headers) + matches, data = support.match(item, r'class="tab.*?data-name="([0-9]+)">', headers=headers) videoData = '' - - for serverid, servername in matches: - block = scrapertoolsV2.find_multiple_matches(data,'data-id="'+serverid+'">(.*?)<div class="server') - log('ITEM= ',item) - id = scrapertoolsV2.find_single_match(str(block),r'<a data-id="([^"]+)" data-base="'+item.number+'"') - if id: - dataJson = httptools.downloadpage('%s/ajax/episode/info?id=%s&server=%s&ts=%s' % (host, id, serverid, int(time.time())), headers=[['x-requested-with', 'XMLHttpRequest']]).data - json = jsontools.load(dataJson) - videoData +='\n'+json['grabber'] - if serverid == '28': - itemlist.append( - Item( - channel=item.channel, - action="play", - title='diretto', - quality='', - url=json['grabber'], - server='directo', - show=item.show, - contentType=item.contentType, - folder=False)) + for serverid in matches: + number = support.scrapertoolsV2.find_single_match(item.title,r'(\d+) -') + block = support.scrapertoolsV2.find_multiple_matches(data,'data-id="' + serverid + '">(.*?)<div class="server') + ID = support.scrapertoolsV2.find_single_match(str(block),r'<a data-id="([^"]+)" data-base="' + (number if number else '1') + '"') + support.log('ID= ',serverid) + if id: + if serverid == '26': + matches = support.match(item, r'<a href="([^"]+)"', url='%s/ajax/episode/serverPlayer?id=%s' % (host, item.url.split('/')[-1]))[0] + for url in matches: + videoData += '\n' + url + else: + dataJson = support.httptools.downloadpage('%s/ajax/episode/info?id=%s&server=%s&ts=%s' % (host, ID, serverid, int(time.time())), headers=[['x-requested-with', 'XMLHttpRequest']]).data + json = jsontools.load(dataJson) + support.log(json) + if 'keepsetsu' in json['grabber']: + matches = support.match(item, r'<iframe\s*src="([^"]+)"', url=json['grabber'])[0] + for url in matches: + videoData += '\n' + url + else: + videoData += '\n' + json['grabber'] + + if serverid == '28': + itemlist.append( + support.Item( + channel=item.channel, + action="play", + title='diretto', + quality='', + url=json['grabber'], + server='directo', + fulltitle=item.fulltitle, + show=item.show, + contentType=item.contentType, + folder=False)) return support.server(item, videoData, itemlist) diff --git a/channels/bleachportal.json b/channels/bleachportal.json index e5fcdcf3..59f84ee4 100644 --- a/channels/bleachportal.json +++ b/channels/bleachportal.json @@ -1,22 +1,15 @@ { "id": "bleachportal", "name": "BleachPortal", - "language": ["ita"], + "language": ["sub-ita"], "active": true, - "adult": false, - "fanart": "http://i39.tinypic.com/35ibvcx.jpg", - "thumbnail": "http://www.bleachportal.it/images/index_r1_c1.jpg", - "banner": "http://cgi.di.uoa.gr/~std05181/images/bleach.jpg", + "deprecated": true, + "adult": false, + "fanart": "https://www.thetvdb.com/banners/fanart/original/74796-29.jpg", + "thumbnail": "bleachportal.png", + "banner": "bleachportal.png", "categories": ["anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": false, - "enabled": false, - "visible": false - } - ] + "not_active":["include_in_newests", "include_in_global_search"], + "settings": [] } diff --git a/channels/bleachportal.py b/channels/bleachportal.py index 3df421a0..9377fb9d 100644 --- a/channels/bleachportal.py +++ b/channels/bleachportal.py @@ -11,6 +11,7 @@ from core import scrapertools, httptools from core.item import Item from platformcode import logger from platformcode import config +from core import support host = "http://www.bleachportal.it" @@ -19,17 +20,19 @@ def mainlist(item): logger.info("[BleachPortal.py]==> mainlist") itemlist = [Item(channel=item.channel, action="episodi", - title="[COLOR azure] Bleach [/COLOR] - [COLOR deepskyblue]Lista Episodi[/COLOR]", + title= support.typo('Bleach','bold'), url=host + "/streaming/bleach/stream_bleach.htm", - thumbnail="http://i45.tinypic.com/286xp3m.jpg", - fanart="http://i40.tinypic.com/5jsinb.jpg", + thumbnail="https://www.thetvdb.com/banners/posters/74796-14.jpg", + banner="https://www.thetvdb.com/banners/graphical/74796-g6.jpg", + fanart="https://www.thetvdb.com/banners/fanart/original/74796-30.jpg", extra="bleach"), Item(channel=item.channel, action="episodi", - title="[COLOR azure] D.Gray Man [/COLOR] - [COLOR deepskyblue]Lista Episodi[/COLOR]", + title=support.typo('D.Gray Man','bold'), url=host + "/streaming/d.gray-man/stream_dgray-man.htm", - thumbnail="http://i59.tinypic.com/9is3tf.jpg", - fanart="http://wallpapercraft.net/wp-content/uploads/2016/11/Cool-D-Gray-Man-Background.jpg", + thumbnail="https://www.thetvdb.com/banners/posters/79635-1.jpg", + banner="https://www.thetvdb.com/banners/graphical/79635-g4.jpg", + fanart="https://www.thetvdb.com/banners/fanart/original/79635-6.jpg", extra="dgrayman")] return itemlist @@ -40,7 +43,7 @@ def episodi(item): itemlist = [] data = httptools.downloadpage(item.url).data - patron = '<td>?[<span\s|<width="\d+%"\s]+?class="[^"]+">\D+([\d\-]+)\s?<[^<]+<[^<]+<[^<]+<[^<]+<.*?\s+?.*?<span style="[^"]+">([^<]+).*?\s?.*?<a href="\.*(/?[^"]+)">' + patron = r'<td>?[<span\s|<width="\d+%"\s]+?class="[^"]+">\D+([\d\-]+)\s?<[^<]+<[^<]+<[^<]+<[^<]+<.*?\s+?.*?<span style="[^"]+">([^<]+).*?\s?.*?<a href="\.*(/?[^"]+)">' matches = re.compile(patron, re.DOTALL).findall(data) animetitle = "Bleach" if item.extra == "bleach" else "D.Gray Man" @@ -49,19 +52,19 @@ def episodi(item): itemlist.append( Item(channel=item.channel, action="findvideos", - title="[COLOR azure]%s Ep: [COLOR deepskyblue]%s[/COLOR][/COLOR]" % (animetitle, scrapednumber), + title=support.typo("%s Episodio %s" % (animetitle, scrapednumber),'bold'), url=item.url.replace("stream_bleach.htm",scrapedurl) if "stream_bleach.htm" in item.url else item.url.replace("stream_dgray-man.htm", scrapedurl), plot=scrapedtitle, extra=item.extra, thumbnail=item.thumbnail, fanart=item.fanart, - fulltitle="[COLOR red]%s Ep: %s[/COLOR] | [COLOR deepskyblue]%s[/COLOR]" % (animetitle, scrapednumber, scrapedtitle))) + fulltitle="%s Ep: %s | %s" % (animetitle, scrapednumber, scrapedtitle))) if item.extra == "bleach": itemlist.append( Item(channel=item.channel, action="oav", - title="[B][COLOR azure] OAV e Movies [/COLOR][/B]", + title=support.typo("OAV e Movies",'bold color kod'), url=item.url.replace("stream_bleach.htm", "stream_bleach_movie_oav.htm"), extra=item.extra, thumbnail=item.thumbnail, @@ -75,19 +78,19 @@ def oav(item): itemlist = [] data = httptools.downloadpage(item.url).data - patron = '<td>?[<span\s|<width="\d+%"\s]+?class="[^"]+">-\s+(.*?)<[^<]+<[^<]+<[^<]+<[^<]+<.*?\s+?.*?<span style="[^"]+">([^<]+).*?\s?.*?<a href="\.*(/?[^"]+)">' + patron = r'<td>?[<span\s|<width="\d+%"\s]+?class="[^"]+">-\s+(.*?)<[^<]+<[^<]+<[^<]+<[^<]+<.*?\s+?.*?<span style="[^"]+">([^<]+).*?\s?.*?<a href="\.*(/?[^"]+)">' matches = re.compile(patron, re.DOTALL).findall(data) for scrapednumber, scrapedtitle, scrapedurl in matches: itemlist.append( Item(channel=item.channel, action="findvideos", - title="[COLOR deepskyblue] " + scrapednumber + " [/COLOR]", + title=support.typo(scrapednumber, 'bold'), url=item.url.replace("stream_bleach_movie_oav.htm", scrapedurl), plot=scrapedtitle, extra=item.extra, thumbnail=item.thumbnail, - fulltitle="[COLOR red]" + scrapednumber + "[/COLOR] | [COLOR deepskyblue]" + scrapedtitle + "[/COLOR]")) + fulltitle=scrapednumber + " | " + scrapedtitle)) return list(reversed(itemlist)) @@ -109,7 +112,7 @@ def findvideos(item): itemlist.append( Item(channel=item.channel, action="play", - title="[[COLOR orange]Diretto[/COLOR]] [B]%s[/B]" % item.title, + title="Diretto %s" % item.title, url=item.url.replace(item.url.split("/")[-1], "/" + video), thumbnail=item.thumbnail, fulltitle=item.fulltitle)) diff --git a/channels/canalporno.py b/channels/canalporno.py deleted file mode 100644 index 01a8dcf9..00000000 --- a/channels/canalporno.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- - -from core import httptools -from core import scrapertools -from platformcode import logger -from platformcode import config - -host = "http://www.canalporno.com" - - -def mainlist(item): - logger.info() - itemlist = [] - itemlist.append(item.clone(action="findvideos", title="Útimos videos", url=host)) - itemlist.append(item.clone(action="categorias", title="Listado Categorias", - url=host + "/categorias")) - itemlist.append(item.clone(action="search", title="Buscar", url=host + "/search/?q=%s")) - return itemlist - - -def search(item, texto): - logger.info() - - try: - item.url = item.url % texto - itemlist = findvideos(item) - return sorted(itemlist, key=lambda it: it.title) - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def findvideos(item): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - - patron = '<img src="([^"]+)".*?alt="([^"]+)".*?<h2><a href="([^"]+)">.*?' \ - '<div class="duracion"><span class="ico-duracion sprite"></span> ([^"]+) min</div>' - matches = scrapertools.find_multiple_matches(data, patron) - for thumbnail, title, url, time in matches: - scrapedtitle = time + " - " + title - scrapedurl = host + url - scrapedthumbnail = thumbnail - itemlist.append(item.clone(action="play", title=scrapedtitle, url=scrapedurl, - thumbnail=scrapedthumbnail)) - - patron = '<div class="paginacion">.*?<span class="selected">.*?<a href="([^"]+)">([^"]+)</a>' - matches = scrapertools.find_multiple_matches(data, patron) - for url, title in matches: - url = host + url - title = "Página %s" % title - itemlist.append(item.clone(action="findvideos", title=title, url=url)) - - return itemlist - - -def categorias(item): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - bloque = scrapertools.find_single_match(data, '<ul class="ordenar-por ordenar-por-categoria">' - '(.*?)<\/ul>') - - #patron = '<div class="muestra-categorias">.*?<a class="thumb" href="([^"]+)".*?<img class="categorias" src="([^"]+)".*?<div class="nombre">([^"]+)</div>' - patron = "<li><a href='([^']+)'\s?title='([^']+)'>.*?<\/a><\/li>" - matches = scrapertools.find_multiple_matches(bloque, patron) - for url, title in matches: - url = host + url - #thumbnail = "http:" + thumbnail - itemlist.append(item.clone(action="findvideos", title=title, url=url)) - - return itemlist - - -def play(item): - logger.info() - itemlist = [] - - data = httptools.downloadpage(item.url).data - url = scrapertools.find_single_match(data, '<source src="([^"]+)"') - itemlist.append(item.clone(url=url, server="directo")) - - return itemlist diff --git a/channels/casacinema.json b/channels/casacinema.json index c964ad15..4532df5d 100644 --- a/channels/casacinema.json +++ b/channels/casacinema.json @@ -1,70 +1,12 @@ { "id": "casacinema", "name": "Casacinema", - "language": ["ita"], + "language": ["ita", "sub-ita"], "active": true, "adult": false, - "thumbnail": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/casacinema.png", - "banner": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/casacinema.png", - "categories": ["tvshow", "movie"], + "thumbnail": "casacinema.png", + "banner": "casacinema.png", + "categories": ["tvshow", "movie","vos"], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } ] } diff --git a/channels/casacinema.py b/channels/casacinema.py index 5c742def..564d5a81 100644 --- a/channels/casacinema.py +++ b/channels/casacinema.py @@ -1,340 +1,209 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Kodi on Demand - Kodi Addon -# Canale per casacinema +# Canale per 'casacinema' # ------------------------------------------------------------ +""" + + Problemi noti che non superano il test del canale: + - Nella ricerca globale non sono presenti le voci: + - "Aggiungi in videoteca" + - "Scarica film/serie" + presenti però quando si entra nella pagina + + Avvisi: + + + Novità: + - Film, SerieTv + + Ulteriori info: + +""" import re -import urlparse +from core import support +from platformcode import config -from channelselector import thumb, get_thumb -from core import scrapertools, scrapertoolsV2, httptools, tmdb, support +# in caso di necessità +from core import scrapertoolsV2, httptools from core.item import Item -from platformcode import logger, config -from specials import autoplay + +##### fine import __channel__ = "casacinema" host = config.get_channel_url(__channel__) -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() +headers = [['Referer', host]] + list_servers = ['verystream', 'openload', 'wstream', 'speedvideo'] list_quality = ['HD', 'SD'] -__comprueba_enlaces__ = config.get_setting('comprueba_enlaces', 'casacinema') -__comprueba_enlaces_num__ = config.get_setting('comprueba_enlaces_num', 'casacinema') - -headers = [['Referer', '%s/genere/serie-tv' % host]] - - +@support.menu def mainlist(item): - logger.info("kod.casacinema mainlist") + support.log(item) +## support.dbg() - autoplay.init(item.channel, list_servers, list_quality) + film = ['/category/film', + ('Generi', ['', 'genres', 'genres']), + ('Sub-ITA', ['/category/sub-ita/', 'peliculas', 'sub']) + ] - itemlist = [Item(channel=item.channel, - title="[B]Film[/B]", - action="peliculas", - extra="movie", - url="%s/genere/film" % host), - Item(channel=item.channel, - title="[B]Film - HD[/B]", - action="peliculas", - extra="movie", - url="%s/?s=[HD]" % host), - Item(channel=item.channel, - title="[B] > Categorie[/B]", - action="categorias", - extra="movie", - url="%s/genere/film" % host), - Item(channel=item.channel, - title="[B]Film Sub - Ita[/B]", - action="peliculas", - extra="movie", - url="%s/genere/sub-ita" % host), - Item(channel=item.channel, - title="[COLOR blue]Cerca Film...[/COLOR]", - action="search", - extra="movie",), - Item(channel=item.channel, - title="[B]Serie TV[/B]", - extra="tvshow", - action="peliculas_tv", - url="%s/genere/serie-tv" % host), - Item(channel=item.channel, - title="[COLOR blue]Cerca Serie TV...[/COLOR]", - action="search", - extra="tvshow")] + tvshow = ['/category/serie-tv', + ('Novità', ['/aggiornamenti-serie-tv', 'peliculas', '']), + ] - - autoplay.show_option(item.channel, itemlist) + search = '' - # auto thumb - itemlist=thumb(itemlist) + return locals() - return itemlist +@support.scrape +def peliculas(item): + support.log(item) +## support.dbg() # decommentare per attivare web_pdb + if item.contentType == 'movie': + action = 'findvideos' + elif item.contentType == 'tvshow': + action = 'episodios' + pagination = '' + else: + # è una ricerca + action = 'select' + blacklist = [''] + + patron = r'<li><a href="(?P<url>[^"]+)"[^=]+="(?P<thumb>[^"]+)"><div> <div[^>]+>(?P<title>.*?)[ ]?(?:\[(?P<quality1>HD)\])?[ ]?(?:\(|\[)?(?P<lang>Sub-ITA)?(?:\)|\])?[ ]?(?:\[(?P<quality>.+?)\])?[ ]?(?:\((?P<year>\d+)\))?<(?:[^>]+>.+?(?:title="Nuovi episodi">(?P<episode>\d+x\d+)[ ]?(?P<lang2>Sub-Ita)?|title="IMDb">(?P<rating>[^<]+)))?' + patronBlock = r'<h1>.+?</h1>(?P<block>.*?)<aside>' + patronNext = '<a href="([^"]+)" >Pagina' + + def itemHook(item): + if item.quality1: + item.quality = item.quality1 + item.title += support.typo(item.quality, '_ [] color kod') + if item.lang2: + item.contentLanguage = item.lang2 + item.title += support.typo(item.lang2, '_ [] color kod') + if item.args == 'novita': + item.title = item.title + return item + +## debug = True # True per testare le regex sul sito + return locals() + +@support.scrape +def episodios(item): + support.log(item) + #dbg + if item.data1: + data = item.data1 + action = 'findvideos' + item.contentType = 'tvshow' + blacklist = [''] + patron = r'(?P<episode>\d+(?:×|×)?\d+\-\d+|\d+(?:×|×)\d+)[;]?(?:(?P<title>[^<]+)<(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:<br />|</p>)' + patronBlock = r'<strong>(?P<block>(?:.+?Stagione*.+?(?P<lang>[Ii][Tt][Aa]|[Ss][Uu][Bb][\-]?[iI][tT][aA]))?(?:.+?|</strong>)(/?:</span>)?</p>.*?</p>)' + +## debug = True + return locals() + +# Questa def è utilizzata per generare il menu 'Generi' del canale +# per genere, per anno, per lettera, per qualità ecc ecc +@support.scrape +def genres(item): + support.log(item) + #dbg + + action = 'peliculas' + blacklist = ['PRIME VISIONI', 'ULTIME SERIE TV', 'ULTIMI FILM'] + patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a></li>' + patronBlock = r'<div class="container home-cats">(?P<block>.*?)<div class="clear">' + + #debug = True + return locals() + +def select(item): + support.log('select --->', item) +## debug = True + #support.dbg() + data = httptools.downloadpage(item.url, headers=headers).data + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + if 'continua con il video' in data.lower(): +## block = scrapertoolsV2.find_single_match(data, r'<div class="col-md-8 bg-white rounded-left p-5"><div>(.*?)<div style="margin-left: 0.5%; color: #FFF;">') +## if re.findall('rel="category tag">serie', data, re.IGNORECASE): + support.log('select = ### è un film ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + #args='serie', + contentType='movie', + data1 = data + )) + else: + support.log('select = ### è una serie ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + #args='serie', + contentType='tvshow', + data1 = data + )) + +############## Fondo Pagina + +def search(item, text): + support.log('search ->', item) + itemlist = [] + text = text.replace(' ', '+') + item.url = host + '/?s=' + text + item.args = 'search' + try: + item.contentType = 'episode' # non fa uscire le voci nel context menu + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + support.log('search log:', line) + return [] def newest(categoria): - logger.info("[casacinema.py] newest" + categoria) + support.log('newest ->', categoria) itemlist = [] item = Item() + try: - if categoria == "film": - item.url = host + '/genere/film' - item.extra = "movie" - item.action = "peliculas" - itemlist = peliculas(item) + if categoria == 'series': + item.contentType = 'tvshow' + item.url = host+'/aggiornamenti-serie-tv' + item.args = 'novita' + else: + item.contentType = 'movie' + item.url = host+'/category/film' - if itemlist[-1].action == "peliculas": - itemlist.pop() + item.action = 'peliculas' + itemlist = peliculas(item) - # Continua la ricerca in caso di errore + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.log('newest log: ', {0}.format(line)) return [] return itemlist - -def search(item, texto): - logger.info("[casacinema.py] " + item.url + " search " + texto) - - item.url = host + "/?s=" + texto - - try: - if item.extra == "tvshow": - return peliculas_tv(item) - if item.extra == "movie": - return peliculas(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def peliculas(item): - logger.info("kod.casacinema peliculas") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - logger.info('DATA=' +data) - - # Estrae i contenuti - patron = '<li><a href="([^"]+)"[^=]+="([^"]+)"><div>\s*<div[^>]+>(.*?)<' - - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - title = scrapertools.decodeHtmlentities(scrapedtitle) - cleantitle = re.sub(r'[-–]*\s*[Ii]l [Ff]ilm\s*[-–]*?', '', title).strip() - cleantitle = cleantitle.replace('[HD]', '').strip() - - year = scrapertools.find_single_match(title, r'\((\d{4})\)') - infolabels = {} - if year: - cleantitle = cleantitle.replace("(%s)" % year, '').strip() - infolabels['year'] = year - - scrapedplot = "" - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="movie", - title=title, - text_color="azure", - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=cleantitle, - show=cleantitle, - plot=scrapedplot, - infoLabels=infolabels, - extra=item.extra, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - ## Paginación - next_page = scrapertools.find_single_match(data, '<li><a href="([^"]+)".*?>Pagina') - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="peliculas", - title="[COLOR blue]" + config.get_localized_string(30992) + " >[/COLOR]", - url=next_page, - extra=item.extra, - thumbnail=get_thumb('next.png'))) - - return itemlist - - -def peliculas_tv(item): - logger.info("kod.casacinema peliculas") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - - # Estrae i contenuti - patron = '<li><a href="([^"]+)"[^=]+="([^"]+)"><div>\s*<div[^>]+>(.*?)<' - - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - title = scrapertools.decodeHtmlentities(scrapedtitle) - cleantitle = re.sub(r'[-–]*\s*[Ss]erie [Tt]v\s*[-–]*?', '', title).strip() - cleantitle = cleantitle.replace('[HD]', '').replace('[SD]', '').strip() - - year = scrapertools.find_single_match(title, r'\((\d{4})\)') - infolabels = {} - if year: - cleantitle = cleantitle.replace("(%s)" % year, '').strip() - infolabels['year'] = year - - scrapedplot = "" - itemlist.append( - Item(channel=item.channel, - action="episodios", - contentType="tvshow", - title=title, - text_color="azure", - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=cleantitle, - show=cleantitle, - plot=scrapedplot, - infoLabels=infolabels, - extra=item.extra, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - ## Paginación - next_page = scrapertools.find_single_match(data, '<li><a href="([^"]+)">Pagina') ### <- Regex rimosso spazio - precedente <li><a href="([^"]+)" >Pagina - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="peliculas_tv", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - extra=item.extra, - thumbnail=get_thumb('next.png'))) - - return itemlist - -def categorias(item): - logger.info("kod.casacinema categorias") - - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - # Narrow search by selecting only the combo - bloque = scrapertools.find_single_match(data, 'Categorie(.*?)</ul>') - - # The categories are the options for the combo - patron = '<a href="(.*?)">(.*?)</a></li>' - matches = re.compile(patron, re.DOTALL).findall(bloque) - - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item(channel=item.channel, - action="peliculas", - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - extra=item.extra, - url=urlparse.urljoin(host, scrapedurl))) - - return itemlist - - -def episodios(item): - def load_episodios(html, item, itemlist, lang_title): - patron = '.*?<a href="[^"]+"[^o]+ofollow[^>]+>[^<]+</a><(?:b|/)[^>]+>' - matches = re.compile(patron).findall(html) - for data in matches: - # Estrae i contenuti - scrapedtitle = scrapertoolsV2.htmlclean(re.sub(r'(<a [^>]+>)*(<\/a>.*)*(Speedvideo)*', '', data)).strip() - if scrapedtitle != 'Categorie': - scrapedtitle = scrapedtitle.replace('×', 'x') - scrapedtitle = scrapedtitle.replace('×', 'x') - scrapedtitle = scrapedtitle.replace(';', '') - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title="[COLOR azure]%s[/COLOR]" % (scrapedtitle + " (" + lang_title + ")"), - url=data, - thumbnail=item.thumbnail, - extra=item.extra, - fulltitle=scrapedtitle + " (" + lang_title + ")" + ' - ' + item.show, - show=item.show)) - - logger.info("[casacinema.py] episodios") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url).data - data = scrapertools.decodeHtmlentities(data) - data = scrapertools.find_single_match(data, '<p>(?:<strong>|)(.*?)<div id="disqus_thread">') - - lang_titles = [] - starts = [] - patron = r"Stagione.*?(?:ITA|\d+)" - matches = re.compile(patron, re.IGNORECASE).finditer(data) - for match in matches: - season_title = match.group() - if season_title != '': - lang_titles.append('SUB ITA' if 'SUB' in season_title.upper() else 'ITA') - starts.append(match.end()) - - i = 1 - len_lang_titles = len(lang_titles) - - while i <= len_lang_titles: - inizio = starts[i - 1] - fine = starts[i] if i < len_lang_titles else -1 - - html = data[inizio:fine] - lang_title = lang_titles[i - 1] - - load_episodios(html, item, itemlist, lang_title) - - i += 1 - - if config.get_videolibrary_support() and len(itemlist) != 0: - itemlist.append( - Item(channel=item.channel, - title="[COLOR lightblue]%s[/COLOR]" % config.get_localized_string(30161), - url=item.url, - action="add_serie_to_library", - extra="episodios" + "###" + item.extra, - show=item.show)) - - return itemlist - - def findvideos(item): - logger.info("kod.casacinema findvideos") - - data = item.url if item.extra == "tvshow" else httptools.downloadpage(item.url, headers=headers).data - - html = httptools.downloadpage(data).data - patron = '"http:\/\/shrink-service\.it\/[^\/]+\/[^\/]+\/([^"]+)"' - matches = re.compile(patron, re.DOTALL).findall(html) - - for url in matches: - if url is not None: - data = data + support.log('findvideos ->', item) + itemlist = [] + if item.contentType != 'movie': + return support.server(item, item.url) + else: + block = r'<div class="col-md-10">(.+?)<div class="swappable" id="links">' + patron = r'SRC="([^"]+)"' + links = re.findall(patron, block, re.IGNORECASE) + if "#" in links: + links = link.replace('#', 'speedvideo.net') + return support.server(item, links) else: - continue - - return support.server(item, data=data) - + return support.server(item) diff --git a/channels/casacinemaInfo.json b/channels/casacinemaInfo.json index dbe6737e..0bb89bb4 100644 --- a/channels/casacinemaInfo.json +++ b/channels/casacinemaInfo.json @@ -1,36 +1,11 @@ { "id": "casacinemaInfo", - "name": "La casa del cinema", - "language": ["ita"], + "name": "La Casa del Cinema", + "language": ["ita", "sub-ita"], "active": true, "adult": false, - "thumbnail": "", - "banner": "", - "categories": ["movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "thumbnail": "casacinemainfo.png", + "banner": "casacinemainfo.png", + "categories": ["movie", "vos"], + "settings": [] } diff --git a/channels/casacinemaInfo.py b/channels/casacinemaInfo.py index 9c54779e..d94c55a4 100644 --- a/channels/casacinemaInfo.py +++ b/channels/casacinemaInfo.py @@ -1,151 +1,130 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per casacinema +# Canale per 'casacinemaInfo' # ------------------------------------------------------------ +""" -from core import scrapertoolsV2, httptools, servertools, tmdb, support + Problemi noti che non superano il test del canale: + - + + Avvisi: + - Sub-ita non è nel titolo, lascia il puntatore sulla locandina + per visualizzare il titolo completo! + + Novità: + - Film + Ulteriori info: + + +""" + +from core import support +from core import scrapertoolsV2, httptools from core.item import Item -from platformcode import logger, config -from specials import autoplay -__channel__ = "casacinemainfo" -host = config.get_channel_url(__channel__) -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['verystream', 'openload', 'wstream', 'speedvideo'] -list_quality = ['1080p', '720', '480p', '360p'] +host = "" +headers = "" -checklinks = config.get_setting('checklinks', 'casacinema') -checklinks_number = config.get_setting('checklinks_number', 'casacinema') +def findhost(): + global host, headers + data = httptools.downloadpage('https://casacinema.nuovo.link').data + host = scrapertoolsV2.find_single_match(data, r'<div class="elementor-widget-container"><div class="elementor-button-wrapper"> <a href="([^"]+)"') + headers = [['Referer', host]] + if host.endswith('/'): + host = host[:-1] +list_servers = ['supervideo', 'streamcherry','rapidvideo', 'streamango', 'openload'] +list_quality = ['default', 'HD', '3D', '4K', 'DVD', 'SD'] + +@support.menu def mainlist(item): - logger.info("alfa.casacinema mainlist") + support.log(item) + findhost() + film = ['', + ('Al Cinema', ['/category/in-sala/', 'peliculas', '']), + ('Novità', ['/category/nuove-uscite/', 'peliculas', '']), + ('Generi', ['', 'genres', 'genres']), + ('Sub-ITA', ['/category/sub-ita/', 'peliculas', '']) + ] - autoplay.init(item.channel, list_servers, list_quality) - - itemlist = [Item(channel=item.channel, - title="Film", - action="peliculas", - extra="movie", - url=host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="In sala", - action="peliculas", - extra="movie", - url="%s/category/in-sala/" % host, - thumbnail="http://jcrent.com/apple%20tv%20final/HD.png"), - Item(channel=item.channel, - title="Novità", - action="peliculas", - extra="movie", - url="%s/category/nuove-uscite/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="Sub - Ita", - action="peliculas", - extra="movie", - url="%s/category/sub-ita/" % host, - thumbnail="http://i.imgur.com/qUENzxl.png"), - Item(channel=item.channel, - title="[COLOR yellow]Cerca...[/COLOR]", - action="search", - extra="movie", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search")] - - - autoplay.show_option(item.channel, itemlist) - - return itemlist - - -def search(item, texto): - logger.info("[casacinemaInfo.py] " + item.url + " search " + texto) - - item.url = host + "/?s=" + texto - data = httptools.downloadpage(item.url).data - - itemlist = [] - - patron = '<li class="col-md-12 itemlist">.*?<a href="([^"]+)" title="([^"]+)".*?<img src="([^"]+)".*?Film dell\\\'anno: ([0-9]{4}).*?<p class="text-list">([^<>]+)</p>' - matches = scrapertoolsV2.find_multiple_matches(data, patron) - for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedyear, scrapedplot in matches: - title = scrapertoolsV2.decodeHtmlentities(scrapedtitle) - cleantitle = title.replace('[Sub-ITA]', '').strip() - - infoLabels = {"plot": scrapertoolsV2.decodeHtmlentities(scrapedplot), "year": scrapedyear} - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="movie", - title=title, - url=scrapedurl, - thumbnail=scrapedthumbnail, - infoLabels=infoLabels, - fulltitle=cleantitle)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist + return locals() +@support.scrape def peliculas(item): - logger.info("[casacinemaInfo.py] peliculas") + support.log(item) + #support.dbg() # decommentare per attivare web_pdb + #findhost() + + blacklist = [''] + if item.args != 'search': + patron = r'<div class="col-mt-5 postsh">[^<>]+<div class="poster-media-card">[^<>]+<a href="(?P<url>[^"]+)" title="(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA)\])?".*?<img(?:.+?)?src="(?P<thumb>[^"]+)"' + patronBlock = r'<div class="showpost4 posthome">(?P<block>.*?)</section>' + else: + patron = r'<li class="col-md-12 itemlist">.*?<a href="(?P<url>[^"]+)" title="(?P<title>[^"]+)".*?<img src="(?P<thumb>[^"]+)".*?Film dell"anno: (?P<year>\d{4})(?:[\d\-]+)?</p> <p class="text-list">(?P<plot>[^<>]+)</p>' + patronBlock = r'<ul class="search-results-content infinite">(?P<block>.*?)</section>' + patronNext = '<a href="([^"]+)"\s+?><i class="glyphicon glyphicon-chevron-right"' + + #support.regexDbg(item, patronBlock, headers) + #debug = True + return locals() + + +@support.scrape +def genres(item): + support.log(item) + #support.dbg() + + action = 'peliculas' + blacklist = [''] + patron = r'href="(?P<url>[^"]+)">(?P<title>[^<]+)<' + patronBlock = r'</span>Generi</h3>(?P<block>.*?)<div class="clear"></div>' + +## debug = True + return locals() + + +def search(item, text): + support.log('search', item) + findhost() itemlist = [] + text = text.replace(' ', '+') + item.args = 'search' + item.url = host+'/?s=%s' % (text) + try: + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + log('search log:', line) + return [] - # Carica la pagina - data = httptools.downloadpage(item.url).data +def newest(categoria): + support.log('newest ->', categoria) + findhost() + itemlist = [] + item = Item() + + try: + if categoria == 'peliculas': + item.url = host + item.action = 'peliculas' + itemlist = peliculas(item) - # Estrae i contenuti - - patron = '<div class="col-mt-5 postsh">[^<>]+<div class="poster-media-card">[^<>]+<a href="([^"]+)" title="([^"]+)".*?<img src="([^"]+)"' - - matches = scrapertoolsV2.find_multiple_matches(data, patron) - - for scrapedurl, scrapedtitle, scrapedthumbnail in matches: - title = scrapertoolsV2.decodeHtmlentities(scrapedtitle) - cleantitle = title.replace('[Sub-ITA]', '').strip() - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="movie", - title=title, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=cleantitle)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - ## Paginación - next_page = scrapertoolsV2.find_single_match(data, '<a href="([^"]+)"><i class="glyphicon glyphicon-chevron-right"') ### <- Regex rimosso spazio - precedente <li><a href="([^"]+)" >Pagina -> Continua. riga 221 - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="peliculas", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - extra=item.extra, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png")) + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + log('newest log: ', {0}.format(line)) + return [] return itemlist - def findvideos(item): - logger.info("[casacinemaInfo.py] findvideos") - - itemlist = support.hdpass_get_servers(item) - - # Requerido para Filtrar enlaces - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # Requerido para AutoPlay - - autoplay.start(itemlist, item) - return itemlist + support.log('findvideos ->', item) + return support.hdpass_get_servers(item) diff --git a/channels/cb01anime.json b/channels/cb01anime.json index 26183875..24fd0c8d 100644 --- a/channels/cb01anime.json +++ b/channels/cb01anime.json @@ -1,36 +1,11 @@ { "id": "cb01anime", "name": "Cb01anime", - "language": ["ita"], + "language": ["ita", "vos", "sub-ita"], "active": true, "adult": false, - "thumbnail": "http://i.imgur.com/bHoUMo2.png", - "banner": "http://i.imgur.com/bHoUMo2.png", + "thumbnail": "cb01anime.png", + "banner": "cb01anime.png", "categories": ["anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "settings": [] } diff --git a/channels/cb01anime.py b/channels/cb01anime.py index c3b62c31..b996eb58 100644 --- a/channels/cb01anime.py +++ b/channels/cb01anime.py @@ -1,276 +1,129 @@ # -*- coding: utf-8 -*- -# Ringraziamo Icarus crew # ------------------------------------------------------------ # XBMC Plugin # Canale per cineblog01 - anime # ------------------------------------------------------------ -import re -from core import httptools, scrapertools, servertools, tmdb -from core.item import Item -from platformcode import logger, config +from core import support __channel__ = "cb01anime" -host = config.get_channel_url(__channel__) -#esclusione degli articoli 'di servizio' -blacklist = ['AVVISO IMPORTANTE – CB01.ROCKS', 'Lista Alfabetica Completa Anime/Cartoon', 'CB01.UNO ▶ TROVA L’INDIRIZZO UFFICIALE'] +host = support.config.get_channel_url(__channel__) + '/anime' -# ----------------------------------------------------------------- +Blacklist = ['AVVISO IMPORTANTE – CB01.ROCKS', 'Lista Alfabetica Completa Anime/Cartoon', 'CB01.UNO ▶ TROVA L’INDIRIZZO UFFICIALE','Lista Richieste Up & Re-Up'] +list_servers = ['verystream', 'openload', 'streamango', 'thevideome'] +list_quality = ['1080p', '720p', '480p', '360'] + +checklinks = support.config.get_setting('checklinks', __channel__) +checklinks_number = support.config.get_setting('checklinks_number', __channel__) +headers = [['Referer', host]] + +@support.menu def mainlist(item): - logger.info("[cb01anime.py] mainlist") - - # Main options - itemlist = [Item(channel=item.channel, - action="list_titles", - title="[COLOR azure]Anime - Novita'[/COLOR]", - url=host + '/anime', - thumbnail="http://orig09.deviantart.net/df5a/f/2014/169/2/a/fist_of_the_north_star_folder_icon_by_minacsky_saya-d7mq8c8.png"), - Item(channel=item.channel, - action="genere", - title="[COLOR azure]Anime - Per Genere[/COLOR]", - url=host + '/anime', - thumbnail="http://xbmc-repo-ackbarr.googlecode.com/svn/trunk/dev/skin.cirrus%20extended%20v2/extras/moviegenres/Genres.png"), - Item(channel=item.channel, - action="alfabetico", - title="[COLOR azure]Anime - Per Lettera A-Z[/COLOR]", - url=host + '/anime', - thumbnail="http://i.imgur.com/IjCmx5r.png"), - Item(channel=item.channel, - action="listacompleta", - title="[COLOR azure]Anime - Lista Completa[/COLOR]", - url="%s/anime/lista-completa-anime-cartoon/" % host, - thumbnail="http://i.imgur.com/IjCmx5r.png"), - Item(channel=item.channel, - action="search", - title="[COLOR yellow]Cerca Anime[/COLOR]", - extra="anime", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search")] - - return itemlist + anime = [('Genere',['','menu', '2']), + ('Per Lettera',['','menu', '1']), + ('Per Anno',['','menu', '3']), + ('Ultimi Anime Aggiornati',['','peliculas', 'newest'])] + return locals() -# ================================================================= - -# ----------------------------------------------------------------- -def genere(item): - logger.info("[cb01anime.py] genere") - - return build_itemlist(item, '<select name="select2"(.*?)</select>', '<option value="([^"]+)">([^<]+)</option>', - "list_titles") +@support.scrape +def menu(item): + blacklist = ['Anime per Genere', 'Anime per Anno', 'Anime per Lettera'] + patronBlock = r'<select name="select%s"(?P<block>.*?)</select>' % item.args + patronMenu = r'<option value="(?P<url>[^"]+)">(?P<title>[^<]+)</option>' + action = 'peliculas' + return locals() -def alfabetico(item): - logger.info("[cb01anime.py] alfabetico") - - return build_itemlist(item, '<option value=\'-1\'>Anime per Lettera</option>(.*?)</select>', - '<option value="([^"]+)">\(([^<]+)\)</option>', "list_titles") - - -def listacompleta(item): - logger.info("[cb01anime.py] listacompleta") - - return build_itemlist(item, - '<a href="#char_5a" title="Go to the letter Z">Z</a></span></div>(.*?)</ul></div><div style="clear:both;"></div></div>', - '<li><a href="' + host + '/([^"]+)"><span class="head">([^<]+)</span></a></li>', "episodios") - - -def build_itemlist(item, re_bloque, re_patron, iaction): - itemlist = [] - - data = httptools.downloadpage(item.url).data - - # Narrow search by selecting only the combo - bloque = scrapertools.find_single_match(data, re_bloque) - - # The categories are the options for the combo - matches = re.compile(re_patron, re.DOTALL).findall(bloque) - scrapertools.printMatches(matches) - - for url, titulo in matches: - itemlist.append( - Item(channel=item.channel, - action=iaction, - contentType="tvshow", - title=titulo, - fulltitle=titulo, - text_color="azure", - show=titulo, - url=host + url, - plot="")) - - return itemlist - - -# ================================================================= - - -# ----------------------------------------------------------------- def search(item, texto): - logger.info("[cb01anime.py] " + item.url + " search " + texto) + support.log(texto) + item.url = host + "/?s=" + texto + return peliculas(item) - item.url = host + "/anime/?s=" + texto - - return list_titles(item) - - -# ================================================================= - -# ----------------------------------------------------------------- -def list_titles(item): - logger.info("[cb01anime.py] mainlist") +def newest(categoria): + support.log(categoria) itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url).data - - # Estrae i contenuti - patronvideos = r'<div class="span4">\s*<a href="([^"]+)">' - patronvideos += r'<img src="([^"]+)"[^>]+><\/a>[^>]+>[^>]+>' - patronvideos += r'[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(.*?)<\/a>' - matches = re.compile(patronvideos, re.DOTALL).findall(data) - - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - scrapedtitle = scrapertools.htmlclean(scrapedtitle).strip() - if not scrapedtitle in blacklist: - if 'lista richieste' in scrapedtitle.lower(): continue - - patron = r'(?:\[[Ff][Uu][Ll]{2}\s*[Ii][Tt][Aa]\]|\[[Ss][Uu][Bb]\s*[Ii][Tt][Aa]\])' - cleantitle = re.sub(patron, '', scrapedtitle).strip() - - ## ------------------------------------------------ - scrapedthumbnail = httptools.get_url_headers(scrapedthumbnail) - ## ------------------------------------------------ - - # Añade al listado de XBMC - itemlist.append( - Item(channel=item.channel, - action="listacompleta" if "Lista Alfabetica Completa Anime/Cartoon" in scrapedtitle else "episodios", - contentType="tvshow", - title=scrapedtitle, - fulltitle=cleantitle, - text_color="azure", - show=cleantitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - viewmode="movie_with_plot")) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Put the next page mark + item = support.Item() try: - next_page = scrapertools.find_single_match(data, "<link rel='next' href='([^']+)'") - itemlist.append( - Item(channel=item.channel, - action="list_titles", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png")) + if categoria == "anime": + item.url = host + item.args = 'newest' + itemlist = peliculas(item) + # Continua la ricerca in caso di errore except: - pass + import sys + for line in sys.exc_info(): + support.logger.error("{0}".format(line)) + return [] return itemlist +@support.scrape +def peliculas(item): + blacklist = Blacklist + item.contentType = 'tvshow' + if item.args == 'newest': + data = support.match(item)[1] + patron = r'<div id="blockvids"><ul><li><a href="(?P<url>[^"]+)"[^>]+><img src="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^\[]+)\[(?P<lang>[^\]]+)\]' + else: + patron = r'<div class="span4">\s*<a href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)"[^>]+><\/a>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+> <h1>(?P<title>[^<\[]+)(?:\[(?P<lang>[^\]]+)\])?</h1></a>.*?-->(?:.*?<br />)?\s*(?P<plot>[^<]+)' + patronNext = r'<link rel="next" href="([^"]+)"' + action = 'check' + return locals() -# ================================================================= +def check(item): + item.url = support.match(item,r'(?:<p>|/>)(.*?)(?:<br|</td>|</p>)', r'Streaming:(.*?)</tr>')[0] + if 'Episodio' in str(item.url): + item.contentType = 'tvshow' + return episodios(item) + else: + item.contentType = 'movie' + return findvideos(item) - -# ----------------------------------------------------------------- +@support.scrape def episodios(item): - logger.info("[cb01anime.py] episodios") + support.log('EPISODIOS ', item.data) + data = '' + matches = item.data + season = 1 + s = 1 + e = 0 + sp = 0 + for match in item.url: + if 'stagione' in match.lower(): + find_season = support.match(match, r'Stagione\s*(\d+)')[0] + season = int(find_season[0]) if find_season else season + 1 if 'prima' not in match.lower() else season + else: + try: title = support.match(match,'<a[^>]+>([^<]+)</a>')[0][0] + except: title = '' + if title: + if 'episodio' in title.lower(): + ep = support.match(match, r'Episodio ((?:\d+.\d|\d+|\D+))')[0][0] + check = ep.isdigit() + if check or '.' in ep: + if '.' in ep: + sp += 1 + title = '0' + 'x' + str(sp).zfill(2) + ' - ' + title + else: + ep = int(ep) + if season > s and ep > 1: + s += 1 + e = ep - 1 + title = str(season) + 'x' + str(ep-e).zfill(2) + ' - ' + title + data += title + '|' + match + '\n' + else: + title += ' #movie' + data += title + '|' + match + '\n' + def itemHook(item): + if '#movie' in item.title: + item.contentType='movie' + item.title = item.title.replace(' #movie','') + return item - itemlist = [] + patron = r'(?P<title>[^\|]+)\|(?P<url>[^\n]+)\n' + action = 'findvideos' + return locals() - # Carica la pagina - data = httptools.downloadpage(item.url).data - # data = scrapertools.decodeHtmlentities(data) - - patron1 = '(?:<p>|<td bgcolor="#ECEAE1">)<span class="txt_dow">(.*?)(?:</p>)?(?:\s*</span>)?\s*</td>' - patron2 = '<a.*?href="([^"]+)"[^>]*>([^<]+)</a>' - matches1 = re.compile(patron1, re.DOTALL).findall(data) - if len(matches1) > 0: - for match1 in re.split('<br />|<p>', matches1[0]): - if len(match1) > 0: - # Estrae i contenuti - titulo = None - scrapedurl = '' - matches2 = re.compile(patron2, re.DOTALL).finditer(match1) - for match2 in matches2: - if titulo is None: - titulo = match2.group(2) - scrapedurl += match2.group(1) + '#' + match2.group(2) + '|' - if titulo is not None: - title = item.title + " " + titulo - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title=title, - extra=scrapedurl, - fulltitle=item.fulltitle, - show=item.show)) - - if config.get_videolibrary_support() and len(itemlist) != 0: - itemlist.append( - Item(channel=item.channel, - title="[COLOR lightblue]%s[/COLOR]" % config.get_localized_string(30161), - url=item.url, - action="add_serie_to_library", - extra="episodios", - show=item.show)) - - return itemlist - - -# ================================================================= - - -# ----------------------------------------------------------------- def findvideos(item): - logger.info("[cb01anime.py] findvideos") - - itemlist = [] - - for match in item.extra.split(r'|'): - match_split = match.split(r'#') - scrapedurl = match_split[0] - if len(scrapedurl) > 0: - scrapedtitle = match_split[1] - title = item.title + " [COLOR blue][" + scrapedtitle + "][/COLOR]" - itemlist.append( - Item(channel=item.channel, - action="play", - title=title, - url=scrapedurl, - fulltitle=item.fulltitle, - show=item.show, - ontentType=item.contentType, - folder=False)) - - return itemlist - - -# ================================================================= - - -# ----------------------------------------------------------------- -def play(item): - logger.info("[cb01anime.py] play") - - if '/goto/' in item.url: - item.url = item.url.split('/goto/')[-1].decode('base64') - - data = item.url - - logger.debug("##### Play data ##\n%s\n##" % data) - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = item.show - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - videoitem.contentType = item.contentType - - return itemlist + return support.server(item, item.url) diff --git a/channels/cineblog01.json b/channels/cineblog01.json index b2110524..a758b139 100644 --- a/channels/cineblog01.json +++ b/channels/cineblog01.json @@ -1,65 +1,11 @@ { "id": "cineblog01", "name": "CB01", - "language": ["ita"], + "language": ["ita", "sub-ita"], "active": true, "adult": false, "thumbnail": "cb01.png", "banner": "cb01.png", - "categories": ["tvshow", "movie", "vosi"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero di link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "No filtrar", - "Italiano" - ] - } - ] -} + "categories": ["tvshow", "movie", "vos"], + "settings": [] +} \ No newline at end of file diff --git a/channels/cineblog01.py b/channels/cineblog01.py index 19358108..2b9a2c8b 100644 --- a/channels/cineblog01.py +++ b/channels/cineblog01.py @@ -9,9 +9,8 @@ from core import scrapertoolsV2, httptools, servertools, tmdb, support from core.item import Item from lib import unshortenit from platformcode import logger, config -from specials import autoplay -#impostati dinamicamente da getUrl() +#impostati dinamicamente da findhost() host = "" headers = "" @@ -28,76 +27,77 @@ def findhost(): host = permUrl['location'] headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() list_servers = ['verystream', 'openload', 'streamango', 'wstream'] list_quality = ['HD', 'SD', 'default'] checklinks = config.get_setting('checklinks', 'cineblog01') checklinks_number = config.get_setting('checklinks_number', 'cineblog01') -# esclusione degli articoli 'di servizio' -blacklist = ['BENVENUTI', 'Richieste Serie TV', 'CB01.UNO ▶ TROVA L’INDIRIZZO UFFICIALE ', - 'Aggiornamento Quotidiano Serie TV', 'OSCAR 2019 ▶ CB01.UNO: Vota il tuo film preferito! 🎬', - 'Openload: la situazione. Benvenuto Verystream', 'Openload: lo volete ancora?'] - +@support.menu def mainlist(item): findhost() + film = [ + ('HD', ['', 'menu', 'Film HD Streaming']), + ('Generi', ['', 'menu', 'Film per Genere']), + ('Anni', ['', 'menu', 'Film per Anno']), + ('Ultimi aggiunti', ['/lista-film-ultimi-100-film-aggiunti/', 'newest']) + ] + tvshow = ['/serietv/', + ('Per Lettera', ['/serietv/', 'menu', 'Serie-Tv per Lettera']), + ('Per Genere', ['/serietv/', 'menu', 'Serie-Tv per Genere']), + ('Per anno', ['/serietv/', 'menu', 'Serie-Tv per Anno']), + ('Aggiornamento quotidiano', ['/serietv/aggiornamento-quotidiano-serie-tv/', 'newest']) + ] - autoplay.init(item.channel, list_servers, list_quality) - - # Main options - itemlist = [] - support.menu(itemlist, 'Ultimi 100 Film Aggiornati bold', 'last', host + '/lista-film-ultimi-100-film-aggiornati/') - - support.menu(itemlist, 'Film bold', 'peliculas', host) - support.menu(itemlist, 'HD submenu', 'menu', host, args="Film HD Streaming") - support.menu(itemlist, 'Per genere submenu', 'menu', host, args="Film per Genere") - support.menu(itemlist, 'Per anno submenu', 'menu', host, args="Film per Anno") - support.menu(itemlist, 'Cerca film... submenu', 'search', host, args='film') - - support.menu(itemlist, 'Serie TV bold', 'peliculas', host + '/serietv/', contentType='tvshow') - support.menu(itemlist, 'Aggiornamenti serie tv', 'last', host + '/serietv/aggiornamento-quotidiano-serie-tv/', contentType='tvshow') - support.menu(itemlist, 'Per Lettera submenu', 'menu', host + '/serietv/', contentType='tvshow', args="Serie-Tv per Lettera") - support.menu(itemlist, 'Per Genere submenu', 'menu', host + '/serietv/', contentType='tvshow', args="Serie-Tv per Genere") - support.menu(itemlist, 'Per anno submenu', 'menu', host + '/serietv/', contentType='tvshow', args="Serie-Tv per Anno") - support.menu(itemlist, 'Cerca serie... submenu', 'search', host + '/serietv/', contentType='tvshow', args='serie') - - autoplay.show_option(item.channel, itemlist) - - return itemlist + return locals() +@support.scrape def menu(item): findhost() - itemlist= [] - data = httptools.downloadpage(item.url, headers=headers).data - data = re.sub('\n|\t', '', data) - block = scrapertoolsV2.find_single_match(data, item.args + r'<span.*?><\/span>.*?<ul.*?>(.*?)<\/ul>') - support.log('MENU BLOCK= ',block) - patron = r'href="?([^">]+)"?>(.*?)<\/a>' - matches = re.compile(patron, re.DOTALL).findall(block) - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item( - channel=item.channel, - title=scrapedtitle, - contentType=item.contentType, - action='peliculas', - url=host + scrapedurl - ) - ) + patronBlock = item.args + r'<span.*?><\/span>.*?<ul.*?>(?P<block>.*?)<\/ul>' + patronMenu = r'href="?(?P<url>[^">]+)"?>(?P<title>.*?)<\/a>' + action = 'peliculas' - return support.thumb(itemlist) + return locals() + + +@support.scrape +def newest(categoria): + findhost() + # debug = True + patron = r'<a href="?(?P<url>[^">]+)"?>(?P<title>[^<([]+)(?:\[(?P<lang>Sub-ITA|B/N|SUB-ITA)\])?\s*(?:\[(?P<quality>HD|SD|HD/3D)\])?\s*\((?P<year>[0-9]{4})\)<\/a>' + + if type(categoria) != Item: + item = Item() + else: + item = categoria + categoria = 'series' if item.contentType != 'movie' else 'movie' + pagination = 20 + + if categoria == 'series': + item.contentType = 'tvshow' + action = 'episodios' + item.url = host + 'serietv/aggiornamento-quotidiano-serie-tv/' + patronBlock = r'<article class="sequex-post-content">(?P<block>.*?)</article>' + patron = '<a href="(?P<url>[^"]+)".*?>(?P<title>[^<([|]+).*?(?P<lang>ITA|SUB-ITA)?</a' + else: + item.contentType = 'movie' + item.url = host + '/lista-film-ultimi-100-film-aggiunti/' + patronBlock = r'Ultimi 100 film aggiunti:(?P<block>.*?)<\/td>' + # else: + # patronBlock = r'Ultimi 100 film Aggiornati:(?P<block>.*?)<\/td>' + # item = categoria + + return locals() def search(item, text): - support.log(item.url, "search" ,text) - + support.log(item.url, "search", text) try: - item.url = item.url + "/?s=" + text.replace(' ','+') + item.url = item.url + "/?s=" + text.replace(' ', '+') return peliculas(item) # Continua la ricerca in caso di errore @@ -108,129 +108,34 @@ def search(item, text): return [] -def newest(categoria): - findhost() - itemlist = [] - item = Item() - item.contentType = 'movie' - item.url = host + '/lista-film-ultimi-100-film-aggiunti/' - return support.scrape(item, r'<a href=(?:")?([^">]+)(?:")?>([^<([]+)(?:\[B/N\])?\s*(?:\[(Sub-ITA|SUB-ITA)\])?\s*(?:\[([^\[]+)\])?\s*\(([0-9]{4})\)<\/a>', - ['url', 'title', 'quality', 'year'], - patron_block=r'Ultimi 100 film aggiunti:.*?<\/td>') - - -def last(item): - support.log() - - itemlist = [] - infoLabels = {} - quality = '' - PERPAGE = 30 - page = 1 - count = 0 - - if item.page: - page = item.page - - if item.contentType == 'tvshow': - matches = support.match(item, r'<a href="([^">]+)".*?>([^(:(|[)]+)([^<]+)<\/a>', '<article class="sequex-post-content.*?</article>', headers)[0] - else: - matches = support.match(item, r'<a href=([^>]+)>([^(:(|[)]+)([^<]+)<\/a>', r'<strong>Ultimi 100 film Aggiornati:<\/a><\/strong>(.*?)<td>', headers)[0] - - for i, (url, title, info) in enumerate(matches): - if (page - 1) * PERPAGE > i - count: continue - if i - count >= page * PERPAGE: break - add = True - title = title.rstrip() - if item.contentType == 'tvshow': - for i in itemlist: - if i.url == url: # togliamo i doppi - count = count + 1 - add = False - else: - infoLabels['year'] = scrapertoolsV2.find_single_match(info, r'\(([0-9]+)\)') - quality = scrapertoolsV2.find_single_match(info, r'\[([A-Z]+)\]') - - if quality: - longtitle = title + support.typo(quality,'_ [] color kod') - else: - longtitle = title - - if add: - itemlist.append( - Item(channel=item.channel, - action='findvideos' if item.contentType == 'movie' else 'episodios', - contentType=item.contentType, - title=longtitle, - fulltitle=title, - show=title, - quality=quality, - url=url, - infoLabels=infoLabels - ) - ) - support.pagination(itemlist, item, page, PERPAGE) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - - +@support.scrape def peliculas(item): - support.log() - if item.contentType == 'movie' or '/serietv/' not in item.url: - patron = r'<div class="?card-image"?>.*?<img src="?([^" ]+)"? alt.*?<a href="?([^" >]+)(?:\/|")>([^<[(]+)(?:\[([A-Za-z0-9/-]+)])? (?:\(([0-9]{4})\))?.*?<strong>([^<>&–]+).*?DURATA ([0-9]+).*?<br(?: /)?>([^<>]+)' - listGroups = ['thumb', 'url', 'title', 'quality', 'year', 'genre', 'duration', 'plot'] + # esclusione degli articoli 'di servizio' + blacklist = ['BENVENUTI', 'Richieste Serie TV', 'CB01.UNO ▶ TROVA L’INDIRIZZO UFFICIALE ', + 'Aggiornamento Quotidiano Serie TV', 'OSCAR 2019 ▶ CB01.UNO: Vota il tuo film preferito! 🎬', + 'Openload: la situazione. Benvenuto Verystream', 'Openload: lo volete ancora?'] + + if '/serietv/' not in item.url: + patron = r'<div class="?card-image"?>.*?<img src="?(?P<thumb>[^" ]+)"? alt.*?<a href="?(?P<url>[^" >]+)(?:\/|")>(?P<title>[^<[(]+)(?:\[(?P<quality>[A-Za-z0-9/-]+)])? (?:\((?P<year>[0-9]{4})\))?.*?<strong>(?P<genre>[^<>&–]+).*?DURATA (?P<duration>[0-9]+).*?<br(?: /)?>(?P<plot>[^<>]+)' action = 'findvideos' else: - patron = r'div class="card-image">.*?<img src="([^ ]+)" alt.*?<a href="([^ >]+)">([^<[(]+)<\/a>.*?<strong><span style="[^"]+">([^<>0-9(]+)\(([0-9]{4}).*?</(?:p|div)>(.*?)</div' - listGroups = ['thumb', 'url', 'title', 'genre', 'year', 'plot'] + patron = r'div class="card-image">.*?<img src="(?P<thumb>[^ ]+)" alt.*?<a href="(?P<url>[^ >]+)">(?P<title>[^<[(]+)<\/a>.*?(?:<strong><span style="[^"]+">(?P<genre>[^<>0-9(]+)\((?P<year>[0-9]{4}).*?</(?:p|div)>(?P<plot>.*?))?</div' action = 'episodios' + item.contentType = 'tvshow' - return support.scrape(item, patron_block=[r'<div class="?sequex-page-left"?>(.*?)<aside class="?sequex-page-right"?>', - '<div class="?card-image"?>.*?(?=<div class="?card-image"?>|<div class="?rating"?>)'], - patron=patron, listGroups=listGroups, - patronNext='<a class="?page-link"? href="?([^>]+)"?><i class="fa fa-angle-right">', blacklist=blacklist, action=action) + # patronBlock=[r'<div class="?sequex-page-left"?>(?P<block>.*?)<aside class="?sequex-page-right"?>', + # '<div class="?card-image"?>.*?(?=<div class="?card-image"?>|<div class="?rating"?>)'] + patronNext='<a class="?page-link"? href="?([^>]+)"?><i class="fa fa-angle-right">' + + return locals() +@support.scrape def episodios(item): - itemlist = [] + patronBlock = r'(?P<block><div class="sp-head[a-z ]*?" title="Espandi">\s*STAGIONE [0-9]+ - (?P<lang>[^-<]+)(?:- (?P<quality>[^-<]+))?.*?[^<>]*?</div>.*?)<div class="spdiv">\[riduci\]</div>' + patron = '(?:<p>|<strong>)(?P<episode>[0-9]+(?:×|×)[0-9]+)(?P<url>.*?)(?:</p>|<br)' - data = httptools.downloadpage(item.url).data - matches = scrapertoolsV2.find_multiple_matches(data, - r'(<div class="sp-head[a-z ]*?" title="Espandi">[^<>]*?</div>.*?)<div class="spdiv">\[riduci\]</div>') - - for match in matches: - support.log(match) - blocks = scrapertoolsV2.find_multiple_matches(match, '(?:<p>)(.*?)(?:</p>|<br)') - season = scrapertoolsV2.find_single_match(match, r'title="Espandi">.*?STAGIONE\s+\d+([^<>]+)').strip() - - for block in blocks: - episode = scrapertoolsV2.find_single_match(block, r'([0-9]+(?:×|×)[0-9]+)').strip() - seasons_n = scrapertoolsV2.find_single_match(block, r'<strong>STAGIONE\s+\d+([^<>]+)').strip() - - if seasons_n: - season = seasons_n - - if not episode: continue - - season = re.sub(r'–|–', "-", season) - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType='episode', - title="[B]" + episode + "[/B] " + season, - fulltitle=episode + " " + season, - show=episode + " " + season, - url=block, - extra=item.extra, - thumbnail=item.thumbnail, - infoLabels=item.infoLabels - )) - - support.videolibrary(itemlist, item) - - return itemlist + return locals() def findvideos(item): @@ -295,7 +200,7 @@ def findvideos(item): def findvid_serie(item): def load_vid_series(html, item, itemlist, blktxt): logger.info('HTML' + html) - patron = '<a href="([^"]+)"[^=]+="_blank"[^>]+>(.*?)</a>' + patron = r'<a href="([^"]+)"[^=]+="_blank"[^>]+>(?!<!--)(.*?)</a>' # Estrae i contenuti matches = re.compile(patron, re.DOTALL).finditer(html) for match in matches: @@ -378,7 +283,7 @@ def play(item): data, c = unshortenit.unwrap_30x_only(data) else: data = scrapertoolsV2.find_single_match(data, r'<a href="([^"]+)".*?class="btn-wrapper">.*?licca.*?</a>') - + logger.debug("##### play go.php data ##\n%s\n##" % data) else: data = support.swzz_get_url(item) diff --git a/channels/cinemalibero.json b/channels/cinemalibero.json index 0124d1ad..820ef7bb 100644 --- a/channels/cinemalibero.json +++ b/channels/cinemalibero.json @@ -4,83 +4,9 @@ "language": ["ita"], "active": true, "adult": false, - "thumbnail": "https://www.cinemalibero.center/wp-content/themes/Cinemalibero%202.0/images/logo02.png", - "banner": "https://www.cinemalibero.center/wp-content/themes/Cinemalibero%202.0/images/logo02.png", - "categories": ["tvshow", "movie","anime"], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://www.cinemalibero.fun/", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "thumbnail": "cinemalibero.png", + "banner": "cinemalibero.png", + "categories": ["movie","tvshow","anime"], + "not_active": ["include_in_newest"], + "settings": [] } diff --git a/channels/cinemalibero.py b/channels/cinemalibero.py index 58634f13..0f9c26b4 100644 --- a/channels/cinemalibero.py +++ b/channels/cinemalibero.py @@ -1,326 +1,237 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per CinemaLibero - First Version +# Canale per 'cinemaLibero' # ------------------------------------------------------------ +""" + Questi sono commenti per i beta-tester. + + Su questo canale in: + - Cerca ( nel canale ) e Ricerca Globale + - SerieTV e novità del canale + - Novità -> SerieTV + non saranno presenti le voci: + - 'Aggiungi alla Videoteca', + - 'Scarica Serie' + - NON SONO PRESENTI IN NOVITà GLOBALE E del CANALE RIGUARDANTI LO SPORT!!!! + dunque, la loro assenza, nel Test, NON dovrà essere segnalata come ERRORE. + + NON CONTROLLARE LA SEZIONE SPORT, HA PROBLEMI!!! + è stata eliminata dall'elenco ma i titoli possono apparire nella ricerca o tra le novità + Non è errore se dà problemi!!! NON CONSIDERATELA! + + Novità. Indicare in quale/i sezione/i è presente il canale: + - FILM + + Avvisi: + - Eventuali avvisi per i tester + + Ulteriori info: + +""" + import re -from core import scrapertools, servertools, httptools, support -from core import tmdb +from core import httptools, support, scrapertoolsV2 from core.item import Item -from lib import unshortenit from platformcode import config -from platformcode import logger -from specials import autoplay -import channelselector -# Necessario per Autoplay -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['akstream', 'wstream', 'openload', 'streamango'] +list_servers = ['akstream', 'wstream', 'backin', 'verystream', 'openload', 'streamango'] list_quality = ['default'] -# Necessario per Verifica Link -checklinks = config.get_setting('checklinks', 'cinemalibero') -checklinks_number = config.get_setting('checklinks_number', 'cinemalibero') - __channel__ = "cinemalibero" host = config.get_channel_url(__channel__) headers = [['Referer', host]] +@support.menu def mainlist(item): - logger.info('[cinemalibero.py] mainlist') - - autoplay.init(item.channel, list_servers, list_quality) # Necessario per Autoplay + support.log() - # Menu Principale - itemlist = [] - support.menu(itemlist, 'Film bold', 'video', host+'/category/film/') - support.menu(itemlist, 'Generi submenu', 'genres', host) - support.menu(itemlist, 'Cerca film submenu', 'search', host) - support.menu(itemlist, 'Serie TV bold', 'video', host+'/category/serie-tv/', contentType='episode') - support.menu(itemlist, 'Anime submenu', 'video', host+'/category/anime-giapponesi/', contentType='episode') - support.menu(itemlist, 'Cerca serie submenu', 'search', host, contentType='episode') - support.menu(itemlist, 'Sport bold', 'video', host+'/category/sport/') + film = ['/category/film/', + ('Generi', ['', 'genres']) + ] - autoplay.show_option(item.channel, itemlist) # Necessario per Autoplay (Menu Configurazione) + tvshow = ['/category/serie-tv/' + ] - support.channel_config(item, itemlist) - - return itemlist + Anime = [(support.typo('Anime', 'bullet bold'),['/category/anime-giapponesi/', 'peliculas', 'anime', 'tvshow']) + ] + +## Sport = [(support.typo('Sport', 'bullet bold'), ['/category/sport/', 'peliculas', '', 'tvshow']) +## ] +## news = [('Novità Serie-Anime', ['/aggiornamenti-serie-tv/', 'peliculas', 'update', 'tvshow'])] + search = '' + + return locals() -def search(item, texto): - logger.info("[cinemalibero.py] " + item.url + " search " + texto) - item.url = host + "/?s=" + texto - try: - return video(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] +@support.scrape +#def video(item): +def peliculas(item): + support.log() + #debug = True + patronBlock = r'<div class="container">.*?class="col-md-12[^"]*?">(?P<block>.*?)<div class=(?:"container"|"bg-dark ")>' + if item.contentType == 'movie': + patron = r'<div class="col-lg-3">[^>]+>[^>]+>\s<a href="(?P<url>[^"]+)".+?url\((?P<thumb>[^\)]+)\)">[^>]+>[^>]+>[^>]+>\s?(?P<rating>[\d\.]+)?[^>]+>[^>]+>(?P<title>.+?)\(?(?P<year>\d+)?\)?<[^>]+>[^>]+>(?P<quality>[^<]+)?<' + elif item.args == 'anime': + patron = r'<div class="col-lg-3">[^>]+>[^>]+>\s<a href="(?P<url>[^"]+)".+?url\((?P<thumb>[^\)]+)\)">[^>]+>[^>]+>[^>]+>\s?(?P<rating>[\d\.]+)?[^>]+>[^>]+>(?P<title>.+?)\(?(?P<year>\d+)?\)?<[^>]+>[^>]+>(?:.+?[^fFiInNeE]+?\(?(?P<lang>[sSuUbBiItTaA]+)\)?.+?)<' + elif item.args == 'update': + action = 'select' + patron = r'<div class="card-body p-0">\s<a href="(?P<url>[^"]+)".+?url\((?P<thumb>.+?)\)">\s<div class="titolo">(?P<title>.+?)(?: – Serie TV)?(?:\([sSuUbBiItTaA\-]+\))?[ ]?(?P<year>\d{4})?</div>[ ]<div class="genere">(?:[\w]+?\.?\s?[\s|S]?[\dx\-S]+?\s\(?(?P<lang>[iItTaA]+|[sSuUbBiItTaA\-]+)\)?\s?(?P<quality>[HD]+)?|.+?\(?(?P<lang2>[sSuUbBiItTaA\-]+)?\)?</div>)' + else: + patron = r'<div class="col-lg-3">[^>]+>[^>]+>\s<a href="(?P<url>[^"]+)".+?url\((?P<thumb>[^\)]+)\)">[^>]+>[^>]+>[^>]+>(?:[^>]+>)?\s?(?P<rating>[\d\.]+)?[^>]+>(?P<title>[^<]+)<[^>]+>[^>]+>(.?[\d\-x]+\s\(?(?P<lang>[sSuUbBiItTaA\-]+)?\)?\s?(?P<quality>[\w]+)?[|]?\s?(?:[fFiInNeE]+)?\s?\(?(?P<lang2>[sSuUbBiItTaA\-]+)?\)?)?' -def genres(item): - return support.scrape(item, patron_block=r'<div id="bordobar" class="dropdown-menu(.*?)</li>', patron=r'<a class="dropdown-item" href="([^"]+)" title="([A-z]+)"', listGroups=['url', 'title'], action='video') + def itemHook(item): + if item.lang2: + if len(item.lang2)<3: + item.lang2 = 'ITA' + item.contentLanguage = item.lang2 + item.title += support.typo(item.lang2, '_ [] color kod') - -def video(item): - logger.info('[cinemalibero.py] video') - itemlist = [] - - if host not in item.url: - item.url = host + item.url - - # Carica la pagina - data = httptools.downloadpage(item.url).data.replace('\n','').replace('\t','') - block = scrapertools.find_single_match(data, '<div class="container">.*?class="col-md-12[^"]*?">(.*?)<div class=(?:"container"|"bg-dark ")>') - - # Estrae i contenuti - matches = re.compile(r'<div class="col-lg-3">(.*?)<\/a><\/div>', re.DOTALL).findall(block) - - for match in matches: - url = scrapertools.find_single_match(match, r'href="([^"]+)"') - long_title = scrapertools.find_single_match(match, r'<div class="titolo">([^<]+)<\/div>') - thumb = scrapertools.find_single_match(match, r'url=\((.*?)\)') - quality = scrapertools.find_single_match(match, r'<div class="voto">([^<]+)<\/div>') - genere = scrapertools.find_single_match(match, r'<div class="genere">([^<]+)<\/div>') - - year = scrapertools.find_single_match(long_title, r'\(([0-9)]+)') or scrapertools.find_single_match(long_title, r'\) ([0-9)]+)') - lang = scrapertools.find_single_match(long_title, r'\(([a-zA-Z)]+)') - - title = re.sub(r'\(.*','',long_title) - title = re.sub(r'(?:\(|\))','',title) - if genere: - genere = ' - [' + genere + ']' - if year: - long_title = title + ' - ('+ year + ')' + genere - if lang: - long_title = '[B]' + title + '[/B]' + ' - ('+ lang + ')' + genere - else: - long_title = '[B]' + title + '[/B]' - - # Seleziona fra Serie TV e Film if item.contentType == 'movie': - tipologia = 'movie' - action = 'findvideos' - elif item.contentType == 'episode': - tipologia = 'tv' - action = 'episodios' + item.action = 'findvideos' + elif item.args == 'anime' or item.args == 'update' or item.args == 'search': + item.action = 'select' + elif item.contentType == 'tvshow': + item.extra = 'serie' + item.action = 'episodios' else: - tipologia = 'movie' - action = 'select' + item.action = 'select' - itemlist.append( - Item(channel=item.channel, - action=action, - contentType=item.contentType, - title=long_title, - fulltitle=title, - quality=quality, - url=url, - thumbnail=thumb, - infoLabels={'year': year}, - show=title)) + return item - # Next page - next_page = scrapertools.find_single_match(data, '<a class="next page-numbers".*?href="([^"]+)">') - - if next_page != '': - itemlist.append( - Item(channel=item.channel, - action='video', - title='[B]' + config.get_localized_string(30992) + ' »[/B]', - url=next_page, - contentType=item.contentType, - thumbnail='http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png')) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - - -def select(item): - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertools.find_single_match(data, r'<div class="col-md-8 bg-white rounded-left p-5"><div>(.*?)<\/div>') - if re.findall('rel="category tag">serie', data, re.IGNORECASE): - logger.info('select = ### è una serie ###') - return episodios(Item(channel=item.channel, - title=item.title, - fulltitle=item.fulltitle, - url=item.url, - extra='serie', - contentType='episode')) - elif re.findall('rel="category tag">anime', data, re.IGNORECASE): - if re.findall('episodio', block, re.IGNORECASE): - logger.info('select = ### è un anime ###') - return episodios(Item(channel=item.channel, - title=item.title, - fulltitle=item.fulltitle, - url=item.url, - extra='anime', - contentType='episode')) - else: - logger.info('select = ### è un film ###') - return findvideos(Item(channel=item.channel, - title=item.title, - fulltitle=item.fulltitle, - url=item.url, - contentType='movie')) - else: - logger.info('select = ### è un film ###') - return findvideos(Item(channel=item.channel, - title=item.title, - fulltitle=item.fulltitle, - url=item.url, - contentType='movie')) - - -def findvideos(item): # Questa def. deve sempre essere nominata findvideos - logger.info('[cinemalibero.py] findvideos') - itemlist = [] - - if item.args == 'direct': - return servertools.find_video_items(item) - - if item.contentType == 'episode': - data = item.url.lower() - block = scrapertools.find_single_match(data,r'>streaming.*?<\/strong>*?<\/h2>(.*?)<\/div>') - urls = re.findall('<a.*?href="([^"]+)"', block, re.DOTALL) - else: - data = httptools.downloadpage(item.url, headers=headers).data - data = re.sub(r'\n|\t','',data).lower() - block = scrapertools.find_single_match(data,r'>streaming.*?<\/strong>(.*?)<strong>') - urls = re.findall('<a href="([^"]+)".*?class="external"', block, re.DOTALL) - - logger.info('URLS'+ str(urls)) - if urls: - data ='' - for url in urls: - url, c = unshortenit.unshorten(url) - data += url + '\n' - - logger.info('DATA'+ data) - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = item.fulltitle + ' - [COLOR limegreen][[/COLOR]'+videoitem.title+' [COLOR limegreen]][/COLOR]' - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.show = item.show - videoitem.plot = item.plot - videoitem.channel = item.channel - videoitem.contentType = item.contentType - - # Link Aggiungi alla Libreria - if item.contentType != 'episode': - if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findservers': - itemlist.append( - Item(channel=item.channel, title='[COLOR lightblue][B]Aggiungi alla videoteca[/B][/COLOR]', url=item.url, - action='add_pelicula_to_library', extra='findservers', contentTitle=item.contentTitle)) - - # Necessario per filtrare i Link - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # Necessario per FilterTools - # itemlist = filtertools.get_links(itemlist, item, list_language) - - # Necessario per AutoPlay - autoplay.start(itemlist, item) - - - return itemlist + patronNext = r'<a class="next page-numbers".*?href="([^"]+)">' + return locals() +@support.scrape def episodios(item): # Questa def. deve sempre essere nominata episodios - logger.info('[cinemalibero.py] episodios') - itemlist = [] - extra = '' - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertools.find_single_match(data, r'<div class="col-md-8 bg-white rounded-left p-5"><div>(.*?)at-below-post') - if re.findall('rel="category tag">serie', data, re.IGNORECASE): - # logger.info('select = ### è una serie ###') - extra='serie' - elif re.findall('rel="category tag">anime', data, re.IGNORECASE): - if re.findall('episodi', block, re.IGNORECASE): - # logger.info('select = ### è un anime ###') - extra='anime' - - block = re.sub(r'<h2>.*?<\/h2>','',block) - block = block.replace('<p>','').replace('<p style="text-align: left;">','').replace('–<','<').replace('-<','<').replace('–<','<').replace('– <','<').replace('<strong>','<stop><start><strong>')+'<stop>' - block = re.sub(r'stagione completa.*?<\/p>','',block,flags=re.IGNORECASE) - - - if extra == 'serie': - block = block.replace('<br /> <a','<a') - matches = re.compile(r'<start>.*?(?:stagione|Stagione)(.*?)<\/(?:strong|span)><\/p>(.*?)<stop>', re.DOTALL).findall(block) - - if not matches: - matches = scrapertools.find_multiple_matches(block, r'<a href="([^"]+)"[^>]+>(Episodio [0-9]+)</a>') - for scrapedurl, scrapedtitle in matches: - scrapedtitle = re.sub(r'Episodio ([0-9]+)', r'Episodio 1x\1', scrapedtitle) - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType='episode', - title=scrapedtitle, - fulltitle=scrapedtitle, - show=item.fulltitle, - url=scrapedurl, - args='direct')) - else: - for lang, html in matches: - lang = re.sub('<.*?>','',lang) - html = html.replace('<br />','\n').replace('</p>', '\n') - - matches = re.compile(r'([^<]+)([^\n]+)\n', re.DOTALL).findall(html) - for scrapedtitle, html in matches: - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType='episode', - title=scrapedtitle + ' - (' + lang + ')', - fulltitle=scrapedtitle, - show=item.fulltitle, - url=html)) - - elif extra == 'anime': - block = re.sub(r'<start.*?(?:download:|Download:).*?<stop>','',block) - block = re.sub(r'(?:mirror|Mirror)[^<]+<','',block) - block = block.replace('<br />','\n').replace('/a></p>','\n') - block = re.sub(r'<start.*?(?:download|Download).*?\n','',block) - matches = re.compile('<a(.*?)\n', re.DOTALL).findall(block) - for html in matches: - scrapedtitle = scrapertools.find_single_match(html, r'>(.*?)<\/a>') - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType='episode', - title=scrapedtitle, - fulltitle=scrapedtitle, - show=item.fulltitle, - url=html)) + support.log() + if item.extra == 'serie': + support.log("Serie :", item) + patron = r'(?P<episode>\d+(?:×|×)?\d+\-\d+|\d+(?:×|×)\d+)[;]?[ ]?(?:(?P<title>[^<]+)(?P<url>.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br />|</a></p>)' + patronBlock = r'<p><strong>(?P<block>(?:.+?[Ss]tagione.+?(?P<lang>iTA|ITA|Sub-ITA|Sub-iTA))?(?:|.+?|</strong>)(/?:</span>)?</p>.*?</p>)' + item.contentType = 'tvshow' + item.contentSerieName = item.fulltitle + elif item.args == 'anime': + support.log("Anime :", item) + blacklist = ['Clipwatching', 'Verystream', 'Easybytez', 'Flix555'] + #patron = r'(?:href="[ ]?(?P<url>[^"]+)"[^>]+>(?P<title>[^<]+))<|(?P<episode>\d+(?:×|×)?\d+\-\d+|\d+(?:×|×)\d+)[;]?(?:(\4[^<]+)(\2.*?)|(\2[ ])(?:<(\3.*?)))(?:</a><br />|</a></p>)' + #patron = r'<a target=.+?href="(?P<url>[^"]+)"[^>]+>(?P<title>(Epis|).+?(?P<episode>\d+)?)(?:\((?P<lang>Sub ITA)\))?</a>(?:<br />)?' + patron = r'<a target=(?P<url>.+?(?:rel="noopener noreferrer">(?P<title>[^<]+)))</a>.+?(?:</a></p>|</a><br />)' + patronBlock = r'Streaming.+?:(?P<block>.*?)</div>' + #patronBlock = r'(?:<p>)?(?P<block>.*?)(?:</a><br /> |</p><div)' + item.contentType = 'tvshow' + item.contentSerieName = item.fulltitle else: - logger.info('select = ### è un film ###') + support.log('extra = else --- select = ### è un film ###') return findvideos(Item(channel=item.channel, title=item.title, fulltitle=item.fulltitle, url=item.url, show=item.fulltitle, contentType='movie')) - - if config.get_videolibrary_support() and len(itemlist) != 0: - itemlist.append( - Item(channel=item.channel, - title="[COLOR lightblue]%s[/COLOR]" % config.get_localized_string(30161), - url=item.url, - action="add_serie_to_library", - extra="episodios", - show=item.show)) - + #debug = True + return locals() + +@support.scrape +def genres(item): + support.log() + + action='peliculas' + patron_block=r'<div id="bordobar" class="dropdown-menu(?P<block>.*?)</li>' + patron=r'<a class="dropdown-item" href="(?P<url>[^"]+)" title="(?P<title>[A-z]+)"' + + return locals() + + +def select(item): + support.log() + + data = httptools.downloadpage(item.url, headers=headers).data + block = scrapertoolsV2.find_single_match(data, r'Streaming\s?[\w]+?:(.*?)<\/div>') + if re.findall('rel="category tag">serie', data, re.IGNORECASE): + support.log('select = ### è una serie ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + contentSerieName = item.fulltitle, + url=item.url, + extra='serie', + contentType='episode')) + elif re.findall('rel="category tag">anime', data, re.IGNORECASE): + if re.findall('episodio', block, re.IGNORECASE) or re.findall('episodi streaming', block, re.IGNORECASE) or \ + re.findall('numero stagioni', data, re.IGNORECASE): + support.log('select = ### è un anime ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + contentSerieName = item.fulltitle, + url=item.url, + args='anime', + contentType='episode')) + else: + support.log('select anime ELSE = ### è un film ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + contentType='movie')) + else: + support.log('select ELSE = ### è un film ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + contentType='movie')) + +def search(item, texto): + support.log(item.url,texto) + item.url = host + "/?s=" + texto + item.contentType = 'episode' + item.args = 'search' + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log("%s" % line) + return [] + +def newest(categoria): + support.log('newest ->', categoria) + itemlist = [] + item = Item() + try: + if categoria == 'peliculas': + item.url = host+'/category/film/' + item.contentType = 'movie' +## item.action = 'peliculas' +## itemlist = peliculas(item) +## elif categoria == 'series': +## item.contentType = 'tvshow' +## item.args = 'update' +## item.url = host+'/aggiornamenti-serie-tv/' + item.action = 'peliculas' + itemlist = peliculas(item) + + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log('newest log: ', {0}.format(line)) + return [] + return itemlist + +def findvideos(item): + support.log('findvideos ->', item) + if item.contentType == 'movie': + return support.server(item) + else: + return support.server(item, data= item.url) diff --git a/channels/documentaristreamingda.py b/channels/documentaristreamingda.py index 84fae55d..876a3a95 100644 --- a/channels/documentaristreamingda.py +++ b/channels/documentaristreamingda.py @@ -6,13 +6,16 @@ import re import urlparse -from core import httptools, scrapertools, servertools +from core import httptools, scrapertools, servertools, support from core.item import Item from platformcode import logger, config __channel__ = "documentaristreamingda" host = config.get_channel_url(__channel__) +list_servers = [''] +list_quality = [''] + def mainlist(item): logger.info("kod.documentaristreamingda mainlist") itemlist = [Item(channel=item.channel, @@ -156,105 +159,107 @@ def peliculas(item): def findvideos(item): logger.info("kod.documentaristreamingda findvideos") + return support.server(item)#, data= item.url) - data = httptools.downloadpage(item.url).data - - links = [] - begin = data.find('<div class="moview-details-text">') - if begin != -1: - end = data.find('<!-- //movie-details -->', begin) - mdiv = data[begin:end] - - items = [[m.end(), m.group(1)] for m in re.finditer('<b style="color:#333333;">(.*?)<\/b>', mdiv)] - if items: - for idx, val in enumerate(items): - if idx == len(items) - 1: - _data = mdiv[val[0]:-1] - else: - _data = mdiv[val[0]:items[idx + 1][0]] - - for link in re.findall('<a.*?href="([^"]+)"[^>]+>.*?<b>(.*?)<\/b><\/a>+', _data): - if not link[0].strip() in [l[1] for l in links]: links.append( - [val[1], link[0].strip(), link[1].strip()]) - - items = [[m.end(), m.group(1)] for m in re.finditer('<p><strong>(.*?)<\/strong><\/p>', mdiv)] - if items: - _title = '' - for idx, val in enumerate(items): - if idx == len(items) - 1: - _data = mdiv[val[0]:-1] - else: - _data = mdiv[val[0]:items[idx + 1][0]] - - for link in re.findall('<a\s.*?href="([^"]+)".*?>(?:<span[^>]+>)*(?:<strong>)*([^<]+)', _data): - if not link[0].strip() in [l[1] for l in links]: - if not link[1].strip() in link[0]: _title = link[1].strip() - links.append([_title, link[0].strip(), 'unknown']) - - items = [[m.start(), m.group(1)] for m in re.finditer('<li><strong>([^<]+)<', mdiv)] - if items: - for idx, val in enumerate(items): - if idx == len(items) - 1: - _data = mdiv[val[0]:-1] - else: - _data = mdiv[val[0]:items[idx + 1][0]] - - for link in re.findall('<a\s.*?href="([^"]+)".*?>(?:<span[^>]+>)*(?:<strong>)*([^<]+)', _data): - if not link[0].strip() in [l[1] for l in links]: links.append( - [val[1], link[0].strip(), link[1].strip()]) - - itemlist = [] - if links: - for l in links: - title = unicode(l[0], 'utf8', 'ignore') - title = title.replace(u'\xa0', ' ').replace('Documentario ', '').replace(' doc ', ' ').replace(' streaming', - '').replace( - ' Streaming', '') - url = l[1] - action = "play" - server = "unknown" - folder = False - - if url == '#' or not title: continue - - logger.info('server: %s' % l[2]) - if l[2] != 'unknown': - server = unicode(l[2], 'utf8', 'ignore') - else: - logger.info(url) - match = re.search('https?:\/\/(?:www\.)*([^\.]+)\.', url) - if match: - server = match.group(1) - - if server == "documentari-streaming-db": - action = "findvideos" - folder = True - logger.info('server: %s, action: %s' % (server, action)) - - logger.info(title + ' - [COLOR blue]' + server + '[/COLOR]') - - itemlist.append(Item( - channel=item.channel, - title=title + ' - [COLOR blue]' + server + '[/COLOR]', - action=action, - server=server, # servertools.get_server_from_url(url), - url=url, - thumbnail=item.thumbnail, - fulltitle=title, - show=item.show, - plot=item.plot, - parentContent=item, - folder=folder) - ) - else: - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = "".join([item.title, '[COLOR green][B]' + videoitem.title + '[/B][/COLOR]']) - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - - return itemlist +## +## data = httptools.downloadpage(item.url).data +## +## links = [] +## begin = data.find('<div class="moview-details-text">') +## if begin != -1: +## end = data.find('<!-- //movie-details -->', begin) +## mdiv = data[begin:end] +## +## items = [[m.end(), m.group(1)] for m in re.finditer('<b style="color:#333333;">(.*?)<\/b>', mdiv)] +## if items: +## for idx, val in enumerate(items): +## if idx == len(items) - 1: +## _data = mdiv[val[0]:-1] +## else: +## _data = mdiv[val[0]:items[idx + 1][0]] +## +## for link in re.findall('<a.*?href="([^"]+)"[^>]+>.*?<b>(.*?)<\/b><\/a>+', _data): +## if not link[0].strip() in [l[1] for l in links]: links.append( +## [val[1], link[0].strip(), link[1].strip()]) +## +## items = [[m.end(), m.group(1)] for m in re.finditer('<p><strong>(.*?)<\/strong><\/p>', mdiv)] +## if items: +## _title = '' +## for idx, val in enumerate(items): +## if idx == len(items) - 1: +## _data = mdiv[val[0]:-1] +## else: +## _data = mdiv[val[0]:items[idx + 1][0]] +## +## for link in re.findall('<a\s.*?href="([^"]+)".*?>(?:<span[^>]+>)*(?:<strong>)*([^<]+)', _data): +## if not link[0].strip() in [l[1] for l in links]: +## if not link[1].strip() in link[0]: _title = link[1].strip() +## links.append([_title, link[0].strip(), 'unknown']) +## +## items = [[m.start(), m.group(1)] for m in re.finditer('<li><strong>([^<]+)<', mdiv)] +## if items: +## for idx, val in enumerate(items): +## if idx == len(items) - 1: +## _data = mdiv[val[0]:-1] +## else: +## _data = mdiv[val[0]:items[idx + 1][0]] +## +## for link in re.findall('<a\s.*?href="([^"]+)".*?>(?:<span[^>]+>)*(?:<strong>)*([^<]+)', _data): +## if not link[0].strip() in [l[1] for l in links]: links.append( +## [val[1], link[0].strip(), link[1].strip()]) +## +## itemlist = [] +## if links: +## for l in links: +## title = unicode(l[0], 'utf8', 'ignore') +## title = title.replace(u'\xa0', ' ').replace('Documentario ', '').replace(' doc ', ' ').replace(' streaming', +## '').replace( +## ' Streaming', '') +## url = l[1] +## action = "play" +## server = "unknown" +## folder = False +## +## if url == '#' or not title: continue +## +## logger.info('server: %s' % l[2]) +## if l[2] != 'unknown': +## server = unicode(l[2], 'utf8', 'ignore') +## else: +## logger.info(url) +## match = re.search('https?:\/\/(?:www\.)*([^\.]+)\.', url) +## if match: +## server = match.group(1) +## +## if server == "documentari-streaming-db": +## action = "findvideos" +## folder = True +## logger.info('server: %s, action: %s' % (server, action)) +## +## logger.info(title + ' - [COLOR blue]' + server + '[/COLOR]') +## +## itemlist.append(Item( +## channel=item.channel, +## title=title + ' - [COLOR blue]' + server + '[/COLOR]', +## action=action, +## server=server, # servertools.get_server_from_url(url), +## url=url, +## thumbnail=item.thumbnail, +## fulltitle=title, +## show=item.show, +## plot=item.plot, +## parentContent=item, +## folder=folder) +## ) +## else: +## itemlist = servertools.find_video_items(data=data) +## +## for videoitem in itemlist: +## videoitem.title = "".join([item.title, '[COLOR green][B]' + videoitem.title + '[/B][/COLOR]']) +## videoitem.fulltitle = item.fulltitle +## videoitem.show = item.show +## videoitem.thumbnail = item.thumbnail +## videoitem.channel = item.channel +## +## return itemlist diff --git a/channels/dreamsub.json b/channels/dreamsub.json index d9cb58fd..ba8bf611 100644 --- a/channels/dreamsub.json +++ b/channels/dreamsub.json @@ -1,52 +1,12 @@ { - "id": "dreamsub", - "name": "DreamSub", - "language": ["ita"], - "active": true, - "adult": false, - "thumbnail": "dreamsub.png", - "banner": "dreamsub.png", - "categories": ["anime","vosi","vos"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "autorenumber", - "type": "bool", - "label": "@70712", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "autorenumber_mode", - "type": "bool", - "label": "@70688", - "default": false, - "enabled": true, - "visible": "eq(-1,true)" - } - ] + "id": "dreamsub", + "name": "DreamSub", + "language": ["ita", "sub-ita"], + "active": true, + "adult": false, + "thumbnail": "dreamsub.png", + "banner": "dreamsub.png", + "categories": ["anime", "vos"], + "not_active": ["include_in_newest"], + "settings": [] } diff --git a/channels/dreamsub.py b/channels/dreamsub.py index aa57640b..521d68eb 100644 --- a/channels/dreamsub.py +++ b/channels/dreamsub.py @@ -1,112 +1,294 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per dreamsub +# Canale per 'dreamsub' # ------------------------------------------------------------ +# ------------------------------------------------------------ +""" + + Problemi noti che non superano il test del canale: + - Nessuno noto! + + Avvisi per i tester: + 1. Gli episodi sono divisi per pagine di 20 + 2. In Novità->Anime, cliccare sulla home il bottone "Ultime inserite" + Se avete più titoli in KOD, ridimensiona il browser in modo che si vedano i titoli + a gruppi di 3 e ricontrollare, è un problema del sito. + + 3.Passaggi per Aggiungere in videoteca e/o scaricare Serie: + 1. sul titolo -> menu contestuale -> Rinumerazione + Solo dopo questo passaggio appariranno le voci, sul titolo -> menu contestuale ->: + - Aggiungi in videoteca (senza rinumerazione non appare + la voce) + - Scarica Serie e Scarica Stagione ( Se download Abilitato! ) + + 4. ### PIù IMPORTANTE!!! ### + #### NON E' DA CONSIDERARE ERRORE NEL TEST QUANTO RIPORTATO DI SEGUITO!!!! #### + 1. Il sito permette un filtro tra anime e film, tramite url. + Se nell'url c'è /anime/, sul titolo e proseguendo fino alla pagina del video, saranno + presenti le voci: + - 'Rinumerazione', prima, e dopo: 'Aggiungi in videoteca', 'Scarica Serie' etc... + Tutto il resto è trattato come film e si avranno le voci solite: + AD eccezione per quei "FILM" che hanno 2 o più titoli all'interno, in questo caso: + 1. Non apparirà nessuna voce tra "Aggiungi in videoteca" e "Scarica Film" e nemmeno "rinumerazione" + 2. Dopo essere entrato nella pagina del Titolo Principale, troverai una lista di titoli dove sarà possibile scaricare + il filmato (chiamato EPISODIO) stessa cosa accedendo alla pagina ultima del video + 3. Questi TITOLI NON POSSONO ESSERE AGGIUNTI IN VIDEOTECA + le voci "Scarica FILM" si avranno dopo. + + Es: + https://www.dreamsub.stream/movie/5-centimetri-al-secondo -> film ma ha 3 titoli + + Il Canale NON è presente nelle novità(globale) -> Anime + + +""" +# Qui gli import import re -import urlparse -from core import scrapertoolsV2, httptools, servertools, tmdb, support -from specials.autorenumber import renumber -from core.support import menu, log, scrape +from core import support +from platformcode import config +from core import scrapertoolsV2, httptools, servertools, tmdb from core.item import Item -from platformcode import logger, config +##### fine import __channel__ = "dreamsub" host = config.get_channel_url(__channel__) +headers = [['Referer', host]] -list_servers = ['verystream', 'streamango', 'openload'] +# server di esempio... +list_servers = ['directo', 'verystream', 'streamango', 'openload'] +# quality di esempio list_quality = ['default'] +#### Inizio delle def principali ### +@support.menu def mainlist(item): - log() + support.log(item) + + anime = ['/anime', +## ('Novità', ['']), +## ('OAV', ['/search/oav', 'peliculas', 'oav']), +## ('OVA', ['/search/ova', 'peliculas', 'ova']), + ('Movie', ['/search/movie', 'peliculas', '', 'movie']), + ('Film', ['/search/film', 'peliculas', '', 'movie']), + ('Categorie', ['/filter?genere=','genres']), +## ('Ultimi Episodi', ['', 'last']) + ] + + return locals() + +@support.scrape +def peliculas(item): + support.log(item) + #dbg # decommentare per attivare web_pdb + + anime = True + if item.args == 'newest': + patronBlock = r'<div class="showRoomGoLeft" sr="ultime"></div>(?P<block>.*?)<div class="showRoomGoRight" sr="ultime">' + else: + patronBlock = r'<input type="submit" value="Vai!" class="blueButton">(?P<block>.*?)<div class="footer">' + +## patron = r'<div class="showStreaming"> <b>(?P<title>[^<]+).+?Stato streaming: '\ +## '(?:[^<]+)<.*?Lingua:[ ](?P<lang1>ITA\/JAP|ITA|JAP)?(?:[ ])?'\ +## '(?P<lang2>SUB ITA)?<br>.+?href="(?P<url>[^"]+)".+?'\ +## 'background: url\((?P<thumb>[^"]+)\).+?<div class="tvTitle">.+?'\ +## '<strong>Anno di inizio</strong>: (?P<year>\d+)<br>' + + patron = r'<div class="showStreaming"> <b>(?P<title>[^<]+).+?Stato streaming: (?:[^<]+)<.*?Lingua:[ ](?P<lang1>ITA\/JAP|ITA|JAP)?(?:[ ])?(?P<lang2>SUB ITA)?<br>.+?href="(?P<url>[^"]+)".+?background: url\((?P<thumb>[^"]+)\).+?<div class="tvTitle">.+?Episodi[^>]+>.\s?(?P<nep>\d+).+?<strong>Anno di inizio</strong>: (?P<year>\d+)<br>' + patronNext = '<li class="currentPage">[^>]+><li[^<]+<a href="([^"]+)">' + + def itemHook(item): + support.log("ITEMHOOK -> ", item) + item = language(item) + + if 'anime' in item.url: + item.contentType = 'tvshow' + item.action = 'episodios' + #item.args = 'anime' + else: + if item.nep == '1': + item.contentType = 'movie' + item.action = 'findvideos' + else: + item.contentType = 'episode' + item.args = '' + item.nep = item.nep + item.action = 'findmovie' + return item + + #debug = True + return locals() + +@support.scrape +def episodios(item): + support.log(item) + #support.dbg() + + action = 'findvideos' + patronBlock = r'<div class="seasonEp">(?P<block>.*?)<div class="footer">' + patron = r'<li><a href="(?P<url>[^"]+)"[^<]+<b>(?:.+?)[ ](?P<episode>\d+)<\/b>[^>]+>(?P<title>[^<]+)<\/i>[ ]\(?(?P<lang1>ITA|Sub ITA)?\s?.?\s?(?P<lang2>Sub ITA)?.+?\)?<\/a>' + + def itemHook(item): + item = language(item) + return item + + pagination = '' + + #debug = True + return locals() + +@support.scrape +def genres(item): + support.log(item) + #dbg + + item.contentType = '' + action = 'peliculas' + blacklist = ['tutti'] + patron = r'<option value="(?P<title>[^"]+)">' + patronBlock = r'<select name="genere" id="genere" class="selectInput">(?P<block>.*?)</select>' + + def itemHook(item): + item.contentTitle = item.contentTitle.replace(' ', '+') + item.url = host+'/filter?genere='+item.contentTitle + return item + + #debug = True + return locals() + + +@support.scrape +def findmovie(item): + support.log(item) + + patronBlock = r'<div class="seasonEp">(?P<block>.*?)<div class="footer">' + item.contentType = 'episode' + item.nep = 2 + patron = r'<li><a href="(?P<url>[^"]+)"[^>]+>.(?P<title2>.+?)-.+?-[ ]<b>(?P<title>.+?)</b>\s+\(?(?P<lang1>ITA)?\s?(?P<lang2>Sub ITA)?.+?\)?' + + def itemHook(item): + item = language(item) + return item + + #debug = True + return locals() + + +def language(item): + lang = [] + + if item.lang1: + if item.lang1.lower() == 'ita/jap' or item.lang1.lower() == 'ita': + lang.append('ITA') + + if item.lang1.lower() == 'jap' and item.lang1.lower() == 'sub ita': + lang.append('Sub-ITA') + + if item.lang2: + if item.lang2.lower() == 'sub ita': + lang.append('Sub-ITA') + + item.contentLanguage = lang + + if len(lang) ==2: + item.title += support.typo(lang[0], '_ [] color kod') + support.typo(lang[1], '_ [] color kod') + #item.show += support.typo(lang[0], '_ [] color kod') + support.typo(lang[1], '_ [] color kod') + elif len(lang) == 1: + item.title += support.typo(lang[0], '_ [] color kod') + #item.show += support.typo(lang[0], '_ [] color kod') + + return item + + +def search(item, text): + support.log('search', item) itemlist = [] - menu(itemlist, 'Anime / Cartoni', 'peliculas', host + '/anime', 'tvshow') - menu(itemlist, 'Categorie', 'categorie', host + '/filter?genere=', 'tvshow') - menu(itemlist, 'Ultimi Episodi', 'last', host, 'episode') - menu(itemlist, 'Cerca...', 'search') - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) - - return itemlist - - -def search(item, texto): - log(texto) - item.url = host + '/search/' + texto + text = text.replace(' ', '+') + item.url = host + '/search/' + text + item.args = 'search' try: return peliculas(item) - # Continua la ricerca in caso di errore + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.log('search log:', line) return [] -def newest(categoria): - log(categoria) - itemlist = [] - item = Item() - try: - if categoria == "anime": - item.url = host - item.action = "ultimiep" - itemlist = ultimiep(item) - - if itemlist[-1].action == "ultimiep": - itemlist.pop() - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist - - -def peliculas(item): - itemlist = scrape(item, r'Lingua[^<]+<br>\s*<a href="(?:Lista episodi )?([^"]+)" title="(?:Lista episodi )?(.*?)(?: \(([0-9]+)\))?(?: Streaming)?">', ['url', 'title', 'year'], action='episodios', patron_block='<input type="submit" value="Vai!" class="blueButton">(.*?)<div class="footer">', patronNext='<li class="currentPage">[^>]+><li[^<]+<a href="([^"]+)">') - renumber(itemlist) - return itemlist - - -def last(item): - return scrape(item, r'<li><a href="([^"]+)"[^>]+>([^<]+)(\d+)<br>', ['url', 'title', 'episode'], patron_block='<ul class="last" id="recentAddedEpisodesAnimeDDM">(.*?)</ul>' ) - - -def categorie(item): - log() - itemlist = [] - matches = support.match(item, r'<option value="([^"]+)">', r'<select name="genere" id="genere" class="selectInput">(.*?)</select>')[0] - - for value in matches: - url = item.url + value - itemlist.append( - Item(channel=item.channel, - contentType=item.contentType, - action="peliculas", - title=support.typo(value, 'bold'), - url=url)) - return support.thumb(itemlist) - - -def episodios(item): - itemlist = scrape(item, r'<li><a href="([^"]+)"[^<]+<b>(.*?)<\/b>[^>]+>([^<]+)<\/i>', ['url','title','title2'], patron_block='<div class="seasonEp">(.*?)<div class="footer">') - renumber(itemlist, item, 'bold') - return itemlist - +# da adattare... ( support.server ha vari parametri ) +#support.server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True) def findvideos(item): - log() + support.log("ITEM ---->", item) itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r'\n|\t', ' ', data) + data = re.sub(r'>\s\s*<', '><', data) + patronBlock = r'LINK STREAMING(?P<block>.*?)LINK DOWNLOAD' + patron = r'href="(.+?)"' + block = scrapertoolsV2.find_single_match(data, patronBlock) + urls = scrapertoolsV2.find_multiple_matches(block, patron) + #support.regexDbg(item, patron, headers, data=data) - if 'keepem.online' in data: - urls = scrapertoolsV2.find_multiple_matches(data, r'(https://keepem\.online/f/[^"]+)"') - for url in urls: - url = httptools.downloadpage(url).url - itemlist += servertools.find_video_items(data=url) + for url in urls: + titles = item.infoLabels['title'] + lang = '' + if 'sub_ita' in url.lower(): + lang = 'Sub-ITA' + else: + lang = 'ITA' - return support.server(item, data, itemlist) + if 'keepem.online' in data: + urls = scrapertoolsV2.find_multiple_matches(data, r'(https://keepem\.online/f/[^"]+)"') + for url in urls: + url = httptools.downloadpage(url).url + itemlist += servertools.find_video_items(data=url) + + elif 'keepsetsu' in url.lower() or 'woof' in url.lower(): + if 'keepsetsu' in url.lower(): + support.log("keepsetsu url -> ", url ) + data = httptools.downloadpage(url).url + support.log("LINK-DATA :", data) + + data = httptools.downloadpage(data).data + support.log("LINK-DATA2 :", data) + video_urls = scrapertoolsV2.find_single_match(data, r'<meta name="description" content="([^"]+)"') + + else: + + data = httptools.downloadpage(url).data + #host_video = scrapertoolsV2.find_single_match(data, r'var thisPageUrl = "(http[s]\:\/\/[^\/]+).+?"') + host_video = scrapertoolsV2.find_single_match(data, r'let thisPageUrl = "(http[s]\:\/\/[^\/]+).+?"') + link = scrapertoolsV2.find_single_match(data, r'<video src="([^"]+)"') + video_urls = host_video+link + + title_show = support.typo(titles,'_ bold') + support.typo(lang,'_ [] color kod') + + itemlist.append( + support.Item(channel=item.channel, + action="play", + contentType=item.contentType, + title=title_show, + fulltitle=item.fulltitle, + show=item.fulltitle, + url=video_urls, + infoLabels = item.infoLabels, + thumbnail=item.thumbnail, + contentSerieName= item.fulltitle, + contentTitle=title_show, + contentLanguage = 'ITA' if lang == [] else lang, + args=item.args, + server='directo', + )) + + if item.contentType != 'episode' and int(item.nep) < 2 : + # Link Aggiungi alla Libreria + if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findservers': + support.videolibrary(itemlist, item) + # link per scaricare + if config.get_setting('downloadenabled'): + support.download(itemlist, item) + return itemlist diff --git a/channels/eurostreaming.json b/channels/eurostreaming.json index 3fb5ddf3..88d7d021 100644 --- a/channels/eurostreaming.json +++ b/channels/eurostreaming.json @@ -1,57 +1,11 @@ { - "id": "eurostreaming", - "name": "Eurostreaming", + "id": "eurostreaming", + "name": "Eurostreaming", "active": true, - "adult": false, - "language": ["ita"], - "thumbnail": "https://eurostreaming.cafe/wp-content/uploads/2017/08/logocafe.png", - "bannermenu": "https://eurostreaming.cafe/wp-content/uploads/2017/08/logocafe.png", - "categories": ["tvshow","anime","vosi"], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://eurostreaming.cafe", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "Non filtrare", - "ITA", - "vosi" - ] - } - ] + "adult": false, + "language": ["ita","sub-ita"], + "thumbnail": "eurostreaming.png", + "banner": "eurostreaming.png", + "categories": ["tvshow","anime","vos"], + "settings": [] } diff --git a/channels/eurostreaming.py b/channels/eurostreaming.py index 817cbf45..7e96865e 100644 --- a/channels/eurostreaming.py +++ b/channels/eurostreaming.py @@ -4,176 +4,151 @@ # by Greko # ------------------------------------------------------------ """ - Riscritto per poter usufruire del modulo support. - Problemi noti: - Le regex non prendono tutto... - server versystream : 'http://vcrypt.net/very/' # VeryS non decodifica il link :http://vcrypt.net/fastshield/ - alcuni server tra cui nowvideo.club non sono implementati nella cartella servers - Alcune sezioni di anime-cartoni non vanno, alcune hanno solo la lista degli episodi, ma non hanno link - altre cambiano la struttura - La sezione novità non fa apparire il titolo degli episodi - - In episodios è stata aggiunta la possibilità di configurare la videoteca + Problemi noti da non considerare come errori nel test: + - Alcune sezioni di anime-cartoni non vanno: + - alcune hanno solo la lista degli episodi, ma non hanno link! + Novità(globale): + - serie, anime """ - -import channelselector -from specials import autoplay, filtertools -from core import scrapertoolsV2, httptools, servertools, tmdb, support +import re +from core import scrapertoolsV2, httptools, support from core.item import Item -from platformcode import logger, config +from platformcode import config + +#impostati dinamicamente da findhost() +host = "" +headers = "" + +def findhost(): + global host, headers + permUrl = httptools.downloadpage('https://eurostreaming.link/', follow_redirects=False).headers + host = 'https://www.'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') + headers = [['Referer', host]] + -__channel__ = "eurostreaming" -host = config.get_channel_url(__channel__) -headers = ['Referer', host] list_servers = ['verystream', 'wstream', 'speedvideo', 'flashx', 'nowvideo', 'streamango', 'deltabit', 'openload'] list_quality = ['default'] -__comprueba_enlaces__ = config.get_setting('comprueba_enlaces', 'eurostreaming') -__comprueba_enlaces_num__ = config.get_setting('comprueba_enlaces_num', 'eurostreaming') - -IDIOMAS = {'Italiano': 'ITA', 'Sub-ITA':'vosi'} -list_language = IDIOMAS.values() - +@support.menu def mainlist(item): - #import web_pdb; web_pdb.set_trace() - support.log() - itemlist = [] - - support.menu(itemlist, 'Serie TV', 'serietv', host, contentType = 'tvshow') # mettere sempre episode per serietv, anime!! - support.menu(itemlist, 'Serie TV Archivio submenu', 'serietv', host + "/category/serie-tv-archive/", contentType = 'tvshow') - support.menu(itemlist, 'Ultimi Aggiornamenti submenu', 'serietv', host + '/aggiornamento-episodi/', args='True', contentType = 'tvshow') - support.menu(itemlist, 'Anime / Cartoni', 'serietv', host + '/category/anime-cartoni-animati/', contentType = 'tvshow') - support.menu(itemlist, 'Cerca...', 'search', host, contentType = 'tvshow') - -## itemlist = filtertools.show_option(itemlist, item.channel, list_language, list_quality) - # richiesto per autoplay - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - support.channel_config(item, itemlist) - - return itemlist - -def serietv(item): - #import web_pdb; web_pdb.set_trace() - # lista serie tv support.log() - itemlist = [] - if item.args: - # il titolo degli episodi viene inglobato in episode ma non sono visibili in newest!!! - patron = r'<span class="serieTitle" style="font-size:20px">(.*?).[^–]<a href="([^"]+)"\s+target="_blank">(.*?)<\/a>' - listGroups = ['title', 'url', 'title2'] - patronNext = '' + findhost() + + tvshow = ['' + ] + anime = ['/category/anime-cartoni-animati/' + ] + mix = [ + (support.typo('Aggiornamenti Serie-Anime', 'bullet bold'), ['/aggiornamento-episodi/', 'peliculas', 'newest']), + (support.typo('Archivio Serie-Anime', 'bullet bold'), ['/category/serie-tv-archive/', 'peliculas']) + ] + search = '' + + return locals() + + +@support.scrape +def peliculas(item): + support.log() + #findhost() + action = 'episodios' + if item.args == 'newest': + #patron = r'<span class="serieTitle" style="font-size:20px">(?P<title>.*?).[^–][\s]?<a href="(?P<url>[^"]+)"\s+target="_blank">(?P<episode>\d+x\d+-\d+|\d+x\d+) (?P<title2>.*?)[ ]?(?:|\((?P<lang>SUB ITA)\))?</a>' + patron = r'<span class="serieTitle" style="font-size:20px">(?P<title>.*?).[^–][\s]?<a href="(?P<url>[^"]+)"\s+target="_blank">(?:<episode>\d+x\d+-\d+|\d+x\d+) .*?[ ]?\(?(?P<lang>SUB ITA)?\)?</a>' + pagination = '' else: - patron = r'<div class="post-thumb">.*?\s<img src="([^"]+)".*?><a href="([^"]+)".*?>(.*?(?:\((\d{4})\)|(\d{4}))?)<\/a><\/h2>' - listGroups = ['thumb', 'url', 'title', 'year', 'year'] + patron = r'<div class="post-thumb">.*?\s<img src="(?P<thumb>[^"]+)".*?><a href="(?P<url>[^"]+)"[^>]+>(?P<title>.+?)\s?(?: Serie Tv)?\s?\(?(?P<year>\d{4})?\)?<\/a><\/h2>' patronNext='a class="next page-numbers" href="?([^>"]+)">Avanti »</a>' - itemlist = support.scrape(item, patron_block='', patron=patron, listGroups=listGroups, - patronNext=patronNext, action='episodios') - return itemlist - + #debug = True + return locals() +@support.scrape def episodios(item): -## import web_pdb; web_pdb.set_trace() - support.log("episodios") - itemlist = [] + support.log("episodios: %s" % item) + #findhost() + action = 'findvideos' + item.contentType = 'tvshow' # Carica la pagina - data = httptools.downloadpage(item.url).data - #======== + data1 = pagina(item.url) + data1 = re.sub('\n|\t', ' ', data1) + data = re.sub(r'>\s+<', '> <', data1) + #patronBlock = r'(?P<block>STAGIONE\s\d+ (.+?)?(?:\()?(?P<lang>ITA|SUB ITA)(?:\))?.*?)</div></div>' + patronBlock = r'</span>(?P<block>[a-zA-Z\s]+\d+(.+?)?(?:\()?(?P<lang>ITA|SUB ITA)(?:\))?.*?)</div></div>' + #patron = r'(?:\s|\Wn)?(?:<strong>|)?(?P<episode>\d+&#\d+;\d+-\d+|\d+&#\d+;\d+)(?:</strong>|)?(?P<title>.+?)(?:–|-.+?-|–.+?–|–|.)?<a (?P<url>.*?)<br />' + patron = r'(?:\s|\Wn)?(?:<strong>|)?(?P<episode>\d+&#\d+;\d+-\d+|\d+&#\d+;\d+)(?:</strong>|)?(?P<title>.+?)(?:–|-.+?-|–.+?–|–|.)?(?:<a (?P<url>.*?))?<br />' + + def itemHook(item): + if not item.url: + item.title += ' [B][COLOR red]### NO LINK ###[/COLOR][/B]' + return item + + #support.regexDbg(item, patronBlock, headers, data) + #debug = True + return locals() + +def pagina(url): + support.log(url) + #findhost() + + data = httptools.downloadpage(url, headers=headers).data.replace("'", '"') + #support.log("DATA ----###----> ", data) if 'clicca qui per aprire' in data.lower(): - item.url = scrapertoolsV2.find_single_match(data, '"go_to":"([^"]+)"') - item.url = item.url.replace("\\","") + url = scrapertoolsV2.find_single_match(data, '"go_to":"([^"]+)"') + url = url.replace("\\","") # Carica la pagina - data = httptools.downloadpage(item.url).data + data = httptools.downloadpage(url, headers=headers).data.replace("'", '"') + elif 'clicca qui</span>' in data.lower(): item.url = scrapertoolsV2.find_single_match(data, '<h2 style="text-align: center;"><a href="([^"]+)">') - # Carica la pagina - data = httptools.downloadpage(item.url).data - #========= - patron = r'(?:<\/span>\w+ STAGIONE\s\d+ (?:\()?(ITA|SUB ITA)(?:\))?<\/div>'\ - '<div class="su-spoiler-content su-clearfix" style="display:none">|'\ - '(?:\s|\Wn)?(?:<strong>)?(\d+&#.*?)(?:|–)?<a\s(.*?)<\/a><br\s\/>)' -## '(?:<\/span>\w+ STAGIONE\s\d+ (?:\()?(ITA|SUB ITA)(?:\))?'\ -## '<\/div><div class="su-spoiler-content su-clearfix" style="display:none">|'\ -## '(?:\s|\Wn)?(?:<strong>)?(\d[&#].*?)(?:–|\W)?<a\s(.*?)<\/a><br\s\/>)' -## '(?:<\/span>\w+ STAGIONE\s\d+ (?:\()?(ITA|SUB ITA)(?:\))?<\/div>'\ -## '<div class="su-spoiler-content su-clearfix" style="display:none">|'\ -## '\s(?:<strong>)?(\d[&#].*?)–<a\s(.*?)<\/a><br\s\/>)' - listGroups = ['lang', 'title', 'url'] - itemlist = support.scrape(item, data=data, patron=patron, - listGroups=listGroups, action='findvideos') + # Carica la pagina + data = httptools.downloadpage(url, headers=headers).data.replace("'", '"') - # Permette la configurazione della videoteca senza andare nel menu apposito - # così si possono Attivare/Disattivare le impostazioni direttamente dalla - # pagina delle puntate - itemlist.append( - Item(channel='setting', - action="channel_config", - title=support.typo("Configurazione Videoteca color lime"), - plot = 'Filtra per lingua utilizzando la configurazione della videoteca.\ - Escludi i video in sub attivando "Escludi streams... " e aggiungendo sub in Parole', - config='videolibrary', #item.channel, - folder=False, - thumbnail=channelselector.get_thumb('setting_0.png') - )) - - itemlist = filtertools.get_links(itemlist, item, list_language) - return itemlist - -# =========== def findvideos ============= - -def findvideos(item): - support.log() - itemlist =[] - - # Requerido para FilterTools -## itemlist = filtertools.get_links(itemlist, item, list_language) - - itemlist = support.server(item, item.url) -## support.videolibrary(itemlist, item) - - return itemlist + return data # =========== def ricerca ============= def search(item, texto): support.log() + findhost() item.url = "%s/?s=%s" % (host, texto) + item.contentType = 'tvshow' + try: - return serietv(item) + return peliculas(item) + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.log(line) return [] # =========== def novità in ricerca globale ============= + def newest(categoria): - support.log() + support.log() + findhost() itemlist = [] item = Item() - item.contentType= 'episode' - item.args= 'True' - try: + item.contentType = 'tvshow' + item.args = 'newest' + try: item.url = "%s/aggiornamento-episodi/" % host - item.action = "serietv" - itemlist = serietv(item) - - if itemlist[-1].action == "serietv": - itemlist.pop() - - # Continua la ricerca in caso di errore + item.action = "peliculas" + itemlist = peliculas(item) + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.log("{0}".format(line)) return [] return itemlist -def paginator(item): - pass +# =========== def findvideos ============= +def findvideos(item): + support.log('findvideos', item) + return support.server(item, item.url) diff --git a/channels/fastsubita.json b/channels/fastsubita.json index 2db8f206..3feb7834 100644 --- a/channels/fastsubita.json +++ b/channels/fastsubita.json @@ -1,70 +1,12 @@ { "id": "fastsubita", "name": "Fastsubita", - "language": ["ita"], + "language": ["sub-ita"], "active": true, "adult": false, "thumbnail": "fastsubita.png", "banner": "fastsubita.png", - "categories": ["tvshow", "vosi"], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "http://fastsubita.com", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "categories": ["tvshow", "vos"], + "not_active": ["include_in_newest_peliculas", "include_in_newest_anime", "include_in_newest_italiano"], + "settings": [] } diff --git a/channels/fastsubita.py b/channels/fastsubita.py index bc7e1c5e..71fd1af5 100644 --- a/channels/fastsubita.py +++ b/channels/fastsubita.py @@ -1,347 +1,177 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per fastsubita -# Thanks Icarus crew & Alfa addon & 4l3x87 +# Canale per fastsubita.py # ------------------------------------------------------------ +""" -from core import scrapertools, httptools, tmdb, support + Su questo canale, nella categoria 'Ricerca Globale' + non saranno presenti le voci 'Aggiungi alla Videoteca' + e 'Scarica Film'/'Scarica Serie', dunque, + la loro assenza, nel Test, NON dovrà essere segnalata come ERRORE. + + Novità. Indicare in quale/i sezione/i è presente il canale: + - serie + + Ulteriori info: + - SOLO SUB-ITA + +""" +from core import support, httptools, scrapertoolsV2 from core.item import Item from core.support import log -from platformcode import config, logger +from platformcode import config __channel__ = 'fastsubita' -host = config.get_setting("channel_host", __channel__) -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() +host = config.get_channel_url(__channel__) +headers = [['Referer', host]] list_servers = ['verystream', 'openload', 'speedvideo', 'wstream', 'flashx', 'vidoza', 'vidtome'] list_quality = ['default'] -headers = [ - ['Host', host.split("//")[-1].split("/")[0]], - ['User-Agent', 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0'], - ['Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'], - ['Accept-Language', 'en-US,en;q=0.5'], - ['Accept-Encoding', 'gzip, deflate'], - ['Referer', host], - ['DNT', '1'], - ['Connection', 'keep-alive'], - ['Upgrade-Insecure-Requests', '1'], - ['Cache-Control', 'max-age=0'] -] - -PERPAGE = 15 - +@support.menu def mainlist(item): - log() + + Tvshow = [ + ('Aggiornamenti', ['', 'peliculas', '', 'tvshow']), + ('Per Lettera', ['/elenco-serie-tv/', 'genres', 'genres']) + ] + + search = '' + + return locals() + + +@support.scrape +def peliculas(item): + support.log(item) + #support.dbg() + deflang = 'Sub-ITA' + + action = 'findvideos' + blacklist = [''] + if item.args == 'genres': + patronBlock = r'<h4 id="mctm1-.">'+item.fulltitle+'</h4>(?P<block>.+?)</div>' + patron = r'[^>]+>[^>]+>.+?href="(?P<url>[^"]+)[^>]>(?P<title>[^<]+)\s<' + action = 'episodios' + elif item.args == 'search': + patronBlock = r'</h1> </header>(?P<block>.*?)</main>' + patron = r'(?:<img src="(?P<thumb>[^"]+)"[^>]+>)?[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="(?P<url>[^"]+)"[^>]+>(?:(?P<title>.+?)[ ](?P<episode>[\d&#;\d]+\d+|\d+..\d+)(?: \([a-zA-Z\s]+\) )(?:s\d+e\d+)?[ ]?(?:[&#\d;|.{3}]+)(?P<title2>[^&#\d;|^.{3}]+)(?:|.+?))<' + else: + patron = r'<div class="featured-thumb"> <a href="(?P<url>[^"]+)" title="(?:(?P<title>.+?)[ ]?(?P<episode>\d+×\d+).+?“(?P<title2>.+?)”).+?">' + patronBlock = r'<main id="main" class="site-main" role="main">(?P<block>.*?)<nav class="navigation pagination" role="navigation">' + + patronNext = '<a class="next page-numbers" href="(.*?)">Successivi' + + #debug = True + return locals() + + +@support.scrape +def episodios(item): + support.log(item) + #support.dbg() + + deflang = 'Sub-ITA' + action = 'findvideos' + blacklist = [''] + patron = r'<div class="featured-thumb"> <a href="(?P<url>[^"]+)" title="(?:(?P<title>.+?)[ ]?(?P<episode>\d+×\d+|\d+[×.]+\d+).+?“(?P<title2>.+?)”).+?">' + patronBlock = r'<main id="main" class="site-main" role="main">(?P<block>.*?)</main>' + patronNext = '<a class="next page-numbers" href="(.*?)">Successivi' + + #debug = True + return locals() + +@support.scrape +def genres(item): + support.log() + #support.dbg() + + action = 'peliculas' + patronBlock = r'<div id="mcTagMapNav">(?P<block>.+?)</div>' + patron = r'<a href="(?P<url>[^"]+)">(?P<title>.+?)</a>' + + def itemHook(item): + item.url = host+'/elenco-serie-tv/' + item.contentType = 'tvshow' + return item + + #debug = True + return locals() + + +def search(item, text): + support.log('search', item) itemlist = [] - - support.menu(itemlist, 'Novità bold', 'pelicuals_tv', host, 'tvshow') - support.menu(itemlist, 'Serie TV bold', 'lista_serie', host, 'tvshow') - support.menu(itemlist, 'Archivio A-Z submenu', 'list_az', host, 'tvshow', args=['serie']) - support.menu(itemlist, 'Cerca', 'search', host, 'tvshow') - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) - - return itemlist - - -# ---------------------------------------------------------------------------------------------------------------- -def cleantitle(scrapedtitle): - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle.strip()) - scrapedtitle = scrapedtitle.replace('’', '\'').replace('×', 'x').replace('×', 'x').replace('"', "'") - - return scrapedtitle.strip() - - -# ================================================================================================================ - - -def newest(categoria): - log() - itemlist = [] - item = Item() + text = text.replace(' ', '+') + item.url = host + '?s=' + text try: - if categoria == "series": - item.url = host - # item.action = "serietv" - itemlist = pelicuals_tv(item) - - if itemlist[-1].action == "serietv": - itemlist.pop() - - # Continua la ricerca in caso di errore + item.args = 'search' + item.contentType = 'tvshow' + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + log('search log:', line) return [] - return itemlist - -def pelicuals_tv(item): - log() +def newest(categoria): + support.log('newest ->', categoria) itemlist = [] + item = Item() + if categoria == 'series': + try: + item.contentType = 'tvshow' + item.args = 'newest' + item.url = host + item.action = 'peliculas' + itemlist = peliculas(item) - matches, data = support.match(item, r'<h3 class="entry-title title-font"><a href="([^"]+)" rel="bookmark">(.*?)<', - headers=headers) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - scraped_1 = scrapedtitle.split("×")[0][:-2] - scrapedtitle = cleantitle(scrapedtitle) - episode = scrapertools.find_multiple_matches(scrapedtitle, r'((\d*)x(\d*))')[0] - scrapedtitle = scrapedtitle.replace(scraped_1, "") - - infoLabels = {} - infoLabels['season'] = episode[1] - infoLabels['episode'] = episode[2] - - if "http:" in scrapedurl: - scrapedurl = scrapedurl - else: - scrapedurl = "http:" + scrapedurl - - - serie = cleantitle(scraped_1) - title = serie + " - " + infoLabels['season'] + "x" + infoLabels['episode'] + " "+support.typo('Sub-ITA', '_ [] color kod') - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentTpye="tvshow", - title=title, - fulltitle=title, - url=scrapedurl, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - show=serie, - extra=item.extra, - contentSerieName=serie, - contentLanguage='Sub-ITA', - infoLabels=infoLabels, - folder=True)) - support.checkHost(item, itemlist) - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - # Paginazione - support.nextPage(itemlist, item, data, '<a class="next page-numbers" href="(.*?)">Successivi') - - return itemlist - - -def serietv(): - log() - - itemlist = [] - matches = support.match(Item(), r'<option class="level-([0-9]?)" value="([^"]+)">([^<]+)</option>', - r'<select\s*?name="cat"\s*?id="cat"\s*?class="postform"\s*?>(.*?)</select>', headers, - url="%s/" % host)[0] - index = 0 - - for level, cat, title in matches: - title = cleantitle(title) - url = '%s?cat=%s' % (host, cat) - if int(level) > 0: - itemlist[index - 1][0] += '{|}' + url - continue - - itemlist.append([url, title]) - - index += 1 - return itemlist - - -def lista_serie(item): - log() - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - if '||' in item.url: - series = item.url.split('\n\n') - matches = [] - for i, serie in enumerate(series): - matches.append(serie.split('||')) - series = matches - else: - series = serietv() - - for i, (scrapedurl, scrapedtitle) in enumerate(series): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - - scrapedplot = "" - scrapedthumbnail = "" - - itemlist.append( - Item(channel=item.channel, - action="episodios", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - show=scrapedtitle, - extra=item.extra, - contentType='episode', - originalUrl=scrapedurl, - folder=True)) - - support.checkHost(item, itemlist) - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - if len(series) >= p * PERPAGE: - next_page = item.url + '{}' + str(p + 1) - support.nextPage(itemlist, item, next_page=next_page) + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log('newest log: ', {0}.format(line)) + return [] return itemlist def findvideos(item): - log() + support.log('findvideos ->', item) itemlist = [] - - # data = httptools.downloadpage(item.url, headers=headers).data - patron_block = '<div class="entry-content">(.*?)<footer class="entry-footer">' - # bloque = scrapertools.find_single_match(data, patron_block) - + patronBlock = '<div class="entry-content">(?P<block>.*)<footer class="entry-footer">' patron = r'<a href="([^"]+)">' - # matches = re.compile(patron, re.DOTALL).findall(bloque) - - matches, data = support.match(item, patron, patron_block, headers) + matches, data = support.match(item, patron, patronBlock, headers) + if item.args != 'episodios': + item.infoLabels['mediatype'] = 'episode' for scrapedurl in matches: if 'is.gd' in scrapedurl: - resp = httptools.downloadpage( - scrapedurl, follow_redirects=False) + resp = httptools.downloadpage(scrapedurl, follow_redirects=False) data += resp.headers.get("location", "") + '\n' - return support.server(item, data) + itemlist += support.server(item, data) - -def search(item, texto): - log(texto) - - itemlist = [] - try: - series = serietv() - for i, (scrapedurl, scrapedtitle) in enumerate(series): - if texto.upper() in scrapedtitle.upper(): - scrapedthumbnail = "" - scrapedplot = "" - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="episodios", - title=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=scrapedtitle, - show=scrapedtitle, - plot=scrapedplot, - contentType='episode', - originalUrl=scrapedurl, - folder=True)) - return itemlist - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -# ---------------------------------------------------------------------------------------------------------------- - -def list_az(item): - log() - itemlist = [] - - alphabet = dict() - - for i, (scrapedurl, scrapedtitle) in enumerate(serietv()): - letter = scrapedtitle[0].upper() - if letter not in alphabet: - alphabet[letter] = [] - alphabet[letter].append(scrapedurl + '||' + scrapedtitle) - - for letter in sorted(alphabet): - itemlist.append( - Item(channel=item.channel, - action="lista_serie", - url='\n\n'.join(alphabet[letter]), - title=letter, - fulltitle=letter)) + data = httptools.downloadpage(item.url).data + patron = r'>Posted in <a href="https?://fastsubita.com/serietv/([^/]+)/(?:[^"]+)?"' + series = scrapertoolsV2.find_single_match(data, patron) + titles = support.typo(series.upper().replace('-', ' '), 'bold color kod') + goseries = support.typo("Vai alla Serie:", ' bold color kod') + itemlist.append( + Item(channel=item.channel, + title=goseries + titles, + fulltitle=titles, + show=series, + contentType='tvshow', + contentSerieName=series, + url=host+"/serietv/"+series, + action='episodios', + contentTitle=titles, + plot = "Vai alla Serie " + titles + " con tutte le puntate", + )) return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def episodios(item, itemlist=[]): - log() - urls = item.url.split('{|}') - patron = r'<h3 class="entry-title title-font"><a href="([^"]+)" rel="bookmark">(.*?)<' - matches, data = support.match(item, patron, headers=headers, url=urls[0]) - urls.pop(0) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - scrapedtitle = cleantitle(scrapedtitle) - episode = scrapertools.find_multiple_matches(scrapedtitle, r'((\d*)x(\d*))')[0] - - season = episode[1].lstrip('0').zfill(2) - - infoLabels = {} - infoLabels['season'] = season - infoLabels['episode'] = episode[2] - title = infoLabels['season'] + 'x' + infoLabels['episode'] + " "+support.typo('Sub-ITA', '_ [] color kod') - - if "http:" not in scrapedurl: - scrapedurl = "http:" + scrapedurl - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentTpye="episode", - title=title, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - show=item.show, - extra=item.extra, - infoLabels=infoLabels, - folder=True)) - - next_page = scrapertools.find_single_match(data, r'<a class="next page-numbers" href="(.*?)">Successivi') - if next_page != "": - urls.insert(0, next_page) - - if len(urls) > 0: - item.url = '{|}'.join(urls) - itemlist = episodios(item, itemlist) - else: - cleanItemlist = [] - episodes = [] - for episode in itemlist: - if episode.title in episodes: continue - cleanItemlist.append(episode) - episodes.append(episode.title) - itemlist = cleanItemlist - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - item.url = item.originalUrl - support.videolibrary(itemlist, item, 'bold color kod') - - return itemlist - -# ================================================================================================================ diff --git a/channels/filmigratis.json b/channels/filmigratis.json index b6f56db2..46290f5b 100644 --- a/channels/filmigratis.json +++ b/channels/filmigratis.json @@ -3,68 +3,34 @@ "name": "Filmi Gratis", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita", "sub-ita"], "thumbnail": "filmigratis.png", "banner": "filmigratis.png", - "categories": ["movie","tvshow"], + "categories": ["movie","tvshow"], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "2", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_series", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + } ] } diff --git a/channels/filmigratis.py b/channels/filmigratis.py index 39b4bfff..a40c92aa 100644 --- a/channels/filmigratis.py +++ b/channels/filmigratis.py @@ -2,297 +2,156 @@ # ------------------------------------------------------------ # Canale per Filmi Gratis # ------------------------------------------------------------ +""" + La voce "Al cinema" si riferisce ai titoli che scorrono nella home page + + Problemi: + - Nessuno noto + + Novità, il canale, è presente in: + - FILM +""" import re -from core import scrapertools, servertools, httptools, tmdb, support +from core import servertools, httptools, support from core.item import Item -from platformcode import logger, config -from specials import autoplay +from platformcode import config __channel__ = 'filmigratis' host = config.get_channel_url(__channel__) -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['openload', 'streamango', 'vidoza', 'okru'] -list_quality = ['1080p', '720p', '480p', '360'] -checklinks = config.get_setting('checklinks', 'filmigratis') -checklinks_number = config.get_setting('checklinks_number', 'filmigratis') +list_servers = ['verystream', 'openload', 'streamango', 'vidoza', 'okru'] +list_quality = ['1080p', '720p', '480p', '360'] headers = [['Referer', host]] -#----------------------------------------------------------------------------------------------------------------------- +@support.menu def mainlist(item): + film = [ + ('Al Cinema ', ['', 'peliculas', 'cinema']), + ('Categorie', ['', 'genres', 'genres']), + ] - # Main options - itemlist = [] - support.menu(itemlist, 'Al Cinema bold', 'carousel', host, contentType='movie') - support.menu(itemlist, 'Film alta definizione bold', 'peliculas', host, contentType='movie', args='film') - support.menu(itemlist, 'Categorie Film bold', 'categorias_film', host , contentType='movie', args='film') - support.menu(itemlist, 'Categorie Serie bold', 'categorias_serie', host, contentType='tvshow', args='serie') - support.menu(itemlist, '[COLOR blue]Cerca Film...[/COLOR] bold', 'search', host, contentType='movie', args='film') - support.menu(itemlist, '[COLOR blue]Cerca Serie...[/COLOR] bold', 'search', host, contentType='tvshow', args='serie') + tvshow = ['/serie/ALL', + ('Generi', ['', 'genres', 'genres']) + ] - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def carousel(item): - logger.info('[filmigratis.py] carousel') - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = scrapertools.find_single_match(data, r'<div class="owl-carousel" id="postCarousel">(.*?)<section class="main-content">') - - patron = r'background-image: url\((.*?)\).*?<h3.*?>(.*?)<.*?<a.*?<a href="(.*?)"' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for scrapedthumb, scrapedtitle, scrapedurl, in matches: - itemlist.append( - Item(channel=item.channel, - action = "findvideos", - contentType = item.contentType, - title = scrapedtitle, - fulltitle = scrapedtitle, - url = scrapedurl, - thumbnail = scrapedthumb, - args=item.args, - show = scrapedtitle,)) - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- + search = '' + return locals() +@support.scrape def peliculas(item): - logger.info('[filmigratis.py] peliculas') - itemlist = [] + support.log() - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = scrapertools.find_single_match(data, r'<h1>Film streaming ita in alta definizione</h1>(.*?)<div class="content-sidebar">') - - patron = r'<div class="timeline-left-wrapper">.*?<a href="(.*?)".*?src="(.*?)".*?<h3.*?>(.*?)<' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for scrapedurl, scrapedthumb, scrapedtitle, in matches: - itemlist.append( - Item(channel=item.channel, - action = "findvideos", - contentType = item.contentType, - title = scrapedtitle, - fulltitle = scrapedtitle, - url = scrapedurl, - thumbnail = scrapedthumb, - args=item.args, - show = scrapedtitle)) - - patron = r'class="nextpostslink".*?href="(.*?)"' - next_page = scrapertools.find_single_match(data, patron) - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="peliculas", - title="[B]" + config.get_localized_string(30992) + "[/B]", - args=item.args, - url=next_page)) - - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def categorias_film(item): - logger.info("[filmigratis.py] categorias_film") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - bloque = scrapertools.find_single_match(data, 'CATEGORIES.*?<ul>(.*?)</ul>') - - patron = '<a href="(.*?)">(.*?)<' - matches = re.compile(patron, re.DOTALL).findall(bloque) - - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item(channel=__channel__, - action="peliculas_categorias", - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - url=scrapedurl, - args=item.args, - thumbnail="")) - - return itemlist -#----------------------------------------------------------------------------------------------------------------------- - -def categorias_serie(item): - logger.info("[filmigratis.py] categorias_serie") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - bloque = scrapertools.find_single_match(data, 'class="material-button submenu-toggle"> SERIE TV.*?<ul>.*?</li>(.*?)</ul>') - - patron = '<a href="(.*?)">(.*?)<' - matches = re.compile(patron, re.DOTALL).findall(bloque) - - for scrapedurl, scrapedtitle in matches: - itemlist.append( - Item(channel=__channel__, - contentType='tvshow', - action="peliculas_serie", - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - url=scrapedurl, - args=item.args, - thumbnail="")) - - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def peliculas_categorias(item): - logger.info("[filmigratis.py] peliculas_categorias") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<div class="cnt">.*?src="(.*?)".*?title="([A-Z|0-9].*?)".*?<a href="(.*?)"' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumb, scrapedtitle, scrapedurl in matches: - if scrapedtitle == "": - scrapedtitle = scrapertools.find_single_match(data, r'<small>.*?([A-Z|0-9].*?) <') - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = scrapedtitle.replace ("È","È") - scrapedtitle = scrapedtitle.replace("–", "-") - scrapedtitle = scrapedtitle.replace("’", "'") - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType=item.contentType, - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumb, - args=item.args, - show=scrapedtitle)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def peliculas_serie(item): - logger.info("[filmigratis.py] peliculas_serie") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'div class="cnt">[^s]+src="([^"]+).*?small>\s+[^A-Z](.*?)<.*?<a href="([^"]+)' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedthumb, scrapedtitle, scrapedurl in matches: - if scrapedtitle == "": - scrapedtitle = scrapertools.find_single_match(data, r'<small>.*?([A-Z|0-9].*?) <') - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = scrapedtitle.replace ("È","È") - scrapedtitle = scrapedtitle.replace("–", "-") - scrapedtitle = scrapedtitle.replace("’", "'") - scrapedtitle = scrapedtitle.replace(" ", "") - itemlist.append( - Item(channel=item.channel, - action="episodios", - contentType='tvshow', - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumb, - args=item.args, - show=scrapedtitle)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def episodios(item): - logger.info("[filmigratis.py] episodios") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - block = scrapertools.find_single_match(data, r'<div class="row">(.*?)<section class="main-content">') - - patron = r'href="(.*?)".*?(S[^<]+) <' - matches = re.compile(patron, re.DOTALL).findall(block) - - for scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = scrapedtitle.replace ("S0", "") - scrapedtitle = scrapedtitle.replace(" - EP ", "x") - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType='episode', - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=item.thumb, - args=item.args, - show=item.title)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - support.videolibrary(itemlist, item, 'color kod') - return itemlist - -#----------------------------------------------------------------------------------------------------------------------- - -def search(item, texto): - logger.info('[filmigratis.py] search') - - item.url = host + '/search/?s=' + texto - - if item.args == 'serie': - try: - return peliculas_serie(item) - - except: - import sys - for line in sys.exc_info(): - logger.error('%s' % line) - return [] + if item.args == 'search': + action = '' + patron = r'<div class="cnt">.*?src="([^"]+)"[^>]+>[^>]+>[^>]+>\s+(?P<title>.+?)(?:\[(?P<lang>Sub-ITA|SUB-ITA|SUB)\])?\s?(?:\[?(?P<quality>HD).+\]?)?\s?(?:\(?(?P<year>\d+)?\)?)?\s+<[^>]+>[^>]+>[^>]+>\s<a href="(?P<url>[^"]+)"[^<]+<' + patronBlock = r'<div class="container">(?P<block>.*?)</main>' + elif item.contentType == 'movie': + if not item.args: + # voce menu: Film + patronBlock = r'<h1>Film streaming ita in alta definizione</h1>(?P<block>.*?)<div class="content-sidebar">' + patron = r'<div class="timeline-right">[^>]+>\s<a href="(?P<url>.*?)".*?src="(?P<thumb>.*?)".*?<h3 class="timeline-post-title">(?:(?P<title>.+?)\s\[?(?P<lang>Sub-ITA)?\]?\s?\[?(?P<quality>HD)?\]?\s?\(?(?P<year>\d+)?\)?)<' + patronNext = r'<a class="page-link" href="([^"]+)">>' + elif item.args == 'cinema': + patronBlock = r'<div class="owl-carousel" id="postCarousel">(?P<block>.*?)<section class="main-content">' + patron = r'background-image: url\((?P<thumb>.*?)\).*?<h3.*?>(?:(?P<title>.+?)\s\[?(?P<lang>Sub-ITA)?\]?\s?\[?(?P<quality>HD)?\]?\s?\(?(?P<year>\d+)?\)?)<.+?<a.+?<a href="(?P<url>[^"]+)"[^>]+>' + elif item.args == 'genres': + # ci sono dei titoli dove ' viene sostituito con " da support + data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data + data = re.sub('\n|\t', ' ', data) + patron = r'<div class="cnt">\s.*?src="([^"]+)".+?title="((?P<title>.+?)(?:[ ]\[(?P<lang>Sub-ITA|SUB-ITA)\])?(?:[ ]\[(?P<quality>.*?)\])?(?:[ ]\((?P<year>\d+)\))?)"\s*[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>\s+<a href="(?P<url>[^"]+)"' + patronBlock = r'<div class="container">(?P<block>.*?)</main>' + pagination = '' + patronNext = '<a class="page-link" href="([^"]+)">>>' else: - try: - return peliculas_categorias(item) + action = 'episodios' + patron = r'<div class="cnt">\s.*?src="([^"]+)".+?title="((?P<title>.+?)(?:[ ]\[(?P<lang>Sub-ITA|SUB-ITA)\])?(?:[ ]\[(?P<quality>.*?)\])?(?:[ ]\((?P<year>\d+)\))?)"\s*[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>\s+<a href="(?P<url>[^"]+)"' +## if item.args == 'search': +## patron = r'<div class="cnt">.*?src="([^"]+)".+?[^>]+>[^>]+>[^>]+>\s+((?P<title>.+?)(?:[ ]\[(?P<lang>Sub-ITA|SUB-ITA)\])?(?:[ ]\[(?P<quality>.*?)\])?(?:[ ]\((?P<year>\d+)\))?)\s+<[^>]+>[^>]+>[^>]+>[ ]<a href="(?P<url>[^"]+)"' + patronBlock = r'<div class="container">(?P<block>.*?)</main>' - except: - import sys - for line in sys.exc_info(): - logger.error('%s' % line) - return [] + def itemHook(item): + if item.args == 'search': + if 'series' in item.url: + item.action = 'episodios' + item.contentType = 'tvshow' + else: + item.action = 'findvideos' + item.contentType = 'movie' + return item -#----------------------------------------------------------------------------------------------------------------------- + #debug = True + return locals() + + +@support.scrape +def episodios(item): + support.log() + + action = 'findvideos' + patronBlock = r'<div class="row">(?P<block>.*?)<section class="main-content">' + patron = r'href="(?P<url>.*?)">(?:.+?)?\s+S(?P<season>\d+)\s\-\sEP\s(?P<episode>\d+)[^<]+<' + + return locals() + +@support.scrape +def genres(item): + support.log() + + if item.contentType == 'movie': + action = 'peliculas' + patron = r'<a href="(?P<url>.*?)">(?P<title>.*?)<' + patronBlock = r'CATEGORIES.*?<ul>(?P<block>.*?)</ul>' + else: + item.contentType = 'tvshow' + action = 'peliculas' + blacklist = ['Al-Cinema'] + patron = r'<a href="(?P<url>.*?)">(?P<title>.*?)<' + patronBlock = r'class="material-button submenu-toggle"> SERIE TV.*?<ul>.*?</li>(?P<block>.*?)</ul>' + + return locals() + + +def search(item, text): + support.log('search', item) + + text = text.replace(' ', '+') + item.url = host + '/search/?s=' + text + try: + item.args = 'search' + return peliculas(item) + # Se captura la excepcion, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + log('search log:', line) + return [] + +def newest(categoria): + support.log('newest ->', categoria) + itemlist = [] + item = Item() + try: + if categoria == 'peliculas': + item.url = host + item.contentType = 'movie' + item.action = 'peliculas' + itemlist = peliculas(item) + + if itemlist[-1].action == 'peliculas': + itemlist.pop() + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log({0}.format(line)) + return [] + + return itemlist def findvideos(item): - logger.info('[filmigratis.py] findvideos') - - data = httptools.downloadpage(item.url, headers=headers).data - - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = item.title + '[COLOR green][B] - ' + videoitem.title + '[/B][/COLOR]' - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - videoitem.contentType = item.content - - if item.args == "film": - support.videolibrary(itemlist, item, 'color kod') - - autoplay.start(itemlist, item) - - return itemlist + support.log() + return support.server(item) diff --git a/channels/filmpertutti.json b/channels/filmpertutti.json index 011f40c4..65179cbe 100644 --- a/channels/filmpertutti.json +++ b/channels/filmpertutti.json @@ -3,42 +3,9 @@ "name": "Filmpertutti", "active": true, "adult": false, - "language": ["ita"], - "thumbnail": "https://www.filmpertutti.club/wp-content/themes/blunge/assets/logo.png", - "banner": "https://www.filmpertutti.club/wp-content/themes/blunge/assets/logo.png", + "language": ["ita", "sub-ita"], + "thumbnail": "filmpertutti.png", + "banner": "filmpertutti.png", "categories": ["tvshow","movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Incluir en Novedades - Series", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } -] + "settings": [] } diff --git a/channels/filmpertutti.py b/channels/filmpertutti.py index bf090b28..6a376668 100644 --- a/channels/filmpertutti.py +++ b/channels/filmpertutti.py @@ -1,245 +1,184 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per filmpertutti.co +# Canale per filmpertutti.py # ------------------------------------------------------------ +""" + Questi sono commenti per i beta-tester. + + Su questo canale, nella categoria 'Ricerca Globale' + non saranno presenti le voci 'Aggiungi alla Videoteca' + e 'Scarica Film'/'Scarica Serie', dunque, + la loro assenza, nel Test, NON dovrà essere segnalata come ERRORE. + + Novità (globale). Indicare in quale/i sezione/i è presente il canale: + - film, serie + - I titoli in questa sezione a gruppi di 20 + +""" import re -from channelselector import thumb -from core import scrapertoolsV2, servertools, httptools, tmdb, support +from core import scrapertoolsV2, httptools, support from core.item import Item -from platformcode import config, logger -from specials import autoplay +from platformcode import config + __channel__ = 'filmpertutti' host = config.get_channel_url(__channel__) headers = [['Referer', host]] -list_servers = ['verystream', 'openload', 'streamango', 'wstream', 'akvideo'] +list_servers = ['speedvideo', 'verystream', 'openload', 'streamango', 'wstream', 'akvideo'] list_quality = ['HD', 'SD'] - +@support.menu def mainlist(item): - logger.info() - itemlist =[] + film = ['/category/film/', + ('Generi', ['/category/film/', 'genres', 'lettersF']) + ] - support.menu(itemlist, '[B]Film[/B]', 'peliculas', host + '/category/film/', 'movie') - support.menu(itemlist, '[B] > Film per Genere[/B]', 'genre', host, 'tvshow') - support.menu(itemlist, '[COLOR blue]Cerca Film...[/COLOR]', 'search', '') - support.menu(itemlist, '[B]Serie TV[/B]', 'peliculas', host + '/category/serie-tv/', 'tvshow') - support.menu(itemlist, '[B] > Serie TV in ordine alfabetico[/B]', 'az', host + '/category/serie-tv/', 'tvshow') - support.menu(itemlist, '[COLOR blue]Cerca Serie TV...[/COLOR]', 'search', '', 'tvshow') + tvshow = ['/category/serie-tv/', + ('Aggiornamenti', ['/aggiornamenti-serie-tv/', 'peliculas', 'newest']), + ('Per Lettera', ['/category/serie-tv/', 'genres', 'lettersS']) + ] + + search = '' + return locals() + +@support.scrape +def peliculas(item): + support.log() + + if item.args != 'newest': + patronBlock = r'<ul class="posts">(?P<block>.*)<\/ul>' + patron = r'<li><a href="(?P<url>[^"]+)" data-thumbnail="(?P<thumb>[^"]+)">.*?<div class="title">(?P<title>.+?)(?:\[(?P<lang>Sub-ITA)\])?(?:[ ]\[?(?P<quality>[HD]+)?\])?(?:[ ]\((?P<year>\d+)\)?)?<\/div>' + patronNext = r'<a href="([^"]+)" >Pagina' + + else: + patronBlock = r'<ul class="posts">(?P<block>.*)<div class="clear">' + patron = r'<li>\s?<a href="(?P<url>[^"]+)" data-thumbnail="(?P<thumb>[^"]+)">.*?<div class="title">(?P<title>.+?)(?:\s\[(?P<quality>HD)\])?<\/div>[^>]+>(?:[\dx]+)\s?(?:[ ]\((?P<lang>[a-zA-Z\-]+)\))?.+?</div>' + pagination = '' + + if item.args == 'search': + action = 'select' + elif item.contentType == 'tvshow': + action = 'episodios' + elif item.contentType == 'movie': + action ='findvideos' + else: + action = 'select' + + def itemHook(item): + item.title = item.title.replace(r'-', ' ') + return item + #debug = True + return locals() + +@support.scrape +def episodios(item): + support.log() + + data = httptools.downloadpage(item.url, headers=headers).data + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + + if 'accordion-item' in data: + #patronBlock = r'<span class="season(?:|-title)">(?P<season>\d+)[^>]+>[^>]+>\s+?[^>]+>[^>]+>.+?(?:STAGIONE|Stagione).+?\s(?P<lang>[a-zA-Z\-]+).+?</span>(?P<block>.*?)<div id="disqus_thread">' + patronBlock = r'<span class="season(?:|-title)">(?P<season>\d+)[^>]+>[^>]+>\s+?[^>]+>[^>]+>.+?(?:STAGIONE|Stagione).+?\s(?P<lang>[a-zA-Z\-]+)</span>(?P<block>.*?)\s*(?:<li class="s_title">|<div id="disqus_thread">)' + patron = r'<img src="(?P<thumb>[^"]+)">.*?<li class="season-no">(?P<episode>.*?)<\/li>(?P<url>.*?javascript:;">(?P<title>[^<]+)<.+?)<\/table>' + else: + patronBlock = r'<div id="info" class="pad">(?P<block>.*?)<div id="disqus_thread">' + patron = r'<strong>(?P<lang>.*?)<\/strong>.*?<p>(?P<season>.*?)<span' + + #debug = True + return locals() - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - for item in itemlist: - logger.info('MENU=' + str(item) ) - - return itemlist - - -def newest(categoria): - logger.info("filmpertutti newest" + categoria) +@support.scrape +def genres(item): + support.log() itemlist = [] - item = Item() - try: - if categoria == "film": - item.url = host + "/category/film/" - item.action = "peliculas" - item.extra = "movie" - itemlist = peliculas(item) - if itemlist[-1].action == "peliculas": - itemlist.pop() + if item.args == 'lettersF': + item.contentType = 'movie' + else: + item.contentType = 'tvshow' - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] + action = 'peliculas' + patronBlock = r'<select class="cats">(?P<block>.*?)<\/select>' + patron = r'<option data-src="(?P<url>[^"]+)">(?P<title>.*?)<\/option>' - return itemlist + return locals() + +def select(item): + support.log() + + + data = httptools.downloadpage(item.url, headers=headers).data + patronBlock = scrapertoolsV2.find_single_match(data, r'class="taxonomy category" ><span property="name">(.*?)</span></a><meta property="position" content="2">') + if patronBlock.lower() != 'film': + support.log('select = ### è una serie ###') + return episodios(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + contentSerieName = item.fulltitle, + url=item.url, + contentType='tvshow')) + else: + support.log('select = ### è un movie ###') + return findvideos(Item(channel=item.channel, + title=item.title, + fulltitle=item.fulltitle, + url=item.url, + contentType='movie')) def search(item, texto): - logger.info("filmpertutti " + item.url + " search " + texto) + support.log() item.url = host + "/?s=" + texto + item.contentType = 'episode' + item.args = 'search' try: return peliculas(item) - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.log("%s" % line) return [] -def genre(item): - logger.info(item.channel + 'genre') +def newest(categoria): + support.log() itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertoolsV2.find_single_match(data, r'<ul class="table-list">(.*?)<\/ul>') - matches = scrapertoolsV2.find_multiple_matches(block, r'<a href="([^"]+)">.*?<\/span>(.*?)<\/a>') - for url, title in matches: - itemlist.append( - Item(channel=item.channel, - action='peliculas', - title=title, - url=host+url) - ) - itemlist = thumb(itemlist) - return itemlist - - -def az(item): - logger.info(item.channel + 'genre') - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertoolsV2.find_single_match(data, r'<select class="cats">(.*?)<\/select>') - matches = scrapertoolsV2.find_multiple_matches(block, r'<option data-src="([^"]+)">(.*?)<\/option>') - for url, title in matches: - itemlist.append( - Item(channel=item.channel, - action='peliculas', - title=title, - url=url) - ) - itemlist = thumb(itemlist) - return itemlist - - -def peliculas(item): - logger.info(item.channel + 'peliculas') - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertoolsV2.find_single_match(data, r'<ul class="posts">(.*)<\/ul>') - - patron = r'<li><a href="([^"]+)" data-thumbnail="([^"]+)">.*?<div class="title">([^<]+)<\/div>' - matches = scrapertoolsV2.find_multiple_matches(block, patron) - - for scrapedurl, scrapedthumb, scrapedtitle in matches: - title = re.sub(r'.\(.*?\)|.\[.*?\]', '', scrapedtitle) - quality = scrapertoolsV2.find_single_match(scrapedtitle, r'\[(.*?)\]') - if not quality: - quality = 'SD' - - longtitle = title + ' [COLOR blue][' + quality + '][/COLOR]' - - if item.contentType == 'tvshow': - action = 'episodios' + item = Item() + try: + if categoria == "peliculas": + item.url = host + "/category/film/" + item.action = "peliculas" + item.extra = "movie" + item.contentType = 'movie' + itemlist = peliculas(item) else: - action ='findvideos' + item.url = host + "/aggiornamenti-serie-tv/" + item.action = "peliculas" + item.args = "newest" + item.contentType = 'tvshow' + itemlist = peliculas(item) - itemlist.append( - Item(channel=item.channel, - action=action, - contentType=item.contentType, - title=longtitle, - fulltitle=title, - show=title, - quality=quality, - url=scrapedurl, - thumbnail=scrapedthumb - )) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) +## if itemlist[-1].action == "peliculas": +## itemlist.pop() - next_page = scrapertoolsV2.find_single_match(data, '<a href="([^"]+)">Pagina') - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="peliculas", - contentType=item.contentType, - title="[COLOR blue]" + config.get_localized_string(30992) + " >[/COLOR]", - url=next_page, - thumbnails=thumb())) - - return itemlist - - -def episodios(item): - logger.info(item.channel + 'findvideos') - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - - if 'accordion-item' in data: - block = scrapertoolsV2.find_single_match(data, 'accordion-item.*?>(.*?)<div id="disqus_thread">') - patron = r'<img src="([^"]+)">.*?<li class="season-no">(.*?)<\/li>(.*?)<\/table>' - matches = scrapertoolsV2.find_multiple_matches(block, patron) - - for scrapedthumb, scrapedtitle, scrapedurl in matches: - title = scrapedtitle + ' - ' + item.title - if title[0] == 'x': - title = '1' + title - - itemlist.append( - Item(channel=item.channel, - action='findvideos', - contentType='episode', - title=title, - fulltitle=title, - show=title, - quality=item.quality, - url=scrapedurl, - thumbnail=scrapedthumb - )) - - - else: - block = scrapertoolsV2.find_single_match(data, '<div id="info" class="pad">(.*?)<div id="disqus_thread">').replace('</p>','<br />').replace('×','x') - matches = scrapertoolsV2.find_multiple_matches(block, r'<strong>(.*?)<\/strong>.*?<p>(.*?)<span') - for lang, seasons in matches: - lang = re.sub('.*?Stagione[^a-zA-Z]+', '', lang) - # patron = r'([0-9]+x[0-9]+) (.*?)<br' - season = scrapertoolsV2.find_multiple_matches(seasons, r'([0-9]+x[0-9]+) (.*?)<br') - for title, url in season: - title = title + ' - ' + lang - itemlist.append( - Item(channel=item.channel, - title=title, - fulltitle=title, - show=title, - url=url, - contentType='episodie', - action='findvideos' - )) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log("{0}".format(line)) + return [] return itemlist def findvideos(item): - logger.info(item.channel + 'findvideos') - if item.contentType == 'movie': - data = httptools.downloadpage(item.url, headers=headers).data + return support.server(item) else: - data = item.url - - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = item.title + ' - [COLOR limegreen][[/COLOR]' + videoitem.title + '[COLOR limegreen]][/COLOR]' - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.show = item.show - videoitem.plot = item.plot - videoitem.channel = item.channel - videoitem.contentType = item.contentType - videoitem.quality = item.quality - - autoplay.start(itemlist, item) - - if item.contentType != 'episode': - if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findvideos': - itemlist.append( - Item(channel=item.channel, title='[COLOR yellow][B]'+config.get_localized_string(30161)+'[/B][/COLOR]', url=item.url, - action="add_pelicula_to_library", extra="findvideos", contentTitle=item.fulltitle)) - - return itemlist + return support.server(item, item.url) diff --git a/channels/filmsenzalimiti.py b/channels/filmsenzalimiti.py index b303fa1d..8d664e37 100644 --- a/channels/filmsenzalimiti.py +++ b/channels/filmsenzalimiti.py @@ -2,6 +2,12 @@ # ------------------------------------------------------------ # Canale per Filmsenzalimiti # ------------------------------------------------------------ +""" + Trasformate le sole def per support.menu e support.scrape + da non inviare nel test. + Test solo a trasformazione completa + +""" import re from core import scrapertools, servertools, httptools, support @@ -109,18 +115,19 @@ def sottomenu(item): return itemlist - +@support.scrape def video(item): logger.info('[filmsenzalimiti.py] video') itemlist = [] - patron = '<div class="col-mt-5 postsh">.*?<a href="([^"]+)" title="([^"]+)">.*?<span class="rating-number">(.*?)<.*?<img src="([^"]+)"' + patron = '<div class="col-mt-5 postsh">.*?<a href="(?P<url>[^"]+)" '\ + 'title="(?P<title>[^"]+)">.*?<span class="rating-number">(?P<rating>.*?)<.*?<img src="(?P<thumb>[^"]+)"' patronNext = '<a href="([^"]+)"><i class="glyphicon glyphicon-chevron-right"' - support.scrape(item, itemlist, patron, ['url', 'title', 'rating', 'thumb'], patronNext=patronNext) - - return itemlist +## support.scrape(item, itemlist, patron, ['url', 'title', 'rating', 'thumb'], patronNext=patronNext) +## return itemlist + return locals() def cerca(item): logger.info('[filmsenzalimiti.py] cerca') itemlist = [] diff --git a/channels/guardaserieclick.json b/channels/guardaserieclick.json index b91bf8f7..1729826d 100644 --- a/channels/guardaserieclick.json +++ b/channels/guardaserieclick.json @@ -3,68 +3,27 @@ "name": "GuardaSerie.click", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita", "vos"], "thumbnail": "guardaserieclick.png", "bannermenu": "guardaserieclick.png", - "categories": ["tvshow","anime"], + "categories": ["tvshow", "anime"], + "not_active": ["include_in_newest_peliculas", "include_in_newest_anime"], "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://www.guardaserie.media", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "@70727", + "default": false, + "enabled": false, + "visible": false + } ] } diff --git a/channels/guardaserieclick.py b/channels/guardaserieclick.py index e6ad4ef9..1e129c45 100644 --- a/channels/guardaserieclick.py +++ b/channels/guardaserieclick.py @@ -1,275 +1,191 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per Guardaserie.click -# Thanks to Icarus crew & Alfa addon & 4l3x87 +# Canale per guardaserieclick # ------------------------------------------------------------ -import re +""" -from core import httptools, scrapertools, support -from core import tmdb + Avvisi per il test: + - Le voci del menu le trovi in "lista serie" del sito, e Generi = Sfoglia + - SE capita che entrando in una voce trovi "nessun elemento" torna indietro e rientra nella voce. + - Tutte le voci, tranne: Anime/Cartoni, mostrano per ogni pagina, al max 25 titoli + + Presente in NOVITà: + - Serietv +""" + +from core import support from core.item import Item +from platformcode import config from core.support import log -from platformcode import logger, config __channel__ = 'guardaserieclick' host = config.get_channel_url(__channel__) headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() list_servers = ['speedvideo', 'openload'] list_quality = ['default'] -headers = [['Referer', host]] - - -# ---------------------------------------------------------------------------------------------------------------- +@support.menu def mainlist(item): + + tvshow = ['/lista-serie-tv', + ('Aggiornamenti', ['/lista-serie-tv', 'peliculas', 'update']), + ('Generi', ['/categorie', 'genres', 'genres']), + ('News Sub-ITA', ['/lista-serie-tv', 'peliculas', 'ined']), + ('Da non perdere', ['/lista-serie-tv', 'peliculas', 'nolost']), + ('Classiche', ["/lista-serie-tv", 'peliculas', 'classic']), + ('Anime/Cartoni', ["/category/animazione/", 'peliculas', 'genres']) + ] + + return locals() + +##@support.scrape +##def peliculas(item): +#### import web_pdb; web_pdb.set_trace() +## log('peliculas ->\n', item) +## +## action = 'episodios' +## block = r'(?P<block>.*?)<div\s+class="btn btn-lg btn-default btn-load-other-series">' +## +## if item.args == 'ined': +## deflang = 'SUB-ITA' +## patronBlock = r'<span\s+class="label label-default label-title-typology">'+block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 +## elif item.args == 'update': +## patronBlock = r'<div\s+class="container-fluid greybg title-serie-lastep title-last-ep fixed-title-wrapper containerBottomBarTitle">'+block +## patron = r'<a(?: rel="[^"]+")? href="(?P<url>[^"]+)"(?: class="[^"]+")?>[ ]<img class="[^"]+"[ ]title="[^"]+"[ ]alt="[^"]+"[ ]src="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<episode>\d+.\d+)[ ]\((?P<lang>[a-zA-Z\-]+)[^<]+<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)<' +## elif item.args == 'genres': +## patronBlock = r'<h2 style="color: white !important" class="title-typology">(?P<block>.+?)<div class="container-fluid whitebg" style="">' +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)</p>' +## patronNext = r'rel="next" href="([^"]+)">' +## item.contentType = 'tvshow' +## elif item.args == 'nolost': +## patronBlock = r'<h2 class="title-typology styck-top" meta-class="title-serie-danonperd">'+block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 +## elif item.args == 'classic': +## patronBlock = r'<h2 class="title-typology styck-top" meta-class="title-serie-classiche">'+block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 +## else: +## patronBlock = r'<div\s+class="container container-title-serie-new container-scheda" meta-slug="new">'+block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 +## +## debug = True +## return locals() + +@support.scrape +def peliculas(item): +## import web_pdb; web_pdb.set_trace() + log('peliculas ->\n', item) + + action = 'episodios' + blacklist = ['DMCA'] + + if item.args == 'genres' or item.args == 'search': + patronBlock = r'<h2 style="color:\s?white !important;?" class="title-typology">(?P<block>.+?)<div class="container-fluid whitebg" style="">' + patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)</p>' + patronNext = r'rel="next" href="([^"]+)">' + item.contentType = 'tvshow' +## elif item.args == 'search': +## patronBlock = r'<h2 style="color:\s?white !important.?" class="title-typology">(?P<block>.*?)<div class="container-fluid whitebg" style="">' +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)</p>' + else: + end_block = r'(?P<block>.*?)<div\s+class="btn btn-lg btn-default btn-load-other-series">' + patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' + pagination = 25 + if item.args == 'ined': + deflang = 'SUB-ITA' + patronBlock = r'<span\s+class="label label-default label-title-typology">'+end_block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 + elif item.args == 'update': + patronBlock = r'<div\s+class="container-fluid greybg title-serie-lastep title-last-ep fixed-title-wrapper containerBottomBarTitle">'+end_block + patron = r'<a(?: rel="[^"]+")? href="(?P<url>[^"]+)"(?: class="[^"]+")?>[ ]<img class="[^"]+"[ ]title="[^"]+"[ ]alt="[^"]+"[ ](?:|meta-)?src="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?:\d+.\d+)[ ]\((?P<lang>[a-zA-Z\-]+)[^<]+<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)<' + elif item.args == 'nolost': + patronBlock = r'<h2 class="title-typology styck-top" meta-class="title-serie-danonperd">'+end_block +## pagination = 25 + elif item.args == 'classic': + patronBlock = r'<h2 class="title-typology styck-top" meta-class="title-serie-classiche">'+end_block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 +## elif item.args == 'anime': +## + else: + patronBlock = r'<div\s+class="container container-title-serie-new container-scheda" meta-slug="new">'+end_block +## patron = r'<a href="(?P<url>[^"]+)".*?>\s<img\s.*?src="(?P<thumb>[^"]+)"\s/>[^>]+>[^>]+>\s[^>]+>\s(?P<year>\d{4})?\s.+?class="strongText">(?P<title>.+?)<' +## pagination = 25 + #support.regexDbg(item, patronBlock, headers) + #debug = True + return locals() + + +@support.scrape +def episodios(item): log() - itemlist = [] + action = 'findvideos' + patron = r'<div class="number-episodes-on-img">\s?\d+.\d+\s?(?:\((?P<lang>[a-zA-Z\-]+)\))?</div>.+?(?:<span class="pull-left bottom-year">(?P<title2>[^<]+)<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<plot>[^<]+)<[^>]+>[^>]+>[^>]+>\s?)?<span(?: meta-nextep="[^"]+")? class="[^"]+" meta-serie="(?P<title>[^"]+)" meta-stag="(?P<season>\d+)" meta-ep="(?P<episode>\d+)" meta-embed="(?P<url>[^>]+)">' + patronBlock = r'<h2 class="title-typology">Episodi (?P<stagione>\d+).{1,3}Stagione</h2>(?P<block>.*?)<div class="container">' - support.menu(itemlist, 'Novità bold', 'serietvaggiornate', "%s/lista-serie-tv" % host, 'tvshow') - support.menu(itemlist, 'Nuove serie', 'nuoveserie', "%s/lista-serie-tv" % host, 'tvshow') - support.menu(itemlist, 'Serie inedite Sub-ITA', 'nuoveserie', "%s/lista-serie-tv" % host, 'tvshow', args=['inedite']) - support.menu(itemlist, 'Da non perdere bold', 'nuoveserie', "%s/lista-serie-tv" % host, 'tvshow', args=['tv', 'da non perdere']) - support.menu(itemlist, 'Classiche bold', 'nuoveserie', "%s/lista-serie-tv" % host, 'tvshow', args=['tv', 'classiche']) - support.menu(itemlist, 'Anime', 'lista_serie', "%s/category/animazione/" % host, 'tvshow') - support.menu(itemlist, 'Categorie', 'categorie', host, 'tvshow', args=['serie']) - support.menu(itemlist, 'Cerca', 'search', host, 'tvshow', args=['serie']) - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) + def itemHook(item): + item.title = item.title.replace(item.fulltitle, '').replace('-','',1) + return item - return itemlist + #debug = True + return locals() + +@support.scrape +def genres(item): + log() + + action = 'peliculas' + patron = r'<li>\s<a\shref="(?P<url>[^"]+)"[^>]+>(?P<title>[^<]+)</a></li>' + patron_block = r'<ul\sclass="dropdown-menu category">(?P<block>.*?)</ul>' + item.contentType = '' + + return locals() -# ================================================================================================================ +def search(item, text): + log(text) + item.url = host + "/?s=" + text + item.contentType = 'tvshow' + item.args = 'search' + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + log("%s" % line) + return [] -# ---------------------------------------------------------------------------------------------------------------- def newest(categoria): log() itemlist = [] item = Item() + item.contentType= 'tvshow' + item.args = 'update' try: if categoria == "series": item.url = "%s/lista-serie-tv" % host - item.action = "serietvaggiornate" - itemlist = serietvaggiornate(item) + item.action = "peliculas" + itemlist = peliculas(item) - if itemlist[-1].action == "serietvaggiornate": - itemlist.pop() - - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + log("{0}".format(line)) return [] return itemlist -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def search(item, texto): - log(texto) - item.url = host + "/?s=" + texto - try: - return lista_serie(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -# ================================================================================================================ -# ---------------------------------------------------------------------------------------------------------------- -def cleantitle(scrapedtitle): - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle.strip()).replace('"', "'") - return scrapedtitle.strip() - - -# ================================================================================================================ -# ---------------------------------------------------------------------------------------------------------------- - -def nuoveserie(item): - log() - itemlist = [] - - patron_block = '' - if 'inedite' in item.args: - patron_block = r'<div class="container container-title-serie-ined container-scheda" meta-slug="ined">(.*?)</div></div><div' - elif 'da non perdere' in item.args: - patron_block = r'<div class="container container-title-serie-danonperd container-scheda" meta-slug="danonperd">(.*?)</div></div><div' - elif 'classiche' in item.args: - patron_block = r'<div class="container container-title-serie-classiche container-scheda" meta-slug="classiche">(.*?)</div></div><div' - else: - patron_block = r'<div class="container container-title-serie-new container-scheda" meta-slug="new">(.*?)</div></div><div' - - patron = r'<a href="([^"]+)".*?><img\s.*?src="([^"]+)" \/>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<\/p>' - - matches = support.match(item, patron, patron_block, headers)[0] - - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - scrapedtitle = cleantitle(scrapedtitle) - - itemlist.append( - Item(channel=item.channel, - action="episodios", - contentType="tvshow", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - thumbnail=scrapedthumbnail, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def serietvaggiornate(item): - log() - itemlist = [] - - patron_block = r'<div class="container\s*container-title-serie-lastep\s*container-scheda" meta-slug="lastep">(.*?)<\/div><\/div><div' - patron = r'<a rel="nofollow"\s*href="([^"]+)"[^>]+><img.*?src="([^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<[^>]+>' - - matches = support.match(item, patron, patron_block, headers)[0] - - for scrapedurl, scrapedthumbnail, scrapedep, scrapedtitle in matches: - episode = re.compile(r'^(\d+)x(\d+)', re.DOTALL).findall(scrapedep) # Prendo stagione ed episodioso - scrapedtitle = cleantitle(scrapedtitle) - - contentlanguage = "" - if 'sub-ita' in scrapedep.strip().lower(): - contentlanguage = 'Sub-ITA' - - extra = r'<span\s.*?meta-stag="%s" meta-ep="%s" meta-embed="([^"]+)"\s.*?embed2="([^"]+)?"\s.*?embed3="([^"]+)?"[^>]*>' % ( - episode[0][0], episode[0][1].lstrip("0")) - - infoLabels = {} - infoLabels['episode'] = episode[0][1].zfill(2) - infoLabels['season'] = episode[0][0] - - title = str( - "%s - %sx%s %s" % (scrapedtitle, infoLabels['season'], infoLabels['episode'], contentlanguage)).strip() - - itemlist.append( - Item(channel=item.channel, - action="findepvideos", - contentType="tvshow", - title=title, - show=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - extra=extra, - thumbnail=scrapedthumbnail, - contentLanguage=contentlanguage, - infoLabels=infoLabels, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def categorie(item): - log() - return support.scrape(item, r'<li>\s<a\shref="([^"]+)"[^>]+>([^<]+)</a></li>', ['url', 'title'], patron_block=r'<ul\sclass="dropdown-menu category">(.*?)</ul>', headers=headers, action="lista_serie") - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def lista_serie(item): - log() - itemlist = [] - - patron_block = r'<div\sclass="col-xs-\d+ col-sm-\d+-\d+">(.*?)<div\sclass="container-fluid whitebg" style="">' - patron = r'<a\shref="([^"]+)".*?>\s<img\s.*?src="([^"]+)" />[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)</p></div>' - - return support.scrape(item, patron, ['url', 'thumb', 'title'], patron_block=patron_block, patronNext=r"<link\s.*?rel='next'\shref='([^']*)'", action='episodios') - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def episodios(item): - log() - itemlist = [] - - patron = r'<div\sclass="[^"]+">\s([^<]+)<\/div>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)?[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><p[^>]+>([^<]+)<[^>]+>[^>]+>[^>]+>' - patron += r'[^"]+".*?serie="([^"]+)".*?stag="([0-9]*)".*?ep="([0-9]*)"\s' - patron += r'.*?embed="([^"]+)"\s.*?embed2="([^"]+)?"\s.*?embed3="([^"]+)?"?[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>\s?' - patron += r'(?:<img\sclass="[^"]+" meta-src="([^"]+)"[^>]+>|<img\sclass="[^"]+" src="" data-original="([^"]+)"[^>]+>)?' - - matches = support.match(item, patron, headers=headers)[0] - - for scrapedtitle, scrapedepisodetitle, scrapedplot, scrapedserie, scrapedseason, scrapedepisode, scrapedurl, scrapedurl2, scrapedurl3, scrapedthumbnail, scrapedthumbnail2 in matches: - scrapedtitle = cleantitle(scrapedtitle) - scrapedepisode = scrapedepisode.zfill(2) - scrapedepisodetitle = cleantitle(scrapedepisodetitle) - title = str("%sx%s %s" % (scrapedseason, scrapedepisode, scrapedepisodetitle)).strip() - if 'SUB-ITA' in scrapedtitle: - title += " "+support.typo("Sub-ITA", '_ [] color kod') - - infoLabels = {} - infoLabels['season'] = scrapedseason - infoLabels['episode'] = scrapedepisode - itemlist.append( - Item(channel=item.channel, - action="findvideos", - title=support.typo(title, 'bold'), - fulltitle=scrapedtitle, - url=scrapedurl + "\r\n" + scrapedurl2 + "\r\n" + scrapedurl3, - contentType="episode", - plot=scrapedplot, - contentSerieName=scrapedserie, - contentLanguage='Sub-ITA' if 'Sub-ITA' in title else '', - infoLabels=infoLabels, - thumbnail=scrapedthumbnail2 if scrapedthumbnail2 != '' else scrapedthumbnail, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - support.videolibrary(itemlist, item) - - return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def findepvideos(item): - log() - data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data - matches = scrapertools.find_multiple_matches(data, item.extra) - data = "\r\n".join(matches[0]) - item.contentType = 'movie' - return support.server(item, data=data) - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- def findvideos(item): - log() - if item.contentType == 'tvshow': - data = httptools.downloadpage(item.url, headers=headers).data - matches = scrapertools.find_multiple_matches(data, item.extra) - data = "\r\n".join(matches[0]) - else: - log(item.url) - data = item.url - return support.server(item, data) + log('--->', item) + return support.server(item, item.url) diff --git a/channels/guardogratis.json b/channels/guardogratis.json index 4ebedf28..9e2ec1a5 100644 --- a/channels/guardogratis.json +++ b/channels/guardogratis.json @@ -4,41 +4,8 @@ "active": true, "adult": false, "language": ["ita"], - "thumbnail": "https:\/\/guardogratis.com\/wp-content\/uploads\/2018\/01\/Logo-4.png", - "bannermenu": "https:\/\/guardogratis.com\/wp-content\/uploads\/2018\/01\/Logo-4.png", + "thumbnail": "guardogratis.png", + "bannermenu": "guardogratis.png", "categories": ["movie","tvshow"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "settings": [] } diff --git a/channels/hentaiid.json b/channels/hentaiid.json deleted file mode 100644 index c490a751..00000000 --- a/channels/hentaiid.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "hentaiid", - "name": "Hentai ID", - "active": true, - "adult": true, - "language": ["*"], - "thumbnail": "https://dl.dropboxusercontent.com/u/30248079/hentai_id.png", - "banner": "https://dl.dropboxusercontent.com/u/30248079/hentai_id2.png", - "categories": [ - "adult" - ] -} \ No newline at end of file diff --git a/channels/ilgeniodellostreaming.json b/channels/ilgeniodellostreaming.json index d9a6cbaf..960aaabe 100644 --- a/channels/ilgeniodellostreaming.json +++ b/channels/ilgeniodellostreaming.json @@ -3,76 +3,9 @@ "name": "IlGenioDelloStreaming", "active": true, "adult": false, - "language": ["ita"], - "thumbnail": "https://i.imgur.com/Nsa81r0.png", - "banner": "https://i.imgur.com/Nsa81r0.png", - "categories": ["movie","tvshow","anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["No filtrar","IT"] - } - ] -} \ No newline at end of file + "language": ["ita", "sub-ita"], + "thumbnail": "ilgeniodellostreaming.png", + "banner": "ilgeniodellostreaming.png", + "categories": ["movie", "tvshow", "anime", "vos"], + "settings": [] +} diff --git a/channels/ilgeniodellostreaming.py b/channels/ilgeniodellostreaming.py index 972a7c0b..5f79d839 100644 --- a/channels/ilgeniodellostreaming.py +++ b/channels/ilgeniodellostreaming.py @@ -1,146 +1,243 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew +# # Canale per ilgeniodellostreaming # ------------------------------------------------------------ + +""" + + Alcuni video non si aprono sul sito... + + Avvisi per il test: + i link per le categorie non sono TUTTI visibili nella pagina del sito: + vanno costruiti con i nomi dei generi che vedete nel CANALE. + Es: + https://ilgeniodellostreaming.se/genere/+ genere nel canale + genere-> kids + https://ilgeniodellostreaming.se/genere/kids + genere-> avventura + https://ilgeniodellostreaming.se/genere/avventura + Se il genere è formato da 2 parola lo spazio si trasforma in - + genere-> televisione film + https://ilgeniodellostreaming.se/genere/televisione-film + + Novità -> Serietv e Aggiornamenti nel canale: + - le pagine sono di 25 titoli + + + ##### note per i dev ######### + - La pagina "Aggiornamenti Anime" del sito è vuota (update 13-9-2019) + - in url: film o serietv + +""" + import re -from platformcode import logger -from core import scrapertoolsV2, httptools, tmdb, support -from core.support import log, menu, aplay +from core import scrapertoolsV2, httptools, support +from core.support import log from core.item import Item from platformcode import config __channel__ = 'ilgeniodellostreaming' host = config.get_channel_url(__channel__) -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() list_servers = ['verystream', 'openload', 'streamango'] list_quality = ['default'] headers = [['Referer', host]] -PERPAGE = 10 - +@support.menu def mainlist(item): - log() - itemlist = [] - menu(itemlist, 'Film', 'peliculas', host + '/film/') - menu(itemlist, 'Film Per Categoria', 'category', host, args='genres') - menu(itemlist, 'Film Per Anno', 'category', host, args='year') - menu(itemlist, 'Serie TV', 'peliculas', host + '/serie/', 'tvshow') - menu(itemlist, 'Nuovi Episodi Serie TV submenu', 'newep', host + '/aggiornamenti-serie/', 'tvshow') - menu(itemlist, 'Anime', 'peliculas', host + '/anime/', 'tvshow') - menu(itemlist, 'TV Show', 'peliculas', host + '/tv-show/', 'tvshow') - menu(itemlist, 'Cerca...', 'search', contentType='search') - aplay(item, itemlist, list_servers, list_quality) - return itemlist + support.log(item) + film = ['/film/', + ('Generi',['', 'genres', 'genres']), + ('Per Lettera',['/film-a-z/', 'genres', 'letter']), + ('Anni',['', 'genres', 'year']), + ('Popolari',['/trending/?get=movies', 'peliculas', 'populared']), + ('Più Votati', ['/ratings/?get=movies', 'peliculas', 'populared']) + ] + + tvshow = ['/serie/', + ('Aggiornamenti', ['/aggiornamenti-serie/', 'peliculas', 'update']), + ('Popolari',['/trending/?get=tv', 'peliculas', 'populared']), + ('Più Votati', ['/ratings/?get=tv', 'peliculas', 'populared']) + + ] + + anime = ['/anime/' + ] + + Tvshow = [ + ('Show TV', ['/tv-show/', 'peliculas', '', 'tvshow']) + ] + + search = '' + + return locals() + + +@support.scrape +def peliculas(item): + log() + + if item.args == 'search': + + patronBlock = r'<div class="search-page">(?P<block>.*?)<footer class="main">' + patron = r'<div class="thumbnail animation-2"><a href="(?P<url>[^"]+)">'\ + '<img src="(?P<thumb>[^"]+)" alt="[^"]+" \/>[^>]+>(?P<type>[^<]+)'\ + '<\/span>.*?<a href.*?>(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA)\])?'\ + '<\/a>[^>]+>(?:<span class="rating">IMDb\s*(?P<rating>[0-9.]+)<\/span>)?'\ + '.+?(?:<span class="year">(?P<year>[0-9]+)<\/span>)?[^>]+>[^>]+><p>(?P<plot>.*?)<\/p>' + +## type_content_dict={'movie': ['film'], 'tvshow': ['tv']} +## type_action_dict={'findvideos': ['film'], 'episodios': ['tv']} + def itemHook(item): + if 'film' not in item.url: + item.contentType = 'tvshow' + item.action = 'episodios' + return item + else: + + if item.contentType == 'movie': + endBlock = '</article></div>' + else: + endBlock = '<footer class="main">' + + patronBlock = r'<header><h1>.+?</h1>(?P<block>.*?)'+endBlock + + if item.contentType == 'movie': + if item.args == 'letter': + patronBlock = r'<table class="table table-striped">(?P<block>.+?)</table>' + patron = r'<img src="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+><td class="mlnh-2"><a href="(?P<url>[^"]+)">(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA)\])?<[^>]+>[^>]+>[^>]+>(?P<year>\d{4})\s+<' + elif item.args == 'populared': + patron = r'<img src="(?P<thumb>[^"]+)" alt="[^"]+">[^>]+>[^>]+>[^>]+>[^>]+>\s+?(?P<rating>\d+.?\d+|\d+)<[^>]+>[^>]+>(?P<quality>[a-zA-Z\-]+)[^>]+>[^>]+>[^>]+>[^>]+><a href="(?P<url>[^"]+)">(?P<title>[^<]+)<[^>]+>[^>]+>[^>]+>(?P<year>\d+)<' + else: + + #patron = r'<div class="poster">\s*<a href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)" alt="[^"]+"><\/a>[^>]+>[^>]+>[^>]+>\s*(?P<rating>[0-9.]+)<\/div><span class="quality">(?:SUB-ITA|)?(?P<quality>|[^<]+)?<\/span>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA)\])?<\/a>[^>]+>[^>]+>(?P<year>[^<]+)<\/span>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<plot>[^<]+)<div' + patron = r'<div class="poster">\s?<a href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)" alt="[^"]+"><\/a>[^>]+>[^>]+>[^>]+>\s*(?P<rating>[0-9.]+)<\/div>(?:<span class="quality">(?:SUB-ITA|)?(?P<quality>|[^<]+)?<\/span>)?[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA)\])?<\/a>[^>]+>[^>]+>(?P<year>[^<]+)<\/span>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<plot>[^<]+)<div' + else: + # TVSHOW + action = 'episodios' + if item.args == 'update': + action = 'findvideos' + patron = r'<div class="poster"><img src="(?P<thumb>[^"]+)"[^>]+>[^>]+><a href="(?P<url>[^"]+)">[^>]+>(?P<episode>[\d\-x]+)[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>.+?)(?:\[(?P<lang>Sub-ITA|Sub-ita)\])?<[^>]+>[^>]+>[^>]+>[^>]+>(?P<quality>[HD]+)?(?:.+?)?/span><p class="serie"' + pagination = 25 + def itemHook(item): + item.contentType = 'episode' + return item + else: + patron = r'<div class="poster">\s?<a href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)" alt="[^"]+"><\/a>[^>]+>[^>]+>[^>]+> (?P<rating>[0-9.]+)<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>.+?)[ ]?(?:\[(?P<lang>Sub-ITA|Sub-ita)\])?<[^>]+>[^>]+>[^>]+>(?P<year>[^<]+)(?:<.*?<div class="texto">(?P<plot>[^<]+))?' + + patronNext = '<span class="current">[^<]+<[^>]+><a href="([^"]+)"' + + #support.regexDbg(item, patron, headers) + #debug = True + return locals() + + +@support.scrape +def episodios(item): + log() + + patronBlock = r'<h1>.*?[ ]?(?:\[(?P<lang>.+?\]))?</h1>.+?<div class="se-a" '\ + 'style="display:block"><ul class="episodios">(?P<block>.*?)</ul>'\ + '</div></div></div></div></div>' + patron = r'<a href="(?P<url>[^"]+)"><img src="(?P<thumb>[^"]+)">.*?'\ + '<div class="numerando">(?P<episode>[^<]+).*?<div class="episodiotitle">'\ + '[^>]+>(?P<title>[^<]+)<\/a>' +# debug = True + return locals() + +@support.scrape +def genres(item): + log(item) + + action='peliculas' + if item.args == 'genres': + patronBlock = r'<div class="sidemenu"><h2>Genere</h2>(?P<block>.*?)/li></ul></div>' + elif item.args == 'year': + item.args = 'genres' + patronBlock = r'<div class="sidemenu"><h2>Anno di uscita</h2>(?P<block>.*?)/li></ul></div>' + elif item.args == 'letter': + patronBlock = r'<div class="movies-letter">(?P<block>.*?)<div class="clearfix">' + + patron = r'<a(?:.+?)?href="(?P<url>.*?)"[ ]?>(?P<title>.*?)<\/a>' + +## debug = True + return locals() + +def search(item, text): + log(text) + itemlist = [] + text = text.replace(' ', '+') + item.url = host + "/?s=" + text + try: + item.args = 'search' + return peliculas(item) + except: + import sys + for line in sys.exc_info(): + log("%s" % line) + + return [] def newest(categoria): log(categoria) itemlist = [] item = Item() + if categoria == 'peliculas': + item.contentType = 'movie' + item.url = host + '/film/' + elif categoria == 'series': + item.args = 'update' + item.contentType = 'tvshow' + item.url = host + '/aggiornamenti-serie/' +## elif categoria == 'anime': +## item.contentType = 'tvshow' +## item.url = host + '/anime/' try: - if categoria == 'peliculas': - item.contentType = 'movie' - item.url = host + '/film/' - elif categoria == "series": - item.contentType = 'tvshow' - item.url = host + '/serie/' - elif categoria == "anime": - item.contentType = 'tvshow' - item.url = host + '/anime/' - - item.action = "peliculas" + item.action = 'peliculas' itemlist = peliculas(item) - if itemlist[-1].action == "peliculas": - itemlist.pop() - # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + log("{0}".format(line)) return [] return itemlist -def category(item): - return support.scrape(item, r'<li.*?><a href="(.*?)"[^>]+>(.*?)<\/a>' ,['url', 'title'], action='peliculas', patron_block= r'<ul class="' + item.args + r' scrolling">(.*?)<\/ul>') - - -def search(item, texto): - log(texto) - item.url = host + "/?s=" + texto - - try: - return peliculas(item) - - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - - return [] - - -def peliculas_src(item): - patron = r'<div class="thumbnail animation-2"><a href="([^"]+)"><img src="([^"]+)" alt="[^"]+" \/>[^>]+>([^<]+)<\/span>.*?<a href.*?>([^<]+)<\/a>[^>]+>[^>]+>(?:<span class="rating">IMDb\s*([0-9.]+)<\/span>)?.*?(?:<span class="year">([0-9]+)<\/span>)?[^>]+>[^>]+><p>(.*?)<\/p>' - return support.scrape(item, patron, ['url', 'thumb', 'type', 'title', 'lang' 'rating', 'year', 'plot'], headers, type_content_dict={'movie':['Film'], 'tvshow':['TV']}, type_action_dict={'findvideos':['Film'], 'episodios':['TV']}) - - -def peliculas(item): - if item.contentType == 'movie': - patron = r'<div class="poster">\s*<a href="([^"]+)"><img src="([^"]+)" alt="[^"]+"><\/a>[^>]+>[^>]+>[^>]+>\s*([0-9.]+)<\/div><span class="quality">([^<]+)<\/span>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<\/a>[^>]+>[^>]+>([^<]+)<\/span>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<div' - return support.scrape(item, patron, ['url', 'thumb', 'rating', 'quality', 'title', 'year', 'plot'], headers, patronNext='<span class="current">[^<]+<[^>]+><a href="([^"]+)"') - elif item.contentType == 'tvshow': - patron = r'<div class="poster">\s*<a href="([^"]+)"><img src="([^"]+)" alt="[^"]+"><\/a>[^>]+>[^>]+>[^>]+> ([0-9.]+)<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<[^>]+>[^>]+>[^>]+>([^<]+)<.*?<div class="texto">([^<]+)' - return support.scrape(item, patron, ['url', 'thumb', 'rating', 'title', 'year', 'plot'], headers, action='episodios', patronNext='<span class="current">[^<]+<[^>]+><a href="([^"]+)"') - else: - patron = r'<div class="thumbnail animation-2"><a href="([^"]+)"><img src="([^"]+)" alt="[^"]+" \/>[^>]+>([^<]+)<\/span>.*?<a href.*?>([^<]+)<\/a>[^>]+>[^>]+>(?:<span class="rating">IMDb\s*([0-9.]+)<\/span>)?.*?(?:<span class="year">([0-9]+)<\/span>)?[^>]+>[^>]+><p>(.*?)<\/p>' - return support.scrape(item, patron, ['url', 'thumb', 'type', 'title', 'lang' 'rating', 'year', 'plot'], headers, type_content_dict={'movie':['Film'], 'tvshow':['TV']}, type_action_dict={'findvideos':['Film'], 'episodios':['TV']}) - -def newep(item): - log() - itemlist = [] - - page = 1 - if item.page: - page = item.page - - matches = support.match(item, r'<div class="poster"><img src="([^"]+)" alt="([^"]+)">[^>]+><a href="([^"]+)">')[0] - - for i, (thumb, title, url) in enumerate(matches): - if (page - 1) * PERPAGE > i: continue - if i >= page * PERPAGE: break - title = scrapertoolsV2.decodeHtmlentities(title) - itemlist.append( - Item(channel=item.channel, - action="findvideos", - fulltitle=title, - show=title, - title= support.typo(title,'bold'), - url=url, - thumbnail=thumb)) - support.pagination(itemlist, item, page, PERPAGE) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -def episodios(item): - return support.scrape(item, r'<a href="([^"]+)"><img src="([^"]+)">.*?<div class="numerando">([^<]+).*?<div class="episodiotitle">[^>]+>([^<]+)<\/a>',['url', 'thumb', 'episode', 'title'], patron_block='<div id="seasons">(.*?)<div class="sbox') - def findvideos(item): log() itemlist =[] + matches, data = support.match(item, '<iframe class="metaframe rptss" src="([^"]+)"[^>]+>',headers=headers) for url in matches: html = httptools.downloadpage(url, headers=headers).data data += str(scrapertoolsV2.find_multiple_matches(html, '<meta name="og:url" content="([^"]+)">')) - itemlist = support.server(item, data) - return itemlist + itemlist = support.server(item, data) + + if item.args == 'update': + + data = httptools.downloadpage(item.url).data + patron = r'<div class="item"><a href="'+host+'/serietv/([^"\/]+)\/"><i class="icon-bars">' + series = scrapertoolsV2.find_single_match(data, patron) + titles = support.typo(series.upper().replace('-', ' '), 'bold color kod') + goseries = support.typo("Vai alla Serie:", ' bold') + itemlist.append( + Item(channel=item.channel, + title=goseries + titles, + fulltitle=titles, + show=series, + contentType='tvshow', + contentSerieName=series, + url=host+"/serietv/"+series, + action='episodios', + contentTitle=titles, + plot = "Vai alla Serie :" + titles + " con tutte le puntate", + )) + return itemlist diff --git a/channels/italiafilmhd.json b/channels/italiafilmhd.json deleted file mode 100644 index f64aa115..00000000 --- a/channels/italiafilmhd.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "id": "italiafilmhd", - "name": "ItaliaFilm HD", - "active": true, - "adult": false, - "language": ["ita"], - "thumbnail": "https://italiafilm.network/wp-content/uploads/2018/06/ITALIAFILM-HD.png", - "bannermenu": "https://italiafilm.network/wp-content/uploads/2018/06/ITALIAFILM-HD.png", - "categories": ["movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero di link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "2", "5", "10", "15" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] -} diff --git a/channels/italiafilmhd.py b/channels/italiafilmhd.py deleted file mode 100644 index 67196dc7..00000000 --- a/channels/italiafilmhd.py +++ /dev/null @@ -1,364 +0,0 @@ -# -*- coding: utf-8 -*- -# ------------------------------------------------------------ -# Ringraziamo Icarus crew -# Canale per italiafilmhd -# ---------------------------------------------------------- -import re - -import urlparse - -from core import scrapertools, servertools, httptools, tmdb, support -from core.item import Item -from platformcode import logger, config -from specials import autoplay - -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['verystream', 'openload', 'youtube'] -list_quality = ['default'] - -checklinks = config.get_setting('checklinks', 'italiafilmhd') -checklinks_number = config.get_setting('checklinks_number', 'italiafilmhd') - -__channel__ = 'italiafilmhd' -host = config.get_channel_url(__channel__) -headers = [['Referer', host]] - - -def mainlist(item): - logger.info("kod.italiafilmhd mainlist") - - autoplay.init(item.channel, list_servers, list_quality) - - itemlist = [ - Item(channel=item.channel, - title="[COLOR azure]Novita'[/COLOR]", - action="fichas", - url=host + "/cinema/", - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="[COLOR azure]Ultimi Film Inseriti[/COLOR]", - action="fichas", - url=host + "/film/", - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="[COLOR azure]Film per Genere[/COLOR]", - action="genere", - url=host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="Serie TV", - text_color="azure", - action="tv_series", - url="%s/serie-tv-hd/" % host, - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="[COLOR orange]Cerca...[/COLOR]", - action="search", - extra="movie", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search")] - - autoplay.show_option(item.channel, itemlist) - - return itemlist - - -def newest(categoria): - logger.info("[italiafilmvideohd.py] newest" + categoria) - itemlist = [] - item = Item() - try: - if categoria == "film": - item.url = host + "/cinema/" - item.action = "fichas" - itemlist = fichas(item) - - if itemlist[-1].action == "fichas": - itemlist.pop() - - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("{0}".format(line)) - return [] - - return itemlist - - -def search(item, texto): - logger.info("[italiafilmvideohd.py] " + item.url + " search " + texto) - - item.url = host + "/?s=" + texto - - try: - return fichas(item) - - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def genere(item): - logger.info("[italiafilmvideohd.py] genere") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = '<div class="sub_title">Genere</div>(.+?)</div>' - data = scrapertools.find_single_match(data, patron) - - patron = '<li>.*?' - patron += 'href="([^"]+)".*?' - patron += '<i>([^"]+)</i>' - - matches = re.compile(patron, re.DOTALL).findall(data) - scrapertools.printMatches(matches) - - for scrapedurl, scrapedtitle in matches: - scrapedtitle = scrapedtitle.replace('&', '-') - itemlist.append( - Item(channel=item.channel, - action="fichas", - title=scrapedtitle, - url=scrapedurl, - folder=True)) - - return itemlist - - -def fichas(item): - logger.info("[italiafilmvideohd.py] fichas") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - # fix - calidad - - patron = '<li class="item">.*?' - patron += 'href="([^"]+)".*?' - patron += 'title="([^"]+)".*?' - patron += '<img src="([^"]+)".*?' - - matches = re.compile(patron, re.DOTALL).findall(data) - - for scraped_2, scrapedtitle, scrapedthumbnail in matches: - scrapedurl = scraped_2 - - title = scrapertools.decodeHtmlentities(scrapedtitle) - # title += " (" + scrapedcalidad + ") - - # ------------------------------------------------ - scrapedthumbnail = httptools.get_url_headers(scrapedthumbnail) - # ------------------------------------------------ - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="movie", - title=title, - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=title, - show=scrapedtitle)) - - # Paginación - next_page = scrapertools.find_single_match(data, '<a href="([^"]+)"\s*><span aria-hidden="true">»') - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="fichas", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=next_page, - text_color="orange", - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png")) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - - -def tv_series(item): - logger.info("[italiafilmvideohd.py] tv_series") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - blocco = scrapertools.find_single_match(data, r'<ul class="list_mt">(.*?)</ul>') - patron = r'<a class="poster" href="([^"]+)" title="([^"]+)"[^>]*>\s*<img src="([^"]+)"[^>]+>' - matches = re.findall(patron, blocco, re.DOTALL) - - for scrapedurl, scrapedtitle, scrapedthumbnail in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle).strip() - - itemlist.append( - Item(channel=item.channel, - action="seasons", - contentType="tv", - title=scrapedtitle, - text_color="azure", - url=scrapedurl, - thumbnail=scrapedthumbnail, - fulltitle=scrapedtitle, - show=scrapedtitle)) - - # Pagine - next_page = scrapertools.find_single_match(data, '<a href="([^"]+)"\s*><span aria-hidden="true">»') - - if next_page != "": - itemlist.append( - Item(channel=item.channel, - action="fichas", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - text_color="orange", - url=next_page, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png")) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - - -def seasons(item): - logger.info("[italiafilmvideohd.py] seasons") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - url = scrapertools.find_single_match(data, - r'<div class="playerhdpass" id="playerhdpass">\s*[^>]+>\s*<iframe[^s]+src="([^"]+)"[^>]*></iframe>') - data = httptools.downloadpage(url, headers=headers).data - blocco = scrapertools.find_single_match(data, r'<h3>STAGIONE</h3>\s*<ul>(.*?)</ul>') - seasons = re.findall(r'<li[^>]*><a href="([^"]+)">([^<]+)</a></li>', blocco, re.DOTALL) - - for scrapedurl, season in seasons: - itemlist.append( - Item(channel=item.channel, - action="episodes", - contentType=item.contentType, - title="Stagione: %s" % season, - text_color="azure", - url="https://hdpass.net/%s" % scrapedurl, - thumbnail=item.thumbnail, - fulltitle=item.fulltitle, - show=item.show)) - - return itemlist - - -def episodes(item): - logger.info("[italiafilmvideohd.py] episodes") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - blocco = scrapertools.find_single_match(data, r'<section id="seasons">(.*?)</section>') - episodes = re.findall(r'<li[^>]*><a href="([^"]+)">([^<]+)</a></li>', blocco, re.DOTALL) - - for scrapedurl, episode in episodes: - itemlist.append( - Item(channel=item.channel, - action="findvid_series", - contentType=item.contentType, - title="Episodio: %s" % episode, - text_color="azure", - url="https://hdpass.net/%s" % scrapedurl, - thumbnail=item.thumbnail, - fulltitle=item.fulltitle, - show=item.show)) - - return itemlist - - -def findvideos(item): - logger.info("[italiafilmvideohd.py] findvideos") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<div class="playerhdpass" id="playerhdpass"><iframe width=".+?" height=".+?" src="([^"]+)"' - url = scrapertools.find_single_match(data, patron) - - if url: - data += httptools.downloadpage(url, headers=headers).data - - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.title + videoitem.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.show = item.show - videoitem.plot = item.plot - videoitem.channel = item.channel - videoitem.contentType = item.contentType - videoitem.language = IDIOMAS['Italiano'] - - # Requerido para Filtrar enlaces - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # Requerido para FilterTools - - # itemlist = filtertools.get_links(itemlist, item, list_language) - - # Requerido para AutoPlay - - autoplay.start(itemlist, item) - - if item.contentType != 'episode': - if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findvideos': - itemlist.append( - Item(channel=item.channel, title='[COLOR yellow][B]Aggiungi alla videoteca[/B][/COLOR]', url=item.url, - action="add_pelicula_to_library", extra="findvideos", contentTitle=item.contentTitle)) - - return itemlist - - -def findvid_series(item): - logger.info("[italiafilmvideohd.py] findvideos") - - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data.replace('\n', '') - patron = r'<iframe id="[^"]+" width="[^"]+" height="[^"]+" src="([^"]+)"[^>]+><\/iframe>' - url = scrapertools.find_single_match(data, patron).replace("?alta", "") - url = "https:" + url.replace("&download=1", "") - - data = httptools.downloadpage(url, headers=headers).data - - start = data.find('<div class="row mobileRes">') - end = data.find('<div id="playerFront">', start) - data = data[start:end] - - patron_res = '<div class="row mobileRes">(.*?)</div>' - patron_mir = '<div class="row mobileMirrs">(.*?)</div>' - patron_media = r'<input type="hidden" name="urlEmbed" data-mirror="([^"]+)" id="urlEmbed" value="([^"]+)"\s*/>' - - res = scrapertools.find_single_match(data, patron_res) - - urls = [] - for res_url, res_video in scrapertools.find_multiple_matches(res, '<option.*?value="([^"]+?)">([^<]+?)</option>'): - - data = httptools.downloadpage(urlparse.urljoin(url, res_url), headers=headers).data.replace('\n', '') - mir = scrapertools.find_single_match(data, patron_mir) - for mir_url in scrapertools.find_multiple_matches(mir, '<option.*?value="([^"]+?)">[^<]+?</value>'): - data = httptools.downloadpage(urlparse.urljoin(url, mir_url), headers=headers).data.replace('\n', '') - - for media_label, media_url in re.compile(patron_media).findall(data): - urls.append(support.url_decode(media_url)) - - itemlist = servertools.find_video_items(data='\n'.join(urls)) - for videoitem in itemlist: - server = re.sub(r'[-\[\]\s]+', '', videoitem.title) - videoitem.text_color = "azure" - videoitem.title = "".join(["[%s] " % ("[COLOR orange]%s[/COLOR]" % server.capitalize()), item.title]) - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - - return itemlist - diff --git a/channels/italiaserie.json b/channels/italiaserie.json index ba094b25..fe68c5c1 100644 --- a/channels/italiaserie.json +++ b/channels/italiaserie.json @@ -3,34 +3,10 @@ "name": "Italia Serie", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita","sub-ita"], "thumbnail": "https:\/\/raw.githubusercontent.com\/Zanzibar82\/images\/master\/posters\/italiaserie.png", "bannermenu": "https:\/\/raw.githubusercontent.com\/Zanzibar82\/images\/master\/posters\/italiaserie.png", - "categories": ["tvshow"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": false, - "enabled": false, - "visible": false - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "categories": ["tvshow", "vos"], + "not_active": ["include_in_newest_peliculas", "include_in_newest_anime"], + "settings": [] } diff --git a/channels/italiaserie.py b/channels/italiaserie.py index e31efa2f..4a072910 100644 --- a/channels/italiaserie.py +++ b/channels/italiaserie.py @@ -2,56 +2,116 @@ # ------------------------------------------------------------ # Canale per italiaserie # ------------------------------------------------------------ +""" + + Problemi noti che non superano il test del canale: + + + Avvisi: + + + Ulteriori info: + +""" + import re - - - -from core import httptools, scrapertools, support -from core import tmdb +from core import support, httptools, scrapertoolsV2 from core.item import Item -from platformcode import logger from platformcode import config -from specials import autoplay __channel__ = 'italiaserie' host = config.get_channel_url(__channel__) +headers = [['Referer', host]] + list_servers = ['speedvideo'] - -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() +list_quality = [] +@support.menu def mainlist(item): support.log() - itemlist = [] - support.menu(itemlist, 'Ultime Uscite', 'peliculas', host + "/category/serie-tv/", "episode") - support.menu(itemlist, 'Ultimi Episodi', 'peliculas', host + "/ultimi-episodi/", "episode", 'latest') - support.menu(itemlist, 'Categorie', 'menu', host, "episode", args="Serie-Tv per Genere") - support.menu(itemlist, 'Cerca...', 'search', host, 'episode', args='serie') + tvshow = ['/category/serie-tv/', + ('Aggiornamenti', ['/ultimi-episodi/', 'peliculas', 'update']), + ('Generi', ['', 'category', 'Serie-Tv per Genere']) + ] - autoplay.init(item.channel, list_servers, []) - autoplay.show_option(item.channel, itemlist) + return locals() - return itemlist + +@support.scrape +def peliculas(item): + support.log() + + action = 'episodios' + patron = r'<div class="post-thumb">\s*<a href="(?P<url>[^"]+)" '\ + 'title="(?P<title>[^"]+)">\s*<img src="(?P<thumb>[^"]+)"[^>]+>' + + if item.args == 'update': + patron += r'.*?aj-eps">(?P<episode>.+?)[ ]?(?P<lang>Sub-Ita|Ita)</span>' + action = 'findvideos' + patronNext = r'<a class="next page-numbers" href="(.*?)">' + +## debug = True + return locals() + + +@support.scrape +def episodios(item): + support.log() + + patronBlock = r'</i> Stagione (?P<block>(?P<season>\d+)</div> '\ + '<div class="su-spoiler-content".*?)<div class="clearfix">' + patron = r'(?:(?P<season>\d+)?</div> <div class="su-spoiler-content"(:?.+?)?> )?'\ + '<div class="su-link-ep">\s+<a.*?href="(?P<url>[^"]+)".*?strong>[ ]'\ + '(?P<title>.+?)[ ](?P<episode>\d+-\d+|\d+)[ ](?:-\s+(?P<title2>.+?))?'\ + '[ ]?(?:(?P<lang>Sub-ITA))?[ ]?</strong>' + + + #debug = True + return locals() + + +@support.scrape +def category(item): + support.log() + + action = 'peliculas' + patron = r'<li class="cat-item.*?href="(?P<url>[^"]+)".*?>(?P<title>.*?)</a>' + + return locals() + + +def search(item, texto): + support.log("s=", texto) + item.url = host + "/?s=" + texto + item.contentType = 'tvshow' + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] def newest(categoria): - logger.info("[italiaserie.py]==> newest" + categoria) + support.log("newest", categoria) itemlist = [] item = Item() try: if categoria == "series": item.url = host + "/ultimi-episodi/" item.action = "peliculas" - item.args = "latest" + item.args = "update" item.contentType = "episode" itemlist = peliculas(item) if itemlist[-1].action == "peliculas": itemlist.pop() - # Continua la ricerca in caso di errore + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): @@ -61,111 +121,35 @@ def newest(categoria): return itemlist -def peliculas(item): - support.log() - patron = r'<div class="post-thumb">\s*<a href="([^"]+)" title="([^"]+)">\s*<img src="([^"]+)"[^>]+>' - list_groups = ["url", "title", "thumb"] - - if item.args == "latest": - patron += r'.*?aj-eps">(.*?)</span>' - data = httptools.downloadpage(item.url).data - - matches = re.compile(patron, re.S).findall(data) - itemlist = [] - - for scrapedurl, scrapedtitle, scrapedthumbnail, scrapedep in matches: - s, ep = scrapertools.find_single_match(scrapedep, r'(\d+)x(\d+)\s') - itemlist.append( - Item(channel=item.channel, - action="episodios", - contentType=item.contentType, - title="[B]" + scrapedtitle + "[/B] " + scrapedep, - fulltitle=scrapedtitle, - show=scrapedtitle, - url=scrapedurl, - extra=item.extra, - args={"season": s, "episode": ep} - )) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - else: - patron_next = r'<a class="next page-numbers" href="(.*?)">' - itemlist = support.scrape(item, patron, list_groups, patronNext=patron_next, action="episodios") - - if itemlist[-1].action != "peliculas": - itemlist.pop() - - return itemlist - - -def search(item, texto): - support.log("s=", texto) - item.url = host + "/?s=" + texto - try: - return peliculas(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def menu(item): - support.log() - patron = r'<li class="cat-item.*?href="([^"]+)".*?>(.*?)</a>' - return support.scrape(item, patron, ["url", "title"], action="peliculas") - - -def episodios(item): - support.log() - - patron = r'<div class="su-spoiler.*?</i>(.*?)</div>\s+<div class="su-spoiler-content"(.*?)="clearfix">' - data = httptools.downloadpage(item.url).data - matches = re.compile(patron, re.S).findall(data) - - if item.args: - s = (int(item.args["season"])) - try: - matches = [matches[s]] - except: - matches = [matches[(s - 1)]] - - itemlist = [] - - for season, block in matches: - patron = r'<div class="su-link-ep">\s+<a.*?href="([^"]+)".*?strong>(.*?)</' - if item.args: - ep = int(item.args["episode"]) - patron = r'<div class="su-link-ep">\s+<a.*?href="([^"]+)".*?strong>\s(Episodio ' + str(ep) + r') .*?</' - episodes = re.compile(patron, re.MULTILINE).findall(block) - for scrapedurl, scrapedtitle in episodes: - fixedtitle = scrapertools.get_season_and_episode(season + " " + scrapedtitle) - eptitle = re.sub(r"Episodio\s+\d+", "", scrapedtitle).strip() - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType=item.contentType, - title="[B]" + fixedtitle + " " + eptitle + "[/B]", - fulltitle=fixedtitle + " " + eptitle, - show=fixedtitle + " " + eptitle, - url=scrapedurl, - extra=item.extra, - )) - - if not item.args: - support.videolibrary(itemlist, item) - - return itemlist - - def findvideos(item): support.log() - itemlist = support.server(item, data=item.url) - # itemlist = filtertools.get_links(itemlist, item, list_language) + if item.args == 'update': + itemlist = [] + item.infoLabels['mediatype'] = 'episode' - autoplay.start(itemlist, item) + data = httptools.downloadpage(item.url, headers=headers).data + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + url_video = scrapertoolsV2.find_single_match(data, r'<a rel="[^"]+" target="[^"]+" act="[^"]+"\s+href="([^"]+)" class="[^"]+-link".+?\d+.+?</strong> </a>', -1) + url_serie = scrapertoolsV2.find_single_match(data, r'<link rel="canonical" href="([^"]+)" />') + goseries = support.typo("Vai alla Serie:", ' bold') + series = support.typo(item.contentSerieName, ' bold color kod') + itemlist = support.server(item, data=url_video) - return itemlist + itemlist.append( + Item(channel=item.channel, + title=goseries + series, + fulltitle=item.fulltitle, + show=item.show, + contentType='tvshow', + contentSerieName=item.contentSerieName, + url=url_serie, + action='episodios', + contentTitle=item.contentSerieName, + plot = goseries + series + "con tutte le puntate", + )) + + return itemlist + else: + return support.server(item, data=item.url) diff --git a/channels/mondolunatico2.json b/channels/mondolunatico2.json index ed77f7a2..c07479c2 100644 --- a/channels/mondolunatico2.json +++ b/channels/mondolunatico2.json @@ -6,7 +6,7 @@ "adult": false, "thumbnail": "mondolunatico2.png", "banner": "mondolunatico2.png", - "categories": ["tvshow", "movie", "vosi", "anime"], + "categories": ["tvshow", "movie", "vos", "anime"], "settings": [ { "id": "include_in_global_search", diff --git a/channels/mondolunatico2.py b/channels/mondolunatico2.py index 075ca1d1..15598b02 100644 --- a/channels/mondolunatico2.py +++ b/channels/mondolunatico2.py @@ -2,6 +2,31 @@ # ------------------------------------------------------------ # Canale per MondoLunatico 2.0 # ------------------------------------------------------------ +""" + WARNING: + questo sito è una kakatura di kazz...incredibile!!! + Per renderlo compatibile con support ci vuole MOLTA PAZIENZA!!! + + Problemi noti che non superano il test del canale: + Nelle pagine dei "FILM", film e serie nel sito sono mischiate, + I titoli quindi non saranno nello stesso numero nelle pagine del canale. + Alcuni Titoli sono pagine informative e NON devono apparire nel CANALE!!! + Controllare: + -che nelle varie sezioni dei FILM appaiano solo FILM, stessa cosa per le serie. + -che effettivamente vengano tagliati solo gli avvisi. + + Nella TOP FILM non ci sono le voci lingua, anno ( quindi niente TMDB o vari ) e qualità + Nella pagina delle serie potreste trovare solo il titolo senza stagione ed episodio + Nel menu contestuale potreste non trovare le voci: + -"Aggiungi in Videoteca" + -"Scarica" di qualunque tipo: stagione, serie, etc... + + AVVISO: + i link 1fichier hanno bisogno dei DNS modificati + il server woof potrebbe rispondere con "connettore assente" + I titoli nella sezione SUB-ITA che non riportano Sub-ITA sono in lingua originale senza sottotitoli + +""" import re import urlparse @@ -13,7 +38,7 @@ from channelselector import thumb from specials import autoplay, filtertools from core import scrapertools, httptools, tmdb, servertools, support, scrapertoolsV2 from core.item import Item -from platformcode import logger, config, platformtools +from platformcode import config, platformtools #,logger __channel__ = "mondolunatico2" host = config.get_channel_url(__channel__) @@ -22,178 +47,98 @@ headers = [['Referer', host]] list_servers = ['verystream', 'wstream', 'openload', 'streamango'] list_quality = ['HD', 'default'] +@support.menu def mainlist(item): + support.log() - # Main options - itemlist = [] - support.menu(itemlist, 'Novità bold', 'carousel', host, contentType='movie', args='movies') - support.menu(itemlist, 'Sub ITA bold', 'carousel_subita', host, contentType='movie', args='movies') - support.menu(itemlist, 'Ultime Richieste Inserite bold', 'carousel_request', host, contentType='movie', args='movies') - support.menu(itemlist, 'Film Nelle Sale bold', 'carousel_cinema', host, contentType='movie', args='movies') - support.menu(itemlist, 'Film Ultimi Inseriti submenu', 'carousel_last', host, contentType='movie', args='movies') - support.menu(itemlist, 'Film Top ImDb submenu', 'top_imdb', host + '/top-imdb/', contentType='movie', args='movies') - support.menu(itemlist, 'Serie TV', 'carousel_episodes', host, contentType='episode', args='tvshows') - support.menu(itemlist, 'Serie TV Top ImDb submenu', 'top_serie', host + '/top-imdb/', contentType='episode', args='tvshows') - support.menu(itemlist, '[COLOR blue]Cerca...[/COLOR] bold', 'search', host) - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) + top = [('Film', ['/genre/film-aggiornati/', 'peliculas', 'movies']), + ('Al Cinema', ['/genre/al-cinema/', 'peliculas', 'cinema']), + ('Ultimi Aggiunti', ['/movies/', 'peliculas', 'latest']), + ('Ultime Richieste', ['/genre/richieste/', 'peliculas', 'request']), + ('Top ImDb', ['/top-imdb/', 'peliculas', 'top']), + ('Sub-ITA', ['/genre/subita/', 'peliculas', 'sub']), + ('Serie TV', ['/tvshows/', 'peliculas', '', 'tvshow']), + ('Top ImDb', ['/top-imdb/', 'peliculas', 'top', 'tvshow']), + ('Search...',['', 'search', 'search']) + ] - return itemlist + return locals() -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel(item, regex=r'<h2>Ultime Richieste Inserite</h2>(.*?)<header>', contentType="movie"): - logger.info("[mondolunatico2.py] carousel") - itemlist = [] +@support.scrape +def peliculas(item): + support.log() - data = httptools.downloadpage(item.url, headers=headers).data + action = 'findvideos' + blacklist = ['Avviso Agli Utenti',] - block = scrapertools.find_single_match(data,regex) + if item.args != 'search': + if item.contentType == 'movie': + action = 'findvideos' + patron = r'class="item movies"><div class="poster"><img src="(?P<thumb>[^"]+)"'\ + '[^>]+>(?:<div class="rating">)?[^>]+>.+?(?P<rating>\d+.\d+|\d+)'\ + '[^>]+>[^>]+>[^>]+>(:?(?P<lang>SubITA)?|(?P<quality>[^<]+)?)?'\ + '<.+?href="(?P<url>[^"]+)">[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>'\ + '[^>]+>(?P<title>.+?)</a>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<year>\d+)</span>'\ + '[^>]+>(?P<duration>\d+)?.+?<[^>]+>(?:[^>]+>[^>]+>[^>]+>[^>]+>)(?P<plot>.+?)<' + if item.args == 'movies': + patronBlock = r'<h1>\*Film Aggiornati</h1>(?P<block>.*?)<div class="pagination">' + elif item.args == 'cinema': + patronBlock = r'<h1>\*Al Cinema</h1>(?P<block>.*?)<div class="pagination">' + elif item.args == 'latest': + patronBlock = r'<h1>Film</h1>(?P<block>.*?)<div class="pagination">' + elif item.args == 'request': + patronBlock = r'<h1>\*Richieste</h1>(?P<block>.*?)<div class="pagination">' + elif item.args == 'sub': + patronBlock = r'<h1>\*SubITA</h1>(?P<block>.*?)<div class="pagination">' + elif item.args == 'top': + patronBlock = r'<h3>Film</h3>(?P<block>.*?)<div class="top-imdb-list tright">' + patron = r'<div class="image"><div class="[^"]+"><a href="(?P<url>[^"]+)"'\ + '[^"]+"(?P<thumb>[^"]+)"[^"]+alt="(?P<title>[^"]+)">[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>(?P<rating>[^<]+)<' + pagination = 25 + else: + action = 'episodios' + if item.args == 'top': + patronBlock = r'<h3>TVShows</h3>(?P<block>.*?)<h2 class="widget-title">' + patron = r'<div class="image"><div class="[^"]+"><a href="(?P<url>[^"]+)"'\ + '[^"]+"(?P<thumb>[^"]+)"[^"]+alt="(?P<title>[^"]+)">[^>]+>[^>]+>'\ + '[^>]+>[^>]+>[^>]+>[^>]+>(?P<rating>[^<]+)<' + else: + patronBlock = r'<h1>Serie T[v|V]</h1>(?P<block>.*?)<div class="pagination">' + patron = r'class="item tvshows">[^>]+>.+?src="(?P<thumb>[^"]+)".+?>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+><a href="(?P<url>[^"]+)">[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)</h4>[^>]+>[^>]+> (?:<span class="imdb">IMDb: (?P<rating>\d+.\d+|\d+|N\/A)(?:</span>)?[^>]+>(?P<year>\d+))?<[^>]+>[^>]+>[^>]+>(?:[^>]+>[^>]+>(?P<plot>[^<]+)<)' + else: + patronBlock = r'<h1>Results found\:.+?</h1>(?P<block>.*?)<div class="sidebar scrolling">' + patron = r'<div class="result-item">[^>]+>[^>]+>[^>]+>.+?href="(?P<url>[^"]+)">.+?src="(?P<thumb>[^"]+)" alt="(?P<title>[^"]+)"[^>]+>[^>]+>(?P<type>[^>]+)<[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>IMDb (?P<rating>\d+.\d+|\d+)[^>]+>[^>]+>(?P<year>\d+)<[^>]+>[^>]+>[^>]+>[^>]+>(:?[^>]+>[^>]+>)?(?P<plot>[^<]+)<' - patron = r'<article id.*?src="([^"]+).*?alt="([^"]+).*?href="([^"]+).*?,.([^<]+)' - matches = re.compile(patron, re.DOTALL).findall(block) + type_content_dict={'movie': ['film'], 'tvshow': ['tv']} + type_action_dict={'findvideos': ['film'], 'episodios': ['tv']} - for scrapedthumbnail, scrapedtitle, scrapedurl, year in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'[0-9]{4}', "", scrapedtitle) - itemlist.append( - Item(channel=__channel__, - action="findvideos", - contentType=contentType, - title=scrapedtitle + " " + "[COLOR orange][" + year + "][/COLOR]", - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - args=item.args, - infoLabels={'year': year}, - thumbnail=scrapedthumbnail)) + patronNext = r'<span class="current">.*?href="([^"]+)" class="inactive">' - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) +## debug = True + return locals() - return itemlist - -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel_subita(item): - return carousel(item, regex=r'<h2>Film SubITA</h2>(.*?)<header>', contentType="movie") -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel_request(item): - return carousel(item, regex=r'<h2>Ultime Richieste Inserite</h2>(.*?)<header>', contentType="movie") -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel_cinema(item): - return carousel(item, regex=r'<h2>Nelle Sale</h2>(.*?)<header>', contentType="movie") -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel_last(item): - return carousel(item, regex=r'<h2>Ultimi Film Inseriti</h2>(.*?)<header>', contentType="movie") -# --------------------------------------------------------------------------------------------------------------------------------------------- -def carousel_episodes(item): - return carousel(item, regex=r'<h2>Serie TV</h2>(.*?)<header>', contentType="episode") -# --------------------------------------------------------------------------------------------------------------------------------------------- - -def top_imdb(item, contentType='movie', regex=r'<h1.*?TOP IMDb.*?<h3>(.*?)<h3>'): - logger.info("[mondolunatico2.py] top_imdb") - itemlist = [] - - minpage = 20 - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - block = scrapertools.find_single_match(data, regex) - - patron = r"<div class='image'><div class='[^']+'><a href='([^']+)'[^']+'([^']+)'[^']+'([^']+)" - matches = re.compile(patron, re.DOTALL).findall(block) - - for i, (scrapedurl, scrapedthumbnail, scrapedtitle) in enumerate(matches): - if (p - 1) * minpage > i: continue - if i >= p * minpage: break - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'[0-9]{4}', "", scrapedtitle) - scrapedthumbnail = scrapedthumbnail.replace ("-90x135","").replace("/w92/", "/w600_and_h900_bestv2/") - itemlist.append( - Item(channel=__channel__, - action="findvideos" if "movie" in contentType else "episodios", - contentType=item.contentType, - contentTitle=scrapedtitle, - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - thumbnail=scrapedthumbnail, - args=item.args)) - - if len(matches) >= p * minpage: - thumbnail = thumb(itemlist=[]) - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=__channel__, - contentType=item.contentType, - action="top_imdb", - title="[COLOR blue][B]Successivo >[/B][/COLOR]", - thumbnail=thumbnail, - url=scrapedurl)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - -# --------------------------------------------------------------------------------------------------------------------------------------------- -def top_serie(item): - return top_imdb(item, contentType='episode', regex=r'<h3>TVShows</h3>(.*?)<div class="sidebar scrolling">') -# --------------------------------------------------------------------------------------------------------------------------------------------- def search(item, texto): - logger.info("[mondolunatico2.py] " + item.url + " search " + texto) + support.log('s-> '+texto) + item.url = host + "/?s=" + texto try: return peliculas(item) - except: import sys for line in sys.exc_info(): logger.error("%s" % line) return [] -# --------------------------------------------------------------------------------------------------------------------------------------------- - -def peliculas(item): - logger.info("[mondolunatico2.py] peliculas") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<div class="result-item">.*?<a href="([^"]+).*?src="([^"]+).*?alt="([^"]+).*?span class="([^"]+).*?<span class="year">([^<]+).*?<p>([^<]+)' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedthumbnail, scrapedtitle, args, year, scrapedplot in matches: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedtitle = re.sub(r'[0-9]{4}', "", scrapedtitle) - type = "[COLOR aqua][Serie][/COLOR]" if "tvshows" in item.args else "[COLOR aqua][Film][/COLOR]" - itemlist.append( - Item(channel=__channel__, - action="episodios" if "tvshows" in item.args else "findvideos", - contentType="episode" if "tvshows" in item.args else "movie", - title=scrapedtitle + " " + "[COLOR orange][" + year + "][/COLOR]" + " " + type, - fulltitle=scrapedtitle, - thumbnail=scrapedthumbnail, - url=scrapedurl, - show=scrapedtitle, - args=args, - infoLabels={'year':year}, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -# --------------------------------------------------------------------------------------------------------------------------------------------- def findvideos(item): - logger.info("[mondolunatico2.py] findvideos") + support.log() - if item.args == "tvshows": + if item.contentType == "tvshow": ret=support.dooplay_get_links(item, host) if ret == []: @@ -202,16 +147,16 @@ def findvideos(item): item.url = ret[0]["url"] return videoplayer(item) - if item.args == "movies" or "movie": + #if item.args == "movies" or "movie": + if item.contentType == 'movie': return videoplayer(item) else: return halfplayer(item) -# --------------------------------------------------------------------------------------------------------------------------------------------- def episodios(item): - logger.info("[mondolunatico2.py] episodios") + support.log() itemlist = [] data = httptools.downloadpage(item.url, headers=headers).data @@ -265,7 +210,7 @@ def episodios(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def player(item): - logger.info ("[mondolunatico2.py] player") + support.log() data = httptools.downloadpage(item.url, headers=headers).data @@ -326,6 +271,7 @@ def player(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def player_list(item): + support.log() itemlist = [] # Scarico la pagina @@ -364,7 +310,7 @@ def player_list(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def dooplayer(item): - logger.info ("[mondolunatico2.py] dooplayer") + support.log() itemlist = [] url = item.url @@ -410,6 +356,7 @@ def dooplayer(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def keeplink(item): + support.log() itemlist = [] # Scarico la pagina @@ -445,7 +392,7 @@ def keeplink(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def videoplayer(item): - logger.info("[mondolunatico2.py] videoplayer") + support.log() itemlist = [] for link in support.dooplay_get_links(item, host): @@ -475,7 +422,7 @@ def videoplayer(item): # --------------------------------------------------------------------------------------------------------------------------------------------- def halfplayer(item): - logger.info("[mondolunatico2.py] halfplayer") + support.log() url=item.url diff --git a/channels/mondoserietv.json b/channels/mondoserietv.json index cae7032d..3bd6ab63 100644 --- a/channels/mondoserietv.json +++ b/channels/mondoserietv.json @@ -4,67 +4,9 @@ "active": true, "adult": false, "language": ["ita"], - "thumbnail": "https:\/\/mondoserietv.com\/wp-content\/uploads\/2018\/04\/logo.png", - "bannermenu": "https:\/\/mondoserietv.com\/wp-content\/uploads\/2018\/04\/logo.png", - "categories": ["movie","anime","tvshow"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "thumbnail": "mondoserietv.png", + "bannermenu": "mondoserietv.png", + "categories": ["movie","anime","tvshow","documentary"], + "not_active":["include_in_newest_anime","include_in_newest_documentary"], + "settings": [] } diff --git a/channels/mondoserietv.py b/channels/mondoserietv.py index a1e5d943..6b507d1e 100644 --- a/channels/mondoserietv.py +++ b/channels/mondoserietv.py @@ -1,357 +1,116 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew # Canale per mondoserietv -# # ---------------------------------------------------------- -import re -from core import scrapertools, servertools, httptools, scrapertoolsV2 -from core import tmdb -from core.item import Item -from lib.unshortenit import unshorten -from platformcode import logger, config -from specials import autoplay +from core import support __channel__ = "mondoserietv" -host = config.get_channel_url(__channel__) +host = support.config.get_channel_url(__channel__) IDIOMAS = {'Italiano': 'IT'} list_language = IDIOMAS.values() -list_servers = ['akstream'] +list_servers = ['akstream', 'wstream', 'vidtome', 'backin', 'nowvideo', 'verystream'] list_quality = ['default'] -checklinks = config.get_setting('checklinks', 'mondoserietv') -checklinks_number = config.get_setting('checklinks_number', 'mondoserietv') - headers = {'Referer': host} -PERPAGE = 14 - - +@support.menu def mainlist(item): - logger.info("kod.mondoserietvmainlist") - autoplay.init(item.channel, list_servers, list_quality) + film = ['/lista-film', + ('Ultimi Film Aggiunti', ['/ultimi-film-aggiunti', 'peliculas' , 'last'])] - itemlist = [Item(channel=item.channel, - action="lista_serie", - title="[COLOR azure]Lista Serie Tv Anni 50 60 70 80[/COLOR]", - url=("%s/lista-serie-tv-anni-60-70-80/" % host), - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="lista_serie", - title="[COLOR azure]Lista Serie Tv Italiane[/COLOR]", - url=("%s/lista-serie-tv-italiane/" % host), - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="lista_serie", - title="[COLOR azure]Lista Cartoni Animati & Anime[/COLOR]", - url=("%s/lista-cartoni-animati-e-anime/" % host), - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - action="peliculas", - title="[COLOR azure]Lista Film[/COLOR]", - url=("%s/lista-film/" % host), - thumbnail="http://orig03.deviantart.net/6889/f/2014/079/7/b/movies_and_popcorn_folder_icon_by_matheusgrilo-d7ay4tw.png"), - Item(channel=item.channel, - title="[COLOR yellow]Cerca Film...[/COLOR]", - action="search", - extra="movie", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search"), - Item(channel=item.channel, - title="[COLOR yellow]Cerca SerieTV...[/COLOR]", - action="search", - extra="tvshow", - thumbnail="http://dc467.4shared.com/img/fEbJqOum/s7/13feaf0c8c0/Search")] - autoplay.show_option(item.channel, itemlist) + tvshow = ['/lista-serie-tv', + ('HD {TV}', ['/lista-serie-tv-in-altadefinizione']), + ('Anni 50 60 70 80 {TV}',['/lista-serie-tv-anni-60-70-80']), + ('Serie Italiane',['/lista-serie-tv-italiane'])] - return itemlist + anime = ['/lista-cartoni-animati-e-anime'] -def search(item, texto): - logger.info("kod.mondoserietv search " + texto) - item.url = "%s/?s=%s" % (host, texto) + docu = [('Documentari bullet bold',['/lista-documentari', 'peliculas', '', 'tvshow']), + ('Cerca Documentari... submenu bold', ['/lista-documentari', 'search', '', 'tvshow'])] + return locals() + + +@support.scrape +def search(item, text): + support.log(text) + if item.contentType == 'movie' or item.extra == 'movie': + action = 'findvideos' + else: + action = 'episodios' try: - if item.extra == "movie": - return search_peliculas(item) - if item.extra == "tvshow": - return search_peliculas_tv(item) + search = text + data = support.match(item, headers=headers)[1] + if 'lcp_nextlink' in data: + data += support.match(item, url=support.scrapertoolsV2.find_single_match(data, r'href="([^"]+)" title="[^"]+" class="lcp_nextlink"'), headers=headers)[1] + patron = r'<li><a href="(?P<url>[^"]+)" title="(?P<title>.*?)(?:\s(?P<year>\d{4}))?"[^>]*>' + return locals() # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] -def search_peliculas(item): - logger.info("kod.mondoserietv search_peliculas") - itemlist = [] - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data +def newest(categoria): + support.log(categoria) + item = support.Item() + try: + if categoria == "series": + item.contentType= 'tvshow' + item.url = host + '/ultimi-episodi-aggiunti' + item.args = "lastep" + if categoria == "peliculas": + item.contentType= 'movie' + item.url = host + '/ultimi-film-aggiunti' + item.args = "last" + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("{0}".format(line)) + return [] - # Estrae i contenuti - patron = '<div class="boxinfo">\s*<a href="([^"]+)">\s*<span class="tt">(.*?)</span>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - fulltitle=scrapedtitle, - show=scrapedtitle, - title=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - extra=item.extra, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -def search_peliculas_tv(item): - logger.info("kod.mondoserietv search_peliculas_tv") - itemlist = [] - - # Carica la pagina - data = httptools.downloadpage(item.url, headers=headers).data - - # Estrae i contenuti - patron = '<div class="boxinfo">\s*<a href="([^"]+)">\s*<span class="tt">(.*?)</span>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - - itemlist.append( - Item(channel=item.channel, - action="episodios", - fulltitle=scrapedtitle, - show=scrapedtitle, - title=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - extra=item.extra, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist +@support.scrape def peliculas(item): - logger.info("kod.mondoserietv film") - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = scrapertools.find_single_match(data, '<div class="entry-content pagess">(.*?)</ul>') - patron = r'<a href="(.*?)" title="(.*?)">' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append(Item(channel=item.channel, - contentType="movie", - action="findvideos", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - fanart=item.fanart if item.fanart != "" else item.scrapedthumbnail, - show=item.fulltitle, - folder=True)) - - if len(matches) >= p * PERPAGE: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="peliculas", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=scrapedurl, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png", - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - - -def lista_serie(item): - logger.info("kod.mondoserietv novità") - itemlist = [] - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = scrapertools.find_single_match(data, '<div class="entry-content pagess">(.*?)</ul>') - patron = r'<a href="(.*?)" title="(.*?)">' - matches = re.compile(patron, re.DOTALL).findall(blocco) - scrapertools.printMatches(matches) - - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * PERPAGE > i: continue - if i >= p * PERPAGE: break - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append(Item(channel=item.channel, - action="episodios", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - fanart=item.fanart if item.fanart != "" else item.scrapedthumbnail, - show=item.fulltitle, - folder=True)) - - if len(matches) >= p * PERPAGE: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=item.channel, - extra=item.extra, - action="lista_serie", - title="[COLOR lightgreen]" + config.get_localized_string(30992) + "[/COLOR]", - url=scrapedurl, - thumbnail="http://2.bp.blogspot.com/-fE9tzwmjaeQ/UcM2apxDtjI/AAAAAAAAeeg/WKSGM2TADLM/s1600/pager+old.png", - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist + pagination = '' + patronNext = r'href="([^"]+)" title="[^"]+" class="lcp_nextlink"' + if item.args == 'last': + patronBlock = r'<table>(?P<block>.*?)</table>' + patron = r'<tr><td><a href="(?P<url>[^"]+)">\s*[^>]+>(?P<title>.*?)(?:\s(?P<year>\d{4}))? (?:Streaming|</b>)' + elif item.args == 'lastep': + patronBlock = r'<table>(?P<block>.*?)</table>' + patron = r'<td>\s*<a href="[^>]+>(?P<title>.*?)(?:\s(?P<year>\d{4}))?\s(?:(?P<episode>(?:\d+x\d+|\d+)))\s*(?P<title2>[^<]+)(?P<url>.*?)<tr>' + action = 'findvideos' + else: + patronBlock = r'<div class="entry-content pagess">(?P<block>.*?)</ul>' + patron = r'<li><a href="(?P<url>[^"]+)" title="(?P<title>.*?)(?:\s(?P<year>\d{4}))?"[^>]*>' + if item.contentType == 'tvshow': + action = 'episodios' + anime = True + return locals() +@support.scrape def episodios(item): - logger.info("kod.mondoserietv episodios") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - blocco = scrapertools.find_single_match(data, '<table>(.*?)</table>') - - patron = "<tr><td><b>(.*?)(\d+)((?:x\d+| ))(.*?)<\/b>(.*?<tr>)" - matches = scrapertoolsV2.find_multiple_matches(blocco, patron) - - for t1, s, e, t2, scrapedurl in matches: - - if "x" not in e: - e = s - - if e == s: - s = None - - if s is None: - s = "1" - - if s.startswith('0'): - s = s.replace("0", "") - - if e.startswith('x'): - e = e.replace("x", "") - - scrapedtitle = t1 + s + "x" + e + " " + t2 - itemlist.append( - Item(channel=item.channel, - contentType="episode", - action="findvideos", - items=s, - iteme=e, - fulltitle=scrapedtitle, - show=scrapedtitle, - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - url=scrapedurl, - thumbnail=item.scrapedthumbnail, - plot=item.scrapedplot, - folder=True)) - - if config.get_videolibrary_support() and len(itemlist) != 0: - itemlist.append( - Item(channel=item.channel, - title="[COLOR lightblue]%s[/COLOR]" % config.get_localized_string(30161), - url=item.url, - action="add_serie_to_library", - extra="episodios", - show=item.show)) - - return itemlist - + anime = True + pagination = 50 + patronBlock = r'<table>(?P<block>.*?)</table>' + patron = r'<tr><td><b>(?P<title>(?:\d+)?.*?)\s*(?:(?P<episode>(?:\d+x\d+|\d+)))\s*(?P<title2>[^<]+)(?P<url>.*?)<tr>' + def itemHook(item): + clear = support.re.sub(r'\[[^\]]+\]', '', item.title) + if clear.isdigit(): + item.title = support. typo('Episodio ' + clear, 'bold') + return item + return locals() def findvideos(item): - logger.info(" findvideos") - - if item.contentType != "episode": - return findvideos_movie(item) - - itemlist = servertools.find_video_items(data=item.url) - logger.info(itemlist) - - for videoitem in itemlist: - videoitem.title = "".join([item.title, '[COLOR green][B]' + videoitem.title + '[/B][/COLOR]']) - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.show = item.show - videoitem.plot = item.plot - videoitem.channel = item.channel - videoitem.contentType = item.contentType - videoitem.language = IDIOMAS['Italiano'] - - # Requerido para Filtrar enlaces - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - # Requerido para FilterTools - - # itemlist = filtertools.get_links(itemlist, item, list_language) - - # Requerido para AutoPlay - - autoplay.start(itemlist, item) - - if item.contentType != 'episode': - if config.get_videolibrary_support() and len(itemlist) > 0 and item.extra != 'findvideos': - itemlist.append( - Item(channel=item.channel, title='[COLOR yellow][B]Aggiungi alla videoteca[/B][/COLOR]', url=item.url, - action="add_pelicula_to_library", extra="findvideos", contentTitle=item.contentTitle)) - - return itemlist - - -def findvideos_movie(item): - logger.info(" findvideos_movie") - - # Carica la pagina - - data = httptools.downloadpage(item.url).data - - patron = r"<a href='([^']+)'[^>]*?>[^<]*?<img src='[^']+' style='[^']+' alt='[^']+'>[^<]+?</a>" - matches = re.compile(patron, re.DOTALL).findall(data) - for scrapedurl in matches: - url, c = unshorten(scrapedurl) - data += url + '\n' - - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = "".join([item.title, '[COLOR green][B]' + videoitem.title + '[/B][/COLOR]']) - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.show = item.show - videoitem.plot = item.plot - videoitem.channel = item.channel - videoitem.contentType = item.contentType - - return itemlist + if item.contentType == 'movie': return support.server(item) + else: return support.server(item, item.url) diff --git a/channels/polpotv.json b/channels/polpotv.json new file mode 100644 index 00000000..cb84f441 --- /dev/null +++ b/channels/polpotv.json @@ -0,0 +1,13 @@ +{ + "id": "polpotv", + "name": "PolpoTV", + "language": ["ita"], + "active": true, + "adult": false, + "thumbnail": "polpotv.png", + "banner": "polpotv.png", + "categories": ["movie"], + "not_active":[], + "default_off":["include_in_newest"], + "settings": [] +} diff --git a/channels/polpotv.py b/channels/polpotv.py new file mode 100644 index 00000000..49d8f2d2 --- /dev/null +++ b/channels/polpotv.py @@ -0,0 +1,165 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# KoD - XBMC Plugin +# Canale polpotv +# ------------------------------------------------------------ + +from core import scrapertools, httptools, support, jsontools +from core.item import Item +from platformcode import config +import json, datetime + +__channel__ = "polpotv" +host = config.get_channel_url(__channel__) + +headers = [['Accept', 'application/ld+json']] + +list_servers = ['directo'] +list_quality = ['1080p','720p','480p','360p'] + +@support.menu +def mainlist(item): + menu = [ + ('Ultimi Film aggiunti', ['/api/movies?order[lastReleaseAt]=desc', 'peliculas', '']), + ('Generi', ['/api/genres', 'search_movie_by_genre', '']), + ('Anni {film}', ['', 'search_movie_by_year', '']), + ('Cerca Film... bold', ['', 'search', '']) + ] + return locals() + +def newest(categoria): + support.log() + item = Item() + if categoria == 'peliculas': + item.contentType = 'movie' + item.url = host + '/api/movies?order[lastReleaseAt]=desc' + return peliculas(item) + +def peliculas(item): + support.log() + itemlist = [] + data = httptools.downloadpage(item.url, headers=headers).data + json_object = jsontools.load(data) + + for movie in json_object['hydra:member']: + itemlist.extend(get_itemlist_movie(movie,item)) + + try: + if support.inspect.stack()[1][3] not in ['newest']: + support.nextPage(itemlist, item, next_page=json_object['hydra:view']['hydra:next']) + except: + pass + + return itemlist + +def search(item, texto): + support.log(item.url, "search", texto) + itemlist=[] + try: + item.url = host + "/api/movies?originalTitle="+texto+"&translations.name=" +texto + data = httptools.downloadpage(item.url, headers=headers).data + json_object = jsontools.load(data) + for movie in json_object['hydra:member']: + itemlist.extend(get_itemlist_movie(movie,item)) + return itemlist + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("%s" % line) + return [] + +def search_movie_by_genre(item): + support.log() + itemlist = [] + data = httptools.downloadpage(item.url, headers=headers).data + json_object = jsontools.load(data) + for genre in json_object['hydra:member']: + itemlist.append( + Item(channel=item.channel, + action="peliculas", + title=support.typo(genre['name'],'bold'), + contentType='movie', + url="%s/api/movies?genres.id=%s" %(host,genre['id']), + extra=item.extra)) + return support.thumb(itemlist, True) + +def search_movie_by_year(item): + support.log() + now = datetime.datetime.now() + year = int(now.year) + itemlist = [] + for i in range(100): + year_to_search = year - i + itemlist.append(Item(channel=item.channel, + url="%s/api/movies?releaseDate=%s" %(host,year_to_search), + plot="1", + type="movie", + title=support.typo(year_to_search,'bold'), + action="peliculas")) + return itemlist + +def findvideos(item): + support.log() + itemlist = [] + try: + data = httptools.downloadpage(item.url, headers=headers).data + json_object = jsontools.load(data) + for video in json_object['hydra:member'][0]['playlist']['videos']: + data = httptools.downloadpage(video['src'], headers={'Origin': host},follow_redirects=None).data + patron = 'href="([^"]+)"' + video_link = scrapertools.find_single_match(data, patron) + itemlist.append( + Item( + channel=item.channel, + action="play", + thumbnail=item.thumbnail, + url=video_link, + server='directo', + quality=str(video['size'])+ 'p', + folder=False)) + except: + pass + return support.server(item, itemlist=itemlist) + +def get_itemlist_movie(movie,item): + support.log() + itemlist=[] + try: + if movie['originalLanguage']['id']=='it': + scrapedtitle=movie['originalTitle'] + else: + scrapedtitle=movie['translations'][1]['name'] + if scrapedtitle=='': + scrapedtitle=movie['originalTitle'] + except: + scrapedtitle=movie['originalTitle'] + try: + scrapedplot=movie['translations'][1]['overview'] + except: + scrapedplot = "" + try: + scrapedthumbnail="http://"+movie['posterPath'] + except: + scrapedthumbnail="" + try: + scrapedfanart="http://"+movie['backdropPath'] + except: + scrapedfanart="" + infoLabels = {} + infoLabels['tmdbid']=movie['tmdbId'] + itemlist.append( + Item(channel=item.channel, + action="findvideos", + title=support.typo(scrapedtitle,'bold') + support.typo(movie['lastQuality'].upper(), '_ [] color kod bold'), + fulltitle=scrapedtitle, + show=scrapedtitle, + plot=scrapedplot, + fanart=scrapedfanart, + thumbnail=scrapedthumbnail, + contentType='movie', + contentTitle=scrapedtitle, + url="%s%s/releases" %(host,movie['@id'] ), + infoLabels=infoLabels, + extra=item.extra)) + return itemlist diff --git a/channels/LIKUOO.json b/channels/porn/LIKUOO.json similarity index 100% rename from channels/LIKUOO.json rename to channels/porn/LIKUOO.json diff --git a/channels/LIKUOO.py b/channels/porn/LIKUOO.py similarity index 78% rename from channels/LIKUOO.py rename to channels/porn/LIKUOO.py index f42ed721..a0038dc6 100644 --- a/channels/LIKUOO.py +++ b/channels/porn/LIKUOO.py @@ -1,16 +1,14 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools -from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools -host = 'http://www.likuoo.video' +host = 'https://www.likuoo.video' def mainlist(item): @@ -83,13 +81,20 @@ def lista(item): def play(item): - logger.info() + itemlist = [] data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.fulltitle - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videochannel=item.channel + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = 'url:\'([^\']+)\'.*?' + patron += 'data:\'([^\']+)\'' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedurl,post in matches: + post = post.replace("%3D", "=") + scrapedurl = host + scrapedurl + logger.debug( item.url +" , "+ scrapedurl +" , " +post ) + datas = httptools.downloadpage(scrapedurl, post=post, headers={'Referer':item.url}).data + datas = datas.replace("\\", "") + url = scrapertools.find_single_match(datas, '<iframe src="([^"]+)"') + itemlist.append( Item(channel=item.channel, action="play", title = "%s", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist diff --git a/channels/TXXX.json b/channels/porn/TXXX.json similarity index 100% rename from channels/TXXX.json rename to channels/porn/TXXX.json diff --git a/channels/TXXX.py b/channels/porn/TXXX.py similarity index 98% rename from channels/TXXX.py rename to channels/porn/TXXX.py index 253b7312..32a360b2 100644 --- a/channels/TXXX.py +++ b/channels/porn/TXXX.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urllib -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://www.txxx.com' diff --git a/channels/porn/__init__.py b/channels/porn/__init__.py new file mode 100644 index 00000000..0b95a268 --- /dev/null +++ b/channels/porn/__init__.py @@ -0,0 +1,12 @@ +# -*- coding: utf-8 -*- + +import os +import sys + +# Appends the main plugin dir to the PYTHONPATH if an internal package cannot be imported. +# Examples: In Plex Media Server all modules are under "Code.*" package, and in Enigma2 under "Plugins.Extensions.*" +try: + # from core import logger + import core +except: + sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) diff --git a/channels/absoluporn.json b/channels/porn/absoluporn.json similarity index 100% rename from channels/absoluporn.json rename to channels/porn/absoluporn.json diff --git a/channels/absoluporn.py b/channels/porn/absoluporn.py similarity index 96% rename from channels/absoluporn.py rename to channels/porn/absoluporn.py index e5774e59..32abc69c 100644 --- a/channels/absoluporn.py +++ b/channels/porn/absoluporn.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.absoluporn.es' @@ -90,7 +89,7 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for servervideo,path,filee in matches: scrapedurl = servervideo + path + "56ea912c4df934c216c352fa8d623af3" + filee - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/alsoporn.json b/channels/porn/alsoporn.json similarity index 100% rename from channels/alsoporn.json rename to channels/porn/alsoporn.json diff --git a/channels/alsoporn.py b/channels/porn/alsoporn.py similarity index 77% rename from channels/alsoporn.py rename to channels/porn/alsoporn.py index 306d00d5..5433405d 100644 --- a/channels/alsoporn.py +++ b/channels/porn/alsoporn.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools +import base64 host = 'http://www.alsoporn.com' @@ -66,8 +66,9 @@ def lista(item): title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle thumbnail = scrapedthumbnail plot = "" - itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, - fanart=thumbnail, plot=plot, contentTitle = scrapedtitle)) + if not "0:00" in scrapedtime: + itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot, contentTitle = scrapedtitle)) next_page = scrapertools.find_single_match(data,'<li><a href="([^"]+)" target="_self"><span class="alsoporn_page">NEXT</span></a>') if next_page!="": @@ -81,11 +82,18 @@ def play(item): itemlist = [] data = httptools.downloadpage(item.url).data scrapedurl = scrapertools.find_single_match(data,'<iframe frameborder=0 scrolling="no" src=\'([^\']+)\'') - data = httptools.downloadpage(item.url).data + data = httptools.downloadpage(scrapedurl).data scrapedurl1 = scrapertools.find_single_match(data,'<iframe src="(.*?)"') - scrapedurl1 = scrapedurl1.replace("//www.playercdn.com/ec/i2.php?", "https://www.trinitytube.xyz/ec/i2.php?") - data = httptools.downloadpage(item.url).data - scrapedurl2 = scrapertools.find_single_match(data,'<source src="(.*?)"') - itemlist.append(item.clone(action="play", title=item.title, fulltitle = item.title, url=scrapedurl2)) + scrapedurl1 = scrapedurl1.replace("//www.playercdn.com/ec/i2.php?url=", "") + scrapedurl1 = base64.b64decode(scrapedurl1 + "=") + logger.debug(scrapedurl1) + data = httptools.downloadpage(scrapedurl1).data + if "xvideos" in scrapedurl1: + scrapedurl2 = scrapertools.find_single_match(data, 'html5player.setVideoHLS\(\'([^\']+)\'\)') + if "xhamster" in scrapedurl1: + scrapedurl2 = scrapertools.find_single_match(data, '"[0-9]+p":"([^"]+)"').replace("\\", "") + + logger.debug(scrapedurl2) + itemlist.append(item.clone(action="play", title=item.title, url=scrapedurl2)) return itemlist diff --git a/channels/analdin.json b/channels/porn/analdin.json similarity index 100% rename from channels/analdin.json rename to channels/porn/analdin.json diff --git a/channels/analdin.py b/channels/porn/analdin.py similarity index 96% rename from channels/analdin.py rename to channels/porn/analdin.py index 278d1433..65cb6793 100644 --- a/channels/analdin.py +++ b/channels/porn/analdin.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools + host = 'https://www.analdin.com/es' @@ -108,6 +108,6 @@ def play(item): matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl in matches: url = scrapedurl - itemlist.append(item.clone(action="play", title=url, fulltitle = item.title, url=url)) + itemlist.append(item.clone(action="play", title=url, url=url)) return itemlist diff --git a/channels/porn/beeg.json b/channels/porn/beeg.json new file mode 100755 index 00000000..01d595cb --- /dev/null +++ b/channels/porn/beeg.json @@ -0,0 +1,14 @@ +{ + "id": "beeg", + "name": "Beeg", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "beeg.png", + "banner": "beeg.png", + "categories": [ + "adult" + ], + "settings": [ + ] +} diff --git a/channels/porn/beeg.py b/channels/porn/beeg.py new file mode 100755 index 00000000..3ce4c8f9 --- /dev/null +++ b/channels/porn/beeg.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- + +import re +import urllib + +from core import jsontools as json +from core import scrapertools +from core.item import Item +from platformcode import logger +from core import httptools + + +url_api = "" +Host = "https://beeg.com" + + +def get_api_url(): + global url_api + data = httptools.downloadpage(Host).data + version = re.compile('var beeg_version = ([\d]+)').findall(data)[0] + url_api = Host + "/api/v6/" + version + + +get_api_url() + + +def mainlist(item): + logger.info() + get_api_url() + itemlist = [] + itemlist.append(Item(channel=item.channel, action="videos", title="Útimos videos", url=url_api + "/index/main/0/pc", + viewmode="movie")) + itemlist.append(Item(channel=item.channel, action="canal", title="Canal", + url=url_api + "/channels")) + itemlist.append(Item(channel=item.channel, action="listcategorias", title="Categorias", + url=url_api + "/index/main/0/pc", extra="nonpopular")) + itemlist.append( + Item(channel=item.channel, action="search", title="Buscar")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = url_api + "/index/tag/0/pc?tag=%s" % (texto) + + try: + return videos(item) + # Se captura la excepción, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + +def videos(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + JSONData = json.load(data) + for Video in JSONData["videos"]: + thumbnail = "http://img.beeg.com/236x177/" + str(Video["id"]) + ".jpg" + url= '%s/video/%s?v=2&s=%s&e=%s' % (url_api, Video['svid'], Video['start'], Video['end']) + title = Video["title"] + itemlist.append( + Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, plot="", show="", + folder=True, contentType="movie")) + # Paginador + Actual = int(scrapertools.find_single_match(item.url, url_api + '/index/[^/]+/([0-9]+)/pc')) + if JSONData["pages"] - 1 > Actual: + scrapedurl = item.url.replace("/" + str(Actual) + "/", "/" + str(Actual + 1) + "/") + itemlist.append( + Item(channel=item.channel, action="videos", title="Página Siguiente", url=scrapedurl, thumbnail="", + viewmode="movie")) + return itemlist + + +def listcategorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + JSONData = json.load(data) + for Tag in JSONData["tags"]: + url = url_api + "/index/tag/0/pc?tag=" + Tag["tag"] + url = url.replace("%20", "-") + title = '%s (%s)' % (str(Tag["tag"]), str(Tag["videos"])) + itemlist.append( + Item(channel=item.channel, action="videos", title=title, url=url, viewmode="movie", type="item")) + return itemlist + + +def canal(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + JSONData = json.load(data) + for Tag in JSONData["channels"]: + url = url_api + "/index/channel/0/pc?channel=" + Tag["channel"] + url = url.replace("%20", "-") + title = '%s (%s)' % (str(Tag["ps_name"]), str(Tag["videos"])) + itemlist.append( + Item(channel=item.channel, action="videos", title=title, url=url, viewmode="movie", type="item")) + return itemlist + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + JSONData = json.load(data) + for key in JSONData: + videourl = re.compile("([0-9]+p)", re.DOTALL).findall(key) + if videourl: + videourl = videourl[0] + if not JSONData[videourl] == None: + url = JSONData[videourl] + url = url.replace("{DATA_MARKERS}", "data=pc.ES") + if not url.startswith("https:"): url = "https:" + url + title = videourl + itemlist.append(["%s %s [directo]" % (title, url[-4:]), url]) + itemlist.sort(key=lambda item: item[0]) + return itemlist + diff --git a/channels/bravoporn.json b/channels/porn/bravoporn.json similarity index 100% rename from channels/bravoporn.json rename to channels/porn/bravoporn.json diff --git a/channels/bravoporn.py b/channels/porn/bravoporn.py similarity index 96% rename from channels/bravoporn.py rename to channels/porn/bravoporn.py index b8c52c35..740dd779 100644 --- a/channels/bravoporn.py +++ b/channels/porn/bravoporn.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.bravoporn.com' diff --git a/channels/camwhoresbay.json b/channels/porn/camwhoresbay.json similarity index 100% rename from channels/camwhoresbay.json rename to channels/porn/camwhoresbay.json diff --git a/channels/camwhoresbay.py b/channels/porn/camwhoresbay.py similarity index 95% rename from channels/camwhoresbay.py rename to channels/porn/camwhoresbay.py index 330edb20..85ba0b04 100644 --- a/channels/camwhoresbay.py +++ b/channels/porn/camwhoresbay.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.camwhoresbay.com' @@ -66,7 +65,7 @@ def lista(item): for scrapedurl,scrapedtitle,scrapedthumbnail,scrapedtime in matches: url = urlparse.urljoin(item.url,scrapedurl) title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle - thumbnail = scrapedthumbnail + thumbnail = "http:" + scrapedthumbnail + "|Referer=%s" % item.url plot = "" itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, plot=plot, contentTitle = scrapedtitle, fanart=thumbnail)) @@ -108,7 +107,7 @@ def play(item): if scrapedurl == "" : scrapedurl = scrapertools.find_single_match(data, 'video_url: \'([^\']+)\'') - itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, fulltitle=item.title, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo")) return itemlist diff --git a/channels/canalporno.json b/channels/porn/canalporno.json similarity index 100% rename from channels/canalporno.json rename to channels/porn/canalporno.json diff --git a/channels/porn/canalporno.py b/channels/porn/canalporno.py new file mode 100644 index 00000000..58051909 --- /dev/null +++ b/channels/porn/canalporno.py @@ -0,0 +1,92 @@ +# -*- coding: utf-8 -*- +import urlparse,re + +from core import httptools +from core import scrapertools +from platformcode import logger + +host = "http://www.canalporno.com" + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append(item.clone(action="lista", title="Útimos videos", url=host + "/ajax/homepage/?page=1")) + itemlist.append(item.clone(action="categorias", title="Canal", url=host + "/ajax/list_producers/?page=1")) + itemlist.append(item.clone(action="categorias", title="PornStar", url=host + "/ajax/list_pornstars/?page=1")) + itemlist.append(item.clone(action="categorias", title="Categorias", + url=host + "/categorias")) + itemlist.append(item.clone(action="search", title="Buscar")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/ajax/new_search/?q=%s&page=1" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + if "pornstars" in item.url: + patron = '<div class="muestra.*?href="([^"]+)".*?src=\'([^\']+)\'.*?alt="([^"]+)".*?' + else: + patron = '<div class="muestra.*?href="([^"]+)".*?src="([^"]+)".*?alt="([^"]+)".*?' + if "Categorias" in item.title: + patron += '<div class="numero">([^<]+)</div>' + else: + patron += '</span> (\d+) vídeos</div>' + matches = scrapertools.find_multiple_matches(data, patron) + for url, scrapedthumbnail, scrapedtitle, cantidad in matches: + title= "%s [COLOR yellow] %s [/COLOR]" % (scrapedtitle, cantidad) + url= url.replace("/videos-porno/", "/ajax/show_category/").replace("/sitio/", "/ajax/show_producer/").replace("/pornstar/", "/ajax/show_pornstar/") + url = host + url + "?page=1" + itemlist.append(item.clone(action="lista", title=title, url=url, thumbnail=scrapedthumbnail)) + if "/?page=" in item.url: + next_page=item.url + num= int(scrapertools.find_single_match(item.url,".*?/?page=(\d+)")) + num += 1 + next_page = "?page=" + str(num) + if next_page!="": + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append(item.clone(action="categorias", title="Página Siguiente >>", text_color="blue", url=next_page) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + patron = 'data-src="([^"]+)" alt="([^"]+)".*?<h2><a href="([^"]+)">.*?' \ + '<div class="duracion"><span class="ico-duracion sprite"></span> ([^"]+) min</div>' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedthumbnail, scrapedtitle, scrapedurl, duration in matches: + title = "[COLOR yellow] %s [/COLOR] %s" % (duration, scrapedtitle) + url = host + scrapedurl + itemlist.append(item.clone(action="play", title=title, url=url, thumbnail=scrapedthumbnail)) + last=scrapertools.find_single_match(item.url,'(.*?)page=\d+') + num= int(scrapertools.find_single_match(item.url,".*?/?page=(\d+)")) + num += 1 + next_page = "page=" + str(num) + if next_page!="": + next_page = last + next_page + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + url = scrapertools.find_single_match(data, '<source src="([^"]+)"') + itemlist.append(item.clone(url=url, server="directo")) + return itemlist diff --git a/channels/cat3plus.json b/channels/porn/cat3plus.json similarity index 95% rename from channels/cat3plus.json rename to channels/porn/cat3plus.json index 63a66ac7..ada3335f 100644 --- a/channels/cat3plus.json +++ b/channels/porn/cat3plus.json @@ -9,6 +9,6 @@ "banner": "https://i.imgur.com/bXUyk6m.png", "categories": [ "movie", - "vo" + "vos" ] -} \ No newline at end of file +} diff --git a/channels/cat3plus.py b/channels/porn/cat3plus.py similarity index 98% rename from channels/cat3plus.py rename to channels/porn/cat3plus.py index f746a00d..ea0a7234 100644 --- a/channels/cat3plus.py +++ b/channels/porn/cat3plus.py @@ -5,7 +5,8 @@ import re - +import urllib +import urlparse from channelselector import get_thumb from core import httptools from core import scrapertools @@ -83,7 +84,7 @@ def search(item, texto): logger.info() if texto != "": texto = texto.replace(" ", "+") - item.url = host + "/search?q=" + texto + item.url = host + "search?q=" + texto item.extra = "busqueda" try: return list_all(item) diff --git a/channels/cinetemagay.json b/channels/porn/cinetemagay.json similarity index 100% rename from channels/cinetemagay.json rename to channels/porn/cinetemagay.json diff --git a/channels/cinetemagay.py b/channels/porn/cinetemagay.py similarity index 99% rename from channels/cinetemagay.py rename to channels/porn/cinetemagay.py index ad575f68..ad5f5a6d 100644 --- a/channels/cinetemagay.py +++ b/channels/porn/cinetemagay.py @@ -3,8 +3,9 @@ import os import re -from core import httptools +from core import scrapertools from core import servertools +from core import httptools from core.item import Item from platformcode import config, logger diff --git a/channels/cliphunter.json b/channels/porn/cliphunter.json similarity index 100% rename from channels/cliphunter.json rename to channels/porn/cliphunter.json diff --git a/channels/cliphunter.py b/channels/porn/cliphunter.py similarity index 95% rename from channels/cliphunter.py rename to channels/porn/cliphunter.py index 7ba4ad64..16f3d093 100644 --- a/channels/cliphunter.py +++ b/channels/porn/cliphunter.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools + host = 'https://www.cliphunter.com' @@ -84,9 +84,8 @@ def lista(item): title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle thumbnail = scrapedthumbnail plot = "" - year = "" itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, plot=plot, - fanart=thumbnail, contentTitle = title, infoLabels={'year':year} )) + fanart=thumbnail, contentTitle = title )) next_page = scrapertools.find_single_match(data,'<li class="arrow"><a rel="next" href="([^"]+)">»</a>') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) @@ -103,7 +102,7 @@ def play(item): for scrapedurl in matches: scrapedurl = scrapedurl.replace("\/", "/") title = scrapedurl - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo")) return itemlist diff --git a/channels/coomelonitas.json b/channels/porn/coomelonitas.json similarity index 100% rename from channels/coomelonitas.json rename to channels/porn/coomelonitas.json diff --git a/channels/coomelonitas.py b/channels/porn/coomelonitas.py similarity index 93% rename from channels/coomelonitas.py rename to channels/porn/coomelonitas.py index 5d44526a..ae943a7d 100644 --- a/channels/coomelonitas.py +++ b/channels/porn/coomelonitas.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host ='http://www.coomelonitas.com' - def mainlist(item): logger.info() itemlist = [] @@ -57,7 +56,7 @@ def lista(item): url = scrapertools.find_single_match(match,'<a href="([^"]+)"') plot = scrapertools.find_single_match(match,'<p class="summary">(.*?)</p>') thumbnail = scrapertools.find_single_match(match,'<img src="([^"]+)"') - itemlist.append( Item(channel=item.channel, action="findvideos", title=title, fulltitle=title, url=url, + itemlist.append( Item(channel=item.channel, action="findvideos", title=title, url=url, fanart=thumbnail, thumbnail=thumbnail, plot=plot, viewmode="movie") ) next_page = scrapertools.find_single_match(data,'<a href="([^"]+)" class="siguiente">') if next_page!="": diff --git a/channels/cumlouder.json b/channels/porn/cumlouder.json similarity index 100% rename from channels/cumlouder.json rename to channels/porn/cumlouder.json diff --git a/channels/cumlouder.py b/channels/porn/cumlouder.py similarity index 66% rename from channels/cumlouder.py rename to channels/porn/cumlouder.py index 1bc5568c..4380a53a 100644 --- a/channels/cumlouder.py +++ b/channels/porn/cumlouder.py @@ -2,7 +2,6 @@ import re import urllib - import urlparse from core import httptools @@ -11,23 +10,22 @@ from core.item import Item from platformcode import config, logger +host = 'https://www.cumlouder.com' + def mainlist(item): logger.info() itemlist = [] - config.set_setting("url_error", False, "cumlouder") - itemlist.append(item.clone(title="Últimos videos", action="videos", url="https://www.cumlouder.com/")) - itemlist.append(item.clone(title="Categorias", action="categorias", url="https://www.cumlouder.com/categories/")) - itemlist.append(item.clone(title="Pornstars", action="pornstars_list", url="https://www.cumlouder.com/girls/")) - itemlist.append(item.clone(title="Listas", action="series", url="https://www.cumlouder.com/series/")) - itemlist.append(item.clone(title="Buscar", action="search", url="https://www.cumlouder.com/search?q=%s")) - + itemlist.append(item.clone(title="Últimos videos", action="videos", url= host + "/porn/")) + itemlist.append(item.clone(title="Pornstars", action="pornstars_list", url=host + "/girls/")) + itemlist.append(item.clone(title="Listas", action="series", url= host + "/series/")) + itemlist.append(item.clone(title="Categorias", action="categorias", url= host + "/categories/")) + itemlist.append(item.clone(title="Buscar", action="search", url= host + "/search?q=%s")) return itemlist def search(item, texto): logger.info() - item.url = item.url % texto item.action = "videos" try: @@ -41,21 +39,20 @@ def search(item, texto): def pornstars_list(item): logger.info() itemlist = [] + itemlist.append(item.clone(title="Mas Populares", action="pornstars", url=host + "/girls/1/")) for letra in "abcdefghijklmnopqrstuvwxyz": itemlist.append(item.clone(title=letra.upper(), url=urlparse.urljoin(item.url, letra), action="pornstars")) - return itemlist def pornstars(item): logger.info() itemlist = [] - - data = get_data(item.url) - patron = '<a girl-url="[^"]+" class="[^"]+" href="([^"]+)" title="([^"]+)">[^<]+' - patron += '<img class="thumb" src="([^"]+)" [^<]+<h2[^<]+<span[^<]+</span[^<]+</h2[^<]+' - patron += '<span[^<]+<span[^<]+<span[^<]+</span>([^<]+)</span>' - + data = httptools.downloadpage(item.url).data + patron = '<a girl-url=.*?' + patron += 'href="([^"]+)" title="([^"]+)">.*?' + patron += 'data-lazy="([^"]+)".*?' + patron += '<span class="ico-videos sprite"></span>([^<]+)</span>' matches = re.compile(patron, re.DOTALL).findall(data) for url, title, thumbnail, count in matches: if "go.php?" in url: @@ -65,8 +62,7 @@ def pornstars(item): url = urlparse.urljoin(item.url, url) if not thumbnail.startswith("https"): thumbnail = "https:%s" % thumbnail - itemlist.append(item.clone(title="%s (%s)" % (title, count), url=url, action="videos", thumbnail=thumbnail)) - + itemlist.append(item.clone(title="%s (%s)" % (title, count), url=url, action="videos", fanart=thumbnail, thumbnail=thumbnail)) # Paginador matches = re.compile('<li[^<]+<a href="([^"]+)" rel="nofollow">Next[^<]+</a[^<]+</li>', re.DOTALL).findall(data) if matches: @@ -74,18 +70,19 @@ def pornstars(item): url = urllib.unquote(matches[0].split("/go.php?u=")[1].split("&")[0]) else: url = urlparse.urljoin(item.url, matches[0]) - itemlist.append(item.clone(title="Pagina Siguiente", url=url)) - + itemlist.append(item.clone(title="Página Siguiente >>", url=url)) return itemlist def categorias(item): logger.info() itemlist = [] - - data = get_data(item.url) + data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}| ", "", data) - patron = '<a tag-url=.*?href="([^"]+)" title="([^"]+)".*?<img class="thumb" src="([^"]+)".*?<span class="cantidad">([^<]+)</span>' + patron = '<a tag-url=.*?' + patron += 'href="([^"]+)" title="([^"]+)".*?' + patron += 'data-lazy="([^"]+)".*?' + patron += '<span class="cantidad">([^<]+)</span>' matches = re.compile(patron, re.DOTALL).findall(data) for url, title, thumbnail, count in matches: if "go.php?" in url: @@ -96,8 +93,7 @@ def categorias(item): if not thumbnail.startswith("https"): thumbnail = "https:%s" % thumbnail itemlist.append( - item.clone(title="%s (%s videos)" % (title, count), url=url, action="videos", thumbnail=thumbnail)) - + item.clone(title="%s (%s videos)" % (title, count), url=url, action="videos", fanart=thumbnail, thumbnail=thumbnail)) # Paginador matches = re.compile('<li[^<]+<a href="([^"]+)" rel="nofollow">Next[^<]+</a[^<]+</li>', re.DOTALL).findall(data) if matches: @@ -105,22 +101,20 @@ def categorias(item): url = urllib.unquote(matches[0].split("/go.php?u=")[1].split("&")[0]) else: url = urlparse.urljoin(item.url, matches[0]) - itemlist.append(item.clone(title="Pagina Siguiente", url=url)) - + itemlist.append(item.clone(title="Página Siguiente >>", url=url)) return itemlist + def series(item): logger.info() itemlist = [] - - data = get_data(item.url) + data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}| ", "", data) patron = '<a onclick=.*?href="([^"]+)".*?\<img src="([^"]+)".*?h2 itemprop="name">([^<]+).*?p>([^<]+)</p>' matches = re.compile(patron, re.DOTALL).findall(data) for url, thumbnail, title, count in matches: itemlist.append( - item.clone(title="%s (%s) " % (title, count), url=urlparse.urljoin(item.url, url), action="videos", thumbnail=thumbnail)) - + item.clone(title="%s (%s) " % (title, count), url=urlparse.urljoin(item.url, url), action="videos", fanart=thumbnail, thumbnail=thumbnail)) # Paginador matches = re.compile('<li[^<]+<a href="([^"]+)" rel="nofollow">Next[^<]+</a[^<]+</li>', re.DOTALL).findall(data) if matches: @@ -128,29 +122,33 @@ def series(item): url = urllib.unquote(matches[0].split("/go.php?u=")[1].split("&")[0]) else: url = urlparse.urljoin(item.url, matches[0]) - itemlist.append(item.clone(title="Pagina Siguiente", url=url)) - + itemlist.append(item.clone(title="Página Siguiente >>", url=url)) return itemlist + def videos(item): logger.info() itemlist = [] - - data = get_data(item.url) - patron = '<a class="muestra-escena" href="([^"]+)" title="([^"]+)"[^<]+<img class="thumb" src="([^"]+)".*?<span class="minutos"> <span class="ico-minutos sprite"></span> ([^<]+)</span>' + data = httptools.downloadpage(item.url).data + patron = '<a class="muestra-escena" href="([^"]+)" title="([^"]+)".*?' + patron += 'data-lazy="([^"]+)".*?' + patron += '<span class="ico-minutos sprite"></span>([^<]+)</span>(.*?)</a>' matches = re.compile(patron, re.DOTALL).findall(data) - for url, title, thumbnail, duration in matches: + for url, title, thumbnail, duration,calidad in matches: + if "hd sprite" in calidad: + title="[COLOR yellow] %s [/COLOR][COLOR red] HD [/COLOR] %s" % (duration, title) + else: + title="[COLOR yellow] %s [/COLOR] %s" % (duration, title) if "go.php?" in url: url = urllib.unquote(url.split("/go.php?u=")[1].split("&")[0]) thumbnail = urllib.unquote(thumbnail.split("/go.php?u=")[1].split("&")[0]) else: - url = urlparse.urljoin("https://www.cumlouder.com", url) + url = urlparse.urljoin(host, url) if not thumbnail.startswith("https"): thumbnail = "https:%s" % thumbnail - itemlist.append(item.clone(title="%s (%s)" % (title, duration), url=urlparse.urljoin(item.url, url), + itemlist.append(item.clone(title=title, url=url, action="play", thumbnail=thumbnail, contentThumbnail=thumbnail, - contentType="movie", contentTitle=title)) - + fanart=thumbnail, contentType="movie", contentTitle=title)) # Paginador nextpage = scrapertools.find_single_match(data, '<ul class="paginador"(.*?)</ul>') matches = re.compile('<a href="([^"]+)" rel="nofollow">Next »</a>', re.DOTALL).findall(nextpage) @@ -161,51 +159,22 @@ def videos(item): url = urllib.unquote(matches[0].split("/go.php?u=")[1].split("&")[0]) else: url = urlparse.urljoin(item.url, matches[0]) - - itemlist.append(item.clone(title="Pagina Siguiente", url=url)) - + itemlist.append(item.clone(title="Página Siguiente >>", url=url)) return itemlist def play(item): logger.info() itemlist = [] - - data = get_data(item.url) - patron = '<source src="([^"]+)" type=\'video/([^\']+)\' label=\'[^\']+\' res=\'([^\']+)\' />' + data = httptools.downloadpage(item.url).data + patron = '<source src="([^"]+)" type=\'video/([^\']+)\' label=\'[^\']+\' res=\'([^\']+)\'' url, type, res = re.compile(patron, re.DOTALL).findall(data)[0] if "go.php?" in url: url = urllib.unquote(url.split("/go.php?u=")[1].split("&")[0]) elif not url.startswith("http"): - url = "http:" + url.replace("&", "&") + url = "https:" + url.replace("&", "&") itemlist.append( - Item(channel='cumlouder', action="play", title='Video' + res, fulltitle=type.upper() + ' ' + res, url=url, + Item(channel='cumlouder', action="play", title='Video' + res, contentTitle=type.upper() + ' ' + res, url=url, server="directo", folder=False)) - return itemlist - -def get_data(url_orig): - try: - if config.get_setting("url_error", "cumlouder"): - raise Exception - response = httptools.downloadpage(url_orig) - if not response.data or "urlopen error [Errno 1]" in str(response.code): - raise Exception - except: - config.set_setting("url_error", True, "cumlouder") - import random - server_random = ['nl', 'de', 'us'] - server = server_random[random.randint(0, 2)] - url = "https://%s.hideproxy.me/includes/process.php?action=update" % server - post = "u=%s&proxy_formdata_server=%s&allowCookies=1&encodeURL=0&encodePage=0&stripObjects=0&stripJS=0&go=" \ - % (urllib.quote(url_orig), server) - while True: - response = httptools.downloadpage(url, post, follow_redirects=False) - if response.headers.get("location"): - url = response.headers["location"] - post = "" - else: - break - - return response.data diff --git a/channels/czechvideo.json b/channels/porn/czechvideo.json similarity index 92% rename from channels/czechvideo.json rename to channels/porn/czechvideo.json index b770da2e..84b1c775 100644 --- a/channels/czechvideo.json +++ b/channels/porn/czechvideo.json @@ -1,7 +1,7 @@ { "id": "czechvideo", "name": "Czechvideo", - "active": true, + "active": false, "adult": true, "language": ["*"], "thumbnail": "http://czechvideo.org/templates/Default/images/black75.png", diff --git a/channels/czechvideo.py b/channels/porn/czechvideo.py similarity index 95% rename from channels/czechvideo.py rename to channels/porn/czechvideo.py index a750ede4..23b444aa 100644 --- a/channels/czechvideo.py +++ b/channels/porn/czechvideo.py @@ -1,15 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://czechvideo.org' @@ -82,7 +80,7 @@ def play(item): itemlist = servertools.find_video_items(data=data) for videoitem in itemlist: videoitem.title = item.title - videoitem.fulltitle = item.fulltitle + videoitem.contentTitle = item.contentTitle videoitem.thumbnail = item.thumbnail videoitem.channel = item.channel return itemlist diff --git a/channels/datoporn.json b/channels/porn/datoporn.json similarity index 100% rename from channels/datoporn.json rename to channels/porn/datoporn.json diff --git a/channels/datoporn.py b/channels/porn/datoporn.py similarity index 64% rename from channels/datoporn.py rename to channels/porn/datoporn.py index 507efb1d..243e4a8c 100644 --- a/channels/datoporn.py +++ b/channels/porn/datoporn.py @@ -4,8 +4,7 @@ import re from core import httptools from core import scrapertools -from platformcode import logger -from platformcode import config +from platformcode import config, logger def mainlist(item): @@ -26,49 +25,39 @@ def search(item, texto): def lista(item): logger.info() itemlist = [] - - # Descarga la pagina data = re.sub(r"\n|\r|\t|\s{2}|(<!--.*?-->)", "", httptools.downloadpage(item.url).data) - - # Extrae las entradas - patron = '<div class="videobox">\s*<a href="([^"]+)".*?url\(\'([^\']+)\'.*?<span>(.*?)<\/span><\/div><\/a>.*?class="title">(.*?)<\/a><span class="views">.*?<\/a><\/span><\/div> ' + patron = '<div class="videobox">\s*<a href="([^"]+)".*?' + patron += 'url\(\'([^\']+)\'.*?' + patron += '<span>(.*?)<\/span>.*?' + patron += 'class="title">(.*?)<\/a>' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedthumbnail, duration, scrapedtitle in matches: if "/embed-" not in scrapedurl: - #scrapedurl = scrapedurl.replace("dato.porn/", "dato.porn/embed-") + ".html" scrapedurl = scrapedurl.replace("datoporn.co/", "datoporn.co/embed-") + ".html" - if duration: - scrapedtitle = "%s - %s" % (duration, scrapedtitle) - scrapedtitle += ' gb' - scrapedtitle = scrapedtitle.replace(":", "'") - - #logger.debug(scrapedurl + ' / ' + scrapedthumbnail + ' / ' + duration + ' / ' + scrapedtitle) - itemlist.append(item.clone(action="play", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, - server="datoporn", fanart=scrapedthumbnail.replace("_t.jpg", ".jpg"))) - - # Extrae la marca de siguiente página - #next_page = scrapertools.find_single_match(data, '<a href=["|\']([^["|\']+)["|\']>Next') + if not config.get_setting('unify'): + scrapedtitle = '[COLOR yellow] %s [/COLOR] %s' % (duration , scrapedtitle) + else: + scrapedtitle += ' gb' + scrapedtitle = "[COLOR yellow]" + duration + "[/COLOR] " + scrapedtitle + scrapedtitle = scrapedtitle.replace(":", "'") + # logger.debug(scrapedurl + ' / ' + scrapedthumbnail + ' / ' + duration + ' / ' + scrapedtitle) + itemlist.append(item.clone(action="play", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, server="datoporn", + fanart=scrapedthumbnail.replace("_t.jpg", ".jpg"), plot = "")) next_page = scrapertools.find_single_match(data, '<a class=["|\']page-link["|\'] href=["|\']([^["|\']+)["|\']>Next') if next_page and itemlist: itemlist.append(item.clone(action="lista", title=">> Página Siguiente", url=next_page)) - return itemlist def categorias(item): logger.info() itemlist = [] - - # Descarga la pagina data = httptools.downloadpage(item.url).data - - # Extrae las entradas (carpetas) patron = '<div class="vid_block">\s*<a href="([^"]+)".*?url\((.*?)\).*?<span>(.*?)</span>.*?<b>(.*?)</b>' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedthumbnail, numero, scrapedtitle in matches: if numero: scrapedtitle = "%s (%s)" % (scrapedtitle, numero) - itemlist.append(item.clone(action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail)) - return itemlist + diff --git a/channels/elreyx.json b/channels/porn/elreyx.json similarity index 100% rename from channels/elreyx.json rename to channels/porn/elreyx.json diff --git a/channels/elreyx.py b/channels/porn/elreyx.py similarity index 100% rename from channels/elreyx.py rename to channels/porn/elreyx.py diff --git a/channels/eporner.json b/channels/porn/eporner.json similarity index 100% rename from channels/eporner.json rename to channels/porn/eporner.json diff --git a/channels/eporner.py b/channels/porn/eporner.py similarity index 53% rename from channels/eporner.py rename to channels/porn/eporner.py index 00b0e4b2..b82358c0 100644 --- a/channels/eporner.py +++ b/channels/porn/eporner.py @@ -1,38 +1,37 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools -from core import jsontools +from core import scrapertools from platformcode import logger -from platformcode import config +host = 'http://www.eporner.com' def mainlist(item): logger.info() itemlist = [] - - itemlist.append(item.clone(title="Últimos videos", action="videos", url="http://www.eporner.com/0/")) - itemlist.append(item.clone(title="Categorias", action="categorias", url="http://www.eporner.com/categories/")) - itemlist.append(item.clone(title="Pornstars", action="pornstars_list", url="http://www.eporner.com/pornstars/")) - itemlist.append(item.clone(title="Buscar", action="search", url="http://www.eporner.com/search/%s/")) - + itemlist.append(item.clone(title="Últimos videos", action="videos", url=host + "/0/")) + itemlist.append(item.clone(title="Más visto", action="videos", url=host + "/most-viewed/")) + itemlist.append(item.clone(title="Mejor valorado", action="videos", url=host + "/top-rated/")) + itemlist.append(item.clone(title="Categorias", action="categorias", url=host + "/categories/")) + itemlist.append(item.clone(title="Pornstars", action="pornstars", url=host + "/pornstars/")) + itemlist.append(item.clone(title=" Alfabetico", action="pornstars_list", url=host + "/pornstars/")) + itemlist.append(item.clone(title="Buscar", action="search")) return itemlist def search(item, texto): logger.info() - - item.url = item.url % texto - item.action = "videos" - + texto = texto.replace(" ", "-") + item.url = host + "/search/%s/" % texto try: return videos(item) except: - import traceback - logger.error(traceback.format_exc()) + import sys + for line in sys.exc_info(): + logger.error("%s" % line) return [] @@ -41,71 +40,67 @@ def pornstars_list(item): itemlist = [] for letra in "ABCDEFGHIJKLMNOPQRSTUVWXYZ": itemlist.append(item.clone(title=letra, url=urlparse.urljoin(item.url, letra), action="pornstars")) - return itemlist def pornstars(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data - - patron = '<div class="mbtit" itemprop="name"><a href="([^"]+)" title="([^"]+)">[^<]+</a></div> ' - patron += '<a href="[^"]+" title="[^"]+"> <img src="([^"]+)" alt="[^"]+" style="width:190px;height:152px;" /> </a> ' + patron = '<div class="mbprofile">.*?' + patron += '<a href="([^"]+)" title="([^"]+)">.*?' + patron += '<img src="([^"]+)".*?' patron += '<div class="mbtim"><span>Videos: </span>([^<]+)</div>' - matches = re.compile(patron, re.DOTALL).findall(data) for url, title, thumbnail, count in matches: itemlist.append( item.clone(title="%s (%s videos)" % (title, count), url=urlparse.urljoin(item.url, url), action="videos", thumbnail=thumbnail)) - - # Paginador - patron = "<span style='color:#FFCC00;'>[^<]+</span></a> <a href='([^']+)' title='[^']+'><span>[^<]+</span></a>" - matches = re.compile(patron, re.DOTALL).findall(data) - if matches: - itemlist.append(item.clone(title="Pagina siguiente", url=urlparse.urljoin(item.url, matches[0]))) - + # Paginador + next_page = scrapertools.find_single_match(data,"<a href='([^']+)' class='nmnext' title='Next page'>") + if next_page!="": + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append(item.clone(action="pornstars", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist def categorias(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data - - patron = '<div class="categoriesbox" id="[^"]+"> <div class="ctbinner"> <a href="([^"]+)" title="[^"]+"> <img src="([^"]+)" alt="[^"]+"> <h2>([^"]+)</h2> </a> </div> </div>' - + patron = '<span class="addrem-cat">.*?' + patron += '<a href="([^"]+)" title="([^"]+)">.*?' + patron +='<div class="cllnumber">([^<]+)</div>' matches = re.compile(patron, re.DOTALL).findall(data) - for url, thumbnail, title in matches: - itemlist.append( - item.clone(title=title, url=urlparse.urljoin(item.url, url), action="videos", thumbnail=thumbnail)) - + for url, title, cantidad in matches: + url = urlparse.urljoin(item.url, url) + title = title + " " + cantidad + thumbnail = "" + if not thumbnail: + thumbnail = scrapertools.find_single_match(data,'<img src="([^"]+)" alt="%s"> % title') + itemlist.append(item.clone(title=title, url=url, action="videos", thumbnail=thumbnail)) return sorted(itemlist, key=lambda i: i.title) def videos(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data - - patron = '<a href="([^"]+)" title="([^"]+)" id="[^"]+">.*?<img id="[^"]+" src="([^"]+)"[^>]+>.*?<div class="mbtim">([^<]+)</div>' - + patron = '<div class="mvhdico"><span>([^<]+)</span>.*?' + patron += '<a href="([^"]+)" title="([^"]+)" id="[^"]+">.*?' + patron += 'src="([^"]+)"[^>]+>.*?' + patron += '<div class="mbtim">([^<]+)</div>' matches = re.compile(patron, re.DOTALL).findall(data) - for url, title, thumbnail, duration in matches: - itemlist.append(item.clone(title="%s (%s)" % (title, duration), url=urlparse.urljoin(item.url, url), + for quality, url, title, thumbnail, duration in matches: + title = "[COLOR yellow]" + duration + "[/COLOR] " + "[COLOR red]" + quality + "[/COLOR] " +title + itemlist.append(item.clone(title=title, url=urlparse.urljoin(item.url, url), action="play", thumbnail=thumbnail, contentThumbnail=thumbnail, contentType="movie", contentTitle=title)) - # Paginador - patron = "<span style='color:#FFCC00;'>[^<]+</span></a> <a href='([^']+)' title='[^']+'><span>[^<]+</span></a>" - matches = re.compile(patron, re.DOTALL).findall(data) - if matches: - itemlist.append(item.clone(title="Página siguiente", url=urlparse.urljoin(item.url, matches[0]))) - + next_page = scrapertools.find_single_match(data,"<a href='([^']+)' class='nmnext' title='Next page'>") + if next_page!="": + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append(item.clone(action="videos", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist @@ -135,8 +130,7 @@ def play(item): int(hash[16:24], 16)) + int_to_base36(int(hash[24:32], 16)) url = "https://www.eporner.com/xhr/video/%s?hash=%s" % (vid, hash) - data = httptools.downloadpage(url).data - jsondata = jsontools.load(data) + jsondata = httptools.downloadpage(url).json for source in jsondata["sources"]["mp4"]: url = jsondata["sources"]["mp4"][source]["src"] diff --git a/channels/eroticage.json b/channels/porn/eroticage.json similarity index 100% rename from channels/eroticage.json rename to channels/porn/eroticage.json diff --git a/channels/eroticage.py b/channels/porn/eroticage.py similarity index 96% rename from channels/eroticage.py rename to channels/porn/eroticage.py index 568b39a0..fab51da2 100644 --- a/channels/eroticage.py +++ b/channels/porn/eroticage.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://www.eroticage.net' diff --git a/channels/eroticasonlinetv.json b/channels/porn/eroticasonlinetv.json similarity index 100% rename from channels/eroticasonlinetv.json rename to channels/porn/eroticasonlinetv.json diff --git a/channels/eroticasonlinetv.py b/channels/porn/eroticasonlinetv.py similarity index 100% rename from channels/eroticasonlinetv.py rename to channels/porn/eroticasonlinetv.py diff --git a/channels/erotik.json b/channels/porn/erotik.json similarity index 60% rename from channels/erotik.json rename to channels/porn/erotik.json index bedade55..8724bd2f 100644 --- a/channels/erotik.json +++ b/channels/porn/erotik.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": true, - "enabled": true, - "visible": true - } ] -} \ No newline at end of file +} diff --git a/channels/erotik.py b/channels/porn/erotik.py similarity index 54% rename from channels/erotik.py rename to channels/porn/erotik.py index f39befd7..55f089fb 100644 --- a/channels/erotik.py +++ b/channels/porn/erotik.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools @@ -9,7 +8,6 @@ from core import scrapertools from core import servertools from core.item import Item from platformcode import logger -from platformcode import config host = "https://www.youfreeporntube.net" @@ -17,11 +15,12 @@ def mainlist(item): logger.info() itemlist = [] itemlist.append(Item(channel=item.channel, action="lista", title="Útimos videos", - url= host + "/new-clips.html?&page=1")) + url= host + "/newvideos.html?&page=1")) + itemlist.append(Item(channel=item.channel, action="lista", title="Populares", + url=host + "/topvideos.html?page=1")) itemlist.append( Item(channel=item.channel, action="categorias", title="Categorias", url=host + "/browse.html")) - itemlist.append(Item(channel=item.channel, action="lista", title="Populares", - url=host + "/topvideo.html?page=1")) + itemlist.append(Item(channel=item.channel, action="search", title="Buscar", url=host + "/search.php?keywords=")) return itemlist @@ -49,7 +48,7 @@ def categorias(item): patron = '<div class="pm-li-category"><a href="([^"]+)">.*?.<h3>(.*?)</h3></a>' matches = re.compile(patron, re.DOTALL).findall(data) for url, actriz in matches: - itemlist.append(Item(channel=item.channel, action="listacategoria", title=actriz, url=url)) + itemlist.append(Item(channel=item.channel, action="lista", title=actriz, url=url)) return itemlist @@ -58,7 +57,9 @@ def lista(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}", "", data) - patron = '<li><div class=".*?<a href="([^"]+)".*?>.*?.img src="([^"]+)".*?alt="([^"]+)".*?>' + patron = '<li><div class=".*?' + patron += '<a href="([^"]+)".*?' + patron += '<img src="([^"]+)".*?alt="([^"]+)"' matches = re.compile(patron, re.DOTALL).findall(data) itemlist = [] for scrapedurl, scrapedthumbnail, scrapedtitle in matches: @@ -66,36 +67,14 @@ def lista(item): thumbnail = urlparse.urljoin(item.url, scrapedthumbnail) title = scrapedtitle.strip() itemlist.append(Item(channel=item.channel, action="play", thumbnail=thumbnail, fanart=thumbnail, title=title, - fulltitle=title, url=url, + url=url, viewmode="movie", folder=True)) paginacion = scrapertools.find_single_match(data, - '<li class="active"><a href="#" onclick="return false;">\d+</a></li><li class=""><a href="([^"]+)">') + '<li class="active">.*?</li>.*?<a href="([^"]+)">') if paginacion: + paginacion = urlparse.urljoin(item.url,paginacion) itemlist.append(Item(channel=item.channel, action="lista", title=">> Página Siguiente", - url=host + "/" + paginacion)) - return itemlist - - -def listacategoria(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - data = re.sub(r"\n|\r|\t|\s{2}", "", data) - patron = '<li><div class=".*?<a href="([^"]+)".*?>.*?.img src="([^"]+)".*?alt="([^"]+)".*?>' - matches = re.compile(patron, re.DOTALL).findall(data) - itemlist = [] - for scrapedurl, scrapedthumbnail, scrapedtitle in matches: - url = urlparse.urljoin(item.url, scrapedurl) - thumbnail = urlparse.urljoin(item.url, scrapedthumbnail) - title = scrapedtitle.strip() - itemlist.append( - Item(channel=item.channel, action="play", thumbnail=thumbnail, title=title, fulltitle=title, url=url, - viewmode="movie", folder=True)) - paginacion = scrapertools.find_single_match(data, - '<li class="active"><a href="#" onclick="return false;">\d+</a></li><li class=""><a href="([^"]+)">') - if paginacion: - itemlist.append( - Item(channel=item.channel, action="listacategoria", title=">> Página Siguiente", url=paginacion)) + url= paginacion)) return itemlist @@ -103,14 +82,9 @@ def play(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - item.url = scrapertools.find_single_match(data, '(?i)Playerholder.*?src="([^"]+)"') - if "tubst.net" in item.url: - url = scrapertools.find_single_match(data, 'itemprop="embedURL" content="([^"]+)') - data = httptools.downloadpage(url).data - url = scrapertools.find_single_match(data, '<iframe.*?src="([^"]+)"') - data = httptools.downloadpage(url).data - url = scrapertools.find_single_match(data, '<source src="([^"]+)"') - item.url = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers.get("location", "") - itemlist.append(item.clone()) + url = scrapertools.find_single_match(data, '<div id="video-wrapper">.*?<iframe.*?src="([^"]+)"') + itemlist.append(item.clone(action="play", title=url, url=url )) itemlist = servertools.get_servers_itemlist(itemlist) return itemlist + + diff --git a/channels/fapality.json b/channels/porn/fapality.json similarity index 77% rename from channels/fapality.json rename to channels/porn/fapality.json index c0d28164..564fc8d4 100644 --- a/channels/fapality.json +++ b/channels/porn/fapality.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "", + "thumbnail": "https://i.imgur.com/Orguh85.png", "banner": "", "categories": [ "adult" diff --git a/channels/fapality.py b/channels/porn/fapality.py similarity index 94% rename from channels/fapality.py rename to channels/porn/fapality.py index 20c77965..d0527c27 100644 --- a/channels/fapality.py +++ b/channels/porn/fapality.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://fapality.com' @@ -93,6 +92,6 @@ def play(item): matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl in matches: url = scrapedurl - itemlist.append(item.clone(action="play", title=url, fulltitle = item.title, url=url)) + itemlist.append(item.clone(action="play", title=url, contentTitle = item.title, url=url)) return itemlist diff --git a/channels/fetishshrine.json b/channels/porn/fetishshrine.json similarity index 100% rename from channels/fetishshrine.json rename to channels/porn/fetishshrine.json diff --git a/channels/fetishshrine.py b/channels/porn/fetishshrine.py similarity index 96% rename from channels/fetishshrine.py rename to channels/porn/fetishshrine.py index 52168aae..a0a3971d 100644 --- a/channels/fetishshrine.py +++ b/channels/porn/fetishshrine.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.fetishshrine.com' diff --git a/channels/filmoviXXX.json b/channels/porn/filmoviXXX.json similarity index 100% rename from channels/filmoviXXX.json rename to channels/porn/filmoviXXX.json diff --git a/channels/filmoviXXX.py b/channels/porn/filmoviXXX.py similarity index 92% rename from channels/filmoviXXX.py rename to channels/porn/filmoviXXX.py index 5669cfbe..5993b540 100644 --- a/channels/filmoviXXX.py +++ b/channels/porn/filmoviXXX.py @@ -1,15 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config - +from platformcode import config, logger +from core import httptools # BLOQUEO ESET INTERNET SECURITY def mainlist(item): @@ -43,7 +40,6 @@ def play(item): itemlist = servertools.find_video_items(data=data) for videoitem in itemlist: videoitem.title = item.title - videoitem.fulltitle = item.fulltitle videoitem.thumbnail = item.thumbnail videoitem.channel = item.channel return itemlist diff --git a/channels/filmpornoita.json b/channels/porn/filmpornoita.json similarity index 100% rename from channels/filmpornoita.json rename to channels/porn/filmpornoita.json diff --git a/channels/filmpornoita.py b/channels/porn/filmpornoita.py similarity index 100% rename from channels/filmpornoita.py rename to channels/porn/filmpornoita.py diff --git a/channels/foxtube.json b/channels/porn/foxtube.json similarity index 100% rename from channels/foxtube.json rename to channels/porn/foxtube.json diff --git a/channels/foxtube.py b/channels/porn/foxtube.py similarity index 64% rename from channels/foxtube.py rename to channels/porn/foxtube.py index e8ab9c34..ae2fae11 100644 --- a/channels/foxtube.py +++ b/channels/porn/foxtube.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://es.foxtube.com' @@ -15,7 +14,9 @@ def mainlist(item): logger.info() itemlist = [] itemlist.append( Item(channel=item.channel, title="Ultimos" , action="lista", url=host)) + itemlist.append( Item(channel=item.channel, title="PornStar" , action="catalogo", url=host + '/actrices/')) itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -33,6 +34,31 @@ def search(item, texto): return [] +def catalogo(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + patron = '<a class="tco5" href="([^"]+)">.*?' + patron += 'data-origen="([^"]+)" alt="([^"]+)"' + matches = re.compile(patron,re.DOTALL).findall(data) + scrapertools.printMatches(matches) + for scrapedurl,scrapedthumbnail,scrapedtitle in matches: + scrapedplot = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=scrapedthumbnail, plot=scrapedplot) ) + # <a class="bgco2 tco3" rel="next" href="/actrices/2/">></a> + next_page = scrapertools.find_single_match(data,'<a class="bgco2 tco3" rel="next" href="([^"]+)">></a>') + if next_page!="": + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append(item.clone(action="lista" , title="Página Siguiente >>", text_color="blue", url=next_page) ) + return itemlist + + + return itemlist + + def categorias(item): logger.info() itemlist = [] @@ -54,6 +80,8 @@ def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data + if "/actrices/" in item.url: + data=scrapertools.find_single_match(data,'<section class="container">(.*?)>Actrices similares</h3>') patron = '<a class="thumb tco1" href="([^"]+)">.*?' patron += 'src="([^"]+)".*?' patron += 'alt="([^"]+)".*?' @@ -71,7 +99,7 @@ def lista(item): plot = "" itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle = contentTitle)) - next_page = scrapertools.find_single_match(data,'<a class="bgco2 tco3" rel="next" href="([^"]+)">></a>') + next_page = scrapertools.find_single_match(data,'<a class="bgco2 tco3" rel="next" href="([^"]+)">></a>') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) itemlist.append(item.clone(action="lista" , title="Página Siguiente >>", text_color="blue", url=next_page) ) @@ -82,13 +110,14 @@ def play(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - url = scrapertools.find_single_match(data,'<iframe src="([^"]+)"') + url = scrapertools.find_single_match(data,'<iframe title="video" src="([^"]+)"') + url = url.replace("https://flashservice.xvideos.com/embedframe/", "https://www.xvideos.com/video") + "/" data = httptools.downloadpage(url).data patron = 'html5player.setVideoHLS\\(\'([^\']+)\'' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: scrapedurl = scrapedurl.replace("\/", "/") - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/freeporn.json b/channels/porn/freeporn.json similarity index 100% rename from channels/freeporn.json rename to channels/porn/freeporn.json diff --git a/channels/freeporn.py b/channels/porn/freeporn.py similarity index 94% rename from channels/freeporn.py rename to channels/porn/freeporn.py index 69e1f65d..c2ef1df2 100644 --- a/channels/freeporn.py +++ b/channels/porn/freeporn.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://frprn.com' @@ -97,6 +96,6 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: title = scrapedurl - itemlist.append(item.clone(action="play", title=title, fulltitle = scrapedurl, url=scrapedurl)) + itemlist.append(item.clone(action="play", title=title, contentTitle = scrapedurl, url=scrapedurl)) return itemlist diff --git a/channels/freepornstreams.json b/channels/porn/freepornstreams.json similarity index 100% rename from channels/freepornstreams.json rename to channels/porn/freepornstreams.json diff --git a/channels/freepornstreams.py b/channels/porn/freepornstreams.py similarity index 53% rename from channels/freepornstreams.py rename to channels/porn/freepornstreams.py index adc9881f..f5eae9c7 100644 --- a/channels/freepornstreams.py +++ b/channels/porn/freepornstreams.py @@ -1,16 +1,14 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools -host = 'http://freepornstreams.org' +host = 'http://freepornstreams.org' #es http://xxxstreams.org def mainlist(item): @@ -18,8 +16,8 @@ def mainlist(item): itemlist = [] itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/free-full-porn-movies/")) itemlist.append( Item(channel=item.channel, title="Videos" , action="lista", url=host + "/free-stream-porn/")) - itemlist.append( Item(channel=item.channel, title="Canal" , action="catalogo", url=host)) - itemlist.append( Item(channel=item.channel, title="Categoria" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -37,35 +35,24 @@ def search(item, texto): return [] -def catalogo(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data,'>Top Sites</a>(.*?)</aside>') - data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<li id="menu-item-\d+".*?<a href="([^"]+)">([^"]+)</a></li>' - matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, - thumbnail=scrapedthumbnail, plot=scrapedplot) ) - return itemlist - def categorias(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data,'Top Tags(.*?)</ul>') data = re.sub(r"\n|\r|\t| |<br>", "", data) + if item.title == "Categorias" : + data = scrapertools.find_single_match(data,'>Top Tags(.*?)</ul>') + else: + data = scrapertools.find_single_match(data,'>Top Sites</a>(.*?)</aside>') patron = '<a href="([^"]+)">(.*?)</a>' matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl,scrapedtitle in matches: - scrapedplot = "" - scrapedthumbnail = "" - scrapedurl = scrapedurl.replace ("http://freepornstreams.org/freepornst/stout.php?s=100,75,65:*&u=" , "") - itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, - thumbnail=scrapedthumbnail, plot=scrapedplot) ) + if not "Featured" in scrapedtitle: + scrapedplot = "" + scrapedthumbnail = "" + scrapedurl = scrapedurl.replace ("http://freepornstreams.org/freepornst/stout.php?s=100,75,65:*&u=" , "") + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=scrapedthumbnail, plot=scrapedplot) ) return itemlist @@ -79,12 +66,15 @@ def lista(item): patron += '<img src="([^"]+)"' matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl,scrapedtitle,scrapedthumbnail in matches: - calidad = scrapertools.find_single_match(scrapedtitle, '(\(.*?\))') - title = "[COLOR yellow]" + calidad + "[/COLOR] " + scrapedtitle.replace( "%s" % calidad, "") + if '/HD' in scrapedtitle : title= "[COLOR red]" + "HD" + "[/COLOR] " + scrapedtitle + elif 'SD' in scrapedtitle : title= "[COLOR red]" + "SD" + "[/COLOR] " + scrapedtitle + elif 'FullHD' in scrapedtitle : title= "[COLOR red]" + "FullHD" + "[/COLOR] " + scrapedtitle + elif '1080' in scrapedtitle : title= "[COLOR red]" + "1080p" + "[/COLOR] " + scrapedtitle + else: title = scrapedtitle thumbnail = scrapedthumbnail.replace("jpg#", "jpg") plot = "" - itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, thumbnail=thumbnail, - fanart=thumbnail, plot=plot, fulltitle=title) ) + itemlist.append( Item(channel=item.channel, action="findvideos", title=title, url=scrapedurl, thumbnail=thumbnail, + fanart=thumbnail, plot=plot, contentTitle=title) ) next_page = scrapertools.find_single_match(data, '<div class="nav-previous"><a href="([^"]+)"') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) @@ -92,14 +82,14 @@ def lista(item): return itemlist -def play(item): - logger.info() +def findvideos(item): + itemlist = [] data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.fulltitle - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videochannel=item.channel + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = '<a href="([^"]+)" rel="nofollow"[^<]+>(?:Streaming|Download)' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + if not "ubiqfile" in url: + itemlist.append(item.clone(action='play',title="%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist - diff --git a/channels/porn/gotporn.json b/channels/porn/gotporn.json new file mode 100755 index 00000000..96df587b --- /dev/null +++ b/channels/porn/gotporn.json @@ -0,0 +1,15 @@ +{ + "id": "gotporn", + "name": "gotporn", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://cdn2-static-cf.gotporn.com/desktop/img/gotporn-logo.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/gotporn.py b/channels/porn/gotporn.py new file mode 100755 index 00000000..fc42255d --- /dev/null +++ b/channels/porn/gotporn.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.gotporn.com' + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/?page=1")) + itemlist.append( Item(channel=item.channel, title="Mejor valorados" , action="lista", url=host + "/top-rated?page=1")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/most-viewed?page=1")) + itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=host + "/longest?page=1")) + + itemlist.append( Item(channel=item.channel, title="Canal" , action="catalogo", url=host + "/channels?page=1")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/results?search_query=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + + + patron = '<a href="([^"]+)">' + patron += '<span class="text">([^<]+)</span>' + patron += '<span class="num">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedtitle = "%s %s" % (scrapedtitle,cantidad) + scrapedurl = scrapedurl + "?page=1" + thumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=thumbnail , plot=scrapedplot) ) + return itemlist + + +def catalogo(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + logger.debug(data) + patron = '<header class="clearfix" itemscope>.*?' + patron += '<a href="([^"]+)".*?' + patron += '<img src="([^"]+)" alt="([^"]+)"' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,scrapedtitle in matches: + scrapedplot = "" + scrapedurl = scrapedurl + "?page=1" + thumbnail = "https:" + scrapedthumbnail + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=thumbnail , plot=scrapedplot) ) + next_page = scrapertools.find_single_match(data, '<a href="([^"]+)" class="btn btn-secondary"><span class="text">Next') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="catalogo", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<li class="video-item poptrigger".*?' + patron += 'href="([^"]+)" data-title="([^"]+)".*?' + patron += '<span class="duration">(.*?)</span>.*?' + patron += 'src=\'([^\']+)\'.*?' + patron += '<h3 class="video-thumb-title(.*?)"' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,scrapedtime,scrapedthumbnail,quality in matches: + scrapedtime = scrapedtime.strip() + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + if quality: + title = "[COLOR yellow]%s[/COLOR] [COLOR red]HD[/COLOR] %s" % (scrapedtime,scrapedtitle) + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, thumbnail=thumbnail, + fanart=thumbnail, plot=plot,)) + next_page = scrapertools.find_single_match(data, '<a href="([^"]+)" class="btn btn-secondary') + if "categories" in item.url: + next_page = scrapertools.find_single_match(data, '<a href="([^"]+)" class="btn btn-secondary paginate-show-more') + if "search_query" in item.url: + next_page = scrapertools.find_single_match(data, '<link rel=\'next\' href="([^"]+)">') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + patron = '<source src="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + url += "|Referer=%s" % host + itemlist.append(item.clone(action="play", title = item.title, url=url )) + return itemlist + diff --git a/channels/hclips.json b/channels/porn/hclips.json similarity index 100% rename from channels/hclips.json rename to channels/porn/hclips.json diff --git a/channels/hclips.py b/channels/porn/hclips.py similarity index 97% rename from channels/hclips.py rename to channels/porn/hclips.py index eda1f2dc..9ae7ce89 100644 --- a/channels/hclips.py +++ b/channels/porn/hclips.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urllib -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.hclips.com' diff --git a/channels/hdzog.json b/channels/porn/hdzog.json similarity index 100% rename from channels/hdzog.json rename to channels/porn/hdzog.json diff --git a/channels/hdzog.py b/channels/porn/hdzog.py similarity index 97% rename from channels/hdzog.py rename to channels/porn/hdzog.py index 9418454b..09ef0158 100644 --- a/channels/hdzog.py +++ b/channels/porn/hdzog.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urllib -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.hdzog.com' diff --git a/channels/hellporno.json b/channels/porn/hellporno.json similarity index 100% rename from channels/hellporno.json rename to channels/porn/hellporno.json diff --git a/channels/hellporno.py b/channels/porn/hellporno.py similarity index 95% rename from channels/hellporno.py rename to channels/porn/hellporno.py index cfff8d1c..0dab3be3 100644 --- a/channels/hellporno.py +++ b/channels/porn/hellporno.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://hellporno.com' @@ -61,7 +60,7 @@ def lista(item): data = re.sub(r"\n|\r|\t| |<br>", "", data) patron = '<div class="video-thumb"><a href="([^"]+)" class="title".*?>([^"]+)</a>.*?' patron += '<span class="time">([^<]+)</span>.*?' - patron += '<video poster="([^"]+)"' + patron += '<video muted poster="([^"]+)"' matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl,scrapedtitle,duracion,scrapedthumbnail in matches: url = scrapedurl @@ -85,6 +84,6 @@ def play(item): scrapedurl = scrapertools.find_single_match(data,'<source data-fluid-hd src="([^"]+)/?br=\d+"') if scrapedurl=="": scrapedurl = scrapertools.find_single_match(data,'<source src="([^"]+)/?br=\d+"') - itemlist.append(item.clone(action="play", title=scrapedurl, fulltitle = item.title, url=scrapedurl)) + itemlist.append(item.clone(action="play", title=scrapedurl, url=scrapedurl)) return itemlist diff --git a/channels/porn/hentaiid.json b/channels/porn/hentaiid.json new file mode 100644 index 00000000..0519590a --- /dev/null +++ b/channels/porn/hentaiid.json @@ -0,0 +1,12 @@ +{ + "id": "hentaiid", + "name": "Hentai ID", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "http://www.hentai-id.tv/wp-content/themes/moviescript/assets/img/logo.png", + "banner": "http://www.hentai-id.tv/wp-content/themes/moviescript/assets/img/background.jpg", + "categories": [ + "adult" + ] +} diff --git a/channels/hentaiid.py b/channels/porn/hentaiid.py similarity index 82% rename from channels/hentaiid.py rename to channels/porn/hentaiid.py index da7240b8..495fae4d 100644 --- a/channels/hentaiid.py +++ b/channels/porn/hentaiid.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config CHANNEL_HOST = "http://hentai-id.tv/" @@ -70,11 +68,11 @@ def series(item): action = "episodios" for url, thumbnail, title in matches: - fulltitle = title + contentTitle = title show = title # logger.debug("title=[{0}], url=[{1}], thumbnail=[{2}]".format(title, url, thumbnail)) itemlist.append(Item(channel=item.channel, action=action, title=title, url=url, thumbnail=thumbnail, - show=show, fulltitle=fulltitle, fanart=thumbnail, folder=True)) + show=show, fanart=thumbnail, folder=True)) if pagination: page = scrapertools.find_single_match(pagination, '>(?:Page|Página)\s*(\d+)\s*(?:of|de)\s*\d+<') @@ -106,7 +104,7 @@ def episodios(item): # logger.debug("title=[{0}], url=[{1}], thumbnail=[{2}]".format(title, url, thumbnail)) itemlist.append(Item(channel=item.channel, action="findvideos", title=title, url=url, - thumbnail=thumbnail, plot=plot, show=item.show, fulltitle="%s %s" % (item.show, title), + thumbnail=thumbnail, plot=plot, fanart=thumbnail)) return itemlist @@ -116,20 +114,33 @@ def findvideos(item): logger.info() data = httptools.downloadpage(item.url).data - + video_urls = [] + down_urls = [] patron = '<(?:iframe)?(?:IFRAME)?\s*(?:src)?(?:SRC)?="([^"]+)"' matches = re.compile(patron, re.DOTALL).findall(data) for url in matches: - if 'goo.gl' in url: + if 'goo.gl' in url or 'tinyurl' in url: video = httptools.downloadpage(url, follow_redirects=False, only_headers=True).headers["location"] - matches.remove(url) - matches.append(video) + video_urls.append(video) + else: + video_urls.append(url) + paste = scrapertools.find_single_match(data, 'https://gpaste.us/([a-zA-Z0-9]+)') + if paste: + try: + new_data = httptools.downloadpage('https://gpaste.us/'+paste).data + bloq = scrapertools.find_single_match(new_data, 'id="input_text">(.*?)</div>') + matches = bloq.split('<br>') + for url in matches: + down_urls.append(url) + except: + pass + video_urls.extend(down_urls) from core import servertools - itemlist = servertools.find_video_items(data=",".join(matches)) + itemlist = servertools.find_video_items(data=",".join(video_urls)) for videoitem in itemlist: - videoitem.fulltitle = item.fulltitle + videoitem.contentTitle = item.contentTitle videoitem.channel = item.channel videoitem.thumbnail = item.thumbnail diff --git a/channels/hotmovs.json b/channels/porn/hotmovs.json similarity index 100% rename from channels/hotmovs.json rename to channels/porn/hotmovs.json diff --git a/channels/hotmovs.py b/channels/porn/hotmovs.py similarity index 98% rename from channels/hotmovs.py rename to channels/porn/hotmovs.py index 55a7f1ec..37ec2078 100644 --- a/channels/hotmovs.py +++ b/channels/porn/hotmovs.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urllib -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://hotmovs.com' diff --git a/channels/javlin.json b/channels/porn/javlin.json similarity index 100% rename from channels/javlin.json rename to channels/porn/javlin.json diff --git a/channels/javlin.py b/channels/porn/javlin.py similarity index 100% rename from channels/javlin.py rename to channels/porn/javlin.py diff --git a/channels/javtasty.json b/channels/porn/javtasty.json similarity index 100% rename from channels/javtasty.json rename to channels/porn/javtasty.json diff --git a/channels/javtasty.py b/channels/porn/javtasty.py similarity index 96% rename from channels/javtasty.py rename to channels/porn/javtasty.py index 96ffdcb6..46c41026 100644 --- a/channels/javtasty.py +++ b/channels/porn/javtasty.py @@ -109,8 +109,7 @@ def menu_info(item): itemlist = [] video_urls, data = play(item.clone(extra="play_menu")) itemlist.append(item.clone(action="play", title="Ver -- %s" % item.title, video_urls=video_urls)) - bloque = scrapertools.find_single_match(data, '<div class="carousel-inner"(.*?)<div class="container">') - matches = scrapertools.find_multiple_matches(bloque, 'src="([^"]+)"') + matches = scrapertools.find_multiple_matches(data, '<a href="([^"]+)" class="item" rel="screenshots"') for i, img in enumerate(matches): if i == 0: continue diff --git a/channels/javus.json b/channels/porn/javus.json similarity index 59% rename from channels/javus.json rename to channels/porn/javus.json index efd2ac02..17595685 100644 --- a/channels/javus.json +++ b/channels/porn/javus.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": false, - "enabled": false, - "visible": false - } ] } \ No newline at end of file diff --git a/channels/javus.py b/channels/porn/javus.py similarity index 98% rename from channels/javus.py rename to channels/porn/javus.py index df1b7e82..83979eb7 100644 --- a/channels/javus.py +++ b/channels/porn/javus.py @@ -6,7 +6,6 @@ from core import httptools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config host = 'http://javus.net/' diff --git a/channels/javwhores.json b/channels/porn/javwhores.json similarity index 100% rename from channels/javwhores.json rename to channels/porn/javwhores.json diff --git a/channels/javwhores.py b/channels/porn/javwhores.py similarity index 88% rename from channels/javwhores.py rename to channels/porn/javwhores.py index c974c92b..6746f9d9 100644 --- a/channels/javwhores.py +++ b/channels/porn/javwhores.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools + host = 'https://www.javwhores.com/' @@ -74,9 +74,13 @@ def lista(item): itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, plot=plot, contentTitle = title)) next_page = scrapertools.find_single_match(data, '<li class="next"><a href="([^"]+)"') + if "#videos" in next_page: + next_page = scrapertools.find_single_match(data, 'data-parameters="sort_by:post_date;from:(\d+)">Next') + next = scrapertools.find_single_match(item.url, '(.*?/)\d+') + next_page = next + "%s/" % next_page if next_page: next_page = urlparse.urljoin(item.url,next_page) - itemlist.append(item.clone(action="lista", title="Página Siguiente >>" , text_color="blue", url=next_page ) ) + itemlist.append(item.clone(action="lista", title= next_page, text_color="blue", url=next_page ) ) return itemlist @@ -92,7 +96,7 @@ def play(item): if scrapedurl == "" : scrapedurl = scrapertools.find_single_match(data, 'video_url: \'([^\']+)\'') - itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, fulltitle=item.title, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/jizzbunker.json b/channels/porn/jizzbunker.json similarity index 100% rename from channels/jizzbunker.json rename to channels/porn/jizzbunker.json diff --git a/channels/jizzbunker.py b/channels/porn/jizzbunker.py similarity index 96% rename from channels/jizzbunker.py rename to channels/porn/jizzbunker.py index c453be1d..d6a22407 100644 --- a/channels/jizzbunker.py +++ b/channels/porn/jizzbunker.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://jizzbunker.com/es' @@ -87,7 +86,7 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: scrapedurl = scrapedurl.replace("https", "http") - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/justporn.json b/channels/porn/justporn.json similarity index 100% rename from channels/justporn.json rename to channels/porn/justporn.json diff --git a/channels/justporn.py b/channels/porn/justporn.py similarity index 93% rename from channels/justporn.py rename to channels/porn/justporn.py index 912ab1bb..50aa533f 100644 --- a/channels/justporn.py +++ b/channels/porn/justporn.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://xxx.justporno.tv' @@ -93,10 +92,6 @@ def lista(item): next_page = "%s?mode=async&function=get_block&block_id=list_videos_common_videos_list" \ "&sort_by=post_date&from=%s" % (item.url, next_page) itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page)) - - # if next_page!="": - # next_page = urlparse.urljoin(item.url,next_page) - # itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist @@ -109,6 +104,6 @@ def play(item): matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl in matches: scrapedplot = "" - itemlist.append(item.clone(channel=item.channel, action="play", title=scrapedurl , url=scrapedurl , plot="" , folder=True) ) + itemlist.append(item.clone(channel=item.channel, action="play", title=item.title , url=scrapedurl , plot="" , folder=True) ) return itemlist diff --git a/channels/porn/kingsizetits.json b/channels/porn/kingsizetits.json new file mode 100755 index 00000000..69493b3e --- /dev/null +++ b/channels/porn/kingsizetits.json @@ -0,0 +1,15 @@ +{ + "id": "kingsizetits", + "name": "Kingsizetits", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "http://cdn.images.kingsizetits.com/resources/kingsizetits.com/rwd_5/default/images/logo.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/kingsizetits.py b/channels/porn/kingsizetits.py new file mode 100755 index 00000000..c8cdc8a3 --- /dev/null +++ b/channels/porn/kingsizetits.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'http://kingsizetits.com' + + +def mainlist(item): + logger.info() + itemlist = [] + + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/most-recent/")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/most-viewed-week/")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/top-rated/")) + itemlist.append( Item(channel=item.channel, title="Mas largos" , action="lista", url=host + "/longest/")) + + + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/search/videos/%s/" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<a href="([^"]+)" class="video-box.*?' + patron += 'src=\'([^\']+)\' alt=\'([^\']+)\'.*?' + patron += 'data-video-count="(\d+)"' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + title = scrapedtitle + " (" + cantidad + ")" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<script>stat.*?' + patron += '<a href="([^"]+)".*?' + patron += 'src="([^"]+)".*?' + patron += '<span class="video-length">([^<]+)</span>.*?' + patron += '<span class="pic-name">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,scrapedtime,scrapedtitle in matches: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, + fanart=thumbnail, thumbnail=thumbnail, plot=plot, contentTitle = scrapedtitle)) + next_page = scrapertools.find_single_match(data, '<a class="btn default-btn page-next page-nav" href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + logger.debug(data) + url = scrapertools.find_single_match(data,'label:"\d+", file\:"([^"]+)"') + itemlist.append(item.clone(action="play", server="directo", url=url )) + return itemlist + + diff --git a/channels/porn/mangovideo.json b/channels/porn/mangovideo.json new file mode 100755 index 00000000..af5b8c23 --- /dev/null +++ b/channels/porn/mangovideo.json @@ -0,0 +1,15 @@ +{ + "id": "mangovideo", + "name": "mangovideo", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://mangovideo.pw/images/logo.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/mangovideo.py b/channels/porn/mangovideo.py new file mode 100755 index 00000000..509d2f93 --- /dev/null +++ b/channels/porn/mangovideo.py @@ -0,0 +1,109 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + + +server = {'1': 'https://www.mangovideo.pw/contents/videos', '7' : 'https://server9.mangovideo.pw/contents/videos/', + '8' : 'https://s10.mangovideo.pw/contents/videos/', '9' : 'https://server2.mangovideo.pw/contents/videos/', + '10' : 'https://server217.mangovideo.pw/contents/videos/', '11' : 'https://234.mangovideo.pw/contents/videos/' + } + +host = 'http://mangovideo.pw' + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/latest-updates/")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/most-popular/")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/top-rated/")) + itemlist.append( Item(channel=item.channel, title="Sitios" , action="categorias", url=host + "/sites/")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/search/%s/" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<a class="item" href="([^"]+)" title="([^"]+)".*?' + patron += '<div class="videos">(\d+) videos</div>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedthumbnail = "" + title = scrapedtitle + " (" + cantidad + ")" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + thumbnail=scrapedthumbnail , plot=scrapedplot) ) + + next_page = scrapertools.find_single_match(data, '<li class="next"><a href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="categorias", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + + + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<div class="item\s+">.*?' + patron += '<a href="([^"]+)" title="([^"]+)".*?' + patron += 'data-original="([^"]+)".*?' + patron += '<div class="duration">([^<]+)</div>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,scrapedthumbnail,scrapedtime in matches: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, + thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle = scrapedtitle)) + next_page = scrapertools.find_single_match(data, '<li class="next"><a href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + scrapedtitle = "" + patron = 'video_url: \'function/0/https://mangovideo.pw/get_file/(\d+)/\w+/(.*?)/\'' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedtitle,url in matches: + scrapedtitle = server.get(scrapedtitle, scrapedtitle) + url = scrapedtitle + url + if not scrapedtitle: + url = scrapertools.find_single_match(data, '<div class="embed-wrap".*?<iframe src="([^"]+)\?ref=') + itemlist.append(item.clone(action="play", title="%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + + return itemlist + diff --git a/channels/mporno.json b/channels/porn/mporno.json similarity index 100% rename from channels/mporno.json rename to channels/porn/mporno.json diff --git a/channels/mporno.py b/channels/porn/mporno.py similarity index 71% rename from channels/mporno.py rename to channels/porn/mporno.py index 1071c972..e568594d 100644 --- a/channels/mporno.py +++ b/channels/porn/mporno.py @@ -1,23 +1,22 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://mporno.tv' def mainlist(item): logger.info() itemlist = [] - itemlist.append( Item(channel=item.channel, title="Novedades" , action="peliculas", url=host + "/most-recent/")) - itemlist.append( Item(channel=item.channel, title="Mejor valoradas" , action="peliculas", url=host + "/top-rated/")) - itemlist.append( Item(channel=item.channel, title="Mas vistas" , action="peliculas", url=host + "/most-viewed/")) - itemlist.append( Item(channel=item.channel, title="Longitud" , action="peliculas", url=host + "/longest/")) + itemlist.append( Item(channel=item.channel, title="Novedades" , action="lista", url=host + "/most-recent/")) + itemlist.append( Item(channel=item.channel, title="Mejor valoradas" , action="lista", url=host + "/top-rated/")) + itemlist.append( Item(channel=item.channel, title="Mas vistas" , action="lista", url=host + "/most-viewed/")) + itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=host + "/longest/")) itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/channels/")) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -28,7 +27,7 @@ def search(item, texto): texto = texto.replace(" ", "+") item.url = host + "/search/videos/%s/page1.html" % texto try: - return peliculas(item) + return lista(item) except: import sys for line in sys.exc_info(): @@ -46,12 +45,12 @@ def categorias(item): scrapedplot = "" scrapedthumbnail = "" scrapedtitle = scrapedtitle + " " + cantidad - itemlist.append( Item(channel=item.channel, action="peliculas", title=scrapedtitle, url=scrapedurl, + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail , plot=scrapedplot) ) return itemlist -def peliculas(item): +def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data @@ -61,15 +60,21 @@ def peliculas(item): for scrapedurl,scrapedtitle,scrapedthumbnail in matches: contentTitle = scrapedtitle title = scrapedtitle - scrapedurl = scrapedurl.replace("/thumbs/", "/videos/") + ".mp4" thumbnail = scrapedthumbnail plot = "" itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, thumbnail=thumbnail, - fanart=thumbnail, plot=plot, contentTitle=contentTitle)) + fanart=thumbnail, plot=plot, server= "directo", contentTitle=contentTitle)) next_page_url = scrapertools.find_single_match(data,'<a href=\'([^\']+)\' class="next">Next >></a>') if next_page_url!="": next_page_url = urlparse.urljoin(item.url,next_page_url) - itemlist.append(item.clone(action="peliculas", title="Página Siguiente >>", text_color="blue", url=next_page_url) ) + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page_url) ) return itemlist + +def play(item): + logger.info() + itemlist = [] + url = item.url.replace("/thumbs/", "/videos/") + ".mp4" + itemlist.append( Item(channel=item.channel, action="play", title= item.title, server= "directo", url=url)) + return itemlist \ No newline at end of file diff --git a/channels/muchoporno.json b/channels/porn/muchoporno.json similarity index 100% rename from channels/muchoporno.json rename to channels/porn/muchoporno.json diff --git a/channels/muchoporno.py b/channels/porn/muchoporno.py similarity index 91% rename from channels/muchoporno.py rename to channels/porn/muchoporno.py index 9af38852..73130718 100644 --- a/channels/muchoporno.py +++ b/channels/porn/muchoporno.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.pornburst.xxx' @@ -43,20 +42,21 @@ def categorias(item): if "/sites/" in item.url: patron = '<div class="muestra-escena muestra-canales">.*?' patron += 'href="([^"]+)">.*?' - patron += 'src="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' patron += '<a title="([^"]+)".*?' patron += '</span> (\d+) videos</span>' if "/pornstars/" in item.url: patron = '<a class="muestra-escena muestra-pornostar" href="([^"]+)">.*?' - patron += 'src="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' patron += 'alt="([^"]+)".*?' patron += '</span> (\d+) videos</span>' else: patron = '<a class="muestra-escena muestra-categoria" href="([^"]+)" title="[^"]+">.*?' - patron += 'src="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' patron += '</span> ([^"]+) </h2>(.*?)>' matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl,scrapedthumbnail,scrapedtitle,cantidad in matches: + logger.debug(scrapedurl + ' / ' + scrapedthumbnail + ' / ' + cantidad + ' / ' + scrapedtitle) scrapedplot = "" cantidad = " (" + cantidad + ")" if "</a" in cantidad: @@ -107,6 +107,6 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: title = scrapedurl - itemlist.append(item.clone(action="play", title=title, fulltitle = item.title, url=scrapedurl)) + itemlist.append(item.clone(action="play", title=title, url=scrapedurl)) return itemlist diff --git a/channels/nuvid.json b/channels/porn/nuvid.json similarity index 100% rename from channels/nuvid.json rename to channels/porn/nuvid.json diff --git a/channels/nuvid.py b/channels/porn/nuvid.py similarity index 94% rename from channels/nuvid.py rename to channels/porn/nuvid.py index 4f6a64c6..d87be509 100644 --- a/channels/nuvid.py +++ b/channels/porn/nuvid.py @@ -2,13 +2,11 @@ import base64 import hashlib - import urlparse from core import httptools from core import scrapertools from platformcode import logger -from platformcode import config host = "https://www.nuvid.com" @@ -53,7 +51,7 @@ def lista(item): data = httptools.downloadpage(item.url, headers=header, cookies=False).data # Extrae las entradas - patron = '<div class="box-tumb related_vid">.*?href="([^"]+)" title="([^"]+)".*?src="([^"]+)"(.*?)<i class="time">([^<]+)<' + patron = '<div class="box-tumb related_vid.*?href="([^"]+)" title="([^"]+)".*?src="([^"]+)"(.*?)<i class="time">([^<]+)<' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedtitle, scrapedthumbnail, quality, duration in matches: scrapedurl = urlparse.urljoin(host, scrapedurl) @@ -85,7 +83,7 @@ def categorias(item): for cat, b in bloques: cat = cat.replace("Straight", "Hetero") itemlist.append(item.clone(action="", title=cat, text_color="gold")) - matches = scrapertools.find_multiple_matches(b, '<li.*?href="([^"]+)">(.*?)</span>') + matches = scrapertools.find_multiple_matches(b, '<li>.*?href="([^"]+)" >(.*?)</span>') for scrapedurl, scrapedtitle in matches: scrapedtitle = " " + scrapedtitle.replace("<span>", "") scrapedurl = urlparse.urljoin(host, scrapedurl) diff --git a/channels/pandamovie.json b/channels/porn/pandamovie.json similarity index 100% rename from channels/pandamovie.json rename to channels/porn/pandamovie.json diff --git a/channels/pandamovie.py b/channels/porn/pandamovie.py similarity index 61% rename from channels/pandamovie.py rename to channels/porn/pandamovie.py index 7680ad63..e7961206 100644 --- a/channels/pandamovie.py +++ b/channels/porn/pandamovie.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -import re - import urlparse +import re +import base64 -from core import httptools +from platformcode import config, logger from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import httptools host = 'https://pandamovies.pw' - def mainlist(item): logger.info() itemlist = [] @@ -62,7 +61,7 @@ def lista(item): data = httptools.downloadpage(item.url).data patron = '<div data-movie-id="\d+".*?' patron += '<a href="([^"]+)".*?oldtitle="([^"]+)".*?' - patron += '<img src="([^"]+)".*?' + patron += '<img data-original="([^"]+)".*?' matches = re.compile(patron, re.DOTALL).findall(data) for scrapedurl, scrapedtitle, scrapedthumbnail in matches: url = urlparse.urljoin(item.url, scrapedurl) @@ -71,7 +70,6 @@ def lista(item): plot = "" itemlist.append(Item(channel=item.channel, action="findvideos", title=title, url=url, thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle=title)) - # <li class='active'><a class=''>1</a></li><li><a rel='nofollow' class='page larger' href='https://pandamovies.pw/movies/page/2'> next_page = scrapertools.find_single_match(data, '<li class=\'active\'>.*?href=\'([^\']+)\'>') if next_page == "": next_page = scrapertools.find_single_match(data, '<a.*?href="([^"]+)" >Next »</a>') @@ -79,3 +77,34 @@ def lista(item): next_page = urlparse.urljoin(item.url, next_page) itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page)) return itemlist + + +def findvideos(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = '- on ([^"]+)" href="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedtitle,url in matches: + if 'aHR0' in url: + n = 3 + while n > 0: + url= url.replace("https://vshares.tk/goto/", "").replace("https://waaws.tk/goto/", "").replace("https://openloads.tk/goto/", "") + logger.debug (url) + url = base64.b64decode(url) + n -= 1 + if "mangovideo" in url: #Aparece como directo + data = httptools.downloadpage(url).data + patron = 'video_url: \'function/0/https://mangovideo.pw/get_file/(\d+)/\w+/(.*?)/\?embed=true\'' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedtitle,url in matches: + if scrapedtitle =="1": scrapedtitle= "https://www.mangovideo.pw/contents/videos/" + if scrapedtitle =="7": scrapedtitle= "https://server9.mangovideo.pw/contents/videos/" + if scrapedtitle =="8": scrapedtitle= "https://s10.mangovideo.pw/contents/videos/" + if scrapedtitle =="10": scrapedtitle= "https://server217.mangovideo.pw/contents/videos/" + if scrapedtitle =="11": scrapedtitle= "https://234.mangovideo.pw/contents/videos/" + url = scrapedtitle + url + itemlist.append( Item(channel=item.channel, action="play", title = "%s", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + diff --git a/channels/peliculaseroticas.json b/channels/porn/peliculaseroticas.json similarity index 100% rename from channels/peliculaseroticas.json rename to channels/porn/peliculaseroticas.json diff --git a/channels/peliculaseroticas.py b/channels/porn/peliculaseroticas.py similarity index 100% rename from channels/peliculaseroticas.py rename to channels/porn/peliculaseroticas.py diff --git a/channels/pelisxporno.json b/channels/porn/pelisxporno.json similarity index 56% rename from channels/pelisxporno.json rename to channels/porn/pelisxporno.json index d727ed88..e01fb74e 100644 --- a/channels/pelisxporno.json +++ b/channels/porn/pelisxporno.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": false, - "enabled": true, - "visible": true - } ] } \ No newline at end of file diff --git a/channels/pelisxporno.py b/channels/porn/pelisxporno.py similarity index 50% rename from channels/pelisxporno.py rename to channels/porn/pelisxporno.py index fcebb93d..f8920727 100644 --- a/channels/pelisxporno.py +++ b/channels/porn/pelisxporno.py @@ -1,63 +1,85 @@ # -*- coding: utf-8 -*- +import urlparse +import re +from platformcode import config, logger from core import httptools from core import scrapertools -from platformcode import logger -from platformcode import config +from core import servertools +host = 'http://www.pelisxporno.com' + def mainlist(item): logger.info() - itemlist = [] - itemlist.append(item.clone(action="lista", title="Novedades", url="http://www.pelisxporno.com/?order=date")) - itemlist.append(item.clone(action="categorias", title="Categorías", url="http://www.pelisxporno.com/categorias/")) - itemlist.append(item.clone(action="search", title="Buscar", url="http://www.pelisxporno.com/?s=%s")) - + itemlist.append(item.clone(action="lista", title="Novedades", url= host + "/?order=date")) + itemlist.append(item.clone(action="categorias", title="Categorías", url=host + "/categorias/")) + itemlist.append(item.clone(action="search", title="Buscar")) return itemlist - +def search(item, texto): + logger.info("") + texto = texto.replace(" ", "+") + item.url = host + "/?s=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + def search(item, texto): logger.info() item.url = item.url % texto return lista(item) -def lista(item): - logger.info() - itemlist = [] - - # Descarga la pagina - data = httptools.downloadpage(item.url).data - # Extrae las entradas (carpetas) - patron = '<div class="video.".*?<a href="(.*?)" title="(.*?)">.*?<img src="(.*?)".*?\/>.*?duration.*?>(.*?)<' - matches = scrapertools.find_multiple_matches(data, patron) - for scrapedurl, scrapedtitle, scrapedthumbnail, duration in matches: - if duration: - scrapedtitle += " (%s)" % duration - - itemlist.append(item.clone(action="findvideos", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, - fanart=scrapedthumbnail)) - - # Extrae la marca de siguiente página - next_page = scrapertools.find_single_match(data, '<a class="nextpostslink" rel="next" href="([^"]+)"') - if next_page: - itemlist.append(item.clone(action="lista", title=">> Página Siguiente", url=next_page)) - - return itemlist - - def categorias(item): logger.info() itemlist = [] - - # Descarga la pagina data = httptools.downloadpage(item.url).data - - # Extrae las entradas (carpetas) patron = '<li class="cat-item cat-item-.*?"><a href="(.*?)".*?>(.*?)<' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedtitle in matches: itemlist.append(item.clone(action="lista", title=scrapedtitle, url=scrapedurl)) - return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + patron = '<div class="video.".*?<a href="(.*?)" title="(.*?)">.*?<img src="(.*?)".*?\/>.*?duration.*?>(.*?)<' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedurl, scrapedtitle, scrapedthumbnail, duration in matches: + if duration: + scrapedtitle = "[COLOR yellow]" + duration + "[/COLOR] " + scrapedtitle + itemlist.append(item.clone(action="findvideos", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, + fanart=scrapedthumbnail)) + next_page = scrapertools.find_single_match(data, '<a class="nextpostslink" rel="next" href="([^"]+)"') + if next_page: + itemlist.append(item.clone(action="lista", title=">> Página Siguiente", url=next_page)) + return itemlist + + +def findvideos(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = scrapertools.find_single_match(data, '<div class="video_code">(.*?)<h3') + patron = '(?:src|SRC)="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedurl in matches: + if not 'mixdrop' in scrapedurl: #el base64 es netu.tv + url = "https://hqq.tv/player/embed_player.php?vid=RODE5Z2Hx3hO&autoplay=none" + else: + url = "https:" + scrapedurl + headers = {'Referer': item.url} + data = httptools.downloadpage(url, headers=headers).data + url = scrapertools.find_single_match(data, 'vsrc = "([^"]+)"') + url= "https:" + url + itemlist.append(item.clone(action="play", title = "%s", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + diff --git a/channels/perfectgirls.json b/channels/porn/perfectgirls.json similarity index 100% rename from channels/perfectgirls.json rename to channels/porn/perfectgirls.json diff --git a/channels/perfectgirls.py b/channels/porn/perfectgirls.py similarity index 96% rename from channels/perfectgirls.py rename to channels/porn/perfectgirls.py index b77d35e0..43503f3c 100644 --- a/channels/perfectgirls.py +++ b/channels/porn/perfectgirls.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.perfectgirls.net' diff --git a/channels/playpornx.json b/channels/porn/playpornx.json similarity index 60% rename from channels/playpornx.json rename to channels/porn/playpornx.json index 632234b5..d7582a98 100644 --- a/channels/playpornx.json +++ b/channels/porn/playpornx.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": false, - "enabled": false, - "visible": false - } ] } \ No newline at end of file diff --git a/channels/playpornx.py b/channels/porn/playpornx.py similarity index 55% rename from channels/playpornx.py rename to channels/porn/playpornx.py index 8a03ef39..c39822b1 100644 --- a/channels/playpornx.py +++ b/channels/porn/playpornx.py @@ -1,18 +1,17 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools +from core import servertools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config +import base64 host = "https://watchfreexxx.net/" - def mainlist(item): itemlist = [] @@ -22,47 +21,17 @@ def mainlist(item): itemlist.append(Item(channel=item.channel, title="Escenas", action="lista", url = urlparse.urljoin(host, "category/xxx-scenes/"))) - itemlist.append(Item(channel=item.channel, title="Buscar", action="search", url=host + '/?s=', + itemlist.append(Item(channel=item.channel, title="Buscar", action="search", url=host+'?s=', thumbnail='https://s30.postimg.cc/pei7txpa9/buscar.png', fanart='https://s30.postimg.cc/pei7txpa9/buscar.png')) return itemlist -def lista(item): - logger.info() - - itemlist = [] - if item.url == '': item.url = host - - data = httptools.downloadpage(item.url).data - data = re.sub(r'\n|\r|\t| |<br>|\s{2,}', "", data) - - patron = '<article id=.*?<a href="([^"]+)".*?<img data-src="([^"]+)" alt="([^"]+)"' - matches = re.compile(patron, re.DOTALL).findall(data) - - for data_1, data_2, data_3 in matches: - url = data_1 - thumbnail = data_2 - title = data_3 - itemlist.append(Item(channel=item.channel, action='findvideos', title=title, url=url, thumbnail=thumbnail)) - - #Paginacion - if itemlist != []: - actual_page_url = item.url - next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">Next</a>') - if next_page != '': - itemlist.append(Item(channel=item.channel, action="lista", title='Siguiente >>>', url=next_page, - thumbnail='https://s16.postimg.cc/9okdu7hhx/siguiente.png', extra=item.extra)) - - return itemlist - - def search(item, texto): logger.info() texto = texto.replace(" ", "+") item.url = item.url + texto - try: if texto != '': item.extra = 'Buscar' @@ -74,3 +43,58 @@ def search(item, texto): for line in sys.exc_info(): logger.error("%s" % line) return [] + + +def lista(item): + logger.info() + itemlist = [] + if item.url == '': item.url = host + data = httptools.downloadpage(item.url).data + data = re.sub(r'\n|\r|\t| |<br>|\s{2,}', "", data) + patron = '<article id=.*?<a href="([^"]+)".*?<img data-src="([^"]+)" alt="([^"]+)"' + matches = re.compile(patron, re.DOTALL).findall(data) + for data_1, data_2, data_3 in matches: + url = data_1 + thumbnail = data_2 + title = data_3 + itemlist.append(Item(channel=item.channel, action='findvideos', title=title, url=url, thumbnail=thumbnail)) + #Paginacion + if itemlist != []: + actual_page_url = item.url + next_page = scrapertools.find_single_match(data, '<a href="([^"]+)">Next</a>') + if next_page != '': + itemlist.append(Item(channel=item.channel, action="lista", title='Siguiente >>>', url=next_page, + thumbnail='https://s16.postimg.cc/9okdu7hhx/siguiente.png', extra=item.extra)) + return itemlist + + +def findvideos(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = '- on ([^"]+)" href="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedtitle,url in matches: + if "tk/goto/" in url: + n = 3 + while n > 0: + url= url.replace("https://vshares.tk/goto/", "").replace("https://waaws.tk/goto/", "").replace("https://openloads.tk/goto/", "") + logger.debug (url) + url = base64.b64decode(url) + n -= 1 + if "mangovideo" in url: #Aparece como directo + data = httptools.downloadpage(url).data + patron = 'video_url: \'function/0/https://mangovideo.pw/get_file/(\d+)/\w+/(.*?)/\?embed=true\'' + matches = scrapertools.find_multiple_matches(data, patron) + for scrapedtitle,url in matches: + if scrapedtitle =="1": scrapedtitle= "https://www.mangovideo.pw/contents/videos/" + if scrapedtitle =="7": scrapedtitle= "https://server9.mangovideo.pw/contents/videos/" + if scrapedtitle =="8": scrapedtitle= "https://s10.mangovideo.pw/contents/videos/" + if scrapedtitle =="10": scrapedtitle= "https://server217.mangovideo.pw/contents/videos/" + if scrapedtitle =="11": scrapedtitle= "https://234.mangovideo.pw/contents/videos/" + url = scrapedtitle + url + itemlist.append(item.clone(action="play", title = "%s", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + + diff --git a/channels/porn300.json b/channels/porn/porn300.json similarity index 100% rename from channels/porn300.json rename to channels/porn/porn300.json diff --git a/channels/porn300.py b/channels/porn/porn300.py similarity index 60% rename from channels/porn300.py rename to channels/porn/porn300.py index b222d71a..c84840a0 100644 --- a/channels/porn300.py +++ b/channels/porn/porn300.py @@ -1,35 +1,31 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.porn300.com' -#BLOQUEO ANTIVIRUS STREAMCLOUD def mainlist(item): logger.info() itemlist = [] - itemlist.append( Item(channel=item.channel, title="Nuevas" , action="lista", url=host + "/es/videos/")) - itemlist.append( Item(channel=item.channel, title="Mas Vistas" , action="lista", url=host + "/es/mas-vistos/")) - itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/es/mas-votados/")) - itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "/es/canales/?page=1")) - itemlist.append( Item(channel=item.channel, title="Pornstars" , action="categorias", url=host + "/es/pornostars/?page=1")) - itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/es/categorias/")) + itemlist.append( Item(channel=item.channel, title="Nuevas" , action="lista", url=host + "/en_US/ajax/page/list_videos/?page=1")) + itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "/channels/?page=1")) + itemlist.append( Item(channel=item.channel, title="Pornstars" , action="categorias", url=host + "/pornstars/?page=1")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/?page=1")) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist - - +# view-source:https://www.porn300.com/en_US/ajax/page/show_search?q=big+tit&page=1 +# https://www.porn300.com/en_US/ajax/page/show_search?page=2 def search(item, texto): logger.info() texto = texto.replace(" ", "+") - item.url = host + "/es/buscar/?q=%s" % texto + item.url = host + "/en_US/ajax/page/show_search?q=%s&?page=1" % texto try: return lista(item) except: @@ -44,20 +40,18 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<a itemprop="url" href="([^"]+)".*?' - patron += 'title="([^"]+)">.*?' - if "/pornostars/" in item.url: - patron += '<img itemprop="image" src=([^"]+) alt=.*?' - patron += '</svg>([^<]+)<' - else: - patron += '<img itemprop="image" src="([^"]+)" alt=.*?' - patron += '</svg>([^<]+)<' + patron = '<a itemprop="url" href="/([^"]+)".*?' + patron += 'data-src="([^"]+)" alt=.*?' + patron += 'itemprop="name">([^<]+)</h3>.*?' + patron += '</svg>([^<]+)<' matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedtitle,scrapedthumbnail,cantidad in matches: + for scrapedurl,scrapedthumbnail,scrapedtitle,cantidad in matches: scrapedplot = "" cantidad = re.compile("\s+", re.DOTALL).sub(" ", cantidad) scrapedtitle = scrapedtitle + " (" + cantidad +")" - scrapedurl = urlparse.urljoin(item.url,scrapedurl) + "/?sort=latest" + scrapedurl = scrapedurl.replace("channel/", "producer/") + scrapedurl = "/en_US/ajax/page/show_" + scrapedurl + "?page=1" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot) ) next_page = scrapertools.find_single_match(data,'<link rel="next" href="([^"]+)" />') @@ -75,22 +69,29 @@ def lista(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<a itemprop="url" href="([^"]+)" data-video-id="\d+" title="([^"]+)">.*?' - patron += '<img itemprop="thumbnailUrl" src="([^"]+)".*?' + patron = '<a itemprop="url" href="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' + patron += 'itemprop="name">([^<]+)<.*?' patron += '</svg>([^<]+)<' matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedtitle,scrapedthumbnail,cantidad in matches: + for scrapedurl,scrapedthumbnail,scrapedtitle,scrapedtime in matches: url = urlparse.urljoin(item.url,scrapedurl) - cantidad = re.compile("\s+", re.DOTALL).sub(" ", cantidad) - title = "[COLOR yellow]" + cantidad + "[/COLOR] " + scrapedtitle + scrapedtime = scrapedtime.strip() + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle contentTitle = title thumbnail = scrapedthumbnail plot = "" itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle = contentTitle) ) - next_page = scrapertools.find_single_match(data,'<link rel="next" href="([^"]+)" />') - if next_page!="": - next_page = urlparse.urljoin(item.url,next_page) + prev_page = scrapertools.find_single_match(item.url,"(.*?)page=\d+") + num= int(scrapertools.find_single_match(item.url,".*?page=(\d+)")) + num += 1 + num_page = "?page=" + str(num) + if num_page!="": + next_page = urlparse.urljoin(item.url,num_page) + if "show_search" in next_page: + next_page = prev_page + num_page + next_page = next_page.replace("&?", "&") itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist @@ -101,6 +102,6 @@ def play(item): patron = '<source src="([^"]+)"' matches = re.compile(patron,re.DOTALL).findall(data) for url in matches: - itemlist.append(item.clone(action="play", title=url, fulltitle = item.title, url=url)) + itemlist.append(item.clone(action="play", title=url, url=url)) return itemlist diff --git a/channels/pornboss.json b/channels/porn/pornboss.json similarity index 100% rename from channels/pornboss.json rename to channels/porn/pornboss.json diff --git a/channels/pornboss.py b/channels/porn/pornboss.py similarity index 51% rename from channels/pornboss.py rename to channels/porn/pornboss.py index c2ff0e62..ebe0f22b 100644 --- a/channels/pornboss.py +++ b/channels/porn/pornboss.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from core import jsontools as json from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://pornboss.org' @@ -15,13 +15,11 @@ def mainlist(item): logger.info() itemlist = [] itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/category/movies/")) - itemlist.append( Item(channel=item.channel, title=" categorias" , action="categorias", url=host + "/category/movies/")) - itemlist.append( Item(channel=item.channel, title="Videos" , action="lista", url=host + "/category/clips/")) - itemlist.append( Item(channel=item.channel, title=" categorias" , action="categorias", url=host + "/category/clips/")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist - def search(item, texto): logger.info() texto = texto.replace(" ", "+") @@ -40,13 +38,9 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - if "/category/movies/" in item.url: - data = scrapertools.find_single_match(data,'>Movies</a>(.*?)</ul>') - else: - data = scrapertools.find_single_match(data,'>Clips</a>(.*?)</ul>') - patron = '<a href=([^"]+)>([^"]+)</a>' + data = scrapertools.find_single_match(data,'<div class="uk-panel uk-panel-box widget_nav_menu">(.*?)</ul>') + patron = '<li><a href=(.*?) class>([^<]+)</a>' matches = re.compile(patron,re.DOTALL).findall(data) - scrapertools.printMatches(matches) for scrapedurl,scrapedtitle in matches: scrapedplot = "" scrapedthumbnail = "" @@ -59,29 +53,39 @@ def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - patron = '<article id=post-\d+.*?' - patron += '<img class="center cover" src=([^"]+) alt="([^"]+)".*?' - patron += '<blockquote><p> <a href=(.*?) target=_blank' + patron = '<article id=item-\d+.*?' + patron += '<img class=.*?src=(.*?) alt="([^"]+)".*?' + patron += 'Duration:</strong>(.*?) / <strong>.*?' + patron += '>SHOW<.*?href=([^"]+) target=' matches = re.compile(patron,re.DOTALL).findall(data) - scrapertools.printMatches(matches) - for scrapedthumbnail,scrapedtitle,scrapedurl in matches: + for scrapedthumbnail,scrapedtitle,duration,scrapedurl in matches: scrapedplot = "" - itemlist.append( Item(channel=item.channel, action="play", title=scrapedtitle, url=scrapedurl, + title = "[COLOR yellow]" + duration + "[/COLOR] " + scrapedtitle + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot) ) - next_page = scrapertools.find_single_match(data,'<a class=nextpostslink rel=next href=(.*?)>') + next_page = scrapertools.find_single_match(data,'<li><a href=([^<]+)><i class=uk-icon-angle-double-right>') + next_page = next_page.replace('"', '') if next_page!="": itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist - def play(item): logger.info() - data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=item.url) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel + itemlist = [] + if "streamcloud" in item.url: + itemlist.append(item.clone(action="play", url=item.url )) + else: + data = httptools.downloadpage(item.url).data + url=scrapertools.find_single_match(data,'<span class="bottext">Streamcloud.eu</span>.*?href="([^"]+)"') + url= "https://tolink.to" + url + data = httptools.downloadpage(url).data + patron = '<input type="hidden" name="id" value="([^"]+)">.*?' + patron += '<input type="hidden" name="fname" value="([^"]+)">' + matches = re.compile(patron,re.DOTALL).findall(data) + for id, url in matches: + url= "http://streamcloud.eu/" + id + itemlist.append(item.clone(action="play", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist) return itemlist + diff --git a/channels/porn/porndish.json b/channels/porn/porndish.json new file mode 100755 index 00000000..c6089759 --- /dev/null +++ b/channels/porn/porndish.json @@ -0,0 +1,15 @@ +{ + "id": "porndish", + "name": "porndish", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://www.porndish.com/wp-content/uploads/2015/09/logo.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/porndish.py b/channels/porn/porndish.py new file mode 100755 index 00000000..0a5508aa --- /dev/null +++ b/channels/porn/porndish.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.porndish.com' + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host)) + itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/?s=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<li id="menu-item-\d+".*?' + patron += '<a href="([^"]+)">([^<]+)<' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle in matches: + scrapedplot = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + scrapedthumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + data = scrapertools.find_single_match(data, 'archive-body">(.*?)<div class="g1-row g1-row-layout-page g1-prefooter">') + patron = '<article class=.*?' + patron += 'src="([^"]+)".*?' + patron += 'title="([^"]+)".*?' + patron += '<a href="([^"]+)" rel="bookmark">' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedthumbnail,scrapedtitle,scrapedurl in matches: + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="findvideos", title=scrapedtitle, url=scrapedurl, + fanart=thumbnail, thumbnail=thumbnail, plot=plot, contentTitle = scrapedtitle)) + next_page = scrapertools.find_single_match(data, '<a class="g1-delta g1-delta-1st next" href="([^"]+)">Next</a>') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + + + diff --git a/channels/porneq.json b/channels/porn/porneq.json similarity index 100% rename from channels/porneq.json rename to channels/porn/porneq.json diff --git a/channels/porneq.py b/channels/porn/porneq.py similarity index 88% rename from channels/porneq.py rename to channels/porn/porneq.py index 5b4bee8a..044346eb 100644 --- a/channels/porneq.py +++ b/channels/porn/porneq.py @@ -1,12 +1,16 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ +import urlparse +import urllib2 +import urllib import re - -from core import httptools +import os +import sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://porneq.com' @@ -17,7 +21,7 @@ def mainlist(item): itemlist.append(Item(channel=item.channel, title="Ultimos", action="lista", url=host + "/videos/browse/")) itemlist.append(Item(channel=item.channel, title="Mas Vistos", action="lista", url=host + "/videos/most-viewed/")) itemlist.append(Item(channel=item.channel, title="Mas Votado", action="lista", url=host + "/videos/most-liked/")) - itemlist.append(Item(channel=item.channel, title="Big Tits", action="lista", url=host + "/show/big+tits&sort=w")) + itemlist.append(Item(channel=item.channel, title="Big Tits", action="lista", url=host + "/show/big+tit")) itemlist.append(Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -46,6 +50,7 @@ def lista(item): matches = re.compile(patron, re.DOTALL).findall(data) for scrapedtitle, scrapedurl, scrapedthumbnail, scrapedtime in matches: scrapedplot = "" + scrapedthumbnail = scrapedthumbnail.replace("https:", "http:") scrapedtitle = "[COLOR yellow]" + (scrapedtime) + "[/COLOR] " + scrapedtitle itemlist.append(Item(channel=item.channel, action="play", title=scrapedtitle, url=scrapedurl, fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot)) @@ -60,7 +65,8 @@ def play(item): itemlist = [] data = httptools.downloadpage(item.url).data scrapedurl = scrapertools.find_single_match(data, '<source src="([^"]+)"') + scrapedurl = scrapedurl.replace("X20", "-") itemlist.append( - Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/pornhive.json b/channels/porn/pornhive.json similarity index 100% rename from channels/pornhive.json rename to channels/porn/pornhive.json diff --git a/channels/pornhive.py b/channels/porn/pornhive.py similarity index 96% rename from channels/pornhive.py rename to channels/porn/pornhive.py index 5df6411b..f34ce0f6 100644 --- a/channels/pornhive.py +++ b/channels/porn/pornhive.py @@ -1,17 +1,18 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys import base64 -import re -from core import httptools from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://www.pornhive.tv/en' +# Algunos link caidos def mainlist(item): logger.info() diff --git a/channels/pornhub.json b/channels/porn/pornhub.json similarity index 60% rename from channels/pornhub.json rename to channels/porn/pornhub.json index e1f50b6f..4a719116 100644 --- a/channels/pornhub.json +++ b/channels/porn/pornhub.json @@ -11,13 +11,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": true, - "enabled": true, - "visible": true - } ] -} \ No newline at end of file +} diff --git a/channels/pornhub.py b/channels/porn/pornhub.py similarity index 73% rename from channels/pornhub.py rename to channels/porn/pornhub.py index 5c1fe01e..c485be51 100644 --- a/channels/pornhub.py +++ b/channels/porn/pornhub.py @@ -1,20 +1,18 @@ # -*- coding: utf-8 -*- import re - import urlparse - from core import httptools +from core import servertools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config def mainlist(item): logger.info() itemlist = [] - itemlist.append(Item(channel=item.channel, action="peliculas", title="Novedades", fanart=item.fanart, + itemlist.append(Item(channel=item.channel, action="lista", title="Novedades", fanart=item.fanart, url="http://es.pornhub.com/video?o=cm")) itemlist.append(Item(channel=item.channel, action="categorias", title="Categorias", fanart=item.fanart, url="http://es.pornhub.com/categories")) @@ -28,8 +26,7 @@ def search(item, texto): item.url = item.url % texto try: - return peliculas(item) - # Se captura la excepción, para no interrumpir al buscador global si un canal falla + return lista(item) except: import sys for line in sys.exc_info(): @@ -53,13 +50,13 @@ def categorias(item): else: url = urlparse.urljoin(item.url, scrapedurl + "?o=cm") scrapedtitle = scrapedtitle + " (" + cantidad + ")" - itemlist.append(Item(channel=item.channel, action="peliculas", title=scrapedtitle, url=url, + itemlist.append(Item(channel=item.channel, action="lista", title=scrapedtitle, url=url, fanart=scrapedthumbnail, thumbnail=scrapedthumbnail)) itemlist.sort(key=lambda x: x.title) return itemlist -def peliculas(item): +def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data @@ -70,10 +67,11 @@ def peliculas(item): patron += '<var class="duration">([^<]+)</var>(.*?)</div>' matches = re.compile(patron, re.DOTALL).findall(videodata) for url, scrapedtitle, thumbnail, duration, scrapedhd in matches: - title = "(" + duration + ") " + scrapedtitle.replace("&amp;", "&") scrapedhd = scrapertools.find_single_match(scrapedhd, '<span class="hd-thumbnail">(.*?)</span>') - if scrapedhd == 'HD': - title += ' [HD]' + if scrapedhd == 'HD': + title = "[COLOR yellow]" +duration+ "[/COLOR] " + "[COLOR red]" +scrapedhd+ "[/COLOR] "+scrapedtitle + else: + title = "[COLOR yellow]" + duration + "[/COLOR] " + scrapedtitle url = urlparse.urljoin(item.url, url) itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, fanart=thumbnail, thumbnail=thumbnail)) @@ -84,19 +82,12 @@ def peliculas(item): if matches: url = urlparse.urljoin(item.url, matches[0].replace('&', '&')) itemlist.append( - Item(channel=item.channel, action="peliculas", title=">> Página siguiente", fanart=item.fanart, + Item(channel=item.channel, action="lista", title=">> Página siguiente", fanart=item.fanart, url=url)) return itemlist def play(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - patron = '"defaultQuality":true,"format":"mp4","quality":"\d+","videoUrl":"(.*?)"' - matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl in matches: - url = scrapedurl.replace("\/", "/") - itemlist.append(item.clone(action="play", title=url, fulltitle = item.title, url=url)) + logger.info(item) + itemlist = servertools.find_video_items(item.clone(url = item.url)) return itemlist - diff --git a/channels/porn/pornohdmega.json b/channels/porn/pornohdmega.json new file mode 100755 index 00000000..c8cc0622 --- /dev/null +++ b/channels/porn/pornohdmega.json @@ -0,0 +1,15 @@ +{ + "id": "pornohdmega", + "name": "pornohdmega", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://www.pornohdmega.com/wp-content/uploads/2018/11/dftyu.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/pornohdmega.py b/channels/porn/pornohdmega.py new file mode 100755 index 00000000..862a37f1 --- /dev/null +++ b/channels/porn/pornohdmega.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.pornohdmega.com' + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/?order=recent")) + itemlist.append( Item(channel=item.channel, title="Mejor valorados" , action="lista", url=host + "/?order=top-rated")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/?order=most-viewed")) + + itemlist.append( Item(channel=item.channel, title="Canal" , action="catalogo", url=host + "/categories/")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/?s=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<li><a href=\'([^\']+)\' title=\'([^\']+) Tag\'>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle in matches: + scrapedplot = "" + if not "tag" in scrapedurl: + scrapedurl = "" + thumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=thumbnail , plot=scrapedplot) ) + return itemlist + + +def catalogo(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<h2><a href="([^"]+)">([^<]+)</a></h2>.*?' + patron += '<strong>(\d+) Videos</strong>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedtitle = "%s (%s)" % (scrapedtitle,cantidad) + thumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, + thumbnail=thumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<figure class="video-preview"><a href="([^"]+)".*?' + patron += '<img src="([^"]+)".*?' + patron += 'title="([^"]+)"' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,scrapedtitle in matches: + title = scrapedtitle + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, thumbnail=thumbnail, + fanart=thumbnail, plot=plot,)) + next_page = scrapertools.find_single_match(data, '<a class="nextpostslink" rel="next" href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + patron = '<iframe src="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + itemlist.append(item.clone(action="play", title= "%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + diff --git a/channels/pornrewind.json b/channels/porn/pornrewind.json similarity index 100% rename from channels/pornrewind.json rename to channels/porn/pornrewind.json diff --git a/channels/pornrewind.py b/channels/porn/pornrewind.py similarity index 94% rename from channels/pornrewind.py rename to channels/porn/pornrewind.py index 6dfde368..55d415e8 100644 --- a/channels/pornrewind.py +++ b/channels/porn/pornrewind.py @@ -1,16 +1,17 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.pornrewind.com' +# hacer funcionar conector Kt player + def mainlist(item): logger.info() itemlist = [] diff --git a/channels/porntrex.json b/channels/porn/porntrex.json similarity index 100% rename from channels/porntrex.json rename to channels/porn/porntrex.json diff --git a/channels/porntrex.py b/channels/porn/porntrex.py similarity index 84% rename from channels/porntrex.py rename to channels/porn/porntrex.py index 22d99f01..70dbca6f 100644 --- a/channels/porntrex.py +++ b/channels/porn/porntrex.py @@ -2,14 +2,12 @@ import re import urllib - import urlparse from core import httptools from core import scrapertools from core.item import Item from platformcode import config, logger -from platformcode import config host = "https://www.porntrex.com" perpage = 20 @@ -27,6 +25,7 @@ def mainlist(item): itemlist.append(item.clone(action="categorias", title="Modelos", url=host + "/models/?mode=async&function=get_block&block_id=list_models_models" \ "_list&sort_by=total_videos")) + itemlist.append(item.clone(action="categorias", title="Canal", url=host + "/channels/")) itemlist.append(item.clone(action="playlists", title="Listas", url=host + "/playlists/")) itemlist.append(item.clone(action="tags", title="Tags", url=host + "/tags/")) itemlist.append(item.clone(title="Buscar...", action="search")) @@ -59,15 +58,14 @@ def search(item, texto): def lista(item): logger.info() itemlist = [] - # Descarga la pagina data = get_data(item.url) - action = "play" if config.get_setting("menu_info", "porntrex"): action = "menu_info" - # Quita las entradas, que no son private - patron = '<div class="video-preview-screen video-item thumb-item ".*?<a href="([^"]+)".*?' + # Quita las entradas, que no son private <div class="video-preview-screen video-item thumb-item private " + patron = '<div class="video-preview-screen video-item thumb-item ".*?' + patron += '<a href="([^"]+)".*?' patron += 'data-src="([^"]+)".*?' patron += 'alt="([^"]+)".*?' patron += '<span class="quality">(.*?)<.*?' @@ -120,21 +118,25 @@ def lista(item): def categorias(item): logger.info() itemlist = [] - - # Descarga la pagina data = get_data(item.url) # Extrae las entradas - patron = '<a class="item" href="([^"]+)" title="([^"]+)".*?src="([^"]+)".*?<div class="videos">([^<]+)<' + if "/channels/" in item.url: + patron = '<div class="video-item ">.*?<a href="([^"]+)" title="([^"]+)".*?src="([^"]+)".*?<li>([^<]+)<' + else: + patron = '<a class="item" href="([^"]+)" title="([^"]+)".*?src="([^"]+)".*?<div class="videos">([^<]+)<' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedtitle, scrapedthumbnail, videos in matches: if "go.php?" in scrapedurl: scrapedurl = urllib.unquote(scrapedurl.split("/go.php?u=")[1].split("&")[0]) scrapedthumbnail = urllib.unquote(scrapedthumbnail.split("/go.php?u=")[1].split("&")[0]) + scrapedthumbnail += "|Referer=https://www.porntrex.com/" else: scrapedurl = urlparse.urljoin(host, scrapedurl) if not scrapedthumbnail.startswith("https"): scrapedthumbnail = "https:%s" % scrapedthumbnail + scrapedthumbnail += "|Referer=https://www.porntrex.com/" + scrapedthumbnail = scrapedthumbnail.replace(" " , "%20") if videos: scrapedtitle = "%s (%s)" % (scrapedtitle, videos) itemlist.append(item.clone(action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, @@ -158,7 +160,10 @@ def playlists(item): # Descarga la pagina data = get_data(item.url) # Extrae las entradas - patron = '<div class="item.*?href="([^"]+)" title="([^"]+)".*?data-original="([^"]+)".*?<div class="totalplaylist">([^<]+)<' + patron = '<div class="item.*?' + patron += 'href="([^"]+)" title="([^"]+)".*?' + patron += 'data-original="([^"]+)".*?' + patron += '<div class="totalplaylist">([^<]+)<' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl, scrapedtitle, scrapedthumbnail, videos in matches: if "go.php?" in scrapedurl: @@ -168,6 +173,8 @@ def playlists(item): scrapedurl = urlparse.urljoin(host, scrapedurl) if not scrapedthumbnail.startswith("https"): scrapedthumbnail = "https:%s" % scrapedthumbnail + scrapedthumbnail += "|Referer=https://www.porntrex.com/" + scrapedthumbnail = scrapedthumbnail.replace(" " , "%20") if videos: scrapedtitle = "%s [COLOR red](%s)[/COLOR]" % (scrapedtitle, videos) itemlist.append(item.clone(action="videos", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, @@ -195,7 +202,12 @@ def videos(item): if config.get_setting("menu_info", "porntrex"): action = "menu_info" # Extrae las entradas - patron = '<div class="video-item.*?href="([^"]+)".*?title="([^"]+)".*?src="([^"]+)"(.*?)<div class="durations">.*?</i>([^<]+)</div>' + # Quita las entradas, que no son private <div class="video-item private "> + patron = '<div class="video-item ".*?' + patron += 'href="([^"]+)".*?' + patron += 'title="([^"]+)".*?' + patron += 'src="([^"]+)"(.*?)<div class="durations">.*?' + patron += '</i>([^<]+)</div>' matches = scrapertools.find_multiple_matches(data, patron) count = 0 for scrapedurl, scrapedtitle, scrapedthumbnail, quality, duration in matches: @@ -209,60 +221,51 @@ def videos(item): scrapedurl = urlparse.urljoin(host, scrapedurl) if not scrapedthumbnail.startswith("https"): scrapedthumbnail = "https:%s" % scrapedthumbnail - if duration: - scrapedtitle = "%s - %s" % (duration, scrapedtitle) - if '>HD<' in quality: - scrapedtitle += " [COLOR red][HD][/COLOR]" + scrapedthumbnail += "|Referer=https://www.porntrex.com/" + scrapedthumbnail = scrapedthumbnail.replace(" " , "%20") + if 'k4"' in quality: + quality = "4K" + scrapedtitle = "%s - [COLOR yellow]%s[/COLOR] %s" % (duration, quality, scrapedtitle) + else: + quality = scrapertools.find_single_match(quality, '<span class="quality">(.*?)<.*?') + scrapedtitle = "%s - [COLOR red]%s[/COLOR] %s" % (duration, quality, scrapedtitle) if len(itemlist) >= perpage: break; - itemlist.append(item.clone(action=action, title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, contentThumbnail=scrapedthumbnail, - fanart=scrapedthumbnail)) + itemlist.append(item.clone(action=action, title=scrapedtitle, url=scrapedurl, contentThumbnail=scrapedthumbnail, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail)) #Extrae la marca de siguiente página if item.channel and len(itemlist) >= perpage: itemlist.append( item.clone(title = "Página siguiente >>>", indexp = count + 1) ) - return itemlist def play(item): logger.info() itemlist = [] - data = get_data(item.url) - patron = '(?:video_url|video_alt_url[0-9]*)\s*:\s*\'([^\']+)\'.*?(?:video_url_text|video_alt_url[0-9]*_text)\s*:\s*\'([^\']+)\'' + patron = '(?:video_url|video_alt_url[0-9]*):\s*\'([^\']+)\'.*?' + patron += '(?:video_url_text|video_alt_url[0-9]*_text):\s*\'([^\']+)\'' matches = scrapertools.find_multiple_matches(data, patron) - if not matches: - patron = '<iframe.*?height="(\d+)".*?video_url\s*:\s*\'([^\']+)\'' - matches = scrapertools.find_multiple_matches(data, patron) + scrapertools.printMatches(matches) for url, quality in matches: - if "https" in quality: - calidad = url - url = quality - quality = calidad + "p" - + quality = quality.replace(" HD" , "").replace(" 4k", "") itemlist.append(['.mp4 %s [directo]' % quality, url]) - if item.extra == "play_menu": return itemlist, data - return itemlist def menu_info(item): logger.info() itemlist = [] - video_urls, data = play(item.clone(extra="play_menu")) itemlist.append(item.clone(action="play", title="Ver -- %s" % item.title, video_urls=video_urls)) - - matches = scrapertools.find_multiple_matches(data, '<img class="thumb lazy-load".*?data-original="([^"]+)"') + matches = scrapertools.find_multiple_matches(data, '<img class="thumb lazy-load" src="([^"]+)"') for i, img in enumerate(matches): if i == 0: continue - img = urlparse.urljoin(host, img) - img += "|Referer=https://www.porntrex.com/" + img = "https:" + img + "|Referer=https://www.porntrex.com/" title = "Imagen %s" % (str(i)) itemlist.append(item.clone(action="", title=title, thumbnail=img, fanart=img)) - return itemlist @@ -321,5 +324,4 @@ def get_data(url_orig): post = "" else: break - return response.data diff --git a/channels/porn/porntv.json b/channels/porn/porntv.json new file mode 100755 index 00000000..d65c8cb8 --- /dev/null +++ b/channels/porn/porntv.json @@ -0,0 +1,15 @@ +{ + "id": "porntv", + "name": "porntv", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://www.porntv.com/images/dart/logo.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/porntv.py b/channels/porn/porntv.py new file mode 100755 index 00000000..c2a9a31e --- /dev/null +++ b/channels/porn/porntv.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.porntv.com' + + +def mainlist(item): + logger.info() + itemlist = [] + + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/videos/straight/all-recent.html")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/videos/straight/all-view.html")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/videos/straight/all-rate.html")) + itemlist.append( Item(channel=item.channel, title="Mas popular" , action="lista", url=host + "/videos/straight/all-popular.html")) + itemlist.append( Item(channel=item.channel, title="Mas largos" , action="lista", url=host + "/videos/straight/all-length.html")) + + + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "") + item.url = host + "/videos/straight/%s-recent.html" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + data = scrapertools.find_single_match(data, '<h1>Popular Categories</h1>(.*?)<h1>Community</h1>') + patron = '<h2><a href="([^"]+)">([^<]+)</a>.*?' + patron += 'src="([^"]+)".*?' + patron += '<span class="contentquantity">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,scrapedthumbnail,cantidad in matches: + scrapedplot = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + title = scrapedtitle + " " + cantidad + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<div class="item" style="width: 320px">.*?' + patron += '<a href="([^"]+)".*?' + patron += '<img src="([^"]+)".*?' + patron += '>(.*?)<div class="trailer".*?' + patron += 'title="([^"]+)".*?' + patron += 'clock"></use></svg>([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,quality,scrapedtitle,scrapedtime in matches: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + if "flag-hd" in quality: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + "[COLOR red]" + "HD" + "[/COLOR] " + scrapedtitle + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + thumbnail = scrapedthumbnail + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, + fanart=thumbnail, thumbnail=thumbnail, plot=plot, contentTitle = scrapedtitle)) + + next_page = scrapertools.find_single_match(data, '<a href="([^"]+)" class="next"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + data = scrapertools.find_single_match(data, 'sources: \[(.*?)\]') + patron = 'file: "([^"]+)",.*?label: "([^"]+)",' + matches = re.compile(patron,re.DOTALL).findall(data) + for url,quality in matches: + itemlist.append(["%s %s [directo]" % (quality, url), url]) + return itemlist + + diff --git a/channels/qwertty.json b/channels/porn/qwertty.json similarity index 69% rename from channels/qwertty.json rename to channels/porn/qwertty.json index c9b9bf25..0d618542 100644 --- a/channels/qwertty.json +++ b/channels/porn/qwertty.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "http://qwertty.net/wp-content/uploads/2018/05/favicon.ico", + "thumbnail": "https://qwertty.net/wp-content/uploads/2019/07/favicon.ico", "banner": "", "categories": [ "adult" diff --git a/channels/qwertty.py b/channels/porn/qwertty.py similarity index 54% rename from channels/qwertty.py rename to channels/porn/qwertty.py index 73f2d01c..7daedcbe 100644 --- a/channels/qwertty.py +++ b/channels/porn/qwertty.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urllib -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools +from channels import pornhub, xvideos,youporn host = 'http://qwertty.net' @@ -56,7 +55,6 @@ def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data,'<div class="videos-list">(.*?)<div class="videos-list">') data = re.sub(r"\n|\r|\t| |<br>", "", data) patron = '<article id="post-\d+".*?' patron += '<a href="([^"]+)" title="([^"]+)">.*?' @@ -73,7 +71,7 @@ def lista(item): fanart=thumbnail, thumbnail=thumbnail, plot=scrapedplot) ) next_page = scrapertools.find_single_match(data,'<li><a href="([^"]+)">Next</a>') if next_page=="": - next_page = scrapertools.find_single_match(data,'<li><a class="current">.*?<li><a href=\'([^\']+)\' class="inactive">') + next_page = scrapertools.find_single_match(data,'<li><a class="current">.*?<li><a href="([^"]+)" class="inactive">') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) @@ -84,65 +82,35 @@ def play(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - url = scrapertools.find_single_match(data,'<meta itemprop="embedURL" content="([^"]+)"') - url = url.replace("pornhub.com/embed/", "pornhub.com/view_video.php?viewkey=") - data = httptools.downloadpage(url).data - if "spankwire" in url : + url1 = scrapertools.find_single_match(data,'<meta itemprop="embedURL" content="([^"]+)"') + if "spankwire" in url1: data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data,'Copy Embed Code(.*?)For Desktop') + data = scrapertools.get_match(data,'Copy Embed Code(.*?)For Desktop') patron = '<div class="shareDownload_container__item__dropdown">.*?<a href="([^"]+)"' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: url = scrapedurl if url=="#": - scrapedurl = scrapertools.find_single_match(data,'playerData.cdnPath480 = \'([^\']+)\'') - itemlist.append(item.clone(action="play", title=scrapedurl, fulltitle = scrapedurl, url=scrapedurl)) - - if "xvideos" in url : - scrapedurl = scrapertools.find_single_match(data,'setVideoHLS\(\'([^\']+)\'') - if "pornhub" in url : - scrapedurl = scrapertools.find_single_match(data,'"defaultQuality":true,"format":"mp4","quality":"\d+","videoUrl":"(.*?)"') - if "txx" in url : - video_url = scrapertools.find_single_match(data, 'var video_url="([^"]*)"') - video_url += scrapertools.find_single_match(data, 'video_url\+="([^"]*)"') - partes = video_url.split('||') - video_url = decode_url(partes[0]) - video_url = re.sub('/get_file/\d+/[0-9a-z]{32}/', partes[1], video_url) - video_url += '&' if '?' in video_url else '?' - video_url += 'lip=' + partes[2] + '<=' + partes[3] - scrapedurl = video_url + url = scrapertools.find_single_match(data,'playerData.cdnPath480 = \'([^\']+)\'') + itemlist.append(item.clone(action="play", title=url, contentTitle = url, url=url)) + elif "xvideos1" in url1: + item1 = item.clone(url=url1) + itemlist = xvideos.play(item1) + return itemlist + elif "pornhub" in url1 : + url = url1 + elif "txx" in url1:# Falta conector + url = "" + elif "youporn" in url1: + item1 = item.clone(url=url1) + itemlist = youporn.play(item1) + return itemlist else: - scrapedurl = scrapertools.find_single_match(data,'"quality":"\d+","videoUrl":"(.*?)"') - scrapedurl = scrapedurl.replace("\/", "/") - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, - thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) + data = httptools.downloadpage(url1).data + url = scrapertools.find_single_match(data,'"quality":"\d+","videoUrl":"([^"]+)"') + url = url.replace("\/", "/") + + itemlist.append(item.clone(action="play", title= "%s " + url1, contentTitle = item.title, url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist - -def decode_url(txt): - _0x52f6x15 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,~' - reto = ''; n = 0 - # En las dos siguientes líneas, ABCEM ocupan 2 bytes cada letra! El replace lo deja en 1 byte. !!!!: АВСЕМ (10 bytes) ABCEM (5 bytes) - txt = re.sub('[^АВСЕМA-Za-z0-9\.\,\~]', '', txt) - txt = txt.replace('А', 'A').replace('В', 'B').replace('С', 'C').replace('Е', 'E').replace('М', 'M') - - while n < len(txt): - a = _0x52f6x15.index(txt[n]) - n += 1 - b = _0x52f6x15.index(txt[n]) - n += 1 - c = _0x52f6x15.index(txt[n]) - n += 1 - d = _0x52f6x15.index(txt[n]) - n += 1 - - a = a << 2 | b >> 4 - b = (b & 15) << 4 | c >> 2 - e = (c & 3) << 6 | d - reto += chr(a) - if c != 64: reto += chr(b) - if d != 64: reto += chr(e) - - return urllib.unquote(reto) - - diff --git a/channels/redtube.json b/channels/porn/redtube.json similarity index 100% rename from channels/redtube.json rename to channels/porn/redtube.json diff --git a/channels/redtube.py b/channels/porn/redtube.py similarity index 97% rename from channels/redtube.py rename to channels/porn/redtube.py index faeaad1a..91c511a0 100644 --- a/channels/redtube.py +++ b/channels/porn/redtube.py @@ -2,14 +2,11 @@ #------------------------------------------------------------ import re - import urlparse - from core import httptools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config host = 'https://es.redtube.com' @@ -117,6 +114,6 @@ def play(item): matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl in matches: url = scrapedurl.replace("\/", "/") - itemlist.append(item.clone(action="play", title=url, fulltitle = item.title, url=url)) + itemlist.append(item.clone(action="play", title=url, url=url)) return itemlist diff --git a/channels/serviporno.json b/channels/porn/serviporno.json similarity index 54% rename from channels/serviporno.json rename to channels/porn/serviporno.json index e0307f90..5b72fb31 100644 --- a/channels/serviporno.json +++ b/channels/porn/serviporno.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": true, - "enabled": true, - "visible": true - } ] -} \ No newline at end of file +} diff --git a/channels/serviporno.py b/channels/porn/serviporno.py similarity index 93% rename from channels/serviporno.py rename to channels/porn/serviporno.py index 773d51cc..67096e09 100644 --- a/channels/serviporno.py +++ b/channels/porn/serviporno.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config host = "https://www.serviporno.com" @@ -47,7 +45,9 @@ def search(item, texto): def get_last_page(url): logger.info() data = httptools.downloadpage(url).data - last_page= int(scrapertools.find_single_match(data,'data-ajax-last-page="(\d+)"')) + last_page= scrapertools.find_single_match(data,'data-ajax-last-page="(\d+)"') + if last_page: + last_page= int(last_page) return last_page @@ -59,7 +59,7 @@ def videos(item): patron += '<div class="box-escena">.*?' patron += '<a\s*href="([^"]+)".*?' patron += 'data-stats-video-name="([^"]+)".*?' - patron += '<img\s*src="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' patron += '<div class="duracion">([^"]+) min</div>' matches = re.compile(patron,re.DOTALL).findall(data) for url, title, thumbnail,duration in matches: @@ -114,15 +114,17 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data patron = '<div class="wrap-box-escena.*?' - patron += 'href="([^"]+)"><img src="([^"]+)".*?' - patron += '<h4.*?<a href="[^"]+">([^<]+)</a></h4>' + patron += '<img src="([^"]+)".*?' + patron += '<h4.*?<a href="([^"]+)">([^<]+)<' matches = re.compile(patron, re.DOTALL).findall(data) - for url, thumbnail, title in matches: + for thumbnail, url, title in matches: last = urlparse.urljoin(item.url, url) url= last.replace("/videos-porno", "/ajax/show_category").replace("/sitio","/ajax/show_producer") + "?page=1" itemlist.append(Item(channel=item.channel, action='videos', title=title, url=url, last=last, thumbnail=thumbnail, plot="")) # Paginador "Página Siguiente >>" - current_page = int(scrapertools.find_single_match(item.url, "/?page=(\d+)")) + current_page = scrapertools.find_single_match(item.url, "/?page=(\d+)") + if current_page: + current_page = int(current_page) if not item.last_page: last_page = get_last_page(item.last) else: diff --git a/channels/sexgalaxy.json b/channels/porn/sexgalaxy.json similarity index 100% rename from channels/sexgalaxy.json rename to channels/porn/sexgalaxy.json diff --git a/channels/sexgalaxy.py b/channels/porn/sexgalaxy.py similarity index 80% rename from channels/sexgalaxy.py rename to channels/porn/sexgalaxy.py index 0228b622..506bd45a 100644 --- a/channels/sexgalaxy.py +++ b/channels/porn/sexgalaxy.py @@ -1,19 +1,15 @@ # -*- coding: utf-8 -*- import re - import urlparse - from core import httptools from core import scrapertools from core import servertools from core.item import Item from platformcode import logger -from platformcode import config host = 'http://sexgalaxy.net' - def mainlist(item): logger.info() itemlist = [] @@ -42,7 +38,7 @@ def canales(item): logger.info() itemlist = [] data = httptools.downloadpage(host).data - data = scrapertools.find_single_match(data, 'Top Networks</a>(.*?)</ul>') + data = scrapertools.find_single_match(data, '>TopSites</a>(.*?)</ul>') patron = '<li id=.*?<a href="(.*?)">(.*?)</a></li>' matches = re.compile(patron, re.DOTALL).findall(data) for scrapedurl, scrapedtitle in matches: @@ -59,8 +55,8 @@ def categorias(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data, 'More Categories</a>(.*?)</ul>') - patron = '<li id=.*?<a href="(.*?)">(.*?)</a></li>' + data = scrapertools.find_single_match(data, '>Popular Categories<(.*?)</p>') + patron = '<a href="(.*?)">(.*?)</a>' matches = re.compile(patron, re.DOTALL).findall(data) for scrapedurl, scrapedtitle in matches: scrapedplot = "" @@ -83,21 +79,11 @@ def lista(item): calidad = scrapertools.find_single_match(scrapedtitle, '\(.*?/(\w+)\)') if calidad: scrapedtitle = "[COLOR red]" + calidad + "[/COLOR] " + scrapedtitle - itemlist.append(Item(channel=item.channel, action="play", title=scrapedtitle, url=scrapedurl, - fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, fulltitle=scrapedtitle, plot=scrapedplot)) + itemlist.append(Item(channel=item.channel, action="findvideos", title=scrapedtitle, url=scrapedurl, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot)) next_page = scrapertools.find_single_match(data, '<a class="next page-numbers" href="([^"]+)"') if next_page != "": itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page)) return itemlist -def play(item): - logger.info() - data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - return itemlist diff --git a/channels/sexkino.json b/channels/porn/sexkino.json similarity index 100% rename from channels/sexkino.json rename to channels/porn/sexkino.json diff --git a/channels/sexkino.py b/channels/porn/sexkino.py similarity index 98% rename from channels/sexkino.py rename to channels/porn/sexkino.py index 0aca2759..c530c2b2 100644 --- a/channels/sexkino.py +++ b/channels/porn/sexkino.py @@ -1,15 +1,12 @@ # -*- coding: utf-8 -*- import re - import urlparse - from core import httptools from core import scrapertools from core import servertools from core.item import Item from platformcode import logger -from platformcode import config host = 'http://sexkino.to' @@ -134,7 +131,6 @@ def play(item): itemlist = servertools.find_video_items(data=data) for videoitem in itemlist: videoitem.title = item.title - videoitem.fulltitle = item.fulltitle videoitem.thumbnail = item.thumbnail videoitem.channel = item.channel return itemlist diff --git a/channels/sexofilm.json b/channels/porn/sexofilm.json similarity index 100% rename from channels/sexofilm.json rename to channels/porn/sexofilm.json diff --git a/channels/sexofilm.py b/channels/porn/sexofilm.py similarity index 81% rename from channels/sexofilm.py rename to channels/porn/sexofilm.py index 8a1eb01f..d71a7d3e 100644 --- a/channels/sexofilm.py +++ b/channels/porn/sexofilm.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://sexofilm.com' @@ -44,7 +42,7 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data if item.title == "Canal" : - data = scrapertools.find_single_match(data,'>Adult Porn Parodies</a></li>(.*?)</ul>') + data = scrapertools.find_single_match(data,'>Best Porn Studios</a>(.*?)</ul>') else: data = scrapertools.find_single_match(data,'<div class="nav-wrap">(.*?)<ul class="sub-menu">') itemlist.append( Item(channel=item.channel, action="lista", title="Big tit", url="https://sexofilm.com/?s=big+tits")) @@ -72,14 +70,17 @@ def lista(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - patron = '<div class="post-thumbnail.*?<a href="([^"]+)".*?src="([^"]+)".*?title="([^"]+)"' + patron = '<article id="post-\d+".*?' + patron += '<a href="([^"]+)".*?' + patron += 'data-src="([^"]+)".*?' + patron += '<h2 class="post-title.*?title="([^"]+)"' matches = re.compile(patron,re.DOTALL).findall(data) for scrapedurl,scrapedthumbnail,scrapedtitle in matches: plot = "" title = scrapedtitle.replace(" Porn DVD", "").replace("Permalink to ", "").replace(" Porn Movie", "") itemlist.append(item.clone(action="play", title=title, url=scrapedurl, thumbnail=scrapedthumbnail, fanart=scrapedthumbnail, plot=plot) ) - next_page = scrapertools.find_single_match(data,'<a class="nextpostslink" rel="next" href="([^"]+)">»</a>') + next_page = scrapertools.find_single_match(data,'<a class="nextpostslink" rel="next" href="([^"]+)">') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) @@ -88,12 +89,14 @@ def lista(item): def play(item): logger.info() + itemlist = [] data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel + url = scrapertools.find_single_match(data,'<div class="entry-inner">.*?<source src="([^"]+)"') + if not url: + url = scrapertools.find_single_match(data,'<div class="entry-inner">.*?<source src=\'([^\']+)\'') + itemlist = servertools.find_video_items(item.clone(url = item.url)) + if url: + itemlist.append(item.clone(action="play", title=url, url=url)) return itemlist + diff --git a/channels/porn/shameless.json b/channels/porn/shameless.json new file mode 100755 index 00000000..f8016a10 --- /dev/null +++ b/channels/porn/shameless.json @@ -0,0 +1,14 @@ +{ + "id": "shameless", + "name": "Shameless", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://www.shameless.com/favicon/apple-touch-icon.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} diff --git a/channels/porn/shameless.py b/channels/porn/shameless.py new file mode 100755 index 00000000..2d7ca4ab --- /dev/null +++ b/channels/porn/shameless.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.shameless.com' + + +def mainlist(item): + logger.info() + itemlist = [] + + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/videos/1/")) + itemlist.append( Item(channel=item.channel, title="Mas popular" , action="lista", url=host + "/videos/popular/week/")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/videos/rated/week/")) + + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/search/?q=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<a href="(https://www.shameless.com/categories/[^"]+)".*?' + patron += '<span itemprop="name">(.*?)</span> <sup>(.*?)</sup>.*?' + patron += 'src="([^"]+)"' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad,scrapedthumbnail in matches: + scrapedplot = "" + title = scrapedtitle + " " + cantidad + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + thumbnail=scrapedthumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<div class="icnt.*?' + patron += '<a href="([^"]+)".*?' + patron += 'data-src="([^"]+)" alt="([^"]+)".*?' + patron += '<div class="bg"></div>([^<]+)</time>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedthumbnail,scrapedtitle,scrapedtime in matches: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + thumbnail = scrapedthumbnail + "|Referer=https://www.shameless.com/" + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, + fanart=thumbnail, thumbnail=thumbnail, plot=plot, contentTitle = scrapedtitle)) + next_page = scrapertools.find_single_match(data, 'class="active">.*?<a href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + patron = '(?:video_url|video_alt_url[0-9]*):\s*\'([^\']+)\'.*?' + patron += '(?:video_url_text|video_alt_url[0-9]*_text):\s*\'([^\']+)\'' + matches = scrapertools.find_multiple_matches(data, patron) + for url, quality in matches: + headers = {'Referer': item.url} + url = httptools.downloadpage(url, headers=headers , follow_redirects=False, only_headers=True).headers.get("location", "") + itemlist.append(["%s %s [directo]" % (quality, url), url]) + return itemlist + + diff --git a/channels/siska.json b/channels/porn/siska.json similarity index 100% rename from channels/siska.json rename to channels/porn/siska.json diff --git a/channels/siska.py b/channels/porn/siska.py similarity index 88% rename from channels/siska.py rename to channels/porn/siska.py index b38151da..2ef0d1a2 100644 --- a/channels/siska.py +++ b/channels/porn/siska.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.siska.tv/' @@ -16,11 +15,11 @@ def mainlist(item): logger.info() itemlist = [] - itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/newVideo.php?language=en")) - itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/MostViewed.php?views=month&language=en")) - itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "/Channel.php?language=en")) + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "newVideo.php?language=en")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "MostViewed.php?views=month&language=en")) + itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "Channel.php?language=en")) - itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/index.php?category=1&language=en")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "index.php?category=1&language=en")) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -28,7 +27,7 @@ def mainlist(item): def search(item, texto): logger.info() texto = texto.replace(" ", "+") - item.url = host + "/search.php?q=%s&language=en&search=Search" % texto + item.url = host + "search.php?q=%s&language=en&search=Search" % texto try: return lista(item) except: diff --git a/channels/sleazemovies.json b/channels/porn/sleazemovies.json similarity index 95% rename from channels/sleazemovies.json rename to channels/porn/sleazemovies.json index 8b387d45..1be75fce 100644 --- a/channels/sleazemovies.json +++ b/channels/porn/sleazemovies.json @@ -9,6 +9,6 @@ "fanart": "https://i.imgur.com/NRdQvFW.jpg", "categories": [ "movie", - "vo" + "vos" ] -} \ No newline at end of file +} diff --git a/channels/sleazemovies.py b/channels/porn/sleazemovies.py similarity index 98% rename from channels/sleazemovies.py rename to channels/porn/sleazemovies.py index a3574ee5..10b81e6f 100644 --- a/channels/sleazemovies.py +++ b/channels/porn/sleazemovies.py @@ -4,7 +4,6 @@ # -*- By Sculkurt -*- import re - from channelselector import get_thumb from core import httptools from core import scrapertools @@ -71,7 +70,7 @@ def search(item, texto): logger.info() if texto != "": texto = texto.replace(" ", "+") - item.url = host + "/?s=" + texto + item.url = host + "?s=" + texto item.extra = "busqueda" try: return list_all(item) diff --git a/channels/spankbang.json b/channels/porn/spankbang.json similarity index 100% rename from channels/spankbang.json rename to channels/porn/spankbang.json diff --git a/channels/spankbang.py b/channels/porn/spankbang.py similarity index 97% rename from channels/spankbang.py rename to channels/porn/spankbang.py index 30834ae0..538eabe8 100644 --- a/channels/spankbang.py +++ b/channels/porn/spankbang.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://es.spankbang.com' diff --git a/channels/spankwire.json b/channels/porn/spankwire.json similarity index 93% rename from channels/spankwire.json rename to channels/porn/spankwire.json index 505547fb..bb80d7a9 100644 --- a/channels/spankwire.json +++ b/channels/porn/spankwire.json @@ -1,7 +1,7 @@ { "id": "spankwire", "name": "spankwire", - "active": false, + "active": true, "adult": true, "language": ["*"], "thumbnail": "https://cdn1-static-spankwire.spankcdn.net/apple-touch-icon-precomposed.png", diff --git a/channels/porn/spankwire.py b/channels/porn/spankwire.py new file mode 100644 index 00000000..bd0856c8 --- /dev/null +++ b/channels/porn/spankwire.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re + +from core import jsontools as json +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.spankwire.com' + +url_api = host + "/api/video/list.json?segment=Straight&limit=33&sortby=" + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevas" , action="lista", url=url_api + "recent&page=1")) + itemlist.append( Item(channel=item.channel, title="Mas Vistas" , action="lista", url=url_api + "views&period=Month&page=1")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=url_api + "rating&period=Month&page=1")) + itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=url_api + "duration&period=Month&page=1")) + itemlist.append( Item(channel=item.channel, title="Pornstar" , action="catalogo", url=host + "/api/pornstars?limit=48&sort=popular&page=1")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/api/categories/list.json?segmentId=0&limit=100&sort=abc&page=1")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/api/video/search.json?segment=Straight&limit=33&query=%s&page=1" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + JSONData = json.load(data) + for Video in JSONData["items"]: + title = Video["name"] + id = Video["id"] + cantidad = Video["videosNumber"] + thumbnail = Video["image"] + title = "%s (%s)" % (title,cantidad) + thumbnail = thumbnail.replace("\/", "/").replace(".webp", ".jpg") + url = url_api + "recent&category=%s&page=1" % id + plot = "" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=url, + fanart=thumbnail, thumbnail=thumbnail, plot=plot) ) + Actual = int(scrapertools.find_single_match(item.url, '&page=([0-9]+)')) + if JSONData["pages"] - 1 > Actual: + scrapedurl = item.url.replace("&page=" + str(Actual), "&page=" + str(Actual + 1)) + itemlist.append(item.clone(action="categorias", title="Página Siguiente >>", text_color="blue", url=scrapedurl)) + return itemlist + + +def catalogo(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + JSONData = json.load(data) + for Video in JSONData["items"]: + title = Video["name"] + id = Video["id"] + cantidad = Video["videos"] + thumbnail = Video["thumb"] + title = "%s (%s)" % (title,cantidad) + thumbnail = thumbnail.replace("\/", "/").replace(".webp", ".jpg") + url = host + "/api/video/list.json?pornstarId=%s&limit=25&sortby=recent&page=1" % id + plot = "" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=url, + fanart=thumbnail, thumbnail=thumbnail, plot=plot) ) + Actual = int(scrapertools.find_single_match(item.url, '&page=([0-9]+)')) + if JSONData["pages"] - 1 > Actual: + scrapedurl = item.url.replace("&page=" + str(Actual), "&page=" + str(Actual + 1)) + itemlist.append(item.clone(action="catalogo", title="Página Siguiente >>", text_color="blue", url=scrapedurl)) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + JSONData = json.load(data) + for Video in JSONData["items"]: + segundos = Video["duration"] + horas=int(segundos/3600) + segundos-=horas*3600 + minutos=int(segundos/60) + segundos-=minutos*60 + if segundos < 10: + segundos = "0%s" %segundos + if minutos < 10: + minutos = "0%s" %minutos + if horas == 00: + duration = "%s:%s" % (minutos,segundos) + else: + duration = "%s:%s:%s" % (horas,minutos,segundos) + title = Video["title"] + thumbnail = Video["flipBookPath"] + url = host + Video["url"] + title = "[COLOR yellow]" + duration + "[/COLOR] " + title + thumbnail = thumbnail.replace("\/", "/").replace("{index}", "2") + url = url.replace("\/", "/") + plot = "" + itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot)) + Actual = int(scrapertools.find_single_match(item.url, '&page=([0-9]+)')) + if JSONData["pages"] - 1 > Actual: + scrapedurl = item.url.replace("&page=" + str(Actual), "&page=" + str(Actual + 1)) + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=scrapedurl)) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + scrapedurl = scrapertools.find_single_match(data,'<div class="shareDownload_container__item__dropdown">.*?<a href="([^"]+)"') + itemlist.append(item.clone(action="play", server = "directo", url=scrapedurl)) + return itemlist + diff --git a/channels/streamingporn.json b/channels/porn/streamingporn.json similarity index 100% rename from channels/streamingporn.json rename to channels/porn/streamingporn.json diff --git a/channels/streamingporn.py b/channels/porn/streamingporn.py similarity index 87% rename from channels/streamingporn.py rename to channels/porn/streamingporn.py index 1c08ca6d..383bedae 100644 --- a/channels/streamingporn.py +++ b/channels/porn/streamingporn.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools -from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://streamingporn.xyz' @@ -90,7 +88,7 @@ def lista(item): contentTitle = title thumbnail = scrapedthumbnail plot = "" - itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, + itemlist.append( Item(channel=item.channel, action="findvideos" , title=title , url=url, thumbnail=thumbnail, fanart=scrapedthumbnail, plot=plot, contentTitle = contentTitle) ) next_page_url = scrapertools.find_single_match(data,'<div class="loadMoreInfinite"><a href="(.*?)" >Load More') if next_page_url!="": @@ -99,15 +97,3 @@ def lista(item): text_color="blue", url=next_page_url) ) return itemlist - -def play(item): - logger.info() - data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - return itemlist - diff --git a/channels/streamporno.json b/channels/porn/streamporno.json similarity index 100% rename from channels/streamporno.json rename to channels/porn/streamporno.json diff --git a/channels/streamporno.py b/channels/porn/streamporno.py similarity index 93% rename from channels/streamporno.py rename to channels/porn/streamporno.py index 853b5d9c..0634b825 100644 --- a/channels/streamporno.py +++ b/channels/porn/streamporno.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://streamporno.eu' @@ -42,7 +41,7 @@ def categorias(item): patron = '<li id="menu-item-.*?<a href="([^"]+)">([^"]+)</a>' if item.title == "Categorias": itemlist.append( Item(channel=item.channel, title="Big Tits" , action="lista", url=host + "/?s=big+tits")) - patron = '<li class="cat-item.*?<a href="([^"]+)" >([^"]+)</a>' + patron = '<li class="cat-item.*?<a href="([^"]+)">([^"]+)</a>' matches = re.compile(patron,re.DOTALL).findall(data) scrapertools.printMatches(matches) for scrapedurl,scrapedtitle in matches: diff --git a/channels/submityouflicks.json b/channels/porn/submityouflicks.json similarity index 56% rename from channels/submityouflicks.json rename to channels/porn/submityouflicks.json index 52fb7bae..42bdf281 100644 --- a/channels/submityouflicks.json +++ b/channels/porn/submityouflicks.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": true, - "enabled": true, - "visible": true - } ] -} \ No newline at end of file +} diff --git a/channels/submityouflicks.py b/channels/porn/submityouflicks.py similarity index 96% rename from channels/submityouflicks.py rename to channels/porn/submityouflicks.py index d4fc0723..4d726fb8 100644 --- a/channels/submityouflicks.py +++ b/channels/porn/submityouflicks.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools from core import scrapertools from core.item import Item from platformcode import logger -from platformcode import config host = 'http://www.submityourflicks.com' @@ -63,7 +61,7 @@ def play(item): data = httptools.downloadpage(item.url).data media_url = "https:" + scrapertools.find_single_match(data, 'source src="([^"]+)"') itemlist = [] - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=media_url, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=media_url, thumbnail=item.thumbnail, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/sunporno.json b/channels/porn/sunporno.json similarity index 100% rename from channels/sunporno.json rename to channels/porn/sunporno.json diff --git a/channels/sunporno.py b/channels/porn/sunporno.py similarity index 94% rename from channels/sunporno.py rename to channels/porn/sunporno.py index 2909bd65..e9a0259f 100644 --- a/channels/sunporno.py +++ b/channels/porn/sunporno.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.sunporno.com' @@ -19,7 +18,7 @@ def mainlist(item): itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/top-rated/date-last-week/")) itemlist.append( Item(channel=item.channel, title="Mas largas" , action="lista", url=host + "/long-movies/date-last-month/")) itemlist.append( Item(channel=item.channel, title="PornStars" , action="catalogo", url=host + "/pornstars/most-viewed/1/")) - itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/channels")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/channels/")) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -42,7 +41,7 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<div class="thumb-container with-title moviec">.*?' + patron = '<div class="thumb-container with-title moviec.*?' patron += '<a href="([^"]+)".*?' patron += 'src="([^"]+)".*?' patron += '<a title="([^"]+)".*?' @@ -113,6 +112,7 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: scrapedurl = scrapedurl.replace("https:", "http:") + scrapedurl += "|Referer=%s" % host itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/porn/sxyprn.json b/channels/porn/sxyprn.json new file mode 100755 index 00000000..55157b53 --- /dev/null +++ b/channels/porn/sxyprn.json @@ -0,0 +1,15 @@ +{ + "id": "sxyprn", + "name": "sxyprn", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://www.sxyprn.com/favicon.ico", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/sxyprn.py b/channels/porn/sxyprn.py new file mode 100755 index 00000000..8f68519b --- /dev/null +++ b/channels/porn/sxyprn.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,re +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.sxyprn.com' + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/blog/all/0.html?fl=all&sm=latest")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=host + "/popular/top-viewed.html")) + itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/popular/top-rated.html")) + itemlist.append( Item(channel=item.channel, title="Sitios" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "-") + item.url = host + "/%s.html" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + if "Sitios" in item.title: + patron = "<a href='([^']+)' target='_blank'><div class='top_sub_el top_sub_el_sc'>.*?" + patron += "<span class='top_sub_el_key_sc'>([^<]+)</span>" + patron += "<span class='top_sub_el_count'>(\d+)</span>" + else: + patron = "<a class='tdn' href='([^']+)'.*?" + patron += "<span class='htag_el_tag'>([^<]+)</span>" + patron += "<span class='htag_el_count'>(\d+) videos</span>" + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedthumbnail = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + title = scrapedtitle + " (" + cantidad + ")" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + thumbnail=scrapedthumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = "<img class=.*?" + patron += " src='([^']+)'.*?" + patron += "<span class='duration_small'.*?'>([^<]+)<.*?" + patron += "<span class='shd_small'.*?>([^<]+)<.*?" + patron += "post_time' href='([^']+)' title='([^']+)'" + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedthumbnail,scrapedtime,quality,scrapedurl,scrapedtitle in matches: + title = "[COLOR yellow]%s[/COLOR] [COLOR red]%s[/COLOR] %s" % (scrapedtime,quality,scrapedtitle) + thumbnail = "https:" + scrapedthumbnail + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + plot = "" + itemlist.append( Item(channel=item.channel, action="findvideos", title=title, url=scrapedurl, + thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle = scrapedtitle)) + # + next_page = scrapertools.find_single_match(data, "<div class='ctrl_el ctrl_sel'>.*?<a href='([^']+)'") + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def findvideos(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + url = scrapertools.find_single_match(data, 'data-vnfo=.*?":"([^"]+)"') + url = url.replace("\/", "/").replace("/cdn/", "/cdn7/") + url = urlparse.urljoin(item.url,url) + itemlist.append( Item(channel=item.channel, action="play", title = "%s " + url, url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + diff --git a/channels/tabooshare.json b/channels/porn/tabooshare.json similarity index 100% rename from channels/tabooshare.json rename to channels/porn/tabooshare.json diff --git a/channels/tabooshare.py b/channels/porn/tabooshare.py similarity index 100% rename from channels/tabooshare.py rename to channels/porn/tabooshare.py diff --git a/channels/thumbzilla.json b/channels/porn/thumbzilla.json similarity index 94% rename from channels/thumbzilla.json rename to channels/porn/thumbzilla.json index bf9e0378..fcce22f8 100644 --- a/channels/thumbzilla.json +++ b/channels/porn/thumbzilla.json @@ -14,7 +14,7 @@ { "id": "modo_grafico", "type": "bool", - "label": "Cerca informazioni extra", + "label": "Buscar información extra", "default": true, "enabled": true, "visible": true diff --git a/channels/thumbzilla.py b/channels/porn/thumbzilla.py similarity index 99% rename from channels/thumbzilla.py rename to channels/porn/thumbzilla.py index e68fa3b5..d0273b3c 100644 --- a/channels/thumbzilla.py +++ b/channels/porn/thumbzilla.py @@ -1,15 +1,15 @@ # -*- coding: utf-8 -*- import re - import urlparse -from channelselector import get_thumb from core import channeltools from core import httptools from core import scrapertools +from core import servertools from core.item import Item from platformcode import config, logger +from channelselector import get_thumb __channel__ = "thumbzilla" diff --git a/channels/porn/titsbox.json b/channels/porn/titsbox.json new file mode 100755 index 00000000..1262153a --- /dev/null +++ b/channels/porn/titsbox.json @@ -0,0 +1,15 @@ +{ + "id": "titsbox", + "name": "titsbox", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://titsbox.com/android-chrome-192x192.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/titsbox.py b/channels/porn/titsbox.py new file mode 100755 index 00000000..d34d1f47 --- /dev/null +++ b/channels/porn/titsbox.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re + +from core import jsontools as json +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://titsbox.com' #titbox vivud zmovs + +url_api = host + "/?ajax=1&type=" + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=url_api + "most-recent&page=1")) + itemlist.append( Item(channel=item.channel, title="Mejor valorados" , action="lista", url=url_api + "top-rated&page=1")) + itemlist.append( Item(channel=item.channel, title="Mas vistos" , action="lista", url=url_api + "long&page=1")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + return itemlist + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = scrapertools.find_single_match(data, '<ul class="sidebar-nav">(.*?)</ul>') + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<a class="category-item" href="([^"]+)">([^"]+)</a>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle in matches: + url = host + scrapedurl + "?ajax=1&type=most-recent&page=1" + scrapedplot = "" + thumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=url, + thumbnail=thumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + JSONData = json.load(data) + for Video in JSONData["data"]: + duration = Video["duration"] + title = Video["videoTitle"] + title = "[COLOR yellow]%s[/COLOR] %s" % (duration,title) + src= Video["src"] + domain="" + thumbnail = src.get('domain', domain) + src.get('pathMedium', domain)+"1.jpg" + url= Video["urls_CDN"] + url= url.get('480', domain) + url = url.replace("/\n/", "/") + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot,)) + Actual = int(scrapertools.find_single_match(item.url, '&page=([0-9]+)')) + if JSONData["pagesLeft"] - 1 > Actual: + scrapedurl = item.url.replace("&page=" + str(Actual), "&page=" + str(Actual + 1)) + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=scrapedurl)) + return itemlist + + +def findvideos(item): + return + diff --git a/channels/tnaflix.json b/channels/porn/tnaflix.json similarity index 100% rename from channels/tnaflix.json rename to channels/porn/tnaflix.json diff --git a/channels/tnaflix.py b/channels/porn/tnaflix.py similarity index 72% rename from channels/tnaflix.py rename to channels/porn/tnaflix.py index 7734b23e..0df37291 100644 --- a/channels/tnaflix.py +++ b/channels/porn/tnaflix.py @@ -1,13 +1,14 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools +from core import tmdb +from core import jsontools host = 'https://www.tnaflix.com' @@ -86,31 +87,52 @@ def peliculas(item): data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) patron = '<a class=\'thumb no_ajax\' href=\'(.*?)\'.*?' - patron += 'data-original=\'(.*?)\' alt="([^"]+)"><div class=\'videoDuration\'>([^<]+)</div>' + patron += 'data-original=\'(.*?)\' alt="([^"]+)"><div class=\'videoDuration\'>([^<]+)</div>(.*?)<div class=\'watchedInfo' matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedthumbnail,scrapedtitle,duracion in matches: + for scrapedurl,scrapedthumbnail,scrapedtitle,duracion,quality in matches: url = urlparse.urljoin(item.url,scrapedurl) title = "[COLOR yellow]" + duracion + "[/COLOR] " + scrapedtitle + if quality: + quality= scrapertools.find_single_match(quality, '>(\d+p)<') + title = "[COLOR yellow]" + duracion + "[/COLOR] " + "[COLOR red]" + quality + "[/COLOR] " + scrapedtitle contentTitle = title thumbnail = scrapedthumbnail plot = "" - year = "" - itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, plot=plot, contentTitle = contentTitle, infoLabels={'year':year} )) + itemlist.append(Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot, contentTitle = contentTitle)) next_page_url = scrapertools.find_single_match(data,'<a class="llNav" href="([^"]+)">') if next_page_url!="": next_page_url = urlparse.urljoin(item.url,next_page_url) - itemlist.append( Item(channel=item.channel , action="peliculas" , title="Página Siguiente >>" , text_color="blue", url=next_page_url , folder=True) ) + itemlist.append(item.clone(action="peliculas", title="Página Siguiente >>", text_color="blue", url=next_page_url) ) return itemlist +def ref(url): + logger.info() + itemlist = [] + data = httptools.downloadpage(url).data + VID = scrapertools.find_single_match(data,'id="VID" type="hidden" value="([^"]+)"') + vkey = scrapertools.find_single_match(data,'id="vkey" type="hidden" value="([^"]+)"') + thumb = scrapertools.find_single_match(data,'id="thumb" type="hidden" value="([^"]+)"') + nkey= scrapertools.find_single_match(data,'id="nkey" type="hidden" value="([^"]+)"') + url = "https://cdn-fck.tnaflix.com/tnaflix/%s.fid?key=%s&VID=%s&nomp4=1&catID=0&rollover=1&startThumb=%s" % (vkey, nkey, VID, thumb) + url += "&embed=0&utm_source=0&multiview=0&premium=1&country=0user=0&vip=1&cd=0&ref=0&alpha" + return url + + def play(item): logger.info() itemlist = [] - data = httptools.downloadpage(item.url).data - patron = '<meta itemprop="contentUrl" content="([^"]+)" />' + url= ref(item.url) + headers = {'Referer': item.url} + data = httptools.downloadpage(url, headers=headers).data + patron = '<res>(.*?)</res>.*?' + patron += '<videoLink><([^<]+)></videoLink>' matches = scrapertools.find_multiple_matches(data, patron) - for url in matches: - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=url, - thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) + for title, url in matches: + url= url.replace("![CDATA[", "http:").replace("]]", "") + itemlist.append(["%s %s [directo]" % (title, url), url]) + itemlist.reverse() return itemlist + diff --git a/channels/tryboobs.json b/channels/porn/tryboobs.json similarity index 100% rename from channels/tryboobs.json rename to channels/porn/tryboobs.json diff --git a/channels/tryboobs.py b/channels/porn/tryboobs.py similarity index 95% rename from channels/tryboobs.py rename to channels/porn/tryboobs.py index fa2108f2..333751d3 100644 --- a/channels/tryboobs.py +++ b/channels/porn/tryboobs.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://www.tryboobs.com' @@ -90,7 +89,8 @@ def play(item): patron = '<video src="([^"]+)"' matches = scrapertools.find_multiple_matches(data, patron) for url in matches: - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=url, + url += "|Referer=%s" % host + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=url, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/tubedupe.json b/channels/porn/tubedupe.json similarity index 100% rename from channels/tubedupe.json rename to channels/porn/tubedupe.json diff --git a/channels/tubedupe.py b/channels/porn/tubedupe.py similarity index 95% rename from channels/tubedupe.py rename to channels/porn/tubedupe.py index 44d90216..0897c8bb 100644 --- a/channels/tubedupe.py +++ b/channels/porn/tubedupe.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://tubedupe.com' @@ -20,7 +19,7 @@ def mainlist(item): itemlist.append( Item(channel=item.channel, title="Modelos" , action="categorias", url=host + "/models/?sort_by=model_viewed")) itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "/channels/?sort_by=cs_viewed")) itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/?sort_by=avg_videos_popularity")) - itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + # itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -100,7 +99,7 @@ def play(item): if scrapedurl == "" : scrapedurl = scrapertools.find_single_match(data, 'video_url: \'([^\']+)\'') - itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, fulltitle=item.title, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=scrapedurl, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/tubehentai.json b/channels/porn/tubehentai.json similarity index 51% rename from channels/tubehentai.json rename to channels/porn/tubehentai.json index 73b93b72..57321cbf 100644 --- a/channels/tubehentai.json +++ b/channels/porn/tubehentai.json @@ -10,13 +10,5 @@ "adult" ], "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Incluir en busqueda global", - "default": false, - "enabled": true, - "visible": true - } ] } \ No newline at end of file diff --git a/channels/porn/tubehentai.py b/channels/porn/tubehentai.py new file mode 100644 index 00000000..6352c943 --- /dev/null +++ b/channels/porn/tubehentai.py @@ -0,0 +1,65 @@ +# -*- coding: utf-8 -*- + +import re +import urlparse + +from core import httptools +from core import scrapertools +from core.item import Item +from platformcode import logger + +host = 'http://tubehentai.com' + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append(Item(channel=item.channel, title="Novedades", action="lista", url=host + "/most-recent/")) + itemlist.append(Item(channel=item.channel, title="Mas visto", action="lista", url=host + "/most-viewed/")) + itemlist.append(Item(channel=item.channel, title="Mejor valorado", action="lista", url=host + "/top-rated/")) + + itemlist.append(Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "%20") + item.url = host + "/search/%s/" % texto + try: + return lista(item) + # Se captura la excepciÛn, para no interrumpir al buscador global si un canal falla + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + patron = '<a href="((?:http|https)://tubehentai.com/video/[^"]+)" title="([^"]+)".*?' + patron += '<span class="icon -time">.*?<span class="item__stat-label">([^<]+)</span>.*?' + patron += '<img src="([^"]+)"' + matches = re.compile(patron, re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,duration,scrapedthumbnail in matches: + title = "[COLOR yellow]" + duration + "[/COLOR] " + scrapedtitle + itemlist.append(Item(channel=item.channel, action="play", title=title, url=scrapedurl, + fanart=scrapedthumbnail, thumbnail=scrapedthumbnail)) + next_page = scrapertools.find_single_match(data,'<a rel=\'next\' title=\'Next\' href=\'([^\']+)\'') + if next_page!="": + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + url = scrapertools.find_single_match(data, '<source src="([^"]+\.mp4)"') + server = "Directo" + itemlist.append(Item(channel=item.channel, title="", url=url, server=server, folder=False)) + return itemlist + diff --git a/channels/videosXYZ.json b/channels/porn/videosXYZ.json similarity index 100% rename from channels/videosXYZ.json rename to channels/porn/videosXYZ.json diff --git a/channels/videosXYZ.py b/channels/porn/videosXYZ.py similarity index 95% rename from channels/videosXYZ.py rename to channels/porn/videosXYZ.py index ba26f46b..6f645dcf 100644 --- a/channels/videosXYZ.py +++ b/channels/porn/videosXYZ.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://free-porn-videos.xyz' @@ -64,7 +62,6 @@ def play(item): itemlist = servertools.find_video_items(data=data) for videoitem in itemlist: videoitem.title = item.title - videoitem.fulltitle = item.fulltitle videoitem.thumbnail = item.thumbnail videoitem.channel = item.channel return itemlist diff --git a/channels/vidz7.json b/channels/porn/vidz7.json similarity index 100% rename from channels/vidz7.json rename to channels/porn/vidz7.json diff --git a/channels/vidz7.py b/channels/porn/vidz7.py similarity index 92% rename from channels/vidz7.py rename to channels/porn/vidz7.py index 5f3cbdbc..de2cb712 100644 --- a/channels/vidz7.py +++ b/channels/porn/vidz7.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- import re - import urlparse from core import httptools @@ -9,7 +8,6 @@ from core import scrapertools from core import servertools from core.item import Item from platformcode import logger -from platformcode import config host = 'http://www.vidz7.com' @@ -19,7 +17,7 @@ def mainlist(item): itemlist = [] itemlist.append(Item(channel=item.channel, action="lista", title="Útimos videos", url=host)) itemlist.append( - Item(channel=item.channel, action="categorias", title="Categorias", url=host + "/category/")) + Item(channel=item.channel, action="categorias", title="Canal", url=host + "/category/")) itemlist.append(Item(channel=item.channel, action="search", title="Buscar", url="http://www.vidz7.com")) return itemlist @@ -44,10 +42,11 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t|\s{2}", "", data) - patron = '<li><a href="([^"]+)">(.*?)</a>' + patron = '<li><a href="([^"]+)">([^<]+)</a><span>(\d+) </' matches = re.compile(patron, re.DOTALL).findall(data) - for url, actriz in matches: - itemlist.append(Item(channel=item.channel, action="lista", title=actriz, url=url)) + for url, title, cantidad in matches: + title = title + " (" + cantidad + ")" + itemlist.append(Item(channel=item.channel, action="lista", title=title, url=url)) return itemlist @@ -70,7 +69,7 @@ def lista(item): title = "[COLOR yellow]" + duration + "[/COLOR] " + "[COLOR red]" +scrapedhd+ "[/COLOR] "+scrapedtitle # Añade al listado itemlist.append(Item(channel=item.channel, action="play", title=title, thumbnail=thumbnail, fanart=thumbnail, - fulltitle=title, url=url, + contentTitle=title, url=url, viewmode="movie", folder=True)) paginacion = scrapertools.find_single_match(data,'<a class="active".*?.>\d+</a><a class="inactive" href ="([^"]+)">') if paginacion: diff --git a/channels/vintagetube.json b/channels/porn/vintagetube.json similarity index 100% rename from channels/vintagetube.json rename to channels/porn/vintagetube.json diff --git a/channels/vintagetube.py b/channels/porn/vintagetube.py similarity index 96% rename from channels/vintagetube.py rename to channels/porn/vintagetube.py index c3831dcd..fafe7f37 100644 --- a/channels/vintagetube.py +++ b/channels/porn/vintagetube.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://www.vintagetube.club' @@ -93,7 +92,7 @@ def play(item): data = httptools.downloadpage("https:" + scrapedurl).data scrapedurl = scrapertools.find_single_match(data,'<source src="([^"]+)"') itemlist = [] - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.title, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/vintagexxxsex.json b/channels/porn/vintagexxxsex.json similarity index 100% rename from channels/vintagexxxsex.json rename to channels/porn/vintagexxxsex.json diff --git a/channels/vintagexxxsex.py b/channels/porn/vintagexxxsex.py similarity index 96% rename from channels/vintagexxxsex.py rename to channels/porn/vintagexxxsex.py index d905d842..b7afa813 100644 --- a/channels/vintagexxxsex.py +++ b/channels/porn/vintagexxxsex.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://www.vintagexxxsex.com' @@ -90,7 +89,7 @@ def play(item): scrapedurl = "http:" + scrapertools.find_single_match(data,'<iframe src="([^"]+)"') data = httptools.downloadpage(scrapedurl).data scrapedurl = scrapertools.find_single_match(data,'file: "([^"]+)"') - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=scrapedurl, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=scrapedurl, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/porn/vivud.json b/channels/porn/vivud.json new file mode 100755 index 00000000..7b70e238 --- /dev/null +++ b/channels/porn/vivud.json @@ -0,0 +1,15 @@ +{ + "id": "vivud", + "name": "vivud", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "https://vivud.com/favicon-96x96.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/vivud.py b/channels/porn/vivud.py new file mode 100755 index 00000000..02d6b015 --- /dev/null +++ b/channels/porn/vivud.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re + +from core import jsontools as json +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://vivud.com' #titbox vivud zmovs + +url_api = host + "/?ajax=1&type=" + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=url_api + "most-recent&page=1")) + itemlist.append( Item(channel=item.channel, title="Mejor valorados" , action="lista", url=url_api + "top-rated&page=1")) + itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=url_api + "long&page=1")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + return itemlist + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = scrapertools.find_single_match(data, '<ul class="sidebar-nav">(.*?)</ul>') + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<a class="category-item" href="([^"]+)">([^"]+)</a>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle in matches: + url = host + scrapedurl + "?ajax=1&type=most-recent&page=1" + scrapedplot = "" + thumbnail = "" + itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=url, + thumbnail=thumbnail , plot=scrapedplot) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + JSONData = json.load(data) + for Video in JSONData["data"]: + duration = Video["duration"] + title = Video["videoTitle"] + title = "[COLOR yellow]%s[/COLOR] %s" % (duration,title) + src= Video["src"] + domain="" + thumbnail = src.get('domain', domain) + src.get('pathMedium', domain)+"1.jpg" + url= Video["urls_CDN"] + url= url.get('480', domain) + url = url.replace("/\n/", "/") + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot,)) + Actual = int(scrapertools.find_single_match(item.url, '&page=([0-9]+)')) + if JSONData["pagesLeft"] - 1 > Actual: + scrapedurl = item.url.replace("&page=" + str(Actual), "&page=" + str(Actual + 1)) + itemlist.append(item.clone(action="lista", title="Página Siguiente >>", text_color="blue", url=scrapedurl)) + return itemlist + + +def findvideos(item): + return + diff --git a/channels/vporn.json b/channels/porn/vporn.json similarity index 69% rename from channels/vporn.json rename to channels/porn/vporn.json index a6579d50..d33ff5f9 100644 --- a/channels/vporn.json +++ b/channels/porn/vporn.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "https://th-us2.vporn.com/images/logo%20Dark%20theme.png", + "thumbnail": "https://th-eu1.vporn.com/images/logo-dark-theme.png", "banner": "", "categories": [ "adult" diff --git a/channels/vporn.py b/channels/porn/vporn.py similarity index 88% rename from channels/vporn.py rename to channels/porn/vporn.py index 25344cb9..65727102 100644 --- a/channels/vporn.py +++ b/channels/porn/vporn.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from core import jsontools as json from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'https://www.vporn.com' @@ -22,7 +22,7 @@ def mainlist(item): itemlist.append( Item(channel=item.channel, title="Mas Votada" , action="lista", url=host + "/votes/month/")) itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=host + "/longest/month/")) itemlist.append( Item(channel=item.channel, title="PornStar" , action="catalogo", url=host + "/pornstars/")) - itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/")) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -46,7 +46,7 @@ def catalogo(item): data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) patron = '<div class=\'star\'>.*?' - patron += '<a href="([^"]+)">.*?' + patron += '<a href="([^"]+)".*?' patron += '<img src="([^"]+)" alt="([^"]+)".*?' patron += '<span> (\d+) Videos' matches = re.compile(patron,re.DOTALL).findall(data) @@ -68,13 +68,16 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - data = scrapertools.find_single_match(data,'<div class="cats-all categories-list">(.*?)</div>') - patron = '<a href="([^"]+)".*?>([^"]+)</a>' + patron = '"name":"([^"]+)".*?' + patron += '"image":"([^"]+)".*?' + patron += '"url":"([^"]+)"' matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedtitle in matches: + for scrapedtitle,scrapedthumbnail,scrapedurl in matches: scrapedplot = "" - scrapedthumbnail = "" + scrapedthumbnail = "https://th-us2.vporn.com" + scrapedthumbnail + scrapedthumbnail= scrapedthumbnail.replace("\/", "/") scrapedurl = host + scrapedurl + scrapedurl = scrapedurl.replace("\/", "/") itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, plot=scrapedplot) ) return itemlist @@ -113,6 +116,6 @@ def play(item): patron = '<source src="([^"]+)" type="video/mp4" label="([^"]+)"' matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl,scrapedtitle in matches: - itemlist.append(item.clone(action="play", title=scrapedtitle, fulltitle = item.title, url=scrapedurl)) + itemlist.append(item.clone(action="play", title=scrapedtitle, url=scrapedurl)) return itemlist diff --git a/channels/watchpornfree.json b/channels/porn/watchpornfree.json similarity index 68% rename from channels/watchpornfree.json rename to channels/porn/watchpornfree.json index c6ad57a7..f5f9b0a9 100644 --- a/channels/watchpornfree.json +++ b/channels/porn/watchpornfree.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "https://watchpornfree.ws/wp-content/uploads/2018/03/Untitled-2.png", + "thumbnail": "https://watchpornfree.info/wp-content/uploads/2019/01/favicon.ico", "banner": "", "categories": [ "adult" diff --git a/channels/watchpornfree.py b/channels/porn/watchpornfree.py similarity index 81% rename from channels/watchpornfree.py rename to channels/porn/watchpornfree.py index d2709d5f..73d14f7f 100644 --- a/channels/watchpornfree.py +++ b/channels/porn/watchpornfree.py @@ -1,24 +1,23 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools # https://playpornfree.org/ https://mangoporn.net/ https://watchfreexxx.net/ https://losporn.org/ https://xxxstreams.me/ https://speedporn.net/ -host = 'https://watchpornfree.ws' +host = 'https://watchpornfree.info' def mainlist(item): logger.info("") itemlist = [] itemlist.append( Item(channel=item.channel, title="Videos" , action="lista", url=host + "/category/clips-scenes")) - itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/movies")) - itemlist.append( Item(channel=item.channel, title="Parodia" , action="lista", url=host + "/category/parodies-hd")) + itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host)) + itemlist.append( Item(channel=item.channel, title="Parodia" , action="lista", url=host + "/category/parodies")) itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Año" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) @@ -43,17 +42,18 @@ def categorias(item): logger.info("") itemlist = [] data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) if item.title == "Canal": - data = scrapertools.find_single_match(data,'>Studios</a>(.*?)</ul>') + data = scrapertools.find_single_match(data,'Scenes</a></li>(.*?)</ul>') if item.title == "Año": - data = scrapertools.find_single_match(data,'>Years</a>(.*?)</ul>') + data = scrapertools.find_single_match(data,'Year</a>(.*?)</ul>') if item.title == "Categorias": - data = scrapertools.find_single_match(data,'>XXX Genres</div>(.*?)</ul>') - patron = '<a href="([^"]+)".*?>([^"]+)</a>(.*?)</li>' + data = scrapertools.find_single_match(data,'>Categories</div>(.*?)</ul>') + patron = '<a href="([^"]+)".*?>([^"]+)</a></li>' matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedtitle,cantidad in matches: + for scrapedurl,scrapedtitle in matches: scrapedplot = "" - scrapedtitle = scrapedtitle + cantidad + scrapedtitle = scrapedtitle scrapedthumbnail = "" itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, plot=scrapedplot) ) diff --git a/channels/webpeliculasporno.json b/channels/porn/webpeliculasporno.json similarity index 100% rename from channels/webpeliculasporno.json rename to channels/porn/webpeliculasporno.json diff --git a/channels/webpeliculasporno.py b/channels/porn/webpeliculasporno.py similarity index 100% rename from channels/webpeliculasporno.py rename to channels/porn/webpeliculasporno.py diff --git a/channels/woodrocket.json b/channels/porn/woodrocket.json similarity index 100% rename from channels/woodrocket.json rename to channels/porn/woodrocket.json diff --git a/channels/woodrocket.py b/channels/porn/woodrocket.py similarity index 80% rename from channels/woodrocket.py rename to channels/porn/woodrocket.py index 494c269a..f24640e4 100644 --- a/channels/woodrocket.py +++ b/channels/porn/woodrocket.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://woodrocket.com' @@ -62,12 +61,8 @@ def play(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - scrapedurl = scrapertools.find_single_match(data,'<iframe src="(.*?)"') - scrapedurl = scrapedurl.replace("pornhub.com/embed/", "pornhub.com/view_video.php?viewkey=") - data = httptools.downloadpage(scrapedurl).data - scrapedurl = scrapertools.find_single_match(data,'"defaultQuality":true,"format":"mp4","quality":"\d+","videoUrl":"([^"]+)"') - scrapedurl = scrapedurl.replace("\/", "/") - itemlist.append(item.clone(action="play", title=scrapedurl, fulltitle = item.title, url=scrapedurl)) + url = scrapertools.find_single_match(data,'<iframe src="([^"]+)"') + itemlist.append(item.clone(action="play", title= "%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist - diff --git a/channels/x18hentai.json b/channels/porn/x18hentai.json similarity index 100% rename from channels/x18hentai.json rename to channels/porn/x18hentai.json diff --git a/channels/x18hentai.py b/channels/porn/x18hentai.py similarity index 100% rename from channels/x18hentai.py rename to channels/porn/x18hentai.py diff --git a/channels/xhamster.json b/channels/porn/xhamster.json similarity index 100% rename from channels/xhamster.json rename to channels/porn/xhamster.json diff --git a/channels/xhamster.py b/channels/porn/xhamster.py similarity index 94% rename from channels/xhamster.py rename to channels/porn/xhamster.py index 564fb28f..c9020a97 100644 --- a/channels/xhamster.py +++ b/channels/porn/xhamster.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- import re - +import sys import urlparse +from platformcode import logger from core import scrapertools, httptools from core.item import Item -from platformcode import logger -from platformcode import config HOST = "http://es.xhamster.com/" @@ -63,9 +62,9 @@ def videos(item): for scrapedurl, scrapedthumbnail, scrapedtitle, duration in matches: # logger.debug("title=["+scrapedtitle+"], url=["+scrapedurl+"], thumbnail=["+scrapedthumbnail+"]") - fullTitle = scrapedtitle.strip() + " [" + duration + "]" + contentTitle = scrapedtitle.strip() + " [" + duration + "]" itemlist.append( - Item(channel=item.channel, action="play", title=fullTitle, url=scrapedurl, thumbnail=scrapedthumbnail, + Item(channel=item.channel, action="play", title=contentTitle, url=scrapedurl, thumbnail=scrapedthumbnail, folder=True)) # Paginador @@ -93,8 +92,8 @@ def categorias(item): patron = '(?s)<li>.*?<a href="([^"]+)".*?>([^<]+).*?</a></li>' matches = re.compile(patron, re.DOTALL).findall(data) for scrapedurl, scrapedtitle in matches: - fullTitle = scrapedtitle.strip() - itemlist.append(Item(channel=item.channel, action="videos", title=fullTitle, url=scrapedurl)) + contentTitle = scrapedtitle.strip() + itemlist.append(Item(channel=item.channel, action="videos", title=contentTitle, url=scrapedurl)) return itemlist diff --git a/channels/xms.json b/channels/porn/xms.json similarity index 94% rename from channels/xms.json rename to channels/porn/xms.json index 4c3088f3..64e505cd 100644 --- a/channels/xms.json +++ b/channels/porn/xms.json @@ -14,7 +14,7 @@ { "id": "modo_grafico", "type": "bool", - "label": "Cerca informazioni extra", + "label": "Buscar información extra", "default": true, "enabled": true, "visible": true diff --git a/channels/xms.py b/channels/porn/xms.py similarity index 82% rename from channels/xms.py rename to channels/porn/xms.py index 969aae7e..7fa51198 100644 --- a/channels/xms.py +++ b/channels/porn/xms.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- import re - import urlparse +import base64 from core import channeltools from core import httptools @@ -13,7 +13,7 @@ from platformcode import config, logger __channel__ = "xms" -host = 'https://xtheatre.org' +host = 'https://xtheatre.org/' host1 = 'https://www.cam4.com/' try: __modo_grafico__ = config.get_setting('modo_grafico', __channel__) @@ -45,20 +45,20 @@ def mainlist(item): logger.info() itemlist = [] - itemlist.append(Item(channel=__channel__, title="Últimas", url=host + '/?filtre=date&cat=0', + itemlist.append(Item(channel=__channel__, title="Últimas", url=host + '?filtre=date&cat=0', action="peliculas", viewmode="movie_with_plot", viewcontent='movies', thumbnail=thumbnail % '1')) - itemlist.append(Item(channel=__channel__, title="Más Vistas", url=host + '/?display=extract&filtre=views', + itemlist.append(Item(channel=__channel__, title="Más Vistas", url=host + '?display=extract&filtre=views', action="peliculas", viewmode="movie_with_plot", viewcontent='movies', thumbnail=thumbnail % '2')) - itemlist.append(Item(channel=__channel__, title="Mejor Valoradas", url=host + '/?display=extract&filtre=rate', + itemlist.append(Item(channel=__channel__, title="Mejor Valoradas", url=host + '?display=extract&filtre=rate', action="peliculas", viewmode="movie_with_plot", viewcontent='movies', thumbnail=thumbnail % '3')) itemlist.append(Item(channel=__channel__, title="Categorías", action="categorias", - url=host + '/categories/', viewmode="movie_with_plot", viewcontent='movies', + url=host + 'categories/', viewmode="movie_with_plot", viewcontent='movies', thumbnail=thumbnail % '4')) itemlist.append(Item(channel=__channel__, title="WebCam", action="webcamenu", @@ -99,7 +99,7 @@ def peliculas(item): for scrapedthumbnail, scrapedurl, scrapedtitle, plot in matches: plot = scrapertools.decodeHtmlentities(plot) - itemlist.append(item.clone(channel=__channel__, action="findvideos", title=scrapedtitle.capitalize(), + itemlist.append(item.clone(channel=__channel__, action="play", title=scrapedtitle.capitalize(), url=scrapedurl, thumbnail=scrapedthumbnail, infoLabels={"plot": plot}, fanart=scrapedthumbnail,viewmode="movie_with_plot", folder=True, contentTitle=scrapedtitle)) @@ -150,10 +150,10 @@ def categorias(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = 'data-lazy-src="([^"]+)".*?' # img - patron += '</noscript><a href="([^"]+)".*?' # url - patron += '<span>([^<]+)</span></a>.*?' # title - patron += '<span class="nb_cat border-radius-5">([^<]+)</span>' # num_vids + patron = 'data-lazy-src="([^"]+)".*?' + patron += '<a href="([^"]+)".*?' + patron += '<span>([^<]+)</span></a>.*?' + patron += '<span class="nb_cat border-radius-5">([^<]+)</span>' matches = re.compile(patron, re.DOTALL).findall(data) for scrapedthumbnail, scrapedurl, scrapedtitle, vids in matches: @@ -196,7 +196,7 @@ def sub_search(item): for scrapedthumbnail, scrapedtitle, scrapedurl, plot in matches: itemlist.append(item.clone(title=scrapedtitle, url=scrapedurl, plot=plot, fanart=scrapedthumbnail, - action="findvideos", thumbnail=scrapedthumbnail)) + action="play", thumbnail=scrapedthumbnail)) paginacion = scrapertools.find_single_match( data, "<a href='([^']+)' class=\"inactive\">\d+</a>") @@ -208,17 +208,39 @@ def sub_search(item): return itemlist -def findvideos(item): +def play(item): itemlist = [] - data = httptools.downloadpage(item.url).data - data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) - patron = '<iframe src="[^"]+".*?<iframe src="([^"]+)" scrolling="no" frameborder="0"' - matches = scrapertools.find_multiple_matches(data, patron) - - for url in matches: - server = servertools.get_server_from_url(url) - title = "Ver en: [COLOR yellow](%s)[/COLOR]" % server.title() - - itemlist.append(item.clone(action='play', title=title, server=server, url=url)) - + if "playlist.m3u8" in item.url: + url = item.url + else: + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = 'src="([^"]+)" allowfullscreen="true">' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + if "strdef" in url: + url = decode_url(url) + if "strdef" in url: + url = httptools.downloadpage(url).url + itemlist.append(item.clone(action="play", title= "%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist + + +def decode_url(txt): + logger.info() + itemlist = [] + data = httptools.downloadpage(txt).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + rep = True + while rep == True: + b64_data = scrapertools.find_single_match(data, '\(dhYas638H\("([^"]+)"\)') + if b64_data: + b64_url = base64.b64decode(b64_data + "=") + b64_url = base64.b64decode(b64_url + "==") + data = b64_url + else: + rep = False + url = scrapertools.find_single_match(b64_url, '<iframe src="([^"]+)"') + logger.debug (url) + return url \ No newline at end of file diff --git a/channels/xozilla.json b/channels/porn/xozilla.json similarity index 100% rename from channels/xozilla.json rename to channels/porn/xozilla.json diff --git a/channels/xozilla.py b/channels/porn/xozilla.py similarity index 95% rename from channels/xozilla.py rename to channels/porn/xozilla.py index 566c8b43..4b0b3d46 100644 --- a/channels/xozilla.py +++ b/channels/porn/xozilla.py @@ -1,14 +1,17 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -import re - import urlparse +import urllib2 +import urllib +import re +import os +import sys -from core import httptools +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.xozilla.com' @@ -56,6 +59,8 @@ def categorias(item): scrapedtitle += " (" + cantidad + ")" itemlist.append(Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, fanart=scrapedthumbnail, plot=scrapedplot)) + if "Categorias" in item.title: + itemlist.sort(key=lambda x: x.title) next_page = scrapertools.find_single_match(data, '<li class="next"><a href="([^"]+)"') if next_page != "#videos": next_page = urlparse.urljoin(item.url, next_page) @@ -104,6 +109,6 @@ def play(item): media_url = scrapertools.find_single_match(data, 'video_alt_url: \'([^\']+)/\'') if media_url == "": media_url = scrapertools.find_single_match(data, 'video_url: \'([^\']+)/\'') - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=media_url, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=media_url, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/xtapes.json b/channels/porn/xtapes.json similarity index 92% rename from channels/xtapes.json rename to channels/porn/xtapes.json index 9a1cc2fa..017437cb 100644 --- a/channels/xtapes.json +++ b/channels/porn/xtapes.json @@ -1,7 +1,7 @@ { "id": "xtapes", "name": "xtapes", - "active": true, + "active": false, "adult": true, "language": ["*"], "thumbnail": "http://hd.xtapes.to/wp-content/uploads/xtapes.png", diff --git a/channels/xtapes.py b/channels/porn/xtapes.py similarity index 76% rename from channels/xtapes.py rename to channels/porn/xtapes.py index 13c4f297..4bb3548b 100644 --- a/channels/xtapes.py +++ b/channels/porn/xtapes.py @@ -1,21 +1,21 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools -from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://hd.xtapes.to' +# Links NetuTV + def mainlist(item): logger.info() itemlist = [] - itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/full-porn-movies/?display=tube&filtre=date")) + itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/hd-porn-movies/")) itemlist.append( Item(channel=item.channel, title="Productora" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host + "/?filtre=date&cat=0")) itemlist.append( Item(channel=item.channel, title="Mas Vistos" , action="lista", url=host + "/?display=tube&filtre=views")) @@ -48,7 +48,7 @@ def categorias(item): if item.title=="Canal": data = scrapertools.find_single_match(data,'<div class="footer-banner">(.*?)<div id="footer-copyright">') if item.title=="Productora" : - data = scrapertools.find_single_match(data,'<li id="menu-item-16"(.*?)</ul>') + data = scrapertools.find_single_match(data,'>Full Movies</a>(.*?)</ul>') if item.title=="Categorias" : data = scrapertools.find_single_match(data,'<a>Categories</a>(.*?)</ul>') patron = '<a href="([^"]+)">([^"]+)</a>' @@ -79,8 +79,8 @@ def lista(item): contentTitle = title thumbnail = scrapedthumbnail plot = "" - itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, - fanart=thumbnail, plot=plot, fulltitle = title, contentTitle = contentTitle)) + itemlist.append( Item(channel=item.channel, action="findvideos" , title=title , url=url, thumbnail=thumbnail, + fanart=thumbnail, plot=plot, contentTitle = contentTitle)) next_page = scrapertools.find_single_match(data,'<a class="next page-numbers" href="([^"]+)">Next video') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) @@ -90,19 +90,3 @@ def lista(item): return itemlist -def play(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - variable = scrapertools.find_single_match(data,'<script type=\'text/javascript\'> str=\'([^\']+)\'') - resuelta = re.sub("@[A-F0-9][A-F0-9]", lambda m: m.group()[1:].decode('hex'), variable) - url = scrapertools.find_single_match(resuelta,'<iframe src="([^"]+)"') - data = httptools.downloadpage(item.url).data - itemlist = servertools.find_video_items(data=data) - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - return itemlist - diff --git a/channels/porn/xvideos.json b/channels/porn/xvideos.json new file mode 100755 index 00000000..ddcc89d5 --- /dev/null +++ b/channels/porn/xvideos.json @@ -0,0 +1,15 @@ +{ + "id": "xvideos", + "name": "xvideos", + "active": true, + "adult": true, + "language": ["*"], + "thumbnail": "xvideos.png", + "banner": "", + "categories": [ + "adult" + ], + "settings": [ + ] +} + diff --git a/channels/porn/xvideos.py b/channels/porn/xvideos.py new file mode 100755 index 00000000..6c66b18c --- /dev/null +++ b/channels/porn/xvideos.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +#------------------------------------------------------------ +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger +from core import scrapertools +from core.item import Item +from core import servertools +from core import httptools + +host = 'https://www.xvideos.com' + + +def mainlist(item): + logger.info() + itemlist = [] + itemlist.append( Item(channel=item.channel, title="Nuevos" , action="lista", url=host)) + itemlist.append( Item(channel=item.channel, title="Lo mejor" , action="lista", url=host + "/best/")) + itemlist.append( Item(channel=item.channel, title="Pornstar" , action="catalogo", url=host + "/pornstars-index")) + itemlist.append( Item(channel=item.channel, title="WebCAM" , action="catalogo", url=host + "/webcam-models-index")) + itemlist.append( Item(channel=item.channel, title="Canal" , action="catalogo", url=host + "/channels-index/top")) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/tags")) + itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) + return itemlist + + +def search(item, texto): + logger.info() + texto = texto.replace(" ", "+") + item.url = host + "/?k=%s" % texto + try: + return lista(item) + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def categorias(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<li><a href="([^"]+)"><b>([^<]+)</b><span class="navbadge default">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedthumbnail = "" + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + title = scrapedtitle + " (" + cantidad + ")" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + thumbnail=scrapedthumbnail , plot=scrapedplot) ) + return itemlist + + +def catalogo(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<img src="([^"]+)".*?' + patron += '<p class="profile-name">.*?<a href="([^"]+)">([^<]+)</a>.*?' + patron += '<span class="with-sub">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedthumbnail,scrapedurl,scrapedtitle,cantidad in matches: + scrapedplot = "" + scrapedurl = urlparse.urljoin(host,scrapedurl) + "/videos/new/0" + title = scrapedtitle + " (" + cantidad + ")" + itemlist.append( Item(channel=item.channel, action="lista", title=title, url=scrapedurl, + thumbnail=scrapedthumbnail , plot=scrapedplot) ) + next_page = scrapertools.find_single_match(data, '<li><a href="([^"]+)" class="no-page next-page">Siguiente') + if next_page=="": + next_page = scrapertools.find_single_match(data, '<li><a class="active".*?<a href="([^"]+)"') + if next_page: + next_page = urlparse.urljoin(item.url,next_page) + itemlist.append( Item(channel=item.channel, action="catalogo", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def lista(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>|<br/>", "", data) + patron = '<div id="video_\d+".*?' + patron += 'data-src="([^"]+)".*?' + patron += '</a>(.*?)<div class=.*?' + patron += '<a href="([^"]+)" title="([^"]+)".*?' + patron += '<span class="duration">([^<]+)</span>' + matches = re.compile(patron,re.DOTALL).findall(data) + for scrapedthumbnail,quality,scrapedurl,scrapedtitle,scrapedtime in matches: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + scrapedtitle + scrapedurl = urlparse.urljoin(item.url,scrapedurl) + thumbnail = scrapedthumbnail.replace("THUMBNUM" , "10") + quality = scrapertools.find_single_match(quality, 'mark">([^<]+)</span>') + if quality: + title = "[COLOR yellow]" + scrapedtime + "[/COLOR] " + "[COLOR red]" + quality + "[/COLOR] " + scrapedtitle + plot = "" + itemlist.append( Item(channel=item.channel, action="play", title=title, url=scrapedurl, + thumbnail=thumbnail, fanart=thumbnail, plot=plot, contentTitle = scrapedtitle)) + next_page = scrapertools.find_single_match(data, '<li><a href="([^"]+)" class="no-page next-page">Siguiente') + if "profile" in item.url: + next_page = scrapertools.find_single_match(data, '<li><a class="active" href="">(\d+)</a></li><li><a href="#') + if next_page: + next_page = urlparse.urljoin(item.url,next_page).replace("&", "&") + itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", + url=next_page) ) + return itemlist + + +def play(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + url = scrapertools.find_single_match(data, 'html5player.setVideoHLS\(\'([^\']+)\'\)') + itemlist.append(item.clone(action="play", title=url, url=url )) + return itemlist + diff --git a/channels/xxxdan.json b/channels/porn/xxxdan.json similarity index 100% rename from channels/xxxdan.json rename to channels/porn/xxxdan.json diff --git a/channels/xxxdan.py b/channels/porn/xxxdan.py similarity index 96% rename from channels/xxxdan.py rename to channels/porn/xxxdan.py index f2359eb4..c4d21fd0 100644 --- a/channels/xxxdan.py +++ b/channels/porn/xxxdan.py @@ -1,13 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse +import urlparse,urllib2,urllib,re +import os, sys -from core import httptools +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'http://xxxdan.com' @@ -93,7 +93,7 @@ def play(item): data = httptools.downloadpage(item.url).data media_url = scrapertools.find_single_match(data, 'src:\'([^\']+)\'') media_url = media_url.replace("https","http") - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=media_url, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=media_url, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/xxxfreeinhd.json b/channels/porn/xxxfreeinhd.json similarity index 92% rename from channels/xxxfreeinhd.json rename to channels/porn/xxxfreeinhd.json index 16376ceb..ff580284 100644 --- a/channels/xxxfreeinhd.json +++ b/channels/porn/xxxfreeinhd.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "https://watchxxxfreeinhd.com/wp-content/uploads/logo2015%20(1).jpg", + "thumbnail": "https://watchxxxfreeinhd.com/wp-content/uploads/logo2015-1.png", "banner": "", "categories": [ "adult" diff --git a/channels/xxxfreeinhd.py b/channels/porn/xxxfreeinhd.py similarity index 69% rename from channels/xxxfreeinhd.py rename to channels/porn/xxxfreeinhd.py index b29172a4..ff12d4e1 100644 --- a/channels/xxxfreeinhd.py +++ b/channels/porn/xxxfreeinhd.py @@ -1,14 +1,13 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +import base64 +from platformcode import config, logger from core import scrapertools -from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://watchxxxfreeinhd.com' @@ -29,7 +28,7 @@ def mainlist(item): def search(item, texto): logger.info() texto = texto.replace(" ", "+") - item.url = host + "/search.php?q=%s&language=en&search=Search" % texto + item.url = host + "search.php?q=%s&language=en&search=Search" % texto try: return lista(item) except: @@ -70,10 +69,13 @@ def lista(item): thumbnail = scrapedthumbnail + "|https://watchxxxfreeinhd.com/" plot = "" itemlist.append( Item(channel=item.channel, action="findvideos", title=title, url=scrapedurl, - thumbnail=thumbnail, plot=plot, fanart=scrapedthumbnail, contentTitle = scrapedtitle)) + thumbnail=thumbnail, plot=plot, fanart=scrapedthumbnail )) next_page = scrapertools.find_single_match(data, '<link rel="next" href="([^"]+)"') if next_page: next_page = urlparse.urljoin(item.url,next_page) + if "?filtre=date&cat=0" in item.url: next_page += "?filtre=date&cat=0" + elif "?display=tube&filtre=views" in item.url: next_page += "?display=tube&filtre=views" + elif "?display=tube&filtre=rate" in item.url: next_page += "?display=tube&filtre=rate" itemlist.append( Item(channel=item.channel, action="lista", title="Página Siguiente >>", text_color="blue", url=next_page) ) return itemlist @@ -84,12 +86,37 @@ def findvideos(item): itemlist = [] data = httptools.downloadpage(item.url).data data = re.sub(r"\n|\r|\t| |<br>", "", data) - data = scrapertools.find_single_match(data,'<div class="video-embed">(.*?)</div>') - patron = '<noscript>.*?<iframe src="([^"]+)"' + data = scrapertools.find_single_match(data,'<div class="video-embed">(.*?)<div class="views-infos">') + patron = 'data-lazy-src="([^"]+)"' matches = scrapertools.find_multiple_matches(data, patron) - for url in matches: - itemlist.append(item.clone(action="play", title = "%s", url=url )) + for title in matches: + if "strdef" in title: + url = decode_url(title) + if "strdef" in url: + url = httptools.downloadpage(url).url + if "hqq" in title: + url = title + itemlist.append( Item(channel=item.channel, action="play", title = "%s", url=url )) itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) return itemlist +def decode_url(txt): + logger.info() + itemlist = [] + data = httptools.downloadpage(txt).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + rep = True + while rep == True: + b64_data = scrapertools.find_single_match(data, '\(dhYas638H\("([^"]+)"\)') + if b64_data: + b64_url = base64.b64decode(b64_data + "=") + b64_url = base64.b64decode(b64_url + "==") + data = b64_url + else: + rep = False + url = scrapertools.find_single_match(b64_url, '<iframe src="([^"]+)"') + logger.debug (url) + return url + + diff --git a/channels/xxxparodyhd.json b/channels/porn/xxxparodyhd.json similarity index 100% rename from channels/xxxparodyhd.json rename to channels/porn/xxxparodyhd.json diff --git a/channels/xxxparodyhd.py b/channels/porn/xxxparodyhd.py similarity index 92% rename from channels/xxxparodyhd.py rename to channels/porn/xxxparodyhd.py index e3e04dd1..df554687 100644 --- a/channels/xxxparodyhd.py +++ b/channels/porn/xxxparodyhd.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools -from core import tmdb +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'https://xxxparodyhd.net' @@ -19,8 +17,8 @@ def mainlist(item): itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url=host + "/movies/")) itemlist.append( Item(channel=item.channel, title="Nuevas" , action="lista", url=host + "/genre/new-release/")) itemlist.append( Item(channel=item.channel, title="Parodias" , action="lista", url=host + "/genre/parodies/")) - itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host + "/categories")) - itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories")) + itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host)) + itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) return itemlist @@ -69,7 +67,6 @@ def lista(item): scrapedplot = "" itemlist.append( Item(channel=item.channel, action="findvideos", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, fanart=scrapedthumbnail, plot=scrapedplot, infoLabels={'year':scrapedyear}) ) - tmdb.set_infoLabels(itemlist, True) next_page = scrapertools.find_single_match(data,'<li class=\'active\'>.*?href=\'([^\']+)\'>') if next_page!="": next_page = urlparse.urljoin(item.url,next_page) diff --git a/channels/xxxstreams.json b/channels/porn/xxxstreams.json similarity index 84% rename from channels/xxxstreams.json rename to channels/porn/xxxstreams.json index 522372fd..a92df9d3 100644 --- a/channels/xxxstreams.json +++ b/channels/porn/xxxstreams.json @@ -4,7 +4,7 @@ "active": true, "adult": true, "language": ["*"], - "thumbnail": "", + "thumbnail": "xxxstreams.png", "banner": "", "categories": [ "adult" diff --git a/channels/xxxstreams.py b/channels/porn/xxxstreams.py similarity index 70% rename from channels/xxxstreams.py rename to channels/porn/xxxstreams.py index 2cb55ef4..cff4d613 100644 --- a/channels/xxxstreams.py +++ b/channels/porn/xxxstreams.py @@ -1,21 +1,20 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools -host = 'http://xxxstreams.org' +host = 'http://xxxstreams.org' #es hhttp://freepornstreams.org def mainlist(item): logger.info() itemlist = [] itemlist.append( Item(channel=item.channel, title="Peliculas" , action="lista", url= host + "/category/full-porn-movie-stream/")) - itemlist.append( Item(channel=item.channel, title="Clips" , action="lista", url=host)) + itemlist.append( Item(channel=item.channel, title="Videos" , action="lista", url=host + "/category/new-porn-streaming/")) itemlist.append( Item(channel=item.channel, title="Canal" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host)) itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) @@ -39,7 +38,10 @@ def categorias(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - data1 = scrapertools.find_single_match(data,'<h5>Popular Categories<br />(.*?)</aside>') + if item.title == "Categorias" : + data1 = scrapertools.find_single_match(data,'>Top Tags</a>(.*?)</ul>') + data1 += scrapertools.find_single_match(data,'>Ethnic</a>(.*?)</ul>') + data1 += scrapertools.find_single_match(data,'>Kinky</a>(.*?)</ul>') if item.title == "Canal" : data1 = scrapertools.find_single_match(data,'>Top sites</a>(.*?)</ul>') data1 += scrapertools.find_single_match(data,'Downloads</h2>(.*?)</ul>') @@ -65,6 +67,7 @@ def lista(item): for scrapedthumbnail,scrapedurl,scrapedtitle in matches: scrapedplot = "" if '/HD' in scrapedtitle : title= "[COLOR red]" + "HD" + "[/COLOR] " + scrapedtitle + elif 'SD' in scrapedtitle : title= "[COLOR red]" + "SD" + "[/COLOR] " + scrapedtitle elif 'FullHD' in scrapedtitle : title= "[COLOR red]" + "FullHD" + "[/COLOR] " + scrapedtitle elif '1080' in scrapedtitle : title= "[COLOR red]" + "1080p" + "[/COLOR] " + scrapedtitle else: title = scrapedtitle @@ -77,3 +80,14 @@ def lista(item): return itemlist +def findvideos(item): + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t|amp;|\s{2}| ", "", data) + patron = '<a href="([^"]+)" rel="nofollow"[^<]+>(?:Streaming|Download)' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + if not "ubiqfile" in url: + itemlist.append(item.clone(action='play',title="%s", url=url)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist diff --git a/channels/yespornplease.json b/channels/porn/yespornplease.json similarity index 100% rename from channels/yespornplease.json rename to channels/porn/yespornplease.json diff --git a/channels/yespornplease.py b/channels/porn/yespornplease.py similarity index 94% rename from channels/yespornplease.py rename to channels/porn/yespornplease.py index 8e5abc28..ae7c2b40 100644 --- a/channels/yespornplease.py +++ b/channels/porn/yespornplease.py @@ -2,12 +2,12 @@ import re -from urlparse import urljoin - from core import httptools -from core import servertools +from core.item import Item from platformcode import logger -from platformcode import config +from urlparse import urljoin +from core import servertools + HOST="http://yespornplease.com" @@ -70,7 +70,7 @@ def links(item): if quality: formattedQuality += " [%s]" % (quality) titleFormatted = "%(title)s%(quality)s [%(duration)s]" % ({"title": title, "quality": formattedQuality, "duration": duration}) - result.append(item.clone(action = "play", title = titleFormatted, url = urljoin(item.url, "/view/%s" % (vID)), thumbnail = urljoin(item.url, img), vID = vID)) + result.append(item.clone(action = "play", title = titleFormatted, url = urljoin(item.url, "/v/%s" % (vID)), thumbnail = urljoin(item.url, img), vID = vID)) # Has pagination paginationOccurences = data.count('class="prevnext"') if paginationOccurences: @@ -85,6 +85,6 @@ def links(item): def play(item): logger.info(item) - embededURL = urljoin(item.url, "/view/%s" % (item.vID)) + embededURL = urljoin(item.url, "/v/%s" % (item.vID)) itemlist = servertools.find_video_items(item.clone(url = embededURL)) return itemlist diff --git a/channels/youjizz.json b/channels/porn/youjizz.json similarity index 100% rename from channels/youjizz.json rename to channels/porn/youjizz.json diff --git a/channels/youjizz.py b/channels/porn/youjizz.py similarity index 94% rename from channels/youjizz.py rename to channels/porn/youjizz.py index 54b310b0..4112acbe 100644 --- a/channels/youjizz.py +++ b/channels/porn/youjizz.py @@ -1,14 +1,16 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -import re - import urlparse - -from core import httptools +import urllib2 +import urllib +import re +import os +import sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.youjizz.com' @@ -42,7 +44,7 @@ def categorias(item): logger.info() itemlist = [] data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data, '<h4>Trending(.*?)</ul>') + data = scrapertools.find_single_match(data, '>Trending Categories<(.*?)</ul>') data = re.sub(r"\n|\r|\t| |<br>", "", data) patron = '<li><a href="([^"]+)">([^"]+)</a>' matches = re.compile(patron, re.DOTALL).findall(data) @@ -104,6 +106,6 @@ def play(item): patron = '"1080".*?"filename"\:"(.*?)"' media_url = scrapertools.find_single_match(data, patron) media_url = "https:" + media_url.replace("\\", "") - itemlist.append(Item(channel=item.channel, action="play", title=item.title, fulltitle=item.fulltitle, url=media_url, + itemlist.append(Item(channel=item.channel, action="play", title=item.title, url=media_url, thumbnail=item.thumbnail, plot=item.plot, show=item.title, server="directo", folder=False)) return itemlist diff --git a/channels/youporn.json b/channels/porn/youporn.json similarity index 100% rename from channels/youporn.json rename to channels/porn/youporn.json diff --git a/channels/youporn.py b/channels/porn/youporn.py similarity index 97% rename from channels/youporn.py rename to channels/porn/youporn.py index 97e6b395..fd41cfb7 100644 --- a/channels/youporn.py +++ b/channels/porn/youporn.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys +from platformcode import config, logger from core import scrapertools from core.item import Item -from platformcode import logger -from platformcode import config +from core import servertools +from core import httptools host = 'https://www.youporn.com' @@ -124,7 +123,7 @@ def play(item): matches = scrapertools.find_multiple_matches(data, patron) for scrapedurl in matches: scrapedurl = scrapedurl.replace("\/", "/") - itemlist.append(item.clone(action="play", title=scrapedurl, fulltitle = item.title, url=scrapedurl)) + itemlist.append(item.clone(action="play", title=scrapedurl, url=scrapedurl)) return itemlist diff --git a/channels/yuuk.json b/channels/porn/yuuk.json similarity index 100% rename from channels/yuuk.json rename to channels/porn/yuuk.json diff --git a/channels/yuuk.py b/channels/porn/yuuk.py similarity index 76% rename from channels/yuuk.py rename to channels/porn/yuuk.py index a4adb269..f6e08673 100644 --- a/channels/yuuk.py +++ b/channels/porn/yuuk.py @@ -1,13 +1,12 @@ # -*- coding: utf-8 -*- #------------------------------------------------------------ -import re -import urlparse - -from core import httptools +import urlparse,urllib2,urllib,re +import os, sys from core import scrapertools +from core import servertools from core.item import Item -from platformcode import logger -from platformcode import config +from platformcode import config, logger +from core import httptools host = 'http://yuuk.net' @@ -75,3 +74,20 @@ def lista(item): return itemlist + +def findvideos(item): + logger.info() + itemlist = [] + data = httptools.downloadpage(item.url).data + data = re.sub(r"\n|\r|\t| |<br>", "", data) + data = scrapertools.find_single_match(data,'Streaming Server<(.*?)Screenshot<') + patron = '(?:src|SRC)="([^"]+)"' + matches = scrapertools.find_multiple_matches(data, patron) + for url in matches: + if "http://stream.yuuk.net/embed.php" in url: + data = httptools.downloadpage(url).data + url = scrapertools.find_single_match(data,'"file": "([^"]+)e=download"') + itemlist.append( Item(channel=item.channel, action="play", title = "%s", url=url )) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + return itemlist + diff --git a/channels/seriehd.json b/channels/seriehd.json index ecd59d5c..b6be2f7b 100644 --- a/channels/seriehd.json +++ b/channels/seriehd.json @@ -7,56 +7,5 @@ "thumbnail": "seriehd.png", "banner": "seriehd.png", "categories": ["tvshow"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "settings": [] } diff --git a/channels/seriehd.py b/channels/seriehd.py index 288f5b7a..a8853e8a 100644 --- a/channels/seriehd.py +++ b/channels/seriehd.py @@ -1,149 +1,107 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per seriehd +# Canale per SerieHD # ------------------------------------------------------------ -import urlparse -import re -from channelselector import thumb -from lib import cloudscraper -from core import scrapertoolsV2, servertools, httptools, support + +from core import scrapertoolsV2, httptools, support from core.item import Item -from core.support import menu, log -from platformcode import logger, config -from specials import autoplay +host = '' +headers = '' -__channel__ = "seriehd" -host = config.get_channel_url(__channel__) +def findhost(): + global host, headers + data= httptools.downloadpage('https://seriehd.nuovo.link/').data + global host, headers + host = scrapertoolsV2.find_single_match(data, r'<div class="elementor-button-wrapper"> <a href="([^"]+)"') + headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() list_servers = ['verystream', 'openload', 'streamango', 'thevideome'] list_quality = ['1080p', '720p', '480p', '360'] -checklinks = config.get_setting('checklinks', 'seriehd') -checklinks_number = config.get_setting('checklinks_number', 'seriehd') - -headers = [['Referer', host]] - - +@support.menu def mainlist(item): - log() - itemlist = [] + findhost() + tvshow = [('Genere', ['', 'genre']), + ('Americane', ['serie-tv-streaming/serie-tv-americane', 'peliculas']), + ('Italiane', ['serie-tv-streaming/serie-tv-italiane', 'peliculas']),] + return locals() - menu(itemlist, 'Serie TV', 'peliculas', host + '/serie-tv-streaming', 'tvshow') - menu(itemlist, 'Per Genere submenu', 'genre', host, 'tvshow', 'TV') - menu(itemlist, 'Per Nazione submenu', 'nation', host + '/serie-tv-streaming/', 'tvshow', 'TV') - menu(itemlist, 'Cerca...', 'search', contentType='tvshow', args='TV') - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) +@support.scrape +def peliculas(item): + #findhost() + patron = r'<h2>(?P<title>.*?)</h2>\s*<img src="(?P<thumb>[^"]+)" alt="[^"]*" />\s*<A HREF="(?P<url>[^"]+)">.*?<span class="year">(?:(?P<year>[0-9]{4}))?.*?<span class="calidad">(?:(?P<quality>[A-Z]+))?.*?</span>' + patronNext=r'<span class="current">\d+</span><a rel="nofollow" class="page larger" href="([^"]+)">\d+</a>' + action='episodios' + return locals() - return itemlist + +@support.scrape +def episodios(item): + #findhost() + data ='' + url = support.match(item, patronBlock=r'<iframe width=".+?" height=".+?" src="([^"]+)" allowfullscreen frameborder="0">')[1] + seasons = support.match(item, r'<a href="([^"]+)">(\d+)<', r'<h3>STAGIONE</h3><ul>(.*?)</ul>', headers, url)[0] + for season_url, season in seasons: + season_url = support.urlparse.urljoin(url, season_url) + episodes = support.match(item, r'<a href="([^"]+)">(\d+)<', '<h3>EPISODIO</h3><ul>(.*?)</ul>', headers, season_url)[0] + for episode_url, episode in episodes: + episode_url = support.urlparse.urljoin(url, episode_url) + title = season + "x" + episode.zfill(2) + ' - ' + item.fulltitle + data += title + '|' + episode_url + '\n' + patron = r'(?P<title>[^\|]+)\|(?P<url>[^\n]+)\n' + action = 'findvideos' + return locals() + + +@support.scrape +def genre(item): + #findhost() + patronMenu = '<a href="(?P<url>[^"]+)">(?P<title>[^<]+)</a>' + blacklist = ['Serie TV','Serie TV Americane','Serie TV Italiane','altadefinizione'] + patronBlock = '<ul class="sub-menu">(?P<block>.*)</ul>' + action = 'peliculas' + return locals() def search(item, texto): - log(texto) + support.log(texto) + findhost() + item.contentType = 'tvshow' item.url = host + "/?s=" + texto - try: return peliculas(item) - # Continua la ricerca in caso di errore . except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] - def newest(categoria): - log(categoria) + support.log(categoria) + findhost() itemlist = [] - item = Item() + item = support.Item() try: - - ## cambiar los valores "peliculas, infantiles, series, anime, documentales por los que correspondan aqui en - # el py y en l json ### if categoria == "series": item.url = host + item.contentType = 'tvshow' itemlist = peliculas(item) - - if 'Successivo>>' in itemlist[-1].title: - itemlist.pop() - + itemlist.pop() # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + support.logger.error("{0}".format(line)) return [] return itemlist -def genre(item): - itemlist = support.scrape(item, '<a href="([^"]+)">([^<]+)</a>', ['url', 'title'], headers,['Serie TV','Serie TV Americane','Serie TV Italiane','altadefinizione'], action='peliculas') - return thumb(itemlist) - - -def nation(item): - log() - itemlist = [] - menu(itemlist, 'Serie TV Americane', 'peliculas', host + '/serie-tv-streaming/serie-tv-americane/') - menu(itemlist, 'Serie TV Italiane', 'peliculas', host + '/serie-tv-streaming/serie-tv-italiane/') - return itemlist - - -def peliculas(item): - item.contentType = 'tvshow' - return support.scrape(item,r'<h2>(.*?)</h2>\s*<img src="([^"]+)" alt="[^"]*" />\s*<A HREF="([^"]+)">.*?<span class="year">([0-9]{4}).*?<span class="calidad">([A-Z]+)',['title', 'thumb', 'url', 'year', 'quality'], headers, patronNext=r'<link rel="next" href="([^"]+)"', action='episodios') - - -def episodios(item): - log() - itemlist = [] - - data = httptools.downloadpage(item.url).data - patron = r'<iframe width=".+?" height=".+?" src="([^"]+)" allowfullscreen frameborder="0">' - url = scrapertoolsV2.find_single_match(data, patron).replace("?seriehd", "") - seasons = support.match(item, r'<a href="([^"]+)">(\d+)<', r'<h3>STAGIONE</h3><ul>(.*?)</ul>', headers, url)[0] - for season_url, season in seasons: - season_url = urlparse.urljoin(url, season_url) - episodes = support.match(item, r'<a href="([^"]+)">(\d+)<', '<h3>EPISODIO</h3><ul>(.*?)</ul>', headers, season_url)[0] - for episode_url, episode in episodes: - episode_url = urlparse.urljoin(url, episode_url) - title = season + "x" + episode.zfill(2) - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title=support.typo(title + ' - ' +item.show,'bold'), - url=episode_url, - fulltitle=title + ' - ' + item.show, - show=item.show, - thumbnail=item.thumbnail)) - - support.videolibrary(itemlist, item, 'color kod bold') - - return itemlist - - def findvideos(item): - log() - - itemlist = [] - itemlist = support.hdpass_get_servers(item) - - if checklinks: - itemlist = servertools.check_list_links(itemlist, checklinks_number) - - autoplay.start(itemlist, item) - - return itemlist - - - + support.log() + return support.hdpass_get_servers(item) diff --git a/channels/serietvonline.json b/channels/serietvonline.json index 4781796e..700fe885 100644 --- a/channels/serietvonline.json +++ b/channels/serietvonline.json @@ -4,41 +4,9 @@ "active": true, "adult": false, "language": ["ita"], - "thumbnail": "https:\/\/serietvonline.com\/wp-content\/uploads\/2016\/08\/logo2016-1.png", - "bannermenu": "https:\/\/serietvonline.com\/wp-content\/uploads\/2016\/08\/logo2016-1.png", - "categories": ["anime","tvshow","movie"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_anime", - "type": "bool", - "label": "Includi in Novità - Anime", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - } - ] + "thumbnail": "serietvonline.png", + "bannermenu": "serietvonline.png", + "categories": ["anime","tvshow","movie","documentary"], + "not_active": ["include_in_newest_anime"], + "settings": [] } diff --git a/channels/serietvonline.py b/channels/serietvonline.py index f0c06b1c..647b804a 100644 --- a/channels/serietvonline.py +++ b/channels/serietvonline.py @@ -1,200 +1,204 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per serietvonline +# Canale per serietvonline.py # ---------------------------------------------------------- -import re +""" + Novità. Indicare in quale/i sezione/i è presente il canale: + - film, serie -from channelselector import thumb -from core import httptools, scrapertoolsV2, servertools, tmdb, support + Avvisi: + - Al massimo 25 titoli per le sezioni: Film + - Al massimo 35 titoli per le sezioni: Tutte le altre + Per aggiungere in videoteca le Anime: + Se hanno la forma 1x01: + -si posso aggiungere direttamente dalla pagina della serie, sulla voce in fondo "aggiungi in videoteca". + Altrimenti: + - Prima fare la 'Rinumerazione' dal menu contestuale dal titolo della serie +""" +import re +from core import support, httptools, scrapertoolsV2 +from platformcode import config from core.item import Item -from lib import unshortenit -from platformcode import logger, config -from specials import autoplay __channel__ = "serietvonline" -host = config.get_channel_url(__channel__) -headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() -list_servers = ['akvideo', 'wstream', 'backin', 'vidto', 'nowvideo'] +host = "" +headers = "" + +def findhost(): + global host, headers + data = httptools.downloadpage('https://serietvonline.me/').data + host = scrapertoolsV2.find_single_match(data, r'<a class="pure-button pure-button-primary" title=\'serie tv online\' href="([^"]+)">') + headers = [['Referer', host]] + +list_servers = ['akvideo', 'wstream', 'backin', 'vidtome', 'nowvideo'] list_quality = ['default'] -PERPAGE = 30 +@support.menu def mainlist(item): - logger.info(item.channel + 'mainlist') + support.log() + findhost() - itemlist = web_menu() - support.menu(itemlist, "Cerca Film... color kod", 'search', '', 'movie') - support.menu(itemlist, "Cerca Serie... color kod", 'search', '', 'episode') + film = ['/ultimi-film-aggiunti/', + ('Lista', ['/lista-film/', 'peliculas', 'lista']) + ] - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - return itemlist + tvshow = ['', + ('Aggiornamenti', ['/ultimi-episodi-aggiunti/', 'peliculas', 'update']), + ('Tutte', ['/lista-serie-tv/', 'peliculas', 'qualcosa']), + ('Italiane', ['/lista-serie-tv-italiane/', 'peliculas', 'qualcosa']), + ('Anni 50-60-70-80', ['/lista-serie-tv-anni-60-70-80/', 'peliculas', 'qualcosa']), + ('HD', ['/lista-serie-tv-in-altadefinizione/', 'peliculas', 'qualcosa']) + ] + anime = ['/lista-cartoni-animati-e-anime/'] -def web_menu(): - itemlist=[] + documentari = [('Documentari', ['/lista-documentari/' , 'peliculas' , 'doc', 'tvshow'])] - data = httptools.downloadpage(host, headers=headers).data - matches = scrapertoolsV2.find_multiple_matches(data, r'<li class="page_item.*?><a href="([^"]+)">(.*?)<\/a>') - blacklist = ['DMCA','Contatti','Attenzione NON FARTI OSCURARE'] - - for url, title in matches: - if not title in blacklist: - title = title.replace('Lista ','') + ' bold' - if 'film' in title.lower(): - contentType = 'movie' - else: - contentType = 'episode' - support.menu(itemlist, title, 'peliculas', url,contentType=contentType) - - return itemlist - - -def search(item, texto): - logger.info(item.channel + 'search' + texto) - - item.url = host + "/?s= " + texto - - return search_peliculas(item) - - -def search_peliculas(item): - logger.info(item.channel + 'search_peliculas') - - logger.info('TYPE= ' + item.contentType) - - if item.contentType == 'movie': - action = 'findvideos' - else: - action = 'episodios' - - return support.scrape(item, r'<a href="([^"]+)"><span[^>]+><[^>]+><\/a>[^h]+h2>(.*?)<', - ["url", "title"], patronNext="<a rel='nofollow' class=previouspostslink href='([^']+)'", - headers=headers, action=action) + search = '' + return locals() +@support.scrape def peliculas(item): - logger.info(item.channel + 'peliculas') - itemlist = [] + support.log() + #findhost() - if item.contentType == 'movie': + blacklist = ['DMCA', 'Contatti', 'Attenzione NON FARTI OSCURARE', 'Lista Cartoni Animati e Anime'] + patronBlock = r'<h1>.+?</h1>(?P<block>.*?)<div class="footer_c">' + patronNext = r'<div class="siguiente"><a href="([^"]+)" >' + + if item.args == 'search': + patronBlock = r'>Lista Serie Tv</a></li></ul></div><div id="box_movies">(?P<block>.*?)<div id="paginador">' + patron = r'<div class="movie">[^>]+[^>]+>\s?<img src="(?P<thumb>[^"]+)" alt="(?P<title>.+?)\s?(?P<year>[\d\-]+)?"[^>]+>\s?<a href="(?P<url>[^"]+)">' + elif item.contentType == 'episode': + pagination = 35 action = 'findvideos' + patron = r'<td><a href="(?P<url>[^"]+)"(?:[^>]+)?>\s?(?P<title>[^<]+)(?P<episode>[\d\-x]+)?(?P<title2>[^<]+)?<' + + elif item.contentType == 'tvshow': + # SEZIONE Serie TV- Anime - Documentari + pagination = 35 + + if not item.args and 'anime' not in item.url: + patron = r'<div class="movie">[^>]+>.+?src="(?P<thumb>[^"]+)" alt="[^"]+".+?href="(?P<url>[^"]+)">[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>[ ](?P<rating>\d+.\d+|\d+)<[^>]+>[^>]+><h2>(?P<title>[^"]+)</h2>[ ]?(?:<span class="year">(?P<year>\d+|\-\d+))?<' + else: + anime = True + patron = r'(?:<td>)?<a href="(?P<url>[^"]+)"(?:[^>]+)?>\s?(?P<title>[^<]+)(?P<episode>[\d\-x]+)?(?P<title2>[^<]+)?<' else: - action = 'episodios' + # SEZIONE FILM + pagination = 25 - page = 1 - if '{}' in item.url: - item.url, page = item.url.split('{}') - page = int(page) + if item.args == 'lista': + patron = r'href="(?P<url>[^"]+)"[^>]+>(?P<title>.*?)[ ]?(?P<year>\d+)?(?: Streaming | MD iSTANCE )?<' + patronBlock = r'Lista dei film disponibili in streaming e anche in download\.</p>(?P<block>.*?)<div class="footer_c">' + else: + #patronBlock = r'<h1>Ultimi film aggiunti</h1>(?P<block>.*?)<div class="footer_c">' + patron = r'<tr><td><a href="(?P<url>[^"]+)"(?:|.+?)?>(?:  )?[ ]?(?P<title>.*?)[ ]?(?P<quality>HD)?[ ]?(?P<year>\d+)?(?: | HD | Streaming | MD(?: iSTANCE)? )?</a>' - data = httptools.downloadpage(item.url, headers=headers).data - block = scrapertoolsV2.find_single_match(data, r'id="lcp_instance_0">(.*?)<\/ul>') - matches = re.compile(r'<a\s*href="([^"]+)" title="([^<]+)">[^<]+</a>', re.DOTALL).findall(block) + def itemHook(item): + if 'film' in item.url: + item.action = 'findvideos' + item.contentType = 'movie' + elif item.args == 'update': + pass + else: + item.contentType = 'tvshow' + item.action = 'episodios' + return item - for i, (url, title) in enumerate(matches): - if (page - 1) * PERPAGE > i: continue - if i >= page * PERPAGE: break - title = scrapertoolsV2.decodeHtmlentities(title) - itemlist.append( - Item(channel=item.channel, - action=action, - title=title, - contentTitle=title, - fulltitle=title, - url=url, - contentType=item.contentType, - show=title)) - - if len(matches) >= page * PERPAGE: - url = item.url + '{}' + str(page + 1) - itemlist.append( - Item(channel=item.channel, - action="peliculas", - title="[COLOR blue]" + config.get_localized_string(30992) + " >[/COLOR]", - url=url, - thumbnail=thumb(), - contentType=item.contentType)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist + #support.regexDbg(item, patronBlock, headers) + #debug = True + return locals() +@support.scrape def episodios(item): - logger.info(item.channel + 'episodios') + support.log() + #findhost() + + action = 'findvideos' + patronBlock = r'<table>(?P<block>.*?)<\/table>' + patron = r'<tr><td>(?:[^<]+)[ ](?:Parte)?(?P<episode>\d+x\d+|\d+)(?:|[ ]?(?P<title2>.+?)?(?:avi)?)<(?P<url>.*?)</td><tr>' + + #debug = True + return locals() + + +def search(item, text): + support.log("CERCA :" ,text, item) + findhost() + item.url = "%s/?s=%s" % (host, text) + + try: + item.args = 'search' + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.log("%s" % line) + return [] + +def newest(categoria): + support.log(categoria) + findhost() itemlist = [] + item = Item() - data = httptools.downloadpage(item.url, headers=headers).data - block= scrapertoolsV2.find_single_match(data, r'<table>(.*?)<\/table>') + if categoria == 'peliculas': + item.contentType = 'movie' + item.url = host + '/ultimi-film-aggiunti/' + elif categoria == 'series': + item.args = 'update' + item.contentType = 'episode' + item.url = host +'/ultimi-episodi-aggiunti/' + try: + item.action = 'peliculas' + itemlist = peliculas(item) - matches = re.compile(r'<tr><td>(.*?)</td><tr>', re.DOTALL).findall(block) - - for episode in matches: - episode = "<td class=\"title\">" + episode - logger.info('EPISODE= ' + episode) - title = scrapertoolsV2.find_single_match(episode, '<td class="title">(.*?)</td>') - title = title.replace(item.title, "") - if scrapertoolsV2.find_single_match(title, '([0-9]+x[0-9]+)'): - title = scrapertoolsV2.find_single_match(title, '([0-9]+x[0-9]+)') + ' - ' + re.sub('([0-9]+x[0-9]+)',' -',title) - elif scrapertoolsV2.find_single_match(title, ' ([0-9][0-9])') and not scrapertoolsV2.find_single_match(title, ' ([0-9][0-9][0-9])'): - title = '1x' + scrapertoolsV2.find_single_match(title, ' ([0-9]+)') + ' - ' + re.sub(' ([0-9]+)',' -',title) - itemlist.append( - Item(channel=item.channel, - action="findvideos", - fulltitle=title, - contentType="episode", - show=title, - title=title, - url=episode)) - - support.videolibrary(itemlist,item,'bold color kod') + except: + import sys + for line in sys.exc_info(): + support.log("{0}".format(line)) + return [] return itemlist - def findvideos(item): - logger.info(item.channel + 'findvideos') - itemlist=[] - logger.info('TYPE= ' + item.contentType) + support.log() if item.contentType == 'movie': - data = httptools.downloadpage(item.url, headers=headers).data - logger.info('DATA= ' + data) - item.url= scrapertoolsV2.find_single_match(data, r'<table>(.*?)<\/table>') - - urls = scrapertoolsV2.find_multiple_matches(item.url, r"<a href='([^']+)'.*?>.*?>.*?([a-zA-Z]+).*?<\/a>") - logger.info('EXTRA= ' + item.extra) - for url, server in urls: - itemlist.append( - Item(channel=item.channel, - action='play', - title=item.title + ' [COLOR blue][' + server + '][/COLOR]', - contentType="movie", - server=server, - url=url)) - - autoplay.start(itemlist, item) - - return itemlist - - -def play(item): - - data, c = unshortenit.unshorten(item.url) - - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.title = item.title - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - videoitem.thumbnail = item.thumbnail - videoitem.channel = item.channel - - return itemlist + return support.server(item, headers=headers) + else: + if item.args != 'update': + return support.server(item, item.url) + else: + itemlist = [] + item.infoLabels['mediatype'] = 'episode' + data = httptools.downloadpage(item.url, headers=headers).data + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + #support.log("DATA - HTML:\n", data) + url_video = scrapertoolsV2.find_single_match(data, r'<tr><td>(.+?)</td><tr>', -1) + url_serie = scrapertoolsV2.find_single_match(data, r'<link rel="canonical" href="([^"]+)"\s?/>') + goseries = support.typo("Vai alla Serie:", ' bold') + series = support.typo(item.contentSerieName, ' bold color kod') + itemlist = support.server(item, data=url_video) + itemlist.append( + Item(channel=item.channel, + title=goseries + series, + fulltitle=item.fulltitle, + show=item.show, + contentType='tvshow', + contentSerieName=item.contentSerieName, + url=url_serie, + action='episodios', + contentTitle=item.contentSerieName, + plot = goseries + series + "con tutte le puntate", + )) + return itemlist diff --git a/channels/serietvsubita.json b/channels/serietvsubita.json index fe08633c..dcd8baec 100644 --- a/channels/serietvsubita.json +++ b/channels/serietvsubita.json @@ -8,14 +8,6 @@ "banner": "serietvsubita.png", "categories": ["tvshow"], "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "http://serietvsubita.xyz", - "enabled": true, - "visible": true - }, { "id": "include_in_global_search", "type": "bool", diff --git a/channels/serietvsubita.py b/channels/serietvsubita.py index 302c15df..b4695992 100644 --- a/channels/serietvsubita.py +++ b/channels/serietvsubita.py @@ -21,18 +21,20 @@ list_language = IDIOMAS.values() list_servers = ['gounlimited', 'verystream', 'streamango', 'openload'] list_quality = ['default'] - +@support.menu def mainlist(item): log() itemlist = [] - support.menu(itemlist, 'Novità bold', 'peliculas_tv', host, 'tvshow') - support.menu(itemlist, 'Serie TV bold', 'lista_serie', host, 'tvshow') - support.menu(itemlist, 'Archivio A-Z submenu', 'list_az', host, 'tvshow', args=['serie']) - support.menu(itemlist, 'Cerca', 'search', host, 'tvshow') - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) + tvshowSub = [ + ('Novità bold',[ '', 'peliculas_tv', '', 'tvshow']), + ('Serie TV bold',[ '', 'lista_serie', '', 'tvshow']), + ('Per Lettera', ['', 'list_az', 'serie', 'tvshow']) + ] +## support.aplay(item, itemlist, list_servers, list_quality) +## support.channel_config(item, itemlist) + + return locals() - return itemlist # ---------------------------------------------------------------------------------------------------------------- @@ -159,7 +161,7 @@ def episodios(item, itemlist=[]): # recupero la stagione season = scrapertools.find_single_match(scrapedtitle, 'Stagione ([0-9]*)') blocco = scrapertools.find_single_match(data, '<div class="entry">[\s\S.]*?<div class="post') - blocco = blocco.replace('<strong>Episodio ', '<strong>Episodio ').replace(' </strong>', ' </strong>') + blocco = blocco.replace('<strong>Episodio ', '<strong>Episodio ').replace(' </strong>', ' </strong>') blocco = blocco.replace('<strong>Episodio ', '<strong>S' + season.zfill(2) + 'E') matches = scrapertools.find_multiple_matches(blocco, r'(S(\d*)E(\d*))\s') episodes = [] @@ -351,3 +353,4 @@ def list_az(item): return itemlist # ================================================================================================================ + diff --git a/channels/serietvu.json b/channels/serietvu.json index abb5dbd5..929dcc5b 100644 --- a/channels/serietvu.json +++ b/channels/serietvu.json @@ -3,68 +3,10 @@ "name": "SerieTVU", "active": true, "adult": false, - "language": ["ita"], + "language": ["ita", "sub-ita"], "thumbnail": "serietvu.png", "banner": "serietvu.png", - "categories": ["tvshow"], - "settings": [ - { - "id": "channel_host", - "type": "text", - "label": "Host del canale", - "default": "https://www.serietvu.club", - "enabled": true, - "visible": true - }, - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_series", - "type": "bool", - "label": "Includi in Novità - Serie TV", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero de link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "1", "3", "5", "10" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - } - ] + "categories": ["tvshow", "vos"], + "not_active": ["include_in_newest_peliculas", "include_in_newest_anime"], + "settings": [] } diff --git a/channels/serietvu.py b/channels/serietvu.py index 0a9bbc2d..4dc8ee17 100644 --- a/channels/serietvu.py +++ b/channels/serietvu.py @@ -1,257 +1,97 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per SerieTVU -# Thanks to Icarus crew & Alfa addon & 4l3x87 +# Canale per serietvu.py # ---------------------------------------------------------- + +""" + La pagina novità contiene al max 25 titoli +""" import re -from core import tmdb, scrapertools, support +from core import support, httptools, scrapertoolsV2 from core.item import Item from core.support import log -from platformcode import logger, config +from platformcode import config __channel__ = 'serietvu' host = config.get_channel_url(__channel__) headers = [['Referer', host]] -IDIOMAS = {'Italiano': 'IT'} -list_language = IDIOMAS.values() list_servers = ['speedvideo'] list_quality = ['default'] +@support.menu def mainlist(item): log() - itemlist = [] - support.menu(itemlist, 'Novità bold', 'latestep', "%s/ultimi-episodi" % host, 'tvshow') - support.menu(itemlist, 'Serie TV bold', 'lista_serie', "%s/category/serie-tv" % host, 'tvshow') - support.menu(itemlist, 'Categorie', 'categorie', host, 'tvshow') - support.menu(itemlist, 'Cerca', 'search', host, 'tvshow') - support.aplay(item, itemlist, list_servers, list_quality) - support.channel_config(item, itemlist) - return itemlist + + tvshow = ['/category/serie-tv', + ('Novità', ['/ultimi-episodi/', 'peliculas', 'update']), + ('Generi', ['', 'genres', 'genres']) + ] + + return locals() -# ---------------------------------------------------------------------------------------------------------------- -def cleantitle(scrapedtitle): - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle.strip()) - scrapedtitle = scrapedtitle.replace('[HD]', '').replace('’', '\'').replace('– Il Trono di Spade', '').replace( - 'Flash 2014', 'Flash').replace('"', "'") - year = scrapertools.find_single_match(scrapedtitle, '\((\d{4})\)') - if year: - scrapedtitle = scrapedtitle.replace('(' + year + ')', '') - - return scrapedtitle.strip() - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def lista_serie(item): +@support.scrape +def peliculas(item): log() - itemlist = [] - patron = r'<div class="item">\s*<a href="([^"]+)" data-original="([^"]+)" class="lazy inner">' - patron += r'[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<' - matches, data = support.match(item, patron, headers=headers) + patronBlock = r'<div class="wrap">\s+<h.>.*?</h.>(?P<block>.*?)<footer>' - for scrapedurl, scrapedimg, scrapedtitle in matches: - infoLabels = {} - year = scrapertools.find_single_match(scrapedtitle, '\((\d{4})\)') - if year: - infoLabels['year'] = year - scrapedtitle = cleantitle(scrapedtitle) + + if item.args != 'update': + action = 'episodios' + patron = r'<div class="item">\s*<a href="(?P<url>[^"]+)" data-original="(?P<thumb>[^"]+)" class="lazy inner">[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>[^<]+)<' + else: + action = 'findvideos' + patron = r'<div class="item">\s+?<a href="(?P<url>[^"]+)"\s+?data-original="(?P<thumb>[^"]+)"[^>]+>[^>]+>[^>]+>[^>]+>[^>]+>(?P<title>.+?)<[^>]+>\((?P<episode>[\dx\-]+)\s+?(?P<lang>Sub-Ita|[iITtAa]+)\)<' + pagination = 25 - itemlist.append( - Item(channel=item.channel, - action="episodios", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - thumbnail=scrapedimg, - show=scrapedtitle, - infoLabels=infoLabels, - contentType='episode', - folder=True)) + patronNext = r'<li><a href="([^"]+)"\s+?>Pagina successiva' - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) + #support.regexDbg(item, patron, headers) + #debug = True + return locals() - # Pagine - support.nextPage(itemlist, item, data, '<li><a href="([^"]+)">Pagina successiva') - - return itemlist - - -# ================================================================================================================ - - -# ---------------------------------------------------------------------------------------------------------------- +@support.scrape def episodios(item): log() - itemlist = [] - patron = r'<option value="(\d+)"[\sselected]*>.*?</option>' - matches, data = support.match(item, patron, headers=headers) - - for value in matches: - patron = r'<div class="list [active]*" data-id="%s">(.*?)</div>\s*</div>' % value - blocco = scrapertools.find_single_match(data, patron) - log(blocco) - patron = r'(<a data-id="\d+[^"]*" data-href="([^"]+)"(?:\sdata-original="([^"]+)")?\sclass="[^"]+">)[^>]+>[^>]+>([^<]+)<' - matches = scrapertools.find_multiple_matches(blocco, patron) - - for scrapedextra, scrapedurl, scrapedimg, scrapedtitle in matches: - contentlanguage = '' - if 'sub-ita' in scrapedtitle.lower(): - contentlanguage = 'Sub-ITA' - scrapedtitle = scrapedtitle.replace(contentlanguage, '') - - number = cleantitle(scrapedtitle.replace("Episodio", "")).strip() - - title = value + "x" + number.zfill(2) - title += " "+support.typo(contentlanguage, '_ [] color kod') if contentlanguage else '' - - infoLabels = {} - infoLabels['episode'] = number.zfill(2) - infoLabels['season'] = value - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - title=title, - fulltitle=scrapedtitle, - contentType="episode", - url=scrapedurl, - thumbnail=scrapedimg, - extra=scrapedextra, - infoLabels=infoLabels, - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - support.videolibrary(itemlist, item, 'bold color kod') - - return itemlist + patronBlock = r'</select><div style="clear:both"></div></h2>(?P<block>.*?)<div id="trailer" class="tab">' + patron = r'(?:<div class="list (?:active)?" data-id="(?P<season>\d+)">[^>]+>)?\s+<a data-id="(?P<episode>\d+)(?:[ ](?P<lang>[SuUbBiItTaA\-]+))?"(?P<url>[^>]+)>[^>]+>[^>]+>(?P<title>.+?)(?:\sSub-ITA)?<' + + #support.regexDbg(item, patronBlock, headers) + #debug = True + return locals() -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def findvideos(item): - log() - return support.server(item, data=item.url) - - - -# ================================================================================================================ - - -# ---------------------------------------------------------------------------------------------------------------- -def findepisodevideo(item): +@support.scrape +def genres(item): log() - patron_block = r'<div class="list [active]*" data-id="%s">(.*?)</div>\s*</div>' % item.extra[0][0] - patron = r'<a data-id="%s[^"]*" data-href="([^"]+)"(?:\sdata-original="[^"]+")?\sclass="[^"]+">' % item.extra[0][1].lstrip("0") - matches = support.match(item, patron, patron_block, headers)[0] - data = '' - if len(matches) > 0: - data = matches[0] - item.contentType = 'movie' - return support.server(item, data=data) + blacklist = ["Home Page", "Calendario Aggiornamenti"] + action = 'peliculas' + patronBlock = r'<h2>Sfoglia</h2>\s*<ul>(?P<block>.*?)</ul>\s*</section>' + patron = r'<li><a href="(?P<url>[^"]+)">(?P<title>[^<]+)</a></li>' + #debug = True + + return locals() -# ================================================================================================================ +def search(item, text): + log(text) + item.url = host + "/?s=" + text + try: + item.contentType = 'tvshow' + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + log("%s" % line) + return [] - -# ---------------------------------------------------------------------------------------------------------------- -def latestep(item): - log() - itemlist = [] - titles = [] - - patron_block = r"Ultimi episodi aggiunti.*?<h2>" - patron = r'<a href="([^"]*)"\sdata-src="([^"]*)"\sclass="owl-lazy.*?".*?class="title">(.*?)<small>\((\d*?)x(\d*?)\s(Sub-Ita|Ita)' - matches = support.match(item, patron, patron_block, headers, host)[0] - - for scrapedurl, scrapedimg, scrapedtitle, scrapedseason, scrapedepisode, scrapedlanguage in matches: - infoLabels = {} - year = scrapertools.find_single_match(scrapedtitle, '\((\d{4})\)') - if year: - infoLabels['year'] = year - infoLabels['episode'] = scrapedepisode - infoLabels['season'] = scrapedseason - episode = scrapedseason + "x" + scrapedepisode - - scrapedtitle = cleantitle(scrapedtitle) - title = scrapedtitle + " - " + episode - contentlanguage = "" - if scrapedlanguage.strip().lower() != 'ita': - title += " "+support.typo("Sub-ITA", '_ [] color kod') - contentlanguage = 'Sub-ITA' - - titles.append(title) - itemlist.append( - Item(channel=item.channel, - action="findepisodevideo", - title=title, - fulltitle=title, - url=scrapedurl, - extra=[[scrapedseason, scrapedepisode]], - thumbnail=scrapedimg, - contentSerieName=scrapedtitle, - contentLanguage=contentlanguage, - contentType='episode', - infoLabels=infoLabels, - folder=True)) - - patron = r'<div class="item">\s*<a href="([^"]+)" data-original="([^"]+)" class="lazy inner">' - patron += r'[^>]+>[^>]+>[^>]+>[^>]+>([^<]+)<small>([^<]+)<' - matches = support.match(item, patron, headers=headers)[0] - - for scrapedurl, scrapedimg, scrapedtitle, scrapedinfo in matches: - infoLabels = {} - year = scrapertools.find_single_match(scrapedtitle, '\((\d{4})\)') - if year: - infoLabels['year'] = year - scrapedtitle = cleantitle(scrapedtitle) - - infoLabels['tvshowtitle'] = scrapedtitle - - episodio = re.compile(r'(\d+)x(\d+)', re.DOTALL).findall(scrapedinfo) - infoLabels['episode'] = episodio[0][1] - infoLabels['season'] = episodio[0][0] - - episode = infoLabels['season'] + "x" + infoLabels['episode'] - title = "%s - %s" % (scrapedtitle, episode) - title = title.strip() - contentlanguage = "" - if 'sub-ita' in scrapedinfo.lower(): - title += " "+support.typo("Sub-ITA", '_ [] color kod') - contentlanguage = 'Sub-ITA' - - if title in titles: continue - itemlist.append( - Item(channel=item.channel, - action="findepisodevideo", - title=title, - fulltitle=title, - url=scrapedurl, - extra=episodio, - thumbnail=scrapedimg, - contentSerieName=scrapedtitle, - contentLanguage=contentlanguage, - infoLabels=infoLabels, - contentType='episode', - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- def newest(categoria): log(categoria) itemlist = [] @@ -259,45 +99,52 @@ def newest(categoria): try: if categoria == "series": item.url = host + "/ultimi-episodi" - item.action = "latestep" - itemlist = latestep(item) - - if itemlist[-1].action == "latestep": - itemlist.pop() + item.action = "peliculas" + item.contentType = 'tvshow' + item.args = 'update' + itemlist = peliculas(item) # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("{0}".format(line)) + log("{0}".format(line)) return [] return itemlist -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def search(item, texto): - log(texto) - item.url = host + "/?s=" + texto - try: - return lista_serie(item) - # Continua la ricerca in caso di errore - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -# ================================================================================================================ - -# ---------------------------------------------------------------------------------------------------------------- -def categorie(item): +def findvideos(item): log() - patron_block= r'<h2>Sfoglia</h2>\s*<ul>(.*?)</ul>\s*</section>' - patron = r'<li><a href="([^"]+)">([^<]+)</a></li>' - return support.scrape(item, patron, ['url','title'], patron_block=patron_block, action='lista_serie', blacklist=["Home Page", "Calendario Aggiornamenti"]) + if item.args != 'update': + return support.server(item, data=item.url) + else: + itemlist = [] + item.infoLabels['mediatype'] = 'episode' -# ================================================================================================================ + data = httptools.downloadpage(item.url, headers=headers).data + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) +## support.log("DATA - HTML:\n", data) + url_video = scrapertoolsV2.find_single_match(data, r'<div class="item"> <a data-id="[^"]+" data-href="([^"]+)" data-original="[^"]+"[^>]+> <div> <div class="title">Episodio \d+', -1) + url_serie = scrapertoolsV2.find_single_match(data, r'<link rel="canonical" href="([^"]+)"\s?/>') + goseries = support.typo("Vai alla Serie:", ' bold') + series = support.typo(item.contentSerieName, ' bold color kod') + + itemlist = support.server(item, data=url_video) + + itemlist.append( + Item(channel=item.channel, + title=goseries + series, + fulltitle=item.fulltitle, + show=item.show, + contentType='tvshow', + contentSerieName=item.contentSerieName, + url=url_serie, + action='episodios', + contentTitle=item.contentSerieName, + plot = goseries + series + "con tutte le puntate", + )) + + #support.regexDbg(item, patronBlock, headers) + return itemlist diff --git a/channels/spankwire.py b/channels/spankwire.py deleted file mode 100644 index 67a60e86..00000000 --- a/channels/spankwire.py +++ /dev/null @@ -1,102 +0,0 @@ -# -*- coding: utf-8 -*- -#------------------------------------------------------------ -import re -import urlparse - -from core import httptools -from core import scrapertools -from core.item import Item -from platformcode import logger -from platformcode import config - -host = 'https://www.spankwire.com' - -def mainlist(item): - logger.info() - itemlist = [] - itemlist.append( Item(channel=item.channel, title="Nuevas" , action="lista", url=host + "/recentvideos/straight")) - itemlist.append( Item(channel=item.channel, title="Mas Vistas" , action="lista", url=host + "/home1/Straight/Month/Views")) - itemlist.append( Item(channel=item.channel, title="Mejor valorada" , action="lista", url=host + "/home1/Straight/Month/Rating")) - itemlist.append( Item(channel=item.channel, title="Longitud" , action="lista", url=host + "/home1/Straight/Month/Duration")) - #itemlist.append( Item(channel=item.channel, title="Categorias" , action="categorias", url=host + "/categories/Straight")) - itemlist.append( Item(channel=item.channel, title="Buscar", action="search")) - return itemlist - - -def search(item, texto): - logger.info() - texto = texto.replace(" ", "+") - item.url = host + "/search/?q=%s" % texto - try: - return lista(item) - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def categorias(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<div class="category-thumb"><a href="([^"]+)".*?' - patron += '<img src="([^"]+)" alt="([^"]+)" />.*?' - patron += '<span>([^"]+)</span>' - matches = re.compile(patron,re.DOTALL).findall(data) - scrapertools.printMatches(matches) - for scrapedurl,scrapedthumbnail,scrapedtitle,cantidad in matches: - scrapedplot = "" - scrapedthumbnail = "http:" + scrapedthumbnail - scrapedtitle = scrapedtitle + " (" + cantidad +")" - scrapedurl = urlparse.urljoin(item.url,scrapedurl) + "/Submitted/59" - itemlist.append( Item(channel=item.channel, action="lista", title=scrapedtitle, url=scrapedurl, - fanart=scrapedthumbnail, thumbnail=scrapedthumbnail, plot=scrapedplot) ) - return itemlist - - -def lista(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - data = re.sub(r"\n|\r|\t| |<br>", "", data) - patron = '<div class="video_thumb_wrapper">.*?' - patron += '<a href="([^"]+)".*?data-original="([^"]+)".*?' - patron += 'title="([^"]+)".*?' - patron += '<div class="video_thumb_wrapper__thumb_info video_thumb_wrapper__duration">(.*?)</div>' - matches = re.compile(patron,re.DOTALL).findall(data) - for scrapedurl,scrapedthumbnail,scrapedtitle,duracion in matches: - url = urlparse.urljoin(item.url,scrapedurl) - title = "[COLOR yellow]" + duracion + "[/COLOR] " + scrapedtitle - contentTitle = title - thumbnail = scrapedthumbnail - plot = "" - itemlist.append( Item(channel=item.channel, action="play" , title=title , url=url, thumbnail=thumbnail, - fanart=thumbnail, plot=plot, contentTitle = contentTitle)) - next_page = scrapertools.find_single_match(data,'<link rel="next" href="([^"]+)" />') - #Para el buscador - if next_page=="": - next_page = scrapertools.find_single_match(data,'<div class="paginator_wrapper__buttons"><a class="" href="([^"]+)"') - next_page = urlparse.urljoin(item.url,next_page) - if next_page!="": - next_page = urlparse.urljoin(item.url,next_page) - itemlist.append( Item(channel=item.channel , action="lista" , title="Página Siguiente >>" , text_color="blue", url=next_page) ) - return itemlist - - -def play(item): - logger.info() - itemlist = [] - data = httptools.downloadpage(item.url).data - data = scrapertools.find_single_match(data,'Copy Embed Code(.*?)For Desktop') - patron = '<div class="shareDownload_container__item__dropdown">.*?<a href="([^"]+)"' - matches = scrapertools.find_multiple_matches(data, patron) - for scrapedurl in matches: - url = scrapedurl - if url=="#": - scrapedurl = scrapertools.find_single_match(data,'playerData.cdnPath480 = \'([^\']+)\'') - itemlist.append(item.clone(action="play", title=scrapedurl, fulltitle = scrapedurl, url=scrapedurl)) - - return itemlist - diff --git a/channels/streamingaltadefinizione.json b/channels/streamingaltadefinizione.json index 1cca3246..c028f749 100644 --- a/channels/streamingaltadefinizione.json +++ b/channels/streamingaltadefinizione.json @@ -1,19 +1,11 @@ { "id": "streamingaltadefinizione", - "name": "Streaming Altadefinizione", + "name": "Popcorn Stream", "language": ["ita"], "active": true, "adult": false, - "thumbnail": "https://www.streamingaltadefinizione.world/wp-content/uploads/2018/09/StreamingAltadefinizioneLogo.png", + "thumbnail": "popcornstream.png", + "banner": "popcornstream.png", "categories": ["movie","tvshow","anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": true, - "enabled": true, - "visible": true - } - ] + "settings": [] } diff --git a/channels/streamingaltadefinizione.py b/channels/streamingaltadefinizione.py index 0406e670..ce616fb3 100644 --- a/channels/streamingaltadefinizione.py +++ b/channels/streamingaltadefinizione.py @@ -1,35 +1,40 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Canale per Streaming Altadefinizione +# Canale per Popcorn Stream # ------------------------------------------------------------ -from core import support +from core import support, httptools from core.item import Item -from specials import autoplay from platformcode import config -__channel__ = "streamingaltadefinizione" -host = config.get_channel_url(__channel__) +# __channel__ = "streamingaltadefinizione" +# host = config.get_channel_url(__channel__) +host = headers = '' list_servers = ['verystream', 'openload', 'wstream'] list_quality = ['1080p', 'HD', 'DVDRIP', 'SD', 'CAM'] +def findhost(): + global host, headers + permUrl = httptools.downloadpage('https://www.popcornstream.info', follow_redirects=False).headers + if 'google' in permUrl['location']: + if host[:4] != 'http': + host = 'https://'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') + else: + host = permUrl['location'].replace('https://www.google.it/search?q=site:', '') + else: + host = permUrl['location'] + headers = [['Referer', host]] + +@support.menu def mainlist(item): - support.log() - itemlist = [] + findhost() + film = ["/film/"] + anime = ["/genere/anime/"] + tvshow = ["/serietv/"] + top = [('Generi',['', 'generos'])] - support.menu(itemlist, 'Film', 'peliculas', host + "/film/") - support.menu(itemlist, 'Film Anime', 'peliculas', host + "/genere/anime/") - support.menu(itemlist, 'Film per genere', 'generos', host) - support.menu(itemlist, 'Serie TV', 'peliculas', host + "/serietv/", contentType='tvshow') - support.menu(itemlist, 'Anime', 'peliculas', host + "/genere/anime/", contentType='tvshow') - support.menu(itemlist, 'Cerca film', 'search', host) - support.menu(itemlist, 'Cerca serie tv', 'search', host, contentType='tvshow') - - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - return itemlist + return locals() def search(item, text): @@ -39,38 +44,39 @@ def search(item, text): return support.dooplay_search(item) +@support.scrape def generos(item): - patron = '<a href="([^"#]+)">([a-zA-Z]+)' - return support.scrape(item, patron, ['url', 'title'], patron_block='<a href="#">Genere</a><ul class="sub-menu">.*?</ul>', action='peliculas') + patron = '<a href="(?P<url>[^"#]+)">(?P<title>[a-zA-Z]+)' + patronBlock='<a href="#">Genere</a><ul class="sub-menu">(?P<block>.*?)</ul>' + action='peliculas' + + return locals() def peliculas(item): - support.log("[streamingaltadefinizione.py] video") - - return support.dooplay_films(item) + findhost() + return support.dooplay_peliculas(item, True if "/genere/" in item.url else False) def episodios(item): + findhost() return support.dooplay_get_episodes(item) def findvideos(item): + findhost() itemlist = [] for link in support.dooplay_get_links(item, host): - server = link['server'][:link['server'].find(".")] - itemlist.append( - Item(channel=item.channel, - action="play", - title=server + " [COLOR blue][" + link['title'] + "][/COLOR]", - url=link['url'], - server=server, - fulltitle=item.fulltitle, - thumbnail=item.thumbnail, - show=item.show, - quality=link['title'], - contentType=item.contentType, - folder=False)) + if link['title'] != 'Guarda il trailer': + itemlist.append( + Item(channel=item.channel, + action="play", + url=link['url'], + fulltitle=item.fulltitle, + thumbnail=item.thumbnail, + show=item.show, + quality=link['title'], + contentType=item.contentType, + folder=False)) - autoplay.start(itemlist, item) - - return itemlist \ No newline at end of file + return support.server(item, itemlist=itemlist) diff --git a/channels/streamtime.json b/channels/streamtime.json new file mode 100644 index 00000000..c0a8b2e6 --- /dev/null +++ b/channels/streamtime.json @@ -0,0 +1,53 @@ +{ + "id": "streamtime", + "name": "StreamTime", + "language": ["ita"], + "active": false, + "adult": false, + "thumbnail": "", + "banner": "streamtime.png", + "categories": ["tvshow", "movie"], + "settings": [ + { + "id": "include_in_global_search", + "type": "bool", + "label": "Includi in Ricerca Globale", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "Includi in Novità - Film", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_italiano", + "type": "bool", + "label": "Includi in Novità - Italiano", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "checklinks", + "type": "bool", + "label": "Verifica se i link esistono", + "default": false, + "enabled": true, + "visible": true + }, + { + "id": "checklinks_number", + "type": "list", + "label": "Numero di link da verificare", + "default": 1, + "enabled": true, + "visible": "eq(-1,true)", + "lvalues": [ "5", "10", "15", "20" ] + } + ] +} diff --git a/channels/streamtime.py b/channels/streamtime.py new file mode 100644 index 00000000..c1191f53 --- /dev/null +++ b/channels/streamtime.py @@ -0,0 +1,141 @@ +# -*- coding: utf-8 -*- +from core import support, httptools, scrapertoolsV2 +from core.item import Item +from platformcode import config, logger + +__channel__ = "streamtime" +host = config.get_channel_url(__channel__) +headers = [['Referer', 'org.telegram.messenger']] +list_servers = ['directo'] +list_quality = ['default'] + +downPrefix = 'https://stsh.ml/Down-' + +@support.menu +def mainlist(item): + film = ['?q=%23Film'] + tvshow = ['?q=%23SerieTv'] + return locals() + + +@support.scrape +def peliculas(item): + patron = """tgme_widget_message_photo_wrap blured.*?image:url\("(?P<thumbnail>[^"]+).*?(?:🎥|🎬)(?P<title>.*?)(?:🎥|🎬).*?(?:Audio(?:</b>)?: (?P<lang>.*?<br>))?.*?Anno(?:</b>)?: (?P<year>[0-9]{4}).*?(?:<b>Stream</b>|Risoluzione|<b>Tipo</b>): (?P<quality>[^<]+).*?tgme_widget_message_inline_button url_button" href="(?P<url>[^"]+)""" + def itemlistHook(itemlist): + retItemlist = [] + # filtro per tipo + for i in itemlist: + if item.contentType == 'movie': + if '/Film/' in i.url or 'Stream-' in i.url: + retItemlist.append(i) + else: + if '/SerieTv/' in i.url: + retItemlist.append(i) + # rimuovo duplicati + if item.contentType != 'movie': + nonDupl = [] + # support.dbg() + for i in retItemlist: + for nd in nonDupl: + if i.title == nd.title: + break + else: + daAgg = i + spl1 = i.url.split('-') + stagione1 = spl1[-2] + nEp1 = int(spl1[-1]) + + for i2 in retItemlist[1:]: + if i.title == i2.title: + spl2 = i2.url.split('-') + stagione2 = spl2[-2] + nEp2 = int(spl2[-1]) + if stagione1 == stagione2 and nEp2 > nEp1: + daAgg = i2 + nonDupl.append(daAgg) + retItemlist = nonDupl + return retItemlist[::-1] + # debug = True + patronNext = 'tgme_widget_message_photo_wrap blured" href="([^"]+)' + def fullItemlistHook(itemlist): + msgId = int(itemlist[-1].url.split('/')[-1]) + itemlist[-1].url = host + '?before=' + str(msgId) + '&after=' + str(msgId-20) + return itemlist + + if item.contentType == 'tvshow': + action = 'episodios' + return locals() + + +def search(item, texto): + item.url = host + "/?q=" + texto + try: + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def episodios(item): + domain, id, season, episode = scrapertoolsV2.find_single_match(item.url, r'(https?://[a-z0-9.-]+).*?/([^-/]+)-S([0-9]+)-([0-9]+)$') + itemlist = [] + for n in range(1, int(episode)): + url = domain + '/play_s.php?s=' + id + '-S' + season + '&e=' + str(n) + itemlist.append( + Item(channel=item.channel, + action="findvideos", + title=str(int(season)) + 'x' + str(n) + support.typo(item.quality, '-- [] color kod'), + url=url, + fulltitle=item.fulltitle, + thumbnail=item.thumbnail, + show=item.show, + quality=item.quality, + contentType=item.contentType, + folder=False, + args={'id': id, 'season': season, 'episode': episode})) + + support.videolibrary(itemlist, item) + return itemlist + + +def findvideos(item): + domain = scrapertoolsV2.find_single_match(item.url, 'https?://[a-z0-9.-]+') + if item.contentType == 'movie': + id = item.url.split('/')[-1] + url = domain + '/play_f.php?f=' + id + else: + url = item.url + id = item.args['id'] + season = item.args['season'] + episode = item.args['episode'] + res = support.match(item, 'src="([^"]+)">.*?</video>', url=url, headers=[['Referer', domain]]) + itemlist = [] + support.dbg() + + if res[0]: + itemlist.append( + Item(channel=item.channel, + action="play", + title='stpgs.ml' + support.typo(item.quality, '-- [] color kod'), + url=res[0][0], + server='directo', + fulltitle=item.fulltitle, + thumbnail=item.thumbnail, + show=item.show, + quality=item.quality, + contentType=item.contentType, + folder=False)) + download = itemlist[0].clone() + if item.contentType == 'movie': + download.url = downPrefix + id + else: + download.url = downPrefix + id + 'S' + season + '-' + episode + itemlist.append(download) + else: + # google drive... + pass + support.videolibrary(itemlist, item) + return support.controls(itemlist, item, True, True) diff --git a/channels/tantifilm.json b/channels/tantifilm.json index a869f0de..e50875c3 100644 --- a/channels/tantifilm.json +++ b/channels/tantifilm.json @@ -4,76 +4,9 @@ "language": ["ita"], "active": true, "adult": false, - "thumbnail": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/tantifilm.png", - "banner": "https://raw.githubusercontent.com/Zanzibar82/images/master/posters/tantifilm.png", - "categories": ["tvshow", "movie", "anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in ricerca globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero di link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": ["Non filtrare","IT"] - }, - { - "id": "autorenumber", - "type": "bool", - "label": "@70712", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "autorenumber_mode", - "type": "bool", - "label": "@70688", - "default": false, - "enabled": true, - "visible": "eq(-1,true)" - } - ] + "thumbnail": "tantifilm.png", + "banner": "tantifilm.png", + "categories": ["tvshow", "movie", "anime"], + "not_active":["include_in_newest_anime"], + "settings": [] } diff --git a/channels/tantifilm.py b/channels/tantifilm.py index 0a285bc5..a9b048c4 100644 --- a/channels/tantifilm.py +++ b/channels/tantifilm.py @@ -2,6 +2,13 @@ # ------------------------------------------------------------ # Canale per Tantifilm # ------------------------------------------------------------ +""" + + Trasformate le sole def per support.menu e support.scrape + da non inviare nel test. + Test solo a trasformazione completa + +""" import re @@ -24,25 +31,45 @@ host = config.get_channel_url(__channel__) headers = [['Referer', host]] - +@support.menu def mainlist(item): log() - itemlist = [] + + film = ['/film/', + ('Al Cinema', ['/watch-genre/al-cinema/', 'peliculas', 'movie']), + ('HD',['/watch-genre/altadefinizione/', 'peliculas', 'movie']), + ('Categorie', ['', 'category', 'movie']) + ] - menu(itemlist, 'Film', 'peliculas', host + '/film/', 'movie', args='movie') - menu(itemlist, 'Film Al Cinema submenu', 'peliculas', host + '/watch-genre/al-cinema/', 'movie') - menu(itemlist, 'Film HD submenu', 'peliculas', host + '/watch-genre/altadefinizione/', 'movie') - menu(itemlist, 'Film Per Categoria submenu', 'category', host, 'movie') - menu(itemlist, 'Cerca film... submenu color kod', 'search', contentType='movie', args='findvideos') - menu(itemlist, 'Serie TV', 'peliculas', host + '/watch-genre/serie-tv/', contentType='episode') - menu(itemlist, 'Serie TV HD submenu', 'peliculas', host + '/watch-genre/serie-altadefinizione/', contentType='episode') - menu(itemlist, 'Miniserie submenu', 'peliculas', host + '/watch-genre/miniserie/', contentType='episode', args='serie') - menu(itemlist, 'Programmi TV submenu', 'peliculas', host + '/watch-genre/programmi-tv/', contentType='episode') - menu(itemlist, 'Anime submenu', 'peliculas', host + '/watch-genre/anime/', contentType='episode', args='anime') - menu(itemlist, 'Cerca Serie TV... submenu color kod', 'search', contentType='episode', args='episodios') - aplay(item, itemlist, list_servers, list_quality) + tvshow = ['/watch-genre/serie-tv/', + ('HD', ['/watch-genre/serie-altadefinizione/', 'peliculas']), + ('Miniserie', ['/watch-genre/miniserie/', 'peliculas', 'serie']), + ('Programmi TV', ['/watch-genre/programmi-tv/', 'peliculas']) + ] - return itemlist + pinco = [('Anime', ['/watch-genre/anime/', 'peliculas', 'anime'])] + + + return locals() + +##def mainlist(item): +## log() +## itemlist = [] +## +## menu(itemlist, 'Film', 'peliculas', host + '/film/', 'movie', args='movie') +## menu(itemlist, 'Film Al Cinema submenu', 'peliculas', host + '/watch-genre/al-cinema/', 'movie') +## menu(itemlist, 'Film HD submenu', 'peliculas', host + '/watch-genre/altadefinizione/', 'movie') +## menu(itemlist, 'Film Per Categoria submenu', 'category', host, 'movie') +## menu(itemlist, 'Cerca film... submenu color kod', 'search', contentType='movie', args='findvideos') +## menu(itemlist, 'Serie TV', 'peliculas', host + '/watch-genre/serie-tv/', contentType='episode') +## menu(itemlist, 'Serie TV HD submenu', 'peliculas', host + '/watch-genre/serie-altadefinizione/', contentType='episode') +## menu(itemlist, 'Miniserie submenu', 'peliculas', host + '/watch-genre/miniserie/', contentType='episode', args='serie') +## menu(itemlist, 'Programmi TV submenu', 'peliculas', host + '/watch-genre/programmi-tv/', contentType='episode') +## menu(itemlist, 'Anime submenu', 'peliculas', host + '/watch-genre/anime/', contentType='episode', args='anime') +## menu(itemlist, 'Cerca Serie TV... submenu color kod', 'search', contentType='episode', args='episodios') +## aplay(item, itemlist, list_servers, list_quality) +## +## return itemlist def newest(categoria): @@ -120,24 +147,43 @@ def search_peliculas(item): return itemlist - +@support.scrape def category(item): - blacklist = ['Serie TV Altadefinizione', 'HD AltaDefinizione', 'Al Cinema', 'Serie TV', 'Miniserie', 'Programmi Tv', 'Live', 'Trailers', 'Serie TV Aggiornate', 'Aggiornamenti', 'Featured'] - itemlist = support.scrape(item, '<li><a href="([^"]+)"><span></span>([^<]+)</a></li>', ['url', 'title'], headers, blacklist, patron_block='<ul class="table-list">(.*?)</ul>', action='peliculas') - return support.thumb(itemlist) + log() + action = 'peliculas' + blacklist = ['Serie TV Altadefinizione', 'HD AltaDefinizione', 'Al Cinema', + 'Serie TV', 'Miniserie', 'Programmi Tv', 'Live', 'Trailers', + 'Serie TV Aggiornate', 'Aggiornamenti', 'Featured', 'Ultimi Film Aggiornati'] + patron = r'<li><a href="(?P<url>[^"]+)"><span></span>(?P<title>[^<]+)</a></li>' + patronBlock = r'<ul class="table-list">(?P<block>.*?)</ul>' + return locals() +## itemlist = support.scrape(item, '<li><a href="([^"]+)"><span></span>([^<]+)</a></li>', ['url', 'title'], headers, blacklist, patron_block='<ul class="table-list">(.*?)</ul>', action='peliculas') + +## return support.thumb(itemlist) + +@support.scrape def peliculas(item): log() + action = 'findvideos' if item.extra == 'movie' else 'episodios' - if item.args == 'movie': - patron= r'<div class="mediaWrap mediaWrapAlt">[^<]+<a href="([^"]+)" title="Permalink to\s([^"]+) \(([^<]+)\).*?"[^>]+>[^<]+<img[^s]+src="([^"]+)"[^>]+>[^<]+<\/a>.*?<p>\s*([a-zA-Z-0-9]+)\s*<\/p>' - itemlist = support.scrape(item, patron, ['url', 'title', 'year', 'thumb', 'quality'], headers, action=action, patron_block='<div id="main_col">(.*?)main_col', patronNext='<a class="nextpostslink" rel="next" href="([^"]+)">') + + if item.args == 'movie' or item.extra == 'movie': + patron = r'<div class="mediaWrap mediaWrapAlt">[^<]+<a href="(?P<url>[^"]+)" title="Permalink to\s(?P<title>[^"]+) \((?P<year>[^<]+)\).*?"[^>]+>[^<]+<img[^s]+src="(?P<thumb>[^"]+)"[^>]+>[^<]+<\/a>.*?<p>\s*(?P<quality>[a-zA-Z-0-9]+)\s*<\/p>' + patronBlock = '<div id="main_col">(?P<block>.*?)main_col' +## itemlist = support.scrape(item, patron, ['url', 'title', 'year', 'thumb', 'quality'], headers, action=action, patron_block='<div id="main_col">(.*?)main_col', patronNext='<a class="nextpostslink" rel="next" href="([^"]+)">') + patronNext = '<a class="nextpostslink" rel="next" href="([^"]+)">' + else: - patron = r'<div class="media3">[^>]+><a href="([^"]+)"><img[^s]+src="([^"]+)"[^>]+><\/a><[^>]+><a[^<]+><p>([^<]+) \(([^\)]+)[^<]+<\/p>.*?<p>\s*([a-zA-Z-0-9]+)\s*<\/p>' - itemlist = support.scrape(item, patron, ['url', 'thumb', 'title', 'year', 'quality'], headers, action=action, patronNext='<a class="nextpostslink" rel="next" href="([^"]+)">') + patron = r'<div class="media3">[^>]+><a href="(?P<url>[^"]+)"><img[^s]+src="(?P<thumb>[^"]+)"[^>]+><\/a><[^>]+><a[^<]+><p>(?P<title>[^<]+) \((?P<year>[^\)]+)[^<]+<\/p>.*?<p>\s*(?P<quality>[a-zA-Z-0-9]+)\s*<\/p>' + patronNext='<a class="nextpostslink" rel="next" href="([^"]+)">' + action = action +# itemlist = support.scrape(item, patron, ['url', 'thumb', 'title', 'year', 'quality'], headers, action=action, patronNext='<a class="nextpostslink" rel="next" href="([^"]+)">') if item.args == 'anime': autorenumber.renumber(itemlist) - return itemlist + +## return itemlist + return locals() def episodios(item): @@ -149,7 +195,9 @@ def episodios(item): # Check if is series check = scrapertoolsV2.find_single_match(data.replace('\t','').replace('\n',''), r'<div class="category-film"><h3>([^<]+)<\/h3>') + if 'serie tv' not in check.lower(): return findvideos(item) + elif 'anime' in check.lower(): return findvideos(item) patron = r'<iframe src="([^"]+)" scrolling="no" frameborder="0" width="626" height="550" allowfullscreen="true" webkitallowfullscreen="true" mozallowfullscreen="true">' diff --git a/channels/toonitalia.json b/channels/toonitalia.json index 1ba2b01d..15f0a135 100644 --- a/channels/toonitalia.json +++ b/channels/toonitalia.json @@ -1,65 +1,13 @@ { "id": "toonitalia", "name": "ToonItalia", - "language": ["ita"], + "language": ["ita", "sub-ita"], "active": true, "adult": false, "thumbnail": "toonitalia.png", "banner": "toonitalia.png", - "categories": ["tvshow", "movie", "vosi", "anime"], - "settings": [ - { - "id": "include_in_global_search", - "type": "bool", - "label": "Includi in Ricerca Globale", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_peliculas", - "type": "bool", - "label": "Includi in Novità - Film", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "include_in_newest_italiano", - "type": "bool", - "label": "Includi in Novità - Italiano", - "default": true, - "enabled": true, - "visible": true - }, - { - "id": "checklinks", - "type": "bool", - "label": "Verifica se i link esistono", - "default": false, - "enabled": true, - "visible": true - }, - { - "id": "checklinks_number", - "type": "list", - "label": "Numero di link da verificare", - "default": 1, - "enabled": true, - "visible": "eq(-1,true)", - "lvalues": [ "5", "10", "15", "20" ] - }, - { - "id": "filter_languages", - "type": "list", - "label": "Mostra link in lingua...", - "default": 0, - "enabled": true, - "visible": true, - "lvalues": [ - "No filtrar", - "Italiano" - ] - } - ] -} \ No newline at end of file + "categories": ["tvshow", "movie", "vos", "anime"], + "not_active":["include_in_newest_peliculas", "include_in_newest_series"], + "default_off":["include_in_newest"], + "settings": [] +} diff --git a/channels/toonitalia.py b/channels/toonitalia.py index 89804615..693861cc 100644 --- a/channels/toonitalia.py +++ b/channels/toonitalia.py @@ -1,363 +1,125 @@ # -*- coding: utf-8 -*- # ------------------------------------------------------------ -# Ringraziamo Icarus crew # Canale per ToonItalia # ------------------------------------------------------------ -import re - -from core import scrapertools, httptools, tmdb, support, servertools -from core.item import Item -from platformcode import logger -from specials import autoplay -from platformcode import config +from core import support __channel__ = "toonitalia" -host = config.get_channel_url(__channel__) +host = support.config.get_channel_url(__channel__) headers = [['Referer', host]] list_servers = ['wstream', 'openload', 'streamango'] list_quality = ['HD', 'default'] + +@support.menu def mainlist(item): - # Main options - itemlist = [] - support.menu(itemlist, 'Ultimi episodi inseriti bold', 'insert', host, contentType='episode') - support.menu(itemlist, 'Ultime novità bold', 'updates', host, contentType='episode') - support.menu(itemlist, 'Episodi più visti bold', 'most_view', host, contentType='episode') - support.menu(itemlist, 'Anime', 'list', host + '/lista-anime-2/', contentType='episode') - support.menu(itemlist, 'Sub-Ita submenu', 'list', host + '/lista-anime-sub-ita/', contentType='episode') - support.menu(itemlist, 'Serie TV bold', 'list', host + '/lista-serie-tv/', contentType='episode') - support.menu(itemlist, 'Film Animazione bold', 'list', host + '/lista-film-animazione/', contentType="episode", args="film") - support.menu(itemlist, '[COLOR blue]Cerca anime e serie...[/COLOR] bold', 'search', host, contentType='episode') + top = [('Novità',['', 'peliculas', 'new', 'tvshow']), + ('Aggiornamenti', ['', 'peliculas', 'last', 'tvshow']), + ('Popolari', ['', 'peliculas', 'most_view', 'tvshow'])] + tvshow = ['/lista-serie-tv/'] + anime =['/lista-anime-2/', + ('Sub-Ita',['/lista-anime-sub-ita/', 'peliculas', 'sub']), + ('Film Animati',['/lista-film-animazione/','peliculas', '', 'movie'])] + search = '' + return locals() - autoplay.init(item.channel, list_servers, list_quality) - autoplay.show_option(item.channel, itemlist) - - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def insert(item): - logger.info("[toonitalia.py] insert") - itemlist = [] - minpage = 14 - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<h2 class="entry-title"><a href="([^"]+)" rel="bookmark">([^<]+)</a></h2>.*?' - patron += r'<p class[^>]+><a href="[^"]+"><img width[^>]+src="([^"]+)" class[^>]+>.*?' - patron += r'<p>(.*?)<\/p>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for i, (scrapedurl, scrapedtitle, scrapedthumbnail, scrapedplot) in enumerate(matches): - if (p - 1) * minpage > i: continue - if i >= p * minpage: break - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - - itemlist.append( - Item(channel=__channel__, - action="episodios", - contentType="episode", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - thumbnail=scrapedthumbnail, - plot=scrapedplot, - folder=True)) - - if len(matches) >= p * minpage: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=__channel__, - args=item.args, - action="insert", - title="[COLOR blue][B]Successivo >[/B][/COLOR]", - url=scrapedurl, - thumbnail="thumb_next.png", - folder=True)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def updates(item): - logger.info("[toonitalia.py] updates") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = r'Aggiornamenti</h2>(.*?)</ul>' - matches = re.compile(blocco, re.DOTALL).findall(data) - for scrapedurl in matches: - blocco = scrapedurl - - patron = r'<a href="(.*?)">(.*?)</a>' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append( - Item(channel=__channel__, - action="episodios", - contentType="episode", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def most_view(item): - logger.info("[toonitalia.py] most_view") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - - blocco = r'I piu visti</h2>(.*?)</ul>' - matches = re.compile(blocco, re.DOTALL).findall(data) - for scrapedurl in matches: - blocco = scrapedurl - - patron = r'<a href="([^"]+)" title="[^"]+" class="wpp-post-title" target="_self">([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(blocco) - - for scrapedurl, scrapedtitle in matches: - scrapedplot = "" - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append( - Item(channel=__channel__, - action="episodios", - contentType="episode", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - plot=scrapedplot)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def list(item): - logger.info("[toonitalia.py] list") - itemlist = [] - minpage = 14 - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<li ><a href="([^"]+)" title="[^>]+">([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - for i, (scrapedurl, scrapedtitle) in enumerate(matches): - if (p - 1) * minpage > i: continue - if i >= p * minpage: break - if 'Film Animazione disponibili' not in scrapedtitle: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - scrapedplot = "" - itemlist.append( - Item(channel=__channel__, - action = 'episodios' if not 'film' in item.args else 'findvideos', - contentType=item.contentType, - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - args=item.args, - plot=scrapedplot)) - - if len(matches) >= p * minpage: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=__channel__, - args=item.args, - contentType=item.contentType, - action="list", - title="[COLOR blue][B]Successivo >[/B][/COLOR]", - url=scrapedurl)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def peliculas(item): - logger.info("[toonitalia] peliculas") - itemlist = [] - minpage = 14 - - p = 1 - if '{}' in item.url: - item.url, p = item.url.split('{}') - p = int(p) - - data = httptools.downloadpage(item.url, headers=headers).data - - patron = r'<h2 class="entry-title"><a href="([^"]+)" rel="bookmark">([^<]+)</a></h2>.*?<p>([^<]+)</p>' - matches = re.compile(patron, re.DOTALL).findall(data) - - print data - - for i, (scrapedurl, scrapedtitle, scrapedplot) in enumerate(matches): - if (p - 1) * minpage > i: continue - if i >= p * minpage: break - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle) - itemlist.append( - Item(channel=__channel__, - action="episodios", - contentType="episode", - title=scrapedtitle, - fulltitle=scrapedtitle, - url=scrapedurl, - show=scrapedtitle, - plot=scrapedplot)) - - if len(matches) >= p * minpage: - scrapedurl = item.url + '{}' + str(p + 1) - itemlist.append( - Item(channel=__channel__, - extra=item.extra, - action="peliculas", - title="[COLOR blue][B]Successivo >[/B][/COLOR]", - url=scrapedurl)) - - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- - -def episodios(item): - logger.info("[toonitalia.py] episodios") - itemlist = [] - - data = httptools.downloadpage(item.url, headers=headers).data - support.log('DATA= ', data) - - patron = r'<br />\s*<a href="([^"]+)"\s*target="_blank"\s*rel[^>]+>([^<]+)</a>' - matches = re.compile(patron, re.DOTALL).findall(data) - - if "https://vcrypt.net" in data: - patron = r'(?:<p>|<br />)\s*([^<]+) – <a href="([^"]+)' - matches = re.compile(patron, re.DOTALL).findall(data) - - for scrapedtitle, scrapedurl in matches: - if 'Wikipedia' not in scrapedurl: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle).replace("×", "x") - scrapedtitle = scrapedtitle.replace("_", " ") - scrapedtitle = scrapedtitle.replace(".mp4", "") - puntata = scrapedtitle - for i in itemlist: - if i.args == puntata: # è già stata aggiunta - i.url += " " + scrapedurl - break - - else: - itemlist.append( - Item(channel=__channel__, - action="findvideos", - contentType=item.contentType, - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - thumbnail=item.thumbnail, - fulltitle=scrapedtitle, - url=scrapedurl, - args=puntata, - show=item.show, - plot=item.plot)) - else: - for scrapedurl, scrapedtitle in matches: - if 'Wikipedia' not in scrapedurl: - scrapedtitle = scrapertools.decodeHtmlentities(scrapedtitle).replace("×", "x") - scrapedtitle = scrapedtitle.replace("_", " ") - scrapedtitle = scrapedtitle.replace(".mp4", "") - # puntata = scrapertools.find_single_match(scrapedtitle, '[0-9]+x[0-9]+') - puntata = scrapedtitle - for i in itemlist: - if i.args == puntata: #è già stata aggiunta - i.url += " " + scrapedurl - break - - else: - itemlist.append( - Item(channel=__channel__, - action="findvideos", - contentType=item.contentType, - title="[COLOR azure]" + scrapedtitle + "[/COLOR]", - thumbnail=item.thumbnail, - fulltitle=scrapedtitle, - url=scrapedurl, - args = puntata, - show=item.show, - plot=item.plot)) - - support.videolibrary(itemlist, item, 'color kod') - - return itemlist - -#---------------------------------------------------------------------------------------------------------------------------------------------- def search(item, texto): - logger.info("[toonitalia.py] " + item.url + " search " + texto) - item.url = host + "/?s=" + texto + support.log(texto) + item.args='search' + item.contentType='tvshow' + item.url = host + '/?s=' + texto try: return peliculas(item) - + return itemlist + # Continua la ricerca in caso di errore except: import sys for line in sys.exc_info(): - logger.error("%s" % line) + support.logger.error("%s" % line) return [] -#---------------------------------------------------------------------------------------------------------------------------------------------- + +def newest(categoria): + support.log(categoria) + item = support.Item() + try: + item.contentType = 'tvshow' + item.url= host + item.args= 'new' + return peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + support.logger.error("{0}".format(line)) + return [] + + +@support.scrape +def peliculas(item): + pagination = '' + anime = True + blacklist = ['-Film Animazione disponibili in attesa di recensione '] + + if item.args == 'search': + patron = r'<h2 class="entry-title"><a href="(?P<url>[^"]+)" rel="bookmark">(?P<title>[^<]+)</a>.*?<p>(?P<plot>[^<]+)</p>.*?<span class="cat-links">Pubblicato in.*?.*?(?P<type>(?:[Ff]ilm|</artic))[^>]+>' + typeContentDict={'movie':['film']} + typeActionDict={'findvideos':['film']} + patronNext = r'<a href="([^"]+)"\s*>Articoli meno recenti' + elif item.args == 'last': + patronBlock = 'Aggiornamenti</h2>(?P<block>.*)</ul>' + patron = r'<a href="(?P<url>[^"]+)">(?P<title>[^<]+)</a>' + elif item.args == 'most_view': + patronBlock = 'I piu visti</h2>(?P<block>.*)</ul>' + patron = r'<a href="(?P<url>[^"]+)" title="(?P<title>[^"]+)"' + elif item.args == 'new': + patronBlock = '<main[^>]+>(?P<block>.*)</main>' + patron = r'<a href="(?P<url>[^"]+)" rel="bookmark">(?P<title>[^<]+)</a>[^>]+>[^>]+>[^>]+><img.*?src="(?P<thumb>[^"]+)".*?<p>(?P<plot>[^<]+)</p>.*?<span class="cat-links">Pubblicato in.*?.*?(?P<type>(?:[Ff]ilm|</artic))[^>]+>' + patronNext = '<a class="next page-numbers" href="([^"]+)">' + typeContentDict={'movie':['film']} + typeActionDict={'findvideos':['film']} + else: + patronBlock = '"lcp_catlist"[^>]+>(?P<block>.*)</ul>' + patron = r'<li ><a href="(?P<url>[^"]+)" title="[^>]+">(?P<title>[^<|\(]+)?(?:\([^\d]*(?P<year>\d+)\))?[^<]*</a>' + + def itemHook(item): + support.log(item.title) + item.title = support.re.sub(' (?:- )?[Ss]erie [Tt][Vv]', '', item.title) + if item.args == 'sub': + #corregge l'esatta lang per quelle pagine in cui c'è + #solo sub-ita + item.title = item.title.replace('[ITA]','[Sub-ITA]') + item.contentLanguage = 'Sub-ITA' + return item + + action = 'findvideos' if item.contentType == 'movie' else 'episodios' + + return locals() + + +@support.scrape +def episodios(item): + anime = True + data = support.match(item, headers=headers)[1] + if 'https://vcrypt.net' in data: + patron = r'(?:<br /> |<p>)(?P<title>[^<]+)<a href="(?P<url>[^"]+)"' + else: + patron = r'<br />\s*<a href="(?P<url>[^"]+)" target="_blank" rel="noopener[^>]+>(?P<title>[^<]+)</a>' + + def itemHook(item): + item.title = support.re.sub(r'\[B\]|\[/B\]', '', item.title) + item.title = item.title.replace('_',' ').replace('–','-').replace('×','x').replace('-','-').replace(' ',' ') + item.title = support.re.sub(item.fulltitle + ' - ','',item.title) + item.title = support.typo(item.title.strip(' -'),'bold') + return item + + return locals() + def findvideos(item): - logger.info("[toonitalia.py] findvideos") - - if item.args == 'film': - data = httptools.downloadpage(item.url, headers=headers).data - itemlist = servertools.find_video_items(data=data) - - for videoitem in itemlist: - videoitem.channel = __channel__ - server = re.sub(r'[-\[\]\s]+', '', videoitem.title) - videoitem.title = "".join(['[COLOR blue] ' + "[[B]" + server + "[/B]][/COLOR] " + item.title]) - videoitem.thumbnail = item.thumbnail - videoitem.plot = item.plot - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - - else: - itemlist = servertools.find_video_items(data=item.url) - - for videoitem in itemlist: - videoitem.channel = __channel__ - server = re.sub(r'[-\[\]\s]+', '', videoitem.title) - videoitem.title = "".join(['[COLOR blue] ' + "[[B]" + server + "[/B]] " + item.title + '[/COLOR]']) - videoitem.thumbnail = item.thumbnail - videoitem.plot = item.plot - videoitem.fulltitle = item.fulltitle - videoitem.show = item.show - - autoplay.start(itemlist, item) - - return itemlist + return support.server(item, item.url if item.contentType != 'movie' else support.httptools.downloadpage(item.url, headers=headers).data ) diff --git a/channels/tubehentai.py b/channels/tubehentai.py deleted file mode 100644 index e2affd96..00000000 --- a/channels/tubehentai.py +++ /dev/null @@ -1,93 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -import urlparse - -from core import scrapertools -from core.item import Item -from platformcode import logger -from platformcode import config - - -def mainlist(item): - logger.info() - itemlist = [] - itemlist.append(Item(channel=item.channel, title="Novedades", action="novedades", url="http://tubehentai.com/")) - itemlist.append( - Item(channel=item.channel, title="Buscar", action="search", url="http://tubehentai.com/search/%s/page1.html")) - - return itemlist - - -def search(item, texto): - logger.info() - - texto = texto.replace(" ", "%20") - - item.url = item.url % texto - try: - return novedades(item) - # Se captura la excepciÛn, para no interrumpir al buscador global si un canal falla - except: - import sys - for line in sys.exc_info(): - logger.error("%s" % line) - return [] - - -def novedades(item): - logger.info() - - # Descarga la página - data = httptools.downloadpage(item.url).data - # <a href="http://tubehentai.com/videos/slave_market_¨c_ep1-595.html"><img class="img" width="145" src="http://tubehentai.com/media/thumbs/5/9/5/./f/595/595.flv-3.jpg" alt="Slave_Market_¨C_Ep1" id="4f4fbf26f36 - patron = '<a href="(http://tubehentai.com/videos/[^"]+)"><img.*?src="(http://tubehentai.com/media/thumbs/[^"]+)" alt="([^"]+)"' - matches = re.compile(patron, re.DOTALL).findall(data) - - itemlist = [] - for match in matches: - # Titulo - scrapedtitle = match[2] - scrapedurl = match[0] - scrapedthumbnail = match[1].replace(" ", "%20") - scrapedplot = scrapertools.htmlclean(match[2].strip()) - logger.debug("title=[" + scrapedtitle + "], url=[" + scrapedurl + "], thumbnail=[" + scrapedthumbnail + "]") - - # Añade al listado de XBMC - itemlist.append( - Item(channel=item.channel, action="play", title=scrapedtitle, url=scrapedurl, thumbnail=scrapedthumbnail, - plot=scrapedplot, folder=False)) - - # ------------------------------------------------------ - # Extrae el paginador - # ------------------------------------------------------ - # <a href="page2.html" class="next">Next »</a> - patronvideos = '<a href=\'(page[^\.]+\.html)\'[^>]*?>Next[^<]*?<\/a>' - matches = re.compile(patronvideos, re.DOTALL).findall(data) - scrapertools.printMatches(matches) - - if len(matches) > 0: - scrapedurl = urlparse.urljoin(item.url, "/" + matches[0]) - logger.info(scrapedurl) - itemlist.append(Item(channel=item.channel, action="novedades", title=">> Página siguiente", url=scrapedurl)) - - return itemlist - - -def play(item): - logger.info() - itemlist = [] - - # s1.addParam("flashvars","overlay=http://tubehentai.com/media/thumbs/5/2/3/9/c/5239cf74632cbTHLaBlueGirlep3%20%20Segment2000855.000001355.000.mp4 - # http://tubehentai.com/media/thumbs/5/2/3/9/c/5239cf74632cbTHLaBlueGirlep3%20%20Segment2000855.000001355.000.mp4 - # http://tubehentai.com/media/videos/5/2/3/9/c/5239cf74632cbTHLaBlueGirlep3%20%20Segment2000855.000001355.000.mp4?start=0 - data = httptools.downloadpage(item.url).data - url = scrapertools.find_single_match(data, 's1.addParam\("flashvars","bufferlength=1&autostart=true&overlay=(.*?\.mp4)') - url = url.replace("/thumbs", "/videos") - # url = url+"?start=0" - logger.info("url=" + url) - server = "Directo" - itemlist.append(Item(channel=item.channel, title="", url=url, server=server, folder=False)) - - return itemlist diff --git a/channels/vedohd.py b/channels/vedohd.py index bb536728..f5a43ca4 100644 --- a/channels/vedohd.py +++ b/channels/vedohd.py @@ -5,26 +5,12 @@ from core import scrapertoolsV2, httptools, support from core.item import Item -from platformcode import logger +from platformcode import logger, config from specials import autoplay -from platformcode import config +__channel__ = "vedohd" +host = config.get_channel_url(__channel__) headers = "" -host = "" - - -def findhost(): - permUrl = httptools.downloadpage('https://www.cb01.uno/', follow_redirects=False).headers - cb01Url = 'https://www.'+permUrl['location'].replace('https://www.google.it/search?q=site:', '') - data = httptools.downloadpage(cb01Url).data - global host, headers - - host = scrapertoolsV2.find_single_match(data, r'class="?mega-menu-link"? href="?(https://vedohd[^/"]+)"?')+'/' - - if 'https' not in host: # in caso cb01 cambi, si spera di riuscire ad accedere da questo URL - host = "https://vedohd.pw/" - headers = [['Referer', host]] - IDIOMAS = {'Italiano': 'IT'} list_language = IDIOMAS.values() @@ -34,25 +20,16 @@ list_quality = ['HD', 'SD'] #esclusione degli articoli 'di servizio' blacklist = ['CB01.UNO ▶ TROVA L’INDIRIZZO UFFICIALE ', 'AVVISO IMPORTANTE – CB01.UNO', 'GUIDA VEDOHD'] - +@support.menu def mainlist(item): - logger.info("[vedohd.py] mainlist") - findhost() - autoplay.init(item.channel, list_servers, list_quality) - - # Main options - itemlist = [] - support.menu(itemlist, 'Film', "peliculas", host+"film-hd") - support.menu(itemlist, 'I più votati', "peliculas", host+"ratings/?get=movies") - support.menu(itemlist, 'I più popolari', "peliculas", host+"trending/?get=movies") - support.menu(itemlist, 'Generi', "generos", host) - support.menu(itemlist, 'Anno', "year", host) - support.menu(itemlist, 'Cerca', "search", host) - - autoplay.show_option(item.channel, itemlist) - - return itemlist + film = [ + ('I più votati', ["ratings/?get=movies", 'peliculas']), + ('I più popolari', ["trending/?get=movies", 'peliculas']), + ('Generi', ['ratings/?get=movies', 'menu', 'genres']), + ('Anno', ["", 'menu', 'releases']), + ] + return locals() def search(item, text): @@ -63,13 +40,10 @@ def search(item, text): def peliculas(item): - logger.info("[vedohd.py] video") - - return support.dooplay_films(item, blacklist) + return support.dooplay_peliculas(item, False, blacklist) def findvideos(item): - findhost() itemlist = [] for link in support.dooplay_get_links(item, host): if link['title'] != 'Trailer': @@ -97,16 +71,13 @@ def findvideos(item): return itemlist -def generos(item): - findhost() - patron = '<a href="([^"#]+)">([a-zA-Z]+)' - return support.scrape(item, patron, ['url', 'title'], patron_block='<a href="#">Genere</a><ul class="sub-menu">.*?</ul>', action='peliculas') +@support.scrape +def menu(item): + patron = '<a href="(?P<url>[^"#]+)"(?: title="[^"]+")?>(?P<title>[a-zA-Z0-9]+)' + patronBlock = '<nav class="' + item.args + '">(?P<block>.*?)</nav>' + action = 'peliculas' - -def year(item): - findhost() - patron = r'<a href="([^"#]+)">(\d+)' - return support.scrape(item, patron, ['url', 'title'], patron_block='<a href="#">Anno</a><ul class="sub-menu">.*?</ul>', action='peliculas') + return locals() def play(item): diff --git a/channels/vvvvid.json b/channels/vvvvid.json new file mode 100644 index 00000000..e1f33816 --- /dev/null +++ b/channels/vvvvid.json @@ -0,0 +1,11 @@ +{ + "id": "vvvvid", + "name": "VVVVID", + "active": true, + "adult": false, + "language": ["ita","vos"], + "thumbnail": "vvvvid.png", + "banner": "vvvvid.png", + "categories": ["anime","tvshow","movie","vos"], + "settings": [] +} \ No newline at end of file diff --git a/channels/vvvvid.py b/channels/vvvvid.py new file mode 100644 index 00000000..9269cf2e --- /dev/null +++ b/channels/vvvvid.py @@ -0,0 +1,213 @@ +# -*- coding: utf-8 -*- +# ------------------------------------------------------------ +# Canale per vvvvid +# ---------------------------------------------------------- +import requests, re +from core import support, tmdb +from core.item import Item +from specials import autorenumber + +__channel__ = "vvvvid" +host = support.config.get_channel_url(__channel__) + +# Creating persistent session +current_session = requests.Session() +headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0'} + +# Getting conn_id token from vvvvid and creating payload +login_page = host + '/user/login' +conn_id = current_session.get(login_page, headers=headers).json()['data']['conn_id'] +payload = {'conn_id': conn_id} + +main_host = host +host += '/vvvvid/ondemand/' +list_servers = ['vvvvid'] +list_quality = ['default'] + +@support.menu +def mainlist(item): + anime = ['anime/', + ('In Evidenza',['anime/', 'peliculas', 'channel/10005/last/']), + ('Popolari',['anime/', 'peliculas', 'channel/10002/last/']), + ('Nuove Uscite',['anime/', 'peliculas', 'channel/10007/last/']), + ('Generi',['anime/', 'peliculas', 'channel/10004/last/?category=']), + ('A-Z',['anime/', 'peliculas', 'channel/10003/last/?filter=']) + ] + film = ['film/', + ('In Evidenza',['film/', 'peliculas', 'channel/10005/last/']), + ('Popolari',['film/', 'peliculas', 'channel/10002/last/']), + ('Nuove Uscite',['film/', 'peliculas', 'channel/10007/last/']), + ('Generi',['film/', 'peliculas', 'channel/10004/last/?category=']), + ('A-Z',['film/', 'peliculas', 'channel/10003/last/?filter=']), + ] + tvshow = ['series/', + ('In Evidenza',['series/', 'peliculas', 'channel/10005/last/']), + ('Popolari',['series/', 'peliculas', 'channel/10002/last/']), + ('Nuove Uscite',['series/', 'peliculas', 'channel/10007/last/']), + ('Generi',['series/', 'peliculas', 'channel/10004/last/?category=']), + ('A-Z',['series/', 'peliculas', 'channel/10003/last/?filter=']) + ] + show = [('Show bold {tv}',['show/', 'peliculas', 'channel/10005/last/', 'tvshow']), + ('In Evidenza submenu {tv}',['show/', 'peliculas', 'channel/10005/last/', 'tvshow']), + ('Popolari submenu {tv}',['show/', 'peliculas', 'channel/10002/last/', 'tvshow']), + ('Nuove Uscite submenu {tv}',['show/', 'peliculas', 'channel/10007/last/', 'tvshow']), + ('Generi submenu {tv}',['show/', 'peliculas', 'channel/10004/last/?category=', 'tvshow']), + ('A-Z submenu {tv}',['show/', 'peliculas', 'channel/10003/last/?filter=', 'tvshow']), + ('Cerca Show... bold submenu {tv}', ['show/', 'search', '', 'tvshow']) + ] + kids = [('Kids bold',['kids/', 'peliculas', 'channel/10005/last/', 'tvshow']), + ('In Evidenza submenu {kids}',['kids/', 'peliculas', 'channel/10005/last/', 'tvshow']), + ('Popolari submenu {kids}',['kids/', 'peliculas', 'channel/10002/last/', 'tvshow']), + ('Nuove Uscite submenu {kids}',['kids/', 'peliculas', 'channel/10007/last/', 'tvshow']), + ('Generi submenu {kids}',['kids/', 'peliculas', 'channel/10004/last/?category=', 'tvshow']), + ('A-Z submenu {kids}',['kids/', 'peliculas', 'channel/10003/last/?filter=', 'tvshow']), + ('Cerca Kids... bold submenu {kids}', ['kids/', 'search', '', 'tvshow']) + ] + return locals() + +def search(item, text): + support.log(text) + itemlist = [] + if 'film' in item.url: item.contentType = 'movie' + else: item.contentType = 'tvshow' + item.search = text + itemlist = peliculas(item) + return itemlist + +def newest(categoria): + item = Item() + item.args = 'channel/10007/last/' + if categoria == 'peliculas': + item.contentType = 'movie' + item.url = host + 'film/' + if categoria == 'series': + item.contentType = 'tvshow' + item.url = host + 'series/' + if categoria == 'anime': + item.contentType = 'tvshow' + item.url = host + 'anime/' + return peliculas(item) + + +def peliculas(item): + itemlist = [] + if not item.args: + json_file = current_session.get(item.url + 'channels', headers=headers, params=payload).json() + names = [i['filter'] for i in json_file['data'] if 'filter' in i][0] + for name in names: + url = item.url + 'channel/10003/last/?filter=' + str(name) + json_file = current_session.get(url, headers=headers, params=payload).json() + if 'data' in json_file: + json_file = current_session.get(url, headers=headers, params=payload).json() + make_itemlist(itemlist, item, json_file) + + elif ('=' not in item.args) and ('=' not in item.url): + json_file = current_session.get(item.url + item.args, headers=headers, params=payload).json() + make_itemlist(itemlist, item, json_file) + + elif '=' in item.args: + json_file = current_session.get(item.url + 'channels', headers=headers, params=payload).json() + Filter = support.match(item.args,r'\?([^=]+)=')[0][0] + keys = [i[Filter] for i in json_file['data'] if Filter in i][0] + for key in keys: + if key not in ['1','2']: + itemlist.append( + Item(channel = item.channel, + title = support.typo(key.upper() if Filter == 'filter' else key['name'], 'bold'), + url = item.url + item.args + (key if Filter == 'filter' else str(key['id'])), + action = 'peliculas', + args = 'filters', + contentType = item.contentType)) + + else : + json_file = current_session.get(item.url, headers=headers, params=payload).json() + make_itemlist(itemlist, item, json_file) + if item.contentType != 'movie': autorenumber.renumber(itemlist) + tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) + return itemlist + +def episodios(item): + itemlist = [] + json_file = current_session.get(item.url, headers=headers, params=payload).json() + show_id = str(json_file['data'][0]['show_id']) + season_id = str(json_file['data'][0]['season_id']) + episodes = [] + support.log('SEASON ID= ',season_id) + for episode in json_file['data']: + episodes.append(episode['episodes']) + for episode in episodes: + for key in episode: + if 'stagione' in key['title'].encode('utf8').lower(): + match = support.match(key['title'].encode('utf8'), r'[Ss]tagione\s*(\d+) - [Ee]pisodio\s*(\d+)')[0][0] + title = match[0]+'x'+match[1] + ' - ' + item.fulltitle + make_item = True + elif int(key['season_id']) == int(season_id): + title = 'Episodio ' + key['number'] + ' - ' + key['title'].encode('utf8'), + make_item = True + else: + make_item = False + if make_item == True: + if type(title) == tuple: title = title[0] + itemlist.append( + Item( + channel = item.channel, + title = title, + fulltitle= item.fulltitle, + show= item.show, + url= host + show_id + '/season/' + str(key['season_id']) + '/', + action= 'findvideos', + video_id= key['video_id'], + contentType = item.contentType + )) + autorenumber.renumber(itemlist, item, 'bold') + if autorenumber.check(item) == True: + support.videolibrary(itemlist,item) + return itemlist + +def findvideos(item): + from lib import vvvvid_decoder + itemlist = [] + if item.contentType == 'movie': + json_file = current_session.get(item.url, headers=headers, params=payload).json() + item.url = host + str(json_file['data'][0]['show_id']) + '/season/' + str(json_file['data'][0]['episodes'][0]['season_id']) + '/' + item.video_id = json_file['data'][0]['episodes'][0]['video_id'] + + json_file = current_session.get(item.url, headers=headers, params=payload).json() + for episode in json_file['data']: + if episode['video_id'] == item.video_id: + url = vvvvid_decoder.dec_ei(episode['embed_info'] or episode['embed_info']) + if 'youtube' in url: item.url = url + item.url = url.replace('manifest.f4m','master.m3u8').replace('http://','https://').replace('/z/','/i/') + if 'https' not in item.url: + url = support.match(item, url='https://or01.top-ix.org/videomg/_definst_/mp4:' + item.url + '/playlist.m3u')[1] + url = url.split()[-1] + itemlist.append( + Item(action= 'play', + title='direct', + url= 'https://or01.top-ix.org/videomg/_definst_/mp4:' + item.url + '/' + url, + server= 'directo') + ) + return support.server(item, itemlist=itemlist, down_load=False) + +def make_itemlist(itemlist, item, data): + search = item.search if item.search else '' + infoLabels = {} + for key in data['data']: + if search.lower() in key['title'].encode('utf8').lower(): + infoLabels['year'] = key['date_published'] + infoLabels['title'] = infoLabels['tvshowtitle'] = key['title'] + title = key['title'].encode('utf8') + itemlist.append( + Item( + channel = item.channel, + title = support.typo(title, 'bold'), + fulltitle= title, + show= title, + url= host + str(key['show_id']) + '/seasons/', + action= 'findvideos' if item.contentType == 'movie' else 'episodios', + contentType = item.contentType, + contentSerieName= key['title'] if item.contentType != 'movie' else '', + contentTitle= title if item.contentType == 'movie' else '', + infoLabels=infoLabels + )) + return itemlist \ No newline at end of file diff --git a/channelselector.py b/channelselector.py index 36dd50b8..4734867f 100644 --- a/channelselector.py +++ b/channelselector.py @@ -16,6 +16,10 @@ def getmainlist(view="thumb_"): logger.info() itemlist = list() + if config.dev_mode(): + itemlist.append(Item(title="Redirect", channel="checkhost", action="check_channels", + thumbnail='', + category=config.get_localized_string(30119), viewmode="thumbnails")) # Añade los canales que forman el menú principal if addon.getSetting('enable_news_menu') == "true": itemlist.append(Item(title=config.get_localized_string(30130), channel="news", action="mainlist", @@ -38,7 +42,7 @@ def getmainlist(view="thumb_"): if addon.getSetting('enable_onair_menu') == "true": itemlist.append(Item(channel="filmontv", action="mainlist", title=config.get_localized_string(50001), - thumbnail=get_thumb("on_the_air.png"), viewmode="thumbnails")) + thumbnail=get_thumb("on_the_air.png"), viewmode="thumbnails")) if addon.getSetting('enable_link_menu') == "true": itemlist.append(Item(title=config.get_localized_string(70527), channel="kodfavorites", action="mainlist", @@ -102,7 +106,7 @@ def getchanneltypes(view="thumb_"): # itemlist.append(Item(title='Oggi in TV', channel="filmontv", action="mainlist", view=view, # category=title, channel_type="all", thumbnail=get_thumb("on_the_air.png", view), - # viewmode="thumbnails")) + # viewmode="thumbnails")) @@ -113,7 +117,7 @@ def getchanneltypes(view="thumb_"): def filterchannels(category, view="thumb_"): - logger.info() + logger.info('Filterchannl'+category) channelslist = [] @@ -124,8 +128,11 @@ def filterchannels(category, view="thumb_"): appenddisabledchannels = True # Lee la lista de canales - channel_path = os.path.join(config.get_runtime_path(), "channels", '*.json') - logger.info("channel_path=%s" % channel_path) + if category != 'adult': + channel_path = os.path.join(config.get_runtime_path(), 'channels', '*.json') + else: + channel_path = os.path.join(config.get_runtime_path(), 'channels', 'porn', '*.json') + logger.info("channel_path = %s" % channel_path) channel_files = glob.glob(channel_path) logger.info("channel_files encontrados %s" % (len(channel_files))) @@ -135,7 +142,7 @@ def filterchannels(category, view="thumb_"): logger.info("channel_language=%s" % channel_language) for channel_path in channel_files: - logger.info("channel=%s" % channel_path) + logger.info("channel in for = %s" % channel_path) channel = os.path.basename(channel_path).replace(".json", "") @@ -185,8 +192,15 @@ def filterchannels(category, view="thumb_"): # Se muestran todos los canales si se elige "all" en el filtrado de idioma # Se muestran sólo los idiomas filtrados, cast o lat # Los canales de adultos se mostrarán siempre que estén activos - if channel_language != "all" and channel_language not in channel_parameters["language"] \ - and "*" not in channel_parameters["language"]: + + # for channel_language_list in channel_language_list: + # if c in channel_parameters["language"]: + # L = True + # else: + # L = False + # logger.info('CCLANG= ' + channel_language + ' ' + str(channel_language_list)) + if channel_language != "all" and "*" not in channel_parameters["language"] \ + and channel_language not in str(channel_parameters["language"]): continue # Se salta el canal si está en una categoria filtrado @@ -248,21 +262,16 @@ def get_thumb(thumb_name, view="thumb_", auto=False): thumbnail = '' thumb_name = unify.set_genre(unify.simplify(thumb_name)) - if thumb_name in thumb_dict: thumbnail = thumb_dict[thumb_name] return thumbnail - + else: icon_pack_name = config.get_setting('icon_set', default="default") - resource_path = os.path.join(config.get_runtime_path(), "resources", "media", "themes") - media_path = os.path.join(resource_path, icon_pack_name) + media_path = os.path.join("https://raw.githubusercontent.com/kodiondemand/media/master/themes/", icon_pack_name) - if os.path.isdir(media_path) == False: - media_path = os.path.join("https://raw.githubusercontent.com/kodiondemand/media/master/themes/", icon_pack_name) - - elif config.get_setting('enable_custom_theme') and config.get_setting('custom_theme') and os.path.isfile(config.get_setting('custom_theme') + view + thumb_name): + if config.get_setting('enable_custom_theme') and config.get_setting('custom_theme') and os.path.isfile(config.get_setting('custom_theme') + view + thumb_name): media_path = config.get_setting('custom_theme') return os.path.join(media_path, view + thumb_name) @@ -276,12 +285,14 @@ def set_channel_info(parameters): content = '' langs = parameters['language'] lang_dict = {'ita':'Italiano', - '*':'Italiano, VOSI, VO'} + 'sub-ita':'Sottotitolato in Italiano', + '*':'Italiano, Sottotitolato in Italiano'} + for lang in langs: - if 'vos' in parameters['categories']: - lang = '*' - if 'vosi' in parameters['categories']: - lang = 'ita' + # if 'vos' in parameters['categories']: + # lang = '*' + # if 'sub-ita' in parameters['categories']: + # lang = 'ita' if lang in lang_dict: if language != '' and language != '*' and not parameters['adult']: @@ -304,102 +315,118 @@ def set_channel_info(parameters): def auto_filter(auto_lang=False): - import xbmc, xbmcaddon - - addon = xbmcaddon.Addon('metadata.themoviedb.org') - def_lang = addon.getSetting('language') - lang = 'all' - - lang_dict = {'ita':'it'} - if config.get_setting("channel_language") == 'auto' or auto_lang == True: - for langs, variant in lang_dict.items(): - if def_lang in variant: - lang = langs - + lang = config.get_localized_string(20001) + else: lang = config.get_setting("channel_language", default="all") return lang + # import xbmc, xbmcaddon -def thumb(itemlist=[]): + # addon = xbmcaddon.Addon('metadata.themoviedb.org') + # def_lang = addon.getSetting('language') + # lang = 'all' + # lang_list = ['all'] + + # lang_dict = {'it':'ita'} + # lang_list_dict = {'it':['ita','vosi']} + + # if config.get_setting("channel_language") == 'auto' or auto_lang == True: + # lang = lang_dict[def_lang] + # lang_list = lang_list_dict[def_lang] + + # else: + # lang = config.get_setting("channel_language", default="all") + # lang_list = lang_list_dict[def_lang] + + # return lang, lang_list + + +def thumb(itemlist=[], genre=False): if itemlist: import re icon_dict = {'channels_movie':['film'], 'channels_tvshow':['serie','tv','episodi','episodio'], - 'channels_documentary':['documentari','documentario'], + 'channels_documentary':['documentari','documentario', 'documentary'], 'channels_all':['tutti'], - 'news':['novità', "novita'", 'aggiornamenti'], + 'news':['novità', "novita'", 'aggiornamenti', 'nuovi', 'nuove'], 'now_playing':['cinema', 'in sala'], 'channels_anime':['anime'], 'genres':['genere', 'generi', 'categorie', 'categoria'], - 'channels_animation': ['animazione', 'cartoni'], - 'channels_adventure': ['avventura'], - 'channels_action':['azione', 'arti marziali'], + 'channels_animation': ['animazione', 'cartoni', 'cartoon', 'animation'], + 'channels_action':['azione', 'arti marziali', 'action'], + 'channels_adventure': ['avventura', 'adventure'], 'channels_biographical':['biografico'], - 'channels_comedy':['comico','commedia', 'demenziale'], - 'channels_adult':['erotico', 'hentai'], - 'channels_drama':['drammatico'], - 'channels_syfy':['fantascienza'], - 'channels_fantasy':['fantasy'], - 'channels_crime':['gangster','poliziesco'], + 'channels_comedy':['comico','commedia', 'demenziale', 'comedy'], + 'channels_adult':['erotico', 'hentai', 'harem', 'ecchi'], + 'channels_drama':['drammatico', 'drama'], + 'channels_syfy':['fantascienza', 'science fiction'], + 'channels_fantasy':['fantasy', 'magia'], + 'channels_crime':['gangster','poliziesco', 'crime', 'crimine'], 'channels_grotesque':['grottesco'], - 'channels_war':['guerra'], - 'channels_children':['bambini'], + 'channels_war':['guerra', 'war'], + 'channels_children':['bambini', 'kids'], 'horror':['horror'], - 'lucky': ['fortunato'], - 'channels_musical':['musical', 'musica'], - 'channels_mistery':['mistero', 'giallo'], + 'lucky': ['fortunato'], + 'channels_musical':['musical', 'musica', 'music'], + 'channels_mistery':['mistero', 'giallo', 'mystery'], 'channels_noir':['noir'], 'popular' : ['popolari','popolare', 'più visti'], - 'channels_thriller':['thriller'], - 'top_rated' : ['fortunato'], + 'thriller':['thriller'], + 'top_rated' : ['fortunato', 'votati'], + 'on_the_air' : ['corso', 'onda'], 'channels_western':['western'], 'channels_vos':['sub','sub-ita'], - 'channels_romance':['romantico','sentimentale'], - 'channels_family':['famiglia','famiglie'], - 'channels_historical':['storico'], + 'channels_romance':['romantico','sentimentale', 'romance'], + 'channels_family':['famiglia','famiglie', 'family'], + 'channels_historical':['storico', 'history'], 'autoplay':[config.get_localized_string(60071)] - } + } suffix_dict = {'_hd':['hd','altadefinizione','alta definizione'], '_4k':['4K'], '_az':['lettera','lista','alfabetico','a-z'], - '_year':['anno'], + '_year':['anno', 'anni'], '_genre':['genere', 'generi', 'categorie', 'categoria']} search = ['cerca'] search_suffix ={'_movie':['film'], '_tvshow':['serie','tv']} + for item in itemlist: - # Check if item has args propriety - if item.args: item.title = item.title + ' || ' + str(item.args) + if genre == False: - for thumb, titles in icon_dict.items(): - if any( word in item.title.lower() for word in search): - thumb = 'search' - for suffix, titles in search_suffix.items(): - if any( word in item.title.lower() for word in titles ): - thumb = thumb + suffix - item.thumbnail = get_thumb(thumb + '.png') - elif any( word in item.title.lower() for word in titles ): - if thumb == 'channels_movie' or thumb == 'channels_tvshow': - for suffix, titles in suffix_dict.items(): + for thumb, titles in icon_dict.items(): + if any( word in item.title.lower() for word in search): + thumb = 'search' + for suffix, titles in search_suffix.items(): if any( word in item.title.lower() for word in titles ): thumb = thumb + suffix - item.thumbnail = get_thumb(thumb + '.png') - else: - thumb = item.thumbnails + item.thumbnail = get_thumb(thumb + '.png') + elif any( word in item.title.lower() for word in titles ): + if thumb == 'channels_movie' or thumb == 'channels_tvshow': + for suffix, titles in suffix_dict.items(): + if any( word in item.title.lower() for word in titles ): + thumb = thumb + suffix + item.thumbnail = get_thumb(thumb + '.png') + else: item.thumbnail = get_thumb(thumb + '.png') + else: + thumb = item.thumbnails - if item.thumbnail != '': - break + else: + for thumb, titles in icon_dict.items(): + if any(word in item.title.lower() for word in titles ): + item.thumbnail = get_thumb(thumb + '.png') + else: + thumb = item.thumbnails - # Remove args from title - if item.args: item.title = item.title.replace(' || ' + str(item.args), '') + + item.title = re.sub(r'\s*\{[^\}]+\}','',item.title) return itemlist else: return get_thumb('next.png') diff --git a/core/channeltools.py b/core/channeltools.py index 17c42b8f..56e6fee3 100644 --- a/core/channeltools.py +++ b/core/channeltools.py @@ -12,6 +12,8 @@ from platformcode import config, logger DEFAULT_UPDATE_URL = "/channels/" dict_channels_parameters = dict() +remote_path = 'https://raw.githubusercontent.com/kodiondemand/media/master/' + def is_adult(channel_name): logger.info("channel_name=" + channel_name) @@ -34,13 +36,18 @@ def get_channel_parameters(channel_name): # logger.debug(channel_parameters) if channel_parameters: # cambios de nombres y valores por defecto - channel_parameters["title"] = channel_parameters.pop("name") + channel_parameters["title"] = channel_parameters.pop("name") + (' [DEPRECATED]' if channel_parameters.has_key('deprecated') and channel_parameters['deprecated'] else '') channel_parameters["channel"] = channel_parameters.pop("id") # si no existe el key se declaran valor por defecto para que no de fallos en las funciones que lo llaman - channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL) - channel_parameters["language"] = channel_parameters.get("language", ["all"]) channel_parameters["adult"] = channel_parameters.get("adult", False) + logger.info(channel_parameters["adult"]) + if channel_parameters["adult"]: + channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL+'porn/') + else: + channel_parameters["update_url"] = channel_parameters.get("update_url", DEFAULT_UPDATE_URL) + channel_parameters["language"] = channel_parameters.get("language", ["all"]) +## channel_parameters["adult"] = channel_parameters.get("adult", False) channel_parameters["active"] = channel_parameters.get("active", False) channel_parameters["include_in_global_search"] = channel_parameters.get("include_in_global_search", False) channel_parameters["categories"] = channel_parameters.get("categories", list()) @@ -51,14 +58,11 @@ def get_channel_parameters(channel_name): # Imagenes: se admiten url y archivos locales dentro de "resources/images" if channel_parameters.get("thumbnail") and "://" not in channel_parameters["thumbnail"]: - channel_parameters["thumbnail"] = os.path.join(config.get_runtime_path(), "resources", "media", - "channels", "thumb", channel_parameters["thumbnail"]) + channel_parameters["thumbnail"] = os.path.join(remote_path, 'resources', "thumb", channel_parameters["thumbnail"]) if channel_parameters.get("banner") and "://" not in channel_parameters["banner"]: - channel_parameters["banner"] = os.path.join(config.get_runtime_path(), "resources", "media", - "channels", "banner", channel_parameters["banner"]) + channel_parameters["banner"] = os.path.join(remote_path, 'resources', "banner", channel_parameters["banner"]) if channel_parameters.get("fanart") and "://" not in channel_parameters["fanart"]: - channel_parameters["fanart"] = os.path.join(config.get_runtime_path(), "resources", "media", - "channels", "fanart", channel_parameters["fanart"]) + channel_parameters["fanart"] = os.path.join(remote_path, 'resources', "fanart", channel_parameters["fanart"]) # Obtenemos si el canal tiene opciones de configuración channel_parameters["has_settings"] = False @@ -79,7 +83,7 @@ def get_channel_parameters(channel_name): # break # if found: # break - + channel_parameters['settings'] = get_default_settings(channel_name) for s in channel_parameters['settings']: if 'id' in s: if s['id'] == "include_in_global_search": @@ -133,11 +137,14 @@ def get_channel_json(channel_name): try: channel_path = filetools.join(config.get_runtime_path(), "channels", channel_name + ".json") if not os.path.isfile(channel_path): - channel_path = filetools.join(config.get_runtime_path(), "specials", channel_name + ".json") + channel_path = filetools.join(config.get_runtime_path(), 'channels', "porn", channel_name + ".json") if not os.path.isfile(channel_path): - channel_path = filetools.join(config.get_runtime_path(), "servers", channel_name + ".json") + channel_path = filetools.join(config.get_runtime_path(), "specials", channel_name + ".json") if not os.path.isfile(channel_path): - channel_path = filetools.join(config.get_runtime_path(), "servers", "debriders", channel_name + ".json") + channel_path = filetools.join(config.get_runtime_path(), "servers", channel_name + ".json") + if not os.path.isfile(channel_path): + channel_path = filetools.join(config.get_runtime_path(), "servers", "debriders", channel_name + ".json") + if filetools.isfile(channel_path): # logger.info("channel_data=" + channel_path) channel_json = jsontools.load(filetools.read(channel_path)) @@ -155,7 +162,8 @@ def get_channel_controls_settings(channel_name): # logger.info("channel_name=" + channel_name) dict_settings = {} # import web_pdb; web_pdb.set_trace() - list_controls = get_channel_json(channel_name).get('settings', list()) + # list_controls = get_channel_json(channel_name).get('settings', list()) + list_controls = get_default_settings(channel_name) for c in list_controls: if 'id' not in c or 'type' not in c or 'default' not in c: @@ -167,6 +175,108 @@ def get_channel_controls_settings(channel_name): return list_controls, dict_settings +def get_lang(channel_name): + channel = __import__('channels.%s' % channel_name, fromlist=["channels.%s" % channel_name]) + list_language = [config.get_localized_string(70522)] + if hasattr(channel, 'list_language'): + for language in channel.list_language: + list_language.append(language) + logger.info(list_language) + else: + sub = False + langs = [] + language = get_channel_json(channel_name).get('language', list()) + for lang in language: + if 'vos' not in lang: + langs.append(lang.upper()) + else: + sub = True + if sub == True: + for lang in langs: + list_language.append(lang) + list_language.append('Sub-' + lang) + else: + for lang in langs: + list_language.append(lang) + return list_language + +def get_default_settings(channel_name): + import filetools, inspect + + # Check if it is a real channel + try: + channel = __import__('channels.%s' % channel_name, fromlist=["channels.%s" % channel_name]) + except: + return get_channel_json(channel_name).get('settings', list()) + + list_language = get_lang(channel_name) + + # Check if the automatic renumbering function exists + renumber = False + if 'episodios' in dir(channel): + from core import scrapertoolsV2 + if scrapertoolsV2.find_single_match(inspect.getsource(channel), r'(anime\s*=\s*True)') \ + or scrapertoolsV2.find_single_match(inspect.getsource(channel), r'(autorenumber\()'): + renumber = True + + # Collects configurations + channel_language = categories = get_channel_json(channel_name).get('language', list()) + channel_controls = get_channel_json(channel_name).get('settings', list()) + default_path = filetools.join(config.get_runtime_path(), 'default_channel_settings' + '.json') + default_controls = jsontools.load(filetools.read(default_path)).get('settings', list()) + default_controls_renumber = jsontools.load(filetools.read(default_path)).get('renumber', list()) + categories = get_channel_json(channel_name).get('categories', list()) + not_active = get_channel_json(channel_name).get('not_active', list()) + default_off = get_channel_json(channel_name).get('default_off', list()) + + # Apply default configurations if they do not exist + for control in default_controls: + if control['id'] not in str(channel_controls): + if 'include_in_newest' in control['id'] and 'include_in_newest' not in not_active and control['id'] not in not_active: + label = control['id'].split('_') + label = label[-1] + if label == 'peliculas': + if 'movie' in categories: + control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30122) + control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_peliculas' in default_off) else True + channel_controls.append(control) + else: pass + elif label == 'series': + if 'tvshow' in categories: + control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30123) + control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_series' in default_off) else True + channel_controls.append(control) + else: pass + elif label == 'anime': + if 'anime' in categories: + control['label'] = config.get_localized_string(70727) + ' - ' + config.get_localized_string(30124) + control['default'] = False if ('include_in_newest' in default_off) or ('include_in_newest_anime' in default_off) else True + channel_controls.append(control) + else: pass + + else: + control['label'] = config.get_localized_string(70727) + ' - ' + label.capitalize() + control['default'] = control['default'] if control['id'] not in default_off else False + channel_controls.append(control) + + # elif control['id'] == 'filter_languages': + # if len(channel_language) > 1: + # control['lvalues'] = list_language + # channel_controls.append(control) + # else: pass + + elif control['id'] not in not_active and 'include_in_newest' not in control['id']: + if type(control['default']) == bool: + control['default'] = control['default'] if control['id'] not in default_off else False + channel_controls.append(control) + + if renumber: + for control in default_controls_renumber: + if control['id'] not in str(channel_controls): + channel_controls.append(control) + else: pass + return channel_controls + def get_channel_setting(name, channel, default=None): """ @@ -253,6 +363,7 @@ def set_channel_setting(name, value, channel): file_settings = os.path.join(config.get_data_path(), "settings_channels", channel + "_data.json") dict_settings = {} + def_settings = get_default_settings(channel) dict_file = None @@ -264,8 +375,19 @@ def set_channel_setting(name, value, channel): except EnvironmentError: logger.error("ERROR al leer el archivo: %s" % file_settings) - dict_settings[name] = value + # delete unused Settings + def_keys = [] + del_keys = [] + for key in def_settings: + def_keys.append(key['id']) + for key in dict_settings: + if key not in def_keys: + del_keys.append(key) + for key in del_keys: + del dict_settings[key] + dict_settings[name] = value + # comprobamos si existe dict_file y es un diccionario, sino lo creamos if dict_file is None or not dict_file: dict_file = {} diff --git a/core/downloader.py b/core/downloader.py index ea918462..5b4aea54 100644 --- a/core/downloader.py +++ b/core/downloader.py @@ -232,11 +232,11 @@ class Downloader: self.file.seek(2 ** 31) except OverflowError: self._seekable = False - logger.info("No se puede hacer seek() ni tell() en ficheros mayores de 2GB") + logger.info("Cannot do seek() or tell() in files larger than 2GB") self.__get_download_info__() - logger.info("Descarga inicializada: Partes: %s | Ruta: %s | Archivo: %s | Tamaño: %s" % ( + logger.info("Initialized Download: Parts: %s | Path: %s | Archive: %s | Size: %s" % ( len(self._download_info["parts"]), self._path, self._filename, self._download_info["size"])) def __url_to_headers__(self, url): @@ -394,7 +394,7 @@ class Downloader: return id == 0 or (len(self.completed_parts) >= id and sorted(self.completed_parts)[id - 1] == id - 1) def __save_file__(self): - logger.info("Thread iniciado: %s" % threading.current_thread().name) + logger.info("Thread started: %s" % threading.current_thread().name) while self._state == self.states.downloading: if not self.pending_parts and not self.download_parts and not self.save_parts: # Descarga finalizada @@ -434,7 +434,7 @@ class Downloader: self._download_info["parts"][s]["status"] = self.states.stopped self._download_info["parts"][s]["current"] = self._download_info["parts"][s]["start"] - logger.info("Thread detenido: %s" % threading.current_thread().name) + logger.info("Thread stopped: %s" % threading.current_thread().name) def __get_part_id__(self): self._download_lock.acquire() @@ -449,21 +449,21 @@ class Downloader: return None def __set_part_connecting__(self, id): - logger.info("ID: %s Estableciendo conexión" % id) + logger.info("ID: %s Establishing connection" % id) self._download_info["parts"][id]["status"] = self.states.connecting def __set_part__error__(self, id): - logger.info("ID: %s Error al descargar" % id) + logger.info("ID: %s Download failed" % id) self._download_info["parts"][id]["status"] = self.states.error self.pending_parts.add(id) self.download_parts.remove(id) def __set_part__downloading__(self, id): - logger.info("ID: %s Descargando datos..." % id) + logger.info("ID: %s Downloading data ..." % id) self._download_info["parts"][id]["status"] = self.states.downloading def __set_part_completed__(self, id): - logger.info("ID: %s ¡Descarga finalizada!" % id) + logger.info("ID: %s Download finished!" % id) self._download_info["parts"][id]["status"] = self.states.saving self.download_parts.remove(id) self.save_parts.add(id) @@ -483,7 +483,7 @@ class Downloader: return file def __start_part__(self): - logger.info("Thread Iniciado: %s" % threading.current_thread().name) + logger.info("Thread Started: %s" % threading.current_thread().name) while self._state == self.states.downloading: id = self.__get_part_id__() if id is None: break @@ -511,7 +511,7 @@ class Downloader: buffer = connection.read(self._block_size) speed.append(len(buffer) / ((time.time() - start) or 0.001)) except: - logger.info("ID: %s Error al descargar los datos" % id) + logger.info("ID: %s Error downloading data" % id) self._download_info["parts"][id]["status"] = self.states.error self.pending_parts.add(id) self.download_parts.remove(id) @@ -533,7 +533,7 @@ class Downloader: self._download_info["parts"][id]["end"]: connection.fp._sock.close() logger.info( - "ID: %s ¡Reiniciando conexión! | Velocidad minima: %.2f %s/s | Velocidad: %.2f %s/s" % \ + "ID: %s Restarting connection! | Minimum Speed: %.2f %s/s | Speed: %.2f %s/s" % \ (id, vm[1], vm[2], v[1], v[2])) # file.close() break @@ -544,4 +544,4 @@ class Downloader: break self.__set_part_stopped__(id) - logger.info("Thread detenido: %s" % threading.current_thread().name) + logger.info("Thread stopped: %s" % threading.current_thread().name) diff --git a/core/scrapertoolsV2.py b/core/scrapertoolsV2.py index 9fa26d28..a8e5b163 100644 --- a/core/scrapertoolsV2.py +++ b/core/scrapertoolsV2.py @@ -32,6 +32,11 @@ def find_multiple_matches(text, pattern): return re.findall(pattern, text, re.DOTALL) +def find_multiple_matches_groups(text, pattern): + r = re.compile(pattern) + return [m.groupdict() for m in r.finditer(text)] + + # Convierte los codigos html "ñ" y lo reemplaza por "ñ" caracter unicode utf-8 def decodeHtmlentities(data): entity_re = re.compile("&(#?)(\d{1,5}|\w{1,8})(;?)") diff --git a/core/servertools.py b/core/servertools.py index 925dd10d..2052326c 100644 --- a/core/servertools.py +++ b/core/servertools.py @@ -318,7 +318,7 @@ def resolve_video_urls_for_playing(server, url, video_password="", muestra_dialo video_urls.extend(response) except: logger.error("Error al obtener la url en modo free") - error_messages.append("Se ha producido un error en %s" % server_name) + error_messages.append(config.get_localized_string(60006) % server_name) import traceback logger.error(traceback.format_exc()) @@ -458,8 +458,7 @@ def get_server_parameters(server): # Imagenes: se admiten url y archivos locales dentro de "resources/images" if dict_server.get("thumbnail") and "://" not in dict_server["thumbnail"]: - dict_server["thumbnail"] = os.path.join(config.get_runtime_path(), "resources", "media", - "servers", dict_server["thumbnail"]) + dict_server["thumbnail"] = os.path.join("https://raw.githubusercontent.com/kodiondemand/media/master/resources/servers", dict_server["thumbnail"]) for k in ['premium', 'id']: dict_server[k] = dict_server.get(k, list()) diff --git a/core/support.py b/core/support.py index f815f7fe..d3dff488 100644 --- a/core/support.py +++ b/core/support.py @@ -16,9 +16,9 @@ from lib import unshortenit from platformcode import logger, config from specials import autoplay - def hdpass_get_servers(item): # Carica la pagina + itemlist = [] data = httptools.downloadpage(item.url).data.replace('\n', '') patron = r'<iframe(?: id="[^"]+")? width="[^"]+" height="[^"]+" src="([^"]+)"[^>]+><\/iframe>' url = scrapertoolsV2.find_single_match(data, patron).replace("?alta", "") @@ -28,7 +28,7 @@ def hdpass_get_servers(item): if 'hdpass' or 'hdplayer' in url: data = httptools.downloadpage(url).data - + start = data.find('<div class="row mobileRes">') end = data.find('<div id="playerFront">', start) data = data[start:end] @@ -47,23 +47,21 @@ def hdpass_get_servers(item): mir = scrapertoolsV2.find_single_match(data, patron_mir) - for mir_url, server in scrapertoolsV2.find_multiple_matches(mir, '<option.*?value="([^"]+?)">([^<]+?)</value>'): + for mir_url, srv in scrapertoolsV2.find_multiple_matches(mir, '<option.*?value="([^"]+?)">([^<]+?)</value>'): data = httptools.downloadpage(urlparse.urljoin(url, mir_url)).data.replace('\n', '') for media_label, media_url in scrapertoolsV2.find_multiple_matches(data, patron_media): itemlist.append(Item(channel=item.channel, action="play", - title=item.title+" ["+color(server, 'orange')+"]"+" - "+color(res_video, 'limegreen'), fulltitle=item.fulltitle, quality=res_video, show=item.show, thumbnail=item.thumbnail, contentType=item.contentType, - server=server, url=url_decode(media_url))) log("video -> ", res_video) - return controls(itemlist, item, AutoPlay=True, CheckLinks=True) + return server(item, itemlist=itemlist) def url_decode(url_enc): @@ -93,186 +91,363 @@ def color(text, color): return "[COLOR " + color + "]" + text + "[/COLOR]" -def scrape(item, patron = '', listGroups = [], headers="", blacklist="", data="", patron_block="", - patronNext="", action="findvideos", addVideolibrary = True, type_content_dict={}, type_action_dict={}): +def search(channel, item, texto): + log(item.url + " search " + texto) + if 'findhost' in dir(channel): + channel.findhost() + item.url = channel.host + "/?s=" + texto + try: + return channel.peliculas(item) + # Continua la ricerca in caso di errore + except: + import sys + for line in sys.exc_info(): + logger.error("%s" % line) + return [] + + +def dbg(): + import web_pdb; + if not web_pdb.WebPdb.active_instance: + import webbrowser + webbrowser.open('http://127.0.0.1:5555') + web_pdb.set_trace() + + + +def regexDbg(item, patron, headers, data=''): + import json, urllib2, webbrowser + url = 'https://regex101.com' + + if not data: + html = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data.replace("'", '"') + html = re.sub('\n|\t', ' ', html) + else: + html = data + headers = {'content-type': 'application/json'} + data = { + 'regex': patron, + 'flags': 'gm', + 'testString': html, + 'delimiter': '"""', + 'flavor': 'python' + } + r = urllib2.Request(url + '/api/regex', json.dumps(data, encoding='latin1'), headers=headers) + r = urllib2.urlopen(r).read() + permaLink = json.loads(r)['permalinkFragment'] + webbrowser.open(url + "/r/" + permaLink) + + +def scrape2(item, patron = '', listGroups = [], headers="", blacklist="", data="", patronBlock="", + patronNext="", action="findvideos", addVideolibrary = True, typeContentDict={}, typeActionDict={}): + m = re.search(r'(?<!\\|\[)\((?!\?)', patron) + n = 0 + while m: + patron = patron[:m.end()] + '?P<' + listGroups[n] + '>' + patron[m.end():] + m = re.search(r'(?<!\\|\[)\((?!\?)', patron) + n += 1 + regexDbg(item, patron, headers) + + +def scrapeLang(scraped, lang, longtitle): + ## Aggiunto/modificato per gestire i siti che hanno i video + ## in ita e subita delle serie tv nella stessa pagina + # altrimenti dopo un sub-ita mette tutti quelli a seguire in sub-ita + # e credo sia utile per filtertools + language = '' + + if scraped['lang']: + if 'ita' in scraped['lang'].lower(): + language = 'ITA' + if 'sub' in scraped['lang'].lower(): + language = 'Sub-' + language + + if not language: language = lang + if language: longtitle += typo(language, '_ [] color kod') + + return language, longtitle + +def cleantitle(title): + cleantitle = scrapertoolsV2.htmlclean(scrapertoolsV2.decodeHtmlentities(title).replace('"', "'").replace('×', 'x').replace('–', '-')).strip() + return cleantitle + +def scrapeBlock(item, args, block, patron, headers, action, pagination, debug, typeContentDict, typeActionDict, blacklist, search, pag, function, lang): + itemlist = [] + log("scrapeBlock qui", block, patron) + matches = scrapertoolsV2.find_multiple_matches_groups(block, patron) + log('MATCHES =', matches) + + if debug: + regexDbg(item, patron, headers, block) + + known_keys = ['url', 'title', 'title2', 'season', 'episode', 'thumb', 'quality', 'year', 'plot', 'duration', 'genere', 'rating', 'type', 'lang'] + # Legenda known_keys per i groups nei patron + # known_keys = ['url', 'title', 'title2', 'season', 'episode', 'thumb', 'quality', + # 'year', 'plot', 'duration', 'genere', 'rating', 'type', 'lang'] + # url = link relativo o assoluto alla pagina titolo film/serie + # title = titolo Film/Serie/Anime/Altro + # title2 = titolo dell'episodio Serie/Anime/Altro + # season = stagione in formato numerico + # episode = numero episodio, in formato numerico. + # thumb = linkrealtivo o assoluto alla locandina Film/Serie/Anime/Altro + # quality = qualità indicata del video + # year = anno in formato numerico (4 cifre) + # duration = durata del Film/Serie/Anime/Altro + # genere = genere del Film/Serie/Anime/Altro. Es: avventura, commedia + # rating = punteggio/voto in formato numerico + # type = tipo del video. Es. movie per film o tvshow per le serie. Di solito sono discrimanti usati dal sito + # lang = lingua del video. Es: ITA, Sub-ITA, Sub, SUB ITA. + # AVVERTENZE: Se il titolo è trovato nella ricerca TMDB/TVDB/Altro allora le locandine e altre info non saranno quelle recuperate nel sito.!!!! + + stagione = '' # per quei siti che hanno la stagione nel blocco ma non nelle puntate + for i, match in enumerate(matches): + if pagination and (pag - 1) * pagination > i: continue # pagination + if pagination and i >= pag * pagination: break # pagination + listGroups = match.keys() + match = match.values() + + if len(listGroups) > len(match): # to fix a bug + match = list(match) + match.extend([''] * (len(listGroups) - len(match))) + + scraped = {} + for kk in known_keys: + val = match[listGroups.index(kk)] if kk in listGroups else '' + if val and (kk == "url" or kk == 'thumb') and 'http' not in val: + val = scrapertoolsV2.find_single_match(item.url, 'https?://[a-z0-9.-]+') + val + scraped[kk] = val + + if scraped['season']: + stagione = scraped['season'] + episode = scraped['season'] +'x'+ scraped['episode'] + elif stagione: + episode = stagione +'x'+ scraped['episode'] + elif item.contentType == 'tvshow' and (scraped['episode'] == '' and scraped['season'] == '' and stagione == ''): + item.news = 'season_completed' + episode = '' + else: + episode = re.sub(r'\s-\s|-|x|–|×', 'x', scraped['episode']) if scraped['episode'] else '' + + #episode = re.sub(r'\s-\s|-|x|–|×', 'x', scraped['episode']) if scraped['episode'] else '' + title = cleantitle(scraped['title']) if scraped['title'] else '' + title2 = cleantitle(scraped['title2']) if scraped['title2'] else '' + quality = scraped['quality'].strip() if scraped['quality'] else '' + Type = scraped['type'] if scraped['type'] else '' + plot = cleantitle(scraped["plot"]) if scraped["plot"] else '' + + # make formatted Title [longtitle] + s = ' - ' + title = episode + (s if episode and title else '') + title + longtitle = title + (s if title and title2 else '') + title2 + longtitle = typo(longtitle, 'bold') + longtitle += typo(quality, '_ [] color kod') if quality else '' + + lang1, longtitle = scrapeLang(scraped, lang, longtitle) + + # if title is set, probably this is a list of episodes or video sources + # necessaria l'aggiunta di == scraped["title"] altrimenti non prende i gruppi dopo le categorie + if item.infoLabels["title"] == scraped["title"]: + infolabels = item.infoLabels + else: + infolabels = {} + if scraped['year']: + infolabels['year'] = scraped['year'] + if scraped["plot"]: + infolabels['plot'] = plot + if scraped['duration']: + matches = scrapertoolsV2.find_multiple_matches(scraped['duration'], + r'([0-9])\s*?(?:[hH]|:|\.|,|\\|\/|\||\s)\s*?([0-9]+)') + for h, m in matches: + scraped['duration'] = int(h) * 60 + int(m) + if not matches: + scraped['duration'] = scrapertoolsV2.find_single_match(scraped['duration'], r'(\d+)') + infolabels['duration'] = int(scraped['duration']) * 60 + if scraped['genere']: + genres = scrapertoolsV2.find_multiple_matches(scraped['genere'], '[A-Za-z]+') + infolabels['genere'] = ", ".join(genres) + if scraped["rating"]: + infolabels['rating'] = scrapertoolsV2.decodeHtmlentities(scraped["rating"]) + + AC = CT = '' + if typeContentDict: + for name, variants in typeContentDict.items(): + if str(scraped['type']).lower() in variants: + CT = name + break + else: CT = item.contentType + if typeActionDict: + for name, variants in typeActionDict.items(): + if str(scraped['type']).lower() in variants: + AC = name + break + else: AC = action + + if (scraped["title"] not in blacklist) and (search.lower() in longtitle.lower()): + it = Item( + channel=item.channel, + action=AC if AC else action, + contentType='episode' if function == 'episodios' else CT if CT else item.contentType, + title=longtitle, + fulltitle=item.fulltitle if function == 'episodios' else title, + show=item.show if function == 'episodios' else title, + quality=quality, + url=scraped["url"], + infoLabels=infolabels, + thumbnail=item.thumbnail if function == 'episodios' else scraped["thumb"] , + args=item.args, + contentSerieName= scraped['title'] if item.contentType or CT != 'movie' and function != 'episodios' else item.fulltitle if function == 'episodios' else '', + contentTitle= scraped['title'] if item.contentType or CT == 'movie' else '', + contentLanguage = lang1, + contentEpisodeNumber=episode if episode else '', + news= item.news if item.news else '' + ) + + for lg in list(set(listGroups).difference(known_keys)): + it.__setattr__(lg, match[listGroups.index(lg)]) + + if 'itemHook' in args: + it = args['itemHook'](it) + itemlist.append(it) + + return itemlist, matches + + +def scrape(func): + # args is a dict containing the foolowing keys: # patron: the patron to use for scraping page, all capturing group must match with listGroups # listGroups: a list containing the scraping info obtained by your patron, in order # accepted values are: url, title, thumb, quality, year, plot, duration, genre, rating, episode, lang - # header: values to pass to request header + # headers: values to pass to request header # blacklist: titles that you want to exclude(service articles for example) # data: if you want to pass data manually, maybe because you need some custom replacement - # patron_block: patron to get parts of the page (to scrape with patron attribute), + # patronBlock: patron to get parts of the page (to scrape with patron attribute), # if you need a "block inside another block" you can create a list, please note that all matches # will be packed as string # patronNext: patron for scraping next page link # action: if you want results perform an action different from "findvideos", useful when scraping film by genres - # url_host: string to prepend to scrapedurl, useful when url don't contain host + # addVideolibrary: if "add to videolibrary" should appear # example usage: # import support # itemlist = [] # patron = 'blablabla' # headers = [['Referer', host]] # blacklist = 'Request a TV serie!' - # return support.scrape(item, itemlist, patron, ['thumb', 'quality', 'url', 'title', 'title2', 'year', 'plot', 'episode', 'lang'], + # return support.scrape(item, itemlist, patron, ['thumb', 'quality', 'url', 'title', 'year', 'plot', 'episode', 'lang'], # headers=headers, blacklist=blacklist) - # listGroups - # thumb = immagine, quality = qualità, url = link singolo o gruppo, title = titolo film o serie, title2 = titolo aggiuntivo - # year = anno del film o della serie, plot = descrizione film o serie, episode = numero stagione - numero episodio in caso di serie, - # lang = lingua del video # 'type' is a check for typologies of content e.g. Film or TV Series # 'episode' is a key to grab episode numbers if it is separated from the title - # IMPORTANT 'type' is a special key, to work need type_content_dict={} and type_action_dict={} + # IMPORTANT 'type' is a special key, to work need typeContentDict={} and typeActionDict={} - itemlist = [] + def wrapper(*args): + itemlist = [] - if not data: - data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data.replace("'", '"') - data = re.sub('\n|\t', ' ', data) - # replace all ' with " and eliminate newline, so we don't need to worry about - log('DATA =', data) + args = func(*args) + function = func.__name__ if not 'actLike' in args else args['actLike'] + # log('STACK= ',inspect.stack()[1][3]) - block = data + item = args['item'] - if patron_block: - if type(patron_block) == str: - patron_block = [patron_block] - - for n, regex in enumerate(patron_block): - blocks = scrapertoolsV2.find_multiple_matches(block, regex) - block = "" - for b in blocks: - block += "\n" + str(b) - log('BLOCK ', n, '=', block) - else: - block = data - if patron and listGroups: - matches = scrapertoolsV2.find_multiple_matches(block, patron) - log('MATCHES =', matches) - - known_keys = ['url', 'title', 'title2', 'episode', 'thumb', 'quality', 'year', 'plot', 'duration', 'genere', 'rating', 'type', 'lang'] #by greko aggiunto episode - lang = '' # aggiunto per gestire i siti con pagine di serietv dove si hanno i video in ita e in subita - - for match in matches: - if len(listGroups) > len(match): # to fix a bug - match = list(match) - match.extend([''] * (len(listGroups) - len(match))) - - scraped = {} - for kk in known_keys: - val = match[listGroups.index(kk)] if kk in listGroups else '' - if val and (kk == "url" or kk == 'thumb') and 'http' not in val: - val = scrapertoolsV2.find_single_match(item.url, 'https?://[a-z0-9.-]+') + val - scraped[kk] = val - - title = scrapertoolsV2.htmlclean(scrapertoolsV2.decodeHtmlentities(scraped["title"])).replace('’', '\'').replace('"', "'").strip() # fix by greko da " a ' - plot = scrapertoolsV2.htmlclean(scrapertoolsV2.decodeHtmlentities(scraped["plot"])) - - longtitle = typo(title, 'bold') - if scraped['quality']: longtitle = longtitle + typo(scraped['quality'], '_ [] color kod') - if scraped['episode']: - scraped['episode'] = re.sub(r'\s-\s|-|x|–', 'x' , scraped['episode']) - longtitle = typo(scraped['episode'] + ' - ', 'bold') + longtitle - if scraped['title2']: - title2 = scrapertoolsV2.htmlclean(scrapertoolsV2.decodeHtmlentities(scraped["title2"])).replace('"', "'").strip() - longtitle = longtitle + typo(title2, 'bold _ -- _') - - ## Aggiunto/modificato per gestire i siti che hanno i video - ## in ita e subita delle serie tv nella stessa pagina - if scraped['lang'] == '': #altrimenti nei canali dei film mi aggiunge sub-ita a tutti i film successivi - lang = '' # o in alternativa lang = 'ITA' - if scraped['lang']: - if 'sub' in scraped['lang'].lower(): - lang = 'Sub-ITA' - else: - lang = 'ITA' - if lang != '': - longtitle += typo(lang, '_ [] color kod') - - if item.infoLabels["title"] or item.fulltitle: # if title is set, probably this is a list of episodes or video sources - infolabels = item.infoLabels - else: - infolabels = {} - if scraped["year"]: - infolabels['year'] = scraped["year"] - if scraped["plot"]: - infolabels['plot'] = plot - if scraped["duration"]: - matches = scrapertoolsV2.find_multiple_matches(scraped["duration"],r'([0-9])\s*?(?:[hH]|:|\.|,|\\|\/|\||\s)\s*?([0-9]+)') - for h, m in matches: - scraped["duration"] = int(h) * 60 + int(m) - if not matches: - scraped["duration"] = scrapertoolsV2.find_single_match(scraped["duration"], r'(\d+)') - infolabels['duration'] = int(scraped["duration"]) * 60 - if scraped["genere"]: - genres = scrapertoolsV2.find_multiple_matches(scraped["genere"], '[A-Za-z]+') - infolabels['genere'] = ", ".join(genres) - if scraped["rating"]: - infolabels['rating'] = scrapertoolsV2.decodeHtmlentities(scraped["rating"]) - - if type_content_dict: - for name, variants in type_content_dict.items(): - if scraped['type'] in variants: - item.contentType = name - if type_action_dict: - for name, variants in type_action_dict.items(): - if scraped['type'] in variants: - action = name - - if inspect.stack()[1][3] == 'episodios': item.contentType = 'episode' - - if scraped["title"] not in blacklist: - it = Item( - channel=item.channel, - action=action, - contentType=item.contentType, - title=longtitle, - fulltitle=title, - show=title, - language = lang if lang != '' else '', - quality=scraped["quality"], - url=scraped["url"], - infoLabels=infolabels, - thumbnail=scraped["thumb"], - args=item.args - ) - - for lg in list(set(listGroups).difference(known_keys)): - it.__setattr__(lg, match[listGroups.index(lg)]) - - itemlist.append(it) - checkHost(item, itemlist) - if (item.contentType == "tvshow" and (action != "findvideos" and action != "play")) \ - or (item.contentType == "episode" and action != "play") \ - or (item.contentType == "movie" and action != "play"): - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) + action = args['action'] if 'action' in args else 'findvideos' + anime = args['anime'] if 'anime' in args else '' + addVideolibrary = args['addVideolibrary'] if 'addVideolibrary' in args else True + search = args['search'] if 'search' in args else '' + blacklist = args['blacklist'] if 'blacklist' in args else [] + data = args['data'] if 'data' in args else '' + patron = args['patron'] if 'patron' in args else args['patronMenu'] if 'patronMenu' in args else '' + if 'headers' in args: + headers = args['headers'] + elif 'headers' in func.__globals__: + headers = func.__globals__['headers'] else: - for it in itemlist: - it.infoLabels = item.infoLabels + headers = '' + patronNext = args['patronNext'] if 'patronNext' in args else '' + patronBlock = args['patronBlock'] if 'patronBlock' in args else '' + typeActionDict = args['typeActionDict'] if 'typeActionDict' in args else {} + typeContentDict = args['typeContentDict'] if 'typeContentDict' in args else {} + debug = args['debug'] if 'debug' in args else False + if 'pagination' in args and inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: pagination = args['pagination'] if args['pagination'] else 20 + else: pagination = '' + lang = args['deflang'] if 'deflang' in args else '' + pag = item.page if item.page else 1 # pagination + matches = [] - if patronNext: - nextPage(itemlist, item, data, patronNext, 2) + log('PATRON= ', patron) + if not data: + data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data.replace("'", '"') + data = re.sub('\n|\t', ' ', data) + data = re.sub(r'>\s+<', '> <', data) + # replace all ' with " and eliminate newline, so we don't need to worry about + log('DATA =', data) - if addVideolibrary and (item.infoLabels["title"] or item.fulltitle): - item.fulltitle = item.infoLabels["title"] - videolibrary(itemlist, item) + if patronBlock: + blocks = scrapertoolsV2.find_multiple_matches_groups(data, patronBlock) + block = "" + for bl in blocks: + blockItemlist, blockMatches = scrapeBlock(item, args, bl['block'], patron, headers, action, pagination, debug, + typeContentDict, typeActionDict, blacklist, search, pag, function, lang) + for it in blockItemlist: + if 'lang' in bl: + it.contentLanguage, it.title = scrapeLang(bl, it.contentLanguage, it.title) + if 'quality' in bl and bl['quality']: + it.quality = bl['quality'].strip() + it.title = it.title + typo(bl['quality'].strip(), '_ [] color kod') + log('BLOCK ', '=', block) + itemlist.extend(blockItemlist) + matches.extend(blockMatches) + elif patron: + itemlist, matches = scrapeBlock(item, args, data, patron, headers, action, pagination, debug, typeContentDict, + typeActionDict, blacklist, search, pag, function, lang) - return itemlist + if 'itemlistHook' in args: + itemlist = args['itemlistHook'](itemlist) + if (pagination and len(matches) <= pag * pagination) or not pagination: # next page with pagination + if patronNext and inspect.stack()[1][3] != 'newest': + nextPage(itemlist, item, data, patronNext, function) -def checkHost(item, itemlist): - # nel caso non ci siano risultati puo essere che l'utente abbia cambiato manualmente l'host, pertanto lo riporta - # al valore di default (fixa anche il problema del cambio di host da parte nostra) - if len(itemlist) == 0: - # trovo il valore di default - defHost = None - for s in channeltools.get_channel_json(item.channel)['settings']: - if s['id'] == 'channel_host': - defHost = s['default'] - break - # lo confronto con quello attuale - if config.get_setting('channel_host', item.channel) != defHost: - config.set_setting('channel_host', defHost, item.channel) + # next page for pagination + if pagination and len(matches) > pag * pagination and not search: + if inspect.stack()[1][3] != 'get_newest': + itemlist.append( + Item(channel=item.channel, + action = item.action, + contentType=item.contentType, + title=typo(config.get_localized_string(30992), 'color kod bold'), + fulltitle= item.fulltitle, + show= item.show, + url=item.url, + args=item.args, + page=pag + 1, + thumbnail=thumb())) + + if action != 'play' and function != 'episodios' and 'patronMenu' not in args: + tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) + + from specials import autorenumber + if anime: + if function == 'episodios' or item.action == 'episodios': autorenumber.renumber(itemlist, item, 'bold') + else: autorenumber.renumber(itemlist) + if anime and autorenumber.check(item) == False and not scrapertoolsV2.find_single_match(itemlist[0].title, r'(\d+.\d+)'): + pass + else: + if addVideolibrary and (item.infoLabels["title"] or item.fulltitle): + # item.fulltitle = item.infoLabels["title"] + videolibrary(itemlist, item, function=function) + if config.get_setting('downloadenabled') and (function == 'episodios' or function == 'findvideos'): + download(itemlist, item, function=function) + + if 'patronMenu' in args: + itemlist = thumb(itemlist, genre=True) + + if 'fullItemlistHook' in args: + itemlist = args['fullItemlistHook'](itemlist) + + # itemlist = filterLang(item, itemlist) # causa problemi a newest + + return itemlist + + return wrapper def dooplay_get_links(item, host): @@ -292,7 +467,7 @@ def dooplay_get_links(item, host): "nume": nume, "type": type }) - dataAdmin = httptools.downloadpage(host + 'wp-admin/admin-ajax.php', post=postData,headers={'Referer': item.url}).data + dataAdmin = httptools.downloadpage(host + '/wp-admin/admin-ajax.php', post=postData,headers={'Referer': item.url}).data link = scrapertoolsV2.find_single_match(dataAdmin, "<iframe.*src='([^']+)'") ret.append({ 'url': link, @@ -303,61 +478,57 @@ def dooplay_get_links(item, host): return ret +@scrape def dooplay_get_episodes(item): - itemlist = [] - item.contentType = "episode" - data = httptools.downloadpage(item.url).data.replace("'", '"') - patron = '<li class="mark-[0-9]">.*?<img.*?data-lazy-src="([^"]+).*?([0-9] - [0-9]).*?<a href="([^"]+)">([^<>]+).*?([0-9]{4})' + item.contentType = 'tvshow' + patron = '<li class="mark-[0-9]+">.*?<img.*?(?:data-lazy-)?src="(?P<thumb>[^"]+).*?(?P<episode>[0-9]+ - [0-9]+).*?<a href="(?P<url>[^"]+)">(?P<title>[^<>]+).*?(?P<year>[0-9]{4})' + actLike = 'episodios' - for scrapedthumb, scrapedep, scrapedurl, scrapedtitle, scrapedyear in scrapertoolsV2.find_multiple_matches(data, patron): - scrapedep = scrapedep.replace(' - ', 'x') - infoLabels = {} - infoLabels['year'] = scrapedyear - - itemlist.append( - Item(channel=item.channel, - action="findvideos", - contentType="episode", - title=scrapedep + " " + scrapedtitle, - fulltitle=scrapedtitle, - show=item.fulltitle, - url=scrapedurl, - thumbnail=scrapedthumb, - infoLabels=infoLabels - ) - ) - tmdb.set_infoLabels_itemlist(itemlist, seekTmdb=True) - videolibrary(itemlist, item) - return itemlist + return locals() -def dooplay_films(item, blacklist=""): - if item.contentType == 'movie': - action = 'findvideos' - patron = '<article id="post-[0-9]+" class="item movies">.*?<img src="(?!data)([^"]+)".*?<span class="quality">([^<>]+).*?<a href="([^"]+)">([^<>]+)</a></h3>.*?(?:<span>([0-9]{4})</span>|</article>).*?(?:<span>([0-9]+) min</span>|</article>).*?(?:<div class="texto">([^<>]+)|</article>).*?(?:genres">(.*?)</div>|</article>)' +@scrape +def dooplay_peliculas(item, mixed=False, blacklist=""): + actLike = 'peliculas' + if item.args == 'searchPage': + return dooplay_search_vars(item, blacklist) else: - action = 'episodios' - patron = '<article id="post-[0-9]+" class="item tvshows">.*?<img src="(?!data)([^"]+)".*?(?:<span class="quality">([^<>]+))?.*?<a href="([^"]+)">([^<>]+)</a></h3>.*?(?:<span>([0-9]{4})</span>|</article>).*?(?:<span>([0-9]+) min</span>|</article>).*?(?:<div class="texto">([^<>]+)|</article>).*?(?:genres">(.*?)</div>|</article>)' - # patronNext = '<a class="arrow_pag" href="([^"]+)"><i id="nextpagination"' - patronNext = '<div class="pagination">.*?class="current".*?<a href="([^"]+)".*?<div class="resppages">' - itemlist = scrape(item, patron, ['thumb', 'quality', 'url', 'title', 'year', 'duration', 'plot', 'genre'], blacklist=blacklist, patronNext=patronNext, action=action, addVideolibrary=False) - if itemlist and 'Successivo' in itemlist[-1].title: - itemlist[-1].action = 'peliculas' + if item.contentType == 'movie': + action = 'findvideos' + patron = '<article id="post-[0-9]+" class="item movies">.*?<img src="(?!data)(?P<thumb>[^"]+)".*?<span class="quality">(?P<quality>[^<>]+).*?<a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a></h3>.*?(?:<span>[^<>]*(?P<year>[0-9]{4})</span>|</article>)' + else: + action = 'episodios' + patron = '<article id="post-[0-9]+" class="item (?P<type>' + ('\w+' if mixed else 'tvshows') + ')">.*?<img src="(?!data)(?P<thumb>[^"]+)".*?(?:<span class="quality">(?P<quality>[^<>]+))?.*?<a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a></h3>.*?(?:<span>(?P<year>[0-9]{4})</span>|</article>).*?(?:<div class="texto">(?P<plot>[^<>]+)|</article>).*?(?:genres">(?P<genre>.*?)</div>|</article>)' + patronNext = '<div class="pagination">.*?class="current".*?<a href="([^"]+)".*?<div class="resppages">' + addVideolibrary = False - return itemlist + if mixed: + typeActionDict={'findvideos': ['movies'], 'episodios': ['tvshows']} + typeContentDict={'film': ['movies'], 'serie': ['tvshows']} - + return locals() + + +@scrape def dooplay_search(item, blacklist=""): - if item.contentType == 'movie': + return dooplay_search_vars(item, blacklist) + + +def dooplay_search_vars(item, blacklist): + if item.contentType == 'list': # ricerca globale + type = '(?P<type>movies|tvshows)' + typeActionDict = {'findvideos': ['movies'], 'episodios': ['tvshows']} + typeContentDict = {'movie': ['movies'], 'tvshow': ['tvshows']} + elif item.contentType == 'movie': type = 'movies' action = 'findvideos' else: type = 'tvshows' action = 'episodios' - patron = '<div class="result-item">.*?<img src="([^"]+)".*?<span class="' + type + '">([^<>]+).*?<a href="([^"]+)">([^<>]+)</a>.*?<span class="year">([0-9]{4}).*?<div class="contenido"><p>([^<>]+)' + patron = '<div class="result-item">.*?<img src="(?P<thumb>[^"]+)".*?<span class="' + type + '">(?P<quality>[^<>]+).*?<a href="(?P<url>[^"]+)">(?P<title>[^<>]+)</a>.*?<span class="year">(?P<year>[0-9]{4}).*?<div class="contenido"><p>(?P<plot>[^<>]+)' patronNext = '<a class="arrow_pag" href="([^"]+)"><i id="nextpagination"' - return scrape(item, patron, ['thumb', 'quality', 'url', 'title', 'year', 'plot'], blacklist=blacklist, patronNext=patronNext, action=action) + return locals() def swzz_get_url(item): headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0'} @@ -398,13 +569,9 @@ def swzz_get_url(item): return data -def menu(itemlist, title='', action='', url='', contentType='movie', args=[]): +def menuItem(itemlist, filename, title='', action='', url='', contentType='movie', args=[]): # Function to simplify menu creation - frame = inspect.stack()[1] - filename = frame[0].f_code.co_filename - filename = os.path.basename(filename).replace('.py','') - # Call typo function title = typo(title) @@ -424,15 +591,99 @@ def menu(itemlist, title='', action='', url='', contentType='movie', args=[]): # Apply auto Thumbnails at the menus from channelselector import thumb thumb(itemlist) - return itemlist +def menu(func): + def wrapper(*args): + log() + args = func(*args) + + item = args['item'] + host = func.__globals__['host'] + list_servers = func.__globals__['list_servers'] + list_quality = func.__globals__['list_quality'] + filename = func.__module__.split('.')[1] + + # listUrls = ['film', 'filmSub', 'tvshow', 'tvshowSub', 'anime', 'animeSub', 'search', 'top', 'topSub'] + listUrls = ['top', 'film', 'tvshow', 'anime', 'search'] + listUrls_extra = [] + dictUrl = {} + + + # Main options + itemlist = [] + + for name in listUrls: + dictUrl[name] = args[name] if name in args else None + log(dictUrl[name]) + if name == 'film': title = 'Film' + if name == 'tvshow': title = 'Serie TV' + if name == 'anime': title = 'Anime' + + if name == 'search' and dictUrl[name] is not None: + menuItem(itemlist, filename, 'Cerca… bold', 'search', host + dictUrl['search']) + + # Make TOP MENU + elif name == 'top' and dictUrl[name] is not None: + for sub, var in dictUrl['top']: + menuItem(itemlist, filename, + title = sub + ' italic bold', + url = host + var[0] if len(var) > 0 else '', + action = var[1] if len(var) > 1 else 'peliculas', + args=var[2] if len(var) > 2 else '', + contentType= var[3] if len(var) > 3 else 'movie',) + + # Make MAIN MENU + elif dictUrl[name] is not None: + if len(dictUrl[name]) == 0: url = '' + else: url = dictUrl[name][0] if type(dictUrl[name][0]) is not tuple and len(dictUrl[name][0]) > 0 else '' + menuItem(itemlist, filename, + title + ' bullet bold', 'peliculas', + host + url, + contentType='movie' if name == 'film' else 'tvshow') + if len(dictUrl[name]) > 0: + if type(dictUrl[name][0]) is not tuple and type(dictUrl[name]) is not str: dictUrl[name].pop(0) + if dictUrl[name] is not None and type(dictUrl[name]) is not str: + for sub, var in dictUrl[name]: + menuItem(itemlist, filename, + title = sub + ' submenu' + typo(title,'_ {}'), + url = host + var[0] if len(var) > 0 else '', + action = var[1] if len(var) > 1 else 'peliculas', + args=var[2] if len(var) > 2 else '', + contentType= var[3] if len(var) > 3 else 'movie' if name == 'film' else 'tvshow',) + # add search menu for category + if 'search' not in args: menuItem(itemlist, filename, 'Cerca ' + title + '… submenu bold', 'search', host + url, contentType='movie' if name == 'film' else 'tvshow') + + # Make EXTRA MENU (on bottom) + for name, var in args.items(): + if name not in listUrls and name != 'item': + listUrls_extra.append(name) + for name in listUrls_extra: + dictUrl[name] = args[name] if name in args else None + for sub, var in dictUrl[name]: + menuItem(itemlist, filename, + title = sub + ' ', + url = host + var[0] if len(var) > 0 else '', + action = var[1] if len(var) > 1 else 'peliculas', + args=var[2] if len(var) > 2 else '', + contentType= var[3] if len(var) > 3 else 'movie',) + + + autoplay.init(item.channel, list_servers, list_quality) + autoplay.show_option(item.channel, itemlist) + channel_config(item, itemlist) + + return itemlist + + return wrapper + + def typo(string, typography=''): kod_color = '0xFF65B3DA' #'0xFF0081C2' - + string = str(string) # Check if the typographic attributes are in the string or outside if typography: string = string + ' ' + typography @@ -455,7 +706,7 @@ def typo(string, typography=''): string = '[B]' + string + '[/B]' # Otherwise it uses the typographical attributes of the string - else: + else: if '[]' in string: string = '[' + re.sub(r'\s\[\]','',string) + ']' if '()' in string: @@ -463,7 +714,7 @@ def typo(string, typography=''): if '{}' in string: string = '{' + re.sub(r'\s\{\}','',string) + '}' if 'submenu' in string: - string = ' > ' + re.sub(r'\ssubmenu','',string) + string = u"\u2022\u2022 ".encode('utf-8') + re.sub(r'\ssubmenu','',string) if 'color' in string: color = scrapertoolsV2.find_single_match(string,'color ([a-z]+)') if color == 'kod' or '': color = kod_color @@ -471,40 +722,101 @@ def typo(string, typography=''): if 'bold' in string: string = '[B]' + re.sub(r'\sbold','',string) + '[/B]' if 'italic' in string: - string = '[I]' + re.sub(r'\sitalic','',string) + '[/I]' + string = '[I]' + re.sub(r'\sitalic','',string) + '[/I]' if '_' in string: string = ' ' + re.sub(r'\s_','',string) if '--' in string: string = ' - ' + re.sub(r'\s--','',string) + if 'bullet' in string: + string = '[B]' + u"\u2022".encode('utf-8') + '[/B] ' + re.sub(r'\sbullet','',string) return string -def match(item, patron='', patron_block='', headers='', url=''): +def match(item, patron='', patronBlock='', headers='', url='', post=''): matches = [] - url = url if url else item.url - data = httptools.downloadpage(url, headers=headers, ignore_response_code=True).data.replace("'", '"') + if type(item) == str: + data = item + else: + url = url if url else item.url + if post: + data = httptools.downloadpage(url, headers=headers, ignore_response_code=True, post=post).data.replace("'", '"') + else: + data = httptools.downloadpage(url, headers=headers, ignore_response_code=True).data.replace("'", '"') data = re.sub(r'\n|\t', ' ', data) data = re.sub(r'>\s\s*<', '><', data) log('DATA= ', data) - if patron_block: - block = scrapertoolsV2.find_single_match(data, patron_block) + if patronBlock: + block = scrapertoolsV2.find_single_match(data, patronBlock) log('BLOCK= ',block) else: block = data - + if patron: matches = scrapertoolsV2.find_multiple_matches(block, patron) log('MATCHES= ',matches) - return matches, data + return matches, block -def videolibrary(itemlist, item, typography='', function_level=1): +def download(itemlist, item, typography='', function_level=1, function=''): + if not typography: typography = 'color kod bold' + + if item.contentType == 'movie': + from_action = 'findvideos' + title = typo(config.get_localized_string(60354), typography) + elif item.contentType == 'episode': + from_action = 'findvideos' + title = typo(config.get_localized_string(60356), typography) + ' - ' + item.title + else: + from_action = 'episodios' + title = typo(config.get_localized_string(60355), typography) + + function = function if function else inspect.stack()[function_level][3] + + contentSerieName=item.contentSerieName if item.contentSerieName else '' + contentTitle=item.contentTitle if item.contentTitle else '' + + if itemlist and item.contentChannel != 'videolibrary': + itemlist.append( + Item(channel='downloads', + from_channel=item.channel, + title=title, + fulltitle=item.fulltitle, + show=item.fulltitle, + contentType=item.contentType, + contentSerieName=contentSerieName, + url=item.url, + action='save_download', + from_action=from_action, + contentTitle=contentTitle, + path=item.path + )) + if from_action == 'episodios': + itemlist.append( + Item(channel='downloads', + from_channel=item.channel, + title=typo(config.get_localized_string(60357),typography), + fulltitle=item.fulltitle, + show=item.fulltitle, + contentType=item.contentType, + contentSerieName=contentSerieName, + url=item.url, + action='save_download', + from_action=from_action, + contentTitle=contentTitle, + download='season' + )) + + return itemlist + + +def videolibrary(itemlist, item, typography='', function_level=1, function=''): # Simply add this function to add video library support # Function_level is useful if the function is called by another function. # If the call is direct, leave it blank + log() if item.contentType == 'movie': action = 'add_pelicula_to_library' @@ -515,28 +827,38 @@ def videolibrary(itemlist, item, typography='', function_level=1): extra = 'episodios' contentType = 'tvshow' + function = function if function else inspect.stack()[function_level][3] + if not typography: typography = 'color kod bold' - title = typo(config.get_localized_string(30161) + ' ' + typography) - log('STACK= ',inspect.stack()[function_level][3]) - if (inspect.stack()[function_level][3] == 'findvideos' and contentType == 'movie') \ - or (inspect.stack()[function_level][3] == 'episodios' and contentType != 'movie'): + title = typo(config.get_localized_string(30161), typography) + contentSerieName=item.contentSerieName if item.contentSerieName else '' + contentTitle=item.contentTitle if item.contentTitle else '' + + if (function == 'findvideos' and contentType == 'movie') \ + or (function == 'episodios' and contentType != 'movie') \ + or function == 'get_seasons' and item.channel == 'community': if config.get_videolibrary_support() and len(itemlist) > 0: itemlist.append( Item(channel=item.channel, - title=title, - contentType=contentType, - contentSerieName=item.fulltitle if contentType == 'tvshow' else '', - url=item.url, - action=action, - extra=extra, - contentTitle=item.fulltitle)) + title=title, + fulltitle=item.fulltitle, + show=item.fulltitle, + contentType=contentType, + contentSerieName=contentSerieName, + url=item.url, + action=action, + extra=extra, + contentTitle=contentTitle, + path=item.path + )) return itemlist -def nextPage(itemlist, item, data='', patron='', function_level=1, next_page='', resub=[]): +def nextPage(itemlist, item, data='', patron='', function_or_level=1, next_page='', resub=[]): # Function_level is useful if the function is called by another function. # If the call is direct, leave it blank + action = inspect.stack()[function_or_level][3] if type(function_or_level) == int else function_or_level if next_page == '': next_page = scrapertoolsV2.find_single_match(data, patron) @@ -544,10 +866,11 @@ def nextPage(itemlist, item, data='', patron='', function_level=1, next_page='', if resub: next_page = re.sub(resub[0], resub[1], next_page) if 'http' not in next_page: next_page = scrapertoolsV2.find_single_match(item.url, 'https?://[a-z0-9.-]+') + next_page + next_page = re.sub('&', '&',next_page) log('NEXT= ', next_page) itemlist.append( Item(channel=item.channel, - action=inspect.stack()[function_level][3], + action = action, contentType=item.contentType, title=typo(config.get_localized_string(30992), 'color kod bold'), url=next_page, @@ -557,7 +880,7 @@ def nextPage(itemlist, item, data='', patron='', function_level=1, next_page='', return itemlist def pagination(itemlist, item, page, perpage, function_level=1): - if len(itemlist) >= perpage: # page * perpage + if len(itemlist) >= page * perpage: itemlist.append( Item(channel=item.channel, action=inspect.stack()[function_level][3], @@ -569,27 +892,39 @@ def pagination(itemlist, item, page, perpage, function_level=1): thumbnail=thumb())) return itemlist -def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True): - - if not data: +def server(item, data='', itemlist=[], headers='', AutoPlay=True, CheckLinks=True, down_load=True): + + if not data and not itemlist: data = httptools.downloadpage(item.url, headers=headers, ignore_response_code=True).data - itemList = servertools.find_video_items(data=str(data)) - itemlist += itemList - + itemlist = itemlist + itemList + + verifiedItemlist = [] for videoitem in itemlist: - item.title = typo(item.contentTitle,'bold') if item.contentType == 'movie' else item.title - videoitem.title = "".join([item.title, typo(videoitem.title, '_ color kod []'), typo(videoitem.quality, '_ color kod []') if videoitem.quality else ""]) + if not videoitem.server: + findS = servertools.findvideos(videoitem.url) + if findS: + findS = findS[0] + else: + log(videoitem, 'Non supportato') + continue + videoitem.server = findS[2] + videoitem.title = findS[0] + videoitem.url = findS[1] + item.title = item.contentTitle.strip() if item.contentType == 'movie' or ( + config.get_localized_string(30161) in item.title) else item.title + videoitem.title = item.title + (typo(videoitem.title, '_ color kod []') if videoitem.title else "") + (typo(videoitem.quality, '_ color kod []') if videoitem.quality else "") videoitem.fulltitle = item.fulltitle videoitem.show = item.show videoitem.thumbnail = item.thumbnail videoitem.channel = item.channel videoitem.contentType = item.contentType + verifiedItemlist.append(videoitem) - return controls(itemlist, item, AutoPlay, CheckLinks) + return controls(verifiedItemlist, item, AutoPlay, CheckLinks, down_load) -def controls(itemlist, item, AutoPlay=True, CheckLinks=True): +def controls(itemlist, item, AutoPlay=True, CheckLinks=True, down_load=True): from core import jsontools from platformcode.config import get_setting @@ -599,7 +934,7 @@ def controls(itemlist, item, AutoPlay=True, CheckLinks=True): if not channel_node: # non ha mai aperto il menu del canale quindi in autoplay_data.json non c'e la key channelFile = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) autoplay.init(item.channel, channelFile.list_servers, channelFile.list_quality) - + autoplay_node = jsontools.get_node_from_file('autoplay', 'AUTOPLAY') channel_node = autoplay_node.get(item.channel, {}) settings_node = channel_node.get('settings', {}) @@ -609,19 +944,27 @@ def controls(itemlist, item, AutoPlay=True, CheckLinks=True): if get_setting('checklinks', item.channel): checklinks = get_setting('checklinks', item.channel) else: - checklinks = get_setting('checklinks') + checklinks = get_setting('checklinks') if get_setting('checklinks_number', item.channel): checklinks_number = get_setting('checklinks_number', item.channel) else: checklinks_number = get_setting('checklinks_number') itemlist = servertools.check_list_links(itemlist, checklinks_number) - if AutoPlay == True: + if AutoPlay == True and inspect.stack()[4][3] != 'start_download': autoplay.start(itemlist, item) if item.contentChannel != 'videolibrary': videolibrary(itemlist, item, function_level=3) + if get_setting('downloadenabled') and down_load == True: download(itemlist, item, function_level=3) return itemlist +def filterLang(item, itemlist): + import channeltools + list_language = channeltools.get_lang(item.channel) + if len(list_language) > 1: + from specials import filtertools + itemlist = filtertools.get_links(itemlist, item, list_language) + return itemlist def aplay(item, itemlist, list_servers='', list_quality=''): if inspect.stack()[1][3] == 'mainlist': @@ -634,11 +977,11 @@ def aplay(item, itemlist, list_servers='', list_quality=''): def log(stringa1="", stringa2="", stringa3="", stringa4="", stringa5=""): # Function to simplify the log # Automatically returns File Name and Function Name - + frame = inspect.stack()[1] filename = frame[0].f_code.co_filename - filename = os.path.basename(filename) - logger.info("[" + filename + "] - [" + inspect.stack()[1][3] + "] " + str(stringa1) + str(stringa2) + str(stringa3) + str(stringa4) + str(stringa5)) + filename = os.path.basename(filename) + logger.info("[" + filename + "] - [" + inspect.stack()[1][3] + "] " + str(stringa1) + ( ' ' + str(stringa2) if stringa2 else '') + ( ' ' + str(stringa3) if stringa3 else '') + ( ' ' + str(stringa4) if stringa4 else '') + ( ' ' + str(stringa5) if stringa5 else '') ) def channel_config(item, itemlist): @@ -652,3 +995,8 @@ def channel_config(item, itemlist): thumbnail=get_thumb('setting_0.png')) ) + +def extract_wrapped(decorated): + from types import FunctionType + closure = (c.cell_contents for c in decorated.__closure__) + return next((c for c in closure if isinstance(c, FunctionType)), None) diff --git a/core/tmdb.py b/core/tmdb.py index 59600cb3..60210b3e 100644 --- a/core/tmdb.py +++ b/core/tmdb.py @@ -370,13 +370,13 @@ def set_infoLabels_item(item, seekTmdb=True, idioma_busqueda=def_lang, lock=None if temporada: # Actualizar datos __leer_datos(otmdb_global) - item.infoLabels['title'] = temporada['name'] - if temporada['overview']: + item.infoLabels['title'] = temporada['name'] if temporada.has_key('name') else '' + if temporada.has_key('overview') and temporada['overview']: item.infoLabels['plot'] = temporada['overview'] - if temporada['air_date']: + if temporada.has_key('air_date') and temporada['air_date']: date = temporada['air_date'].split('-') item.infoLabels['aired'] = date[2] + "/" + date[1] + "/" + date[0] - if temporada['poster_path']: + if temporada.has_key('poster_path') and temporada['poster_path']: item.infoLabels['poster_path'] = 'http://image.tmdb.org/t/p/original' + temporada['poster_path'] item.thumbnail = item.infoLabels['poster_path'] diff --git a/core/videolibrarytools.py b/core/videolibrarytools.py index 381e1bd5..5a85aab1 100644 --- a/core/videolibrarytools.py +++ b/core/videolibrarytools.py @@ -6,6 +6,8 @@ import errno import math import traceback +import re +import os from core import filetools from core import scraper @@ -91,6 +93,9 @@ def save_movie(item): # 1. contentTitle: Este deberia ser el sitio correcto, ya que title suele contener "Añadir a la videoteca..." # 2. fulltitle # 3. title + # if item.contentTitle: item.title = item.contentTitle + # elif item.fulltitle: item.title = item.fulltitle + if not item.contentTitle: # Colocamos el titulo correcto en su sitio para que scraper lo localize if item.fulltitle: @@ -100,7 +105,7 @@ def save_movie(item): # Si llegados a este punto no tenemos titulo, salimos if not item.contentTitle or not item.channel: - logger.debug("NO ENCONTRADO contentTitle") + logger.debug("contentTitle NOT FOUND") return 0, 0, -1 # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) @@ -112,7 +117,7 @@ def save_movie(item): if not scraper_return or not item.infoLabels['code']: # TODO de momento si no hay resultado no añadimos nada, # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano - logger.debug("NO ENCONTRADO EN SCRAPER O NO TIENE code") + logger.debug("NOT FOUND IN SCRAPER OR DO NOT HAVE code") return 0, 0, -1 _id = item.infoLabels['code'][0] @@ -141,9 +146,9 @@ def save_movie(item): if not path: # Crear carpeta path = filetools.join(MOVIES_PATH, ("%s [%s]" % (base_name, _id)).strip()) - logger.info("Creando directorio pelicula:" + path) + logger.info("Creating movie directory:" + path) if not filetools.mkdir(path): - logger.debug("No se ha podido crear el directorio") + logger.debug("Could not create directory") return 0, 0, -1 nfo_path = filetools.join(path, "%s [%s].nfo" % (base_name, _id)) @@ -156,7 +161,7 @@ def save_movie(item): if not nfo_exists: # Creamos .nfo si no existe - logger.info("Creando .nfo: " + nfo_path) + logger.info("Creating .nfo: " + nfo_path) head_nfo = scraper.get_nfo(item) item_nfo = Item(title=item.contentTitle, channel="videolibrary", action='findvideos', @@ -179,7 +184,7 @@ def save_movie(item): if item_nfo and strm_exists: if json_exists: - logger.info("El fichero existe. Se sobreescribe") + logger.info("The file exists. Is overwritten") sobreescritos += 1 else: insertados += 1 @@ -195,14 +200,15 @@ def save_movie(item): item_nfo.emergency_urls = dict() item_nfo.emergency_urls.update({item.channel: True}) except: - logger.error("No se ha podido guardar las urls de emergencia de %s en la videoteca" % item.contentTitle) + logger.error("Unable to save %s emergency urls in the video library" % item.contentTitle) logger.error(traceback.format_exc()) - + if filetools.write(json_path, item.tojson()): - p_dialog.update(100, 'Añadiendo película...', item.contentTitle) + p_dialog.update(100, config.get_localized_string(60062), item.contentTitle) item_nfo.library_urls[item.channel] = item.url if filetools.write(nfo_path, head_nfo + item_nfo.tojson()): + #logger.info("FOLDER_MOVIES : %s" % FOLDER_MOVIES) # actualizamos la videoteca de Kodi con la pelicula if config.is_xbmc(): from platformcode import xbmc_videolibrary @@ -212,11 +218,145 @@ def save_movie(item): return insertados, sobreescritos, fallidos # Si llegamos a este punto es por q algo ha fallado - logger.error("No se ha podido guardar %s en la videoteca" % item.contentTitle) + logger.error("Could not save %s in the video library" % item.contentTitle) p_dialog.update(100, config.get_localized_string(60063), item.contentTitle) p_dialog.close() return 0, 0, -1 +def filter_list(episodelist, action=None, path=None): + if path: path = path.decode('utf8') + channel_prefs = {} + lang_sel = quality_sel = show_title = channel ='' + if action: + tvshow_path = filetools.join(path, "tvshow.nfo") + head_nfo, tvshow_item = read_nfo(tvshow_path) + channel = episodelist[0].channel + show_title = tvshow_item.infoLabels['tvshowtitle'] + if not tvshow_item.channel_prefs: + tvshow_item.channel_prefs={channel:{}} + list_item = os.listdir(path) + for File in list_item: + if (File.endswith('.strm') or File.endswith('.json') or File.endswith('.nfo')): + os.remove(os.path.join(path, File)) + if channel not in tvshow_item.channel_prefs: + tvshow_item.channel_prefs[channel] = {} + channel_prefs = tvshow_item.channel_prefs[channel] + + if action == 'get_seasons': + if 'favourite_language' not in channel_prefs: + channel_prefs['favourite_language'] = '' + if 'favourite_quality' not in channel_prefs: + channel_prefs['favourite_quality'] = '' + if channel_prefs['favourite_language']: + lang_sel = channel_prefs['favourite_language'] + if channel_prefs['favourite_quality']: + quality_sel = channel_prefs['favourite_quality'] + # if Download + if not show_title: show_title = episodelist[0].fulltitle + if not channel: channel= episodelist[0].channel + # SELECT EISODE BY LANG AND QUALITY + quality_dict = {'N/A': ['n/a'], + 'BLURAY': ['br', 'bluray'], + 'FULLHD': ['fullhd', 'fullhd 1080', 'fullhd 1080p', 'full hd', 'full hd 1080', 'full hd 1080p', 'hd1080', 'hd1080p', 'hd 1080', 'hd 1080p', '1080', '1080p'], + 'HD': ['hd', 'hd720', 'hd720p', 'hd 720', 'hd 720p', '720', '720p', 'hdtv'], + '480P': ['sd', '480p', '480'], + '360P': ['360p', '360'], + '240P': ['240p', '240'], + 'MAX':['MAX']} + quality_order = ['N/A', '240P', '360P','480P', 'HD', 'FULLHD', 'BLURAY', 'MAX'] + + + lang_list = [] + sub_list = [] + quality_list = ['MAX'] + + # Make Language List + for episode in episodelist: + if type(episode.contentLanguage) == list and episode.contentLanguage not in lang_list: + #lang_list = episode.contentLanguage + pass + else: + if episode.contentLanguage and episode.contentLanguage not in lang_list: + # Make list of subtitled languages + if 'sub' in episode.contentLanguage.lower(): + sub = re.sub('Sub-','', episode.contentLanguage) + if sub not in sub_list: sub_list.append(sub) + else: + lang_list.append(episode.contentLanguage) + # add to Language List subtitled languages + if sub_list: + for sub in sub_list: + if sub in lang_list: + lang_list.insert(lang_list.index(sub) + 1, 'Sub-' + sub) + lang_list.insert(lang_list.index(sub) + 2, sub + ' + Sub-' + sub) + else: + lang_list.append('Sub-' + sub) + + # Make Quality List + for episode in episodelist: + for name, var in quality_dict.items(): + if not episode.quality and 'N/A' not in quality_list: + quality_list.append('N/A') + if episode.quality.lower() in var and name not in quality_list: + quality_list.append(name) + quality_list = sorted(quality_list, key=lambda x:quality_order.index(x)) + + # if more than one language + if len(lang_list) > 1: + selection = lang_list.index(lang_sel) if lang_sel else platformtools.dialog_select(config.get_localized_string(70725) % (show_title, channel),lang_list) + if action: lang_sel = channel_prefs['favourite_language'] = lang_list[selection] + langs = lang_list[selection].split(' + ') + + ep_list = [] + count = 0 + stop = False + while not stop: + for episode in episodelist: + title = scrapertools.find_single_match(episode.title, '(\d+x\d+)') + if not any(title in word for word in ep_list) and episode.contentLanguage == langs[count]: + ep_list.append(episode.title) + if count < len(langs)-1: count += 1 + else: stop = True + it = [] + for episode in episodelist: + if episode.title in ep_list: + it.append(episode) + episodelist = it + + else: channel_prefs['favourite_language'] = '' + + # if more than one quality + if len(quality_list) > 2: + if config.get_setting('videolibrary_max_quality'): selection = favourite_quality_selection = len(quality_list)-1 + else: selection = favourite_quality_selection = quality_list.index(quality_sel) if quality_sel else platformtools.dialog_select(config.get_localized_string(70726) % (show_title, channel) ,quality_list) + + ep_list = [] + stop = False + while not stop: + for episode in episodelist: + title = scrapertools.find_single_match(episode.title, '(\d+x\d+)') + if not any(title in word for word in ep_list) and episode.quality.lower() in quality_dict[quality_list[selection]]: + ep_list.append(episode.title) + if selection != 0: selection = selection - 1 + else: stop = True + if quality_list[selection] == 'N/A': + for episode in episodelist: + title = scrapertools.find_single_match(episode.title, '(\d+x\d+)') + if not any(title in word for word in ep_list): + ep_list.append(episode.title) + + it = [] + for episode in episodelist: + if episode.title in ep_list: + if action: channel_prefs['favourite_quality'] = quality_list[favourite_quality_selection] + it.append(episode) + episodelist = it + + else:channel_prefs['favourite_quality'] = '' + + if action: filetools.write(tvshow_path, head_nfo + tvshow_item.tojson()) + + return episodelist def save_tvshow(item, episodelist): """ @@ -240,7 +380,7 @@ def save_tvshow(item, episodelist): # Si llegados a este punto no tenemos titulo o code, salimos if not (item.contentSerieName or item.infoLabels['code']) or not item.channel: - logger.debug("NO ENCONTRADO contentSerieName NI code") + logger.debug("NOT FOUND contentSerieName or code") return 0, 0, -1, path # Salimos sin guardar scraper_return = scraper.find_and_set_infoLabels(item) @@ -251,19 +391,19 @@ def save_tvshow(item, episodelist): if not scraper_return or not item.infoLabels['code']: # TODO de momento si no hay resultado no añadimos nada, # aunq podriamos abrir un cuadro para introducir el identificador/nombre a mano - logger.debug("NO ENCONTRADO EN SCRAPER O NO TIENE code") + logger.debug("NOT FOUND IN SCRAPER OR DO NOT HAVE code") return 0, 0, -1, path _id = item.infoLabels['code'][0] if config.get_setting("original_title_folder", "videolibrary") == 1 and item.infoLabels['originaltitle']: - base_name = item.infoLabels['originaltitle'] + base_name = item.infoLabels[u'originaltitle'] elif item.infoLabels['tvshowtitle']: - base_name = item.infoLabels['tvshowtitle'] + base_name = item.infoLabels[u'tvshowtitle'] elif item.infoLabels['title']: - base_name = item.infoLabels['title'] + base_name = item.infoLabels[u'title'] else: - base_name = item.contentSerieName + base_name = u'%s' % item.contentSerieName base_name = unicode(filetools.validate_path(base_name.replace('/', '-')), "utf8").encode("utf8") @@ -280,7 +420,7 @@ def save_tvshow(item, episodelist): if not path: path = filetools.join(TVSHOWS_PATH, ("%s [%s]" % (base_name, _id)).strip()) - logger.info("Creando directorio serie: " + path) + logger.info("Creating series directory: " + path) try: filetools.mkdir(path) except OSError, exception: @@ -290,7 +430,7 @@ def save_tvshow(item, episodelist): tvshow_path = filetools.join(path, "tvshow.nfo") if not filetools.exists(tvshow_path): # Creamos tvshow.nfo, si no existe, con la head_nfo, info de la serie y marcas de episodios vistos - logger.info("Creando tvshow.nfo: " + tvshow_path) + logger.info("Creating tvshow.nfo: " + tvshow_path) head_nfo = scraper.get_nfo(item) item.infoLabels['mediatype'] = "tvshow" item.infoLabels['title'] = item.contentSerieName @@ -364,10 +504,10 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): @return: el número de episodios fallidos """ logger.info() - + episodelist = filter_list(episodelist, serie.action, path) # No hay lista de episodios, no hay nada que guardar if not len(episodelist): - logger.info("No hay lista de episodios, salimos sin crear strm") + logger.info("There is no episode list, we go out without creating strm") return 0, 0, 0 insertados = 0 @@ -397,11 +537,12 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): channel_alt = generictools.verify_channel(serie.channel) #Preparamos para añadir las urls de emergencia emergency_urls_stat = config.get_setting("emergency_urls", channel_alt) #El canal quiere urls de emergencia? emergency_urls_succ = False - channel = __import__('channels.%s' % channel_alt, fromlist=["channels.%s" % channel_alt]) + try: channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt]) + except: channel = __import__('channels.%s' % channel_alt, fromlist=["channels.%s" % channel_alt]) if serie.torrent_caching_fail: #Si el proceso de conversión ha fallado, no se cachean emergency_urls_stat = 0 del serie.torrent_caching_fail - + new_episodelist = [] # Obtenemos el numero de temporada y episodio y descartamos los q no lo sean tags = [] @@ -410,10 +551,10 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): for e in episodelist: if tags != [] and tags != None and any(tag in e.title.lower() for tag in tags): continue - + try: season_episode = scrapertools.get_season_and_episode(e.title) - + # Si se ha marcado la opción de url de emergencia, se añade ésta a cada episodio después de haber ejecutado Findvideos del canal if e.emergency_urls and isinstance(e.emergency_urls, dict): del e.emergency_urls #Borramos trazas anteriores json_path = filetools.join(path, ("%s [%s].json" % (season_episode, e.channel)).lower()) #Path del .json del episodio @@ -440,20 +581,20 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): e = emergency_urls(e, channel, json_path) #generamos las urls if e.emergency_urls: #Si ya tenemos urls... emergency_urls_succ = True #... es un éxito y vamos a marcar el .nfo - + if not e.infoLabels["tmdb_id"] or (serie.infoLabels["tmdb_id"] and e.infoLabels["tmdb_id"] != serie.infoLabels["tmdb_id"]): #en series multicanal, prevalece el infolabels... e.infoLabels = serie.infoLabels #... del canal actual y no el del original e.contentSeason, e.contentEpisodeNumber = season_episode.split("x") new_episodelist.append(e) except: if e.contentType == 'episode': - logger.error("No se ha podido guardar las urls de emergencia de %s en la videoteca" % e.contentTitle) + logger.error("Unable to save %s emergency urls in the video library" % e.contentTitle) logger.error(traceback.format_exc()) continue # No hay lista de episodios, no hay nada que guardar if not len(new_episodelist): - logger.info("No hay lista de episodios, salimos sin crear strm") + logger.info("There is no episode list, we go out without creating strm") return 0, 0, 0 # fix float porque la division se hace mal en python 2.x @@ -490,7 +631,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): item_strm.library_filter_show = serie.library_filter_show if item_strm.library_filter_show == "": - logger.error("Se ha producido un error al obtener el nombre de la serie a filtrar") + logger.error("There was an error getting the name of the series to filter") # logger.debug("item_strm" + item_strm.tostring('\n')) # logger.debug("serie " + serie.tostring('\n')) @@ -521,7 +662,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): if filetools.write(json_path, e.tojson()): if not json_exists: - logger.info("Insertado: %s" % json_path) + logger.info("Inserted: %s" % json_path) insertados += 1 # Marcamos episodio como no visto news_in_playcounts[season_episode] = 0 @@ -532,14 +673,14 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): news_in_playcounts[serie.contentSerieName] = 0 else: - logger.info("Sobreescrito: %s" % json_path) + logger.info("Overwritten: %s" % json_path) sobreescritos += 1 else: - logger.info("Fallido: %s" % json_path) + logger.info("Failed: %s" % json_path) fallidos += 1 else: - logger.info("Fallido: %s" % json_path) + logger.info("Failed: %s" % json_path) fallidos += 1 if not silent and p_dialog.iscanceled(): @@ -555,7 +696,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): import datetime head_nfo, tvshow_item = read_nfo(tvshow_path) tvshow_item.library_playcounts.update(news_in_playcounts) - + #Si la operación de insertar/borrar urls de emergencia en los .jsons de los episodios ha tenido éxito, se marca el .nfo if emergency_urls_succ: if tvshow_item.emergency_urls and not isinstance(tvshow_item.emergency_urls, dict): @@ -567,7 +708,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): elif emergency_urls_stat == 2: #Operación de Borrar enlaces if tvshow_item.emergency_urls and tvshow_item.emergency_urls.get(serie.channel, False): tvshow_item.emergency_urls.pop(serie.channel, None) #borramos la entrada del .nfo - + if tvshow_item.active == 30: tvshow_item.active = 1 update_last = datetime.date.today() @@ -577,8 +718,8 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): filetools.write(tvshow_path, head_nfo + tvshow_item.tojson()) except: - logger.error("Error al actualizar tvshow.nfo") - logger.error("No se ha podido guardar las urls de emergencia de %s en la videoteca" % tvshow_item.contentSerieName) + logger.error("Error updating tvshow.nfo") + logger.error("Unable to save %s emergency urls in the video library" % tvshow_item.contentSerieName) logger.error(traceback.format_exc()) fallidos = -1 else: @@ -590,7 +731,7 @@ def save_episodes(path, episodelist, serie, silent=False, overwrite=True): if fallidos == len(episodelist): fallidos = -1 - logger.debug("%s [%s]: insertados= %s, sobreescritos= %s, fallidos= %s" % + logger.debug("%s [%s]: inserted= %s, overwritten= %s, failed= %s" % (serie.contentSerieName, serie.channel, insertados, sobreescritos, fallidos)) return insertados, sobreescritos, fallidos @@ -619,11 +760,11 @@ def add_movie(item): #Si lo hace en "Introducir otro nombre", TMDB buscará automáticamente el nuevo título #Si lo hace en "Completar Información", cambia parcialmente al nuevo título, pero no busca en TMDB. Hay que hacerlo #Si se cancela la segunda pantalla, la variable "scraper_return" estará en False. El usuario no quiere seguir - + item = generictools.update_title(item) #Llamamos al método que actualiza el título con tmdb.find_and_set_infoLabels #if item.tmdb_stat: # del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca - + new_item = item.clone(action="findvideos") insertados, sobreescritos, fallidos = save_movie(new_item) @@ -676,7 +817,8 @@ def add_tvshow(item, channel=None): if not channel: try: - channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel]) + #channel = __import__('channels.%s' % item.channel, fromlist=["channels.%s" % item.channel]) + channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt]) except ImportError: exec "import channels." + item.channel + " as channel" @@ -686,32 +828,33 @@ def add_tvshow(item, channel=None): #Si lo hace en "Introducir otro nombre", TMDB buscará automáticamente el nuevo título #Si lo hace en "Completar Información", cambia parcialmente al nuevo título, pero no busca en TMDB. Hay que hacerlo #Si se cancela la segunda pantalla, la variable "scraper_return" estará en False. El usuario no quiere seguir - + item = generictools.update_title(item) #Llamamos al método que actualiza el título con tmdb.find_and_set_infoLabels #if item.tmdb_stat: # del item.tmdb_stat #Limpiamos el status para que no se grabe en la Videoteca - + # Obtiene el listado de episodios + #if item.channel == 'community': itemlist = getattr(channel, item.action)(item) - + insertados, sobreescritos, fallidos, path = save_tvshow(item, itemlist) if not insertados and not sobreescritos and not fallidos: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60067)) - logger.error("La serie %s no se ha podido añadir a la videoteca. No se ha podido obtener ningun episodio" + logger.error("The %s series could not be added to the video library. Could not get any episode" % item.show) elif fallidos == -1: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60068)) - logger.error("La serie %s no se ha podido añadir a la videoteca" % item.show) + logger.error("The %s series could not be added to the video library" % item.show) elif fallidos > 0: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60069)) - logger.error("No se han podido añadir %s episodios de la serie %s a la videoteca" % (fallidos, item.show)) + logger.error("Could not add %s episodes of the %s series to the video library" % (fallidos, item.show)) else: platformtools.dialog_ok(config.get_localized_string(30131), config.get_localized_string(60070)) - logger.info("Se han añadido %s episodios de la serie %s a la videoteca" % + logger.info("%s episodes of the %s series have been added to the video library" % (insertados, item.show)) if config.is_xbmc(): if config.get_setting("sync_trakt_new_tvshow", "videolibrary"): @@ -730,7 +873,7 @@ def add_tvshow(item, channel=None): def emergency_urls(item, channel=None, path=None): logger.info() import re - """ + """ Llamamos a Findvideos del canal con la variable "item.videolibray_emergency_urls = True" para obtener la variable "item.emergency_urls" con la lista de listas de tuplas de los enlaces torrent y de servidores directos para ese episodio o película En la lista [0] siempre deben ir los enlaces torrents, si los hay. Si se desea cachear los .torrents, la búsqueda va contra esa lista. @@ -740,7 +883,8 @@ def emergency_urls(item, channel=None, path=None): try: if channel == None: #Si el llamador no ha aportado la estructura de channel, se crea channel = generictools.verify_channel(item.channel) #Se verifica si es un clon, que devuelva "newpct1" - channel = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) + #channel = __import__('channels.%s' % channel, fromlist=["channels.%s" % channel]) + channel = __import__('specials.%s' % channel_alt, fromlist=["specials.%s" % channel_alt]) if hasattr(channel, 'findvideos'): #Si el canal tiene "findvideos"... item.videolibray_emergency_urls = True #... se marca como "lookup" channel_save = item.channel #... guarda el canal original por si hay fail-over en Newpct1 @@ -749,12 +893,12 @@ def emergency_urls(item, channel=None, path=None): item_res.category = channel_save.capitalize() #... y la categoría del item_res.videolibray_emergency_urls #... y se borra la marca de lookup except: - logger.error('ERROR al procesar el título en Findvideos del Canal: ' + item.channel + ' / ' + item.title) + logger.error('ERROR when processing the title in Findvideos del Canal: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) item_res = item.clone() #Si ha habido un error, se devuelve el Item original if item_res.videolibray_emergency_urls: del item_res.videolibray_emergency_urls #... y se borra la marca de lookup - + #Si el usuario ha activado la opción "emergency_urls_torrents", se descargarán los archivos .torrent de cada título else: #Si se han cacheado con éxito los enlaces... try: @@ -765,7 +909,7 @@ def emergency_urls(item, channel=None, path=None): videolibrary_path = config.get_videolibrary_path() #detectamos el path absoluto del título movies = config.get_setting("folder_movies") series = config.get_setting("folder_tvshows") - if movies in path: + if movies in path: folder = movies else: folder = series @@ -779,7 +923,7 @@ def emergency_urls(item, channel=None, path=None): if path_real: #Si ha tenido éxito... item_res.emergency_urls[0][i-1] = path_real.replace(videolibrary_path, '') #se guarda el "path" relativo i += 1 - + #Restauramos variables originales if item.referer: item_res.referer = item.referer @@ -790,16 +934,16 @@ def emergency_urls(item, channel=None, path=None): elif item_res.referer: del item_res.referer item_res.url = item.url - + except: - logger.error('ERROR al cachear el .torrent de: ' + item.channel + ' / ' + item.title) + logger.error('ERROR when caching the .torrent of: ' + item.channel + ' / ' + item.title) logger.error(traceback.format_exc()) item_res = item.clone() #Si ha habido un error, se devuelve el Item original #logger.debug(item_res.emergency_urls) return item_res #Devolvemos el Item actualizado con los enlaces de emergencia - - + + def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=10, lookup=False, data_torrent=False): if torrents_path != None: logger.info("path = " + torrents_path) @@ -810,12 +954,12 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 from core import httptools torrent_file = '' headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Referer': referer} #Necesario para el Post del .Torrent - + """ Descarga en el path recibido el .torrent de la url recibida, y pasa el decode Devuelve el path real del .torrent, o el path vacío si la operación no ha tenido éxito """ - + videolibrary_path = config.get_videolibrary_path() #Calculamos el path absoluto a partir de la Videoteca if torrents_path == None: if not videolibrary_path: @@ -827,14 +971,14 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 if '.torrent' not in torrents_path: torrents_path += '.torrent' #path para dejar el .torrent torrents_path_encode = filetools.encode(torrents_path) #encode utf-8 del path - + if url.endswith(".rar") or url.startswith("magnet:"): #No es un archivo .torrent - logger.error('No es un archivo Torrent: ' + url) + logger.error('It is not a Torrent file: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío - + try: #Descargamos el .torrent if referer and post: #Descarga con POST @@ -842,7 +986,7 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 else: #Descarga sin post response = httptools.downloadpage(url, timeout=timeout) if not response.sucess: - logger.error('Archivo .torrent no encontrado: ' + url) + logger.error('.Torrent file not found: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) @@ -858,20 +1002,20 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío torrent_file = response.data - + #Si es un archivo .ZIP tratamos de extraer el contenido if torrent_file.startswith("PK"): - logger.info('Es un archivo .ZIP: ' + url) - + logger.info('It is a .ZIP file: ' + url) + torrents_path_zip = filetools.join(videolibrary_path, 'temp_torrents_zip') #Carpeta de trabajo torrents_path_zip = filetools.encode(torrents_path_zip) torrents_path_zip_file = filetools.join(torrents_path_zip, 'temp_torrents_zip.zip') #Nombre del .zip - + import time filetools.rmdirtree(torrents_path_zip) #Borramos la carpeta temporal time.sleep(1) #Hay que esperar, porque si no da error filetools.mkdir(torrents_path_zip) #La creamos de nuevo - + if filetools.write(torrents_path_zip_file, torrent_file): #Salvamos el .zip torrent_file = '' #Borramos el contenido en memoria try: #Extraemos el .zip @@ -882,7 +1026,7 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 import xbmc xbmc.executebuiltin('XBMC.Extract("%s", "%s")' % (torrents_path_zip_file, torrents_path_zip)) time.sleep(1) - + import os for root, folders, files in os.walk(torrents_path_zip): #Recorremos la carpeta para leer el .torrent for file in files: @@ -894,16 +1038,16 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 #Si no es un archivo .torrent (RAR, HTML,..., vacío) damos error if not scrapertools.find_single_match(torrent_file, '^d\d+:.*?\d+:'): - logger.error('No es un archivo Torrent: ' + url) + logger.error('It is not a Torrent file: ' + url) torrents_path = '' if data_torrent: return (torrents_path, torrent_file) return torrents_path #Si hay un error, devolvemos el "path" vacío - + #Salvamos el .torrent if not lookup: if not filetools.write(torrents_path_encode, torrent_file): - logger.error('ERROR: Archivo .torrent no escrito: ' + torrents_path_encode) + logger.error('ERROR: Unwritten .torrent file: ' + torrents_path_encode) torrents_path = '' #Si hay un error, devolvemos el "path" vacío torrent_file = '' #... y el buffer del .torrent if data_torrent: @@ -912,15 +1056,15 @@ def caching_torrents(url, referer=None, post=None, torrents_path=None, timeout=1 except: torrents_path = '' #Si hay un error, devolvemos el "path" vacío torrent_file = '' #... y el buffer del .torrent - logger.error('Error en el proceso de descarga del .torrent: ' + url + ' / ' + torrents_path_encode) + logger.error('ERROR: .Torrent download process failed: ' + url + ' / ' + torrents_path_encode) logger.error(traceback.format_exc()) - + #logger.debug(torrents_path) if data_torrent: return (torrents_path, torrent_file) return torrents_path - - + + def verify_url_torrent(url, timeout=5): """ Verifica si el archivo .torrent al que apunta la url está disponible, descargándolo en un area temporal diff --git a/default.py b/default.py index 26a058fd..f4508aab 100644 --- a/default.py +++ b/default.py @@ -10,6 +10,7 @@ import sys import xbmc from platformcode import config, logger + logger.info("init...") if os.path.isfile(os.path.join(config.get_data_path(), 'alfavorites-default.json')) == True and os.path.isfile(os.path.join(config.get_data_path(), 'kodfavorites-default.json')) == False: os.rename(os.path.join(config.get_data_path(), 'alfavorites-default.json'), os.path.join(config.get_data_path(), 'kodfavorites-default.json')) @@ -19,6 +20,7 @@ if os.path.isfile(os.path.join(config.get_data_path(), 'alfa_db.sqlite')) == Tru librerias = xbmc.translatePath(os.path.join(config.get_runtime_path(), 'lib')) sys.path.append(librerias) + from platformcode import launcher if sys.argv[2] == "": diff --git a/default_channel_settings.json b/default_channel_settings.json new file mode 100644 index 00000000..943a4b58 --- /dev/null +++ b/default_channel_settings.json @@ -0,0 +1,64 @@ +{ + "settings": [ + { + "id": "include_in_global_search", + "type": "bool", + "label": "@70728", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_peliculas", + "type": "bool", + "label": "@70727", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_series", + "type": "bool", + "label": "@70727", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "include_in_newest_anime", + "type": "bool", + "label": "@70727", + "default": true, + "enabled": true, + "visible": true + }, + { + "id": "checklinks", + "type": "bool", + "label": "Verifica se i link esistono", + "default": false, + "enabled": true, + "visible": true + }, + { + "id": "checklinks_number", + "type": "list", + "label": "Numero di link da verificare", + "default": 2, + "enabled": true, + "visible": "eq(-1,true)", + "lvalues": [ "3", "5", "10", "15", "20" ] + } + ], + + "renumber": [ + { + "id": "autorenumber", + "type": "bool", + "label": "@70712", + "default": false, + "enabled": true, + "visible": true + } + ] +} diff --git a/lib/megaserver/client.py b/lib/megaserver/client.py index 0afe49b8..239f5158 100644 --- a/lib/megaserver/client.py +++ b/lib/megaserver/client.py @@ -84,17 +84,31 @@ class Client(object): def get_files(self): files = [] + enc_url = None if self.files: for file in self.files: n = file.name.encode("utf8") u = "http://" + self.ip + ":" + str(self.port) + "/" + urllib.quote(n) s = file.size file_id = file.file_id + enc_url = file.url files.append({"name":n,"url":u,"size":s, "id": file_id}) + if len(self.files) == 1: + try: + code = httptools.downloadpage(enc_url, only_headers=True).code + if code > 300: + return code + else: + return files + + except: + print(traceback.format_exc()) + pass + return files def add_url(self, url): - url = url.split("/#")[1] + url = url.split("#")[1] id_video = None if "|" in url: url, id_video = url.split("|") @@ -135,7 +149,8 @@ class Client(object): def api_req(self, req, get=""): seqno = random.randint(0, 0xFFFFFFFF) url = 'https://g.api.mega.co.nz/cs?id=%d%s' % (seqno, get) - return json.loads(self.post(url, json.dumps([req])))[0] + page = httptools.downloadpage(url, post=json.dumps([req])).data + return json.loads(page)[0] def base64urldecode(self,data): data += '=='[(2 - len(data) * 3) % 4:] @@ -165,12 +180,11 @@ class Client(object): def aes_cbc_decrypt(self, data, key): try: + from Cryptodome.Cipher import AES + decryptor = AES.new(key, AES.MODE_CBC, '\0' * 16) + except: from Crypto.Cipher import AES decryptor = AES.new(key, AES.MODE_CBC, '\0' * 16) - #decryptor = aes.AESModeOfOperationCBC(key, iv='\0' * 16) - except: - import jscrypto - decryptor = jscrypto.new(key, jscrypto.MODE_CBC, '\0' * 16) return decryptor.decrypt(data) def aes_cbc_decrypt_a32(self,data, key): @@ -179,20 +193,6 @@ class Client(object): def decrypt_key(self,a, key): return sum((self.aes_cbc_decrypt_a32(a[i:i+4], key) for i in xrange(0, len(a), 4)), ()) - def post(self, url, data): - return httptools.downloadpage(url, data).data - import ssl - from functools import wraps - def sslwrap(func): - @wraps(func) - def bar(*args, **kw): - kw['ssl_version'] = ssl.PROTOCOL_TLSv1 - return func(*args, **kw) - return bar - - ssl.wrap_socket = sslwrap(ssl.wrap_socket) - return urllib.urlopen(url, data).read() - def dec_attr(self, attr, key): attr = self.aes_cbc_decrypt(attr, self.a32_to_str(key)).rstrip('\0') if not attr.endswith("}"): diff --git a/lib/megaserver/cursor.py b/lib/megaserver/cursor.py index ec01c2ba..37eeab2b 100644 --- a/lib/megaserver/cursor.py +++ b/lib/megaserver/cursor.py @@ -1,4 +1,5 @@ import urllib2 +import traceback class Cursor(object): def __init__(self, file): @@ -21,9 +22,11 @@ class Cursor(object): req.headers['Range'] = 'bytes=%s-' % (offset) try: self.conn = urllib2.urlopen(req) - self.prepare_decoder(offset) + try: + self.prepare_decoder(offset) + except: + print(traceback.format_exc()) except: - #La url del archivo expira transcurrido un tiempo, si da error 403, reintenta volviendo a solicitar la url mediante la API self.mega_request(offset, True) def read(self,n=None): @@ -35,7 +38,6 @@ class Cursor(object): self.pos+=len(res) return res - def seek(self,n): if n>self._file.size: n=self._file.size @@ -53,20 +55,21 @@ class Cursor(object): def __exit__(self,exc_type, exc_val, exc_tb): self._file.cursors.remove(self) if len(self._file.cursors) == 0: self._file.cursor = False - + def decode(self, data): return self.decryptor.decrypt(data) def prepare_decoder(self,offset): initial_value = self.initial_value + int(offset/16) try: + from Cryptodome.Cipher import AES + from Cryptodome.Util import Counter + self.decryptor = AES.new(self._file._client.a32_to_str(self.k), AES.MODE_CTR, counter = Counter.new(128, initial_value = initial_value)) + except: from Crypto.Cipher import AES from Crypto.Util import Counter self.decryptor = AES.new(self._file._client.a32_to_str(self.k), AES.MODE_CTR, counter = Counter.new(128, initial_value = initial_value)) - except: - from pyaes import aes - self.decryptor = aes.AESModeOfOperationCTR(f=self,key=self._client.a32_to_str(self.k),counter=aes.Counter(initial_value=initial_value)) rest = offset - int(offset/16)*16 if rest: - self.decode(str(0)*rest) \ No newline at end of file + self.decode(str(0)*rest) diff --git a/lib/unshortenit.py b/lib/unshortenit.py index 34bfa739..854ea15b 100644 --- a/lib/unshortenit.py +++ b/lib/unshortenit.py @@ -35,7 +35,7 @@ class UnshortenIt(object): _anonymz_regex = r'anonymz\.com' _shrink_service_regex = r'shrink-service\.it' _rapidcrypt_regex = r'rapidcrypt\.net' - _cryptmango_regex = r'cryptmango' + _cryptmango_regex = r'cryptmango|xshield\.net' _vcrypt_regex = r'vcrypt\.net' _maxretries = 5 @@ -467,6 +467,7 @@ class UnshortenIt(object): except Exception as e: return uri, str(e) + def _unshorten_vcrypt(self, uri): try: r = None @@ -492,22 +493,27 @@ class UnshortenIt(object): headers = { "Cookie": hashlib.md5(ip+day).hexdigest() + "=1" } - uri = uri.replace('sb/','sb1/') - uri = uri.replace('akv/','akv1/') - uri = uri.replace('wss/','wss1/') - uri = uri.replace('wsd/','wsd1/') + uri = uri.replace('sb/', 'sb1/') + uri = uri.replace('akv/', 'akv1/') + uri = uri.replace('wss/', 'wss1/') + uri = uri.replace('wsd/', 'wsd1/') r = httptools.downloadpage(uri, timeout=self._timeout, headers=headers, follow_redirects=False) - uri = r.headers['location'] + if 'Wait 1 hour' in r.data: + uri = '' + logger.info('IP bannato da vcrypt, aspetta un ora') + else: + uri = r.headers['location'] if "4snip" in uri: if 'out_generator' in uri: uri = re.findall('url=(.*)$', uri)[0] - else: - uri = decrypt(uri) + elif '/decode/' in uri: + uri = decrypt(uri.split('/')[-1]) return uri, r.code if r else 200 except Exception as e: return uri, str(e) + def unwrap_30x_only(uri, timeout=10): unshortener = UnshortenIt() diff --git a/lib/vvvvid_decoder.py b/lib/vvvvid_decoder.py new file mode 100644 index 00000000..dd49128a --- /dev/null +++ b/lib/vvvvid_decoder.py @@ -0,0 +1,63 @@ +import sys +import xbmc + +def dec_ei(h): + g = 'MNOPIJKL89+/4567UVWXQRSTEFGHABCDcdefYZabstuvopqr0123wxyzklmnghij' + c = list() + for e in range(0,len(h)): + c.append(g.find(h[e])) + for e in range(len(c)*2-1,-1,-1): + #print 'e=' + str(e) + a = c[e % len(c)] ^ c[(e+1)%len(c)] + #print 'a='+str(a) + c[e%len(c)] = a + #print 'c['+str(e % len(c))+']='+ str(c[e % len(c)]) + c = f(c) + d = '' + for e in range(0,len(c)): + d += '%'+ (('0'+ (str(format(c[e],'x'))))[-2:]) + + # if python 3 + if sys.version_info[0] > 2: + import urllib + return urllib.parse.unquote(d) + else: + import urllib2 + return urllib2.unquote(d) + +def f(m): + l = list() + o = 0 + b = None + while not b and o < len(m): + n = m[o] <<2 + o +=1 + k = -1 + j = -1 + if o < len(m): + n += m[o] >> 4 + o += 1 + if o < len(m): + k = (m[o - 1] << 4) & 255 + k += m[o] >> 2 + o += 1 + if o < len(m): + j = (m[o - 1] << 6) & 255 + j += m[o] + o += 1 + else: + b = True + else: + b = True + else: + b = True + + l.append(n) + + if k != -1: + l.append(k) + + if j != -1: + l.append(j) + + return l \ No newline at end of file diff --git a/platformcode/config.py b/platformcode/config.py index a4da4250..ba6813fc 100644 --- a/platformcode/config.py +++ b/platformcode/config.py @@ -20,15 +20,12 @@ def get_addon_core(): def get_addon_version(with_fix=True): ''' - Trova la versione dell'addon, senza usare le funzioni di kodi perchè non si aggiornano fino al riavvio + Devuelve el número de versión del addon, y opcionalmente número de fix si lo hay ''' - info = open(os.path.join(get_runtime_path(), 'addon.xml')).read() - ver = re.search('plugin.video.kod.*?version="([^"]+)"', info).group(1) - if with_fix: - return ver + " " + get_addon_version_fix() + return __settings__.getAddonInfo('version') + " " + get_addon_version_fix() else: - return ver + return __settings__.getAddonInfo('version') def get_addon_version_fix(): @@ -94,31 +91,15 @@ def get_videolibrary_support(): return True def get_channel_url(name): - def json(): - try: - try: - import json - except: - import simplejson as json - ROOT_DIR = xbmc.translatePath(__settings__.getAddonInfo('Path')) - LOCAL_FILE = os.path.join(ROOT_DIR, "channels.json") - with open(LOCAL_FILE) as f: - data = json.load(f) - if data[name] is not None: - return data[name] - else: - return get_setting("channel_host", name) - except: - return get_setting("channel_host", name) - - if __settings__.getSetting("use_custom_url") == "true": - host = get_setting("channel_host", name) - if host: - return host - else: - return json() - else: - return json() + try: + import json + except: + import simplejson as json + ROOT_DIR = xbmc.translatePath(__settings__.getAddonInfo('Path')) + LOCAL_FILE = os.path.join(ROOT_DIR, "channels.json") + with open(LOCAL_FILE) as f: + data = json.load(f) + return data[name] def get_system_platform(): """ fonction: pour recuperer la platform que xbmc tourne """ @@ -366,7 +347,7 @@ def get_localized_string(code): def get_localized_category(categ): categories = {'movie': get_localized_string(30122), 'tvshow': get_localized_string(30123), 'anime': get_localized_string(30124), 'documentary': get_localized_string(30125), - 'vos': get_localized_string(30136), 'vosi': get_localized_string(70566), 'adult': get_localized_string(30126), + 'vos': get_localized_string(30136), 'sub-ita': get_localized_string(70566), 'adult': get_localized_string(30126), 'direct': get_localized_string(30137), 'torrent': get_localized_string(70015)} return categories[categ] if categ in categories else categ diff --git a/platformcode/launcher.py b/platformcode/launcher.py index a5d47125..fdd09864 100644 --- a/platformcode/launcher.py +++ b/platformcode/launcher.py @@ -37,6 +37,8 @@ def start(): from specials.checkhost import test_conn import threading threading.Thread(target=test_conn, args=(True, True, True, [], [], True)).start() + # check_adsl = test_conn(is_exit = True, check_dns = True, view_msg = True, + # lst_urls = [], lst_site_check_dns = [], in_addon = True) def run(item=None): @@ -58,10 +60,12 @@ def run(item=None): config.get_localized_string(70018): 'infantiles', config.get_localized_string(60513): 'documentales', config.get_localized_string(70013): 'terror', - config.get_localized_string(30124): 'castellano', + config.get_localized_string(70014): 'castellano', config.get_localized_string(59976): 'latino', config.get_localized_string(70171): 'torrent', } + if not config.get_setting("category") in dictCategory.keys(): + config.set_setting('category', config.get_localized_string(70137)) category = dictCategory[config.get_setting("category")] item = Item(channel="news", action="novedades", extra=category, mode = 'silent') else: @@ -129,7 +133,9 @@ def run(item=None): from core import tmdb if tmdb.drop_bd(): platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60011), time=2000, sound=False) - + elif item.action == "itemInfo": + import base64 + platformtools.dialog_textviewer('Item info', item.parent) # Action in certain channel specified in "action" and "channel" parameters else: # Entry point for a channel is the "mainlist" action, so here we check parental control @@ -151,11 +157,17 @@ def run(item=None): # Checks if channel exists if os.path.isfile(os.path.join(config.get_runtime_path(), 'channels', item.channel + ".py")): CHANNELS = 'channels' + elif os.path.isfile(os.path.join(config.get_runtime_path(), 'channels', 'porn', item.channel + ".py")): + CHANNELS = 'channels.porn' else: CHANNELS ='specials' - channel_file = os.path.join(config.get_runtime_path(), CHANNELS, item.channel + ".py") - - logger.info("channel_file= " + channel_file) + + if CHANNELS != 'channels.porn': + channel_file = os.path.join(config.get_runtime_path(), CHANNELS, item.channel + ".py") + else: + channel_file = os.path.join(config.get_runtime_path(), 'channels', 'porn', item.channel + ".py") + + logger.info("channel_file= " + channel_file + ' - ' + CHANNELS +' - ' + item.channel) channel = None @@ -163,7 +175,8 @@ def run(item=None): try: channel = __import__(CHANNELS + item.channel, None, None, [CHANNELS + item.channel]) except ImportError: - importer = "import " + CHANNELS + "." + item.channel + " as channel" + importer = "import " + CHANNELS + "." + item.channel + " as channel " + exec(importer) logger.info("Running channel %s | %s" % (channel.__name__, channel.__file__)) @@ -260,13 +273,17 @@ def run(item=None): from specials import search search.save_search(tecleado) - itemlist = channel.search(item, tecleado) + if 'search' in dir(channel): + itemlist = channel.search(item, tecleado) + else: + from core import support + itemlist = support.search(channel, item, tecleado) else: return platformtools.render_items(itemlist, item) - # For all other actions + # For all other actions else: # import web_pdb; web_pdb.set_trace() logger.info("Executing channel '%s' method" % item.action) @@ -420,7 +437,7 @@ def play_from_library(item): import xbmcplugin import xbmc from time import sleep - + # Intentamos reproducir una imagen (esto no hace nada y ademas no da error) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, xbmcgui.ListItem( @@ -498,6 +515,7 @@ def play_from_library(item): return else: item = videolibrary.play(itemlist[seleccion])[0] + item.play_from = 'window' platformtools.play_video(item) from specials import autoplay diff --git a/platformcode/platformtools.py b/platformcode/platformtools.py index cb927cbe..282d7029 100644 --- a/platformcode/platformtools.py +++ b/platformcode/platformtools.py @@ -22,7 +22,7 @@ from channelselector import get_thumb from core import channeltools from core import trakt_tools, scrapertoolsV2 from core.item import Item -from platformcode import logger +from platformcode import logger, keymaptools from platformcode import unify addon = xbmcaddon.Addon('plugin.video.kod') @@ -549,7 +549,7 @@ def set_context_commands(item, parent_item): from_action=item.action).tourl()))) # Añadir a Alfavoritos (Mis enlaces) if item.channel not in ["favorites", "videolibrary", "help", ""] and parent_item.channel != "favorites": - context_commands.append(('[COLOR blue]%s[/COLOR]' % config.get_localized_string(70557), "XBMC.RunPlugin(%s?%s)" % + context_commands.append(("[B]%s[/B]" % config.get_localized_string(70557), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone(channel="kodfavorites", action="addFavourite", from_channel=item.channel, from_action=item.action).tourl()))) @@ -571,7 +571,7 @@ def set_context_commands(item, parent_item): mediatype = 'tv' else: mediatype = item.contentType - context_commands.append(("[COLOR yellow]%s[/COLOR]" % config.get_localized_string(70561), "XBMC.Container.Update (%s?%s)" % ( + context_commands.append(("[B]%s[/B]" % config.get_localized_string(70561), "XBMC.Container.Update (%s?%s)" % ( sys.argv[0], item.clone(channel='search', action='discover_list', search_type='list', page='1', list_type='%s/%s/similar' % (mediatype,item.infoLabels['tmdb_id'])).tourl()))) @@ -584,9 +584,10 @@ def set_context_commands(item, parent_item): action="set_custom_start", parent=item.tourl()).tourl()))) - if item.channel != "videolibrary": + if (item.channel != "videolibrary" and not config.get_localized_string(70585) in str(item.context)) \ + or (item.channel != "videolibrary" and config.get_localized_string(70585) in str(item.context) and config.get_localized_string(70714) in str(item.context)): # Añadir Serie a la videoteca - if item.action in ["episodios", "get_episodios"] and item.contentSerieName: + if item.action in ["episodios", "get_episodios", "get_seasons"] and item.contentSerieName: context_commands.append((config.get_localized_string(60352), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone(action="add_serie_to_library", from_action=item.action).tourl()))) @@ -596,7 +597,8 @@ def set_context_commands(item, parent_item): (sys.argv[0], item.clone(action="add_pelicula_to_library", from_action=item.action).tourl()))) - if item.channel != "downloads" and downloadenabled != "false": + if (item.channel != "downloads" and item.channel != "videolibrary" and downloadenabled != "false" and not config.get_localized_string(70585) in str(item.context))\ + or (item.channel != "downloads" and item.channel != "videolibrary" and downloadenabled != "false" and config.get_localized_string(70585) in str(item.context) and config.get_localized_string(70714) in str(item.context)): # Descargar pelicula if item.contentType == "movie": context_commands.append((config.get_localized_string(60354), "XBMC.RunPlugin(%s?%s)" % @@ -606,12 +608,18 @@ def set_context_commands(item, parent_item): # elif item.contentSerieName: # Descargar serie - elif item.contentType == "tvshow" and item.action in ["episodios"]: + elif (item.contentType == "tvshow" and item.action in ["episodios"]) or \ + (item.contentType == "tvshow" and item.action in ['get_seasons'] and config.get_setting('show_seasons',item.channel) == False): item.contentType == "tvshow" context_commands.append((config.get_localized_string(60355), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone(channel="downloads", action="save_download", from_channel=item.channel, from_action=item.action).tourl()))) + context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s)" % + (sys.argv[0], item.clone(channel="downloads", action="save_download", + from_channel=item.channel, + from_action=item.action, + download='season').tourl()))) # Descargar episodio elif item.contentType == 'episode' and item.action in ["findvideos"]: @@ -626,7 +634,8 @@ def set_context_commands(item, parent_item): context_commands.append((config.get_localized_string(60357), "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], item.clone(channel="downloads", action="save_download", from_channel=item.channel, - from_action=item.action).tourl()))) + from_action=item.action, + download='season').tourl()))) # Abrir configuración if parent_item.channel not in ["setting", "news", "search"]: @@ -648,10 +657,19 @@ def set_context_commands(item, parent_item): context_commands = sorted(context_commands, key=lambda comand: comand[0]) # Menu Rapido context_commands.insert(0, (config.get_localized_string(60360), + "XBMC.RunPlugin(%s?%s)" % (sys.argv[0], Item(channel='side_menu', + action="open_shortcut_menu", + parent=parent_item.tourl()).tourl( + )))) + context_commands.insert(1, (config.get_localized_string(70737), "XBMC.Container.Update (%s?%s)" % (sys.argv[0], Item(channel='side_menu', action="open_menu", parent=parent_item.tourl()).tourl( )))) + if config.dev_mode(): + context_commands.insert(2, ("item info", + "XBMC.Container.Update (%s?%s)" % (sys.argv[0], Item(action="itemInfo", + parent=item.tojson()).tourl()))) return context_commands @@ -661,6 +679,8 @@ def is_playing(): def play_video(item, strm=False, force_direct=False, autoplay=False): logger.info() + if item.play_from == 'window': + force_direct=True # logger.debug(item.tostring('\n')) logger.debug('item play: %s'%item) xbmc_player = XBMCPlayer() @@ -673,7 +693,8 @@ def play_video(item, strm=False, force_direct=False, autoplay=False): xlistitem.setThumbnailImage(item.thumbnail) set_infolabels(xlistitem, item, True) - xbmc_player.play(item.url, xlistitem) + set_player(item, xlistitem, item.url, True, None) # Fix Play From Download Section + # xbmc_player.play(item.url, xlistitem) return default_action = config.get_setting("default_action") @@ -903,10 +924,10 @@ def get_dialogo_opciones(item, default_action, strm, autoplay): # "Descargar" import xbmcaddon addon = xbmcaddon.Addon('plugin.video.kod') - downloadenabled = addon.getSetting('downloadenabled') - if downloadenabled != "false": - opcion = config.get_localized_string(30153) - opciones.append(opcion) + # downloadenabled = addon.getSetting('downloadenabled') + # if downloadenabled != "false": + # opcion = config.get_localized_string(30153) + # opciones.append(opcion) if item.isFavourite: # "Quitar de favoritos" @@ -1069,7 +1090,7 @@ def set_player(item, xlistitem, mediaurl, view, strm): logger.info("mediaurl=" + mediaurl) if config.get_setting("player_mode") == 3 or "megacrypter.com" in mediaurl: import download_and_play - download_and_play.download_and_play(mediaurl, "download_and_play.tmp", config.get_setting("downloadpath")) + download_and_play.download_and_play(mediaurl, "download_and_play.mp4", config.get_setting("downloadpath")) return elif config.get_setting("player_mode") == 0 or \ diff --git a/platformcode/unify.py b/platformcode/unify.py index b93c1e84..0c8c41af 100644 --- a/platformcode/unify.py +++ b/platformcode/unify.py @@ -253,9 +253,9 @@ def set_lang(language): lat=['latino','lat','la', 'espanol latino', 'espaol latino', 'zl', 'mx', 'co', 'vl'] vose=['subtitulado','subtitulada','sub','sub espanol','vose','espsub','su','subs castellano', 'sub: español', 'vs', 'zs', 'vs', 'english-spanish subs', 'ingles sub espanol'] - vosi=['sottotitolato','sottotitolata','sub','sub ita','vosi','sub-ita','subs italiano', + sub_ita=['sottotitolato','sottotitolata','sub','sub ita','subs italiano', 'sub: italiano', 'inglese sottotitolato'] - vos=['vos', 'sub ingles', 'engsub', 'vosi','ingles subtitulado', 'sub: ingles'] + vos=['vos', 'sub ingles', 'engsub','ingles subtitulado', 'sub: ingles'] vo=['ingles', 'en','vo', 'ovos', 'eng','v.o', 'english'] dual=['dual'] @@ -271,7 +271,9 @@ def set_lang(language): elif language in lat: language = 'lat' elif language in ita: - language = 'ita' + language = 'ita' + elif language in sub_ita: + language = 'sub-ita' elif language in vose: language = 'vose' elif language in vos: @@ -280,8 +282,6 @@ def set_lang(language): language = 'vo' elif language in dual: language = 'dual' - elif language in dual: - language = 'vosi' else: language = 'otro' diff --git a/platformcode/updater.py b/platformcode/updater.py old mode 100755 new mode 100644 diff --git a/resources/language/English/strings.po b/resources/language/English/strings.po index 33f7ce68..9ec7c01e 100644 --- a/resources/language/English/strings.po +++ b/resources/language/English/strings.po @@ -21,6 +21,10 @@ msgctxt "#20000" msgid "KOD" msgstr "" +msgctxt "#20001" +msgid "eng" +msgstr "" + msgctxt "#30001" msgid "Check for updates:" msgstr "" @@ -1807,7 +1811,7 @@ msgid "Delete" msgstr "" msgctxt "#60438" -msgid "¿Enable / disable filter?" +msgid "Enable / Disable filter?" msgstr "" msgctxt "#60439" @@ -5618,11 +5622,11 @@ msgid "Channel" msgstr "" msgctxt "#70725" -msgid "Select the language" +msgid "Select the language of [B]%s[/B] in [B]%s[/B]" msgstr "" msgctxt "#70726" -msgid "Seleziona la qualità" +msgid "Select the preferred quality of [B]%s[/B] in [B]%s[/B]" msgstr "" msgctxt "#70727" @@ -5632,3 +5636,35 @@ msgstr "" msgctxt "#70728" msgid "Include in Global Search" msgstr "" + +msgctxt "#70729" +msgid "Always add the highest quality" +msgstr "" + +msgctxt "#70730" +msgid "Select the renumbering method" +msgstr "" + +msgctxt "#70731" +msgid "Semi-Automatic" +msgstr "" + +msgctxt "#70732" +msgid "Manual" +msgstr "" + +msgctxt "#70733" +msgid "Enter the Season Number" +msgstr "" + +msgctxt "#70734" +msgid "Select Season Episodes" +msgstr "" + +msgctxt "#70735" +msgid "%s Special Episode Number" +msgstr "" + +msgctxt "#70737" +msgid "[B]SIDE MENU[/B]" +msgstr "" \ No newline at end of file diff --git a/resources/language/Italian/strings.po b/resources/language/Italian/strings.po index 2ad48d12..65efc50a 100644 --- a/resources/language/Italian/strings.po +++ b/resources/language/Italian/strings.po @@ -21,6 +21,10 @@ msgctxt "#20000" msgid "KOD" msgstr "KOD" +msgctxt "#20001" +msgid "eng" +msgstr "ita" + msgctxt "#30001" msgid "Check for updates:" msgstr "Verifica aggiornamenti:" @@ -1806,12 +1810,12 @@ msgid "Delete" msgstr "Eliminare" msgctxt "#60438" -msgid "¿Enable / disable filter?" +msgid "Enable / Disable filter?" msgstr "Attiva / Disattiva filtro?" msgctxt "#60439" msgid "Language" -msgstr "Linguaggio" +msgstr "Lingua" msgctxt "#60440" msgid "Permitted quality" @@ -1819,7 +1823,7 @@ msgstr "Qualità consentita" msgctxt "#60441" msgid "Filter links for: [COLOR %s]%s[/COLOR]" -msgstr "Link di filtro per: [COLOR %s]%s[/COLOR]" +msgstr "Filtro link per: [COLOR %s]%s[/COLOR]" msgctxt "#60442" msgid "Are you sure you want to delete the filter?" @@ -3291,7 +3295,7 @@ msgstr "Serie" msgctxt "#70137" msgid "Movies" -msgstr "Films" +msgstr "Film" msgctxt "#70138" msgid "Low Rating" @@ -5618,12 +5622,12 @@ msgid "Channel" msgstr "Canale" msgctxt "#70725" -msgid "Select the language" -msgstr "Seleziona la lingua" +msgid "Select the language of [B]%s[/B] in [B]%s[/B]" +msgstr "Seleziona la lingua di [B]%s[/B] su [B]%s[/B]" msgctxt "#70726" -msgid "Seleziona la qualità" -msgstr "Select the quality" +msgid "Select the preferred quality of [B]%s[/B] in [B]%s[/B]" +msgstr "Seleziona la qualità preferita di [B]%s[/B] su [B]%s[/B]" msgctxt "#70727" msgid "Include in News" @@ -5632,3 +5636,39 @@ msgstr "Includi in Novità" msgctxt "#70728" msgid "Include in Global Search" msgstr "Includi in Ricerca Globale" + +msgctxt "#70729" +msgid "Always add the highest quality" +msgstr "Aggiungi sempre la qualità più alta" + +msgctxt "#70730" +msgid "Select the renumbering method" +msgstr "Seleziona il metodo di rinumerazione" + +msgctxt "#70731" +msgid "Semi-Automatic" +msgstr "Semi-Automatico" + +msgctxt "#70732" +msgid "Manual" +msgstr "Manuale" + +msgctxt "#70733" +msgid "Enter the Season Number" +msgstr "Digita il numero della Stagione" + +msgctxt "#70734" +msgid "Select Season Episodes" +msgstr "Seleziona gli Episodi della Stagione" + +msgctxt "#70735" +msgid "%s Special Episode Number" +msgstr "Numero dell'Episodio Speciale %s" + +msgctxt "#70736" +msgid "Completed Serie" +msgstr "Serie Completa" + +msgctxt "#70737" +msgid "[B]SIDE MENU[/B]" +msgstr "[B]MENU LATERALE[/B]" \ No newline at end of file diff --git a/resources/media/channels/banner/animepertutti.png b/resources/media/channels/banner/animepertutti.png deleted file mode 100644 index 85725705..00000000 Binary files a/resources/media/channels/banner/animepertutti.png and /dev/null differ diff --git a/resources/media/channels/banner/animesaturn.png b/resources/media/channels/banner/animesaturn.png deleted file mode 100644 index 4b3018b2..00000000 Binary files a/resources/media/channels/banner/animesaturn.png and /dev/null differ diff --git a/resources/media/channels/banner/animeworld.png b/resources/media/channels/banner/animeworld.png deleted file mode 100644 index 7f727b4f..00000000 Binary files a/resources/media/channels/banner/animeworld.png and /dev/null differ diff --git a/resources/media/channels/banner/canalporno.png b/resources/media/channels/banner/canalporno.png deleted file mode 100644 index ccc56c91..00000000 Binary files a/resources/media/channels/banner/canalporno.png and /dev/null differ diff --git a/resources/media/channels/banner/cb01.png b/resources/media/channels/banner/cb01.png deleted file mode 100644 index 6acba322..00000000 Binary files a/resources/media/channels/banner/cb01.png and /dev/null differ diff --git a/resources/media/channels/banner/cinetemagay.png b/resources/media/channels/banner/cinetemagay.png deleted file mode 100644 index 3ac1a9f5..00000000 Binary files a/resources/media/channels/banner/cinetemagay.png and /dev/null differ diff --git a/resources/media/channels/banner/cumlouder.png b/resources/media/channels/banner/cumlouder.png deleted file mode 100644 index cd2805e1..00000000 Binary files a/resources/media/channels/banner/cumlouder.png and /dev/null differ diff --git a/resources/media/channels/banner/datoporn.png b/resources/media/channels/banner/datoporn.png deleted file mode 100644 index 1d3100f7..00000000 Binary files a/resources/media/channels/banner/datoporn.png and /dev/null differ diff --git a/resources/media/channels/banner/dreamsub.png b/resources/media/channels/banner/dreamsub.png deleted file mode 100644 index 23f021c5..00000000 Binary files a/resources/media/channels/banner/dreamsub.png and /dev/null differ diff --git a/resources/media/channels/banner/eporner.png b/resources/media/channels/banner/eporner.png deleted file mode 100644 index 55e44183..00000000 Binary files a/resources/media/channels/banner/eporner.png and /dev/null differ diff --git a/resources/media/channels/banner/fastsubita.png b/resources/media/channels/banner/fastsubita.png deleted file mode 100644 index 2d226718..00000000 Binary files a/resources/media/channels/banner/fastsubita.png and /dev/null differ diff --git a/resources/media/channels/banner/guardaserieclick.png b/resources/media/channels/banner/guardaserieclick.png deleted file mode 100644 index 027c3c32..00000000 Binary files a/resources/media/channels/banner/guardaserieclick.png and /dev/null differ diff --git a/resources/media/channels/banner/pelisxporno.png b/resources/media/channels/banner/pelisxporno.png deleted file mode 100644 index 1436a2f9..00000000 Binary files a/resources/media/channels/banner/pelisxporno.png and /dev/null differ diff --git a/resources/media/channels/banner/pornhub.png b/resources/media/channels/banner/pornhub.png deleted file mode 100644 index bc8d7cb8..00000000 Binary files a/resources/media/channels/banner/pornhub.png and /dev/null differ diff --git a/resources/media/channels/banner/seriehd.png b/resources/media/channels/banner/seriehd.png deleted file mode 100644 index 027c0a15..00000000 Binary files a/resources/media/channels/banner/seriehd.png and /dev/null differ diff --git a/resources/media/channels/banner/serietvsubita.png b/resources/media/channels/banner/serietvsubita.png deleted file mode 100644 index 62f21d1c..00000000 Binary files a/resources/media/channels/banner/serietvsubita.png and /dev/null differ diff --git a/resources/media/channels/banner/serietvu.png b/resources/media/channels/banner/serietvu.png deleted file mode 100644 index 9e1c0929..00000000 Binary files a/resources/media/channels/banner/serietvu.png and /dev/null differ diff --git a/resources/media/channels/banner/serviporno.png b/resources/media/channels/banner/serviporno.png deleted file mode 100644 index dc401ada..00000000 Binary files a/resources/media/channels/banner/serviporno.png and /dev/null differ diff --git a/resources/media/channels/banner/submityouflicks.png b/resources/media/channels/banner/submityouflicks.png deleted file mode 100644 index 590cc6c2..00000000 Binary files a/resources/media/channels/banner/submityouflicks.png and /dev/null differ diff --git a/resources/media/channels/banner/tubehentai.png b/resources/media/channels/banner/tubehentai.png deleted file mode 100644 index 0a12cc29..00000000 Binary files a/resources/media/channels/banner/tubehentai.png and /dev/null differ diff --git a/resources/media/channels/banner/xhamster.png b/resources/media/channels/banner/xhamster.png deleted file mode 100644 index e9b137f7..00000000 Binary files a/resources/media/channels/banner/xhamster.png and /dev/null differ diff --git a/resources/media/channels/banner/yespornplease.png b/resources/media/channels/banner/yespornplease.png deleted file mode 100644 index 07084bd7..00000000 Binary files a/resources/media/channels/banner/yespornplease.png and /dev/null differ diff --git a/resources/media/channels/thumb/animepertutti.png b/resources/media/channels/thumb/animepertutti.png deleted file mode 100644 index 7e53be26..00000000 Binary files a/resources/media/channels/thumb/animepertutti.png and /dev/null differ diff --git a/resources/media/channels/thumb/animesaturn.png b/resources/media/channels/thumb/animesaturn.png deleted file mode 100644 index 06698c62..00000000 Binary files a/resources/media/channels/thumb/animesaturn.png and /dev/null differ diff --git a/resources/media/channels/thumb/animeworld.png b/resources/media/channels/thumb/animeworld.png deleted file mode 100644 index d0b57098..00000000 Binary files a/resources/media/channels/thumb/animeworld.png and /dev/null differ diff --git a/resources/media/channels/thumb/cb01.png b/resources/media/channels/thumb/cb01.png deleted file mode 100644 index 6acba322..00000000 Binary files a/resources/media/channels/thumb/cb01.png and /dev/null differ diff --git a/resources/media/channels/thumb/cinetemagay.png b/resources/media/channels/thumb/cinetemagay.png deleted file mode 100644 index 584dd8bd..00000000 Binary files a/resources/media/channels/thumb/cinetemagay.png and /dev/null differ diff --git a/resources/media/channels/thumb/cumlouder.png b/resources/media/channels/thumb/cumlouder.png deleted file mode 100644 index fa685d5e..00000000 Binary files a/resources/media/channels/thumb/cumlouder.png and /dev/null differ diff --git a/resources/media/channels/thumb/documentaristreamingda.png b/resources/media/channels/thumb/documentaristreamingda.png deleted file mode 100644 index c9342c90..00000000 Binary files a/resources/media/channels/thumb/documentaristreamingda.png and /dev/null differ diff --git a/resources/media/channels/thumb/dreamsub.png b/resources/media/channels/thumb/dreamsub.png deleted file mode 100644 index 52079bbd..00000000 Binary files a/resources/media/channels/thumb/dreamsub.png and /dev/null differ diff --git a/resources/media/channels/thumb/eporner.png b/resources/media/channels/thumb/eporner.png deleted file mode 100644 index d63d7748..00000000 Binary files a/resources/media/channels/thumb/eporner.png and /dev/null differ diff --git a/resources/media/channels/thumb/fastsubita.png b/resources/media/channels/thumb/fastsubita.png deleted file mode 100644 index d1d7be10..00000000 Binary files a/resources/media/channels/thumb/fastsubita.png and /dev/null differ diff --git a/resources/media/channels/thumb/filmigratis.png b/resources/media/channels/thumb/filmigratis.png deleted file mode 100644 index d623d0b6..00000000 Binary files a/resources/media/channels/thumb/filmigratis.png and /dev/null differ diff --git a/resources/media/channels/thumb/guardaserieclick.png b/resources/media/channels/thumb/guardaserieclick.png deleted file mode 100644 index 58ae6dca..00000000 Binary files a/resources/media/channels/thumb/guardaserieclick.png and /dev/null differ diff --git a/resources/media/channels/thumb/mondolunatico2.png b/resources/media/channels/thumb/mondolunatico2.png deleted file mode 100644 index 02040801..00000000 Binary files a/resources/media/channels/thumb/mondolunatico2.png and /dev/null differ diff --git a/resources/media/channels/thumb/seriehd.png b/resources/media/channels/thumb/seriehd.png deleted file mode 100644 index e310b89f..00000000 Binary files a/resources/media/channels/thumb/seriehd.png and /dev/null differ diff --git a/resources/media/channels/thumb/serietvsubita.png b/resources/media/channels/thumb/serietvsubita.png deleted file mode 100644 index 38709e2a..00000000 Binary files a/resources/media/channels/thumb/serietvsubita.png and /dev/null differ diff --git a/resources/media/channels/thumb/serietvu.png b/resources/media/channels/thumb/serietvu.png deleted file mode 100644 index 3835135f..00000000 Binary files a/resources/media/channels/thumb/serietvu.png and /dev/null differ diff --git a/resources/media/channels/thumb/serviporno.png b/resources/media/channels/thumb/serviporno.png deleted file mode 100644 index a9b2eec6..00000000 Binary files a/resources/media/channels/thumb/serviporno.png and /dev/null differ diff --git a/resources/media/channels/thumb/submityouflicks.png b/resources/media/channels/thumb/submityouflicks.png deleted file mode 100644 index ae42cce2..00000000 Binary files a/resources/media/channels/thumb/submityouflicks.png and /dev/null differ diff --git a/resources/media/channels/thumb/thumb_intervenido_gc.png b/resources/media/channels/thumb/thumb_intervenido_gc.png deleted file mode 100644 index eb0dcf4f..00000000 Binary files a/resources/media/channels/thumb/thumb_intervenido_gc.png and /dev/null differ diff --git a/resources/media/channels/thumb/thumb_intervenido_pn.jpeg b/resources/media/channels/thumb/thumb_intervenido_pn.jpeg deleted file mode 100644 index f9a87e4a..00000000 Binary files a/resources/media/channels/thumb/thumb_intervenido_pn.jpeg and /dev/null differ diff --git a/resources/media/channels/thumb/thumb_intervenido_sucuri.png b/resources/media/channels/thumb/thumb_intervenido_sucuri.png deleted file mode 100644 index 7c7f08ee..00000000 Binary files a/resources/media/channels/thumb/thumb_intervenido_sucuri.png and /dev/null differ diff --git a/resources/media/channels/thumb/toonitalia.png b/resources/media/channels/thumb/toonitalia.png deleted file mode 100644 index 15c31ab6..00000000 Binary files a/resources/media/channels/thumb/toonitalia.png and /dev/null differ diff --git a/resources/media/channels/thumb/tubehentai.png b/resources/media/channels/thumb/tubehentai.png deleted file mode 100644 index 3b186812..00000000 Binary files a/resources/media/channels/thumb/tubehentai.png and /dev/null differ diff --git a/resources/media/channels/thumb/tupornotv.png b/resources/media/channels/thumb/tupornotv.png deleted file mode 100644 index 49a77d3a..00000000 Binary files a/resources/media/channels/thumb/tupornotv.png and /dev/null differ diff --git a/resources/media/channels/thumb/url.png b/resources/media/channels/thumb/url.png deleted file mode 100644 index 2ed901f7..00000000 Binary files a/resources/media/channels/thumb/url.png and /dev/null differ diff --git a/resources/media/channels/thumb/xhamster.png b/resources/media/channels/thumb/xhamster.png deleted file mode 100644 index bcc48d7d..00000000 Binary files a/resources/media/channels/thumb/xhamster.png and /dev/null differ diff --git a/resources/media/channels/thumb/yespornplease.png b/resources/media/channels/thumb/yespornplease.png deleted file mode 100644 index 20c30eec..00000000 Binary files a/resources/media/channels/thumb/yespornplease.png and /dev/null differ diff --git a/resources/media/servers/server_filefactory.png b/resources/media/servers/server_filefactory.png deleted file mode 100644 index 17d561c4..00000000 Binary files a/resources/media/servers/server_filefactory.png and /dev/null differ diff --git a/resources/media/servers/server_flashx.png b/resources/media/servers/server_flashx.png deleted file mode 100644 index 0bd65fae..00000000 Binary files a/resources/media/servers/server_flashx.png and /dev/null differ diff --git a/resources/media/servers/server_gamovideo.png b/resources/media/servers/server_gamovideo.png deleted file mode 100644 index 08bf9194..00000000 Binary files a/resources/media/servers/server_gamovideo.png and /dev/null differ diff --git a/resources/media/servers/server_hugefiles.png b/resources/media/servers/server_hugefiles.png deleted file mode 100644 index dc7d7993..00000000 Binary files a/resources/media/servers/server_hugefiles.png and /dev/null differ diff --git a/resources/media/servers/server_mega.png b/resources/media/servers/server_mega.png deleted file mode 100644 index 837da85f..00000000 Binary files a/resources/media/servers/server_mega.png and /dev/null differ diff --git a/resources/media/servers/server_netutv.png b/resources/media/servers/server_netutv.png deleted file mode 100644 index 800afc12..00000000 Binary files a/resources/media/servers/server_netutv.png and /dev/null differ diff --git a/resources/media/servers/server_okru.png b/resources/media/servers/server_okru.png deleted file mode 100644 index 22772ef1..00000000 Binary files a/resources/media/servers/server_okru.png and /dev/null differ diff --git a/resources/media/servers/server_onefichier.png b/resources/media/servers/server_onefichier.png deleted file mode 100644 index 97a4326e..00000000 Binary files a/resources/media/servers/server_onefichier.png and /dev/null differ diff --git a/resources/media/servers/server_openload.png b/resources/media/servers/server_openload.png deleted file mode 100644 index 80cf4b1e..00000000 Binary files a/resources/media/servers/server_openload.png and /dev/null differ diff --git a/resources/media/servers/server_powvideo.png b/resources/media/servers/server_powvideo.png deleted file mode 100644 index 29552b26..00000000 Binary files a/resources/media/servers/server_powvideo.png and /dev/null differ diff --git a/resources/media/servers/server_rapidgator.png b/resources/media/servers/server_rapidgator.png deleted file mode 100644 index ef2e9c6b..00000000 Binary files a/resources/media/servers/server_rapidgator.png and /dev/null differ diff --git a/resources/media/servers/server_rutube.png b/resources/media/servers/server_rutube.png deleted file mode 100644 index 9465e91b..00000000 Binary files a/resources/media/servers/server_rutube.png and /dev/null differ diff --git a/resources/media/servers/server_streamcloud.png b/resources/media/servers/server_streamcloud.png deleted file mode 100644 index d5d83b8a..00000000 Binary files a/resources/media/servers/server_streamcloud.png and /dev/null differ diff --git a/resources/media/servers/server_turbobit.png b/resources/media/servers/server_turbobit.png deleted file mode 100644 index 04979bf0..00000000 Binary files a/resources/media/servers/server_turbobit.png and /dev/null differ diff --git a/resources/media/servers/server_uploadedto.png b/resources/media/servers/server_uploadedto.png deleted file mode 100644 index 51f9079b..00000000 Binary files a/resources/media/servers/server_uploadedto.png and /dev/null differ diff --git a/resources/media/servers/server_uptobox.png b/resources/media/servers/server_uptobox.png deleted file mode 100644 index 8ffe1cc0..00000000 Binary files a/resources/media/servers/server_uptobox.png and /dev/null differ diff --git a/resources/media/servers/server_vimpleru.png b/resources/media/servers/server_vimpleru.png deleted file mode 100644 index 7f64a7c4..00000000 Binary files a/resources/media/servers/server_vimpleru.png and /dev/null differ diff --git a/resources/media/servers/server_vk.png b/resources/media/servers/server_vk.png deleted file mode 100644 index 65bdaa66..00000000 Binary files a/resources/media/servers/server_vk.png and /dev/null differ diff --git a/resources/media/servers/server_vshare.png b/resources/media/servers/server_vshare.png deleted file mode 100644 index 769a9a11..00000000 Binary files a/resources/media/servers/server_vshare.png and /dev/null differ diff --git a/resources/media/servers/server_youtube.png b/resources/media/servers/server_youtube.png deleted file mode 100644 index 6f2cb995..00000000 Binary files a/resources/media/servers/server_youtube.png and /dev/null differ diff --git a/resources/media/themes/default/banner.ai b/resources/media/themes/default/banner.ai deleted file mode 100644 index 05e828b5..00000000 --- a/resources/media/themes/default/banner.ai +++ /dev/null @@ -1,3438 +0,0 @@ -%PDF-1.5 % -1 0 obj <</Metadata 2 0 R/OCProperties<</D<</OFF[14 0 R]/ON[15 0 R 16 0 R 17 0 R]/Order 18 0 R/RBGroups[]>>/OCGs[15 0 R 16 0 R 17 0 R 14 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 38851/Subtype/XML/Type/Metadata>>stream -<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> -<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c145 79.163499, 2018/08/13-16:40:22 "> - <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <rdf:Description rdf:about="" - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:xmp="http://ns.adobe.com/xap/1.0/" - xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/" - xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" - xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" - xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" - xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/" - xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" - xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#" - xmlns:stFnt="http://ns.adobe.com/xap/1.0/sType/Font#" - xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/" - xmlns:pdf="http://ns.adobe.com/pdf/1.3/" - xmlns:pdfx="http://ns.adobe.com/pdfx/1.3/"> - <dc:format>application/pdf</dc:format> - <dc:title> - <rdf:Alt> - <rdf:li xml:lang="x-default">banner</rdf:li> - </rdf:Alt> - </dc:title> - <xmp:CreatorTool>Adobe Illustrator CC 23.0 (Windows)</xmp:CreatorTool> - <xmp:CreateDate>2019-04-25T16:40:35+02:00</xmp:CreateDate> - <xmp:ModifyDate>2019-04-25T16:40:35+02:00</xmp:ModifyDate> - <xmp:MetadataDate>2019-04-25T16:40:35+02:00</xmp:MetadataDate> - <xmp:Thumbnails> - <rdf:Alt> - <rdf:li rdf:parseType="Resource"> - <xmpGImg:width>256</xmpGImg:width> - <xmpGImg:height>24</xmpGImg:height> - <xmpGImg:format>JPEG</xmpGImg:format> - <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAGAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8AMtfeK51WWaS5ikdliDMV K7rEo2EC+nTban074ql/pW/+/ofum/5pxV3pW/8Av6H7pv8AmnFU21VrV9I0mEXUbPCkvJGWirzY EcWjX1TX/iz6NsVSn0rf/f0P3Tf804q70rf/AH9D903/ADTiqYq8Y8uyW/1mH03ulfhwYjksZFeR X1BQHtt49sVS70rf/f0P3Tf804q70rf/AH9D903/ADTiqZaMUhjvyl1BGGtZEf4SeSuOPH96vev7 HxeGKpb6Vv8A7+h+6b/mnFXelb/7+h+6b/mnFUZo8cC6jERNGSORoiyu32D0Vlox9jiqGmjhMzlp oQxYkgrMDWvgF2xVZ6Vv/v6H7pv+acVd6Vv/AL+h+6b/AJpxVE6isTzqzTR0MUfEyJKhI4AdFWhH ge4xVDelb/7+h+6b/mnFXelb/wC/ofum/wCacVTDU3WS2s4mnQxwxgIGSQKOSITxYLVvp6Yql/pW /wDv6H7pv+acVd6Vv/v6H7pv+acVRsUK/oe4Imi9L1ow2zlakMR1XmDt+zt49sVQXpW/+/ofum/5 pxV3pW/+/ofum/5pxVMNLWNILsxyxlzGy1XnQBo3Vi3NG24k9N/A4ql/pW/+/ofum/5pxV3pW/8A v6H7pv8AmnFVexit/rcf72Jt+i+qCduxZCPvxVbdQwfWpqywoebVUiUU3O1FQL9wpiql6Vv/AL+h +6b/AJpxV3pW/wDv6H7pv+acVR2qzQG9bikiAJEOIdIOkaj+74mh8T3O/fFUJ6sPhL/0kJ/zRirv Vh8Jf+khP+aMVTHUSo07TpDBLGjI4SWqx+oQ1SfU40lpypXt0xVLvVh8Jf8ApIT/AJoxV3qw+Ev/ AEkJ/wA0YqmSGI+XZZBFMaXSgy8lIHwH4fX40Wv8lPi612xVLfVh8Jf+khP+aMVd6sPhL/0kJ/zR iqO0z6u63RYS/BBIwJcTUPE+C0WvTkfs9cVQPqw+Ev8A0kJ/zRirvVh8Jf8ApIT/AJoxVMPL72za xaq6yFCxDAus4pQ1/dBQX/1e+KoW9e2W8nWP1SgkcIfVWOoDGnwFTx+XbFVH1YfCX/pIT/mjFXer D4S/9JCf80YqjdXe3W7UKkqfuYeSh1goTEpPwFT168v2uvfFUF6sPhL/ANJCf80Yq71YfCX/AKSE /wCaMVTPVZYBZWFI5AfT3cMsfL4U/wB2cT6lPltiqWerD4S/9JCf80Yq71YfCX/pIT/mjFUdDLbf oe5BSQv6sZDckYgAHb1qfBWv2ab09sVQPqw+Ev8A0kJ/zRirvVh8Jf8ApIT/AJoxVMdKdGiuuMMk tInLAus1AIpDyACfDx68v2evbFUu9WHwl/6SE/5oxV3qw+Ev/SQn/NGKorSpYv0lbUjkkPqLSNpF mDb/AGTHx+Ov8vfFVl9JEt9cKY5YyJXBT1Vj40Y7cCvw0/l7YqoerD4S/wDSQn/NGKu9WHwl/wCk hP8AmjFU+1Hyl5vN0fR0aVowkYBjt2Zdo1B3kQN169vDbFUL/hHzp/1ZZ/8ApGH/ADTirv8ACPnT /qyz/wDSMP8AmnFUdfeVvOLWVki6TI5RW5ItvIWUkj7YdfTFe3p/TviqB/wj50/6ss//AEjD/mnF Xf4R86f9WWf/AKRh/wA04qmEflXzd+gpYzpMgm+sKwjNvJ6hXiRVVVfSp4lt/DviqX/4R86f9WWf /pGH/NOKu/wj50/6ss//AEjD/mnFUbpvlbzhGt1z0mROcLqvqW8o5Eqdl9Fd2Pbn8H822KoL/CPn T/qyz/8ASMP+acVd/hHzp/1ZZ/8ApGH/ADTiqN0byp5wTU4Gl0mWJKmsj2xCrVSKsUXnT/V3xVDX HlLzmbiUjR5nBdqOtsaEV6jmvLf33xVT/wAI+dP+rLP/ANIw/wCacVd/hHzp/wBWWf8A6Rh/zTiq K1Hyj5v+sD0tId0EcdDDbScAeAqP3y8qg9e1em2KoX/CPnT/AKss/wD0jD/mnFXf4R86f9WWf/pG H/NOKphqXlPzW1tZmLRnMojpNwt3L1CqAHDLwHtw+nFUv/wj50/6ss//AEjD/mnFXf4R86f9WWf/ AKRh/wA04qyzyp+Wmq6po12uo10qczp6QmtQx4otSQvKMHkWpuD0xVMf+VISf9XuP/pBj/6qYq7/ AJUhJ/1e4/8ApBj/AOqmKozT/wAn2tBMG1OGcSoyAPZBeJZWUMOEy7jl32xVB/8AKkJP+r3H/wBI Mf8A1UxV3/KkJP8Aq9x/9IMf/VTFVW1/JeSC5jmOsRuI2DcDZKtadqrKGH0HFVs35KyyzPKdZjUu xbiLFSBU1pVpWb7zXFVn/KkJP+r3H/0gx/8AVTFXf8qQk/6vcf8A0gx/9VMVf//Z</xmpGImg:image> - </rdf:li> - </rdf:Alt> - </xmp:Thumbnails> - <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass> - <xmpMM:OriginalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</xmpMM:OriginalDocumentID> - <xmpMM:DocumentID>xmp.did:d19bb605-fc41-1147-84d5-e8306b9c7bf3</xmpMM:DocumentID> - <xmpMM:InstanceID>uuid:0f882cf7-ca0c-4f37-ad94-a9aaa2846b1e</xmpMM:InstanceID> - <xmpMM:DerivedFrom rdf:parseType="Resource"> - <stRef:instanceID>xmp.iid:97f9f605-276d-fd40-a033-abadb5344d0b</stRef:instanceID> - <stRef:documentID>xmp.did:97f9f605-276d-fd40-a033-abadb5344d0b</stRef:documentID> - <stRef:originalDocumentID>uuid:65E6390686CF11DBA6E2D887CEACB407</stRef:originalDocumentID> - <stRef:renditionClass>proof:pdf</stRef:renditionClass> - </xmpMM:DerivedFrom> - <xmpMM:History> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <stEvt:action>saved</stEvt:action> - <stEvt:instanceID>xmp.iid:97f9f605-276d-fd40-a033-abadb5344d0b</stEvt:instanceID> - <stEvt:when>2019-04-25T16:40:01+02:00</stEvt:when> - <stEvt:softwareAgent>Adobe Illustrator CC 23.0 (Windows)</stEvt:softwareAgent> - <stEvt:changed>/</stEvt:changed> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stEvt:action>saved</stEvt:action> - <stEvt:instanceID>xmp.iid:d19bb605-fc41-1147-84d5-e8306b9c7bf3</stEvt:instanceID> - <stEvt:when>2019-04-25T16:40:28+02:00</stEvt:when> - <stEvt:softwareAgent>Adobe Illustrator CC 23.0 (Windows)</stEvt:softwareAgent> - <stEvt:changed>/</stEvt:changed> - </rdf:li> - </rdf:Seq> - </xmpMM:History> - <illustrator:StartupProfile>Web</illustrator:StartupProfile> - <illustrator:Type>Document</illustrator:Type> - <xmpTPg:NPages>1</xmpTPg:NPages> - <xmpTPg:HasVisibleTransparency>True</xmpTPg:HasVisibleTransparency> - <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint> - <xmpTPg:MaxPageSize rdf:parseType="Resource"> - <stDim:w>1400.000000</stDim:w> - <stDim:h>140.000000</stDim:h> - <stDim:unit>Pixels</stDim:unit> - </xmpTPg:MaxPageSize> - <xmpTPg:Fonts> - <rdf:Bag> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Regular</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Regular</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Regular.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Medium</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Medium</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Medium.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Bold</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Bold</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Bold.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>KozGoPr6N-Medium</stFnt:fontName> - <stFnt:fontFamily>小塚ゴシック Pr6N</stFnt:fontFamily> - <stFnt:fontFace>M</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 6.016;PS 6.007;hotconv 1.0.70;makeotf.lib2.5.5900</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>KozGoPr6N-Medium.otf</stFnt:fontFileName> - </rdf:li> - </rdf:Bag> - </xmpTPg:Fonts> - <xmpTPg:PlateNames> - <rdf:Seq> - <rdf:li>Cyan</rdf:li> - <rdf:li>Magenta</rdf:li> - <rdf:li>Yellow</rdf:li> - <rdf:li>Black</rdf:li> - </rdf:Seq> - </xmpTPg:PlateNames> - <xmpTPg:SwatchGroups> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <xmpG:groupName>Gruppo campioni predefinito</xmpG:groupName> - <xmpG:groupType>0</xmpG:groupType> - <xmpG:Colorants> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Bianco</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>255</xmpG:green> - <xmpG:blue>255</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Nero</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>0</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Rosso RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>0</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Giallo RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>255</xmpG:green> - <xmpG:blue>0</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Verde RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>255</xmpG:green> - <xmpG:blue>0</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Cyan RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>255</xmpG:green> - <xmpG:blue>255</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Blu RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>255</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>Magenta RGB</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>255</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>193</xmpG:red> - <xmpG:green>39</xmpG:green> - <xmpG:blue>45</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>237</xmpG:red> - <xmpG:green>28</xmpG:green> - <xmpG:blue>36</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>241</xmpG:red> - <xmpG:green>90</xmpG:green> - <xmpG:blue>36</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>247</xmpG:red> - <xmpG:green>147</xmpG:green> - <xmpG:blue>30</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>251</xmpG:red> - <xmpG:green>176</xmpG:green> - <xmpG:blue>59</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>252</xmpG:red> - <xmpG:green>238</xmpG:green> - <xmpG:blue>33</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>217</xmpG:red> - <xmpG:green>224</xmpG:green> - <xmpG:blue>33</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>140</xmpG:red> - <xmpG:green>198</xmpG:green> - <xmpG:blue>63</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>57</xmpG:red> - <xmpG:green>181</xmpG:green> - <xmpG:blue>74</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>146</xmpG:green> - <xmpG:blue>69</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>104</xmpG:green> - <xmpG:blue>55</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>34</xmpG:red> - <xmpG:green>181</xmpG:green> - <xmpG:blue>115</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>169</xmpG:green> - <xmpG:blue>157</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>41</xmpG:red> - <xmpG:green>171</xmpG:green> - <xmpG:blue>226</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>113</xmpG:green> - <xmpG:blue>188</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>46</xmpG:red> - <xmpG:green>49</xmpG:green> - <xmpG:blue>146</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>27</xmpG:red> - <xmpG:green>20</xmpG:green> - <xmpG:blue>100</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>102</xmpG:red> - <xmpG:green>45</xmpG:green> - <xmpG:blue>145</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>147</xmpG:red> - <xmpG:green>39</xmpG:green> - <xmpG:blue>143</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>158</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>93</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>212</xmpG:red> - <xmpG:green>20</xmpG:green> - <xmpG:blue>90</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>237</xmpG:red> - <xmpG:green>30</xmpG:green> - <xmpG:blue>121</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>199</xmpG:red> - <xmpG:green>178</xmpG:green> - <xmpG:blue>153</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>153</xmpG:red> - <xmpG:green>134</xmpG:green> - <xmpG:blue>117</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>115</xmpG:red> - <xmpG:green>99</xmpG:green> - <xmpG:blue>87</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>83</xmpG:red> - <xmpG:green>71</xmpG:green> - <xmpG:blue>65</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>198</xmpG:red> - <xmpG:green>156</xmpG:green> - <xmpG:blue>109</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>166</xmpG:red> - <xmpG:green>124</xmpG:green> - <xmpG:blue>82</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>140</xmpG:red> - <xmpG:green>98</xmpG:green> - <xmpG:blue>57</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>117</xmpG:red> - <xmpG:green>76</xmpG:green> - <xmpG:blue>36</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>96</xmpG:red> - <xmpG:green>56</xmpG:green> - <xmpG:blue>19</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>66</xmpG:red> - <xmpG:green>33</xmpG:green> - <xmpG:blue>11</xmpG:blue> - </rdf:li> - </rdf:Seq> - </xmpG:Colorants> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:groupName>Grigi</xmpG:groupName> - <xmpG:groupType>1</xmpG:groupType> - <xmpG:Colorants> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>0</xmpG:red> - <xmpG:green>0</xmpG:green> - <xmpG:blue>0</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>26</xmpG:red> - <xmpG:green>26</xmpG:green> - <xmpG:blue>26</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>51</xmpG:red> - <xmpG:green>51</xmpG:green> - <xmpG:blue>51</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>77</xmpG:red> - <xmpG:green>77</xmpG:green> - <xmpG:blue>77</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>102</xmpG:red> - <xmpG:green>102</xmpG:green> - <xmpG:blue>102</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>128</xmpG:red> - <xmpG:green>128</xmpG:green> - <xmpG:blue>128</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>153</xmpG:red> - <xmpG:green>153</xmpG:green> - <xmpG:blue>153</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>179</xmpG:red> - <xmpG:green>179</xmpG:green> - <xmpG:blue>179</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>204</xmpG:red> - <xmpG:green>204</xmpG:green> - <xmpG:blue>204</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>230</xmpG:red> - <xmpG:green>230</xmpG:green> - <xmpG:blue>230</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>242</xmpG:red> - <xmpG:green>242</xmpG:green> - <xmpG:blue>242</xmpG:blue> - </rdf:li> - </rdf:Seq> - </xmpG:Colorants> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:groupName>Gruppo colori Web</xmpG:groupName> - <xmpG:groupType>1</xmpG:groupType> - <xmpG:Colorants> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=63 G=169 B=245</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>63</xmpG:red> - <xmpG:green>169</xmpG:green> - <xmpG:blue>245</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=122 G=201 B=67</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>122</xmpG:red> - <xmpG:green>201</xmpG:green> - <xmpG:blue>67</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=255 G=147 B=30</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>147</xmpG:green> - <xmpG:blue>30</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=255 G=29 B=37</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>29</xmpG:green> - <xmpG:blue>37</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=255 G=123 B=172</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>255</xmpG:red> - <xmpG:green>123</xmpG:green> - <xmpG:blue>172</xmpG:blue> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <xmpG:swatchName>R=189 G=204 B=212</xmpG:swatchName> - <xmpG:mode>RGB</xmpG:mode> - <xmpG:type>PROCESS</xmpG:type> - <xmpG:red>189</xmpG:red> - <xmpG:green>204</xmpG:green> - <xmpG:blue>212</xmpG:blue> - </rdf:li> - </rdf:Seq> - </xmpG:Colorants> - </rdf:li> - </rdf:Seq> - </xmpTPg:SwatchGroups> - <pdf:Producer>Adobe PDF library 15.00</pdf:Producer> - <pdfx:CreatorVersion>21.0.0</pdfx:CreatorVersion> - </rdf:Description> - </rdf:RDF> -</x:xmpmeta> - - - - - - - - - - - - - - - - - - - - - -<?xpacket end="w"?> -endstream endobj 3 0 obj <</Count 77/Kids[19 0 R 20 0 R 21 0 R]/Type/Pages>> endobj 19 0 obj <</Count 25/Kids[22 0 R 23 0 R 24 0 R 25 0 R 26 0 R]/Parent 3 0 R/Type/Pages>> endobj 20 0 obj <</Count 25/Kids[27 0 R 28 0 R 29 0 R 30 0 R 31 0 R]/Parent 3 0 R/Type/Pages>> endobj 21 0 obj <</Count 27/Kids[32 0 R 33 0 R 34 0 R 35 0 R 36 0 R]/Parent 3 0 R/Type/Pages>> endobj 32 0 obj <</Count 5/Kids[37 0 R 38 0 R 39 0 R 40 0 R 41 0 R]/Parent 21 0 R/Type/Pages>> endobj 33 0 obj <</Count 5/Kids[42 0 R 43 0 R 44 0 R 45 0 R 46 0 R]/Parent 21 0 R/Type/Pages>> endobj 34 0 obj <</Count 5/Kids[47 0 R 48 0 R 49 0 R 50 0 R 51 0 R]/Parent 21 0 R/Type/Pages>> endobj 35 0 obj <</Count 5/Kids[52 0 R 53 0 R 54 0 R 55 0 R 56 0 R]/Parent 21 0 R/Type/Pages>> endobj 36 0 obj <</Count 7/Kids[57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R]/Parent 21 0 R/Type/Pages>> endobj 57 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 64 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 65 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 58 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 71 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 72 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 59 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 73 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 74 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 60 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 75 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 76 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 61 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 77 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 78 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 62 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 79 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 80 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 63 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 81 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 82 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 36 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 81 0 obj <</Filter/FlateDecode/Length 1163>>stream -Htn5^#.o[2 4%S0 o.)tTҷ廏|Ϋz^}T=K.,~?^ˏK;v||/'|_Rr,UnWSS㻭-<_5Wɲm6 mkɾR-,t`WO}:%jY&G(ManTeA26'cd|["EN\>EBxA<JcRM-"Tr'G\+U,%>69-74S~@2gPÓM<'"V" z`iOUXٔެy.5nc".'kWMF %۔J5 r$XфvT.,%eePȾuT%sV\2rAM#FrTO�)x]/>eCWa{A}\�ZWJyv:UJ"RWdQhrobȞ׊>P@ *'lUM]hNlz1y,us[GtuBgb)A3q -4-eCQb$ JXjjnk2-vqJ@XE_95 bs??VGC0Ѓ+d"/xFSgV;)'KaSok_:hK0Kn ܃�t#/vYU ?q]{īGlo؊[M ZWǑ1Q9lMϡh$wff.l#梠B<mi y#OH<JLc݆$dt=Q-ū=05�"Xk+#(՜ں%z,,cWI޵,4W=r,K̵Bh_)硣4x twTܩ_P:@XN1W hjv1Zp 9$!C/i?8Wb2.nA:QkrɼG!!?[FB"(Zk̕WP -YnSV*6�lHU115J&BĹzG%T$^Ao!sC0Hpzt(Rj*mlPKU-P{+�5 -endstream endobj 82 0 obj <</CS 83 0 R/I false/K false/S/Transparency>> endobj 70 0 obj <</BBox[0.0 140.0 1400.0 0.0]/Group 84 0 R/Length 60/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0 140 1400 -140 re -f - -endstream endobj 84 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 69 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 67 0 obj [/ICCBased 85 0 R] endobj 85 0 obj <</Filter/FlateDecode/Length 2574/N 3>>stream -HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽�'0 �֠Jb � - �2y.-;!KZ ^i"L0- �@8(r;q7Ly&Qq4j|9 -V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'K�t;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= -x-�[�0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c.� ��R ߁-25 S>ӣVd`rn~Y&+`;A4 A9�=-tl`;~p Gp| [`L`< "A YA+Cb(R,�*T2B- -ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 -N')].uJr - wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 -n3ܣkGݯz=[==<=G</z^^j^ ޡZQB0FX'+t<u-{__ߘ-G,}/Hh 8mW2p[AiAN#8$X?AKHI{!7<qWy(!46-aaaW @@`lYĎH,$((Yh7ъb<b*b<~L&Y&9%uMssNpJP%MI JlN<DHJIڐtCj'KwKgC%Nd |ꙪO=%mLuvx:HoL!ȨC&13#s$/Y=OsbsrnsO1v=ˏϟ\h٢#¼oZ<]TUt}`IÒsKV-Y,+>TB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O�[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-�u`ֲK³8%yhYѹJº;.! -zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km � -endstream endobj 15 0 obj <</Intent 86 0 R/Name(Guide)/Type/OCG/Usage 87 0 R>> endobj 16 0 obj <</Intent 88 0 R/Name(Sfondo)/Type/OCG/Usage 89 0 R>> endobj 17 0 obj <</Intent 90 0 R/Name(Icone)/Type/OCG/Usage 91 0 R>> endobj 14 0 obj <</Intent 92 0 R/Name(Livello 4)/Type/OCG/Usage 93 0 R>> endobj 92 0 obj [/View/Design] endobj 93 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 90 0 obj [/View/Design] endobj 91 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 88 0 obj [/View/Design] endobj 89 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 86 0 obj [/View/Design] endobj 87 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 68 0 obj <</AIS false/BM/Normal/CA 0.600006/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 0.600006/op false>> endobj 66 0 obj <</LastModified(D:20190425164034+02'00')/Private 94 0 R>> endobj 94 0 obj <</AIMetaData 95 0 R/AIPrivateData1 96 0 R/AIPrivateData2 97 0 R/AIPrivateData3 98 0 R/AIPrivateData4 99 0 R/AIPrivateData5 100 0 R/AIPrivateData6 101 0 R/AIPrivateData7 102 0 R/AIPrivateData8 103 0 R/ContainerVersion 11/CreatorVersion 23/NumBlock 8/RoundtripStreamType 1/RoundtripVersion 17>> endobj 95 0 obj <</Length 1135>>stream -%!PS-Adobe-3.0 -%%Creator: Adobe Illustrator(R) 17.0 -%%AI8_CreatorVersion: 23.0.0 -%%For: (Concreate Studio) () -%%Title: (Senza titolo-2) -%%CreationDate: 4/25/2019 4:40 PM -%%Canvassize: 16383 -%%BoundingBox: -6407 -1014 7774 246 -%%HiResBoundingBox: -6407 -1014 7773 246 -%%DocumentProcessColors: Cyan Magenta Yellow Black -%AI5_FileFormat 13.0 -%AI12_BuildNumber: 530 -%AI3_ColorUsage: Color -%AI7_ImageSettings: 0 -%%RGBProcessColor: 0 0 0 ([Registro]) -%AI3_Cropmarks: -3567 -1014 -2167 -874 -%AI3_TemplateBox: 683.5 -384.5 683.5 -384.5 -%AI3_TileBox: -3279.43999671936 -1233.20000648499 -2454.56002807617 -654.800018310547 -%AI3_DocumentPreview: None -%AI5_ArtSize: 14400 14400 -%AI5_RulerUnits: 6 -%AI9_ColorModel: 1 -%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 -%AI5_TargetResolution: 800 -%AI5_NumLayers: 4 -%AI9_OpenToView: -7157 4861 0.1 1576 1034 18 0 0 46 121 0 0 0 1 1 0 1 1 0 1 -%AI5_OpenViewLayers: 6777 -%%PageOrigin:283 -684 -%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 -%AI9_Flatten: 1 -%AI12_CMSettings: 00.MP -%%EndComments - -endstream endobj 96 0 obj <</Length 4662>>stream -%%BoundingBox: -6407 -1014 7774 246 -%%HiResBoundingBox: -6407 -1014 7773 246 -%AI7_Thumbnail: 128 12 8 -%%BeginData: 4517 Hex Bytes -%0000330000660000990000CC0033000033330033660033990033CC0033FF -%0066000066330066660066990066CC0066FF009900009933009966009999 -%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 -%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 -%3333663333993333CC3333FF3366003366333366663366993366CC3366FF -%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 -%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 -%6600666600996600CC6600FF6633006633336633666633996633CC6633FF -%6666006666336666666666996666CC6666FF669900669933669966669999 -%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 -%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF -%9933009933339933669933999933CC9933FF996600996633996666996699 -%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 -%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF -%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 -%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 -%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF -%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC -%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 -%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 -%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 -%000011111111220000002200000022222222440000004400000044444444 -%550000005500000055555555770000007700000077777777880000008800 -%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB -%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF -%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF -%524C45A87D7D527D527D527D527D527DA87D527D527D527D527D527D7DA8 -%527D527D527D527D527D52A87D7D527D527D527D527D527D7D7D527D527D -%527D527D527D52A87D7D527D527D527D527D527DA87D527D527D527D527D -%527D7DA8527D527D527D527D527D527D7D7D527D527D527D527D527D7D7D -%527D527D527D527D527D527D7D527D527D527D527D525252A8527D527D52 -%7D527D527D527D7D53527D527D527D527D527D7D7D527D527D527D527D52 -%7D527D527D527D527D527D527D527D527D527D527D527D527D5252527D52 -%7D527D527D527D527D527D7D7D527D527D527D527D527D7D7D527D527D52 -%7D527D527D527D527D527D527D527D527D527DA8FD047D7C7D7D7D7C7D7D -%7DA87D7D7D7C7D7D7D7CFD047DA87D7D7C7D7D7D7C7D7D7D52A87D7D7C7D -%7D7D7C7D7D7D527D7D7D527D7D7D7C7D7D7D7CFD077D7C7D7D7D7CFD077D -%7C7D7D7D7CFD047DA87D7D7C7D7D7D7CFD047DA87D7D7C7D7D7D7C7D7D7D -%527D7D7D527D7D7D7C7D7D7D7CFD047D527D527D527D527D527D527D527D -%527D527D527D527D527D527D527D527D527D527D527D7D7D527D527D527D -%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D -%7D7D527D527D527D527D527D527D7D7D527D527D527D527D527D7D7D527D -%527D527D527D527D527D527D527D527D527D527D527D7D527D527D527D52 -%7D527D527D7D7D527D527D527D527D527D7DA8527D527D527D527D527D52 -%7D7D7D527D527D527D527D527D7D7D527D527D527D527D527D52A87D7D52 -%7D527D527D527D527D7D7D527D527D527D527D527D7DA8527D527D527D52 -%7D527D52A87D7D527D527D527D527D527D7D7D527D527D527D527D527D52 -%7D7D527D527D527D527D527D7DA8527D527D527D527D527D527D7D7D527D -%527D527D527D527D7D7D527D527D527D527D527D52A87D7D527D527D527D -%527D527D7D7D527D527D527D527D527D7DA8527D527D527D527D527D527D -%7D7D527D527D527D527D527D7D7D527D527D527D527D527D52A87D7D527D -%527D527D527D527DA87D7D527D527D527D527D527D7D7D527D527D527D52 -%7D527D7D7D527D527D527D527D527D527D7D7D527D527D527D527D527DA8 -%A8527D527D527D527D527D52A87D7D527D527D527D527D527D7D7D527D52 -%7D527D527D527D7DA8527D527D527D527D52FD057D527D527D527D527D52 -%7D7D7D527D527D527D527D527D52527D5252527D5252527D525252A85252 -%527D5252527D5252527D7D52527D5252527D5252527D7D7D527D5252527D -%5252527D527D527D5252527D5252527D52527D7D5252527D5252527D5252 -%527D5252527D5252527D5252527D7D52527D5252527D5252527D7D7D527D -%5252527D5252527D527D7D7D5252527D5252527D5252A8FD0A7D527DA87D -%52FD0A7DA852FD0A7DA8FD187D52A8FD0A7D527D7D7D52FD0A7DA8527D7D -%7D527D7D7D527D7DA8FD047D527D7D7D52FD047DA8527D527D7D7D527D7D -%7D527D7D527D527D527D527D527D527D527D527D527D527D527D527D7D52 -%527D527D527D527D527D7D7D527D527D527D527D527D527D527D527D527D -%527D527D527D7D7D527D527D527D527D52527CA8527D527D527D527D527D -%527D7D7D527D527D527D527D527D7DA8527D527D527D527D527D527D7D7D -%527D527D527D527D527D7D527D5252527D5252527D527D7D7D5252527D52 -%52527D52527D7D5252527D5252527D5252527D7D52527D5252527D525252 -%7D7D7D527D5252527D5252527D527D527D5252527D5252527D527D7D7D52 -%52527D5252527D52527DFD26FFA8A87DA8A8A87DA8A8A87DFD07A87DA8A8 -%A87DFD07A87DA8A8A87DFD07A87DA8A8A87DA8A8A87DFFA8A87DA8A8A87D -%A8A8A87DA8A8A87DA8A8A87DA8A8A87DFD07A87DA8A8A87DA8A8A8FD25FF -%FF -%%EndData - -endstream endobj 97 0 obj <</Length 65536>>stream -%AI12_CompressedDataxks.Uk:>ۋ{ϮS"Ll';sRS*FmN$Ry^\ ")K53&l4./o_~_.?5agyŋ7nW_zv`T򏗷n?hTs7XrݛW7%򿾼͋OKo}'ڝAM6_N\\GhpwSoT nBvg}%M.yz/oo]~}@o_9pqwȹ7_\<kʞ~{i)Wn^<o՛ï.{6>͗_?>XuyՋK,wedU>WՋ/Xa^cj0K]ģ/0VY_f_+J՟WX7\ͫśJT+>}s XYS~4[?0>,.>ôf&d<loG;Mh:AC -z<QBF ΆTd/vu6Lc:k!7e}<` 1WqBPJ|sqv͋7wB -&?\r.tӠ\ѣQ5J3jUZVSUF<63KW]]GmZz>7c"!V&==$?&7*$ :7wժsvpZ5R䡊7|'|_\n&.1ٛ챡*ח'b\]ǧ]z}O_|m'Ϯn}qN^]}󓯟]\|+u3B'c+MJG<;~~˗h ܮuh| Xdɿ<ޜ~u ɳ7~/7 )I.^A`];W_^ -YO^^<c0W8Y'wyvus{reٛ˓ỏ<{ /=|5a7Сy!=Gf7x~Fzz|v]58;~䐺pr&˨zy,yl'Q/ _T/|EywW^p\P7X-8n^\Ć/\To_Ħ/J%2'p\/c˨겼wK]RWUW%:6x>T/ܤ"W8oobKoyS!f`?䛳Hf?=5l1OМ]?!S钝踋?4%N"{"#?.Toȴl͢/xr,z9{|%mt^<>Y8_}[􈯈=~ON߿/ 77o^}~͓O~eHɅDۋoqI̺o/^JݳUsT||7ZfsAq):!g1^~Oٟ_ l38UȌS/.ZSݛ |}/./!] TYj{^w-zL p8^}l}777/!:\S<KEPW!5G^뗨+T%xg/."q>%,*U[enCx=BJ;ϯ^ݏb6`ASЋ{| ^͡9>7WwBy2lݼ|uisgc}}u]8]iۛ_s,q HC?g7t^qQU2UUHN4VivH0Ɲ==Tl]%,zloLJJcvH/!&OttHuw$+=D|4";4)謹vUw92Z~7M[_P _8>f\~o/j<UP~([U 7&C\ bN|"uWF^ -,sXVCYCC -c)εt$bNbQ>0V'+_>ʪs=K_3'mnԈ*M0̩9+tXk vBۃ=gq9&s{wtBƣFϟ?ǢQvNY8DzQ3э~ 8Nn܏t<'P,LfG&7zݴt6c)Bdw͆ݸv~w؝α{twXq?wt?QRx zp@a:pJ1Ox:NQɓONQ  Ya =sg3|(i:!=QEҨQMɶj]r+)y9iUWiHSNq:UVT $5"Urt1=DWiWJ"**cdTIWIUb2cUǴ\.gL-g3m=#L,9iqxcFr1q[VY1r\R$)I>%dRºY䁌?{I&IcJO>}JNMɤ|ăLq/6<9 *ud4:h /WU;w^Zs!=,L'Ye=z%u><\qys7`a8w8)t8- NM ǹ:#NY8},3L!q.O8iڀEU`αN1{y^G0; 8A<;Ŕƒ34[ �.d^}W3\7`{a; O{)f2LJ֥#On#Jo *N?!-c-9vS?ɑ~Y5Sڏy嘴iL{ Y.q6S<5zwgD/8?#!/\Q"?(CkPk -i"DPPPtCw<&SL5s(1osUeC`c[ouxfՔx_jvi/.=;1ڥF-Ouqy_- Nfa%'ҼOAj~|\:2)LCg*Ze%u}Ym{-1w/f~!ݧўȄ^W), }RI +z F^)Itڦ/ӾKS۸t\f,ۤ~POcZhDGL*SeXJs7Ηl=K%I 5OFjlJQ3d~fN^ۯHq?ڙý3I7}}͚nkv-\4ef-_sڃhᚽ~9OZkQ 4?<șyZ>}{rf5dMgLyO5@=愕=4ny^ {Ợw DȼE9\:rđG<|%,e ωFrj%|YΛ%=#Ҟ$,E/@DO -~Q_�C 0ʀQ -90IQ<,AȃO>LHyHaLo:x&j|>ƝHȋ)3ai0�"9 ^t#XyZ$c̒d.} gGo\ N72gI0{SH5}(z2 /TzJiJlK3e+fb$MO9ʴHa%-:?+jw*_LsBG,q<Nmk*|Lmߥ?KCePi6A%ל"-- I~-e ;ǔ4luڷ)MtڥOY}BU+I&OHGSZФ4=vq`?295NPctm*P㱼SY/$EilɖhVRL)%j6Iżd(`+hjLXҔҮ -OPN-(:mZZC45:Fjʳqsi{i -ey{#(HC)Ė^Ə?J'Iz:pϮ?; O5:+FoAd "D~GC<ʾGAAd ' -~JHl3E7$$e$3)&ERTBR"E2>Kk)-Eϥa#K{ɉM&0E/SټD&5y5!CO>RB&OLmz -6RDcAo3u L=g9S˚FFXQ5i'ݒa`@fʶe ZzT<|1p%uBPcOUгh7㰵;`-~?<}L:qfT[¶ԶUjPl02ux'f'6n1RHG<ԓU*x |2YVDiDTޚٹU8 3C�Y5 wC4 $yt*5q ^ #toXkN$ilo! Uv�V0 Ja2 t oM#> A;Sc<:B $CpڡɫβVIKnz`~^|$;KL=@Fi{][liPiKcdmYO q,m -H"G|PKG,.!SHX8'y2'Rf2Ą`Ť3aTr&Im'Ƌ%+ pO#nSǘ̞ gvvkcN.YI, -euw4⬡$$"E/'=墯\Krb 9KsW<^,~l}V?n<}vŻ,qya$^F\}#N=F 0RLxt#(\98*6 9VE']q^tghbsY -Y%qH.f#/9^ehrLmvHdz /N UblCdMH#-$fF&6&/"Z ٥D;*6lN |(El;$},E$K( 7ДLĸ,șF#}ډ(W s"vEPH'vJb~0$bBR QBj.vj2.r$$= %#J(.UNN.%SPJ'}5^pe%ҩ,vhT!%1ٞ -݈NنS/˰9T\S(MQdЋ$ -e*r NFsҨZ;] z1p0To\_ު'ˎ8ŅN'sv./+Ǟ*5rST;gcgQCm+#ZBWb!B# rCyH(gB.t׈FWJ:"q.T DC%''y̍1p,c9 Sw -u坒# -h#E80Q bZA:{(buV<V"ڈ{"fKDM0Fԩbu9>ditH:Ng(k<nbzUJ^Vz6i;*<E|'5uZ!x/̾Yѩ'ڜ'3| B_ymZEF|>.:[kJJ\ZWǩ=}|4o5=tʨ՝,}^S:v0:`I6z}A)P -,%(DYۀd@.vLD#ʿ؞cy5JipE'8!hI7bQJ+uʏ՗~fQ4jH'Ίrѫi -`P�/JJJ#1+45KҬLBP)Uw|#rSF MլFYkB�N*L؅@Frn)_i*6++9mG6O[jWn2:]R#꺢k\$MWt8Ӆɵ12!\7Fp/R|ߓ2'IfφVօU[duXcêu\B5 NY2oLx]-k`9&[$$,4f{/$yZ0 $䜕I*w8=qq5Shļ>Ӈ) ,jy7@̸r9$p5 yFB D?耰ʖ:~]啵OYD;5Vn'ml?t+LVV՚ C2{2YeGDWtdM"zX_ PZ7V%9l%C\ uXn#1<KZ¤!Ěi=ȑ]9&UvI�C^C - -:)io,Y_Ҥ='w=<5d:mRO ИY&uFs(TW"%+:/g'48ak픛ϸ _1GP }LWV(F !'+f'.h:ci<dwSN'1>?]Ǔ%<VG;:MN\W$'Y@)x UOETMU_/k5˚wM,UV -(>| "deͿh~Q RPM3<֢뻋K -7m\lߩ3EZI34GZ#�%+ph 2"Xh5IMI2@>b}SN>Ɉɗ�8:^*$%8q("fr/#$5d<oÍfNA'p|*"j/w |pZ47+4MɧBJ>I*l+JL8u޳Oq yFG)0.+H0{+ hJF9te\kR gGґ .Tc(H2&QwF>Rų$wmɌ5LPvc&TǢjmjxָ{vIdnjP4x\rٲkitX"\"JFL5jWZ2\rRP&MZE^M$=^e -5/QOYPTlL$<J45ּm6B* %Uie CĶ `Kalཪ0@g;{,0wPcQQ+LKSyH)W%g̠sKΡ�9U Kt!ɦs Y+r6LΦڤ?kC~1ڳ4߯;tl )si_,K>2hJ3\J6gc.cCe? geqZƒp>]IvNTiFSTq,#j-_ <,ҾK&rVs<eJD+['185=%/튼%ޥ̻zk7IX~!ήާ wU%]PLl,Gw(Gx!I P$1W+>G)3e�2DPܲ"DƋlAFatk,t2Hg 6A!1@H "R "t.Y:M^]rZ eh($jUY`HQڪ!Z�S] -d b &9H]jzc8+X -EQC!3> K':5V)=1d`Ԕ[L/uMLJk-u_>"V{tL1lҰ2y}@3sVjOCab2^gL8pl-W/^^>|mӟʱ=8[wxOr 5@pkOd~g㵘NޛdGs1럸 37k'8Y`>:0NƎ`n'KIGF zrtǐC1,a5 z<9MDw{KhjEG+'oGbM|i53LM4bCg2{Lf-Y@iIc}%gh䙔dw_ږIWY,Zj'H*>oc`PtF[V)B$*"VYk[EKEIǙӮJaNTE@HۥqA{T0j|T~lB._ƊKR+F1=(R/J|ﶙ=HvhS=iatg&F'$nDSxTmeޣri*}hW6kT;{XLliZNTsbv=z"v6lf2(s{l̵˄(Q1)=:]REو=SULM|ѧXy-Ϊ_X;FQcW3])> caG -1CkO>If3S)iF%%{AI-RVѶVnU9f Ǩ\⽦_jj|gt$S3͸ ;{ߩf¯\OlVNB@c|[/(yF럽O-H2.Qٻ<k&^"�b >( *?G 0H\(^ 'JJk(+$d,?"PfA1jT-RhRe'\2/H]t:<&QHJWJiw5aøssN!N8/9=.iAra#p/7%7ݦd+r(h %<Z8m<ڻwy<*ڵ~@'J-:m*6 -Nd,gZb{-<ۜgsmoAyagṋu'}uya[Ϯ,UMVd^E(멿Hl38BQ~(P_(ʻ EBQ~(ʄ{?GĩIz 6mN$F|pʂhE/25, D7GԩO@=e6NmPڅWAUz,ՖcmzF׆ka~//|!ĕƂg1я%&aZѻk&q0(%26֢ǧrrӍND�nw! N GC5,]G[SޠVbV-Q1C) u&}པYQy N#(D@�^{@זL-7Pq0' NP^>gK -k żDI@~t3GoG[Z?i~}_޲}m YE[i<N7_O(}},|)j}UKI \W]wREZ�V4N5*ߡzPpNDHF`DI=XYG((2 9u_k1|k *1ȯ6&�} ksX{CЉPI++C7[C5PqbFU<pf{Ǡ@T{}U4`\'c{;xy1/]E/-u[[wJ{u҄ -9lޑ</$# 0 '#ϰUDvnJx]w.c]^{]FB6j8ȬWg$tH?  E#ΫH}OTv-ZZn";+.E iԟc9ԝcdL5e ̤Чqֵw*䛄ۉv|p6j K(|Iq{E/vV/DCf]m<+߉=]zgowA-F1KY\([xֽ ~wjr ; 4F|FH?޽cGauJ]D>[י0jq'AVb[.ddY_Y1u*~qE-fe% -] >`%L/uvIۈW?I[HU.?-+HmAbakzqδAuRuJWe,rdP!0qq0|TU#л -vUfiN!]přF+'M '4C-<G⩽x,Ya -g¡ -'p-R JiKaws/<47}6|޾FDCMm7ydsH>FN)�@W{L@`I؅v. rxǍA -N෦$�` `u8v8/EC -e1pjᆵxux`T.]/Îry[\5bS%x;Umx?֑_j|7Kl6jH&BJZ���k__q?M^jtGsy<=-7Lǻ.#t2K7S|yթYM?ϡh,g옴.g޻$>=Գ4dgmKdB޳b~y$,1DŽr -|ܸE]2G^Oq=GԠǿ5<VȲ,x+Մl<L2|cP8ƂК.!U$dtmXVQ\G9ʱޓȬ qc7wq$.^K^V˽W|A_쨼d/a;'3u}Plk q%4z|σX~xhEwq]Xy*ل3FN@ftrz 48 -rgռ(̂9dH<X3ÑM.!(^8Mgב#|!q)ſtQ$"mH3H,Lq I+1=HYКE}w|+]g'~EPcZZܩŠ") P"NAv3XQ6_Ue -:+WZe}FxW\F -:Dgd-1فggߩ#"Ǒ4 9K!hr+뫥1Vx<_:F]Pjl?N<kJp&g-/N!?;#AjW$Iփ>%,J˥Ubn[h)[-Lʹ9,#[.jl5I¬Gk\cfDrT_KK c9xoL$ˍZ:*HLٵOZ*[6nxڍ󃷕L$@aF FO(/ӪV [ ?xa6,?6Hjt�>ktc2"%Ϣxoc<M5UhodJ-:!F%&Mf)R+)&-Ao 9� 6w^xz/T;.o&f2dNcWiwl)FB:C#Q:=t;%Ey{ta5ֱ _#茶w!,_bX~aU*kwr0?5?]0_9_OEK>r|g>WA}ފޭMlSm#k}ssY:j5:8$*h\[vET׫sIY.=_߯;uiO IB;M@! ;LYĎ50QMK'8ov?xi<y/oﮮӚd9O>+31ˋkP݋^[ oiN^OBX d^&id Ro[ ,9EⶋK&$͟~~7<;b͟u<"omC}?߮ۺՇ^?'ۻӫgwW7?l>3vy<ӳWw7OՋ˧_]>Yk= WO\)"(v�BE iHF5ٴ8e zrR -/qk4`4I[3y7nz X-qaˀ< cVaV6Ϥmך3[ET3H6vچl`8Y_ pƚ-뛶<'ȡ` JFnqqu&Y<l1b*U#ўG8 ێ> jctfJdLn Uͫn@_vThsIbȂ@Tsx3tih #Cβ|ŵk,B}jk 5WmmMm!\D2ڻ-0HPZD"yH YfVcvRP|ܰOlDfV<E`ZsU`q>U[zVIf4(i24is6+k ZS=X ~ Xpv�K�D뭓6 1if8fH&8.s!J`wظ,˨-&9q8n 6Yͱ  -HG).Xv~M2+C ߊj #`h==C79 ݃-q7<xRfXӆ4"nnl3iN+ F,N,D{A;D -A0h%5zHq׫ ֠ab!a aQ܍xI#[y9Jäo#=wĉ=n;5y]El%HD8,Z4j|_z ir/=d܏B� x,Ԅ 5m9cިuך1(< 8&.7-WE>̓I\ wbD)S3`AHc.*KڌԿT_8 ZRFZ;#7B>w`7~xzp%y*!|uS4+W=uْ!FV7<;c"mp@z[- 2<Mh.N<arP40@6m>#@xu'Gd#58`A}Z 3fvT\Qb} 񵉟j!ntSz#b@&пQ2M2Чے1Ӹ+<X ?@ bEy6f8ӮDCf6gPnFS<]GqbV7lfX!8N^B2ࡆ . ہv|)rO<LiSvdYlP,”ks]FӼR -+xdvHkK_PJ\?2T-9r?灄"v%+/Ʋ8C: -4mx0۴5O4 RAz0x2BkU6Xby;fsKEXa!!=I'�~d\(YboGӴg 2F%(k'ml;Ě@VDž!'IO&}q88 0�AđViE!2^:M.L�h5|H1c':#?l%MUlPyKG -(GggHǑ}u\*/s9d|18B'FcϟILssq[.<O=J5XMH[w-gw̥.v'Gs*hP#z]â1AEpkq=G!BvkgwSS&3li)LX}RF.}J)~sP;C矑BR9<u wƤxST(=ۀIp -DC0#ũ vZ4x"QJ_FSp$Zܤ(,] /b8԰ ~. i,]9ir!x FQ>&*d)Q b T0DQED\낤PG -x0q=ꬰ+%4(_q(]o8 _F �QPX5.;"pG%bS'l i|`t.bdp P.QJP |tRr^JyndZmQ䷊S땄�TKj7E,u(5v�cwY㉎zXX=8qhb 5>a z@t Hf>,Vw  + LV[KI̍qɦ' -\Nscโ#l v55ql<8H'N M7NCz# =N8r_Y%WK!Dsb100Ng pZtCN+J`? T˂ S_lTbpkh̉`.t'b%lHt°kÅ -nSnHzlЬUƩƶ4 @@]5FP%n qm1 < -JW KnTk $)Xbᣕ<R$ -%뾩)Z2[r zSD+}JTW/>0OՔw uG~z.zUc} X7w{W2m4Ęv Q\P,ӊe>(79z)#Bgځ G -?FVҦGFr_B٦> ( k U` ,BEX)+0yMo3_4oA{J28sW|X+lcvҸ {U Su ۞08UI &jmb٤ V<r 2\?S\PAI<AWF Q\Z/Fْ4ْG -HIR@ҒG6D c+p1zXH͌0a4-v;zu`=-t$uPnֹI(7Ulq4d,&8J ]ZTgxB6q![Q(l0yڥ&89s h q^ıO NQby#KƔbyS{Ŏ^nSn -"sz)fd%Su8::,T^)-u {9:9:5͡zu {Wd];٬;0u_0nG$l8qd yisu'\1Ag(8wS -SQ!vPf֭>7_m}+_SJ]?2Zn?|hsJR7>?c)znt=XfMD{?Px<P|t2(~]7.�\xce} \юM%kxrC;L30F Gd$R0Dϯ%Xy7㘜~ڌib%9˜eF Z2 "]e8 -P@G+Ծ-Ft܎a �& RQ7դ:P⨚Y).bhLC<fFW ',_O@ddu4g2#I6Mk`(%Қ] /`*ZB|~AL(D9!RVݖH Uԏuۙg㣑f:�uP78=WEjhDù+>|`Ml)oCJ Lb0U;B -<NrpSAjD7G:�OG2aX0am#JHdH 7lJf;A䎃L I:-t>h"_*A6 |A-nވ"a%i@⃗(#&A:W7{J2TogF E,i}/e;OK/n.Zp T"IfB>@/+Θ}ձ+wTdVF|L:wb|WcF2 -&Mh~{'N.1xv:n9EF3unޭSx�C7޿ EJle�) 8@^'="TZO6?MS©wKhIK -.4M܆ZxjM,>CCAPGh;?QZHXYg3\0J#F#sJb0XBMSB2HqJ;TÎ^(w) Hq:vrٕX8]HKW7P{Hd< 87Q R +RQ;]_{|X}(:Jzau`@T53ֽZԕM\kص+jqz2]׺j|h΃è4驳O=\m\ I_;0{t8 ؎VT`81S38utw$ (ʳG%Y>cS|D&V`"%N/]ͧV30%$[3)SW\q<bG<0t{L2N$Lũȍ)gUxo�!MeS&jAgW*cbXDQ/M_LEf0 co)}Fp&bc& 8BDRZTrBeJ1prv}cRSm1 hv9aԻX^ -RG5#cҽݎfׁ呒GZQv)[<VdYFd6t(YB+.vJ.K/8LrrS{ySpkL\8#^c1_{cS }J{^ZȮag]OKů!kGbPdl܆TjzN ;oP])Ѯ5cZwHn:⑯5 -Xfk~'ld.c]Зh>fݕ_LAǴFLŪ -╟>X_yЮG�@+xbټ9d7X5=R D/ <14Ӛ yJqE\Lϋ7Ʃh#v dɅg3Cgz$>. ai$! [B~ؙ; c?8sr@vT8vn[b=HMG,}Vm/U`FVrˁz_HeTV̦]gb*LkjծO_Q7]g?cu7[#M_"QR/=e/×#ȞMݱQ9HH)ؗ(NTG -"Jh%,=;4rQhɴy -d'{ʼnk1.}=v}yh> -S3`a^!#(%ln+~VOmjE T¾Q$nG|Nrp)9#4x7!CgX ibiL+Y?CJ8H-\#w'FBa(ȇL7jz(cHvcy@ng-IQ\( -% `K;% -xA O5a4A! 6E@qKԇ hN.QE -Ql#!MJP|Gl4ј0,t c@F[ %`QI(z%A EFj:J?r޻W!k߱bU\G#pH 9Qθ<ЇPa$1a!Z\]1RxmV賎EC]3E {Pn*m6㏼g$c" %Lm -e"?e{Ϳea@R+ 3/KB6tt�P l�Hɸ}I؉kZMS9J}}:^PUm2 -9j{  }v ^!Y@/d^b@0Y u."S\Zt�  t$| -Z+hX4YNn�}IgR(Pc�h$xpvd!#Q-Ø%Mgk@fިŜJ RRrEikRO"AO]LAYbU1@&27%v%{6~"D@n"tWD9iq03NbD8WxcO5BEh@l -2b,蘴ztfq#!zD9i,׉KS3S2J2\KtHV5ߔ>K} B: Oia3PoAw&}&fhi@hYEz Ghlr:RDO8vBi!A% -yT09=#H3ĖG ]MV$Ӓvk$R*c. A :փMj3g( *#fkJi\XXY3G@pLJr&>|O >qT&=P~,Mb4ѷBH+X]1p#_Ot`hĴ9Y,pmL8Y+F% ߯U.ޭ =o> U2i'PToVaqoZwS"5~WO7]_ʝ+:3ȄƍY!_)6%7 ]躠Z^[$Xxz[ ) R\W ĺ)J_Gb!jhwv)tI~T[ N_O7]_jVA`G2Z7f 7piƻhj)SJR(l]F9$@ZkC"G?zٵ.t%oIMu(35d, C'-}C;͗ж<8DY.9aSLA^h/[Qp1Xޱ-M+t"u.@m<V:$Q<ryH:MtͬvMB[wfDU^M ۬t&sIij<tuCtṪ0F;D'~!bt 'nUl@>JL:@d|7Ё0ܶ/,üpIQ#q|.-tҕh?șMd=ŞT<y#Ǻih s&Zɻ+%Dwb&z#RE~lhw ZҊdwQ*nZ"oN1KO #cgS?/H#yًKB ?ZyMŪf֭E  GiD򋬖A~q5͋VME -֊Cz7(W| Z}*u F峡�C WK-qu%UXyT[BS^t;Ɛf׾-Q42X㦷_ﻖw̬q4@ӥj+ PJEKyT[ -Қ&RV߁]@`E}ISXZu}xh*>`$ņpS<BAp@\2<z1wnp\մ^șӋBg4E6"C׽q9rK.;F3sj߶c8 JI_ҎAWQ7]gpAJpF,DMĖ( H-J#1S:7puTT ='fNb 7h` `GLx"u%<![:ӤeVJL*F)& ul6aD#S;KQ7J.I[ <FI #掫UBXJK0ۗM8ړ 50x /9bNA וHf5jD6sRMwu=Glj.Q^j䂟U9&&>}`z;jhe)W]^Ѣ1MbC 'NТ߉s,^',Zފzު5VmgP=a,iJ5?�]A2{hl1Mode.pDMS ]1Hg̲:`4Oh FCQ85B`Sa{3rGז H<kѮp#0*VѓaqBE/1*Ǵ.>)ZjVi VҕXX7:]g mݸヴN#? c}婑g$6(][0 L I_g4T47;==_OYgrIFܶ'#i?:vE +:l[Ǯ:î\ױ+: C@,:huC:4bu ` bцcXd+ʫ]A7~`X$X! -v=`Xa .+:"c vtpȀh -E+\ȨD/&2:DhBMtDp;갏jAס&2a0 v-:D KJK/RAw0;\ ]+!`}k +3XDun0VÃ3(p+w":tD804ԕXkX)}軐"(;Kndvcf>ʂ2 - C_6C2`iSIo~`$(OZ)vdD�bAn֮+|l \xOc47Ir&q<*}xpf*rˏ. \$6ڜ(QW(Fb0Zn:16#}q\DT\xC̮@1;vFAz(H=n#mv9ϲ+ɲc؈YۼbV)ƥٮ/MQ~##pV]A1&K]1z8PՋ.#ꡕ]6$!~XY7YDH&np}yU^#8B+t/|SbbDe,�$8vD>ԖHԌM_O;}WcFžy-l0o4ńb5j,^M܂A}JR` Ct (0ȔYEĭrJ?Q+6{n Ɨ]G|jm!2MkMuW]C )Xr]%Vۀ,^G&‹{ ` /C[tD\o -t3SQYf,ƾ']擊!+t:]Čr06_[Cc_`l9'g@\! CLFE1b0~ -.*E4L馃 zZZɨsH$o 8NĮ}KJQS,оd! FǼg_Дx<HtuiIͺF.*F+QH&pvㆪ1j#EÅ y�bL},7 Kb0YZi3R lEn ֞wn[>>ߎPߢfPex7\ 1s*28Ţr)q ŸC^iޥښL]+$TuK%eMvrC%"=:P䈺O!DHpT xbTVP\`"ؤ(ؚa|x1mr30YS3!g4Pܘ"Ξ7Mc0E7%8׌AWQ7]gYkv7CdHN@9hȞ/D#i$ck3-vV aH+I7C?vӚ7!yt|`[xj+F8QiaC^vA,<1v:t|\s1"W$_.su2U\zq~+7Fx{Qk+In@hV6 r$&>t%o(=dARHN-d5}d?.#Y` mݼ\bh3I<ƽ b!43 Q8' ]4ⴶ͸jl^8']JKM1OGP�ƺo͐4S ←-Qrl:D}\H"Mt7MehCb)E)8+#m f><%hE ܫUP;ȖkJ4SlbX8 vc]v%\ _ij<n+J#Ȅ}B%rGo@HQAK ̆aT@V* Hֱ_s-piwk DP9Ai RYvA.U@5 mqCJU3cit�Ҭ#]PV=޷# h<#^= (1=ܙ(t匾Hu.9Sn@q[@90a/XUsšT*@vkc[3 -V:MFn ٜ�aiqSkx 9\lHב67Sඡ9c kmkHegh::~tFNqS #xd] H62z25c]xLb[ ޘܿK{*<U]XH':T0N*$m."105`," &/Me1/5zt/5AkAWҁ˦VVѺ"s4,C8h\D@!YO-琜{-πʼn1@my_E‰XFZQZ<1U-%q%#Ve[7uwU9+*Zъ߷3gAJ͹ $Pf5o |U9CћǙft5綘RɟC"a8fDV^ðrAWuĪۂC:\ԽuXMm<M3Gn^#wC*- %-@kh`x-t]LsnI PS5bT\D[ٱ!Ga82^D -4N(Ox ]yA4T2 BinA_4VZc71m0Sl!@ox^D)5_G_guXɥ@rv U9wtTIHW5R\(DSב9 6}wR(EG.&`H0\!3]{%c䶈,olP?>m3U~G;b7'_Օݛ[//.c~{?_Zpˋ+^|ꅕ)Ҭ|]WnI=7XG>/]Bu<dž˿]]|UV_3<=~^O]]Gm~OWO⿢vWQ4N-%WN “$ϟ|-f~7<;n6ϟH-_Ea)mp[߮uK箷p;_ gݞ}ĝ/_-qĮcM<U¾}$ T0"ж$c]@v~զcxxr.sR7Z饄 <11>!nD0z" !fG0 VlvRr%DsޓBy^>Df]K%YM=8"x3j2F)WD&*ej#Ī<gktV-ZB8)2_f1Vg(ju'wva%4Q&c "`>DxH'i0(2rc㐁Fal3xgaa%{�/})땨E\x G0Ć,cPˆ$5A-aŗ0=t̕9B./5}"2chv6T/�%Uc'_ Hj]NѻVt|ny~XPҽIN'uD xwi>* - W:Y˨?!E4hTGx&/wZ08b=ruM A$MqD$(Zl6%"9j+̃G8I 5_;+F)ƐR)6zK93^h eEC.Fw5GN`%x{ K_P!TU=UѾ& y|P#+VSa|cv`&Guu6<oa`#. -"-".Dž/8q p0rGnđDSԃ1Z*)@aM4 cM9{G3'J1/\e ,f\/jPD. %hAD~,k%%@,!Ax9>q0H j&%4-V:]6Iiڏ4M`oS 'P*F/Cy[#<N}*;c)҇#I|1yZvbh@DMVr@֧/W<Q 2d!R݁ߒ! VM`4莫IAW)l_W1bĐ} tSɎ0܎|x%<EcEmj% j14+c(&x=28½RsqD+-bʢIrEߐ8 -l1p+{L܁tMrb ӭY(X4X͗ TZ'w^gŒ<n%3rK,UpҌ#�j?GuMT %C$"ʀWr 2 -fE]FwmP@wmFDD&.J%ށ17 :_52W`0F@#3Tj \ &yNV2Cu'~-&U2 N.Opfs-#8VVU g!Л1F| .xgHM!^t+ 1Sw`fq(`Ii$~=AiI l34gK $̍P^}j(` -ԧ`E5(o 2Fܶ C/$v$C2xtgx+ -28"@ p� 8x <ɮV0hSzgɽ-=O<G}04%.nXT 'q@m; &fD_ Ѯf<,Vq8$^&$pGBi*h3^ZhZ t/:F-cDfKdC$\#!iHtQEáICFG[I0�κ{#OE[!\%=8L)4P -G'7*O.{rܞsZȂ:DF8W2}3|emغ 1Q(c 2x!swV<C'O|QvqTa:U -\r rPC$SO|lm-ȑKd�$\Ov:7GΪ(€-w2xK.4n\hqv $ ީFQK`Nz8\uRzHf{TA9$PH;)EtG@5#xs&(bMx1šz;xkNǰ%pitY=0vQ\ A5O)ZֱѠ9쐊ތ^}cP!?H`GQ+/Ez@щR*wR0Frņq]0FILFPb9﯉b+j, "+= 9ܭx#|L* ڍحakbic1EC`g5z8~9ez@,+v`ύF޶̬ -jAj#r+Y) !Vz-ɐaxx" ZI_=|;rq0?$s>!_O¥= .E�!Q,xa GX50dD"a#GPn!>74c~bäñiPJAAZ+ɑOvqģv U`Fr%/eK_h8rEq!Nkh NrYxa73-`{Jb72)zR|*h1s'AEﳢ F< :pJL?V`:.̵H>~M٘!)+bDl6E &pZ~&'VˈǠ"kE9/ -mer8h9#\f7+ď ou@az;^qOb.ck-�Aad -To2=K;7E*DOF90`2lWgihFV֭ U๮ӬbƤHGI34x\/17SfN8f�W&'!mA� :IX�T 38fmZLw C` Gj4J=o -z}o@.XrV41wҨ[I~w>`uGZ#!sO>f}zp|( 7PFX Ђ P10PJɽ�`ur^91 ?fIG.M@J9Q HfDDГw>c�.5z%|%̦ͥ>Щ}Tjri桇=* :ZZl7-5l#3xr"n#u"�gQcqݍ ׂaDb' 6Ahj5QR*1+)z^MD~YY|(i5z=t:dUxeUrFUO}>,.iS1^G\4a tb$E ]A0DbM 3f+x;O<ʝR\s; - -G2sɼJ'- '%^^.p%RtVa-~RxM\e@`(𲧢'BT HgPR8rhyL%K%ZNW -0Y#wܧwϢ{2!CDl]f\;޻ o -)gu=Xb 2.k FKEݞP 1Aގ}s7qݼ<g5* R(E 1a@x>\M=xq#*-2X1bK"R3wVUWO򚨝=Urc:Wo=Ƿd?%j3qpdCSe&p!qd 1 JjT0( N?9ERKV5~B2xɄQn1 XIc0R#<I"wQ .D- -j7q!]1Q4Gh:l"cR~ʛH)Ab#V&Qx0 -? -)pK0jXP/kT/zO^.$y_yԀkφC3hyM kȨʪP}*2ENҋ~B[ɖdj=(r:gv</t!WڐByhνИ,ڦ FY.qX!wʀm޳(ܽQ(<<Ճ/?@�iǼv> -+~[{|"K y2Žq)G&ST 54+"͙f"c:1 j55N+S#7!JuI2F󑞃eQmo o2mJt)^3- S iRdу8ߢ#WEvc2U\gļD|| 8{nc!%g{2ȃ2d.E:}"0ݽlzGUT4#9Acv -ىT}F{P:c#N -MBEQ -t;B':f qI'0sڶ$g0? a;cKpEj{ntn.~|]ҩ, -~ӝmBrQ{1H )e-sbֱ}UqN -V[92L%<\_7hQf`Av@s/#\aq Bl XzR0pl�&qDiCWq8!p hބ籇3#@fIQѥwe𨝗 sb|$}yˤ2CGzyr(cƉJp6t)D<1zHȵF4 q,_ eākPq0&ctvJho3=Eq\1"gN$[@S- p<$ e3G,8鯔/ӞBb|q)(72/#$cħn#ЏJ ~?x>Ι=vc$UDBQI>w6~DԧǶnGƵuVၺbizbK|[Pz}#;UtI$4zأkC�y=tSJsPg1o8�/)s:x"I*)~!~r r̆\|ŀkd`)@HU�cN1̛CV�\XAɥE5Gqu s{'wr'[?!IC,Qj6kC=6Xzj씠:3w0�=%.tLj>TОhs1`Z0H1)>3!!N%4 -'sh0׉vДDj/x}K_o"@M􍖤 -6<\ XeFV 6<;hx5J Bq@=iq}ZÐRǪ>l.j3 C<àN~&$p*ok*;51 S4S:lG+u 33yj„~HN4'@ʾ  %ؘܰf/c0nk7VG3suai1W://ʞtY[+ΥR4b'[ F[1D]</Dzߎ6X9Dk{dɯbc*L,`6fGm,L؝!CjnF,,�o" pJ릵% gCKBbÅx9" ,gG5B7LHŖ}Zt;5y5qsC<?"jZg}W6 6rS~$RLD:f*N@BCS;Y7;WЬX~U o[&urc#/b'HW#LSp[чqzvC$s�^'sK^9ݭ+d~4_E(uxZs)"*ԓ<nO`~^ftouq;c8ԁ 0NJ8ң�E%IS03Rm -٭S]"K͹0p.W~}qW: tBtt\6$i`ψ3X.uSUj5eww`N+."׈ڱ{L҅x .(O&OdW2cDؘ<ʜ[u("ƅYjщr3<;skP̬=w}&x#Nm>'7NR^E<YO@cNpc~N1~:HZq[U+vE wHrVIm` &1 .tecCn>sĉ <ꇈ`4'=PsO'{@ |\.{{ف5kjLo,~HbwH6l֒X 6]m-gPhLkiv*q'Abݨ0&1f>C!t(0}W!]P5@dYY]`/Tm vU4p;We2$fbh{SYW.8h39#wޞFM cch)uw85\5ouR7|a6 jr?##;Dw)tZ1tnu8$JR`q |rDW iL3()j\9;suVH^D_cpp<AKO{PyO0KBU 6O' ݟ,{(ˤ Tx$Thْ7%lsFΊQs.)gC-E+pXETS"O3@;Dc.z5>E:OfC9𰖥mٱ0"Z G4`Npzk!b5OrQf5> fCTu7`dQAE5GaUDZy_7zaSBQ}#< ͭ!Bі3;FF-5Ew"7s=}278jf}B ..m1Ɛ|(:pTDp8bz8n1C#RS*bLq{TR8T&l1J *97 2}XS<؊^Ӧ?DU—q)x_UU -ߨrk>k|߲:aujn06x *<ZX@lTŇA|}~%f:h:$URV͞9|ܥ=$z}?'Gr fdqAmNWK/+7za[atXlMQ9HڿcGW!0BE;%VbNH|-X_G:+'[#֏}?ȺW=IVxˈݳ'<xEX1k #vF=02*Uy){4T!`a,NQ'A`l$<T,:߽U(d+"Ɒ qI3H:M஫ "K-z`b`- P}0tE(jq䗾NB Hh_٪J*?rd/[bÜ\W -B[QւVuГ6ب ph.pi Z>6\q uu(]SA"s}9tEs戉yshfnvoZ 弻H>U@u'GAl@AQEv+~'Q8f0|%p xYCZ# '-ymsP]c X7*Q; -VL\ႽV bJGTB&@httbyq^F7zqJrD5oI -ǰ;z:ތn2M؞y{PHPӆlrx<+/vL(ל2owy_.AҲTzdWꐬ'qP4k2LSi2MNubDW0(88 -x FZ |'T afr.U"?|VǍx�<Vƴe4i0)3qV|<jB1HrJD`V9wWjbaK+h{73b`6+,VKx,s2 k.aP. -BF gp y(Iy pI2HЩ W\߄"02綑,W2_|!ay5ljh]%2$;:x{³*hqORTkV$+;H9䊚\=P<RQ +aXSRxG͉a<֔gi .m3{s+ĢnY=uW.WaqĔ7}!ƑVаKOeVܻv,r+oY~hj.c` PsXR]oQguVgzpjJZi *LP-j4l_"  1(L -0\t:/H&SQf1y1VPU?kj{λ-F<:H8-ZY.ޢ7ė-kƑVq1zfSG|wZ,W6uzjE^%GMVȈɖZkmJ5aBt2T ! a$uD([NZsK(~ -CyG̻󎷪3@9z&Zׯx Qt#]\[uRG̶%WWǛ3o, ^č8'GW8q̉DHl~ \tFx%LQz"64h0GAMZ~҆{ßJK * ›VoZRVŻ.M!"u "&S;#r59A?#Sk\z&\ 9'-J-?5yKxS=<q -u9M Т7 rfI! ;QPЬn0zIc;ìYy8p˳j;F]%JB>%&):.V8 :w͎ͭ*X 1nN D;Z<?XM|Ч`Ռ_,;H,NzEZQxXwQ¹i -&GCEHƽ3dfAV@4lgc�+4=p~Füp_w&sL_|f(Z|Jy <Z"a2Ϯ懬a}\Jϳy7cD&mpi{+*^ɲ/4/篿?۫d -:yd}/s{[;ccƏun*Vw 2VYY!=jXgLKM%߫ޑS&㙖Un^hؕR{kpP)",wSvV Z_ -Tgєp@8ҁ,!z5{z0c. -ߎ[G0[Ff{JYm{:s$(y>Y,JS& J>x2m} Rn %QN Lh%#1NquqD.6aUF+T@6$ .("2GuDsn -hP[rIh)He3ЏoS}5\Ee4X?csTwH nJ6(m8`ؔiPA| ]S|?yX#P;P Ĭwޟ3kp&b=wywcmjCX"Hk4n^]<1pވ{ hTwёVEpI 8qҬgƊzeޟ)ݗXZK`OF01=q0)a(F)ks::.aax"hBkm1 <C# &o83@hc>`N9dxDF $s\|{Gϕ ֱ04(˺w'$A}."}Yw1J~4s|E%VW̰eʱ3R@P$dTE3>;}]ae4Gޱ޳(3*'rK=(j:w"<dQ9"}#p͸neCFA=rx'eYyi@NA&}xZQL%kzӗπȈ -72{|J'/n/^ls4#hDNɓt9<er8Nuz#Kw}h~=@,$X׽7ب<e&4ϥ|Ay'@aU7Q_Ga:2׊IsOP`#zz14h FM(?nX"{vmޖedW.en_ᴼl5zyrJ(IDr5EDS%Օ,rb[께Vmy~%cDגr+.Sqz9ǡ7l&G*Ȳ:9Ҟ/t8c`yM82gF(1έ Z6՚s#kܞSPR$9=ɛWS,AIa|Pf.+ċsA8d#:_H|bxݽ~d*EKp%TR F}8;3+jvמ,O< 5+xE;[&Z)r,Ǜ˦I8O�˧zݶVӖcNG,-u툲('t}J;orE}#f&T(Ku՟1XaAchFl̂vC&KTX[FJ]$+,G/ i$*Zr}EqgM8I@Tp0Xul:QdNj$<8=@[iJ zb>e9,Ȗ?DZX:e,O+YBJWƜ(!ˆ|'ߟAZiMY[k3#pXDZU٣ qs"eDqÅcΓPJ~Aݨd-j(@G`:wT;f -(֨XBiO3ݥtoB{Q].[5CS"k<9=Nk5ů ,h+my œ& eM(C*unw>1J/ĘԩȎ06h:rT5GU%;KhAi0+uG%7m, -7#V ݪ-}~ 5Rr=cAdWX]fuB<ȂA[yʮmº; ᬄlۧ ^WOKgZz]D 7pl m0,{h9#W GA3*TiG RYWzx dL3 =O5Qu>mL)rZ8kLAYm0;Czcq {rZ̟{4WU Sv#T/ -8"a.L<$q>+,+b(~C+CǏֵLt(и`(:RgҬX6jX$h؇+!jXA='({BWR 0 -Vw%oL1Ą&4\O.pҜC!,ZqY@Rku1;^Fd&_yh -}f,{'itXcI;T*5a84Yl%m 7Cx۞cc3u7R+=@@!#(I5x}(Һ%!_ FDVnݜ�ds-ƁWJAHSE)@:/.? (yhr:6ʑT"5 ?Dk %gF鞅dY<șTKZ1ڈ=#c ȭ9dRTsn%v-̺  -~dm)GU!L#TQ䕘VmsVV'ޤE2tjU4EYww C*nI -ABaWt^foVC/|g %״,GbjhiۉO~m7Gt,<wtrEa^kIY@7s$/['y5>+HG v[{XRTWIB1V|Xr<bϙ@%~!Eyy'?60:$Vz.H#4w2T!K65N{5vzD?%6rL) sԭt-tjҭ -7Ңb>x*( n:fE55oŤ7^;҈W8*14 DHݿ-u= C^ -݈ju1ZyNW9T=+Ww1h,qv[R ! JkyɽgÅW Ѐr/:}X!Zd{J\ af>湩>kp{GBa%*sI9g<hlS&"}W VM>alj`S?yeUѳ|#>3(lvΪ{'zu9"y]~I#׫ $K1e!6`Z^|ŖElӆbp}ɡӳt g4 "ke8ɪ?F&|ZDV{x}Wd\!eRp Y(?bo{%;aa,J:FH``\yfkڇaX,wfVSUw.7>.��O/y}b Cuߺ>UgXIChrSDIiz粅1{]aFxs⏟z"DSbuS,|BXtlZ,~"[J|CWi~F=xE +=mExc34ƍSt24l|1@O3'ɬ5< -b5=Z @Ќ$%-ĩgN;.pDQ]|vօ ȱ: #΢ .gÈruBCO% ֵr7leZHf/ɮPƈQB/.EYb[uiapIԴZ)f(L4v/hCÙzl+vi\譕Srl=rY5Pуu׊N$IP8oAvDs ~- *Yr t1tf;:;:ݰVfo4oay?Fyq\q%!rY[`eg&7=J2m;JeaDCqy`xjmS=Y Ad;"H9 -s%TGnMu:VlH9`)m J6fL8ʞq.r2E}=ܛu7p}>zFqnGgF̵Zx.2Eu&]Ol\ 2?#! W]0+`Zu.~b)4x-gzUj%-&"x$v!v .`r Ȫqɪc9x& Z]s:|�z,Fm֕tk:luSPr8ޖVұּZ.)..R-m:EYoGu(K-LE HY9y+|th Vx_E6Vȏ_kc,pW)I`aflRk>_e,Srl f"n}�a.#B^~9|,zbվ /4\U'[2l^|FB֟>/~Vʭ4mE?Vv2A*1U §"jT bЇ2@~S>Kz~XGo>@^e29Q6`f ȅPi�Hpno -Fk,.6QV5f08KP. Bzm.i-(C,qgu}N cChKmݍmݍ}ńp[F nrv[AF_.S.rQT ٲg3:G #-FV㶵IDcZ}Ayu]MUS1vܽ;B7%GWbaÎs՟/$Hq.ZR<!#ռb{NDSc8r5-zv=c*nHfܰbKFjX9�S{vZ$7x.1^?B= ޯLAޓ -m9 2# vh%KgiHhkbq,>4MEg2:޺I[:XhP}/c Zdm;AȢ/RAg3s4P\}o`׿_Ϳ?ǿ?_???翞ׯwsq91w(@F2DMvvH+e6x �fgsm{�SV<dY쌄2 5=5#`_N V~}  J`#WDFג嚿mۛHcqdoDdmEJ=),dLxtr Bw^kX�H%s\-7/EVU;Ni̓ڽsň [֊Se7A|8 N?G�'@Kg{t�H^a?s -(-ӑ IÞ:KäR%|A;|[ C yXX9U:!T}U #$iܙAw8Z41}x=o[dBIGKT!so}p_d=ũY=5/8`b x} wDAw>ml>=#JZ^0z RL.+>mZ7sq5f w4j�<;z -oxtx,{h(0ߩ?@"s\J ҙ�~c3 -q;b) -oƝ\-.=.B' wIY tm+j!!NyݣZ,j|-Ld#ʚTS#ꦺ]<BuSEuAs{CcӂA9wWx"GkTƩpU zv0Bp^4wokC];5<?#0qXQq܄ ؍e7sMcXض"C^#9NZGۛk<uG{q)s+aqW'ƨ{2= Ҋ43񾛕^�߬pDz] 7|f�W8usn:zxh{C<vR];\UmB`vɊ{l 2mPU[n -ߴr m<!Jzɱxn3~of-�r|;^Jp3NXkY*n7L\S\?i%1/◅+zUp3 <nV\)T0d]7Oj*K]=SBxQ[L)fF$k- ⍍k\-PP vZ@nΥFm KIq7275{go#!R3SW0m,˜oA-B%1z/6r3 ݎlr=X٬Zd&cΏ�b0V1ht-Yk^![1èR\k֟ X@W#rf5mfnTT gԨTsN D3x?0Ԡ+Ibiwk : oԇ6M97lZh}1-}KFJAҼ)sۋ 9ʃT718̷W�ATF#uG~c{C Սyn1o3rƀ)1q`r|D,ͫx\7J`3ZHz&3ol2^+XOKJhXċ4I3ETS�q#I*/>cdLplqLG" pU]+ѐϵ->#o1~.w-_3cp-eŇrnZa'Uq)K>\tdŇ|)?J!6T> ۦcf DhaE7RP -:JC耙Bxka|b^cn@0<\`>%, 5`F#6/֛,  e`cZ𿉾=8P}|ae!o][i{Q&:I{yo*/JƅN^p}涹o.bѻy5on^7hB7 h^Kxw.+?Dpǭ2x;D~~` {D2u;sZIڕgd.:Hv?عI0ky7D%ldoOnB=e[]/inܜēHmrϟ D22d[zH%\dD7E~~\"i`O`ÈX3- 생kB ; i"o^+%ў)0GWP@&ϙ-+2utcc0\a߬\^^ꓙ 낎WM 37W|3s24_\ߒ-y\w7Jr 5KX8oL|)&|KN\ ?H@)Ohn<myQ*#4WپYGqEb9GV.7HY~oV._�rs mݓ?rӹ\HpԿY!#W# eQ@o (ݟƑQUN;/T.=R<)7+ߕ;K6AsNQlk|0r5˟&oXS ',ג~P8׍~wMƝ Kko7->\?Co jv}nb0i)+b%^hd#[E~d?~.7v׎֚o`b֖Ʒf#QP ;Ũޡ,V�zoV-H -%]cRK}iymNDř@+;w63pb_ޘ khOlZA$ ֹʑRt]ƘtJQxК5G֐@ Ȧ+ @kixh#�HlmdG JcR8)}O)aлFj % ^A˥Ҁ<)쐚?( AZ)1F,6Qz}hmő-}5(j25VHC=B_x(ZZ%vYyhm`AaQ6FE-Ekiκ!X(Zo, ٛItq̕'6U4U^TZʓu'yEMF ,W聧tA³l:mZŻ6ILO(-/XeJkCS{R巡6te6?,@%G=MRsEӢኹ8:-:5ݖMM4YQtim`nS,[g+ySefڛRsIe 3»)[:nJ-qʒZ5ל۲!s7V !I*szzBj-yŴ6)feՋ_Z˹!QO{JJ#֓f~%ϐڨMQIԲͮ+{ݔ(=Vq3& =\-^ue_Z*o\- uܵ߸Z{$6G7ZR)8$bwͩ׈-(\ߜZW(khZez|aT5l)<ZPO}�j҂럀Zjl㚄O@m25~ V7҅jM}F"/i�)xPk X* #V=�aA Բ ̹qjc53|ZٽZ^r\eii:Jw>j@�3m@ LP ݊'#R4Nl7ցLJU0S7VR 2AHPPz:B miY^<B"?U@^Lީ "a[ԃwtl;./낿wPqݯQctմ|׶/+R¿,lݝ2 ~guGb0)z_l7uM#0D4"<JcfUMx#[%s ,/@䃗 ʋ<7|1s\%M|A֪i3=(_8#J MV> T1t,J#SƧ6?plTx -,iu\&?JEt;j -~j{J[;59E1̢5g'b6buKӠ~'j6͹@ZӔaI 5\4Ҿ ~b -G{kuC)e_ V+N+*1;N4WMϹѱx(/2|PʍFs ʰ@R8~mJpr~oxRB%~^XbͭI۫PӞOZc/P!uul֧[;so;S"vTkS7w`@"\P̙T2sڨO6@t܄Ot;'!j7SwQ{2FIkiO (["vnkn4\w撩/P{r\˥B%a]袐NhOb=Y?ўFcǨݲO{9Iueq&|=m5Cj}=#EuHQ}[ OJH:?؞Ʋs5�~s=5,!q\l z"=KJnWhFz+/I-.z6]T Glys8d73KdkﴶzDyἹPLwsFy4$Dy~-Ӈ԰[)MR_�_q"yjK[Öi+k5 L"_"63;iJ �y,|˙6ɓ#/'e%(O|=0XO'"`/.t1`G!'ӨrqXW/ZWaM봡'3^,S< J^oX'NikOX)huS;  _v_@m$@ѢuRjA:-oQ͉F6#Qi9яqTnov,7m?q!hqؚ4Fjvdg$Mш�nonfcCql+ex2ܔL51 1̶tW\Vw@:*zm*7Rw`;,K Z*Y%7\=?2PJv1o\%e{P*�hEO.&%Q⟄OV6te2$/M3&Q4yQ(>D :Fg㲠uVfDRNU ,t!A{y )g}y?zߛșhz (zjQ{ؽ6D;},#a则@>NpRF]GʵyԋPyqq 7Xxa~2Z)Wf1^=7FS%wn&/b0o'pC_Eڜū+O։�e3RxjMr_Wu%mb#8oF١\.nhVH&;:}~ Z=YU 2>li8gqV-䢅$w�<z2#e_A { ];nĪ-4N; 6{kWߘx(LX؆|D݅|k*RHٟEGtgv9dw2A:40M'ӚHJ\}SR�:z3Jo ;;dQ8xaOL4O!3xODCc1̝`&z r>Pnr -V?ƨHn"#5>/fvl:Gf3}3yc&@&~ &BQML 0&&8 #IL4 M&țHiA|9-L,݉Q<D@^ȹ}Ip%ڬTDKΛh)Y͜XDw9=&RN$Ҹ|mN3]TC$oo^ܜDNFpZ84S|N)z&m9378QJJjDgPh,c*;Zw]\ &rpH !-4 o"i5d�EzH4BP[.HH^!!bB6LmF(zr=ɉHdn(&ـ~D 9':a -Go9/ /7 UB.|R^_H;m,|@\ d}"(r> jm75MEX9ۜn" )cQG0E S=`:Ŋ?)eF(zR?FPLqAF(b yom�'%I!YdnpY 468,K~-HkqmpbҮ` NAmˌ&Xmn'./|WO'zQOr"2!g:x)DΓA>F(~5<X߭ iDG:O% *45{!w�ck)l*~7cZob`itnc ,˺^`E+*` -Og:bV[t݄E5gVOB H9r Bw <]s#C0C&,ڹ!qOԢ َ6jQ 試KVs<Pcc(鰖& -kс̝[2Ef-g q Z!=ۘ"ٻcSm`ZM]sē]-jn袲0*!=.Rqt%@&G"7uT_hW]ԭb7uB`H=Hw#%|yNxK,K_ţ}E:LmbZho9Z?_G(ig烚vSQPHH~mj7;l'>Jg>,1q\W `j09q�rk#nHdg^�FTCQlQ[4<�U<o~_3k_ ex1Z~_ʹ{$.ɚ$;[?&}sݝR\q}-:sOAU"OE] ?_ūkcaO$ޑa56IR_�VEOnb%(ޔƆO8|[ gHXw|ηtLn'/"K#lz" 8(dL=o;ܐL iwZ^џ(C^2 `HZxq )gx -)=KP -;,A)o \pBx .&!N(um(B&RrjD7fLKEDhAV>n )`7H޵O`Ρ@ʩ4f *Zs7&0/eBs1>ŧ?6W?⻆1ÃcYU._;0?^, -cț.jWz0$վ~m1.W�Cky~[!|x8=2xԯ=Oucg=�{βzɎN]L4OUO{ޡy|I\nVh%{#| Hx-I?76-wm">Xw %-vZdd;*hf@;pg-)DNPXBݰjx2xgM'F7OJy芵yXE#oV+zVcV*p=rHfɁJ"|#?rMok9??q\v+7(.%\\8E4 |rS0/Q|߬|_h7ؿ6 QO۹ 7h߸X<xng Sq+ -z[u�:6˫EXhS�96_4qTs}؈R|. V|zq΂c[ݔWQ`E)sH\7IYӯPMQZhi# o4Z_*ED;ȓ/%So3 b./Y,q}0Hw}w͸o/B2˱ʹf皽on&c<qe(@ (MǑ>d7(e#Pu4x{1-Er.ءV,@_̱жūZۯS{l ^l1d{B7RvIb2ybusðbc9{2yP(4Y& -[M߽7 ij+OW]Iw lFӅ_^^#m/:sF.^t ]B6EV.YN ?fυ\ ]Zk0.P)׊X7ˑ6F&n?@[7_ycQb;Mg~~Gf/ޤ,Aaڀ^B{ra4qXpInE|¯xQb^uys&[gyVY<VĔ4^} 24ԑ�.O؍2><UET(MR+gE>zn3A5FYz2NANK%\ˡ!RAŔ7Lb͐C%.mPuک>P8! -i5.g/uo>OTԓ<@ <ZNԚ#؉`~b^4nA˂6r7R&jM"*2a*᳕2+aM%,DYKzK}"dN-r {�?rzpfC~'5s*ԎŇ'w (alG^SIfn?(@d;Ðر7%鋁D;\>HeDQ1L<)/2Z^|#u=FJX#7$KeX uAr b&/"? -q(|.\;-@8<DQ$_dϵW?#,+tCW>;*XEvCFa/0fMBj&"֥B�}0! 75˼@!XRL#SIz$[϶LgILssj)huR`ۄ& 1,DlUCQxϼ=x,h&j (7@Z5.Yu$:y,dm+k5_A#&QTSsA c0FyEBuoI�g1'u a!^6e/(V"JG3m-Ғt7!S)=6(œsnv+%=4w 9;T@ϹiέnEKJ!YG^gI3>g%49�P8u`N@. 't2-~+sG#q<<gZ$5"c>;M"9oXv; g'r3q$_O2]ϑZэRuᅼ4 kE8ѕ*W'"g [7|->ƍ^a e8q ʤI_~@46_/c`}L\>C~2|>`LQ5}| уm*=궂jVLtܨ?C'4޸Xead4Twk m{kExbDVk7rjϕf]OPsFE]�(,W80NSPݣ꼦F@Q@j…E5ˡצwO<Fnu_|ɹ[M6 jzT_.7VKcG -2B2`Mؚ"�c4Rq N⁘Q<Q$,@[N{z(-z":\V0ysns 櫚6oRPRn>5'39?41dRQt6V k,qhF(}f$ކ Q?2qyQ[$=)0 #�\$_ho w`^0^խՄ@o>|d</JImxή(^WbpGc+]/V&(F2yވ!ot Yۗo -3 /vOHhvm1p9ڜyvhC27w0.ܑ! E~;a>S}l 'ʬ0;; c qn*$E^Yvq$iSrQMBكJ}D_S4exḾd.D$w&onOza'g]++<5}1}·Ćoڻ9cq -??|i;,y>|꼲+ AdHxr֐I/ 4o 7+ʲ^Műk~6Bacح~/!9__{.ՠI_Bsl="/pu;BDo@Yx"E3˽PP#f6>jɯ/B7s$jH<'5\cp@\y1Tx2s&Q0{DM58;٭[y+0Z<Dc=4fPp&n]$!" -);{NJĠ l윋r.vT[3&$¯D*(<! -JqbىyŊQX ,kV=bزjyOfJWGF<g_FVC!]�Of5׺MjZ'^+m\Bvasl⟬:{١*]wZ SX:Negb3;0suh*Ŧ%VZD__{cDh\,jiPo:Ns}~rŊj>-{5|׻#b}2hG<SӹV#:P9D1yucECCxlcZnD)DïQJxgsԻ1u]#|c<,WۜB^^׶6d^X\ׅ'N? %<T�rϭ`L!Ix<!oQ9MLTHEk #bks2;\ZZ;>Joj^U9<qΧD{-tS]@AZ4~ n mļj+>=>BEO@:I `IIn/=Ҳ G<!۞2|,O}e:[nԧy M+wA".z6` y" u78Y|f<XF.S ^qn8;mPAݾ>>*F̞sq5gÛ5E -f! Uˏ)}hȹ)Ayy65;byrjf^ -:~쑜CAvFXqwW&_O#U=uHp,jdJ>bQyj^C;toK*۝9,p7\7�ɤ1- g͕,J9)?KLcGF W@SJࡨQh;4Q88wygcyCi4v}1 h W -~LhP%Gh@bmsX ` 4ƝN:C.Q:{#331Grw=-0lTj `=$r`CIT3G Wzy%Ӎ `oA*g̴:#ӡ:NvSR-TDa^^2`]fŸgf9ϯ9mgF_c]6TSmG~Eg1nY! HUR"g"%g2%Jdj.TNU)AW3!=)p\)1XgTɼB עHv"~9n-@y*\|'Fܭ-üv/w`rzq NK6{oSۻ%j7XJV>Q -}ae=[~&[Dt0[ѶrHv{ՔZgղ#K64 -%dHO<nNϧʵlʺ^hBNseMs<m07e0bg(v'YEr17UBnGVYmGe\HOI8GDg+ђ:>mH_e@Tt8\nh1dt\Rrcz_E ÇEnz@=҂Rʲ*}yg�i7q[=(Qiql -P_&Z0EVD`d}E|vͨo/Gxnn6eFʕ%*X -v~y|^u6yH#biA1kz9[<��{0�'罬u bBBiԩ-I(\ead;9͕pbMdT&\nQ֢-Dg:Ez }vbZ͈kkډ M`&OȤ"<ww7WCQV# Q}GGC(YZ2L<1̀Lma0Û/*DI@ag\ye8˂^VoB!ENv8#n#`{[>Sk4$I'S^AՂOGQtOEG4("f[IXkVF[̇W?|}G63bCjK$Bdc;*R :kQ#B ለ"<I+]wف93ZNQXAN2P�眓˖fN'gHVW/! L3ŒP^>9zخ[ز -m -(Y(ۄ\%#J4:c/[!-˞LE hH aty9\1q1/a qjyp>h˅z(ػF!bnBj%Oha$yr΅B,sіX�a,Z5:'KLyNR,?&yS]!q~lD5@qn05yfg:;lfL䴶2b|UO*=C)6Lr,KAK3oMb<;{TЭ+~^:e"[[tMRbʖ4_4njx,pq56W31W'4FN:QZ$82oxvFgP^k,gТnfs&l!^K%?C=ﲵ^Zay,u$眄NX5v.12EK#nbĈ9$SI--f#G_wgs\Z؏]8'Ţ-,p3tme}v-݊Έ,(*o捿g1 +z6#sP1>cH"©'kVzc.C?0P'Q[>1?N[l -]^ Sg -XyE3 *N -+;t}TVNe<^'Z52y+ -Êc2v"{GmO^cv|H=caZɞ90a6tNw�.+T:\J '\m,^ - Y~I<B&E!91`J$h1$ p<l󣂋NOȹ=UXZ<ρM7ٍ8պO&Yfn_=$$m5 uOk_Ь<#oOj+ F �B-^~w|pBt=z8nDcw[ugR.0GvURI<mvO *e<' *aĂuz1.`7Лѹ \=㾉4zY�X(KEd ʑi]]5WG ,<\.bZi)N1VhF~  K^Q67wD %~tѭ[iD\dNG]9^| @ꙩ!zvC~Bvd$q̢\;\{/ןane`VIYB׃Xkޅ -#1o<뛊FzݝsXrE}ָDix lI,9Tڤu(M=eӡ <l9o=Ljv{$u7sυ3Kt(3U@Haf&FzP�A#l>d*aObM3VqPZ>Ӆ*Pʞ!,neKCpEw>L$jԀwT -3IEe?bJͷDR y=M0($ئ z n'JAxJتv 7?>= >H\h6ЙmG0*H%SW) -?[u@x {Fbyn0~ 6yΐRjW!t>_ =Dvs~DmpZo ;CDOuCǥa8]cj3%~g74>GCU$y;$z6P>GnVѠЅ&mP-,9:S3Dk js�',c -k.^|{߬Q92=%j_%dK(sVp.Tq-74GcUwفcty#tTH ڈT0'P>0 -\=!$ZԂx(^*@):IY\WX;mVBya7ف߸b)Yʊ)r|Q4+5~9Rs\NPlW!]1Nno]_H7Ex>0y>559=PH;8gtcG^L5yk>̡@#(@]*RxeՅXs6Y 2ƣsE.irXc+xhaj8˸'2T%o=kfʋ؜/vuת:SØf )w?=DX͵J 7mY10ňzSϜ9;{SP{h\fñXh6ǯH<e7|\o%ښis"b J']\9X>i-̖\^DϱZ}rkUBu*LgO -I `mMhڃw`F|4v?DDD`e s=90@ZZzGN\G;*rH3r=!~+0� HdCʆ3tƞUt/դ8CN2<kjK]mb)[:W;Pf^!0J{�rtbFyKK5; ؁كWIm( -Zߟxz><sy {;\~c:XG8wF+:'#Kn/5g,bmcR -su}iI~ J& Y膋!P:C6.if=Mq9x(ftnuf!f\H9kG;@̯twr+vj[?bd̏ikm -2_=,z~);ed A#vP_ڷ}(3Mgd�+걍EHǐ+Q4K~BVDDHGʫ\-S0a IY=.e_2[Q,,Rh>"Q-葩c3>܌c:dN5{'gEj8UF=T� ӣ8N+=CGNߢ,AnLX l -_eՁ۽M`TzGZf8ۊp eA A2 -6$)y TԸ%B-Rt=bOЈ@-1uzvHDj7EF>BGƉ2i- :V̓~qJ||jBLT*A,*>|o*²Mj+=AмmrNK/B/YY9MuAUqgiG mG<D(?tCMD:Vh. - | f@WL\66!B5J)Df!40]WQ%*{zɦ"X%TwkR{>b{jΪ0Q~֘5|T'1=i*X <[^IQg -:({b_XVC}?�dEP6wW$3g[Fř8wúcL?_AM'Vre'enJQ[ v~t+k#Q׾L?*JyRYWܣ^q)|92)Lq�5/6תBd9/{,6f3O(ȫ=^+vf}  -xUc{` H ]tԍV6t.#1Bh=q!z*׈D8B&SaR=1겋(W:D`D룢<, )>3va) 9foNaQua)²ѵRϺG}WՙXI9ub9-㩭,QCvZFI"s"4<%Q!D~4ˣ_HvMIc^B(G%K )XC%qTeQq/ٍVCfx -Vuͅ"^@ġUaУ~ -m~H$ЃPo[ă O@-d)<GdOU_(繵6/)W�Pk ?W ÀM^3K�O soַ - ƥ>Fka8XW/55ޟc-"#e~)?y5UH$_`$eLFTfZJ!uQ%1!Q:iey-uQeZҷ<zQ#ίRAGt#7NRR hu tW,hoi.[ٺBj,=VLP#naq"iLhzGTyZ"n"c\Cp)5xP0l  r)U-܁l8KO؏{C+ ҧPےҊkZx1{8.utzdl[F['aXݺ^#%@!P$)jѨ$!|ϕڷczлVUSk Rgʨpxqњ=RX�W)&|v+NpztoQw%:bINhP?[xTXDw'rbvR8z GhvZpbTGne\C{"zt!mx VE&SIs -om"{CxzMxv@7>W%㖸�>o]> Ifj]:rqGFyF|]O'D9䔭Q0{J_xc%ީ\N/"if|"#2Ißvp"~] -ol䘇5jC y$GUpS&~Z 㐺,f fi?JJ-+!-hg]I7{촍Bu Cr!dK>/;zSC{nDTaEᾒU\9ȧdCc_f's7n" F12I׷3D](!)!cB΃X>}XPi>$Ql3^ ܸޘTG|ɍ�G8e/_.e,*b,n!xQ"VYNV23L"g ms6qcb.תG*ϭN Z -[ Q?\nAX WW%-60Oet$)ܖZ3ypBxfit -PߐXEQP^yM" 2i/Rվ3b +['{уxD&e"(oNw*[,Ma)nc.$Y޼gJCHVII Z LVJeE"/~眤4fP'޸xo{]^$oҭZXlQΖj婍!7BAεmIVSf<$75RC9%'hDݚbm`c Ɗ /͗mp'/p;+FM ^f"ʖ6\q% x(@\*UՎA)"~MS.:yuj^e?I4+e7 -3k,ՙc&I7;"I 92RuaZɍB&_JK|m} :=fA.y{*IZ!)YU N})K G/V{JnDCF(~�'$ӟ%#I:)נ 2KWThL2A qy -Ibo2 `2kթ[$̝⬱]cKXϔ_r(ce4\թ+ȣ_l&s 9~ :~-mP)Rk0o9:k,OvG&XIK Mp;- -g -q:k9-ݱBd)vn7թ R|'"f|_R!CXvI@v+ s򋼅V9BK\>05pZ_WW۲R|/JXkESs RUR�XEJf;~ kq aY C;*[(`6I(%Vʏ@Ud{9Lj8Nj8d4T|Ot!$^?*C^$,׻|3GRNA .AD:ii`IYnwhr9rC5~ -ٺ/"Ndd5gHI#W.7~&?%.zqL KBY7kkVᩙNH\9S5[bjs'仚کNJyx"/n:XC1WսHWE/D�dk*6.6VP"l`vR&\ccɋd.WD -lX?X)%Hu"JEW�q !}/ADTojHB,+ ;撇 XOQ$#Hv[ߚa1% ~옣 -lkCg_S ǬIK S3zH|EgK5 jwԅi<U-N)O{+^߂@'4>ZU)Iơw>gh4vgEz ]Z(N&"G+$$$$hT@$ `JJgմ—2GI3A<"An=A@N"n`ZBcǯ7vԙJ,\Ó1I2=D²K.\}v2qwtl7/MQЪ$ϯ�=YGZ/#qL!G>=;44_f)[i!rax@n4jH֚ I#1-$"xR$[Zkx54S${8t[A -ى8b�e#ȃU*wKp)j QhՓVAf)ޮЃn3?E_ F``)pcn>sʔ? ˹4nqw"Dj'wv Q{0HbZ1rwT/Tu)N%F<ֆ4D*> ]x9 kD@lC[Eld`!ʃI>2(j^Rʎ1vYX埒VsB|=Le/t"o>jȵXܔjַP蝉+f{w AY*ICbˆHp6G*xU�V󝸈Kd9Cʎ̃Y{21f;S()z0>RM4iXzնN+lꑂq$>j -=�pmۡ(L)AF֊LTuA(%z�7" -aJYj@# 0Fa_Ih)(?L/՛NϞz6d٫U{0uXc;6kS<AP}d[elmYD5MZsW1 eΤeVmd8#qFy,kM"]f<SC̒5Rbzu jIE"!̻5 TE["l^@g}tk 0h}4=;@"_驇El@],J3CAvDmo& 0NemX,IYWƼ+{aJ ŪRȽ%AGLVZ*%C*ZP"Lw[.xi\ XNiU?{z׶kNsPbzj{Tr-C%6i#Ԗ,WmKsB^Y0C=, n5kMuE"4dTTH`j7}ep>jRAcDTi;1qFiuXzur8iG0&YEz(N3XSbSSR^}V[d5U{Wqw}~#@ 6FwDv" Ih &?72_N#JT\J׎25QflFYbø�^> E}zH]VUb}9/(pӽĹҟb1SlϬ*Z1W IqnQ:/É 1Η | \1L; -s{'RR8b aiS, UUQՔ1Y]O$k'" ?1Bn}~RdWg}M+ "xm).\n56̯j_KD>R&3-Drb,mDx@=8Qkv&1¼ԡ8IA@aœ{:כz(nQŹmi~$KE++JG9 I__HkbN4 L=a|K 7Cd*2uxE&�in Z@JԮ7[\B'H5W BɊsf ?FS]δ̢=ْU)cUH!W<.ПkoHdIͿԜfy(G)m0/1ȞXpk v@p4 Ht-I -ZI1 9NTQn,C 12^ A~Qwv)J6ńiI~*@"md6Ή4IDl.og o.Tg^3=4Ƀ,tLjQ 8LȕьD2626J!qYxJ8Tuty%_1O[[^<:2P a `FD -{Fi_ݗrp"uK²�GM<$5dI:2w{\&r)G]tYeP{ꧤ 9 t3uHO`=ܭ棨*e�$u=Dd'9l*Q8K*'LCPӴRSmCb3X"95(Ry5} -g՜¤Q)vfD-҂kB % x)I<r"F cYOG jmXqiiâιj?~fU &loqCH$chع| Ӎf暽y@n20 `AC4{8/\(-.mBn&ɫ~O,K] <k֞bh,:7>(oj<Z[u!uWꘇ� -y\$!7H&f(,>כ:VHYjD^дsKPC#"xv:` w'yGKd4 xwCe^|G34$Oa#Ӄ+~pyDQhYeBk~ z4Aߤ^\5lc*A /.d~F,+I2 f~a 7BPãL &st]fő= dFÓߔ6 wg -"(1 vT˥b8-hr1Q `)t]^0("kP�[ nEtc\6TmT B@KNɩvt)uGM- -7TSsԢvBsHN�Õ[),9I -P+*zB@WW-Sǂmfq\ (Y?ڜnh q wxSuhr=h"!- z\B Oݶly0_<K~.B ""G H&޸lR[W6 ♒(!D%V]x]yu8H'2vCS! -F4Uz=գ"R5!z f.-de*C=7*!ڨt K)| I2,Z \MFDqTƇm٫QApq1F/r(#(2$Xv|+V.dj0АrMN5T[ա|fբKn(m[fH/&P^:T _='_:�@ڗB0ž v7rR2WHZdO걈LE7!*AAyl\i8Db 1^٫l=JU%G8c[]HLj)RQ!P!|>:gb 3![>by,{uF 10޹ $wRwn!g?Y. "hkiZŐca/d_/E -8EZ%d%zX/5 %y&S2KH v7PEZ}a a|Sfx2ZtjU&]5\Ug/3k 3ը(&MJhtUj0`fE:0<6 ۭ ~3 -a</,Θ15/d] g[N7\>cn5ςjTIy6o<%=D/f[!&R:jxLkRM_!V(IlR ]Q-̚} Ըr;�p'ْQ6*+;:`/b#jʥNT~vo tXYYb 4-$P\l:Ŋ\"AV:j֨|r"} -r!5cS!11Ŭrhw#Qby]@I#zhm#uKb>Wϑ,MLp!W#ZЫEKA!rG어Τ1I Tܴ[^֞ePdt'1G“ɓPTC8՘TS'.##a˱[d>Q'lU/pzoXM ;B<#Q)ˬ֡o~ Kx?¤Ą&:{0wң nk<=k~$ By qCZrͺGaal -~J}K#P(s -;~ȼPO@^JsyڕF>%~L)+:6T> -lM颌% reQ)7eA!?-榣ͤc5g'֦^m̒?g{ z`-8B|1D:>ΑvE-yAƐk63xh* L{v{jDSaȝL$[}:T>ymڙ6=T6kr+/!l:,#`?T02dx4ѻ\N@)\'#viۛvtG�P(XCN|C_jeY b·I0}Kî}F '1%]9Z)NY11 ]*qr�o> -R(sFbS! %r7?=TQPzӀ;I5rHK<\W_AtK2FuDr -oqZk3F: δ3 fQUønH�L6Si@A[`5mi䐯$(JRQ1]ou(K]'U?CŠpgϮGpSg+!%8P˽0&c~h^SDZV -mpD@n: cP(|CJvND}YxAS~PP?Sx"A>ٗKkÈKgQ$)IDZo!EJ", Lȝ(˹C�:NJ5O`8S7^뢅o%S%7 -;,fȻDɉ?jh6c{2~-(|d ?D74U]ToHK],Щ\!5)pORjМVn2Vٖ =#}Ơ(P -]&BLt L)Bp?Z�@_5%e%J~]1[7nMAVP4ժ7C` 4zwv9A̢N\4rb9:=*aUHI H, ۦ}BIs?ݟDw(^û83}[2_ ryAcp/֖@BH+Ofg0G~!kcF1x8A\\ĤDůȋUfjcTUץ8΄ET CMbJ ˋiћNMwlH?4Ť*:Y|@u;:)j!RQ15Kq"-Wh <YFapbBS/@��nϨfsn؊]a[ (?1|&$Kh/4+BWZ='QrH>7BQn[�B\_-8#Aɭ;nf,A4]NL#\-/}()_nl-[Y>_K%+G9|6rAmj/Ac,IQnS<t]%KFQJfը߯zk*z~Kė$,%q촰˖h n ){w=b &VC:4R諐#Y -;͗ڹģRҸ�@FL֡#j컉lFGtuS=/2_ɈǛpUWrdq`?`weҥi#{81fHIR8Yh{)틗昖\;OJeVy{AݩvS92ڀݴwE!_6H,`.dh]d T8^ /YWUޡ I堽 XkQ>Ww -endstream endobj 98 0 obj <</Length 65536>>stream -X 󮨖Jb_*HR̞2Po,Dh fIV[z lEeo6(Gڛ*9 ztbs("B�Z, ԂԨva=Tj*$Uɋ6M g 1 -Kiѱq", - ĒF(((g~GduΟȞFO h-)uXZfI쏂(m(Ϯ<@. 7y23%q+o_cgO//~7~÷oWۯݿ?~WO?⤟~~wv_ϭ B 02^N!REUBHb% �s%XH#n\fpnZ_.+(%inWV!dR=ŔhƁy nE:Nos_# A"HJ~-Ea!r VXj5PtSهPDÛ }d"r-1VLg$ZF= ћeǛ :< ' -A5P2!]mL< noJoltI 5Q$lRXT[Gbǽ. 驭?d-#jkhBXZ!VU $ڼ }}(1g 󦪉x % T H|||k}T^,uϪ,s-lW(?$J&Ǔp<@P$ ^]1H$ˆU#1>lI)�Oxc VBʼnـT^Ӕ47D5!eCaQ ug,Z/ r6v >D%, 1HOO]'?@Hb DAaDԆybzw -b%5$Xjl<ϛ vŞ5XcFj˄p"JNv[0\SױVlm,qE֊8m,�竊t!(rsϘ|\@4sK{$uףx)dgTۄx^Ύq; %^ޮR9wCM9DRYk.?#% -GɛfOb2 -/& -D՛nkpMKӇiCsORAMW@1.**uUna% #-sc(9*ryr!@/'|b.%] 8?S("RzGnCO -SwKby0(RhY]!#V//`xBv&bT6i!2VitJzXbc1ۭ?3JRDMp 7O>D34bIz7@?R(1vѥwbY3-U#:.)D=pAu cayKA1=T=_2jr\n̚lvTWiڕǪz֋tGg)6-ZtM*r8ԣR.{ |P-FrbIDX;!B`)C6c JUOG|:*5OTn QȮu蘚$3�P&MTEg7ljܣMXK5= -өN_WYBkRoX -lsYXtlJh'6:rQcξ:O"B)@v UGyϪJҌB|!էW%>zioK^<"-rn!� 90Tvb!] "05O&^i+Rc0RȌ |L&&뿗L1c*#-zMEhݐy"fy BJ9k%!�Ɂ)]6D|kspBob)zt=U_^+t6x>iyjgؓz"p'PZ闹\c13tD(\*i~A}�!EؓHdh -(ϑTj@[!.py%3x z{lM,d=hr)|cImi ^S=3Rx I9wA+sZY/0"[yvmμU2@40[DŮzOV2`TTϟ;Ǩ%xuT#G+vK�#6.AL#!d%CS<UxvM&X h1٨n%8:va⫋!sC)Bo2lU٧QkOzBDMv$j1ATdD Bəu@WՃ> -ư͌RD9 JG#@O,!CVrРBlr諺Ol \VGVZQ\Eeq<O_PJu %#ħGI# M%,^P1OmYA/ܚvS1IȺlvkPȞBfK[U̚rO{8P Q0D5%!Z2wi線|P%vm&U\7'ާ g:;J(5BY8F#\}>k _iZG -UxNZJ|LM0E>K`$Ô[*0Ȕ `YRwHgJXbwѬ&RM.9oRClNeT SJx{+} 6"FMDDEtBK"<Φ]N7صe51J8C>QYŜ T|09ϴ .2p'цm٢zS׵kڳ fOb FaM)&@k/0vOjfV) "TŮ nhn|Ǟjs^4]d>$c0HUO�ID4ҺhZgF&6?> HT۬"69P];I*>zEzb>;3mԕ{/}{"%aٮ~M{ρogٍ[|OU=>~od26;~=#4Rl%ך)bMs7u*m~2>$鍐`2Fͯ+z|譙7q@*`&MI:jÃhga Py(|懲Ԇ fϘjCglҡ TTsCY--O'w-!^+'JSʖ׏ %p7$levS$#6mc - 9'$:E#:*` 0)a[B"O&Vޑv#ڼ"X1ɝ騶oVDAlڤ\`v@7 Βȩhk:_y !`yI3)QVrMݴ5%r ٰ^L � 9ToʒS=jb50KQaԆV%?ˏV l,¦З -}&[qt0\&L '6dR4[,>D%kRXZPi T -uOc 2[}X$@曊Oep[�bQh)VX*;v8!.SgLGR֡QvgɆ)i 'h8؛G´d -ρ7tlf AJ6fޅ? bwl&Hn\ŏR!6 jĉ7l}ב -b27 74ʔedjXBV$g`K PefHQOW[)&plCKMh &JAg|!JF#f$l^; SJޱ\#tek!4Ib_Zx訨YEאBܸ!"b )!HeH!^B1:sA\զR%rYEq`JY*=R@CR)RH#ua=^3Y)BIqNP& +5I}$.ca2iq@\E,G B{n*I/쟲qYV<4Ui{C+ H.]ؿ2N|MhkkE1HqU@,Q`G>P[ABMw�BLgJ,A+[ee^a,0DƫPՊKumCXX*Nы6 Ӄ,%7;r&mN2% & .B^qѶJsJE4KKL&yOcrAUEUO=,< -F]jg1cͿf%2'jt(cNjIThv�|!uXJ - qOFM>ONLEJprovBȅR+0]FO/ Sj9fMk I.aUabTaBqꈒʁp[+!Fٞ'$r!E@u P)MBm(QRv" .eª7ܮڥӚ/+j!pyadp\]'ͤ'dWЦ\9[F}jhiCbn$,\'n(M3CeW CHβ= 5C[UG[cw7[BG ©sZ06jRnJ�cjASZlljDc#.Q¹*`XH *Ad6;:EF` 3SNxG$If8ɅP\((1\FtI]rMublGfm( ľR_ܕ6_ݒ8p&›Z -: 2 M~fyID,7A77p*ѣDaP%00,cb,;yBr=+ G7/oΓd $(mbܬ^r I^LJƋ )0(\Q:rHlPK<fpr{BiCB:9O?=WBph ƹeKW1A}3%jQ@v(te`̌]R0`][D%&X\8p|ko׺]kDD fXS/ySTq"DDb)kQ$f&N:MaǶջ]zVR>U@ 61ѫ\tGͪt4P oηvӃ$qХ}Tg I.ha3_Hu0P*nMIIjʏfo^I~=4&n%N$c:MsJѣ)bW"dBto㗽L5Cs1ٚwv)Չ,Ҧ?@aZr*r:k,5{'_BW5Ɉ -۩h>�B)w&"kkty  C]}vH5K V4r%Mi瞦uWzG/9D#z<Nr@Pr#N ;z45MhZA*r@ ]fHK~yзbL{#B{YPٺP~wokRvVdG݂s C ;cc#{EQ}d%Q= kC#1hRC|ԏ~d1QԻ$/5tV0V)%>PCO>uU�[ĜMP]%ݒB1&XM&s/w2;^] B)2i(DhCu F|)Vaʎ6eEα)-ĒU Fĺzo&w@݂1>*;¥܁KnZ~ {;9]11pTH ^=S3 -R N\׌r!1̌wZ TMG Ps7K_qK#.w_)IV=/9M$J+%UEs)2DI~L Cj}#pWC#R莹Z xyVQ":!f#y* dg� `%dKXK0,'ʉen"+Ӓum!.zKHZ*,ń/Y nI\s)ұ �챀0_bP:DD~= iZ/R;W,E \!8I^ /B9(4 Oj9hXO1Oa<3xB_w4r,MQiv z]$H=ڌr7 ڰA٠UWh -Gu6dCvu/pʹ')} -hR;97ы[T$mڈٞ=ʔ=|&s-EJHj%MoWb:~=@Mm4,"y�kIVTg&^wca!7l4FySXjB#V p$Dn4K}N`4,mS02u(>pмb'ް@{XI$, -is)ҼC8RЁ8lJ,=&81=z4!W%RHC󃄬Z7^! 9K�d/my\ @tCݘڲCr…xK=oE:ej(+,_+3ũIwyw0uioCbCr�ߖbu_UbfuTX'|&=V8ṗvGaRl!~hoP�2k"4H0cUm9스Tx'Cc)Dky'<" lINe,qEحK$:`RuRX kkB`@@!ccm!IǸUpk:x=xTX8kS¨ڰHo=LQXz|@!lxP/)EoߐŒ\HaJQ)  Pϊ`o|aE -. 8҈Ug_ڴCnU;p^l30FZ1^93 GMEa2w.-Z`FFvqBPRﲷW GT-|6[UR)0˔b,ީܖ -"RJ.@.Hwbg]K7+Ύ(Nz? �&CO2"5:BܵDhs^I?<Sb/M F05 O'6?]$ϒe- y(*d#)ty -:Z`Av߭Fl+b]5\o;MvRlB0^v>%Xxl|q*-QFE顭T - {]_Ԍ%AUUrG}P�&C7@"XRj TQ+8[ȁmN)'{W .'Wք{ϾRI(mǦJY ? - D =h$_kpdsX򅜄 :m -w,u:ZŠnZw -&RP 1�^~̮OMLr.u(�.٤}2 ~H2[-ԚY5vd?LY(BW69' )02f"`S]W~!vd'.n. PR ׆QWzre00)ASJ)i:KvwxAo;cXTkRQ&H�I$솪Q&ܛh#G֗؏񇔅8]5ԣS_^߁ |uE0T'H M ߺ,I8:hihV8?$qN�ꋝ\=̾8;^aQ%ՃW+pc?RLw -LgnLnsԯtWIEu}` v#u $摅[4$ϝntq�4�/lii f.R1R¯a -VWEMϚw5Aw!ŹFRMڻ]Zվ { Ι- 5YrM*DY>TΪde&);TwaLbuYfFuLg7-X9V\>+~!čZ ֛j(wި=1$';0l჊b0og>tA/KnS#"FI {7 6>X뛙D=cJ&"-$k3i3A(=))j6(*͔⦍hY@_`h7DА <SOk) -c# LrQ25_' -xErgF-5*ȹ,�R*JX&ku2Kjml;Tu/5#oژȟgck;fQY# -Gk.Ḿui$v@= eX`�؟Bf%Ǥqk%Yؽ@CdQ9ZPD -[r%(d$TE.wnFh\[3aH!p-kk&t]|Trڗ%_q'&A -'< [HaTqw0{B$ݰ)LHsoC: ΋4 - -~0:UI9Chq@$ P_pכe`t|+&3?9->]@ #o$PCs4*0Y-ǧmų+qyAS ˻)#F^kAQT\jvϓXn@!;)ᕦCW^o3)5Ug$2N uP8jņ(uxkpмPebS -Iq_$.+kdS,W.GpW -|qwTW{Cau@Rt+`k$ڄ( -NtU>_d֘*a/:N4(?RG%-ll>[&ptUD|۔ O`egXؓkg͉_3q=I@V߼"KE4YRb. -i/W0 R®FRk<Bt_B ixmUg㻤 1S -)\Re1O M0OI3E% r_Zi+H$ -P5tF$c*fB}YV)檢4c t6ހv띿y[I#D7}$X=hGsuL*RqAS%dΜrl敥rW7_eR5 -GTEgUP)fAC6}G.ў!Άh6Bo e/t:ml|}7&G_KD \!Z $]tڲU>$Y/傓$xɉr6tq[<+a30Q" -_F&2!kCVYh )BePkeo}IO<g'&U^eC^SDSn?%W7ꦌN# % hGhfv !Wuk3 fX'p5Rraڊ=>e~mdvKVfK&ҩf1-h(ѩIJ:ۈ^E ?uߗI!�z[@J8Х9p)pJͪ$-9^*B]�PӐOlj -zA&XP|CsX$diѣF�B.% sVa}p9cz|:$hLS\#K*ٔ]#GhnHY54A8 -]ʨ^[=S]EfLL-*'M 8PX&nlGO|x-tR`W=M@zj`&/ I j]3)k5X%v0Y,�,LF<gP -/(еQr raģd"�zvE:c;SIDVļs#q#HpW-Е\wg,"I*)Loؽ0;_h> <)3d!dkIvoCÆ,C`%I{fA%mh)<m2 h*#ڈt:qMAZ芆 -k@B׽(NDm)ewvm)$4(ѻCLX_|Fe zv@R@Z+Љpμ:TR2 id%Rz*[XNPdztU+j>Q ,6SlET7ZTJѢΈmurSm,X6 -PVn�Mm2~K00e#o㪥;#=V|]WvTx4W?iϳr<。x6v[Xn[`Ŕǭ-h(PtŢW0%'4zB|fQ K)2%?0#)XI\OZe5y2Á+>~ >v+.?A U z;~aIpQ- -gQ/zO]3;'*5/ *gt_g=CgƵ};}rsF9,} VTVyLTU=*u>m'׶ xBYFcgz <|$(יzH#tZ NY# Ԫ0F^ڝq_K=Fb>Zaeѩ{4+*Є;2E -e̱WcQ"͍I]a(;0|_R\SZ&Hjzea}{*ͿK@J0e$C ԃShk -lBI*#hڗkзշvdb[oRx¬/uY%Zϊ{l6 ;;XAkF!ˀԂp빞7>/ֽ=)D -6ϊL$ltb 1cm -se~1[_%y/Ĕ$RO q~k]( 3e/t:gx!B̍vS-V6h!_Ķ.وGg^.LAKG4#-X <Y>zXBJA)Aylݓz$Nhix$ �M#\5�.&w|BT2OD^K Eo:{̍)ἂDSe' ZQ!z8`-6&"Kus-q5Fq#CR -ծk^k˚)?ry� -E?T:q"!#aq#Ju1%�-\mE!9,L540zqp(Dk %]|%P1kHQ8CS:�[ZKUj^gǦ; -<򦖈RA(0+fSc]HQ.)Mރ]Vl [A8w' -pO=vȰ`EgӘ -NiRm )]`]UH5Z>Ѵ8l̈́:cG]SBZZ\ѯvb5W2FF" ]Gr:=-Ih]|v)qWr}.o}D^.LK2W�5ol xh讉!-P&iĊ* ]D7Fx^1n<[[B<!,V}ֺ}- �zcC#�ȿU?\a!\Ui}r#n<Y[3 |˟  -/dӑ$͐} B+`4]e%cgbU�ᇓ*GxknT(' 9*d3$:g)pHB( YaM>OL֫_(,UO+c .D򀕿:k~$rx0IK]HԋFe$3@zIvATZC|dQ?Ł&HtY2|\tMi'{~�-] E>O Е$P$4 \GS=g̰mI`[{q-5 \NэDB1'l $eY"`n90- n<ּ^C.̷`$u-%((yG}U ٗIgM#U"R:A) -pg aKC~D X 6j(&RLRħeD1.mEnuP:R/`_Hc~W+A^/x1s/KqhQE -3@ul:z NNcς�E$K.YpECB\?3ĥ#jބ2</X1ޑf.Ѫb -%|0F42*=9] X�4Tp58@$YrS_5&WoPm!Hޤ`8oGCJhx6wƶ1Yk* q)20VɄ -1V -VoFZop<GXMkȧs ɪ7뀌8TݘQSY]Qp {i=0O@n"�v$mW4#ka$s(#ʰQgWdAL"q?S#nRЯcs=S.X?֌KE%\"`»d;�#[+p_euX]kSh*sbG/i�aX]*3!oeY~jk6%G :4E)[}%^k5^kndM7)CULCJܟ3Ks�IBUƕLkB(mȏmpSqT"X>chk{O9GZ9ვ[}8IO@43-ϼ}UCEѲD-zB憲oѬ!Zw`AՂy`eeUd] -嬺%IfSIQU+JW5_9z8z J6&<[`k>aG{EA}2{5=YRL] {$E@ym Ҿco "1h st֞64c¯$`_v!P gЪ桏%~EF7(#lpcͽ.V?Ńln$K$SD2Cj v -f9m(mw6w-Qvmjq@} V#8z,! ~EN6)Cm}>>K"qdr85.<b^eI)x'fvaZo-@ Ԡ5sVYh.7Zލ׽qwB.𻠴K.K 4Ӯd@dG۵p@r}9sx:ژ$?wrʚP8\W$ZH!^*o]۞ GG?:BZTL;DyW(K!{w ǣa<L.5v -n8T67I檗 ba -o@#az'9 -ٓ2Ї-NA+0t@w_ׁxi�.~)%BIs1%win|;<r8jqǺ KaXHep^=6KX۴ߥkO(6lڵ;0vJo[kՂÿ5ϾcF| ZPn-Jy Sp`yqkk1}lfbVN18iLHI@VgGZJ قX(>~i̳95w;df]]LÒRD%�ECNd -lH5斈G LsKD;1nKriXz�բl 9_ +R!QSNdlAkNq@u Ð.0Rkwvj)a\$]fd:!+Ƹ:I~%Goxr&w*,.9!ց}c[2\/zaWT6;)չgЪR}6a2R)YP"ٰ;*oO*JOei6lwL;/@y8J0* QJh"I !El?[ $1!(xqa CcXHf]r-"%p6J/q4+C؍a(G "%,%kJ/~vb;icnLzcG*) -q䂔Q "P>1rC%*~kj'b+_4D*1]1p$^B( 429z68;6^-Wu~K gNz.w& *˓vM+̐=qZi?yRx;/~JzX9KPfKur2KЊL]fɎY}zŸh <YR�^?. ۟?۟/W?_?|oo7?ogow۟^O~߯?͏zzWɟOۿ^|?}n?{su=_^ONp.vo?v=6ӿo~~ݿ_{'_~E_~W?&\ oˏ??_D_~_~c_O~mٟ_dp/4]{ko_7~+$:�jeiaZykW"8[#!xJCo,( ,{\->v pd9[%_ʫҏ^:U/ -='=IE9rc- ۱(t{C)ó_\C@)VWXkA{R;77"KyٍX>ď^\ ?~>ـ1#ErMq Wڷ.K{?p'Eyw)]u9+(D4?Z'-iFqW �z[=}<OKzd(ZZdgÎ/ֹzYoq|y{~:!I{~6vۿƔsѵA9kpBzF=Z1&ԣ1e׾4:߻}ݖ\}z^TG@9JWU?(>Z?*3>TL2m'2q x}k%_~Cc Gʆ7! v -ўHG;r(,1;vDx݃ƿݞߢ|#[4{ϣl9D.hid|Iǫ-~.ņw:PIu9CI`7#io}{4=e?Ab͸s"*ho-r/sz5=WoH/-s/`_ܐGG5i K˴p yG|qe~J8C9y~{;ڗGr5(Gjpۍ)^6s^?q $;O;hDiw㽇fD19}I^gL) #naE[oqi4n N~w *z>g!` D{RYS@w?ؾ?k48Ih?s5w[K1&b37!JXkvkZ >@hi+FRwgQO<~6=]uRHW j�k8ՅS4(陟5NynߑEvN+9y?4Nrfie11_ƙ뾄?ӛx}4_~Ӟ*{#YDOBr_3\eDE#ih9ûk}e(GQ={Xk|3)RcL+*㙪ڥbِjy #*J?Sv':2_Dݫv{n8rn0zv@'&^? -ū^FٞVvx*4)Wm9>=YQ];q~۟-ŮӞ|y=q8?>9s7On&[SwK3x:1zw_+iR.P>v}6^F֙?oEgPswsn/*F,p<XǼ: {#}Q^6vKyoJ,)7vnĿUIs>1Nhsgƾ?;kx3,ȮDcIyG+'d#c~:'ٟ'`5F|/t~͛C,W4lO^|~yYO-w+=gؓRy"῞ӌ~ZcwCt7QfwC}_?pXv=J<Rn -mvPz}a~:<yjV]=@;gѡe9sqr3w\Xg=g%\<]Xs9Ê1zp}7~i}5Nj1]ϛ,ZkP?O1s$ExrinL#s .eD,8[gX-rޟ�jY)43HN {{P=o‹Npᛁw]W[~}%J6x>,:ω<~?st< -'hswe9i|*ڋD{U -s'+;ۑV5F:Ϛgd0|k=I}f:$ӎu.pcPyr˫޵ <:U^a qD9`Vu;cq` }}׀DXj>QeN3%u?pc9sx$i|f 3 8s<~BL gVv`䜉Αy2^cƙiޞ.|Y%# ƴ4:#7^cSIvV嶿;(*>@Ѝ>` Μy?ۓ>}. uخ2ƽ;tHKTBltx3lH s1|쑝Vy8A:3kH'8[*N@9nO5W�dt'${=n'D>9CbGF(|j Y͏:oخW,P>8B9v:ܸ/BEB7֨ov <S0glpRױc+VhWEt>cM4cqmyvqaQܑHGٚ\$TQ;YM)zBXyms:ٱZߑ<}Q<,q+*MNc\}U@X{u>qqJGْ<'m:_XksNy\'(+-nR;rw>/=g}d~kI{Ӝr9T$x/HF3 5r~*}o<иJ1F}Ӟ|B]L?E1ҩ<RΙ{b`Qf$ri/bד2qvN^L.{B<if>+ >̂+fŵدAFD/ KH{@\r=%m}ޤ+E-{8(ZMHܸ;WyG]'ls[)~ FpοOR{bEp=]k3'R\7 ޏ%G7x;O t]vq. p֔Ngk)9ӮIeTP{8޾&jӥ"P9tK+,󙄛1^YdhQ=IS M//D*,Yh߷<r/c+QP4{@{iyo U/J S9g %Q)Ælߟ<Hɫ.<[ܨLy\ƭLA�VNP,g-@$(㎶Cv_g{Y0y̌?uqΣ"@n(rgg p/xQ?NAЍ鬅ߧ19�re|28kױ^w%^+? -Ӊc)>w@=b_.uC}$Qp#rvIt>$"|'@4ۿlCS2Y�?{ﮅ='^:!GLpi$TyLC'}_x-Ԩ(xR/ƍNH UtSǿZ?y>|؟P7]禁͟Rt'diR"ǣ&?ѳn�KH%hPʻwkc.ō5Zht6I5#̏krϾ=B =OvZ__,ÓPH,C5МaNYCW:.S_0nǞ;{<\M찮8+Y_vj?TqglO&h{)g0 �~)(П -Nf?1\ЦF A(}F~IEy//#Lg2,oTf@:@tҒ4"m-tw-1e[j<! r!Ph~yi'èGx`d@әkb:y=g3ݹɴ`U93j^d;"sOJ#Jb1_ zYu_m =O}|@<~2os+|,^C_@ei|f!\y9N\\8C;br眡;'49J/~tЛi7gCՃ烟7}=os{8[!<g~nf3<tN{5RKӘ5ȕ_mЯ ->rN!& -cc gPZ6X;4- p[cG{gBr8@?{]os_aSGelFPxJVq+iUoCO';sEz)\=|5Y\OԠ{.-N@7H$ٽh�D[<˙i<e: 1?m HI,_K>WGe]\z $b卟Ft <4+?'[el(q__`uzQN3q]JG9kPٝw'Hy~bnja\w;Ws|Dgt)|Rsl‰ M^+vSV'=U`,i3*BRY@Wq=/97#o55!rb\Y;_Y(.VrO'ڞ9ADNkmz%ޟ5eP/fW7jG-gg_ƘNu) Gz@u|92k\Ax] -y4Q3I|mB+P_Ü$όSƾ?ik7P^ӒngvTsqȝ7x -NYW&'P]T缻<OB_q">$*Ҟ<{ɱbɶ8$�)<pSxvOO}*nhXf=wv9Q=gHM(8e=?(sQ=qO?wNmDnYxɱ !w)'/ӂQ7vbk;| ̮CB+'C/~k]8SDgs6(̓+ zsq'4_ EH\AO/Plt!m\ދ_ʆ='|ʜ/Ft?({6)`{OLt 2μܝ=67/9k'sv}/RY_/f״'P!~4+zzv%NﭝkkQptwj 7^X?ˮs]gpvN16I}f?F{{ ũ"7^z^-4G>)-4휠ɺq!Qٍx{9F;feƩkfq<\ܟ{io `n,u::Yd <r$YdDAj~c?|W;]w>_U8GN`ߥ<}ꑱG1iwz^‹ &HG)S<k|=gxhhwlzO6t?Ś{{)_y<SGHgcjLTm[<zr)D:PrCi22&rg+1Q rɀ hbJ3{$!P@9PHB@ `c0& 3޽ޏNMwڻx(TwW:}9uJ_5gA*HB -"aMgJك򠒁}-cX(y7ʎ<ٴK@A~`ʁ';)l!:7Bj -٪)%ANIicDn`,ɤ2x#/r ~42:HGOY#$)hvJ>h\ł(&'']%eF%ji?(!t2i>9A%ybv;pVaׂ-׫姐JR͒ҹOf  Ti UZ aZeG\"8MF(R"nJ:|%6ܭYs+դDzSea[c"ޑ-FvkLV)TIOA<z)#\H;BQeǮ�\,*q.s{&gVET2F#Wu%&pXJy_)jK -M]i-`M;%]jK6B5BJ<Ip^E|͠i  z= טh$@'oҤp,i%>H4ܭ`1RFVO#XyőؤnNBT-^Ҥœ[N$CPiFYxSIc()lH6J[s"DH,gwKK $f/eeD?v Cc%1|Hg0hKjd>蒵QF Lp+I|J ZIS *[POԺ-K/J!B恂rIWR(ij=vTW,d3W/ˡ]"TE vNiڠW $~yTdCZ`5N/ .wφ gܬUe,{ ,Jz56v[NzNh3OdmûQJ6iuu8I镰SF ΉXcRCM>HNj$=m�nȏW֧בZL'T.ɉc=J<btq:3(5=䵡WZ@N@ZI@_=q*m{UZW~ޮUrrʪHuh yzycpbVv$ U2 di+븼�7htr͂?Y*۬k Isf Im7'n'9/&eƬp\I68AF ~+]l kT`KR٧49FҐv@Y$W%kIemEG)gګH=H0VԠ"nP\π3dE!d -#I.`|csuˁRhxQZO`#O"r"h$I[7aOzq}qrAG=I*T[>@bBӠ%{$ -҃Ri5JV^k`%ִ( Z QZF6"a3!&ң4|҃de![Dd;kW̠z ͠+'mC$;Ԓ21JFj`:tɐQQz{WrFN ,k(/8ywm(gRT0iUYXm(1z0"]`w3D"[BO^BKD )SZH -0V-|'- CD.5f_uG"nѶKE.$](t/Iy5gܮRI&P4If:(qxmSkTE$5vDTVdRqc@IA+wUH-U -3I51ĵ7N3Ԩ i9uri?F|ƴlpVm? c^^eUr!x�ڵTn} JFzYOQK*92 1ȆMZm!.>Dn1HPV)HԱ(m{=)4h3)5.RJ[FȂHnҪIŊ#diɞ\!R1MR0N8Nܓr''[i&m6VzNMȒX"$^Iޢqj;ׁIkjϦۂJ:Fcd*-#|=ʶ (Axud崶+52NB0ШuR `clTPIBkӢR2])LW#ls8JPR?p;8wQdM.Z* �5f G+ zDkz!v/hԑ`͏oI%>'R^V F6sւ5K)fp23djk/hn.TMq@CZ~]K)B9LR 58!i'В}zD\YsnRYh$4VBI -jH!\'ؚR:!VJG#5dee -Md )%qX|'} R\Ү)ol͖čN$gu1z{&'II5$n+9ғ -/Jkk#]/No]̆p;aRF- "%FH@ZI*4<"Jo4:9 2 1l<!ڦғܫɆe v`kP U-u39]Q$%$1uy{UdHD*A8 N앆@Rޓ�wdJͮKvZ (O^ &ֳ^!`Y/_,kB0"1Y^mM"xcNZn)= ܬ'+v3%qKY7A|Tt"Ѡ!K07ePfq IF'HMHr 0˅p`5Hr!>VV6#F[0s:lhђ},L;E|R:6ZnFiWNOG'^I!hhԓs5lY}$ ف(勍$I㨲ٰOWH -qvlrG -mK:+xL04Wh*5)y}]֥j q% -6aUURI-2(ΥNVLR>BLr rQ$R�ͧďggJ2lDxbzTV'*و-gm )h4jȃYKF-WQKYA-4BuȞK5Ү[YbR&<j&I&H= `ceBGYel:Y6y$=nԓ6⍧rΒ-1<ғA @؍J-"{TVt֐M_|܃QoGk+) -dT@+TkItvZm j5A+Q(W,Ffcc+1D6v=kۍ\M*}YAR׭!ϡ&[PVT -Luc/T\يd\CZQ Iv57ҧ$*r)`*UjŤ$-@j4Vj.,ɵ<Pj$U, jܫluʈ$j`2HqwIa] ﵂m@K㝚6!RJ8TǒqZ -[_ZICy#YDJqXȤhW6Tr @T>Mc-aӡ:RQ)Y'mKz\p&6K`S JIITLCZlQu-QVmloI-FnHNƮ Y؁im6"` DN͔z0ZJJbjWJmU쬢2ؗJ v5Kcl;> *҃TK5H5݄EF~\J^ԠilOoW .V:*m Rᕎsek0N}A'F;"c۝.~s]b|޴\R%oyIm;#LSA1Xnד$ 6PJ;"$og*K|\FR^uFb'Yucmj^_ށ$2;;WF6$F�Ή�Fp3\OM SQ#nSe|#UTH* qf$ k0i'ȒSGN:. %ٸBCI"*2' Q^.-~[G(̱;__/�ysdl6}%=VFNmFibmRhw@FK%vGK rD-KTvW—Iy} LV':8? GKrd�ViWLd#Zg(ˈ&FhjDbj)9w@*(7$ O}GVCVµp9y4iSo[ dM%U>rIVܮ')o]JHu-[-PJI*)InFt?}9g IOc;pK,)y/b<TRhlYzɁBOf;OkWV5[)N .l!5mv@:xdq5Q�d@Y(!&r3[zk;9hTQeQʵ+4vBlF#7lBJch{RB#UNF=Wr?{rS[=r\ -pprƖ"9v46Z;KG.Ff;S+*j#:]vK|O:r\Jg CaR~9ymUs5'H<ɳV-N6dI5ݕv6=&{4ġmpl#썒Ζ!'%BR9bZ+%rr6oKF6fy6d�j &J1&GжE)_L(CgMYΒ{ET4b6*r˟cSj{IYr:)~hK(aɿgi6kvl춳ӕJ'9 id SORĴ+@VNXk&A:' $d-]lUK'LnɆTIlWo»vxGf<~8qGg-4x[bvxjURlU>ټjW -GڧwrOĬP cbo-QԑW3n4 ^QSxNdi?7!>]JfJ__0c~@GUݼVD/9=#s}},e;2ѓ=z%W_oH? tk=Dxs">r(u:C>>/,U,\J+B9g)ewξ]>_)uS,Z+L]}RzP=MI=L=VDuwrVsb2K2JY(: -guwWЮ>>>qy(:/W8L>=<c-v^*>f.D?$d'ƕ BV㊇[KFZRfSjF3=\PZ_au@aUJ?au`!nT%Ql/$TQúZ.~4Ї%sZ\pR6(7z}ĊbںBb().|W G"ѡI}O\wjEeb+>=a\@dO'ٲ*^A]AT@d/;ѝBcˮL-f 0y:<s˻0+z0+׌ -MS׏gc{ -]h|pz?'U83<0Y0XLngl~Mn|DACa_j/WqUW7lhJ?6zT7ZH~-Ggc\>K{(Ĭ!eCSQ+R "983>Ho7.]%9.K ş.;ՄއFcąƯD⾼9 Ǵ<l0YYV:,Zpkzu]S^X+d Q: gbB\ WKDׅ躅s.fO$ =9\GT7Z FS)ȜA s~&aBR1QH#FC<BL# a{S=ƷW -'|Q\2a찫bzAQ܁ww-YMA=*F[1}ŘabB:};yEhwſ+Е^՝ F2dl%vX9&u3@H#-Ĕ を{񽸈A ߪnOXw1$k�d#*gW>R,_o]3 N˄$9қR& -9[& U#9~ Bjx>{lͷ'LюQ|d:,㟄sں q\T vUb&875DLkFb{ECy$0ogP77;n ׅq"#+hĨnn\hWeD73qKqeɫɲ+ߛFk޻٢pݘ=ޱ~ʬ>ЏyEWگ+ށ LFUe{]H9 Ѓ_֗M'0Y -lZ$teVЮң!BLp1hWX[)n+zGV`#&Y#$yó1EÄ!L@DO:0'U5Sb(BQQ[4Ef8^rOKS$bN$1| t& sŬ } 2#Fg"Y%dO -M2&IcnF3bTP!"w0%D sP2dz߉b։ք6͎|f֏R֢58֒]|U}~\jX1*a>j4_> Oec0!hRik #|d@X,Ы|txVʂ/ O/'ܝKZj|gŢ%n -+A9XĢ0qH'QM~1=A~@7R>L]; -'қ(6Y-G2Fytg3+1u# Ex~|TP.0Ӄ G q6 s(B;@Kc f}]:BX^|x@Ѝ\`Bo&07S<T]{ --n%O4ތSi㐮%bcz e1͓`ބV\2^#nvL]$F At,\lxZ!p8p0[>\zl3&F y $Ko1k"CY@*GpQC`- Y'E>Le+O/Qgw!iͬ94KoDŽS嶿e1= 1gD1e%};^#a-~=l̚s`[= - -}H|&(7֩Hײ^h= Fc{3.nW&�م>Q#<^\@l/ -E�_7?'}0ֱ #%Ub _3f~|l}wDwRX/&=�סY7G&'ϰ e!oDЗBP ƁBpJ_!`+G` :2d SbyF2=X MuT\h>tov0bB(! BlP12kU0l0(lÑ ]u,`Ka!bƺwGa߰^a]rхCn,׿#}Ɩr(mħՏgـqD6b2[{2[*S pd6q4X0q :Nd֏V]&glU_X  - D'<?X5.=.f$` {\hz.*o0p$QC@oⶈ^7}/Ct_:OE^' |@1lY<ZʘxJk q�Ѝx.�l}1?odʎϠkhCSa|H�6qd*xS{ \2 ʮ|\~i\e0Iyw#|5/,]z" x)wL 5t&BLP>g{\ީ0xd`AF2c`!nUj_!4??(A0<<tOwXGldc#92S|xW*S xг "O6lLYL#3Hsb˰ğ!lBP6G =3y'2-c$+Y 9k6w蠤ff0̱CMcp4~ɽ`lH�&b8ց]6`�T:Wt].ƶr$ zq�[37;JZX>s6vqCY@?W]`7ĿLx <;`?Me*j?NfW #aW c>ƿrwLdJ|fnyI$Ռd+3ØC%B -VDwwa rCfnC!NfA7'`�au>l(d+> -o`}=_җ_3t#sqMDknc|Z8OZA�FcoAvk 'D< p0V@'X,//1@ $U�!܂` VXNVjGd=Ģ琿g.>.~ 7S%FŔ6 Yv+";3' -qfd(4G4V8# s=X[>aؼ!OYdc�9MWuۃB Ax'x3Y8ń -|I hAn!Ȧ#.~g0HgMFX7_o*/l B49A>Vv3v3ꂁ&.Z aFv*/:3)7GhWMtl@b/7'}ȧ!pZζtOw> Xr(k0/m{C#ݎ{ `\pOx7WV wѰeTldB’|8|(K!nQ30Ahb?!$O!>o(.*s  -k#ԃFؔ I'F#lW< E1Q!^9Zd}=Ck= qkX|(z6G'5Lۓm]Mp{p069_3CD5.Н`[AzЕ -@80Ad6hI9r�3# !\&cL2HJk dXم+`M݁?#.`]?Q-w0>YSa0fDKiel֎@k'ԓOeFqw+,"NA1Hv}z y|MDLJw5hm uh\ 1co na;_(~�;~0U-oU'l -`|ǥkR/er7Mx;"شcͭBZƭ i"aߓ%uxY{ -aq?)Ї`˱E6tz!m``dS֎2f ZBRh6K\j<g` ?dYix/>]xhiӓYT - ʜ~`kĞ|\Htz[ X? -!ЋH_0RwxK62IjbSڋFg\ˍ9\Yh5]Ik >Fj -K)oq1>FcәEL -e\,]lu$WS?xΉ &{? !BM ׼ObkF[sŃ@/iyd7I&0V2ܛ įHIyw*ƾ:1-bgb(`T>dx`0pQ�ɍcBhR?.mڳzQXf3:|8ȟoBOq0V0x#=yا>S? j#2_ /|)o έNq1T P_ -u.o0�zHJ_F1sӻlف| j [{2_6E%:0WAl8}S?ﲥ3\|[aNE>=j`2%Tq2ޞij<cs6DB"pNGX|YtӍOէ>s)e=әCӹpl"toSc>`'n>p'XKV � `-! 3a+_*}H炽`>]v|:Wpp*]; F7Oo$U7C2->V.;ҷ#3! 1!1o -.cs>Bn~= 'fSFQǜX شVLi=Yߔ^ ޫV%&"_:9Ħ$BT1-+bF;!W�42e C-%8<ИLDy -ho7cp>5E;~:j8gʾD!'��~Q==2Z&PugtLВ`wͯB;};\6GӘK".n~n<mKD6 s)Qݑ./4^7ߚ yuSlW7:^79jOk4mq[Odǂ:h!}˕v3[u~K]k2ߥN/>+Q1%> q%6m/ͷ )|l|Ѿ8*` +_z`_Cr⑶qZ7u/ב}9a mI­Mb?7sW[np;' M额�4+E8J ]?`tMx!$uT Řc4p!v,׹1_" yCfϠkOj貣~J.\=~ ĸƱL. ;Q:g"L2 <Xglq�C1~ywz?aS7jF\٬ºa|ӟDz8l$Z}ځmĔ'赨bJx~Y\Kx?&(/P?hl5>ʴ^M5"]r�\&}bn9״y:0Y֎IfG14s�&`Si<ic=Me'g8.ݜ+vk`,>hcS46m#�ЯBGGIנ{1A}^q! ǻK(!pA/䏭8~!G;֝1y-|f|1&[Ŝ ?藄q5XE.` v#qOaHְ*tz>ԆlΎآS #ƌ %#A?q#'d`b] -?`-ۀ_ck1GU욯f`DpJ_`'A WuǼ-&gS5r{ 1M# -Ae -9=ހS`�Z׽fY]6FM1VK}a6|3}ĪmSLš|b[pphkz^s&epp73%ft&fA»"{cn\۝Gm!t -r%O ;&]ͣ@gz A8]y -v'A(KZG ǀ{s1_"L4^/::|4f :g^2op.]^`e„;م.f69n2gQẄ zo@dЬTOa? -[ - |VQ/d!`Km$X!x�1! =K !H~\!9 l0'onͭ`AOl΀! 73Up$HΐoN e]LXfP26@H㙾Ϥ5A !d(U@n,b|{`Bں f|]H�#\1gtYtJHmz2)O~*G=ʬ9<1p g\I Q.ΊeK\w]�Њ-Vs⥌|Տ` -) -1,00?fНw�}SǂLv8/;⨓Ӯ њRBp?p^謠.qYa>.YD+,b/KL? 5Wu?}CXA ȅ$آ -'X/_'l1S{R8M� t*O*㨙k! -z<d7^dF<6P,H絾o3xyU> [c~_i FfͿ�|<&mS C['kAp!Kz-#ZJF?A{t@w!&<pcE -wL=9g|H!{Lùgg_.4n<Z3y#�aqK/Ἀ\/[q ߘ^bH} eo@WײɛƚsCA nBÂyΊYs(.pU88 -^w}&ՌxhLpaS|ba|=Xĥ݅֋ omW2 #n Jk.۟,`~2c;p+B }Оb`D/1i8lt 7|kh=Q{T?F\(~1=fnBtp% "=U Xuם0rVGOst2iN̎NgnSb_+ֵg[.qekO@70[n-bvK[2 rH�ّSj"3󦻟AOiaMd^wzO@O' -kvM3blWCF(=H\Mg?ᚯa[/Ρ[/} g[n䖱|IS܃5?:h+%S}`:!x�䪰?a~{�,y{H&گ 3[,]wvrtɱ踦tdsx�A{vse<"9 kZx"Jׁn�\(n4Յ!_nB3@W9˥"�cVT}vM|�sdɪG0Q,>8r:f8{?PT`cO} 8aD Fkz ?8VksZ9;߱gq"칰ľ8tq95ۦ0o,徺rJ (\e[avc"s)fsKo%{bhX4SqSÅw(L>KwLf6'6Vc1_NrP̣7Ov<L)?[{D~k�<1VGBS#J;,vyv̂ SgUyC)8:Mn \wVlx2~ -<<57\_w]~Z �cBSC,8:"Ay:D<rm۶`-Х'3-#ՙk_q%.Nmgn:eߛEs(MGyaUR_ ә=A8Ϭ ǎ r~]|@Lk{bBp -KcX@OGV!=)2{Z_w b:M,M?g|pMc/ -}<bFz F'!1rg}LZȤ�ۄveJOE^Mox0x}L[w -.c >:&$?L5Τqfħ�>ajҷ:R}A}eLJ}lB\mh|躯`-Ui 6Ob[Υ7+5>Joz<HX+̺[wk GHn+>x7B![qLɔfxrҡlbH,%ǧsIƀ\>�nƴu.`ϥ4evL`ѺF%U_ 5}"ČCpbaE=9?ȇ";GyB(;3ٕ{?d2Қ} UӰ .{D.Қ<0;8GrNcwOAo8ĆG -B:GWx ι-4|JtpDO#!X�gORWՊS!9duEL*B -;L6Gہ>|Z?Uy'ΔgSw}ż99lt06׾ 9BwpHw@ ?5מPbI _ '\с~,옊s raHm|6r)}}_>m8nucxZZ/xm@8%9�EKiqO1~A1pnkCEd1аnOrs0",ȕ�6Ŷ9$?NjA]1[W@5_"{}/5oo�`=4Σ~ȇ搒/:8 bg?&/_9< ft/ p;k-;l؟qHka}]~TWPSnf<Zd1;Z3 I όp̧\݅شa]}7�m -SsՙWhdOW]sC68u{s/4yV17]2r%'/8xd]jd{@C.o'Ηy8ti BS #Q2S5w.od>y Q4D"&8PR7c1 \X(:~?֎_ٗ rQf{tߒGHWW%10C.MHz?6uS~JE]Z0{DvCXŐ KG !/-;Ah!tjҭ א'ꑹ]K6a')Z N -McN0fW9p܁00X/ –P gdxH֛UGU8]q" BL3ngT륿_iq*$g[>|Oc*N`::zjDz:dۑ1cZd!+3͏?7ݝn~Ie_kћ}N5}tw:f@Cc #8<@ߟnB5]< CԆ'>c*.haA?B+S񝚎$4bsK0oXJ5_a_pyA&G2}^! ȶO9ɠD8;̝S̵辀YF#+SI-m?}N|}L7ԏCXzO?ͥ6~.&|sws=[GnDKpB_KU4ft$zwe-ke~f3Aa&<+럀/J yTO,1D؞m|1<f݃7t6tΤ3"K_�Im~8t s[@΄]S/z ~9;&fеuG [:w;g7榫\S~#狘]n܁;}ËȼgG3~́ }е}ル?xד=/(w n[~IzŠo],#na7?_hj? =u<S{(4]ϱ{|I̺{M9Qaw:gz쿺cut'>d逷[3qL+cO\lYPCj/ Ų BA1'!4NkGglo>4ey0Q'gˋ7_Y~7}D٣<OaA0v3+7^G_W ˱{[nk[n}δvEcW؇LτMnQ|˃|ѱ=3&I=W < -`3$o8GfCgf+W=xc?\ǝxoHQSͷ?6=Ѝav6uGWjkWvCԝ=rw -+<O[l|8zƧ39'K1zӓ\E<\fz1m7S;>n@c&,4o~>}s/;.5yRjϏ,H<c~ٯ,wwݶ; 'ncv?R_L~3_OWrū_yUޫfkRBx6l+Q'~Dv,˷d[q[;9x�B==kr(wEܧĭinC"2vEl0#}tA~:/?7>\ox^l_f־2mS-r٭J^,^=7%%yc&ts+|^x}k QR'ho]F(;,P8w;rN8hsХ'Oz9&n12|#nwˡf3-CzŲkU-7  m{ ;<7wM{|}악; ;49Byr_>f}Ȝɇ>ʏ,9"�}o~0N\z*>/><__|ȋDoay݃Om?ͅL -¡/vry9\}gˑ+~ ߖcVr{1K=h]//j篋{\z`>t7yJQ'^ZS? e/=^͜\y\}N}Z`=e6Q_L#/MNcs^$#J;kLoBn~|‡BЄQ u9¥`_Vq}|,g.G~q"Z\{s>SzC]/0mόk}f_ܛ_BK=׾k3g<.M_~L W7<+*^,�F#;n|aBit.sy/~N~:_"pQ!קOw -__1_f /Rҹ6rIczǻj&({tjaG}q4P|ٓ?m3PӗR,_ ~Gb=wc=[#\L _-'^y\|gxf(Ppc_'˅<^ &tkӏ܋Ltkr{J}?cyzZn>3_xv(x_oO@?1Nӵrߧ녟:W'Y/9e_Ϡjn?.6;'/GYN\ -#a9pc5/=b>eO忽"J8z?⡷yK͇_1' -W$7Y:{==[hosO4<YϿ^ ܻ_Kғ=?컪/Nԭ|)sCcƨw52Y r;VS7Zͤ^nzt.Sڗ]Z1|]S^7O<>^u߽ܵx3= n+z,]䡠i_>e;[ޏ ~%ƍ7{>W�vI[8}s>֩BWV;\x3ûA#o:][xdپ:Spuj,[.컐Z|fmhgkWWKW+es;f 3YG'ћ~؍�k.=?ݭtӗ1 -}Z*{w2'?F|r98t'/b:b\i?VɊ'Gk]msuKkԛn a+72o6Gt6>=P/rBoW<;\nj^~Q~.{>p>p?`Ϊ2[-6w=ہ{fͷLئ+Q[\ qbxJ -woMUfKLs>?|xbM~O\ky|t#㇋UQwod,i^w-!fz޹<փWW)oͻ_Wy'n-7+w^IB[w|aMژu˟b?Ϣ/ -a|%$*-w x$/sMB;wZ'>^HyۅM7`߽qYz| O.~~jW<;Q{Ȝ{0 �Åh ro -i\hM͑6&ܭnȹ^Ttj՜͗ӪL:u3ҳ+N_Ip#زU\Xybr5k.4P2"Gͷ;7sg~G/´:OfFsG/:pOOen ?]._?~~Xhyujޓ$/|F|Z3n+>}ӊ'_֊/<FU՗]Ϫw-͸wb˿[~<u+͸ujzK.g\-m7KŅ)[Cz g:=/s*a-^t#|3w&[q3JN_i_ܛoM[}sw3"k Y Oy<W%zlųM7of6k_':_>x̎E 7Ӫw^KޫIU_y:y)ĹԆRj^HnUp[ baG\…;뉰6".-\Xy!ZyC˹Ei߼qw&5 -6ͩx66V +-٨?.Ro,5u}ݳZɶk`{r<wRD0O9y5j䪍ӪH:{'b:g{멿>Kwy& vMR=_-MVP|5~̚gjԅ^W~.sKRgǫwGwKܑvb˿xw\ h_ҹ/Yx|1/e][xw#ծ߬t~t=U[=nuei,esr˰e:S/$|nfCZߧ]&b7Kz#.~[ 7ޮ wǛHkײͿaIM., -\gk5'_i׼RFC݆Ⳬi쭇 ;wZRU5_mhy:wUruOGu/U>FesЃz濞ҏ's"y١[:og4*j~,H=-eg,[QK]x,'zuMޕ 2ݫy6:bqUpG[U̫Y? ;}pڬkI>y>=ߥW.zYu>O}ykᕢcߧT{.b YƕG9t]֭zL]xo"t'lGL; $ԔvT~g_-jo>[T:ph׹ -E -GQ茳*,S4g -'b9˼ģϔ̧~yrjɼڝdT.m8UPtVuu;mo^</xz֖_,hZ]Nn�8T+i'~;~7b=c+_'sl9ycPWPU U>Rxkbl^PHtX`'bొ1ъ]G(9Q1$ c5)Sf*.W՛^{Ùw$ݛw?z>c=âJֽ"*A 0`DQLLw+v7"$g JècŜf {z.}<\~sq4 ݮZUuZu;.6]UsjVWjo767UޖkKM{I׵\)i1:կ)̻y>Ni<Z{?ĞNe䝶e_S+V޽fz\#wH4j7Ym =t.~ ?!d17B3ђj ǔN- OBW!-ɍG +߼(|vEKu;/aXBQѫugel_q݉9ug/\Uy#ɓ -u|էi[UFW!0ץbe,4ifk܂W{zl3q\1a `4i!MۥԐ5+պO5}5zd4s-] Sw N5(;_ZxJI} 귞/?p.ܺskɫݏ澫u/_˨YwU)R66y}9C#|pnYV@~uKC 5C�iaȵll•G=ټ\a95.︒_mLͩYՅ*k_ɩkZT|{=rg?r 5Orjb\ΎYmL_!<dG~KkFZv/;]y\$96m0EAXν8ŭЧ'j#6mnNt e>lЙ†rH-=z>W72k_-ßJ$h/B5A q>꟯ƍ)hInO髯otz}þ6;trN+95^<x\^+uyUMJ+om֏Yurj -? ܊8EQ1}>Arq̩A)|mj96a:@Z㑅+Yw?ܩ -~uEʫn|8ageWث_s1yo{-&MuS5;T SJ K^??^j|@ɕWH %w m!tl4eArXW}`+#?*Vwcݥud=쬿{.ӵ q>͏l{#̥F<>]kt磠T1&s뿳 vwIsjCFvh$9옌(o,~"Y~a謁Sg/t|~G՜_ȭPTuؿ5* {ww3uu;9g?/Ch%f$ c hxda uh\ya|6[?�P{Q}_ySяaSF@L W3<Nݍs' ~]/'.VAV CU6 FA#M|d6E&Cf"A3tdug!S}wNh0dCõW"# -b'7abAE[^\|{pw7򶼿nvǓ[ r)>a}@iY!CM3P܋Td iMC:D61{mVw/,cIߜn>oJZkq!żM7g7_|bn+==}%^oVT\p2ݖ?&]b}~>χ~4F~0CL%b sk2/AfnhX/4jl}¬C/ 3/Ofל'quG/جja3!w/8v-Ŝq|BDmP}]`'ˠI9Khdk g K[4?(d1E,hD -#Fȑw3hQ!n/;!<с)~قMWo>嬺׳>g6^fٛ &MPY_P =<{kL͑d?MǶy225o27Ž!%ml(k%7#M.Eva4lxmxHq*}/,[vb -kzN_fVs/eu=AK}8(v',0=6ڊH?3R7GF8C911�P0dOmLǤ,ţYh MZd -=h_/f1o$_ؼbMpuȵ솣]jxޗfVssֺ]/ =x* 3d=i$&!c N}2ӱ l7퐅4fDKRx<4%Y,֠nFZfnQ_Pl1a}1{j9u;�9Æͫ6_yƒdR}s/$Ĉ{ib_gm52<"iLMqƢzXo,1l -25Y#hh4~q/Ecˑm^u{zK -\ -8Q8YwkCՙ' 5<m~.ڗӪ~Iw2گ&VÖ :\3}hN&,]A#8=[FdM!l2f1xWQ5n|8ġG0_/v%?g]岚% v64OngmnfVNǫ,XKz*K'8`? p[p?YvBcp;l+"~63<F/B# K3G4jYNbиّ-Mwο1xV]E]t x-?>I|~lM͆Su7u_xl~ /.½xJq.,q\{lȸ]MD`%uIz$2d:tx¬4=ME&KѸ1%F>o5r>)h4@tQ4#ḫz?ka{aKYQ-{:ưo<yfmsuͱ{6w>^mk6OjZXNgۦM3aȌ=4Ѳ1(<͐<-2냬xIU/)Y`ң¤EnPx׆ ro/H9:xNɮ'Brq7$<j|rr5Bz!ĕھ5ei{-8%1a|Bdl62MA+ &ETi5mK/i^MgN3Ri:5ܲ'sKͺ2x^AC -EKw ֎OL]zI},BJZY];psIH3= ծ<}\\wR>Yza\>> #7df#AWT1F*4'j}]E=Sn so -,o8/r E W[SkqnҧNM?r=*ϯBIܧ>o޳oc6%7?/.w݉7ő_?ުމT�DGe`=f8֟F[IةA>MtOC"4s58MѤinMǣyTģq[!KvċՊ~9Uo>Os_yo~=g`'HF/~^ {Mc _3>J *Vp>+,oFcYƥ:dm8 Xo<&G=b=UЙhat悚+K/ -S*sO&qo -_ǏAYq~OLGD[vC>_sϼz|W˲WumzM$ClX[}rt0}u IF٣2E1ga!7Gt~,88渽&,OW[{#?.Ne|XCc`qD! J3?ߩ>\wDpF;͙Q>F#Ssf"}(el!sؚ7@zLf>͖ !ZпM gk ?Gv*s̗/BW!^ۂ{%!P?!TAHV8ISRVRRNpwTs!ʷyCVM=?z2_dMgQU'Qm1+_Qn\~p?m0ѕg+.`?f.WQ!Y ]. DFcq=f!=ko/.x>=O =Nyt4=#oGãkDx}8nxjmqNoak˂7Qidh/BR5%;<@ܟV<8;<$Zy/LJ%?Q_[w㏽ } -9)8ڡ7vg0>c 9ZWs:5^Z)~s>_lw@BD-o=|3q氷?{}JZ}-8"Qْ%_I󂥾z/W/*X/GT@IKBvϢ.Mu|\([bP/5#>Z}Zhk#Ir4?\ͱH4^fп?/`}Sp{.s8uJXG'9JjMrXX`Nr<$WfHS@lj{w;\yvhh\sߢӂ.z{IߺRvIׇm&CKa).hO<ZgWTax]!o|ó| KGDuL/ʏ؊|~H0-Qg`dgщeCwdOtT ZWn|kwlrczj_]3?y>3&-X֭1Ewh9ErO92-玟la/NΝM۟2 -K%MgJ?{~[bh#a5Ͷ@rOR7bM̒P'sy?SRف_e&/?8QYfDUmH{$&{4O~w7Y,mYh<2AԽx-:vseLi ⮏Dmfz6uVt @o9u)B՜65s/zxÏw~7ѽ`Gb(oƞ坖ڽ]=9*OM;GIM\Z&k%k[6 -Z_I%H -V3- dg6#tv. {9Gx}ZDzy-wV<[xjܝղݠʨ5'.>})%Rh+d<8)FN9=\XH -.Ib_ˤ!SKl4"}stCsh(R+DwX֌2S:jKUaĮ=0I;tmel5LIt+g"t]T/ww('y~ou#jiЇKu/~Ҥ?z%P^^)!C\ͯ4ћ5W̱9ybR/$#RQ Uv[B'LEKA"g' K6H6Y3, r~q!>R?zHw^"/鲤z=İVgwi9]6Ϣ״Q:LzpYÅ̮Twi{\i7$wU]Ss?/8xD޿ -J#:-_8)wq+mQhHZ0e rGbÒل}E!`/N -_[tXR5QUf볩R.fZ19-LnBթ!O'UKo4W{u3A\{/u<YǬ1\OYyg3tߡ|h{}\B -BEM=}nrY9/X:"~(_+ I< -h^*InAh`ȷ<^ -s*9N\g@m0b*MUCpĪon,S~Rm{ʹ>_,o{>W%J]܁xl멲C?_cBk0oÃZKDD iR07Zl|<U 9NC]X4|9-rF^n"$Hn9>g2GA#7x/]YtuWgQɍƲr}U$2e&3gGoIutܷOK[f|'ie/ b/=⢭cɖЇH2k6 'WJp5y x<=j@KO\j ZTtk/Ww{< y$cvj2\Zp.Âh՜Z=t{ Żqԑҝ?ȶTə9]~?,Zgyzfue=s�Փ%}{?OrJD e6sE"of(}!CVq|HR]%Jє+ԝxNZ?L['7".P 43@ H*7QV~3;][zD*Yd8-^Pϭb <Of>i]h[{smDli̺xYE?zP'љU&TNifpI1+ĩیRݩX5eNRɓ иAh8ΛfF. ]"#&:by \k)£hV*!π_5;}OTݥY颽%QFSx*?Qב97ﲤ6k{ǃv u使nr?%㤅-eqz/>(nJH.3qOuk}p-V!"YE<p`[8n6=iPŴ/>r?qzq&}јN4ԙ뱟Q~g%ԙ̉* ܋e2]qb`5IJ ߢw:~EKySoUC.Z+.-CƣC/ke+hԤSe5l?s <6*̀ѓGuI%FÅi1:<(=T2[FѩFkȤ͘.cW"B/ϋUMɾDf{Ac3'%VtL8N,(m:?Hm, v Ѣy.IԠR]c7Y뚠CѴab@|ybPZwĖk8w2) $ZH,ȯa:.-w/ı-喝l^ܾh֧$ -tjT얷dWanK5e<gz&eμ -f? fOt -vXʢ tt;H :鄍EGd3vĪӫj XGP|aKOuB}&}8l0eld塩TLgf+vK1Z|FuNj'mrY͜x q맅ptjPy\Sv`|'jGgͤMJ 2SA뗥f#Q03i&5@ gFW\=o?E t#Oo iSk@{ h"ht:%Ŷ -W'ƳǮt'sٝE= -lvk.y$hbCO̞ݨ<&n�!WeNmmb}&WiiyE4I[{w]c$aZ~<LMIo4^0=-<b)Cmxڝ6+K:tW( 13jA_e"ԑb?0ɪ3c -,һ?P߻UزkZ�x6܈e5$MYDWdLtw,]wl%D7j'jkː$hҠ4M*T <z' J= f6[l{`|/+F3 C镥tL.1#=M䪯m囯/JUoNg//o6ž_PkޟdYfĚaQ?;z;CǦl'g/KЂ5 2L4͑vܳFj:/A-@ ="F2e<yt|tY&0(KXZk•>\c\:8pY SW-K Ƕ-'Ơ㨮K쎧Pʕ=A둓b]T㭓tw£X]ŲٵۭٜTՁ)=H7Jqqw,ƐJ5:/w[J_?0n3'Oi2vr!v}/'d2Y@:(F4:AJ%l~[f o1\8O ,3؍ǦuMۥ\nʄ+;Xtz `~i2':kp>cc&s%V;Kס -mԲA5:|Ш-O׆:i̗3/D@㙊-`zwyAm{Lm&x[w"hN4@{nаz^yp۟٣TO9ٶN̆ y9Ծw~ԞWgSY氮&Om0˱|b=Ў)\ Ѡl4yt9Բ<΃ܑø@+)RkX9XZSX= (U}3u@h\vQ}YףEx>:0 Ggm} -wU=d\ f-7fwoEܱ;OܻTNr*2Y #ܵcvZ\zo>s7-_1eLǷo@_)/=4^h30[ 1<s|a=3My*|]+=we Ä,ïMtz;oٶNmF5ݷ-:`08\Ybn`mQgʥm0a2M\%m0d61 |}ze`7p@lj ԷR玠oMXE8ib|1L1& f _# rЌ!Tˆ-lZOtݙ٠=lIt/B3a&!Goƕ-c ]@N t8Af鈤* ._-Lsۑ[{`Hܖx _QIZ|Ѡ#:@Ll0@/"H%h+ Z2,fMTڞ|i|T~$,CȈ#'\ z= -njƒxkZ9*QB]>uLD隽+8IТ @Ӊ͕#VũKB5}ġn"64Ušzs%iQzgSLIorZW}t&ҁ|f9I&Ɂ)o L9)k&U+ cw[Z ԪC@#Z]9Lmfm]z#&ӚGȗ%ka($OG -`?_Sj .ࠂ7_ka4uhhF%U!h}Ȼ,�aOOI? yH *(zW7gMĊuF&\H>j6JJcCZC0VNK$<CVj)|N90Ёu2 c5yX6Y>HE"j̸ҭq޾t-<\͑YDnWvr]yȉO~?hC֞sT||9IiA:LP0e+47b*Zd -9<Tq/Z0i>r[ꇤa)Z2U]]<%81"%`5i/:4QKF/SCVi&LٞI`A:W+F [;_G ڃ>YzjyD; u.K"S�6 -l]`sњIxx|&X#&$JOc,pRv@Ha-e14E*PV].`VqڠS6_ZW -|l}eavՁhnvN`*=TB>K\sMT&Ƅ)֓VTC0`^J5jE6a vX1 A8>_\e Zk›)h'tҁ%>x[̪uCc0mT!zRY{xvW|ǝ;>%p9tn>䃊DTף\f N5&=\@4'dOk{٭pn^x>*ңV+bթTm*E9 8-ܜ@3DMA'W1vg* A'T G8HY>CE -OTؾ~y-uv-fb27ɷTs`1exnϟF0.NzxȑAr p wO)Q-oŧP<\E3Ưgf"@mmtJSk5]Ow\[UnpX�OC;Rz̪yH&o3L[;-b]6*[OtctE|u=hG @҃0Oa3F$^<1ԑxxlX -s hg�}c&ےOa_]ϽU]wAݷ-}@?ѪCَ|[ $&ñ Su,u^l01}~n뤠w!~?;' ;ZVN1ˇPӴlbWhRD25`#kZEtx0*է muayB6\4y.ЀwlqW".M?M3ҝ?0M@QX}�Y]> tٵ'm�v"sZYrڭr,!C!9z7Ao Ao_E'LP4]5_]\V% x~ Wa Z3s}(4KPuV}U+랄px*T04`w6.[bsX{ -X3c -{DzkF#hcaGw~6]ǐ~|zѮ"|r^`fY+>Ƽ;hO֛K}/ \?`0o,w[ :&B/\璝Lۓ%Η.Œ ]֜b:oKak U;p5^|5YRl|+7X}gC7Õ_= -7Nc$T Cs@஋jȭ3I`q'ezʈ1U@PU~hf@։2CEafsRemO2}B -z׫ q}fgQ8.\<r?hmq\a-f^UVhUJhd5Z,Zt /ؐdt=ϑW׏T?4_H!l|^-nvcdn=LdqDwWjMֻ~TDrʎKq=4!Q5Bpl_^y hӫ -ƃ@f݁tz}Yh=/QUK%;'A�E$p` -\C[2.V|0=R WVL!@_om*GYzl:=$cR& % zv@stwDuc{VՎp2-@;n{4)>8<s6U"BOLR[.х:9paX`}:6�w`ya*poNoDi_$ܬJw0ЁyLW`?MY~uPܕ1Z^+ M֐Qǭ+4PEhʆ$ksD6Wh*>}n`@$7pf6 -anaIÃb X5-nE鶉T3W]=|vNS-{&6؁-O<Gd\K7h>p2G;K -#,Y] ?["_J" - l! lxK=aR>p7?q%q).c X%TxZ1Ή[Åg +2x S#`6 VNj)o.4GK#TН|COBC/Qn/f+L&y(6N6"1 gZ4|&h8./>Vs^1ppP)HG.�:,Q[MJ h+=#"|m`g; wCy@3Vgv]'q\:W`Zl�+`>cdM$x(BLMtN%Z~q%ÀWQ5Rdž=7-=vG 12b2p[GhqPKљ3\yWZ؏F1ktց# *GQʸ vV%r -@1L / 2&E3;k^G+NNTbFtWnWzHPL_oKUn%h2-,#<x?Cޟ;NKЬᱚRbZ=1;xmɛnSwCw~c՝ Ga34`h*37Rv/Kц5 5ՕFせ%Bt8j;!;FF[I -lj&ᰮ*JXEʜ&KUr� SG%E{-syvSəD(�ܤؿDR V-KQE(W#7Sg׎T6Ydt\i{`} nUXہ)ʺc {me{f[Qfmw{k%U13oƵv�9l=7BX]ca,Rq}&6vxZ,a<&+v!7wvV�;+�Aњ_*aI0wA_b фg< s9#wi{ ?0y)~Eǁ6aAQwvK`) -S}3a;Νtd l<~;a iNnz&?�pˏ⑘W)PֳE2%&6m[unĒ|\I0eHe2ӀMcy9a)ck[{hÞY]yq5�oY"+;Kpv`; w2ceRTȂ!hٰ8-E,6/ D`s/Z."4 -| 7>TM1N[#Fq)躉>瀬QZ ׯn~SB[E;'R- ;m@YYSrZV7aSAY*';+3;+vV &0Rbqnq;ļd ߀X`<?k-@ޏ~~ - S. /?4<mZ*br,r `~+2s>͏ -Zi\ 1^ -$qN9F$, D_Sa υ5 NSa8l4* -`sˑAF&c{\m\X$~{\U-O| ; 4ңSuddg|fg U픉%d`58wmýRUzei ߚ#{e+~4DxM^;_^-Wݘ+K3O`e6[Aof<{T\Rֻ"Elhft]⚮.ù�_rv%W>'ˆէ#IhQ`g0_ime[eF Z*jNةJOv">KuUn[d�Z߂P�Lպ}S+!=|ܞmk;sL2! <ºkK;\SӊJב0u$M -wKC5ڪoUG�l2aTe=? *g%/TqY`1UVh#_#]XyO~vkfQַ=:8b ~'e -7F*C!N>f7<8��&;0/�f0\o`A_X�"Wv<pQVA&e2/ȷpuuʮ>o?1Bp 7W {'L\.ܗbjN̢v!#Yݓ+1Z Ys>9Yex|t6;`=m>;|Yo>_lIbMl0x܎.u%rg-sI,6 0J{l>'ѷބ?TxOGҚ̙-rTXPCC\D6;RαH4Ibi04mXQ3�2*UWބ|%󦄰dTB,@|_u9ی -֍G$# ]UV(`wA[s/6jL:S~5 /t9 KS~a aRH1x$(7mB>Jb~(`V: s /(0PUe  ġ|58Gxpl .*b'pp;8tm80 4(U[\`\#E595# 8o?SsHޖ<:2 qy#Ҵ8gSZL(yc?Ycmj:Iʂ9C]cWum>mYȚUyd †+ )<G -w^s`sWNM ܑ"н"37q> Hf_]`,{xD37vP՘V38& n+nxry eH& @LD ]LŹ.A2JFXR_"Lcks9L9RsYXbEkk lWSa-|4CVjG+N"|rTckPKW{Vyk0.JLQ�jUf+՝-<>QU-{װ<Ѱvw{:;LaCa_HBm_H=@Ӈfmsז(D1YN`bϡ>v/ͅp:FT{ -y$Nɬ*h"}Oϥ΀ueuW -+I#x޳mXeR'22y3vO`�Ұn" ΰSV#:c)Ĭ྄{}m{g`O Z%0F�SƘ~^8U ~p9e�銲]a AB̨H7 L,!FsSLRԞ3b<)KLRkÞ6&KW -K`2[GT�>.S/syDA6\zȳ},ܿ ^^>[GE[qBpl9a]u�v{q 10 KMSXJk7췥;9)wܖ'WR{kt WZ`y{|lrO';x [,}@X1rhG@]"_}<%WҀ\Us�M߈LO[̫ bۯ.}z&4S[̭Pc_VŊjdOdfs+궢7گ8PQ>&Xe؇)S̀U�6G-؆ -c\p izEr1߅mT(·s&o5Ge8rwC[9<f421"}4c3tk΅xxZž-eQ5݀y);8pW7"{1m -Vk -LgY-٭8FԘ zš Cas #`bG8Wuv<q` hS{b#ĄLˉy|% N~(aSJ ɽRM1)8ކ,:+tM Ovmr>l88^k<wn"0a /#k J6 ̭<mcS#ٔZH`K5O,^ 8ҞK_q=/O}ݓeP ~`2+1 M—r|9_/Ǘr|9_/Ǘr|9_/Ǘr|9_/Ǘr|9_/DŽ naCtY!WK3]#C#bRk/j`e83p^dV6N^fwN;sl;h+¿'D./B?Bg.ENe>sU%m_uoP1aVe+CfZ9 ѝi&ÿNCtWÓYV3 -?yg+kVfZY)T3Y][3[ϟio?ͳ> ~~<Ϸ>%?<YGF;|~NGL'z ѝXcVʒ?sf[f͆.W[ᓘ5\:;+\'`e7k޼xyzz1y1O&aÏQSj"P5?q]Gjlm(Gdj#2aIZJu7'1ZysHDGVQ,ruGkrui*-x *&OWHW# D~RSDMyx iP U3dm.E2u(mAoH5:"USTiA&) e4Cy-Ճ2kRNJZ$;C y @ &RS%  rL(5>&S^i:xE6 +"eOSb T _dPL="-2f:@R0a+JmR5 PCG֦%2tDd[e 5Ƃ@n\2LY;Y9ʟjLj-s m/6A@)*\τuD6)Rm,2Y]l&V׫*fY`UHrD#ќl='29E@BNH(-d<CҠ udt7H?#$`5̓ !h"!@~P#(Y)b4=t(gtsEP -RLd.Y+Ip1H<`mzdJU+5x!F~PRV 71r6N^\@8H <@Iɨ5m=ULbu*scU]ۋA]DBa r$Z&0~d:2Y[e$ -j;@QuNUaŦ@Co#2-c`UJHS7"*�d*UZ y3t`E(uل,}( l|b""S[@2„e)0R>,V _2<6 L_U{tUr)e8A@RZkJJ+ al*s:EP:e S0+e*x<rD<䷨k7\l.)oI+4R嶍V V$&+Pj�FDkq-|= m;2x4|}Iᇔ_'ȇjd<C$T�W8?eòAS9*L͟YFqLK1T =+r@ -((K@,Q+ -x 8MŊ<=e᪄2#eL2*U_*LP(HӆZ.c)O(Kp$PJ2|_RpOu#3ʿU+^` %*6 Gf휬$[&2 ?G@l?kղm /#sT@r^W7 QPQ9H4M9(s}~߃%4BUsVG&#̄9W(,+~$ueg85#p!\ 0Itm.,c/-d-Y#9 4klxd/ l\Dzn x>b1_(K !b.U 7NXE % -rcZI KG8"0$1VxHQ@\iچF hHBG[BX&f r?X?c!pZKO@r!QQ $!Hx1-8RD9h w{l8) R !w\NGu I,r/@XYڏY) oJs 4k'>j7 /sq$,;J|h8GٌA^2\12qA7W6q~WM-z>*p ps&:8#X  :Ib8.)DGq(#?XnK`�2RpM0((J|78Gh,4~7H1W#r~Y AZ웻H2s U>A>qN*\N{a4Ę"h`)b:a<p?@r݈ [( \F-e|f(s~8H9 pQ%A@$ůX,=,N ǭ F0KDb938*@6V}H MlCRZ /q,p<恜|4_w怀Q.wA-n6gA='U�.2&cgc(1IJ-ΈE(`([ـ)Xr `οPQDXC13o0Y:LQ#$0/A -¼H^'&�Il Kᣑ<p})H5xk)Hq}'tOG[Mk Wr 2( _S�Av>5p^Z�/pk148bld,;9Nxy$edrc~);5dHpoX$ /P~QNky-T�6,�n=\Mŕlßr#'3 ]LۍUx=CiKy}(*68w<8uX^,/EjcLŅU;y]|HK< BɁy) {qY |=AK .ĞpG^`שp/EyXxG9x?I9F|Bq�|\qH -L: de؝ ōɢ1VǹɌc�l/xc ')$)l|'}i>H�,ZK2 <ӧv c�t8,X)睻 -{71w7Q & nAޛ:6,, \7sm1r=}D -|nXK Z`[rHͥ`�2t9ďaS W!VL67J&̈́2@J Pc O\6!rID5᷅� #:>9To`cXЩX>"EGGᜈWTG+AZcw`jnj_�kPޚ� <?X`xHph@Y_X_�1@mQ#q[pBoGuhEPd~~K<C36Kdk͚ N\_d`߁ CXy$m< ofQ#c Mz;pDv~5ʱQTsDYypn81XyA|2']g8./@ -i2zI QP3d:Hꁵ�?qF9qQ[a~AnYT,!ej9Tha=T`n3G톃.H'|PJv(&^cHۡPNQrPA=M`l-XQ m@zո^h-arN<�\¦ Sw9}T;&&8tj 8Jj# ,4?5 z8 sq aH衠Z:v6HJ!N`4;y~4Oo -3`0pjmđH]!n Cv - ]V(X"|4(g- -%�s2ְX{#�<|:[)�Kמޣ؃ 0xCFNK `ykq@c4`%`LN1}򂆚.03XΟz�dc6pAĜ  ]a'S@siRGG -Q]mj}#c€5,#(v9JA^^(:%r HZy(09=1зDPp6}� uտ�GX/6ai%ո @]nӡo|0^U*V03`T9*J̅ HsAx+ģ{]q(BI8(7z}g�H�Yk1 zw2bKq8L <zC>rP9b~ Ȕ]n\$gb y%&2mn/ dYK߱kVGxiX!_bna" -62NqӁRGG9WLkڍe\%e</eeۘze6vT)2('̆L&%]T=DwW0W1E5u2 .t:+SXع7DPs Dq}'0~YT: - -endstream endobj 99 0 obj <</Length 65536>>stream -"4s5Hc5k<pA*bY`nD1G]F']FBl$Piܫyh~St.ԁVÝ\˥񜀥&m^I^d)SN 9K9˂ 88WX69 A]:y'OL! ;볅^ -^#荋mQN >(q+I\C%`|A~ud%..hX)}>HDd;&S;TUDǖ:2@:jcf<[AScҞY@^dg -e9>:<r-9>J0D *TRN2v#-܂%^N@|Og#n 2’m PÅ<Y [ +(Hkށe,]FSOzz$MKRs)ix0m8A?X {s!_|5{*j6rL8?VIe{ѽ*| ✐I"-":0 -ք~?u1ЯBeo#dӆ>^K]i9Af/ -u$e8Pӱ&C;ł"6š8IJY 6d_' -~y$aIϟrECKg Ƃ׆e#~P .he|5AWCM] Hm_CL{M$Q@"3?aa2}l[K(Ӡw-:joy[i\Ki`Flkp6`KU\B^Qr>'8 5kt]q61X^[xE3Kŏ{ :vU瑠{ -:Dsa4DxF_+JQ<R:x9 xܯ+萇+q݆j%G!*~771'&?u&jUtu/c@q81vϜϹ)-;,2|x6R,}&lCMTכtv 6lCqss-Y˓)AUT# l^N#�,Yπ~6*Qel롸^Yx^"P"EJb#XAoVC 4,!,$+ڲqA -`q1B!lC! -ag.b DLm~P"v W -;-Ĥ ڠ (VMiCi m&n j;e w -s50XQsy_Y,LV[{neeo){脷;%\'HgF?` %,Zi0{C^npu 0ח`yg\%XX|<2`!'A_:4dl`ma$Bw<X_ CPaE)[lCᗢO@☈?`P- -@W9hT{$+ɳ!S:|=tٌLН>gt Q�95X?54X -K;!G@uql<^KL2L5a:<r(9p݆m(й 8 -18`=GO63M A)ͧWwaGj"yz0yJ*AG[6) _.VU)s_w#kfQb4fBo߁^s6QLBK">R)`{%O5?}?:?Lb*=O9&:�+ -`.<EB? ,�HDz ANj KĩʝGgTbaV0|QF.iлG|[W]PPnDӆB ֮tĄ'-l'}I7k #gG@K=裀<! y+]Rxj%Kd6(m|v$h-?E'Qg[Cocܷ?5 O[!ئPUehPqP$gq@1d{1ՆkІ8l#Fbj#C{\GBw'=0[JT"_~[ Ů0O[q8-qPn-ώ=<PSk$9QeAFj!򈜞O9>�0~MxE,=Nk{w zFG>,NokX{c9[_Q΄~!XaB]V`r&prPD&,%պOpOͩM` 6z An<FC# {m(4)B[$#N#%`' 5N -GsO:!8EM;1.^'؂E=^O^l Ҍ0 AӰx+Q Q$dԽuLv&Hna_BQFqvwCT&Vm6h0W  _ P[hr`քЇV>Px PpjCa p<):&. <Oŗ`b1wA#tQ|/:3{4~K<//`fQ9j`k^ۆz <=u9VlCA8?R|od'HR%Vc@:<>Ӑ;*GS'4 =^I[L G6q=z=gP- ΥQ8p>d*^n $Ldvh`+!fiCqfP\[ 2I[3B󉄽'kfa/G@P(&LJr§a{s᝵ -H>Fo)xB*�S8ߔ ,{Ң^lւ;+ e{Ĺlj~F|3`[ лA@B50oPÚ_64fukr‹M̅Cq!8b7\xk_6TbNeSbZ1w+'+0>rۃƊJ*&WcQi0{ -ڍ,}-&5 # .Bt{\ҁ!EWB&l'T 5 S<C1ʞms۵ķjLW[X* ->I,<4 ̬&C PB B#|5oEz&Ia+ wVK|..|t$د}lxZ/yE+0`pPp=�s$'H|w 4sp@g&l&㸇g|&5;ފ8ZUWkfGwX.\={liס&C�l#мeZYQ%Fjk`;gk4)[m$tK6?cBfsPuQaM4‹*`Cw9鰉`N<]m(C:*8{)8Ĺ؆{ІB${&L?b[Tx)a7Tbc<Z¤ת$YL*ȨJo?2Taߏ!5(W$ _,JoR" -}kB`kPC/ !DjIG/OTW@=_Mۥ(>ԚP/u!1%v*uĻ&⃚wc$GvT0W,򊚍%aYoB5քb7X4W 0Xq6^p(m4//?�lP|CC2}IR4 jE~&68 ,6VӼ_rIk{V�֩t4&\Aol#Cn/+\*]==Ltfe"GG`ņD+^N POJi5Zx#i{%Z%/ -/**&bE6 {1TKRT2iGel_UJa9#X>2l7?;#lse�BI?j9uftV:ty 2,Is4^!f!afƢ\<J٤"'!{X6(ρ)C?D{pF} -`ʺD :8;3]|wA�( u*X߃!Q^+U +X{�ģ·NΌ{dP>K@Y`7Ztxy9683jf&X -:= -'Cأۡgۡ&up@]q*XYF[ "kȜGGZ-̨-L,B_]DL=Hkl|#+rP~37q/6 e V}dlmtg%X,{`8]w}ٳa},k x_"T3, -47sQ1VxO$7uv5i{š}}cxoKlXڇ<v28 : lMvQbÊ7`3f|s^<C,AKx~/;PB/\o]R<`8k,7`߃ Ntw-YZ=>&_BB+{> )^=,g0/L8 -L 1~-(~:sy/h6"ffi:n0wŒ=`ɞ Lt]`5BN;1_+\ v_M"<U큾 -&7r> OԳz;JeP0ġZ sZA/8T}V&ocC^}i47`ۘ_] -k>6m8EX]ea}yqTn v{&div"]|gn,9%v0ӡW"ύS}47.2q8?o59xQѰhc{NޒIy O`¸͡#S[`./˜N -0 ރSk=HWSҊ-`WyװO+uKEV`?Bb 7c -<>J?>;+00ʗS~xa"o�/ܿDqR$+A[3*z;8s š;B'm.O(i廩gI`[kFG>�620Ze24u(砜}e`mE7ܟy@մ=~&EEXnե{ɍ;q܇dr6:*7B[si!. -&kˍdRv?{>^ձpۘdz2Y ##a#lL3P{EY:`Ɏp jX> ϋJHϪ_Ϲf΅=dnlA`O2`p]#Ŝuu>|wP.pVxm$9e:7W(- �uOWUodǃԽ u铖0~2_m=n>,~Yoýj:A?u& )$Vc/{6h.aCeҚI.ՓB2CQ|ll6U⒄1ԕdrNψžm}dJN5'L;m:ѧJuxEƹ=ؐ7ƕ4p 'ݡ -B($X@qז^*/zs|d|,"d%Y{f=6Q% 5B^0j; 5ޡ {GK5k-`OMz'4-Hl.F?1;ͼ➴5@?+Ykhn4&m2atdD:2Za\V{{]I^pq^~!iSZ `-+%Ugﴱ̍_}4g1ںW }u7ڲv͚CTW5*Z>]mߒ5-+!~!P2E!b"+* -x -H2E=Ѓ/^{\Ͻ o'?obMo4ͨ/Nl;? Uކ);NRQUֺz-G"{p\V$PX*N?@5Gسƕ NiS.\'E)jǫV4L/varwW"6 -֎c(u:ȏ=n;me'E-D;H2_Ln!Rft2iVW]Gfsnu1ZE-^ӢU&tf n0[=!Wk!.!ƨ]jlV&ײKj%Kgժʀ}L¿=f!xG~Q~Ru[Gx_QQ~A<E8Ð>u]Gxd5H-uzFw~>L1 ^D+˖reUN&/ߞ5yfԢC׀Do\ -GbnI ,8x؄IigxJv(^Zqk; -kѭcn!綑K Ѣ)e{4+F񿵄o֥Q<($eӠ{~Q$~fma=ya3o)xyC]_X$ŎE}-=~5 t6tK?OWQd{q D7[Œ&ʭȷ3}Plݮs -۶$j0zd|6AϘiE8/X#0^ujM*CXTnrwMD뎉7Z n-|E@= a_۰'A>0c -ڏQ?K{l^kdWߌ/d'SZ^/( U;OߙR7  aj.a֧0۝s52:MKݹiӓ<< -y\nhNF;i2eWj -o~a ɻF$OB=ļf;O%'wgS~MCn"}v K4 lW(n1T[dtCID91v:eRЯ2Yexػbs'֩aV].MK3-|O"lm(u@C*4U}L޸`k/RGYqf(�sPQ(14'9]#H"ٍT 2v}~t7_v-Wz%C[U~!H5;vݝx)5DDuCӚ~5`8$Wѯ,~dmRX*yz}0ugws\IIkq(WľjUًK]L .JZl/EoꬹS̋N UAyJ+qA WXe0 {QНE oC1o@7J%}&şi -9ԨOa/Gw؁�qܧP)Eҫ'| -L^=m0~QqVZrfNjSA;<z'>fƓܣf›u im\e]\o]}dG${' Z+}Eev>͆iq7ym<ֲZuKFmCrٺ٩x˶\q~8=[Pq@;1E=L{ԯ\ Kt~t7fRӺ COb;_Ʋ͎了wx# he!'r:[ofRf~=Ŷ)3hd�kRt@tݧW%gM%/+O3[E3LG8sqI%>ҠXC=b -"ş^/u-uUY%nI=}7h80CKy oox&s wޏS0y\{F0°ՆիOђ@Χ G:%VG\W1`JP'=$8]f+vw11z$Ք9M]/f~N6?Zj͎OKJO K>Ӓl}'N2~j}k 6s)-X[̴aQ͏#7G_mCy_ /�ܕ9vVqv@ڮ$U&cn&/}T^YWy*]GM9D^e(-Y#|< וyy$pDIgY]@Y٦dﺐjxߺtqkU~[GcD_lTglv4%jk4@YpI`Lp|C\ゥ''/ůkqO2Z(JcS�o|jK<r1պRU˵TqgM UҰobA폣ª{<27_]22]u.A(լOݩo+N4 -<~#Q̱;ɶMxߚ熰* -w::saEvU5ve*R{e.e1e֍q^k̺I= ;0o|3D:>i_UK]}Ŗu6]L;oSEޓ(Pi[%[n$|N(*=.i.7FY~%yS(PӸ#7w_o ݪvG6Elx>GG<v]z,CZ) -|*+YeFxvvIiIcQiGqM 0o,n:⋙'2(ݭFnV$e,W~4Jn"E~+b<mRӎ]K1-BXkW}m7+sh%'չy%[椊?3G;o&z5$y7'ԹKV;GfsC4N/ʝϋnJ˼cuň>; lAWZg'*i*j`nH/VzUDĻWGħ{W%S] ^FM#B|c3e1(RR"*SFu^:6𻭚nWԄY]˲4V8g"a1jKtf{ZFF=7_{<G ae?'ã0*R"XԘS iZrzHB-m_ɫbzȬ,TsNɖܤn}cI,_7{S:puYAoi2pzWxvGC% z/y-ݜotյO2U7yA"ŲR|DW|B̢7No>b>:WޖV|~s1K\qIMu[.51i1~M➪`ɝpWy{N5fUG';T']-=xmא0iCEYOaEݸ-)AQs߻/P.lOΊ({qV g[<}냒O-dg'ao[jئ?]+,oF1bתPʠbO){ҫER߲hh+~o!3MG;n&zׄ&z.}Q}=߸I3zB9( -k`eP㷮҂b\YUB?G:84ZyCkqE#5:J6:Ƅ5WC>4x-5Ys#M2∭{5w%oV!nEڬLݬG Quz4I5oy5KkYdt ?W1Q�YF4 8'rݕQGo#^Q7>SxClO<<[̬̏t@.F]č(GNާMzv҉DĊJ -\BML!f|șĚ{E$.߾"OM"fAW &$U"f\L(MYM̟XlIߚ_93~N5 -%&oo -߸D)v*(s|%:367ޯ*8ٳ*<)ou<҄Jb> -;=Oz85E6oh=PGf#w \LִϚzKA+䭒fޗwI>]3~QbbBt ӈqb,1WTBI~pf$R^ӱ*sԚyu/ _y{EAlӀǗ>Z܅ꐄ71˯c }d]J.{ <>}&}UUX^)Mhi9w[G|iOtδ(yM_MY}drRBFN璂WTգ*Hb1߇GC_Ez4+yqˈE2Hn ~W%},#-ľ_',Xs+3Y^{×7ܼQ.S)ʿ*8~n\klE6uw#Xp2zFW%f z+B<OG2 }O FLXɜ[`؏�0lz9>7;-*WL[1Qϋ\"+CM?)K|5[7i|Oe{N kk0{SkSXB;۰hyW7&NC05ME7}/W߆aF7 ʁmTu#L{_IGUY裭yvu/E1 cOxE7҇1Ů ,;yF?n(նZ~kyGa?ˆEjn SmiJXҋ@ٍWޱ e=%y# ؗ1oqae~JTwUHEy j/ͪקX8ȭY.7(*Ϙ_)|0#C} BqtbҰ,f 9^MŴAH^Gthqxkv ֍2ePW">:mϓJܣ+govuf}w_p*#F̙1Eֿ+htF x" Qx)L\O,fIl?v}U~;z;TUf?Ó1I%h ܓ_{6%Ֆľ|SCT+iF}$ yK2s.yȮl~gP5g}bST^VV#^{LZԥ":1(Kc5xKc k11}Ґ49Ą! -h Lr\bʰEĄ IVۏRaz \o|�9!ƽ""Xl<xsaLci(��'Y|>*9Ze:Cj_Ɔ/X _/`Cפ8r1}bČ)[ i[ɛSG!&YMLG#ƢSP!7'uG-XU_�nvOL}m2[ -|:z#C{fokZKsRYk2]{+_8<Kq1i"jE(BX26t)1eJbʨUԱ"FgRlbvL›=\_~r!mG|y{|kRn_zS[W|_V#Ϋ,_򿾖p0b4F??qd'qT6i֔lČٻYT9   YĴy%4J+:N {5Yh -cK7{KόF/Խvy]Q?2Ln(N pr$FA 1@LN1i 1knb*1d bF $f-Bb\=b*1sXbk8wnȬ'A1O^y%x&E59Cc|srmkpRx&՘럀9ڄq0|nzv0|1k"b -V1y'8e'1un|mp5V2�b-maݓKu?_ -�w|MG\22Dsu.ծi No\Q-ߵh:6l b<мT{sh 'ǔ icWk[O(،SŤ.1s 1g51o H7X$bcMSƯzϟ+L ~:$qjtmK\eQ++vuWķW:v=S1c{o+kq*8>'7P!1knn$f)& 6Xw <E܉{9/Rhbqܶ ʏez#lkũ!^ёO'W?I哙.!< ޶)1 N) ~ьk\>s-({ El碈cs -z*o1}bʘycrBa**SBi1oqb.7bn41O3Xeq]noݘyeă|NdE [ZCր4-qsjOuZSkSJ ~]% ’A.< -4צ1S!'c8gA-b&_֋_StY 5 ř*<5Bq 1w;s!z˛mSɯWE%Ă 2q/F1RU[)-zIRV^okc<>.#~Q!)iP&f݇b0-3<CsmĬ9zĜ%1QbZF9rOngu-?ٙcB~z7'h~UTTPiEOfQ[W2wP}Q i[(?^`n!h̲ C$&qRur5;b3b2Cb]&By3"NG[I֊*պ!j*xα[3U>{z%p˵HX;VM/S^ǟhd8ƽ.:!>";@OӶm8q87O$1~ r9FQ< J{?y6tWDߴ]{KOy/ٙۥSwO^>v#wVLR/_ǫ|OO_|MjJB=59p͇P˞u.+uj.qtK-qM~ivV20߉Q?s9'0cٓVWhm="X|o誀7f󏆮qy>loMA-c74vf۽+}ȯ[s_ڢ/_^ǫk5v^̳Fs5qYrwvӣ i4/=3,XK9<fL(U%KJb(`yY~Kh9{7hQQ3dahuzOhʛ8|)sc-%oϖ=v o*L? D2?w{Œ5GSI7Py!0&z%Cb -bb5{b-zQbFXRXTX%6 l=p6{3>_ߧY/]-:F>`훝GV9JZW:e^)OVLS3üIY cG0UogX‹U?1]m^ɕeޕRWoĥTm{ysʘĬYE V7t&vO-=j?xC}~cwozZGvԾzyCX+oNMֲn:\4*uܪvy}ހn~%p3M7uurl@ҏ{9Ol,\ix4n(n!2B<׏brxE{[|Ixs!<߮RoPUuEKݢ+=5ѢCDߢ~xWkM yANܷP;?ʆ*(a0IzN5;9uCoL|V3rQԲr>1k ؔG< q KXbq)?rP;o+o?ՈB^G7]qr}З9G/gQFy;vR;w 6> 0FqV -onEN .S&e`?UyL6{].NML9<~7kkt-ǯ W1v絿߁ށ>XvW+-]I M^^B^O/0FQ䑡zmז[]kM>LSh݃vC/m uxAatTVV{l<o7cZs%e rw .St#/~Te;H9W:w̼%qoQXF@lc<WK >?9}w/<o^4.MڪNl޶е>3NQ[7֜tT{2c^%jf\j^Y%޹^?b?O:h>52BqyisoWM$vN1K}*fNSļq!?r1Q%[VIeYLg} nx;'v/@Ѱ|hΑoNpuM^7^?'tHQR"4o#h#eC]? .0uHWI0I Xė4Ω$KMʊ|$Nw;86Pӵ__(|31camqwo0 -,GԲ&vZ_6B=O4yFgkyۮ}e q`a`hB0Bc<t -f"vcLBmBQ1-XG i=і.(3%˦vijtTz>j3CWwۊO /|WMp{V7WUNv8S~ܡ;SvUGS~]E {^$aW';_U .mp.aΝYu .̝/̄sbRoڏrF~54Tw & #7g njb19]`20Sn=G6iCYZ26&ts[,!<sb)`ZE*Wn|p?b5kSČ`~iAp 26]z(2ctl>e:ryxe6u"h܁}݄&W'6HL(τYFq %l$l$$Gigȧ,W8HC^W?9f\VaV*ظM_ckty@U3Mf+wi㔈)#Q=Хk‰~<M~I~O\U]A8AwC>cASPGYP۴ݣJ%>+<sEMgyWla|&a轥T%߭%Mj1[q -g0kKȌνTbN2jA}{_,i.2wg,IJ qsqI)1ooP.U|De:wdNbJǁ-<G=NڿG74%'KAjVo t&Yg\q(q N|ه &{¼ꆹݻ2P:`_75ø [+6\G:( -O87k S*7FZѳY߯co־oT+෫u59^G~k yF9XIp]3ky'55ԉm{l!4t pX1<xf(>K-5d,)'=viu;(ߋJ[ ]6CPg.Np|#ɤϝܣVsqU'샔}H`dֲ2,~T7|q^ߩhu}"HDs!@(KU% %9'Q *gDN&`c0Dv}½;O7Qc’J{֚{ڵQ{OZ~KY>B| zrws۸۹q3gJȶ~㫜y/=aJ,79̤3,4#'@t;_{v|Б<$_[/f3O7?P?k'۾jv8~Ucfpsk>YNo|-79b8wӭ GGR8:Ã۱d uF˹ny~C{^ i*fx__f<w7Sqgt`o;LG>Yɧka{ϒ?4>sBQTSݏ_O= -=}\/=%y_6 L+86ֿ6 -Z^91֔>ޔ8_ رn#~nu7[wBdp̲AKOO -vr̟=կ3Q(ŃoT,l"g6󺧈9m߶M+f`ƿ} g8)I?z"xwŔ2G?hxTo~o/K|Oy靣n5WK4dۘҭ(KMl-綳|DHmWft} qZ{{;LIB|n<PqE?>Q*훁Y/gC'OsnK|rs''jZ".r- .kx_ɱt=|m'ZzZR94:nf ˍgur]ۦ-,x=ڊ8հW_qғ֯ .=7M.3ew:G>\iuPvqX]Z%lU>s]ݸ|{iBfXh7~ .++?k.2fio/w}_0lY>OqfaԸ?֋a~:gRӬީBכg; =#T0ufĶ{'37̋ ̧SBz!8QOe ga?Ο[օ;?}_h{[sc'[#[%Za~K8w֣/>,2z7O|go~uq7FpK&>OxK!2eh͇);v1m&5bB!8BOR+i'[+ivJPN?.=?S:'cߣMݡk(׎Qr&}|t(kA&cM.8K<pXwuT"4Y!_Z򄅆a8NkߞmLn㶛 k6s[ֹqr>P Yb[Ͷ9[2z*ȯ f Wc&O?xcrk`JPp9ښH.7OX-v}o3˥[1^|'8|+8 -bR(p[GGZ@V"@| V|`aYLėf)-ܞ~t# I ܾЍwY -0[.anE</|>&ߎO*!x~ǜ#C>bb、 ~Mz+s[Lo/5uP̷֯fc_Q\;|_\n&_{i_\ӑWz߷Z}WpKYm^۵kbˏ=dWzs!Vf'h¿`FZK|fIﮓ{zBO(tkN͑>/SaRle24s_tsM?c&Lhr#R8Imlxx�7 PwgX~nhhi -ߗn'48rl7\->ۼv'ݛM#F$ʳ Ώ'>tWh0�?#fA$CE9RyG&%LO7 şͥRV}@/^JuɔJ?z{|kX~fPuqqm|?p+̆^d'4eZU6(?'8@Si=? -Ky]Sk _}AŤQBb[` vTzaFAn|}볍d/P~?TX7}/^y~OX7z}!f1&m̿:'Gm;0i<3E$٠ᧅZNKՆ 2wn,ڼ٥5 -Q 42hmoH4^Bl䚛K]WsZ1<0"NC- ;sQ,fh=AC;1A:5}M~C:srzKO S?}/8ҹ?O=!UΖ -O,2].f_xʘ<O;vkLW -WgOuu/[́ ֗>c4YGIc҆A3MRq[wV%t&\jL86a\2Ej']ֆ4N>6qR*814uX=rRI%yxm'ė8N sj>"gCʸ?sۓ/Tj\&$C-|왏+v;`xWw;6u?*W^mw}߸Ac C‰! k s ]|l<xНC0j/>0d3 }5SƱB-=϶"۾܈qC;Ҩ/֊jހ‘V%=VἽNN-W͂6\7]Kg98\ccLpc`!$ -&z ֞^$7 -:$%-m+6>&+7w7+_z꧿2}w~+\WmlOj_}Xΐ?Vsżc]#2杞]තΙbkF?_3Tum)r=;l oC1,wX;XYG)xxuG( #`_/ Mt/Ɠ?Bی?h=/,cX]X(vMYe|sY<4N9(1ILiF -, nq@8K)i[_]ov@C.NzV||1 CRj(hVn<Ѵ+_ i՜[ Ut@I8*hπ ":I8_ݍ=7c@L&`\6 y ?.lpwX- ,(44<;_` wST):Ptf:[;+}C9�CRmW� ńTw/"-ص!h -IВH?lR󔪾JŤR}i>];7n'_4L{Az^W_'|V{VvK s1jS덽?m5վ5U6՟۲xjh:QL, o//N -ɰTh˻"hE[ })q: q[ 󾫟FMo.4wVb?MbаkYN -)qlf\O*??quq_5#ȧԏ63Y 2_V@o2e)"LJ@A'k̞BCC֩iţeZJչЫc1uH#k`-"ͨԺq1ևm  <wV#< $0EZA1CFh,XijAJ;>O o,a!R^$!j`,1t< $iQ|Nؗh~SI`b!*ءOD[m+ԍ#h)<AM+vCn4NMz7%I;FM-A,WzOy<PCU -f,JLkfkT7 -*!3joSŎ-}8ChQO`^KR$)П~)da);`dԏk.̇np3Q{m i~良"PrWR,e"?;z0 ٶ~8e,rYLϷS.&*}AϨphk%Xjh))@H=ty)2Zڗ`CzUזkuB *)2:uRˇo87%U| MR}7f %nv)T/=V7DIB&ٵ7bf81bVLM֥ςʰ%Pix+ZbyZXhkŧgoe*Otgu 2ޖx(1y,1 -;i/WzN>W# -v#' u}zP|>.網<LS愱FL%m -^Ǯ=l=I]Gq|x-kf'Ǎ[?o-q:n+t9YX iMNsԺ1Љ*qӪFƀgr}">y<h ܠL))wMs`Qo69&&8aj/� -}L,tw7q{q]=Hqd6[B88Zޤ3BNHSlHSC-z;;חîdI?(u~_r^3Z'> tiV5�h -lN}ipT8X缼}zbp=?{Q{JZLgHRt=֟Ju7 -m(MwC+53ҠM$ΝH)׿LnC]~w?Q7N.-C<¾isT__$d.OKZ^N 'MVIݟT:1\O9m,-$=*G01[_?o>)<;1tS\'ԎgI[wq[6o'GX-05buAℰX0*-։شlZh}cnP -M\HΒvw:I/~՟ٿ F69SjGC']<Dq6yG :]ǦZxyp&9zۂ7􆅰Dҟ<=W=f-Bs~e\=ZƎwʗCZh+bڰt3I&.Wҡ닅ԒK:g)>9zrI 4O3&)eN6gقbh =?Jnd6OBu}L]73 }1Õ ΄_֛l69kF|﫭 EO/sbdzmzbwݠ`Ϊ GIkR >RT;Z?fte)s{UB/wb{&_KӳI ?/´מ - -}|BԺwOoD9X~ґ3ٝAk$cU_^[a.'ԌQG9-۵{h H z8ggY^vƣPT+<J0k%'@Suޯ9]Oo� TsiЃE%'^fZ=m<Ֆ;Xh>:Y d06툃^1-5^(__}^Oz CZܽw'P=m&-nԔOz4Qh -},b/Y!xmzwb=ŃW #!i6{/QT $eYDyġ+p a[F9\>ؿns&9"@7e=J!'h\m W/2c qW"-D-dipV|}yc'k9BNjBӇ+;@xCy7<Tsuo/}\  餢i끏�;;=ɹf~ <4%oNO(vmX;߉acu%RX*tWwC4<M,;k1$lYce-ǭǗ:ꑅ`4[4m G9 -H+ 783殯|X!qB#q KN LzwK-n< wG}N| qNL/'6@3wrw%b6qrZ&eC;tonS4*#V�mGMAlxҥgKv..c RXxVCVxjq &9"NpbBciB-fxթy1Xwf|nʽ/ܡ(v<bM?t~أ_{#?BPzrD}źkKcE/b cz#?sBIbppD-Z(zͽ?\$Հl2Is3bgkUv -GjEǧB3VfqwvS``y.'ȡV>+9$Z˒f։x,QO$|e >4IkI-_1 m]}z>W/#c/Ka9S\9M{Hgg\u_Z -ZG#~olP8`Gi9CiҩG^i`g9?L҆Ӆ}7tY"җ쬰ܮj534H?Ȟ]٭]=K4h9F8}7gp 3 հo)jz`߼λ|n}RwS;NΛً*bZnTo)"= ST09 1,_~daGl sɈ` YF1`P9f'a=P:Xiec!^+'%Be92q޻;(k&vL|͜n/ᖈOzXp="N̰SR)&>uZiR|=.صYӧT;!oX"ꡋK՚ V:Cxgo+Z$ 9)zjds#*흉~ {)G!rb1bKvV׃J{KyBUSžq^2jfg̬F|1֏WBSmvsBN<#̹ ءd#{~`!g<z|ZY,hnƑw7V]9CgbV^'G:`ǂGg=�5yC$k@?{^>)a>F-P;k80e3V"T+Fs>"kDs]l.m :rb"T\X`+υ=f!7Y <Y8+)ZeeN;8<c`)5cс1A%#hTBlx5OOV态5kMnd+jagsA J绑c9Oxc} ,(l*.G,ߺӜwd]qxR`_g['v['v&bg嵀e兵[ӠMlꃧ vV;KgvVKvV010ҊXm9/Ӡ r ->O[%=?(ʊB-B@<b�S%C:'hZ'L淚sbpҙ?{lr}V:!6ebra3<g4Tơ = pP$׽ -8/|[LciV}jXWT2j%8o?uUy; 1v?Y鿳R:LmFKm4[ൃR=yVvI`ib[S=}t"鱷~x,KCZD%^g JoQ;>& x|2].x_r󛫠%sZ%j}#o L++XY6U>`2eC,Y){ 2ba$"m/Y/9@|Z݅ZQE.rùj[kKTF8&zatƪ!>[kS悟EP㪻B?xi0 XEZνrkh,F{LԒ9Xg6/D.qM):(YC-;)f8=`g!do솉`'ˇ.-z!dU/'U8"zq?؃\ -qLN156OCt_28[lxQsXyt"[!j.WY -CL:!Sn y�1QarM;  0qC"B9FW;\p~6ɡX4Oi|S^i+2nIҮʁQ=s/%6R8:3ES`gI/̇\vj3Z"o/$vX!g0e_JYJ-n@~+z~45xJYLb͗ \+gqm\>Ɯ0N/;*w w -w_[ 8=i7'&6JihQouwb5W(oS} y!̩rp-z>Zb#8ZtV=N- bd5:#X=umQ0B<5(#i2.|JA4070cB}ӳ%+yJbaĀa^\ bB)G_/xz"jY,0%uE=J~T0iΥ郵 ʬ%Q3 UXf5} /*vص<L>t)= ך~Y깿S6WĨ)hL/pސŖ~?oexc%qSǃMᙶ&K`8Y %;s&F2ԉXJfޞ=5_nTjF۔PϪBbÕ3g�6pX-`z \΋[ gXF&3 -F)4(*̈́O !Wf"-c=k_;gjyT3٤f6;Q"˩a]6n"-M@9̉Ð}} VO3<R+{goK$L8Z0G9Vˢ%E؀ֿ\{m1zRd'Z=t|^/Tm3YCodJkgEC0a7igCv|PnIhp^R=k*n޵ГerRH%2Nڗd5ǹ7ůUuk?fb@k+Omn*O'9,磜B/P OK:zk0ԍop-wL1j/G.f<%dÅZ叾uF5 -bB>gX7#غ/X~' 2O,#rut^0�ۿ"yg5T7[zg=_RӻkW48#g%%^sлB+|*MYEmp&pp6FC1D0U7&GYxzV.ǜ~hej͹b9THL,#竇oCF-g^Vqe<g"<{5Kr&#N`:4#6\񉨳i9_0kql/js`X<lϡz*[@`@O 65,�W BW#81ث'Wj=Ag/Y^ 1 [MnYE{:,vvN}@#pv8褡u:RT C2lL+V!�Nn`q -[UB{eG:?&yg=Ő\[?9ʂbYi z~گeP1kL.s/;?ķ|?̢J19vcJvje\ IѩYJEZƱ ``i|Tg>b$F` )5!A:PᨦՎU{J}>V3Qk 0h&wqݑ'aUf6+eڑm1ͮZ9gy{ kzg8uׁb53jgoMOv3G`82"gvәx8Jn 8fU%VW=b 7ا -XSص+fvEAV9:>'~(O^1JYN>stb:˷q]gEG2eWCv6]CWysspD0q^rvmj//%&8{YdU'g n.jo,C>G ^>݄Dp fz;_w>s/|1"!ؽ N i==_H忽zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz;ww\ޑs]=$%e_ -\+2$92>.8)e}M=vlrY"puB. \=Vd`]?b٪5. a1. ~ _RdDd1$8&݌_~ͺ V\eY~K,}}eW_O_oX7O?^i7>`F ]$+\\F'~uDƄm;;xyOtG/#{H -.+\ u떭ࢻd]}WG^>O\ְr -O<s{se&orYrݺ ^{n>C-K|(,` ߀ p^ -gR9i1,\[Sx!4_Km߲#sB9mSvp{sPG['XE2{L/C 㷏"1$V2nH3@g>�98D? GZP93kC\:S%ߘBLCˁ1<0N%cRS/i)LJ -ULNC %&4}Ye&61]ړ:Feک P/i�)R-c:ip%9QOb? j%bB&e1m,-x5JEPCm0mb9,*^+9L)BD@Kα$%U B¤~4{ZNBgH 1$ +N1Lz&CFy3bJ\Ͼ8Vh'F 㬠*' 58ٔk1儓t*Vd D= -Ph 7[xkԘZcH[|@:k0YjTcL!욲J]&O*F}6P_0g2GYAaZ:P?& $Gvq>| ΰUFɇH#LR% d+snP ^Ԋ֢`-jQzl5|t`^#ln茓&~kTiSniHJWU`?rLfeNfw -ŊS#w67yu329.ZRACj3`M̉9#t=z H@#$6P&Bi%ِbdt7cS1$;vTpt -qJL-hJپg-%@ BMgZ>zjݕezQg%6AϵcJE 4S2t EoPZn7"!&0^0{dfϘ-"Jf^1CN-G )LIJFz16rN9_ ܳÓ=AdMO6( V&%dk}(K_68+R Kck>Ÿ7sPb냒7 9blb),if9yQdgԓ7Xd5t074u %JjTIK2j̏[QEZzx=IqТ30jάsC0i X9MAMS5RI%W9a*TRsdRrLAbJSjP`$zgj?O|M2|&h`W49=d Zi2S'0C)cޘ_SkjcԤs]{]GS4~p`^zz.֚V?WCirg6*<梓oA 1R:Sh4 ];KŴ&FORǓ20c(C*m0Ŧ6NPSFa}C~`xK#&yπ}BB#`W{8Oou'lqx9ž|dc-H "}e%Zc*HbXo[m(ƄtLcmaz&k%ŗPSkB;PP뜠˝K5|P5;H!^R`>BδzT2 -*RT٘hm)>S؃I[9"{8)5<fM>6i(/蜡a4 i}sKs J'dI 64r %0LjYcP!2 D<L5̖01C~Hk=d6;C k j͕%4|g5&0Y (3> F1X0BgvI6be690%L?) ePix(sqd֊Ǯ}|=ȧ2_ E>8ݿ _G=PF7Jf H<+&[2m<E^DF(f@ jPF:ff #H! D)j y a6b\R/W˯, EdRek2ya)ǝ1nBfIOJA66 2&i?&@-6߁&H}7;Sby NL%{j >= lgBP!y|MUrYLjM)Ԫl>oL b DPʨpҋfjŝ. G^.@>(6\Jx4Xx&aLV]\�EeSIW@1 PgLĔba4Ld%5J@Uj,Cjg̗kk,|?aD(?=,Dn$!@Z'RSגGQfi"Ƙ?)|ŗ:}` >K5ccW -yvCӡ5ZNk� (5o,O|Qjxs9^_DrVD다G[Əȱu~h+5YTiStJgb2 -s2e,/S}MaG-ds*)hԑ(_۫U`_""Me<S@}&1Qk)\H+pd*$G~%UƵTHHN="(lPfbvrbY)/E1? uT HY%P̦iVfZFJHqkƂv? -5�T_ʁT9;J%\zzg)g><j,s\} &$v"AS @5T+=5[NrOBM6O7Y � -Y`gu"<Ba쳼ovna`OcYȱV!"%P4ZyyP)4ӿU*͕^_ 5k)D@2I!vN% YBܥĊyIC`5a£&7%;`QcK;(YH+ߑvۿ}(>v -r+VLaqky"*XBΏ.P8 0̖^LS,o8rRɌauCt=",vʿW/l~ R=赕BP'zځzt$fk砤buF* oBj+Ԍw+': ,HMfT:X9,&le -,ԎUS&VA%!/kQXVDYB  ?}f> 1vjՕEX_PGr)hk><hM@(>2jP84|H/ 1AJGYPOẙHjN#sCmhAP)d5n G-xXޡ|׃-/3cۍP$%`$�Y�M<UrJd+ļT5jS0hNc9AB->U9 h*P>ǚZ,G4[B%( -S ezx,f^B!9r -4"�;kg^I1T_G!&#Aoklv  -b yJ+Y(ANH8PQ!cy5Ԛ\6J+ZmekAC,.xpMA6AZ?6 @m$[2)@ rF?(<@a"3[Kà'γ:4@.@ Iu>i?ݰl[J^ -<&YA~Bx-֡)51cѷd5?#AC�92#G#_w֒?P3 >ҥ_?_18? @N<)bb6S ]@XE\6(7TY>LKd�XC}CrP}:.NP%@TMӊg EP˪w3s'Q\;[b+QҪǠI-3ժ#^ $c;vD@bU9'&"?#C\<F6R[}+s1#H:vwhMiJ&Cj,NE]J>PD\υcV_[,Z&hC/veי]aM.6OPE}JG-P,Gy/ϐ,[tP{:LP;~zPtMB]I *Q -#씤мM(?"Q*R3iVuqHu`,RKF##UQ[1oh=oſNCiע-їZ78\+Rw:g~s(HJ=}]H$ Pe¬ח^ -7X"S?f8DW'" ';*Kfr̂#աn,e53Xvp RZh(B~@S'#Bk/!A*dMz;^ryL)Ib1/9e.Xj=WVI%Q6Ro4^ZHY nPG W2\oӱ֘n&<{q_ u :$˛|OTFxZ ׂA\XJf U|.TKņ7)U)iǜa>'k3g kwʭi5qVPREjx5"{Bzez5+dL.M=Bn)à T!B<zYj/irxp1 !Q)9!n9ǡX394fnePg%N -pIywU>G5u,%z}$j,6Rw,lTjT77N5z kj/BM^[(|^jxgT6]2Z`?s):D~"G ,%:g+ń:G48V{qAZt(&bu%PU3iVG0ߩv<rE9HP=ub׉wIG#@oZ&Jio; nyY#1kzlfٓ&JjIV5JԯRK@L6V+A 6VG.7 #ߐc"ױ^\Ok>N fiǧRu#ؽs\GR>Bh*vW.>奓?x:>HHvCY.5JВTQY|&^Q#B@IPB?$fJKs cSU^,^#!@0;k@6Co}JX^J:k(j*|&P焮gYN2D`9)lc -xs"E. LYsbpﴈj - @PvDR;96DP*O*RE2c<"*\I]y|ǃ-/@1ZCNkVznEO(qm"!c:.~*>py2";]H]6w֐}V=Vw{\xE/Q>U+u}DLB_CY>8{ CFg{}%6Y||;"1#"FPc6TjQ-!~6@Y-<L9 #bjO(O֍}:QY^2U.?7Gh=uP=Ь6BN@IbYX]nf >ĶiPSo/~Dly".$V6ǰ5?Ά6E&ڛG:h:qdSω*x~EL-3|H5z*]LHYMg,"ԞYJfrLPFo,O<XԐv4hy7ױg|&zRBrp?zsXmKʲ,'| -h8+>j~)H?߬6-<wyZ-Df1�ll̓~, D1B5qr*2"k&}ʷ}t+4.YAՍ]\JE'%S7s&Pܟ: =,=7@EuiCQcz]zE<RNo?@:@BSgR/wbkkDI} -~ -w&"zz`!D8Pߴnjb /i&s u߃{3-dbݘ3X 5\ -KBa ԎD$`wK!rE{W靕O)% TN)'_P"װ*EԠpSB~K??۟cuF'$8/,]vmvnˁ^1 o=,:L A#:zALydBL~`kj-h٠Ey@)<FQ@gDujExsA`Ӈ~ӾFH }ORcX6>AH%?DEkՖw_DΉ^']ͷVIC ESHM}Ԓ6죒rcɯ==ss{{~b{։\un"Ė6-8o & >fB!Zϴ[1(JP,)Ş0b6,爛A#Tsf]/uKS+jJnq= Q UlK8>T:Ed6G]juԿ{"CM OW -{PVǖ;@]Hn 4h8W7w=h?yv(B=,�2Q-7VlTܟb+Z].5Vczuhg9 -w=*}AkK`3iuE\X}-r zkF=a{bP#҇fuNc5'z(_{%?eooT[o.vDT sԎM'n=Sz:Ev.S<Ό%iPc%-B"ZW۔?{/SOvs#fڟaGؽEmOh.AvL/nJ25ZŔ#`0{%E&wu?߁޳*ݨ _]ǷYh`TqmXQ5-R>;9؇@B9[;PYǜQ7`u8lB9v{pt/ʗgXwk>ALitja I,X,5o_)p9"P\60cp^ s7t{v &H?JX Zyz̑Lw^{m9t 4]Ө>PjzzPM.E{<N胣>حdPww\ZEϞȓ]�rه>wAwr@l=*_zm #hG>Z|X~S,G@pjFg'XmpcʥC}ӄF.Uhuc=�=/m"JhׁAj,SX=PBd6V0uUy3;#Mxn5CtΠcs PMob]l`%l@^*jtY^x(|'^AOX ⡷IZMcTŞnwOz&Aey-.8ht0w=%SI){G8[3?,.*PYX/쟉=!Dh%WؽY1 i%׿?NM9sԆ�Zy.hb~F*ΰ]9蛘ۿ r>5 zQ80!(p]Lqo7> zOҕ&Sx8&ݱE ֊Sz]>:jlb?yztR|Hڃ'ZW*9 SgAbK -f#SKsA&|I;UOW^"'pRz٩^W:9Ojtqy;%Ӏx;ä5ER;P,!DDP*;7g@sL {s5vL.לOts@2rǣׂ0bư),#Rx),WDW",qyY c3h{L:F=pPAXJ} -/@KU|NA :זF@烰߀}}i6اУY˅Ε=8PĪX^?VMFgdX<D]C -!:T8j#Ӵ곋pW93l'Ȩo8c3*wl =ӓoGMUqn>G=[=pvTZ N6^_Z3fJMWm+f3C"Drz{ Qr'@U~7H;T_^(?Jꛀ.}d"P\]R^un9p]ک8Wqr|:_SsYͰR҇fu[k>*jJ'7.8S=?)">>ζuM-j!TcbbHPQ'>G\pE9JnT#i?^<,.AcD {nE/|7-&I΁gXE}JR[YccbBE, aϔ^G cy^1(Ik6XA$ӱU3e׍7רMWW'�!^:'t;Jj *i� ޶)};* -kk]u Bl8r|? Pt`\sVoT4[8z WL771"w,Q*yY/`= ~F<F%nIg%S5ֻRyi1-Y'W\mOoGgߴ )S6] GQ,YLQCgC[2[g `"vO[%|=d42gsNCΠ>\ʡkptb*fAL<zPegvs%].E"ՃcOq00,R(gE<>Ŕ/%ՠtQ= @q7W -wm\ bOuϠ3mki*4󫇮,G?Mjz{5hDo`_[,2?M,f[H9- U_ZH{MOK'gg?4u>ۂ=)ვ_}œ?:o!?t4uBYZ?}TVA[-;=1Gzmtc9@A>_hbx,@WgCtv -=?>[3RӇ쎉rb7;> Ss]A|JKiV,-oΐI7WPQ|E.9?K?.rg>i9Q,:3?rw5_5?X\ɺ]@;I=Dpn{YN$6Ҹ$X H HpwwduVf;wϚn!Wj||7~5>cQgkREo[ ߵ% [CTlaI63кs*3 &~TJ87˪bfLQ.@1+#h}Fj/Oj<TTf5Oj=j :: q f֥;3z5o!:U$RAv&/1J@?ADWnijDF h3@ -XrQth;P5ګ!"Maܴcn%,bDPw*<N>&WdBv1AA)hêva;ضOD�%ztZThrQNFd 2UQTнdt!aBQ7z -.5NY&;M[5Zh;BvF-EuVNQ=HG1C -mCZ؂!]E^O g*̧p-;e!{񝇿*J3#Z*aέ-NdGn<U2zSX5bM</ƄWgϛmL-ķ8MQRҡ}a4xdRv\ԣ%xՊ kE!KL/7@׎_3JNH]C"S=Uŧ^ q-<0ր -uC$C,}1"}0ƍ^ROBQa늋dz/> -dsd軝.Z~V/M#qv.W'o5i*Qi%u(kXZ21͙ Gu{X~!E>S/FWDsƼ_*>4w Zc>b+b=DPEJ4^}/ Lߖۙ>/?+ʫٝd.:7*h/L\_0$RǴ( TRI=s9c˓:%jR\ ~Yk+2{n\J:CFTƐgvEDH*3 -EP"yX>Az OHRf}Vŏ=.1N}7Xsl&فE~MTX?+o  [CLj$'z^'Z}`? -w_ECo.D&S7EfO* 6Ϛn%uåZ3gvA?n=2(F&֫I![կMvqͧDlxy`O>cb~iy~)ňx2J_ZP=ȢVDqj<Y9bKt/ -Մ3/hF ڊzoz+5N>3"oGdMb=G[5| ^ÌzFYXF:?%~Rwٷyi~nI<4&s{v33=,!u zؓA=*&XQCTMErYw￀$M=vK2d2B8m9M5ɎlFs>0:,Fur֫88wTDO_ۋ⛵Ȑ'[ic|"g7WU^~nW%A8 3o8%.-jR]a^YeZT(|tFC 5fr#ڨN#`taN_t{/�6VՂ&X$ -~l󧾌 G!$:Ӣ}k"jǞ.9Hj:T)wz;~{؟ k̈́/6"znkZR*~uv8h' -]N'NAEEQYUQUiCuAeeћf[f[aQM5n\c꼰<y&Ʒ6pM9<ゞV_`Mx!T0~?yS8Ht9raƭŚW$?'f=8V#@wGXXDxT~}eɛZ;[qA(D$|#ZPvNYI^ ,!xCK9 7"O%tI<1(jM`OU+nr ގRFwӡ#cNOLܚg}=Yz;+d(5rwC# pX)z1=P⹿\N,8a>ԢHb\`"Ʋm ÑWyc8PaAEhIOv=N4iCqzЉ ۍUڙ]tEPgzb&TDW ʏ2(}, ~,qj06U_^mۙ#vk5Xu~h>D8h9&l) oڼä:ϛ.2B*s"^~% /N>7iwy -ZoGɊ~^GټC8Y}kzlqGcb9,ZXd\6Vv!ߕh}Nl2 u^qM7B/u$Z>} ~ |zu=%TwNnɻY‚nǵ~Bܕgb..ta&-<QrPw )ߏg1U׹ 2UEVBJq$;Dߋ/A&_HD$osPsl\rfLDgLF$%^k$loԍZJWZcċGRD9帙Eћ6[QiEI*v >s'ԗ69:o'vf'tO7Ns!5}?yfXiط?( ʻ̇+-^G]NdY<̟O -ouɜ>&1i;=qϢN<Jܑ.6D9DFfԺKr#ªC9W597:Vßk믆WU9EVDfT{DWImbMކ -ƛ,I?s?dW.xD xo&Sh -W_o'tR}ޢ00b|ؓ_<Vn:R/!/b/0AqqG XC{gSHr`K-^FF^ƞ̋;>x?jWdlhwt~jxICvRZr5j؋8R=k<k=}cCX4^M c梇 U^meAfyYحQuaVOJTn',1g QSO`]@[$լL/>MzY|6"w{^nON9}?t ¢ъHPˡkщ fDۮdXe(q?/ޫ#(5@.zȧp8I^WI_TFUJQzsƆaUAX憤:hZ0{C4;66 v7~Gs9?K|c˼[}%%L: p3|OцoѿmӞc}@A V{_[sɫ9,:;FktLuor,ksOms9>2OӆǾ}t3{) _QTs59BkJ̩,x4bD4*kuvbS+ :Ś~{*92)|Aq/}ڸs8xԣ52ۤ:-ouQUFW\%w2] Ȗ{I=K/&ôP|14-ӗ >ԷgW.ZhձVt^3ml;ՕU{#1Sz]*䷶S-zH[ȅ[In Jwth>T<Va1Tc=Xkיx'3m:j6z0֦'+ήS*m$?vミf¨68q LX?$gnvVK}ش -O {{eH[w#ɱqouǩ~דyލ7Αѹ=zHw{X ;Z]y9< Q}wK@,n]4}meWž9J -B:|jQ<4(p~I9>a+azI(W遽JCj`~UsQm -ع1Mg43E?VG}wTD/:[Vs3a?=yRŇU%WzF!G<nM>׹GECxnCXnCa},\u}yjv" -,ˁX -OSK7�55:j=唎``Xk %̕] -OZ OV+lk[(}l[vn+a qO[5/d-y%1yKdRgLLF}`g}hB{̘zJʯFTވ1y.Bx86u\ ms(>Ftr~ٮrw[s ]S}zi%ؖ*``u` ,0tx́?)`B^a5q3 Srj -Z>j2*T02ot -zOݏ7*[rKbTFO -WɻJQK^IޕETDxFGuvуa{&2z1LJoiRz;«2myY]Ez^ 4O^۰j5 f` -<l|�ٿ~? [=dL\9k ع[�2/@e@OSS~=JZr#:'vwT~gԫbwIa{ӷypnVKEvYO}j~anA)yfhsJi@g*まY57QSd`lBxV}%mXqcv>J8x4;-"WTVg1\½낥f|jBm>)u+wH+|NdF -~kwmkш~|QzB؆OgςmZ�-n>|unDc7{ \߽P8}[t<ٕ}I*uh}&JKoDq,xč7KGU8G -?Tڠأ7n%dd @mGES6kv+GAZXx*)$t;ϊ<c=*wy]S3mGThģ.,6/&FtFj]$"9_ZoZ_ݱ}?X,;iY6'c?%NOaޏy(üGMЫ<`|4o&Jka\̆yDWGʈBm[j4P] s(?z)*dO}SY s&CXbb@ ꕰ)+,I׶j_hdgsãAru3 ~:t(z u]OṶԨ"τ8e n M5.1o߻@~VP?Av)Y -w;jӴt2|Ne?>aL[Ta z'ڪW~^ļ~)}_PSR]CZXR#qBg]pz/PjZM s19Of1X(̑YIe0Ư -Ilu`޴`";P:N^A¼E Qa1Ձ&㯃tܒ@FA9m[K*%W"ӡ32mַ,JY+6)N�.PKŅY;);|~.h&E`nKp$KN#OZ?irW>Q 0uzw-H)=\qk=}595]j9ro~)hWyOs(2KV6)[´m``r f3n*Yf?Up<ϴ蝫ʋ<5%R*Wiy]_U rhytDVi-M#3}_2~d_qT_ qZ,_,Y~ ,۠ Vc%`z6P\ 7`~85K=C5UpތzZ.Ytl1- *+]KݢJ\`%_iCCdQu.'2a13Pv1X2}3X2oXذM6< i'X7b`*X .aG\giFE{uԠQU/Zy%T{&/}W"rskr7;'6U&T;-Z4f09ڜ1ͽ͂&/fl�Kfoy X4oG@ӶMuBv آZ -R@oV}oC9bV8NQ=ծh64:%v_z3}tϺcVgerBJιrgl8s0eX8s+lnh~h&ݦ`~[Fl0 -�[xO, ur5b_]_Y sضǕOapvu9KJb.5Gj/(R-S6-�~> F?]m݌ob`ݞ`1^lPwJMG vܒ==G5F^H* fbKw>EEѨf^n:ƉY|xs]%ްdɎ;Obr-#5 Ʋ_'~~ȅm*E}kŒ57cO``ͮ3`Q7( ۬mqVVyϹƴAQ^yKzD¶UE<rk1~191+6u~߾G.< 81\ V9;R\mP,vrIBbKU-Rs8>'/mR6DޭZG`u{Mwƾ4ј&礑O-NICn)u.h-IE֭>oܿc6l >fnW5ua;TUW(EX|�L8\[XXevIYl祀' -ew{L9])Hj%nAh]DD`ImOzY[̳wo欗#X_|3z=i*ʍ2YkvmӘyL"R0Ӣ9[27?i9 ,-vQeż=`҃0d5[ f�lT�=BnwX̃O襪czf4A[F6-1"mڳooHݔN0roL:Zw5,;Jgwo6i,&63W @~Aˣc5X0{XFSW.<z^ތI#X$Q8:8{CWN=_;OޢL/?|F\hz(|j.UNQunIMqguJ#wls_'ʌ,mk۴σU:lu.xʳI;\^󭙾/s>֙\ʧw(]7K)M>|^ܹH=ޤLk<Z`AHve٭><E@< >^~To/n.e1C~}"̇E4f6ؤvl|V:!{Nߑ;4H6B5zzZ=}Á-̔!�{Q2lu}̯KA5rnBrOQ˼hN` -вxl~%˯'JX`D$~xRXudTFq6+WsMgF`lչ = ~ދM[5Z`~>؏tʡke\@Ɔ#upܯ_x;wєN[ߥVlVMph3^9ٙkyc1&Z7hwT"^S@WChb]P5kW7RUm0 Sazl~a1حm` It(|r)wæ'. ->>w~s4痋rp0>fi9hڒ8m8H/׷m<٠ЖF9dY}Lc{ϕ^jOK>ݛh6iy2.aN+N>>Ӻ8cL_=fq[x�lƅy pAJ)":hW;muJ5!ZwHIN[S)xPih?Zڌ3H$L}aV129- h%KkW!"8Z.<>V]_8ng~&:f*[Mٺ Zm< Xs6`I4>1ŜaB}۠/h13 ٭ov4ϰjhÖlc{`nEs?A~9 O:ē [ {K|o2 E5eNfŁgfT҄Qw *AvfoEC5Aju/59rܩ+k`I0 -?ڙGR> K }T畢MtGoi-txDq9fTBXQs'&.^rm]ΠP]y+u9`d0}ǰ;uyydDA~@ÆzcAuVVge?hE_*ft1ƌ;x/zF=/&_ 0⟿z_' oн=6h0$ohDG^v+3աCl9R`|ޭ0|BFF7|_Qc^o}䂜1`3r ' SVm;_%Mܔüs7f;75f^&F12٥<+=`8(QZުJ9xQD.oy -{,8+lnUwQBZ"}U}t\9{͎/?ƲƴQ./q5n1哼R蟶V1l!ĥUWM|į zn9Iqտ5]o[0iv4n+R[mS4?/O5:q2&? \u L:sLʚviᑲSu -|ȀY -/Gбe)R;�0i^ۖS~S 0<gԀ'4a2b5)ZdD꠺^E6 ^u\2~nK&;�mUG*߬xYȒW=3E9tl#&=ѽ8n 'G2;vp';A#Z81cyG˖60?{~5ח}b5='uu'pq |0 ؈綳{4_ [ xg2ka';yA52}V{ޤ{5Nr+wrn`M7Jݩ^HM&SE 6ؼgeV 5Q iRʣii+h_nq{qhYi{YJ[0Ÿ]u5i1rgxw9q6`.<r p`ⰁPd&q˸%܄x=wuQ3Uތ_Cz$ǵEOTyXԾ 4p5^ޙD*0,32j|䘅X8k5P -Xnn%s5;h a?~u㼣I㻴*5n ؗv>x½SV@?0831 U4־HY^!癵!b1:{c7嘴z\D$HԳlQ1JSB OW#⛎aϷ2>rz pc&ޟ<ϔe= ҤtN_JxvVt 胺Wr檰́a|V}ߞx] 3{ xY+7 S|K -I}Xa/<ƻ YGgjywjqb{>iۅ_KR:M##rSw q-NR>N-BZOk|?dpwZŴm -Ԟ ZirZ o\AS״AՆ&Y~Z�z,#[O&/D M#E8&!A:.`~0<"�EL!f!/0u𽽚p[BG/A_(z]{Ƽ/j@Ȼ:y^RT_;c\nJ!Zr|^M|vAysyYӵ h]ʚ@_Aqi #E:&@SIRj4N?wλMgs�I| >< E#oܫ2pRW#V2sX !Qj{@崳D/j -Es*cL9K=BMh{>͗8~(a~E<[̰TQ?mP0u2 hEHtEc5WS_�P:" TG5~hji#j@WpY8-.86L]o杽 y/G{>!7:%f}{%/ -OR Q ɻ7B0{]%(ͻk1τGr_:vJ^vwu;_wn7rȨ�e4˸"~?򹽄^8KbxV2*6;8S^6) ;j3+x$?jSy~;"o#QW#R.)xo`7Wyȹ3 -Ja?q8ws3?(s? < 75%e٘īaɁ @52zAkEn5t-TT3: FWܠe9<+)YU%U8v�evsyhQ&2Ť$]a=:<Zpե "nΐ:~=k5N_z[ǢٶIEQ#2V-qUi?}w67dm`n礅lUM, ]Y-쬌Q-exv9f*SBX7혿�JG>x2s\y鿈F-3ўa*@TXg!ca8c*σH-<#A[ D폚g -jy#g=bbnjYh}4a7Z\s3и#1�~ckѾRka^pO[ǵ**xF O(B{vU,SǡO!ܓWB+k(UIb3bJ -Ǹߵc_0 ڿg}=o9eRC\YB }Bޯ[׃gˁ 8'M枺6$d$5Mp c=6RlmZ -9BͨWQ&m!V?-myƘor!h>7E=ĕy|PE"E]ڢɆ/Ǵ4ZBtz-*ƎQ9Kفq/Ikzaapd:PUKϒswލ Y -`(?P~e➼F|57=7R|z"DZ| -<#QQ)R\zn\^n']*w:t s|;rKj9Lazpfƭ5XL>~1񰛇ƖxoFw[O 03^XiYm-h� qOO/ŝӗ"nn:E,~1b<}+D>闷 ;: =pO<ы>2g,0ҩF'!M`Јx8E4x)GxqrT> Tˢ{cb8i_|9O#72UjnnIwr҆w)sM;k;᝻50:0XϘzFb=6`[9DGA_mZD?8`V~\̻Tj֩ݘ " k=yHtNl\GI"&n3OP"t ,,&Y >{-n&%Xr zT:r8uT{wY?/dza_نr|hcFpxV6~ F$b o,J*CkCxaE,A{k#G -JEHx%%uMc9kq</s.e] W0` j'|;ᛳ{{7lD [ձ/# "NrLNN0F |mf <!#~c*钼+،4G0XI\۸M8MEH:^B!frؓmCho%&zK~AH] <oؘ[d ڛz-89_T.IKsy˹_Ucj(߁X`њKh)pZ{8)p״ƦԎ#[:.9BgkK[t %x"P϶"⺊# ;L59~uw&H[KUF']bqXZ1"IC\;OOkWmnֈ*'5(!(i?+xq;f72בnx'tO?`Ѵk1㥏*Q{yp%*�x"/.[2 I]BIFm#2{|{﹔ w -<2v\4ʔtq-l`=ъ(NnK5X^Uk%y5r!~q~ky wXo>|ĨpI#_b;n51�dYk24_9ԹǴ!5,s\y`#b#Nޣk=`XcTf!#v']7cLy3Ρ-݃b?*vc.Kк!Z>3(!Ch8#v$W皹v-T z⒲=qz|Xi}>.ϥnElJ+}EԕgrM.OXCx|AL A`OT؋݈x =mb2,m+q%{iG|T""[zf.^Mܪ$uFԳ^~C"@7+z@ %\ù;bs]hje I /.Gl5op#}62zVS2Z$S*!=<ą CELtΨ7cDͰؖh|ig`]yl=y ,/H+'"j)j#y]|r<YϙyY8H0:³CKS{TǃL^h:GZ~�!}<ˋc.Ľ^v0UDk1  -p݈=ApX'9X΄6703aF! n3)(oni>!]cXˠ i�~k"veG|,bNOv{䬄s[Ɉm4ic>,^ +Gq3gq)`H}70 dHa~?3MX]ȭ~mfaIǯ.WZQm 5ڊznrU"|H}H'yk^BnQ^MS>SU. Ӊg =b9YI, 7-�i0,L4vitKCt[aQi*NĥCL%Lv7!?sٷ?+>yÞ9eċ]Jzu(΢k~vbcoB@r\YW3=g6#Ubq{yCCy@dFc ұBkb 8C4n91=) .#jAE,nMWcFutf]1D^Z1/h"=7{PEw1_3=)ۈ0V1 XYcFJ:E6a46L? 3cS g3u(G1bn~^:e-| B6N:Z2<Kyq)\4)+%BʈHj!RjUǻ]mHi 4_lꅃɽ:1Æ|Q^/;e]>=T#+aj})9>ą9h -w]jphAl8W"[9]Xa. sHIF3ALnğFR-.s㲸EyC"& '$A2BU~}n/q.x;HQ;qIހHwGp㎓u9�EF Sӑ6'nufb2zо$hcvs p.-Cz]$paM3  iV'MF:R?ψoCuHkJdZ:3vY86Y)+?0&`_"TL%F, l|g,/# .D6%2N9LfSV}gsLa~bcb}b =1z3^HtEu b#..Hoxsq%B0pOZ!~3ÓB뜑;iuZŒ& Q<ߍts" \AAf֮L9~X4exmOZ9M<^w_MWC '}f`ܧ b3/uYym*r˰vA'Ta{B07陳�q}6ħݏbb Q) 3yI5J Ո�QBcml87daehdxz:/v'y@G3 4fwl o.X #L4<Ô/9"J|}5a}IȘCdR2~Q.\+ Ry0× �Q@V:J 9x6qlIιoZAHHw#GXޡʰ|'ON'ON@\i*6<?�b!54fh- Ȍ>mF9q)隲׃_nT)=ڢQJ\{ i! -P^q oL`rŸȨ> ~Z(e^jGD8 <V– - v)jjuh 650maxzgf#ML<(9Oeu NxЄo*&_~Ɲ h}pY;{cn1 :Eɨ�G+tM;. HnWA_`]�G ˁmZ8Q_ nKG=YJyl /wE<9w> %8cCr\I'omBi'".=e}V%j-i-zpsMd 2A<F7o o:/'odoļ;LI+ ]Ve4惔_:&Gc&6ŧM8.U ^U%"E&C -f!?yk6:F9(7Gk׭Ո 9kkiKy&#=3".:JF76~|Ǥe .E\j^Řu85EZFvǐT뇴fe^zQ Ek"E|:"(UHӀkAEy4њ0`Z*l`d6zM<l!}w{uA>?M|s70׳1|nJ-\Ǹ61պưD, R% -|3IC52cbsN%db0A WȰQ|Ev=lK摼o,G‹Q)+rIZ)bb--3ZxW}#&4i7 *ybǨ"Hظ2%r&CPقu'ů+!02ӪDƂMXjaōjʔeXCFAT/an_F{87M/N[b=7763A%Ϝ5;kw6\1<"$'ԇȶYYˇ_Ш)NlnE/1d7jq/`q {25&Jh=ێ8c,iv^^xk~OԤkRgtϢ*2I;O>E>H5Uf? vME+;xثDHZ"cNGz$@zHv֭tOt5& -桦2͉l=gQ\dtCZ)h084 ;%9 cq,RM#3x)0AY's-&!mYuFGE<n9٢3 Ô5L1L[ Sfz>s# {߹Ḧ -ml;-Xobl"o/c#ݭ-~Z~ܴ @6?tb#] Nm~N;v+J$af`ftKvOdhg E;AՇJ?|�F,Mh3\lo,a|?Sc89,ҚG#DZ ׂ|Z -uue4ˋ4)ZH�?,a[f_FcbPT󽂤MեҺHlW1cw~ǝOtZXqfȠ[uC - Ϭ+l%Ck˓rEi-,4~+s2zHi" -eBK&c'OFH^ ҃4Y`J>dt2Y>o -@Y0u%Y"G"<PpRea#Xˤ)d+} t':. W-_ $!;�qww%HH]Zw~'IϾwwx↓ -PPUk9O #~DW9:u T: xX�20+)~d!w<wNJgsYl 6G)a ՙ:83Yh߫Gj>`GInYY`g&x� nI>zY#΢zYv=Ae߈#vM?:NzPe($RӌHl!iW17z}X*FCs#}'v}eiuq1͛*ԝg>n3w+;>D404Qb1JI({^2Vm2aE'dqP~w J\T~ҍrXD,vRhh;׆1h*[ٺ -\"-H 8&Jņ(;˂oQ#O41V+Wb $zɎD;_Oh):$+),4' .Ƚ.,{%B*X؁"1m 1iTl.hZ7Bߖ:% _Ҵ1)jcF(+[[(7r4_e֍Ϥ>3;iPyoj)YW`g! yxe`gY],5\lu؅%eb \9"3׌T$6p|`׃-ӆ[#Bs2kh.-K/=U Lg) 6nDvǛ5B+Ȃ 6}=g;&vq=�ꁘ2R -NBTZQ6`bfp bZ+6 -V#$ SG :r6߉7ʂ;XSUz><2ZIR,%+XH}w+i-boo+Ⱦ`4 -9[7]q3`w,$l"jvYQO|ѭw}C+FyT|lyrH%qGX(އ\#$ު[֌C{[f $y}bd^, Qv*BY\%\�v!Ƣ͇ nʦ,d"Y?>`-uT-%#;>x4@LKg`+דCp rQ1ZR!f>4�S%]:%r/EޔOo10$se녡{UV:X_ΐr5'zdmt6 zoMU - Fm?e?a;%OPH>T*6\TW*osgk'KJؓ8bsI.#fP[ږ ;7Pv4]|{Yꥦ쬽3Ō󥭱,Z8w1W*dRwO*o5i>3XByKC+l:v -o 5fKn\\<a}eq]|֙ВǺG)tpIƂKK7SF~@ Ɠ\/b);'ꙡ kP{X>1gvK`PR\)e )<k =Ĭ儃݃`8&rX>s|n|ʍ)wq-*-/8+ 5:`X֌!NY}!b/X.pO -}9gՆ/4Rf8kl?r@0O`ӤFTsz UF-S!\ įQ.j$o4K%5_>9/g僅߱)AJ>2K$*8ov1SuqEyj>o( K> ĺѿ`o0p+b^xpQ2Ϣ}l@& -Ew/aNl6ixb?31?^r[bcNmºa^:;ɿ,yW z ,.mk!eҚ)VYIVk" vVd;K9+|/&` fN2uǖ+DW|KY5S Q-\ T� ҺByjGWiفޓx|?wRNCMCsA\Dkۖ,|'c\#tOB%Ḽz[7ڧ;j>Gx?pP%g_=;q_vgeE)eg C,|̔JҷYYѠAc09 ԓ F݅O- ]={Lh)b8K`=#0ʀ!}IL? 9/gC}`bI\%ѕc戍[(y\2. d@}R3iġB&$GCO969rinNO?1i!|(\E -rs7eԄf}E_!sC ϣy[x(!ʒߕ~ݕ$| -&~bq1gvVT`S(c]1}+A 8ɵC3 H[g1 Y%l! )2FW4-51̾Һ%Xc9w)Ln7NNnn0cׯ r3l\2%r*'`S7~Y,N,):|>[?JQ[$\`z >uy.A*Y<gq%$J>5ɽ�0>ˢ9肵)ťZ>|4K%{tGsbIBz*jK&d9+<D "T)jp2}5bK:j&IgӶF <oP* {zq=uE̡Xyl,(;p Sfj;}t6WrGOR\$4|4fM? aİrNcvT\_]7ӽ.QOJ;v5)A9_ɑ%tNwUY?#]LW͋)I&#ds){'s$>'y<<O$e{༱n_ uq</.q8ezJ{\VC̊6%^uvrT:7mm>ڹbMjqV[t--#T5anwfdĴBB}wOLA sEψ~E|4b$s}n!3b CSx߬X뉾X -* -~R-7B`Q~X[`@M瑃IA^^ƁG(q$G|̝ÖSOɭ%`54CJ-b 0 Ҷa$K_vpSѺ\m�'s-a]{Z#�%ǐ|c rEӏʒ1 s霎;du G`p`Ȯ#P\[3^e㫫 � -1p\@:3?J ksecs[?񚋋0Ou7᝴T/W^_5A?|1GogNV\*Pwy>r.\}{qU(kHk -Nć|sU(MQ>}'Iso/M~-DBD%Q%hL4 =_\afR Fn|q[yg~hc316I' ^O lIaŢO0ΰ߈#)7+q]sOdžP?+)_00)O )[B-j )s(5bǻاQX1&z{AOh}v1![xvJރ\'剁 -0<s$&Mz`}t6ܷ]2$Av6iG{c+`b ȽCK~) 'Ǘ4zvj|| -=6{)2u 7'ΧF|M!wC�NSx{-=o:r|9_/Ǘr|9_/Ǘr|9_/Ǘr|9_/Ǘr|9_/Ǘ0afU[qMX~%yzV;Ͼz)Y=rW }3ڠZJ ־v-ZN^sf[WNџ=s|Yv.X^q3y~X4f/Z g.;>h.ZBn6~/?M}ؾz[?y>G~T}{k&Sz6zv}~jfkW;[}>y^ᔾ՛yv}狟 wN9o9Ey-y!g_0;盲p̅O,Z_7{K6ˉOaݒO7ϭ7k6GF>GzHN|mOv]0w^sI,k/^w ޶xlrIK/џ?gH^n=XHވUYjx MTZf6ZF&Z ŚU -CQaܤea=AݕmJګ(N~ 0fJg5br3ź5 -hʛY\Nz&v~ -# -_Ylan̒~LBzz\a;hco`Eƌwb}CEK -&uh7_W{-IRȂ1s}Fn"C%@ti؟tk _E'^;Z2CWjkOO~Kw~'|Afa݃zS;[ͨT6tzbo%Ovݡn*k3m 1^O-29BKBie!lKLOO -L.%"Vl3Q҅ 2o"Sph1[>++5<1:47@wCCFT'z 'Cta] -9[iC'TvІ8MLͭ M%,GwFD -죵]uzrO]jlo:Fc}tanWkR Pc s[Rx kMFk]؜ҟߚ6sܴ0SoYOnJh[iA m& mXٽk]r --bXgύ2aݽ\/9m'}TVM;yt*oŻ]/߯Es獒4)#7<;f^[A5Z"J^@6CyK̑jOo'q6Ŗ~`Bz8kYc:q}T; -D^T+)4k=|R.Az-ݡOF$8lyBB!}c[@h {)f9ޜ[93B {b~EatKdM)| ʹPPs]GD tVҟ9r,4%(nss5H+{{=5KڍKw˾]#z -vkFaΒ&of.(gҖ[\p62Ɔ\GYjy1oeR+;n-gXט>"lX-'M{mYy^>؋-:>m'YcMp8gߞSToc!;jMt --=I%g^ؓK`χ_w9h@3ev:E>IC j -nJ)P3BH99 {>'{rE_r_Al/1'iHTӢjm>ٵdb3g%m9{;r }cQ5{>],oK,m(z{Q}0y@ -CK G휀&EWW>ǚqt\T)h4gA#Z8 -{ʱ"6bLpH?c(AKPس'e c|Cvh8WFM@Nઋ=@2Xc0`#}q0ڠV(zbO]l C|z6+t;nnhTqڬw1}Gc|tc {.rI9\[Tq[`.A_֔A7\jB%h?K|/ 6BrӃVS`/͔ba6L'iO+$ka_1Гyӽt8i7) wdW\P:F>$m %$ [${ &gKqBp{t%ġāoPP=6h:jn"p/a0WC59aж5a,ath:{uaa{!A!ţQ[{ C!ab\xhT1 5c {~ѧ{A%龚+frgTbk_v'#F{`<t-8X# Nze-v7ubU6> <h&=CҌb*;]vslhp'1&S;<t,E7 ͡iSb'9+]F''TŇƁkHo_^w0F_LbQ?C#m;H[3 UIBmHdH1jSyE % :PoFQI Gb 匤{ѡ;H(V(>fWKmb" thDkQ Γ%@C=at&Ɵ{uO~4C WL{2*Fc-GJ44.m7bɽ k0l?p9Ⱦ sh/,i$}v[ FU9dmv/#j@;-/�bX-=po-!tz3ĿtյCYtl�7;6Bəl\YTc9T-_8?1+|#qs>vYG&!d=EU} QGp8]I|EՋ/2;VpVtEX]')A'~0TҎ^\#ڠʱCb!ashoåQh/τ"l]q|O}С">΅&1$O?Kڋ|~Aȳ@u4ӎL>8ݻKNm%}x' ; -<H<0 L.t)G#?Q;Bg�ӭ9Q:O=69O~=8?`.+Hj `SϠ{Cqo$@8 {o]J -?c3̉/7W{3Uۜ_JB!>Ǎ;6to7@&1>mgrbf Bƒ * &X yxhЮ<b]bvFLJ ~@ �!qk`HA% 7SPM4vE}"i_U%` -0駦Cڀr}мClEro`k8?g!G�%E v/SVKP0-j_"w򟞧2Ќ"}v)g![E~G-j,xwgRO;>cZ H_~^gTS|&J[3[ g䈿c�#˪,=hG' cyGs:q`۝!|1O~K�04pTIrJ $ą87y9@'mwDf'Xph*|3pyT~ćs7{7G7$W9v/I^ޥo vsdoʫ)uq k| ]ZT;c`Oh R6pHIqZ̮ `CJZ~ v,8m捁r_V[<Y MP-@fKZ`ٱKsyA*[O]pρ1 xݤpp&j($=E7 Hn>z?%g;HMbuMbKh",T'k(gBc{bt kf T:?H=ʼ0zȌAQƍ{LTOwKD_*'}ql'5-X yc6qbA\и d4&14cߑK5?9Lc }X2$J5 -W3]g.xVڼs6Ol ->1# -endstream endobj 100 0 obj <</Length 65536>>stream -,;(d7Tڌ4 -3FkaMt&uhޫDOhBːqҍ1bcQ$^7 v �w_ b4jɑ}a{ rFBȈ;B L`#3PS+4пcNL/blgC+q+cX>\=C f2{H$ ~hm{_Nm(4nLALݓiR4Z(85C?u٥/1q);q T#[1zh%St\O0ڎsLZ~T=gB\g\@|::g1SՖk,k.+F?>˭[?X&6CKQK;ܮOcNSOrn,40V*P@02Tv_aLQ wO"rN?AMQA=w'!Um$ƿ;r:h[Aʢ<�vjЯG2� x Fw %xm{oBq%Y.wfw t%1ܶֈT8UэE= oCL%gmeM8jc;AseiFњ>jHz|mTe9-Z -7H=&e/S?]"+4I!ާZBzк1QmЭ<9!/_yG:$3͟v|&؃W^|ұile\Nw\D7B@H.lUå1ۿ嶥b"qNt>ƁXذ-n)m\]Dug6DCGf}%# ;å̽3_Y=Vsc7"_琯O 5:4JiZ! sE|}[�Zc$6BIlBѩw0ާ~O]ZHAW:IELIrxިZ!e|L8Z#Dxlvϓ 5Sj-?1x5AltCN'lI%Ag8sMIR-/K~F -ZIZWx1AO#y?`oWW9΍jYj'y -͛Iuiq 5|5I{"NMd -n,/OG`HmA+*E|;laQ:ɻ|.$=|jf{Vݥ?MsIӡFJⳡ!<tOK*l\!<X f -b pN5k\]r9!o CS -'?|=ENd̻Q=QboR})l ɃAc1(ti| 󸔓ߚm$Wf#HlɃHwKO۟:~x&XO!NXE ԕcN?_#~b}7$_-;Ԍ2OH9<Db}Sa~^Yr}1ec8{nKbq{:ӥKrb06q` _GL>jEA ԓHRNLsG4_O:oq4_G <Pbds/ u)iFRC[QO2%KcڗAb2SZu RQ6Ol ߘHlR1}E/b҇!ءܕo3Vk]l yPڶtPΞ|W A v)Gh͕j*iAUfxcKpϢLTG7P닸\'z'YO5Mjްwh\ʹ|X> *GmW)Rں*k?]-tJ2s蹡vIĶ.R :(u#>4y)#TO6F")]ؗ"\@3 =F䶔t?OZ03O:2~χ bƀax͡In~:aR[ - jPFst.h4csh=57yʗv!c`f]Q6Fh?|Ɛ)8C=p>1FkSfc<;_3I$ )ɉPK4ɻ<6 -tSUM.zc@Mu̙Fd|,ڗι"Tg*.HnKutI<RAVu"[|_Z$VXkfQq >X˒1%IX8 -,Kp@c@tKSq ?IfRglѝUUUEw[T8 KSo]OJ[01a0wel"+6( -uIm6sMWCtӶaAC+N~,+wuɱUnO.m=i<@XIn~)3Ô C]k+x)p]Gݙ}lݻameglo6FyJz6 g6RU!R"m 3#A|e[~%9Oγ;/AH dNߨisK;f2r6Zx - -'_ڡC|+缭' /3Q-xh"b6i(7*Hޯ<ȇ1I`Q]UZbX:XZ8i? b0A L5vz!}EZ rK >19r^vP}Ӫ}o֓1�lp1LCR  WEZܔa*62 -~S`O5$^&ho:aY~wŽ]-7㰍![d\ \EĜuUuz.{a!LEMaܓstWFy"}̣RʬcsncEKly\xa\b!xbV=[*j18LT^l b 3[[*E7mKDs1»?1?1V:M] ?}X̓ L9p)z$*~Krԥňㄠٚgk9/4/a}yPfg�./s(rԏ#jhOO-?].}{c57왭?%GMWU_k0|(NRB5, &4H=>kGM^yKڥ\֕m2a-G(k+UeM?۟lgT1|?1)cLqQ[ kA_X jm*Ymt&yXsU5 -!_,d]^+G{lS:S=&Ž6C/[-kͅU| \hQvI׃@5qȿ1gQ6b#ZՎe|lx0{(7vW9E`ZH^;%co1w˄Ӆ3hx{[|a%_^- 3ue.nDpMT?ɼ:=:M=3ڨSwODLGcsC 7"z<__ܸ 9; yXHr}'5jʇY{64֯x81Hs68+-3Op$ e,@7jQ/21`;ʗ!qpd:zlIi%wW - o\/Ƣ}TWp'瀍!j�XsV '5]1MhZ{Gh[@Zc -8a@+xkt:7upV¦brvT9f)gC' B �,K>unwpV},Kõ`!ӵlwVUŽ{Q% f7�gw<H1 |8\¨v<^6x\T嘮-iNl 4JY41b_Pv�e/SS2=_ָh^M3|?&_~U>_u?l:]gP2Fĺ|>4 ꗉkٌspwCKEZ!ɑ}͌n&[]c,igr�@|oI@mqhhhʳ+ H<hj嬚Ŀ?/mꭆK٫LY.4掰 k~_)xlV-R(1Bk`s#(yDMDlG/G`FT}KuuMq=⯑>>í<KI( mi[>~5?PTFJ|P2TyǫeZW5([sYQܢ9bc0$BQ%cqG>,|=5ROۛQ\ b#v?xgygѵ}Ҝ6z"W|{TҸF,m\n'ߏf|:L:P?"}BXc!XLgjrfT5r3}-{eYF n63 Z °9C-t1g&_8Jj(X'ࠍ(9pxF=w&^]kh  Դ3h aମ5S<Z3^0߀y޺PZ)L+sp`%8'u0뺵]#C!¯CV׌wO^,Kۛ UV=YJ(l5XBE KP3?ȉ1bLk`ϦAr] E*f-FTt]SoC3UM?,bN`rbMDLUSRPp0{+L)Lsh,-~#Sfґ {5}X;q'0_ G&5!.@r9Pn�l0+X\ ̣"D7?7u -)G.>=QEl:w sI`H,V/ݚCE}[D_:/8ls@oCOKDz/䭨D󍔣(%Ico"CJ=6GL::m9kSꘘDk|Q珬KB3%壆ב8H(XQkFM?>rPO<WT8i85_<2y\W=p Sټ}jl[ --uLӶe ׊!. j ƥk -%疴2FOֹzd:yn -r6XXZ(c ]PQ],\Cdl`m&bʩ/}=^t!n/]/󢦁8llʒ֔#]+"1ޅ)?{jEd L@AtBľI ;POQΑyhku4Sךzn-YXfr:x-|Xh.\6"pH^mAl,bͥ,>̗  -RsAHTzX|z&_.mE:QȲq4/E ɉc0U1l0) >B"Ntܑi4B]KjJA3/I'u28 }j.CN>1'yGԌ3Olt-oB=<?lY~B1>:v)$v:k3ƴmx` -)ZroQ?T9)6/Bu1[rSi[ȔO|Bạx>jb?9Ri|Y -S~ _=2/PrڬKX6W0/qw>>b +y}3 (V<^!VOׅsQ/ءy@nSݫg} ֐QX%X zgfӘ#b>w,|t*|.bVa*́LP6|nju7]<wcocoyvGCUUL6Rf3zϿelk@o%Ur$tzf6_޺Rc][/nWYWԙ7RNWup1+{?>#uL@9'W\\7&j*ۗ`Vʯui>,Oj}xI Z*]/zp -1{&g`*Vm6ex?Q_3OalSE럔Ej_Ýyi)xU:y ȃ|ْ?Ц=RG[#9&&lU~w?/e=3{6e]*zeͣȕZ.bapx -tVk&re+Ȼٲm-޳c~]æ_ xv&e?XJON?N; Ci{;1 QW>0+_G =<O#ذl1ccM 1=ܹZyJo_++oFN/˧q\` .BjhνgO3o%C٨墦ru\y*b{G2駧sI;ͬv<`kĤ3+ZEFZmdY=Ayʭtܞ'&޷f<C<(~ l/~050%WV=_ybzq Uޙj`|g|²^X':Dp$k:kxъd/29.lK1v5B# -O7;j^T-++m[9 UӥW+,v_|Huf#[55/yjxFq?ƃCt}#Cb=7GȯFʣN?8(JuWA{%5Z]F5݈yg]_@ -dKx'`[V|]ulʼnP+|gC/-Ҿ'\w>dv1_ҀO<9 l/>$Vsk!f]^E#<qzJ_+.6ۏ_jzSe|>)_ܘ_|7"7oپ:qz7_z U|4IaM}Kn.tn=W_hvVnp-=ʒGK-ǚ7^{QCX0&vTz{jl<Bճshx|UyoT'~Qߪk=/37p w{ww;wgGKY*/"0W?Zsw_ˏ'ƻ٧WJzUUUWa<p't͚?s UV -5L'пէ: :8v 3v3#cV:j-yl@uﱊ9BuÜf/j|}kxk|ɜ{'q^pM̹"sRuR8.Wl^˷-NwN{mgܥv̮LCF /Ü&$.@< X)}&ONLZ ~TޱYТ%b&'~u77޾iuNtE&OhZi,sILP -1ZYؼHySխl?JoH&H>$򿾉޽ե9=ոWԧfݍl_.aқ4G -^H:R'mIg~s)k~_|L>nundp{=Ý~!I[}:nJu¥vW֣-F?NSUӕXv|ΆxtՓ̞|t! ;Fb,ͪ^,H:2yZm~ӌA|0FnMS5^x/lMf= wJu{e/cSǶT'{ᥚDy}6~qs!!϶[^ߦ>]}N>b>dcyɚ;XO=Uμ 7ҩG'63/<m/nd;==XhwɦG -\K:bĺf_+#^ٶ9?W^Yp\ֲG.s_E)p1?7#-1Lӥwm]ʰcL?,䮾dzW잝ɳ}v1Ohj PHrcmX*X^[ tͳznq5~;#l5t6L" 5qm>sŷs$ڽ<cJZͫ'kvd{{yL݋9oӤɶ/r-̏un`j_,y=uj"uVʧ9c*L즙ʳqGMnzruS!=yS2w뙫GK3Uyp7p Ϳm^<C>?+ޫ 4;&Uּ[l|K/wɵ>"!0989dk{y#/ ϏR%۾<Ѯ\7',}避b"}DBi|y]ڗ=$ݡ~ ?1y72;?.<rlBS5Y̾5Kvm,*~]䦧g^-R?K6XZR}?4~JIYSxA -VV75-qZ"B5Y{B'&NInylի([7;kL|]v[:jg=fD~\wy(soYھL~v/wT5z5&/DhWrm_:^ro< TfzA<Ҭn{Z\Jt||ɩGJ*j -b%=LNmɮ}oF]wڍ&̫ w}ב2 :V]]ZPRob9)xX4gw7 kQ<l)Wjis;+=&nKwϟFogH3w"$ɴzݨ:YSxEv;N~۔n&9,a|ʯo$ؽ<B:Ej -ܸy7bo524f%㮢1<wܲܘ|+i&ui);; ߉ұ/lkVwnEZH~r+[ꡬ}RUfTۦN<n|~trCRE=M#g՞X<\kQhkj-+wy b /Y-0\ܒa#K;j䷷g,lK)zTPx?L)( A'I;]9+̭܃wB4uQ9NOv:'m1{M•Ǯҝ_^ ƆV,IyaMJ.uZv:m")nBQ7rUZ_D΍y>zɥN#exoM)Rr<_5~F5 {go>}7%8|揗᦯:ު?Z=ܔ]_t'2FTN`cNòχyNki6/hWQp[f? ٴxT;<=WgOUǽ~!֔l͛'fا.X5-0N:5دtIp㲶9fσ,h,(kb/[wZnx) t -o;96fvzӋ))Z/!F҆IG:2n+jהq$^NyN}\I݈ւ -ec5$@|.nIl* m.o,({52l߇f-Pϲyy5mI+šJ\s}>{,l%>|ǵ -F<H*>'2/~d`~F7d0L5j,јא_y+BCfML]rk[U=wQWŏvď;B,ZrZs\' ל~3*9ond&6$r+(ج;~ۼS? b$+!t}G^h ɿq%@s% '-Ln{c2kfxsqPZuVYmBR|@1OW(.\=GŌ(V?yйIhH]f q{/Ed]M-[y5Jq%9/n5W /6=>X@⢢1oG"qC^}t<8[~!,ogZ}3<87{KѮ L|5Vic SQ SR V|E=Rjb -Q^ -^Y8pkHW#}u)hM_1D+LYX`X0tݹ:bw -vzvSS{=*뷂d]ZWSט\ј^\z=&?mMqy_֨þyؚ;"Dtu{U 0 -940妾_f?;?Q1^bq -a5 UUVQRGpPY?Ye,9gyk:ךҹN?˷/bdǧcR -T^!v1jt[!Kv܊!XsZЬ*F4oK|c?lIvyVeNU:4GOkΒIgLV^sAdՎ:+()z*z(t?]r]:䟖B3}U둿N~ҡ!;E1{I^usF|lRJ&JBN؜qۯFsrDι+acW²O^ >H[a#7Bsf7&>K~~cwG^vyg䵅{ibɤ"sAJ^ڦ7yL}ЦW5|ݏ4T1btU1M3(;M{sQ9WfU_̩ClLQ ֯NeDM+D<q-$PM59_[CZ -zefuUQ~ܠ3\COz䚆7|jE[CJⴟ\ ]sMW1'6g;v4ͿxIJO ^ʽp5l+a9-B ʖ>J"gY'oN;,1W $-ktG{6رƊk|?7_snםҴ .E坾{rDGn板wBD974 iu yq $ .5k΅cYn=kBg}NO^CWON~߃qEs=ɿĪUP z* +<\y)ngJuA>R y%rW<ǻ4x~z?lu}3Jؼ9!'#y~~׫w]ݝ=rȿtvY.Z{7l\Ί%Nu휡|kq8óq{z<n-9͗#o_ {@፰kemC]Gg7br wsʊ}ӱ ^ڴ;ד^ANR*,V̓J~ms]˾s G睿QpJx+uBK^ /8v5,j&>;5y : M}]P?֧&jP 5`b&>~bEnt)1lb0ŒMt_ſB  9ay҇dwS]ڪ4&;mz+H擽䜾ٹFwڭ|:{Y1BC(V/;.k^T*E(,XQEzaS 齣TJ"v%jb7kbLKϙg]d|w?a{]*^ 3^<5^ |t4p14uA&ː'df,@c#cy]i"S.5Uתhm8lŊ_^-x{|ǷJ[<Aan,쁺j8o~/s-[di5"D~?խ/&h#1s2_&ZASqU}jKu9_yϪ^(u%n(z/;_-n٫[-+<^fw>?&]XGt~<Gs#6sD֫tOdc'FvRd1M̭<ф)z&U_.l9N/6T܆s-pjqs ~Qŕv|m6-vu}^'ϠIsPd#BYGVW -4sY"qj YMe48Y&{"KKhECϯTAߩ"J=Pw=>_m8wRՍŽw;=|0mR- 3H6q42Ӷ@Vzӑldn<Y?gda@&ȹYۇ"k;9:?F571r=wZ*&H5䠟)17_,9ÂW -_=|U+sEd [ c \!ye眩dddp~Cs[,bt6,"h{TfhӋFR_ ooef\k,8-'py`˫ontyዢi[=/["92מۣ)~�Glџ[#s{~YBnq* M*A=3MEV dsq'UDTk7_W_vz}^|Ѕ [f|sKNx|+Cʾ?[zP5b5I9"^8bo5b??[b&?Su3|~SD=;d7F?bolh4ea<M jESCuʇzz<Q<8A銤շ8]v\ɖn\(j9u#{M?<~<e} /ͅuhfЂ<L5&!qXx`G'-RI 8S4?dņx!h shQ!%O \FTQ9=>Ȧ+-`qF>Wo(EZR vٿ5nG!>}B[_|bD?&:ak+*dcLM]=K<_{L}Q魱 뺜PMZ1%"7*ܐW++ηl>vBЕKE[O/"ks_\_\5eikU *׍WL 5tHv^RdY-'qsF^YhS>KN^l2vy2SД,@fyAhۉ~OUnT=R}PEުoy9ȯ&<9pncgMF}{a[9nVY?69#s?HίGBT x>#c-x"SCd1٭qi͕MMXG5yg*{'WP\ &9w<1vem#cYk܂PP% ?] ͩO۠rP^*Ղ֛7Z]o.gEMGwlSX +dm4MS=fF74/k/'5ZRyKwIs%Տ\4;'TU+VSٹ6<7حPXERUfVYvܹns#@wzOj!Cn.ɘ_`ቮl'2)h]Uh -ۣpňf<>wUK煮-{d4vXc9*՜h,i[kN/Po|n?7^g.n|&́߃3Xv0ԏaѷ -/RaSUNT{3x/Bl%hʜPdfxe#I[82h\Odo.RNmYډ19Wtc=#Up[Uӯ_kxJ/YԏP>f^cMXtCJ¨'Dlkě[dY>|%RPw[^cϝ9wz~2vaP3|&zӐR4}q0Z䝀r=-WVJ"V}X/T1;z%? -jׯ***EϪH7oT>Zu.TA_&.3Qz\̾~WjoW냝iO<$D\d|z|c;V.a׆i:tqdf8Hq9%ZVK2UL_U~Uݟ\n{~ jmֶݷZ;oh}8[ -k(~Ϊ}nDTa7y_7?}15($Nm2剠1҃O]ٖs eۭFB1;vcCٲSc.#+im-lSY8g-cHW&HKWU/TQO/xn@cU^*^tKV^9وq{ݷUYWݿ/Wl{ч/n:=9= Xv\qJ^uɯk;N\cϸggܪTq 3~q5?Nu4e?k:mbLZjOis݀#T^ܳ۹q_V~{mN%HTn.JZ)ZA[TTa]iE$_ gic7_* -Z--{y_y/~3#xUԞ_<̎=_3~ -?r]~ޔH1sSșQs+83n]*eԀwbw~)e~P}oΈ2Woy! -JN ->GjQʋၬg}oma_"v~?ϿM*W9UPES3ğ|%G]0uotF4$U?B2^$~q d9 K2SIRW)$Fkt?R qmb4ӉB˔uj[t;X*%Wy= {^`.E!Qi"{9k|]'ttOoqC胦:.,wb':/ -&}53Λ+B/nd޼R<0Q8\RBDZoZ>o34 kzX&@sъc|ZX{ިUhDh") -"UՏ(!l; ANS,4+,;/8=ZǞzK^\ȤՎ#w@DYڠ%+xqgo<ܽ7dW;n> =sCmkUM7c4ݥb.-c2,9igR؋Sty#7 C?-Qy*8h -W4-B7 -OLэ)_e }bd/߹//IՓ;2ʯ5v`>=> &gh"Q-HעbSHˮ7ГSB.<ʠO$[/ԝ.4~E \h͖sVna1YmsC*U*o֮T,qdJp݀4CGȷ.҆3܁Lz ;-cfk |<|UHD0uJΖvYI;.-v^\$vёt1z[+K=+aF{+N_rNIu!7). *VSQF= ^XԘF lX\:~]L[})E*.xM\e_ -lM6B4]=' \"qBZ& -")?~-붦;o.ٳ5frϔ =t6O nLf;`tj{/Yn7J}s1}ZumOj%UxZEU-=Uk~#zҶYĒ0Dz4?kOIh9h( #4" -MS+s&2_,}‰ǡ/%%ެmv"WKKj1?$[,drz<6utrv�z{/I%D,Sy9`, أrr~ -JAXpUtV|MŋΨ6 L*HOFγ'#w''' -BLd6Z$<M?`EkToB@g( -j͹R}.krJr-[eo/T~t%sk9Uup4ј82M~ERz5=N*Vnh1>_RI?@^{J+g.]vQ-|ʄ|a3y8Fy$~"fR)EbAO2)�zѸ|C]>ܲ[?[ s3IdHgo6fΆ =w?)>#;T8(Ώ~r7|ʮ>Ld xr6_/N9՗ת0<nT7?Qzy(H!Io/C+<y"׹{QV#_ $1HK5 -V>2 zȏ -;twWrȏTV3|$j{WB:c4N4[l3~fzީt6Kߚ>d'(>GWw\ ~iAGq.{E% -EpG\TBTDg;&bq^ md$\:#h傥(�;&p,"o|e< G -笰/r܁-[&Vl^7ơ0%{y_ʾxDQ"tґ߲)…=Si5 -Cx{[دo~T">} cAȏMQ|T-?5#H.բB35:u77<8akS_ C@3tdMezf+5xoh@(SHwTe Nʇ&Cہ>Ot<~BlwA\sMg;޻'^ ҁ+}?zӇ ddLΉ ꃓEWgv*3սD5yIWGQ[% VcL\77<A.+PP5ZA8)ˢ|Q&V"PHׇa~~؝J<*׌nP2Ε80X]by:mUvU Ot˅l hm= E|gÿ *i큩}6Ҽ TR?2͘c3 `tW*]0?Q xКzu?wl3"zB1w^vYNxF?~qךl4a26S]]yJy'ϽQQ0g߆JŜz';PȇCS4ԣu!/(,`ϼUSU4oi k> 1Z#�Ibsr#R4Lmr'Z窥.FEzhuBR<ʘ0bu$M!!C'b'rte5Uo,zx lfh=PqTIOZBOLcw4T[dW5`4]6Y\%[m7םuyxzq9Z@IYJ+ug8 ;]S4oV)'OyweHYBh$ZH/+mۏ/f/,ǹ뮣Џo+֌|jrrn[2ڳO\~򒂱eϽ.bNaqLtvHtDL\EH:cL%F1хcDl,#l 2h8Vؑ\t|Zx~[Qpt{k9ܝڟ'>&)iPVP$߹BԲRJIe3Y㨤|Lj;fug՟Lڮ. ~"jiFwPZ<sr0G,Bk֬AAhm8? _|DOITV1hmZ?P%QR~fhvzliܞgAwd`\_i Xއ#pޓ71] -%ML;鶫쁷©Wԟou -EZw82_K,QjLM:P.Oy?iZy~S {WdVw t@PB)QEYb"l}8Lb ٲrfz^Lg\N9eNKߴ~ -E^VT&z} 7bzOv!QjصlM:Z/ ez' =d֖ -ևK@ԺqLJ!PKH|3Anԁ 8(ݍ>Q(I?Z6긾ñ,M5?I zͥi-!k/ґw`tT-X#ՉNKŒNLeph -b3ZۥI$GSQL.gsu%1$/ZLV)_{r.h2L56$&[GG+bt%SA 1szTz*+u{AO|&@|&z&;s;Vvi7"'a;u"tx6/]>:;;,fUwTLaT*-9sD^+p<%8HQDb'd3ƀf*K7C͕BFx>9WO(aZOOcS|qdW &ٔbq+ :9Ĺxَ\aђn$0IezDoS{5шZ*\m=,yLr~0$ A`tb_kE{woT3@t -ءWCLǨ5=ڛ~zAq'^*O_ҝ͟9Tگ- ,`]ba9|%t}g=Ў\ OРsM`m|i)-:  Oo -ڔ|d|-VSҐ D `v0w\@|g@[>ud%Z8VH.->] B2ra}?C)?t˛~דs !½j/C}؅3Y'2lx:{@/.7i7V9FTB>;7/TiTVcE܁@߆FVAxQcfU:屫1RЅacAt[76;90 x\WT}Vl)య`ͦl^]Flz1HH,gR*  'sYͦJs^_7py b./@cK/./OÏR@3NP^{s@{ }/Ü 33E|i -op퀻kɀU -6 -tbND>A4ߩuT\Xd$<]g#*o, :"]K(6 tAM,Ut-orjZ؀h2a%vDKn!TM!Z)5ggO.F?vz?ėQ<c'+^BʁV}@}65tەT3%*zъ9ː/ @Ӊ͔r�+i7# SB.!iqez粚Luc n+> ?r=o>�t@S<=^I* [q4:S|Ko2 GAU8 u4<Q @#0^X}f}]F�zٝ @)N2aa{=Ҡ%(8|F8!tἀ -ZBޙWcۨF֎u"^o -:A >^|‚jŐw_q`RKX :4~8VR,2d l=bWiW$42\`S':6# G  O~S̄f `bA<+db!NjTd6ވ#NZ-|in_ >lmWBy`vO Q? -wGI![-9JuwX.|<\" W64 ulF }lj8Xbr;̠F"\W ː@$Ԓ*5|q#ƹ4!e-@A4-)΄L3n~mbCA9+2hwOfN aN>b6Nr;'kӴY$&WW/N& uDk.&UbM(T@lxm,|<Ra@He94EΗp�].`VqIڠSu^v}Qa<uxu_ 4C 7h`>)O[';c.9 l_Kংf*b&TQ&K1F&,~[v}$'߁/k=3L@]^:bGx3e}"LW8\V:8F�o]ibBŽ6DO -9[xw>{qm] -!q}7ܠ uj1 ęhNH{;3GV|x!6B^W,KTxZ"<iy.g8,^h6f7ƦN<hpF< }F3>>Sa -Q 恶oJקzoo?W.ck PǵW`0Ty')#B"c` -)q&2Li9 -M4L:lєᄡBs]ht>5`+\ՠ4\2 -0(}S=4K]%*C*<^p+MmAn;֟gnDr4.R+ԥ�]id| ‣ckiMʛ0O{,~+7|>U^,DYV)_60 AG31[<dCrckKޯECw%A?yҮI&KYE\5wM'܆1ǺYDO/L;~m [:)AIO~z>D%nc[:zm Ss[X= :F X=u_rp]+pJFam3&lZ<Zȇp[./X<VnH;˶ἫPD~'be${~`sMAQ$[c(P7tҹfo�v"щZ!ʢ^[ep!jC@&m7 3Q)ZDrtk+ -گ8@KSsn )-~ @[A6x\BGnp~دC{0eϥrIz_4![{ -3hIEhcnj |mymj?!׊h =@ ,X#pS=@xu^amXkztBaM_U{؞}}ف{2ޜX֜Gw!YY]O30[uǗ#ܫOfɆF^+N'U#vDnK('OC }ԦtF}uq uV t m&~# lw.F=GJ􎁭 ;fjd5ey\σ{>\eGyn9B -zK q΢+HVg'; (F >4E|栁,jzk s[',J#岓|{~ΛRimT4`ld6\Q-nqdXvN̵$uCĄM/+ˉ7ԔVzhB="__lH -翄 ЦWNXz3}iD=/"+30.̄\4Hl`[R>Q|`m==O}BKQjL qWjqm>J!m1h\ \Cy^۞˫Ouqbչ-yZ8Eߐ;A :;?kHV\4_^V65!{,zWɛO+N\+i:=|i>C|,0>WkzG�;`wp/�y{b*q'oN\jF'iA\$ܬ:#`;aqU&,yFH@ʏy ֖J#5-Kz܊rCEl0Nlx6O4mis"r<p3{6N4$²B&&SEipڟZܲ3著WcB+dfֈ(c"pw ~`soaSqȎR~+Oh1p:-E)" ;K/,jP�J - - lB`S6<ѥ`{ݏ};s\%Sض5!aӲB>*o ]/{ե\�3z 1D~'/Ay<;O7oVԝKqyDĥED\Yd8;'3d]\v˹%.ڠ Z!+`a䜄W \`"ʣեHm)E"AGid6l@ΪOvV-p~\l /j \`gqzGs -B5-Z6ׁ>cdM$rNLMtYB4<B.$Ri^h-/ey8gJ,bG  љ3\n8�{rtFׁ CW(yR(;ņ `g)X<1n 8$O5YDOvVTXe~$YiGerψ]$ SX*l@K_}!WYl3K8}}l@K¶Ye44#_ض{AnOyO=$]w;+Oދ2iДoMb2aMZ3` 1YAt UVNh \!m)&Ma]_>3*E6Q^MgO�8 pE -!,)/WDQyJp|VQfȢ6ǂ7SZʋ;lrI: _[~Y'`} 5ƐqlyI' k2콁RY7{AN -k"]y|!l)Bؿ6M$Mr1?Y}܅>'; lC س[g -2`g/jbgׄLo Dk zcȁ*J;&YN2;1_ ^zz}SAs0 h;=Rg, tLX`w|% +Y`NX`;?sm1c Dz -$2$ՠv >krI! XX$A2FC[k,68P)ĝv@XU=)/rv1恝{%u`gQ,X`gaDYjMCBc (D&ksIZD?݅}P=4 P#k5뾳ᄊV3eр-0*[}ȩ@ 7LeAl!*wo39c6ηn+ ڬqEzY!yW ߦ{d;_NDY߾gu.U , $uh hu6]�~2JGYeg%JÆj-8oEl@� LQgq!ׇӠH5RA@?s8/99M,Hb7,ÂiƟ{th/gj5R'$l˄Ehʐ5yT 1pu!!@ k#qՂd6*E!_ -Af`l!e,_W-?و}.e&VgnŽY:2`gmQv־ySR*L >;^"eaܐi!ioMD 8\e&o(4k4\BO*R`0؟Cj>[8/E%GTAْ -."^S.Wk|ǵKXzJ_6< C}@XLtIL[:Ov/s6Ow4Z^e7#kQQ}h.+eW 8({mF;nLe-..Pl:8[^hXpSN\CWX_#܁%X܄}oDyZ)a8ǗֽV,.pM[..WGES!;I ^ -q9ڊ*Coy>|p|a A{kǂS !Ҋ$ 4\M {~p\ -☢g8.y z(d؎m<NPs'�@> -l Tv ;2_kU`(SxCc('y�a� ׄ}' `F!\B%g -か|b#h}|Æ -<?1Zp& =}6)_K-/d:-vbY}烯5/-k9EY -ZlU;l%< bYo1_QiCrM0ЄϻP10+[O.ᷞ[Fp%HY`U7݄L͕6^ G�8{`}s`MC>yYzJw_\JN"F͑BU–K.'$aQkaڰ#O)1<.KWQc-&,&3\qNafFn <X 9* -:5Pk bT1!L#v+_& -)E %Y݁9p?0K LC&<4zDdS >Bp]%~t50IK%]G Pm\AO86Urړx<t77 kCCw]w>$Q_FMQ%a| 2}/,bRtZ MB>Ns֦pev+MV}xOdgNs4av؍$R nLy ۘ3z,dͪndaUbrۀ;(Wk{e1ޛ.k#& KÎ_Y}drāʝw١r H^c^7>pr R3wueIYSuɐ-p8l?`NQ!87"D1y[X#jl`a՝l##}(.&^ X[p=e ?kZ e.<0QȽ^`RuOmC/tY!a]T-/38Ԋ>[÷-<잌57k] ǧ:\x,y -Rx,x,:,'XC +w$Ls`✏ufBVO-fv<;//p:Ɨ둘To6yȥdYF$OoTؒ{Bؿ3g':RY:+S*{`L #xs9e1'1ycs3ns`�2n -b !;;{rk4ޗ<xO/=XTro:,J^lTɀpq뵤Q&bTs{cl:@?_ʐcl23tv,XC{3RK  hȑ)*GfZO/Y%?UgY-`OP+%~_ݖ'eO׃K%<" `m.wD}< ^^AGpBp|9a\sv{PbLU̶{jq.\%90OI +ژ=FTϞy-<po%s}vvcc|.+r#`p^h5 =I$T O#(z %[90Fg -ߪztyIWvl!{mv ӳ"~Dzte'xr&CQ1bȖigO^u;/-^p^T.>O\Bl{HJvMP'bBq>m>tI\sý7/%gq eu&B Q=dLk|iKiy4&Pu< flbLV; yr'@<-aϖbne[͠v y$o1&{1S} -jLg]-8FSmBXMp^a0اba1Yvp}y /q|Ѐ'?ðUF^)Ή&(Lo^J|6,:+t5P'66C] B/ڂRL"qas7M%vZӎ|rSw|j -97}al$k'\2*ꓯLþlL6@n:pzpE# &|x|<>x|<>x|<>x|<>x|<>鞉k t9nKB3iQAnikb#bRl]s\`�> ,+*5dAS,n Wβ `"Gx[7?&'aQr;-ZblyK&;9;[dBx< ߞ??~~.khllk?˖\`e񊍏r{(|^+ m9okc#<y[_A- ;% .U.\v" g/l_ o#�:.\tg_]_yz"@J#l:<pu(V ! VMU ݏTt6-LS=Dh -ţ &N-HDũ{qh[0#PF+֪Kk%k %Ժ -]QT$AI#41LM=s/*A|:tCP;| -' d,K{t5SХ( (%ɄhʠkPsuA1t^6^�ݚY&$e -U.[G %2EK3imX!z2PcP*abBT:-P"P`#STmPЖ<5FenfbR (sqy:E ʪR*TM*qХ?)[W`.=KQ40:jl-P\ ^sonQQAt˒Piȥ5L&S6hl"Q\B}Ղ'J6F@GAVKp]d;(8Äi0|:&1꠮ ̢h5$L_,G$><P P|(]RYχ2= :W6Bҥ3@[0D)i"_AW5(8"E/P@"]aYBb8>mPOqI@nVi�P5P0JEҐtMVFgj) -e*LJ4M6.t -/ FSy6+Eq-((2LA\eU:Ll<__+Ulu5tT[vL4 %={~Tk2|Hv2%@Ȭ1%԰$ذZJ0LHE" -u}To_!PCڭKYo*kkZ$jrQ)Z!Ķ^i}sd)2̈́=.)_@:DH^V~/۔O&jX 7W@w#_0 Kx,=4lЕ[18-1Otd+{&2ƒF>+>TO,D{a$,otMA qx,4iύmDI&*51D -T\Ȃ1Е&T2T fcԈ2>d[L"UU@g,X"юkP -5V\'kH؏$i֕3'(Rk yz,PUfכ ݯ|fAJAG38՞ZSyZ1t$ d& -'C$thC, _WPH{/Rl3KNPA|>vb}&tЀ]nU<V\\XFQdAG+JStn4""DVe$K-2�?EԲ`sIG)޴c|d:5yi|57lG& AGYӎ-P;H)tAWNAtZ9M*0z Q 6!\doP{ -`Y%KG>T+-+?/ Pv8l> - P"J>HբALT: &*A:E -"٨m6Pno<0st;%\;K*חי -,|x#Z.nb]:4ET;:*DBl]PN -ܺ<TWA73-!'O Uaj=e%bOYs&b1NWM ( 7M Iq="EFcP⢓H7[@Ǫ<fl}4A:(@<knѨ(ŶݲmQ#k=d%VK:q[..-*'gN6xoPNT.:e lqiج5]k]o\'!TI'<(0$1= -}R.t}-9ax`usx@8\PErJ5 /p8.+Y6$M%Pc_ꐿ@G#e:(т*<H\O&rFM\bAth=QH/%xN@^ʌ`AWѸ(u8$(Fպ@\nI@yB%bFr@8Ú3(؃$f(Ղt !QVy\VQjP>^^mBTm"7 t 9nA:A*XQ7E^k ]W> |0o@EFT'$ZTHGcq^gj{PSe*=e"t'W:ltUb[E P%Q3ea2Bʨe蒄\b�]Rͦ%Ex.Ԁ^?lӾ1I>(%2~ \x/H2PNj ş|2p �73'םcIWcFC>k"\ף|UG>P$?!n65r·qrʷO|P# -@L<pQRYc*;\Z PF"R?Y,>lSjL@ tdq<t e ݴpM j*8+($JR>W<3C( (&*?᳐fC8xḢ؟Ym u(UGZ6d6*j$<2jZ ]%B�98\I5QH-7$R9򑩠:�`ÙN!5w2pl.t%sxb -X - (wՆSAD/kb΃5�-(pE:R NDghX!Or.VX.㯸Vu (( (%ٝlP%]�HsΏMӹO瀒51h_@ZLm`{-j@: `ΥT�CLR<\)9�(MXQ /A/POi0% -HCb"_z}PgOwOm@^ -p[`Ɓ}BH(8fAy888&9eB.o6#8o!qD!3 q9$y -JxM" )BEbF>[@�sLߠLP.�sA QXH\3k@x�m:ZI!L,k1$6σ,mcm}Q3t)\0jy!|66xu uzN�3Yq.#><fPSkR!?d4dM*2Eă{Elk%Ɯ19g, wb΢s9砀#䜑 眳Z̹;y>xznFvZ}W~Sc6CA  Ysc$mn=䨢1G)n"㊠Hd1O8 =0z93d}As -JTmezD9j 7B&Q,{r)'nLu\H:pZ Q7 v - -1ʠ.(?1qQcF�L>N*zkp̵1F -*F-;%(لLu)p+!*'\k8l�qsJ_<.$o(4{%žc/vrZMK-D-( ˞r ؃58V�`߇\ }>cvL`6\.pLI10zk,su5McZ߇.j#w6;~ w�PqV -!9SJ3!uP0Pc;06ŜDhLŖ$~r^( |)IEPe?v(Cd }Kȝ &y}�;p0UP|=Q?2sՐ'b@ X㌅rn -.-_ƞ>?jmPN -蚪TR\o$wIX7(c>LzPa8B-'9_@u `K|,"9a=qXJ킦lC>N.F~&Q-\D^Ogj qo6r!׀ҡ(|CpnEW7ЂuCTFĖlSUprJ:& ` ѥ:uqr8\TL q]qW^J}@8xd|ܥ\УlTA/P_4q\"egސ� q}'p}ƈ1orvii78(=2gNx8ˀw' j.>8хw' ${Cl#P)/ҫg~CTG0;1Q49>z&L%m~ԣo|0e3!L/ J݀ZewX8O|Qʤ= W~DMPˀz}KxuP'޸TvST0~yp(P\x�;ǜGJ@\ZF怊#1k2_ezupzw{1*V.u:`A/R&:Uu3E}46**^ \8왠 A\1JWu `k5۸ D(ćhsTqjCDU @]8\pE%DM[!cCסNb=T LZC�fO 3H\0->s!x7wl0xM&PFz&f -(܊vsQEP | =2^$~=!OƟ|a$kH2;k.wg= !6)|n _NpcSӉOO%s%7%qH@m{lPf% -+HT7T#żȷDj(;dy1Nx&p>5ז�.Hm`C^d�CL{1`#jp 3sOCǼRBxiл-g%G4ᒸ1W j" Epw)i|IR&8�ƀ<.xN5kl8]/U٨|�H]C[y_'?b7k|+J⑬"uKy\P\ -*_nEײ["=ކ(CTܱ౤/9O΅YGk0�_<TG3׌9Re-0_<5exEDL)"{8BK]k"DכS|`,nq"-=8?a6=?uT$P~p</]],uVD:({$|z'Ay zЧ$\ RAiz n,8!\H'o9:Y c`a|/qS8s.~60W6cqOkC)Brn$B3`bڀS$FCܤ p@ 9v]s%rrPIU[ޝ nRDp<.'Ȏ{lC _o`7[:%-#Kd -QL)ͪ7kDXGBأ.XH.\Uc^La:�Uꖮ5 A4KY)d;jޠpp8C^$l8"@{B-qIVS8ECb@8Ep675 u#sOPMX#yLDOYOy_]2=S@ 0JT o-5Kr)N0/clCkĄ=]IGG'n '|5ۈSDL6ހԏs!C&&RDb -s"OSOica0|@:Յ]8[bN=O9ĥ% g 81%[ذd Ȝ߽%TlpPN *�u3%L:pG!{n "ؠK`1%'pʀ'0{̇E{ 1Z b�Na�x2x̓#(pvDc_@dS[%WW|͘-f *l0i4]`mK"D :E@n+#c25E/iuf`bjPf$q> -(UZم셠Jʏ d/. *B&N�^cO18.eǼǐ֠;!O O w&n&P{!I8EViJҫuX"Dӊ$fi8=8EH])c)8Fn9>ޓCI5epGF 611GAJRgR;4I{,}s'Su4?<D\kpmegxSC8`j8^NA_ ρc /.ܬvlۅYz;|o{X�&_q̈́~!g/7Opj509 ༠b ׅ}^l]kj=8eS. 83ej }qkҟn87װ<:|:>0?n{a$ C[?X/{EGk窀3A=r`̀ -iTꑠD1<o5YaEnsO<Iz.YfPzݘءM%Tn$NxpWP)+D"0FfHrLܒ=P-+a68:E)z(c~@T xqgJp1E8;I"#sE)In,dSwr~ KKܯ;&`:p^P8hGE؆M^#ФVˎ'+Y&z2u{$ӧCA| -t1EA -IVZP5WC |A2rKإ:lxz)mn8YPsMWRq)"$w O?"N+@i_zg<քx=pcMc ܸ0 (bw,=2(Ù ϋ WA<167]SU`>Ss@Xp{X|IH/Ue );g:=Pf%9*~9�="XQ]|KOjLgPչY`4Lf(u㧿"ƭR O! -{2︖C-=^'`v=8\1E[I\j&Z g&` H*~ V= z(;�0x\<2q[Ju<] _pnDŽ8FIJ.6M_vBvY>Z&*1֡c`Bhy|)k>)p�^@^ (/2֣q[P{w|gN.!I*%`GMpQb ֳVS6 �g䞱erW™L2ޡtg<;FO>Nz{k,�}p⫴$8;vpw|I?z�,fV?,=Ύ:Y5FKzTrFNڑE -d?\0FlvS`_pԦNNz؟ȘI -%)6p"Q%HE"<"$U (c/|-UaJ\JVEIj와۝?;܏P' fI\}PL+W50:@=!p܁TKz9z m1=g+Xd%P | -GrKLPXgZ4!0i@\G\qu):΢A~ %D%luQ -~yKegÞ_{ΊA|�zcIỌ̓<\ 80S#8aK!v9[?W<~֋g�'^1;d~u -Qj)W׼-{ETz"5퀳c%Vˤi&ҠEJ.Z,ʚKva.\ zt1d_"h_ɾg,p5>!/�ns#q(^7K4qH\%g_NP'<^ȍLPe^_%7sVMT-Id.i$k G8j| -8wD=\8#�C+Ď)3 . �7c/6pWgGϫsED;O^ a& Z=31倣$bD)yX}9p9cgr0~<ĤY5G{I pJ;� rF2.'r>`e!O{7= -8 HQ!AsA#32!C31~8AV9Swe e03jF.3 -G=FC8B g$'uBr>@pή* -ny+=Y60&lTzv*ds|6j2p)?g눣c(\v?wk1|=l5雀Ա cL'.p%Lv|ņ3w3{ ^w5'{> ݅CƼ_ڀ}TcAa|Xqg'H݇9fNζ:(-p48"GOaN y:k8xc2GxaEÎڏzHTy %x+R}/$|#0w)q4qsx/Y+\g߀iPjr[سz(}Lؿ~!>G=S{^>8;w~<ɣ{!V>g\Z::I~G7LHxl7X1Դ3Xa<@B~6)Z}2&>Ou;2blp> \k-;M腲fq*p -z=Tb&qդ/MpnEWL\l� {yo,\#eayquLv(ftx�9+ =Eػ.H48EL^^>co Dq~^^Lj? C#^AΨpgQ&2;8p`- ͎)BϘ:4g;sMɆab6Z�W28.ęKBQӠ g`"7,8B\9Q37̉%ž@?<pʒ-" -U ffDݥA_K\xB.ҿq"p p*1&; c> ž;B+uOѩeۙاɾ11+Ɔ=[ Nĩ>PE䮂L<Mjp;`Zp�!I%بƞϜ CQrVؓbB -W63[]tRV NN*߂k*aGx%^A# @}J X98@@!ށKz:[ +Y#ae^eEMb퓦rW2im;$ 5. xT`1ܫzu9c!#@g!bxWU8ks؀T4YmPai䩌[,*t-u.ZW-Q#73:n&c.ҧ>3]B飦}u'/;n.GGB_] :](zKmԔ_-%)R$H[O;%k N -Iӵp.N -@sble3`ZlJ7<ެƀShZv*+!ҙZ[fup3%J΋Z y rW3aV2oUvM;̦]&cqf?R)=B;XNkW#zf8HQTwmq)U}VV|?n՘q7DMk$N-YMYE6ldVc:9CjK2|+j�Ipր.$M)*nvظY ؔ׫FfRT1UU y -q%~OVg:5u2Ǥ߹v(A.Hj(!%%yz$[zP; 0ʸfd/Ϣ׭6kϿɨWY0߬Do[X[2_|ؖONL\aavRwiEi_<J?=bvR~F KҒ%bSvܳyMnU^j65TGK۴%V�W4wO#s f~{G|q8?#.N tP٫>S.r[ݒGuڬ$Wi:_N"ة]mpX!uߘՈєojg]B~DrY*˫c^9Ѯ-JJeti:r%sS[|UkF5ZXM5CqKnR= *~0Nr.sːo@_hHh>s{pe܋%y%7oz^n^)WCQW#gOӯbqiś3ݪ ٬޸uP H]~Q&qi}smGM-3%셚?)?.m&KKd٭r=#No֓duqz߃t],V%H|:-^/hדeҺ5_4D }߶ )AHsҾ@q_1 у&PȃmbuAw`βmeu^:J_wJNJn7k-ʎ~ocqN%Jj,)Pt\&AXbRF^krLzpC"6K=k8"uy'j;!:>3{9vK i/o[}}s}�]^73/b[u\VzAWRY>ygz/b?R)mۨvz`t0ܽv4ɂ٭Tf8X~bķQ!e\0lcw-ď,k_[ m.w^9u/8Wq}uxw8I?헲y],&iND4=l}۬mCC?.g;e^:.k}TeIr9ƥP_%^.wMqnLՃgge leuE?~F(GUm$僮<]uP֬mW%ҧ5e7$vSU.�Ocp2t1&T:\) ń*f|v~z(P(ΏWzJKfGkN./;z4)x߻qo#[eMLmY|=/?Xq?e}A˞57/,s?h9(~~s>J6ژIK/H[OɊ*me%UNU%oekK^7wX1/;wKx8"+(9!-<sŮBq5k7%xěE$myoU񂸷1i}g/,s+Qŗ̻ OUV]bw'rj1zb%UJ_I4X=/?#Vv\[WvL~V{M=|'wq+IA1鳺҇$-[ {_yAR[*o`Uqݭ#Wwލ<V_+m0/z͹'jW{zjx9=޺>)Lm|ƔCf!_ nЉYt;5rwOr.Y&U_XGZxE^T.!z2G~b+:KˎGn$[7fdhdV_ uLK.7Jruzy]E)JF ~-;\l[hݷ>> -|/ҡ.dvkǛScd8nvFh+ 5|6 -x:(k ps.G5e;P줂߮DT=[:o`S.nipv_&JYw~2>Dfߴf+ZE5]u0'{:FKKLs1X$ѝjFGZ2c+<j.$z'nNM+R&$ ^ԩԄ9…?]Xۊ|R.h-`W6[;-2UPfu"YJXyJ_#}zĬ]VZ,~BQDJ*rAەԣclj$;J%j>FiLJ L LJr L0um-D5_ opɬr̮q -VS/*BؘEp{2%}' e^U>n8nfͦ~-HsNK)Ǜ/'i"c?M&qA׼3^8kɥ%oZ~_Y4ށ-<ʖb @rF.~S~Ҽ߁{Fldݔa]XTYy1"&lpQ]Xa}XIMHeMH)6!<)"-*7xCzYߋIeH‡!{󛐽#-фM%ɰw1Ҏ3 qg7SW*TwnTF-' (IAay[Y_UyH i.|-)$v׭}]cl["bC=oW9Fچ6؄h }نچ>r.-:-:=ڻ2 V ظ,^5w%Ҽݲ;]W'K=-ڋ#$O5&~^٫3B\zTTGYE[QW&o]>쑈ݭSR^O6)¹0?Ƽ8B>dOwn]StRbk\lGY@ǭDzZkUU�2g.qo8GƕzFlω|l 7y˫΋ ڎHKjm$ol6"+(s -K. (Ob:߻䅂F~|⊼c2<p|%'V\H>5oh75?ƛi!U9A9[_̍e=jC3a>ZSDFk}ݷb_LL{qD?K}b0ة*".BlBGTfgCeT̉1#_[v?o k 5w}_Z6FlJ;֜ݭ=O#~z-.VFeHvi}̻j}w#.7~e}[opmcIF)MM=N:/Dž6zWG[u]4?mɛ}L+o}WyQ_8R&wy=f;*߃-R}2dݕFW^RW&i>p1٥*"ɮ2.ZG.68g?[vXuƞiNNKs O:ܖupw7Yn՝{-;Ls\\l{wSفf/-x#;6MQ-5ߏJ~ M/vu/Z{wi@đVW#ؾ~O^\qo%xV%~cD+蛯KdϘC}{91,笒JېMg>Guu?їc΅>lm -nN|/ | zhU3Oxu#:+4?M(Ewu#M;U j6\UR5Fj -㵲Xצ8Ed<3*/:.7:32 <=}ͺ*݊ø(!71w\[bʽ� ~c~XFks7ڄl nh`iM8M} Z f)HMDCdtr|cJt2hxe4Mÿ5 V)LGS h:xZorP1yS~a/uaM_>n&2glkNa8E$ĔzT$W$&A=2>1{ERcz{bk΅Է k(e.l/3t=E?^ΗU_w߬[@]p�SYLTcFh '%4 (NF&Lv0EsOFi$|| -~mHzō<$MǞ -Ox^yG$΋Q^#_u TqW./ ] :GGUx77 从~iMTpC;_5=_N&z&Z@-[iYP<E#s;T84 G4|RğŸ?ό£k(I<7 -<z1ZF -;oKŽE"GEFFż9WQu3v{ȼ׈/"ny5nKR  _z_Ong[bb_4z64%fWo Z4m {ߕHw:?h7 -F_Ǡ -cOЊ{N)~\7>8G6jUX#*{1ϊ<+,? * ؼ9ȸbCmYQ_ZY7DRy62j2pwߏc#n_F?Oߛ퇑_dk~~?[^d$@KN8/01 s'1gB2oKF5;t9FH?ʠLzM[^{gQ+52l>3>UwџKE|5a{"o\bżz"-*o[EhlpoLPOtf]NJ]"K=_ykIVv -+W -cI Ds -+8y 8>u8| ǟ#qVCJ;Ѣ-Ev=M}tST}%3 -he+1_jbD9o]#1f 6Inq_H5΅9m:ֿ*+3_s,Yu )9֟2n Z|krQ7oNʌHkHwO|[S簾5{J[Ě2]cp|F?,tN,Vqw0ӡs8XkuhBZ~& ږ4[m73g/^%$?)t+tJ-t*{EP1{nK_c */s:FWG񃦢Ɋ3AS<M9i!ŹhO)5Wy!JH\&DH?? :t1瘨G8W20%[ #E\ÜӦ9";W;݂-z24Uqenɕ_h`LJ磩c֢6i7"Д ѤѫФa+ф+~j4e)hޚ=hY~qFKn?JĵGFs7ni=o<//sWS\XZkG9:VM~+�|) QA+Yʏ KfɃÖ?-GFASwً0vAkAi -[~-/Ey|>M[\Yk\+7.q^~U7|[H6^cJXʛ#F><ӟߏ4diuHy:4My;1_ ͜kiL -4y.R^ȢhShJ黧Onyu!Ak$fѱŞg�Y bo:EվrzUi߽Pܵqmo prAX4Ya*6b6~%1u;\n<欳Ch 1FSPh,c4YI MR:׎z{-o?^?g|KD\^9E+qpuL)qNL]o3xc F'zy^_ fZ&y12~9^д [ĭhdlʋ̑\)Z)kz.hG1j߷/`'< b<U:F:'kuJorNmwHy]ꌹof-mRulz6Aa^W񚛤8 ?7 s8?&&ZǶMSǤT=fpBb.-jG -[C~Vʯfzϝ-L |*0-^Uxl:G?5)))1.Kicz|jR:i:IѸbxMA)C<w#W⼹͚͘Ckm<m74_RE3Zh 2ɷuC~q_TqJG~D{xԽw\gݘWyB}CJ>>?~?m&X 0"^q-s\4xpDN&9NR7M9M9FM\=BWF󶹠yFh^�ZnuCaw79 :GdOU3[t=[IKLjwUjSʪK<"LtY.�%X'<[#ZpyLR)]IJi&A}4kdU,)Fh<=4])FJѬx͙5n)i2?M_Qo0a| -Gci1UN5=u)+]R;*Uo͛ǁ1Qh.:6K -54e*S7^kӶӷJHy1As@ -Q*Z?Oa{ա#6?ޚcB~No,lovexx|B/ݣw?Lb~Q}7n.ᷫMT=@mCȒ#ʂ -=4e24m4%Xچf|9cr)O߈11AWIhQ Zġu+ >?]W|0[^ˊy7Hcv\ 6]Nx_ZVVf[aPW6g4# I|9iLAzTBCMMa||m]g=T{/ܚi#{&n ɵlԦso+/Yk~O|⏉y[>٘ |89`] ]q(-qoz_\9v"Nlg-d4lRY@h[* -s5~oZzstz6dwوͣ֏ZfM͞w<巪]5O:Ƞ4b,0l]*bkj"21]M|v܅T sy}SєYZHi ZZAyeyR!fLgx~*;*MԍW=Rɣm:re61}[&j~U_._xsg/EݼxW@LE&!EKOK|OH7 .{-G-Ĺ=2҂pɨ7U(NRC`M>c5gp-жE^h.kbt.BiebJ xMvE#v}vWǛԗV$ߜ~f#^veL/kU~a)ob\3 -BkuUyc<Z=eVORϊ稨q� c8'fPEך5:GmіI7_NI>=r~7S߫m4|yW~Ӱ7X$'cF+SxSP}7N7jddb=aOWKsiQ$zm뤑o!<g hr!ƹ>hÑC6ٜ+۸3O1Kw45Zݼ~ڈȜ2 -HɇCñߠs_6n-] QoAܗw>xu#C -k7"=m-Q9F*Q ZbQYz4l%o.8ߌx\-Rҷ -l 1zGl*b1Ehz1Zg5m"保zm?b WZ2*)I=o)M;e<geٶLuŠ2]yA U\Abz]0d5tL]c*{#9XvZpvW+ټ&֢y,иgWoqyq27|&0f6%h-p >壶^Ϛw=zH׻J/xmл lΨ76R2>).^c zF/udfɕm#m? ()h:=k䊚Kߖ5.MФ/}?|[)T pXR6q~4Yɫ妟}R\w/o< pnе<~Rݴ?=n.I-Yi6Mq){znX/ -}ߗ3 /x#5&~RwzME7ӥNT7!J~X$kL&a {囑eYyaYa-c>#Mm'$=mъ>ϸ)6u-ZA6GwOx/ӬE?9ypY??œ=Kz-pTZ!+mv]} }yb,u&cfZfn -EES9~ ҭfYuUyiiQqnT*:wRq%蟎m&2n1y&Zm=~};R<~A/6 om^!h -G+>d?-u8dpo�m=m7mH{D寓;<1c^r&OPВthSٰgk.M&겖52IX.U.9cѮ5.Lش/Cq[g83LܽZn'gq\wy5خU&_6L/nz6~֭htf $ڥv=1i>1_m^UKpwhLh>}oiz-]TP!'^0˯;K=goW 7NjԻJ5o*u9ZkjhZ;lFp-~K~N>~y?muNG0r44lӀ&7׮3~0b>m*}&v"g<q2KSimݎz^ LTf [(03qkkE/S=6~.&*/$fRfҗudVY 0+)vW[ |Ђ*(Ig|FydM־lvKoe[(4y -8C2F.㴚zyѝEgM&Lkyk(3u&^@SP] i߀Դ=D"qsm§h~ #A+]O-bn-d}n/d4YfUɸ͜Cd N$lCe~Ԕ32k&}`͚}_Gr?x[\ώvn.Q\8uHGaB2N\qySM,G""= mm_@RK=g'Xv8}T:8+~PoN :3)c8W+M[۶Vq}մ]u'>b0a s߀$W\lޭjkwdpWuf>H^7ԫ Fy}b3~?R1<2cz:hӒYhdž H{eO MӃ!_i3(|miߋo{}k3YZJix_Ra\1D8ʞ]ԛ~)9Gh2;OeA߼gn ͛s 'L -y"GVmLJ㵎g9;Vt(ݻzGTFYSv!-uC<&-I ش^i34M.#Lr h1s tͮK}i*!ؤk -2>}a e< ].Xl$Q&˭e1 mD[ZpSoڂT%K L +1jwux uok XQS3F:&2d$;(85NK_mDdHG]/[tS1B[w ]-#$4Dnhq~{< ˋ {2]n3U_rTx)f -ygQGuQdjlD᱀QKOzr]L]:rON*|o5I[gr뇦镯j񥫌/](c"شo2ӢwbuiKD6y}i\Z؉"ɢM{nB/BV"^6ғZTӕtNND|VjfLv.~o90 9`pMFd̂u(ҧItK^}|f}T^ZO[ |!:7C^T$o`˚輗uֹ<㍍ZFѽ v@z sLsyaF -K!"sM -5[0euj1f $ zV^N+UWmg/ *0[>8Le=3f^p<w\|hɻ%Fle̅K̃0ugV!xk!:r*pLl{sq؛6u=Dg'NP3BsMD1oZ9ge'ܼbc JvH'{x -/c@wKvm(g˪6UXJoȩ+DS׫Y}׍9e"=@Xjї>iuW23iېO<ez뫖;Mslߘ#6S0Yt{$̋>Hܛc} -훷qOyߜ - 8LXDk2_MhVl3"zBh>mIB]jԠ5~q5Y=2>4$u>_]\Jn K<{̹}T^Pp6O"HCb E+{TwЬmGfm}8<>LiZ:z X$8`7TxnsCr;v?n&~li1q +cgGHϜ@<Y,>r'J_n0l2:M)xe&p0n3sKt sŎ!JLF+ˢGn?-=\Ӂ{8sȚ L4:*&b .QD4 p˜nltxM-mA[U5]Pgg)8qNUh@Pqmg3$D -CUR"JT -(det�eVm[v;;~?[}TRtK嬜kZ{kW[L2]5<g_bW +]xWwkolX!)P?oE,욳+_|5<?H~鿦_77Gxp|޴zlwgV6qWx~xW`lo)q5qwSU 6ozKy+NeEkZvZ?A#5׶i{+#>#keügWE:߿h#:Mz?<jSmoō4<-KřoOQ~7xR{MD}kk<?'!owӋW{72Ƴ][Lyٽ`׹fEM56eԕ&UMmiɦULofMnZmSM,}c=wk`o-o|0Ï{RW}@no*W l8<:|EȉzSOՅ^&1O;a=[/hc6;?j7lgcOp}ƻք|qP͜C[άcɩ.aզIi7Wtό# kC|zja.~!Gޗǯ{\_U{.j>S}[l ܵ~ 6["fq߲i} -߆r?񧛼/uxJG#_Fm}j/❷al6H?z E=ͽ}6: 9ɮ̟t gZ&ܑϏ<GϾߺn% u?1u? gs}/uZ=hMkkU^=+]>oq$;$O$4gbO:8iPSof1d 3L7\2Mx+eigrGb=q-[9׺xxmsf0(YC};F{zA^Ϗ4wмhX88cX= ~"r=!7o#mxJ/nS܆\|_VZS}&^?/S᷾xߪO}qK`с;.n}Z]~/K.q?n;=_[B\YyLhzc 8r/=`c͓,G?4LerIz3%N|Ђg[~Rߎ7a)'|spŮwm\U-6*c ,BS.-\{a,eo9ۼ4GUO{ȷqM?ZW18hyV.{1t?i'2{ߧx}cp W#;9֐{{OӂxOo?&~~ta</ſ>={jm"yaCx؅Ǒ#ksZN޵< xF_ U6-D~TSՌ)xvp+2 wɻOw7Nf&�9›\cu^qreip> 4'z ӷ?ȧM?SŸg׆G/?}g5޿~/}ٿU]\s #N3i ?O -t8pgëWy?|.lѩ`B~7rSW3<ݧt6zk)\%a͡?q#/N3מg~ɿU _f?I~w%_HW<?Q%]Ar}93|w5 a8@ǶQx{Cy<+]ư'?g׻fBg! -e$u>uG@h읰B=;6n|;{ >|Ot>D0 &G/}/k 'P`ÓWBFCÛZ:lVmt`|ܱTϼey2۷׿|ͬiMLUC&olЪ.CqV�[׍t7:mF43D A.�˟hK:ИЦcR6xr S?M<7/MxY> -G~yk~>_lŻrUy�g班A<>=~rMkN1p4|tb杫Ϩq]zp͜1қ1S q*rO5m 1NjrE9[GW~_? ySɻmҿ_ow=aD67;[/XgW礆 mH;tu 6BE.4/:s& ypE.!Zdݗ� `Y6pP;kְ -9GW"pXΨG!!r}x~~,TwL|6=gxnO=)6"2>p<<:2xvt?>(д4!.pVMC Ðv70>�lw fy6VklY5!oΝC_D~.&sZ >YMh`yo|yi<(\K?ቫoyzo nc9xN`E3'?o㎆>g!w-`zv\ZsB&#(;N/NKgaʷ#TybnirLSm¡SZyk dC ?e}̓}sچ:k{> =?YՏ^{O3B{~` [wOx޹١U5&z`6/>uZ")#; d+ˆOA^LWIP?gސPdlKv_ <. -?e&:0u(Wu#_ /0S+P7\vF$lu_÷ V6CPዑ37>#gw&/EG[֎4VFpv ü 佣T%z߶>!}ܿ~Z`yYyd4ÛY>1LWJVm=˿py `K#IasLJ~05'5}O |\?̱3Ç=wg.S59'{v"ыѶ铧| -֌ޱbpjToX0tzu|JjeLS*sΠh߂m}* O<r2΍ܽ}�ϼzV؄O H< -< -n}g&?o-?G0cΤ1x^3gLAߡo*=;~f6cj,p0룃x7br F.o#:`ahPSa_PI-?7e"?X_{߻yK?ZPbő�@}/]\ݿrEwmIa8k2;8G6`>sU vx`޲^4+7@8a̰D'8a ܽ3{X}sKhngU} Xͣ\\ȣ o_qRfslᵁߓB{89tCֆh'\Wn֋^ߛ~%ɦdd>quX>Ԇ3ō<ط>)A/֏~uHEV*nla&Ąfyy|ȯ |lao:a</"> -<3G>]}&\]+  |}/jJ-:|m2Ρ}ȓX5 ND^`Sjh/_\K@7 Q5 >n"rq#߰/~Pr1>1ˊ _ n?4{޶_9IM0mh\n?@Ї^?೟uF" L`o lls=W=nFg'3_^iT`њq6"'.!3|u>p|^`fa_í9|dnϧS-pIGBs\?`fϡOoDP0 >{f7|'SJ}ksly"r{?0[^ ]pպWƅyFk?\ho_}<ʗ -8FfgםM> p׫s!b}y!f ]mypխn*_XU['wNu%. n l{G,} +]s&0΂ -va^CMYN{]bgEHlENGn#j҇/E>X s[gXx֞#'SoaXw=~m| -,06c8Ԯ9w`ˑq? A陋{zmYU>9='>=,7|_L>4G"m+!ۊ_H~䦯[}*}-p ʧx -qk`+ g#xZy){azA}A~Vm2'}\$~ -\c_ΈlxÊ<!a;Fb98z^ ? #!g'2\^=_|6<Խ~S쭷׽gYt,0 ܳR8dLriҫACoյ<ߔufݹ``a$ üdWL r"/7"ui#"_o';YsW w'<7ҫϬKSv΂S,3XN{_B~n`@,X{6p3SәXaƭkdaݞZv&0UJ#N{{i!3M18M\�\ {0<lǿz˚'>wqJhEk6Z"`gyvVDy?*"5l%;k -`6e#MY^C!3dOΊ<о'399^h!<Dp߃=^r)ؼlX04drhS{kF`wqofay7?}]pǛbxGSW7xiʹ汼myy/ԺW~'?l~~7'/v.W޶c/6>Cdc];Y5`s2b14id=Sjݘ=5BrQ}~ ;k VκYdߵK3n1{ -vV fD-3'{L`@=a)XPZԓlyt.ǣudמM1L^?S; -Z_CzkXȽGƆvD.GUɏa##_B6SjPBv03\hAZGc-w 1y�vT$dS`pM53Yppw^֡H -vbJUwYx[bʧzqp۵xE CqQ[Rү[B5X5֟J(OYrr\Ր@dus=tuo>,7H;S?Um׼OBq04`hF~C{= wl\͚3w pV=3:wNع/l?_] HN0ֶg1,kΉ,Һ[e6{_%`�zT5VFyv#šX=4kJ-/M>^׼xX]cX8~Zifv\YȥПaX6a7 5B>k#;pxkfۚݗh*`?Ou, -ؤ '$oaؿ^o,o,=a9њH;kGB?{)*vp ϡśF YKoZ)cgՓ{r֗/8T]m>6tnG.cxfw-�kG(4E<p>#ߺ<Ț}W"6샭箺?lX̵%Gg=3,/\SCZ<6+Ok'�~,}jw=3X~ b^3!Su(>x;l 6 Y A`KFήfVMUjMSw~Ǯ�:rmugcw`=79q�>ٿNn�y`gY```gyAY$O ;k:={]}E<!1Īh 5hL hvІCWjlf~pSnkx0"wS`# ->{k HXGvNJ. .>zRҝ[>6,!~upoj|ȝCb\K ;k.`g2s1\ĥͰ}ag?Y+e:=vVZΚ!q7@evؼ_إ $[王ʓjq8Toz:05.?yUxnY>%Owx#xfx}9ۛOr_ -SM>w{fxM9Cwm}D?P/0;m$/ n~ZU�{Tit v # ,_fWҺ>YO:|PVVǿ=uBd0PjVϰ)Fv{vm#VZxa+5?xǾ^CaWw\k ^O_u0B>M]oKg{a8|}f+<rcd.iOfvް`yXrHvIn $_VƗ ;듛BiF׳qh]qii z+OW~-{\{v[.'b݆veu8+9}{́_e| 7ff܋# <ͯ}Ȳ-BQ~Nbs#[b\t "٭su_shÁш_Ỽ< =`[<44__yԌ9NkYw&ۺ[.� trt&˃XܻOf֝[>=gP [ -X=55=Op> 2~-#>6-zlXwf!2se*ZCan{C� %`k !_x70`vj =+lEU\6&eУ<o"^9ɌCAҟ Ħ zCmBLcO=q)pGޓU~ύ;5O]\v=1,``?>uO_`gBs'Jk~ݲ]2[>0[`~S m~Eh́+c";ް~pmsɮ=~pdlpNFcT^<;|�)5kݢG.7 uӈ<v8-G)1|'򱘯ׇv{S_MT]5 F=ȝ ȼu 6 -meÁ0,[G=$:0o <k0.^t%ZR`n<y%1aL+@^^:<t3`1 C<ah\}`/]x  9x%0~H[|?ʇ/f5{eۯ /h&Zq3 6ZGpl`oo<EOS}dǞF#u/}P8`Cj6dBa,~찖UgvV`Oݳ8={!?pJ S8y|yPZ -`1yaGV=1Ze zSl dSf=MGơ 䞞[6N l&_G7{3{ߟ3vG{Mv,?+ko^xf~Ch3tQdKi,[y_|]?^|wdS3 { {OنnoZtcر/Aino I -?8V806a=;0G)s _{QP`m4>밗5:X:[w(#^5 zIY6% m<&bkFV?38u+q&gm{gc&q}C?5Y12X<,0'34`p'fսy8Ձ]Ld=C`ӯ{~scY5 d1u p: ዁xMW]E\=I=w-<lpsrխcf1!]?{|}<up`W0LZW[gXaA7ُly�'j7/9 ٳ_ - @ o XbzFs%[·͊zK=\�[wϯ+SYl:?~/XLSmAD\TA71dmɦ Bm$1/|<G}ώ*bÙg2L,Za#muk\Z?j_dۿ3~"a`٧؁yl_�?ő xy[_al_hQ>b g{]2߃Jr _{죉yȖ�^|Yy#7pbgX_7Ξ`g6<76Z >ѳ7NΟ,1x,^2#yNu:zN/* ,B ՆDy1!Mo;>:x \ZV?n~ǁYn{. 9dmynw~%ywQ%Àh^3$<ueZC[x* KI>d|3{~Tuш@ۺ3 6ZytԞK>LߠrgԚf&Mﰓo S14,re8J-zu;ięȚCqv -@8;CÎdegQb<^I8 Of>]cXMLc83!;s<5YtùV,iV2H>п'R~Ā -a`|sXl"೅l&ޣ/${gi}j`12o? uی:vxW+pA_F B_-s[6dadrѾ޸ηq;Fc}ùG3al5Nxgqf73|?wyx?:0G`ם1>c|1>c|1>c|1>c|1>c|q3%89u1 De㙑ga|E&;9&ҩh<3''VE;[0<<b:gk8fEx4i+WlՙDs"EDw,+N?#[rvhv8\󜹅ѝ6:z]v\p;#GO>{py8s.߉GNhRmnM4KI80+$RDbQS/VMH2׾`tc}D㰰%-LbN{6XLv'67lS<~z*d;Zk3<ޛJĈꦚSwΏ&ە[TE ;Q|:C.͍'fzYtnA1;)UsDzFjtG&-l[+W}Pl6pE5H7t}qo5۞ӞbY".vܵGIRiw60+ukc{x W,x[{=WY:/ee.EwrN->5&n VBbE?~{T=}pdL,>-mD爐v꺔ngtJLzBLْqj n&D72|S75|ᛊoe&JVyrV:fxwlzoiѠsj8szR:dNNN$"zZA0ʓB'6b̋Q//ʙhcKKUtun:n.z2twЍ 80tclFC7[&nփx8mfa-eJWLL5- T1M/a9WĠ5HX4I⻘+W]DfLMw"`.k WNMT{)y;hvr{ ƍH_u4oI45Y$%컮%Lh,޳1tehG+? fJET0/gV|OKQ6}fJLSBKO}h*R8(6EEuntmRI4O8P(CD*娃TY !w˴h{[["c -)mDwԘju{Ju�v d7%ҫVʤr&l^ 3l߇Nv&ϖ=QO=185^M/~捗X#+y=\ޭ~X44~KbnP4FPCP!h;Yg>oXB4F |#o@qgwG#o v1^BғrSd2%hnRT˕pB,pJҤ4ov_3MXN#re:E.Zӥ` `[p](/A3xj"Tc9=q~"g'fәhhl7ۍvwԷgn9{'|$]q+gY|-$ -vQURg{wS(r \m)Z;ea+]nd_uw@=Czl2'ͮUp7vN6 (e[mH;QNeD;QNY'*E -0׌c V;1g'@s~gvd"[M^zF!KQ&gJ>l)ygc*gl=xzE`e:N5YyccACb8 gS$N/ Nԥ;p1ХB4eѹRg}յ4┦x67ҥE c0tn\#1˄4rcݑnjjg14xciQr$rW dc >Dc:%5auؿu`S2nO#OM4ˤtk4vLYKY;JzKH#K]Y S!<JokR#Y>qʁ(ę  iQo 5Rv)Hޡ0R"Uei9(?7\W"1WyȌ\̉8^= #3Waa#|MHQ#&iԐFfHyMrl$v(H`,FbXq;"-ymU6\'�+A:)giiDchrV:Q+/Vfnny$;zم=d)7y̜d<US_ۅjKF}V|xN->5I;ŪXߋDK+>OK9-+:Lm=+*gi)+MNj2YZf [j'˴'<%P_N=DIO7-/ߌxgH8rƀg0`�?ql&]9jG.7YKxɰ y)Ȝ-rgsJrŇS|%nce4=-g-4p0'$N3$_J"wIϐ4ÓښJ@釳W6U9rDϱ^o_ -5}NXɤSd zʐ"s@:'Q iT3=N278L1^?9iNzzQ2^,^ hBd)ZYx8̥tpK6p\2'OF% ;),y|nLlp^Fd?2+Ytӄ4 ZpЄzxEW> F)o6l>;F ׭JZ(+Wx#UY*T΍R;Jr1+!E"}̭׽ZX]J84W^xR^|x8Ϭ, -endstream endobj 101 0 obj <</Length 65536>>stream -x-kmh,OegF[ymKWڋ )7՞KhZ4 C>>e>@RT2@QMo|4}�o4gYl66&%5}5z6]%x-]LΠD_u)/*^.=eﺖJJpX{K{g6򦜮L_u2\_/Li \MtK ^eTm,֏4X-Kic C,Ssͥ}$ESR4ǫ!';'JZ[ɥɥRShRl\*kO>Wqvpo٥٥Rֽ9Txb^f]2.yU.$:ĝtgJ]Rr(٥>T�8!r<U�tr{ O)g9s\s | 3$k)]2R} -R:W^)\th6P  -@h:G7) ~3Jrfivĭ9)&[c YcgF~$JlړLe:ՖJP]KY|Gm2Nl͕&aS[-1K&,#0eJQR],̯rY I=^tsgģyimVpR:U5N-*SЩI'R٪?~q++lV7֮vxnh}5R3D=_eGw0h&ϖ !0yǕϒ]>C0V=U捕Xj3y=ܚ\./'Q6L%&' < :l1画Y+~3d2gf⍥irt1N9aZ >K_v#ex]Z8w~.N06o.N꽛sV{7eTػ)?ػ)IWB2ٻ1r{7'@.cػ8{7iұhsI`oȇ`L64SW<'ifL"Lsԝ% �8|d6 B,}7d<A)X[X2qR4lb~ JD CVy#oL]T<Z|@'MfKҕ.&RDP$hvr)@"}L%ӌ7%YɾR%X=Y -vy^d4 oeL @9MtK ~Tm,֑%5X_^6G wQTq6kI8) - ɐr.~3< @>^J猃é5&khQ>'QD'[X(oOcwz̦;O %`t84<ԁbKzpP5TA5⠎5G 5Jj"iQ͉g2IcD7f9f,ߊV\rf_Wѷ;,gu6s#v2r}X77Şê?pHUSy!x.CpjӌIfrJ`uffN'wYp)ijI"5%&5Hfgyt:i&jHԔTtN2>=ѨuZؚd=ipXf8#`x493J7Ur'2H" LqFC4m {gNXQ.q_/T(+07&bhC[5-,W\Dm6=č e̒NCt&UH*/z%hvZ%!-.&IC%T:lrD9 -h s(6kQiZm]MZTB%~W"*IeZogUQxZpVpI:pҤ -SMgsmjg(k-u \]F#F79A#ZÚ#(\5}QFBgn$4hU$/pɥրeJRVU ׳<j&4Mah47g8Ma-<s {# N* iNI$/IbqA!hԱ!8\v/!'J!Z%&8NNmsNy"vjj{Ҥc7Uv5*<[<~V:[3$> [eI>M9OS:"6xCtW ;FY$Z^ !2%u-sQvݚy -HzEe2w]4BשĮjbꢽzTih4MivQJ7J)CUuY9X|isX]/vrL rZ@XR�`˩icIߵvQcT%|Y%M$ .&b좝w8sf9A9El/wq)N ^/j%E2x$`w& :% -OSw|%t8̜Ƒ9!^$Ɠ5LS<[%8Y]D{9aněD6ݣ'.xqMrqCQ !삋t4xf$ @,IP!;R;DDŅ3qN�$J(NZE# Y9-zpv-H3(n9^ގFsr[4"[%MV;)/ݎ/n9ɇsxb DZI<)\FDўdeEɆ'V(ZD B8R�z^X8J|J*-ꔫG%,}ޮ8h.nX:\ר̱:%^'1.rnh4u`dbe8; - -v <|bkrٜxU%&G MI@+%2%IN6 ljhvSHe13KΎ[F|"q`@Mh  ˄1Q T - $s4Row`f@XK HMmF/WQN(u43Nn&p#n'}0}X`$ޞEsQN2J۠ePDq.pHLm;̼ -K%IK4drnoD^qeu"I2'4%ќ 0 j&QSǴ[nPPڌg RɍNC^i5=_z +v6tFVD~#s8V#j=7wu^h;[{Hzdy֓'Y-@#Q(Yi(hܺj@2[{4^J.^R|jrs`vjqq<=n"FD[ٜt1YsEdK(Hp:G-ZX!Hl1]IVtgQ<-U0 zW診*(HԱ#׬ļ#浩�§y=G,,H]v -ȟ w>c&۲;1[96^]6^Ƴ1G/<)*RX2ǎBHzϏVAMkD@Ew )'`w ;$ʮ`Jԋ6YHGs`_0ĝJԋƄ_M;Rfπטdxc҆?=D*{ < ʣͫAVef,K%2y%^)_Àc7jIMF{$"`ڵfGkf&+}m| KjمR|5 tz{Oᘮ[<ĮM,BT'mBLG :H%}̚75O݅߄^C'yעD2O`\@ڵP%?s$ou/$^+]~ԣv,"?6@E&z^5;)yG9Ek -8:S\?:J�%r*9.&QyU֥|TR9Q  -5) -<ʥ;(_7.]-@:Qc V|Q!eN*1`hKkzr4ӉV-t!xrIȡ$(>yr\v !K1o9'"YntRQU3ʁFI9ψuٍ_*V$I.G uMM Y4ɮ敇V0h]b.Ym[$[yJI+)-!ci$p=W:Spӣb1g dofKl'_3)Zt,QቨQQ'zH/7h<af 9KO+(0C;`C{lݭKޝMH*Yi;Wa$#tWzlS{.M z,cەە#=D`=UNJCU9U9Uݗc'6P?8vQ-1`=JlJ/ԿTfs),4K:sz)Pd3=2SN-0G{p9CqUXwbv*ѵ3^MJybw3pWd\6ެ XXrbSPWjla9>RAq7q -v]6,{؊ l⺛M\wpWrW^ ϱ<&yg+;Dq xΟKNKێ+gkfySQ 3oCk**BWY}]9̺9ꞵC=7եn=b 6Y5Øp҂XQ~6H+ēɴ9jM<鵝fR:! -I{(šM}exyauhIh&DH8-xX8c'䣅2 'K就vr)<] t -NBT'IJx;B1+zeX&=J(6UZU+-.V|J#8Rh* 'au+1fL\Ԋu*|,Ȇ/4]Nq%{WڢPrv(Us3*g}0jiYK> c%Oٜ6lyNsV!=IlI-@jW !ęvtq91$Cb󈹲DrcVU׈8*y+pG4j$6!A8FԣN;9{HrũcEwy92 D - k8vlV8(5\]i/*T)*ImRN]4v T=M+Eة>NR{JPڥVڭԞGR9NIzծ=v^y`.<\if2TgƄ97GBY(_wYy; )y.$x9;O,*I+T哹Vyv\RR^.Pkʒ(-S5zt25Xu`Wr.\ڱ %٢+ebZSc?rZKIP/+©vRaҊ`_*Ĝ3ӊStKgClA1w25 lā}zJh(0%c{N!$YO0υ0A1bEٌǣyŴghf)*3FF&r6uI�}X6(#+k -*GqT<B\I^H?5qpCd;YmN=S/E6XR --av�vDS)8 5ɶh*hoLqslHK, CQ;؅qɎu!]@9=Rȿe=r@~Poe;ԥ$=P`]uˤS sҝ@WDVɚr_,-Nc?$rWS)wDMWĩ0yOBrSh?KtȐ5]b݉ wFpEHZPKeE6:)$ r -+ԪJRT$muM'Fۣ:;jYAVynw== L;Q#<?h# Hfw^4P~d+'}wiGUOlT]UC:V>%B +m];zky`91 pPﶽ(o,D,,6P`;)Ljd\Uhޜʕ-DӕmRl1lX^2Iע&9 -rvZ(փbᵃh$w8$h9'v Cx;X+np%Ul'9V ;)rG"z mN`a�El4-D:"?En*['6WY,6IUvIt8qY|߈FD"$'B$9T1hVs;NN4qQ}bD|hA+\S-r1RtbN#(%ٵiz[?36Dj^!ɉ6.LVnЎXЩd|vTImMW@$49>44d %`^QaNm`QnIQS7D3ų6a 9 oxM?sb~ G> dA+0vS^x[eھhQ6tsj\Xylg][LKx7еRYP=SRxb]wv0@43jWk :k::PWC\MWMGhrrN[34xCK6?'ԄCi! 4!;24LgSN۽%)U1\ўMeXвdVigmljW%/.I_rh5=&%#z%$ˤVCI:!('q+Rj*Bf$b/4v`Fa:mqgH3_TB1G<'<{yQWڠTy+GVKVO_RZ+T -h!SZu֊B<Sd <$pdž+҉(W]/OJřzpV+We%Et)Zs\ʸ*kæB?js#uJ+Rx){ъ8%K=Q,cht DG>3V;;˜Lpñ\YEVWR8jUkZgV='.iesV4NvIL^yrNu);)EsG?N`s)/sD3DѫTqDkE&Rۛn4uU9MԙkUHgjɧUv]N$!e[I\؋yy:byDt5Wʍ\+tԚc'\ZbnL$%ubƺiZzljR<< -Vc!5Ki =Ae`㟞.j5<cL󴾨\o*pIft ꘧:uZIr3y+/8<ޑ=;˨dukլ'rCfuc\Ze])k5'ԳNOc/O^dg;<_ЫK4%ԪTh9iVI6S</ZAJͺky]TffNG"ԩX̼rYɲpLFZo14+}x|[ɑg-r6+U8CYUTTIzK1WNeVs_YK -T3G<uQ4&(yAgjiTNY%虧t.UkLPgL=Ԯh45:s-gJӺMTJ= -sOմ1լ\ytˑjPF=ԎhU:7iZnj)tn)uɥgjiUMZ%虧t>Uk\P7kvM[3i@9BnvSJj,Pm'4K:SiVtrXUhױNmsjOTc$Ww3;T9 R{M:iTLUqL##~V<$Jk[o鸥~9Bj'鸥XS:fJR 2RZ,cĺ֪v[yWjtrT=#i]V*]̕|N+vK5yE:^֓YR,0VZ,c$+VJtR{R;֚Vՙ/U=_>o9apԼ\nM 7w:W"u'w]4_f|) Cc#}15㔠y|n1Wg4;wqLMG.%Ӊ\JEFz*SƔm5.T@ �u"@Dm D.!:%ĨQY_0Pԉ\J -1roE`Q>Yנ#*lTGgxxR'r)%)1rJh׸R'r %ֻ%FUtBa|j'=1PP@� ^ -p屮.ʧ‹ ]#T,v/bT(5JO-:N.uTڋXUDžXX8% zi|j,tk@ ^ -&IXW>h+b^DX.1|jQ/֥.q/F-=Uk=,]Cb:j)A1ۖY%tƴn{*Z|p,g_vt5WJ�׎3ؙΜqg:9ǽ|*Vk<UMg?3aބts>{n+N78^EtVq>{YʝtEorV^tr{әy].g1*,cn/z98 <"ڋ_W>e1?i/B9K7soK{ -ʥ <"J3zxڋHaδi/9k7vQzme޽ǯ,JF3m=5uG0ARr, gvsP |EE cW!h.@.a_M, +ҬVvUVڧ\1DvWR=i(RER}+(苋UӢ~UߝHyM Y>~6vW l9~ߕ¬,u9ɵDɛYayj]{/UڣJ?6V\溊6LTu,.!y�IA9 &@JB؀=PM.Uɗ#ђ?HӍnu"EuUѤJ'ѝFY?UJHSm"InSy;}"x|G̷hS_Rr͒i^u(bPi -Ȣc iHRW>/T -=#FXbeOL,!^-UWB6~+sR؍Va*w4D -sRU�O|&YyP N, -,-a -$VNͺ}l25'YpxUof -q6dKR=SAxsf -Z)'wW/.i�ZCe.%9ڲũ+"Be l"iK`V+,J5bjoN9RW 3>GCj+]lVs+sLrv bG1Z[i׶*[D[@ռʢTt%Y*W*ɜZxjRP;֦]K( -=m2G1yn#DeYa2Vv^38]XYT_i4D!٦=GZfk{SN9)wKjQ b8FOEM�*$c~nRҹW"Y><<6Ēa.cZjsrlۘ #M�1s -FbDX>Z6]AV3N&6"ct٠ f[@֡d( ~ǒ pLJmIRrS{8'BBÌDνA -}% ,(Yy)p~)`}~oI`ZID~T/!dʡ;xc丠1,c^e12Yȑˁ,ӪewDL7iV C@Em ) #A9DN88dpf'B,b!i@7d%&,qbkf8 -fsVU@-~ye:+OE)&td|'˅]2MBb3B$CgbRS'.%S萼+|qy۔ 9] ĶJv$GJ*V@؉^ȃ|訳D(J\c+<cFɠp@\`A]qged6I\tr&DR$['`^rܱ[9i YUn:$%C:]l*Of ^ 2a\ R9$`yѩ%YD`?!ւ4;tו0}To c- Cf@-yN1`HO`>&@٩uslN٩"%�1945NcMUl?+ H[4sᩒ,�o$I0+V-#'7L{A" -Ċ+I]8ObZ4y޲*3ZYE$qY` }(8^Ef͉* <˹AÐ(̹ddb,D *rx |. 6vc(rȾ@s(@('4IP\nd^e`7ШqH~X" ߾%7 Q>bp>CJ{F?sg-E5!6i2eۿ<q@$jjp0Ex)E@Jʑ0qp"NOZVQipRJD"Ujҍ-ܤ4yd4vSWZt~sc,vˢﺲs=WcF?t%"N)(D]e~V+uE`[RruXǁ׹sɛ'kKPۭ|9&Z9u**Gɥ% $ڝ-9W%;Ch=A?<QԊ>K6-y"`/;;_W*C;jpPTIm)LjȾ\*;d9K[|y+֤\j=01i kPnSGzYT -YzŢٲeY7[MsG<3Oʴ5ό:όGke4L4gs1V x`n͚Tcz|[Ǚ-C_VȻ׎[:ZΞKx]똫'N+[IbTl1Ѐej\hD=5ƓɸZQEw*vhz5lU<莃tiƹS@BFpۄX &eHqVMUbφJ7)5LMF rWk԰۽B;NF< 0A8x?RYmY9ڑ3~8MPvQQ-'{(K -BD,b+'ݨt^n%_.j;z{xӉy϶g3)M ǹ磻Qs!KeCo%F:HF?#^bW'V$;ڢ "<Lq8nO5NM$S*F)|L{x_-A @%Tɤh["WC&=/^J<)YQVElHgk4�WF@?9dh9<VW&dD3قԞWF3Fm)F9cqc՚+m0gG~`v'!B -iN3 u֦8WBډM1vl:i .ʼnm SxgMǕ[kCy 02w?9qnd6SIwӽى-GzJ4e8wv LPm(HYɍݰ t/߇1no5kӼ:ʍ ~7Q`e'3{MZ-M{m'<*jP/z|JSݩVK;n݆rm wp*7]0;ǵxG0[z빡l+42ɮ6Kzċs؟- yQ),gv6KW*ub$3<_6AV' `x(tʇB -%Ҭ@[En1"Ah]*4>3y 6Vs+;u3FMnP9bʕa?,z:ա͋r1tXvF~rCY|U'Nq Q ~"Ip2+ϾN+OiKVB#JW� oB$(  6B?VBB?V -VB?V -X -C7LVo AxBg~Џۭc~ЏBV{u ܋2[r=Yxs4\*:GiX7ykYզ/8ΔowUF'UU~7nץע-f_X..K0߭I_ 4ԛ铿_ Px~qFV$)q P?ϏZ?Vj?$pe~9}}?㱉GB?gW{ -j CtĆm= E/Q] RH}^cmXX>'<, g 0xb0E=J08A@Ͽ,<GPG OP=ƊC+ctAQzrA^Ki@.z5;KMU>rP1?_EЫ,Z2>W/6O ;W~󴸄>য BvO# N\nF{SM.W D] -$ɓ$ų,* "ˑ/dI Frybϰe}jUvjJ+S?l2�}<6?V۾`%p-T)(uGEY~_9hZ݆-4˛`Sqk �Ģ&,hoG+ ǥ[dZR)M#XZihsCYVמ^;a/oUZ5*\#|YֱAKu7늤GPG IzױHO7\Ҕf#V[]ٴZYv[[o|֏t%+*.fiz3s #|4iic|^OI5�xPq:yZ#=pO4F;2Iz ӟ6j s.H%[;!9/ZO9C}]?`5[u$U$}[89oJ JsG"(aRiy|Ea'Ha/89u -s  -+-<T)0"R`R'Yb |ayG92^4Ntq3$?]J?#`kߧ>*YϷ}IGb(Ff/6U�<YF,ͱEY}Vb1(L?fb+r"Ѡ ?GDs-,GVK4QKx#ER'#O Q)%I0ϡ남S( ).KM-Pم@ۜ噜oZw+pgADm50<C@! -y,,}o|fae?%'fѾ.C*@ mI"#IR^.ɔPag#HFK}($]`#)XGĂӟsyGt`U(tPGXV6(V:Ѻk!q$ڧhrۈ4O<8Y`4N٥HJk~rc7يݿ-ߟ( d~?)Bς$UetPHo:Yv~;V>H;hΣ4%^ M/muo:T9�4鏟^?IW}vv g7YXN|I 1u[%]zPeX)cX,q,am ߽dFy`Xn!;;SnRw+ ;s*sAP,?D"QR(]1vE4堒:HௐhF,EarO(LWBmp ϒ44WcABMR@$%2E^,DRf&HCK "MSЊ@,OxÆaE@4GDf?4Ψ $XBR\di `O1,P&2"ŋ,%3(y\I3N -xԒS`, If}BOI)ԉ2E3@C"OYA8 $QD,R;[ Fr!d@U3�i$t2)8=X-*Ch8gGF0iT$,4$@cw ESe{Ҋ\01 ?A2a6nI(aP)&k~9u]`E+3 d 㧬8_0NZDd8`9a)t!\2҆1Cc^Єd -2IhdY2E`YkaiJ0$V/E0>sE+Fd 1\ إKL&gI@`h\2jM4> 0q(꒩,<Դ,)Y_ yf&l;)eW AHfD:(QQfq<3~DX6 ,J4:`qsmDtAP<>A^�,m�o$@[`uaY�5L'΂  cTeAs`chKj,9HΉ?jȥDI2890l�+Zqe`d tWtCWxFA+pF!kgҽ՘ F7�\S,(2e=},mYLh0<(B@XIPgG85 Fn臙LHX!s#LGL,j A Ea � -6K:O/ljC =1� fCK b X@IU -N_@`C՞e `9aC!S,P*GL.? bـi'ZSl 0`gօH�: zDmCC[F$HFh)(F t&\@6I04 OB P.[\K3b}~PX櫔`Z # Ƃ 0: K"lEu  :kbųDu4V?{�+8H#DY -?肑p4~pgiur`_"A&D!>1Y8p�5`YcÇf\Ӳjٹ .tDJ�x,J -ւH�@[0 ≵iπQ@0V0KAQPP!�(H|099!amS ",[E%ϽK@a (�R"$#,D,| _C( cWFrg!eR0c:m(!:<M*S0'd هe.@݂;XfYpUf!q+Pf?+Ն G�>P~gaZ`ɕ0DG#WK<aSHXD %Dh #�$q=ED-0$:FXq(8^ k )&Es"ĴD'à(I^`Q,}h ŪD -X6TD3\i]"<c9hG-y1X W-"BAnaq553^z0D%SNk�>e-ni(DݪiIKtEYy|OKici,oєQpmC1Kndz1Kb?4MڮQv3jE(w&bTE uzàŢ:L@' H , m+8Vp{&T'p %:Dx#wl> _%viߔ#"#% (W�Yp�$ðq�6G c/EM!xv`9�ep[p'!W hDOY8<q1>[w(PBG,!q}؟B CH-+ӎQ%4}!C )NB$c- +BDY@N`sZsA"K/Tq0@,gPNb]@)Dc,r<-";'"?2Ҙ_F a9^O2CT- -bQf!5� 2$^P,?rz>z[`/sDuo\8?23N_"CEskqS:-i6ՓH9h(}EF'Qlh ha*s\dJ8->b,D)?9MمˢG!3RZdo:2[: 71\>cQQ"w v=ˮڃ!aՁO^@n2%qQޅE#B -wtO| >⽆#M\@q` z à| x֣~=UcY:ga)NNR7qg[[6mY:u5? s4=p??N|r@$b jqI_cESF1Uܔ?i~/R Hq7PZ@q$U3>hvlTKjuf:#%)U|R U Ym5Ա㚊^>vŬ2qdT%F$K)R� TtuO/Otav6-ޗfAnD?pO_'2B秌1?4Bi]@Yޢʤ/%/瀊crG/FO2P~˯B皌t(XŸ�̣:Q5;TV.;MNT||8IKHj*Xn/ahxN Pudkohmmg7liVӰ%-3[B+N',+ߏ-il)-`{ -PjlǿitԎr<]~\__wB%g>N,B-nl\Ypi Tˈ pP�EƢ-{i6:Ns (^<E<[h/KؙtXf0Iח1YTi|bʵq#:>`n(NbƵm$ ^D]t}cEĺv}U']_Ƶ>+R q]Tkթ֗rbr [#2uMLML}c\;L(T{ΩΩ?yf X%X!dqOKڍeAt3͂l yAii -Lk7pu\E_6Lk7lu\M|s݀$kqY֗qNj'81G4une4U;}DS'V߷g{Xnηdp};LoW1 e%:envS'`_s("^;3Q/Y*TwZgZ_t aVw<P#:P¯<߄зInkU;~:k0ńk!ńjN!vc];i>biaJĽvT'_)&_߇\k'PudPtsP^ tMk/Qoʟf: Tg%g!w _yh+^L_ʶ Ym,}k7`{N X|,{Gv=DVgW_F=auus;"C`uhk1 ]w0 \,Ӯ/nk7=`a_ykp5#:2#e4>YnV?h,˘ы*NBvB8hbFɨc?ssq}S͗?䝉n�Dl։wB:!GuB}N:l։ٷcn#:72F l'XuV˸Jn,l'Lu,ˠ;jNvU`{ Nj>:Ͳb"DtvR7J:%K|1%cIŖ4Kc_9@΄=|N'g߇Ow}k'tufE6vee}DWge߇nSNO [Z}C3[LZ}|A$lTu&L;ÄA#! Z#!FkEA§5\%:1>p$$bv2%:;>x/3 Z%q|hUi)Pٙrhc}Cnl/aPɰ;|jAgӳ�^|oXnzq7ty {:]>.EvBvSu"7Ɏo i%:ۏBgu;!}@=-d=-.�5ZP Zj_7I1XiCя)nP{MRPf)84ϴU;l°mH[e.J`p]-+>j ES)+V+c'F!f%GlL2hH>f{M+ thZZ=%ƿnj"杔4`91՘<<&ZԑV6sVt/G2@pwV4J0vb)b˕&vLԆW&~y,5!Έ_c靭tT_ I> dtPԖh2ZҗD[SOuq2W[]m6RƋ6M3w1S&:4us ·&c"/yzC`d|V\XHlm(i*(94jTb$d&}c_Xf6t@OC RꌩX]hL?l\ÖIR/UЈ*R^4x -˪oAM 쎥zw-г&JIZu>J*/i9-jawe|`ݲTeѨ֙i$Ԁ&,UJJ4^LeUSPٗ479W+#T!4ZW:ϔn%P FGܧ!:sk("y+^22ÅO5ǁVPS[rxKGnؔ[ʰJ鮪}Ygw~2<On;jd%|bڇU'u0ie8*hEYN- -uHQ(Ӡ m^l4R!/6>uZ؞~1K}F1U~ınL kUg14>egMi踬撖5mcLưj_N$d? -or6Ə' -}N\kV989~͘F_W˟K#1w pZjȱa{ڮ\wa]mlR=Kc H,eoŮw 4iR?,ͤI8jj/+i t䙍]Sȃ%NKk[E%MY,e5g^fbt.54M r*n_^a-eQ`jyxGjmt$o6P>7.LE{�&SMm*YM2A"H*t;=^:c [ڜϦ+ޗ5zb͙d -x<MGT'#  4uu+!Y PԦ\/>IOF\@D.+c'Ls}Awctc5J J$Pb %̅lj201'BL[Dډ<RRyaO%C%V;7IuNv|PqK E,!;Ym�? C<3xԃx>4d h -Z2#ˌvʔkB@j2AQeַXJuGuigM{YFN�)R [ʁ)B$iVlZڌʭQg@{P+�k Ђ<aޯu.e*1Z<xt窥>@(`=gDA%iĔS46(2l6P]-ؚ >4-&CZ%QsY?7PB3(>dժm5 %FCMAźz`N*V[5PJ\qlU1u١Js(X!r2n֑7`Cm5D#́\]LQO\T�:ڸl.ظ`}ռPƉYt#~FM$ڙy٦y}?hɲg7BesHDBG:"+A -A('Z BƇ9R`i Zg&H` CEY^X+˲G-tJ@q$O{38EJ>~j}�U4 -cH Yuwz^,m(*W2[0uc YZ\m%VæLwijdfB( -OH2z`3{ ;2oZ0;k[?uzj M -ҨXJ,uK-<QtHjvֶ}xnbWT9 -~4ԍ.SG9 -!NZ@kZԍ`.2mm/@`>jlPڞޢeWplMMVMmR߸Du#̹j -4|c,iۼ-Xw6XJE-pj /\ -B:-%`} -p|t3lXH&T85m@(h <b:椇)`( -c -z!JMD5a8^21Ud,ղ;iazmM.KCCi!\;˱Ҭ)T&QvDΌ4~mBV9r2rXsju4[]iMPKB6qTk2VwFSwkfhy86vQ>?zx|qQVѪ:�Tg ?[V$z-QK]?duxiwֈh#aL OZYg"6?o_|ljfn >MiUu]Q{q/\omGښS|L�=}#Η[:mOfC2Tl0wgUsP,2#1f\<o$b F.]W4<(|hme#ʫ-n 'v p%;�XskDqŝ!])Lzq&r3ԇRE?Wnz|MSNStN_IH# v#7NR*YC!S^N}TXB{'2(v6Rp*I[x@=ĚJ]>�+ =BH" q4!m#=N$TCH~<ݯ_WPЀJHF{З@)I=P]F -HJtEkt'c%u|P-5b̚ n[43~;^ӹ6,e+뭽ޜQ-%09=MKAP<MiA=u @TMt FCČN̏̓a%L8ޝX5 lRFlD,_lw<.eœtƫ@\l as2J4TnK(M:ig0yMl^fsۡY-J@9~9Tџ/G.dQ9Aӻ~qFy7B3&\#mGcByNџ5qc~ËJ+ /PTՎџl2X hKw Y}G^?Ȼ"SG#B8v0/NNqܨ{:ĂtKǏX];J^ -v?ꇡd˕=J'3F ICx|1C%stJ>kstF9j{*e ď;o:'Ph4W-c -{ -8k s+ {ia{MQ*Xi3~}%Vi9c{ߟ}H4Tn#]7nҨy%oeMg=6Pړt8+q\qfCT@F/UH_pq<oE*o4<Ū0m7i~ ?St<x[><W )l)U'Xт|C2̹x?ڧ}ZOh/AvAU'/Z|фA{xb18ƌ1ٛ7-yÀ |zj7&}<6oHbegr݊@n}_Tt+ٝO!ßR툇U<-hBD>?<bO6ߥ=n_?_7[؎S1(_Hmc|h'Wuml&DML3Y[l;i44N7-9/ήO۶!oҖxpRNЖ.Gm٣ѣ-W9l$f+HG/3Vvr9e=ֵUsEvE^ٮ'ovۭO_N;Ho{?^kVTmѡՌlEzN"kmJ)7nmc?rŋvgᴻ;Wv_⌰W;QN4Y;: .$4|G\RUNjO?{)׷%{Yd~5h1ַ_{}�['9޽ѓ}TrHu9Ud:O~T}a iI;%GJީx8joǝr<#C*KCnW7*bJМt:tCssHYP||y?GDtfXa+~&>_Uw{p4l'Ss伽(&#Bq(|ʼnV(ӹ󧞣*ǷGQFikJk^:gL>8ݘ83uY 5y;%82&oIsrj7W@>u1OAɣ+WWTmʏ3M=r=O:EW܋k܋!k芜xD.>}T] Np7Gw?Npq<ors=|=kAO=y^s{*!1z>orOwYyt*Nuc|N/J|dwSU}];ol ~qT:wJKw=iNM>/@&﷔5H^o^ LD(9gvFHL0 ^‡A) χc9>T*c`q)4ΟAspcar3VJ㲃n'o%CLCc9(W -Ou2l:z("JOwԭ7J{=+`_2?(Vh Dx1aɜ̭pwчyǬxL"q^<l#&w'Y.?rJ}]sGEO3<\9_GT/5)np6;8#GN.n>&:JQJ|Y;Ge_CXBv.C,;Pv1'r$2dҥԒO͹d,7a`[7\4raIx[i^Hatt&FNEޛ -DFݑ,H"YiT(IiLIb9xl7ٞz1ZzRͻv}ӊN j9qGjb /QH:'ZuvL -y^ -O7XrZn*.x=G[,Ү7-}rr*]/-9Ͱ9\ 1F1YB'ɲvRo|$xrWDM̨ uqjt޹#ywA˟?_灎`<[P -/Tй~x+zHu1ҍ'.U|.||sR7b~LI)LP_zO\e#9ʹIe<=&BZ_Dl8O}\&*g_*켪f+s3쏾P; !wWƵ*]WWjw>Nxrn<*bnbͽpdQ[-}z-'^q{=OWJI}S8C )<-zsڰ=&QtPZxRj}8svzޫU%&marĐ>?a(Eoh*MrI\_7u[45iT5sRߚ Bm<2sNr>.'}oJ7V4Eڥ[tǃN]sҽ -=tqFڹӞ7{FR?wRoA4\ ]Ô|6SyQ:HxD%Ǩ\}y)>9y^#MN6:(ӵ3%|~M◌Xc90We%/?ѰQ~v[qe|oN]'ҭvtB<m]lsWH9 ]Ũ:iU;BK%~0zF1l8^aF4$м|2}3SX:"cN27$[y}ek/cDzTsS4K?ECZpK&iw1Kil=܆Z8I "d,G AsYߜ>0V 8z'nĈon_#`/݉rN_x7r}�Sz跮/*tt$q,j5}>oGg{ -U;'zrA|;~Ɔ wZ<9^xڵp9k<׮9%74 uL2Y<urϗ -GD.IEQdsD _7BTۍ `H@pCU$pCA|rRؙU$C7q+!EaM*OSzk %|HO%ڧFC73YRRY] ݧTJf5O`f{%|q=%I8WGWR"^NSX5sW{wgnct%}OZv:a+Me.PRO'=ͼk} k]RImlǓ-kBb:mTVP)lyԦ^gI"_$+|Y5Ot2t9�iB8ј:/db/$֛otvS+"ܤ"isItJ/+s}up`cSM5Fau 08'4qU<kKL*ோEՊMze,EP>rS=d^dΆjҩ$ǹ@۞ cב76nuno(W.3?* =9㜯1Le8Mb6; !T-:ӹ]54k9gR{ o@[_@bs"Gt8CM̰o1nORY=AT@xCz0h8BkgĪ3 #WQrSf^' vt,|^r�y-A8֌v\TFi" _rHQ.SbiZU?6p7YG,?3ʻ C>nD}Zj$,zH -.[$?X 4dǣ6w85jH):9SG>Gx!M1^Dδ>Bh W[j>:.x�p<ӈ7A ;c"s1U YC>TKVL܀Rl T)ZmAC -uo+lZ ci4z\:M\e\Uacڲ>7X2k'2M`]nh,+�u -4fa[znlt=DP] ùvgԬnVƒZl scs]KoiQf'Ɔۅk.yBi8+ً8ډKyFݩbSLĎ9vݬgvsX@sǹGL*|=nREURց HA b״Xy�b}=J58&*LMeM!b|"΁1BGNJR|vVZkڸeZ@9.Vcc ZC֗~@>ʹ,�(l0ޜq 5gyq[2ZȒ1f@Sz}L $xqˣ1 ɯLG|0{ c,/b<<,SؙuI4qٲ\a,SFLHuvFgF(N k5+Rc~udrVW6soi|+^=dus$:teOAp0}-f!Q6ofjO>x:z O^G:5RG@x y-S^E{m 8 7(h%Yhd:WHAT-QU\1pB# -9SQ<g&q_i6<<<ē|`vƼ1GUy6[7! -l/[ ͥ]pVw^JdsZil.f--˘bN%nZƆyյ+y'hUZ咭UB{++v/m̧˘&3| "+c;OilD߸ɖH&]-Ϻ9eCS6ʖ`vy,R/G-vceLsG�C>w 8%aB8Z^)Pϥ D,'<x1n፠| ]9A!^cr;VҙMX(R`UjjK�x_8'<1h?iV;X*Z7 x֊yߡğׇLtfmƅt%ւ =d<t -u]Et.]58K9w<<-2ByE+$IUSf0P7,)CR2gm&q>[cF=@H^F5"ߌfϊBsHi=N <@6aKJk?dARl)tIW1+RI|4s'BGcS"_Sع�j <ŔNɻ/( -hӠ[g9DNiQX -)_K- YG:{jv%{xJSH1[]*}^rR:?Ф8=QaRRNj Y;o\ 33lh) G\]u615'`'M;q0al5{* -cN1#-MgMKTsxtJy"}G{',s\8٪$bN{zmx'[\"Ѷmfݦ3zy=(׬]۷.A:#G2"gڬݓ;׼AYۤ~F\b[4X"[Digh82Bnͼ(<6Ah{.rŤbl L(|NS+8 0L5!H=+rj1 pW)֒Gb�#pC\ECE md~/g ưkA/A^TNe}ZޯX*sRrNMf|SG1Yˡ;A - /S"Vzx?z]~am)ߋ%8(q_zoNdb{cS)`kF0>i N o5DZ -`SuJs<2NF~Wr�"!N7iЍ|i֪ ,EJ|LD}CXw.N90\?߶S1! >\'ȫv"ucyYCILCLٚn~/, -qҚ!Vc[ejpXHNG۠I9atBlsc0K(Psႂ~�DnL gz&w}t-glд#f/d>ɹj'iə<]A8_�8XLt<dVY顅=_{ \4f9{?yrwo -8=N7ٺ٪Z(æi(;}Qޞć''O T™sDAF-DIr  Cq|K]<'קI)0ט9'ƒq$8p mmfgj霉kk'ˉMv[F>@VDHހZ_LTW%F5.Ą sQ 2BYFϢ}B~8nq tSϷ+=ya}OZ/] cSH?m<(aEs%Ŵ Ў37tg;VKj^=/v V'P4Խsm -N74X}DdYёvB|WL㷤ϑ.l^Ks3i}lgɔ{_Y%9 7lxf+�DE<S_Orl ^a4rڈA qNQ $?r<#V|pʊ_|OZiF$ ]9GUPlߨб,JcNch=_xJMmjWj`"iyMY{JeUn+Z}S^xuvR8x7Yygճa ӧ] {6^x�IFGQ7)毬^ &Kj؜}&_%ɗ뎦7ӖKy"+;Ǿbw7 _ٍo }V!nʩWdvVc F�16獳c'\<tcݻx IO7v:bm %:9h4X;\z[ۑLmF0|9Hё! Μ^#D #d5>Id>gûFd/xY>rݧ]9nl,e9.@~ju5;IYS1thۍ{OW+1Rn;$AQ)HMK湸A_p&>�Q;7!Ҋx �cps 9i_X Xo:<LY"];cnu�L91CoṢ-Vz]bަ`4U4 ͗yM"h TϮm!@Qw>[V"b -isHay[<[02GΌ|ox+o)pV=RCgX -uDqTf5 5!=h:IyU9,a7s~J}Tfg6{|xhՂTU<RWK- -yRg*k.1F*qKjګjO?ը_X5\"GHCsF3n]TRgla'yR[)5jk#W,,C=eWH ,O~(K -U Բ˵ e/TB_ԧΰFjT!Rke,boqpö'ё+^&<AaTI?KEscU(}Z*swGEbT{VTiTOO5Ga1NDd׫fKvwX*YyR.Sc/mz& -|DR RAf -WGj\xH|~^'5IO"oZ{EԋJVj^*hݨCx쫆Y^)5lZ\ֱT<܇ qWK-GWhtѹ}Td뗌}qsOZ^/VJ}*rX*7}c5RIVKx J@/HFK.0\ zTH"RJEn>M3y_ uڳx<ɋQe!Tܢi>TMqRg.5~GFѯjWtR .[\�&Kv1ktgd>`#B<a(RCJ!J,HU՘Lܶ UcB9 ]+kMl gV޽$v <.;0I0N_bڱ7_ K͸ ;Ut Y΅(ouݎ욃\ F9k|3jzu2(B֙ _iݖ]\{Ni-vU?W-^S޽9}LNg(z6.k2h^::]{b"@;j ºN3]{7+wϩ3;:eD;u}pWΌ`xiyfkol^ĕ%!1%G}9 []ܦQCDqFN'#md%~`7w0J -vuZx5N8h&x *dZEaz;;kwVx&q={PS5^Þ ThT΁xjZS8<\LJE>Nj,"&m,\ī&M1L*0f;[@>J`T Rh,}Z+@֘R7X+ zY=ܰ-IjV*4RFF283&Óo)< -V`MQ-}Xg؍8165K=@�ULɜHzvY.}͚i׋lѤg6ECBiSVLI?EŐcKbG#K-$Ə;rhbY$1lN_ź ~UPvZ19{t YQs 2e .)aʻ-:1t>MG?]#Ds3$vsX<SM[5H^mk9TcK6FzoMaMPx>_s:i]2G%OS{|35xYg -=V^kM8#ǜjpi N -9#5=>rN%m_<qoŭg׵GpgNc+beOqYܚi\r9n{u>bO i wkwqBnk?"CWw#b(өgVFnڪ0m".ͫyO~;8EяicI7LSUS@3*:`/+pft9듩chƙ}dںaF y|u-O}|mkzCT[D<׺)D<>1KAJ+X -o|,UmAzӽ(n6>dim6>1`ޔ_h:ܢchyn՚|cb$34G{_ENЬ-l^yuݎ#ڎuz]Eź+}6>i{ٿoyo?Gݥ̢;&s6VGz|<Um3 \T;=ت'Qn|`�L=1ojgQ]ۜ+SCԓVR[~֤? DmlVZ5 %9rh -L'Z{O͞z[SGu#!�bowVrLFXOۭdFk;,N76b_Ktx}r[-v\>{֕~Gc]+ǹ(P^ɔMIDbw6%r)sk|:ȅT>Q9G'&B4j3!N!`lZkDF.78Gw_J!`.5B%%1b ʰ>8[Db8 hsMDgWkA-lS1%nB̓Xso87;GEGnH: ]LijFׅ�Ђ/\c4&\C!h\pmX -?-_mu[^z+Z[]5Ǻ,-jp5Ń>pSaCVLwVfsB;y^`EkϹU.K9nk0'be{"o6-j -~~pMdzBޭnmѺi=ϒuzۀ[Xɔ`}u[L|m` -u/̵ fnu>oݖzC_no mNݳ]cSdcɄҵgw W.pHRV]Vߴ\MҖ[V|ijU}gwʒa &(!m8GlosN3sЭLp̬})ՒZݏ -. bvPbq{7j zs)O ( lPGGU^<n#?#އvsEArӏ#zYrGd/?3U/v>{7 -Ò_,}<H`nqoknǎ?ku΀|pGhL/DZEw2q=: -}8R9}}.gz羄:a(r2\hv4a\xGGvuܘ"P6eL&BSVUسݓ素QC*T1g{RIgwh/M -7!Y볏7OߏE Gk)hд@G6S[ڛDzoFiAdf±Ȍ4]n1jxւ&_~hrE>|e\>t5g._Ėu:.E>y^E<S;L勰`||.ut>\ObG||؇t>v=t> -r,ãt>\>q>n[7M';D Rpx<\VnIwx[+.$Bhk�>SXGt=TqnڲWL )?+Rv0(/ڈ.u~ӝߓkV-ܒt -vʶ&j4K4f/6j&δւND:ыiiw^nvm{+X,pkRQDp^Ӓ1e#˘.O/%{jv!Yx!s 9�4^nqKOsrmA\cƨs]tqzU=1d4Vcs -#;)lߌswwy?eQwy:,]YOw Sx[rV?,gbL'Oe{i[wRᨙ䃨jpKBY85A;0sxp{><:x}]Dυ:-0:pDBvGP#fpY{]s!PtܗN f#"r8=s~l=[ψ3&9H!)}uֱ5qA.@9�;-ߍVﭧ=;ゼ3I]]�%C'ξ%u”C||J {O!y~24-*aoz CZD$M̥zaoX^`wu02A>\7Mđ;{lM +t޸VC$قhᅘB~*HYOzEZ^ڟ1#"ok fn{? z0p]FsEu.u KRB1ɬ6ð5Z2fNp-g}U_>i<G.ӏ=</n?3\îKGy#twK1DfX B!32Nwf^^K&;3qH̺^!B:sXk^~!Sׇ[%:Ä^ - DGWՠHb.\w!; -ًP戍F7M9#n>!qG{˰-Foj蠗h?C[<c-zSwfSN>:&uM\Q_2K鐟{ -v;,Ƴ6/E,᤼pE@lnınN {;6Ir[H;O{dqG}Iyk'^$; -Wf7] -XҘz<y=ڒ<0Iy47VIyIy=p؞=$|<7<\OcdA!և˾ SަSvS82U& xƽyTqP3aR!}@~}g]SN= ؿ&V2J/vA=7OwX>-n_CP[ҚJst\X^{BX, oii3ܲ߈'Jx'eIƧ_m5s]|r!JSG~iwU^7or~>W&sUas,mgOS榍T;1ejߧp+OWONߞ^<:ոk{]:`#𥳐7N#<"ϟ{]+W>Bwk\SK%EӆꢢnfbC4ik?E!a^!VPlPns{=-W".`BpQ~uF۝BGb$g -;~VM)F+a0 ->h{56`Tc +_�AMb_M}nVA1/l=XDǺ=-/m"wbKb70<}Ks*P̤ľn?&ygܲ8^?}nY}a:Hsc }no}MsSy($eE<J缧q>7 Zޡ[U}w`*Sob_Kb+O} Zlj}^}Kwb[2}Nss#6}A>%#m8U_} eIssFLZ6"3hjNyifFξzX+^*G9鋸nf;*kK$m\jD#lLom񾭮 ' o*}=|xiI\LD-`Gx*FWH}<ۇ3˾E􅊹}Uo0Z6 &!_8Z?jtK coOok:򱰳M p 8}02Aޑ!e|;RI&tХǧ)MSGܪZy9[]VhjĠB]ǧB "&@؟D=)xEQ=pzavI/4ksp=-TlgK3i~�1=t7wzqR3d`ھ|ObYٹsU;&6G6tz1h/tԏ2^wzv-{603gqle=HG_i}[U׷qHǾ!l_@_ύ -;}q|;N=R~<Mپ`4}O߻u$bfzepk6 -Q `9HG}I0]BZkyL; -"I["^Xpǹ{̥ -H5?[g-L.Օn<sfBZ <$RM_y׶QGTIx_IogQD,aRI/ӗbʻ(o:ݧ0hiUjR^nUlZm`˼[fy§ct~ NsjңX,WK׫,-_/fUER +G48V"3Xae|4Xfߚnx̋y~|_̉6 -qDDu|Bۉ<*~ʛBuxVkkuՈPf VFb}NkS-26tvUt<K{"";k [WU'ړ}ZPZ?vj셗qv}ry O ϧ)N. -"lp[ Wpn*vut=-/dt&LXͦ"@3u'W)iQ-{"a򫂓>#ژAӄJ[l$/^HHP:N*'nsQ my˝N00q6*.yOxeǘ, y=Dy ܯJd6gDҡDg^JF IGݻlbi>J$Z]׭]3o-Ȫqֻ1<4>Y{Yh͒8[:ZwovA0!z20ʻ#"1ѹa:1vǣ"ez:*ܓ=]Uu ͬ'BF]>yA;@CƑ߮ -m#t[FBӎ_l_-0(c^-pKzbvSA2%1l>bPMpZ|D)a]xNR#Z]$Gtw)|B1$G$}J53:MI hY]$zܓ#{;r>WFoRffNG6+mRן - -#L}߬If!߬0j^6+|[mۡbLSv!7< Wժ GU+ ;vCHȮ6<< 7<tU0Ądž&ㆇ e}}w;47=oxpv ;qvqlxHlx[=؄57<[fy{W>lx&G:*᡿=vņnY~6<ŏ~hC^c, y#$n7<tQBYk F֣v*]d憇}CkB7ᡕF6#-2 džcH>lx>吮 {1^7< OaO.SI\^w᡿/z}\ݥMdz wm K~C~e7놇q6=mxKwCnxc g�Hg[:d{cRJ6<4|^yCkunM0L.n6<0>]ۡӹanezIAz46<ֺ?@u˻av;N7<+/۳ -sEۆӂ 5F}C$]#cw;tipzFfP+䆇47<dߦ䞱ņ - 7<V@sq짻m+b'7#oK䦔9,bҧT~zFHo^npj||HwQYΞlLGY]щzJyNn7I>Ǧ v2]PmXdkS;&Cˤz(fU墰]W7237+108pz4~O~,Í yNޜz@m{M͞-GyzY -BjUS;asLm}fZ'[fl><Lɍܘ<};Ʃ:'\q<rnsL8_Yn_SQ% 3[{/ʔ~?mۺjFo[!ѕޤ0qݦ+пٖz"g!sEurCg%71W:^e޶ -k|WjJM&r+^B-qh;죆S,g}lਆzJ%3bd pE:IM>^IV2U/w(SLgVҕEքRb2Ss='yxQ/_Et ?KcżqN -KƁy5ɉt`#`Q6.ͿWRW${mNK -TfC9ObMm([gf۳IMw.NhB^a])J-JXpڇxU$񉨿fe6({ rTsmf -eDVv'ˉ\ `e.ft/IgPi[2v)0]υuq_Xg:$xĎwiHۿ'.*籓5)~40a4T}T:+?!63}IDQ`r\%fp28F^@=;sXn?|<˳<aA8b𔺍l]4Jk讅._h S|gy~m\o<<%+~tyov+,ŘVzZ;.ˇS@btzS5 ޳< qrirF{ZN>/'pnܬ[deIIޘط^G:z/pt)R)y"%3O}"%脹E#9y27+"FȄ9NIgj)8102a`j5)0e[ѷbBx0ZK82/IvP+^<9mBo&0Yx -&Dt+?]uj1AF?":m4RkɊ;=F:-`ێEweQ0qX[+ `=o7A/p(&ū<w_ӈ8^+KOiݣbXۢ_yμȋۇ}uӈ׋( nzA7{6ƔE;_ԄۊtQ.(:}̍Їa/ΆR{T*iB-׏;tFJfB!kF.LmɸZb]NdG",v ڙl W*ͼ]Vg3"=  Z˭<JqI! z;g]^av< RְN޻ mFnh9+Vod46OU4K+R,L/(N%уBwVojaWP4a .Zx,K-Ls`iYYDr =Bò$O-ūXNl56 -]b1:X;"-G:@o!lk5yX-nüIVVZIy͍xRf 0xTDKS UJ[Ge'W$%zV|)]!>Q|./ v>/N:~sxM^}.c  PTguB~r|Nt׹ -N.60XJ!d%dE|OeѼ/SiA-D,ܽyLf=_/4tpj[+,Ri'Etw=k:^i3'tY^(v -z ҅K' T/S뷪q}Y7߀]|#܄MɅǺVbD(.d -aEL>1LDc>pn,>ұb9asaH)gjpWm(O60B*d;b)$_S{Q&NR>Dów{zLn%~G_~`+ȧLޭ&\e!eLkOPYvhI KLDnq</LsooYlPvXZe V>iz#bP熄k$ѯ,26L;>Lc5B &tn5s"Y73 VEiٱgdNWΣ@oM=[[53VUSIb:yȠKߢE_mRؼ3gCn1un]x>3; -3<h8H8d †5N,VΛ %p}M莚'8MWQkɔ9Gn ?x5kBat|d -8鿴"XuFyF(}vw3;FB_7^q +kt}bǘ g޼b5O_Ak2o_̭gv߁>h}<E{i/ϴkl3G#x=;Ӻz#[a_r8hM4[ ->kay1?4׾M<9hR~=M FǃnB<:N>ҭVwwϛ>aqԲ5q?{˗hR4C/vf'Nsbl9_>m5fŧ('Nqw)1a5Ԩ+G̙Fr$DhMmRxqi-؍GjUU.@NԐδ2t`kEhO1M1>c_tu$"aF,q q:|P>֐6]Mj%yC^K0!Id8Bs<k*Hxio{^ Nv!C1Ms-d&[x8^ƗSM!:,cc ^-MYAXi -'3.]mJdV -ף3k$Xn#aܠ7]gczbƊEvvQj2iAڴzv.a&lMX}l,<;Fn5G&T8kb>+;_9/M})�6 -1l?fgR -f8D/zlk!q4{f0>L̐C ШعFBJKo+lԘbLA1I+q bbf_A:٠4ͦ'˫\e 5T:YZEkeNvbS% xUet:nƒX[VѺM/ȓhA  "!6G/(=M"p%8+Ʌ뢐^Tfhưb.JC�h,:?a܏@I( -qKTRl0Iq$/�=YcPk;, aorARGw]c|Mb90}I#ш;lO~F܌Y8#6C|'B1 3f>7EXCq' #Gh,l8s@5I05r$U^IKS-ͤ[Et<}X\0W%pVnt[K儛Ƨ淪`b=&& fU\@`>z< xTW+էpdI:?0UQGrARqT-O8ZĦW\`Kh amfs^^9ĉ)cQX+jmF<+iSa -A7irEXi.nt2Ơ#x(!xzT)Pc<nBj1?kǍ鈼_'"z|? #FϞeYAM!}5-onqdazLOcͰ᮷츘L3qezPV^um*{؋NHgǺ:\O -(08.Φ(pwzØPѭ&sE)Ab\@Uws^jtҭzZkU%' (UeW:ǫ4RFf]|jDRcD rll/6Uw9r4ڎs&X+s ![<G> -wLaTml'=+b$+, _uyi?Z)5kiq6,OmnGy ],4UC=ߖN͌8cƊp`~L$=1v3>:5[;4Mg}`\=�g£w91kbĬg -z`d>嶄^vo[ oeh& /c%prK@'elzmYs1Kc$^}o.rVuv.[lOH3Zb.C"sKK3c(*HŽ@^!ζ#:떢J[=NV,lœc֐:'CbSC ^ѧD@c)ZB Hn`ߍ]L:G$0[‹RUY˴(U`א4XY?m}i,dS,4FvV]Z)doshzq"PyIB<8$ H ڜL )]ߛt~Uɠk=,SU9v[VI�gX奢<Vh٣4/(1Ҋsuj:35S$. Ȅ=!ދu鮈0*]/p*۹>G-P*]/LX})^*s$~=êt>.mTz<BJ!uSX[ss*2 -O=m4t3*lgj+Y4IbXJ1MФrtigr]:XCM -&+kbL#q'`ZYy~;G -z ]8&?˜<҉a;#";Z;8Sjt= #ܫFPo^3Jфyn<,'c)ScGdl. eS(샏/M#=8/OZnGrq'@9YR� kؠԐf9Y:p vBb.\='4{JMY.eX9H#zKs9lsV'!M_HS?l>Ϫrs0}t; O!׳ tvƼaYu^$4Pn>}v;t6̣ըj@8R/Ʉi[;uAxCza)az g8ë "n,t#>iWju1ǻt"&n?k}v;52D#樂n7" "h7]8O.Oܗgh:8MšBY\89-N9(K;`XUwitc=Wnjnmڦ|`Ew}=ĺTh8>^j0ԧ1$iam=}[$f+7`3T,ZK'e̯p - 6&d - tO&߈D8l toF ĚVҫwVT~n>K,='q9s6uq4SqZ2( -y̼X`gx% :3 Ͽ{!]lב&5Z<IWw/}w#:^Rږ~cqƜi v@p';w@XfCki߃uv{)c+3Y v&(|>I4s"O~gӕAy$\c-t:#\U4"\q1 uvڙm^bF!y͙8є"6;k$pB'^BUGz & "D\qlAr:y14Tu;mH䊓2Ԃ8 -Sk QJq.-5rR(9E`&ΝȋɉUdx?/chNq4K}fjqhzJ*LƭY-5½Tw 6|VA)1viq4R=ڑɊCZ;2YML3JZLVӚsر׫MK&"E+(sL uq҅(&~KJ<LS3PT9j@2܍64Ay-w%}<++ I˿$c?MlţACyVE{X(.,URFYLNʚPR 4rؿ 7 - Ej!~*ūLSNh7bcY5ik/D,h/~J{Y=Jou]*u^}:WhgPVF \d]Fq@Lү磤}H&!|rHTNvxo+c呥yRV8]d3.K�o,ϸۆk(j+h̙SscT\ΟU#vz]Ow7v"38s#䭢K,w7(NƚgC _+(7y_;P'2jQ-.}+,ŖW WI< Hezu#I@Iľ{u}.#ɹ\-hY(22m΄>y1 n`4y[!eikVT(4E3fg`Ij5ӷuYeIar;G.K, eZJ>,*)'RqK2Ů\~lثG%WTa! 5jT;ZWrej=n[QЕQcɕF)Y7ᨷ.R 2Ԏ<{{NR5_TDG7X+(e[OWڳQJ9ڹT%>ZJKil 4E�2dH#j./\JFZ)-7ۥzYZ>&^՗rFl'!#]H*Q#dKk -ߺh4dĝ_eZĔƴ3,Nl<q"\цZUhq5jEx} -XYSRuS$*Zt[łk/ 7Ibp4Hv;tP~"Zg5npe Tq=kHrշ9>+،m3u �˦A.R^$QLT?C07@XTfM~-1fZb~~?5b}ߖV{t\i[8ИgcW*rqQ:& CZXFSiHCX _9b`VRv}CrmaKrUHb Ir\SbbV1k3Hw*= ;ĕKx} "$oBLX)6 N*5\Gx qSJ휬,8nWjK - Wj^<R#F"x̆jkV -d[XWKZRk.x{ -e?XjVfGFl@\{areR#\( 7o4Cq+5"^-/Tsa -Wjdj LkV!JD)?Vj$Bw([<|˗@Q ;!7m3_^fS՝fvq}7.5BTCBgx[$:3TI2UݓH!ͣ5b=\xezaq2) -;2}Ϥ38REHiT M ;3X8Yksbf*4<�ԗ;LȈ1v*&R+8'K2Ϫ<17;<ސ<N2+#$+s`@C:Ӯ㠐9mQG $#?+ q= [nxBɡYԭ֭$vӡɎ9޾qUuje꽊"$f$dVkXUзܛ]N -2VkG&+LVkG&#j<MV=jEVk}֥xFLVRO>nVIYW6uu"ʼdʱP'tN2?4o/"?:)!ì>̈́T~΋ϪI0R۷'zA+񡀫l rؒE+뾾 [B;ѿM;ɭᗆv=nN,*]pUbz2G0U[f#k2EYA@Zu/d')U)gb5Jܗ{ :Oz!FCzv6iv /gۧn*b-`EVu5aZavn?}?i?>*n.E 4ӬTKumQ -'<;wI⇤6O?Kx ٨q*8^eMМ:Әgh&4ٛ(<Q1UDQÍ -.CRFkKB@8"&ΓEGJ#8yVt${5H;}>g)? }7D;L!tb5فnxNJ ,nxM#^(C<[Q7ŵ NTށ$rDB#?zO\Oi|^*r{Jj$]5Eb~D*NR-!MR$nW}tڂv$\ 'H[XnBraKzaŖE3㵃Wc,:RAL&tqM\ w .i9RH͐h|Tīd>ap},c#TVK.>%H[Zr3ӫD( -tB:NF94Gu<G5DIyn$w46pXI -ūDGP: -_8!l[xÆu ) RG7X㢱^P(:7KW@&ŏ>)Eו˕̴Nc:wuӷ.O+kq`ʙQU:rF -~.W2zsRLre »\$U2=$!#5'&ޞrF -%pZżUnGk͇#涣3xA+"R]•iq.BW2qդS^ٹ+uqo#`O?Mfz4h&QCBAGOPW =㢙Y<r8~ɥz ]0!*ql]֠T&PG5ytil,}֊eyjF^•4]' y!Z7+b:?"5ǤlUttV=Zx+W"]~ێj+xOFcWqWG}-: v'E: lć/Q>qD#4Fmb8&&hN%Hwh bMLv0_Oc[=Y1T˟O;Af{C:xbed@,8d->? NadXLXުxu||a/k}W4P.PSjH;3B2FScQW?jv%6,cpy.ke ́K 䩏p_cd!XȰ;7pY@CngWx!4yUN~ <I;wI:c}" ^:f׉i?+RQS}#ӌ9z`>=mlz؄@/L84,ޭ x1'И.9$j䷡[ñbZ\yC56/O'ЬZm -D :}ҭlllmV"# -2vs匰Mo`SQa\w$l 9!l }*mU A)jsX.鯙y|%1ڳ Vt7f~~$i�L6ouu3F-j.Mdt-(Gt}ƒNpiMt҄&&'>q$$<b68_ F7hx̡ ޴+Cdp -cnr;:g^n -T|R" -z*�q횵EIc]N/t.'ȨʹioQ% ҏc)Zf"e=\Bz-KթY/s3اQKbCٟ2l`e֪QJ/&Mg$fc ؾ6xظb o}`@ =33gVgg`u�-FZ@]sx4 b 7!ErUO>︾)Jgv "#/Z7/}ITL:fmS9>ʦNx88g'͕GK EN[{[[y98#]ݛI_/H/3piR;HyMH&:,/<ҭ[?Z<)M5i%2<^JvC𰅮dUy1ЭR3ARrat>225;Iu�[_Y[PAQkOϽ入#ŠbSt<u?9eSxEtajO%H0&O?l~H>S>#rWёin@d>ߊۆAdj FHv߄=p|Sc)C,gQ .. -*)&rO -.8yg,gvP)y2k`ŅX ? HiaiCׯ s I] ^H 2B?͏?h!IEqZ޻ן?b͔^t8.4sB'yB)}]Uk;ҍ\taqL&KW)R$*љgMGc^ND+@#ΣEPQѲ.${ Z>LO=.}rbb܄&(%NKǕx\[9R7r=_ɍ?nbtFi>- bt?3&9-EZV#z`8CxmKdhD$V -)JTv ۚdlm <)8Ӯݜ'8< 2' Xz* NCLLjɊ\6vﶞ�x5+Ńd^M4jGn[_l Q+IE'K^S6uu 5�*?\Zeecv#tqeow{|qL<y&lOaPw?Ƞư Cb_K}_c=_"7p ̭^'CT0T־{ڝ,'r3#b=&54`t�8 _O/m~)6~Gەf4U*IBL$ -<pTv4vYcRU)$pIza�Ag4( -뫥˭Mt TM촋Wk FEX>M/ ?|՛^ttM/ cU7񡟲2cx$z@s-\eҖK -ɗj1˖L#,,2O)nCx&&Rq8V[;VRM(/lZl[Dm鿹>jS5NT5Ć}_'j b[z7w.4$} 4yh%Lkb-)3HJ/Q۟]2Mp`ƆRbk {{G0[AW%I [vb3K'Ox_2AGY}$-cU61;f܎tRɇ2aNS@X}fC*ɍX3pAnA8fݎ52r˅ k'1k ͩdJA-cF~8Up}M8|'&7!|Lp3@&ځ9}4lY=i&%z߇Ggލ\6GƠ#[oOm>lqcyͭOۃ=H|c d|cFg޼b<5qyBom{A[ϽϴݗgBgOgK3 ZnAMf=~F6BP -MZu@ÿڷ<c|׈Q>zi#:}pj$Xi}߃#&yeΰz:[/_oztwozx5>ƉS6CM|S^fN -&mF4~IC~4N-]JR2Faݥ4Bw]lɡŬ3,-_2Nb `|O]1lSwvUqCʻs4NqlO%Rt?\DHZ:?'*Ɣ5d6(YoյE)9Y.f 29ݦ&t/E׬. [oyzTo磮UX>ɚ -$e&YkzEuwuk?֑Yc׉hΤ\]Bu) -C;I8qH<2'̚s-+<h0WYT>I|Vv[Or<_GEuO3A3ץhjKV;|zP:cxhɱ$m15\ 2QKئ5LW -;KMF쓢֔ZΤI2JOLRn,a1LH<)Y6{O3&yi30ƹ>FABiCG0󾘢EVx\is $+;r10%E~z<e-YFyb;L;nKu?O?^}jyq??R&Gdh\f؟K -+_חˏ#;ZoKgA7%@c񭞓?GQo )d2^|%K5N yIUjٜIAҥ)t%KO?Io~\_~҅ק?3ss\?};'r]_/_?^?~ŸEH۝ܜQkoQj_қe/M۔:6:@GPtg\[|9_///_\I)H3NS"fr3kele_wѣ޽l]~\>~#̹˗GFI}<ФI -+Wu!ܟ؟#Vw$94)s`ɝODDDEU FJ^G?6?)M35D!'hhٌ$)b.'jFrh(ɂ*dEtH dѻAEYĜ*hYlV3RNEMstOj˫ұ(YsWӎ;XU ʚRÔDA]ED pH/!+*P"mGQYEO3hd'8`߬IP&&L:⤒SB J%B-y $XX>1%T9D2lXr -88l*,Ù2)L6g -``>d@0gʡ'rY4e"18>sLL33 -ÙJ"+KKJ[p U}`9b˙r0d(MH9   q(!q8S92$ gJ%$Mm"p"̙rI\Ly5Op8LAg*ÙjY1HdV%\�UPDDqr|"@]UrcZ:Uc|I.l"pȏ"̽r5a/\u=P<r='gNtdOApF" DCd!p0Xg_G�)YY#FE'" bY|'z^ x]�S�S�ӡӡu5ɍq*{J&83C  "uz.RCz37 z6�,��lIeOPAgh3N�rw�|(P  A$Y$ $g9dzp8pY fR@§x V XG$X9DB!Z({,Pu""j"<L.@4˸n;O<�4�xl!,X:bâz(Y5DBR>iJ6U9 XӕEP x2XzQdXOpJreZyu;?@؂ ( -(:rdZs+#H0.іBB&)f,,!X-`Pr֔9   q(!qפwEC5)e3B8%%@CQ8$:.#./}@@r@ɗ*9KzT2Rڒ/�9 K �` r/`o)[($$$%$_ _T2Rڒ/|`Ni?!(w>}KA_*g/D& J %K@(` `r/`lŋPi$$$-$_*gT/DKd0%/_ -|)@9@(R|)DU9O]Rw$$*9\OTYM -OqPDYT((P1pDNs i&1%{.Ф��� Ɠ*ll CЍzڌ"PP|@M2h&ʁ'{.ξ5��rᤚrY+ 5b4% 0 0`v6`nTOp���C F&5ɊR54JNlttEF"8S{!+UOrLV 9�ع3u@ -.;X{�v� lX+tDQ)!ۉ>Z6NֹN(Эu&@֚.U{�~Y@z@QYOh*rDC�W 2`(`�e[JNx*m U@fTo@9bCrD|`hld888^86UVv- -}Oq0Ƞru[eM94D`G5��rj*,_c -Yk.�=:>@@?�/zs$ C9dzp8pQU,;_4p_*;GE?8Mj,A&=(��*uRSiڻ1x �D!WVdPcVUD~WJ6ZbULjE]v1x 8W\GR.a*փPUhCV_ dLȂ~ 9�Xe+KV** m @GY}@9bDùrFV"P94DUWDъB'�u -)8(Z)8A_d#P94D`G5��r ᪪$3gImKzKHA -(JY ` r86,I$s@iʪ)s`ɝ<)@"@"@PBѤIU0f ֐tVqJzKJ+(oL9$:.#.0}@@r@ɗ*9KzT2Rڒ/�9 K\`9b�˗r0d(MG9   q(!qR%eRt]/Җ|)��HvbEOSQA/3_ -.$ R90|$2aPd0%/_:�r@Qak=�_#F|)/C._ -88t|QTU/Җ|)��HvWR?vKAx:ʲlT-~ڌ*�/ "u@9b�Õrwe@MbJ\I'Ur4U'�E -)8(Z)XeM>O\`G}j.�$� I5.kq9%XIo8`:>�M>16 DXozA!+4f=,))PQIMT:M8`D9([lGje)^v -meA>Snn@+D72a$0!ZT)�ÐAQj_#00t'Ns8j&ꉥ^}' 99lsc rS<�? , = ( 'b9Frv!jm00t�2ҍ[%'Zt6a* �PB1Z!b9W"Kr0i4@/*gd+VɖOݾ8T`PGdP9ĺ̲tm"? � �95Wsi1O( @P2@ r� rIC4P(s888N86zT542ܩ`ėQGG0eaxri4@= -j.�$� jJdmTj.Gz^t�d*@k�_#Y9Š�UkQ_U****VEX@;UVi+p��H)]0^z*!+/}&dA?~,%+Lpt6\#,PP>1"\9D#pLm"Ъ��� ƫJh]KZTTЍzڌ:PP|@ꔃM/tm"? � �9pUUjHAҥ)et%%p $-$Zf24/ذT&)gLK|I&M -3[CjRFZ)-+G -3尓 &f{l]�I�aI'_T/E=×R`HiK^t�,s 刑,_$94e;RDDġġK\KuJCJ["̗r؉u\=MG9|)��KȄAҖ|�E�,!X9LRL\(f{ |)@"@"@BrFeRITJCJ["̗rIt\K94eK/}@@r�{<*˲iSAi3N�t�(P WA$EIC4Q(s&888N86TedWeChnf�)PhRlbݖADC4P<sw=��'n;ŕf`'Yb4% 0 0`v6`nTOp���C F&5ɊR5;4JNlttEF"8S{!+UOrLV 9�XhQA x�v� C6EK!е(:y!̫'z , & & P"qj΍5 q -ꢂ8O<�,3ЊU1ۉ>ePhH72nh -TЩڌ� -@ rh '_,& -ppp8p8l,Z%'[?t6`PAE?A`2˚ri4�; -j.�$� \UY1<2Fל]�zt|�_#0(Hɇr@ɞ (!!pѣYviN#Tv@= -((>p) XXƓNMz'QPs  QU%ko뤦r%TӴw9bc=p T -_B1'.ǬZr -P P P9P9l*]Ū;b*큗s  ~)ࢫb= U]YV9dBτ,��Џ%Qbd f��xQ%�J�#F$0+hd.IMZpxpxUI+tI+ -QOqP@HrE6NMvQPs  YO)?$]jK%/-#) !2 ,!X'r0d(MY6e,'HHHJH64*]Po aJ+S[W -\)@;fa'qL4e1vl)��NTɩ _{/Җ|�Y/#XI$s@i?ʁ%w>���C CǗ*,×2|) %K/((E* /,zŏrʝ|iRw$$"K% %!-y  -[XB1rK9$xQ*vRDDġġK𥒨2|) %K/((E* /尓*Ǘri�_ -.$�]%y�UeӨnf�T�xQ3�/#H(hPM -ppp8p8l<Ȧʆ0ݨ8(RHGH9ĺ-hx;{Ps  N vvY+)OxS#ٗ`W@'hJ``숱 l '"} bY0y5fLLLLMjjiZ# @e >DpT+ H1TCVh+ l@pps�Z& 3% Ѣ8O<�t�lRB,1k=QtQC4WO,8Y@L@L@̡Dad՜k@E%py�YgGgg=96bW}W\-hˀЖnle*9S'�;�VP - A$NYIMpxpXV9#[ٵJN*=m  -((> &me5hlv\�H�AlMcy*Fל]�zt|�_#0(Hɇr@ɞ (!!pѣYviN#Tv@= -((>p) XXƓNMz'QPs  QU%ko뤦r%TӴw9bc=p T -_B1'.ǬZr -P P P9P9l*]Ū˺:8bTY=pď"\tT{1*\@s�$V,0UTڌr� -@ @rĈs Er0i4@/*w.iRQA7i3N�S@q@QS6qFri4�; -j.�$�@UU9I{>#HThK/ #a"Tf,4 /D#ؘT#Ȣ)!%{60CF&UER3[]h$ꪬ4H"= 8NZh:\HRt!! !S-GJx 8%&RB1NHYD"hqRgG -xxx8x8tZ)őR`Ei;^8Rqd�9R8z@)Z(#MrQ,T']0XQڎ#9E�)!R'r,FrKl`(fk )!!qrF8RIT- -+Jp ̑I[H94[eHϑ  9�MWʲlnF�O%!J,>A-4$ P9QBBaF\F6,|U7ߺ-OqТ@HZ  @9dFߙ::"lT&?SdrΞ�};b$pꅮHW#V'z] X@R@R@ҡDacd\ujw#b @M >DDp*H'@S#V+L@}@@s�&0% -Ǣuyh}b! -�HGX`(Z/<gAԐLH=zr(rxX58gp:9<�p̏ z*֎sLh,n~,��ГVl&*9Ѥo18L@e(9blCDp0hjX,,,Z,6fUf򬒓Mzڈ5  |@֔L S&#@tt94ˈE k.�%:�@@`?/DJGT50hj,,,Z,6JT5Ӽ44o#Tv@% ->Fp )XMMJ(QPpQU%s[ꤦreTäw9`W>G -P"QlU;q't=dNTIIɡaRoCckMW|^xVwdU`Hu=dN`H>rr@3D +։ڈfQ%@I@߇#0<+h`6ԔHM*phpظTI+tE3hmyڈ.  |@L}/2nMm"0? - -.# RU9QU0~'ed'8J4RP@䈱�l)Hb�ҐtT4D-0���F&UEPg;5X.V@! -#fǏ2IZ IJM4! --#0Urɇ"eCo%8%pHB1CxDd,H2g -PPP8P8t|˚|(ɇJq̇2Z 5 "@Yd>|(��Cbh4Jq> /#X>GR3 hj(((V(:>TΨ&*ɇJq̇2IZCY4DCχ~ 8�Vin﫲,<ej,@B1Bh[x &uР��� ƃ*L6NZ -{@ -K͚h &ɂuΎq᠚ 5Ќ$وuty�6Д,+c @R`E;bK:%$#JlӰ?L7P@ j(R݁ʀP}jA N�a$VN 8Z{I4`/c:='ZPހsJ6U9 �-S+#'ª9G? 1`'`�c JN4SH 7>{� rhe'L£ގDZ6UF # y=ǙeiG6 W !1$e<Uu*tOwk }%22nϧޟ!]Kj]n~>BрS=@MPIF?pG^ ?'C<cO gf/ܟ țj.t?O6x X6ܟɞ9OF8ϧtޟ zeԾիd#|֞dOQ3Y7~Ӫ^SATNd΂'|3 ,+.& 4S˵y.F<'<Y"_$|inSp0U{ÆWQ~*s*_^}8}Od'k ]EOM\+.9bS>4@vO1U>́R -ϧK d'|~ 3s,| E=pOd'<e/oDŽSP8Ztѓ{3] v$z{"]n~>B֞dOn|ڃ{4}>񃀭>`!tΌEO> gf/#K<rhK> = On"KsJpaRjwkF=6l?`St\?38^t6Er-'tZOc 5]}鯾Q0Cl>7 ϐO~fހot!q#WgO.{FOnxrÓHn|o^}ar -=}'?hFlqN%\~>orOxǧQgaNՇ7ހnv'||3,}K)+.9o>ѓ/8ߨu6]}ar -=}'?hFlST۴.YxF7zj'<hf?{?h -�YvϐG~f_tOt#;]''<9 _&'|i>PlǟƟG3^`?z2;t1^iv~.{'3O'o|0lV~0nn?Ŏv> rrؓ>?{jwUr9{3~ؓ|/47}tn?˟O=?GqꂓB_1 ~t>ԅOy'ЅU`\CCt>KԳ~F!\ - K:~ݬ{ltgz2˓YE2˗MUJ\-y t{?}/d' =J͸.aU_N#eOd'|: ,ϧ #+'|<3#,Kl*p.9t:TONxr“\N<>9M6T?[h [zzKO~2?.9&UZ.tzBz*'o<yS(jvZ?Чp�x<p.#j^:8r\:]''<9 _.'|ilgc]~GzBO~2?]pLy\rrt>+TnOxƧ꬛MiU/M||}>w F?!̜ -KJN;Sӵ8.<}'<%_$|i.T0{ÖQ a**__}8'w}ERCtd1O;_O'|Y?Zp G,>ݫO8ƻG<s.#K9B?.ԓ/4vŒs<tnғ s4ݤK<{.]rr>'TnOxƧPn7/w_7?z5oɯd.@1_/ǯ~wX;љ~?~w@i| `a:E|dmeM3^3~˿| PL0pyer -KoSkS6&@Y;d_j*ƀ6,R)*M!mn}~G`˿l>f)|~zc -4o?ny7C__Qo7ۯ~wX +9B!5\|dC3a4B[W?}3e~`L_7__'8o]/ 'oem3oOZ  @CT ؉']:~Ð/ցXBG<.t� Idl/b6G6^ ȈU } ~n[S.BTi%�V|_+wg</_Ie} ]p1gWҍz)Гh&ػ1١xi#/qy]ʸѡƭ-3Zq~ =J)$tM69|х|/ܔG6΅?8:h~~A>bǿ}77Д_ۯ~jk̬xikp(^׾Fr`/|re5f]z*ZT,$_ZB/1B" -",Ql-rRj*L䋯@NCV岶d-ru( J(e:Qh^t8.0ӏx!:l3zgY)GmT .Yto~Z zs`=Fc+\/.ga,\ǯ>s?/BC-ZpW>T6r(&R.\v8>\Y3S<&:P &=`RCIdo嵌.8㦵øj%liodg$pgvEv:O7H->2FV�CxW -endstream endobj 102 0 obj <</Length 65536>>stream -pl-u_, ~fmM4ʁlC`-IׇԵ]`&{,t+<>׷_1�=WaL؇5k\5_`c`LWDYYW4iq}B6`.ՔFI5iL%pP:ětmhz !ռtE C|fC6ʢP&hG]}6RGz>ldzwPY\w^E;k`MY0Ԙki3(<KReJS; G2෌{&6)O {e1#L78܄%d_l$=-Y^JôI^l -ڐ89 FWf56GhkBh=R4% {gt 06 .qNsAhLܷ<*$: -VjGuǗ8-̛쭖X`502@%R"; -HX&y4s{#rb<+° |႑<* X9LBUz `|D C>TW!؎TcLTY~b+ !Իf6#Vn:0c@Cϱ#%[9B$ P +0!8O=mqCC8YT+*]q -W$BaO}RSCI`C*ߩJu[~0ySmd(eyZ>C\fۂM` PHoq`)rG0Koq톆x9KC6>66J g8x J+`ZBgԃ3߀ t{GoM1S@GE+G-@Xw02s\.$cRpCG*n ^) *7! -h#&B_sIS>N`f�v@`p6&R~.)m' N80Bh\Oo'D\dHX2.ct+D /MT􌂨=`؈X`03 Ȥ\NG X3Eg7g@NAHYm j3{?"` ˄m5D22I`cUWT`BڎWmf\"^ ~7kw mLdY cq:?N"l3<Jщh -[$ BX9OCQz&U;8œe)i]?zr^M\z)2gº^OGhh 9siwv#tY8Y*pΐu,!@t -W*%}ؕ {8a_+qҥX{-~ S)O@^ԳqbCvjV=i;)~6ۆͿbCk1Tcw!BcNM8s>9(E9KG~窰qP7Pc6 j2+8)ejj4|qT@\#2z0hÍH X5%&Ē|dMc‹ P>Ng҆ Qm(tD�2=xO|8‹OTDiu2ǵ/ׂJ9KjQl#0aKGř-r9nH/!kF~!@�͠+(�x)ցNK 1h'a|y�adh϶C9C SQh0O!l҆ <#"DP[*TD8F_GԶ!qKPDC#o BhQ4Jd2N |--Ti D6FA͎݀.Ҁ1/4yH�>Qk !ۓ$P+={rۦC:489$ 5ky:ț(zY,A!I08(@~ŹIMK$y XEe"Y<2qF#˒F \کB0$тt"u2/f(L395,FQ ӕ“(S.r9*.!88v>B)(ˤ6xH|gJC6@S-#P2HFOj�*:(!J<$ Ab%i#m>y& 3+厀F!aNZX XE>8^6_j:2�r%B[8ufk[e5Fڌ3H@"vf@VLJn�4< DGѢ%&˸GYrFӠz009,WizyzC)*t#Ty taABYm4vEz,!Ɔh,֠a$ƿ@70]vpZ\o{W2[)a]?٠�`l Zis8=:q؁Wh0 Ƀs~@8_PBIhgE$\\'íPRl׈t*CCq.jwP $ e)OQ_8DjPQ %"p xhh/�H@2ٵ ^h'X�LN H TbNao.оzy'cQ!* an{y< -'̻-z{mäYR+ 6߀$),.Q`Aa 5"a+@6$7rcTnkIo<?]#ZA| &a0i60tgrv +A,>.Hp~ۂ?/ l@kc 3끺 H0�*1q !Is-țO -jA 2MWzjm#zѓ*hm0fw8`À1%J8@ : h1U@+CKl< -2O L͉U�y%Cm'w� =*S鱅zvcաGߌ@TO#0ِ.<jpy|x3d&NKB,L -Ft4\ (&2fKl6N&Wfrt}^j�C7Ґ^ᣣzp_wƾ⯇%]†ZV֍mP,4 3Zzok`,TnXBqSU4å_PgCxuJ6LJdl. -zRQtr {ZCZGѡK zHΕSz4B֨rG(햬];v PMB - r44כ9ܛ�+57GW갔Tp"!'Є…Aҙ[/P_ &6ry303èy]V(P[fh7�?tt'@ըܗcaA,+8 w&IB9+.^w@/.\s"T++ !kx3?^E^QA<82Dbw 5;|A Z||p#͌{EK2ݑlS�3 ^*b�•* `AqM2LvqX2"44 Ӛ !;OU1xGJg daeK*jϔ^hڵhX*y3S0 -2t -rp3s -Ғ -*8#6{!]G4>*ݬ0Iv~ \F $f(b*Gw6(b÷:"Ԛ`<t3H6�V+c8يݥ7b@gEi,@gNB$" 8 -�7nKk:-vK/[ "yym[ -K@ܰc\bn!;1bO)F\?@;[*�X _,7gZ|D'"eiPPX:4ۚth$(fae@ x`P -㜄H@@c ͘-AñOX8aV&9A<\dp msrS@݂@#t7Æ]Ǐ@ d=di0JUNa;^"O,p،IVM0y `D~ȌL+s6J% FzZ<HVcGKX1Kى_>k ^5wI -,>m BCcd`+l4_a H=\2~~�u &lA}PLǑX@ӡ@,e|z,0~ ʓc(\/aѢa R' - -+襻twNAh8|xzSxZX90sg $0$Id7C20g�~Yzg -3�[ĵuxGZ4U�#ݧ+gHykFH &~_A/*YɄh-h!8SV)Jp6 !sTpq(FB - 6= JJ1i߳`8HU� -#~t0\U*h)́رB$+|y"Ub Đ(~a|28%0L1Qm vy0Fe,7%bDRy#%LH" Áa?w04W @ϑ.spAwAL�I$9]E ؾ9&FPh @5 C^ Wc~1a-QtEo/LѦu^H -+~wЃiOHt1r1>4}h]ؤoZ#CNR 'ZP #Q,C9"md^~)#K,&aRO$6ElX6+3fm#ci+W,wک�MT|%f�ީ#Rjz @,0N!Bb:n( KqR9+L2's2-"1Qv_�#,] |8| - SBpK'/]P&z d5.S1' $h:(T`xyֶGN4(u(pƝ2Qu(FYrf Tdך·Ca� y7"FTe -VF!r:|EڪD*OyGf0=In FL!'UgiP5ބeAPaCThQUTiLx[WʌNc-7_e)*%0j0`$WD <W*Lpqs<sG̋<4;ޅ@F0.UF H7&=ͥ*RUF7'{U3.Z&<z)$U# X(0k"%oPS:Eޘ%- @WE %[$%% -@:{T\ϸ4.LaLC/tqA@c[KPN}'P 5-RY֓+'&*a'^v>z\IࠟvͺdXR0 -ii -wXJxIg2痦;R7~f=zqY|`jT-pLrjc,[ @hu{2d:+SYıJ -qCu9G'╢*ClyP(X)OSӐge$*_i $%Jxfƻ42K:НL#\O^v98(N-v$6J52\nQªC,lL�4%1y_WJA` 7V}2~ށj5 GrRnjOT6*3Yaσ9/ |%>'78@]gnneC@a!cq=~5婼}bG�AK9^vf?2!3B"}e$ B m<xaLl[hF8R|0 9Pt#P5+ҿ˔6 �veB9{la&@=MUfg -SmJqpJ SvtCycF^ @NE2`yPsiP[5|Bl|B -}F.O8LwH-SG/8ZHd*d;PYT=_vdC^H4e;тKP>z7:1FvgR2߉Xюo Niؑk [l+)Pl% G\}yM׶ /]SB>^#S.7\7MI(" }rFn&Ցd'`q0<zG(_0^�06be*C,C -FCƁ~&a5Zi`Űa SdB`n? j<z(#Y̞ qPn#͘$|z<1޵*EU0E`t`*1T bG1,>bVC=?yfBteNV;&J"+'V$ 訊!6a[ )j@2wXf ޥʒ -ĥ5f7u'Igԁ*xa -S2߲ҕSraUBoQ=8^V J28nIӐJL䬕v n -* B;^[-u!0@mOSYIt-u-H�ўe8muԚ LIJƈ>\5yUA04+.q;k 9͝nܷg8΁m�xU#0gХK2*мj3Uw*:k�;o-jߑ߫{;MaϚKT?A@ ]cGѹ"% :;qU ~I?ocG'^})Lv-dg-"x %D/VwL`rGZ:dۙ8C! ] (<#$(mhN$҆V(9<)1\`idɆ7U(YNY/w6۩_'7&r6P5=JiW]؝:1GnI΢;y_h&j$+B IԀ&UCzS<Q}7`_ꟽ٩J~7|s?Uo3%8UXl02憔emIvaKCPb_m3ؼ|yg(La^f95|j<-krL0% «{7`0 זtxv>\H00y!gZ~2_r^"mB>s`Uϧs˒fVUah�hv`SֳZe` rFOH-1 43!Wȩ|fd]-dG0+s0 'J|pima e-<XQ(\Šu銱:9m&eLGr -%)D/83_Lds.|ő=NQ,f8)2Zz"Dd%V1+lK͔kzR&1p{=>X1T/Kf2֏ K2JF+<&a'$b(e} 2w߾!}/3Y1{r%Tamm553pș+D]~ӕ̥,n-4o?dt1[}G'μ17ICª(`O`'yx%yFEH?ǁc/k퉳5u?M충>EIR5Y\SzO%:GVfLLZ|k]0<Lj7V*2Ȩ-X7׶.ۋ% VaکW^I9j�XH:f)6b`}Ey7yv5Č,[7{F"cllwCl΍ɪdo7;�k29CYn5t0,.u蝱4:p ;p -5o%Em nxwӺVw&͒nvX4 k ȝBMOYy5LX7z±B:{j2;;seffM{#BAiB0;Libau$̸HsJn2-.)k4U*�_ do]Ajiy< i 4yòHANIf˿%BX6ww?\G/Cg')<mnx-[dE+Fr8#"z(mIYf>'X)SLyFqW%Q%*/E8 # sIdSe,Un)n6�j|N^lz< �R\wz*z5tw/ḮLjrV3:UEYaFyb>I#F/醫tgf7dRYyRX�4/G1L{sήu͟X$1 bZ>ϊHC(s=◊v)+GVquaۏujZsywɷˏ4T.("8u_~?.خ_~y;oztt}թ||?ߟ}/ @vL.Ã_,¸zjmZ2"V&Q/Jb] >_ۂ~~iGϳ킕_\e|Q&:؏k<; NniGu̵I57MιV6' -8J὎:Nqݴ~3~evmx;u…oB|xӅ׍צߑ7 t+o.̛6c;ť׆~\ޕ{pk`νi{c9>#:&|mv]} 6wkck#V7h$=6Ľ6ơ JP@~Wǿ~/~O~48^I#sR ="5U`y5b,1rSeCkpHALMl� ٸ˃A$Imh64cʳa"V0)*Yok f֍-"U6L [`w}-MmlVƈ fz0ٵ AzmDM~<-8MzJ-\a?6Eb ,Bv>3 s{7-N*rU2`"jj%ŵ< ,2P0\HAv#NlouerOk>,lVniF%a,:,XuP Dj!Xwq0D@aht͒z*5ibka+]K7+Im #mg@ -"C!V_dmTt{,W Cqr,3Y[dc?|~#V.#,/JUc>eƊ^,XLplŲq,*; WPKrATd -wuf@V]^Y X<\*}(,B 3JicL~J'T$k̥ b=;°Kgv^9֒JKzP W]*Nx�8 .Qǖ+:GIs=B,U 'V& {^h/M5}}  *Al6irSLU#1i%tAzƪ^T/Kj,NZ6Bǖٛ4t ՗ -k . 0@iRyEok RNjX*Uu-=gOh8>:YD` / v1HϬmSl-NJB"'7Ѥf[;bc>SpUu9[}_[?ըH>88m{�TcW^gy{f)Ea=ԝgϛԊh+*Ff5Αc;@x7k>7\[3PſX jUm3Ai{y,-}%Z3nR1QYt  U,kh)(I]0R/I>+1c(}?r %ҕ#QWm܏e+XЭp{w3I⭉>f)Złlܬ})6,{ 諭rfNzq?Is 퍠˖#yY=yQSpw"}j͞ycc�Q @0lfQE#U0v:f% Ko9\}zYGv:hűep(ey% @ߙ -Ӓ,ksFu~wӨ\覷**}l3fgĦy; -b% 7ib8̼< XKZ_= Eo+y"=m~1`{0(c0)=,],B'xِS(xaz@M98cbkTi&n[t籙mE24[ڸ7^yl`Ǟ<2[:;B}1q2T3Χ|&|Hz 棞Bo 窟nO8,O7su1"oh(%ch0P,ifClz^li.+)ƂBc9j;㝔#XIb-Ef[LhKsb yDT[B%V'RXOc|1V&];dc2Ra`ӛQ;Z|!ְ+ZBrWg%f[duIRCXF \< 'g4#[>|Nd֋ef<s[O"*Rds-+HYJ_J"Z|by sD7XRl2069K^h>cVXq @E=0%'jȆ۰t�qEaS;[3 TX/9v+j#v#1PVֳ/W T -;W(<BlUVuM8 -Sb[4Jvn u~,\!Kh7X z\|t`ר5, -jY*e94 -̛8Hc**obi;qMQ 83V&Y͏A5m:t-dbT7`sQZ uo]݉3<0”!3<Q=N=0͢RQFG~dviܵ>#{9v՜/v=J[6Dz]zGԴG=5{n)!P<{cl|4]yzY)e/avzp8c)"mL$ˊ)&OnuQPq]=zN8/}V+0+L,p{w`wPի~@eSwq!N^୴,J@Gf�ƶ^c.-p*-ֲtbM"o7$v6̢CM`%`jeN[-g]v�tzpU'WuVYguWҿ T(WLlMl@{,.Z=:@OǪ3l23FQ]wl@{ͱl!5�P'[v{G gIx]$0NQ+EQu-nf4"bWآvWhvFO,]w:pW�]vT(�Qge7x.Yldi�3 -l);qoTk()HsvۅJUkҜO-+W�r 4qri !Ⱦ& -*`~=Mn?nݑnwx}~`tl`1-0qӗx7հ&BbbU F6ij4z۝�v/{H|D0QTa4ZTZ젔=ig;[ڹQ0O.Rh:1*g; vb)PzI-VX(]k4Z-c:`yΞnpgxeupIf]tі[bjhh¼pZȷ٩męK?vV,1:nٻ]}D_XK~\LK󺌊.{QadhuIWێPՔ&ęI =Bd7ofh+`wXмtJq%u|e鶪ҷaRb8/ &QRb3츺l - -c@!{!>J{0Lʢ&c<n]jĉE=ccuY. g\a*~%6y瓜HQn�mȄ9YGB,EZci4d| %> ( a@(8`F_�WiXE0dw)S20CʥrH| /s0P05;J/ Ȓ$1 cv,F ,.�_N4=p\[;D`dCEB a4k k{|GL⺸,v *9zŜ1՚q'ffБeR(d߭%jMlV2a2jtg0q73Sqj9S<˜#'ya)S -}ųga` )r l+ef7t0\槳ݳufJI@Qbd -<bvatVI!M?~I'<baa&<pRE02BgV44<@x- ׇ%qjHld/\y0o&bnNB Pv0ҞO%maYV#S[/ byИ\.Mt¼ 5sttvSŊ14&+MVY'!Cd$g[kVd^$DIKCTmdZm0~IS3 |@ pPphF>%u0:0Qݒ);Wޡt  1*2Ɏ,a5: 0(iCvSKI/a sPۓQVԁ{4u+R}tr3hUt7 - K5* ?˦u!E&dz|6+*4?M΁)D=2^x?߶i4(Bbp+Нw+;gn8JN|=z=X75%r쌴A--TjLڛՅvN5npDT£ߘ*:*цRF[`[c[04_XdG b5|9vQ4E}[wvUXA5vOb+u(Xɝ81%u04Q%i?:] I×9vҰHJݾ&1jѰfP &0փ`lO&$'e֨ez1a4Z^!YjcM-Pn4Z D|Uݸsr,c=KWc<=XN8~2bVjrxo淃(xUIج˩=X!^N$Xkiق$ - ,Vs&Q 5DFae*ml50 @ԂN71|`}b&fcu<F7M8-Ռ*Џi{:[g/8X”0!W*E6`^)0$kCߣ0n݄z36AW]M,HݻC^1/BTo>*:}R{I3UwSiLˆaԪg bÎqJI%ZqŦ-^oC̜o~ӷry ߷Aq&2IQSw2?p*qsq FϿ?@թېTRb2 7#^#FeKHˑX&3/21o|% 4%:3V0w q(Z1A6cfS(ńj0 ^LwAZ4-jl-vE֌cIF,⢵5 fMq$Av4Y^n!#dYb?8aѺ +k0}w1[ǰ|0#\KBdS 3}1K&@bv*4X ׄ.u^l3]1uUq9hl-g0\y##2h|3`r.f!YGْBaW<,ubMgp9_4-`, !^WٰϡL3PV>\.+$όx3E4& }`:Đ7p.h\\ĽJ?~(يӠq{3:Tz+amG_O.-KG\'Ю:H2g%fؠ f]8\F9'[b`Ðc!}xkPl~@BZ/n3{zsbl&K@oLl[wnNlrՋ$O,tYuw[eF6r.ݒĠr ‰=G q+$ -ow_/ !W?tteZa|/.YJN -ő{-Wᶮu[1?07HJFkHTƒrǷbV -YsSfzzA`h"k38 X\"K=ecpOŷ--bY$hPC젯d!EZMPcY% xSb@&X¼<}θEmPRߎLcv5cv^H :}w7!YRg<D -!NÄYƫP 9+[' Ro$%I$=(Ƥ9 -v3@#<q;x\ gZލ`m,3{b{ΝVv¥1;LC'FA%܂ې[OzlC l5_v‡N&[Ӳ(g2<c <Yk忩K ۙԙENs_X6Җ~3y>aZ=l@sdMmg J%i>HŏC߮*}<_7N%3 5t- $L(L vF*@̫Io&OcϔK73; Ō9e9rN}NSbxϮ.N"+[+|}$pQABl -#Xz|YXp`(ٶ3v[yμ٦ك.'o>yχ7B55b|ÛE+?|7Eiomߴ_QS`)x5!Ca^kpQЯw F1nZk`.$=Fxꜷ©~T KW߾.?ውp=&ȟ]SlEa5d10,lkl406T` )|^7ũ _nxPF*h>gҢ,w#V%@P4FYvQԁX- _[u9z[m 2a6N/7qa*3&oՁfkhm-0Gb.r;i1s<PYo ta׸tΒl �}Ic ?}.ɕ4'@:;WGYXr~ahSjR+)jO{ ͢"3%bՁ$Fa,-gTe U,-к8G[__y}$Ce0'Y_"2k2>HYe+\p," |.Z ?+a`˺ -,AA(c?K%e b|b zb L:KSql"~51PS�À^k+S-`́Vs-p<˰g<~'$ 2Mg}gsͻ\MBd{5]$OI,ODR^ -"ZkWB0z|م黩Fn >m>i8:l\wDӆc ;Yi+?5p`C$>_7sH؆z?qjuBPO,4 -Au3׊#1n./^�Ðc*3.DH()֜Đ>G׺`u)]mIeXlȬgKfJU^ f&`ق'KhPP%YȒcwd -z�{ -/0={s_4?w,JJ6٫00@tl#,"4)r&S>,,lX+L,<e᧗Ϲ(*` Tγˆ* sv' B:2ٜXYoX81:P~P A(:3E -UكoEHu0' O#Y{ȁY2H<Eӈ\q((4_Y>r%"u׻djRE{4nHCS!F$Eby@3Z-ΧQ8'Ԓ|ReS~NI4Z>o) OI$K0}ccu1PlGdvKfpM20s` Ic,@y^X~-c4h" hΌ&@0sٱL3/!J,Ɔ"% ^B}�]ՆbYU;kԖH&�I8gf3KtKq8Pmz 5; d ba6UrtFo>JFv3WV..NyFD' &Z聁L'F6%yޱD,<x"fa(ë x3RpU ."[d`g`l&JY82#!1n7ng:)mRB9IhƸxT�IJU+ln;8!9vdcR6!/]$9a|7X _|-yj|ǿS+w;UMj L^g9:DFUK#Wte۠ F'Zw,H9Ч7BY=b֪;qRTsmR)vE`KYiY"oOC0MǰSB]sf\>8tQӁ9bPխO궥u`Y[i=dX~ 1ʺ`01G,?r �H9bT0f\8kiǶ{l lM -R^;X F<j6 jڮOvfuQꏢ[i=dX֋?#t0)4_ bi FC QOVK JKgRĎuwM{41WAgF)Jf)b7"k[3Q;:>xX~1pd>IqsĴ7X{IbYIb -5=~$ڮ~͎^M:%}we)}`Z/Y43dF+bYo,W;XuW=)퀴۽xh=\ݢ,{ Z6uUKP.# -$7xQ*Ȉ<wSkr9H-fB@�?: Ô0T?Gqd).$:}xi(މ`@γ%_vЛ?FZ$Ν>1zD\7>2:,n .e72 >كUyv@*B2C#2sc<L{ -`Ԇ<솇�LN{c-A|8 Ŵe,e43gƥ#Wl}:E7C/B >Y h@[Gs Ȼn7^pBKSbWl*S[ оh`Z ~hCgg4KCmc<]{lqIwmkB4r>2M0:Cڔ["PQeϵ*sj6uT߯ŠƑ1&!Z& $ -w$& }̸p -9&i<;&e= b6CGr |QbmP+HNM[<V}#s9(6_!>ㅊ8) }SuCm1N~6X֖spZ?:ذc@"N1c~uE JTa*P|кLRc�R$O0b4mRN܀/Y r@ 'jV-NF9u_y=dSԯa*m3!>jSԳ>0'2y5aN=q['?UÜz(-̩Q s:^5In:$9 Әz8orWaNVI - s=œF's3"##3aN4 BijߝVN&ׄ.¡c6YT A �v�;�(wz2`QCzj&*i*G "<|G)(�pm7ueR�N|2a62E -oи<~8<D#rCidXLJ:;^" \1@.0s Pvz XC�u[tEmf:{ vn÷�)3m= N׊kn0R$+g^/1.XHn]{]@VPfv_~۹4jW�nq}dBN#JUtmrx °9lqms5)nA8Yv`ދwN͋噈`7<`zlMEN|0:'Kg 6мl0s٠̔)>9fcjXMF -GdxpzhM&6*Xge -h3ٱ1)cԷ:ߑaz]<m�ok{h`xj'0UX=#xvC5LR#KN ٖUSn:#ڍ!gR1>9NkYg|G:!ϫ -6Mo6f P/nIȣ?9kPKzUZmb<bz>8CM[hl0,~V`j::˿}Tܓ@B/zhd" ̲)"!h%Zj{d+0:)֠&e954R"v#}st^ωEJ yhYXċ -t}AFNTt!.I존~F-4x]wH82jh$$M?*1'옄k538C#{ -Q@}̸T44q96jһ |ٯԼE~롴W[[ChAo[~v3cx&2*̝ -G:gM@lo>°�G\ A/zV.i s,-g.oQ'M@=)fazE#!bns%Y1Y& 8tt)+'9%j0*@Y{i?pbߘquTne~D,-w+L;ws�nxPnY0p> <燁Og0mM -*tI eŰh`G -Ũb^`& ^3^Crdjۻ3%43q \ӣA -G\ [}ɝ!L:2FH#@$7l_~ʕכ'(Xc[  !F<0FZqa.'i*+8mqh\L)BI|(1˟9kdy䭑^t᛹)! 9;@S%8e*fQ h-o?wV̪!g6Uq/P R^{T 1{ @/7BhH�Ps젝>)i3a_ގ@ ?SdnTB*. ؼx6!6r7ե"Xq<c&LDB2ʦǪ uoC2Ft@5\p$&iD+ -7*%W>rz40l+lfSq0Iٲm�aI/+@xINB KdpÂ;Sb -A#j $dBb# RBNcg#v�%o}�`G:4AW04p -q^pͦ楬`OR7sPR3B aj0 ,w/t -�%?�bųa$7^DA͕yM.'#Gby]^r�p 8 e`qҥP8>a -w=u<13#:=542L+t51zM݁*%S+y.=Dz\AЦ+ @)wa -�drrz 2]mK9 j+-pSɸgY`Isd m†/tzv,zCH.-a5Bt<RJ`e-ؗ+o)nb$U7 mJ(!z2XKB|R]ۊW-^ %|VDgd7Xzb%-D;0D 8=P#8 >@vU�h̵A$V@DkX<NC`+\!0:cDA -y:r,9RHqa!ϧQafE#{37JqӀx%ɴi3 ɭ.EsX `X>MGL#?Xc u"QPAmr㝳H-Ô+`@|Vj1ĩPX=_4{ @`- $Ϙ%٦Yq3lU~5[?)K @>=<)#HNH׋s`@B JŁ d;Bcq*!vP#͛,\�\S_}Hi9@!C'Ԇ[bd Օl ~"dq`lnV;6`�az� WD&j(-~4wz 7]3Ɋ<NCN[* -9+^Ö96 ;D CKNU -,f!2"4=F:4Š 1"_yH#ͩ8(N`q3XV֒qTS^ؐ@SQyfq)MĞ8o n*�ᣛi)A)q5XmmJ}R( 9pqlhIi-<<@=m/8Zg{:ox_gs쌆w1Rd0 um0.pFV@`1HJqr/γUK ;<5DG:&3G€H;Ûn'`FD.WƼ0°ۃ/t4</b@`XEvŠU:Hh =-M 2Y⪣`�, GvaǾ\б\.*^iKa|`DNFHiި!З-f_y:r핸u$!*c<:q/:t E -SSXoېif.);x@9uVTpU‚mgӈaނi@4` hUi)48ab= ܅׷\ع!?͛7^?| -AB8n5c2t$-vʜpԕoˈlya -2/UjL&ZeL; |_yOq~~=|XLd>rn{Bm'ql{!k%5m6=oh$ 5GD+A{~ -GRMRQ1fYqAAs #Wƶtኄ<�2b%HBX]L ;-f@Y9|50yUa/fT.J,Nz <nIU*Xߖo44zJNT]E"a |C?o -}v@y Tr]Mhi]+VUwd>-u^٤{(]uЎj`$fVa<9/ص2#P>wŰR;ar<J8(Nr8sk|%8Y&XWm*)ǟBhnc(>|{%q{կ}ݸwDn7σcciM34: &ZV2|f7m ?b(Of E7+i(K2Jm&U֓;'MS47 ۂ;xp\-nEMLc`uBM&RP$ XdT LЃCDj֞N @:[ U|v9:SVsPt='ΒlF\m^)*4.rk0ab[&!qwSa,aԜ5 (h i;*I,ˆ}Kn$ΜV'ZH~)Ҥ:kc `CuvU-?0 Aیsn\fS%-tT۾}P<n.&fG"URRv6o E_e8/IG|A ?{nWź] ad{Dՠ!`hз<׸I<U]~" #+ gssA6S I'RH*%' - # -hj߰p8A {F?HF`hX'\ެصEN͊+4fk܃1}+%GLç 30܃bQR&0vv*~*<G,R_7m.Ԁb.<ήI]`$8G8L&O#WgW砯;^u)$@ -nc^ Y9ï kI,[m,h"]0M)g: ZrW3X`F٥(tt0e -X�>/l -vSzPg_(!|[l EAa^2%m J_Z%|.V3|B QJ)]c){K `8. a[! kQ{<bVImAp/\- +pH&s̿pSuGͮ* J=Ġ\n63C$P G%(zwRKo$@.>\ЯR긾B2k( <>_|{NDrN|4` lrf*}71B -PHS.ԝZF_3!◷YRU0` ZE]`�d.D s!3 d>1ٹԼ\31[5O/BDYgzM9pUXlcx(Mî a=gxsqUf5 .ɒeuL~\4 pU%ipZ[1&.I `:vc-}{flِM'2ET:M|a0Lއ&J^a\6OfbA,gJ-婷p7#PO$BӘ$5+o c9FN7+䭘'r5TxUB!Li;i}#Ͻ#E+ .Y띘v)@ ,\w:%F-7?/N6 Pbq O( sad0|YRPP.PXIb4 M`& J&{sY<՝4m$^*V e0[Y S,}AmibcAO [fU ܙ6^N2".W1Rzf,\ J4YdV,XRCިF>a.O)UL2AZs*++e´IL1d?MeJҦ,Ǟkс4IH:Iְi$)GH95!Jh²4K8P9L_ql͎ ,vnjr:lTdR[<=(�\}d73kyR3a,ގw&<r<*p0j943 ӘϵOrAQLkk(mjRQ$^Mt%g~$' -h('zjè(9 -Ot[ڬFg{ˬzr'MX ,k9v_yq p| QaOS.LZp3T!Rw岊QbyÃ2%~{%:ΈyuYO( HY҄W7捚l;pWܱRL?xmbz\ "]XyOY3JÜpT9qFtlŇecFL;ͳ|*r:n)5Mid[RLNc>0YŲ{w%+᫄ -Fۊ `+.& - -!ɵQb4iӡDJڇXqc0'<æ]f{yOz! 띈F2U9B{z`"<[cq<f]Z6BWD`lv)t'0m%[y3@m"`Hf9KC۫CPyƔlHyÀtA@19#鑇gH_RJh0-8V$P]!Pd` \<9Kf*;WGH%Ӥ Ud2<%VP+$'FE8VɊ!-q̶<yC ^4$6&yT@6 -%$(X~Uw/HLƴ|} ƅF(7|< 0/Rs< ^J>4LEk#/c -d~d)zK@FўP w#*)"a&ŋ/WG:/g9WaT#-<BqzEch5/b -Ba -j\.?-IsvL:]J4WtTc>q1SXĔXH1gb,Rh>i.z01TLO6̀4&W'X5̡|^(/4,{"5@VwIȠҊ*5ITͱ1 gͯ1K']a&IМ4fMhriј3͡qںg(43xWnWʰ\tĘbDW +P`|PTōAQ)ȧ|uLG0+A) fԴ?t]}Zsh04 -~ ]Nz_,{ƣYqY� bh1p 1:\d^fi9sSr]{x.F;~XZ=?-- -?՞7~TfӢXZ秪XAmcQ]y&ݱACyb݋nh9)>xv &ƱAm2�mH㻞fOrٓj[9+yHݶbm=E*B DX)R7 (R5[R1۟E#b+ۗUw ݸmˍuŮM.:'~ѭ+fQ#QXPXX2Oi4jzWi|ꚁ5Sf`mt&I/f`͗L3GU4Oj< kfC5ɤd5YU3?xA3&1Tjʿ]5 "'4NͦŰfS|I+xR/4jVU4jy&j֜&jV4ugSu*S(VWJXyg(QLy:ԕzܽ'k߭kS N>Mlh19󷲘"+ܴq'aJW-& 1: \]c^f1IGSdMSb7-ւ$n1V"W-Vo[L@ݲgu S&tbb ,&@N,&Vla1I$(^~-E/&~5ngn/r^7%I~^Ǿe/I4xi/Ii躽2M^dҷ%Kj/ij#c&sd4{i^Z^OkS쥙4{i%s{i&I_/f/͗Lzn/w~'ޡKҬM'SZyǷI0h$bkiT*έYnj,5ki -DójYKYK3YK4YKYKw觏h'֒\֒tn-)UQ2Og2xXKB׭4CLyS([˻/忕DyZ%A\4|:$hs4yQ̜{ݰ�e-r֒$3n-=Mk Zꖵyݰx47%Mk7%@nYK>kݘnXKܲ|7%`n[KzZ䖵֒嶵qnXKwZb[#n[K2 ^dҷ%֒[Kj-i*1+(ZG}>5ki ZZIZ zW狡YK%Ӭ[Ktw(ă4kie2siTf^-ki 4ZZ$չnh3MZEf-Ͳ|I#ixR-4kiVS4kiw&ki֚&kiV4ktg-u*S%T׭%[֒QYLy:Zn-asoYK3D'Դ)t|Z:-4eV63g>RTnRRȒQX[H8m %m4&r7ZFnpi]} K`^tGO] -Ye:H9߶|Aj=SvTP>)>~-ֱa:cqf¦x+m?폘qeΰ/ -&)=,3Nl-FgecD[!㝴M2*ګe2m>f\Zm1&AC -�ɳ^]�iM{4hje>7O $nXbZ#=fW?5L -ӛ -q0 'W}(6chi-nq/51?ܗ<݆B4#2?tl3`e4l<& `虡hM5l³/ nH %V  -\Cw1+'hX깚?YY'lő؍@JdŽ�9l"L>]"8[@KBc:ǢV]IrP/AMhR7 xRH N"d =6sq*ޤZ;L`C[1 HKΔ0֕6Z > T߈e.LJ&kJR 8\蚙`'0sHQ3MKQy;aԑ!n}pv ʛ̉v`1X+Eg*saO ;=4=fӐw!Kd&|{~As~0 vv靜Sx.9 [+%!$[ϖ. 7xN9H0ô- tvTE t#4;;]ls`σ ;; yrNa)[<yEб&|)m0!V vz#R?iz90m!UAY+vm^Z~ L0eU⬫BώpęHOY6X)5+Ȫ vE+KkHI!H@Jʡ0D*,/Z6QmTNY/w\tTpJu*T1Fj/196vaŮ myp+deex쮺l[I�_.Q/] u@ZB ̱L>PkG/+Ce]W"X"vmH 4Fls}d_b SHNI#HbQa*}[vY.GG[B(݃tD̬e 8 b9Z<hKg_`l#``8 _vb99F\ShYdwվ� {nIo0z]�qv`qwf* 䬜cCa - .ɦBjtHV`iʷX(Ls|v=e>3cX$osN'^D`mC.+c\WL_�+,y.cG+JG+ȾW}\`ȝd�_Gqucd`Ya/vV6<Peݯ(0䕻ra}Rd~3މ{"8v~wz__/,N22qٕeⵏex2l`Xؗ1yReDkJ#dcdsqsde/{6`uCĘmBx;UUHla4Bhl}owHJhPe,|5Z\a٫TJd[ -QqVd:E vYvNmsXa+?r譁16iq[;l9@nO}i=&>#57Hs/ZoܪfK.0J\a&cC^s6UF 97-ܺRw  54_;r~q�Mwp-_1~J( b&FNi|ϜR$6wgB&ƞut¯8bÇ{.ԑ[h QcSss!M .'\⎉Wq?E{SroNNruA/7_7 low27.[p;f -<PR9;EAX.o 83v3a^;;> NZRN~hl?#|/K,`G(oTY絷f=�Y]Z<z ) !ס>q�;>}l.ıB ENcjҸV4AI55mW:P0ֲfӢn-rr=`C$˯a::PqX}jX~jsT lޱW4YqI^Y0dx[^Ovu +As -34-v|a\- =1| k]f֬V9IqXm`'WAV6 1O>Z6O{�[De ~X oj>JcMۼ<$̺nF1||I*PΟ@C?zWXG(-l$\:X~_N%-HQ\1`";+q&z) $20a@L49دN%-zPF5AV NRsag2?6 u0(E\xbu&$]V7/.buw3Bpѓi/lM2 ژu`'~g9eYf#%nb?nk-rfFWqUcՇl&!I m̶y MLt΁m^a -KnWȜb[$u`S u(ucwU W%?asPb/;e?C/'6Sr35S<83K`=A!(v$G?%D)>]ܔsMbϨ𜤟,QgKO%ͩ^m8}ؤU -$Ȏ1W%WŰ`FaE&a#<k3Ї;aRKڭe&G#l[=l~tZk}鞕KBNU}Cmʯ~&x9$75J +gm&e7:a^ݮ t%EoMjFM@31@0xD"'-ouufrƴ48jQ_  sy3܁}%pҩՙ /Ζ0jeL|^8w1zT%.5кwg<x%VX"5ö€n7]$wلUEwWþ7Ins&DNe5yPcϳ1̚OT;N>&>#a>+|WIϷjԊӰ5, i/<_,$g[`]S3לͽ=Uo 8:h[Tl7GzN|)sa*aW)* x-a'RjB-c-/i\`v3c?.Ԙ`Bdl0 fЛr4ό]<3, 9:<2 _ZGpFm+/ HLd&}& -ˮf5Vs~ ЖNV`xd)D\q`Z>7 uI1%b,8R:6ԲXu|h ή3[#v|&=t}g%94|cf2H@V[Eϊͪ| D -c� - >K>댑lM0OgJneFЂbxgՍU }I+DdިMiS`X-%(*:*Md`^`2 ZF:{L0,JJ*lLHҷs;B Wz*xjLLbFهfp -~P-16`L$&ٓ2c ZUB@ J0r՟0$jeZ<u4>Y9]gـu!y"/ lJ8/զ4lHL17V(J| d_dBKsw`C7BѴd*Fd 4PزeBRw<fޱrcWax;tnfl{4g'bO!|7K f5d."_<||7ofX=|50pe7y}cJC+AG܇<8 -pCN,9n 0ܽ^ ܽvg}ՙ+?Vzc7G_0@B (q IjHIߔ>N`UZh]g m~G?t-pns] 8ܻŃww+>>l~s_ @ܿ_w⽃+a ->N $n#^>h@$nr现ݻDn'513}O=Þ -X<G?W}7=o6RJ=lU 3&H%K؞9[WxXű¿ЊpVc=1yP-|</݈=nq/*=D '%O_ )7eS’B A2?67 r|n7'[*Oɫ)JWzYc/')<.lLZ3D^" - d%XLU $XXK`_07Mh( A3zhb1M< N} /K"E"Ob<Bs,[=t UjhR6ZD2d%BLۙgϙ%VtԻWmn!d}V? u.Vzr -B"׌}v=-~PP1@mWlyY!Z1|D1/6$Tȶ!"|Ak0q+2kd9_gLʣ<9δ6Vd4lKߵ $,šjeȩ~<AQ}V\گuty$N gD0VpXln )| ce[%8(h%31*Ad\)x!hzy eX.BOK~\2$|iyFN.ujTt"=]xW"|VHAIBO6$=V$bmcUEݨx(D@^Xͧkxyaa뽄_+ә0`J# =%h;,d2U]ڈiÍ{|ijeF) 'N%@UF�>\ēx‰ۉ}! ߃fjUa0~ZꇬT=ͣ h+>[7ӭu&pa~7-ȗ UmZ0leoITɗ5j!upP+T6=g0M5vqKA�iWoiLD"6ƵN-)V ̪ҷ:lZA w-tluPa+ӯ{Y,Wgoqɝ.Z_&̠<ݴG- g9} W˧^-slU-cav&)⛝ -3[4G #?fǧP%\XZGS+ .HFVg+WàJ j|^6M !lLB}#Е!rl2-B )mo[BUTR)7Ya010[r+ m0:0()X5&YAtۭ(pvv %cN[V(tzglT Q,}z+I3PCC$$;-z5$!K"%c uh?ObuR:,YQK1ɖ^ ,pl&@J M- e[*O`oCHY]?U z?ߣ0s?Pit/T')h7$!3&ㆻ^Hrlz՝iGuP U%NRXȞ8JY-KaW\?~l`:J_bF) S -t$f -AIUW)18) ̓ ;[gG9_V XS{NoN*ȂSazg -K>Fi[_pPx a:@K4(k]̓ S=YŸ-'PwoG6z'L: g1z3Ly;agg1GuESW1̓ ;[ULO] S7z'l�ĵ -۟Uq�9NoN(VBKEZ\v<uLa<Ha^|!KbsJnǧeF0ر9S*e-j >K0 sLk4]tDS,`JNm ƴ#"RLɳ?\uSÔ^.411 %Ic$^lIYXTy`J,�0He/Եv,vLaR&جeEcf朂aR#2]3O0}@AjaDbFXT@`y1(na%SB -f_cz:+DrX@�hOϦi:aᤲrVdFxK{8+2%S+_8 pT4SY!$qqEVXfz25VZʌ (&eFt -+n1-%fXXȲa9 HoXxxmʘS_:>c_1C :&=KTuv>fW'+)@ =`|#Cunl3%%lYxz -z2U6 uh/ sȊI1ݍPI<J s>/D˛`/.BgX- $9VgmoE\$8ZIodD0� - -q\  +2f&0 Fw&JI2$ d+ Z K ͔`)EBq{!ٶ\r!dVHnB@,d3>X:% z4e-,o>uf_ZSH.2QRA^)ـ$B׳e8^?ĔqeJz^TBU*)ya"A|ao?`3)FL'K5XaJKG %:5$& -zV< MM]%ޔY+o܌/sUGgZGgjh΃ ;GB&K&1=^V4}3a0M=n4}(V.Gd.Bɩ4�"x[&QPvژ&F jW{DzܢMd-.["lĮOPaZ  $-ZgN*1~ X,ژwTX ^|qMAйH=1uyg0 x -C$>`c2EraM> źnަ.dP` 0N7GaKOj`01Z�D=lKM2H2(1S0; -c5؎,I*;ۿGbR)54rq[yzKawvϧNYQjznnÿAPyY�Oj6/*Xq)/aPLm{-A,a ZnӧBxƎvBg z+CXro'D0C F"eb]VߕDPovM NlnLͬ=i%=u0/qraZUh^kMV:K!,4N-[N;pR(1%  -Svm}T&@cr"̫%}(K$L-S VLT[۴,,)lP#w0sYꁖR LwMƭڢgE9[+9d!;|8>(6BRe;BKDUv)fbߛ`2-_@ێ,fޤQyL3$ GF3-|*B0</Gvu'>Y=A]_QbHG|0Ǖ sX374ݔU] L@PQ8zS' e84E0Ezde)MRD7fL>UG{<oVA8 ,]vRxbAcJ|@{?zTQ0*1y@xT{ 7/asdO?zzݛo2jq7_}[o˽ ,MSM'| .E4AЋlCPn7.FŽ&lm?s~BA4yU:lvN2@eiNG铇lC\qkܤ.Yp<3Rţ.RY9D-Ytk{>t%|8Y]f+qD_TQ>oܓY`K{}:Ҳ?,ŽːPBd3{M`{Hw@W0u[k'c\ -4*^NQu2BmpԴʶҿ2ǔ艑!{8D2 UN2+:=d0 #RX*@<O=*O-҉Lujnœ, l�~�ԜuL7BCWOVGpyaWw2, -9WGQ[Abs5 -bG_l6!G_CcYp,Dv hYcd1A؃Dx809d#m x6G_T;: -kp,J˼9ת݈b &aG|&n+ӬeHS = U4cc`g PxxO-k 0?ѝ7B͞Ye&@"_3<S(x1xlaAg߇r_<˜e8BEA>cT2PT`jZP[@ ;!ޱ'hYeesܚtUL 1MŀJoNX.�Xpr,-eO8pX>љj30232mU|=4֡(DzV `K}ΰ5aO{ )ψe%ܷg*-"0\UTiu(FfU7ٰNed{n/O+!],odO TuDf6" -@ JYOd\[8 zr0 $4t=*\ڊ-cI^Xza<ˮPfuLln(\HQ#sNv‡t0T*4H2%j=9\K> 8(_4fCИda2'Ћ euSK5GmJ}Fc* E^(PGƥ&)(r(T9[̈DLMPDtǦ[\]c+.T/Y09 ֜Yxζ':) { cs.7+ lDP+(1,hZE^UГLݓ:$HלD-k^C[aƇ;G3 F5%D`Ib#B8Tbg&>ulLXJG1Fg mPm3!4Iid-0B*I N LqVVndy,S{ED`A0TK1q -fDtzLv1~/O[ͦzEtC}_uXބ:C̟Zf3gJ/dDT/El@8# -ld56~= ^VS5VkjA=';/q SA,0>/Ed:T^˛2`k�T(R%meJ+M;HSz1 -QJ{fEV`zO `ՉMÊk j0Žca_X͝*X_vOu{] Xf�ez/,q {jt/0&bw(<ӆdth3*8M6tP&3>1?AdHlyiм -5X' %uDjՙddǑ4Ț.DgX!xHf;h5vq`uf'C2]"\;d.ǜV7raY|XԮ?*~{.,ؼQG`d(Ch3@*r+>Bc&2WY-X#1%ەV7 UUJ*Ϯꨐ'6K.Y,0m=-d E<971AٗƒqL]$rHP3ը]=n]e)GGȱ$*: -X|6;^leY,ЭX _=q۽"Rf/qg*/wkݗfȵ"3{,lR!L\j4f/8M9K^o~ɢ0H`u/ʄJLP/O3qv-2\o5SVv|gv|wևY+$rXDa~Mz_.7"|_\i�LTq=@5Hbue8*"j. _jue_rw}-v1T efMKUKw!VuZ&rJBE9◵|˾a}^9n{q,@!BQKaǭ8ʕfGԣb?V]>2by2?ಝT+AJ@#lE`tuIoƯ ,6/o%:;Z*g�@d뮘 `]9`eˍ fֆ_SZLWbC˸G]+@Rm*t[OojCbC⦌>_'+g?)�Hɋ~SYJNsNԙVAԾ~\38q|9p=6|yG㲇=;8)z'nm:?n~")o5�{BH ʾ!x85i7]8l+9uwY!}#1< #盛Onai㵯W U<Tj"Vp%Bb]@HYCN^F֥2¡A z+5an#,[@^}6 -?VIMv=ag�e_^^#˾aa�(ȗ½e3rN[,n+fkw8 ;.\_ܦkf+50V~|ݽWv9gK >B%9A wwe!J 1݌q7gQ1ϱay=%Jjۚ GƽQ8T IJ>ld-W,EjX3y۹> -UO�w=/ M^u m;& xmNV\/_~lcἨ~\f^_R&(לU4"+cBd SfwXV> KےE[9@\VtRyG՚ -12*3qrc<';Y#ꪳ4kӗyGrLIݾ*DCk<9o]Oe?q6 ^�(}D+ ml uHJlxl$+SRQ:{߆5"ԕ3Aj][*c m bۚj5u:YxV2zy) :E5s -q-S+0iu(ܩa5k މZ& &Q�u VKJwjj<Q#KmE3@˗P[-D;V+էqvV+ՃڳjG<Q2M' .;)o -*)(]`_.y4_| ;CX"6pl0_7>()Y7fg\D޺uw$i"7Q?5 RMCp@U&(qR#-+:LJ\q~WKo#A4E\7TWsOj~nI꼾 Fiܛq51Ћ �DB:{"Q 6uգG0X5+vF5x : pDd0PSkLluN^/ǘ /o:_퐏 5<Y?֖xZ, XXx\"# "Y9!5ObY_ feO,ǥ*Y]r?<KǭV~Xk⃺^EQg[1h|&~ovMm`?`g4|cxA'8*U~ ?vMm`3ka'ۤ8f>]]uA}̾y\|ǧyKqdz]xvW<+gwų]xvW<+gw7gwų]xvW<+gwų]xvW<+?wi}/)?,?>?^FèJa=N{=&"Y(\WY)Qg^:i0̏E\T@1z@큝E(y;=ww6XrF@;GSZ,nh .Gpo#ۖn^ȚYU>=!C ,˖кLb" -RcfȰ>ڄ[|XqNK(%N[Y.͟zSybevSիo#7*~OoDa+L`_}ֲE^+fGxa/wo~}]:.gvmx oR˖NFve\ue"\{:lvFP0Y� 1~p Җ&\('6hӄg sDYeiO{=ơ/Cnefcf(6<GactFQګ[>(틅+;)W?UuV(#䌣(< 2,픣'V{8f%lƥqrQO{=ơ=s %rY-;@p?33r%!rrQOl@vQZPCVڄZ<AgҭrQO{=ơ=s%ݡ#OygvR&\ 4}m*{_b;RFٽS>5*e>#bXKYGs壾,Jbcr,OM;=O֡=%KIg<!Kvwh:XO?,|/_zٮ>DlG)i<lcX=7{ޮY3|jtF3#˅٫zߥ3z)?5i>i发ԚvhϜ'/N1hp@y1%×X -grS#c3upEνyKKD<R33hi2NIَ)vޓݡ:9ۉ1!h`.&Z* vqE.[ˮ{ S1u 8MA,AsSQ) -S+ ͐am(=zL}P&Â#$Y[M4jyB7i_O< 2ld|9;?]]z{,|هB.Ϡ8Zk\ w^c*)�kAy#d Ņ7 HTֵb ڎ;\K 6A_8uҎeiM;=֡=Nu1#(l;\/G Ц${eRdWs"^ŵi]YA䌡(< 2픡HN\3p=WJϬi[:PS2}hy6홡| %nGtGT)?鎖ﭥ)JbO)??52eBdX?Yz|&uF gEԴnۓ3Oyz"O˙jI L\NjRc‘n@]CRf3A<=/q˞Lj΍3n|jyBGt8ʙWCTYNܳac9i, Y>=<qK{rQ>5r eBdX)j˨.Vh,돨k! h] :gN_C{f@eyݚ0 !Z˱ UI;vՍ h2Sw'4A1V3ڤ2F:s g HԴnۏ.?$oRkWE}W m7F?s皥5Kk>,}Y\fs皥5Kk>,}Y\f߼f鯿_훯?|=:~볡߾iRVԞ<]T#9C1H -ЌI21у z=]gN%K:OqL(vͩd`Zأfk$[g*jNދSc_).n<ߦͱ]e a KRF :+j;Z SGw+~mzw|7_iuzͯpIO'wG~^o3}? -ͧyXo%l)T }sAReqظϝz¡hB+[$x&4y#*f;NB?} #H~ZsʰڸsX=svTm֚e ~P\#I4umd蘋=ME&<8Y }_r=bb;6`L_2xz#qPa1h<S?\%'zvm"׫4r;X/l+HC|4sGУJĵLQO/�.dMT̪! /X<˞B{H9/H;KnT Ž9dcau'~IuDžFW{Aǃu/sz5 Ȋ{eעۈLE"Qc؍{/Ni7Xe;CDtƆ8 - %}cY`I{�v"'@;hd:!+hV]+"+.- -DhqM8^bҨ_ْlϗ(soz76o"bi ʑyP>o -aq =@} f{Y?|IVQ9NWH [L杨mq)]eQb~߉pA#D9sޑq?{?`G7v8s -rSk9@}HSE\՛1.{1S)A} -ۈ_pct?IgM!P?caiO.?]4};#$OʃOC0J>d@H?B2RV;eǟ^ĝ\6, Iif*Dʰi`UmG<#6R;e4^;Ge2e'E 1 f +iCjZ*$n\iq'J.Lon܈�ٞmq; 5D6VM47<l8.>Xånb8=i:H>]m -N\jUJ5+x}ԛu ,-&QnӸ; HW/N-ȇ o; `ǜأD~q?X{ď8!999999a,7lzS&G@ :@ORR 㟝F*}x=(5Ʈ} o?g)q#4 -S}g8zznDž{(@/@EؠV^5C)! Lf;B^r,H^0W_V(1lFĸ6d3m@y\cX!  mQ#DvGttnQ]R`+@^}OZv{gvH#d`u�*G-2 -AC*JZ>]jnt-ɝƖ b"vh2h1dB3*][=$A5 bXQĘ f.ʴ`2o97F)cB>c|Y>. wҖYcIpat~& /Q?fmX`7 |*"LJ4V 7ȁĒº|g #3>E /,eDQ߰`bV9ۄM?vh؜abY7@p!5s䈲YoPAfSpu=u i1yF0P|dYAZA$Rba }:ݥ KL0Pb�; MAqFka@$m61hM$1qp%@M -Ux Æ[Hp>ҺkGN-, 2tF'\7fGf 7}ʹ(qЫ"?6 hߠ5f#X{o/ɰvKVM)~qo}+s-2#67 {$c}͛YWw;hYe m>? ^QV029`ZxM#aOY,D@%rt CKQΐ�+ڇOq0 y#w*Xl|,wt]ӭϐODǝacz❔'e0!,1*;n&H2F774Rp@"o4nw:nɞ/#2?度UGyㆂJY5 [@PVA _ -0.B[n7osb?~&_^rSv LG~)CC!]tz/><B@\W5/KS5XAXąF8hU;jLrX>_#3̫pˇ~J;̥PqeiܦлḻCZ"uWAtytAlJ(8_-!/& 0B8D#3 s?.ӬVa4>$ALIcwWFK4R{[#]. 0|h*|cȇ[PlNn.VK-S~hq>d үT`0(u(g@͒3?Cidz>k yYd`#Y`N+fȍ3$ƭʄY"DF`yQ}Wh50adcm6V>چb ]dg˝g(C|@ʌ!D6 -cZDЪnx#QP0taWb{�aur2iye$\@CE(^.1"@g|?7y9>`ڤaCqMچh4i`jB\V@ft٤$1!ME@U!b?VޢpJ!j3C  'c#NC^o� 5tFk bb.&�Vdgܐ4Dű r[q\XKZ>r‚p :jL -HAv!=˃ 1͓&׃hp+wvs("6V郼(ӍM hLX&KPȆj֩!pقԛhbd.pCiر^*\ii^2n*YmnTuZ -;/> @NNBO4ixa_wFj?U7b[.N}DU:4pF{*v;! āSJU 5@FEŋ NXA~u&*TcB'r[zRGDwSaԇK٨^fbʙ%|p]d^mD6=WIzS|yL"C))ا27d!| -CqS;YCFa> 8;4O[v+f[@e09z#|C$!b45炫h,(5aAkH</((T Bڅy(qL`95vE4@2А!+GzĞY(|z*I2_f7`DC>(WW(6JhPd\OS418sȢAQ@uZ@ jTf+! -k�̭v g)視crT CP_YkpԜ I> - \q^; }0:ȃa1sLdRTy6<ܡE|8ާ4.|>RFUP%1zI&VPGK�}<* w~)?]j oVR,d-;߮ۻ@s;%ʫaG-1*1Úhʠ5Tp&oa}51Ӯ@[aii`ey;V֬|q Ә.={7גE[ۦS[a a@K&rk_LE5JBkBN�G5Cj9- l~] -p\m \HGm72(ĖȻĩeӖЖc -1#%j ?צ?gHVܑam/ǟy-t8`İ䂎c5/jMV4/;99Վr*-ZrSK6_>o ~_%}ބcT;q34/vE;$Ǟ~M�8Q7oq߯K9맊ӌ&JXlqZ.1lnI) ׅ E]TV{({CٲDJ1\2lX8TŹ]D,*6g\Auأ}='rRn8ӝy;[aKq8Tv8ܜwW\O*8wt+nTyU[\)04u֊θ״ƕ#\-s`k -d!]"5ȨG*# ; tQj')v>V)Wj,e>nyж]. =SjWtM ڦ74Nt:glY4,CB-4/}MKۜc]<tu-�yeHC(�>ږ[$1n^e`XJj�[(U�04җQ8 -H>1d:u6ѻTI(6I6&Sem[w:&03�I|}%0(,aGy"-,cA_Mx.6,GlE3>jI_4 liLf”☬N=FxW$6e};:%s¼vJV`dºvBJ%&iz|Jo'o\_ӛrʝ?O:%3r5sQC}DX< 䭞0<p nR/ƛgi n3@C)çl~@?}CC[yLj8 7m|eO+!|{XsӅN(o {|ϘuoenY 9S,|ïLAqUf+%,*DŽJXhFI .s n <ߖp:f -D\z}ӉQ3Dρ]|S`: &*$3v,`w”A'7q^o^~#b|ۯ7|j7_}[o35%$ks.'|Hd'x|6!8ĺyHM<]{M kжٿߟ9elDA\wɼ*[{fn ;XVCш'j s_3_)\Sn*PS %AO-C sJ#= 'gi kEe��K T̅ !>DI woaT,kThxAr~/1@orfsFEC9")R@GaX_1 ŃbwqǤGi1 *]6 jBx4}!ZE\ L؟ȼ [6 >wj1\,e:1xh -LM2`H.L�4x<w` -58.EWc.0llYj~<֚18zs59a -0&m12\գSA09#SC9[,ҋ -Ӥd6ƱĄd&>D&dSK/&J9K{S)=[ڱ& y"`J #?daz%ck+ǚ<1D>|,؈O1)sVBlB jMh @QЏ1Xch IKX3b" ؈i+i�cp` K saxL 80v^/r�v tv|M8Jq\۬0IdFsyۼ�cs), n2"nD{_܂p*̴gq<VA9ݘ\M$s0\&e,!SV/6XSh5^cH -arqT zeL/ 뼗aueX+`Z`~쀹Fjj{{6Z]HLd "ؼF L:W00Q$˼i;\ҧ4eDf,a<&Ll -/(F.33\/mLʌHOYAeVrc!5`hM"M _vR-aF}`rE$g#Mie=8b#iqm'H_.z!uKwRD^ęVXJV!IԩΔJdX.HJ6XND3= He3'"l2l!Hѥ}M -v`"5 hkTCf[0@&ڏdZ Isͩ2|:  -Uj0|a6y: $]{hJwU^aJ/s Sfgrj!|g9Ș/K.F4 5B_#b?Y``,D-Qq -mϴ S% TH 2'af 7$23ܢ$ 9 �RfΩ+FpLs7L}s@ES[uNGGuzTV;66D/-06mxKVvR,TIݪ9zK+}{"2 -ar[+aYoIZ^0ӗ[de�)KHħ0K~RdgLOeVVrNS]HS5`D1Ke2=ɲT"`Cv(s -jR5e=s[D[H�kz=Q;Y0؝?XcMq`>gfI΍G} lL4kn`DrM1QQqٴKUz^ЏQX djFh/[U=0Mcއ҆ :2fxl_L;/s 3 -e~2ͽ,QWRXfԽyG/I6QTY�1B|;6'7Ha=^7?ůlo|O`o?~|g/CXwfϳW?9 ҐF]۟ӾVoeϿ_~xwk70ubA[c),5wYr ;Woq>ae}iWf!Ww?/ m ]/&22G$bͰ!e jG Z_`T -#އF<Mc18t Aˁt:V**:ձ*π(Q%^KbqK1,đ f{JG�)z%S:& {�2K(taeVΖ(m0̤y)ù|c>G, L]ҌV׆al-Dc2%veTmu 7nqõ)<; X1%2"(>:ĚF??1,} ]ZoO$ZFmſ+~̘2/kƾŸYY<сYkaI |Y==3)l՞YL1j0R9jyJfZ]3Lޱp{4 V1XV7aƍ>5<g!,SgX>A#">HET{N3{ZVZ 콼3V45sDKP4(w`I8>gnryRAQ=|=ey‡RdRY -Z"BQJ9*\j CN+w -3GB]WY-2>П 7$ux&֓Z<CD ۝5]}wq7N<J1igkuYBQȉG<b]4i߭1 T-R,)ҳ-|mv),SX\?rw”Ao^H5;vW'Fy/<�E3?zi=>Osc6 'R?.S<.X4 Ï -c b@`LPl#Q1&V>#t[1hS}=y󬡏b9VڀҼ*mfj CfT1mVbkT$8ve*yy9 /3C+P ̳QoaLMDc1Gt lYL-LR|Y$pvf526؎AǓh^B�qH!85j=3[j Lo`-lWkͷy!o[,k -CԭFAۛU4ceqrlX6ezz{|(EkKJ7 + 0 ud T$e-aPfZ{\`&#`İEaTK8Z՚hn.]/b yB(qlA)0vI2$C/=A2v{dd윓Iofi6'>݌Һ8X .UWlTXC[X�Zlb9LƂGVXc#t7s*ȦOj"f'16kQenF@NV9Ifvru1`ɱv,u$DUe ?ѳ69EP@Xԝc}s'yϺz@L?y\4X'ŮN5X{);ޡD&vgāNT!:C߽3诖eVi\ Mi:CnT X *s){3r:l 'I:f1>&bjŌygHdA.g(;7'v Ά/%?GI3BKrSY~MsV}<Uu"0_sוiN`ςVI`ߦ06\p q0$Cʲ 58M%w6NaVvL -{hL[ Ǫ!D"0ՠJsT>Dta|2[@k EvPu߇$ AtEco˓$;@(#勪0|e*])Q=s[=Ic/L.YkmLѰCck_k`]'}R\҃zZ=UٙW -K~ aSAϹĪE(&R_K;Syn/tfl>[=5= wS|j!]RӄM!ɥP|º:$Pm6`5հ#(>yhT)*sN˱ ;\tKnYl!X)6Yn5EEih33Ca -aCD?-H@C DŅCPeV;E+ꮧ -]ڪahʌXΟFGt(&.6Q4.{-Kn"CB=;ű4ol(XsX7ӛ/]m E27j6gROТs?Sm|G&]e+w,8B~J;T<Ȳ |1b;+T v[ij8^4q$Ia ,YJ~\0ffMy&<%O#2#}#v7-yAb98Kshʥ IJT9s-1(G@aB6Ǣb;íʂ@W: K&F&̫lǘ^![++yɋ$Ҭ "gKΌeb5%{ f\X ӈ2;;QZ{ BoZfL>;bcJ'b)CcU 'i b Ln~PɃ<mER{׎$J+chTg;%[{-٘J+4+oڐlZ3ٮ,ob>@XSĵp4aͭ(-d^l Z =Y<5hCo y~wMjTwYrX˲\ERm~یtR -k yϥ2#N3b#mɢ[qNo!ArA텤C -b.{M �P!gXΎ~'MNppo." +fۧ*W}Z!2$˔t'bw"R\%2)Fe6EByq -n yC_  À* 01j\H„#M`m&Sc~/۲-Lϰ5gS5ka=&o584!1WSd -m;c-<v N`x yGAz4C<Ts8q,d B \K*S^``e]ʄ#u,l߿`ܱaG?S$&0woo 1BG̃M(3JjDu&,~L�qZyv7b-<l7pu׎p@!o/c6Ž85)h-mCgAcDN81uKLv<񱮯 -}%&dt~ ,\NG7)"GK/d!#DcQl #K/Fj ^'*=Qц]& ՞9K*{Y G`ogL1{-"uN~!U:D8Q˰}o9@ �ŧ -~PբA+>_,jŲ>Kt<Iee)ؿ0] ? UA^�|#>Ku2(PY7@ݕO9 *|" xMu9D0{IY%6FQ mO671?TexIӅպ- -` -j?=5nm&d -:5AQC&}9-,3bGN$BނP((('iYeF{ 1=\w -PG%U]I~I#XaR>ԉ'"-<Q#JPʴMHW7aX|[ hg\ Lz%8ej�[kcï-ӼabL'b Z 9f@b%%Lp;T-ܾ\ܙ);h_z/QW,@|<7kL*roj,>m<ƿHu,&JАN:YvZ$ -<˭ڊ5M$ r޷NqAYdxׂBڂ"Li)`6ɃôQ3rŝ^L݋zZ"f+o72D[.MuR3~f47fiFXU&J}և/"EhoM2% 7O!)7+iJm+1_ѝs,,l@1-=O)'3*Z̾_".W<:"dDVu&c'S|-[lh"ph^K@k1XўE4!G�=S b~yB[0A[1D '+!a˓"6%6\]" O=( T;TA<*ޗyAW -JUurq9H[#oNfUj[+e{B'fÆ^LCQ><Z@NچP,T혲սV 08ҒB?M_^[T;D"q/2A47( b EnX0!4&RL4Y&n1(_.)rh.ZFnPCf|9: V[ܩTbv9H[{v0Y̆ WXU$δJ�[[++bOy&&5vO_^ՙ,jSv}*u$Y'k(?, ,2mr@B=?YvRe{BVUbą(_+0(o']®/W1h5>k[hst09X٘wokێȢYB95&$M!c{ߊ0Na)h۟@(Bsj^,!nqR79yL1! O } "D~?;B1{Mw̹dתq -.478ȴ5q:J0 ?B}t7)wSν(�]S:$Yj'8=T(8tMaRdƊ?[D5>Lj6cg&s[zdB0T~Xdt voIYdCkL2]NzKSn˪v6m4;2'.eJQ4jQ@U+L;hwX)~!#"j!0o-\⽲D\.#{vڦFG,]G϶tb�e '+f {)jAj[ܑH]oC玪9^],+t8&/bbM g.Ş_ 901[p")?%#>#23i -ߤ3V-܅@f2.za1,z1AŽ![r|D�H`Ilnɴ)f Oӳ9}S+T& <K1x^ǧ*a_le 'N"9/n[k{}H%YX[X+Qo/ -bo}ZȄVD"ÙY^=}ež I8i(N_Hhz; {e(Tt1Z0u~FgHSx%´uJ}ĎS`2 _m=($ |_Fe &.;M6-LQ%; {g`rvVh4QvػO-pt8 ufKt 'V?` s -WA;wxрb2H@|,-#Mf8#b?Ypv[oNZ:IP@�זRAR['}[|@,`:a{qniwh}~E$PBL jpQ޸W5 -'fe8[$BiLmL9~ֻ}?B9-<s9+ ǭ`1OS7&~/veXVr1{qxHPH x9vކ݉:Cdav�kGp1(dUoUm$OkӑF-XE|D.X~1(H -3Tti@?CP4?|<K+Ob&_XEk+`G, -A&I-ԟ`ESD{[E%PNEXh䀑%kF ]tNH/ELu+,�"hз]Eu W2TZ&^XouNY^>teykQW < -uIiCcslE((.5p`DM6oM6nТԪ:e!bb5*F@n/"U/\�4 |pAFӢ iS~"㾆-=E6 #윥4fۿ3M#oU ʜiN~! ԙq藷B+4gb -2<]eYJ0iR+EW�ȡQiu_<>̓qaߘ!Vt˪\~zսr4T\MC\ - ʂ]~`A?g^&k OL>%X VgT!LiEx/uY)1$q<9;u&f.P~ XYw`1;υWYvD^.8֧o{;T67iÊHܵWPG7Q+NbF'Dx>{GekЧ nv(ӏ_;"ԾxE4y<tĚ-gA[ʽ�:fN;]bA:tw]#VnED3\= O4?~u,~W!$IЈ|ڄPC3<~?g@itUauP[^Ua(>\8dmŧz32(JMv 1*Gyr8,D ̊X,in R047hZ?9jxAB.@7lP'DrL+NsTy�(eӤ�@:4?)إA3IX%�%F[B~J[AlUhUNc׼$:QKeQ!BqExA(wB-e[ 04_&'pE$j?:uH^^k42Fh _~:_B,J!Oi 7TRk z7cllY<,mQ(R m3x<Zr]n 5w!_fWhSI vtU#^GSK<uZI7&l jAޯZCiuiʄFZ":3ߑXdZÓx-*&$?Zeǁ`w9++(Y@Z֜ :LӴ4STg;X+[Da^[Iq+ h'sxfT!LOf%9] C8'bfvr[  1Q܃6]-9O a%|8u�DQ́XG 2Ȁ #SZLHIq)Hܘt?(!<%X"I[]'QV*/K@Up㕉k1 SAbd'ǾX"G�֌DQvӴKa\8dj֣\uBա^.q\dEK J.�?P%.̞aQVD4GuNHF,AGgM&&6(1=LI m,+ 4ۂR \Tu'xlP1Q$Lh"1is-'VˢjЇ!m\, eo.$ Z 9éi_Ÿ{;�>]V+{KSN7cP8Ivd/:f9+$pUP ~~ed\|#Kh_nm-$ɾ^ vݪd^ZMxr4,šɄp"S)S NXxd*_ЖEtį{e&vIFr1CՅ* ,Y;~&b]I.1Ꮆmscx,S{?KF8 vzj>( rDJ(!\lE>6%5hP*0"TAϽ EFB%WM߫Ca[n_4"NUُoxow5}a`p Mn3g\V$0Evk3d5*-v':U$UϋuFԣn^~cL?J$L?ý]{jL'[1%+2>b uvv@bzw ɬB%n3w9B_[QcD+6<T�At =AdmxZP, .Tj7NX@iFR{|*֗ ?)ZR�\,AJ{`҄7}&d,"bxǍj<Rp-Xս/":f ,8t;@6F:JvgB?*h#L8ȭ!qG? -QZ_Ä#) -njɛŬEv_f DnyܥiIMhY0wNx۝۹B`NEÔzdX>b %bJ+]A`p:u,$lg *ˢ7c7iFɈ v{ vXq/@u+rp`dڇdHCX!H#RH آ'rI0Сm8fclQP%۴xdhpDr;vP3"2GRU0 Z9Ӆ]m4w < @$n9{LE -)k-Opqy'd�,b -}'7QF&aZC,{Dls_: ~ġ1yM&sۏ[PJ0YQ,X-<r8h�PbvJ▶*'z~-E(Azu;Gly`K=XvWE_U c)P-bIiSFT(g 0,sYf)9! 9H6N-yr[(kԦ4FE٤ .fG̐(RCvRhq. iR.FT.IӨzoǖ\1P_|Ǥ]ɤPa"v:ۭu8^D1,bJȊFWVD%ůFBHZƔ<]ziK7F6Sc'k@3{%V$ (NH,,z?f-3^L -:%A\+5ug;iMPo&dq6YG[ 2hoD6v8h~`NH((SMq's1KVW"7@êr#5M 'mJ׶MbF}m]nR*앱vbV !p2"LF[9韚_^4=^p%*5{ƒ"'F̖sW| 5O 38#7 -1iJG:h 1ᇪ -:]55vǵpP Y<f-c'适~pAY@jTZu-: -0PP'M2f^MSy}܊mO~2,p(##Y&DŒ/OOGy+ڕǜv3! ;rp!o-�L{Ղ<6#kcy3ZcfJZ5KMѴ;GlӨ_1x -0F0g:PA-wԫ'$`+zt1&F�Wj&4ٗ2싉̀ɟލ$m c~D!Gq*.qr2G],%FküS)"&ps)tPӶٻw8\ӂ9ĭT0HypDNn6|l[oӾˀ7W/Y�y#C;vI -xL=w=}[u(!s)!ոeY54ad�.ʗͥht0k\B -,l] Vt ۑw58P@-Ϋ0IՖx 1 Isr!I͟eŕbT,uh'r3;lZP&@Q,TmJm ԅp0-U`1_ <H^1LtPm^ʵ(1(>6mjd|:Xdv05]ѣn4{vQ6u3\t[q` *XJ�SAmS`ءVI+fKj_RIajFcR.G I!Mek#s;ʚphIƹS?퀦^6] Rׯ+[=pp2R<CHOVD@?-ХGo:ΫmwlŃّ&Dn<9l!tn(g<+2lD`O/'N@ 8`g~OEsTbާ2s!l_N{d^71{a1' gy"<QQ/1 9dqb_B<SfzyR 2ȭWj=t`|&C\_V4᫔ʢTWXxʥ qM -t]0$2fa/ʧeM#1KJҙјE͈u+ -t<%/>&s|s*d` -n̞V(l-Nnycq .vJ=ۍُcRm2wJ<%? 3fS�pg<Eޗ#uC5S>>0?v|VȎ\O aXJ$'DEY~)HcP?XX ?4ڡ7+Wbg ->!rG 7Y^l*%:hA~d(y MLa"I<}n+i~ݞ&2ZR\[u1"h$˄W8kbde?#-,#&Ϣ6@'s#ɞ@4,L+zB!-X[4'"G}f!I[o~"˝;"zsy\,30Ж7PPP(7? PqCv^%zg#q@^gы[fIk936 I3@D+6DX=dR<`nyGm.f7c 1.rA8[l]$}w&ԤE Q>ʹBOT*wB<BUڀ$ѩY~l"_TtKNkW sqpno+ JǽNmҷ|) 6%+x4X$Y[p5GMJK苢ca$zoi - - A:5#=<>4 }ɠ³Zδh՘qǾX0q+ߪ̓-uףʋMAEȜ|3�Vh `dxu]a f6BDkzw,q":WvwW)YܩC MI[.;0>} ^?"%wAl4a6$-fH&a&[`ٵV+շ"OR% qhm)y5[aCYV t}e`hU*xQ --f >(‡0I!qzHmlwWƒ%8|̨l^3'5\1^D#7wIਦg)XLE1>Of*JruI�&zFeD02O=^<GDH-QrAcRԏm_}'*EEݰr�L$JxH kci2CڗnP͸vF嘇_SZl,{5,Zx&Qm_t(™;} FuZzWcke#:Mȶ!}Js ( Zl9#yIh$ĆIQI'gjC7FM& ^_BHzG^dǥyfEưȲ-? -35I3 w@3`3^0dˆ 9w6ÇϸݛY) @B`I]2:/E6C|ks:0DL|r%1 o -҆Y^%,\q<NC -ajd#j -p�2L{|g Qy:*W?`<Eiwv̦*g-@"3C8EޑH=9&x,dc;Ôrl3uSWrJ3& ZbN&s26@i2+^@0"".7[t$f1uD 7$$ ķYcj)1(\ ULs;CMPH!/e+=l,g&[٧~ت`]�%iR,;%8tMǠ?N"v!2�(6Y`Đ_+Jf2^r}0'B4j�6U6TU'YP :}Z2F@['RʚyI"āޥV寜®Eob󱠨l| re�h@Q)v -^;0j4�”?֓"2M(P̴Slq784 P,�ܬWD]ShKi=A96K\^;cAQEssx EE� V}֑K-&Hv-[L_x8KU˴YCYX96MeʜvO.O=Tu`\e#rԪ 2 vcB{k~xn2~^e\;~Py5 8߉5 )!OmЃY_TclH0O,北*Py ng%e4N7 ny�r_Gm -Zal>g݋LJKI)6YpGT*f6@{+-"$3Xs08�[@ A˔TX,Ӡ%6^SZzT.764dDԏl�ِ3RfbE6ԙQN["T - CǶ-uOU.; -p/b)t2Y|qMEߩc㧠cxjFbmw Mj ;'&/ϚO�HU1K%xc"N*BJ|P~F1Eؒ1{t,gi47tk4Ϣx[|6+bP;سÉVzX5�E5. -|imMY=8}Kcj" =5>ha6P#t:ފ,*u͚S:u%f^zJP{sf[St8U�^nI -UЮ1QGH(GP,!!{ ~ֆ$d8l!gx7Cy[,?^(S5p bPW -^S9sq.2~d:rLu^c+2PQ(,ܣ +* -M<99 -L|?e) ?Tq4 &grQ= *8ǥb9vi6)vͦ}Iw^Gzyܷxl;Rǰ8K0qRa3 ITpqC*&sabp}[�\AQI@!J15�ln� *2h'hn`K2 )$)*Tqc؊8=dk؎kv30(brsw2LChT،R^YTM"8J+3?`$p|�e/ Xߐs I7lPBc90 Х&DC,V+35/:1�;GՓBpQӀ] -5m| bB=(X�puLU昇 -2ն Kh>$bp) +Jt]HZ@@턿0 -Jk99q}mk$c0cl $"D㏓1C[vo.C3} Q ʷq̘|j|m8T4#oP؞l�ݻD\tjs4p |77_iHZ:X`N̄"Ѫ'6!Tal2cPߞm惠o6H>`H[O+�t a'HiZ sg?ei;Q -endstream endobj 103 0 obj <</Length 51383>>stream -<ŽukPci2 sS?lB8>+?Θ.S9p?*vX\_ 0T5Xz턧^~L� -V (!?ݭPg ڟ|3m q3$}L^I|a55nYY"UˌQK(绱řoXb)K1zXѐbRUuUABYpŒLF:|vOVxss2&(hBi*[x%F5Nޚ0||B_$&2�tLI< QڥFB'9q0yR)߀X@^EhX$mM臏cFKz|8#?IY{@|cw42*�\0ǖڠ.DW .Vu!J1y3GTU:'[b!$fR VDWҖ= W-n>9DQFA6`uN^ e}&AǪ<[_de@/#UJ !ŋ|݌1q; F3JO6C6h &1VxLwQgD|(\E9`+CQ*S:&A@xkuN%jo/u]ޥy*cpCQeW6DuSϟi=;LԪF_Ϡ; =RN Ai.^E%DH5jj0lp̬u=()P$gCZA\ [>-,Qg](J`Y$Dt=.԰ZH*}2sRoѕr D9yQI>?"L*xe*  -va"Գ2<`-d~;=u('فZTRd36^2<Cx<h+C;xKBvǢ@LX A^دWQzPf 4vȹxĎ1>[v_MȅxƠTyxu3L1K|RhT]0Dw|ʮ=͵xKteKj)8#4q.o|2 E; 0+|Ue>�B�R@)l.6DA5{N+ 5m5H0chjO*96b a876 :Q|lܝ!(~4DZ@"? :Tt&F.P96.q7QU+1z}/C&J˶SόfouFR`Κ�|H4 ,d/) 8! <Af~�`F UDQ!Ip[̄hJVCZ;τE3 +{D[q�C[_YgQuɐHl,Z"k ^ KAmwYOyDx 31B%΢VIvP # -˻#0- 8Z4\I%FK@ JhD\$Q_DեbrcG :pWiu=1*�8?'<; "T45 0KU\J%T1gU"!ug9OP>T'c(~,5@‚ -|2Jq1LV-g Ht"Wibb:�+nQnBoQæ1>TM+x0P~Al$R=6.Lxlj,'PDeyp t1I:() '0jd{@:(n&T}%LcOWn&~YNԣfCF_*}צJ©q zZz5P *t ۉ<,n+6Vd Fe0*5l:-&gòp iY&JzRY @#xyĽeKEc4U`N:Yi_! 8Jh@^_wTh�A*!(\T[޵Γm”�7"<䬶 "i`nK^6T=D�,,=DL1D5Esb qz;vf5HVJ\rD$@G SQ"RPp>:doL+D !hHL藥"?h~@(D -rcubcMM }7LppCX~(\S\c_2;2&́%J -#a<BթK dCnc\.Q/JjN3 ({Dp5')w v)f[PfV_Q0~/tyܤQ#0^ڳ*Mv lTZ3*Vcj8V sb CQj >U1Cpi+-  ^+:s=%WAMٞdXJha{Tp-(pʱT,+c#*B~ %4ʂ=bVJ qK)ڜRހ5A66y ;g~(SJSd'DO c=Ù\'wa#,PfL=)7cy:E RCi0B> $ |IT\hM7\'ZK.Ls%*$elZAmI/΄@qxBe1$e_^9VܞQcnnqsJ{ 7: H̼6JI/j -fhC5*YwtE)#P)TMn ep ЅC0U>uf7]+JBp'շj m"B$uMut-[ueᡠ-6B`W2/ ZFBaΨ%wiz蕆k 7�j"ETPчM('Px;_/h� Z)7a wHt{t"KMeBChF_:@H(!A,/ב>WiMhR$+1zqH-FpjR&ށULO$j9jvþƞW0̶ $/L%{ri�KX눌V -R3Cc]G'Óq 0ؽC<Q`<`nQ@U4u[̊QD35%Q@R.1Nk9+L5o}:zh6X#l>V%@.'re4L"X"X'Y῜G�KYl@ h3� 7_%l4z -D(aOӬ+HbZ|v⣯hcm+{;)M-2Q!I 9@|uW}@WJw6I"<巗j%Mm[M(?dIeP!lpt:Dc' ZrN=O2O\[ $C9mx -7Ee F-m)Dh.y7mW<B8liV!u1-8\J3D™�AXY' .^nJ -ŤfN|#' -]0iQ ͝D҅?=P-fjZTgC߽Gמf9c d/ Fd" "SB]s+hdP?c!ѹ]ee[iu("xR�`Ԇ)�0n RΑY M`J)jp;q|wٛ4]Hb` (1 +-u:У"[@jAtbHp))B -9,)D1(݌04ơ|mdx>#c¯0c8z, iӔ^AvCP`c6$$P5 cw:iCJΝԒWݯrDX٢d#c4Ťr1PE~Kq| -ql{*ɭÀ -\KL2]50D(�s䰵Y/h# 5 ؙfaJ^ -Ca%-oQqMmD_45(J̵I!>/f)>iE60B(:,oaOp ۥ^tHOcy[0`+(MP>TےJ;Oj|ɽ$7.)n{3A'^(HԘAYAXv3H*C^, ;y$A"wQ!gj:ġQ{6dA~{'f/ A"[(i0i.'5{- J ٱ9)D aΤNo:l{ -QY. C�d-br}+WCǞzjqD|>�h7!x]O.zF 6m5W`$?pf\ԁfh&*C>C ch=ՎP;C �<mq `n: H,0@b -1�$I3!B�W&[貭/)Z4 |A28gLiɕqdb;(7Ŏ12T(DMԁl2"�sd lXL巺6PB�*P�NJ 'ZFX1?o h-DKui sLMpo[8h sb\ f"/P¡%v-[롇b *HW9j -zp�Mv֪ك!z(!ilMﺀ; -І-E6/p"b)d8gg>4\LPODʄ1I'Ňpw8+@}b2e{H߭I(g}4"c&_vw_K >‹L_:p@;Ij$fB/,6"zO#j8\ʹB(A G3'z S&0?p?J,h/F<Lf >i& 1GPk./m/"bpxGx&gVU2DK ϣ )`X8'*[L(f +Mq#po,G< vUC;,EQ G�;{2Bm3a'X@tzT^ 5ġw \Eixps0߬qؘ5ԀtxǤggBd0|F(TD&5e q 0W͚jxxX‡=g]ö"mq ltq'7 ٦A “CKp"~,G2t\Z < p'ByZA�tL.I3nHbAOq̭Ùh)unq-.(K}\Bi46umf'\<MĜ""mȂR i 9%J F95س=ˬ(NO؝/RL 4^!upTIg0Ą|RJU7: - ACd^4(s|qx ;8aMjO}(ͧ!vyNʪH !?INX@DM(@^͊'Y%L0=jp]]S-( RnLսT~wV?ªi~r@MD䜾@y3E)| Ok)ۥ.r諔@?WdmA@uD/V u_289B$BKVăjzĭj4BT˂R2=3Rqi{A$4CRn29PދcTú[Q̗̞]TX|HPaB Eef5PQ y 4>2GA0jD!A36$2+(.WS$.p,S>'ԝ N8bqڰ]?KEHN1 .tf$_MW$Rs<{-@9{<fH4:ߴd)pDI D^Pއ jp p0Hǂ3N0%ۏTh - #91e1aQWy�d~`7`)sU3~9\.k@al<_N"j4["M^ -{{w ȡ�xl-H0D;-C -,<O#*SM""%G/3U8�+DM# &\4K5VK^׽cc8چ :B::CSZE+ɔ#/G&6G >|}ArgN)Gn_{Jq/^Umy_痕?~<�dMД Aq _VDkH>/$tzFt)zѶBϸGҼQ=?KA8P -% - )<cKYvuccYC Fzf4W(ES))9bb<! bNT%phNԎWآVa:�b̉Hv eU�ҸQnc^9yV3صS?Ch 'E0_4a HGDc͎+7Y=7H5pDP:Y-{fX L`I"k4A2IZ[cǺW d(.{18)7-\Jo4IqjtחJ{TRjR+nB-JK`VX*֞|> џ,-9 78�dJ X$[ͱ{."rs/@S[;b -FhT>~\bk.{CUǤfL&,�ԼlK)],滪0z%;ݵ%*f,bMQ> 26 ]pXVabR2+5ZЏυ�CG|ꗛIrۊB*1q5VS48HugHyg9|tHp-PiW]A NQPT"0DJvzIQʌ,4,]ۛ�@iiHKXClQq/֔>[;`HA}*,eH{4fSb|]ƒ#D`" oB#k-IP2UYxs|n;OLKah5kح}fpnP #ֺ7/ݑ�QR/"-n4.QAeu <:{l}RaK;.,ob"{Et+u7Vf]:DsL̫mx}H/a",6 g�ħ^|k[aaϒx14ZXQB{-O<! c(2?w `sDFxƤ$:K�GuD _" t3Tf8�${eG6̦"d_EIRr-5А"yRoL N@Lx=wyo)hzNۀIdBf!)9/*5 - >xS%WؠaY! "tb"L�-,9ȏ p&A2KnqᨄKgCevH;'&H T{?[Q_b,+zh ė NIGJV�`jKʹRc yjUCmtYc[<3}YͱB]yR -.<rN"0x'1R�% r1gEM>:ѫկod~/źev`sgct2#꺐;UANT9q�›\&P*1 Y6y| -8m"'jԊ#ٛHWPWM="b<F}LJ^gD�E;qQηHpENC(8x ޘNjꗱ"ʤQW V-eI�&Rv@Qdh(CJ‚3"4X:0}q -VQ5꧐EMAI@aF [<<7&:(uagpDj Ba$;MfUB7*p1f#lDmK|`e3uLM]8< \ߤC@vHhVw~I\ZIhM靕\ s<I ݚˆ*57V,CGr -?&8E!+L&fd7MV "[}) J U �-[�o|DA /g!hRe5<.,8]8h$E7Q%.kKuR Bl`ɪ~\!ÚAKh -RY&90݉[ ,KNˬ9JGU>ͣ贄d <~QQ>y2W"KZ@Gݫv&(ܟj'Hݫfv6Cݫvm߁~Nryn59ԛw; Me3b<adBx11_vYBW=48 -J9It0<$Ox܋:ILK+܌ >yⓇd#^OY ~h6+Cu$q&Ƣ�T^tI, tvnIƢ(q&^<W5L"uPc UB@Ԡ_}< TGN<qQb(¦+qVt$O:ecgԱ/N/ %EŘo+k2R5G(S9y0I}]gE$fn.J`j `4V&*pzUNхSBMr17\-d}QХrF1㦎.QFtp4y@j#`@FRĒ\ ͠Dx$HqAJ~D8ڝDմTȌC0G*E6{;u-REUل]Tc;5ͥV R?IFV #�#4Ni )bnZToF9/ (m19Le{PSL!<ڙwʶlS:ٙJ>,;W E -!:Gt`}tg% D4>'j*{-;"|s:tSSA'D0*2v+ĞKdV1y${W訧17Ԇ`:ޭ9 -:3q+Ϩ -[=+ - V_\yݘ8;I0Urg$ŇC >Ov$>z :LE(1{5ѽkLM -aσkF-搄~XԝWV<L9Tv?跂ڊq�9<cO -;^Qiˈ<,@{xH?إ;n7@|-Et_Hl3VE{z -`L #` -̅ fC=@X\ )6 Q`\hu"QZd JFK�\,kRQjJ2U"s;@s[QJ/s0{kg & ge Z1oDߝlD 7DM*NAr2(}584]fd\mvl(i21xDqĚzhtPo�>+l q+^C|m=hBrW�bFIWɣ34- xSifSY`-u IS<O*J>ǃQcPWu v(RIBFMH:hn1f/qP3!qUMauC]  adZ4YM^У�@PV C [ bP>UD*=}&q4 ay8IƬ -Ye" #L7׃U&P3ڥh{iRy3ٌF`f8ܤ dM%tӥspP}LyW\jR#\Pҧq\I*$1T3C -9lPN -jY]z=\+4kW9.tl ax{ vRC$EgMh35%iV} vO38@5V�K ",70SbCrl@"U*1]38ؠ{�2FL8�"E.ܫ03\THx/J84X3Y)q9ƕȚ -jF'/* pJIE:<ѕj׈aruP=űR7!zdJ,\UR6h f ڴ~ݫ3Daև&Sė 0N̍!iMhAFa[`WyK -p h#M{gBz% -qt8kYVcp2HZ~.$ VLBB8 ;*qQ Pٍԁ|kB�)�ۤ^oVC 5|�|5j>B^P P𕡩[*#^y` -;dF6Ӷ|oF BL ô^a -qX;mn%h[ŷC`L  -ȭ04ѳ"{^A;CjmZtv1;@DȬY_:9>;(VHa50i̵@&HG'w/&NEkΑ"AFel3'ϔ2!`A ZVjA C&R[B n2m)U�4[?cm?p^vm xJLm@%,M@(Z7JP>qR�J^4PIcxOE|"Oc1 -B ܰ@[-c +Eҭl@Ĺޥ<Eyބ5'qMnEz2"0l^"&L'�?�l.:Ν0>�ltS8PCQ(M,p4[mM@Oy59+&YRj*p,~Z"_1vU BSTcSM툹W -hI'M1%JpQ퉣!EXc 1~ -ԒJGg!O[%[)I;^`?:%\iů*%>`Ďi4K)p0&F'GiCsï3DHQX隒C_v~z`8{7pgR/jԳU~R�e1S٣˒<ʢKzT Eh"m}:=BX0wGgy0x=�&270L)1iM#6:?~A ͂ )UV`  -: v hx/-v@يdOQ*@zs?׳RG2(`ILL.C�|m} `ׂ9XC&̈́PӐ;oDX&pW֡ g -RV#xf=/<NnkN9,4hJo#FJ8Ilpnw6{1ASĬjFI~lP%@ױO,|[z7D7j>zbH?V"&$v3TޑڦnL.MEw -?`ybvZj&C<Q6+)"}:bR&NJ]&[^}[۳䑴!i &2x*pׇ [Ij6":*9f -~KxPkč쀥DsNS_~@tAMô6t-B #7&U֨�lW! i6)*R⻋ήƭ*mU9AF pt9 -Czdm+C5;w`lgjڂnqqj8er-$?Ǎ }!TP}UU]2LMzOJL0.\:tV -5VG" -6_*934!{g > ,4_(4կKh)_n0LxP<i}(2Lp_:Ե{Mt1YI,a禺7dwtj8?LBwpv8x{ݘPfs}`a1'D!hmg9b0oͬC=Y#N A@6FηjrnxApzb }LgFQ0`88tiLu/AbqiaA4G< ݉ G͞8f� f -r -Ҕ{ʑDl+Bl-<SL{=j$w"NQ䪧Aܓ-0 L&/EXі_q}hBqlC"jT*V'T?KZx^?x} <%/rNXPJQ_%SeM0b}:2*hFZ񙣛q^ C!~8w> |uE_@LOZhv)[x ~p͂}5[1t~]L?t\W/6O:W|xiIA5rUtmh,~XpL! j 8ZG�E< hbi!9Ae۝ɽzbėJ9)N#(^^VCs;98RuY<JVFZTz{wOW+V�PLбX we~EC?6cA1_+)Ɂ<򶜩jE1BISEeu BeȩI34pԈu71ū#iCr!{kc -i0h'1S#:}噉atmubyqPr(6y2xzP1#3)6AgibU3}bB(T j9S (t[ 5[$u\8 yD -%Ī4@{v;!>9$/  Sh5C`ӈUzHkDnc#ٽxYixY7Ɂ!샜vBx -:if7nS]p1zL:գ6(Hwؑs \#xAtQʀR/ KRUUS}4)mD>T+N]j#eP9hĝ} v U7Ko&׉AvO6faSMw2pW^VPfKG0)+,.AOs/uxUۿ %[H%fH1! :Ϩ�ǿ`O\ �۟RˮqS@%nx38vXvIѥ@zH;HKVBH[5w N–3j49]s2C#",Kv0Pb݈>ܦEc>V0E:BSԀ}t}Q:d - ʷ2gG\hKvjњ!ltgj`"!KCFۡRgUp'-٠A>h>dV5lQ.*BH*װS^V#6:4Xi.(&K,v( xWS[D߬T@K-|GAQٛ_Od@&OX:F,\'MR^woTzH4{FPdX};U�B 3Ӂk* w`COlժ?ֺ19n.q0]P3#M# D|B=D Fq `sZ*POdw'1תu1QRIZ-*qsF}F{ᔄ ĸ8Rb{4 >_%l2|zƽ*$qs&mk`S59㼚+E ])"iyu&.+E9rܔCuoD 1e:'Y�$ ` BH9%+e_EM<+-AvQ/ëHFĚ8h'v_L>Ht`l@XPc%5B il{^UAHX׋ F>pqp_dž -FFQg'CㄹJa0R DU#(_Ti5.qFA*ڒ49VH]띁߉St^erJ0itF7yTknzM :y7l 3)% -+#"y;0!xkF /oOjx Bҏ_&h!87ZV'+|؍CTgjzw}B 4q+{)q`,UEOL5ۅ% ssy3]VoI¤XS%q[шp:()͂rRFǮmQ-,#npֺH̑)b2N=} -,av -OUt2nؗ OUtJ&ӛ% ]<sʆOpQhr௷ìƢzjmQ9>-ݾWߘh`CgYCQC v8&w>k{dE zY"1aq4!4fqy,n 3�Jxw+Ȥ+ee_FFX@o틉 -^  5s,?̫z5z9oTXU6.pOiXitϺA3>|1r qcI LL˝ `Wp%! x7b -QfKlTX)Wk.)=P|)Śy3YoFiW;ǜ�37W:~؋$^ص43Ḃg~5oFoa޿ۏٙjJ@Z@frތ_Ӽ>Rۨ?c az&zr ,Ā|m3h -E%=B4RT'l\ Ĉ Q7FEH(2p!/8u(J|Uأ&~=.AghCo!!u4j0LvB$le|/b ݄>,= -&܉9Bw耔@ ^}tQl?4ȅl�1pE]UӇOvַb QlU^j +$ ."[M62ƠF=W578P+ä" ;3<G&<*Bȣ1 N s*IJ() F@AQb%R5&n �uS%f4Jj QGwz!5 jU\݊`=~T.P vd& O\eI##:ϣXrGf -`Iu|(ۇrEf3nnՊB{۟i A!@&J{,e+}l+La).x)!0ANJ=:߮9`Km"͒/U06ADR m-uUDo_үM\FDnޖt1qMb(XM*cTӓ7 729/"&EGRd\lr7p#_0_Fn( 5&HZcA �U,!Xcp�=J*Wq"i;t`V B4$ ;=*0ϒ(3wѹ{ }vQD8+& JOHӿ{ К7&g!J˯us!qG M|dBd./.B'Q('*-A͠`?hpNJ^{a< ~t-w5#gIDDt(FAӢ!%*<erPM㛒cS0P$@ z݋6JK^f e%-ewFL0B ?b9n;EgJñΙ-4f<m=5vsU�oIJw J"R�cz;g:bC A ̀^.)a1)C_`w!(P�"AΦQaC}(*hAeŐ/WN&4ҶfR:bҗg/0FYHkv( !&+tb!JF#o" -: ]82&Ȓ$[y.ӂNJN4R-obspC:J %KhdtM%)KRF|Ch�J<3Ÿ~^D`a Uhbb^ -q,G`e%ICYY5e pPɼW@n=^u}�u@6|`dV8# -66dCje~35{{QjMyن-wW4g:�3s2^e'ڰb5[qۃ¥2󪣚sb j<#Cwn]sNxl;(_˜CaN:j$N -dգk^� vݔ".̈|Ja^#hӭ -cFόM|mQ*Z1UR fƋ^JC*n% -I&m{g}M&tv? |j2Z#v|wĉ5RVGAG'yt -+ȁ -G걫VPYiUue2`kJ!Z\@[\ǭj3ؐ2jrz�YiupalPa " c2+ mFLJ˼:S` -obW'o`:aڇdp+FS1]_T`0"w )!B̒눅 K 05XPb$FmHT�sPà1m99d6uYMITQjtR)hȁmoQx$SJ|Cpbʅ ODL{Cd4G9 PcA"ESK&!%�1D֚SA<?hcp`ؓ2M-ޮI@,M .5; -Oy>X{~) T"2ypx*(\ `  IaV4y ,� -2I\/%EB Ua qhl$d4!MI\-+1rYqHR~8)&#T}! -K!;h;/df1dڡ*E2i&hGjoDF' - -S2K$:DT�Qw�&8 B4[0TF%=dq -tҕLР`y2t�sä*کP I?CPYR3Y$ə-�8 rbhPW|GA-[ҸnD[tHh 啋L[&T`t Q),K�Ȳ|5-i] M{?8P-rIH#>b&k B S2AM2Ĝ<h_ Z89xy!lu2-PTD`ĸx#U)&>1U(^)( ypjЭb_2FҞk(J1X %�q<p1vaX6䢚]W JFSYtMp>6XZ]hx`RTdۇb YĪu�ʙ_w"%%>`%&цA+-)D8n$er gr_Eȇ"c_?d'�QQT u)2&ӵޱBh3 ?~c )%g?{cv͚r b[cSs4w9&QA*lWmҺ|p:3iӊ@bP Ó=�jKuXf#dZT2RȲ"n_?7lD@ێ83=HԤP|8ց=ܞ=GE!g^JX=.E&-Y߷puϬ`&ɪ *DHi|%B)`l>_#)^@6Pj -XCˑyL2s�ID(#%qft_ԫ \tU{*A_&W3; 㜃T -43* |,tClwW6 oOɨruSʚ3_q]H`bpZaYxI739k-TEs|p@O̍Dqoɗ<\Z6%xE;3%啢@Ks !!)! S B)p!vtVS@ph"Bg `ڣ%yc<_>"JTtl- %/<@R#M{HH0% #F.oP;"Y[[�ee -9\JBJhvI<l*^6&K-[*TFj!fIgg22$l.Dk)pb tl¾ ôLl7-IKaŪwG\Ǭ:29 Iũ FMf$Ur]57)KΩͰv,Sr<1"ܤ/fV$t(ݥh6*Ѝw@o~ef~ߚӟ|ŷ~|ƟL|7/_|o_b ҍəCt #y a)f P6lvCAv$d0E6Md'L6E-iXp5[q'שODHb) 8 ̇,ܑmҚ�??*ȻQ"ȇ)dz$%nfNjskA勢,Ga1҈RKPTf*!jdQ"kHSDXaȯ�3�yEpHceJDLѐ H/IP+hDq3#"?;JmmSW- -eQ�id*%aV6"W%�=1]2e(h0$eHqh^'D0 3C˛l(M8 J{._c?ĭ\8`NulBRjά_W4dcnE`* OLxa:tq5i'[BM4UâjTT$$lģ}.8RM_ElґLBHxWkj0w<!GFDtM=?Ed?E:HÆcBrlEL?]е$3g<TSx2u6A $%at F TIAHfJ`NIb2Qy>K]0)Ћ vDZ(AR8[l�4Bv-@uiA"cr(CAoL&ǯҊz3y}?mIgHi¼-M"LƆq!Y# E 0&œwDoax཮CBiT-;sv B1hQ5z% fun` ŝ=,@ȶ`e"yF dNZ# -#@:4e -zgY[^&p+�`I jY΍]~S4E;K$-OB ),D=saCo 4I z -0]tfܭSZ"M=dtpmm!!y̸=HU \nH^|E@;GX?C]S[pz}W$I5Y& mtĻd\3ŷ&D^(E؇۪ +.kW_(T@9Mhshp@whtl< -Q#h)C1; ' ه(Ȉ3/ŞV =QOP!?\ ڀBe?_Y2nfφh>N zBqU7Ks �N =Uk3:cAR^s{'QY6$d%a:R A9ЀV4g9S 5gCRND4H=u\PT_HFLx-gI -Tl-dAx -\a\~z?h?u!#d -( H5_Pg޲k06`%9B5ye*pG8F^EV+3$l*BxU_RP 3vzw}ZvY\|Gr[lk[` ״E��Eg3⧀|W)dj㠔;e;%9V?>@vgtFm@XR�녲#++7U#i wc"_Qqن Zh \*HX~xѲr̎H -Rj/+,q=7*WQdD{ r(h/Vnd~P[B!#"mBw%vHMN/?m-֭0Yf\Ҍ`ҰէB.ԡꊒጘĽ,,) ~u`䢰z ,FS k�P͝ Ɇ-U 2pTEp 7i qnlWےNwSQqt\PqKP"vГB 6[щ}Er䐠A,u6,[.?B?ˎ"(zHA%ae;4C,f;Zȧ2T#WU(2I"Yc_X=\M@^EAܯOˆq#BýӅ0``/ZI|DN+E` 4%>=~SuDMWd bOjAs{z:IX[bWuPef*4sst]@?,v�$/dZ&VsMD 5.] ڦWa�RVy sh2E7HQC^nhOIg2i*7҂^2`$tԣ6ۋkV< F˒4eE[ -I6M>rb[*D^?EFChѫ^pMr &'PMM 1HH-F`3NFǤ̩"ɕ#ԋ"է'!U)&)ָQkVoWHMX݆ԑ Tׄ:.E$?3HR'JӧSu6yOab^艼h[mJ. -G -_Lׂu_K?}fm*azF,6S*]ϪZN Ī-}>ZPHTM\-k룞$^:x) {*sihmZS)hDwy),Xwjk?�[Kz>3whJ=1OXɎD*^f^~/bJ)&~`NFbEҺML4zi;^̢] anByV yI¦R/ϸP4+ԏ P4a=K -w,hOD{RSpSnQJAK2_~�M|垃q};kU`H6xd FXf rz&) vU2-m{7 N=>*BBA-z T^*OSA,ʭ<U8AW܈Ә*5Fm$o!>h&ӡf4q9:@s:͊--t(S }3Ap9_a2ExRKPVF .<z-^C :$7Ckw#i*"./P͇^"@ -�_<jDOݏ/B1HC�lD -�(i";w@_XE%֣OOz@n+.^eה 3Dbˌ{8"t43Qzlg0g@I[tIZ  Ǯ%fYxs;cHh1މ\@JDҒ\:kAMnO*R*,buWlX*/Q d� nO/!E]Ra5}~8)8i"> -XTz&IdT$ȸ,��%&ȰsMY݌k?f@TSGD e_;3&x{&u(e6ă3Q%yF`_ R�`SWG;o4I/{b| [ڧ1oDbPЋigwm1DQq8XP9auBNCix/. -2jo]~ OI/]'Dv㹿$Lz% -G0Juh#CCdV`mY6̉`Cė"EHF+!|< 1dC? ÿԉOQUhtz;.!_?Z? C,]~mDH <*R.ouNd/.45ᒻ$ :S/zOg5#ԞX0DSnn,}*Q1DNދqI'uc¥nݼyDzk{1Sfꯟ˯.?{^^}_z6a:5_/7_ -|o}o^W/|oQʭoWo}ͯǏ]@=/GW_̠'sW/򛗿]߾y_:;^W߾z׿`50H{=iI]Hqx3_Sm0$$^[{_S�[ -. -^ l>c|J#7A9-?[P|F?8G~. $x |V."QH|w@0d@_ [K6� TV58k,REէ, ˡS@YLJ'VZYr\>Y\8o_Qo}~_~?7̷g'Ӎ^~AY-s}d_r];B'`63g)?%߿_syc>qVy])qOY~#/s=2a@U$>4�~=۱=O?|v\}=Ԫphx?s%_L -r%#G)R.Yewcf)j�Jw;Ug;3oryIo_'u!PgIDC=?r\ IY~2,ϲ/0n%c4u~&MSH&5�,|y4Q3?ew(ŪMiU<%XTbLZz^360St텸P L!;;2U yY. dv#9IZj2OWgEӁkJDu$Q ()^HG 6,*@N- \BI"<)exi޶%Hk lӄ [ڌ1.[$Q/UvS<p?f)"~Xr|À6ʍCL%b=h3Yqíҏ=iį6!/1W ۃ�p 謢h~6D6֖.jeF/}^h -֛ٸ߂ś cAi:3fk( ۫$fa0 B`8eqe#<g m*O (/ᧄ'4O4_%}je@6i@\R8)XP!E1Uk -dG3?H9n`nU PV1e ;(Xs/cl2ׇ1h4-I`RIc2E*5XsQDyOo2I -_EKZK΀ j)4@ЬKn304DY<8:1(Hm<+ꄐsc[u t.$:>eg|3b=ȵ,]RH vM㹛(+4@;s]*+f;j$;` βN^ -[uð 4 -P*8P^AB9t˩fU8XtԘw z][MLDuv'rf+1cf˚O[6yM -״&]jUMt�@Fۮ5]'$^PE!-%ӧ �;4,Iѿ3"1׋(xCc)d@5]Wy0"C׈v+E*pLdxNOb-Ԁ7O.Ã)-ׇ<ٱ5 N<oi-ƛ+B"Xj!cչ>bl3G GJVl&�F.A1u mZI~v&1q9_g pL1}UX]nTT -f ޮS gUZ5,q1�cHha9~X&y=|z_',5΄j3>Grc&j=O)/QʨYKa^q�>`$]JsS/fi4<$x\L6QF\%[j%-l쇺֘HR$lq.0<c .Ϊή"@k>5�g$fo7ZbxzU ~K\ϛ|w̾3~~|pٖP ZU"�Zf(� /2p'toLcL/V <d1?@iX,z{wՌTA*zW◨@l3NO{l -P>!h. -;y藂?A!;b|#iGsxZv,b\?-P�NO(aݹհ0(2,v$نXXdg63n.žk -HM50nۢ+ii4h% ilƾ~+P9_'g -#!I|K[v3Sv@٧0Mݠk8տ\#M.vU;p&(yC$|$qx{Nis$L{P|L  'csえՊHvL.En#Jlok\.Dc{c5MhlA"E5&r a7WsO50pյHh\2 "驄8?$x Ѷ wrK xS" -#\n!)'"l vnD%o`7661X1WsfnR�1] - wc=xثEiiKx[h] \I OāSaQM6h\!{fhj EyR%,`װ$2a)V"dhҕ:9#]tKs)W?^gVF;Z>if_BttYd;B^no Չ(${�) -O -b$caVr?$3>y3C qMȅ5 ' -&~cK;$p`v\0y>�¡BjBn6zu%/opނqhĆ1+ >z2C%bAK'w~'N?ia~h}L\ P\ѝ`weo -P**gИם GPz_+!)�YMJů!2|Vўe-[gm䁌!CQE|05wנa6\է)@u  n6 \z!n -1h)\{:iP?K YYL,El?Qrm?]&*ҽb�?YlYY5ʺZR*.[ CuM P:sc8DE&rgG4Of2(cc0vz΍J9ˀ*p7-Z -}T,š HWlc Nz׾+[moiԽӜPύ*k_VHZ7vNhlrY{z |^y(Tj:aS+/\ĬPRv_[bMYؓ{F̘qrp"Qb1<[ӧ5}Qt vAȳ`\oV 싥 Y0z5@'fl B C)0P7w<Om,�MKf~3 K2mef@M/ń.Nf\7W0:{]s1U^DQ˗!}s]O>d ;1C,4ŁP^d 4p -6%Fj)zv*䙄kۗn<dH hQգe0R'rm<upY2SUxF)Z^I,LΊ(ܦZ 5CI#h_b <[y>=Mv(0&B~A#Zn2SB -?]bY `e,TI.QjK齋CBXn4yG:;_F6 aR_:lY}lH·F7Gn֝-Q&Pяm ]|+4&.{SzT*ݜ6ab}Y!EO-h*,9Y  86C'v9z9` >gyzp@4*΂6t*.8% 2KTqjrc&e`a7)dJ1#zA0WFjdoyʦp -2*&HN 'ytuzRY2#.Ve&EnW o;Oz#[θqqMFI rVLMZb(53PE \<}-}. 44)!@W<t7Wנ;ί&1[7Vs۽<yG>2_3_~~ۯ|u_Ko0|*9gLR@w`�dB&)Gsp$7KKH<DI})XgdD0&z`:L1mBD~a0jP(`Ɇa_~JʄE]A1.s$ ЄÚH  7iF&  JP|va -dkW<zsi!-#{였 zjݹgV!Rc1aؚ*R/WPQ4i+ǯL]b] :aMOCr7"�18.XHYrwCP逐ą z%rj$MG@x!M"Atw9,tLt-0uZs=!D:;>.vVP&&C jaJe@ dE| f0a.y"EKB_MN#^]jqЖ/-" EnU+תDk,9z@sZ�u -#&|\ -/ID1{0!]Wh+冐q7 J;Dވ`)fdv{X= v-$(SJھ[ّ(YS4Ч uᄐEoM5%Q� W̊u<xabe]+XQ/Q˸>KT!Go .G9q&$XO&"0B1I@tޥs6u%8aRS1�= k-R frL{QL|)#56vwPU~nWWw]V\�<U΅-pXmQ {H+NJ -"D 7w<`.!�\lTX:{&SXh aQWNR - -2M0F63 g <A< HX]3 Δ`/:}Z:wdq&P;,uԠXRW~;άƶQeaHǩWdV;K0#͸V44aYY2A oG@-Ѡ>b)0Vr6.Y+&h$ -%LJ`#;)ȣLl=(}ް2u�82"#}_|P'%c@tΧn%x:~@j5L Fbe}uZhGk[8UpYgگ|~/4(m0|">T\ -e*%Yt"br-<â -"΋反Hk91 …gz{Շ_mv $]Xp.b YI!5 -SN7O&1TSQDC XcB˶^ڸpf#3) D(ml墤IZ(-nzD˻Q{ee9(70ּ-=` ;ņ IlV$@7yĴ4zVJuKk"k]Þ ?Qyo#yI_9�-UL`+Fq) _{`R&|a㙚Y/,'&Igu"$$pnZFέ^xx(͠"f_3w1+~K$=;%JR5_-aP Q`*@I2Ϙs\k4k16P1r1+&Cpi->1qM{̆(v`uf2J?A']z%KQ|6I meR֪Fln34u#`odNqMm:]chI=+եBk`gtو;L&FL�`YyOZ[߁DaXd<#`u$7pSOAS,ue-@:u+!XEЩ=j")Rµ -t #)j37-Lcqo]lɃٕE@Cey?SA:XCPNAa5tbŤ9A ;j0Xtz,AeP&tQ;zK)2̢w<IANdL.8JxNe ?,awƶ{Ezjv(([+fVhAx&+5SU)dl`[h2/lnLF -Zvy -lhr3zjsŵn,ua:H:ʨbsݾ ȝKc_~1�{v'^)ts~.{Ej?ZZ -T3ߘ,2jh F#"C1%m9b~Ox7|jG"L=]d@]MlLWQ ]AQ'1= -#@- -q/C"ր#B#{]9jSe'9?aFɇtZ (Sϰr4%M E\h1H܆lMWKL6\ŅY[`WKvQ(71\ 8Z -1+dQc1�0(UݛnK eaψ&a!3ՙLFT>'0<<_ -oOƪT\įˀ< (ú` -C ]"BV96 ALf�&[uh``SZ_fZD=Ou3>j>B E&?fbQ]Ԩ,$B6NyZ4zp̢dydB,qhj * -sdqFcwa<{ὔĉ)-y~dѵP"v25`RM t0 /�"GD2YD uUxU&ݍm@@ G1y[4rLVTv;-L{dgA^(6kCTtP.TuK~$:+,4{NW4t:cy/"z&?U ЂȖ&eXSVvrGF,"%<9ZǴXU>]2ɏ0WR!xGI(kV ľ$w~4y=I" of@Oΐ9XLYU3(.\oiޟxЬ8$` r^IaF 8!'*4x[cy حEC:(Y먹p\To - Pk,֝m‡jOjXWѼ)Q{L7cooP-AEǭ/?lѭV'd1 jWƨm AQLlO.jcuO%M:BTCo<قwZgvr.m@DC;Z_]~ʣ#ba({M7ݥHK7<({B??C(Ch[tY s>LA?: \CWz,=^d$DsbQ - -_&z&@dnGhƞ/idHZ8}(7R%~H72Ϣqquk )>Kg BP{?MDT,/>ٻ:V`PCLW]ġ v.C~ܥ4qƤGiM�"K-jwۡ"z�K"b7GF4~y||W lY͍CqY40-L++v]5�]`GCS# ݙ(@f BDn5Pf+_rTtk9C7T#e>o X6$n'x,gќbKŪ{R~wԻ+W*izT`q_ׄ"Ahx"}X,6>U\ -Z v:8͑r3J�@ B,^D- ZïQl-5 2[IԝCrd( KpbU G5.'TuD b7Kq[ye]KQRZJxc@g>zԯMB73yo6MT)Qԇ?_iT܄}l!M2Zc(S� T]hdUά=zmMP1@<a< c \ŝW;(K 6!<nIY~ԜiQD^vkPeE$$R�jP~aaH6+$PeŸ-;B$f(;*hSom,Qnˢ#cVkȤmoL䉛$N䨊< jB3^T^nL*"T2}kIm3,c:?8:Bh֘P$ڙ,W014\ƕ0cYW¿+9C41|#3ooxu4evSZ̉y$u%'!֙=!j+^2fƦI s%#`UZl/޷b�r"jEّ$܁U;Ht)HO5gu> ՘60O8qAO܂ ]Qb_hk%ahC2MQkdD@ɞX- 7IХr͓g1ts,s#9.ύL}LH8*--Ko wW}DACaZ: I b2>ӦkBlzFK|R/.I)]f_1̚)(qIŀsb+>攈<~OӢ9[�`6e Qu-DHA-)J 46g `-0[8' )ʐpğDFd钊@:&c -[x^`DJYhReҍ_xcĞR36k@=$P`H8L+[x*48xɖhaDWJ dequ;l,z,8?^ L#Ὠ wNvۏ6$G]NL --\/�'gζ@d'S>BZBڏ\Suem@=N"1R-gaP0S݇rP[+yt8͕\CQscׂ -"J-&B!HH  -v5тlj!?X1C)h -PiG\ `Y.aZX zEIn;g*O#S*N}P@ʤVPRcܢd_>`S#r3 c:HIIUaƋG>-᭫Hӡ;z )FqAa:�b)xசHٹ]"{l4,rtP_8أZ ;-{$E 'B7@ y *>DܤCw^]L{A1Ⱥ2\Zq}sS+vr8L0xh n=`RXfMyXa?CEn%K!8vY%DHF::5=GR*|3gB\4>!ADsЎDYcpSĩΠNIХn-"oOTA,0A_8p3@ܫpOT(@p[јطG)n� Pv,Z%"yyfGPWIďxr .�%TAO'ݿ,׎A HWL -Gr*6 Jć'}@=P"R{B b�e{Y_*'P<Qo9AP%iB=-A^A(=Ɂ)U['i @uԽo-a|=Qd"d ~Z"VL?Х\ g ά䢨olK|by*ݴf 9M!{j㓪9Ro*8:` M)߸`_ HX``* .=Q{,H;+ɲ!A :KE^LATvGGKnCxc%Q=`싈5cu[`ЊŚ͌k`Jcґ -Pt�"o ,YADh W9_zW魏h[\\,dAX\ 4adNSKdi KMr1fHŜl:.Ax0(ձz.ŘEu^lK[ -odn!8j!b%Ҭ|pҢAv<]E?z%pU#NDY�WT//$U^8A,W ba"BX &D%PJx*HZS<6Ł%(j#O`[.CUEwSS/#ni|,q-!)8ЇBKTKQZ"C2ea&MF"9ʗٝ0ѩeDn .9}N Z/)1JKNhk{$߀roCeۭ9"4qD@o Srp+0SE --44 pug4Rcm?`DEH\; %r:Gc[<81}>XnlyũV,m݌[Z2yK6tLL(te^f -̦.JM aMS1nŒ9`>.wcfRa -;.``PRrPۇ<( -hGEB%'+0c  Vb쉙BjoEtķQz-H-IWT4:eC3+ʇ&(Ri:.@Wc9rPg(HB% $l:p K= vA �*1W`;ƌ8d o60"͔%D+;"毜<:t<uJ"k4HA33 E-M:όZZB -5!&#v/N~jR1.M]:,Uy<N@R|)̂=H)c% 4.F1쒏# 23 - i[2E2]/S*hiqy-&^%t|:>E-�[L �ta3*["c]~荠Y`ذ;!o/W(B_x A H,_nFt{3.9V]ERMN`IC MnF <a@3ق 24O Gq -Nv*^C ȱPFTyT"4{_zhu2!_)bLⳏ{pkk/H$4 $`<?]3L+^Wؘ5)j;Mvmc$lA,1,3p"ޱ>U'H_$5pͨ?×"\M CqLpl)>�:g4@^H --t,xSjy%:񌊻AS|oSGIOtƓ.Ja8�<tDiwb!�JoZ0SA�~k~DoVg3~<!/`�۩g-6[2L)ԄN8$0[hTh .$6ε (L7_C1*",™M!=ōDƿMIsc"Z@0!14-'[k zh<ȎS@l/?eTe4X#jM[2)rS -yTaIL:=@Rm(<�@ $8hd%,pA߿c><R4L95EfҲ1y+C3!wk;` ɆJ!q= -ppם8:F ӊJF Fm/ Jr#N\P o9xGx?SRԂAT:eQ)ŭAPػVSA)c֗jLs}ŧSmNVqј&=I󭵒L@G@z$j5*I8غR{~rQύSTF:/lTmWP2'WrR�3|-J(qK膟k\�o譜T w7( -+δJ>060aH}KtSU?&"A!Bթ؂7acfdwlNH ҩx` bea᜚H*0ͧ5 -lM+0f酰<j!*=]NpiУ Up.b, ==A*&꣜n],ouvYrlAC4Ps,Yݤ3腨~781: ! - IR؟>:ݘiy1w3Hٶ)2Tr`B|0"ՏNX# 1> X@ZhbAZ~aCG^w BAHt3P;Vܒf2aDeh\9;s4-E`,чi&$ϏdخFo'FmgyMx<7>"I? z5EҎdž̮FRbc#C"kc{[m@U:޸r -&Uwdi3yrPMqbyΰLٱ mk&(Pd1LˠꝈ[? \tw(Ax!M[e 0%:B9^B]* - Wo#zFi 6�1-<sݰ$\บû {tv{doDPxMl.yf %Qu?|(AdCne -Xoϛ43FPgWQBlE4Q -<'.-?΢IU%VIOvfI -K0jr;Wb)!EHhX;ľ C�,<<󝕏+<ܖBE1m:bCC, -tqqHeRZPšVvN~Ze )s08 ^2sWC&\KőZ . :9sEv$/ wOZ ᵘ!:ڭǰu7; -lFЈo$eq#R>]N -v5 c]~.FLtԭu}B0Ne.ƌV\ZO"�obO'k"hx4ͬNrRtV]@ \.5>[A_B f@O @|D>O]J`*RlF*NU6ĉSOI +-W=ZP= 39)0Pa#ѳCژ\t#˱EnS21\...4/<eڞd%�ڠIb+;&m]!'Pt"@4knn~j{݇^Y⑌&5ORw|y-63u328/bΈ? A'I1k.e(Js.ܷ`ٵ4yUUL9D_XhCS!+$!]5`?>3]P ,+atmWi]k0eH*~X CsZHӔ==ZPzh9Ů׎|!P@DJ߮k~dh$v ~4rVAW ,frכ&IB;V^<2K̰"Esl[L׏~,C z);Du (/ -Q>- [}z1=%a;z,L| ijej<*hOx(ߴ8~R�{b39Z|z(VFۨ7g)3Bn淀{e@uFf&"' x54B]9tIQB"$_hyky>Px]_ E[.DrR E >.URZ-寻1I*4�4Bv1hF)E�UfRo{('.\L�ގdlNM+E*ijLL~X']{\x;,5{ ;u>J-D+dR7-Oj[ֺ\jTǢ -MM &U~L7N5U<KN og-jMK0c< p̑D4ɘغJQfBeImpb7 %x*p[B -eD!X-y<�s 51:=F}Ck{pւ pI +P ʶz"%Ӧ(KtW2ӝJjȪUM0T-)&Ζ$*RC)kӝ0FB_fA/ 0,q -Q؍ gDʼ8?fkhjyP%t) #SiN~n6vL_xWr -;1ΐ~8?6�nggl$2<=H$KAFxx!zA؀$Kl15Z]VoT:'̢2ۛp\(wEڈG0|q:-{vɼvݦ:�|SCzm;K`>N`BO-ٓ?ZS Sk| k-E冠e.#aUzذW؞+L.nn1:5> 2U0RnKvT9z^�CKtIC@Q_ p7:wKPvfUd|$+Z㈨P7Vy  305@݄OMIZ `.0% -5 -ːd 5sB9qDvzi@PY,6ǯ} 'AQt�bLa ^3171H r{w%3c 5/ t@&:\zTxjpbCcN g1:?$"40D;E-=d|t5g wC6yxiJ,@dvⶐd^R|Pac/ Pߢ5TUuZBI%ZP iWAK QiȠƇXqj-F˃jhT]ۙUI [Vuw/RQ46hAq洂]$#hȿ1ʪtMfQ+`'7ҍ,ܞ5X`I)r[=F> 3㙰~Sm4Jexo9(R )Rš#傞(!iάGXޯJ[Vy"YX^D=X= &§,#Ol&{4+n!1�yRBrOZpLd2.hnœ; aD pz(D[TxQ� [<"HexeZ "cF !Gf'?ZPm0`T.YHqM26Sq1)PڇBMA ǻW)[�៣pHT<h -&1{djLVFALl*"b[j W()!aG`DL 4xF@(FUO6L9\#@cW^iM#:yD&ȔF}")z h?.ׇqlAkSi�!RI]2 !1BԲ |hW:iuHrBr(Íxx%,&MBZ j`l0(1E <<UA`hx+֗y1yF^ - Ud00�݆o"|@ZtFhJ(#]D[ChCȄ[ڈnc pA"5~Q 2cT ؀`.#�4FOS(E3¸wb|5elk̴G(?Op54h SHrM¨jXm!<6 {(5y꾣%rى V@;DS])j yo.VzXuoSzl.aD~f#r2R}"dCK ^ XlDZϤ> ݾCh.Bvď|w.-94' ezۏTH"TJRwRD%8=+j6r@ {('(DQ**n{!4=AhUq6XZ{A D;N;3T�aveO%fd~kD*쓌 -oOQ_[L=%iRnnQ`XQOkIL~s-dCs%KϊI ,,z͵b{S\mxM(]U8|6j75WRiO''ҿvK<Pž𸃬O撼齚@E_ -"3ӘQܾL na4t+cM!,!HBN>dXHrpWb}`1xFaK䞑HvRd8<gUŀ&a I h9B8K_!ThXxfBB׺*L̜92& -CNQ8EZ~Z"6LD 8c0ҁQj ;.K@')03/P^Y0jz< $RA[IL/vdՋ2řD mPaχ0J}7!<X �J%SУNe!jo'M*jp!*W}] Dq~%ޚ]xۢbDLG#\S%AӾ/*�ov[c.|cE9<K E&LCᴑ7I DxfKs:!$D+B�/@ -3 zg>{HKrGVOјZ;f�Gy.i,BziVEYԄRRUWA)sE<$$!%C$X0S|CC(Zcx}lfᾰ>]U�Vic0\vӇ2'Ci{/sHCiiD l洿Z;/w,qOXh裢-eu8 Y%4;a $$o -t02*[jdB%*:PubI*SpkWdb4^ -A?V`\[ Tl!-U&E=��&:Mhd9 - -13M27r ۏ�Ew\Eb;ȰhBqr5P6RL}L*y 4 "XiRHX{+2~B^0+~h'MNy?5~AIZρM8Dז t iN*ߡF7H7/Bŵk1Fћ1ᕢhy]"K*K"Ӷ91􉗩$2;a!׻god<0X T -?ކ2$؂ʔc:~ki(dJ6!<6;Ef֒ob7Ei!" HIi<u5H]w; -wm_ ?T*) @Fv|`o%QR˷T nεd+ c[4גd"ɡ[=`Νӱm`E(P:yĈ}6nQ")$7@ؓF -Ke٢m<d TC߮>%u=A;?sCZA5T0�'=1؏RjGcv y-@)�|w4µ4}`3JS"%pf[M5c?Np6ȸ.a8ظDscMo. ~ΜE‹SGfD|t " vgp@"> ,]!As HJ`7!�G 0?o\@n]T,=c`ˮפGt(xIhK1YLx3r6V1}@Ue.0?". dFhmP5OȢ -.%R<x*FᒄC,JS6e`@O/֍ a0P*C.̂OJ) -P6%x&NC,(D jQׂm;9+F<|r R1^%?c| 0в-]lf6Gbn"8T=J |p9rA+5Z㸅K([THQ$`} 6C*<t&CP�bvxffx(r$ zn=EGGdM8Hs)XP 3GXѼJڞm.LRN%ѐ�}~M3t & XawXˁ[/QD"1p9Wh(*#ۢ6nWGI2Zu'~=/%ThDh+/a5Ħ3)�0cG{ h@h/1?N8qѩQ,-zAYgw|D˪$ MZF -8X5'>79ԍEa_`t> %֡LNVQy.t\�* =Cq&15nE>F}TJR0)�!)Kh2`3TA#s2iT<ɘYjk*2TYvS.N|0}Lnnku+6QFX�GE+{T8x Qak%Ǹ.'v%PbU=⨫G›+do6s<MD?$9i}P49c%>;No=ϙ;v;Ԩ{h6m1c_}O˜->]>yo|5F_/|nW柯R./zw\~O.g~_w_o>$/^,뿓Utߟ}_}חߨϽO?_g_pw/o%0_A -c]kwIC~֢E4o(ɢ4^tVv".^B} Qs\~RoňOtϗM/30DcRO [6a(vø9Sn.zEm=?}._/ӿ.?{쯾}7__|^U,?bҶ߾y_:vڻo޼?mO˓W/|}YAo9_z6̨bƫ7߾=% f;~W_͗fUk˧|/߼/߿oc,?;9s`ίsn5Kg.?^^o%__ډnOW/|իoڎg~O;^ݝû>݆~s?+N|QNHN5xDo.ȓOe1|VR4_Qseޞ fE4{ ?QCg5h@Gy5Opo.~jLp/p'r?I/Kh\ENL\0ip{;G.J[&Xc?NIQ4$O v qgv$9-BK9=|Ç?|#[+[(YT0\PR:̶TN4w=)[ʔX+4q<N)[ϵcxs?{& wlGz3Ç?|#[x>[ŇkalYsrt4f|cj #_x5Yo to73y}{|$ ?b�É?É?;{*UHtXecϝq{ǔ*َuy2)Uzop_.~fwﺿG# @@pp<yBɹkVBI)jW:;#nx#OBϓx3c>fFޛ'.~fwﺿG# >Á?#O'OVTaouproΎ eH>$a}||13q|DI]Nrgv]{d?*[jFp~xGlАɫ_J4iVk ݭq{Iǔ$z8fx<ywy'^ p<Ʉ:ꩍya%S~ku:spsyG'4yz{ c?fN&.~f]{ ?fPwOO&<G Gj3Ow;~OV?3fg} - W赽b֛?Cq$[TϞKmx~G|Zlj>nE:O[4w=([xH5?NIf Sg6|d C>-g2r&3u/=~SdCOx(x>N)R$T ܧD{xa$cpЏ8nLyX |<=y4s&pg?SN~&)˻^nG/+#pp\, -(k>S:1;Mn/z#[i5Rm3}4>=>/_x+?É??\`H<sVggz -QW~2?SO*+g -93>~=/Kx+?O?]yg j>}voΎ�> ࡜8A~Z'ȿ y*ugvxD?^t/Qlo O7Ԣ{*Ϗ:ŭQWyoG?$'O"K>}fw?﷟Gpc2淧k]C_YiqPZ~H' y gt˖]}n#KM t6+w8Ws?|w<{΅˿X~jN{<g՜l =t~0|f>,ϓ>xN=_}?ӱpk~\re^_ԂouJsku: <7TZs>O*Mf1e\H7 i&􄞐T%esZ%|TsUd1Q]*AyåufK뢥mtg6^CÒ6}S˲Lܖm'Iijl2q{#3vvƾ<Gyէ5ep ExDžxjq!a胍ϥx)Nt "`S2t 6ڃo|K�eH 4btugy>R+O@ݸ :BCw!Ih*}SӡƲCʐ/oG]t>>>rg_w?(B7.bPPNQ$49B} *}P|~CJ_\vV~܊җ{?A*;*}>KBTbtM軸.U>(Cj~>Bߐ7:,&&Ҕ̯R;ɸ z&7Y=P35lǞdpF/9`:@y5g?:t ђ;튐 ~bvT7TQ*{d)1fum9"9Roh>4?Fl!ھᤸ3; 렄z7[L}@}':՞7sa**z<@i<&4f>q=׉]t~ 7݃3 ν^)l>,ߙә9kui1kDLuPzQVEpmƫnɳͰʹf^j9Oqga2Ώ>>A;p�OgwD$Uq=@K 84FX˸=ul齄3L}^k+ -"w R̿_8SJO#^E\[s D`/>WRa/K}~FV߅.3[s1= dBI>>g.[[D1ݶBe<u2>>.)—%|ϥ ;XmBe['L|;2Ipp#CTW̮exaj=eeb$Opl`Hq~eq>Ғd/Ku~F*AJ$$A^R{?@{dq8Lv/Ń{MW %X V2`'Y\Ȥ#_QR?@R[kV$?O?.uc{TWVӌ[%STV A _a4)4zA)�)m]`'vR:K:j,W]BB$s4nZ2 -Hy9:Y5ka謉뼝szzi*J=}NƇ -Hy9:'GK}') -\:l,]r{)Ͷa*C7w]#_QN_ĎO{_OfRu±Y?:.vzP%Tz -"=2bmX<%FGPs?Bs<ЦJB"ñU*W..B% ^.(TRkeG]кM.3m'I)poJa{DpJ5j. DlYO-.S$꺤9B 3.p2vҌKhi.22څ2jjڵ 2h̊]O-.]]`&N.\ A[.22څv;jռ[wV �eHp;PBa8+ttLY�aJٰ76 906F}aP>1qAG{KMGO} -=Iw\ms__Mp2 ]]4xmT삋sYYYBeIe م)M5_6jji54%S}Rb CnQ8!N0[O RO@`FYBC^!%gXdaiͼԲ$-V>*VvX KKW7DHͦSiNRT  -0.`y+L]֢$1ܓ`uP.:?۹!q&4 ܝRZu ߌsUbLUCeU4 3]aKv\CEGp S7M~& gM\*b3PZQVEАM0>Mghmm6Lq},A/hnh3jp&i#{LU0G2Kټ*wOi�@m R /[!yX|{)e2[&r%RIURT>'ثX 6PpL|d*M+7.kmwQ._<gX3.@ŃGR ԺMNx #I_җb D eIe`R -G }F հմ+el�O-.S$L7'[g0!N/#clɊ]V!�-0F\Ѽ(aa�2ΐffd8NpIp֢Vq0\r ]�eIe 75:s{r1pJgai׼YG~\;.>@Fx900, qB_& _X$K9u T�TXFА_M>հհ4dl_;.6@Fx9//, qB_ n)|!r)=(Uh*t}fai˼$ 29a2Ώ66a1-p>A1C@D DH@uPzQVEЎOMfff 2duP.:?e0NpƇ=:expg)[ݕ#_qGx"i66Jx. -^nBZ/w]wu\o4c'*yw] #_Q[?X[mw죭? 4>CmU\;5MĵvT%U);۟7vSsU>ב -⾝QV\ﶿr<zn66Ӓxq}Et opy' EƲyM?&M.Sm'Ii#i<9%6vc/S5`O-.ShFzy(D:N/qVtp)ι~4%ȱ,dĶ -Y0NU'1k/PnͶöӔq~N>AzX큌3 t@F -Gw㏊, -C!ۗT-(}KZ9˟ -666S/d1,j۩/"),ԭANkcŮOaL.[sU>#UoʫMQVڍF)%<y|T -ì0{{=g\Oڋ?dj (Jмt <saIGC`taHY7!&m^nKv'(CIeUA@IOnϮ:Ѭwww>>B"B| s׽@ΚD'It~!&bq'#Ӎ?֯xPK"ߛ3s!:lZ+-@U9|ޣ%a){&t%7:E>BT`^U50J.~RНETDOEGep%^y0k>ꠈr(wx1<E?hYXv({h=$^{{N+=ZI c|QA_ #OaN?i h ][kQ47\卮 @�3ʪh sj47:ܦk57Vz+B\'<@Fz@\RϞy0oM?{bnWO7rkj9hIkv[| -*{BM<eO8a86?#FT*p,`0KRvoڅ~Eeoީʫʂζ=OVUVEZ1 R =!@D-Mw aNd9Cu@<H�U K�(b{zNͤĒQ LgyS1s: q ^t~KPsœ0̟>g'ҝ3񙁹HŐ AѶYDEtw6d.vӥQsSjvvc�ːA^rnt s J-ANso^5~ޓh}j?GeW!yUEi߂Wɘ]%Mw.[Añ8R~/߀g:6H Kl}Pu^.E 3`:QW!Zu݆ݦnc`I2/hR? -p始_5lD'!<`2QT*p?QVE>t~ɗ)Dqq89I m"ЋΏ^vJ9aN 6EYF;W -0I?d.3jΎÎÎ B|_'<@z>>haNm؇??}߾_~_~۷_~?K >?' -endstream endobj 83 0 obj [/ICCBased 85 0 R] endobj 79 0 obj <</Filter/FlateDecode/Length 2882>>stream -Htn$]"ם]ⅱ?`2z/R`QdDF&x[:~qW~Oy㖎\/wu_`?G:~/:bkyGwR?h+Q9r㦅gHgsօJ93vg傳Y8#ǹ\:۹F9!18=Α?d#rdhCڙZ;")wcwȀ8ZYmg _q(G 8BgXO$gsbm.|F`w]bb#b#r!teL@"#q-;ursrrtej1ώ][ƙrjKmQ؛E𹢰(hLD$B=UYV1:<Om3!9mgGD0)c܁R%޼ -pa,0 jHuuJ[S}a"LVٚ(YemkY^9Y?6 K@ўd,a. KeT5NYr<n*Vp]^EqK#%$D>ڑ*_8%K4/MY em ɸ@�^T$y1H.jsgZkn'H -8BMds=9JPZ-z0fZRI-"-"-}tK~{r|@` PGhSc PNU㤣Dy|>^�:EѨB} b<LqP -)㦲h(:S_�!վ!n~P` -q4RG :IF(&Yd/z =L|bU.~iv'uќ8FK4*[dE9Ƞn$LƐFz MLVLH2@MOsTj5۹H6hcۄ6 -ƑH3;[P$5hy#Sy -MLLeTLUPQJupTdp/:D@U%uE3>]Rݔg@�In|AQfX|᫂LS`1e.ǐ2fUyC܄exz1"EKΎ .Y% -rٽHR _vmk71>T$wUda_LLq!B㳇@Na2a%mA50`L^#u2wuVRyu -/�"ܦqjI&vn"쬶 {ֹ+M/iu%B%9NEmYv]qiq 41?)␽&)i7B[UhA,UܺHp]|}k8[Xz -vMݭM<Gňf^*[(~gfD(U^Y@9<VAF|E;Aê5$go0*Mb J< tI#pMF~^)шp!ҽӍej!2"թe'涯{Ԑcm)6 k%ɃLxtG9Kf74Dq)LP)#Ԓʸt8` ICXC^Q ʠWJS_L" bq5OY֫9Ѩb p fo[UQ%7D#I],CQJIK(I욊]|9zu3{8vO77 dD #54qVmfɱcHd1ުia"ƞ=[UK>(= "2̬;;e!Rqգ J3_'nz~DHg_ygɽ%bnݳLz+iRqSJZ_3U)aRQ-iH:E\Savƒ26zțg`g)͉'1^uKݛGj\Rl#}C -hڶ!F.Vcr@fj6v/6^7 Vzj-Ψykyxvd}J"4È!0z$j?R$X@\.y펷l}wg5Mӏr96#d}f7E4sw}ie]- sH)D9V ۞iWc#ם -q|Y-N{MDa= =~j֖='b%ϻonvL1lX-Kg#h<^dqd؜-ԂӥwZ9gKstZM{2_KA#^ch$&ඟ&`e;ąV\Pj.:HeKٱDWW쩥 ʼN2{M㹌^\U4fVys1p =_޽YKz v.KbkQwk~yrXhFm[UMX~tA IsWva5ܷ @Hʃ$*zgQicbYMS0}K󘥮F - vazWkW+#B$_GoB'v ۖf"hWbNtN'+|gcة4}H76vzPӗNY<|}G.)Hh^GxD*7U$}KoĈ^Iq^V}T -$%p}?- J OUSHEY ><̊ɲ"ɬɉp;%6 -CX \cI&ħ5|� -endstream endobj 80 0 obj <</CS 104 0 R/I false/K false/S/Transparency>> endobj 104 0 obj [/ICCBased 85 0 R] endobj 77 0 obj <</Filter/FlateDecode/Length 1656>>stream -Ht^5 S5ҟI -U �#`3STqV-wνNbۙ_\Oo鼲^^w߯|xz ~~^ofvx<aO5m,kqUl~=v_%xvY.2x:jmy˯g6oWkBuo%_}(TFYnboV2}Ӣ>{]�x0mLۗ[i [B/^'Fpwڮ({v({l{ ne~]VZߠ`}k)ڬ铌6Ig"{>yp9TmF dZfu@MLBXzmn/ozC>@o7^hrk,܇:z3Q0L2¾VChZ+'m -<|n]iPp{5a>>c <x&)j]}5 k)"4J=8B [FT@/>!:*ܭ1>zmm}#bH7:EJmvj@h}S]Rla&ˎ O| @x.N�GEM\4# IҲݔBKn8aIjxBP-mΞuȲ]񥭜ː)oLI HSJAt?Z} u*:a*k,%ZuydPjEYMz?VJ-vXH̀-TOЦ1X{V혉>ex6)D]$vҬ)KF kylwqSyg)߂z`CP?5l,J[#s 3 ~&JS6pՋU(KiCSW:gNGk3"I9.NrUB -nnd-A3ӺtR,[G!8'rԈ "ZK)aA @M}sn\dĪDqplVx+9U&ٲp)G<*Jzழ##iݥCJl;+B.#E#;u68FSZF2Z4POU<�nLDz5o$Wπ)<=% -th6K_U!puc۝hO׸4mN}Wj0ѥ?.;9Qil -.:Se sb8TgT^y݈~fORZUc`ּ V܂~pѥ:<]2oڞtDt5uj')q Բ )/q&e auhj-4/֑އKB9OzL]j5%HXW1is/&␏G?Iܖ6BHmo\r竫7|y޾j@ثZD3giߡt"9!R1Ǚ; Bɵk,Z7r]={IpEjp-'0&tBZ䯙?.qz;5\DJ 4oIx:_��ؚO -endstream endobj 78 0 obj <</CS 105 0 R/I false/K false/S/Transparency>> endobj 105 0 obj [/ICCBased 85 0 R] endobj 75 0 obj <</Filter/FlateDecode/Length 1123>>stream -Htn7 :,RԿkE}EK"  -v>I9=x{eW/Xo+'ᷟ|nߗob-ƇDbS\?))g^4~ :g>_|yVҫaOQlyfyp'FVr<x}^O]v;mݗ[K::N/"cꀱ]W;_blj�`ʈܽ.zWl쓕綅ڊ2;2jt5(^W'%,Vu^*]{]d!V#ܫD5r6\kە$zʍrv8Egb:;OKrj/9 b9<( xx^Zs,5[!APuprEhIY#:DFf3_.pԜл $lVӅNUJJ$U)[@ʨVPnB |@=2l@d/zDU!Ȋ 3:5S<q]cs1,f+H,^/\5%Ӽ'iYJ%%Bg#GT9:s&<>`yrrh]V2dꐥ0Fz|80c)"T8$:]h[xMY[ `rj7_XBS=͑ArɎAKҚސ'z -/w+FQ\EW2r,cpr 20uµw- 1$f+s -DCA -(1Ȟ"J"vUd2"cD 7_/!j; o+MC`x)O3 DBvڹ(3#-1"WtN 22d5u֠_SBP^�z[#e8ĸrdKoMҀK<!I^ίUoH5ATnns];5Ҭ-uM\5:# -3Fzɰf\7O-˗o(^?opW�N -endstream endobj 76 0 obj <</CS 106 0 R/I false/K false/S/Transparency>> endobj 106 0 obj [/ICCBased 85 0 R] endobj 73 0 obj <</Filter/FlateDecode/Length 600>>stream -HtTn0 +%z]i{iP-08dS@d[Fbi#j<^}p#-=zxdif_PX>~ ||z<8bxzecٰ=(mPW$<`Lj׫jB$%M0^A$Rm_+X9ոS9iG7u賚=6{*^!OR#g'NAl]%P-[L - kG?<G36֖(q[Jv5S)K-*ؘjCRS8H܂&[5S qX bA9dq(@Y)Q=O_;,$ -R;pSe\]Vv"U6c?esݥ:A+S ptsRW玔m囍T{ყ\"P %ZWE#hg1ڇ(*/xpl`S1 $07sA$V`՜X3Ե f=;Xcp%LNa (t%Tr6vgvq2eGS}dz7{㌪˜vu-?9(6? �m -endstream endobj 74 0 obj <</CS 107 0 R/I false/K false/S/Transparency>> endobj 107 0 obj [/ICCBased 85 0 R] endobj 71 0 obj <</Filter/FlateDecode/Length 840>>stream -Ht͎$E >#uvNϕY -@Z,E˼ Tt/OrTOr\sQErɷ8~l\ʟo*:agr}"MjYB/RSQԆ2.z\f>ĊsEYM0*bɉ[.,HhK6-ٌҚh#RexKVƽQA%VqG6IDm;<B[6%\n|``]+i%7Iw%IeRf]v}'KF0c/@Q }Q|ueR| ,pPi,cf\+I29r]ޝ@X;ch4Aиۡy })@hdslԺsDd hT<4</C/OO }AIRw!dzXҞNO+iȩp [DNT3UM:*;ΐ�9Cc r3QJ&$Ԧ<թTκ 8u< -S5 x�B} wX9)]b?XY�f5ȝ.Y9!dI+5`Dh`l[φjQґ\^|S}ŔeK%(d'3-|haa]ge_7N$Aoٱ~c*YcYg,Y&h1>,+~d0K~(!fT>F6mU!Zjw =0�H -endstream endobj 72 0 obj <</CS 108 0 R/I false/K false/S/Transparency>> endobj 108 0 obj [/ICCBased 85 0 R] endobj 64 0 obj <</Filter/FlateDecode/Length 1171>>stream -HtnE)fLwmlP`8(%?'eskUy*oZS?R>Z鑿<?~/xVā~~7޽aw ϟJϟvB㧗1>v痛_nUW>J԰]ZKo*7tD×Nw+Oq]XڲlLΞ:nkGu}7oV1cX:e Ї6\{ ZF*2EV20Z=˛Y1ס=4 OgN:ќp4VY)WY5zb(9WqRYŕJ<[ٖI?Gju0;p%#Vl][C14G -e#c̝A+qe`,cZIxYȜ (ة9/9|*7ˣI +?ϭ&Z ͮnu -2]㜵y/[B9sʦWAge{Ă|L댌c)PuD@%X'`;';i|ȲW\ q�1uhKA,${-hD/$RQ:< 6Hכ@&\&Zw6/HՈI�6Дј q?Fh{ْW?߀@bJ&]/Vkܘ;lJQL&+)"K!:eaҙ eDP)c+s> gYEtpg&v&F0gj5Pt"{bIu!b;/إ.FB i&dfLF{O_-Eӛ, dށK ;У,>SScGZs%Wrه4b.=BzXZ@!N*0BzQ@r%}P")_HSޭ &O2\Ęԃ,$qoRphB -btx3+nz7pu'G`@=~R$zF=I/@JNFf[Do2GGY2$uV*Q¼J7z#Pro[I-Gg[jgy݃۟!w�υ -endstream endobj 65 0 obj <</CS 109 0 R/I false/K false/S/Transparency>> endobj 109 0 obj [/ICCBased 85 0 R] endobj 52 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 110 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 111 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 35 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 112 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 53 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 113 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 114 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 35 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 115 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 54 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 116 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 117 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 35 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 115 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 55 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 118 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 119 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 35 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 115 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 56 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 120 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 121 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 35 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 115 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 120 0 obj <</Filter/FlateDecode/Length 1524>>stream -Hn\EFrolP06qPK| !˞9j?T>r-Gv=xk"[yз?~\>pݏ 7}_:'t?˟AjMj?c%v kv<ì{1/cQQO8oUb, "J_.QC$SG%q$8D)ge:\jaCpSnޞǭxaEGDaU$Bi$Dsuctjċ'u֥10#44BxFT=]`'A#WS⃴.5jrgKV + b -tJ>B]бBw1YLcIk';΄ա 5oѥ,ioD$)iMx"*HǰQsN6i -Gh(Mdi3Wq9zg>xoZ|Igo8S:rD8�=#%>P2pQ]- Xt'i+m,N+`x V- vYE-zڈE$&5Uė""1.AZTc7h7D朎QՆ]\mk4򁮵S9YL<Nt*22-E9c. 0 3K:2ۮDrNyE$ջVgR++ @%9LQ;gSRn-�)0 L GBٳ(w!di;ED2%+ kvgcZPf ,(("lOǐ =/|/rC shlPJ|.[5QЎT-hgR/UsؠWX' K$6tW*j\)CֲjHF9 >J2.U`2TIW [[onepZiW/`[2W p^&צذ'#Au}@/Z:+@LTP\{2 #+D=uD~9,('ksAlҗ2`ٌpŃxo) fd5|n̉qEA ՖNW>ʨ3AI[#@abʤ>�-gGubl 3S�I4Ud1#e%"47XC(sْ4ۇ�uwF5Э6{6"HV,?@׆M+vr)М# k^p0@;j~bHfuMf+^*s/y8;Bɯh7ȇ&b# =|Iܺ(>LtZ;_jIĨJ;kl&l vkNLW&mǪ֨e5J7S;(OιZVW4ytFf72DkWIk՜$,ۯ_n{n -0�WfI -endstream endobj 121 0 obj <</CS 122 0 R/I false/K false/S/Transparency>> endobj 115 0 obj <</BBox[0.0 136.0 140.0 -3.99998]/Group 123 0 R/Length 59/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0 136 140 -140 re -f - -endstream endobj 123 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 122 0 obj [/ICCBased 85 0 R] endobj 118 0 obj <</Filter/FlateDecode/Length 1710>>stream -HtWn9Wx=R`CH|@4Æ /9Uv߾AQ]v3Wwy궷s#_[p7o޾ܷ|sp?Ow2g)+d<8bb G '!yi[g =zII߫MpF($h,"?NÈNHɐa:AC겏9*U:%55_ 5ϱN>Bmʾ 7{j~,0o.ހ  -u^OiSE.$�{}eܬjylIķZյ2|ZN3 сgr%x!Dwx)x(5Pڽ"i}/,XiA-vRHD2?:(xݷ=at# sQqJo+ O\ 6d2#Gzd^O* b MH<"=iw]_BaɷHw+ՄڴRx-M?L泔bU=?Hgja+ B- u(B {FP+h]'2;k* -bH4ϋDE"xhpDi<P5BmbZ/1Iݙp,EC6%82=<[8�{AB0*6'4kB[k -B%h͐!YZԟXk%yRbV=A/P!dгṳ�mÁ0 X+gk l�ߨvm.nWa6'u4ԣ`DzSzP*T„@{Q'�yӆ$0;QKa)i!j}[X1+Y&H+‘&qz -WОF 6ȏ 6a}CUIX ̃>SמtM5X%QAjiFfk=)k 0!vE*FZf DEsFbHFn⎳/)&EuWY^+kM->2jbX{M$SycQ + LM&$`VE1+FoCCHYrK|P&XhO)] h@+|/l9~C4 PI,#ԉNО EZw8nv(s4 4"qI~n>X3.->c3sc -g[ֈ JGOI4kvը}bƤܭb)&7- hj6mwVfĞfhu qK/Ztʢ^ =^ -638aGV۳4( R4E`aH@(yQ('A4T`SdlD>b,+^YὯ?67.OĕX0dZoymmݶDUr\]"W#gTxz0sbD7pV, ]x5Ěi E $^Z$VppBV֠bdKmQKMd]΄Vl|7>6>ϯw{>^vxukro@#-Yo޾ܷ|ݳKʧ_�'"y -endstream endobj 119 0 obj <</CS 124 0 R/I false/K false/S/Transparency>> endobj 124 0 obj [/ICCBased 85 0 R] endobj 116 0 obj <</Filter/FlateDecode/Length 1232>>stream -Hݎ]5 SI)pBH<%}Nˏg%,/;s+_~.t kí>WϷ{&_?bO_k7a7/KϿv@㯗1ieXۣig]~JhXKbWuX//SwO]^b6 ~B>7<-w;zYy`<te ^GhGO^cq3vM|cpyMcn)mdsx+s=P@z?ͮlc]ҏg }Y;"ɡ##V0˧+V yq˂axA ȉf:^ EW=iG;7C y]5H;Ŵe:,`aFV%.5@ -V{�uf �BAzD][R4%]sdqjG3͑~w* d-=vȱ=2"b|fm62i 6 TӏEVr$=@.w?RXkՔEQ`BV,ٙi(P"#_1rx$P$KGp֥,2kv,-$K -L]K@' 5ae_SyzZ/)#`BU.E8o' ȳl?c�3tkg$Z'I4UK ٝyr�N H\MI^ф�q6B*:vB&pJS&%-$`ӬrQ6(9;35=R )c wH$Mb&;q${*wK _ъZRJo9-M)@Ej`Zmv7fφJBYD . 4;beb F9sNfw˶p,XF\"-gOAH';1sT YԪ47~َ[\={L5~LWBWyF~},vr%5L@bu<)5! TMq׷7)P#:{:g P&a潒e޴ŵo'=D t_TH뒕LižTSp�MҷaWD]Cެs2TLMuA<6\~$ >D(hqө;];IWч#s# I -a}}{=7?� -endstream endobj 117 0 obj <</CS 125 0 R/I false/K false/S/Transparency>> endobj 125 0 obj [/ICCBased 85 0 R] endobj 113 0 obj <</Filter/FlateDecode/Length 1425>>stream -Hnd5^#q-`@Z )0BQ[)??t=瑝Gn%Y_n?xǒ~{}._Q{'$rmM~ARܖ[.MϟoTɮي�-O=o~Ғg!e5ֱo,XG,5=V>c0 8n0l%/\p/m*8Y9tiKM={5[0r΁36 ە h.܇=[1-isZض3~7xg/U##+G:~P|y!dvpf@7~r0fmz%a)[6],�޶֎i/KZe#-ٷx ~><!JooS6q:A -b UE* f'(P/R$oZ( - u(SȆ={@&& -RWKJovgQÁA>2`{'nB}Y.bRDD{?uqP)G}luI!McEZ7ǴFjʅn)NԮƞђXjm - J<zuR%)!Pn@%J7Z)嘱i1*GΫJ�L8)\KPXW(<ao xY BnQS[Sn*R aq%+wRmE؉"љS̗s&֮=:AMToQB"HQ:] XyIx$ϞN'H!WzUD Ɛt!- kwIq='GJ$6y(u&YXEoe!S=8r!LGt[d<J$z"F@#bPMCTYDpe4ks@Ol1ԍQIS?%5س$3T;t@Bz昩do,) ~}Gx41dӱUcŽbSuEǎ+ a(ev3ED# HonCpqKP'%&١"=4Z]jKfoD5n5:($h@_MQ iTff" -Üq;B& -hu*ؐgѣxR3*Ghpn0Xwp WW$@4NH%"SVc9i'۩1QdɈX<c=D5%dmgw D(rdz.c7]>( ,!�j\1N&8ݎcytudK@4CWčX Bґrƛ81gC'Do~s -��+E -endstream endobj 114 0 obj <</CS 126 0 R/I false/K false/S/Transparency>> endobj 126 0 obj [/ICCBased 85 0 R] endobj 110 0 obj <</Filter/FlateDecode/Length 1073>>stream -H͎$5>#م +4h{^;/񅫦B5=v:US -x -O|]|,}Re׷߷6.?Ÿ[ -ڞ{<r'cq4i)Ci[m[kEO>b5x>?EJrl˔eX+^�Ͳ =֜ն<f!טruq;xr�-2J][M5GxTbPJ.Y%Ea -*pva#t.lהk(#ZLBmdqY񘹎ܦ^6ek8PM$3RpxVj\lpm"5b΢٩WB6)Њ[ŪAz]<HfpON$s>##[T~CϑJ 2@2s]@Ѝ�rD8ݙ8LO&&V/w&V)b}cb'sew&7"pywusx5D¢zX"ѨyBucPRW |',|u�LQ.۽ Eƕxqen1TҴb^?V$F S55Vr Y -,4i16rWK(R-fGȩ m:#Ab�k+s;`)!L\-Y,\?M4x4ט %"Jxu6R�2v@'Utc?T)8]*eͅ]=`CR=vo@lN9+1ܷI]9->5xT7c*seĬr+@O` "N۾Cṯzs,k'Phd*#@GY%:m_cx-Cvk -�45@e]Cw " IyuQW6'>f[UTQTĚJͧHØDe WkKR7aݧȲ>"G&•XnU?"".E�c -endstream endobj 111 0 obj <</CS 127 0 R/I false/K false/S/Transparency>> endobj 112 0 obj <</BBox[0.458298 136.0 140.458 -3.99998]/Group 128 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.458 136 140 -140 re -f - -endstream endobj 128 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 127 0 obj [/ICCBased 85 0 R] endobj 47 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 129 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 130 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 34 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 131 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 48 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 132 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 133 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 34 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 134 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 49 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 135 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 136 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 34 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 115 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 50 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 137 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 138 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 34 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 139 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 51 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 140 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 141 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 34 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 142 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 140 0 obj <</Filter/FlateDecode/Length 485>>stream -HSˎA Wn_V(\Ȣ%/Q(!4JzܶˮDS'jow]uKLp}Oo/oz8xv%n+G;ɳ.vl{�sŁC$1>ik`$I6O!5cQwck1ݔJDUi#bj5BQyVL05x! 2WO-$}kۮZv4 >QWiH^ZP&9:BJPR#AL PT�Ӫd%JMt2}BQc1 -O%ȍ-$Z;Gԩ9Ǔ[O ~rmVA2E$iQJv }@XܡX (hT yzma:H^XH 굎[{zH~��Ķo -endstream endobj 141 0 obj <</CS 143 0 R/I false/K false/S/Transparency>> endobj 142 0 obj <</BBox[0.166641 136.0 140.167 -3.99998]/Group 144 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.167 136 140 -140 re -f - -endstream endobj 144 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 143 0 obj [/ICCBased 85 0 R] endobj 137 0 obj <</Filter/FlateDecode/Length 1106>>stream -Hn5SxԎ a"xdАNݐjrr]N񱤯?<㛏z8()9}fKO|{yx5gr§Q-k/_K}Ts.;׵KNt=.N\LVz@-ړ{5 6=Ys|Ⱦl ?Y7gZZ[q91Ry呧Mvm!(q,_\^Wۖ\^yRo=d2nȵt3|%˲7<:NƆ쵉\Hzv̞ -cPpNXk"Y!04ԖB RG6 ^^8wK*?MK޽9Д&}ih<ʪbh7h ;IpKM̏tYyFAJ`^!rM* &Ase."RII;ԶC^] WNFdC.IţPb -fxғ=J&{3Ι:8tvzEM^V$9VeAl4'\Y0INJpLؐaS']/-ͽT�sg*){=HYZz~>pDXttiE%qsM ]6ns$#Kߌv4]%4?Mz9BsH˒ -C[QCi!wwM-P4XװzKQJMY5ik"^登j%Jg ~^{qZ4[ҖqO)@iLl2zlZt@5063. wFwSOw<D GQ2w_pG#dzҪ$L,0K}mUDJG11ddOKZjty2Ũ&( -,1,i- [D_]Ospv=LX/Xߢsz]K:UOG+L"@ǧuȿ7_j?� -endstream endobj 138 0 obj <</CS 145 0 R/I false/K false/S/Transparency>> endobj 139 0 obj <</BBox[-0.125031 136.0 139.875 -3.99998]/Group 146 0 R/Length 64/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.125 136 140 -140 re -f - -endstream endobj 146 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 145 0 obj [/ICCBased 85 0 R] endobj 135 0 obj <</Filter/FlateDecode/Length 710>>stream -HɎT1 E+F*W!Öf؀P $>İAq -$J\__ꦜ_M9qjW_Zo-|bu-Hx쾖'0qo <\>%lK/|Z.:,nbZ.G.'eoҺJV.IMzkEV25un{#ڋD@S$V9:w,]GT )8 pTƊb2*>>lHb,{[^lI!3}Tj]\#jU!CT4N馹S*Z -r9 $f>[#I%CCH$(mB`yYټK%<KS/s{G[t\ݷ%vI{NX{0b&YeO}OMwx*2'#M#5'L@ƌ#FvU hȘ0(vh 2lbBbQajm5jCʊշmmz:ha=P9X/ ovxgg7"zL -sBM<.2:VPhXa^ɼ4k6=W-Z]<Нi:sCa5[I{ z9(G{ܹٜ\FV ax {u-_�� -endstream endobj 136 0 obj <</CS 147 0 R/I false/K false/S/Transparency>> endobj 147 0 obj [/ICCBased 85 0 R] endobj 132 0 obj <</Filter/FlateDecode/Length 1994>>stream -Htn$7</ 6 � {P1duKh"'22s|~NO3]}=RRxҷ?~ _XK -~cï?]~eO<s[/|~ѱY~A_5Ts G+vhv< -)ZT✜Tc)=8 -ײ0Xk-!7` O3&XMmReZ1OjkN 8l-7p&Uk\1VqHwVa5f X$w-֐-ZCMd6dv<bb#r=I1ˣBz%)Dc<b"MM-ᆮd2n.>Fu Pcƻq5*y#΀.ݾRWs'"jSPh䶡ǃălǼ8Iw6:E]Y{h$i26ͅPf~=]UnjK(GV፱6g5KvƝ6ၨG/ׁ0{'2&%qU<"ݹƉv+b:B QNSEL 3jװt'NIb-<u"vIvNifMf_}jpRz,J bP$AIb -2?wPeiMEXQݎԨ9e5w<vSSNY -Y/(8m>ЎNjǭ#p=  \fh@5VLy9y)͔N zLd!%ܨl.U- WU'gѣRz(Fοb-# R4ޥQ{DHzta΂|L.7mTS06H1qD铸idivU{,iEE@쭪Bє -@]AeUgi#p$z,4EշD>V!YQ%n{>L!T2%oƼ1@ r:lZ;<]Ixݬ�u:wT`rS79}|ӫf@gr`VU -Ȉ,utƴ `bu: -%AW N Zl[YgB .�Ks/mC- TdRp#d궔CZNtxe#yL\S  -\+ް-X+K~�N̛yVM4 -&AMr4_Yǥ%5$ZN"DTʧ46J,d2e+Z5[!vwj:*樐 %[Gxm h'dH2be٬Dj%m~W[9nq>8kս׳b>Jֹ{T~ý{г.*[ony+F2wO-Ȗ[<g{T/-pn M):}3bnj#rD&S\目@^Ď*|֤qJiʗTꠉg֦GR <:3y-r]ШL1|հ:Q$ind[K oxDV~ \{KvTXWMs>7"u8ѕFvUXJTUp#|L@^4kުc4eWI]'|@esn׺ڕ]@xu"@R.L6Aόt -6 3XD^3|Fќ"[g+}s#sQŘm}seb7 !,b7VIoN/URoHSYݎiˌ(Ƀ")=;s5X^c@M6%Rzu';=x9w@/#“[_R~-OOy9'�D -endstream endobj 133 0 obj <</CS 148 0 R/I false/K false/S/Transparency>> endobj 134 0 obj <</BBox[0.291641 136.0 140.292 -3.99998]/Group 149 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.292 136 140 -140 re -f - -endstream endobj 149 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 148 0 obj [/ICCBased 85 0 R] endobj 129 0 obj <</Filter/FlateDecode/Length 1328>>stream -Hݎ]5 Sd'-S -U �G@/:E/-L;"4v^^OcI߾zL^ἪՇKIoIW=~.鏏lLJJz6xVqj2[e/ -?5yKOsQ颅˵YF*1Km1z}uw8UrcVKChsxjC+ƟQVy6U؝-l]GjT=Y $u{q1.k6b=sS,;ԼG�kQْWBU<ÙK7)�r -ctnx+5\c KMuFN.)zQ,'h\\V;1I }K$W 6d<&d@dw53sëA2}7�U+cuY%4X Wl$Yx ^(8 Րx2t\iF%\X:`kx &ѐ{)�qL>$Ɔ>λܰgj]hwqK?CA8dDl9o“BϏ=t+L81+-EPk+?9D6WUV_pv -Gyj@S-`3/x(2Ɇ&K57e)2J' =;Ju\t'2qbXG*_q{w%!`DϥFjC1ץ"5"{T.Z%*%CH;'a&HҽRƃPx#F;&<::͌E`!k2` 7+b #:£*`I}1 -4J@sm-A'beΩQ䬉:OUN]-�6j4o -bu+GE!dRI vOcԨ>ɷ$yBYE)*i3L Z+ШA ýcqD}5�'{-"t W]ٷ\pUk}|5N iBPwuB*ť21ch~Η9KQ457$mԱ*sp#KMY)N Z;Y=㈉1>,b+-mz!IH1.MHR ϓݥ(Qߩ?BZC!qn?c<.RsB]_5e~veO}o. 0�' -endstream endobj 130 0 obj <</CS 150 0 R/I false/K false/S/Transparency>> endobj 131 0 obj <</BBox[-0.0000305176 136.0 140.0 -3.99998]/Group 151 0 R/Length 59/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0 136 140 -140 re -f - -endstream endobj 151 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 150 0 obj [/ICCBased 85 0 R] endobj 42 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 152 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 153 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 33 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 43 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 154 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 155 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 33 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 44 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 156 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 157 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 33 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 45 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 158 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 159 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 33 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 46 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 160 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 161 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 33 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 160 0 obj <</Filter/FlateDecode/Length 1087>>stream -Ht^5 )F3Il')B#xLQ(ک?=|\}䏇sї[߮_g.~HLJ_[Uqj<Gj<(ۣhvQDʲzuuk/q,u]VDREp(U {rFts9.7Q2FQz`Ym=|jהBIcjfSˍg Q҉Z}uΪyӒi0j}v!$W2nC#NYE6@&֋/iGVPӵ: *eF�GdM~YnAhw3v<8ŢӶ?)J=!&:Cml$#_-1w<_DF)rbb抲 0'`TcV}KNbϻvj5ӄ{H5oFFckT<pYyu)zscbAwޛfD6`@A#I03`P"d$lmht'-Q](?r1z{FK uQŊ[OYP뷓X[v$$!*EMb#B}̖`~oyrsb NN5$Ŷl>M'4Twov vz5-Ȼ;v W�!G P -J!'{bwy{3ގ, wOK<Ƈr,>:f B e5b2BY4rh72̈́6QbmYXXkK_[Q#1> bR920K [Ĭ"?&Yo1GJ8=]^ t,05F?Ccr?]]V vJޢv9LcZ m6KX!�'&Ht$p|5r Jihbݠh#@$dZ3s:m)7h 2-cܣvO |<] 0�- -endstream endobj 161 0 obj <</CS 162 0 R/I false/K false/S/Transparency>> endobj 162 0 obj [/ICCBased 85 0 R] endobj 158 0 obj <</Filter/FlateDecode/Length 1652>>stream -Htˎ\EDw5~l,d0,f_Dԝ YYȚ_q=?RK/Hq?\~?>ӯ -k<}`#o36n_Ǘ'M2ȿtZLGiy^/Z~\S)q\cX94Yf=n\G f|'VVȵJ+bR#Q, -}]GFqa.Uw$Qs#1ڶnaɉ8ӛp\[kjX9R+K[ՄKh9%VRyQ`.~ HP=!*!WcL9͕ߥn-e7\U0mfՒB˒GL$ImbpY|}$$#TI"Ԟ9Ҷ@wEt@B|T-IK%̻n :ZSfҀ#$V`XSB&WLvXi/1KF}:HNmLgrcz:}Vj($vٟ:WXl7VYK s4"aka�NMnSѶJf1. -K ;7CAX^J92oiuR7W*O8 MEO[k#WVC*&@]?Cx48۔DDY%�KUҴꁔO!%mE$A{Т AqI6H9^d8໸- hJ,܅:FDEﴓ4^2*s>W-T -Q97H$'8LHQL`Fք ?$Rųo0F(x'd 9"&6*ldn3YK24QR^ -ļu%,HJi͇Uey,2#�bX(g`z'ijA^Qj.tIZu#fqJuR/$Aw/2I΋x~ !X(KMLCRg G+TM=ֻEr&! .%;cVP $,q }P=hR!}};ٌciVa/kT/*AśHPT'�rG<O/ζ"ϖP~=l6KR| -Bܤ�%\h,+ꀚv˯=T(JEH°MGUut *$M7HژD5qRd! �oAb3mXw:ӍCp[BZ=N_ˆI/ Sٓ[dKheiAOr T+~F%x)s7)d2ao�u%4qEq$4<k1WKi -u|U),eŹL U6\( v=M9̇UYyiz4S8lG Z]Rg*Tގ!඾ t!<Xo#d &굟+4I@;<ΣzPEU]Uq9ȁg aL|7S1M!AJ1tQR�q}/Qυ}H:]j㾰Gh7v?p|?opW� -endstream endobj 159 0 obj <</CS 163 0 R/I false/K false/S/Transparency>> endobj 163 0 obj [/ICCBased 85 0 R] endobj 156 0 obj <</Filter/FlateDecode/Length 947>>stream -Ht͎7<X$"�ʁ L]UM]~LO%_>s9~d-%=_( xV҇71\q}Ir(|,(-yfߎF*yj^u}W^^z<x.c&VڙFns$ ՝{4J. 76WZ%[n@_Vsݞe]y583Yvkkv- o<y\yz-{'ّ8<RnA1<k9qʚv)jɣSu1fbP`!Jx9Aw6s n3^C6 -ύӘp\LLVvT̼:s;JdW�l-(zKAvSe -m]&`ozsZ:Lʎ3XT"*+2[ma@vG&|h]Wr:*iكcQdKh{r06y`vp 9xH2{[-v`_fN'# @#CDgR�{I~#zdC"ar5{A 'ŸO+1} -rLšؤIUUH ػG̓_lDocb)z<} ~:h`ۤFu0=K"!D.Ʋĕ̀X.?n`nfO\ܚχ >SV-!;]:]f&yp7Zқ+aOY\6 b>г -ɜ~ -#bM1=zOTy1wY]y(1Vq pGBl _v=Ͽ}:`�uq -endstream endobj 157 0 obj <</CS 164 0 R/I false/K false/S/Transparency>> endobj 164 0 obj [/ICCBased 85 0 R] endobj 154 0 obj <</Filter/FlateDecode/Length 172>>stream -HTY -0sI&iWS"E[?P,,|slaW'}\ZJ% CNr$=v3C/3Z&S.&Y0uCV{̀( v zV=t{WWbƒ(aiX'ُq?�6 -endstream endobj 155 0 obj <</CS 165 0 R/I false/K false/S/Transparency>> endobj 165 0 obj [/ICCBased 85 0 R] endobj 152 0 obj <</Filter/FlateDecode/Length 302>>stream -HJ1 yI{kWqa`E\eb_t:'AJM/bW@]eI'AWwOB__p`"2�r,pU T:'qIC賋CGU/*p4>e>Bg<&6P#LX O5vWS/ħhd) JTڗr:py#AKi*JC4Iʰa2 Eѷ.m$m%#[ngtIh߾yv`�% -endstream endobj 153 0 obj <</CS 166 0 R/I false/K false/S/Transparency>> endobj 166 0 obj [/ICCBased 85 0 R] endobj 37 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 167 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 168 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 32 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 38 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 169 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 170 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 32 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 39 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 171 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 172 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 32 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 40 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 173 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 174 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 32 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 41 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 176 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 177 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 32 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 176 0 obj <</Filter/FlateDecode/Length 882>>stream -HlUێc5|WN}, !4$>eEHA= BQf\V~>s|8G9-^[_Sl-y__.\wג?qxJ33'?JJ28 ?dc2\ N}lJVw y*M5k'ey&?&DJ37P|I*ljq  6n9۠zY/G/7 8lS?6V 筐֞7#QEm=m46nj@cW9R tvB0je೯% ;Wh6úH(4G$AKkwۉAM -"k`o+^Z#!kiڽRC"ɪїȪ`0u3؅Hp%1n͐@PG5aCNBg EX<@ Ϟo4GoFcyw;(ɛŝ 4.@M-TѰMQ>`_h+eD)7 P7Zda]E-zCKk@ Nh@uR7x3@6"aG#&Gí ]g]�1u҆jw'6Fu`(riMoA+]wIK`W7D nf5x/^!ZYgss2js9>qܕPɞ:8EZyw*8G Nn=&;pr\e<7jxn6!؛vzA7"Ρe1P!J?i)+�tf -endstream endobj 177 0 obj <</CS 178 0 R/I false/K false/S/Transparency>> endobj 178 0 obj [/ICCBased 85 0 R] endobj 173 0 obj <</Filter/FlateDecode/Length 242>>stream -HTMKA 9a3׵*UԛEҭf-!Cyy^\Ь bYVk}<ytFص xs?0~TPĸΌ ,*r<0U^;@9 k\j)>aJ9H/u_p.<#i> '!gdb -;޷8 -fGm$'8AOS/q9>gڽ/G�ѬLY -endstream endobj 174 0 obj <</CS 179 0 R/I false/K false/S/Transparency>> endobj 175 0 obj <</BaseFont/FAAGWJ+FFDINPro-Bold/Encoding/WinAnsiEncoding/FirstChar 45/FontDescriptor 180 0 R/LastChar 90/Subtype/Type1/Type/Font/Widths[426 0 0 0 543 543 543 543 0 0 0 0 543 0 0 0 0 0 0 0 638 0 0 659 605 0 0 685 305 0 665 575 0 0 644 628 0 0 591 571 0 0 0 603 0 548]>> endobj 180 0 obj <</Ascent 1195/CapHeight 712/CharSet(/hyphen/one/two/three/four/nine/A/D/E/H/I/K/L/O/P/S/T/X/Z)/Descent -206/Flags 32/FontBBox[-145 -206 1174 1195]/FontFamily(FF DIN Pro)/FontFile3 181 0 R/FontName/FAAGWJ+FFDINPro-Bold/FontStretch/Normal/FontWeight 700/ItalicAngle 0/StemV 132/Type/FontDescriptor/XHeight 521>> endobj 181 0 obj <</Filter/FlateDecode/Length 1353/Subtype/Type1C>>stream -HDS PTeww]ayM⽫E!F!"$0Ve˺fc A"b@R -8c%L2;sss{;e4*eY}b|ʵɳVsp, DdID1 -͑O#5Cal 1*5;t8K]ynExrIζYdlɷZRcw8n˞.pسmƕI\η(V`veJKxi5.0Z 2: S30Q,3efL,,`E Oe<OeXMgٟTKTyJתyJMäu= am,5cߪա WD Ez+m5PQ -Z*VF-DAC�)�Z,@S�J p�q0 ,$/Μo["MZaV�X$A@�Bcas)|λ}@g/2=bW-m]5E.A\YRr3f7(} B7aL@0Pw TM*F S1L-3x,3:_E8 X(^-nGcИEh)VS{Htfz,k2:n<{=7I}@èI FM<3qş?MX -qrB, AV'@0yƫҭuI1"VrV|l@Y@MYVM=]^/BAE!d]MzAkg B`̤յ{T<އWC; (d^:qO̖ -4KH<6_^3MG^WMԐJ{ߓ 4^9ihIr"~€ԝްP\̔-Fрb)sP- V - -풻xvh|~l" yQknۛ<< -+A(}Jt`t`#$?[) -H-.]!nhtS#դr}{-DαWTz&yzZuλSy>Zyscxj͆MrtI߮STywL)qޫɩfIqq\Bb$Yn+4p8EO0RC !4aaPM~EXȁt-m!beQ[$,tQpWÊp8P3im/j>Vx\ӒQI��' -endstream endobj 179 0 obj [/ICCBased 85 0 R] endobj 171 0 obj <</Filter/FlateDecode/Length 881>>stream -HVnSA }_1?pxWR@BT -%ER}g"'^(=zl'[Zfk47b fէߖ;k~<—wGkn~-w6\q6O<,G,^lB!.1"$)?.zk(y߿xr!a7ϝP.]vh#v72m?-B.Ӽr:(D8pL QrBECИD?;lYg=ыMmW:sfm h)I(qĹĜɁ9K>UeM8h|8ɣ%Im L_R1uᤆVjl)V}p : -# - WGCXdO'+2ρ5fE>yhPTu`Y 1 Khh -Vs)t^kB1ֺ;"3…DO<$O fQ#Vz\őͱU10(Z'&Z}=Z[AQgmFYɆvÜ5 �3J"bMUE(+V M (<8s� -HI/+amhP&)y2(ڎt(8Ć�Ūͦpj}ǺN`۪OЎ@e+> ot8΋ו;a11j(qPK\Gs <o#\Jj.R0w4\4hx6 ЙIA%vj#BeC`ו�`[+Q?h/8gN�Ug �u,�A'~Z*iergn+� -endstream endobj 172 0 obj <</CS 182 0 R/I false/K false/S/Transparency>> endobj 182 0 obj [/ICCBased 85 0 R] endobj 169 0 obj <</Filter/FlateDecode/Length 841>>stream -HVnS1߯ds%$DAUP -.}uoeŦx<3qf{,/oo[ܶ~,pt|`h͗Gv݅ l-9-ը)VSQl'bxGI8='X x9szXTD(пxӲBݔ@"nvd`_@څ9mWgÿG p7%Pr@|x*շƔmX%.SIqwزhkXxwq+3JġB˛ G,Ŝ'f!qY -IWqyc6S~gbdk?^_|zV śȧMVh6RB%U /D.M"8/yI\pW[TRV1aJL8fhC -R@bi1qG1uEDWkqc JԬH2(S(2#|>rWڱTNMjWXJ-ɯc;6DaG8ڒɧR# })XDF�IZA+74Hh%eltR[5muYJUmHt4)i3"F<^l5-ǸX"Wwj2d;&^_C\C*@\=ϊĎu*&D o xOMD$\ dP{uSIjJ6ptGTۘOlQRvETpu !*)f+Hݾ166mû��=3 -endstream endobj 170 0 obj <</CS 183 0 R/I false/K false/S/Transparency>> endobj 183 0 obj [/ICCBased 85 0 R] endobj 167 0 obj <</Filter/FlateDecode/Length 295>>stream -HtKN0 9/P7v6 hT$P1` 8 ep?7vp\o6-j['c|, <Qlw~ip2N1@u<ݛ1DOE ieй$LI]b(R#Chh)]Bb| 9cZ=jr9&˱#d ,ʞQkje0FՖh㐹өh5 kP; LP-2E8Cm8*w̗��x -endstream endobj 168 0 obj <</CS 184 0 R/I false/K false/S/Transparency>> endobj 184 0 obj [/ICCBased 85 0 R] endobj 27 0 obj <</Count 5/Kids[185 0 R 186 0 R 187 0 R 188 0 R 189 0 R]/Parent 20 0 R/Type/Pages>> endobj 28 0 obj <</Count 5/Kids[190 0 R 191 0 R 192 0 R 193 0 R 194 0 R]/Parent 20 0 R/Type/Pages>> endobj 29 0 obj <</Count 5/Kids[195 0 R 196 0 R 197 0 R 198 0 R 199 0 R]/Parent 20 0 R/Type/Pages>> endobj 30 0 obj <</Count 5/Kids[200 0 R 201 0 R 202 0 R 203 0 R 204 0 R]/Parent 20 0 R/Type/Pages>> endobj 31 0 obj <</Count 5/Kids[205 0 R 206 0 R 207 0 R 208 0 R 209 0 R]/Parent 20 0 R/Type/Pages>> endobj 205 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 210 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 211 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 31 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 212 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 206 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 213 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 214 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 31 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 215 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 207 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 216 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 217 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 31 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 218 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 208 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 219 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 220 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 31 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 221 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 209 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 222 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 223 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 31 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 224 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 222 0 obj <</Filter/FlateDecode/Length 403>>stream -HSN0 }Wq.+„&64NvP6>4G#fsW(nAWvNj/ 6fM6*\\r=+AbDAdL.YGS G1J*^E:”`'̘ $8\ <L* 2Ţ6)` #^fTpzaP]xqh!h3vhIEZLiMǁ&9.]7HI{oZIo6kܧT6{<cB-b#YÕ!HHNtaM:UꟚxo 蔭fu:YƳ-HD5U/G!׳U0hNdYvLTr!Re+yq߫BB̗��tR -endstream endobj 223 0 obj <</CS 225 0 R/I false/K false/S/Transparency>> endobj 224 0 obj <</BBox[-0.375031 220.0 139.625 80.0]/Group 226 0 R/Length 64/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.375 220 140 -140 re -f - -endstream endobj 226 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 225 0 obj [/ICCBased 85 0 R] endobj 219 0 obj <</Filter/FlateDecode/Length 779>>stream -HUS1 ԍIt +KwѲLBU؉3!o99-~ˤe~sSzcCN_nmwŰQ8>%t|`XeG2>F)x=7:]5%i+b/ߖv!CmV,57`Av]Fnd)iRzLX[M; X`%@SUbwnŲsD6:"z91tyPTuV<6ⴆb9,KHL\Y&5Il0{)ɚύ)tQCn0fd܎e8z쪲ݑ -obL B)aV(.MDqrHnA8 2PR8z4PK:8S5.ᧉ)#ELjs& -Qn Su 3k9aCHNK 3Ȕ8ŤUiLyYcx!E@ mcvkʧB6KΰW],Cs)vFX[).UNx^]Q!gdSA ̩C"t,&6fP_ֵ^0v],VjkӐ_PQ- ;Q+la(`CM ˉycQ/ dQv16!.PԌѭRFc*'qߜyw^i)~!8eyܒ~k{Ww/�@? -endstream endobj 220 0 obj <</CS 227 0 R/I false/K false/S/Transparency>> endobj 221 0 obj <</BBox[0.333298 220.0 140.333 80.0]/Group 228 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.333 220 140 -140 re -f - -endstream endobj 228 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 227 0 obj [/ICCBased 85 0 R] endobj 216 0 obj <</Filter/FlateDecode/Length 1348>>stream -HWn\7 |?_q~Z/$(, R$[E!G$x^< ̥0~ ?op7 _?_>xryr;k-Ż~>rg.L7b<GpG.B88bYݐwqzeeXNӛ .ꩺ4JOv$Inj<-R)!446\EyB#xZsMv)+L͵8Ζ]ѐwGIiXTd,gF VyStZlJsjTX<Sqj%Ɠ\Zf<- -hJ@,]OMIN$WOvhЅ࡙TcʢOH^E,70/H֝ ʬlڢp;\0wTaA*qU5F'pqNqˬʹ<:YgS'Q ՕE( 7wo2ͽH< \t<XF' 掆Ғg.#h-nt4/N7ZC<ƃ\/SU0_W$?µ;GTʦvDLrDطBU0ÈN HimQ|(;(lGavufh+! > @{d�e2&^6נ&IZfuoߛ3'>`L(,A`|'^+`_p&p]B<cIM@&ܾ ԛ^b%"H7ss(%(|*B=fƻA_R[H3 .+K{+>yVRFs|HzTŜ`_ziOH-NP�Ή.`ڋR]{) n3sB¡cV VיZN /f@4\3A轶[Tzxp^e㣲6@./I.8/4|\<HDz$2ySS<șڦ�l ޿B \3@T5B -YGjK>\n-D{̓W4Ozh -wqu@Oo\ -yR-f&?lXL8Whɜ.ƔT/Y _#eY7j`7F$,)~Ma$"NONGLn\x4m[?~ߦ}~z9ϯ/n||#�ul -endstream endobj 217 0 obj <</CS 229 0 R/I false/K false/S/Transparency>> endobj 218 0 obj <</BBox[0.0416412 220.0 140.042 80.0]/Group 230 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.042 220 140 -140 re -f - -endstream endobj 230 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 229 0 obj [/ICCBased 85 0 R] endobj 213 0 obj <</Filter/FlateDecode/Length 476>>stream -HQ0 { -_ ĎJ Z X!bA \t;;Zj:q8?.0.n^kS<' 3tD/~~@pkȑG̋XN$T/D~!"uSU{)NV $R)u4}3jo{fR,Q.)0i 5ɷѺU0AkiPW�0l 0}oTv`T 7_jR,QXBK`v:,fж35˕5Tr7S|8u  7s.0Fvz+VL -|Th)�<% ]^3c;r nwh5,oav>|%9j.>ڒoe)(r=x_��"J# -endstream endobj 214 0 obj <</CS 231 0 R/I false/K false/S/Transparency>> endobj 215 0 obj <</BBox[-0.250031 220.0 139.75 80.0]/Group 232 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.25 220 140 -140 re -f - -endstream endobj 232 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 231 0 obj [/ICCBased 85 0 R] endobj 210 0 obj <</Filter/FlateDecode/Length 930>>stream -H|Vێ9 }ێ\^aj4H|@ ;>ǹt uǗ㓚 ?^]=IARr8ӿo9 >qx}{x#c 6X% 7Rp*J!)3GBK-O۟6TJIZm;#B7{6{U!{m2[('jɪS@ -} -e YTD,S)g$m١p+ @?[(Ê�XZ v7GRt05VwEݜ:*CD xl<Ae,Jt;`du$vhSZEP:):- :1!>XI9`:#!i=jT9P$( -L\:oO3 ܒw#kgRMb iD:v6֪ $yΊC[WZ -8A`b80],)"eمoF.EHN -^dnZ)6Ksbte�4dYaw"hwsTO"ʎ\X54dé,Xay؜Iq[I}lClע3OծET>$["&ІyL|wcj"^ (Zv}Nθ`} 'O{R;yif3sѢ:kiEJUrڰ Nk|L8pMp9:C,Y]8n^}heg0Me0N8qp3\0-8Y6 r4~3C+r' t�T&[$i 1A jk,ǯQɒm.ItAu@l~K`x9\:_ � -endstream endobj 211 0 obj <</CS 233 0 R/I false/K false/S/Transparency>> endobj 212 0 obj <</BBox[0.458298 220.0 140.458 80.0]/Group 234 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.458 220 140 -140 re -f - -endstream endobj 234 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 233 0 obj [/ICCBased 85 0 R] endobj 200 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 235 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 236 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 30 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 237 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 201 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 238 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 239 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 30 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 240 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 202 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 241 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 242 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 30 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 243 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 203 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 244 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 245 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 30 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 246 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 204 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 247 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 248 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 30 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 249 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 247 0 obj <</Filter/FlateDecode/Length 981>>stream -HVA7 +ֈDQ׬\bqrq)ivT*O)_=wh@Ro0\~3^[ -۞#yb\_'^?[X$S9& -{z 5^fX$o֚c5P @9BtRT<pKjXo"*o#mU"$=%2@p5}`r+a澹9^͚DI6r.4\-2|k=ĭo;A7)fq@^΀ػI`m:i6(9C .$%,ېhD,̫^Ȫ +,qZkLl䕎S5Cb'3HK5T u[ -c"[`s~"%t#uUY3^(p -ZG\^|uq 2ڑ zI֑ٻޅj9) -E 6^üR#P=sG|l~2C`9+(i6ȊAm3m-) x$(֠SFB"A+KPT f+*`tւzwY q5'ƒ -f(kœ�/< a3.&#;v+x>R$jwŝvY} 긡)<y.Xv#g焥( -Vg$gpmDîVSșK?L $&{:+( 1U}$Pu3*a[/`P!'S+t6fqF6z7lڥICNm -b#ҽ{q l!-"JY&ٮ#F7H~<um ʭz40HLh%J^�i>>}_at}`� -endstream endobj 248 0 obj <</CS 250 0 R/I false/K false/S/Transparency>> endobj 249 0 obj <</BBox[0.166641 220.0 140.167 80.0]/Group 251 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.167 220 140 -140 re -f - -endstream endobj 251 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 250 0 obj [/ICCBased 85 0 R] endobj 244 0 obj <</Filter/FlateDecode/Length 305>>stream -HJ0 ǿ)ɚ6kׯTO|P䦜ۛnsv"4??Hq[C-j0k=!Cho,ó>7M..: pCtu /h)HO p٫B*lH6p8(.j@ w3Ja>(9f̣isiRWGq㪺ĥ! -ՙK6fRŠԟ8u>OA5.qɍ|̍spn$:.{4J>$ #Ʊ1_ �b- -endstream endobj 245 0 obj <</CS 252 0 R/I false/K false/S/Transparency>> endobj 246 0 obj <</BBox[-0.125031 220.0 139.875 80.0]/Group 253 0 R/Length 64/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.125 220 140 -140 re -f - -endstream endobj 253 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 252 0 obj [/ICCBased 85 0 R] endobj 241 0 obj <</Filter/FlateDecode/Length 1036>>stream -HVKn7)x&Mr&F $@0H䌞 =?b~yO~6tN}$_ ;G~_pW _ᷟo?>K.F1;1'_V&?GRCsmjسmh4dnHJ N[5AőiF1 "pV=ؘ(Zεا)Bi1rZ,�΄ nTX%稬mb8Qb3 Q{C )XF4(6bJ}zGuagEZ 'zl Q̗(n+0i$ʢ'Ƕbqq,IPu,=IPHcuEB -RL9T|lo &B10w#1)|Tб.& pڅBfםL+=SԇZkv ES-!pP/@lHiL0}Rb�qb6*PyLL) \%b܃;AY#QP;hT/"- MH)WpsMb(yEz ث(' βrj*s*oOخu"< "(w4ju(008R4g ȾHrGHus=yn_W^ZA0J(ѶiuvICiq}ӱI7'yh_+5[2%6<ǖC'6H<9J >~E]wr9jd@1X5hx 7̐�V ZЅ7D)^4 05da�GO䋧hJB%MHkz[p_+>~xE -}*S$V$N"34фk0HaOeDZ9ILR; 휖 Xh,0+a:{[SNѫ346۰]s8 G吏ᅭJ/6zq[�Ł -endstream endobj 242 0 obj <</CS 254 0 R/I false/K false/S/Transparency>> endobj 243 0 obj <</BBox[-0.416702 220.0 139.583 80.0]/Group 255 0 R/Length 64/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.417 220 140 -140 re -f - -endstream endobj 255 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 254 0 obj [/ICCBased 85 0 R] endobj 238 0 obj <</Filter/FlateDecode/Length 330>>stream -H]N0 s -_ bH& =8i"ec Ͳ%Zr5^@z8ێ O͖`Vf`~40~еʢI GQAå^T!yt&FH!VGGcb3J{{!<Ex`Du*Sg = tʣ -[ S@"kJThpOE #?~w,1g&ÔՌY:(֤`플83.2$ôNt5a.]Oϓ_ٲ?ʮԗ�� -endstream endobj 239 0 obj <</CS 256 0 R/I false/K false/S/Transparency>> endobj 240 0 obj <</BBox[0.291641 220.0 140.292 80.0]/Group 257 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.292 220 140 -140 re -f - -endstream endobj 257 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 256 0 obj [/ICCBased 85 0 R] endobj 235 0 obj <</Filter/FlateDecode/Length 348>>stream -HSN0 }WڹME*.BlhafE(qs\'u?@.˥,|V-˻'e'՚`VgzXUA4 ;ePGo2o g+.`x>�Ze "yȺZs'YB'ST?O5y=ثar-RNG)Ttf^H -9D(&Urpic#A,P3#~>NEh1fڊ6.enq+L>63ڄN7-CבKIhOlϚ<ZJ} 0�OY -endstream endobj 236 0 obj <</CS 258 0 R/I false/K false/S/Transparency>> endobj 237 0 obj <</BBox[-0.0000305176 220.0 140.0 80.0]/Group 259 0 R/Length 59/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0 220 140 -140 re -f - -endstream endobj 259 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 258 0 obj [/ICCBased 85 0 R] endobj 195 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 260 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 261 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 29 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 262 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 196 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 263 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 264 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 29 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 265 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 197 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 266 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 267 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 29 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 268 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 198 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 269 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 270 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 29 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 271 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 199 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 272 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 273 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 29 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 274 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 272 0 obj <</Filter/FlateDecode/Length 325>>stream -HRN0 }Wڹ&!LvmiP&'9v<lZU v#?]&.WGhYKmh^cVB2kE~~ȼ"E$d0䀎`wPtB T[!#YAWݵZyw%Bp!C%ml2 -{F"/b 4Ҵݫ7)nEH>TGm]йL$`d ?zj-LH<ἋFrThaaj M6קbRkUJ%q ngݪ_�`' -endstream endobj 273 0 obj <</CS 275 0 R/I false/K false/S/Transparency>> endobj 274 0 obj <</BBox[-0.375031 60.0 139.625 -80.0]/Group 276 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.375 60 140 -140 re -f - -endstream endobj 276 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 275 0 obj [/ICCBased 85 0 R] endobj 269 0 obj <</Filter/FlateDecode/Length 623>>stream -HUMo0 WDֵiˊ!w0 CҢFJvf#(=R�Mcԛq@Xf /L>;~WsT~p2c� .ˋВо㋠8 }DSK OrbZ V4TV"bBD<P<Wʱ 8 ->5 e[Ya1t%E a`z_'# kjA TEfg GG^ }#e ftzN D%T-0Jhq 'L@AqD"֐$%㓄V _Jra [XEϪ|'cX]UQdjOJo9V{xmO켷=cuKYoV;[z:([ sָ2{R mĝ؝ĶloQvazг]4VT -U* -b{CDrлUmMV4L.Fe=}EX~VÕJ%!Cw9ڻ0|t髜pTC?qL 0ͻx74:?5(p4�? -endstream endobj 270 0 obj <</CS 277 0 R/I false/K false/S/Transparency>> endobj 271 0 obj <</BBox[0.333298 60.0 140.333 -80.0]/Group 278 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.333 60 140 -140 re -f - -endstream endobj 278 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 277 0 obj [/ICCBased 85 0 R] endobj 266 0 obj <</Filter/FlateDecode/Length 623>>stream -HUMo0 WDֵiˊ!w0 CҢFJvf#(=R�Mcԛq@Xf /L>;~WsT~p2c� .ˋВо㋠8 }DSK OrbZ V4TV"bBD<P<Wʱ 8 ->5 e[Ya1t%E a`z_'# kjA TEfg GG^ }#e ftzN D%T-0Jhq 'L@AqD"֐$%㓄V _Jra [XEϪ|'cX]UQdjOJo9V{xmO켷=cuKYoV;[z:([ sָ2{R mĝ؝ĶloQvazг]4VT -U* -b{CDrлUmMV4L.Fe=}EX~VÕJ%!Cw9ڻ0|t髜pTC?qL 0ͻp74:?5(p4�[? -endstream endobj 267 0 obj <</CS 279 0 R/I false/K false/S/Transparency>> endobj 268 0 obj <</BBox[0.0416412 60.0 140.042 -80.0]/Group 280 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.042 60 140 -140 re -f - -endstream endobj 280 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 279 0 obj [/ICCBased 85 0 R] endobj 263 0 obj <</Filter/FlateDecode/Length 623>>stream -HUMo1 WxcmBVđÈnQ2h;q2yϓ9|<^sԓ @ix>ã, -YX>]t'wQ8gqO2"RGΥzq:wqS.2D/m"2Rܚ¯zMjRTb`,J)5 DP(Y KV8bdB[pvPٱ;DFMz(bQ} 1bf %$*5B* YeUQGC -Eq*T$.*N'Ŭ)5arPHxuf7wv~_ez mI[ [oޚw{o gm)ovbgvb(vV'ecc)ZܚZTs>`)Fݙ`Nb&/P^0r_Y욦tTPi:H=B'rЅ-#lztl#iZbauu&+ŚKe*n0*Y x `ͱޭ{n9<(w-j(!䅰p击[aA> -'[�? -endstream endobj 264 0 obj <</CS 281 0 R/I false/K false/S/Transparency>> endobj 265 0 obj <</BBox[-0.250031 60.0 139.75 -80.0]/Group 282 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.25 60 140 -140 re -f - -endstream endobj 282 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 281 0 obj [/ICCBased 85 0 R] endobj 260 0 obj <</Filter/FlateDecode/Length 673>>stream -HUMo1 Wxv[P#q0 [TKXJFɼg='sxã;)S/qs`u ϲpx}88iN ±_YiIi_dCpESbtb,rL2a�FɷhfNT+LOQf]XQIJM`t%K{@(x$ˈn30p> SVϘ#k%U8]HX*+ -PQ!LԊOX{tHr�N<'S*ǒ XjA2]S - 25ࣆ 1CR @Ӆ4cʻ/|gci6.Gm -zU66i*xQX ;2 ;v5O]ۄg-u=5&G-g'-6b{uQ9fS֤ܥ{RumԞVĞ(LamcTMyyٻ{czᚚwO4V*\[:.~iaco[͸w߄;MkQZ8 c3rJ/Zcugp(vD Ƿ;Iדu67..9NAzfHIi7va:$g,o�? -endstream endobj 261 0 obj <</CS 283 0 R/I false/K false/S/Transparency>> endobj 262 0 obj <</BBox[0.458298 60.0 140.458 -80.0]/Group 284 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.458 60 140 -140 re -f - -endstream endobj 284 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 283 0 obj [/ICCBased 85 0 R] endobj 190 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 285 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 286 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 28 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 287 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 191 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 288 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 289 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 28 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 290 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 192 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 291 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 292 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 28 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 293 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 193 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 294 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 295 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 28 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 296 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 194 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 297 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 298 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 28 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R/Fm1 299 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 297 0 obj <</Filter/FlateDecode/Length 685>>stream -HUn0 +zMK"h~a"Jޭ(%CghLs7wgroBB.Wppz)c+ÿȱlOV43?(v\*>n9/RdKW؜=IMm.e#Tn))1!w.L28ʾQv\Li֘ -'{tqzPGV(� wnJLGʑDS,RZ\9D(?7H{FVBu5Xg@5/p*JP$x&!5.xK.M舘."x*(oz{8x;QގӨ\WuQm] QWkU30mKչ\j),o -L+>f8¬e/?5U"-=x<f9(Amu5'fnT##Kv^P^1F -#ЃG덵ns?7}ߓe w$� 8@ -/(Hr )Q؜[딦zG#= h -Tm .,Dy1j3Dn )U(o-�^nR -endstream endobj 298 0 obj <</CS 300 0 R/I false/K false/S/Transparency>> endobj 299 0 obj <</BBox[0.166641 60.0 140.167 -80.0]/Group 301 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.167 60 140 -140 re -f - -endstream endobj 301 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 300 0 obj [/ICCBased 85 0 R] endobj 294 0 obj <</Filter/FlateDecode/Length 554>>stream -HUˎ@+ܞy_bAQ� $}. - d%~U&ы&LƑ㨵շOGzF>^}m;8fzp `bp8<B1s >Rr*487geX5c]hhZuXvND֌QMt3טhExFpHw'q9Cx ` e(\B٧Gu #A1J5]34Ğ]BԐ*Z%_LRO,8!F:vik$.*̬KT,ku GIasMuc%HPˆ!i`Z@(ۡ W�_�,i;blS)kIv_ -.vy?_'ӿwC}r@))a,~ -<ٞ+~3 'vBKq1P .&<ɡIJ8 -˝{5woh{%UZ1L͋߇l>�DD^ -endstream endobj 295 0 obj <</CS 302 0 R/I false/K false/S/Transparency>> endobj 296 0 obj <</BBox[-0.125031 60.0 139.875 -80.0]/Group 303 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.125 60 140 -140 re -f - -endstream endobj 303 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 302 0 obj [/ICCBased 85 0 R] endobj 291 0 obj <</Filter/FlateDecode/Length 284>>stream -HMn �lʹtTE,TC&CTU(y/�8 G~EE: ʃ s*^ }>}7!x0 cf,)c)c, /^9$rfҐ2p,m1<(ӹ˾|$QU#2L%Ѥ+UOq[RulUC^󊬇8KdS*wl\.UI^D^D.lW|VAV`a݄fF#� Y -endstream endobj 292 0 obj <</CS 304 0 R/I false/K false/S/Transparency>> endobj 293 0 obj <</BBox[-0.416702 60.0 139.583 -80.0]/Group 305 0 R/Length 63/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs --0.417 60 140 -140 re -f - -endstream endobj 305 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 304 0 obj [/ICCBased 85 0 R] endobj 288 0 obj <</Filter/FlateDecode/Length 289>>stream -H_O0 )Z1xuOC0\ԋ3'~};�,emZ"."c#.(,i߯g0Ss2#b`_G?*I -wQd]U .sP౅tBVx*d ,9啟{4*ݵx^$BXM -8^`+$a/-UՊ&[iۧ(=2WIBrl݆ɹ,+JLϬ9sRU㢳t֦ bj`�3 -endstream endobj 289 0 obj <</CS 306 0 R/I false/K false/S/Transparency>> endobj 290 0 obj <</BBox[0.291641 60.0 140.292 -80.0]/Group 307 0 R/Length 62/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0.292 60 140 -140 re -f - -endstream endobj 307 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 306 0 obj [/ICCBased 85 0 R] endobj 285 0 obj <</Filter/FlateDecode/Length 1393>>stream -HWKn7)xzd{cl8bF- @nW*6GAMVF Hݯ"ux6dz3of{?'y؜i:ϯ?ݜy=qxgǏy<'8xӋufS smzl׽VDz<.n臘uOf}U# -/-'$>i&}*d?><Bs6e6E@ Hw6fBɑ6Cc)� B IƤ]T.^M1ZnQo:d:`kIxm-/6Gs-Q$쉖Yf}&he~ ],P*'$ZGqWe0-"y,``(:9@R,5.17gkB> -R{Z*+o@_ٽɨA@6e<X_qȉ j f>/U'Vfз2R#U⧍!À!6Bd�dvݏ yt|GΩU[dWXWmLT `2mz Q'ZZd - +S6ሥx|癡ʊ&!UY<ӞHCAJԡ-/0JӜL~D~u}r4l#5f -v\#.}F;PAv4�T>5s6秿ĈFKhL<cX$# QLke56T^(zyaK[ENZڔp+Niibv5WJpH%P`8oD6?>c69n"sv4ehsi!P<ǔ 2@ ]>*}Ymb{@Nhg)E7)2ޯg !Xb&TqEdۗ <c^Opt@Q }*** rv)I C1 e&`OM� T^G#wҝj'bXCxGv·o$pG({aNH9 m#A 3W]7#$*3_H W"xJb8tD*2 S n>McRŵb$Uվ:0v4K+*¸FVl~~`} 0l!4hƃ.lYҌ[qVfCmtyhZx:/$ hPNw:giD -#'0u ̌ߑ4s^G Q '%:p2*\,GPDcnCɈ#t `A:Q8x6ٜѼy�B4p֧KyƇO|{Nn<|W/�_4 -endstream endobj 286 0 obj <</CS 308 0 R/I false/K false/S/Transparency>> endobj 287 0 obj <</BBox[-0.0000305176 60.0 140.0 -80.0]/Group 309 0 R/Length 58/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 69 0 R>>>>/Subtype/Form>>stream -/CS0 cs 0.114 0.114 0.106 scn -/GS0 gs -0 60 140 -140 re -f - -endstream endobj 309 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 308 0 obj [/ICCBased 85 0 R] endobj 185 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 310 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 311 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 27 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 312 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 186 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 313 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 314 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 27 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 315 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 187 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 316 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 317 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 27 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 188 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 318 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 319 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 27 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 189 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 320 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 321 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 27 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 320 0 obj <</Filter/FlateDecode/Length 271>>stream -HtQN1+vvI&. TSJ~?H(8'B|J-|,qa;>W]3 23GR -eIŸPiRhڀ -sLen⴦F+i*/�UE~$!H6KQcF\^Q$:YvvW2.u+fB!`zI!mƥ@5<c=˸?w?n�\ -endstream endobj 321 0 obj <</CS 322 0 R/I false/K false/S/Transparency>> endobj 322 0 obj [/ICCBased 85 0 R] endobj 318 0 obj <</Filter/FlateDecode/Length 199>>stream -HlMj0:ŻGm4BPJ n~F.a >ء0sT6rh1 d4z7'Ƿ^qf73a1[Z&50'#Sm?5O8Wq%dDm6uQ  .@.?zQ>Uk0d%XRLQ - 0�@ -endstream endobj 319 0 obj <</CS 323 0 R/I false/K false/S/Transparency>> endobj 323 0 obj [/ICCBased 85 0 R] endobj 316 0 obj <</Filter/FlateDecode/Length 328>>stream -Ht=O07ر6- P*"JҁBr;rp\,ʔ:Gqr,^ǖ!c eK3RxAMA} KD7=ii0J=|R'r -0 ~aL6f.ϭ%A-`?Takjӽ}u6vy CVZGJT/bؼL +c=rCmGY:c!yNA#lc&o|  � -endstream endobj 317 0 obj <</CS 324 0 R/I false/K false/S/Transparency>> endobj 324 0 obj [/ICCBased 85 0 R] endobj 313 0 obj <</Filter/FlateDecode/Length 157>>stream -Ht1 @ 禃MZ],R 8v(*h?xm !|$| ܃2,3Y/;`=.Bgz}+ȟTĨS2%0col2FFsHNm3)D[Ж>s}�X%2 -endstream endobj 314 0 obj <</CS 325 0 R/I false/K false/S/Transparency>> endobj 315 0 obj <</BaseFont/WSIEAB+FFDINPro-Medium/Encoding/WinAnsiEncoding/FirstChar 33/FontDescriptor 326 0 R/LastChar 63/Subtype/Type1/Type/Font/Widths[332 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 511]>> endobj 326 0 obj <</Ascent 1172/CapHeight 712/CharSet(/exclam/question)/Descent -211/Flags 32/FontBBox[-118 -211 1170 1172]/FontFamily(FF DIN Pro)/FontFile3 327 0 R/FontName/WSIEAB+FFDINPro-Medium/FontStretch/Normal/FontWeight 500/ItalicAngle 0/StemV 104/Type/FontDescriptor/XHeight 507>> endobj 327 0 obj <</Filter/FlateDecode/Length 401/Subtype/Type1C>>stream -Hbd`ab`ddtutvss (MM,I)f!CG7tI2,SX|_1)9(3=DR1')D+1O! ??G4)'8#5E!R-?$8#@3$(/$3?/1G=7C!-H$#r2*݂C* RLRRAQ%p3\xyG_1s?ޗ }΢QΟ1`&` Y~3 R<Х;*|QˏEs\7GCkw:)>8XNkqvcaTǕ'-6KwV/6,ظ[ܟ ;XAvN?{D �[ -endstream endobj 325 0 obj [/ICCBased 85 0 R] endobj 310 0 obj <</Filter/FlateDecode/Length 155>>stream -HtO P ;|vi];HFC~ltHg,JPf($^(ɤ1z_ጽ5hb6u#?P ov@2IbK7"Ǜ 䛸ml>8Q;XJg0�3 -endstream endobj 311 0 obj <</CS 328 0 R/I false/K false/S/Transparency>> endobj 312 0 obj <</BaseFont/UPJSYF+FFDINPro-Regular/Encoding/WinAnsiEncoding/FirstChar 43/FontDescriptor 329 0 R/LastChar 43/Subtype/Type1/Type/Font/Widths[522]>> endobj 329 0 obj <</Ascent 1148/CapHeight 712/CharSet(/plus)/Descent -226/Flags 32/FontBBox[-107 -226 1172 1148]/FontFamily(FF DIN Pro)/FontFile3 330 0 R/FontName/UPJSYF+FFDINPro-Regular/FontStretch/Normal/FontWeight 400/ItalicAngle 0/StemV 72/Type/FontDescriptor/XHeight 492>> endobj 330 0 obj <</Filter/FlateDecode/Length 285/Subtype/Type1C>>stream -Hbd`ab`dd -tvss ( JM/I,)f!CGTw =߃g|'Ș_PYQ`d``ZT땘PPYTW_WZX䡐_P -V -9IEEzn! -& -)i @XDZ}?c|}O~#Ķﯦocs+1^'zw'N]<v9݅u⏆߳&.`�;lv -endstream endobj 328 0 obj [/ICCBased 85 0 R] endobj 22 0 obj <</Count 5/Kids[5 0 R 6 0 R 7 0 R 8 0 R 9 0 R]/Parent 19 0 R/Type/Pages>> endobj 23 0 obj <</Count 5/Kids[10 0 R 11 0 R 12 0 R 13 0 R 331 0 R]/Parent 19 0 R/Type/Pages>> endobj 24 0 obj <</Count 5/Kids[332 0 R 333 0 R 334 0 R 335 0 R 336 0 R]/Parent 19 0 R/Type/Pages>> endobj 25 0 obj <</Count 5/Kids[337 0 R 338 0 R 339 0 R 340 0 R 341 0 R]/Parent 19 0 R/Type/Pages>> endobj 26 0 obj <</Count 5/Kids[342 0 R 343 0 R 344 0 R 345 0 R 346 0 R]/Parent 19 0 R/Type/Pages>> endobj 342 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 347 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 348 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 26 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 343 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 349 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 350 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 26 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 344 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 351 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 352 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 26 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 345 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 353 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 354 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 26 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</C0_0 355 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 346 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 356 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 357 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 26 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 315 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 356 0 obj <</Filter/FlateDecode/Length 157>>stream -Ht1 @ 7`kCM赺XptVvxI>>pE@U O )X }Qpy -'53F:1ˆC\z1_2;%؍&9$WO4WJY -kiYڃ*|G�3C -endstream endobj 357 0 obj <</CS 358 0 R/I false/K false/S/Transparency>> endobj 358 0 obj [/ICCBased 85 0 R] endobj 353 0 obj <</Filter/FlateDecode/Length 155>>stream -HTOA -0+v7MhSM=V4223,sq&263)p<B4#GA~jO{P iPs�;;y&!?mVYe`l&#m,?BW� -.e -endstream endobj 354 0 obj <</CS 359 0 R/I false/K false/S/Transparency>> endobj 355 0 obj <</BaseFont/PXYOGP+KozGoPr6N-Medium/DescendantFonts 360 0 R/Encoding/Identity-H/Subtype/Type0/Type/Font>> endobj 360 0 obj [361 0 R] endobj 361 0 obj <</BaseFont/PXYOGP+KozGoPr6N-Medium/CIDSystemInfo 362 0 R/DW 1000/FontDescriptor 363 0 R/Subtype/CIDFontType0/Type/Font>> endobj 362 0 obj <</Ordering(Japan1)/Registry(Adobe)/Supplement 6>> endobj 363 0 obj <</Ascent 1418/CIDSet 364 0 R/CapHeight 763/Descent -374/Flags 4/FontBBox[-538 -374 1254 1418]/FontFamily(Kozuka Gothic Pr6N M)/FontFile3 365 0 R/FontName/PXYOGP+KozGoPr6N-Medium/FontStretch/Normal/FontWeight 500/ItalicAngle 0/StemV 116/Type/FontDescriptor/XHeight 551>> endobj 364 0 obj <</Filter/FlateDecode/Length 15>>stream -Hj`I �xw� -endstream endobj 365 0 obj <</Filter/FlateDecode/Length 543/Subtype/CIDFontType0C>>stream -H|AhAgd!ҥt1M ZJA6$*f'6nV7h{Tު!`专Fݭ}yh|Ăv3 DVuo6ÎgY 3'wc -&c|%6N{>Rv gPpn�_蜬-sRCR39ѢrYQ̤bF<L<¥nϪe64*DsqLwfMyͨ*e(FP,aJ7TI]5?>M—Tţ:Ty:ZS5BV3X&oP + -�7{*Omd&9ҳ 8t KG8sY<ҁv~OQ'+ynowB~XO /Yoyi'gYsDžjvC$:,yo;Y>m{(&Qe63j_93h6Pd6z_O�( -endstream endobj 359 0 obj [/ICCBased 85 0 R] endobj 351 0 obj <</Filter/FlateDecode/Length 168>>stream -HTO -@+L.\m -  Vh -K`0tS0�UMHzBad7:a;2cH=|RHr!]u7 k�SŠ=R?pFY8[2RdNBz:GuxF"{du+�O3 -endstream endobj 352 0 obj <</CS 366 0 R/I false/K false/S/Transparency>> endobj 366 0 obj [/ICCBased 85 0 R] endobj 349 0 obj <</Filter/FlateDecode/Length 153>>stream -HTO -@W;kxPTZp"X !O\{PųgM -MF VA5 3g4T -O.BO@1@, wr:6wP ?nMfbrg UhkyRE{+�U.a -endstream endobj 350 0 obj <</CS 367 0 R/I false/K false/S/Transparency>> endobj 367 0 obj [/ICCBased 85 0 R] endobj 347 0 obj <</Filter/FlateDecode/Length 170>>stream -HTO -@ oC{ʹk"ŀCQV﵇` I/DTE@U -ԋLɈG ͑@j1'534x4T)�= hD_ȝbNBZIYÆ%rX΋m[BVEvT￯��!3 -endstream endobj 348 0 obj <</CS 368 0 R/I false/K false/S/Transparency>> endobj 368 0 obj [/ICCBased 85 0 R] endobj 337 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 369 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 370 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 25 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 338 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 371 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 372 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 25 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 339 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 373 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 374 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 25 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 340 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 375 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 376 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 25 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 341 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 377 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 378 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 25 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 377 0 obj <</Filter/FlateDecode/Length 152>>stream -HTO -PW̱|i]:v $.09 ȋ�*x"Itnb;]1. V/jVPn!nvn֑L!?}"&͡V}��N.H -endstream endobj 378 0 obj <</CS 379 0 R/I false/K false/S/Transparency>> endobj 379 0 obj [/ICCBased 85 0 R] endobj 375 0 obj <</Filter/FlateDecode/Length 153>>stream -HTOM Pﯘcr}xi]A*4= vfO\A^PYųdfMlF}<,x ѠGwE"5J`&`h1w&q.w6Ia[ h4ZT`�.} -endstream endobj 376 0 obj <</CS 380 0 R/I false/K false/S/Transparency>> endobj 380 0 obj [/ICCBased 85 0 R] endobj 373 0 obj <</Filter/FlateDecode/Length 165>>stream -H\K0s3- n-Fb&XQ3#Hk -M@J7;!PO IH} :ĸj8e/:Q jm8.%{#Hse\`֖"kId>:9ĭZq& (sf>>��6 -endstream endobj 374 0 obj <</CS 381 0 R/I false/K false/S/Transparency>> endobj 381 0 obj [/ICCBased 85 0 R] endobj 371 0 obj <</Filter/FlateDecode/Length 166>>stream -H\ -0YfLI[ʐ_H!u6lfD4,Eo oN{M'?<v`Xi6);V08}`\5Af +4 -ʳ^C:ˀXb,N9H��-U7 -endstream endobj 372 0 obj <</CS 382 0 R/I false/K false/S/Transparency>> endobj 382 0 obj [/ICCBased 85 0 R] endobj 369 0 obj <</Filter/FlateDecode/Length 207>>stream -H\PKN1 q8ɖ)BH`DˢST BY~? -v#~oߠAW믯wz"8-&x}`I?=@~4 etwbPSP+:>S,bMg[Qh{-hx&r?_m<MݐÐaTvGUZe:Sr)nԛ`�D -endstream endobj 370 0 obj <</CS 383 0 R/I false/K false/S/Transparency>> endobj 383 0 obj [/ICCBased 85 0 R] endobj 332 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 384 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 385 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 24 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 333 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 386 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 387 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 24 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 334 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 388 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 389 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 24 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 335 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 390 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 391 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 24 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 336 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 392 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 393 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 24 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 392 0 obj <</Filter/FlateDecode/Length 185>>stream -H\PI0 @;K -U @J/4Hd9̌'rԡBTB4PL(vn"8DA펌)N{'?:gh&p4-iz%9} gaCzG&D$SZ%:GM^B<q0 Q5rȯ| wf?`�B -endstream endobj 393 0 obj <</CS 394 0 R/I false/K false/S/Transparency>> endobj 394 0 obj [/ICCBased 85 0 R] endobj 390 0 obj <</Filter/FlateDecode/Length 512>>stream -HTˎ0+Wf +`/̢e$$g2hE3釫mgx$D=z6BO6W󅞐Xz`˻p, 녴?tY6gR\ʉ}qֳi ,.쪒gf OV]ܘ{57�{Kfu,ޞ|k]^;2tU,@WpX@|{{-{Z&t/CFkwD@\rlc귅t, A96. iPEZ&"ɺG 0KGT^��PڤS^p H8V bBwl^om{ @z^㞗L,± t47Ɂ\Tv1A!,N� cV5lV= (m+2W.7)MJ&URI\5IyqBuWwL[Nv=m-oۊsvWo?|Z� -i -endstream endobj 391 0 obj <</CS 395 0 R/I false/K false/S/Transparency>> endobj 395 0 obj [/ICCBased 85 0 R] endobj 388 0 obj <</Filter/FlateDecode/Length 530>>stream -HtTˎ1 +ueB#,ED$hv\w/ϴ<#{8Sxe[2^C$QG: |OˇH/49.gYXo$bb؈ iGJs^é$:q[ۼݬ&C#`zlZsQ]潑޹#ʣ#ʽ J�YTml1rQP)ka*YsV$hiZ E^mS -jdTUͅ*-\$Ñ.6>^'RZ;OM$qБ4T{.vUGC<P'ƺ[jSU4!C>M.S}*LST6Y6L-5LQCq-4qܒp L]& CSlDpB /td ٥,u:%8 -۹10ǔ5^{{ \R ٓ!<*1BG }[.��Y -endstream endobj 389 0 obj <</CS 396 0 R/I false/K false/S/Transparency>> endobj 396 0 obj [/ICCBased 85 0 R] endobj 386 0 obj <</Filter/FlateDecode/Length 2433>>stream -H|Wˎ$ WtM2jV aa-fd +"ӽ;]Q& 2_~~_>OgyW~ni?~Ç_bak|*/Xu7ۿ^eNjy^^G*}R\|OG*sTZ~GyدeN{nn묇~b@?y);ȵbf2ci.hz9;viaB1؇m:QͶ_iov1x50{`=�&66+,ar gÎ6ߎҼ?8pN+OKNthz#@'~䬚VMèg6ڃM5FQZGlbD"0ÖO}y8cޙ!NX:ZC�& U -{X%c$fg\3 -d,QE\IU9݋a>\x:aeL?`4q!Fi(l tPa�:{P#$ \%SVvvadN˽ ̾)t,DB`4dBfS61hNns1�$I[$.` aSg  Y .+6cmڑnV~KdY#/t1/Ɓ0wœБ%Cu)1M!/M3XbUiDP�B4W [T|6Ɂ$9RAO.'G8x^ ,YK -2p7t Y4KSړyB+3 U0wԎ#&Dw7A/:S(,-B`1bx=X;A?]l3Tg;Ca|/EM!NS6I=?Ԅԁ+r<R,/jP+rpm$/_9⺾Vt!ȜF@Ž WN5&w-cb"D}gUVhYm7 q\#CI$=сH=Wxb&1DB_E -jʷTw*v%O*`baK+1ŐSS(bvar;ۇh6*ȟw%Q]R -Af/zN(\t�9RmBeMciЃ)?óJvvo>n.@, -;ۓ|mkn?DR N|�1!d҆ޝ. TOI*@bڠvuqc@.#sL3ƪA`I=:QL|<޷i2p?Aj~4`u"!oNȐv5Ț&O"xp{yNPXwu(n<MՓGx}f4CNS[慀]܅\%̬2ĚHu1w1Qw)?uCϪpL`S07&o-,: ʲrwаaQg~kѶEWɾ~PA8O 2ӯFz̻N2:Ujn1Ox`UWKu{tRƱE*ӡ< zĻTRmzT6lJǚˊ6pZWYMv> 87ŧ&RO֮ 谯`9g8 ĖVY8J'AzgʇQYhJ|Z뗙H݊h0 L> LSol -+ec笽olJT-R, -+V -hRN7p|.zƮ(L%`ВK.vzQSƾ]jPW-oXf:]!&{nM{N=ʬ͞QK,yj]:UyCyKeڣ ajRR1xթOOt^B:Yg E ʶ�R^7`ȳG\�Sq44sͅh~yM]W:(&rDŨC :Z5 DȌڞ!8 \9}ARZ\qAX*;[+\#uj[VY< lϯ -d2zFѽ@Rd5Ed$G|cY<lFfL5PwxHAVt֢9g񌨰Tn+}Ks%Ld{tYW=:M� }はH9rף0]f{ *jgqk<=@4YH]#i;CCKVhkcxb}u^~~_>O@zeC�@c -endstream endobj 387 0 obj <</CS 397 0 R/I false/K false/S/Transparency>> endobj 397 0 obj [/ICCBased 85 0 R] endobj 384 0 obj <</Filter/FlateDecode/Length 217>>stream -Htn0 8?M[ʶmpAX_Ca#HS'>v>;y`6`@O5f"I`e -N0/ W< _4V 0)fPFa/s>-س -" |֧<Q&jptXQݎ .7,5 s1rI/YF!iȑc5`NE2ߌ#�V -endstream endobj 385 0 obj <</CS 398 0 R/I false/K false/S/Transparency>> endobj 398 0 obj [/ICCBased 85 0 R] endobj 10 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 399 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 400 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 23 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 11 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 401 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 402 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 23 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 12 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 403 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 404 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 23 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Font<</T1_0 175 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 13 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 405 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 406 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 23 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 331 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 407 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 408 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 23 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 407 0 obj <</Filter/FlateDecode/Length 248>>stream -HJ1 d&zkXeY(U}}'i -ɜa{_`7q.097 'at|2xׄ_Zpkv~0آ2BO. 꾪ܠΑ:g.RSNLM[BT-BBeM5]1/A(ϵTk^mx '؋드}\kUqYs뜪ަDQQI -ʍpE-�g -endstream endobj 408 0 obj <</CS 409 0 R/I false/K false/S/Transparency>> endobj 409 0 obj [/ICCBased 85 0 R] endobj 405 0 obj <</Filter/FlateDecode/Length 804>>stream -HtUˎG W |uK`�+ Sdhw)Y|[C-?}x(qY&^[-lelwpZ|ƁO]~,g<\8_=h9hP2&5G޶߶iXӶ+7<FM S'Vp`4O 7'*"(MA$f ]� q] uZ* bTk<s54+ '[L*Ԉ[Y{Q}8*dӣlG1j#ӆ,(w&?Yg J>GDtEaJ4P#76J1>bH0{m~SKC@֠ !MTvv#G4gkQ%^^2aXkWFG)"}g0ra<$CGC,5:SC'GLjGct?[H#) ۠-=cAf �Jxv)Y;9k"qVYOJ3R q@CFwܗ_@ gAҁ}ou4 'h};# ,D圕I e6_ad!I4bYN>^҈%]L6s vjrgnN$ANdOyD1q9(ǥ�%]5\kJ+v:S}y@Δ36CU#HD.àeB0`}X6N|LP#]drl}+�bvI, -endstream endobj 406 0 obj <</CS 410 0 R/I false/K false/S/Transparency>> endobj 410 0 obj [/ICCBased 85 0 R] endobj 403 0 obj <</Filter/FlateDecode/Length 239>>stream -HTMKA 9a3^;Z@[(J݃L׊%dHIfˌZcfIf .x3'-(/ad\~Ό , -Är1SH":@9 ]co)y1d-}9+ϯ`Mߚԟu -LZlb:KѻOg3;Um$+3Ptwra XKE\)G;��K -endstream endobj 404 0 obj <</CS 411 0 R/I false/K false/S/Transparency>> endobj 411 0 obj [/ICCBased 85 0 R] endobj 401 0 obj <</Filter/FlateDecode/Length 239>>stream -HT=O@ w -0gI! -rRGd4TPY>پ׏eݦe\u-zc[JN(}{Əݍ'lªkM=L(gi8�ȫMu.qJ(FUpݖ=m3(Yҽ#p(^)?ɔLF)&Rрs}۝4cTYr6xw`�!K -endstream endobj 402 0 obj <</CS 412 0 R/I false/K false/S/Transparency>> endobj 412 0 obj [/ICCBased 85 0 R] endobj 399 0 obj <</Filter/FlateDecode/Length 243>>stream -HTMKA 9a3|i*e/+nok2$'9d*#7$s^gTPȸΌ-, aB9NñL7e"]b(V(%簌ph^oֿ_}~G6 ~kW@I&FIbuNM;O;t>.O^t 6爕Hjʻ>w�SL -endstream endobj 400 0 obj <</CS 413 0 R/I false/K false/S/Transparency>> endobj 413 0 obj [/ICCBased 85 0 R] endobj 5 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 414 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 415 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 22 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 6 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 416 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 417 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 22 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 7 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 418 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 419 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 22 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 8 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 420 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 421 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 22 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 9 0 obj <</ArtBox[0.0 0.0 1400.0 140.0]/BleedBox[0.0 0.0 1400.0 140.0]/Contents 422 0 R/CropBox[0.0 0.0 1400.0 140.0]/Group 423 0 R/LastModified(D:20190425164034+02'00')/MediaBox[0.0 0.0 1400.0 140.0]/Parent 22 0 R/PieceInfo<</Illustrator 66 0 R>>/Resources<</ColorSpace<</CS0 67 0 R>>/ExtGState<</GS0 68 0 R/GS1 69 0 R>>/Properties<</MC0 15 0 R/MC1 16 0 R/MC2 17 0 R/MC3 14 0 R>>/XObject<</Fm0 70 0 R>>>>/TrimBox[0.0 0.0 1400.0 140.0]/Type/Page>> endobj 422 0 obj <</Filter/FlateDecode/Length 192>>stream -HTKj@ :k$kco;i!I .�ݒvG/ $$ ®^Vs.3 4TTBXo؆Y] -[ Ʋ'W\<vݠTIXMΜ8XtqQ ƃlj ja&0Qc=TW�: -endstream endobj 423 0 obj <</CS 424 0 R/I false/K false/S/Transparency>> endobj 424 0 obj [/ICCBased 85 0 R] endobj 420 0 obj <</Filter/FlateDecode/Length 529>>stream -HUɎ@+R+ 1(H|@4eA>펷ޫ- ? ֏x|#`Wb~O[? k_iȨ\p0|%11,Ha=@p;x8-E3.ѥ5&Ǘ,.`l[Dtne^)DokJ#ngAj$BOֹ^ólYM8z3ul$X \r<Kj"spѾč,\7HI`2k*7fAp 'ɼ1yӚ"Z/GXԯYUkIUE{d^ċp6zRHRI!ǨnTd+v4]ad,ap =4 ;k=шK#֟dG|WFq'?+H*&,!ev[[&Fzlg ZՎ)j<m>K �Z -endstream endobj 421 0 obj <</CS 425 0 R/I false/K false/S/Transparency>> endobj 425 0 obj [/ICCBased 85 0 R] endobj 418 0 obj <</Filter/FlateDecode/Length 628>>stream -HUێ0 }Wqn~ H-,NtXxY͉}|I{} MS?;Ao_g׋:|z?yrp{0x�?8:F_~+,x!0:Lj1`%><_OMq).G-QNQ$EF%3=%¨ct>v= 2z\۸Yqq \7@_t^z'lۅ*L$\w1ZOQJ#.QRX N]L2w5qa..L,^HzV/0$neGL#[`> Y33oGv�ʾ9ڿYY0xа jN& bWD3:FSy JXK+ lA*#^%0z@PPq}u3d^)͇NdN[Sl-rDTJŹ{йx;6(7M=^ eɨ΃lӄYpQ5|@cC*hJŀzH)ËQ gKuJC3ujP24"QSsJƤk!랦[k9W#�R -endstream endobj 419 0 obj <</CS 426 0 R/I false/K false/S/Transparency>> endobj 426 0 obj [/ICCBased 85 0 R] endobj 416 0 obj <</Filter/FlateDecode/Length 545>>stream -HU͎0 )u8$ĂFx}4v:v8M# #׏!~uM3vOb>ޜ ~v 7aa^?t.31;(.PP$NЇ!fc!?R.W$Av1E%A%esWGF1C}zVvKyͥ2-7 p%n.$@_m^z Gٺ -SOԣV0EԢm.%j szs*&7 p%n.:2kv)`,k.7)CV8.gtדr>:3/%2~ 9,"k|yK-ټeB3]FNӗ)Wͷv4VfO<mmۺ ӴN:֢Ym0!ɱ hSWz-61Ū5Ro/5JgTՀYHo4[|gb\Lv뱇ŵ6\"(F-gCLׁBi@1p/m`�U# -endstream endobj 417 0 obj <</CS 427 0 R/I false/K false/S/Transparency>> endobj 427 0 obj [/ICCBased 85 0 R] endobj 414 0 obj <</Filter/FlateDecode/Length 398>>stream -HTKN1 xb;-S@BTT|"̤vTXA$qOw; \vXaX 2|2UG{Ӏjcan'<p,Lij7حR/-;#ȉK7(TؓCrE.+"$)HD"'h)CaLզ){68JLQިhFLǕi(h#yT@o\M[A'zփ^DEf.y3S#p=sm2uGj*3�'~j -:WaZ ]\FbE2J}AFʰMJZ׵FEXX| n?o}D/GR@bS?_89z8[�6P -endstream endobj 415 0 obj <</CS 428 0 R/I false/K false/S/Transparency>> endobj 428 0 obj [/ICCBased 85 0 R] endobj 18 0 obj [14 0 R 17 0 R 16 0 R 15 0 R] endobj 429 0 obj <</CreationDate(D:20190425164035+02'00')/Creator(Adobe Illustrator CC 23.0 \(Windows\))/CreatorVersion(21.0.0)/ModDate(D:20190425164035+02'00')/Producer(Adobe PDF library 15.00)/Title(banner)>> endobj xref -0 430 -0000000000 65535 f -0000000016 00000 n -0000000194 00000 n -0000039123 00000 n -0000000000 00000 f -0000607193 00000 n -0000607648 00000 n -0000608103 00000 n -0000608558 00000 n -0000609013 00000 n -0000602161 00000 n -0000602658 00000 n -0000603155 00000 n -0000603652 00000 n -0000047766 00000 n -0000047558 00000 n -0000047627 00000 n -0000047697 00000 n -0000612615 00000 n -0000039190 00000 n -0000039285 00000 n -0000039380 00000 n -0000585078 00000 n -0000585168 00000 n -0000585264 00000 n -0000585364 00000 n -0000585464 00000 n -0000545694 00000 n -0000545794 00000 n -0000545894 00000 n -0000545994 00000 n -0000546094 00000 n -0000039475 00000 n -0000039570 00000 n -0000039665 00000 n -0000039760 00000 n -0000039855 00000 n -0000537322 00000 n -0000537778 00000 n -0000538234 00000 n -0000538690 00000 n -0000539187 00000 n -0000530025 00000 n -0000530481 00000 n -0000530937 00000 n -0000531393 00000 n -0000531849 00000 n -0000519843 00000 n -0000520311 00000 n -0000520779 00000 n -0000521247 00000 n -0000521715 00000 n -0000509010 00000 n -0000509478 00000 n -0000509946 00000 n -0000510414 00000 n -0000510882 00000 n -0000039964 00000 n -0000040418 00000 n -0000040872 00000 n -0000041326 00000 n -0000041780 00000 n -0000042234 00000 n -0000042688 00000 n -0000507669 00000 n -0000508911 00000 n -0000048426 00000 n -0000044874 00000 n -0000048303 00000 n -0000044761 00000 n -0000044438 00000 n -0000506660 00000 n -0000507570 00000 n -0000505891 00000 n -0000506561 00000 n -0000504598 00000 n -0000505792 00000 n -0000502772 00000 n -0000504499 00000 n -0000499720 00000 n -0000502673 00000 n -0000043142 00000 n -0000044376 00000 n -0000499685 00000 n -0000044698 00000 n -0000044909 00000 n -0000048187 00000 n -0000048218 00000 n -0000048071 00000 n -0000048102 00000 n -0000047955 00000 n -0000047986 00000 n -0000047839 00000 n -0000047870 00000 n -0000048500 00000 n -0000048810 00000 n -0000049997 00000 n -0000054711 00000 n -0000120300 00000 n -0000185889 00000 n -0000251478 00000 n -0000317068 00000 n -0000382658 00000 n -0000448248 00000 n -0000502736 00000 n -0000504562 00000 n -0000505855 00000 n -0000506624 00000 n -0000507633 00000 n -0000508974 00000 n -0000518258 00000 n -0000519403 00000 n -0000519467 00000 n -0000516661 00000 n -0000518158 00000 n -0000513010 00000 n -0000515257 00000 n -0000516561 00000 n -0000513375 00000 n -0000515157 00000 n -0000511350 00000 n -0000512946 00000 n -0000513339 00000 n -0000513275 00000 n -0000515221 00000 n -0000516625 00000 n -0000518222 00000 n -0000519807 00000 n -0000519743 00000 n -0000528186 00000 n -0000529586 00000 n -0000529650 00000 n -0000525680 00000 n -0000527746 00000 n -0000527810 00000 n -0000524799 00000 n -0000525580 00000 n -0000523179 00000 n -0000524357 00000 n -0000524421 00000 n -0000522183 00000 n -0000522739 00000 n -0000522803 00000 n -0000523143 00000 n -0000523079 00000 n -0000524763 00000 n -0000524699 00000 n -0000525644 00000 n -0000528150 00000 n -0000528086 00000 n -0000529989 00000 n -0000529925 00000 n -0000536849 00000 n -0000537222 00000 n -0000536506 00000 n -0000536749 00000 n -0000535388 00000 n -0000536406 00000 n -0000533564 00000 n -0000535288 00000 n -0000532305 00000 n -0000533464 00000 n -0000533528 00000 n -0000535352 00000 n -0000536470 00000 n -0000536813 00000 n -0000537286 00000 n -0000545228 00000 n -0000545594 00000 n -0000544216 00000 n -0000545128 00000 n -0000543164 00000 n -0000544116 00000 n -0000540696 00000 n -0000541009 00000 n -0000541073 00000 n -0000539643 00000 n -0000540596 00000 n -0000540660 00000 n -0000543128 00000 n -0000541360 00000 n -0000541688 00000 n -0000544180 00000 n -0000545192 00000 n -0000545658 00000 n -0000578891 00000 n -0000579389 00000 n -0000579887 00000 n -0000580385 00000 n -0000580842 00000 n -0000570807 00000 n -0000571276 00000 n -0000571745 00000 n -0000572214 00000 n -0000572683 00000 n -0000562898 00000 n -0000563408 00000 n -0000563918 00000 n -0000564428 00000 n -0000564938 00000 n -0000555014 00000 n -0000555483 00000 n -0000555952 00000 n -0000556421 00000 n -0000556890 00000 n -0000546194 00000 n -0000546663 00000 n -0000547132 00000 n -0000547601 00000 n -0000548070 00000 n -0000553577 00000 n -0000554578 00000 n -0000554642 00000 n -0000552594 00000 n -0000553141 00000 n -0000553205 00000 n -0000550737 00000 n -0000552157 00000 n -0000552221 00000 n -0000549451 00000 n -0000550301 00000 n -0000550365 00000 n -0000548539 00000 n -0000549013 00000 n -0000549077 00000 n -0000549415 00000 n -0000549351 00000 n -0000550701 00000 n -0000550637 00000 n -0000552558 00000 n -0000552494 00000 n -0000553541 00000 n -0000553477 00000 n -0000554978 00000 n -0000554914 00000 n -0000562044 00000 n -0000562463 00000 n -0000562527 00000 n -0000561207 00000 n -0000561608 00000 n -0000561672 00000 n -0000559661 00000 n -0000560769 00000 n -0000560833 00000 n -0000558847 00000 n -0000559223 00000 n -0000559287 00000 n -0000557359 00000 n -0000558411 00000 n -0000558475 00000 n -0000558811 00000 n -0000558747 00000 n -0000559625 00000 n -0000559561 00000 n -0000561171 00000 n -0000561107 00000 n -0000562008 00000 n -0000561944 00000 n -0000562862 00000 n -0000562798 00000 n -0000569628 00000 n -0000570372 00000 n -0000570436 00000 n -0000568499 00000 n -0000569193 00000 n -0000569257 00000 n -0000567369 00000 n -0000568063 00000 n -0000568127 00000 n -0000566240 00000 n -0000566934 00000 n -0000566998 00000 n -0000565407 00000 n -0000565803 00000 n -0000565867 00000 n -0000566204 00000 n -0000566140 00000 n -0000567333 00000 n -0000567269 00000 n -0000568463 00000 n -0000568399 00000 n -0000569592 00000 n -0000569528 00000 n -0000570771 00000 n -0000570707 00000 n -0000576992 00000 n -0000578457 00000 n -0000578521 00000 n -0000576197 00000 n -0000576557 00000 n -0000576621 00000 n -0000575405 00000 n -0000575760 00000 n -0000575824 00000 n -0000574343 00000 n -0000574968 00000 n -0000575032 00000 n -0000573152 00000 n -0000573908 00000 n -0000573972 00000 n -0000574307 00000 n -0000574243 00000 n -0000575369 00000 n -0000575305 00000 n -0000576161 00000 n -0000576097 00000 n -0000576956 00000 n -0000576892 00000 n -0000578855 00000 n -0000578791 00000 n -0000583939 00000 n -0000584165 00000 n -0000584229 00000 n -0000582610 00000 n -0000582838 00000 n -0000582902 00000 n -0000582111 00000 n -0000582510 00000 n -0000581741 00000 n -0000582011 00000 n -0000581299 00000 n -0000581641 00000 n -0000581705 00000 n -0000582075 00000 n -0000582574 00000 n -0000583903 00000 n -0000583127 00000 n -0000583416 00000 n -0000585042 00000 n -0000584393 00000 n -0000584671 00000 n -0000604108 00000 n -0000595143 00000 n -0000595600 00000 n -0000596057 00000 n -0000596514 00000 n -0000596971 00000 n -0000591078 00000 n -0000591535 00000 n -0000591992 00000 n -0000592449 00000 n -0000592947 00000 n -0000585564 00000 n -0000586062 00000 n -0000586560 00000 n -0000587058 00000 n -0000587556 00000 n -0000590737 00000 n -0000590978 00000 n -0000590413 00000 n -0000590637 00000 n -0000590074 00000 n -0000590313 00000 n -0000588382 00000 n -0000588608 00000 n -0000588672 00000 n -0000588054 00000 n -0000588282 00000 n -0000588346 00000 n -0000590038 00000 n -0000588795 00000 n -0000588822 00000 n -0000588961 00000 n -0000589029 00000 n -0000589317 00000 n -0000589402 00000 n -0000590377 00000 n -0000590701 00000 n -0000591042 00000 n -0000594765 00000 n -0000595043 00000 n -0000594428 00000 n -0000594665 00000 n -0000594092 00000 n -0000594328 00000 n -0000593768 00000 n -0000593992 00000 n -0000593445 00000 n -0000593668 00000 n -0000593732 00000 n -0000594056 00000 n -0000594392 00000 n -0000594729 00000 n -0000595107 00000 n -0000601773 00000 n -0000602061 00000 n -0000599168 00000 n -0000601673 00000 n -0000598467 00000 n -0000599068 00000 n -0000597784 00000 n -0000598367 00000 n -0000597428 00000 n -0000597684 00000 n -0000597748 00000 n -0000598431 00000 n -0000599132 00000 n -0000601737 00000 n -0000602125 00000 n -0000606779 00000 n -0000607093 00000 n -0000606369 00000 n -0000606679 00000 n -0000605959 00000 n -0000606269 00000 n -0000604984 00000 n -0000605859 00000 n -0000604565 00000 n -0000604884 00000 n -0000604948 00000 n -0000605923 00000 n -0000606333 00000 n -0000606743 00000 n -0000607157 00000 n -0000612046 00000 n -0000612515 00000 n -0000611330 00000 n -0000611946 00000 n -0000610531 00000 n -0000611230 00000 n -0000609831 00000 n -0000610431 00000 n -0000609468 00000 n -0000609731 00000 n -0000609795 00000 n -0000610495 00000 n -0000611294 00000 n -0000612010 00000 n -0000612579 00000 n -0000612661 00000 n -trailer -<</Size 430/Root 1 0 R/Info 429 0 R/ID[<93FFD496C399A747AEFF94E9708E8808><9FEF70E4187DF64490CB8A247299F2F2>]>> -startxref -612872 -%%EOF diff --git a/resources/media/themes/default/banner_Tavola disegno 3 copia 3.png b/resources/media/themes/default/banner_Tavola disegno 3 copia 3.png deleted file mode 100644 index 6514d213..00000000 Binary files a/resources/media/themes/default/banner_Tavola disegno 3 copia 3.png and /dev/null differ diff --git a/resources/media/themes/default/banner_Tavola disegno 3.png b/resources/media/themes/default/banner_Tavola disegno 3.png deleted file mode 100644 index ff4a3948..00000000 Binary files a/resources/media/themes/default/banner_Tavola disegno 3.png and /dev/null differ diff --git a/resources/media/themes/default/banner_Tavola disegno 4.png b/resources/media/themes/default/banner_Tavola disegno 4.png deleted file mode 100644 index e82fd4cc..00000000 Binary files a/resources/media/themes/default/banner_Tavola disegno 4.png and /dev/null differ diff --git a/resources/media/themes/default/banner_Tavola disegno 5.png b/resources/media/themes/default/banner_Tavola disegno 5.png deleted file mode 100644 index 00ecbb4b..00000000 Binary files a/resources/media/themes/default/banner_Tavola disegno 5.png and /dev/null differ diff --git a/resources/media/themes/default/banner_autoplay.png b/resources/media/themes/default/banner_autoplay.png deleted file mode 100644 index 76afd382..00000000 Binary files a/resources/media/themes/default/banner_autoplay.png and /dev/null differ diff --git a/resources/media/themes/default/banner_back.png b/resources/media/themes/default/banner_back.png deleted file mode 100644 index 9941d33c..00000000 Binary files a/resources/media/themes/default/banner_back.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_action.png b/resources/media/themes/default/banner_channels_action.png deleted file mode 100644 index db79379f..00000000 Binary files a/resources/media/themes/default/banner_channels_action.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_adult.png b/resources/media/themes/default/banner_channels_adult.png deleted file mode 100644 index 29620d75..00000000 Binary files a/resources/media/themes/default/banner_channels_adult.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_adventure.png b/resources/media/themes/default/banner_channels_adventure.png deleted file mode 100644 index 653fd434..00000000 Binary files a/resources/media/themes/default/banner_channels_adventure.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_animation.png b/resources/media/themes/default/banner_channels_animation.png deleted file mode 100644 index 7a8d1858..00000000 Binary files a/resources/media/themes/default/banner_channels_animation.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_anime.png b/resources/media/themes/default/banner_channels_anime.png deleted file mode 100644 index e0297ab8..00000000 Binary files a/resources/media/themes/default/banner_channels_anime.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_biographical.png b/resources/media/themes/default/banner_channels_biographical.png deleted file mode 100644 index 4b235812..00000000 Binary files a/resources/media/themes/default/banner_channels_biographical.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_biographical_1.png b/resources/media/themes/default/banner_channels_biographical_1.png deleted file mode 100644 index 42a09613..00000000 Binary files a/resources/media/themes/default/banner_channels_biographical_1.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_children.png b/resources/media/themes/default/banner_channels_children.png deleted file mode 100644 index ef5221d1..00000000 Binary files a/resources/media/themes/default/banner_channels_children.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_comedy.png b/resources/media/themes/default/banner_channels_comedy.png deleted file mode 100644 index 8d2c0a91..00000000 Binary files a/resources/media/themes/default/banner_channels_comedy.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_community.png b/resources/media/themes/default/banner_channels_community.png deleted file mode 100644 index 300a166d..00000000 Binary files a/resources/media/themes/default/banner_channels_community.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_crime.png b/resources/media/themes/default/banner_channels_crime.png deleted file mode 100644 index cb9d2d86..00000000 Binary files a/resources/media/themes/default/banner_channels_crime.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_direct.png b/resources/media/themes/default/banner_channels_direct.png deleted file mode 100644 index 510f960c..00000000 Binary files a/resources/media/themes/default/banner_channels_direct.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_documentary.png b/resources/media/themes/default/banner_channels_documentary.png deleted file mode 100644 index aceef079..00000000 Binary files a/resources/media/themes/default/banner_channels_documentary.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_drama.png b/resources/media/themes/default/banner_channels_drama.png deleted file mode 100644 index 572c0aa0..00000000 Binary files a/resources/media/themes/default/banner_channels_drama.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_family.png b/resources/media/themes/default/banner_channels_family.png deleted file mode 100644 index bcc9173b..00000000 Binary files a/resources/media/themes/default/banner_channels_family.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_fantasy.png b/resources/media/themes/default/banner_channels_fantasy.png deleted file mode 100644 index 67e4ed8d..00000000 Binary files a/resources/media/themes/default/banner_channels_fantasy.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_historical.png b/resources/media/themes/default/banner_channels_historical.png deleted file mode 100644 index 13a3cd22..00000000 Binary files a/resources/media/themes/default/banner_channels_historical.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_latino.png b/resources/media/themes/default/banner_channels_latino.png deleted file mode 100644 index 2a25901e..00000000 Binary files a/resources/media/themes/default/banner_channels_latino.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_mistery.png b/resources/media/themes/default/banner_channels_mistery.png deleted file mode 100644 index 2596bc60..00000000 Binary files a/resources/media/themes/default/banner_channels_mistery.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_movie copia 2.png b/resources/media/themes/default/banner_channels_movie copia 2.png deleted file mode 100644 index edf28236..00000000 Binary files a/resources/media/themes/default/banner_channels_movie copia 2.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_movie.png b/resources/media/themes/default/banner_channels_movie.png deleted file mode 100644 index 3b84d374..00000000 Binary files a/resources/media/themes/default/banner_channels_movie.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_movie_genre.png b/resources/media/themes/default/banner_channels_movie_genre.png deleted file mode 100644 index b4060692..00000000 Binary files a/resources/media/themes/default/banner_channels_movie_genre.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_movie_year.png b/resources/media/themes/default/banner_channels_movie_year.png deleted file mode 100644 index 8e7a119f..00000000 Binary files a/resources/media/themes/default/banner_channels_movie_year.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_musical.png b/resources/media/themes/default/banner_channels_musical.png deleted file mode 100644 index 114ebce5..00000000 Binary files a/resources/media/themes/default/banner_channels_musical.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_noir.png b/resources/media/themes/default/banner_channels_noir.png deleted file mode 100644 index 3d94f683..00000000 Binary files a/resources/media/themes/default/banner_channels_noir.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_romance.png b/resources/media/themes/default/banner_channels_romance.png deleted file mode 100644 index 1eddb2e2..00000000 Binary files a/resources/media/themes/default/banner_channels_romance.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_spanish.png b/resources/media/themes/default/banner_channels_spanish.png deleted file mode 100644 index 64f06122..00000000 Binary files a/resources/media/themes/default/banner_channels_spanish.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_syfy.png b/resources/media/themes/default/banner_channels_syfy.png deleted file mode 100644 index 744c3c15..00000000 Binary files a/resources/media/themes/default/banner_channels_syfy.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_torrent.png b/resources/media/themes/default/banner_channels_torrent.png deleted file mode 100644 index 2e6674ba..00000000 Binary files a/resources/media/themes/default/banner_channels_torrent.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow.png b/resources/media/themes/default/banner_channels_tvshow.png deleted file mode 100644 index 784f145a..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_4k copia 2.png b/resources/media/themes/default/banner_channels_tvshow_4k copia 2.png deleted file mode 100644 index 266cf33b..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_4k copia 2.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_4k.png b/resources/media/themes/default/banner_channels_tvshow_4k.png deleted file mode 100644 index 30bbde9f..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_4k.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_HD copia 2.png b/resources/media/themes/default/banner_channels_tvshow_HD copia 2.png deleted file mode 100644 index 1bb449e5..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_HD copia 2.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_HD copia.png b/resources/media/themes/default/banner_channels_tvshow_HD copia.png deleted file mode 100644 index 05b67c42..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_HD copia.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_HD.png b/resources/media/themes/default/banner_channels_tvshow_HD.png deleted file mode 100644 index 8a37b43c..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_HD.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_az.png b/resources/media/themes/default/banner_channels_tvshow_az.png deleted file mode 100644 index d335bae4..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_az.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_genre.png b/resources/media/themes/default/banner_channels_tvshow_genre.png deleted file mode 100644 index 4fcc4ec0..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_genre.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_tvshow_year.png b/resources/media/themes/default/banner_channels_tvshow_year.png deleted file mode 100644 index b8e5b118..00000000 Binary files a/resources/media/themes/default/banner_channels_tvshow_year.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_vos.png b/resources/media/themes/default/banner_channels_vos.png deleted file mode 100644 index 796a2f9f..00000000 Binary files a/resources/media/themes/default/banner_channels_vos.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_war.png b/resources/media/themes/default/banner_channels_war.png deleted file mode 100644 index 37e2bd94..00000000 Binary files a/resources/media/themes/default/banner_channels_war.png and /dev/null differ diff --git a/resources/media/themes/default/banner_channels_western.png b/resources/media/themes/default/banner_channels_western.png deleted file mode 100644 index 94877c84..00000000 Binary files a/resources/media/themes/default/banner_channels_western.png and /dev/null differ diff --git a/resources/media/themes/default/banner_downloads.png b/resources/media/themes/default/banner_downloads.png deleted file mode 100644 index 2ea488c1..00000000 Binary files a/resources/media/themes/default/banner_downloads.png and /dev/null differ diff --git a/resources/media/themes/default/banner_favorites.png b/resources/media/themes/default/banner_favorites.png deleted file mode 100644 index e28cddc5..00000000 Binary files a/resources/media/themes/default/banner_favorites.png and /dev/null differ diff --git a/resources/media/themes/default/banner_genres.png b/resources/media/themes/default/banner_genres.png deleted file mode 100644 index a3a0569f..00000000 Binary files a/resources/media/themes/default/banner_genres.png and /dev/null differ diff --git a/resources/media/themes/default/banner_help.png b/resources/media/themes/default/banner_help.png deleted file mode 100644 index b2f7ec71..00000000 Binary files a/resources/media/themes/default/banner_help.png and /dev/null differ diff --git a/resources/media/themes/default/banner_horror.png b/resources/media/themes/default/banner_horror.png deleted file mode 100644 index 60faf292..00000000 Binary files a/resources/media/themes/default/banner_horror.png and /dev/null differ diff --git a/resources/media/themes/default/banner_menu.png b/resources/media/themes/default/banner_menu.png deleted file mode 100644 index a26e96a1..00000000 Binary files a/resources/media/themes/default/banner_menu.png and /dev/null differ diff --git a/resources/media/themes/default/banner_more.png b/resources/media/themes/default/banner_more.png deleted file mode 100644 index dbdf7a4a..00000000 Binary files a/resources/media/themes/default/banner_more.png and /dev/null differ diff --git a/resources/media/themes/default/banner_mylink.png b/resources/media/themes/default/banner_mylink.png deleted file mode 100644 index 344b5e33..00000000 Binary files a/resources/media/themes/default/banner_mylink.png and /dev/null differ diff --git a/resources/media/themes/default/banner_news.png b/resources/media/themes/default/banner_news.png deleted file mode 100644 index 375495cc..00000000 Binary files a/resources/media/themes/default/banner_news.png and /dev/null differ diff --git a/resources/media/themes/default/banner_next.png b/resources/media/themes/default/banner_next.png deleted file mode 100644 index 68f229e2..00000000 Binary files a/resources/media/themes/default/banner_next.png and /dev/null differ diff --git a/resources/media/themes/default/banner_nofolder.png b/resources/media/themes/default/banner_nofolder.png deleted file mode 100644 index c74d8dc3..00000000 Binary files a/resources/media/themes/default/banner_nofolder.png and /dev/null differ diff --git a/resources/media/themes/default/banner_now_playing.png b/resources/media/themes/default/banner_now_playing.png deleted file mode 100644 index bb7f8e72..00000000 Binary files a/resources/media/themes/default/banner_now_playing.png and /dev/null differ diff --git a/resources/media/themes/default/banner_popular.png b/resources/media/themes/default/banner_popular.png deleted file mode 100644 index 3460089f..00000000 Binary files a/resources/media/themes/default/banner_popular.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search copia.png b/resources/media/themes/default/banner_search copia.png deleted file mode 100644 index b16159b3..00000000 Binary files a/resources/media/themes/default/banner_search copia.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search.png b/resources/media/themes/default/banner_search.png deleted file mode 100644 index 900d95bd..00000000 Binary files a/resources/media/themes/default/banner_search.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search_genre.png b/resources/media/themes/default/banner_search_genre.png deleted file mode 100644 index 8187207b..00000000 Binary files a/resources/media/themes/default/banner_search_genre.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search_movie.png b/resources/media/themes/default/banner_search_movie.png deleted file mode 100644 index e837d3ef..00000000 Binary files a/resources/media/themes/default/banner_search_movie.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search_star.png b/resources/media/themes/default/banner_search_star.png deleted file mode 100644 index c13bb0ae..00000000 Binary files a/resources/media/themes/default/banner_search_star.png and /dev/null differ diff --git a/resources/media/themes/default/banner_search_tvshow.png b/resources/media/themes/default/banner_search_tvshow.png deleted file mode 100644 index 0ed0a60e..00000000 Binary files a/resources/media/themes/default/banner_search_tvshow.png and /dev/null differ diff --git a/resources/media/themes/default/banner_setting_0.png b/resources/media/themes/default/banner_setting_0.png deleted file mode 100644 index e76778d1..00000000 Binary files a/resources/media/themes/default/banner_setting_0.png and /dev/null differ diff --git a/resources/media/themes/default/banner_setting_1.png b/resources/media/themes/default/banner_setting_1.png deleted file mode 100644 index f7526151..00000000 Binary files a/resources/media/themes/default/banner_setting_1.png and /dev/null differ diff --git a/resources/media/themes/default/banner_setting_2.png b/resources/media/themes/default/banner_setting_2.png deleted file mode 100644 index 983156b3..00000000 Binary files a/resources/media/themes/default/banner_setting_2.png and /dev/null differ diff --git a/resources/media/themes/default/banner_setting_3.png b/resources/media/themes/default/banner_setting_3.png deleted file mode 100644 index ccc511ec..00000000 Binary files a/resources/media/themes/default/banner_setting_3.png and /dev/null differ diff --git a/resources/media/themes/default/banner_setting_4.png b/resources/media/themes/default/banner_setting_4.png deleted file mode 100644 index 84e4df71..00000000 Binary files a/resources/media/themes/default/banner_setting_4.png and /dev/null differ diff --git a/resources/media/themes/default/banner_thriller.png b/resources/media/themes/default/banner_thriller.png deleted file mode 100644 index fd6b4d46..00000000 Binary files a/resources/media/themes/default/banner_thriller.png and /dev/null differ diff --git a/resources/media/themes/default/banner_top_rated.png b/resources/media/themes/default/banner_top_rated.png deleted file mode 100644 index a7020238..00000000 Binary files a/resources/media/themes/default/banner_top_rated.png and /dev/null differ diff --git a/resources/media/themes/default/banner_update.png b/resources/media/themes/default/banner_update.png deleted file mode 100644 index efe3afcf..00000000 Binary files a/resources/media/themes/default/banner_update.png and /dev/null differ diff --git a/resources/media/themes/default/banner_videolibrary.png b/resources/media/themes/default/banner_videolibrary.png deleted file mode 100644 index 8f293347..00000000 Binary files a/resources/media/themes/default/banner_videolibrary.png and /dev/null differ diff --git a/resources/media/themes/default/banner_videolibrary_movie.png b/resources/media/themes/default/banner_videolibrary_movie.png deleted file mode 100644 index 6b6ece3a..00000000 Binary files a/resources/media/themes/default/banner_videolibrary_movie.png and /dev/null differ diff --git a/resources/media/themes/default/banner_videolibrary_tvshow.png b/resources/media/themes/default/banner_videolibrary_tvshow.png deleted file mode 100644 index 167fd660..00000000 Binary files a/resources/media/themes/default/banner_videolibrary_tvshow.png and /dev/null differ diff --git a/resources/media/themes/default/icone.ai b/resources/media/themes/default/icone.ai deleted file mode 100644 index 42bc2690..00000000 --- a/resources/media/themes/default/icone.ai +++ /dev/null @@ -1,4301 +0,0 @@ -%PDF-1.5 % -1 0 obj <</Metadata 2 0 R/OCProperties<</D<</OFF[476 0 R 2321 0 R]/ON[14 0 R 15 0 R 16 0 R 187 0 R 188 0 R 189 0 R 326 0 R 327 0 R 328 0 R 477 0 R 478 0 R 798 0 R 799 0 R 800 0 R 951 0 R 952 0 R 953 0 R 1106 0 R 1107 0 R 1108 0 R 1321 0 R 1322 0 R 1323 0 R 1519 0 R 1520 0 R 1521 0 R 1717 0 R 1718 0 R 1719 0 R 1918 0 R 1919 0 R 1920 0 R 2118 0 R 2119 0 R 2120 0 R 2322 0 R 2323 0 R]/Order 2324 0 R/RBGroups[]>>/OCGs[14 0 R 15 0 R 16 0 R 187 0 R 188 0 R 189 0 R 326 0 R 327 0 R 328 0 R 477 0 R 478 0 R 476 0 R 798 0 R 799 0 R 800 0 R 951 0 R 952 0 R 953 0 R 1106 0 R 1107 0 R 1108 0 R 1321 0 R 1322 0 R 1323 0 R 1519 0 R 1520 0 R 1521 0 R 1717 0 R 1718 0 R 1719 0 R 1918 0 R 1919 0 R 1920 0 R 2118 0 R 2119 0 R 2120 0 R 2321 0 R 2322 0 R 2323 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 35707/Subtype/XML/Type/Metadata>>stream -<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?> -<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.6-c145 79.163499, 2018/08/13-16:40:22 "> - <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> - <rdf:Description rdf:about="" - xmlns:xmp="http://ns.adobe.com/xap/1.0/" - xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/" - xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/" - xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#" - xmlns:stFnt="http://ns.adobe.com/xap/1.0/sType/Font#" - xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/" - xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/" - xmlns:dc="http://purl.org/dc/elements/1.1/" - xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" - xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" - xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"> - <xmp:CreatorTool>Adobe Illustrator CC 23.0 (Windows)</xmp:CreatorTool> - <xmp:CreateDate>2019-03-21T16:26:52+01:00</xmp:CreateDate> - <xmp:ModifyDate>2019-04-25T16:07:53+02:00</xmp:ModifyDate> - <xmp:MetadataDate>2019-04-25T16:07:53+02:00</xmp:MetadataDate> - <xmp:Thumbnails> - <rdf:Alt> - <rdf:li rdf:parseType="Resource"> - <xmpGImg:width>256</xmpGImg:width> - <xmpGImg:height>208</xmpGImg:height> - <xmpGImg:format>JPEG</xmpGImg:format> - <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgA0AEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8AfpOlX+rahDp9hF611OSI 0qF6AsSSSAKAYqya0/KfzlcSXcZgjga0IB9WQASEryAjKhgdqdaD8cVYhJHJFI0cilZEJV1PUEGh BxVNvM6PJ5iuI0Us7mNVUCpJMagADFU3h/Krzm99BZyWqQtPG0oleRTGoTiGDFOdGq42p+o4qx7W 9GvtG1OfTb5QtzAQG4nkpDAMrKfAg1xVEat/xx9E/wCME3/UTJiqNtPy+82XenW2oQ2RNrduiQsW UGkjBVcrWoUk9fp6YqoeafJ2seWZ4ItR9NhcKWhlhYsp4kBhuFNRUdsVUbb/AJRTUf8AmPsf+TN5 iqpovk/zDrVlcXum2vrW9rUSNyVSWADFVBILGhriqL1v8vvMejaNFq15HH9Wk481RuTx8x8PqCgA 8Nid8VQHlv8A3pvP+YC8/wCTDYqlkcUslfTRnp14gn9WKrvql3/vmT/gT/TFURpaOmr2SupVhPFU EUP2x44q7VEd9XvVRSzGeWgAqftnwxVD/VLv/fMn/An+mKrZIpY6eojJXpyBH68VTTzGCbqyA3Js LOg/54JiqW/VLv8A3zJ/wJ/pirT286LyeN1XxZSB+OKplc/8opp3/Mfff8mbPFUuW1uWAZYnKncE KSMVcbW6AJMLgDckqf6YqmOk/wDHH1v/AIwQ/wDUTHiqjomgatrlzJa6XB9YuIojM8fJVPBWVSRz Kg7sNsVRz+RPNqW13cvpzrBYhzdOzRjgI15PsWqaKa7Yqh/Kv/Hetf8Anp/ybbFUtt7ea4lEUK8n NTSoAAAqSSaAAAVJPTFVeXTZkhedHjnijp6rRMGKVNByGxpXblSle+KoTFWT/lmsjed9MWOV4SzS VePjWgickfEGFDSh2/HFXqOk+Y3vNbmtki123a/Yp608FutvCUU0ZD6ZpsNq1riryjz15aPl7Xms zdNd+qguPWcUb947CjGp5H4dziqG8zSSReY55I2KyIYmRh1BEakEYq99ktn+vC5OoXgbT4zFxIhE MwcAsX/c7tyjpt0I26nFXlv5s+VZLG6GuvfNdNqEgRopFXkhWP8AnQIpUcaD4BtirEtW/wCOPon/ ABgm/wComTFXr3l2GeTyFpPK8vRxjFwpt/RqvoOCkZLRP8NQOta9DtiqX/mr5al1HSP041/JTTo2 AtJFRlblIqVjZBGRXrU1rt0xV5jbf8opqP8AzH2P/Jm8xV6N+USSf4U1ZzdXEMXrlSsCoxWsagyK DHI1aHfrsOmKsk1zytL5g8sppv6TuoFgcAmdYnMnp9DIEWMtt0ow8TvirxXy3/vTef8AMBef8mGx VTsIr6TTLoWiSu4ngLCIMTThN144q19T8w/74u/+Bl/piqI4zrrelrOGWYfV+avUMDyHWu+Ku4zt reqLAGaY/WOCpUsTyPSm+KsmtNK8vo2iyTzXkjeif0tbvBe+kZaMxDyJwkQ/EEUxK4qtT/lKsV1W K8jsYBco6VuLgxhxIBx4xfZ9T4qfPFUZe/8AHf0b/jBp3/JuPFUz8q2enfVbn9PwXnr+vafVvhu/ 7n1h9a/uhT+68d/DfFUBrUBjn1VrWOZNN9CIRl1mEfqepD6nD1/j48+XHl8XHriqAuf+UU07/mPv v+TNniqa6TYevq8H6Ra4h0z6pGVkWO4kQv8AVVEYpAOVPUoTTwxVEa9a2y+YEbQobpdJEbcvUW5B BHPlzM3tSlNuNK/FyxVItJ/44+t/8YIf+omPFWSfk1dRw+cDE8nptc2ssUewPJgyyU39oycVej69 f2sflTzVKZQI63EPIbqXlhWJVr48mpscVeKeVf8AjvWv/PT/AJNtiqF05oybiB5BEbmL00kY0UMH VwGPYNw41999sVTHRNEv5pbhYGimuDbzLFaRTRPJMShBCqrGvAHnTvTbfFUjIIJBFCNiDiqrZ3t3 ZXKXVnM9vcx19OaMlWWoINCPY4qn8n5h+aHh9IXk0ZAosqzT86+JrIQa/L5UxVjkkkksjSSMXkcl nc7kkmpJxVNPNX/Heuv+ef8AybXFUfB+YfmiOIRveTTH9qR55w5+XGRQKfLFUivr+9v7lrq9ne4u HoGlkYsxCig3PtiqO1b/AI4+if8AGCb/AKiZMVV9L86+YdNtxbwXcpgQcYomllVEG9Qqo6da4qgt Y17VNXlV764kmEdfRjkd5AnKnILzLHenjiqtbf8AKKaj/wAx9j/yZvMVW6N5l1jSAyWVzLHC55PA skkaM1Kcj6bIfxxVW1jzfr2rQehdXUpgahkg9SRo2INQSrs/T22xVT8t/wC9N5/zAXn/ACYbFUri kMciyAAlSCAwDLUeKmoP04qiTqt43IMUZW2KGOMrQ+A40X2p0xV2kf8AHWsv+M8X/ExirtX/AOOt e/8AGeX/AImcVcNVvF4hSiquwQRxhaDxHGje9euKoaWQySNIQAWJJCgKtT4KKAfRiqaeZP8Aemz/ AOYCz/5MLiqCi1C5hiEcRVFFTUInI18WpyP34qp3FzJcOHkC8gKEoipX3IUCp98VTG5/5RTTv+Y+ +/5M2eKpfb3k1uH9LiC9KuyKzCn8pYEr13pirc99cXEYSXi3E1D8ED/IsAGI9jiqP0n/AI4+t/8A GCH/AKiY8VS2Cee3njngkaKaJg8ciEhlYGoIIxVN9b8469rUH1e9mHoGT1nijHBXkKheTAddlxVS 8q/8d61/56f8m2xVKcVXwzSwypNC7RyxsHjkQlWVlNQQR0IxVFavq0+q3rXtxHGlxIqiZol4CRwK GRgDTm3VqU3xVE/4q17/AJav+Scf/NOKu/xVr3/LV/yTj/5pxV3+Kte/5av+Scf/ADTiqbeYPMHm A+YJra2mZmZo1iiWNGYsyLQAcSSSTiqVy+ZfMcMrxS3BSWNiro0cYKspoQRx7YqvPmDzQLUXZlf6 qzmIT+knD1AAxTlxpWhBpiqO1PzLraaVo7rc0aSCUueEe5FxIB+z4DFUs/xVr3/LV/yTj/5pxVc3 mfzEoBa4KhhVSY4xUeI+HFUxt/MutnyzfzG5/eJe2aK3CPZWiuiR9n/JGKpZ/irXv+Wr/knH/wA0 4q7/ABVr3/LV/wAk4/8AmnFUz0DzLrctxdh7moWyunHwRj4lhYg7L44qln+Kte/5av8AknH/AM04 q3/inzBQH6zseh9OP/mnFUTpfmjXX1O0RrmqtNGCOEfQuP8AJxV2qeaNdTU7tFuaKs0gA4R9A5/y cVQv+Kte/wCWr/knH/zTirv8Va9/y1f8k4/+acVTPX/MutxXFoEuaBrK1c/BGfiaFSTuvjiqW/4o 8w8S31k8QaFvTjpU9vs+2Ktf4q17/lq/5Jx/804qmdx5l1seWbCYXP7x728Rm4R7qsVqQPs/5RxV LP8AFWvf8tX/ACTj/wCacVbPmjzCACbkgMKqTHHuK0qPh8RiqZaZ5l1t9K1h2uatHBEUPCPYm4jB /Z8DiqWf4q17/lq/5Jx/804q7/FWvf8ALV/yTj/5pxVM/LXmXW5dbto5Lnkjc6jhGOkbHsuKpZ/i rXv+Wr/knH/zTirv8Va9/wAtX/JOP/mnFXf4q17/AJav+Scf/NOKoryFDo8/mzT4tXCNZO7ArJ/d s/E+mr17F6Yq99PlXy0blbk6Xa+sq8A3op0PtSmKvDPzMttFtvN11DpKokKqnrxxUEazU+NVA2Ha oHeuKpf5heZPM0rQyGKYNEY5VJUq3BaEMNxTFXrukppiQXdxLdB5Ckz3DgXCOYrZ/Rlab0eBaTkt W5VP8vw4qwD8yozbyW9tBchrSOWaNreIFIRIoSXmVAVfU43IDGnbxrirHdW/44+if8YJv+omTFU0 /L3y6ura3E9zBK1rblZjJwrAfTcMySt2DLUfP2xVHeZze2lnq1rrWqR39zNOv1GzWR5HgdZATLxY fulMPw8a9xttirHbb/lFNR/5j7H/AJM3mKo/ybY6YWm1e+dZf0ZNbPHp3JRJcc5KMEVvtcdtu/TF U71ny/YmxmsLqy/QV9p8F3qEHryxn6wssqmKJSuzFUBTrscVYr5b/wB6bz/mAvP+TDYqlkKc5USj NyYLxQVY1NKKO5xV6n5st9Ib8vNMSHQ7q3KiZrduH723MTUd7jYfDLTkfv7Yq800j/jrWX/GeL/i YxV2r/8AHWvf+M8v/EzirMdN8jR3Wh3c9jcwXNnc/V3j1KULGbYR8jcrKCWMZQUrQ/EKUxVhV/Fa RXk0dnMbi1RysM7J6ZdQdm41NK4qj/Mn+9Nn/wAwFn/yYXFUZ5R1cxzNol1atqGl6m6pNZoKyiTo ssB7SL+I64qg/NOhroeuXOmrcJdLAdpUO9DvxcDo4/aGKuuf+UU07/mPvv8AkzZ4qjPJHl2z1rU5 VvJT6FpE1w9pFvcXAQV9OEdye+KoXzN5hn1q9VjCtrZ2q+jY2UYosMQOy9qnxOKrdJ/44+t/8YIf +omPFUZ5U8v2GrW2qTXQuK6dCbkCDhR1VXJj+JTRyQCD/KG2xVkQ/L7Q/wBI/U/9yH+8P6S5fuq8 PUp9Xpx/vePwV/n/AGaYqxLytT/EFtTYfvKA7/7rbFXeVNEGt69a6e5dYZCWuGjFXEUal347N8VB QbHfFU9HkKGLVdLsLl5q3Wo3VldOnEUigMYRkqpoXEhNTXttirDGR0PFlKnwIocVaxVmlv8Amt5j h8tNpAatzskeokn1VhpQr/reD+HvvirDCSSSTUnck4qnXmA2o80Sm7Dta84vXERAk4cF5cCwIrTp UYqyTTfzMtNOuNQaCxn9O6YlCtxwJ41CyOpVx6rL9tgfi+dSVWOa3rWm6lp1uqQTQ38Ejg1k9SJo n+Iu5Yc3mdz8TbD8AFVHVv8Ajj6J/wAYJv8AqJkxVPG/Mef/AAOvliOzEThfSa7VyKx8+Z+Cn2m6 HfFWJXFzcXDq88ryuqrGrOxYhEFFUV7AdMVTG2/5RTUf+Y+x/wCTN5irflbzC2gaoNRS0hu5VRli WcEhGJBDrTowpT6cVTjzN+ZGoeY9K+o39haCQOHiuY1cOgB3C8meleh3xVJvLf8AvTef8wF5/wAm GxVKQSDUbEdDirK9Z/MfXdV8uW+iztQR7XVyCec6r9gP8v2v5sVY/pH/AB1rL/jPF/xMYq7V/wDj rXv/ABnl/wCJnFU3j85zx28ttHpdglvOVM0KxyhHKGq8lEtDTtXFUjvLkXNy84hjgDmvowgrGu1P hBLfrxVMPMn+9Nn/AMwFn/yYXFVbQfMx0SyvPqdso1a4pHDqRNWhiIIcRrTZm/mxVJGZmYsxLMxq zHcknucVTW5/5RTTv+Y++/5M2eKpda3Vxa3EdzbSNDPCweKVDRlYdCDiqY+Ytbg1m5ivfqi218yU v5IzRJpa/wB6Ep8BI+14nFXaT/xx9b/4wQ/9RMeKoG21HULUcbW6lgUOJKROyDmoKhvhI+IBiK++ Kq36e1ylP0jdU9T1/wC+k/veXP1Ov2uW9etcVRPldmbzBbMxJYmQknckmNsVS2C6ubcubeV4TIpj kMbFeSN1U06g+GKoxfMnmJVKrql2qllcqJ5QCyBQh+11XgtPCgxVC3l9e3s5uLy4kuZyADLM7SOQ Og5MScVR/wCltH/6skH/ACOuf+qmKu/S2j/9WSD/AJHXP/VTFXfpbR/+rJB/yOuf+qmKpn5l1PSk 1u5V9HgkYcKuZbgE/u17CQDFUs/S2j/9WSD/AJHXP/VTFXfpbR/+rJB/yOuf+qmKppqep6UNK0dm 0eBlaCUohluAFAuJBQUkqanffFUr/S2j/wDVkg/5HXP/AFUxV36W0f8A6skH/I65/wCqmKppb6np R8s37jR4AgvbMNH6txQkxXVGr6lfhofvxVK/0to//Vkg/wCR1z/1UxV36W0f/qyQf8jrn/qpiqaa BqelNcXYTR4IyLK6JIluDUCFiV3kPXpiqV/pbR/+rJB/yOuf+qmKu/S2j/8AVkg/5HXP/VTFUVpe q6QdTtAuiwKxmjAYTXJIPMb7yYq7VNV0gandhtFgZhNICxmuQSeZ32kxVC/pbR/+rJB/yOuf+qmK u/S2j/8AVkg/5HXP/VTFU01/U9KW4tA+jwSE2VqQTLcCgMKkLtIOnTFUr/S2j/8AVkg/5HXP/VTF XfpbR/8AqyQf8jrn/qpiqaXGp6UPLNg50eAob28Cx+rcUBEVrVq+pX4qj7sVSv8AS2j/APVkg/5H XP8A1UxV36W0f/qyQf8AI65/6qYqmmmanpR0rWGXR4FVYIi6CW4IYG4jFDWSood9sVSv9LaP/wBW SD/kdc/9VMVd+ltH/wCrJB/yOuf+qmKpn5a1PSn1u2VNHgjY86OJbgkfu27GQjFUs/S2j/8AVkg/ 5HXP/VTFXfpbR/8AqyQf8jrn/qpirv0to/8A1ZIP+R1z/wBVMVS23hM1xFCDxMrqgPhyNMVZkfy8 s2vrayi1VzLPd3dq7PbBI41sT+/lZvWO3Egr4+2KsPvbSazvJ7SccZreRopB4MjFT+IxVNPMUJm8 zSwg8TK8SA+HJEGKp5N+XCJf31kt5cNPZIGWJrRUlnqzqHgjaerx/u/tDfcfDiqU+Z/KZ0O1sZzc mb64tSrR+lQ+lHLVPib1E/fceW3xAjFULq3/ABx9E/4wTf8AUTJiq5PLk8o0MQyc5dbqI0409Nhc NBuamo+HlXbFUw8y+TrPRLGSf9IvcTLctapGIAqNRElEgkEr/C0UqsPh9vfFUttv+UU1H/mPsf8A kzeYqqeUtFsdY1eOyu7v6sj14qA3KSgJKqwV1UgCvxYqyHzj5D0PRdLF3b6g4lL8FjmJf1DQnivC JaHbqxpirGvLf+9N5/zAXn/JhsVSnFWXX2neWJ/Kl1qFjazWps5LeC2vZpDyvJnFZ0MVWReA+Ice 1MVY5pH/AB1rL/jPF/xMYq7V/wDjrXv/ABnl/wCJnFU5svIuu3Gi3181heJcW7QC1t/q8lZllLc2 X4angFB28cVY9PBPbzPBPG0M0ZKyRSKVZWHUMp3BxVM/Mn+9Nn/zAWf/ACYXFUR5G07T9R8zWtnq EXrWkiTl4+TJvHA7rupU9V8cVSHFU2uf+UU07/mPvv8AkzZ4qmPlnyjqN5cpNJEE4xrdW0U1FEy8 wqn4kkHEsyjdTXkP2akKq3mzypqUWqzhYxJqFfVu7WD4gOQd+acY4QQViZiFXb51AVSjSf8Ajj63 /wAYIf8AqJjxVZpulWssDXuoXS2tijcaLR55WFCUijr77s1FHz2xVFhPLep1gt0OkXK7W7yyNLDK B/v5zvG/+UBw9l64qp+XbeW38zQwTACWJpUcAhhURsDQqSD9GKpMqszBVBLE0AG5JOKvUF/J2dPK TySnl5gkeN4Y0PwIrMFMTeOzVY9j7dVXmdzbTW1zLbTrwmgdo5V8GQ8WH3jFVkcjxyLIh4uhDKfA jcYqm8fnDzJHK80d60crvPIZEVFYPdMjzFWC1Xm0a/Z6dupxVLtQv7vULyW8u39W5mPKWSiryNKV ooA7YqmHmaR4/MVxIh4uhjZT4ERqRiqqfO3mP61JdieFbmXd5ltbZX5VJ58ljBD1Y/EPi98VSq+v 7y/uPrF3IZZuCR8iAPhiQIgoABsqjFUdq3/HH0T/AIwTf9RMmKrrPzbr1nbW1vbTokdnz+qsYIGk j9QszcZGQyDdyftYqpar5k1vVoIodRumuEhYunJV5ciqpyZgAzHigHxE4qvtv+UU1H/mPsf+TN5i q7ylq9to+v22o3IkaGAS1EIBfk8LopAYqNmYHriqeebvO9nrmhpZA3MlylykyvMsaoEWN1YDgzbk uO2KpD5b/wB6bz/mAvP+TDYqlOKpnfalFNoemWCTTs9o07SwyCMQqZWBUxFfjNQPi5/RiqH0j/jr WX/GeL/iYxV2r/8AHWvf+M8v/EziqZWXm3UrfRdQ08z3Dy3bW7Qz+sw9IQlywHf4uQ6HtiqSSSSS yNJIxeRzVnYkkk9yTiqaeZP96bP/AJgLP/kwuKqXl6+t7DV4bq4knhhQSB5LURtKOcbIOIl+DctQ 17e+KpdiqbXP/KKad/zH33/JmzxV2k6xPGRay3MsUUgEaXCStG0IPIGhAb92eZ5rTfFVXWNVu45Z bKK+luwjMst8Zmk9WvLkEJ6Rn1XqN+RYmpriqlpP/HH1v/jBD/1Ex4qu8vrHLBq9q00UMlzZqkBn dYlLrd28hHJyBXgjHFUZo2lGwvTd3F7ZelHBcA8LqF2JeB0UBVYkkswxVA+Vf+O9a/8APT/k22Kp ZFK8UqSxnjJGwZD4FTUYq9S0387PTnuJL+zkkSWFDHFGy8UuEUqwWu/pvQHuV364q8xvrua9vbi8 mNZrmR5pSOnKRizficVR/wBW8qf9XG//AOkGH/ssxV31byp/1cb/AP6QYf8AssxV31byp/1cb/8A 6QYf+yzFUz8y2/lk63cma/vUk+DkqWcTKP3a9Cbpf1Yqln1byp/1cb//AKQYf+yzFXfVvKn/AFcb /wD6QYf+yzFU01O38snStHD396EEEvpsLOIkj6xJXkPrQ47+5xVK/q3lT/q43/8A0gw/9lmKu+re VP8Aq43/AP0gw/8AZZiqaW9v5Z/wzfgX96YTe2ZdzZxBgwiuuIC/WqEEcqnlttsa7KpX9W8qf9XG /wD+kGH/ALLMVd9W8qf9XG//AOkGH/ssxVNNAt/LIuLv0r+9Y/UroMGs4lovotyIpdNUgdB38Riq V/VvKn/Vxv8A/pBh/wCyzFXfVvKn/Vxv/wDpBh/7LMVRWl23lYanaFNQvi/rR8QbKEAnmKVIuzT7 sVdqlt5WOp3ZfUL4P60nICyhIB5mtCbsV+7FUL9W8qf9XG//AOkGH/ssxV31byp/1cb/AP6QYf8A ssxVNNft/LJuLT1b+9U/UrUKFs4mqvorxJrdLQkdR28TiqV/VvKn/Vxv/wDpBh/7LMVd9W8qf9XG /wD+kGH/ALLMVTS4t/LP+GbAG/vRCL28KOLOIsWMVryBX61QADjQ8t99hTdVK/q3lT/q43//AEgw /wDZZirvq3lT/q43/wD0gw/9lmKppplv5ZGlawEv70oYIvUY2cQIH1iOnEfWjy39xiqV/VvKn/Vx v/8ApBh/7LMVd9W8qf8AVxv/APpBh/7LMVTPy1b+WRrdsYb+9eT4+KvZxKp/dt1Ium/ViqWfVvKn /Vxv/wDpBh/7LMVd9W8qf9XG/wD+kGH/ALLMVd9W8qf9XG//AOkGH/ssxVLIYZZ5o4YlLyysEjQd SzGgH34q9Uj/ACQJslSS+Yag0ZdpQB6CyAikfGnNgan46/7HFXl17aT2d3PaXC8J7eRopV8GQ8SP vGKpxrNlLf8Am/6jEQJbuWCCMt0DSKiiv0nFUy1f8un0+X0V1zS5bhGKzQPcxwOhH8wkIxVj+p6J c6eOTzW1zH8IMtrPHOoZuVFJjY0PwHFVbVv+OPon/GCb/qJkxVNtM8tafDb2rX1tc6nql9Cbq10m 0dY+NuASHlcq7VcCqoq1piqFvtH0m70y51HR1nt5rAr+kdMuWDvGjNw9SOQKnJQ5CsCtRiqDtv8A lFNR/wCY+x/5M3mKpTirKdJ8pW8+irqN167m4huJoWh4pDCltVS88kgoeTigRd/fcDFUs8t/703n /MBef8mGxVC6Npkmqara6dHIkUl1IsSSSV4gtsK0BOKsxk/K7lY25g1KMXlJmuXlSdbVggLp9XlM QWT4VJO/uOmKsN0j/jrWX/GeL/iYxV2r/wDHWvf+M8v/ABM4qyaTyPpFqHsr7XrWLWZhC1hEplMN JAGb139M8Kq3w7/rxVjWs6ZJpeq3WnSSJLJayNE8kdeJK7GlQDiqK8yf702f/MBZ/wDJhcVTLSfK mknT7TVdc1iGx0+9EqwogkkuPUjYoKoqN8NepxVLfMHl+TRZLRHu4LsXcC3MclszMnBmKjdgv8uK uuf+UU07/mPvv+TNniqt5f8ALUep2tzf3N/BY6fYyQrdvKX58JSf7tVVuTUU0HfFVXX/ACxZWenn V9M1KG/0uW5NvbgcxOPgL/vEZE4kU/V44qhNJ/44+t/8YIf+omPFVnl/QptbvzZwzw27LFJMZbhi qBYl5GpANMVTi88o6PLYz3eja1Bd/o+1EuoROJEczBgreiGjXlGa/Cfv64qlXlX/AI71r/z0/wCT bYqjfJHlRPMd9dQzXH1S2tbd5pbkkUQjZSQ37NdzuNu+KplN+Verx3rQrf2LWyRrO90Z1ULAw/vi hPIJ136HFWOeYNPs7DU5ILGRp7Mf3FwzRt6oUlWdTGWXiXU03+eKofS757DUrW+jFXtZUlVT34MG p+GKvogXHlmTSjrf1wiwaVL8z+vIFDxqKLTl7UMXj2xV8+6/qrarrV7qJBAuZWdFPUJ0QH3CgDFU 2uLuCz8/213cNwt7e7tJZnoTRE9NmNACTQDtiqBv4Le+vri9m1ez9a5leaSiXdOUjFjT9x74qhr3 6tBZxWlvcpclnaaeSISKlaBY1/erGxK/EelPixVX1b/jj6J/xgm/6iZMVZloF3cSanpvmfSbY6nP Z2S2d9psTBZklih9FX49fTcUPJQabjFVDX9Q1WK31XVvMCQ2mrarbixstMjVVkETSI7yzAfGAAlF 5mpPsMVYpbf8opqP/MfY/wDJm8xVOPJGladNHJqF3bx3awzJHKtxIIoIIaF3mk6lunFRTr2OwxVK 9e8yX99LPZw3LLoyyt9Uso6xwrErfu/3Y9t99679cVU/Lf8AvTef8wF5/wAmGxVE+RtcTRvMVvcT SLFaS/uLuRkL8YXILFafEDt1GKvRY/MHl6zjh1J9TjEF0E9CQNcSs7WKlYwbXiog+KnL4jy7UrXF XltveTXvmKG8n4+tcXSSScAFXk0gJoB0xV1xeTWXmKa8g4+tb3TyR8wGXkshIqD1xVmmoxaLqk+r 6pBr0CaXfC2/TEckUonV+aOPq8dPj+JSB4CvzxVjHnnXE1nzFcXEMiy2kX7i0kVCnKFCSpavxE79 TiqG8yf702f/ADAWf/JhcVZnpWqQazHpdxFqdpb67a2U9ncW1ys8NuLcEgMGiKqX4NWnQ+G2Kse8 16tp50nR9D0q7F7p9jCXeZomjk+sSSOzirivH4thiqW3P/KKad/zH33/ACZs8VT7yzqVheeXl0W+ v47K4tb+C50nkkoDSEuGE0kRBC/EPiqCvjiqI8x6nbadpWr2UeoW95rOrXxk1WKGJzDGtGb9xJJ4 O1K9fuqVWM6T/wAcfW/+MEP/AFEx4qmHknV7G1fUdO1K4W00zU7Z4rif02kkDKrenw47jdtx0PTF WRpeWGgQR3kmqWUl/DpXo6NDbQzOsscjlg1xyqockt8O25qcVYb5XYt5ht2PVjITTbrG2Kpr5Eb1 YNb06O6htJ7+0ESy3HIRiIOGnYsAQKRcuvfFU+k1vytcaV/hU6oqaIsarb3x+tfWPrAJbnIhjEfp Fj/d1261rirCfMtnNZatJZScSLZY4omQhkdFQcZFI2pJ9v6cVXf4buf+Wyw/6TIP+asVd/hu5/5b LD/pMg/5qxV3+G7n/lssP+kyD/mrFUz8y6BcS63cuLuyUHhs91CrbRqNwWriqWf4buf+Wyw/6TIP +asVd/hu5/5bLD/pMg/5qxVNNT0C4bStHQXdkDHBKCTdQgGtxIfhJbfr2xVLF8vXaMGW+sVYdCLy AH/ieKuby7dsSzXtiWO5JvICf+J4qmdvoFwPLN/F9bsqte2bBhdQ8RxiuhQtyoCeWw77+GKpX/hu 5/5bLD/pMg/5qxV3+G7n/lssP+kyD/mrFU00DQLiO4uybuyblZXS/DdQt9qFhU0bp4nFUr/w3c/8 tlh/0mQf81Yq7/Ddz/y2WH/SZB/zViqK0vy7crqdoxu7EhZozQXcBOzjoA2Ku1Ty7ctqd2wu7EBp pDQ3cAO7nqC2KoX/AA3c/wDLZYf9JkH/ADVirv8ADdz/AMtlh/0mQf8ANWKppr+gXElxaEXdkvGy tV+K6hX7MKioq3TwOKpX/hu5/wCWyw/6TIP+asVd/hu5/wCWyw/6TIP+asVTS40C4Plmwi+t2VVv bxixuoeJ5RWooG5UJHHcdtvHFUr/AMN3P/LZYf8ASZB/zVirv8N3P/LZYf8ASZB/zViqaaZoFwul awhu7ImSCIAi6hIFLiM/EQ23TviqV/4buf8AlssP+kyD/mrFXf4buf8AlssP+kyD/mrFUz8taBcR a3bObuyYDnsl1CzbxsNgGriqWf4buf8AlssP+kyD/mrFXf4buf8AlssP+kyD/mrFXf4buf8AlssP +kyD/mrFUvs7Sa7uFgipyNSSegVRyZjSuwArtiqZ3vlfUbW3adoZ0CVr69vLAH4glvSZxRuIUkg0 NAdtjiqTYqm/mhWbzDcqoLMxjCqNySY12GKrRoR9IsbhQwlEBl4n6uJiKiIzdOWx3px/yqb4qlkk bxu0cilXQlXUihBGxBGKppq3/HH0T/jBN/1EyYqnGh/lxq+qWUN2W9Fbn/edAvIn4DIC1WQDkq1F Kn23FVWO6vpN5pV/JY3YAmj7rWhB6EVAP0EAjod8VRVt/wAopqP/ADH2P/Jm8xVDWejajd2z3cUa rao4iNxNJHDH6hBYIHlZFLUFaDFUQPK+uFvTECmfiZFtvVi9dkVS/JYefqMOI5Ci7jcYq35b/wB6 bz/mAvP+TDYqr+WvKs2ux3UkcxiFsyKQsTyk80lk6J02gI+ZAxVP1/Ke8YoPrpBdlUVtpRu0iR/r lBPsCe2KpDd6HJovmSwtJJPVLNbzBuDRkB2BAKtuDiqA1C3muNZvY4ULv60poPAOanFWhoeqkKRb MQ4qp23A223xVQuLK6t1RpoyiuSEbYglaVG3hyGKo/zJ/vTZ/wDMBZ/8mFxVGL5H1eVrRLVo5pLu 3+sqhbgQBDFMR8Wx+GdR99aAVxVAajoNzY6bZ38siMl6W4otaqAkcgrXxEv4fLFV9z/yimnf8x99 /wAmbPFVkHljzLcQpPBpN5LDIA0cqW8rKynoVYLQjFVz+VPNEaM76PfIiAszNbTAADckkrirek/8 cfW/+MEP/UTHiqU4qiZNOvI7KK+eOlrOSsb8lNSCRuoPIVKtQkb0NOmKo3yr/wAd61/56f8AJtsV SnFUxfQdSTQotcaP/QJZ2t1fvyUVr8juK+IxVLsVRmlXcVtdcpgfRdSkhX7QB3DD5MAadxtir0PV /O8XmuKLSZZbW2kZ5DbSB5uBleCWJRIzxRhF/e9d96bUqQq83vbK7sbuW0u4mhuYWKSxOKEEYqmn mC4e280SXCAF4XhkUHoSqIRX7sVTyPzgD5ZHlw3qR6W9A0pExu0jMocx0C+kQFqtOVD4/s4qx3zL pl5Y6pK1wEMd2TcW08R5wyxyEsGjfao3xVvVv+OPon/GCb/qJkxV6B5U/MbSINIsLa6kS3ksCvJZ BIeQS3MA4lEfZtmPcbjiaYqxfz8kuoTw6/alZ9JuQUjnStUmLtLJFKDujc5G4g9VpiqT23/KKaj/ AMx9j/yZvMVTfTNI1HVPIjQWEJnmTUzIUBUHituASORFd2GwxVO9J8ua5B5w0/UJ7N4bSC0tY5ZJ KJRxp6REcWIY0f4TQdcVYb5b/wB6bz/mAvP+TDYqzn8l7q1t7XXzcTJCrrbqhkYKGIS4YgVIr8Kk /IYq9HXV9Nmu9uKmQwrzLRU5CUAbqxrVnQCldyMVeU/mNNFN+YtpLC6yROLQpIhDKQW6gjY4qxaQ BtZ1NOSq0huFUuyoKlztyYgYqzW3to57a3nh1aOG2SDTlnjVnIV7OICZfgrGfiHXlirDfMbQmaVo pI3jlvruaIRuj/u5DHwJCE8a074qp+ZP96bP/mAs/wDkwuKp95Ruri2sZtYuDdTlJIbOyWCP1yFj KSyjizKAvCOOM+zUxVIvM8M9nqc2nepI1lA5lsY5CfhinVWQ0PQmMID8sVauf+UU07/mPvv+TNni r2fyPrGnW3lfT0udUtDOtpEFV5Y4yv2ysbDkT8AYAmmKpjrWtaU+h6jHDrNt9YkglERMsMlCVOyq Cta9MVeD6T/xx9b/AOMEP/UTHiq3R7KOa1u5zaNeyQmNUhUv0ctVjw+LbjirJIrDVJtYl0660l4t DR+J5xSKsUNoslGWRuIDEO7EnqzVxVjvlX/jvWv/AD0/5NtiqjoOpQadqcVzcWUWoQA8ZbWdQysp 60r0bwOKvoe4sbZNPmtHsbWTToA0y6Z6cZHprGGVVjA4A+sG3xV86avfw3+ozXUNrFZQyN+7tYRR EUdB7nxOKtfojVv+WKf/AJFP/TFXfojVv+WKf/kU/wDTFUTfReZL9oWvILmd4IlgiZom5CNCSqk8 amle+KozzRpepvrtyyWkzKeFCI3I/u19sVSr9Eat/wAsU/8AyKf+mKol4vMj6fHpzwXLWcMhlihM TEI7CjFSVqK9wNsVRmq6XqZ0jRVFpMWWCYMBG9QTcyHfbFUq/RGrf8sU/wDyKf8ApiqLtF8y2lrd WkEFwtteoEuYTEzK4U1BoVNCD0I3xVFW2l6mPK2oIbSbmb6yIX03qQIbsE0p2qMVSv8ARWsceP1O 441rx9N6V8emKr3sNdeQSPb3TSABQ5SQtQCgFaeGKpj5d0vU1ubstaTKDY3YFY3G5gYAdMVUdLm8 1aWsq2ME0SzFTIDbiQEqGUH40anwyMNvHFUxHmX8wBSnrChBFLSPYhgwP91/Min5gYqg418xahrl lc31vPJIssKc/RKAIjCgoqqoAxVC6tpOqNql4RZzkGeQgiN6Ecz7YqpvaeYHlSV4btpYwBHIVkLK F6AGlRTFVOTTNalkaSS1uXkc1d2jkJJPckjFUz8xaXqbXNoVtJmAsbQGkbncQKCOmKoZP8Ux20dt El5FBEWZI40kQVehYniBUmnfFVO8g8xXrRvd29zM8SCJHaJy3BSSATSppXviqNudL1M+VtPQWk3M X16SvpvUAw2gBpTvQ4qlX6I1b/lin/5FP/TFXfojVv8Alin/AORT/wBMVTXStL1MaRrSm0mDNBCF BjepIuYzttiqWR6brUZrHa3KE7ErHIP1DFVp0nViamyuCT1PpP8A0xVNfK+l6mmu2zPaTKo51Jjc D+7b2xVLE0vWEdXSznDKQyn0n2I3HbFUWr+bV1A6iovRfk1a5pL6h+bU3HtiqC/RGrf8sU//ACKf +mKu/S+rf8ts/wDyNf8AriqYSWvnJLGO/Zb/AOpSp6qXIMrR8KkVLAkL9k9fn0xVL/0vq3/LbP8A 8jX/AK4qmvmfU9UXXrlI7ucD92FVZH7xr0AOKoyLyt+Ysl7BZ+ldpPcRmaMPMVHBSAxLFqCnIVB3 3xVKNTk8yaZfS2N9cXEF1AQJIzKxpUAjcMQag4qi9V1TUxpGisLuYM0ExYiR6ki5kG++Kr4NH8+X Flb30Md69rdOsUEokajM54rtyqFJ/aO3viqnr+n+cdAmih1WS4gaZS0R9curAdaMrEVFdxirdtqm pnytqDm7m5i+sgG9R6gGG7JFa96DFUq/S+rf8ts//I1/64q79L6t/wAts/8AyNf+uKpr5d1TU2ub sNdzMBY3ZFZHO4gYg9cVSr9L6t/y2z/8jX/rirv0vq3/AC2z/wDI1/64qitJ1bVG1SzBvJyDPGCD I9COY98Vb1PU9WOrXccd3cEm4kVEWR/5yAAAcVdI3mSNHZrmY+kKyotxzdB3Lorllp3qNsVQn6X1 b/ltn/5Gv/XFU18xapqa3NoFu5lBsbQmkjjcwKSeuKpYdT1kAMbu4AO4JkehH34qt/S+rf8ALbP/ AMjX/riqa3OqamPK2nuLubmb69Bb1HqQIbQgVr2qcVSr9L6t/wAts/8AyNf+uKo6SPzRHo8WsPPc DT5pTDHN6zbuAT9nlWh4tQ+xxVX0rVNTOka0xu5iywQlSZHqCbmMbb4qlkWpa1NKkUV1cySyEKka ySMzMTQAAGpJxVMtS0/ztplutxfpfW0DEASu0gWp6Amux9jirflfVNTfXbZXu5mU86gyOR/dt74q lY1bVyQBeXBJ2AEj/wBcVZLF5M/M6W1Fylvd+ky8gGuFV6f8Y2kD19qYqxybUdbhleKa6uY5UJV4 3kkVlI6ggmoxVZpOnSalqVtYROscty4ijdzReTbKD8ztiqPPmvzVBLbI1/PHJpx4QITQx8aAoR4f DQqdsVQeuXdjeapPdWMJt7efi/o0ChZGQGUKASAvqcuPtTFUX5kmlg8yzTRNxliaJ428GVFIO/vi r6FlhvPrkdyb3j9WR43hWGqvz4MSfiLVFBShHfFXkP5s+W9QtdSOvXFyk0OoOkcSAFXXjENiOgA4 +OKsV1b/AI4+if8AGCb/AKiZMVeyeWotVm8iaKUvViANrxIiBbiJ1CoSWoR9GKpV+b3lnVb3T49X e7ia302NucAQoayOi1Xd6171PYU74q8wtv8AlFNR/wCY+x/5M3mKpnoOoaXax2yanLKlu0CPGsck yAt9fpLtERuYOe58PGmKptqWueTHsLz9HXFxFdmNzaetNemj+o4UbOVr6a132qUHZziqQ2IC69rK qKAW+oAAdAPTkxVC6JdvaRmYStEgvLX1WUkVSkpYGnUbYq9v85NYW3lzWZ09OJ0sx6cyKAQ8nJU4 sO5JHTFXiKSPJrOlySMXkc25Z2NSTzG5JxVa0iR+ZLlmcRVmuFSU9Ed+ao5PbixBr2xVkVrZepfM beMlpmBjh+pwQrxLiQxxTKf3paNTGFX7Ve61OKsIZWRirAqymjKdiCOoIxVNfMn+9Nn/AMwFn/yY XFXq/k6xs7620i1vIUntpdEcSRSCqkfWVxV5j520zy/p2uS2+iXZurUfaH2hG1d0En7dPH9eKoa5 /wCUU07/AJj77/kzZ4qh9F0qXU9RjtUqEo0k8gBbhFGOUj0HWijYdztirKvNF4U8l2UBVIDf3X1u C15VkSyijMNsCO4PFmJ7nfvirHdJ/wCOPrf/ABgh/wComPFWR/lZaaZNf3MssktvqMAQ2d2o5RR8 zwaoBFXflxUb/LFXpOr6e1zp88WtXlxd6YVaSa0FuVLqDzRVaOOAhk47VJr4Yq8X8ueh/iaH6uGE HKX0g9OfDg3HlTatOuKon8uoIZ/OukxzIHT1i/E7jkiM6n6GUHFX0WrE8CUIZhVuhCnw/wBrFXzZ 52gSDzbqsaTGcfWXb1WNTVjyIPupNMVSVWZWDKSrKaqw2II7jFWUWv5ia3DDdK8VtLc3URikvWiU Tk0orsy0DsoOxYVxVi2Kpt5q/wCO9df88/8Ak2uKp7B+bHm1IuE128rt9uWkKsB29MCLiPfkG+jF WO6x5h1rWJfV1K8kuWqCFYgICBxqEWiA08Biqrq3/HH0T/jBN/1EyYqmOl/mH5isNOj0/wBYTWkH AW8DpFwUI3IV+DmxDUI+P5gjFUNr/nbzHrY9K8vZXtVqFg/doCGoSH9JIg+6inIbYqh7b/lFNR/5 j7H/AJM3mKoax1i/stoZW4gHghZuCsTXkEBCk/6wI9sVV5vMuszRGOS4atarIlY2Xx/u+ANf8oHF V/l0lrq9JNSbG8JJ6k+g+KpfaX1zaPyhkZQSC6K7oGp2bgVP44qmb+cNflQxy3JeEigi+wBTpRk4 vt8/niqD06eabWbOSaRpZDPFV3JY7OO5xVZq/wDx1r3/AIzy/wDEziqFVmRgykqymqsNiCOhBxVH 6xrEmqyRXFxEi3ipwublNjOR0dx0502JHXqd8VVvMn+9Nn/zAWf/ACYXFVp8z68bRLQXjLbxwG1V UCofRLcyhZQGILDucVSvFU2uf+UU07/mPvv+TNniqponmWXR9N1GC0i4X9+qRLfq5V4ogauqADq+ 29cVQmra5qerNA+oTG4kt09JJG+0VqSOR79cVV9J/wCOPrf/ABgh/wComPFUuFzMts1sCBC7B2HF allBA+KnLap74qjrrzHrFzHYJLcuf0aKWrF3JBDlwx5EjkK0B8KDtiqp5XYt5ht2NKsZCaAAbxt0 A2GKqflzXp9C1WPUreGOW4iVli9XkQpccSwoRvxJArt7Yqy3WPzm8xXaRpYQx6eEYMzj967cTXjV gBQ99q++KsT8ya9Nr2rSapPCkM86oJljrxLIgTkK7ioXxxVd/iS5/wCWOw/6Q4P+acVXHzBeqiu1 jYhHrwY2UFDTrQ8O2Krf8SXP/LHYf9IcH/NOKpn5l1+4i1u5QWlkwHDd7WFm3jU7krXFUs/xJc/8 sdh/0hwf804q7/Elz/yx2H/SHB/zTiqaanr9wulaO4tLImSCUkG1hIFLiQfCCu3TtiqV/wCJLn/l jsP+kOD/AJpxV3+JLn/ljsP+kOD/AJpxVMIfMV1+gbxvqtkALq1HAWkHE1juNyvGhIpsfniqX/4k uf8AljsP+kOD/mnFXf4kuf8AljsP+kOD/mnFUz0LX7hzft9UslMdlOylbWFewUg0XcEE1GKpZ/iS 5/5Y7D/pDg/5pxV3+JLn/ljsP+kOD/mnFUdoWvzza3p8T2diFkuYUbjaQA0aQA0IXbFUHJ5nvJHa R7SxZ3JZmNpBUk7kn4cVW/4kuf8AljsP+kOD/mnFXf4kuf8AljsP+kOD/mnFU08x6/cRamIltLIo lvbBOVrCxANvG1KlegrtiqV/4kuf+WOw/wCkOD/mnFXf4kuf+WOw/wCkOD/mnFUfeeYrpNK05Ra2 XB/WlKG0gKhy/AsBx2JWNQfliqDh13UJn4Q6fZSPQnillCxoOpoExVa3mK7UlWsrEMNiDZwA/wDE MVTO11+4HlzUbhbSyWT6zaQGlrCAY5EuJGVhxofjgQ/RiqV/4kuf+WOw/wCkOD/mnFXf4kuf+WOw /wCkOD/mnFU08v6/cPdzv9UsleG0uZo2S1hUh44WZTUL44qlf+JLn/ljsP8ApDg/5pxV3+JLn/lj sP8ApDg/5pxVEafr002oW0MllYGOSVEcfVIBszAH9nFUjjKiRS6l0BHJQaEiu4rvTFXq9v5DuB5L fUrG0ltdaiufr+mW8h9SaOJGHGIhhQllBenHc0BxV5nq1vDBdKEuvrUkiLJcn02jMczbyRENSpQ9 8VTDW7G4v/Nj2Vsoa4uXiiiUmgLMigCp6b4qnnlfTPIc2k2f6cSeC+u5Z4Y7kyBYOUdCOQUllHxq K8euKt/mH5LsdJsrHVdIQfo2cCKY8pC6z7ncSbgUU7UqDWvbFWN6t/xx9E/4wTf9RMmKvTPIX5a6 S2kWur3DRX015EH9GeP1IYwxrQKGWrDpU4qh/wAzNF8paR5ZNvBZQW2oidFtHiFJHBAaQkks5UKa fESOmKvNoP8AlHr3/mLtP+TVzirIfKn5Yaz5gtYL9Z4bbT5i1JWJeSiMUakY8CO5GKvRB+WvkybR bWS8txC8NrG09zE7RvQR1d3AJUmu9eOKvItEMRl1UxAiL6lcemG3IWopX6MVSbFXo8XmTyrpenWP l3W9ES7hFpDLNdpx9dHuUExpsrCgkG4cHFWKWZ0s+crM6Usq6f8AXYPq4nIMnH1F+1TbriqV2VvD cTenLcJbChKyOsjAt2Wkau2/yxV6Hof5MXl1bSvqF36EobjEiJIopSvI+qiE79gMVYJrOgaro06w 6hbvAz1MRcU5qDTkMVRut2kl55litIyqvcR2Uas54qC9vEKsT0A74qyDzj+Xl/Bd2raTFDcQSQRc 0tgV4VKxrJJzZj+9Yk19j4E4qo/mH5Oi0S00u5t/q6xvAkU/ouxaSVVqZuLndX/ydhirGL//AI5e l/8AGOX/AJPNir0X8i3sBNqcZWuoMqMr8ekKmhAbtVmG3tiqB/OqxjXXoLm3gQB4K3U8YPIuG4j1 aEjpSmwPz2oqw62/5RTUf+Y+x/5M3mKvRfy3uvJcXk68NzEkl/DFK+q1hMkhiZyEAJFCCvH4QeuK ptoFh5B0PStVs5uc9rFwnvpL+3Jbi59JVH7tSQskbClNmriryvSvqn6X1X6ly+p/Vb/6tz+16XpP wr78cVRPkLR7G91Zr3VSI9F01RNfTOQFBJpEhqDy5uKce+Ks/wDMl/Iq6c/lXQ7TVYb2oF2LVZU9 NSqiKqheIDcg3PptirBPMllp9l5/NvYKscC3FuWhQ1WORuDSRqR2VyR7dMVYsCQQQaEbgjFWfQ+d bsWkTP5npdfV+bOdOR5Vlp/c+s27binPFWBSyyTSvLKxeWRizuxqWZjUkn3xVOtdvLiy81PeWzcL i3eGWJ+tGREIO/uMVUvMPma+1ySBriG3t47cERw2sYiSrkF2IqfiagrviqEfV9TfTE0trlzp8b+q ltX4A5rvT6TiqK1b/jj6J/xgm/6iZMVTbyl+Y+teXLOaziVbq2cE28UpNIpD+0tP2fFf1Yqx3U9U 1DU7t7y/nae4kJJdj0qSaKOgG/QYqrwf8o9e/wDMXaf8mrnFU/8AJX5k6h5ZtpbM263tlIxkSJnM bI5ABKuA2xpuKYql+qefPNOpWs1lcXzCxndna2UKoAdi3DkBz4Cuyk0piqF8v/8ASy/5gJ/+NcVT ryB56tPLH1xLmwF2l3xrIpCyAKD8PxA1U16Yqx7XtWfV9YutSeMRG5fkIl3CqAFVa+ygYqu8uf8A KQ6X/wAxcH/J1cVS7FU9i88+bokVE1WeigKCSGNFrSrEEmlcVS3U9X1PVJ1n1C5e5lVQiM5rRR0A HQDFUX5p/wCOw3/GC1/6ho8VTbUvzE1O+e5doEiN1Y/o6Tgz/wB36hkVuvUcivyxVKtf8yXetR6e lwoUadbJax0JPIIAC7V/aam+KqF//wAcvS/+Mcv/ACebFXp/5f8Amz8vvL3l+GGS+EeozgSX7ejO x59l5LGRRRsKYqwPzlqdg+ual+gr15NJ1JknnjUPGjSA8iGRwteLkldu+KoK2/5RTUf+Y+x/5M3m KrdD1n9Hi8t5fUNlqMP1e6ELcHC8gwZexII6HYgkd64qmGoeZ42sL21tHlkk1FYo7qR0W3jEcDcw FhjeUF3erM5budtycVQPlv8A3pvP+YC8/wCTDYqr+Wtd0+xt9Q07VLZ7nS9TWMT+iwSZHhYtG6E7 bFjsf7MVROt+bka0sdM8vi407TbBXCs0p9eVpSGdpChA6joNsVSTSP8AjrWX/GeL/iYxVF/WfKn/ AFbr/wD6Tof+yPFXfWfKn/Vuv/8ApOh/7I8Vd9Z8qf8AVuv/APpOh/7I8VTPzLceWRrdyJrC9eT4 OTJeRKp/dr0BtW/XiqWfWfKn/Vuv/wDpOh/7I8Vd9Z8qf9W6/wD+k6H/ALI8VTTU7jyyNK0cvYXp QwS+movIgQPrEleR+qnlv7DFUr+s+VP+rdf/APSdD/2R4q76z5U/6t1//wBJ0P8A2R4qmMEvlg+X b6UWF6I1vLRWT67EWLNFclSG+q7AcTUU3r2puql31nyp/wBW6/8A+k6H/sjxV31nyp/1br//AKTo f+yPFUz0G48stLepHYXq8rK4LlryJvhSMuQKWq0J40r+GKpZ9Z8qf9W6/wD+k6H/ALI8Vd9Z8qf9 W6//AOk6H/sjxVGaPeeWE1exeLTr0SLcRFC17Ey8g4IqBaLUfTiqGml8qRyvH+jr88GK1+vQ70NP +WTFVn1nyp/1br//AKTof+yPFXfWfKn/AFbr/wD6Tof+yPFU08x3Hln9JK0thes8lrZyVS8iUASW kTqKG1boGoTXfrt0xVK/rPlT/q3X/wD0nQ/9keKu+s+VP+rdf/8ASdD/ANkeKpjeSeWP0Lps7WF6 ULXEKIL2IEBGVyS31U1qZfAYql31nyp/1br/AP6Tof8AsjxV31nyp/1br/8A6Tof+yPFWX+QtB8s +Z4tQ0kQ3tnCrQXbyG5ilYtEJI1Uf6PGAKTNXr2xVlX/ACpDyp/y13//ACMh/wCqOKu/5Uh5U/5a 7/8A5GQ/9UcVRFl+T3lmzeV4rm9Jlhkgbk8R+GVCjEUiG9DtiqH/AOVIeVP+Wu//AORkP/VHFXf8 qQ8qf8td/wD8jIf+qOKqlt+S/la3uIp0ur4vE6uoMkNKqaitIsVeK6ZbRXWpWltM3CKeaOORwQCF dwpNT7HFXoP5qeSfL+hWFjcaTC0EsjsksfN5AyKtS55lqUNOm2+KvNiCACRsehxVOfMVvPc+Zpre 3QyzzNEkUaipZmjUADFXrHkz8u9KtNAgXWtOhm1J2aSf1QshWpoqAiooFA+nFXnP5heT7vQ9XuLm K3Mej3Ev+iSqQVBZeZjoDVaGtK9hiqU6t/xx9E/4wTf9RMmKsv8AL35a6XrvlmyubW8dNWuWkaYt QwxpG/FgUoGrQrT4t6+GKofzd5A0nQPLYuDdyPq8VwIJlNPSfkvP4FpyFFZTUn2xVjFt/wAopqP/ ADH2P/Jm8xVfpPlTUtUsxd2zxCMtcJR2YNW1hWZ+inqrgL79aYqitV8janp1pdXb3NtcW9mXWZ4W kNJIpkgkjAdEPJXlX2p0OKoLy3/vTef8wF5/yYbFW9A8p69r5kGlWvriEqJn5ogXlWleZXwOKszt fyZuJ9ISZ9RSDUAZfWjZS9uBG5T+9FKdK9DirE7zQLrQfNdvpl1LFLPFNAztCWZPjKsBVlQ9D4Yq gbfTL3VNa+oWUZlubiZljQfMkknsANycVegt5N1PR9Ob65o+k6kkClbj0mmWaSJVqXWZmCrJyIWi pyJ7YqwzzXpOnWf6NvNLSRdP1K0WdfUYScZgzLLFzCqCUIFdsVWa7bS3Wt2dtCAZZ7PTI4wSFBZ7 KBRUmgG574qyHS/yxubewu9V8zv+jrS1VjHAXQPK4B4guPUCKWoOhJ7Yql3m7yhb6dZW+r6U7zaR cO0QdyrEMpKh6p+xJxPH5d9iVUqvf+Ua0r/jPefqhxVmn5V+SvLmv6Zf3GqRNPNHKIo1EjpwUoDy AQrUknvUbYq8/v7P0NQntouUkccjrExG7IrEBvpArir0P8i/+Otqf/GBP+J4q9kxV2KuxV2KuxV2 KvmXytceXINWVvMNtJdaeVKlYmZSrkijniVYgCuwOKvU5PM3k79D6rZyeYZLhrtH+ruzzF44Sv7u IMVHfZv2j+1iryDUtTutQmWScgJGojghQcY4o1+yiL2A+89TviqN8zu8fmK4kjYo6GNkdTQgiNSC CMVeraJ54/THlImK/gtNehVUlMzxxgEMB6p9QMChXdqD2xV53+YPmuTXNUWGK4M9hZKI4ZKcRK4H 7ybj0HJuntiqV6t/xx9E/wCME3/UTJir07yp+ZWg3dmqa1JFpa2JRLKCL1aEBCvIlB2G3Hp8+yqC 88/mHow02XStHMWp2moRSidpPU5wyN0YM4q255CvSnhQBV59bf8AKKaj/wAx9j/yZvMVVdH826lp WnS2NtHCySNI6SyKxeMzII5eBDBfjRQDyB9qYqmF1+Y2sXqzJqFra3sc4kV45hNTg8yzqg4SoeMb r8G/TY12xVK/LzBry+YKFBsbwhRWgrA+wrXFU0/LvzlH5Z1SVrlGk0+7VUuVShZWQ1SQA9eNT9+K szX849GgaQRx3jrFJI8CKkKRzerVqS8i7pxcnjwPTrirzg6pdar5pj1G6NZ7q7jkenQVcUUeyjYY qmvkPV9O0nzxFeahIYbcPNH6lKqrSAqC3gu+5xV6b5w87eU9MkjuY50utVgY0htuJdlZSpR5gG9M b168vDFXjmua8NTt7GBLcWsVkswWFCSlZp3l+EGpFAwXcnpirfmVmXVIGUkMLHTiCNiCLGDFXqNl +aHlC98v2o1ySQ6hCI2liVJPUM8JqJEeMKoqRyHxDrTFXn/mnzxc6t61lZR/U9EIjSCzHULFUgtT bkzGp+gV61VS29/5RrSv+M95+qHFWaeUNf8AI9rpMKLc3Gi6hG0bak4kmYXaJ9sDhyArXagVl7Hq cVQn5keadOu9S9XQ7z11vLVIrqUBwyICT6UfMLwVwQXVR169xiqO/Iv/AI62p/8AGBP+J4q9kxV2 KuxV2KuxV2KvFv8AlRvmH/lvtP8Akr/zRirv+VG+Yf8AlvtP+Sv/ADRirv8AlRvmH/lvtP8Akr/z RiqN1n8m9dvtSmuo721VJONFb1K/CgXsvtiqC/5Ub5h/5b7T/kr/AM0Yq7/lRvmH/lvtP+Sv/NGK o29/JzXZ7HT7db21DWcckbk+pQl5nkFPh8HxVBf8qN8w/wDLfaf8lf8AmjFXf8qN8w/8t9p/yV/5 oxVGxfk5rqaLdWBvbUyT3NvOrfvOIWCOdGB+HqfXFMVQX/KjfMP/AC32n/JX/mjFXf8AKjfMP/Lf af8AJX/mjFUbpX5Oa7ZyzvJe2rCW2ngUL6mzTRlAd16AnFUF/wAqN8w/8t9p/wAlf+aMVd/yo3zD /wAt9p/yV/5oxVXsfyU1+3vbedr61KwyJIwHqVIVgdvhxVTn/JHzBJNJIL+0AdiwB9Tua/yYqs/5 Ub5h/wCW+0/5K/8ANGKu/wCVG+Yf+W+0/wCSv/NGKo3V/wAnNdvbuOaO9tVVLa1gIb1K8re2jhY7 L0LRkjFUF/yo3zD/AMt9p/yV/wCaMVd/yo3zD/y32n/JX/mjFUbcfk5rsuk2dkL21EltJPI7H1KE SiOlPh7eniqC/wCVG+Yf+W+0/wCSv/NGKu/5Ub5h/wCW+0/5K/8ANGKsu/Lr8v8AUvK97eT3dzDO txGsaiLnUENXfkFxVneKuxV2KuxV2KuxV//Z</xmpGImg:image> - </rdf:li> - </rdf:Alt> - </xmp:Thumbnails> - <xmpTPg:NPages>1</xmpTPg:NPages> - <xmpTPg:HasVisibleTransparency>True</xmpTPg:HasVisibleTransparency> - <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint> - <xmpTPg:MaxPageSize rdf:parseType="Resource"> - <stDim:w>384.000006</stDim:w> - <stDim:h>384.000006</stDim:h> - <stDim:unit>Pixels</stDim:unit> - </xmpTPg:MaxPageSize> - <xmpTPg:Fonts> - <rdf:Bag> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Regular</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Regular</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Regular.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Medium</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Medium</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Medium.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>FFDINPro-Bold</stFnt:fontName> - <stFnt:fontFamily>FF DIN Pro</stFnt:fontFamily> - <stFnt:fontFace>Bold</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 7.504; 2009; Build 1022;</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>FF DIN Pro Bold.otf</stFnt:fontFileName> - </rdf:li> - <rdf:li rdf:parseType="Resource"> - <stFnt:fontName>KozGoPr6N-Medium</stFnt:fontName> - <stFnt:fontFamily>小塚ゴシック Pr6N</stFnt:fontFamily> - <stFnt:fontFace>M</stFnt:fontFace> - <stFnt:fontType>Open Type</stFnt:fontType> - <stFnt:versionString>Version 6.016;PS 6.007;hotconv 1.0.70;makeotf.lib2.5.5900</stFnt:versionString> - <stFnt:composite>False</stFnt:composite> - <stFnt:fontFileName>KozGoPr6N-Medium.otf</stFnt:fontFileName> - </rdf:li> - </rdf:Bag> - </xmpTPg:Fonts> - <xmpTPg:PlateNames> - <rdf:Seq> - <rdf:li>Cyan</rdf:li> - <rdf:li>Magenta</rdf:li> - <rdf:li>Yellow</rdf:li> - <rdf:li>Black</rdf:li> - </rdf:Seq> - </xmpTPg:PlateNames> - <xmpTPg:SwatchGroups> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <xmpG:groupName>Gruppo campioni predefinito</xmpG:groupName> - <xmpG:groupType>0</xmpG:groupType> - </rdf:li> - </rdf:Seq> - </xmpTPg:SwatchGroups> - <illustrator:Type>Document</illustrator:Type> - <dc:format>application/pdf</dc:format> - <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass> - <xmpMM:DocumentID>xmp.did:a91df9ec-b741-7e4d-8aa2-e936b107d8af</xmpMM:DocumentID> - <xmpMM:InstanceID>uuid:479e421e-4dc4-40e5-ba41-79ed843133f2</xmpMM:InstanceID> - <xmpMM:OriginalDocumentID>uuid:b4f6c558-8e78-4b94-823a-7218c4b2a016</xmpMM:OriginalDocumentID> - <xmpMM:DerivedFrom rdf:parseType="Resource"> - <stRef:instanceID>uuid:24bb8938-6511-48b4-b3e9-c50cdd9a70e2</stRef:instanceID> - <stRef:documentID>uuid:b4f6c558-8e78-4b94-823a-7218c4b2a016</stRef:documentID> - <stRef:originalDocumentID>uuid:b4f6c558-8e78-4b94-823a-7218c4b2a016</stRef:originalDocumentID> - <stRef:renditionClass>proof:pdf</stRef:renditionClass> - </xmpMM:DerivedFrom> - <xmpMM:History> - <rdf:Seq> - <rdf:li rdf:parseType="Resource"> - <stEvt:action>saved</stEvt:action> - <stEvt:instanceID>xmp.iid:a91df9ec-b741-7e4d-8aa2-e936b107d8af</stEvt:instanceID> - <stEvt:when>2019-03-21T16:26:52+01:00</stEvt:when> - <stEvt:softwareAgent>Adobe Illustrator CC 23.0 (Windows)</stEvt:softwareAgent> - <stEvt:changed>/</stEvt:changed> - </rdf:li> - </rdf:Seq> - </xmpMM:History> - </rdf:Description> - </rdf:RDF> -</x:xmpmeta> - - - - - - - - - - - - - - - - - - - - - -<?xpacket end="w"?> -endstream endobj 3 0 obj <</Count 78/Kids[330 0 R 331 0 R 480 0 R]/Type/Pages>> endobj 330 0 obj <</Count 25/Kids[18 0 R 19 0 R 20 0 R 21 0 R 22 0 R]/Parent 3 0 R/Type/Pages>> endobj 331 0 obj <</Count 25/Kids[23 0 R 24 0 R 25 0 R 191 0 R 332 0 R]/Parent 3 0 R/Type/Pages>> endobj 480 0 obj <</Count 28/Kids[481 0 R 482 0 R 1110 0 R 1111 0 R 2325 0 R]/Parent 3 0 R/Type/Pages>> endobj 481 0 obj <</Count 5/Kids[335 0 R 336 0 R 491 0 R 492 0 R 493 0 R]/Parent 480 0 R/Type/Pages>> endobj 482 0 obj <</Count 5/Kids[494 0 R 495 0 R 1112 0 R 1113 0 R 1114 0 R]/Parent 480 0 R/Type/Pages>> endobj 1110 0 obj <</Count 5/Kids[1115 0 R 1116 0 R 1117 0 R 1118 0 R 1119 0 R]/Parent 480 0 R/Type/Pages>> endobj 1111 0 obj <</Count 5/Kids[1120 0 R 1121 0 R 1122 0 R 1123 0 R 1124 0 R]/Parent 480 0 R/Type/Pages>> endobj 2325 0 obj <</Count 8/Kids[1125 0 R 1126 0 R 1721 0 R 2122 0 R 2326 0 R 2327 0 R 2328 0 R 2329 0 R]/Parent 480 0 R/Type/Pages>> endobj 1125 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2330 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2331 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2335 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 1126 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2336 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2337 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2338 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 1721 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2339 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2340 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2338 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 2122 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2341 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2342 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2326 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2345 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2346 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2347 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 2327 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2348 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2349 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2350 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 2328 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2351 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2352 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2338 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 2329 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2353 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2354 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 2325 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2350 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 2353 0 obj <</Filter/FlateDecode/Length 1230>>stream -H͎$5>#韴}eB#x_dM74V˕Ό/kIzMZkQR[-okI_eo?^ҧtJZ߷/ky^ٶt{?8[gJKOfy{:-7[\J,f$ {9o|{N˃ld{+R߹][4jՔԑ(:sȵIFɳt@k7]Od S܎Kk</3ٮhdm7sdb"{ͭtRqр �;xz{UW*F! `^6.E7ʹ9{Ə݉g`9 Z` ^9Bp{L"YuHC(:1L[`R'[Sjf͠I @' -V -nI)<,҄ՙ%U. <65mtb٘Y2ΞKg$9̹�Z5z V\2ks,3_Ԯv:zyHGB ̨@@Bg$PDIXL:q." !i-H]ǘKod ʔG*tQE#ds4g:np1w(Jy{]w)mRnm 0 Sy*£r$=;�!8`O@|xͣz -| IPj~ gAisqG#_㌘;T1ъpƉRxHUS4P3EqK&R¿1]Xo&F ޕ@\,h,U9'ܔ3Fgv8?4d+E(A ϕ0 -)pѪ Ti͎TFVn"CE.J-:,N3Kq -*HKfRO5~Í-!y.US8q)ᗘ=VaZgԆ6 F] Dz,Ϝ5dciChW2BT-#-.�q|!A"\X!ޟU s -9> 7?*k<.#6BṴNC2aX7q@[J˴!L/eh" SҕE]*Q1,/(c w UB[� Ϡ܎?/O�C -endstream endobj 2354 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2350 0 obj <</BBox[0.0 383.598 384.0 -0.401855]/Group 2355 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 383.599 384 -384 re -f - -endstream endobj 2355 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2334 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 2321 0 obj <</Intent 2356 0 R/Name(Guide)/Type/OCG/Usage 2357 0 R>> endobj 2322 0 obj <</Intent 2358 0 R/Name(Sfondo)/Type/OCG/Usage 2359 0 R>> endobj 2323 0 obj <</Intent 2360 0 R/Name(Icone)/Type/OCG/Usage 2361 0 R>> endobj 2360 0 obj [/View/Design] endobj 2361 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2358 0 obj [/View/Design] endobj 2359 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2356 0 obj [/View/Design] endobj 2357 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2333 0 obj <</AIS false/BM/Normal/CA 0.600006/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 0.600006/op false>> endobj 2332 0 obj <</LastModified(D:20190425160752+02'00')/Private 2362 0 R>> endobj 2362 0 obj <</AIMetaData 2363 0 R/AIPrivateData1 2364 0 R/AIPrivateData2 2365 0 R/AIPrivateData3 2366 0 R/AIPrivateData4 2367 0 R/ContainerVersion 11/CreatorVersion 23/NumBlock 4/RoundtripStreamType 1/RoundtripVersion 17>> endobj 2363 0 obj <</Length 1226>>stream -%!PS-Adobe-3.0 -%%Creator: Adobe Illustrator(R) 17.0 -%%AI8_CreatorVersion: 23.0.0 -%%For: (Concreate Studio) () -%%Title: (icone.ai) -%%CreationDate: 4/25/2019 4:07 PM -%%Canvassize: 16383 -%%BoundingBox: -1712 -1186 2309 2026 -%%HiResBoundingBox: -1712 -1185.8090553094 2308.00005716867 2026 -%%DocumentProcessColors: Cyan Magenta Yellow Black -%AI5_FileFormat 13.0 -%AI12_BuildNumber: 530 -%AI3_ColorUsage: Color -%AI7_ImageSettings: 0 -%%RGBProcessColor: 0 0 0 ([Registro]) -%AI3_Cropmarks: 308.000028558463 25.9999713897596 692.000034280502 409.999977111806 -%AI3_TemplateBox: 297.5 420.5 297.5 420.5 -%AI3_TileBox: 210.800024934497 -194.439997673046 789.200013108935 630.439970970143 -%AI3_DocumentPreview: None -%AI5_ArtSize: 14400 14400 -%AI5_RulerUnits: 6 -%AI9_ColorModel: 1 -%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 -%AI5_TargetResolution: 800 -%AI5_NumLayers: 3 -%AI9_OpenToView: -4137.74468085106 3097.10638297872 0.163194444444444 1576 1034 18 1 0 46 121 0 0 0 1 1 0 1 1 0 1 -%AI5_OpenViewLayers: 776 -%%PageOrigin:0 0 -%AI7_GridSettings: 72 8 72 8 1 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 -%AI9_Flatten: 1 -%AI12_CMSettings: 00.MP -%%EndComments - -endstream endobj 2364 0 obj <</Length 25954>>stream -%%BoundingBox: -1712 -1186 2309 2026 -%%HiResBoundingBox: -1712 -1185.8090553094 2308.00005716867 2026 -%AI7_Thumbnail: 128 104 8 -%%BeginData: 25782 Hex Bytes -%0000330000660000990000CC0033000033330033660033990033CC0033FF -%0066000066330066660066990066CC0066FF009900009933009966009999 -%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 -%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 -%3333663333993333CC3333FF3366003366333366663366993366CC3366FF -%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 -%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 -%6600666600996600CC6600FF6633006633336633666633996633CC6633FF -%6666006666336666666666996666CC6666FF669900669933669966669999 -%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 -%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF -%9933009933339933669933999933CC9933FF996600996633996666996699 -%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 -%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF -%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 -%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 -%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF -%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC -%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 -%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 -%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 -%000011111111220000002200000022222222440000004400000044444444 -%550000005500000055555555770000007700000077777777880000008800 -%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB -%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF -%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF -%524C457D527D527D527D527D527D52A8527D527D527D527D527D527DA87D -%527D527D527D527D527D7DA8527D527D527D527D527D527D7D7D527D527D -%527D527D527D7DA8527D527D527D527D527D52A87D7D527D527D527D527D -%527DA87D527D527D527D527D527D52A8527D527D527D527D527D527D7D7D -%527D527D527D527D527D52527D5252527D5252527D527D7D7D5252527D52 -%52527D525252A85252527DFD07527D7D52527DFD07527D7D7D527D525252 -%7D5252527D527D7DFD04527D5252527D52527D7D5252527D5252527D5252 -%52A87D52527D5252527D5252527D7D7D527D5252527D5252527D52A8527D -%5252527D5252527D52527D527D7D7D52A87D7D527D52A8527D527D527D7D -%7D527D527D7D7D52FD047DA87D7D527D7DA8527D527D527D7D7D527D527D -%7D7D527D527D527D527D527D7D7D527D527D527D527D527D52A87D7D527D -%527D527D527D52527D7D527D527D527D527D527D52A87D7D527D527D527D -%527D527D7D7D527D527D7D7D527D527DFD0452FFFFA8FFFF7D52527D7D7D -%527DFFFFA8FFFF7D525252A852527DFFA8A8FFFF5252527D7D52527DFFFF -%A8FFA87D52527DA85252527D527D527D5252527D7D52527D527D527D527D -%52527D7D527D527D527D527D527D52A85252527D527D527D527D52527D7D -%52527DFFA8A8FFA8525252A85252527D527D7D7D5252527D7D527DFFFFA8 -%FFFF7D527D52A8527D7DFFA8A8FFFF527D527D7D7D52A8FFFFA8FFA87D52 -%7D7DA8527D7DFFA8FFFFFF527D527D7D7D52A8FD097DA852FD097D52A8FD -%097DA8FD047D52FD097D52A87D7D52A8FFFFA8FFA852527D7D7D527D7D7D -%527D7D7D527DFD0452FD04A8FF5252527D7D7D527DA8FF7DFFA87D527D52 -%A8527D52FFFD04A8527D527D7D52527DA8A8A8FF7D7D52527DA8527D7DFD -%06527D527D7D52527D7DA852A8527D52527D7D527D527DA8A8A8527D7D52 -%A852527D7D52A8A87D527D52527D7D52527DFFA8A8FFA8525252A852527D -%7D5252527D5252527D7D527DFFA87DA8FFFF7D5252A8527D52FD06FF7D52 -%7D7D7D527DFFFFA8FFFFFF7D7D7DA8527D7DFD05FFA87D52FD057D527D52 -%7D527D7D527DA8527D52A8FFA8A87D7D7D52A87D527D7D7DFFA8FF527D52 -%7D7D7D527D527DA8FF7D527D7D52A8527D52A8FFFFA8FF7D7D527D7D7D52 -%7D7D7D52A8527D527DFD0452FF7D7D7DFFFFA8527D7D7D527DA8FD05FF7D -%5252A852527DFFA8A8A8FFFF7D527D7D5252A8FFFFA8FFFFFF52527D7D52 -%7D7D7D52FD057D527D7D5252FD057D527D52527D7D52FD097D52A85252FD -%087D52527D7D525252FFA8A8FF7D527D52A8527D52FD047DA8FD04527D52 -%7DA8FFFFFFA87D527D52A8527D52A8A8FFA8A87D7D527DA87D527DA8FFA8 -%FFA87D527D7DA8527D7DA8A8FFA8A8527D527D7D7D527D7DA87DA87D7D52 -%7D7DA8527D52FD057D527D52A87D7D527D7DA87DA87D7D527DA87D527D7D -%A87DA87D7D527D52A8527D527D7DFFA8A8527D527D7D7D527D527D52527D -%FF7D7D52527D5252527D7D52527D527D7D7D5252527D7D7D527D525252A8 -%5252527D7D7DFD05527D7D52527D527D7D7D5252527D7D7D527D527D527D -%527D527D527D7DFD04527D527D527D52527D7D5252527D5252527D525252 -%A87D52527D527D527D5252527D7D7D527D52527D7D5252527D52A8527D52 -%52527D52527D7D52527D527D527D527D527D527D52A8527D527D527D527D -%527D527D7D7D527D527D527D527D527D7DA8527D527D5252527D527D527D -%7D52527D527D527D527D527D7D7D527D527D527D527D527D52A87D7D527D -%527D527D527D52527D7D527D527D527D527D527D52A87D7D527D5252527D -%527D527D7D7D527D527D527D5252527D52527D527D527D527D527D527D7D -%7D527D527D527D527D527D52A8527D527D527D527D527D527D7D52527D52 -%7D527D527D52527DA8527D527D527D527D527D527D7D52527D527D527D52 -%7D52527D7D527D527D527D527D527D52A8527D527D527D527D527D52527D -%7D527D527D527D527D527D52A8527D527D527D527D527D527DA87DA87DA8 -%7DA87DA87DA8A8FF7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA8 -%7DA8A8FF7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA8A8A8 -%7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA8A8A87DA87DA8 -%7DA87DA87DA87DFFA8A87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA8 -%7DA87D527D527D527D527D527D527D7D7D527D527D527D527D527D52A852 -%7D527D527D527D527D527D7D7D527D527D527D527D52527DA8527D527D52 -%7D527D527D527D7D52527D527D527D527D527D7D7D527D527D527D527D52 -%7D52A8527D527D527D527D527D527D7D7D527D527D527D527D527D52A852 -%7D527D527D527D527D527D7D527D527D527D527D527D52A8527D527D527D -%527D527D527D7D7D527D527D527D527D527D7DA8527D527D527D527D527D -%527D7D7D527D527D527D527D52527DA8527D527D527D527D527D52A87D7D -%527D527D527D527D527D7D7D527D527D527D527D527D52A8527D527D527D -%527D527D527D7D7D527D527D527D527D527D52527DFD07527D527D7D7D52 -%7D7D52527D527D7D5252A85252527D5252527D5252527D7D52527DFD0852 -%7D7D527D5252527D5252527D527D7DFD04527D5252527D52527D7D525252 -%7D5252527D525252A85252527D5252527DFD04527D7D527D5252527D5252 -%527D52A8527D5252527D5252527D52527D527D7DFFFD04A8527D52A8527D -%7DFF7DFD04A87D527DA87D527D52527DA8A8A8527D7DA8527D52FD057D52 -%7D527D7D7D527D527DFF7D527D527D7DA8527D527D527D527D527D52A87D -%7D527D7DFF7D7D527D527DA87D527D527D52FFA87D527D52A8527D527D52 -%7D527D527D527D7D7D527D527D527D527D527D52527D52FD06FF7D527D7D -%7D52527DA8A8FFA8A8525252A85252527D7DA87D52A87D527D7D52527D52 -%FFA8FF7D7D527D7D7D527D527DA8FFFF7D527D527D7D52527D527DA85252 -%7D52527D7DFD04527DFFFD0552A87D52527D52A8A87D5252527D7D7D52FD -%077D527D52A8527D527D527D527D527D52527D527DFD06FF7D7D52A8527D -%7DA8A8FFFFFFA87D527D7D7D527D52A8FFA87DA8527D7DA8527D52FF7D7D -%7DFFA852527D7D52527D527DFFA87D7D527D7D7D527D52FD05A8527D52A8 -%7D7D527D52527DFF527D52527D7D527D52A8A87D527D527D52A87D7D52FF -%A8FF7DA8A87D527D7D7D527DA8A8A87DA87D527DFD0452A8FD04FFA85252 -%7D7D7D527D7DA8A8FFA8A8525252A8527D527D7DFFA8A85252527D7D5252 -%7D7D7DA87D7DA852527DA85252527D7DFF7D7D5252527D7DFD0452A8A8A8 -%FD04527D7D527D525252A8A87D527D52A8FD04527DFF5252527D52527D7D -%5252FD04A87DFF525252A852527DFFA8A87DA87D7D527D7D527D52A8FFFF -%A87D527D52A8527D52A87DFFFFA87D7D527D7D7D527DFFFF7D7D527D527D -%7DA8527D527DFFFFFFA8527D527D7D7D527D52FFFFFF7D7D527D7DA8527D -%527D7DFF7D7D527D52A87D7D527D52A8FF7D527D527D7D7D527D527DA8FF -%527D527D52A87D7D7DA87DA87DA87D7D527D7D7D527D7DA87DA87DA87D7D -%FD04527D52A8A87D5252527D7D7D52FD04A8FF7DA87D5252A852527DFFA8 -%7D5252527D527D7D5252527DFF7DA8A87D52527DA8FD0552FF7DFD04527D -%7D5252FD047DA87D5252527D7D527D527DA87D5252527D52A8527DFD0452 -%A8A8527D52527D7DFD0B52A8FD0B527D7D527D527D527D527D527D52A852 -%7D7D7D52FD057D527D7D7D527D7D7D527D527D527D7DA8527D527D527D52 -%7D527D527D7D7D527D527D527D527D527D7DA8527D527D5252527D527D52 -%A87D7D527D527D527D527D527D7D7D527D527D527D7D7D527D52A8527D52 -%7D527D527D527D527D7D7D527D527D527D527D527DFD0D527D7DFD0B52A8 -%FD0B527D7D52527DFD08527D7DFD0B527D7DFD0B527D7DFD0B52A8FD0C52 -%7D7DFD0B52A8FD0C527D7D7D527D7D7D52FD047DA87D7D527D7D7D527D7D -%7D527DA87D527D7D7D527D7D7D527D7DA8527D7D7D527D7D7D527D7DA8FD -%047D527D7D7D52FD047DA8527D527D7D7D527D7D7D52A87D7D527D7D7D52 -%7D7D7D527DA87D527D7D7D527D7D7D527D7DA8FD047D527D7D7D527D7D7D -%A87D7D7D527D7D7D527D7D7D527DA87DA87DA87DA87DA87DA8A8A87DA87D -%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87D -%A87DA8A8A87DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA8A8 -%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8A87DA87D -%A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D527D527D527D527D -%527D52A8527D527D527D527D527D527D7D7D527D527D527D527D527D7DA8 -%527D527D527D527D527D527D7D52527D527D527D527D527D7D7D527D527D -%527D527D527D52A87D7D527D527D527D527D52527D7D527D527D527D527D -%527D52A87D7D527D527D527D527D527D7D7D527D527D527D527D527DFD04 -%527D5252527D5252527D7D7D527D5252527DFD0552A8527D5252527D5252 -%527D527D7DFD04527D5252527D52527D7D5252527D5252527D5252527D7D -%52527D5252527DFD04527D7D527DFD07527D52A8FD09527D52527D7D5252 -%527D5252527D525252A85252527D5252527D5252527D7D527D527D527D52 -%7D527D52A8527D527D527D527D527D527D7D7D527D527D527D527D527D7D -%A8527D527D527D527D527D527D7D7D527D527D527D527D527D7DA8527D52 -%7D527D527D527D52A87D7D527D527D527D527D527D7D7D527D527D7DA852 -%7D527D52A87D7D527D527D527D527D527D7D7D527D527D527D527D527DFD -%04527D527D527D5252527D7D7D527D527D527D527D527D52A8527D527D52 -%7D527D527D527D7DFD04527D7D7D527D52527DA85252527D7DFF7D7D5252 -%527D7D52527D527D527DFD04527D7D527D525252FF5252527D52A8527D52 -%52527D7D7D527D52527D7D5252527DA8A87DFD0452A85252527D527DA8FD -%04527D7D527D7DFD04A87D527D52A8527D7DFF7DFF7DA8A87D527D7D7D52 -%7DA8527DFFA8A8527D7DA8527D52A8A8FFFFFF527D527D7D7D527D52A87D -%FF527D527D7DA8527D527D52FF527D527D52A87D7D527D527DA87D527D52 -%7D7D7D527D52A87DA8A87D527D52A8527D52A8A87D52A87D7D527D7D7D52 -%7D527DFFFF7D7D527D52527D527D7DA87DFF7D52527D7D7D527DA87D7DA8 -%A8FF525252A8525252A852A8A8A87D52527D7D52527D52A8A8FF7D525252 -%7D7D527D525252A8A852527D527D7D5252527DA8A8A87D5252527D7DFD05 -%52A8527D525252A852527DA87DFFFFA87DA852527D7D527D7DFD04527D7D -%5252A8527D527DA8FFFFFF7D5252527D527D7DA87DA8A8A8527D52A8527D -%7DFF7DA8A8FF7D7D527DA87D527DA8A8A8FFA87D527D7DA8527D527DA8FF -%FFA8527D527D7D7D527D527DA87D527D527D7DA8527D52A8A8FF7D7D527D -%52A87D7D527D527DA87D527D527DA87D527D7DA87DA87DA87D7D52A8527D -%52A87D7D527D7D7D527D7D7D527D7DFD04FFA8527D52527D5252527D5252 -%527D527D7D7D5252527D527D527D525252A85252527D527D527D5252527D -%7D52527D52FF7DFFA852527D7D7D527D525252A85252527D527D7DFD0452 -%7DA852527D52527D7D5252527D52A8527D525252A87D52527D7D7D527D52 -%52527D7D7D52527D7D525252A8527D52A8527D527DA8A8FFFF527D52527D -%527D527D527D527D527D52A8527D527D527D527D527D527D7D7D527D527D -%527D527D527D7DA8527D52FD057D527D527D7D52527D527D7D7D527D527D -%7D7D527D527D527D527D527D52A87D7D527D527DA87D527D52527D7D527D -%527D7DA8527D527D52A87D7D52A87D7D7DA8A87D527D7D7D527D527D527D -%7D7D527DFD04527D5252527D5252527D7D7D527D5252527DFD0552A8527D -%5252527D5252527D527D7DFD08527D52527DA85252527D5252527D525252 -%7D7D52527D5252527DFD04527D7D527DFD07527D52A8FD05527D7D52527D -%52527D7D525252A8FD047D525252A85252527DFD07527D7D527D527D527D -%527D527D52A8527D527D527D527D527D527D7D7D527D527D527D527D527D -%7DA8527D527D527D527D527D527D7D7D527D527D527D527D527D7D7D527D -%527D527D527D527D52A87D7D527D527D527D527D52527D7D527D527D527D -%527D527D52A87D7D527D527D527D527D527D7D7D527D527D527D527D527D -%527D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7DA8527D7D -%7D527D7D7D527D52FD057D527D7D7D52FD047DA8527D527D7D7D527D7D7D -%52A87D7D527D7D7D527D7D7D527D7D7D527D7D7D527D7D7D527D52A8FD04 -%7D527D7D7D52FD057D527D527D7D7D527D7D7D52A87D7D527D7D7D527D7D -%7D527DA87DA87DA87DA87DA87DA87DFFA8A87DA87DA87DA87DA87DA8A8A8 -%7DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA87DA8A8A87DA87DA8 -%7DA87DA87DA8A8A87DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA8 -%7DA8A8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8A8 -%7DA87DA87DA87DA87DA87DFD0C527DFD0C52A8FD0B527D7DFD0C527DFD0B -%527D7DFD0B527D7DFD0A5227A8FD0C527D7DFD0B527DFD0C527D527D527D -%527D527D527D52A8527D527D527D527D527D527DA87D527D527D527D527D -%527D7DA8527D527D527D527D527D527D7D7D527D527D527D527D527D7DA8 -%527D527D527D527D527D52A87D7D527D527D527D527D527DA87D527D527D -%527D527D527D52A8527D527D527D527D527D527D7D7D527D527D527D527D -%527D52527D5252527D7D7D527D527D7D7D5252527D5252527D525252A852 -%52527D7DA8A8A85252527D7D52527D5252527D7D7D527D7D7D527D525252 -%A85252527D527D7DFD04527D7D52527D52527D7DFD05527DFD0552A87D52 -%527D527D7DFD04527D7D7D527D52527D7D5252527D52A8527D527DFD0452 -%7D7D52527D527D52A8FFFFFF7D527D52A8527D7DFFA8A87DA87D7D527D7D -%7D527DA8A8527DA8A8527D7DA8527D527D527DA8A87D7D527D7D52527D7D -%FD04A87D527D7D7D527D52A8A8FFA8A8527D52A87D7D527DA8FFFFA87D7D -%52527D7D527D52A8A8FFA8A8527D52A87D7D527DA8FFA8A87D7D527D7D7D -%52A8FFFF7D7DA8FF527DFD04527DFD04FF7D52527D7D7D52A8FFA87DA87D -%A87D5252A852527DA852A85252A87D527D7DFD0652A87DA852527DA85252 -%52FD04A8FF5252527D7D52527DA8A852A8A85252527D7D525252FF7D7DA8 -%A8527D52A85252527DA87D52A87D5252527D7D52527DFF527DA87D525252 -%A85252A8FFA8A8A8FF7D7D527D7D527DA8FFA8FFA8FF527D52A8527DA8A8 -%527D5252527D527D7D7D52A87D7DFFFF7DA87D527DA8527D527D7DA8A8A8 -%527D527D7D7D52A8FFA87DFFA8A8527D7DA8527DA8FF52A852FF7D7D52A8 -%7D7D52FFA87DA87DFFA8527D7D7D527DA8A87DA852FF7D7D52A87D7D52FF -%FD047DFF7D527D7D7D52FF7D7DFFFF527D7D7DFD0452A8FFFFA8FFA85252 -%7D7D7D52A87DFD04527D527D52A85252A87D52FF7D52A87D527D7D52527D -%7DFFA852527D52527DA8525252FD04A8FF7D52527D7D52527DA87D527DA8 -%7D52527D7D527D7DA8527D7DA8527D52A8527D52A8A87D7D7DA87D52527D -%7D52527DA87D7D7DA8525252A85252A87D7DA8A87D7D7D527D7D527D52FD -%04FF7D527D52A852527DA87DA87DA87D7D527D7D7D527DA87D52527DFF52 -%7D7DA8527D7DA8A8A8527D527D527D7D7D5252A8FFA8FFA87D527D7DA852 -%7D52FFFD04A8527D52A87D7D527DFFA8A8FFA852527D7D7D527D7DFFA8A8 -%FFA8527D52A8527D527DFFA8A8FF7D7D527D7D7D52A8A8FF7DA8FFA8527D -%52527D52527DFFFF7D527D527D7D7D527D527D527D527D525252A8525252 -%7DFD04A85252527D7D52527DA8A8527DFD04527D7D527D527D52A87D7D52 -%7D527D7DFD04527DA87D527D52527D7D5252527D7DA8527D525252A85252 -%527D52A8A87DFD04527D7D527D527D7DA8527D527D52A852527DA8527D52 -%7DA87D52527D527D527D527D527D527D52A8527D527D527D527D527D527D -%A87D527D527D7D7D527D527D7DA8527D527D527D527D527D527D7D7D527D -%527D527D527D527D7DA8527D527D527D527D527D52A87D7D527D527D527D -%527D527DA87D527D527D527D527D527D52A8527D527D527D527D527D527D -%7D7D527D527D527D527D527D52527DFD07527D52527D7D5252527D525252 -%7D525252A85252527DFD07527D7D52527D5252527DFD04527D7D527D5252 -%527D5252527D527D7DFD04527D5252527D52527D7D5252527D5252527D52 -%5252A85252527D5252527DFD04527D7D527D5252527DFD0552A8FD05527D -%5252527D5252FD0C7DA8FD0C7DA8FD0C7DA8FD0B7DA8A8FD0C7DA8FD0B7D -%A8FD0C7DA8A8FD0B7DA8FD0C7DA8FD0F7DA87D7D7DA87D7D7DA8A87D7DA8 -%7D7D7DA8FD057DA8FD057DA87D7D7DA87DA8A8FD047DA87D7D7DA87D7D7D -%A87D7D7DA87D7D7DA87D7D7DA87D7D7DA87D7D7DA8FD047DA8A87DA87D7D -%7DA87D7D7DA87DA8FD057DA87D7D7DA87D7DA8A87D7D7DA87D7D7DA87D7D -%7DA87D7D7DA87D7D7DA87D7D7DA87D527D527D527D527D527D52A8527D52 -%7D527D527D527D527D7D7D527D527D527D527D527D52A8527D527D527D52 -%7D527D527D7D52527D527D527D527D527D7D7D527D527D527D527D527D52 -%A87D7D527D527D527D527D52527D7D527D527D527D527D527D52A8527D52 -%7D527D527D527D527D7D7D527D527D527D527D527DFD04527D527D527D52 -%52527D7D7D527D527D527D5252527D52A8527D5252527D5252527D527D7D -%FD04527D5252527D52527DA85252527D5252527D5252527D7D52527D5252 -%527DFD04527D7D527D5252527D5252527D52A8527D5252527D5252527D52 -%527D7D5252527D5252527D525252A85252527D5252527D5252527D7D52FD -%057D527D527D52A8527D52FD057D527D527D7D7D527D7DA8A87D527D527D -%7DA8527D52FD057D527D527D7D7D52A87DFD05A87D527DA8527D527D527D -%527D527D52A87D7D52A8FD047DA87D527D7D7D527D5252527D5252527D52 -%A8527D527D527D527D527D527D7D7D527D527D7D7D527D527D52527D527D -%7DA87D7D527D527D7D7D52FD057DFD0552A852527DFFA8FFA87D5252527D -%7D52527DA87D7DA87DA852527D7D527DA8A8A8FFA8A8A87D527D7D52527D -%7DA87D7D527D52527D7D52527DA87DA87DFF7D5252A8525252A87DA87DA8 -%7D7D52527D7D527D525252A87D52527D52A8527D525252FFA852527D5252 -%7D527D7DFFFFA87D7D527D52A8527D7D7DFFFF7D7D527D527DA87D52A8FD -%04FF7D7D527D7DA8527DA8A852A87D7DA87D527D7D7D52FD07FF7D527DA8 -%527D7DA8A8A87DA87D7D52A87D7D527D7DA8A87D7D7D527DA87D52A8FD06 -%FFA87D52A8527D527D52A87DA8527D527D7D7D527D7DA8FFFFA8A87D7D52 -%527D527DA8FFA87D527D527D7D7D527D7DA87D7D527D525252A852527DFF -%A8FFA87D5252527D7D5252A87D527D7D52A852527D7D527DFD07FF7D527D -%7D52FD087D52527D7DFD0452A8A87DFD0452A87D5252FFFFFFA8FFFFA852 -%7D7D7D527D7DA87D7D7DA8527D52A8527D52FFFFFFA8FFA87D52527D52FD -%047DA8A87D527D52A8527D527D7D7DA8A8527D527D7D7D527D7DFFA8FF7D -%7D527D7DA852527DA852A8527DA87D527D7D5252FFFFFFA8FFFFFF7D527D -%7D527D7DFD05A87D7D52A87D7D527D7DA87DA8527D52527D7D52A8FD06FF -%A87D52A87D7D52A8527D527DA87D527D7D7D527D52FFA8FFA87D527DFD04 -%527D527D52A8A852527D7D7D527D527D527DA8A8525252A8527D5252527D -%52A87D52527D7D52527DFD06A852527DA8527DFD07A87D527D7D52527D7D -%A87DA87D7D52527D7D527D52A87D7DA87D527D52A852527DA87DFD05A852 -%527D7D52FD067DA8525252A85252527DFD04FF5252527D7D527D527D527D -%52A87D7D52A8527D527D527D527DA8A8527D7D7D527D527D527D52FF7D7D -%7DA8527D52FD077D527D7D7D52FD04A8FFA8FF7D7D7DA8527D52FD057D52 -%7D52A87D7D527D7DA87DA87D7D527D7D7D527D527D527D527D527D52A87D -%7D52FD057D527D527D7D7D527D7DA8527DA87D527DFD04527D5252527D52 -%7D527D7D7D527D5252527D5252527D52A8527D5252527D5252527D527D7D -%FD04527D5252527D52527DA85252527D527D527D5252527D7D52527D5252 -%527DFD04527D7D527DFD05527D527D52A8527D5252527D5252527D52527D -%7D5252527D5252527D525252A85252527DFD07527D7D527D527D527D527D -%527D52A85252527D527D527D527D527D7D52527D527D527D5252527D7DA8 -%527D527D527D527D527D527D7DFD04527D5252527D52527D7D527D527D52 -%7D527D527D52A87D52527D527D527D527D52527D7D527D527D527D527D52 -%7D52A8527D527D527D527D527D527D7D7D527D527D527D527D527D52FD0C -%7DA8FD0C7DA8FD0B7DA8A8FD0C7DA8FD0B7DA8FD0D7DA8FD0B7DA8FD0C7D -%A8FD0C7DA8FD0C7DA87DA87DA87DA87DA87D7D7DA87D7D7DA87DA87DA87D -%A87DA8A87D7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8 -%A87DA87DA87DA87DA87D7DA8A87DA87DA87DA87DA87DA87DA8A87D7DA87D -%A87DA87DA87D7DA8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D -%A87DA8A8A87DA87DA87DA87DA87DA87DFD0C527D7DFD0B52A8FD0B527D7D -%FD0B527D7DFD0B527D7DFD0B527D7DFD0B52A8FD0C527D7DFD0B52A8FD0C -%527D527D527D527D527D527D52A8527D527D527D7D7D527D527D7D7D527D -%527D527D527D527D7DA8527D527D527D527D527D527D7D52527D527D527D -%527D527D7D7D527D527D527D527D527D52A87D7D527D527D527D527D5252 -%7D7D527D527D527D527D527D52A87D7D527D527D527D527D527D7D7D527D -%527D527D527D527DFD05527DA87D7D5252527D7D7D527DA8A87DFFA87D52 -%5252A8525252FF7DA8FFA8527D527D7D52527D527D527D527D52527DA852 -%52527D5252527D5252527D7D5252FD057DFD04527D7D527D527DFD05527D -%52A8FD0752A87D5252527D7D5252527DA8A87DFD0452A85252527DA8FFA8 -%FF7D52527D7D527D52FD05A8527D52A8527D7DFD05FF7D7D527D7D7D52A8 -%FFFFA8FFFF7D527D7DA852FD067DA87D7D527D7D7D52A87DFFA8FFA8FD04 -%7DA8527D7DA87DA87D7D527D52A87D7D52FD04A87D527D527D7D7D527D52 -%7D52A8A8A8527D52A87D7D527DA8FFFFFF7D7D527D7D7D527DA8FD04FFA8 -%527DFD04527D5252527DA87D527D7D7D527DA8FF7DFFA852527D52A8527D -%7DFFFD04A8527D527D7D52527D7DFD04A87D7D527DA8527D527DFFFFFFA8 -%527D527D7D5252FD057DFD04527D7D52527DA8A8FFA87D527D52A8527D52 -%52527D7DA87D5252527D7D527DA8A87DA87DFF7D5252A8525252FD05FF7D -%52527D7D527D7D7D527D527D7D7D52A8527D52FD05FFA87D527D7D7D527D -%FFFFA8FFFFA8527D7DA8527D7DFD05A87D7D52FD067DFFFFFF7D7D7D527D -%A8527D7DA87DA87D7D527D52A87D7D52A8A8A8FFFFA87D527D7D7D527D52 -%7D7D7DA87D527D52A8527D7DFD05FFA87D527D7D7D527DA8FD05FF527D52 -%527D52A87D52527D527D527D7D7D527DA8FFFFFFA8FF7D5252A852527DFF -%FFA8FFFFFF7D527D7D52527D527D527D527D7D527D7D527D7D7DA8FFA87D -%527D527D7D5252FD047DA8FD04527D7D52527DA8A8FF7D7D525252A8FD04 -%527DA87DFFFD04527D7D52527DA8A8FFA8A8527D52A8525252FD05FFA852 -%52527D527D7DFFA8FFA87D527D52A8527D52FD05FFA87D527DA87D527DFF -%FFA8FFFFA8527D7DA852FD047DA8A8A87D7D527D7D7D527D7DA8A8A87D7D -%527D7DA8527D52FD047DFF7D7D52A87D7D52A8A8A87D7D527D527DA87D52 -%7D52FFA8FFA87D527D52A8527D7DA852A8A87D7D7D527D7D7D527DFD06FF -%7D7D52527D5252527DA87D527D527D7D7D5252527D7D7DFD0552A8525252 -%FD057D5252527D7DFD04527D527D7D52527D7D7D527D527D527D527D527D -%527D7DFD04527D52527DA852527D7D5252527D5252527D525252A87D5252 -%7DA852527D5252527D7D7D527D5252527D5252527D52A852527DA8A8FF7D -%7DA87D52527D527D527D527D527D527D52A8527D527D527D527D527D527D -%7D7D527D527D527D527D527D7DA8527D527D527D527D527D527D7D52527D -%527D527D527D527D7D7D527D527D527D527D527D52A87D7D527D527D527D -%527D52527D7D527D527D527D527D527D52A87D7D527D527D527D527D527D -%7D7D527D527D527D527D527DFD0D527DFD0C527DFD0B527D7DFD0C527DFD -%0B527D7DFD0B527D7DFD0B527DFD0C527D7DFD0B52A8FD0C52A87DA87DA8 -%7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA8 -%7DA87DFF7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA8A8A8 -%7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA8A8A87DA87DA8 -%7DA87DA87DA87DFF7DA87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA8 -%7DA8FD0D7DA8FD0C7DA8FD197DA8FD0A7D52A8FD0C7DA8FD0C7DA8FD197D -%A8FD0A7D52A87D527D527D527D527D527D52A8527D527D527D527D527D52 -%7D7D7D527D527D527D527D527D7D7D527D527D527D527D527D527D7D7D52 -%7D527D527D527D52527D7D527D527D527D527D527D52A8527D527D527D52 -%7D527D527D7D7D527D5252527D527D527D7DA8527D527D527D527D527D52 -%7D7D7D527D527D527D527D52527D527D5252527D527D527D527D7D7D5252 -%527D5252527D525252A85252527DFD07527D7D52527DFD08527D7D527DFD -%07527D527DFD05527D5252527D52527D7DFD0B527DFD05527DFD05527D7D -%FD0B527D7D527DFD07527D527D7D527D52FD057D527D52A8527D527D527D -%527D527D527DA87D527D527D7D7DA87D527D7DA8527D527D527D7D7D527D -%52A87D7D527D527DA8A87D7D527D7D7D527D527D527D527D527D52A87D7D -%527D7D7D527D7D7D527D7D7D527D52FFFFFF7D7D527D7DA8527D7DFFA852 -%7DFF7D7D527D7D7D527D7DFFA8FFA87D527D7D527D527D7DA8A852527D52 -%7D7D7D525252FD05A8525252A85252527DA8FFA8FFA852527D7DFD0552A8 -%FFA8A852527D7D527D52527DFFFFFFA87D527D527D5252527D7D7D527D52 -%527D7D52527D7D52527DA85252527D5252527DFFFFFFA85252527D7D5252 -%FFFFFF7DFFFFFF7D527D7D527D52FFFFFFA8A8A87D527D7D527D527DA8FF -%7DA87D7D52A8527D7D7DA8FFFFFFA87D527D7D7D52A8FD06FF527D52A852 -%7D7DA8A8FD04FF7D52A87D7D527D52A87D7DA8A8527D7D7D527D7D7DA8FF -%FF7D527D52A8527D7DFFA87D52FFA87D527D7D7D527D7DFFFFFFA852527D -%7DA8527DA8FFA8FFA8FFFFA8527D7D7D52A8FFFFA85252FF7D7D7D525252 -%7DA8FFFFFF7D52527D7D7D52A8527D527DA8FF7D5252A852527DFD05FF7D -%52527D7D5252FFFFFFA8FFFFA852527D7DFD04527D7DFD05527D5252527D -%A8FFFFFFA8A852527D7D52A8FFFF7DA8FFFF7D52527D527D5252A8FFFFA8 -%7D7D527D7D52527DA8A87D7DA87D52527DA85252A87D7DFF7DA8A852527D -%7D527D7DFFA8FFFF7D527D52A8527DA8FFA87D527DA8A8527D7D7D527DA8 -%FFFFFF7D7D527D7DA8527DA8FD05FF7D7D52A87D7D7DFFFFFF527D527D52 -%7D7D7D527D52A8A8FFA8FF7D7D52A8527D52FFA8FF7DA8A87D527D7D7D52 -%7D7DFFFFA852A8527D7DA8527D52FF7DA87DFF7D7D52FD047DFF5252FFA8 -%7D7D527D7D5252527D527D7D7D5252527D7D7D527DA87D527D5252527D52 -%A8527D5252A8A85252527D527D7D52527DA8FF7D52527D52527D7D527DFF -%FFA852527D5252527D5252527D5252527D5252527D7D7D527DA8FD047DA8 -%527D527D527D52FFFFFFA852527D527D7D5252527DA8FD047D52527DA852 -%52A8FFA8A8FD05527D7D527D52A8A8A87D7D527D52A8527D527D527D527D -%527D527D7D7D527D527D527D527D527D7DA8527D527D527D527D527D527D -%7D7D527D7D7D527D527D527D7D7D527D527D527D527D527D52A87D7D527D -%527D527D527D527D7D7D52A8FD04FF7D52527D7DA8527D527D7DA87D7D52 -%7D527D7D7D527D7DA8527D527D527D7D527D5252527D5252527D527D7D7D -%5252527D5252527D525252A85252527D5252527D5252527D7D52527D5252 -%527DFD04527D7D527D5252527D5252527D527DFD05527D5252527D52527D -%7D5252527D5252527D5252527D5252527D527D527D5252527D7D52527DFD -%08527D7D527DFD07527D527D7D527D527D527D527D527D52A8527D527D52 -%7D527D527D527D7D52527D527D527D527D527D527D527D527D527D527D52 -%7D527D7D7D527D527D527D527D52527D7D527D527D527D527D527D52A852 -%52527D527D527D527D527D7D7D527D5252527D527D527D7DA8527D525252 -%7D5252527D527D7DFD04527D5252527D52527D7DA87DA87DA87DA87DA87D -%A8A8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8A8A87D -%A87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87D -%A87DA87DA8A8A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D -%A8A8A87DA87DA87DA87DA87DA8A8A87DA87DA87DA87DA87DA87DA8FD0C7D -%A8FD0C7DA8FD0C7DA8FD0A7D52A8A8FD0D7D52FD0A7DA8FD0C7DA8FD0B7D -%52FD1AFFFD0B527D7DFD0C52A8FD0B527D7DFD0C527DFD0B527DFD0C527D -%7DFD0B52A8FD0C52A8FD19FF7D527D527D527D527D527D52A8527D527D7D -%A87D7D527D527D7D7D527D527D527D527D527D7DA8527D527D527D527D52 -%7D527D7D7D527D527D527D527D527D7D7D527D527D7DA87D7D527D52A87D -%7D527D527D527D527D527D7D7D527D527D527D527D527D52FD1AFF525252 -%7DFFFF527D5252527D7D7D527D52A8FFFFA852527D52A8527D52A87D5252 -%A87D7D527D7DFD08527D52527DA85252527D527DFD05527D7DFD0452A87D -%FFA87D52527D7D527D525252A8A87D527D52A8527D527DA8FF5252527D52 -%52A8FD19FF7D52527DFFFFA8527D527D52A8527D527DFD04FF7D7D527D7D -%7D527DFFFFA8FFFFFF527D7DA852FD047DA87D7D527D527D7D7D527D52A8 -%FFFFA8A87D527D7D527D52A87DA852FFA85252A87D7D527D7DFFA8FFA87D -%527D7D7D527D7DFFFFA8527D527D52FD1AFF527D527DFFFF7D7D527D527D -%7D7D527DA8FFFFFFA8FF7D5252A8525252A8A8FFA8FF7D52527D7D5252A8 -%A8FFA8A8A87D52527D7D527DA8FFA8FD04FF7D527D525252A8FFFFA8A852 -%A852527D7D527DA8FFFF7D7DFFA85252A85252527DFFFF7D7D527D5252A8 -%FD19FF7D527D52A8A8FF7DA87D7D52A8527D7DFD06FF7D527DA87D52FFFF -%FFA8FFFFFF7D7D7DA8527DA8FFA8FFA8FF7D7D527D7D7D52FD07FF527D7D -%7D527DFFFFFD05A87D52A87D7D7DFFFFFF7DFFFFA8527DA87D527D7DA8A8 -%FF7DA87D7D52FD1AFF52527DFF7DA8FFA87D7D527D7D7D52527DFFFF7DA8 -%A8525252A85252A8FFA8FFFFFFA87D527D7D5252FD067DA852527D7D5252 -%7DFFA8FFA8FF7D52527D52527DFFFFFFA8FF7DA852527D7D52527DFD04FF -%7D525252A852527DFFA8A8FFA87D52527DA8FD19FF7D527DA8FFFFFFA87D -%527D52A8527D527DA8FFA8A8527D527D7D7D52527DFFFFFFA87D527D7DA8 -%527D527D527D527D527D527D7D7D527DA8A87DA87D7D527D7D7D527DFD04 -%FF7D7D527D52A87D7D527DA8FFA87D527D527D7D7D527DA8FFFFFFA87D52 -%7D52FD1AFFFD04527D7D527D5252527D7D7D527D527DA8A8FD0552A8527D -%527D527D527D527D527D7DFD04527D5252527D52527DA8FD0B527D7D5252 -%7DA87DFD06527D7D527DFD07527D52A8527D5252527D527D527D5252A8FD -%19FF7D527D527D527D527D527D52A8527D527D527D527D527D527D7D7D52 -%7D527D527D527D527D7DA8527D527D527D527D527D527D7D7D527D527D52 -%7D527D527D7D7D527D527D527D527D527D52A87D7D527D527D527D527D52 -%7D7D7D527D527D527D527D527D52FD1AFFFD0B527D7DFD0C52A8FD0B527D -%7DFD0C527DFD0B527DFD0C527D7DFD0B52A8FD0C52A8FD19FFFD0CA8FFFD -%19A8FFFD19A8FFFD0BA8FFFD19A8FD99FFFF -%%EndData - -endstream endobj 2365 0 obj <</Length 65536>>stream -%AI12_CompressedDataxz(ϓ{$22g h6k?8767&,UI*VD!פ$" YY+J&v:USO% *{ȿ-o$Em˽Lz?{uDTA-Gbiu$xޮ=))ׇhLg"LJ("L"!jЀdiF?A2ɑ|< !EP,juоT$OD: $4G< !+ EK;f"_b/r*1r/u:H#?mK6[~; OR=:~Q=[/h:%[Xx&I };=L $+jƂ=$ܠi 5 _1U` p }ǿs]"iHU9g+{AAu" oB4ϰtJ'#i^a -'aAo‘ xk�J~ &%pt|7 f$r fQ$C#,G x!IA& ^&p m-D`^4*ZEp CjБ^I>A'ܐ:D#bZOEUT% fhXC,m 9K|`HKr & D/49*B$AY�qD4FH`KqGX$EG>^ JD\i{s4kYi7F  (B%<Pa~14gK"Dk.kULn<A? @$ vSŁ"\%,-j* %kWۀ>%<O -h#K֒k*uQ{wP�vGjj"HiZ~�x; Q�~RR!@H)X�Lu _TCe '/!uhK -XԾXrL>PW"JҐҤeTM{:GZߒz)'xu- +0)ՇE)hmYIi-E&t -֨1:NGH -o@Ztpx= -NSaF@SY,�*cZ>Sy "~=U/CաpئRg!9_8_8p|^wίԹA2qmZ{a%+ -,[=55%Es<mQG-%4z@IzުmA=7>ɖdFGc:1 l ?01~?/Zl赪"dY{WhLnY))G]W0ti&lԭKS "yd M=-q#t -}2~L6^*֯An Gq7 -1 -ǯ0 ^^zò"f%EOY,+b< <lH��)iXTo:8`7"\.G]p0 b� ~AjBG�З j0"*x7#`&3ۚ6PD0~@I](`!Dcl`y -/NDsm̋`o둜2P[,w,i衐@n4 -C@�BInM.�! Ta8#At2 Eo8P_qJ&ߏq " -T| !ciKV14 :C_Aߟk5`pA[J ˪&Zfٲ2FkuK$EPRz-F"]>adO3dq u>ෟ&ry|&" x -ڧ#\ rIo/=BeԚ~:1EI6STPs,M&),M7I:)|@0+fjoSs?@Wp BC+ATH=֑Q@ofT$uˊ -Q|(Fÿ+I윊 5*v]Yw}_8B#c[c?B$Յ@d”tmTҧ)F5/#IC(doך zyD1zGSkg(H(uܓ_Hcٞ܋$EGRgbWBUkȘl%T*$:5W5u!B# k(;da44YJt=i 1LaHԄ/phFN):M Ir,Å{/OOgO?n1p?c?&mo>hwhk/˷�tDo*m6NNꦭk r&vذPaT%mD̒`zIMIds_x{ %x`8@as -uG+kWR]VR=n/]?톾}+B-P*JV.eQcW8:!Ap7A `i,(0έ.Th?ޕ/yp\:*HFC'%B3"SmbCH1ӘߐSciwP(/3C_WvVοj_7$U;!! sW;CAKw;z3|e296HCM0̉ആӷ`NncrSרڨר?TO,H>ºo-4˧92(JH-ZJ<&)`Q9IG@P, 6dIO nNi;=5C˲iiv lp&DJ̥?4Xj\Vd?t1/> lm\T(RxߥxѠ.gm3{DAG -W쪨7f,;*ZZ˺<DdO -`ܐ$ťf`p<˳fI`QQ,_a1`3I o'}xc\}\5,E05t*~QglbJqzE͍:d'�qM=ā@c_06,O?0>)c9(*/))P/WY'.¦yV_.d~>S?�Jͩ|Ob�Q_6A]u!4\dy^\I|w@х@cr.MqhH~  Tʇ*JMFEHuMjx02-crcb4GQ3w4a'(t:-!$!՘ H<4/h, za`>'f#88"Ӗ�788yd ڒN>5l$$8͛%ѹV+xsgLtObtn:MS i�3Xt ̘|�+NA>6,7$l=?7&_4@=8%7҄16pX`C2i!Ƙw&dFQqJ^>4 -N໯Oʁ٘Jԝe'+ -VƸmҳq)6p$3Nќő~N~0sZC^;ETρAvvߏCv<xTo; EcObf6vlwFX#A<z`ԘG?5hd7m6!$gק9ϦבĆǔ9vߟTg̜ij34(�sKM{<PfﳲПh( 9dܼ8+@ߎ=,S 0Ò&v^10�b ob{muؚK`f& ?{IQk㢦YC3h,bydyxx`vM|?%us {h3ő9B̸֕,Ն~LqIQde�=%f, 2/_f̬q?k1917=03[쁀{ =5'||}71}mƠYKfQѽ~^n?C ӎ<sʏA/ρ7 ~iqoΛymi6 -{\L G^_#A{3'Gٓ ps*i하1Egf33g,05v8<?5v7qg?YzF矛s?0Scۜ g 3g,0Wk'O` -8#ߞ780266^1K>C؈6~ʰHɹ7 8c �{W K0Og5@2(;Oh7$Ӯ)3`ZC, %@̜?S.<`(.N (9K`�w7riFsi"x"Mc.[�uyL{ZKz37 AAg5H{<W䟯7|Qܱ9p%@WܱD pʝt&!ܩ9p"`?~6=gZ:}�rV(D@<C梣'vrͧF As%C& Wɓ~/iq9pj,uɩW4;[955IX5vobqTQ80g�7veՔFV*Qs*5~́A??Γ q�66k1p:r 9Fk)NgRgx5t-?}2)7@sDƗos`#ft`Or&ڪ&+8v>@NLIb '+� GrߎO80tx4Ş&oB\> SIl$$f#yf9SE=YfXw槤 ; +8H:; - JN3t(&"Is" ߏM'Y&2ؤ]W&$lJdh4&y& ,8d%808)"vʼn&ʣ$fY`?A Lih C~u+!3sUF h?@1qA9pRsf<X<O4`PZ,}Mmw&'N#@{0,C0 x$hߥȸo% Egg IH'<xm0fa Yt71 ."̓Mgg/IYV$q|C.i[zTW8ٝH;5g7(MiaҤAigq3JgsJ-+b5= <1m ]`Y"B$X9%ktM~zzhF90 0aRDGL"U7<B%XaxTAMClv΁Qip\6 0?ŁPYvF͚L҄s$h38 oK G,O9cBRcc'9.Qsic&18D !}CxR,]sbXȦ '=g8I>@Wq<KP.sGROLN&Xs$rh` z4 jA9pA9^lN(6K;NmEbf|c4uwzrAqk|̜Xڍҗ.CC7I[?DE3e GÞ?fM{ 6R@ҊdlrYSlOyu6Ў\&4S(f'Opnjf8'W -j=>P5 oь*v j"(ww6~4iq=o -Loݣc>jxsM$kIV(9l-F!^gBh-9<s\5YDjjf _6֠yԥ<5 GW`s0sg۠Cɜ53gI2R0Et#'b} K ?;#; ZQ"`waڔW\e |u8!qj_֜jhT9}a9vr4a$;ȕG?WhwEKhS" u4V-}I׻۰|=EHPlKE6 4@ƁG&mP$UR~H)6ښXkwޚyzؔ!bR-F$եxۼ(4]"֠n0% TR[Cì\I4a{|A^""%d}!)j_)C*D^IH~H,+72E~a$Rco"3# \aLSAx&,.;x`pQ_:np={@y) O -C\pCN *uB晩!簵`rC-&*�se`>ML!C)r^C"^c—JmE_c7[ǹJMi+Sɑ^ --P2jeP5V{zͱ4t\lmSG_}YP% uUiPg;>x t;@W3; -V0HXjbG7 AkנVuE DUƔGk踤lmϫJWI9YYiNX4˚_+*Mq,˖wȹ -mGGkX-LڷqIKN Z]iK?aڪf>ZUq8APd6UE4p{L?a-26 vX0i^Iz.tTZ Q-iO\z (V)B)f1ֶحI En;VE@Aݪ#tyj[c Wݓ".MYKS#w5$LUSaT%FIG]t:RwSdEuo!ve!5\HLх:X̔:'DzhY{x=En")^T"yeʾZSp}zxMw CsLD^9^qo8ӹsG.mֺ͍ (k:@VS�_C%1?Ng,3P|>tf=W+m}"pθwl~5 z8lN?#vk1Exɋ+VF6~|AhfCm}mR\V&42#by)yV#$8p\P< -هQШ 0zקpXZZW@tdsЫzn"Olj 7o:Eg  Dkh*OXuه9`0,k(Z`ngk8'->Mx�T�*- 8z񠛣AI6ta]i$U%LVޓNGNܪ P֖I6DJ>|'LX'jH %,d7Ny ^zؑm098|PFѡI -IQGR ۢ|gײ$ zk! U+˥9m]MK,O$G -͡? -MGXlD#fr�DkcmiK]v]泓ޭli&[Gd8ajNlPl`CR=Ѷg$r0`}hl.4}Y8.4{eݾ5alzsA\9Z>JEoU~|D4p} RScu!V4aOuw?XCozѲ2xV_adRkk#I*NP[PwLt~_"H~n|65hMT|5-hfB`94Bdf=wESE5+`l|jdcBT -:NQo_i#_vc -#!u&{;Fd÷~AE<uÊ`QrXmfW/k3o( T sO5�٬okoydw"$Gj,`KGCeEl W#"F~oF |d-x1ޡ鯅f]ƶWzKRE!w#4^ms*@wD; - H9tX4N#]Jת%j -o+yVa(nnt`y4ca$Ukƅix'<6lI3uث|_cmYZjv"?8xK[:m Ү:x<-r&Dl3/P:޾תDEo(-x+gI]gκMj|*|b{UEu߷Ru8r8nޱ2>o=ނI}0q Z.?{z!dk8xJ>/R 22ˁhِNrŗ݌&'^&LAP盡)_']K}9QA?lj<_oi>l+)o!~x"F:EYְžkZ)]Wܲ&R^6jDT#*+5Fr_U9BC zDtmi/G &E�o2r/tܾM�cWn-[4?D ^=+Mh5@qWT:2j9i@$D#Dݎt_�wWوld $tY m֕v?D J l!vYB /n mͫ&[۫pTxӳ鴜d0MM{%:Uƺ u+P(dt5?tXǝqT\:7\1׾%<hCx\t!.HHSf|1}%mѫܾR2Q)[˷Ť^٥uy˜<+:W*R -0K> -Krc{T -oDՑ{?<fJ[/$kcN+V2CY+|<瘇f+Ê֊KRY}tnMI\-sB||Vov~FMv͕A)Vn4 W Bu;wf[ijN|oꀠjEo_a4?ROĝ�#XżnmgWxl-_.Rk^?ѷv<iI"%rJ{-~9j:+{k %4ȞTV�Z4anZ7sO;mKM:g&q4ȴ)LR]t1ܟnBZE9|dv߾i<f3[!K--{C} C@o'tZH۫hAAhXCM� Q[<dҶmxoth=u|GwwTa}�t8{&h;vy2sZI -^1a)c>f(k9v})\]gBzμs_} 6d&eK|Mm5+|sqUC!+_q8֩cZH~2w#~Ceyq-fG`|pZ(a2N*0(˻Xy޶ -Dir]*lls䗝Vg0h::)g_H,7[)<NfNvp%Hj=b>di$0el*}]UzUTU{n|8؀/͚S:le+r'nM-\&O"2s:.>EiU*n-hFCq՛b! =Ifc-uz7rں[!~qS>J 1{lkϫ96~2TzvB單7wF Us[ƴn+un5{U}6nu5g.mɘE?\mVbQ$Qc;_ tLޡRe:TK9<f+oGy㩐}>' 胓0xVUf7F: ~+̪2Dݪ)%H!ɏ<qk[# 9ϣK%<x܅o -nMgJ87{W: w�}3Y ƇY+4O>7cMԧ1ਉ'1k!#4_p{ [4b4� ƏGm4q(XG_͞?uoܗ}^fכ1#xpG'۶7]η|<f3KJX�qL#<H 'p :$1&܏W1u@_C@:L}<$SJ\  - 2~3%K<I'I0}Hc7hb^ Mm\ u5ãaBy3dx2E1ا>ی3:Eu(XGh=R6\;NR GB:L/n'Jզ�G -Tؖ㑲yX{۰q&UoiRN`?)gJэdj4W`|>oW8J9v ,KT=Ľ]vw63kpl9<948ec ö obBsW^nᤔM燐9x-e+=[U.* np_JW𕑳cjixNJý*^ף-} կ-||wiV j*v_78l�p|ȃ'D4WT$E*$ n ]l2(6W.>%br(7_1qt\h^Tr+h<Pmʧa܎{Id%U=K%%goaſ(;E ({,#P<28IzM{cu,,#Oþ?ܞQ"sD%b`|[mfZ_:<@MR,XlXDmk=%�MQ<JsAb؊E |l�IQ먠ϒNl@Ih4զl(|'`wKҺf2{<F4dp=r GjИ]}N}| -[ =2_v:T7$`q ho2-.,j޸` -!h|Wq4NE%IDG !Ug#heXnEXZ>TziJC˘.]5tQ�RWOYE1Dž&Kv'mdpIƆNIn4.H0.Q& -�Kcf<{60~uAGȵAqXo0= d4SuHQp*fZҌʜ?yb(-B<eJ!yHg>x2МP\ecqS>dTgc͈pyG>^-.'(p|,o>s yߪa7R"[VXKΜoݼ#᫫˕U"x|ͽ+Ca�d1pqɣ/Nvl_IFKd>v/40I|Qhtja,-m`jI/oCƲbpPl-PNR1Mfc&ȸVWjkթ^?aR^<={a"\|գP6ゔo/.xy72bƤZ7tj6gn=M<mW <ΉH@6x) -GڊekW6.xƾzv`.NW/lcFR`מld~Ҵf1ҟ_:l|Ku"/;,m�53yIޡ]JإEwM6Ckhs{No#Ҟn`]XWՃ5J;|$^KSj/'0yZ:z,<>ZF }\ͷ"C붭owX3b|mZ-wH_s/7˚fo2`z5cޠhBsç[%\'h{6VK 3JQ|{T}Px_z$V/,{utM GwX ڏe4z\Y]tpCSŗsY%Gp -{u!sdl/10߄\ g#`K -b5 Wh>)?tBwZ(֚;h aa!.}~4ӆD#<fm`KQII? �N!{I)v\,ϔ -fQRCDs~, 5Q8<DQ*)H/ًˇ30r5Pv\] ׇlo -2GP;RB/˖Pz͜u ogm4^=g9 Df-5GԨQ}zw _9ޚ1jH,"z,gBz[nq:\riKW<UߦU4I[W -Rp~K!. =MLX`g]xuЗB -. Ѷ1^uNbpظ -GX iXvD,<Em0j>ǧ}TaxKߜU{&^׻U 4o #5Xrz5sR^.{Hz%8Ƥc|DnD vՎk'4npxۉ#fl ښ,ǩ,_V5=e*˝Ѱ0~Z^yn/iY\߾_@r;# ]݀0)p;vkPϋv9ӏ0=Wy3UC55POd 7& ~j;.j|'[leq; b[zb`%6uiHww,<PRrٞ`]_}>pCRWUT1Hlp;6Gؤw>2[+ \}891`dzW9]ܘTL[2I_^'odiIoHړAA˘VE#zze*-^te VOV/O nll}Gvl -%~8{]fX.1l>V*![Ei =?޸EEm5́p5)kY9یŸ́bPAqWs mi첗`+2~XLP)?#5iG 0GF?o8B6JE`jX54mz'{ka.#@[mrJCv\֡@\ɱurݗ. 6o󹭒u8M>}Y|Ĩ|W?olBw.0{|Lӏ!ƋqL`ko. !)tSg>ݣ8?ⳇSIyڇT"(]t!t�'ݱ-}H |�-CzciV8  -^cx+J9CÅMO ߻T4ki4F1ۗzr ?آZʟ`0+wOA_h@=o~DDnE7O -b1IQaF/1~fm8x;C,I ӓ[\0>)5}vPTqYowq˗{~JVᥣ.~Ǹi<Bb}GY?JY~V^y|?ABM4hGf݊CM N1>a]TUx?2Vy[n 0B>o;Dcus={+}:NҍCr% -z.)m`A ٸZ}n[LFLEqJؐsROq iv$czԀ8x򊲻S .},MQyz `pNvGΥk<(29ֺLE)Hi(} r@dR Y]x!>pSZhȇ8n_w Un$VIoX+ʗzU*&/~g7ʓ΃n9:�RSGuߜN>([DĬҊ'u=wj _fT kMyIoݱ֗7 -{{nܱ2w+ <!b;.-/DyVqZ*yZu.Q>vo+̖ZN[i{cz{CVFc 3bMfÚNw_^X_~n#6"˕IW/{oW^X+4 賺Ԓܱ^w'nX[̮V'K_}#Q:޾pźX -+Y +QG#7vīR D/zvK|n*;uJ1gJZ|,ٰ>'ncr{ -h=6%Oi8Wܰ,='6\rJsXO1!uKcrR~\ZkU:Kܰbˆy<$n^v݉|"Ģg{Xo7Xo%и M<lc=;>+VLgȃO{Kqz_otF0Vތwe#u;U'<~|߮+B5Ԁ6X^RksZay -Csų>a`B,f|(Kkrm%&Ÿ{Z8N*qc#գ(+VJEVGh�116㮰X5@Qqs:F)xj[t0:8rŪ4TVG͘?<mG4y~YNz?=|~8-ʍ x^isOWSӴM\2>}=}._,[Ҁ}~*x?}H?OD{{c|HOz6 t'ټ~Əh.-{~|Y˯~Di˧ӚS F)|CIA|{dڷ:&۪y;T9;'ϥn KQTDtu�KKwO,�XZs 3ީ,a}ػ)QeZ۹HeKv6ug()['n!ݍjn!=%b+8C! -FsZ^z -hkwqcź]be*V -_) ꒅkHTqߊ8Z=vܱ2XKb+,b1\Zy`Z^f1v-<v+2b;ets-aX`;)v(4diJ L6D;laaz(X—I -<G"fqOluސ|5X@z<'gz'[ CG s 9bꛭ*(@(2UwD=1s)lQJ\%VҐ@n=c4~w'x*viܼ&7ǣ5S," +w6BzynicF-ࡱZ]&{x,<4x!LB/o $v -/ҁb%2Y|V˞5@V2IfPU "䣃ˡOv-Ttj&bv-$]$Wucuz~#;5PCs@"<['8=!>>2>*K^dƭ>קѸǫ|B²1~h|*rc.i/EI.Lυϛ\Ӕ9z=- y싴c}<'qhGkRfoTȆ\]ѹj~ HiLZAv˚o5zݣo0S-9F݆di!oɍG}&'n.S22aT(]egr٩a5d:-iѫ[C3sгW4#[lV<ݨ|!Pfɛ&F̕hF͕hD3VjC6ǽ&CX#yk+>hNX4= i$"CrwZhwګ;14z2j1y ӡzb=ѝ Π`V'tauNL);]֬y[(=<nM֋yKwm ޖaX@,>ސ[>UH\`@!TвybS1BzzA -?ʹK,gh4͵ ;L39 -B3YhJ&^NxYMvzYXTh4)~Az9[%Ȅ#ߑӾwr{drqc!'Εz@P < nTCh7gf6A"zifbK<b;:؎@-$a7SfvnfӖLHKە{*h}ƭdu1sfY=½V2 .3y?)Й2̸xl!4d XCpU�a%*{-~f.iqwٓB.RGTr|V@Us{o]7 &DAfw9lq @aÎ�M7ǠiZ6 -\PfhdY5K@(-?dveЈ,?h] SIJ/5GQ6n7v߂d^9݌e-?1vP'Ned1v݀v!6@.ifnf>vq1vv~9rD\g;F9lKV7n&^ob)a w϶'yB(]X8V-'OO=#/KT6 O(#p-„bAB4ήx3e{8ڳ GmmqF9@fAܹNaq6A'rfFxq}YG,kֿ`#(#. qtW6cx7e_8qԬxtHqx6okNr=bf1rPOډk LJ6)IyO4C4v2Bn\M_26ƁNXv8 jO0p {?(A#OL -'S2}14%(8c%64In9R,R=IlLČ|lrȗ;)*/;̧ϿoZ4K9-OY_˷`+]Ͽo^8}9-߂tqr>Z>@3r>ZG||HͥϿϘ7x[߳n|hJawww}ߧpbV_Uc(9bUOX4u�|S*aH5o[p+=>y@ r[J"# tMOB\S[.>!c'ߛH,ೆ=tBF^%C#L}":ÀҋC=y&K$p '4 i -p旌6i㽩; t!72kcܬKz¥o9*{Ɔ9Kp[F欛Q_~D67ƽֈWkd;0j- UhMTS{5Bp X9{wcp=tkNϟ{'QOQɱ2~j1}+Aҙl.3-bgBLA4Csċ/G.zڤ/mw9̍Ѵ �`=I/Hsw_|,6?x<MWpp9e۳<- wKVU}j톎LCv!@0Eu>M_y3hHr0ǡ[nazfƂO %Z@YU\TZspX#.iZ|m*h@V&+(z'3b>,XO G7N77ϔ=zs4K&irfq�Gs*BD 6p3e$|=\s-NћѼ M:m<DB{ mdH/X*t`-z;dl׌ 3 .dּՙhd26~/(A09KfLǶ�&/N .@LlVB;nbʼ1oM/Λwe^P*H*t;m8oޕy%N]簡e(ɪ'O[e0}ԳNd.yCec/ |+5}<>y.uksKuks9y(HL SV.A%g10GT:I<b6:Y�PQu]RQwܑy.?>7MZ3*|!KD%P7JyǛ:,q k7rN8W4C]pYÀfJM8_潁q`O@{cTiv`f;"٧9ɒdŀVso-T,L.؊dEحP}s*W\doU${kӆ>"'?~е-"8 r5* -_Buy(Ϲ(o!i׳٦Xz܊f=%ͱ(O?XSȦ,Xfˏ~NEZm>G™DSѹ8eO4= ?t3Q)$ ޵!}  :*=W6oUߣktrMdhH(;}tQEx=y,\TX|i㛭MQWI1TFp/^\+K&B,oSX%tW݃z~ͳ'Vty kQว0W`uݡ۹Xʡ۹cu^6,E"x%8.-_ub{b?Z| -hХ-Ƥ֓5Oz;Nw؏]?'6J3htô{t{ bK<]eHoKۢB.L{^k%8ՄwftyO8rO(eOzn + ȳA7mx:e.~wٲrYs a O&pz]`*v5ն'9V-2. -QU)Sa[zMPao|p>6}nN̵EQSX&> yVca[U„(sY -ywq.s[7>]ܹW̭/]3UynN_8N< Ga[U߂A3:oTʲY<>> -f $}DKa[UD ,sf/sI\g,s̥m=X7`ӹoce>U}4}| CMU${u+=h4Y%{9}Y/p (39f/-~fA -?#$Š1=IlmH?>y)+&*]NA - -)=# VXeќ.* -J̼}OSϙل\7rDgόr3b|.[z7IP)\7y?o Qtaa3h yƃ޻B7{ka3}0AMXxҦIuӸn 0Aar}'IRCq/^IjΒ&umI|H[l*{S_tjju j_"Nqs昤 e#PB -b@sWb!Ts1;ͦ:CV/wyoЦ>sO"Tl̓U*7VgӷbiT XX1\cJQƎusz7}t@8�og}di(Apf,^s942x?)PҴEMӦ/>ӽS꿉S羬<M(dT'o{ e\i {|;* -qQN_ﭛcɪ}o'=3s%&~ftfz`@W&GU߻R9,||U#6q==z3i!U&F-knTrȆM{OW%T|;D!U&nx:{z(;ߌ�q<5{֨}ˆuZnzp5u\.2L3*>&8SA?U @i+fGk-@p0)y] }'g='Y(DuAh؄ eэ- *JtQnT,va'g,D;wf,^oN)ªlyڲܷ|bO<@7^{]Z[6^#⃵M{c-!VKeK_ɫFΧ2ܷްhouzNycvu!޽_e;M'W#򙺩ya.#2@$hki|I᪃h&0~, 4B;_ƫN4HebY8ѨRFI ou~fg݋ծcG \pji@g#yE{̍<Pέ+[p\LX%qާ3r;u"}xj-Šq%n`-@6'wۅ S2pބ/�i/O?oίpfo4~ӻb;|8K,I6Ne3MDGz:}bCP\"`P -6ęO,[ j�gXxw$F\s=HhO4\QퟩN]y&;{{0=HhO/ Ug{h$ Kb39CAi3@/N閶wD KS8xkh/z -}& "}k@2-h2yg$L<Li&yj*ffT%aF{%asҒıNx#6K}ЖzB0UIb('>%a=%a]—$G\ -(I [I*I [I=:ﺬp9^V"0 -, -]t︬pRV]VhLX')V蓛]ȼ]zp|j;Zn;tᡥ)/<U{m o;=׸p�.T+T�8S/< [9ㅇi1p).<ցns<fp9DZo;tKC-C9\~/<0x?녇aapml/<VS} Wq;m O95,e |SB\x*z 㾷.LzOtU7j ǠftM}oZ}/<ߏ13_x`;zۡ#C}C ~᡿kICtLC.%{es 'S_xhb6S]xe™g-% =\acICZLy\xá̻vhjP:m {UυȸI)=ݖ /< [^f  =AsCȌgi 3":8Cǖ0˅6v8EtC(Q\xp*VB_x8SF˅S/<D3󅇣:f?4ng߻m mpX߅3/<ѮX_̩Å0{C"]Ez G'+)-I/<йcއ(uxZaTyݻ\^DzZy _D8 RDSJ Xz[�2)˺6n!nB+;A6w*}ɫW*{|8&!J r2V'(Q<DI("(压DyspEpGNnI&*{9 nz-"nG^@<Zx=L􈷍me]Qk}fU^E!eե~O‹nZ:Bq1qMXy.Tib^*~zTOīmb;Y�1�/Uϩv\5x]dۉ̈^Xh^"0U4v9X[u^'vRD Eouxc5J:MKzdR'y 02F;}K͆ncQcRbh y.[EӻrnRhrq+Hj3H\s֊AHP:<f^+ۗxaseP}*?<O#dߖ~Rџ)C9ֆbC.: a=DnIgrf*^;@yn|[LDj L4b JFKf|9z�+ɮ<xN+rf]u.[#YQKluo')}H t]^$Wk -A�e ƀqVÄbz-vM>49  ޫ:חaD3-ys<oI/|-:oXbhcήe@^]#xNխ|;g-bTqE]{$U顐Y\;ɋ5م߮DMd7 _п�A7zYj�= ^uJH�lL&.wF")R�)S4r({o]d>F뽩Z|iDU16JBD2п7s;rqZ7[؇A\Q{wL�M~NbaAW+[$M&ʙ-olV Jt+CRGcOW3mk@ %ydBP橴e(g9%Ɏc@hSڽX-~K?㙫p&e.qӰdKײ41>n ~6U;M9((nͷhV FɚQnRD/j[bNU/EĭEּk P^R.+(.ioE,U&n .m -~x]'~\W:2X5׽с6su΀GGu8-ڲxa7[o.D\vls߷>&J~m6nG(+&Jy2E'+8_j¯M`1S;13mh)cqBn0D/wGK&#?DR�vV҉?3KN!VZױ1V>\} +ksII}|R'x'& }$'3C͚z+K˙ё -^^ s+ˣxgLNyp"pKЗΊpmCtmCag*T_[/R#SfG,04 υ:%,r"Tg.MуUVOg=P>Rݤ+/n{f<6ri@ܟ-8`z!98cig<b/Slpk t|H~,=d_ܢ qvQ)#.6LKǂvUa5/.@`kҎ-Hkٝ'2f7q=Lf׎#w+ i|.Tű x!canF ) Cמ'6ô61 .@r8wO=LסEl5zH Z o0 `_f7i-: *u\F@24VK -ٱõTi|DM ~73gHC+sbŁKAfjO{6_A-n9` 8kp[<Fs3$uSφ:l6@5+QP\LN -1C IzpR֖:30 Y -nC9L_7|gSMjkG4h:>jD%+>+8L sofZ+S3`m:Alcj NMʔɯ7g85qs~ߒl3T猅㯑]ɭb<4[xPၲ:9V7fgqhd Vk\2|sg=}|UxD8cibNxԊ]Ngx;> B<mC7Yg8|I~xs1MJܟ6+tGV& -? _a@0fK|(6K2aaCNvMM?Š>G|oBkݭYׂצQUOp[d47sʟe$Λ%|b{UE9^d۫rtɖnjEȋ cT껼=B<Wldʅl<5r2=?Fk  d 0>*ٜ n+Qi<Cv�*p":z]cs~bի9ٝG#25�i�1/Gv_\?m2z6gF*e{q3y'' -ڮmh�]mV1+7=?_*}qU|k{sw(Mḵϧ𭞇b.؃&pX9&;ZZJPb }K.T`HiqI<|]gy4}ߖݗh*̤j74ћSvX{T/,xo+|-T(\}G_$4C"̮tsq;Fn5g3_'C{G 啋fyjT"qzw7) d/z=:ԫuX9\ߵ_?LL׋?˚*:@\^:=9Z\?O^:g0^t; fW'G ,r!B`hMo<T.Z}3sӸA5Pm?]Z|TkG'Omw6=&S>'U/~NX?F/w0zyw Xo֎ӏ?xl[s9u8|3o=̓QZKZUK3U-[ϫ=ϑl?SS1xߟs%4navs�?XA%@KlS -'wwa ? }Z 3ӯS:׿=Clo/U/TK N0@ܾ\/0T4C5(lnRIxҞ;?XyȞa<zO{W&RauKUaҞsrsX4_7_׶WxqB:2n9zP||Wn 31;{iG:g=//@eBl6$_i^OLv8tCƐG930|-ckό.g dOT_]׫ɬz鿇e}0RkU列nTf ]>盽Tzչ_ٟg -R=*l^!Y6(&KM'>p,ϼCZf"'ީHW<\yJ"ˈ'7?KoSc&ןç)?}<AF(Y u?WMqh6}KcR-Ƒo1S>Y[WGrfӨ>؂Apy|vvw2>M@PtXNX}cVkWɴSLTΪ0]zae{֡V  a<{ Fu -ש3MLZqPہ Z[\_|~֐NQ9|7=w:ay]K{<ɞikd9셝Y_PR-xf1 --/HlbLp?(➐/k?7<C 3>XA!$y[l'I~xuv<h*On&7'i-w5 y~E+i!Ur<l++{ -zA]=>򽼱sy0%UXttalY֠ŗ~˿~f_NɝW :{p26?*؋g^Q=Ƙ9MH:}0_iƖ֑^aCw%WXxKNXׁ|iμ~ګ^rzyK{Ki'i=6(ބ!c8MչCpn 9\M=TJc&_Nȅ/gIJ*ӵNoUɬpC>q*W5.?[qtx jE/7(FZ{2X ]gYYyޗ':25r'{{<N݃[5RlkyR{0w}[$x{0ܠiG$8ǟiCEzi!Tqw%xa4vرH!TvNP,Du?s xT _ҟ8*ʜ_9G1ƒtcTnn9 Oh q'U_'9U^#Ii]�y5F#=#[wF)D.=SQ|VE|w0F1ZjW| -/{"kd@_+X>~IOO_b'\#/ U>(fx#lfmxX^hz72\�I4< I?-VLKA ? \UiWvɭի*-Pvoiy�d'ZZ&XAaN.UF5,v YBt>h金~vK->Y(iZVDF42`{}*śZoL;冽ܨ],0O^$6*Vm2ڞj^4Jٖ) N|:)@\DN ڈ˭o,J2iqN x) -pgiSdYlTlيT.㏸ wi -Wx~џȋ6'ڜ͎ʉ܂sZe8nup:=e:=|cnv _'  ;XkC^h CmZ -0H0o~!<~7/")[rV\1 /櫋8JFKIFQk`t9[-D&58d'k}mJ w oe5L/rVA9 bƙ21kL?lpddV퇦G0idGD<AC]ܕmd1o+pCIBlȠ5Z`;F+@]&p.^Cl1|qϿ9;)؈ܖGX} 3k2۳ we]~2(NEx#v8ͦLP8UwgȉSh&IŒL2:=3YaulnoLX y$NvV`co[E/<<G0ZW`o 'wm$ C:7V86;?4ysJ1nR--8̸q>|:S~2矧(}r;v`Zib?ۏQ&)I6>̤Ap'tY&ȔGgyBs1spCsey/d'fZ 6gqDۿZ|Ɵ9in0J|A5ai2kr hbˁQ2&4+WiuYr"K2VolqF:Pd_C4l<VSA'Vqû툈ELxt\Z|`L'$b/wdޘ?Tb"Q0\54kjvP̹^D,p7e^;~+.MOJ1|MZA?iO.f.^%4){ϒq8L9ILi!S,轫AZg<Fh!Y6@Y�) ',_<ޭL ---FN*<ʏٕ<&&:]n4? "#<#íkܱ< >U\^|T9= 'f1<]ב%1Csao-3^bXJmN=KtÞԴ$Ol??>ЮL1 ]ds+?#qsNx&GH~l<91ιnAXNǣt+rcz_ GvCJ'F77bHEUeɇ߻"OlϺӊ nkǰh 3cTSg1X+1_hbJ܄Q'GZGLC3ewv(< SX"#1t36Nhc38YOTYpl,+E,_HT -**1�;7bL Z6#P_pE=⻉!flc&<43y-hGg ަ&Kݗru5dpjBn>eH8a9_�VoA&slx+2B{ I tr_n!%|EF2oa>=mf|3.1m_jGVv[ű4_6m4m 'J|R֙x}Jn-m]&"k!JK_:zF^ߵ$5ؐ?6\ joe'y p`# S1"A1pTzKB1Q]I~ )0x)b]8ژgR3prW'R -4Xԕc<)r2o#.&ܞ�MkfUp{m 6Wise ګ_d-od̟#hD:d-k&J֒1Y˕#J֒|NS2rb%CW6>ˮFZ2&ZZHrٔF?+E ]ˁy.]61Whm:cG=~/zTpi682Wdd,L';n19rp}2C懻>:S'GɂV[|KJt#!]Gr H78 -fŁidv|[hhҟ CGx#Չӹ\ -odm -q)\3`>JݩL ^1y &$;OL?sqc3H+c/F23eRlPθlyS g~fض¼36S5be<ߥm1 X8+E]CML'Xqk v\) ~q,C,XD޶SȬ5V?Ӳ]<px -۱UCϏ@TX<??h'WJ<b. NyvĬpY =LPӢxQF04 -P,y$sxtBg?5z8B  )+FJ|l<zA>/?ssב8BN&<1SG.UM\ n12a`q\4tTTΦn8RUô3Lr2} Mbczh 47?0Mql,j-f~B]?o>mx4+WB"Y}!&$E?wxJ֒19S6J֒1>VJ֒p0%hҟ6)e0 -#̑s{dx+%!($Bz,d,v;@&p -'>+CζQ2\R1-Fd3< gIޝv%Cne*IWax3% d dL)YKB+!;d-C}3%kXU2?җb$Ø|hv1}ldžK{boˆ2%VA|7 Y(]~;+$+bft>Z,yk&WPwZx)Fa҄j ] ¤nV_)r|1j҃+Bk[(O.3 E6l~8=Xyī$ N1OqA /WZo"-;W(G&$_'$.'#xQܫf/M c+dWqF~M%}~ڜUYڮ0H)@95:{Zt]LQܽ"bsqwlX F7䁀bRsoZ OpzL.?,q3҆n Ls[ܖ5}hb|j x]uО.: -u=ޝ1^c3x@98 -_M5ΫUZc\گ] kuVꊋaO =\^nDī-B**ӯ@LZZێJS"N};) T0I;L.~+ټLe~ml1lAr6z3< ~<6vFHVÓgxKW;,҃S!դ$td<X -iM# < 䴊 &̕K0ZΗ?YLЧ~֡?:~g�1\n�'˩JgE+S/Ɂ`~ wYs׈:aڠh菈W8ܝ}EJu|B_(*~e`E<M6<cuU�#*WMő[xѶ7/ġ,!埏J$O^ z޳bn`ȏvZJ:uVId9_dgdED5k,P9ptH /\|a,c0;P cqxs5KmWNy@3":H\#d~`Pivu^FTbȠQHYͫ`e /ؑ= '6b&G:WH yLaA0crҁJ±X$3a±K`'0 ל s -NHv h#ش:>Fi)+\`RU -Ýe0h</3 9g�hnjA1)0I+Aύa@,O, 3w$]Nړn^˷<$7l}i<1`d)’6ۑ%E-Wp 0N^x ,|WQod-SMwLZ2&MF%bn*i s_@)9nOcTsƊSN$(6G#vX160FHL/Ysm)zMpw:49kbrEbL0eX8}+&?}fBz@ k"Q0{M@Lrrr -<O.?U기DM/NiD'GaYĪ; "Em)³Xk[yR,Λ<[O@{AL;H1;Sga[ #؟9{ pC -&lg}S8|;Wsu ʥY9r|Kx?Pd74M838::%bRbY<Mɜ~x T%POuPa3 v+ Ov0OO}?߆NhJmzXG(۸֧,Wmz|+b |ΟDvnɆ۟0^Bmۑ+|ye -IxG:յ*<*7n"Mq݀'=YtGX8xGh|"Tqmm9Mv)-` 1+BUIٱYkmv4#M:ؚw~x<x:S5UwB;&b.<1To|iZm26WȔ0c 3I -.ns&0iʤIhpko<>B>!MDcőKB/(VBV$k?7MGrtA5\[5q?iX,xኌ>?-X1iQpfg̰v - -!uC2ndWh}WO?�eI4+Gk`7ΧOU־Ə--<N0<.pwt95_}..pi1XR8)90 xquV^^^ -<q -rS>2kEߍ)` -ai!Ш&>u_S&L~]͑y(|:Sc僟GA"7!Wx1OfJ9wƀĄu~ X{cPhq~)=I hFyV>�S(Moduk?y~Rhɉ37@ -3<q -&Oyk+6O -Z̡?W5k 7q|~p\\9#=UA pRq}:k-P\LxFT; qՇ m='$їo \ϗ$~GB͔qCj MÛЍ&{ `D+6'7ݛ9*X ]bbH9ý -#EW75`e3=M38wZnU6Zc07VًyN�|&8S$O9}<3yb-1t7?�eM$u\, 3;jrԅEUXmoU־F -$pw kϞ/Mi1k^6ͳO==7Yf_5X,lZ7G4k0@Rf bw0kIq:5XIH mgڨw0kޫ>k!pm\fp2x`xڋ .Kx@FŨ NCl^I{6t2x`}2k XР_eZ k_ �+ XSBGψ Lyr~=sEnXGRmMtlL\h<թϱ \2>GϦe|\x#7xrds+F:N["C] GY+ßHBT5 -3`Rey2zpUsr1ٴebJs^C.掅rCGH@=4RwlewQ0dYq-q@W@%J0<6X[0?&ڊB*YVJvq -֪D\;0/<ql6{YŜ܉0,@8XNg &isּNo^kn^`&)qph%S̭գ<b&F vп^о_J&'B~MB+pȎHC?x4VJ5E - :,k)= -J x6#u8ƾ^m^܋:ӜG'fgQ Yi<1 =Iv巟6kщ%x_lVݪz>K:A<&a!)~Zq^9<}Vt?)9v,H+ z_pC\:xƘd5ōcϟ,Tں!98 ea{͂{ %C{kf*﷔4tyn53KxeANژT�i ̘ ]2%WXoB1'ixP8njW;@ܬNҮiqma-Xa "  ? 2"Y杓VxXv|z&okVˇFZ؄LAkD{3bF3~ cn$Th񅋞Z3ܼ5KߔV >+ finr$Nk�RI^X/#"7꺁c Sxmq]bNm|^hHR+?6Z�yڀy풛FAZgQފN/p)2LY,hd7̥j2G ,+:pe5'~: -&ܳ;AM�7<>ċYĈ B)׫:.L?c9mPS&B?~lȇB�]F#@|c\5~W?oLLogXG ^~ "$OC�ʰ7"pHDEvBpe%vzJǘ69O=E&*8j >RcL nzinq0v_?^1orI1:|mTO#r֞H_ss |M?˅i `Z.L\1l`_<3uE[�\\gw+w}O<OMl>ToNή>}(T]zvrsz!/vО%9"LX=~5>OUύoS}ެ1_( ~`ןq GǾ痶c -?'jAHԎ}3Q88[8`E\ p90ObfZc59m'G -<eD+zD:_CA6?\>nT>5F=vupٜ9߸m.-r>\.7LzיH>?nf�gǷku x--D?]ע0\Vq s/W>Pƾ 6Z)_Ll8h= -> = >(?)~Ps[>#G9|C }pa!!zPgT—Tïkዃ#wM*ɀ3&GҍؔrR$hR N5"ɯp'<٢G -&Fٴg/Fʫ'MΎmv:O6. /֜O=/Uc8Cj~>نz;ONdd<Vaaw�z8Ý[xbO@mFoo{|-;c?N;,A׀ Ď̂rAO -N)' |*Co[rO4ltap PZJu뵥?,\as LLFxLxii^O.5`OTG={;90SZ>Y;lggO5.S�Գ"߳E/tx1^a1^@Qv(Sě:rOh /,2HX۷k?mE<h_'*TZR0|\c5v sdh6WHx’tZyv_d0vR=GB;gbҥfPK)۷hлy,5Z8:w6~I|6{s9b')x?FfFcF)䆧w!=0gTr#R?ROVC)a5xvsB1ߡ˘sx|J<skC ?C =s0K瀷'/>99 KAf]౟?>?y;1L>=[ Bcx�?x?S j$45y6�r/ ?M %x"0\_49WUioBԊlߴ؟k4N.c@<)F^)6DGM(\Dz)rl7qwhZW -b>kDв'M؟Fv؟@qNC?4aشqɖV/&hi/z6sEu+Q4UE[+tyU pK^txoHP7^U$I--kkonD 4̇D M??ݴnbtTuPL}qK27M4x -. iTϿ |'dq}ĬNlW@Ҟ%5=~g"5R^ !ְلVή% o*n>Cs2,S/ +[gTQ~ů{g"[05ׇ@ ~? aT -!n}�#=$-7?&&QR Lag9R-"_8 6mdX+x]AnAГ -U^dgҗ_ث6=vzhm2ǽbQإH\Pm`6岳w:oۚ<l52\+S 6&qX*8k�ˊ=7XQȟV,ܙK:z)bq]^0R=?|f&L[9<;@,V"% W=~nrs|ג?Uv_ʑہb+zǓqaOuOdn%BF8%O>'ONk`W- IRjGrS_1,v#%Z-ɖ`N'USvV(y#6k?2Q񋑥!rzrt4z( -"}]k[[aDry ymfF[CjAHC\dXNjRxn.ޒlHe8ŕ8=zP> OŸ?ß=<r`yggZ`៚sgkBw˓˛룻0ܜ~c0ܔq�AO+|QYZ1<`mq-JMyԳzrE(3lq |dzMף6Plq1,ץ̢Ic>OD<য়>Nh7 $a?Wh(:6|ΈUSik1OXJf(q<a$U>4{sﳱ_sy&9}yPڼ/w/]m-L䗍#E!v~l=ڿ6"<0ˡH\ŏqܢG]Iߩ@;9f/m?*x>O5o/}(_?L/.~=]?$uz#,x25?%uy×mi}q[=;o -}qt}n,E aeH5A\)AmVܪ@{lەV3)煖Eä rZǕiJ}m~y5>N ӣ\@EgsMJ4 \Cכաݦikh;&cW (&tY|0G˅"^ss˫62׶ïyy ϲyv}&PʳyФIZW3�x5;_y8jƃ\.g5ΖO�@;1qk{WJZu[Gx'߉7n+6D5oWP{_s]ސ cNLL RxlVӻ\hG=v{|N03@Rô1cVJJzQ]۞[N-PZ= ؞ڍ˨:GupQ=;*TzRFzúؖTۆ԰-@4KpLbYax٬4w R%mS}X\N.:jVw% �ÃV* -JzX]kڞZꩨ<IP*_TviN|: :uF̨1Q]oFz:q єg2IVҶ*A=f\+/q1ThQ;w% Fa&^p6,3VX٬4wԵj9դJpÁoA|ڃ[q]P\>o[&^vX^#|Pr{ c>6hP]P/pPSs:cSX5V -Hsz8DnzѮv:7NNc :]`486 LXRw,6лH2j2}ՄF\mӴ,hg:%, x|üqY -<zV<#}<O5.䠣gL4ire2h54/N0`$>3MI ;NMD7\ \S9UO63-*X);^\&#csZg{Og5qeimVlQ6ԭy - 5"umA{O$ 1Qy^ O[4.CsP/\@sMTrH2i8;sh�F4j8O!a-{'d_cXP8-Ǎ/..¹Y=S' &6\`bˋSצz{_stսg8(</o]Jo<qtxx.wRLSEN - -7 q#yNJdkxQCd0i^op-  %/%^<n"Xq4wϵj=xDn*gU%u;=ݧs qMU5-8*:K]KZ40t.3m۶%lԦ :eHݱ2i6ۆ6ex>]=3&M=2u? Jo&7Rw{YO[h "NŵUy*t8\fv r3N.3\g'٨<-&]y9G\ײDDaT)EdkDN &nAG;iԳIRPgU~7LFC( q#U~Xq4wεj=pTj(Q/ftѯY7W\5}Zv8A2 \_ icޅaRw??xEE`;_ul(J+phـi3f -X٬% =8pmg3njQ{] O^�Wb I;1`Rj9Hڊ[5V09i-0^h_PZ=V3zYjĢ-vxmh*<*t/T)4I(]:&<bV<Nqo~T1&` 6QX5V*�HCz =/uԮc]7e&8v˙m$ir%Ǭ�+1.rz+jNOt9OPjQK.%%89�y-<;*NqL1=ŗטØ.wV~ȂtqCMSQzJhF_">G{=5;D&zjD)uOA1#zf{QZ-Zj{@j5d1ϋ.{tLױbwPG <Ù~sx3ͧm.s:m RcJCz rv*OR=:;JsfԔ.S\b q+ylVӻbOXbb9=ezvPUN-JL8ڸHrE8˄OI=㸣\7gAOs5.S*Rs0lT= Y=nx4w=Oqj9&v}:tRsl&-x(=f XyYl4we6 -Zf5{sMS!ݳC}X/犤q6V}5 GqxLz wH4%33pA'2MjPe2l56/2M09N{nƞ` s-ײFMe2p=8utVy.ֶmS|ذv.ֈ|q|q<9 -<K'Ӽx罋!# -<wqJEm tF -HyD Q-N=67<'f^)fQf=q Ǎ/..yDqZg{@g5ΝLm{?�;砧,q<8 -:˛ӹDx鼇\np ~s"RPߤ31uGbk`QC| ԅXz:G=/;.v\Nwgq#rNJd{\YNl4.'rG9zڜ}.ᲟG٥˩Sw=2L۶-kD&"6 7|ce2\=. atLN;=0;0 }mHXNT.ȽiSǍT+..ypZg{@g5LΈc1=pzA8:e'</f^yyX[ɲ p?YeMYbGª( n6~,[dLU?=CzlKمvgQ3LNU(#)F;cT^J c k(ޣ*̚J3ׅu4vdbhTPVϢkհDvH 䒂*VoG3'ɛ,?ٗ'IZ^WLν$}{z<Qu Şr;Wx*) 準Q*H.QN7R&fHϨw_4C 6nA{{|o."ϕÛVN'bfI31U^Xaz�]kՄFpA>-(w[ɢb5S;Aj u]yuEte(lh6Ea BN\qnrh7(*+P/&8&ܻJU?9`Ż"1M+h3G81DҮvj)s!#;Z&0ػmŭ*+}qN|M3%k;:VPZ Ģ-vHHsoVvӟ6\1 zr[}^ײ=\KqdUI7wkN#NB0QM(*+%G d!8n(kױ\7e&8vˉm즞M(=jh٬4wV'sbb9=L9E |t9.'SڿsNy:`8cmLO50d)]B@ѡNcVJ�F3z=X"F5vk|w{uMԈ.s!D螒УFJ􎕗Jz=Zjj@Ot!6c: -]l.;YX}zs(S -ϣtqo<ɏxx.O LfD p %�zJ=Zb6+ ]tK !zv{u|wFPCRS< -ZxcV)h٬4wV'ybb9qtbപ©ij^ ui-wNI6.;1ysVWDw^z:"|QP8"Z%~fcf2ҤER<Ʃ嘠ycFI9${̱�17GT-/fn2z4jFOctSնi7{vO;<\6ƪO&xypx'Ϥ{ADSr,Àt*L `Hݱ2i6C&bqi񽝒n̓љ_m:_\Fܑ2h("GUg< M-N ȩrk}*Yl �Y2SymPGO{ʉ!@9i+ql(-Bl3iu{H۱2i(";+1sip%b.e3rcRrHEݱ2i8&k:s:<u`mua IAkDr8]uO'ˌqQyr.mlpp.wPLR9'(oҎ#ee\=.!IԃWE.v]Lz[$r80D*.bFJގHCy\ٞYiLNrN/1uv"HJ#9N4gEܨ< -7]qEx=21K}MmM8Q-fhq4wmC|tLN;=0rb4àj. N3R"wLF˻:Si` -2 ;#ŨaNd>21d2õ �.; G16{Ω<5 '>h:[LFλEzεN2xrF)[V94̣6ʌn2i0"k{< ̩<Qv*v*B%xAk u]S<8oQ2-{ ൉~(tpw\u\Fl(*+CGMi-1u|  N&f'eN=[b*"opL^J-Yl Hۊ[5UV'.R7f2R KJWkՌz~(`q E8{Cڣ(+6QΡrHB^"iY-t<<J11i|'޸7t?*dX w2Nq!qQ+%Jf98bB4t"=8ݟN�u9M-ϤM@=jfh٬4wյj9ըrܡԢ .g=n_Fup9`tZ8p%@QF = ro,8Sú\+y c%fҰ=XwKCK`M.8Tr8M7cVJ -JzY]kڞZꩨ.w;vTźgTLױסb־G(%0Q#RM=L2?!l'eBTxcNǬ ۣ%fҤER7/E}ݡ4ԩQ]X>eףǭYiT&kbsbY=evPLÁo%.1-ɩn"eBU˧zpG> -2ݟVOa4.S*r섭x?F3-%ǬT+0&.z% _Σv5bɺ<7a#P|cf 3q+ -d1V+m)#9km&JJPP\Kovs =9*H!Lw .{ADCr,�R:\o0-ӤzxFޱ2i: 1ɴϨ}6o(slTO 1#vNJdټluVlf467= :mۊU †�Ԉ ru</GG1zBEy91D(>2-%;ۤEm -fFEݱ2i4";H5xTګ]pk̰=u~w:'gniVJPڨ;VX&#v j,O27rp][Lg 3ԭ͞rtҽg(ި<F.ݞ/O50=.uS)6 vB/f$hq4w=j&4!2j.;rWSXNMxbe2`E0*UTVyKq/='sq*ucѣ(tF = 2!4۶-uZ8"'h.Q);Z\&# ]sLY.{[NduF@ CqYJSyHI2i4&k:s:<eNvFQGU]w:v9Gse\p< -9J8K<elp޻pNy~i0F y~Л#u:[LFλv- Z4EF4j8O'O.g2i%SHrBM[=Q&wHy\VSYihN2 -PtyF,hZcplFhEut潋!p'` d4-:ˎˈUSeLf9ēVYJ]v>O: x'r fx6]G:vu|oi ૈn#f係S꺶Z&rj#~vv*R`&#Uy҆!=)qճZg{@g5F,!� ̲-up @#ڎBڠ 'Q9 < hK C<*: -9G!&f1=͏טF nF2,䀉i3ӣVJ�Jcz71q)ÅiE}a?M rrZI=$pzJYiRkRsRI=DCEH]ι{1LsR7 4((I=1oMOz6hVaV{+?d! .7W8q3R2xlVԻHqn*×v}ݑ4إ4aB]<@B%G�-.AzcմjFOet!6czjD=>ٿ5"O:}sM %k@a@ q{*\f&č6* -#RHq4w-WlXv㻣s?:!b,%qqvH==).yMEZe{@e5L~9qx.Sl'rE8<|b-}< -9~<Oq5.S*RԆ[P8daJ󨑊ce2xM<GXL}v{q|ox@ Űqݑ  4i7zJޱ3i@k:s:=sNW[يJxզv2{HgĴH;OG!G1~<O\4.Ôx)Lhy -HEޱ2i<"_bڦjQ &"癌TqW4l<E1#uNJdѼkhXHklhF447=wZPa}^`s& <+G1xv4]y91D(>'Lql$-\èZ_bF*Hy7DJ @׶K5Ȝb7e;r=ԫcF*掖Fcy]`uv-= Sg &6pa^XZ#r93cy oTX#2Wv'{ -1‡*0'rf&S5FJHyܣH%aR#DߨƮ�t"3MM%czJ\);Z\&#M]ʦUV9{xs"wSFsu3g?�=8J:K'<x=2 45ωL>Hmh<#eeXM, U -(T^tLΈmhfr?gk@<e2L=&oXjSklhfT&qLOV2LN=d]f04gF(<.ݟ.O5.Sy`kB/M`NlJ<jN)..b91 "ڸe2PZ3j>r*%g2j0urv8ޡgz1#eZhq4w˵j=\T\θ|˩<]W9h!cYz%{v0:[^=W6h2]2/扄}dH&/Zf'pw\v\Fl(J+˕LjDŽYȌf2y%9t?6sD1�vu%h/"rQzPg`<"Le-$m+nTZ9O g2fy,Zb6+E>;zùVPZgrp 3qpܧnN�jwOWIFB&MH];DO?+%D2x߈Ȑa1Ƙ24.H@c%fҠEPw%ÅiY>@ݟN u9M-ϤMH=ffX4wVo?bbY=tCE1V˩wT^[wYu&3@mށY=cbtSy=rwG,8S_8ā;4VJ -Lzh!RELG?v|wo#rcjX['jEf4Ӱ-XZVz*<;MrZ� j#řcQcuż}Y=<*VSFM=L2=!g2Nuбmàp3jZ[WNJhinI I]HBj\O[ 3qp]fY&Tb5 -+yȌf׻Zlj^Ou$^=k[H%g&3zyc(漮8> J 2Q83ezqV*JziV jR;֓cP c sq+KfQkV+m)F39wm9 (<$kt=Wdz4'zusz9w9 -0B=}1)RbF*JSz(=)i߱|vNMϾ.s=5ssZzxHEYiFk:{:=A#yw贶m3 ^lc<etTζ�<T.3AGqE#z":1DP>3Ո86o!i9fBxi٬4wЃ/9c4i֎vlIGbܰx@hkVJX٨;^Z6+ ]vI;j8O@7spצ lx"blC٥)w = rWK]4UʁMnpîm%nԦTКUlV͟@snG o¤VF6vm|osD!g I;'pz{ܨ -/t<wۚVZJ= Љe&C- -ܲ't!H8LMy1Љ7/<01#ӳiËtLUh9.܈>:qL,qdq#%~f!if -|;?wYt]:g,Nh׀I8-nXy٬4wѵj9Ո蘸5\<Fta=Bl\ǰ ZCz@G 1ykHj=mxш޻N?蒕+xStM,ރ7RwlVѻ콢abތ^~]pwm1YghyЗQwlVлZeʶeBx -Mf{ ƞjY(꺰=Jpg*j8̴E9GEq6/{ y"!p'j$y)xBhKVMiS׆i- Xe 0=Xwxh3G즂as!Ȯ;-{z0p O-l I3k*LۖIFf*z'VOkmPOjɽ#6bQu,[ry-yaUbIP'=M9uX2c|6p&faf:{S߉sݢ - dƲ�%YEj*4+1F."8| Dz!{|H`|7 !zE2[135 -hޮIZqe=Eyq{4 څٮ WJm. q1g]{%9k:FS6 c\:qp@$+CzXkeVΙُ2DtGWfcEȈ佐|NIiXH>s�~êW~`̷݇L&kXXh/$GQJcbJߎgf�斔|W#�F.�?ma+fC l&nVSoALdcbJߐ+*o$z$r)~/bֳx5�}hlaxi>tY[*F9q9;S8z♟Znurc4ņ (Z:֘{6礤&65g;!\хP3 IGaư^Ͳ6l+e?cD:i,1pԤP^-'1yl7h =bZ ˻~1rlsNJjה]VהN׮༞]˚mb_߱k mAXZ߀mv/Ʀg� ܄~q%.J X~5 ٶ4#2z7ťFGQL>4:)&57#?O,~XSH5#lE?g/)@K&p.=br褘q?+*~?Wvo)c\"wFop}n_/}e3/p}#OjFۏKޝ-uˀdt/>,ޕX$J>8'o 5w>1bTtjDX0:[ йV]w؝%dV|;D64:-ll׉Vq`<w`˳vsmW_Ц弟OGߑd<6Q~\s6aEH\z�œEz$>7'Lz%<Vaf -sGj<L}0I'} -.J/䪵& -Hdͣ礔!OWU=-[4=T-kS&$ޥ֍mh -6MJ=;gH,}d1ooee@1 -<j6UՖS>qh|+G1 -I{hnJH)R\ ֤f0?/nS /yN)oƞėG){-I)CKHH{4U~OxG#|AR˾6c ^+F˳ӵ/AyD -|_(=?0=:c603tHRX̽9)$ڊ`096ڎX:dJ6RxB@m3iq(uͿtZA[4fy%dޥv+\Oӄ_Je7k}#^R/JLԋ'O-c'4Vj�,ȿM )GKNAQڍj7x6eq G ;蔊'vH:pz�&j[)~-I)IKXX{4U~gceyj, +GR}ޱƂ`?{ѷLG[ RRt<L2o\yE^s>@*L}✔%c -H2XdO%Kc^k+,2 ) N )KKHH{8U~xr&Lӻ>Ooh18[3QKy#Ƽ4SAs.kǥאָUEOT1@+0ɐ+>mJK.64:)՟_H+muϡ/vE{VZoVqwP۝/;f{Փov$lJ\;MImIiig"�zp{�U~@슃˶{D/~o<?ζP Bڳ)gg'B\vwz~\nw'S?aagXaХ�%)-I)gC^YvRPGijD`фbDV{&d10AHbc{sRߐ+*jߌ&`&2]_v6)Tyv$>woh�23kL~ qo^;(3J,|hqNJr+P7. Ԁ<quc)WA:4C3yy✔7d - -[e뷋nYS zectMD~1%kd} 2oOo)%%ɅS 0D(u)1; 3JI4|lqNJ[uf Ҫڏoo?~nd=Y1S`H4T' 3;d}h✔$ - -[%KM)l%޵j_zGK2 l}ɍ|Gb#9�[a}&t$E yabI1oHٳ-5ԊT+�VFZ6s j@%GQL>6:) yq5c"Wy+ 聐Y]hB+]Cq+ހnXK_a1wWGJ]ܽ, 3t$;q,d!<rhAL$cb2\H2qɐԒ<%qwk?Tx[9qZjVnhtRL[Fܠv9k)`l`])5Ln79W�p G#y{~ˮW~9ˏ߽W޽[>o#"A/3f8ǿ7Ĩ/nwO'x/~fW7[_~q|x~tx>|?<|#|PgVkػܓuj*G]>p@ŰY/>^`!e1{-ZbXJaTRH4d :k 6``f?m{�fO-c] -o~W'/Eރg; g·kޣ_W LgRPV~{>Ao]݃[y/;=յྉI>|#'IQF'jO{�v!\nψ~ZG%)ioiWdw<ypoD~xj>Q}vݿ n¥v)dg[\ŬT -Gj5ޗra[79ߋh7I?<yNJ 5U>Qp: \nǠ~Z,wZ4S@zom )ԕ>XBz ٓ}j6Qmf. _yg@|j_kАUa0Fެ՞Fs< I R_-~U%J⟲wz _ɆAW2!oCڤ}Vs }fs1л~V a|BRۧȨ#jO{W ?;=PC \|)ͦ��}VC xSM? @R _Hj`x씐j*QUjd3~ -+݇@fQ>:F~tgg_Mha$h ѐ<uFFm}UQ[n|W;6|@ 2Yx~cw5Q�Z 4;C-><]#1Y'ho;%4 <5T5jc{v[jNJ>_'k(+R"E/}&MԹ?QOWo~܈n|%>]2Ϲś)5g -jH�6e)!J TߨQZyw( Kb2 )qx-{?+WpY eڰؔe mT(kz2{H}SFA*f08~s݉6* N %p)!%JTQw ~ -f~wJ^<\W 3ʏJS19BqܔRoT(u{�-"kπ褘"U5TI@(UabjP}uڌe lT(k{-Df0~gJ^2l*ۣRT.^T*r(4 JT٨Qiw}(hwa6礔2eWďSYH7C! [QOm(_PFUO,,c&.]RsRވ-lJ(+]P ?:+]8N e9uSyS>@206#A *U6J>E)|D203=SZV?:+ex�ɛxWAAB%{ HO)j$SGQ\D5Ԭ&9(sP:G;S "((`ܬ"v!;.(S!Ղ:s󃃹۳R>K0G6rzJkByڌ9(sPeF9̠wIL<M)e3kHQ\Q (mCg˓d{rw5AQ*_ߎ`J T2QJpz[pzmw0`\!Gao(J+J5MM~ow&ukN<VF6I))PRFՍ'΂^ڣ�3(?7 Er.RW?8+kxl_"k\}Dܷ""ښRΠA* ^my9.B;L` -gz9 ɂU)ŏJޒ2Z/f1Y9h+$9) JTQa/P)Rע4"ё\Û651Օf%>' 椔8(qPuFÇ7LAxAj$aghC2CCkq\i҆5+gDZ4}+"鉡)!e TӨQaB2 ~)Yx%P| yBzZ!d B𞝐4 -zz.i:HbhlJH5k.|(]w.HL` -'zClS Gp oY]ڳ 9WtA IK MM )[PF5.0,|G!LD+WtچY�+YP?:+YxKY j[͹lNHrAFdƦ.(]P]FӅ pgU.H0" ,ԭ$kxV?:+a8TfXs)!% JTרQ饛.H0W" ZYA3q% o^ GI*zPd%J -T>QR0QYp,�k[|E;<ZY3j5UY$V&lo[Rr@u%Py(L$Gf~J ^@h%g -˕?uOe0H`%pT(yjλ S/p2WbZY3Crǩ\oX9pAJCsR=QS:Py%^0SSZ⺮)+=+8L]hdr]ГWSm{sRJ>QK;Aj b{ -3@?;%E;rr%GlwR=M}ܔ2enT(s{-߼LP~oJ^6l<k$҆yr4g}tܔ nT(mR;>Tq^Mikцj~oO*+Ǖ6ܳp>={/jtܔ nT(mԚ2o9 &)҆W ϊGq ),bo~7!lRڠAՍ Zy/Hi ->03}SZ^V?:+m8Rg^PS)! JTݨQw.E fP~oJ^6hh Ǖ6y``=EGI-1Zs(+PmDYD h JrRMJ~d&Cukih?Th�?%0Hv)!%J TQb wHKr;L`zȃV$\Á? ^D ;(wPG'W!~(L -f~w^;l?++ʕ<34!O>v %)!%JTQIş! dV0SSZa- [$ԨWʏJQ95EOr"B¶)!JTߨQ)o�UE}v&`~oJ^8<}N+P\@ec,!EQ\Tt%: $芡e T٨Q EoU5}|D603=SJ䳯>-E񣣸RC|v0v<QJVJU16#A)*U6J> t| 1 `Lϔ2e(lcҤJGGq ) 2ex+rދAHPCk32J2Qeᓊ=U}|D203=SJԳZMA ]M*m(_PFUOWw}yKk -1JR9$,iS! l[Q A*% Tyݯ 7 & RW ՝]5ŏJ޼X΃ԣ$/b|޹Ty ->Q}`Rf h%9 ׶n}'?_ 3 -lގ - -ԟ)P -" 9VH6I)5PjG5RgCf@^#3@?;%E³"gTY5= %҂mSBJ:Q <1)v8 N+1M}gH~t$Wpޗbwb%=YL'pAJCsR=Q*<U0/)"kgG‚\ 1j<[[Z. -{r}6M )wPFՍrO)W^;P@)mx-T9;Lq\i!*<'_VQ\mhAHCsSBJ6Quj</|` -ghE[ҊGq L<r칼gE|$]147%AiU7J> |(| 1LLߔ6mۓGq N+=Ў$]147%AiU7J>._qGxALS(?7 D.={}8(J*ٔ*ǾZ&: B"#67%AiU7J>b^3(?7 E}bm 㸞6mgJ}t/)d7ޗ+[!lRڠAՍ S>^3(?7 D,쇢Aq8K?σԣ(dهOV^@%�K:@+ P}nw 1䳭igdeAI@u %LY4-)@F)ZRr@u%S>ȷ0/퐁"9p-l -X~t,;,6Z8"@M՜B^D <(yP -GG,< fp~w^9d[`3PMH~t$ף7<r`" -`]1J!mk&[AQS1zSrB149)&B U;J )g$[Va4b]Vs+Oo6ݹxxx ?;?ktіu1|?GQ褘Ԩ %xT(M$搞DSX/ -J0.6=-(7TSN$=GQ-a<؞3)ѕJecO&| HS)@WtGΣxahoNJCQïB@<&@^۹0SSZL qnA1zZP-Ƀt)jl@](hG!AYM )sPFՍ2eS㯦^ Mi+цKs-e!q҆ Sߑ?Ԋ5�JYKΔ{)Ʀ4(iPeFIÇ)t濏0~gJ^2RZ̑ Gq- 5ެI' Va.T F!)uloNJi+ݰwg�hp7^%_m!6|uagzz?CH5 CRe!J-v u(S\q2"%ZR nTy3| R;|` -gxCO$RR ?:}@j%)cp@{юi(SY: -`ܔ mT(m`0?j -%>0}SjSOQǏ߫ύ5ٺ!vX' -HWӘ;-ebbЍ+9PrJE;)vQnqQp>E9p)Ϡ -ן\+x -֝<!W6ʊĆzs2ďR[RAuqaaU d:0SSZ ZGуۣ27͐TN9ZZIg I5)\&AJCSBJ>Q#$M <7 Kr2+)wx-Pr }jm`BB\Ûe'aX4F+PP.hv~rpT(w z 3/ɤ` -gzոϭ/zYP-o/�2>XB ;73M,Usa+N)PGr0zQpBQkql DM\[ -Gtozڛr -Ɩ�IE&G.Q]RƗy|yhtRLr U<xK|m)A?)rWQs>Z,6אBBQ %_|߽W޽[>o#E0<D~o?ޣkE]<?>g?qϬ -b?~,k}`?>kg7-AP'�SOm`C햅+ k6kmnȞbda,W,tN806Qo~?b͟㕔TR7߽U'.Fן~w{*`6ȲO޻)_s2&}� Y~b:֙Yߡoץ.?Wҗ<5b;3=ׂHXs [N`2!cP1w6/{r2ᔡbLLs0iMw\LuT`5gRǵRhucd{k`o'_)EuZ9`e+_P= ɕrkE]d^~Z/Sqcc[;SV&w365m >7y(Kl=ERM05nUyR}3mN7o([;)0ʋkݩ7̋MS^l3\;oןt÷7 x㟽Z>?p~. >F <@A_~d}.'`]{t`#T "bcrr;OZĒkacQkRH1T/'li B1g{zjNb[1; "<fmWǣ ;xkǭKڈ"o/^YL>tЍmple$ ݌Ex鑼:xj~6{ t_~"A@d[}x#"Ke-׬VxgJ6t͹1Aa3ϐ )3њ%//x^s.8 -J1TGs:9KY#cdgQ_~􎉳3+pBVJO1M :tz\8 y^2jjs_/b޴7�׿i>sDmݼ؃AdC{O \''9yX?|V]ORFY^o"r*b-=$P}AImio|2`9/͇'{_᜵'WhA7]v`ևg5ǢGy3n qFͽ.h&w+fWm4ȭ,LiS:ֈm?3׭4*;(YQ $ "ûFj.Pnв1,twDzk0'eyk}Bˆ^Ua^b{%bMMK{5( +P)2JlO)%AzEeۉml�[_/!C6CG`ّ%�` v&Co^gXE\;zTS]ٌv1 ]hjH9%ubM#@ lH'wW(fCʞBN֖4ž}<1 -rzwuPB(kmDfSx$IzM>7ZZ �hj;oe@53j8<è8f놖"/El�\�Xh}Zǜ-إJ1hXS!X<!S8"8al+,#O}J6�Ŵ♡|@s^ -BZ_0vx"%Q)aC<%3C�" 53T'r?Sȹb\*iн!z\2x,Hظ: @e|eK cԶ BnI伌%-ul=`i$_}F`B -˫l`0ב:-ʒe GaAL˫P䜀Os=A`>!%Ĝj 㸦`;Ęfַ3uy-3bkP{4mcvE${:X^QhŠO `,f؃0}hEh&k =(Ä6vGKe&TB}(]9$T,Sk3 ÷JE�{vvzA;'Q}0\OF5 }qxR&‚Z*(.U"xyGZ"Դɣ Fٶ\=Ŕ~bp q RK=pH>mS4t?h :F5X/Cm8־i�FJ2؟G7Zk l 2rRdn:P?cI?h#5"\⇄߆mab.#4 ^R0�-Pa9`զQ�;F_P9T8u, -Ww0 wRZx -NnuryRbgs Sp4;8EńG<B<ɚ0az3`kFx,ji˳EFf O<oeem60_^bc/aX8J&:qedMwX#|4D0;1"^Ǚq|m -]00`Ԕ`mcIBO2Dty;C9F[44`zR .`<\t{p2jݯuglFhJR&TbN�3!Cc/0Ż᥉*@V͋6;$ qOnOaܕXd, *5E +ªDϱHg12ք.2`Xc<YҘ5&db4@x{uSMK "`y a#|_6ó>C@KR+-`cbf9'F! x`a\X,2\5|PO b˪0J8+.`]ڼHt@ր[J*AcXE`14c H'saqeAбq(GSc}dA$q~Y[)@x.3K$6ÚYa@ֶ\1-;xm:"Ue@JLVpc5U d4Z\=�KC 2L^`o,V{{i $x 6Q 2}p\@jqR,!(b3(8\0F6m`Qc<L, -aHO nE*yh|^ #qF}I G!Bkyy - &/g/]}9>`n$�b†qtMusyA`[qiS]X( ǫV4>k6дW15qY<06c!B%omv JHZVaqS'fZ1] z8@DsA³ǜhcsi.rweh-ؾ x(,^<j ElZ* wlqev?}ڤX2bjc` 6]ZfN͊w, -8A ' #[   a1³XICmEkHC h^,6ln5#4td0W0 v XsҠynP -+&64XAИi*-PҔǖ"ʮ؉w �0�aLn Y5I\R"K "vtP}F,ތnX*]p&1#d.I�)hb5t#o@ܢo#,c~r:DU62eWZT4ʢh=ccN<Z1EļG}�:<L쟾.#~[tG(�[`P̞QAұ/1,Iqf>gB?EC)BUͽj,Zö܈iH;BF~Pf1<,7K|<Ùۂn?S|X3Te99/;UJv< Q"׳ԵT&u C.Jt?Exv_%R t }KfUz8Co.¯ Ё !b I]5L7p$M1L0d ڜ@m^5@cA``'4MugzC AxHo -K^,>;B` -:7Z8>|g'^Xrtl`aHj΍T?6f5X׹ڒ.UIϠ̩vQ -=4\ok۝(z?]k#۲<oq|)z Ln쨱;^8@Cwa7__}�9^ m'ﰎ`vиqURfd[V0&vNV|0ckh0&s-Mc;@>`"Acrxb7dw"yq%Z+7Mм&!gT_g<I<x݃Jhꝁ-LM/ <SڡI˳6 -8;xVv3EEtlLܟcaU1C7_Ϛ2W}1>$p*8�@Î70^ -7Ugot7h^ kyVg n@NXd4�UHg߱0� cہ}qޠ-"6@p0ˁ6ЃmJ em` -Y4`y8@C皹./BHZa2:7Xs=r-C,l0;j܊,ʈMƁ ҃L F]N'XMc^y$sb {aH] -Vyd�"OG7U1U;V)m[Ϝt ^s,WLo.N>.}�UڍQ`xbwyB0L0<p̬TO,62E|rk<Ǹ ;yhEbhȒj K+eV5 Z*㝒R&=]};Hs#p0)c0\ζe΀CgPr -endstream endobj 2366 0 obj <</Length 65536>>stream -*s'wn\Whڮa -hb8}rSP-[wb5$o 硅 jq-Q":< 1MэY*tuݳ@x:(;7c3wC:BbS* �`CU'ӽ�P2->K>,ڎ Oa~yXzP<kБ<hwH#y«6G&$ -@'3iC_FJI,hm28)zͫ[?G 5Uo1Pl>tS;[ů|ތTqaƒM1DGԝQDx/AZ E"OŹ<"O"ӼBe|EOa.1E{ Ӑ?XKy^_~?:3 EB#]alD{BaX\]GM+� -P1F[+RR*&p莰™B_2+7kѷ> +Xrn-5_\jлԑ%u^`7<t$2%Ўy[-)}4s<#F#7ڲHu +Lg iӌ0ε`MQcs?2ܯuCIA3UcX~X,ny+-|"Г* -%BebOZ h}PY_b�(a[.nk�lKĒayPhAiH¹EY%cÃW(@.lØ(êx%[:E$!DwaD9ҥD -ayCD^2<GX,l<(#ʀB9yZp4 -oJho -f ^QR4k#K�]9:`βIѢDyTƀ1Nl{-L�wy mϓVG?&b-eS`v`beH\B`fq#,a4=`ưc[?w|0lL;1i=#ȸE4 ˱(0ٍa53'7wz'ʣ]enSȓ9@zJB("a U -cw2(%Q we$i) {0tG9eG -2dd'`QR[ӄ獆+g!^4pxjIkK1<uh?Ç$tgkښ ̄)9Jiaar(ql\O@6Vr߂g-Z�%sa0hF]L85d@W Q<,YXe @1[2:A6-wL%ԇTsm�%ׇ)0rd'_3Kafc�~.~OF.$û tl11ͷ$SSa\; -IE7U\!d /f-Ysʰ`9 VeKӻ|UDhTh|<R<2\ӔOSZNZR5 p(s sBulvF֭dAcc(ʎ!I QHrj$/oy?%b@nRxz\[̓ݴ\=ګ~^1 @LhsM۬ h' ޓis*ͮ2 wfH9BәB>m:Xk+- ,KzڠmBXw7@җh!ە4~Mkڳ܀o6u5fKX;>Hk_`wa##q~W%О]yֵd;h+)&(J*`z`<aS=tA0$ +-1 M!&/Ʒky. S]F㗶9x67L �#sea2!cs5t\&&;bs3~,ETX{nY*Lk% -<\uJ`K~&I \Z/G(&/ -Ԣ]$ϥ8 xLkrsxᰅ0UD`v SH g#((@3Vb,Y^f|Z&g322[2X9LrX`x1z9&#C*2cYچ/x [4̀9Cx&&'x=sgܳ-~7ăr^uKoTxz`[, x$3Gnb^-a-3Z4o4oV[ )y7%643 -de -^8 сy{}[WL�J*Ұ|h-zŪ D>U= B4:M<r-hgx&»sNӷ 1kVN!Vى\Q]tC½hw &r{Cty #݆Td%8f,׶0tJC;@F^KhI0\ -J.bq6s -٧sxXx -C|wF80HnE6ǰ0XO܎1vqhatmIh@17XMݔlDF23 xM<aB%S~CBS-=Ǽ!ݤ44tZAYB=NB'OF.ߖt+.BO]`&9޺qcgٳX wb?&oX^X%&Rð6uFe45OILYi{i{;9`jN}3/-҉HTFL/-j dfc4w7Z#Sbv&f5ӢC"I(JРKBƖܵˁzq0ͳV|mEL;:E]"eBH{#`c]z&llz!ڮ%na?l67/Է2It7?P2i0 N~o޺ś1HOr -٣ oXa7!mQlKz kS? O~g&E#B_✔7%/5=|5›u f*P?Zˬ.&%W@YꋞxZȵӨ' ϳJ2_Bbrb9>"<c^I `-e>u U1 FRZCUkJ5T{05U34+zAUE' p<#[yU{B [UUo[Nrb?dhT}j&ЬfyC-3}"_,=O^:^nklҶޥ|@zF j';+'鹈?O߯o?Oa_>oڟiI{kC. -݌9$x Κfsʵ}gvoL5SS >huxnڼu+( -V̵ $ G%ygHJbwF{RhĻ!<ޟMeD(5"V#<h;Co,E>yw|+O綿c+=/3s!>Nn `cbyTy xJa*6 wyD*mjYĶ8":15 -fG0JDxync5;50&!4LНiZYűCБ35BX| DVLj;nG/W#1'Ge 3zG[]fPW~scqÅLq';_< ;R^=`G}a$~Zjwv ck˰.)D fe홎~[+y 3?=9/&>eprfUoݕ_Ƃ`TҖYs %^3[}lq~3V6#.LU0u+* +z_W>l3=tᛝ)+B` _#ey3\ԕ[AQ*ˠe& MjhoFFhSTx`O:S3"E=U@7TMT7vyԵZbS L<D�9|Wi˼[<;51F2+%_ˆDk!^~ɠZus?i|cuv?_⳰ ~|?b~o6(?{nlr0:M0T[TwaF!AM {uǔ=My-=hQuNݞ1n.<->nw}3Lw/;:KLE`)jWԣ&ZrEʔ5,DUV0I 2"RmF.Lmyv;FjWv!]M**,7fYխԝu -/GGE,R.x; K4\ $68 /}<RRTJeϊR*T|0-3z U|Je?8Je -�-3K4G3i +s0]]i `WRatv̾h/2鳪bN]y Itˆ;Zʮ%8rF'TϽcms gzNGH9q29{p'QѽsQHRhݎ{rl17>b)NQ׽c9'*Wj4-w䁔MeH0a^*zuX3a7 -I)!p -M+FU8= eriyNǪX+2^pE z^2N> ]2l-Jz2_vYՆv3[brb2yPx,*x|TfcЅ$5-oOHRJ -p\+Bw{}Au8\ cwJoqD8@0Lן]@2kloItkp1rw?f,Qrv_xհOů0C{^tLDa٪3C9K+/̶2[wo]]uB|(~԰qV!8j%՜͕!Y?aOIP*+P(0ț)Oh&!;)tifd)ܚq/3NXhzX[1o^=t8=? 0L0>05&\6 t]^uځj40J|ۭЉin ۞ ildڅ27؏ 0|6F c}0C?sk0;gQ9c(DŽެzpҀMFz Fx5<\�bck"զ[@^$]­[ - h*rcWߪfXe$VyNOw]@px*I{up7Nsϸj`$,ERL!1f+dGGQJȂ)8'%Cv!Z̼dH>zރ|'g;ajxSRCB(B㬗fELcs鉜#dZ -s|Q eZ)dPQ("PCoƴRk7fSIG*L狥r~H)hPR ƜPG؋yL=Xi XKȓ8nJiXM -gU "PCwR{)4LН)ST]W}^?X�RTx&A1ȦFSTu>/2VUjhOLQuW)li'FؽU=G4hPYX9k` LQUA\tIL=IK& -҄lD&J $:qg24o/Bʂ#3�KNAH M M<L٦=Liza[0`¸&Aj1v3y+e@xhe@K%O{7K%:'FL֥3tfp /%4Йsg(_r͎ KG?/m˴Tw2B;'|'x\/iMx4aaU %P\E$ |B{IΥa| ݩzVϒ<kg [UwYJ6t3 ΢<+ۃ˷Ѐ4H9ɯtOn%fހVb(6J -7 xX7PW3ߋ_)Jb>Vʰ[+Jťoډ(/nsѲeYAys'@kTfVK T[<u "VןB-F]Σ@j"hMeew``n˔rbf}eTO'/eB]⢭d;?>~<Ōxby/&p}9=̣$SX7 -S*iZwgO n}˜hA2a9/;U"Mр5,t^%w%2Ռx!beg>QJRQnL\Tz5T=?xcK?U6Yl.0S6 >\54vvM I/e;c MoPy?ĤZwY(SPyIl)]6xSt{I}^1.u[4(= hRwY$Rs"R[Ko&8Oc}wR[Z=nAD\Fȝ1~-R8mʁ)9uci^p(D8s3~'hslbbZr`KLv{l 3"=K&exff`gQɧ]!ߒ}H/7Ȍ'Qx];syrs}ñ;9u8VW3vñ؜LMyHpvĘa849>gvi-N$9$ln<C0w5y{[͉1TT)dcta.MsGڼaNHS& /3r;4bpwc-q -'걥c Xv.7c0!4p H ={;T/-= ohJ:mWAfv` o{c[j?fe CwSCmNՅSOՇ _@N)&W\][sp=WuTƴ݆󹸴GI3aМ$E!ܛZTs�u8 P^<$�ŵMtJX鮝fDސ=Yy߶Uq E@,Q>ˁKkymZH/<cWe,@~F,y5N΁i=5\__nb!>&rgY4~JDߣNjp8'Lwuge'gVQjjaxtw2 -.^4%d-ۃtg<SBRsiMa\O~|ʡDtrS;IЈO{#EpW|j̣]'_׶a3V -ۜ$4z+4y. w;9i7)\(بgO%$�.@j0Xk 浡[!DJ]<cWZ?$9fnnBl$&hߜ[Hé?H|H r̐&vJb^^.MamMep('Dܧ3Ea7q83DbTVx*&$#mRlLɍNۙ9}ZS$e'$3d!6Cx[SCyCýwcBVΦcu1((lA>lӚfm褘Ԩ(CeNSH&zA”q&C8!^r1Z d6.2B 5K=.ǗC8q5Х{3!;a $~̹cN?sp -bC&{wCh-ublK9cƸqGm\{N9:ӶqL!2}C879Num9HIcR�Dwm{9sl8?0۶oe9?UQw+ o -ټ2o1oɛp)̕�9NdFwkwz:.OfJ,bbq Y=ڥW-�& &sq:嬡G (t=N\䭉<]WrN%̖޴= r,4?܎dh7<6!Y65H1 -]ƶCyk&MZپ<ɫWT~epaQpbM09Q<eeԢt5XW"m@B u< -/2!2Jߑ iRy#Ctpj)>?!}/5)Vp=Aae.c˓||%I|vo|H@f;V-f[<i.K[)K@q&Wke  z-zz -2-貯.g+ѶgF 0J u}ZO_KA{ɝ%g)ְfs'wӒtWƔzAbXBa@LxZ/šCG='%w$֢@VVHk 1 PLjJmXm&[~Z-m-}y4D8ci.(}FWVZoPlBХyV|4UꓲН8ej 8uxVVTNOgHkiYK\ؙǙz٥ā⡷((MO M뉻뉻5ӽFi {zyqO\o}qnzZ/^KRi9INrI2%T/mͪy[ׅnFǮ˼ -<Ix)!|M^Gλ>;^}IOޚe}y}^ܛכy2[3uEpׯ>goUm/[b޽ Ľ72>w|=MO_{_讷w'[߯ ''Lqбͤ{nBXSiы$F!>6+"B TѼ{�;qORGkBr>v$$O"``}=s  SF.-BOF P,|x0*c#;t*G%eXpVn8A4{xohC BqߋRCo\O[+H]J,Hm%nD8Ӝs%$жؗPNRqlz֒}C:^@޺%�oi9yhLj褊トTp|hL*8~GOWky1鉉rqBXcgByj1v;:qބVܞ8^Egߴ8LΞ= Q歚st;(5d>{Z"RB=zD\$?"b -]<Cfzw.͉l!>ŻuMx-V|YRfYm)|]M|_Ev - -l&כd/^Z#=%k{O|.Nl}U/F(?Eݯw u]ssV|WIE9u/7VY;3qyH%19a_~gMJ}W߼]+=DN/ -Mw~QD|nڸ aw+5ڹ53 [̀Ln󃭄<9 q8y%2\=[?3Os\髍tU*5 wO6Aͮ턀-bR;om0yŠbȞ5:Z&Y:9ER>a b=]Q -?3䇱7bEhه_/W+IO| -8I=$7d{dTx2d(N BuO S1�(K.2pO6]0)R7[@ms*:/ZCK u$]1a [h6"ah ;,iJbĎ`[pBŰ8/ kc0w܏BMa9R/ձx -K#VK,j1ϫVW)S|q x2Ҍ͌q@/ Jg,<v ID: -o'Τj(Ѣ5tĠse] n|ֵ17˪#MI/Jl-*[jaT�<GcK?9rh6UޥDdz1ؠշ[x74fKv=l@@EVȬ8ōaZ&}{uJL1ם\mwiE7NX}>j\ͰY -TaiNvZLyx6Gj] œN F'' * ߉Ɠ֟v)'|vs15F\v'Z;Wĥ_F}I vU}#\+bxXZYϻDc xMi�YA+ -R[:f[I Yc0+`5= �ވ&V@[a`G,-x~pתMgn@p9Us -X4 U{coSx+Ac`oB ]zsjY&2HH4 c3te5P -iK` z5Q [!smٗs;n G0.XkW~oP%< +qFY!C:;mEN{�];h^a -okv3L#5?um2 -d`0c҃aM;wrb"hQTL{a4@Iia -93Fױ`M J̧fk ]̉sc4{x2>G@̾m�VCST=+uUş vSs( GG86wИ&'1 Hows4 L4X>8#ފ@QVa( bqjɉwMa!epCB?g$bK4%/y.4xqOe Ol/?�i üNAn6&a,&&~}ꑡ Ձ^40젞;E ag-CE!>3EJWcܔ?5O�/A1ԁ.P1}O;.S N܉79e MuYKvcfab#a5}iQDGvԐ̶Ǚ)^ lv,#x -0CXG_fS,BGK,J -mˬ{}IV[C -l^-mWlkR"pf_~(4ʿ O,&aIV:~Bykj4&Pd}IOsBCs^M&2_afj@~fۢlш  z.P9")t1&:KB?{qirLGCOlWcySXYq@9uV 3Id^ -)p -&'4<*ߦj̏Xy.d�[xJ'gp ]JӋb Sz=T.ڴ8v`\i0x }{,ڦ3RCqQatwNXK - E0Y);`k fU,SFȷfO,y8ra1_jMq.e=Y\ RFxbu -mlNiy \3̜I N8L/׵UkZ,lB<CvHXDqI�)G CKշT"#7[E`ږhRHs-XF)[c.29]ͷ"?1rm2yT=D_&x+yޟvEq2t[et;tj۶Z^܄5 Dz=  }KB(IKr#$ȭSB%u\F%}רּ<[eZ!%bs>m6AD\[)yQRtl;-$`{׷듘 oS`5:w>Qqv.r ʬ3}*$F<@>c|X(!Sy,Gt\@ߐ?_ -30[/wt+C8#34dW%'PF`]ImGQeaarﭧ5פ}{B,CwG%P|OGZ՞zKZ 2b`zI(" %(5ɡӣ^TœT$jXa.Thb*6G#x@-~^ " %(5Nɶn^TwѕzE>,w{cI�61hQDZ6GA_FRT�e駨#_mӃ6R):=Nu$G+Itq{J~;(Ac%|\cHsQM̮PMFYr;J~Qc1Q+ -l&R?G "+AnGՏrl;.Lu%(.lsJ. FdɃ�5cͪs³h'xS%1}"/O]JÔJ^z@sĘ2[IrGpwDzg#=vT+a7PjaW /֋݊l_h#5 (%ƦҜn~rj\3Z۶Zҟ&EcS/"r#,R1(JtbflWVDAj(dap9\[ymnvVJM)Iߟ=t^[z$5|:@</- r~Xv_pn{™>c#.s2޼W{+g[g/NOP[8|ac{xG`RAlӊYlgve9;�|%s4cA30 ؤlHJ(k̨ս"7G=%rUtUdfd]8 -TgyRܲ'pLkG|V^n&.ff3 L'.P]=' K9C5XreSP9]MbhQmұq>8 y=)PO8Dz,ˎE5Qfe3s3W3af@Y,c,uBn�gWv*[&y4ZG`1%5:c=R Upд=A|I4/O*+ˆ6|da][ -w$(B# Dk#L*PeG;# �V>t -7:pm#oՋ0I^' U~Ǩjtdl]�Q '2BC%fkӨY S�e _Nry9*@.` -6?,~ʠO\Xu_wzEydW:(W^pl Ys;�+m[iH٫2 [!(`&bx2/2Pݻ*J{Z|$PiyOw׃cx2-Mӥ'(X> d읏%?.LpZ} \檼h> [ڋ Em< -(o27+6f8"4pv �}l"[&7q qa/\/#sԿsa*sbHHdLЙ0+A^4m΍ff~Rq%4f\h.TxV7Pli )l U@ %v6 qs xW{ь/(-uM ۱2m@'/u2ROY@u-P(|NV&DapVPy$6]�%QO`'b!;q$޼o <tf}] A:68`ϕxS9.A vܥ5EI _t.BխPK !I hVht&lA@]x?2nghA&:p+cᢼh=D?j=u)'L(Ld -VY@uPMh|ޜ.k/*Lp[a ʓ/"bY*kf -^4љ kZ7hAg[u=SLlf lbQ59gxUAt}mZվEuץl|&8epSca3뚠 Ѷy\1%Bd}aw7,_ga?H'P}3h4&A hvS%NpWz/eqn/^x:S7b!M<_�?X;uw0aIb {QdC@/P&hqbbN摾yyfQ$iXu7Q7$&P_6( Be@lzw!P6a G fa]  hxZw2+EΫ00A1?iF3J0"6t Mi -{U7�YʹBj3PG,tf4`T$SALl/193/sbe2<3}są؝jOwћwν?>;v:ak*uj̦It{:j <X˲ c /=&pF8tCuiN*y~=)]o߁ [!t yV]tߪyw؜86_xF@5&Qt+, N<r(P|ҙA/0%HQMb�˶BX,Gy! Pc¡gx«< ^h3TwP 0p 2]arD:?dFvgX``Cm %yc.AۍQ:C٦Sf'iO\~]=GNP-j崝`>!-foSяH2 n5m¨˽Ot9^hO#{ZXcZN T! -ԭWӏoJq62.r$>:J$f"~?ҳSM$13^}qN$q,`*;{&HHHd_޵$ -d1vHwt$>@I=ҾZM_WT|";Y>JMJ%J[T#8*&MGo%;JwIbMgZjpټ$fI9?$%`?k-]vH%+D%gpY -Xmlyi3B:GKwL."޹"tA6ﱅL&ȱk\I'u -: ȴ -#t'pyld ʺf{ E]VqX&%L"H)A՗_~? _}m`:S;}oo/9M_vh{_p*dt™K{]vuz/6Ū .+01'a[rQ<s0Y.vpz&Ppo,HuW+HmHSm=I:M�XuM,>o6{/(t~g)BORG9(00q?SajD"�sIN kl=nr[v+S.w -3o=;i_̲5ߞ\l'P7islQҷ+&byW|/bɍСnubϪ1ZM;x/xh @Z >ORn.Vh݅bI)ڝPͺ hѻ}gGu ߱:[;-;uvػٴ/a5Y:`j[ .^c[qX1H�6!q;LL]rͭ gǤ6I$sFe0(tlį -E,rdtqF=> [B ͹iPc/ߚZZIX2- $ e ЗAJZ+ ` ıu\&DвD!S?(lXoy>]"}DeKuJʈيRIR<b-1邭FadȤ[݃cleN͉e*$vd`8PgI+; T#;H4lJaYas8�0L-4c|2nQX&M5Ζs8gp ~dܱ <yP%Hf>:6t0a0~N9YNȱx9wUv DqL'`E γ뛾j60@8\B5&A"2ȈN>=&I!Z'�$plv2 ȱ{  P9ɒ吿,|iiqN/r7ך;z^aEPp]:8hl^ 98 , >TjG_= nllqa2q`͂$Ȧ -# 7ً K164ڋ0_6juP@X9Ty&I%�l -cۄB7G 5HxDlp]߱eW@ ҵBƺWPE68Qp`s[;<N"BGT[ @PDd Ep2+vP$k<.3 -p -J%mHe Bҳxl2.#[Y vEalA<|ҠN -+nr,V8?v Z241koqh'Qd 6ksId-<d{KΡ^8D9*} {wZƦo)d̵lYa!eM1;3B+^)]Xe#sn)\dGeJ(S<eɡ 1%P̯fZvMUbŐ&T32 -XS 1$<癹A@\ pBAc:tTkC̙mMWv�_"ZdrpDpfV$RN[UJ  Y}m{M DF(*{'NHZ -[dd_%=y+9j)QI)vqc^ž"2X9NUU05j8ZJ+ 絣"&+>I\yqlq 5 1 ` -( $Q59VXRV2«$ў5>J'h^AYг"bX]rG^3-Pa7Wotf0={<'Nƶ2RVZv¨J`& a~m[X^2tr8{6l2{Za#1Y[NlᤷKRӮTȾbmkV va'Cվ@9J&kE'Lp{TŌ -F -SOdoĢ0~mMl+E,8LwlBѲWq}�n4Q ЬH"/ꋐÙ]<5t޳HQt*R2ڃB� 02] *KV6. -33B碌~_y-hP84Cm3v^Ff븕`,/CG!]_ d)z"$ᘝN -8@:U&naE\Y(IZcJbYX -6G;ǽ -juntpgM2#mV8޷v$o[e8Hkh (;u'Wb eـ5Ei U B +j/bfwlB$M6|KeiQ}JsX#׹`l�yܣLm7Î>+Hg4Z)dxGit3mSV)lF7/w]$#o?~矵G6 Q1M*nc2Ɨ2=ٗ9`,e}{Y^ػ;!ʺۖF?N=#ʺ^!5Xiw?O\=~i!b - -T2]څ ĻtjB/Cŀ)N*�=Hi(NԢ9OKɲ0 ?[$ 7k*zeM,X F(NÑ"+DW - u +2Ǯ45T)NJWBNB3**a0ky)tačm@GbнBtX ;JΖ~po={aR̦lت؏[ҝ@bXE e'&16pt4�RrH~-%XɈg9'9[jvaV:�"6}h⌖x!q٠LrJw_$sbYbC76`(t"> TH;m�ӆ@ x,^4k71^\s: -"">x.^]m}]ЀuڂjKQu$Yl&o#DU4RAQ9HgJLG\q -w *JU<ӗ|*zqED.0iꬔe/eT] -kBɱvnѽױCw e2zCpNtW( _x>%PX䴋0[_fcɢErJq*YshBcyJ'[T=Z{UPw_67(IIړ) v+l!urg ZE]J4t r[%߲IF5 -l'gmX>1l-EZeU8Ho ߻HzJFc4Xj#j1[R]?ߑ+oh6"}!}`ysj/1ur0_~9%3_)̗3r1//7AߪK*q0KF;G;\Kfx3JZj@l^*2to,D,W C|bUQNkδ|l -׽pÕUJy!=) ]1|khX_n<Zvh0dCկd:\y>ZsR;<M7?<e8~`W}9Y|�qRQWf~dnLJ~~x^<[b0dq\0㿻5])֓\5 y߁O>5vr9tk?\+?2񲘦(FCP?QthEt;姿wrYmte,#3ZNNTj@U٭@f(]Yp8*Iz13HڸB8{-x+-�1˙R6c¡dSEAlt8p62nRas‰2b^dh2LQvw|%TYbw�2/Y7/N -M&fnyjrmZ:pv< "HflmOy=ZU>Z4NfY99,�|m+FDR[7qkFNr.P(}g9z['D*P\U峃u2i -gI_ҨzHii^VY*h˹%8:H0.qe1*@TiɦG t�" ؽvNsY AG ٓXaAɂ7N`"em ú5X6žP,o('Fn=8 ǟO\Q{/ l| *N)oW6Q1ܛA},VIƎ-t,m<W/1_bYcݞ+El,}%1o&ecÒY@˵^n[)(LdM <d$ßJ] R\`]dM+[+|ŝ+^vxfr`iƜ9"%XJ9)ǧ"ȅU%7ls@b$ЋYM0Jفtc 4qBl_7;,=-9D02_rb1CLPxJ1&Ԯ/󕌜DX/5> hu鳗o YxUcc�B~$r\m.d3]2ˁy=<Y6FWKBDehc$!4EB3"'"]62%ʌ?mhirUM'j ߣl>_ aW',s!opR(q^+#lQq(K`�Z.ȴ*UԌey/3oJw`a3֤rgLVMd@˾̘,[{N׭`7 -oAo\8nfm s_3PtŠCs!^!X"VaQ*. ;2*1Cp)g %2sɱL,.@,,{޼t[kzfv%`  -K e@oة& -bʉ"\0ceYٽ 2og@aj]+q)RG<2d -+v| м3N>7TIo76VV6@Ru4f fQ`ES]�UY^Wz 8+>0fI %sr)NDh^͡B VUNd_1Š 2M -ͬpzRZG -vgoQ`/.bq+ݥεWCqp~g2VqsZC&.^)*V0q-sGfi8W[KF9bOؕsHc+I: Yy զ@2Q~hgmJuI[w�z'X'%+97CĬ8%q('CD|?6#)df8B8T?Sq;i\99ճL|B+ފg R+HJq . 0; `!|,0;zN&kx`qlFZarS.03]ј91 Qhw10XNy ĢEXrePbʹK]$ʡJ蜯b.LAs ,Eq <j16 Լ3Ur "3W|\] G\(cyxfѪ"U#0C`Q[E}RʝC`%,!`�Dw6^a�e -bwP4[3&!GsH5.X] 5qaVx,�|YdFcۇs57~_>o86Oo>w_GF9_?mpOo53w O?%["QX*d\ 1!|fHY )@Gm`d'6O^xv&#*`l`05):(D: <5%%9۳fTv }pâ%^d/]to?+8|U(,Nk9Dfa?9ʼn5₆%2>di)F9:pzjTN5,R&kxk\Դq-HI (s(`Wevkl Evj)S} m%V|H f겚>%{ðfP !M6\-b*_%5j˶ sEU󀭦Oa9|P<Jz/*>B& j 0(EdVӇ0 Gz'E8*TOg@3]1Y7F~rX<hڕYh1^^4ތ.=+ .L#xULI^/A<FΜjnLSμw}ľWL"@I@C QI+j j%B٨@,EX/xA3 df-f1Eh6VmJnB\ kVw~DH82eb-*]fcAe +Ҭ+x/\8EV3a*BSge[&D֐f3?tb)'FTfV bZ6n4O9=tFcMWr-|q*q-{/2nIeuIyp9(O&C9Ä,9YM%|)P6'cKfAʮLxpB_N>ݫФE`@Vz%=4{٬YI^|5ٲN詟K~()HqxyX˿PGmWƲlPՑ>85F.EaXIv*NQV2E@gZ�u*] H3f:1EW9$jDdegW+H:SVzv(2ڞqĩ>bqdN㷢r(_ !Nr*e͋%d,ASʰ n_j?(B YBCݍ=G.Jҋ9@I]�-wdazKhWi3Z,WSh!ǚhXs&@3Cۭ,ubf)GB QLYY3[3;gB ^sd -*$2Dgfɔ'8e{tcsbkhj,nYj7K|gBM4%CtfY#ZRDJMm>XCJ<ȔáQ0/RbM!t&;-3*kr"5EIђ'H @h+֍QY7}P,`(}"H2`(b:\H vH+Ф!,,JƲ (ϓKEZh8yf~$D!,'E\m<s4n_qej`TDvVz -.Dn Tn5TC2(6gH\ /tK/Νd=@-"\Z bxkE"tBV,/UNN "!"Y"3טc0^,G!BMb,ʂjAx{*Ƣ~p ̡ab0Zd(6d-kP. `TAҢS1 ]Fe$r.Pe7?0߲n1$bE Hp`@Pqg5F1,&@@ <ED `u֩"V~h3|LG,rXD|ҊE4Sjud8RĻP-6ѸPaXEݞ/R5&9fj5Df33Tm+92qIh&,STh-Z%I7:&תIH&,nUh+M%I{P Y Q,IY YZ E ZK3`6+1+(:;;I` R3@<vZՒWD JIY2LzgU֍QY7}WGEӿ?A\'ۓWN Lo"đ~96ctnL=HY6n=k\z\psFC2kLI7z Yqz| -g>z۞3a+B󰵆>aO `Om 0b,`Bs8M [a,?X>Z|1a%�eܞ5/ {ȼ ?yČ8%lC $tLЫW\8E xHhr]5eWtnwh2äb4'_}Ҩ _}"]K Lox~7_ -X ' -~{\ǭH^Z^??5:-T*RP!t�rs0)м2Z:gi)Y\n۠yx̐|WB4K)pރ$H]5cnI\tZIw}C>XAwK}$]^ ;C'XOH^g) *ۑYg8w2pS6bqӋB!5 Ց{E}v40}8NSϟd#A6iM R `8;=S hFZ9>w - _U +vswnbh7f(\>x=; \'}糽1WNv~7u}Pg{??co N?ZsbnJ vJd9dg }cu33fP_t}Ji7Q%-v? FkAm o:z,'[ʞJ/5*PmwpϘ?C;>4ZuCg0y#IzT?:}.ҷ~7u]@_{E{1 6BaH\?jJ`<H?}b %/ڄ4gLfA6 Rؓ#VmИX5+&g>hBǤo39A:v32K\b陛Ȱ|mkY.Vc k1Kxۏ8<+�~{2"g $jhZ"MA2q'v<2G'_B Rrq!BhB�}Z,Pl>ض T>bz̠M$3e Rآ&q mۙqBl2>Z!c83'3ޱyϛ6L&2 -R2P )&rMNliZ/}^+sɌV_"HU $T%4@"TE0Y!v咙;lrꤗr ҉ro9l9` pls=۳[O>5C9ELB~MB{QyI~äY ?ֺUf-Τz oK&RogUٙ >H\R^EH\sɼX|郁[Vqɩ0yW֙/,u ddods+#9CW# -V 0ӡ߾p֨iH{2|`]|gX!kk.~e$�׆r+=6jTU$mq$�yg?rBN8Ywx%䒑- Z1)H8. K,xcAbN;Z". ˆBlҩO];ja`Saƅh;O۔ֿ6vrbl%bޟ1658#xQx. ;2WPY? -TŧyZm6JAF]b#Na}|`(xPG(R?^NcL e- Ͷ&Y -8`&o'# ;P[j^-3]�fw B{et`m5w2e - s[I"6U}T:. mPw# Di7g9 6}5w:0$#*zԴIpn̒b NX-�h @&AMf⏥r(M^DEOC qb|Lm,>fZ7#GRA"TNrSx( ƺ!UsUeUqz] 4|+o<1'k?qӟxꏟMq;w2R䧿/-^t4 _s9}ۨ,)XTO=ccw_1*ljڛ&pG#6-ًM ̸*%} 9W_DE4%WZ1Qvjdm˖΀Ɓg0[mԗPΒg -J]_a!%+\ƒ" -B7¡aY<#9d$Le-&3�n!$Hn d8yv(]fc6M ;<qlj1L!D+F:wAkJaEp G&7Bn@iyWOj{@evv{j",- p@mia7|Gc]r< $O#f�ᦁ@`̌U@!TM� !@As X -x!İo e H=N{8p P`o=V8pZ:.}(>(PWyU [<IpCbЯT"L;86l3Z� --os Θ]&M ;} ۤ"Y}&ZfU&˸FCbGa]cDk j3jXl@  49 ` Bsl.3vk fqֳW l -uVMikAڎ^ϥ{Iyn$86?.4`~9Ѡ1SM6#L6R5 -F4FN20yޗJO*`dj¬)ܛ*; fW[ySg%P,NC`<y5ہ9ٜw,9.6>PbH U&V$`aM_KG -okAX),NnP6SU6×h1f͘ `qw+8bkXцJM'_h"l[K_ԌFQزf` dcR�XkSݖfPmܪN-*\r)q33BZ%sX e`g6U!;E1arLff-YITq8nF`;AV$&5@GO\'k6&"^Θ;X1Gq t,xݘe7lMZ95mV15?pw5AҞ6$NiV32?|3%45\n,(6qdወI]7@tGш^73f[Rqƙ.)oc~SKOTfa+zd58TeN ,EW&`'K9 f7'l/pر�uTD^SW}+WO_WEOR隶 ,g1J-D2d% s�Vr47vop/Us&Ap&l+G0is[o5V  +l|U+p^ل$d+</t`OB5CJ35s΂�ݸ),\At]3>~)wG2;"\\v�^y  -Nhߙ�:g),uy ™Է0PȤl �7*$Ij nY*Užt'DlaI_ 0C6RluD�u= v7}'q XxW[2n)*!c*M( ̡ɵ -2.�SNEt@]s{Cod˜*os.̕yXiˆв0`<"6r۪Rv4w#֮p -h\n4t€ŞvLwNujv99@&LຝfD8|e00Aϯ&!{RY�3C-2!nxC2n_{zd,[Dߟ2OD^͹z3m})m:7:VO&5b.7l;Ջl;Ѷw]Ӷ]fV׶s\gu)MNnۅ^o5m{7 {-M>}m3vu>dxU^ySC+/ec+~.b][='E鹪0|OV1swu˼s˼sqݰOλbcR\߄yrWΓb.riks%gn3~Wϝ9_;{n1d}/Эv]e=t*<wds9r%~_|</_|6_B<{LH %1WͲ -<PqpHxe#w#9J[)h,fQbй% f5u� -N~sd@�̲oţ"\zx?&?s.\Qa*"~{ >R<:!W#sט@~r3܏4ͫnuVXp -w%XY6�(kY`> osE G6YWdr v@!L)d`7nyC<k -iW)i) V!գǁZ&Ffe -ffg7ȧ -1in0K|dB@CsE-в73#!Xv4OeoBO8Qf|w\: q%a `AcfZ+V΋E  ϗ/eW dAu;Xr#'uruDq旤<yg4�0lM[0iBÖ[Ɨ Y^lƭsy+i~aehgZܘQP!x.@wHW("~�>bgFgoEמ!J7*`: 4ҺiEG3@}fTyI=`%8 Dq,ji6GyѲ+:76zWtC흻d K8m Sѻ[[;+O?p_;\S%U<ڽ]_NMbOu)Mgb߿r[;~'~WY9NЃH F3|#y1rNR枣G) KÜ!ͨ;Pgwda˹d_~oۡQ - HhIc*8#48;?k*w Þ+`jϰUKaIg!uH>y6־?w]}VgY$W6C5Z̦P4eD]UHOq|dl:)]Ka DŽ`|0_Kk6чƶ5m`mg~qn}s{m_zV&o[^(u<J Amї_L tCh`YjFI[9 :j3QZe4uM]`i={OeEmTb!mL9�:uݷQʱXnWY2MYYYceȼT@@ *tbX=d}qˁ{ kcLg!}q_'̋#{a@@OfV#~@b`ǎĄAd8_hON0gG{’$m&+U[{($I&4v2Yh ܷؓߧrwMW%$V2Z9V&(,j) u=a_yVhJEk4mb ;ƭ;ƵbZ'�I}3nژ I+zh]@簀ݐʜӬ,eCԗ-@Z:"WpAj<p_'A}|.-v3@9J-'3U$0CEpbpr&,߻f:v)`꽘?y?(lrV0떮ߺF~)h/7Gy -~Zf0+U+B˷ю\kQ(ӢV=286eq|;BY֊¤)W 5E"E+lo@пE8",Lqd, V-}$f]gӉȌ%*cp\eyE2icҜPyLj`As.*X-ZY:2%~6Tf`90�a2Q9P:CwJ�a] 1к�R=|%1H@ECQҋa$^mfX@e/m -"0RnS/'�8;mh0/yѴ- @ -3m:0`9̂A8N8�X�~> 8$E8=Hv-=mPgr+Ǘ$68-#I�zpW\#Fe&JqxKr0Xidj6Kb,@ -O\+ƞ̘IWa~3T!2bݓ*Sx&VgwcTj"We=_� W(Xo`.t�Sٙpe6a<z,taUyg5&\x9./'m.<ʻc 2L|Xz: 鯱 -01+G9 G϶9 -,Kl$913 ŅSfƾ60 -}W ]Ӥ/F)13('y6Ӏ>B -KFّSj(_8Ձ}?U+@8�2LuO0Xf$!(I� Ǯ��m0\4 vlRƱBLK%m{V麶+l s*`Y�B]n b;oqM0-VMbvRDŽZN dž4[eS,~'_M]O#C'9 <wZr/9m3B"`RagV~Ѯ@LW;}OTu@5.;oIn*GU"CK]ITTF3mosbN`8[>VNi&VjZ7J pc�P+9l]q� -m$RB I^&htk`MG*΢I׆`]X2oX � u"d_?Ke/umpaVr#9N_x2EgMU$<u0ɓEz3BHJg#5$ >>n>J~qgt>@0I*羙 -W),l#p*Ȧ>pt:/k!8L|[`XDYX  ; �J)IMJ-)p 4F) g^J0+qzh¥uƣ#sn ob5M?X "ŋU3` -:9Nf3),BcיQD8p8^2Bsq6")sۊM[` -+xC=o~#a\( 0pr�_)@Ȏ,?iERp9Ca<[y咼JկeeVVi]}6;8]v=á bXɀ|ndGz/K?}wPSfNqdf|*L,fvHU foL8vOe'L6k\73\.p'Mx{h�| -QQuK!`ƛ-Kl8O#w =cБC4n `"XR'-x)(:llm߈̀HYx(Z´zFÌzi+6V˶ۄ$UEw&wJ21C #@J(b'Iz3̳]\@gy]@%Ar|)},/LO|77X-Gqͧ}? -z[r,=%LJO*`0-I샇)6fٙkqoɿaUms.G<w;P=!;}ɼ*[;~>;mXc]7+Yk=>$=6&[B1vtHk F1QQ)8Cؘy,"Xrf:1XT4o#%Au5LпtְLayP|ش)^dذgX=(X}I0ݲ*mU ֍fTYSА::FMBm>DŽJ�F&bsTds:ԣ8=ϰ_~E4 2+-AfMY8@u͙jc} Y_"uF{)Nˋ *!t.{V?H&֪چfhMzнmv*qE+P;mc;|Y7J4@EɌX&r̈́P6cE&TV rfSaK5Fe -#9 ƴ9 d^,˞h㓰ZXLkvP*8[ڲ<~贖v{@z}kbT :WJL˰ k]tse'<a/5ci`b<`(wL͡'F^|S9'\[E(CXa�qcFe_v\x aO~�=6|Y^Hގw�i#4�>/uol>a<0]1lo` -d<m R'r XY <G!57.݀h|n{ -Y͜%n*gXxSG) _xH'Kٔ[ƾt=V�#ZVO^B;0ٛl6j$&lK :4�zZh�`eDiE`蛃ذ;L/!яW2: 5r&);A[Y^ yc)QC;^RJQgI։v{]lϰ½>"Ete9bd$t`%ӷm/x]uGI -FZ1TԄ3-I)Դ@Q- ag3޸j!,/ҙpf%4Z\'xKu'ipbwfE<@l9hm55i hԥEFj*y}iɛ{ _4g]2IG)xDM~b3]AAq~{"1 -G+lanVlF#Y ގY=G^$)U1dZÁsc10BqƁ,H̵"l_ƞIM-q1Rj�$]F#Ѵp.'WR"mE<ȃ}$^$q.BĿ_i:Mt"I"1JJ83Q�t@6Bws�aG1?YΦ>?wi{̎wmURx X^>OhgSOrxǪ3҂SWT I=[b)b9>8'L -ɞ3J@@)ExDt.ǚ -nˬB#3* 5\ >r0ah,c=G0})=p8MGK;8b_/4Sؿ RYnr@FZȉؠӲ3PkA˞,bܵ1 iykجH6F^LzIL9И�f@Ѫ4 - -"qgAH=P+҆..B*2`-#!{rk헽oO v8&<h=]gvn[dJC8@aC('(6cJNIE v}`HjB2�N2y=2QHO֩N!w\ xT7EG67Ee9oϖDž'KKs` }NiKme||A=Xj֢ <d9"/l2ȶ'2l]6KW�HozS{-CQ4!Z?J -2dCȒUۑߙM[BqB>+u/?B8~˥m=&T0Viu|zBbGGS9N&SnM7w<RVbwXGm -5θ+7k^\1_l^w9_lֹQ·Mp cT9;;3H7+9EM䰊lIIsF 5lM3+]P֋:.řW/ҥ=;nѺY\?x<ؘ ͱ2�H0]dxK&Vj%nO6PnUٝ1Fh@lNcGDc/[ ,,/v!�n2B2Hz@V3>ɇv_NS^W|g7׽5jL xcdh_8v!j| #a4eU=A,gbyn&̷+1%]Rƨn`$6 Ub벽cP5-myc.bbcLwZHU?HzvQ[e߃ݚj+й_= Cf8дBf^s[7R!󃽔apV|c S=C޲osn=r7{鶣G?tT6[`` -$hX&TT|j^-Afu^Nhz8rcomC\\DeFʒ'BUGf@n٪qt??QcTB=\7!>d=B=@D&:\fŶ@)![^;{G"ʈRモcXښ6ʠ"^S+=i c'pR}z~3ЊoM֖=C,byv ټWtqtz1Twe,wWy , !;{uO%Q}z43z~L|5tռ)11r'Em !10V �)ِ#RV9Εc;,᲎cmЁzwfO'l;3ɦ:vv+yF48!R(Iwze%\nÖ�+ZmzoAKMӗ+2k웪 @]hk',ީLG/ ]4wfk,UQ՘b. )3h|~[ӂh<Fe]-Yehܹf).�m`uBA d5|iYY銙?cPK㎝Ι|bI3†nKI͌<$h[:futD,vXӅ3~V/}Ψ H*;1;n>u2ۏ# G^(cϡgi�=+@um{` aYEw~oBr`!c �IMܮ|. s31%8)j_jj<+�{y~W@GrVPv\g�dW03 -,چ-q7,]c<MMP/>~ic{IBbTB8b8 :: -}G|0( - 1>/>6Qm8BIy$ a0GKb/ej’ho<Pㄋ>쟍8u/XдÓlaOvGACv*#|{Y]gsxuW�&J -ēKSPsﶳC_Iʁ\۰H0;CH_6<\sܼf8[gB:ͳf+FvųjXY[wℒkL$+6O~aٳlv8M][QrPn/?=+<ME p6ԷT˘-^qsBNwƽ|Nh"պiP:Ɗ6KӖ{=k:N7M�;|O`.`q7o#zozr*!%6|ƿwPӃTB|fNw ̿9<Rq oo 5:pߵDK'l_g.n3/z:zFmoQ[+xE+>yѯuڒ##>}yk_AjKV_-<ڒ_WFj~h%G`i`J2=IWI7~JuG^=O;#%O;WJOR|}ARzvJv7$i -i~IRvJv=SOŸrkM1Rvkv�8+�j -IARvJ"v -8+%jG|@$l?Yq/ؚ8q^%1q?Ǭ'Ƈ9|xÇ9|xÇ9|xÇ9|xÇ9|x\ïÇ9|xÇ9|xÇ9|xÇ9|xÇ9|x?i-}>O/K-8}5%F۝+гYgrx|N0Sȡ֘UAWOǃ}Ἒs=Jc -c -0ԟAmQ~�Sߖ_3&HNk,y{qW; C͛?sc')&>2ہKD`^P cц\Tz�D%-oqmk- s^]-kP`ʸ/ӟgnT_lgm`::}oo/ 궽w_̘ta/p8j-HB-v kx*N!+XD/6ma ܔlo1qM`a(7njS_% r"1j0kLpF&r/h \sb,jE/8w"P'v7u\䮽.\3l6L@0(2_7n8a#ۿ"3C̫:a#=]3'Fxt\來j8#ʋXqVFJ.Hesd#sNZ5F3{ CV qHEfVuHZP H.5+Ʃ{ NyWdnՃ4HPK( \B#Y$6g\]ܖM[|qFkf�)9& bZ7na �ؕ7ЈfGʚf7*/wEAO.bLyGttrzI[2bD~Dw� zs_yn7~&3v3A+̦gcI3 Q^4qA'̦3hdjz/x(ڂ&Vh '^{b``r7FmUR!UhFi%ԚQ;"9Y3 Q^4 `Z U7d%GM;!\5Bۊ&Nf9G9nh]rgîDY:X^ӈFSL?3X6İ/G7hLaՔ-7.ߺbjn8&7G["Hi}HI.VDyA HgA?-Ϛm9uI DOFyѼ 27-lKAw /ಚl!1 5\(aBvZ ڔ˖38j\Xs$}7]ReH -2K˅!黬R8gFy BL:b6h nW!%1FKʠ0`dNf^U|jpZK9酂!(>)q^(-u.ҫ2@KN}�Nx/,NXH/C*+,b -�+_<5̘< }䀕U_a5=!X(/u덦O�',d~rLViI',ZVK-Ё ℉(/wFA=ȏ@2NX}k.2ߥQ2@`ƮWwKdЯZY!UQyHdmvE20,4eQ,`rkLK\Eq޳B0,yMBǽVBIxbވz^n`㗢>3 Y_3⸢^ yw]XM/AOƙbV4A0EN:k˭qN1=+B`g\^ӛP٘.T[l<l�f'Fy%f\iI'̦?!O+IFB25 L:W>*=r؟3&Nl+rCno>?EzRڿ7}W_鳟ȯ#H=:>:>:>:>:>:>:>:>:>:>:>:>:>:>:>:>:>:GiwO?>[g~^voM=i;`p)bJCK/3A �XY1Ԓ_u^C?dL6RN(`Kq/AUVge [Z㫃vom}>X\Cqĭ.m! TU(0�PF\,J+>y'MYQ~mvN6Op3;3o_%Q/>3cǯ -[Lp:U܂/y`h]Y}ܥj :7U, ǒ|VHN.vuo\ bs3XZ)qp}bm |M㈮W{?=,;MU >ބJ7][+z)S/&q?0'f.kϷ>CjkJL? 5H!'�^wn@ =~f�uY,q0_4_SQqWfs_5Za]q|:Q7[6}7m՞A<5}1Q[fB6_ռ|q{,r D_BDc{;'ܫ67OGJ{.y.K.K.K.G#AȠ}d>2hO2hEFo[ /F%L9EqM5U7̃#=k߼J'$վ.9cq+q=`#\9Տ xn]bA("1Tp5( *S=~#pSJo~oe..۫ } Yt=d m1.�w6d;H'sV췬|12\BLL_`D՝SeDk`\CeI")/te%C-q|U�4MFx)fxeH:-ꑣ8͍kzGxLk(Ón$Ov1h1zv:�hrETZA4B5t|4ű}R."2wy/]j $N=4$ wNJGOr+œ=ޘ2xJåK((;׈i-&@E"ӯ5#0}&-D0uyݎz>>U -73ັ4XR9p0YPD7Lܘ-�M7'$7D s5A+'_QsuUm g?b*eV[tAH!m";g^ N*Uw@~.!$u\3pdPoǭ t?1h8H5cw6=RH* Jpxy`Sr^z݈nCޯe??͘^%wM)[o{_&,,?%>6rt/?1Fz4 VR -D>=UkF8H8<(/"6TL}a8`R<۟O(@8OG\QY!C Ps)AexZP00˨>zn²Z6f}Ͳ3*en⡆8NLw*,lž=uKqg ¬"A鲅!lyBaO_Ρ8\Ղm)AԺTt#hBщ'"Ƨj.@A %DT0!pvH_u.eJkT@/*n)B$H$g Z|hG3p`|qB,UCnΖ'l 2$\9wkU�/@+N颜DL) !R=ΉLcHuzGɎLD"`1l$ ;>G(&q4)B/r;+/.yYIl-i1gl@z"*!KVƛb`|)0,mX8ﳜRMc \g?OQ3Of3Ӛ7rE4)立aI Unx]vT5x B+d"/g&-a?Ao~H=x(%+/CM6`Ną1+X\W<BFw6VاM#her Xr* We;q>8WaA0JI[Xj=a_>DH4ΰR V\ 3!1!@GǗݹx w63 tô=ȱJ9'WrM<;r֨kmq~!ݭÆ�!g RvG4{% mT �Ǵ{a [a!\D4 -vtp玣f(0;Qo`ȼc>Y® -�'mJ70HGn[:, y[){a뱒fVA؂O@9??0OC!fbM &AQb# r])a퇢J2'�drh4'Pd2_()HRUq1%n-m[v޻Aa=C~7 !1l)d$اn_cFD#Ω]V*9r9ǥ~i5 -MZѠ"W'f\ꎒyzE {b'#6zDZ#m${D~WyD@r`8݉*qɟxrYSXG.f^V_xU94;>(t:HcK֓ -4$&TE2wc ma;niAîjfVTq*yـ|9�zް�kxHF?'J07~En~8 z�2(:+ |շ atj6@0jm} +Zff;XvB.Q=hcM<%h\4.S`t 04p?c'R?1<G_L*BM]i=�y;_ -4]J%vOrM4W_AX�~ѭ~ޕEv@ۅ6 glq3H2S䷡oqW y]*("ܫ&SןnNhkb> VFqr^\!.1hn��n^h]2{D5ox2v(c@vS:ynYEHL?O|gz?M^1ԗedü|Prn8hj+< 9#KWhʴ(Dmr9 m`a֑/Bvd{ +U/qT(("ƐVt"$hSFlE/?^s~J-͇ )566wsäcߌԁ44ѿ3zIU4Co?',3^ݍ̽'1uTj -)Q0::ߺDlj彎۹�R{wmbi4_\G[~_߼.Hk .Mٯ8zR߀t'fA%pduuNsp.]qCV8>zKToW!Y[ȼbZ@1sպ}r�&�i)kT}qtdv� ި1Gt*Ǽ]\Oc4�~�$z>|E#&i@X՚ -Y1o={Dv@fNv]w NUi94=#g15fuj6Z(UFZ}s*8sEۤMF𴶞^j̀AO$8hGff�ۚHZ&?ܺt[Ͳi0֚lμQ\9E9uI%U`I{8)k(Tn"KLVd@%! $#Wp~<|% ^eLGқKsa+t:#ߺ? BWDc. -jFK% J2;{;'wT||jKey*5bo!쏄<+Ͽ6% 'ԗ -g=P4 ! q!D=k'7+<f7?ǿ#d1<kɏO}wo>_>Տ<ϿBz9᫣}!p/Qس]$t!T&/.@[W?B +pH;x!l3םI�v&KCM3U4:g Zb?V`zN/rA-D=x]v @}_39Pw.IxWx9G k7 -IR+ǣ_(IE=k7�r}m~3Љ7ë1o_~>=/x_>[X ? -H7t?;#[Q_nhmXqI3W;%oz.v{4V^Jvc& 0 I3,,"-7ƛJt {WU^Qi׵3jnWLr@>ռʝit<짮W Q E(җ'h<u1SgG?.݈?'y6.?wntq`߹}-8~~oV7{y; κin}6~' w_=;g-~%~|ʳ?#!f ӹwoqnO?ڽ{B[HyǑZo@4f4:,o)8k4U^-m>AGN \Aߜ3rˁх_x<tSRMmN\y%q'(S/8 ɺ昫Nxc<L51WmW5 Jv.&y?~(w-GA>o,_?mqO֎1T9xո\n2kI@d-~]eތ5xm 6|};u#)蠓%aӭ?ÃZA^tww+7/ �8 -E87n /+-/O:wg[.;C|/iu!\, `q: Yuߖ i)oXh;5<qlip~Xc bCOgq㋋N;'FFud6V6W}(oXN0t9dn1Sa̯˶5u?v3t=<ʦ&hUg螼μk@ThQJTփ8)uQ0*NBxz.Y)~ȟ1l\|C荧.fv -Xd�ǵ Ǻ -րI�՛0OoMӐ? o:g@q37Fej`sꐹEƭF{GOi#uh~~dPWUJ!ʰt6z_*|&FM} oT'DBykt8q87jrP9QNxeNם�m#t-芢o$rhmN(Q YF!O FVqC ti/p0~zI<I1B΂ X~o6pW@Pd0p2DgFOש_ \_s†>eJ`skVnn .fK[h -jv9h<pjBd5dpd9ysjc2;77NJKOd?w7`T�ܼU~`Y[ܑ[&?$@fwMie4wwmׯp]L ׷:Rg6D'y6ߑip:�'g(#={@U2w -.`o20*A F}@>*jX #lH"_1(vLGX{WqW3t !Vp$Ms#rƅЂPC&y5tjZ -Sb c -ЮoFB*HCd!dxLc~ crǷM(Ktq*?b5,gS}eIp YAk�SZyWcK<Dq hц/>漷d:h:sŇHt#[ֵ4(@!'1UN3ygoD:Nqd&4cٲyM!AxvA6I ,gLX 弳k}Gwks -N6o̢fH Rs=F/3(nD;4InK63QK;t5A]qᕰi?nO`|@TM;q }!ϲ,c;.KG6xAEn20%s(:;I3yEd9ٌ$;; /L tgKLM|_(xQ9v)ԓ]!rXhȅ[6�x޼ӈ?ݽ/$^c>=(X&͊ ȳBy;0o9}/H ӎ< _+^ZbP2,y!]v!xkjld;4%<Jn3yb8bi_Pn)˩o}:VtziO.7߯*M"ӔV0nA'~7P :/wn/V!!BޱR\h�> DZl$3UI{n.9n\<MN* eAc ipIӧc/_"}( - 2bN.~IG.}3ݨ;_u+}OeT{DݯFÿo|Fc?~;jQ:D65)UOC3n7&槟R9;L׳;wC'WhEK<}_5^gMJ?w6pV7v.êFz&j^%QFNz,G~q3K64qy7�ٕ?QMn_\P-jvѿwO7?2Qf.[c+ 2皼{ w(M&<=KS7#BPUgw|^(=T7'h|ҬJaZb|6 -jb}Wq8rZR;mx3oz\- XG}E`.+I'<,Wm)r{ -#UǕ۷!{يI@FMm_V_"!D7ZP 4Oo>z䡗c~GQ$?74ҝɐg=>=(:orU楟 ;嗷7~ӆn]#e3}^`P"<Ba bF*ՇvQA(<'g}> z mLg+<[A�~kDIn  -x.\jHJET8}eŢQ^E%l4 Io? XR'8PjEo< Bw\H[||-gkƮ4AV(65kvd{Wlql5(!ޑUGD(t8/AaȊa6Rz! R FQ|h -Z Jw/X^>ݔgNݼ*mCD#cF ]ͯ?$HM'M&CcD B b˰auOC6yfLٷb[*"}9||TT !=GhF:z|%V(jfTjמ<+K3h:?GJƶKg'.(QMpݰWX+?X {fQ|Av&uY -ҞDc5v- -Bq|[.Kw?u?y?ܡ7&|pKq r&@u.�0\K�}A%Yܰ9jGg0'_Z;}i8|?X?☂ - �3FvP__G{[]B*'Tpo;Q ֟׫Mc?ٍnAop#ٸX{ޖsO܌lQ?q`>jzڡXgB%9yr S7uL^>i>(l!mpTFЕ �g ֎p7�Rl9>c &tw  &3}WF$p<nL *ӘBT9 6~O5~Ƙ(M7<cfHLF]wpٰ6bHBbQXX [Wl=_ݸ-] b�BQGtBPdF�ܰq% jY[v 5v<yWx#a^"m|~&$Ca Yۧ8EFw9W8dWtQъyPH(/wEZiD_`:.8CE!*<z2OVhF Y -zGI;#3f?ݽgIY'٘9Lm"ΞefFԴ=e?g@4"5n : iw �4e#R WӤJ{�uMP3W-ݡHZ;_#wkp9];# ω Ё6in@#2 <l0eGDzL~Q6y5mȠh"naX RlM xwS//:)<惭!P0G5ʃkk&rP6$(i6mhR=aP!Q$'~=7E_> FcSA`ľ 61h[ Aq@Kih�+cz[u93vB`賨`~2]ϹgQ�3蠌Jߝe=:d4?Z,('tYd/ pm)Bw*$?> Gtp (ŮF P1 P=?% #, 7 AʹN:Vy3Ҫ[t -m/i3Ul+|n(5 jB -n}GB?Gx>~ eH = nIs'Hw0*ԃ3ԡjQB'F:`pPBou/!b:cw 1 uB6UhD`@a ذņΔ^<h&@zQ,"N t<FS2([ fB ˪z T͞re`xຈ~B<EPQOL@ yA"_ svеD43z"PI88m+^yRz VLyFFQr:"&?mr=D -R$h[r˞SOA -o}Få! ҩ?]kQ紌dft8V�Zĝe4hq^y)~hHW Yd3�u}a: +֊χ?a||7ZdZ,B{ifhU87 %jx> G;+ȿPGFC գ |v&b-K6q"ls@KbF{ό%җOep� tY#KŁd|3X$ գdD`X\ǒ 3˓^.ba D L.�O PQ@݋VJeE{KdE'lƨf^kb1lǎ&Fc`id*tectӦ7iFF[ ].*|DVicʴhX29hek:g\N=H-Z/5Ϻ:.פ^γʽM;13ȧQl||,ݙ¦A싍>}d ;B#֥;ZQ)t3c\'c _񄶽3Z8C Y%"ٗ -Cs/K"HY7uOW`lgd#_0FF K~?NX.:qE[Ұ(ͼKg~?{lɓ ].Iw+!SА[˥0|n+ ͠,Ȉ;_ú4 -HŐypq> JU^J8KyړF j<Lq4h Al'uR,Ptm.s8-ǠLj7-:Р݊`Jt|6!nqX]atRGsn~B {O#2*JbV_�er1Sq>>}`V7; Π3 GeF<\>"nK O -_f!׌,(k!otxM(ڹ;)MťQ\> 53l^E8˻ -dTJPMM\SqA'_%)TLof8$ %%}0=}uy -eTQAܐ3rV@][.IDΏf=}lLQ.Qh74㺴_4XfuJMrL ls:벮icե2YVq{)K8Up*+ȤN0?Lp]' (4'D*#^s-Ķ dn[e3E0?8!D4bZf8/)I H<8:PD 'oɒ)b&Y ױy#x *r $"z@ $�Wm1]Ng{0<_;K,r9iKV-VX(Q12,<O$KUqPaQcwLóauҺ \@`Xt}F"!6f*Bd:{Qf/hE4]6񤌎|H2WhKdg&eVӵz lVs.[d+ޗ&ӤO$ea. \[izq,̬*tlvKuB{Qe;�.?DO( ]Bj-X:ϚNҘ ʁr&yi]5PG,b %Mg=,է=*^x~ 9xT`Rb(bFjr',V7$R}=#" tx4B U.D<E/l\i"&hs)$6\LtUۥSOӊ'v@yT\8{4$< L5oXN8Eܳp s%#Bh.U)p(fA~jjG�[]'EB~ᆀJlWh5eǜ꒰m'l+b{[YdSF˿Lt@GݖLJ*׹鳼#ƢPJ"Œ&Hc&}pC!4ޫԠFͷ skD!A^ʡmaRU*_#?~jA.T8bL#6٥1_L?^}}oAE5gstdr& ~X.,˴geO Ǔ im1ʋ?t"ٽmhgG0G&;.@d=(pd{Mw;MУ&C((OXŶs#t)o<qWzwt}F8"�ؓKTjA~gA~E^½hĐZ鰮?aMF<Q,j׃ *"s0t@AN3�ut\sXwC>B _( SLu.jس=D&Aw׶G]FG5 Kd;N]9g -=<=m!L~eRW+vhBFqGPnA5^M< -e1LJCBtG+f^ȑpuUՂ &K \Q.)V";o2u\`I^6B AvJ7E!&.Y7qQ΅zi0QeXؒTpHUJ{wkuaOMq3 -vdꚝa;)Dz/h[jUBQn{u&ߏh@fg!dFuXl,WNb#G!6+u9[}lYAM c'g1{@rxPs=S(12X,!1:PhSr p5P0#G}[0FFWUÛ;J`B&l@yAkQ*8(ɫCol`C$HԷBIa&W`:.jgOS]~a}?b8$ vUG][ -BP -e* MDڷT%N -|(%Fq - f adJG! ;8"  -l j`"oy{bkE|ҨvljγGq)had*1<49_XE #<YD&ۗW2Ɗkzqp8&jtn.X4<~jn``ʠc]oF  wD/lq.fٓcOT{>$! +̔ck]d`L \չz6cv"kiI8͵՛!~8X zzC rnu*R�(՟}p/ݹ(om$̮mC:R-y3TA[a<=lD%ydd.Cv]S |ƙOYxʉ3]z7C]^Ba+x\خs(9 V!�W dIc]1b6%۠fAP` qXLwB3xlh�؈u2aVD%0<$2PJ9Mf!( jF@"\r H8G1T}2wk\ gP2 D}_;Q :?y7ī[&:bE\q,Ȟ ڡ̎]dk5؂B欙BP^Hӕ wZMr K~"El^%ө9 Pn`:DZjub]M,$e~St;`7\ uW} Z>U(%'M}<eM+r[R;;z"�Q 15aeB\Ns8ݔ9O׽KEnG{͛!,^�a!V -Jֶf'ֶ\nIV-{G -ѲNk$a'd$�@%HJHBGfHxIañ6HFWʺk N,H&Ԧf7TO~*& HRU`ֲR58*ʮ$Zm - &GշMt% , ;QÞg -htyȀj3VGH-NW$(RzY!g_ץ4ȝ9zK^FԻufdAuu& I4̛!WrtN-1ݨTX"t*wWu&3bhޤrPXS]JVI G{zXotO@L$X5<ds'VldRT_.UNO$P -x$k,MDXN0# -T؂hYG3e[`܃ - nAJ-/WŪCLcU}nDAhsh_OhNk_1�A|WJįꎐ"/b݁0PyAƭjKqr4w~̲w >u :2 =)C),L!0j`<ݣ'`,%L &>>S-%s / rl!}HJ&3 xF4XK5.gԂnZ* dKr^P:G,p]z -ieŮQ4MvK=uq+1<rUnATGH)׍fHWpZ{զX)00MEo>Tku抮-FHMq{ \cڏzmι2myV@wQ�4 -^G7 U ^Mh/]AX$g .掣]Q>`g�.AJVb㘼L48(HӨ@­zLNKXYDd9y�b]IqgD>D@ Pl܌\EηKcmm.C9kexR+<-3Ęr.oQX:*Efs;g^uɨksfDȐdb"t9U 1zv߼Xрkt�4TqG k"}EFg�DetarY:#F`f*~S?h/B[LMB2[#v{vtV@SS"}bPv֠L?QԆy5. 1 MI$qNtG>fw�ܒi=CP6ӟ@FH4QS)2=Xgdw??= G0gtdcf8TiտiQ2�d'qմ伄56芾Kho3L;T,3ǭx\2Cf>{TҹL8 j pK ;6 -XFW K/O4V [k1h9uSz-uyl;)nG ZȊR3�MmDZpW+cqFInG暍2G3*#X ^. ߿X@+2$hn *w=f3B^}~(Q€:Ka*m<R$Krv#O:0rfc}.j'Jx-l((̙`YR^#AX//[;NKKɏW{zôOXnϵC:,;^-!ol\?8p'Ah:RGsXƉDOEN#k$Qd�G]HgnP=+ 6H_T^@>۰P6ъb07Ajo,\u mOhG/<oNlF:}nP(@. |Ao#߂m(q+<fW˛]M; @+>֕VN)L}O�MŭVaG +#$ -=m(ubHځ+@ mN@>T7ʜBCQgՍea7?( 3~19q*NZ:ty P_VL~ID]?vBچHC7O/`+a(s}ۚ> @oC}dL[Ii*-U -} - ҄D\v~q~a- "-`*0/:_2Lđ17EEbm;|(bB\tPN<jn+<H=5%WvN (ׂ2 -@: ̄jBFeXL+V]xe^Ӈ[~kh\\aTr]A8{[iF${&=p * yn(03X X 4&6h}] 4<:]H7l6ZU +g92hnB#+0% lWҿ-(5z]IO$tBPjFsY oB8g@S kFQz11O Q㌐-E -8ʔ$HEI#RM"h],�ՅEL{n+؃ VFw q։�L|hb5$d<< BQZ]u~ R!n.O,1B|bLoX~T O(?N6|uRy6k@_KuP|ϑr{b!B ztB4®궟R[%�&KъDS Z"j$vo1v7 / --^!y,t=0R+aB^g -$EhpeECTX@wL2eAb(GYN+TifL�i, ӵ;}Ư/r*<F`$ށ2*:fy1WrDz 0 wfs2! AgԦ)sAQW {D\xv,p8>)ze"66X;Jȝ&J%;35jtL{EKAw^1.H$zPyǑ(ЎbT%eo6 -]dO/L0,3qr5@ z~bS_Nu0,YGN,w=T57y{=eGDikXA'pfn*Тnx߈hlT"٣5jrL3>S3wtwt�ZJaui fJNW mU]Ix4<Ẋ -V$Lo uK"II RZxNޱ`@' 1vpPa $ׂ}ek*oT<%4 _5ij&_ec�*0Vx;/tYS0Y$p#ޡ=$Jv)6tr*vq jE[^M՘'k)rf7A)沒ǦEF-p mq,fv.T7AVN# 24ze1~Q排EKy~j7F -KL'M<~!9$9-i,c^(huU~ [0\}f6>z%7b3U#AL$5u#[>;Yrp<ܓr" H~L*>eNܤq#D?ir4y8Zs_{_@< bJ#\T{mv@+7�\FӒ8D -]0z v}GWZ[$84cn/C2 "f$F  -PM6clJJ3z]UN]ϿVPz<>g N -x\L˂Ej~ #OǙDP:jFΌ˖hG�fYx1>GXO -K@63q%ʲGn= <m#D {-K}KzP?\3Xms  s47h00!o i]װ�alw1D/Q7�n/TٕpW0v(6q6W�.Oau3FUV~eJVzEyuNWkZfp4+IST$70nsDx .k>]5b7GW42vJC 6ݯchvi\Oq,寧Nu&b\*Sci'>L߾TF(!� EiHljӠpELw;tuUqԁ/�ߠ_{qݎ1$;:\7�`_|T]Y$aiv?f/&iO@#d8`$U41x|? 2vfl{r}h’ŒTrɽ1+YkYF78 dQF}XJoC_G2ĸPi֊"4pwV-4GpOk@u6mJ_P0ݍYn[ ǫqМ"R1砭�-FA9Jq۸C6`!I=֗? T[HaSh)Nq͕Lt%^(Jm~ i)qo:;젺*)EcNzRC4pTP;GAӕ muX`,DDS dB,.,SngGiQ Ԃ^E Y,rưkoN.h0?M�# KϏT؊CN>9lKYr9fBa t\Ӥpc3Y\O' 04""烦;lC¯4{bT-&$Z]PעE4ڟc� -12cҜCr wWvphūvgnpj#  hc|Q%@r*mYEo)P>Cz(*8gbLݴh~:CsW><h4pLw*:UCZ`X b+{H]p9 xDKX\p bE[7\h D`GacL)m�=mO%9tt E#Z(鐎%bD顧 Z !o@:hj;u :H`(f@NGhntgOXJ#J2 -dʎ;|̹ܐŅ3ouj|$ѹ zo7GaAOf灞YMA6tSP�RÔ܏�m C.:B.e0 %71@H2; %^s|  ޠ(h3ALW23RߍK -Z2njKB4uTLG< -&d82E[ z?i\{BudeM7[rfvz_nQ.L# eϕc<(2S˱L}ژXsׂ"=5'5h"u ^0SvEW+du) n2GJvwJɨqwEk>h3t7[3$=)Sm.EA5iipm4S8AARљrdҟBš0TA}.j%Eq!9$ObҬ~R4 pz%9(y>K8i\;d\dh%!/⓼^i|e_/8'R_ВEƵ]3<ZطLLW7 0',Ȃ&<A@CBPI3G=: -p4<:/>CZ] 3(As&c̛ GЖ?+c`�=紏ѽ4 = j_C[轢*8OuYY]<9|V]L' ->O. -nWWV\w]m-* +1vl!_j0;v*7J@@|5 Btڭ=EoUE AJ:{XJ둇rWl0_u3d‘)?ոd),l_hU_OudGfS7N8=p,tBVLj}V62 ~eU3j)5E RĻ(KPqXJ(2*l2j"<z6"CK.Z%=LwmSYLo0w|~Jxե -Bg:AP050B~A5W# p $ƅr<=xt40\�tp>) 3~rXR@&(Ȗr+@-k (]~WSşX9 -/pV5vT]F+Κ X>&Ր!"<[ .Pks24O4f\0taL`C ncЀʟ�i&[8�\ \sݺ:`y?be M(S6-Q%F.w47R -Q3<D!w\Ka,1ma v�<Oǰߩu-s]DLkwѦQ�+> ":,D`>DuL? &y|y.qiT bNiN J0wiIV* b)4e `TBh mMwcJSL_G۟"a#-Wb&+)%Hm4uc%3n r{2_5pϛse !/<tR\ P2ԏPln&>nK 6~~T(.&_<8/nh\џMڤGa = ɥU@6SW%xa/惴ެPw$va[f pJBdZ?7`IiN=kJpN@:>4g he&< 0e6jl9 (tChMM.XidSMv%<j1p^'NÀL!q.(A?vk9h\㕦^%2qn ܟtnvLq6zdm݌g\nͥ䏧 ;mK#к| -r 6BJXN%$I8hKMi lT@ Z$0j3X MK@cWIPqSg^MMݜ jdǓ@q|3 -/YGyLr>a8@f 0~1?9`yA~E'^v37Kp$&q`BF<@OEܽVfHoqIBRN - $/@xHQ'7X(yXRA m W7cB[@}6 ,:i>ƸE[y8_ 5OdsaZ~*BB$`v3 F#>3[nD[Ӈ2?6}w?6#ԆlQi:03VL�Y%`f&^eCN 7@p'7O5<f+p_Q).7{OA4vo\HΘM?~L<qP՝ViT^5> M_co'UcL؈z6Bd>hK6xNT¼MҸFwˣQ8N[~ o\~ g?E{IW±hVM1ߟ픫HmFå,R+kԷ=tN"4؁}=qřsf$ 'Wߢ0F$Ӄ0sIE7 * >~q"߱ݦ%c sWj͘MDO)8a)Nɉ}6]n&.uŤԂOURmھ#N.Fs2͏#0u< y릚T 4uySl*A9PT'ӑVyTxüc`#/Qh -?" -:IX60D=�4;L&W4*iFZ,iMW'=Gu(`>~In;Kz5q |<Y#-x۠yDdtY|/n6b @Mnv!eţϐRj4T|w, b(6B66i D?͠ hs~Gc vT$܃?@DQէC׋{v {0S¹L~E%_o uQz -ɕ B[r5`(`ʦ E^xp0U&t?#OMP*xH;]Fgđ((dQ}$]i+},,/֛".}hT׀Ȝd'gTqd| 48C^o_N _sfab@C澕S’ j,ʼn@a5;E盒ht{ bxO0K}b|ݏy=`尺f,nڈi=j8+&C΅1'd:pdyX yrP#7[|t˱Cÿ6eB:[Œp O͌# Cȱ_E;LT:_/+@ �A>ZNÓCɮ%[oOCA I%rҚQDs}SMu 5OlՊA5Ce 4Pl ,ͤ@c '.�CB;<q+6\?V0r ozV>�-Q5 ASQ"qc0KOQJak +ۉeK0+F&^C)Bb6 v'(8f=8βV)j~R JW;HG< -Ya >9p Ouӳbu1>![B| 60\#in -Gp@|޷iSüJԹX -ra];CϪ4d:uۙfH%JES,4wƐǩͽωHluC8ys$th~`Jq%ɰ -fmqx4AB#('b�#I.chfm�\-I=*e[2eZ/pӹ#Ƌ(rh+Ka*xZھ:d0r&|/ӈ0}5B_%6~va:-;� 帟c - -W$x!Y2\ - JPu<.֎zU[+tIO -Lta@zܸ&h87)CPyX21SDuԭ 蔴y_^@su74KRu; ڔPaE*:f<#kdvSv䳝$V�h6r\|!y8/: T<iw=~? >"Nڣgd?b uc"�| ٞahO=MC11/v tnF[(?5ADHPE!$!t;3ᖿ -n(H$^cM;2# g>LcOUtS@ -"ă:5-Z"vA޳|{B�]qSrMmw-/tlewKOtu(_C?7`w;lv7e 32 y\66WejE"cfyb6MIN3 Jp5p`9|AZDr}Rt2gBFe~78 P(qwmA#L2fk>ܴ !q:`/$#S>Y_ҮM|jv*hgDhAV[ :I^E {Nan~0A[4$<MJLSܩJf(_VTy۩* -Ng -$=!svYLUj?!Aa6ԏ[7!xfE?_K3@F1ٽIj^?8C -3ЎI<S ̖r|'ʸ#%r1f`[҉D�t/uP|҅]Eɀ׫.|F - -Iв rq?vd -\W.qdV -LrE#^iL<z&O}9t3syuk`A:BളvrL W'Κ?XQ盳y`-.k:_9QD;f/CV*5®]mgy%рjñԀdU(M+{y3YjWHXЩJLuhPN&GIoD -egs`qh܉@h]:;ݽ<&ѷ1F -0tI'Ѻы¦wAkQss�rhd8t#Z#\B5K:D l077",TSVPsFJWmCIps{Y5mvmt@?� - s8Bk`-hJn@uz �r΁Rl;@~ K7b͡bqH}1 -Q070ٝ:�z"BsIyǝz3{zp`EW)-lՀ92m[Y=@K$a&]b$˚'gk7wd+͘)P])Nӓ,5q? ^cE$chHnj )&ؙJhSPLcFR< l\suX d#�},t|b ml_wg6'ʲ 1 zt -`b|7%<16'-̸5�S/R 67 -endstream endobj 2367 0 obj <</Length 40621>>stream -q@| -F�n& MKf(AQ`CZi;ۍL?+4xcU|Ӊ@0N C TO9 -%[V8),b$h6,aOK&JÖA4,u71h= 7~n6X<&p69;clt D?m\mzra@K0uP"f=N̦iZ3ˑzS(0J\֦a9'0\g~tVh*Kai)fma(&pxS4%z<fy J-T -Q˝5ROO2S$?"ˏJmBi+ WjP2RVҮlTp2�ܧD1`z! PaלPd"e=EheNξ .ƀ6դ(ʻf $$+O_M8,R|fBIgv,ݣ\luYM,�yƘJ3 m:XD>R3QTA ͭ.oHH -*]=6g'U�Qw4eZ]G;΋k}mM  z$_=)6 96k7wh: X0 $ a;9�(&sHP&?'٭L�eE.-c lHAqtM`QxD8P=,`(U3tqߛ"3rOE479A&xp -@ɜ=/bѦh"*ﮠ Vcds͑RŘeHm'VLC1x(NYH>D/I xo^&ůbtΦf hl'b3ۄ)kLH3enb'2W;bbݗ1m)xKCwE&X0ڰ'oe2xlcs7 /xo:u@"9)!3`4Ԁ1>~pӬ]ÑkNu-}VDcPQs -Z|UO*C#\.-]0j.\֠"6O&Bip@LFü0e%LxDFʌh>̀<a`* P[6@wY(g%f -v@;�,џ}`Ak5#hT1k2-u4 G L 3YDTyM')I -2 -Y5<nuH5]76_;܅$m>"0h/hmX削avgLNakM8+pZ9 J88.d B\/NR�O2 5< }C]TNVuЃ|Ϻs^GטptD04G1Ț\NiG( cg }ԔH;EMՇv@g!Hѻ`F7$ %I88.L}NĐۊ;R x98HY&C{gM}zldҰ�]KAv�x\# F;^"W9@`DCHT6d7E -@WI%|;۝PR}YEE |` iCL#zteL'+sa � f6BX.{GSYK'm:"8Anq2tw/[Îݕ30I�lL6lM:2N,h: Gt8ۿ͂8%~bDjah%<zrkS!cߤ>ucr64Ф`XdWCCx71LFv d CaTVT{P"d�C\Z!mz2HEi릤i<wj0ָ[LK枃�4r δ͔NB b$[6' zv'ޭGk �6#b=0!=mW}XgVp�Wb+R)jr-)?гg! 8ВB>${I'8hl{ @7-.1z@Zoko{*(Qb? |3Ӆqj<`AԙDƢM:o<G!X Pϣ,hU/# !dAC"Ʒ[*Ǽ_H -=kѺmfnRf/$"LA Xȩ587j'=2iyrw..|yZh=Gdlt}bI8btj0nKFH]4u΋{.Y >JvVWe*< -]`rm v -;VP8ߜۨ㇛נHOgerY $B]@ڝtK SqĽ[8Btփ\ ʓ9t(PvHG}O[hG!-b&Fɉz;$o`ylHjwǣ6D?\ޑ6ũ9 À'(E3Auj 9Ozh c -[|!t{o*)LJ.s @Q wp>(`]FC@'{P}Q"J:2yPUڒ nFh�Ȇb; ָYzuR7'�[m&oi\DN_R z4<'dV> 7U2Hz6 qOnKgnvk1P^<jy|c۱JBzY~6hQike-ot%M/t -b-s%%oE8 t%;uM}3AFܹ^eW} -{9LMTpk$w4V+@GEFĴ+̀Z?uQoyN(:ґ"'Պ^Bv+V@^v\>Pơv CcJ\Ux˨Njc dN6 *:7?2x SUPّT d-}r iWc+5慅Ya#x?,e'IF?cPI)ѧ>gWcwWu%l'LL`)Hu -'P=e=h[KO >N"m:/Zˬ\[2nvcȏEFX$uUb55m585yQNTyivKFZLMN"<@-@feDD@Toe)iQm's>鋔ͲF Q~\g]D/E+GI͈Q*p?ɺ&N#}vRBrYkIWm\ j䠔P,yQG)83H3۳hK dƂv*\iiY(cEd$nV9Fi: -x7i}lEk$\*@8a$0[f:%t>y6FߘFųl:N! =I6zNͱƳp[dyrѧ=/ \�,|{iu*3L) -XצNEH~R4&>$W[H`}l#]sёHjv@pI'n onhoFtѓХ?ݨI$l`L'yo2yTGh.,,2-=|T(L4؊#].* e1;QF{eMlP$h(BөBN(q u{B '/#NFKҬx}g-i6DNhq`kB {*օ[$HB:zW]nv<CJ)x#k<<Fj Ư;ȸV<| OfÊC2j<6]㨷%Ë\l1\q#nUEh<lBauz^f{e\ςMLlD c20^Hxt.'԰v1E.R4-?l_L4b_ۍhWqom"[HhG,No]@x3aHZa ]hMVڲaٷ>S-_C5�D~l7mcو+]F|+EA!'|XĸkDZ--\Eάaya2;^#eG R10+W.EQC9a R^! -b-O^ ĤNp!7 -&FbDs->OC˪1]lEڝ!bۛ8 -HCɀΩs7 r~#y/XCu-fӵHP7C-&w=Q2΋Fu>,iqcOWCpL#,i?fdMq$ -ݼ@ X#E)h *^>ܴl&9Z?C� -h'<}γܗb(]M\$jWC9!"!t­sWH&'ʣ棻…cU:0)Bfh4`ij,nn njpٯK@^m:xg(QzԼAc[RCS,Jʶg< m#]F+*-OPt[f2WZ GnBpTvPlӞWwP@"c7,vג`E4*ij@642`|0v/ 3nrЖyQ9&bD'軚rv_0ݜ+: `j9!6 [i9-G֩6V7ƎsN7D ܳ,"(,e!` -Y]^o̗ލO'�W -j "AzwuzI \ ]&~jdEc0`j4A@mSHVYQwLuptZ ӾS BcG { ' _jC:_ '6p?u"]wC nяx8V+kF<zX< L>7;B lWEA6> 鱧0#@@v׿sb%J}i4@_|-8&T36&@OW;&rZsޡO-B5RULǃd]uG,&pf/)E�;<yeP6K8+ǏλX+/3GN=/ 5f''R("]g~F-giAy2XD-t0?mFo&�%pK6 ?5 xA;(Z&̓aK!I;A?_`p"SX pu'Z#糣\+54Z! r@wq˂҉X,TX Ԏ"I ±s' - cP:Q)60r+A_$LZիޔԬfAW|D�^D%Cp])0ςY{C( 4FlEu+K -5 LKg=<0&r�HnmJ4beZYtkІ|mะ-r L![ 1`ϐ 8^<HrY<;꽾 RI \AP#led}pc`,t ;d\>ֻRg!OKFalN0R%.zmZsPx΀1\1.ҢgY.y�I�HoհjbdeVFp0(ʆ}u?n~oDTsUV!2X|Im/V\^WjJj]{+]^ ?_ Qڊ ]l(8|{S|j!}@ىC+4礝@Smo.|z}Nuc^nOC\9>\nix)=,4U*16r l/w{`=1j>(f*y 7UB$!> p O �OTrB%=_RojϏ{w+Q> @h )f:lV7ПɍKxTӨ}ӛRpZ^EQKׇD^Mji(zTM(?tz;LS\#cr YfU]D >զLjI]ßGy}¢oqQz$R6D&{nb,qg=�E6lSrD{9Xgӑ]S<^J([Ƹ&aC{YsQs/~L p\JB<4huϸaEdh^_ub_,<ѭǟgҝ ZeQkkG|}De~D?iKذL|,nm�W@@-״hCF:ϋ8]nh)hftsp>Aj?Z o̫uu\V:SO -ϳXnaE|0~d+Rm'rE.t},UWYU iQz돭sd5SAmK6_y2׼ Y/qU-XeE veW!j+3㹿ն_!B;u&6((BѲV9y#^~_%{I<FMxP!l,"<7Qc; ]qjӨX;|T-bl5A/b Ux|cni~ljǤp#9D?>D95-ljCDlz:"hԉk+3R)"gkZKQ]#zGM`d_̨XxV@O.{sQYڒIc/K</b+(CZ<*Ty([op#]S8,bE<iy4`(XAI8I#{iLjH^HV jo_+ -p!W sՕQUe,Thn6 y69gwU5*-kK dQq 9c;5ݜ+ݥ˹:~P#OCLl`=gZ=O*q5=y߃9)n!'6A&ed&VLMQA<p5=h^kef)C+1^"ecr -voZ㳮aLn~5X糲Y5Vc5Xs@&rjv:f~ g LXEO_0[9G j&# ؿ3cW)UPǐcǯ;%("^ eS<$1~F(“|l Q -4p=oxUDV UEq#WE33z=)sQ]�W;k~xMsl}G?pW inщxzե #2U CHp}s|E }h6 -!+l8/�XR4n(t 'ׇ|G|8vVnH-nD!% JXckUL$.v"py�_^j X9M*.B ds}{)XUF>x]kd:yﴀޭo1!?/Ni_m2Q\s?0GW]Mz-֓:1w,jC0ro,%ZiPNۈZq#jiJoPu95A΀ϋ]눉,1'95*bǽ|%,9C"JNNKIW OVy~`d}bZu/WL!<ZдA~oMڊۦШgt%g,o'rNc0[ m A?"ͤwF6P -IUtw�񼅳! 1i @ UA~V{c"W�9z\9a]_N3o.W= и//C�vn*V-;(j./}c dWF 5j hz{|,]U04EZ/ۂǽ#4Q[AZԤvF6F@]ӊ|1mF 7羥5N=S>Ɛ#n5 - -]t&]'g==;RCl1ҜNS$+xUZ_ 2wAY" WzWU`'2&{I3]P-YqĊGn띧>NS׹\,v򆽽H_k?;_0$w7#؞/t=ŕ^-c]@g шsF<)\*'W]H 6 Ȋ -] Y4}T8ExSN *h@;d\Qp(_1jMwLdk>> x> 2'N⣧ k1, M62t֐uRBPS-!&o3TF{7P0ŠrŨN\D?!2nK߲ -ƒ@r#F)DO5R[N 30URߚySݔ^[G1T'q˺ sNb_ՑWrp+IAF(tLL +^wZ"8yqC0J=W#lyva +'6 KRİf" hX0Q4Ry4Z_e)[ Et1[ S،3]k -W{7.UzQ[Ӆ@ET`M@R_ -@y AJj#5JwO{6Weh/kB H]v - gB٢aԭz)m ;Ef`䱶%I١kj%<y,LkP{ Z)h_10D7tRVݫEe.G|s~Ȑ(x3{P;J;"~'Yj<t. -.Um)w`:F4z%v2w:6k\TLs5 PR.N~y2�Gxf0o& շ29qC暦slΚrؾD<JET+)a@RzRHV*NԆs "hiF ֠9'v[׵6c~f_N! ¨j}z]4~_GQ$/=AO!e[!ܐpO7N|a>f¸Ya<c7`% yί:Qk?p)J.0x!UJ@AA8q³(\Crro5@^"R4N}e&z7 \9MHޚ~Q1h%~˸UԼl)"WqL *&G]'AFƉBDQʼP*X1r<Kjr+,ve8J8sؕ{#{ ! =>(^lR[q8#MK cxiH 700":@r"n%f1t%kéeڈ•hzԗ࿳|`+4r$SJ/ op7|ݳҔ0ﰂ �os:':עVnWQ-xU+= -. 7(DBE@I!2X7${>4l=ź9~Upiֈ2{6/ֈYVf?8G`u `yH݋j߽_G f5jhqfm=. @֝7|]hC vs't`v*yइ:teoSk1vu| - Χ!jX6GuקQ,I!?C7 (cni@;�͓s+RqqVBy"':zS? WY?_v! ] 5,؉jAOho.8qyB.N,uɶ|MU0ǦiY]%mY?h% E*;6k#R.u!F -68%Dʹ}X<"'г>@-{m&D6~iʛ~a0, \x;y>uyl;yE")Z vQOR`_)kHtœFu}➴%mI "-|l?Bܨ+ղGUYߡh2"5J!N0`hJ_57b]X/צpF|93l[&K=Һ4RӬ-ߪv1/?kѬGP&ZWҟiCt#40miiH.η4O$F7t+Û}-}l j)TkK%-bvG"^}{5yi"w0[j:Gq6U x)A)E�  2]EN8fSkeqoHQ#*89mdR}%Áu.e͜#sN&䁨YR:V#:5ۨ3ezv=#+-&#D|{b8+hQ>[s+e x4>!pӿX:~Dl|YݺS۞ABZ8hi,SBy~!qbc5{, �[pL;Vu/P9R[q'9d!rDz֖՚Dɥ\H߯X{Gq {+*0g";CCX -\:3N)~EVoD<+*C V!É}SōZJLΈg'Kxb=Ӑt<ކ^6&q -|BK9w_3Y`xc`ՖOx^f u+YbLT;hCu3k| tIϢ&3UBF}ZloHu@+NNhl}[-`LJ&}$ -/VkD#\j߇1/7<XJIB)Bm_Jtq*$C#??@[9~_eUDsUq;ŠjH|LcRf{[oC[Z~!T[ wO>W -Q3*~ -w"(֩k'LW}9TɇY]m(e6, Hk2s6ԼYNJ}AI5A^9i|Ds' !)g ё;?-sǏxs=Upzݫ|sh&Cy.L !{7`߯Br'Eȹxl;=a8Te90h  cLϮeZlPnCȈ[*g%zeeI#U4cEJچzنgP6W=A\yH;xQ=^[V "Z“!z޿?APY'\Q@�/1Ade,4=YƟg£|Ј]+q[kwp.nqI+m zYRcIh Lh1mgqDt]MӐ -8VxCI^ޮ7̠x Y4COQ ğ0`026[FcU6hQa`Fϒ(.|9GbΞ˝_EQd"F9ΧOSpKU{qr{Dm=Wi\4N|\ ;*Y܆u7SNzA�z:TwXtn z??1Q>ʄ-ʾLG82îZ-vR0$w@ q j+4TD 1=`;#~6ɬ+B;sX=BZe"['y#(Cv2a,G-ʍ~m 9�rR#LfsAM|&WLf-gw?:Fz99 -*1)#[Q{yH1v -e( 1^ 3+̱8*kYxE$(~d_f_uS<dϥz2$O# ee'}G)q i%YM| -EitкA|,?"lV!Cॿ3y+"lޏll̇Ac(|s> *ΊeI^z@*[dDQfB\CpA1XXoC~ő∐?\MoG콂d>g{@zb^VUcJTY8oOcKzjA)wWDV9r'Կ:皜Kr|�^ŃHPP9h%pyUIǥ*3rk950\jGxX a]b 4BD;M<t 6H:PZy^;[:6Y7D0CE(Ϧ+:*ڷ%.>݉<g?=SM\dqlI K_pF4ʃYLPAȶid6{VZZNDÐZc<dJx!zSncTxEqNAgJ5_(Y^yTt=B- A(PADiӋk)p)P93ZȂF@Fgt`;Twr_Cr ٭>?_(@^<9}UGy ub HJ;"zGeğ潊es݀TDSMq%t&`Q@|rܧ2he~B:Y+tfO?ېёq/f!<yG)uW[+yntCOrfemGV* #d14~Ƿme<6]dh“y-/_QGX/2<:ZB -鈤]R'!wh%/G d{QIQve/Dy]g��Q We?#ޏ}U+R%3{8N1Y߶-?>.9~?j+>g?iTj""X"m1#t˙F5BK];, -ʅ̡ؕM`'*N-FxmHeEZ74$u=csC, ,AU*2hQm~(0?GCqhɮ$l:ӁaES]/1s%z3)F)gjϣ*ϥ,ݿ S*L?T ΨuyB!hՋ{*sҟU|&V;gXZO@ !?!mWCD8掰_{ϵ?3 T>XׂȽHǃhn1yZZn IutZT~Zo#>oU̦UJOv3"TQ9N }}}Aj=J軓7]{h8+/܇QI|fG* !Ɖ?�> -b qh,z |RmHUڳ3 !K֎0?=Ð>?kOOV_7bd~IU[e >\V4$ -̄:> -h[ގRҁBF~Ԧ c= ;=< y]>y{_^?d -,В@mves4 -? -dT_:>eFÐxliĜ -wq~u>b!ҽH21}M88?ېy 8߫:;`Gbjզ} G݋MaKޟm x&{f ƶ<~XcO 8oCQ/<~_>ʀ$7WԴR>׏%A|Ġsd/;Cl1|cnڌĦ/&*/, \_uWjQC|S2dh$BIpz([^NZ,XjB`-=D ^uk#~]%d@q+LN&ŀsɯڢ3!>h 1pYbd..BՍ<dJ򢂫֔ДKxD -6ᆁcu^Z{qJv`v\(F#żRT!y^�~|)+I_(e7 a -K&5JuOQ#t�lE?rb4IIlQߏQk,+U8W*=I=Mkz -{ sL i QDJzhA4 w[K\pW#,qb -{d7\rU 9ąU^w.Эm)2zYfv~LOZ_GX;ћqp�OctGFf?νiTπ-K,xf~WZWkdՒ M{ 3o\*q wM-Z!KX]՝h\gT#m|hj >w8s?[-9jr&&a]hҒR_ -_ƁeƒOz䔱mr5`0}5{SS_s,` },)0}mU!m*lmfcL ji˜y:� V>";^њug>b@\=y3!_ -q躾{YUt)* \T -" [C-f}jJب=(4%$W_W:(l ^LZ/>ʴ$vkj' !̫OX&_5ø"Š>uYS7f $y -Roz$i_\g1ƝBbwZF/QQ - - -m 6I{(.QӻPJQHC~g$ Y_5XIQSЎ(A*HOKjKZ>"<%T%hC4f7M�Ne8.Q L"B^)LKBZ㰢J s<xb !/t5aA4*o-ټ| ;Ҙ*r3 _[Vob4, dfo58)\!C n`BxVxԮF dxEAubH50&|Ԫ@ElRH>Ô#1\I{:#" sʉ -_ 5F9/)Imxs\m?"цdVʆq5 -W7lm}),~SyJ+pFcGm !Zjv8aToUe\j#OU -/]Jf |o\1@! -%\j&XK(ھƒA>MO G Xhvɾ_Љ]+�_acw\>ZSߝTOhPڇIu9O^eÿ. -P>Z( unG`Sg+H9$39qE(2 6ȊgU٢5 9[KwSAXqܫ%KƬtC6[|(gUڬLU\Mx; |^U$'p,gՏW>1(-^<%*~7"ڂ0 9"sfqם#I'\z9!e(* :2@GcSY1Y[1uX]|izA?r2笒.Jm62x`o9j?'P!Mȫj/ -1$0cPՒ&+ A -G{s€`6j.Kqx(l%f�?Ṯ\( \BDٵu4JQO*ȎWùC 8+3yYO59̙8 E̩/Ds)i.y&pbyd?M5FE}CXd&8ݚʹ磾`CUȸi&y}c!ŔQ*{HpkIs\kT1%rڠgrY4cf0meO`a{{:Yr D*K &}f`@C`7I@P,}gTsPPzܶp&өFg ^L8H&Y. -ߗWtN\HUNTa\Q6D|12J8S] N׭"I _15ˬ@NjFMC= k_^l zp7H>Z"waBoز+W\/s~ō6zbWlfEKځM:{].}{eH؜\\_;0X!i|-2UK*fI (q޹lH4;"D!Xu蜝d)gjvj ª"S_n IC\_x3b - -% -?qS]Ĝ!L:ɻs? RI:C$!@a@@^AL+iPEKUЭӺXm +t)Х Wy͉2b9I8 ~ = pCsjST-?K97#s00H n%Je6#k!`R /3iMk );O%iH -viTKhIh6 -y>0BajMs>i�"x ,G]FLEKDK=UQ>! fQ&$8FK$\%qָ5=kp}y<`Ԏr0A5Y5*7e |EfMVh'Y#cF@жاa]WM_ԋK>dHTB$H"UG[W#4$h>*}:tF?C QSZMsk](o)Jcu|%ҘՃ8IPV9C)\hChPi[:-iFm-AAT^3\ڬ6G;<qͤ!®tt_h #z*p[nacdQ1P{X>6[|`FAmJb)]?A/4q)BLp$pcAW(0b( -=SA[ 2= -2Nf\|j%Rʻj<WT�aF4kZ?Γ^cZy$c02|9Bg#"jp -}q)�y9 - -{eYY?cf]֐k#I+`|�9}7}T/|Q<{r]('┈?dK;W}}Iv@YbI? -$ϕ- +BlL\g.xNt.1_( .īJZ0miigh._E0vm[Z,XKd̫jP#+;i%(T{Dacogz_hKm=bwp>ͻ=W>['ͯz( -!]) a9ua9pQr-(k Dh$J[:sڔsC�\7 -0%k*77ŽBԣMV%&oK0`f!B/64_ꅔHCR~!^M<c9)퇺]YqUO]${x{:v3Xt+'37k+\=2K N2e8ǼFn~t~<tcR4'xj_ه8ɯ -=D)L<囚+JT9"@]ɻqy՛4!XT뫑nf+R$HQdo0tƴ/U  |ÜgoJ[jG±r<"ݫ$W2YCFW#ZNHK.HeѲS˓~2'̜JӰ3TJU/}J?٠�y@p'N=5E6Q+Cl*M^*VF43cZi&0YܳnL }34hpюh]3l[}c?;DuGm>+iȀ[bPL QuzNQP*r`vi0sXiG)<rκ]n-#"hC$pV3g<c*:n8wTQ6,3Sw`ODٺpfm#A 5!*qeLQ!(I'ramBܧbA=@]t3Owe}:eLmtNml'7LK&%++gD ufо!Lm( W^Uey4a#Bk*Cǘ~2FI<cm帇akgW2 ]MadXƚ!f# yi Ny.b6Z/5P'u첳fR3 ]NE%}Tg.[[v.JmDo1qf$WDsK4nXƈK>%p6H ΨyD9gc!֟ن raoHv~\{%Swu2/qiё^`S_zϱNӉewa:=#rw Yju]QFڷB_j -\@q> U j!Hby=tHj_T\tTjƛFMl7M4"xIRv˰k^`! m\=XpV@O%-[VzcPى0gwwJg@(x{XXG.$1i{iO&*B>9R,;jL'1٩:yO)1.ERJIhp7L}+bA0fk Z@39G,VWfu[}b;xPXt~F66ʄ דL+%|UAw$\~dՉo˘*~Xqӓ H#6c 92NgDL`<ٶa86c=KL|S�+I:0cVR9 -l}lws2{h}X_$$dt錗Nv]\A<̀ݨ#_%\>ɬ2DY jfZYl`#?nn<NRjG=;>N-aN<惄(S4vq:U߷Sswҭ^ -8iDH4f:ڎLNJe.G LX (:Y|¦HQ*n_N2Y1B;Փcq+oY҆ƞ�è2HQcma_;>NI9juiȾizVO/}G$ȃ3|YvVA%#W`v^C?J-,f3Xzwe˥(s)n\6=}9H7U1uxvF.GKa] -�11KTԪrb�2KXm9*Y)Pf'a`P[7dڸDQ.-u䀆n -5Ĥ#^\;O0J-A;{_"31c[%;m$;I\_;{rK3h̉<yiuk"0b!{[QtiMӈKy銡 1$C3Ol Hg,׭T*+ N@Ο�#(RbvXCSiѫ?k$4hiv9ݦה,JK-:3i`D))}ka't։r0]Z+_`%J~s]'eaKF\slh[jH0GCkN!8(]!~ևmZƌ\?=. ;ۑ�dLu -íWiϒSh ]kya. k�ʶ$')d&;J8U]h d)/4s*[.NЄƐq*Bl[ƥb9=TAQZCK0$LƄ،\GRBG�Nowd2CwڒDa0;Πڏ0KgzcѮi iʳɸܣ4i n2Og0S$z% Ț*ӴQ4rNOÌ?w6_X ʴ_:eF7J(SnI?� nM’R`�i߹Q5bye ]Z.YSc-j=G(^iNQ@=^fp)mc=6_rsC *(cc$5w3l1۫8+g3pYyTXM=(KUٗ94c3-*3,XKj[0R@/3/~DL -$M*LV3,'pE~ `21c;z RI0}s<͟qd:2K n4#)ӃBׁP�F$5׆دڗvԸݕZIT;e}A>oK-L8fE| -OMw@ W5c8?0uOx}8ʙdV(Rmc"F]yms}-X=ljolTom~TfbRA)'`!28xC۠}-*$_ʸk]NfeY`*IfG"ywMmQ]6,z&ԱspB -ó(-_rN+)Ӿ}LyFm]m} #jg`zj\ֹmm}^`1̓:\]ߏX=$;ͲYeÀ29OA'7/uXu!Zd8Vf8^Q;v;?]]( Kt?hnnj9zu5U|ջZ/Q]vF@ˤץ)sFބEr9k÷"]{S)װzuX+_fߕЩ+Vs#qsjc^i1'hZc#YVJ:'dKB GW5 -^aZ=.]Brx� bB2<S:[-b -@k" 0` ȘOo|2L٠iWwTmsb4$Ӊf#{> m~/"蚐f(4ID?fVPE:U2Q\1&z22%AlU*al1Bɉs.OsWߜOuۿ^D?2Q=O6BW}?zRՙϣ~8J*4QwQw?_͟?OW`~_o~/~~_qׯ?oyyzd}??k}FHc'}2?wȓ7o%~-Kg_s_/%>K>}~iE7r%/c_Ъg~?WͿO߻?܏~w~g[EG,jfŗͶ32Tx�d#u*AiR;C |Gdm`_Ϳ~ s_?8x{5H\a.ߧ+ۃ&_t -EKɨcc(d0PkH܉±\[QU8K?]Gh[5Q0S2HtZm?߮{-g=)ћ{!CEp# -vDZǗm"M7_7_?3K[վl:MjM;r)k?1ZkFK+^ڨ!Y@%?"Ʉ0o~ۢ0KK=ajԥ'F'jx"n K-}k*e1g,fڏT&$\ ~6c75#2,Z-�h- bÎÙq ] L5-N\)<HX>7l-?ˡS-)u xsQPwAĘX&:Ol/JIxevRУ9 j6jLc [ ;EwܕtmZ -5 ~n Djè|L\Y{^ƚ:0MSL;p \CGIi {׾׾9sg,u mGkh�}1gIq;/ 7LW =^?lq᙮{]̤?M5.@xG0S`~guk1`QϏtbW*Gd+9ñH/7{WVz/M9Xs_ZE <_ބ ͱv' ??X -s+%U5erngtXuOb2֥V)2 ֿ9ަUTax}TI9#GByuocH![<R[$Z -ij?Ø_0E? oCA{)2=ttvlkF}-�>~<r9ߞU4;:<ZנXjdz>A0`8 ;$^]PE֮U } l׷-m+kk_.F"p{(ۨk~0rw;Ch'7X3Mb$A0-O.01W 0=Ӭ[x[ YcbCWg pD�kLѐ=12nW/do '?;AzzJuL* -4B OpEŧ1 ʐ>"!?ɸ!8䴐xn][b#:'z�&m2>\rpfS[CKxK0-GL3?3+5&,T!46C0.% W?b&R556W(<L|rzsYb2 -|QDRK0W?<͇ao>ï{ u<åhE3~u;Êӳl>N`q�).aZ |+l,`% Ƨ|Œ<Uaw=7b(cϞ:iIJ)B< k)^6VڃQE%*D·aG<vyi>(b34 -I%x) Dh U.D!()k[90Z)ߧrwy:DRLy{W5#>[(Lc4zxæ A>nz.~F>}XN|;f ͗^[H0yj?3}?7׶bƧ7-ǎsb5<~2ԍ_OV $VbZVZyթHhO P:) ?eKjDpY1BHL;gm yF`4LEs>P(C&=lW¾J5HN}O /' S"EڋS\%4- 'ͽX*Ímabw5r_?)Hcl0* @/OChZ\hLw:N0\12IkVQ֑sOJQA*SB[Z<|.DpOC<"&駹5F.35BhnJ͗<V>s9 qFi{PB(uHR^42`"8l|X].[1κFUYԵ,줨kg ؟ӹ ^XЁqm iǐX&+@ 8pȨdNs ^](G`4.UQauB}q(}.]{g 7`y$fĂMӈϊQUr,0^,1=-q`U? ?7VC -eN߃mԴւŠ VfR bQVQ,փO�v, #?n 9a^|Z\ HΡ�\3E޹<B} SeISX ՙ!m#:cfn=>CO۟²wf#3}[L(+~>o6_MMޱ5@V?rŠ&GdZZ{sܭ 0Cv&ل 94^JjMv"2WQ2J\j}[an=3S$=2z}Whm뤾Y8AƸv6),@|DpjJpA_Lkː%?,X#q}Ȓ[Ҟۨ^ec媗$xq͜5[S;v=/!;j\,LQܣy޷~ Rt/LJ^tDHz >9LG>iu /#\y"-J5hWh^8KU2Dܶ <siA\[N~AGXeh龺[ޒ٬syVl9 -0J\!(vؾEI1þsrX b˂{8>p Aq|}#4|ҩpFځªQFmL4<5E<d1x$+Ӧ4]FPئoI>]~~|>R 99tFكS8Sٯ{Td@G>!V`+"XrZE<.Q;]|v6'=Pg{@ &Tƅg1&YpWUi~E** z^ 9AXOz8`c4w"G_�-27 lkf%32;[۫ 9DP"X8mbz|(_p mdul²o16_,]sg9S9 7͎ -·Aʍ/|\"19۟Az("Ts:v{xaߺEUA)kI%}&,XlOCƜv%t!ӾD&r)id7MCq.R(U}l[,tƈJZ0KxGfn7D_1&bܝ0Sd!v<!S-/=1~%OM~z/k|G+fbv7;cĬ('oћlqdup<ZdF{=FSֿ*ڝJh4jWbΑF|EWԉAw@}&?rS(cMr3F#OA*.E -yM!S>M0%7%z~:s;+S :a4 a WOHzهM!S<SLl+Ja*ۏ1Fڇ&$Ƀ2ʊF?@s3=0:SӯZތ05Jۊu}de vV{|S?Jz<_2;;e.i)yT׾jx`"dF,lEq !>K 8 G9x$-ȼhc.tp*fv~`-QCw^NW)'=+VZKg/U< P?9||> o^?=^7`s-'8!ܼRH4~2]41~! rC/wgCWm|0 J[$=.!4 �׫k Bwq98};<. 7dv@YACKxW>h c!%WC:}�[.}/#DHjRٔ�}޲3tI}.|A@.y JnaiWdv”yL^MN"X;uP!)�'V"9/Hc\a?[VFzTn^ (uM4v躎`E;fE?]pc^is~̋LIUnG4cbf]=;W»ϙP쀋'%v$ъ'#zW抺dm}aʮOPqR?dr`g?IAlR<W~!ǘa兵DIŝI=0M_[NM|7<d29 @qʛ1p+t,?[찖1Y.ӫ<1|Kυ#Ӓ* f`RG~<|Ї+9nKf'#iB^uz]xF*#$>)idТ3s&-C^p:{Sa_?֠ĺ80ܒ~>4`yQ4dïYe;ƅtbqwش$;8ۼʁ`^fʉMG;iJ/<E,ӧ!XgpCŧ a2r !vv m ΐoq}jVP,܎ �pT7Ji[;,b1KT;Ot�G9k?U7di_+N΀/iXRݵhFʂ?#{.w:7 -q83vQ6]3`3�-T_D.ZCwY00^W "e_VWm;6 4~b#>mrqarADȿՎ痹(qIz~P7N?!>{ .]DY4{ QdJ*5{Tq5gW}�P1w\%>jK}d_*LFXD|vzdȿl[3)%L}z^j$g3qfJ*i$Cxڼ7,ӟ8|! |%UE:<J .8Ģ0n*wbA\L>=e"\~W=(zGKʫ1Q n `]Ƌ91M.% k|*Y *"aA::p1 -TXF}1PE*/͓ՏGX3ϪGY@F<ψԀC)Y>%3+<n }tvPqޏTgRqbD!u:cnI~d n~_QxPOqEb?ѷM6YJV �YwQ%HN.(*W1|ZB!IG - %٣_f&k{!vҸjsqKx&zջxQb-{zl5iT+LGD(MP' E~sSI-m,z=P\MtZը.#Ec0$c5BMm16icyU3i/PC,5ƊX^@!)VN[jϴ+>PƅĢאH\AAmjU?s9*Ac(lBilB/6-f[!#џH@u+HiT_GJHP!jXjGO -in[<ZjXoBr~ )+qn ̈\*<f*V_ -%׵~}{ &FGf"YiJ.jY9<T8`M G-Ͳ$߷WpG|[#d? -nf, v)tfG/MǸ4ߖxJyCI`&hQtt5#sr-+ İnIE[/f 3O"ӢrGC [pǘDJ#yZ#t99+*#GpSƐPnU*(XvtVniQ1[RW�fԌKF±gT{/ ϓ"s$m/ц[UGD<0U=*1rlP&{Ơj^&6@S?E! ALAs<E5Y<sO˿5Îr�M!DkzS<SPACwx$ֈOAefPPn_H;Ol}5<`H˞ 2ΫpI!F8KlHך[qoJ< 3eUSX-P 3– -~7h+A\G~ǩ:8!K}MQh"+_yBCkFٱ $JcLq%HÕC#l߬kwܥ�!nyP-q*P͗*r}9>VlG l+e=_Q;>@_WBu<7ǨnaMsSDeE~kA? lG -j0xt8!O@zo/7JiQoi{A55i:m{m; -as:m8{}Ju!$.A[!U6 k=BmWCS\k %FcM2Wj`�^5gRO IXW޶z=ܽP�D3-pie+X @KNLQ5zpk_گH <$JI#2o†gwJ'I>9jaܹå&Ў**/nK׈WU,O}Me6U]:||T6gaQ~UA b J/>} g@ \{N$˶*OnTP/k6|:mY?U!" ft#lODʾs2Ue�V R+ r -# _KEk!-#jm4 cO q(MdB]9ox86QR9mC[Ϝ|)<in곌0#+)fp;y8J1#Д#%8D B" t:a7pw%0뼽աHI6yVuHeQt3sѧ넎pOrNĤOkp!vKS_jf̹vV(]x S�5,[4mk7Dlj*&y\} n4W�^֊!YQ?kWRr/r#oG�}G+f[uJ{\;<}IgD $2f .,3z ( ,(ӷǛ]+Fsi0]?rDSVؒVPSMJ^@܉69=m#8wEni.6E}^GqnXh9<Hna{UB  ,8J!qC4njgqపn=<}~s,6{P֢uԼ'ɯ�D8tnه&sj7Αt5X7h7Mi+,1Qm]YL6Zb~.it /nC ų_鷶 wjKlDt^a " 5v7%Es_g)_ 6LȨȤK=~9ݕJ)HJ@+jAbNrTg}vcɥdm+R`>u#cjbfI p(!UlcSg}#=1U. )P/Q3/jGQ_rZ(xj7C؎jðԡ2>ԖFj]}ZBD^7_#8V~ȽDq}x+S[4+V|F�m$w@h"TLar>lYja|YWF{|c"R,+pqCbRϻ+L)S^d -aŽL K05l0d}'q7t~>�N^5�Wɫq;xʦ! ƠSPRR8g(=r' N, |rXu:YE^7y#~s6:5 66_6a.0n(/+6dVx RAcQ>u@!få%\T_PXq<8O1DyI=v* �D0.-.5G0<g-r/ iO'1M,\d -/C7/9LdeDz1mWZ)фg /A\7@ x"}^Pt -~` i4QM_K@RB@}gjrK {M0qt[p-~pb3F.u4^_)km E[I#Ԛ�:}m>RK݄K?5\&p$)OUR|iT/l>貣Ξk Ub?N2X,BUR&3A!9i 4nQd= -%g0}#x-̬08 _ƙm*PfRh;UGJTz -o/fT-e/r/ -s$U…N).,l%ɼ)^kͭHm|I+ٰOs!'\_0 lmz= [3Wa-)uhQt-7{)jc= "#/pɟ]cU\V}trsGn? Žy&QZ Fֵ*q@ D$æy'd5z?}Yܖ)rQ Lmg#Iv֘dm#C ܑfȽw[Q'Iu$@r4ͳ<GŁ'pnȞS0y8JT >![` 7}Ԋ+i|b 93W)9 ',I9 ǮX|,mV.q>*})拶QVzYd4d:NF=?BzYd;tD RɞlW+0)Y$#CēML5'{ -z -r>i[to#uGVáw ^rj^q܁_/'DphI6Zgvi�{ ጬd[EhPFZ4(oGK<(�W.Z{yC_׿R2;XM}n@踔2N}ql׏3*A}7<ؐ6jLGIJ3A - ( -9zH,Pm#~iQ*|9X -vgJ~}}u:XW+>> -zP}J?{\)9@m�Yʎ]R?5Џk՜} -8B:btg]aPt繐5Uğbbz+yF=!Vaô<Ltlb݁=mp押rkzU tP#bM}㫟'$ WW{žTU uUeҡIqVBk)Eh -g?>W;6kŷUQ;o<¢kr*N1W}js@NCl�U`1j1/8\)WL'**}vW8?2>y|T#k h1V;pc=վNiH6U|;nd_^U#4bsp"'G)pn ܷ@):cù5ݜ{\cAԫ8##)O%~9)9Z\(>$/pRB`x a*T^WCHbQd-^軤Q*3=ff}<2TU7)#, KW6%&ۂP&)ݙָq7G/A# đYǐiAƄfNac*A;޿79xAg=?@.__=KWD~H9Xzg{ n_~GLE.idlU /se2!5"2aS@% hr <JwAiQ,3DܛBy(яܞfWZ$jӣGYQr =jh>1/O` -. <pf݀"AO')Ea#MBcy~vͷ+rNL3/~ːXh o΂n0ȶ FtLپ'1Ǹ>=8n% qTRy fbiXqi|hXnoTg@< uT}S_ǏB%|!۠bhof?-rwװ %n=(_|> rc<*'jq'RK~-SQ{a7mm8 +,svJk~(to$z/hh'w&KLUUe7b%gzCTq9j#(w`Xd&!gQW߆\c.h~G>hZ:Kc۟GhήbY?meCGLSVo w9)n:UTi-#y$Jh~@oRkQ -0[ks? O -ٜ{jW8mF]7Nтap|!(6AķmH5S_/Em~ЙV= -.-}!,ۗwD`r<'`gI_l)7|8S e#2j_x(}N(Ž}T(1aKP3-XcYfHEB*Wa>y4GF`VUh+j$1T]Ļ -HȼD}H"t=]h)H4A?gP<8I%<D<+7J u劽cʿBA}0MYҮsZTx3oIYiҰt2Cn=wq.$UMXHlLG3{6|=l9aQUKwJ*vId~y&{XjXllѓOKl; -C7 9P`7!AC8̘ -WתHozG3mF`gz$n?F2 @.h|a'R -Rs,0FUrE@ȼ::aiCHN.NDoy%T$ -4wYb&D ;kl?ڵ{cz Sc̡%pyb <ެ{MbˏzJMobH{ubu}P$܎bUk< ׆,TN�C6PB?́jДn%謁zRq -ΪT=:k5i1& M݃+՟`jgjܳhu}W(|0 :uņѡHCd^XA@ÅlKKYۊh]opI~U/yq8Z_xOFA:ښ -sF=AtңʭEqŔ_ Dݜt˪%Gv@'Vy64AH$l߿"OA` zҥ8;˺c#)DZw4Tűa'8uqd MJv, 566i4{m7wN0FitzWXBП" x|%ձ£T$xD7{ʩ`~R4vH15Jts t1?j#) nZlL:yV=nx.9ՆXZ0'ĮGjN#QO40u#s"[Kq5h7Q` -*uH< "ʧ0wzi:7%db}_-8K=jMW1:poUi-bX(HqmhߩD-Ae["C`I#l#9$N'ZNheHB0VwqL6HEKc+j e| `-H]8i¡#>h2{3䑗h9VH3RtVKlHj]e[oOGqܭc<rl*%ޑ o'ta`98a4>f U^ɯHD;u.8))= -2Gl}=Keǩ|M_z,!CzD}A ;ñl{vXI4Lh98dbnFq,k.I'_- T,zjʒ$x;}XY.Z3;RQ_ LEm\ /q$52=�[wj_r6;W%;N%7 RFRntZto\l_M*|* @?0o@D3{pv-fg/vz↫$kt*Qw ["B.1΅b)0@ulys $-0A<@-KεבBjl G& U9Q$D> -6;ʘTq(N;K|SLjQ!{J 4#�wD!&QQ<ŏp48@)ԫ6 -TWE,VQ}q׵G/snw:i~ ƪY#_"V}F-j,E;D UKt h_J#C&ZٮHɥ*٫й8wl{Gn.P>!!yŭ̩M4rHiWpfx"-7nИ%V#EAk\f+kMȱoUg݁jLjq+>3 ` *.eV x;ץFS\LNnxuA A)dzmtʳUWQ?.z,C9x;aР.%ʯ(ZbK *$,;vC jŹ'H-zD@GR(cTs*҄BQsQh{6謷cn'=d³9qxWGL!7+•Z~+A* E7 -Nx(:)6Y@?uq ,wzU7Htp4(NЕ8 9#/j3YWh.nskHld{Iޅgc*]MU zmGVkA(8)U'v8::� -EnqO gSم8y\H12C݈5}qo[/m}xp+ `TL 0 -'m4ф$ʘ[bIW<F۸uvB?|!G yѣZhz9;d¹c~&O9m)XG~TůΈTEW$)[s}x]{05gXq"ihufRKl -tBR;Q#)!C0af,1/Iפ..vܧ{zԡʃ7aP%VUxZhyyZ).B^vc 0 ~Mso󶼓hjQ+rdDX Q3'==}pl&1b֔ƤIZgYS4mx!=B-D!ڔbJR<K*#IBj;]i-qsA#=$ - Z>W6DkߦqACKQC\2Rˁҏ*B$y)36:h9&Ո٧Mڻ[A)` J<Y7@j6ޏ|X<R87MmNyml!&[^#Ox5&s"UB"[eFo>d'|Ɨs jvKvwF%5e;lhP?&As||FpM<_/9X=vRAl J?S�W34Ib=zL>@+`P9 ś>E%,ݦH"T8^eW�;U>iAj5n]SkTWSl67| 4}5JD-ё0oqZEV0u6}!|1Үd"Y!cP`'јQ(}(ykxQ-5fˌLV"@Bp@vBH|q?C]l2\{u8`%=%ov` W"8cߝ5R"rF>$I:s q*޹ eZ{|e`#fD1R037~QQK[ ɇ%I$&�(I v:ٙz{oUq_�SϘRsG/"X'9Q%yX\VM2' 6>xgv4lM%5kH~kH<Ea/rl0㊪{]W=B^pa=˵H7S-]UCy5 -W\]<'SM(LYM0=-fp{P<Q -'xhT/ƀS.B�*Q)8-h="=uuW#TǏYŮEfu4r:Td�F3;KJ_k;6u}cyA|1~/Ȕϔ& pK"9uĘঌiFݜ Q}3䲝ߑͳ~3*4Ž:M F/ <Z*O1*w<lY+lsh-D -AŌÏ/۶M(KzN�`^WƥKuq[~˛9c+;Qꋭ4)mUa? zu4Ln5aʙ\OQx : <lR֊bx,GW3I)0(dC OϟEj -:QZd2 n}c_x5I.rྞ"˝;#zF`~F+wJwT̡~;cù9࿀F ,uZ:%GmbMyH9^#؏Ij"P5Q`;vH{\q"zm*K*|k/-&Ƭg}Ђ+>9C;^LQOGG@<F0ecRQFP<>�X|(HM06|Y ^dFe{Yܳ4$v agi҅+Mv<΅z~cy8tQ -C[q(\oVxk]# [X}D^D t�֚!HPb#ٴ򷌲+գ6] ,L,L -n~9lRz?=RR9߲NA{k9ߒq3r:COtTo$;SSXTBH XoDw {gR!yV:F,Haxa}nQp -ųVeF^Sq)<b%rfB1s7Uw2lZܞ]Yo> KܰX<]N|;J;*Ɠ;wWFmJ+vODyd M)hR()$hG<9hPqY>u zl,(\SIӓBi8^J[xNm1Z{Yf 3ŢO -{r}w^B~~r 1c\6S_h~V(Ԁϩ)db aޮ#W 4wb99#_ZwݱK е$WJ-+6Q tp7RoщV} tYP~ NN<gtL$a4ޓBi/՚ i~TP(V9V\'!s{ėF2Ϣ$pm'bJXi?]_5D[=FNVej#I13GP/s'zTEJZUEW/{ -LqKXՖ* q5)+Џ3AmdT_Mo {լLsJ: - n J^lo -Zݢ.FXԕdPcB?#!Edn2A`\iT -Hc)$c33in�B+p&<LѶBt7 ] ƒ>8{Ս;]ADC]QϪH`}mcOף!mVg(>YOd2nrؼuYwkw%Pg8HiEY@P4Y(F4dFOB b�> 6[,f7]!eQ)Cq{C{5 AVV^}Lh9⬆z:U�@j1StY w!+UDkޔNnH~7Sz nih`8U}fk\a<ocBKIح˧\Ӝ?- %ImA?jVxh6{Ъl.z5q}֯A{CĀ;<kߵ3bU` MJI [�Ur $y][jQ{%ܘx`AnLޚЄ]H ->o]_oOˇ>ۗO/~/O?_?O|ן|~?Gowۿ~?�|/c -endstream endobj 2351 0 obj <</Filter/FlateDecode/Length 3083>>stream -H͎$ zw� c}E(gO�SLD`_H_~!?Cz'rGNm}~?Hf͗?-_ڿ˟s?ۮ~6,I~E+f_kJm^?c|E/YUNQez՘,ꫥj_2W19"sV}Skb]}4?WzZ~W~ؘQp'Rk U2#},:qp<f9.51gzkeqe.mEţ//.۲r'qCc\U'1xzG^tGbG|m2Ih$B$rDB|{ɅK)]9&|\踮qv:-#^DY޼Ku%]rj.J_>OΎ}7kI$E:Iޕ57$A+ze%E\e|k5~ f Y -O�VŞ>Ә<n\,_[؎فoܻo!ڼW#֌ɼǦڨiI!:œ^YgzrMB3s ףC%n53 @Qqvq,7nM%AvI>�=ugBgOzYxߋ⷗8<)HL@"JK^[P5uU9dc9X2&~s+f$ ·'?@& ,>M%l(o4 s.#{ -̓ C»#% 3� PƯAZJAtvRY9#ܚ7Tɏd�"Գ)51FDZ`$"{YvV>djO>�d]'DY@#Ey2rVTܛ"kI p -7q*XbtQxT"]dwN) S9hGW V bqZL6B#B3Ȝ|&ȂTbF 3\ǩbY%fZ/I'1p/`*M4^hVmm~IAm6Ud - "W1I$6[cՋNČb�؂o2]!]$@iCCj՛sI^Ѫ"&i6ӝi[?!kmo[A'aN%#5M%@eQ.|!j2%a nze<QQ5ESSpVⱽC1Gc9{|חV-9Pxڳ,p: -`R84Ve0kR)I1_�͗I<U)[t}['uS쨪5|| -kdj.gEC7(q*zVOQGM\`0}RĠ)LJ)eFyRrqŁJ?Dlғ �>fo"5)6.Ս fPth6 a),FKތ",64,pͺCC*]AK[XT7.oւ&V몖~).j 5i^ft>pNMqg3ܵ;oignɻFEΕ"W,y|}G;Q}PݤftH*V.+ZLYqX+MpлQnMmP|ha%kMk%TM44ry:'jrBBΥBn箷 :QAd SxÎ+ݚV*ȲvӑGcio!Gtm~%_UчgMSF%LEPR&]2NkeKz_EDbei3$P~ a5rܘ{qC֦~V"VJQ78M,{Q&E.{/!#2Y* -AY?OVn4~2uFCvZ`ftʪzY\9ZВFDov+u]GMU BUl>`ser嶼'6En P#^,wnoJ=۔#ʂ -/;h raEVР492TKhshCiT4#aaX!6{jnx DvϱV#  Q wc*m,nf]�5} JnO ZS ehTb5>'n. -]>wk:]E]Tb5k>w -m1Ϡ 8'nxYo[#? 5$M d@-Air߾t3Wէ3Dƣr7TwtxAiؐߚ$p PC?aBÑś 4*p? j-q8Q8m{X`յI?w[hggODB=`r|װ&N`rK0NpD] y[OPO�5W#o41Hm.w܈a{, GRGȼTeI; ^IFG nݚ$o]t@P։tޗIlG|SRa-[^qnʪH԰2-$:ќ ܮm|t D-"([O3ܟq\?!7<;^z#HB1m2I{Vi M{9X5Lm:tZÁ.IPp^1r;)[C'd}J.@bŏ9N\PG9ӈ*?y4KUV w'KJN&Gš2Ɩa -*@0oӄo=_I ,3:!" �͑n? A6H +ZA ֥fzumxw}>now| 0�ih -endstream endobj 2352 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2338 0 obj <</BBox[0.0 383.598 384.0 -0.401855]/Group 2368 0 R/Length 54/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs --0 383.599 384 -384 re -f - -endstream endobj 2368 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2348 0 obj <</Filter/FlateDecode/Length 1794>>stream -H͎e )j6 �w +궝̹ёb~×V͗z.h^g?/?~_?y;{|:Њ5+f-3C/(jkmuS<j;C v>./k_e{c3_eE`:.yp3jҭ2V8ezv/K3o.O!dv[D]ή{4 -6=5}yIG$=+F\;6ʙէm@3갲=:N`.^ȵڬWĤ8p V_3͝„`<wm>qdlޟsO2 -`։n (|g>&SUߝ\CFaʖ�Ľ:-D,D4wr2L^ D%ONug/pq~=O ,,ODšP.*1y:g}y71ђ| :@X¦Aїu煤{].mE2ѽ�xsB*M#K#P-P=/ ;)UG"\zL$l"նAvյ!}2AOB}Z26z"qJk+^펞ؒ]%+ BWCۻI6b,[:dcP`DdG7Nn0>3S -`mc"Y (/bԥ>4+Aӏ"K꼩!إhf?̊08X:-Xy x;āG=2IA= -xq<x|1m@L"\HQ2%-QUu&,)8KP^x.!e)uJzlaA"3vW# >r{HUPvFz sd1#2Dv{· %/?}D_&"^7B,)IE/T2x<%Hd "7 %9vm-FNJo,C '<[Tɫ ķg -3b<3Ve:zs4Spm=P. -=T_N`t9R<mƜGkZ+[G4TP~j[^U#̲P ;}G -Q�ĘZz -RV*GS%MժC4ňʒzND~Ic%C r8AHLkip4OHr4nLz<GV -c -Fu?ٕOt(L!opY*%4)Q6[Sxs:D(<92 'H#,5VMU-q>j-44&PK'}yyKi1g?QI'dQ(7@e}Cs͖ֆXJ@EN-<~O=Gȉ7PiօeHNVniCT35I"qP0Q]6+iCr'iXq.B�ψ0I[ewNtCҫ~+Ed?n+.B Q($:~1$з+sIq(<b#IJ<`n@b5 -e9[|ț ^[_ּǏc �Ȳ -endstream endobj 2349 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2345 0 obj <</Filter/FlateDecode/Length 1190>>stream -Hˎ5Sx_\ !BH<@d3 JxKVh.캝s=%1?}ùTϥGI}c|^_uK/]> k߷/ޯ?(R-9vhv\̳{-;sqQr]=ȥt=.ru)+--̙Wۧ[{\xٯ0e9ʳ]=w\˳ռ,9U+9&n(lN|$;NBIA6,2Ӳ<oɍV)ٳqyYCV-njn4a<mXv)TI̭NQǙ$yRrbj 'E+R_y0'ձEw\nN1=触 KU]fi5v5ΜJUm0a>l/ND�-O٭r9@X) [h@ð,h%u ƹu+Easm6ꞣz -@U(9/ -G8gO;Ac0!¶*; - -n M{j/&Ϊ|-Ɇ=8P ^pBi20A �+h-{6 -:Yv=IHCYϵ5yhTgS`pInx[Rͧl/SN$LVM۶A<Y D]Mu3&pۃ(0جcp� RƱ(D" 0 -ͣ5 * LBXO-,|~ |SLw3ik[KVH[>nCw{R P{G3FEnA">7PI>fPNׅuJ{I5k(7לܚzG"JQnQa%W@[P=,X6,Q洞6\ e cs([:MRp;!μ.w ejͷCG=@+@3;`ؤn|K9tR⁞mU*?b3Mdo�bS\E*[%R|Mkۡe9B~E[�x[&yӋ)ߩc-C.]C?> 0�X -endstream endobj 2346 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2347 0 obj <</BBox[0.0 382.376 384.0 -1.62418]/Group 2369 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 382.376 384 -384 re -f - -endstream endobj 2369 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2341 0 obj <</Filter/FlateDecode/Length 143>>stream -HTA 0 96Y[y!ӈGOs Lq0 Hxb m&!- zMe >pz]: ' U`̳L99fHn쌋IDo| -dTeحG�5(g -endstream endobj 2342 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2344 0 obj <</BBox[0.0 384.0 384.0 0.0]/Group 2370 0 R/Length 49/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 384 384 -384 re -f - -endstream endobj 2370 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2343 0 obj <</BaseFont/UFYDVZ+FFDINPro-Bold/Encoding/WinAnsiEncoding/FirstChar 45/FontDescriptor 2371 0 R/LastChar 90/Subtype/Type1/Type/Font/Widths[426 0 0 0 543 543 543 543 0 0 0 0 543 0 0 0 0 0 0 0 638 0 0 659 605 0 0 685 305 0 665 575 0 0 644 628 0 654 591 571 668 0 0 603 0 548]>> endobj 2371 0 obj <</Ascent 1195/CapHeight 712/CharSet(/hyphen/one/two/three/four/nine/A/D/E/H/I/K/L/O/P/R/S/T/U/X/Z)/Descent -206/Flags 32/FontBBox[-145 -206 1174 1195]/FontFamily(FF DIN Pro)/FontFile3 2372 0 R/FontName/UFYDVZ+FFDINPro-Bold/FontStretch/Normal/FontWeight 700/ItalicAngle 0/StemV 132/Type/FontDescriptor/XHeight 521>> endobj 2372 0 obj <</Filter/FlateDecode/Length 1465/Subtype/Type1C>>stream -HDS PTeww]r]- WDdمe]u3S1|I:D!a(C9Dcʐog`ӽsss|ie $HXĄ)\<X2LG0-QOt5, 0X^# Z\=9vij\L<N\4\;YkYMDӛjwM ^Ǚq937XLY.k 䨟ɑcdxOz4de1  e 3aYfL`8ef2l>"e<GcYMa؟55ٚך{>y]D׬ȭ7{W{S$~s }Hz!BKЮ%Z3@c^(_7糰D-DE=,C! t]L - 0OM,B0~4ȝPiaS`NeO^<C2a^(`X$Ap�8Gd+X rd˗uͷ04:!#Ts{OZK)zےEeUE -<{1K0F!([% Fb8qz(">Xk(4~U8 X)6MV�cؙhvlρ2` y\͵׌(4$Yf7u\ol8{1+I>T̜|v?H!㡧fTr(Op>q]Fv[Aђ@ 0dGת+I5<5C z͍6=]0Ĉ\}+]YwMGQHR` ! i4 afPGoR@jvQ-(4ۨ~ - -4< >g(A6'!~ =htM[DKv?H;&tɭi)3KiiJBY(Q=+ANk/U*]]{4UԖ\_*YXBUVեRcry0 -yTrend#c�rCLo?(m"-Fk"0 )`|>e># yekxƒ 6ŐiKq8η7R!Ee-GiId:6Ydlj# txc_Apt2on+\,]N_#IS12JTAǖM#.,T;P1&~.O%tv{ AV9HeU@} Arң]>goP>@֒G~@&?#-->-LTv=Kߠ>/ A'W=LxzO07r0Q2fصdjzH<hiYnu^X1,.qE4 ˆ�9 -endstream endobj 2339 0 obj <</Filter/FlateDecode/Length 623>>stream -HTn1 );WZB*x$ Y;3v^n}w{c;.b 5Pjunxnٟ8sۇ8ó NAqYq_`z<p7ҚX.B!hg[F rN8A%ݚfGfJ *B@X7N~wqo!9[賙J{1K�`ऒxd\JT2`c;K'ghྒྷgᘐRȗ AO<SJrǕRm`T=bO -G~.XCVl$ hوUe#n�ںԐ\I�i9n&{r*Ֆf9RDw8&rtVv5?TY A}d,ʇL U<| fP(y SF4,"nehN殌&TCf2ʰ5qYw+bf1A5d :MXzCĀ+kRH7r? qک}#*NLd].{YIv!,F]&8"˱/A%1`_w�e5HͶ7kBݱcG/=+FX{8df qtϸ7}o0�L*W -endstream endobj 2340 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2336 0 obj <</Filter/FlateDecode/Length 887>>stream -H͎\E )FjwU-`CF �-&JR>WM4}]9)9~zϟG"uV5^Ώ?\ȇ/"=^ p+`52'1)31kjr{;k+&]m,4Or .KtDh]zը]uK KǴtUiPѴԊy4BΣ.rϪ\lUYM{]۝h{'7f_J-Wf13’J8_b/-+Ť.V)س_`Y7Qv - -tm4]EhyR)@rp!n 5iӍ`]g۰mAMP6PV[V<tR/Aض8 -x img: &V/"L#9 -tӏU(U$ תP �2YEJfvҾTŶ8U)OŭTwIבeTr_Ys]T5! LAiLN>) ~�}8͸:vA)2Dʤ-JC6#p>j#d[ZiJ:os9]g6!q֍WtE۰42+%VGF-4077 {9.H;52|o2<u_R=mvQvڵlZ[[|7G.N6P5柳I.:�jinwb0xh.axNncՑq4sYpԠfNig+D=ⰦM ayHSw" -3N74��Wl -endstream endobj 2337 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2330 0 obj <</Filter/FlateDecode/Length 1235>>stream -HnG D0&d#  H1l?Swb<%1|ȮG_ꪹu{?_|~__Kx WВ~}V\SܯwϽwO{Hϯ޼g6GK'bn'lr3m|%Tg^&Rx5~p돷\1g|nS_SH{.<hpR=Γλ6w|cϣ*zm6S7{2>EK(V5*IΖ;!Fn[o -Ji8N)D9=NaV@T,5v˳v\w:ѫmi܇0ri"Xt)�@݈+Z+6SIf@hRJF;1Sf",x4snr*\`X`y42@HQh�Zp,XQ44!(<Zbv\_!TskU @!PGrWhXO| WʽƐϼa>./ k˷ +<vXx<�~Q휸|wzXG]jZ<c 'iTjťtxO;<ainU[E/O/K{2fJiA1؄c=+NЁ - f)=�tSa]̰ -lc[fͮ-$$*033i+U! K <>V&N UX{@3.k~aM- 뱍@^E|FQKo1xaJf3$~ -A6fmW5M+FQCoipfrQGCF(c< `FG'Ceۥ1~j�rzRq C"Ʃb]T,FIssEl?hA )DMdEײVj(ޮL7IUK&&49c -C F0>h]=,BRQA YXqnqϬ7F+ jQwXg =sYڀ4I8ӭ6iz̙Kx2]JX-/v]t{WȹC`|rdQ-" \(tO= 0�VI -endstream endobj 2331 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2335 0 obj <</BBox[0.0 383.598 384.0 -0.40184]/Group 2373 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 383.599 384 -384 re -f - -endstream endobj 2373 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 1120 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2374 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2375 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1111 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2347 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 1121 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2376 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2377 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1111 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2347 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 1122 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2378 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2379 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 1111 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2380 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 1123 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2381 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2382 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 1111 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2383 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 1124 0 obj <</ArtBox[0.0 0.0 383.598 383.598]/BleedBox[0.0 0.0 383.598 383.598]/Contents 2384 0 R/CropBox[0.0 0.0 383.598 383.598]/Group 2385 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.598 383.598]/Parent 1111 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2380 0 R>>>>/TrimBox[0.0 0.0 383.598 383.598]/Type/Page>> endobj 2384 0 obj <</Filter/FlateDecode/Length 1640>>stream -Hn%5^#]2l@hl /e"Snw~9<!=?~H,Yrvo<[Ie??ZOrhI?_?˯ˍk3[]#=^zzlg۞Zmd=w[uV򴝞ZM6-9-6ړbo{Rqp]sôKew%$sj%M6H/k%J`5vV,/wVz.XZљmU;sXydsrrM7:dyuRٽɴTB_t;1ZXN39t9>{'ZM-Ƹdڮ2a6gދ⤙*nٵ{Y`_yj.60^wՓNɫpIXX㖫7Bq{ε}7k6}E(J3b.o˅TG<pQxR1P4ҪkXiT-;'7AVl@ѫ+@@\SL|6w4'͑'6Kx"~]˵wEQ:'Llg ~`Qx -o)Tci Aki**%5#AQƑSD<ILe�C -9QKAv"*aD5|; \jSЁ.εNY -?ET�Q+):|I \ҁUN]5 YGaM0z"ML%:0\7b!~@-tETDL6ڤC?@Xj\G*$@l L^Z}bCe&4 2R.eaOoVЫ$R)Qlt6"3B(|QQOa֕L27x ɩw͇Wi*Z K S1 #>:-g"@ICԿ- {-t?{9P[ T`0aYG&�;hru@ K4:QhF@1);6?C*X#EcSQsqh>]IBۑERy-UE4Lq@#1-t0l"(Tݸ;U-I7p -0reD Hn#Y/LF,J8pxCD4$z"%; -u#(W ] V$|<.)h(}kdB3zՑvM'�ثFk7ϵ ^doȂ,qoэ>:"3u~A+̭<ƹ"cAD!ԯ٤ڰJJ: -Uw=CJ dWNJK #z~EgJ%GE2{h@iF4d堁`I6X4m(ǬǕJL֕BV9(n[qa|U�F`ո<kw\*"ƀRC reg(sg)jWE vlVk~7uK36.ؗ-QqI+X=dVPrNq;ȕ&Ms[8~_|`�M] -endstream endobj 2385 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2380 0 obj <</BBox[0.0 383.598 384.0 -0.401855]/Group 2386 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 383.598 384 -384 re -f - -endstream endobj 2386 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2381 0 obj <</Filter/FlateDecode/Length 1747>>stream -HɎ$5yF*ʰ\!Ђ̀ӕ,ԙiR/߾;^޿_;n_dԓ+|ۏ/y{|?|'|'qq? ~ Ar#|L=rM>BK5fW8]KP:z+хQP\(ŵ9ҏ]RO`4#λ{쑰z ݵ06#ITwiHwI66z|q:C3sltH.ON g -p6@RxIzkr&R|9[Յ1T^k@}±{6V[ղXQHżj5ŦtKvf\u3$:>\`}no4%м}PRg::\TJ`Dgy@s??H?Z,>!vX*^IoР'ҕ3/T$WXӔ*|u/3PX4RU\=<Nd!bi<mMf%/9!ـw3*Y+(OtEJ7qҕ,dK&3x)� -xZrT ]$`ޢ�t2Tu}IIKKEXF ZP3 v~ Rj}!/Ѱl.w�wT4$Yȝ8VaT1j})䙧\I �Ft1zC 3a(Z!@4n+y#U&.!c$#^9y3b@"g:٫'Cf5ot1B6'cݞT$_a]:)3QQM=Q�+׶dy%+gyKG.K51rmҜy#)-TirJ?GpB@ qmtBˠP02ʹbc1hц4n hLsJ2Y(p -l”D0k-r$ZUbjY**ӌ i>icV'!y86I"E/ot6ρz [IA{fK,rJ{-Kk[P%VczE�2L5'kB<k=!H4r�hjO@X, nʖӊ[^ECS}H,j!V N!ib$Zt%KQ?>)E3ەRe^QWA&lHqLyӲdKL1=7rPȰVTQ쫻Mk(:3�enaeu`[�We qQl XdH٤w&l[㒰^͇Mgݧf2rX$ә4Ӄ:GIJ\{CsHۏl=kX/VAV9o-j ]VZ[àL0wh-i̖]X"ٲxT"cD֯hŶC;כVMF=lm푪ͼ9wT̂, Y`F~L"hx;~gIW%sasa.¨ߋBqRsqi޺k|]v'w%iuv%͎M8˝AeC6m,W" `UyCguM݃Om3OoޟTgߢנ@gɁց@v -0�fB -endstream endobj 2382 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2383 0 obj <</BBox[0.0 383.598 384.0 -0.401855]/Group 2387 0 R/Length 54/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs --0 383.598 384 -384 re -f - -endstream endobj 2387 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2378 0 obj <</Filter/FlateDecode/Length 1327>>stream -H͎d5 )FT~'lH<@Ӡ_;UN>>>/?<㇏K\zWc˷?_~ϷJp ֤o*W_MrwV^[z};v<Vs-ܺZ*e$y^6sMJK1g3:}&[y NƑu^BݙXXyȼ6j).9&3yIcY2`'yeΗir7ZJFg.&Օ0A[36\yn%%Y65:IU;Q+gs ptv>NunQs] G`kn\=, ͇Ww,(ՍSp;--=S 5b,`0L.#7܋+؊#h?\#& v'h+pq?tΝf2dӬ%VO'M\Z�AfVi^"&_iڤ<oEhl;_tɈ\Lin"=3T=h}fjvbELR+B.[y2cp�(]\ qeqNϕ.o'R؎+Y_lb|0#^eKjqhgAnAKѷwktڥX{C _3xQ 9.놩5¡H>P�)`"ҬZa,7~n‰]}хP&<Aч%]!úH<�njD%}Ԙ6Gb!fBQU)eƢ2%c܌ܦ>]Z򨘩g"o - {Mv<,OLv Ԯ 6ʭ>6K7Qfo&ȟ^ =epxRG{\#dSL HKx*>QvS%1WP7PѴ"FEstϓᨡ'M#[z|:ge05b6cB:_η*`1@Z#aCN -9$z zjE#Bd4V% ͗# Z(6Ӡqb]h%'?>y=j aajL3 RWxokTëj L�o\c_i A% -ABe[DzH\-�=BO{(^Q5?MV9辠YDLc`@O.xa9<>}wmr+� -endstream endobj 2379 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2376 0 obj <</Filter/FlateDecode/Length 1524>>stream -H͎5 UdebK lP0eܿsofhWh8oyMzx߾I,Y|T:_~O_K{ǧ}ʝwCKQ~M~?c~X.5RȽNO<]7{$eV:FgwYݓ<m[^w(+N Ýl۶F{dy&krmi -jZ?F:mœ}N =M˫͈f+-~nֲDm3f';Y]&gj\=x^Hsf=6Қ[Ҳo /3OtBolqK庚@RP g.Hy%XQd)7%+l~힇OUG8퍟%�2U8o: -2"C`k@21[=?mfF*ا +En+k݈* UO#UK'Pp -\ނ$^ŕ@y̙Mm?cD z'm\GF&!hz5Hݠ=5�iդx5y^Pt9|r&}Ш\Mbae& uQͣUaVLYTn%C &V;HS 6bҵ]1mW TH *]]* y+HL�-)6ZnCjkLSKZ5r-^,;/uT׺M!8!iPo۱-=ǂZi>K u:aD:.t62�G5T$V+5G"ly=t oV(ɱgZf@;z"Rա4JP%T`;wLwwYă&M܀ki@̡1WaB37ѼXU4T1) )^8ķ%`UL|$<f! ԣ4C <m"`ѐA6xZq l=^ҿ|tapcz̳h c"!8k;w?�/$ 픀͸,+^ Y&j?\N7zRg2Pa_;!mޤ@ADTR&NWu#'PᎻ"媑Az2TA }eh(}ҏ 6qUž?/Ȇgę6c`KPŃzX̜!AZUGi`oo<UD7P/`5,#u<.Ɠ(xIݲ=3;}ԃjEBūF^5%e(Bݪja02ezEQ1D%əxf6vo2xMcT+*JE<ԵM3&Գ`jTYP㱰bqp;�kغi 5;ԑTWėox>|+�aY8 -endstream endobj 2377 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2374 0 obj <</Filter/FlateDecode/Length 1126>>stream -H͎6z -fK`�yEbf~ _QlVXUڧ_ӧ~Xc떂s~|s#MϿ;[ -^*hA}V]Sݯ,Kh׷M;on&bnxhJBn9n{.1Y =c09>KG ٣:kQWzy\媏P,ZXfdcJufB/-8 �R֜ZI2,AH9>*$Ǵ'SL4Ft'](>% ƸR%\8Thr�Zؽè'.FXSH׍jҨٖ^8B u%|^/-(s &mF[兾b0]d#,6:8BX"憙)ξ2L/]V<H* ey#P׭8)~ȹ L4Xf'e\poz{Ӹ%< |8LҔF'�ӈU S/d<u%V4qN^{j4WXS9%:#9_V]hir6iyYqEd&н\Vǚ$} h]NRAc -PtJfmKv[rwбJK!n)Aٶ:ְbHP%fR,*w 7MYuk@<:nκɦr3m`G0-S0X!Dk`KݎknfI(S6V1 Kv7:z/L"u%A՜؆;6<L Z;"`aU htewE*[5Cg2~(@H, -Y�O\W>!I] XŠq?oinޘ[^`GO�'Z#A"g9=@\кv˱I6ə64L0B3Ku|, =߶/'ztI:kmC5⊩Kc8@Ǯ =g��f" -endstream endobj 2375 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 1115 0 obj <</ArtBox[0.0 0.0 383.809 383.809]/BleedBox[0.0 0.0 383.809 383.809]/Contents 2388 0 R/CropBox[0.0 0.0 383.809 383.809]/Group 2389 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.809 383.809]/Parent 1110 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2390 0 R>>>>/TrimBox[0.0 0.0 383.809 383.809]/Type/Page>> endobj 1116 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2391 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2392 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1110 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2347 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 1117 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2393 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2394 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1110 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2347 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 1118 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2395 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2396 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1110 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2397 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 1119 0 obj <</ArtBox[0.0 0.0 382.376 382.376]/BleedBox[0.0 0.0 382.376 382.376]/Contents 2398 0 R/CropBox[0.0 0.0 382.376 382.376]/Group 2399 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 382.376 382.376]/Parent 1110 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2397 0 R>>>>/TrimBox[0.0 0.0 382.376 382.376]/Type/Page>> endobj 2398 0 obj <</Filter/FlateDecode/Length 492>>stream -HSˎ1 +|FjO$~\.$>`{aXK{HPK]ӗ3ϝ?}xtO=:PnxѾo`Nvzz[vNt"xx_v<Hɑ>!I[ҭm<}QNMRYѵmh 4#*dR9kS89x4Ux 27iutZ8 -B"Gtma$:$@6 _-;ۄT8'aHHάLhr(jՔq,6xux:$evXW>h -,UIt!iwp̺8*\Xi5w4c4piat"1}PbT:.^FYJ'BX{QtE.|KtA:Y ,Z5 !\D*ذ�](ƪa_Ьmma~xVi6~w? �b(G -endstream endobj 2399 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2397 0 obj <</BBox[0.0 382.376 384.0 -1.62418]/Group 2400 0 R/Length 54/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs --0 382.376 384 -384 re -f - -endstream endobj 2400 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2395 0 obj <</Filter/FlateDecode/Length 1171>>stream -H͎$E yFt8Wv +hr_du̞PKmWӻ]I߾>r|Ԣ6|k3O?\ҧ9ˏO߿p -ϗOkKnde9gMC^jRͫlcfp:8�g3W#+EMpH9FQMs,�ĵj-L[yvTϡj{jgyl1oGk Rwf3 -kCICsijrNDիX;U(#W_(<uҌH$ քE'kWgr{;8x@:ss'VH6s_�Nx 9qU.QI#WwCsBض�j<RyN4ZV*^}GiNJ|OАVm'^Gɛ: cOΏ @R.r],U6iPIckYi<%21Lalg\Hy6#RO&_t<;5Դ*P%-}U}Bd/+�WcM:hG:BTNbـo&$q44^ H&<zmC.tFKoajpa Pw-uDS3P0LUkOIClƃkYh8S7: AL/!R4'B+hOD`ŬɐֹWw]EWX-Fq~N%_vlOK4uK*46^5-ڸḾ8Ji"|RznSuw LX�6D"vN eUa5WaZ64BCfh*"&~_`nI&2>68:$zA2 RQ(x9DmZ\ӭ}%(2FP0œ.m$"݋ӕ#UFi-E2 !SUޢ*Z({nb^DBS)C"!y{km1r{ cPx4h3.kv%[Un^֟5}=Yu7e OЇZl66EKW݌}(]KZ{ -O"o'[n<x#�Xg -endstream endobj 2396 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2393 0 obj <</Filter/FlateDecode/Length 729>>stream -H͎1 9#';\@h9vyi 4=8vw7/n-_HϣM,|'}-_}-/~kg*%?_fʇ|͢Ҵȿ '&k&mNҧGx:FQGɨU֒ 9dXIVےoTrdU'Mzq̼M' /\߁v�P[\۽s"Widb Ҙ(ե7]T:vh<_<jH &eq$v"c{N1Hl.kC&&P -K'97^4EVB Te2xdt0L&<X-)GY)rk?a5d*^IL -+ڕ40$ -Ʈ=aŖE=J́>LOFK˴,U$ᚲJ}7ê}׮Abتl4S%CQkkl3'DZscޟqc8.67Dʿ'UF" 8h$4*9�t,Vs}ܞ;?"8aop2t~ ޒ(%;D F NKcC|n6ϗ ҂=}8%\cMq _m0 ,:ߎ/Ϟ^/�  -endstream endobj 2394 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2391 0 obj <</Filter/FlateDecode/Length 2091>>stream -H͎ )j`J*6M@H< v ;;;yvsxç%'pyۣjns<_?~_|?J>kI?zhI~Y ej%={^>F*^fޥ&ϵb4?,Uˍs^%oYO/F=hj#/_~6dl¬gsL=~=9{>\eq˹oXcl;rl^o6Xb&S3ʭuJVrx:rsV6R-F1{O~Bl Ia8s/[Fǣ:\l#z5-˓ ^=V.\ hkv%Dy-؝,`e\}e_s|⩗%q82aSkIݜDN5L{$L{}71$`BND?uz}bkNcrY's'iyG@R R(S8Mgz!YRM_eWֻp -9<8Ȗ2/dдt{˶s6eRZ9#vd)XfXx A="+5?%R0* -g*b/i1q`JjY}Hn4oK^r{7.%W%lJGZ="In/X8U"PiAU0o+"8GE` ]=ҥS.~!/�[ -Kwj/ʌa%#ޏ$@n$+*~NJ9Y9ue3,b*nwq�d)Qb?Q@OAUCU5N.a,g?uCT_~S=< փ5t P Z &97)lF 6cdP{ZH bqۦ<!^f%IAD~MR`oBl_+U_Wa^;/mȒ뽢# +DmPϷ@iR}#/C&ZlȺtBMlpi:QJ=GY,fJsuoRi{s{m-A/~8@Q�F -S}vB*Fg'D> GFǬdE78vɸCqy?NO0(0HҐmt�CaAhs4be xJd$TFè'L�;<`%d F,k̸]Yet\;5j\צQ%>Wþ1 -G-cI< Ar7tIM&X\~HĖ; V4!%\6ccmf(f~iUikjy,S zJF̱xqeyF;j#$FQ.Yշ9<q?Z0 Ұ&rvdDLQc~Tv~y-t ݺ[I@pF[VJ�tX쯝E7 -n9&,ᶙA<lhW1 掴ڹ\Tx?`t 8u>]mC�\h/}k$?T +}XK¦E7TѠу De!!bj5]rRFCwԹA\.0p`H/2М8:\_* D P.Ыó'NMEca-򰖚 -i)C}9 2s*-OsێZRy#& HlQ!ueܳUA'�,rFh=;`kt=ɪ5hfcLIxGPXk=Ge*2j "1+lhMCu"%֠ Zxk8'Dr]}ĕ5{ 1opae8Pj$vSmRJ@_}₟~H9N"ղձ(hʾk09˩}:jiΎBozd&j2uT^dŌV;Zt\M付_?㧏 0�ېs# -endstream endobj 2392 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2388 0 obj <</Filter/FlateDecode/Length 1391>>stream -H͎\E )j5e !BH< (%ݙh]?c>?t|%;>%U*oǯ<sI/?>|Rһ?orhI_>ɯgm9kKQZzz9r\,ړ9RnXk3=m䞷ՄUl'y,O8SG=>bqkrs#Z]fn=p;ha?[xVOǐM -^x}lQ1Dg^Co6QGMͰ -(?OskZuMAϱN4k$oyhu/UN4lmÆx{'.nY=w܅<%3-\^i,47<,<6fϼՀH͛왻YV$eA;&Vek+ݕ?.BIwxl2mXw -f~er -#t`,yXipl_n'ž"R:WAo^4H0G j݉쬢3³#ML wf8P$'X佖\,cp"2|IR]H/p/qZ LJYхFnhu${]WzSc@1@3I?GkF-o @qi罡"uN{&(tdj no):ĎMSyDQOuYE4(^²S_M;#&n6=A= "52;bKgE4P,*Ԭ -HXYuv2�w';"wuS/:]^8CH1vY].*p ݣ1MrOvvs"ծyv]=dH( 6Ҧf9Q"4-$&m{C&16Ԫ٪&J:`3PRfI'4#69)'*_Qm&p,!,1CNϭxCTxC5'I vhǶQ(:گwX z͘H B$GFD]SlZ4ԻMWHWBRW3:pR%aR~3?Id^8šF2'} |k]]|@=yy~n{HmM}(ϴvmEK+:@w}VJ.w+qU5SHaK*OvE:yh9sA 9=c^�q~Tp}T6LiG|R5_=j{"t}%e 8JM-S*2NsGȳ2}p G\Ltw|~8`�F.7 -endstream endobj 2389 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2390 0 obj <</BBox[0.0 383.809 384.0 -0.190994]/Group 2401 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 383.809 384 -384 re -f - -endstream endobj 2401 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 494 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2402 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2403 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 482 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 495 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2405 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2406 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 482 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 1112 0 obj <</ArtBox[0.0 0.0 383.809 383.809]/BleedBox[0.0 0.0 383.809 383.809]/Contents 2407 0 R/CropBox[0.0 0.0 383.809 383.809]/Group 2408 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.809 383.809]/Parent 482 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2409 0 R>>>>/TrimBox[0.0 0.0 383.809 383.809]/Type/Page>> endobj 1113 0 obj <</ArtBox[0.0 0.0 383.809 383.809]/BleedBox[0.0 0.0 383.809 383.809]/Contents 2410 0 R/CropBox[0.0 0.0 383.809 383.809]/Group 2411 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.809 383.809]/Parent 482 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2409 0 R>>>>/TrimBox[0.0 0.0 383.809 383.809]/Type/Page>> endobj 1114 0 obj <</ArtBox[0.0 0.0 383.809 383.809]/BleedBox[0.0 0.0 383.809 383.809]/Contents 2412 0 R/CropBox[0.0 0.0 383.809 383.809]/Group 2413 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 383.809 383.809]/Parent 482 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2414 0 R>>>>/TrimBox[0.0 0.0 383.809 383.809]/Type/Page>> endobj 2412 0 obj <</Filter/FlateDecode/Length 1137>>stream -HnX5)Fg7ޒ*D,PK|NC=3/cI߿{L9|T(/\yג>o??Rһo Zϗkcger-En 鹵r1쩖VM]q[ -r>]w_HKaٺ8zYS/E`F~p)_#n ͖k`5EÚib3c5wBݽG"ߜKέg/jeJB4Qo+犉7 7bک<G{-rl%3t]Is޶9;RQNGC!<6.! -moVM椁K5WMsTd@ OM�)0jRAɂm`L-bi*h2[1d17<I PbqH3S:p4'FIK%&{ h_:10v.}3JK!Zv mz"l謎MVA 4ÔeZSa8u�m5B3XUۦ)Dket'`aC;6�0T5&`qc Je  8E2K26TW tSQ;-A -lS[^IQ>c#l4I4EH\ ݄XUw /i>Lט}L*� RzC `5-l%Ow :mӻhywMm%X;P=TmGSlp&vI<Oןڴi #Nm<ɻ]i' -\dtTg^3 [iO:dZNjC+x>ɛ<uTf!(.(ضW (B�*Le? -im -e<TP=ܙLjK(z+u %c g#Խ(jСi:b"7&tɆUJz&!قDV]| % 9`|o&:_A- X֕E0ĵ3߾W -~a> a=%1LR6T1%cʛSnOpC� -endstream endobj 2413 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2414 0 obj <</BBox[0.0 383.809 384.0 -0.190979]/Group 2415 0 R/Length 53/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs -0 383.809 384 -384 re -f - -endstream endobj 2415 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2410 0 obj <</Filter/FlateDecode/Length 1786>>stream -Hn7 ZYԿunA 6]-?Ps�ΥFCG_>a/^rPf3?y>~~%qOˡY~M~`&<GsF5[xz98k=Xg8sl=f 9ZYεC/bx#O~7[!XZc[*mb-_fg`c>g*#gV-!s^#BݍEt͚҉!r~:Nq)Zbk8ﱖp6S VJJ ߼B'J/7Sgeޟxr8.R;n霤<+wS|-8D#s$aH:m(UBZIhWn+vaXAwi 򥒏0Mr|@c-~P `RdUZbo&)&mJSa)}iU⑀6jLNC5Z8I`8�HeP‘U^9}2?۴:A # vle, 3ߔiQFB6"%|NXH xcwJVзv{wGY[Ŝ9I�\hy_8SoáEVީ\ih2鹻I]zI* `PCR*{7>FS<83V;bYl;'u -{a|NB#_MȷTۂ8ę@ZQؑ3&hr:Y *9Z� IbZյfZK"Oj&]L)Z^,ҶX[mcN21h <iFvpVzFqI_U1�Rƌ*Mڒo -:<B`@a po;@7&ҝhPjvb*-Pv߮t,ة]wjECPP7 שK!ZrNM Q; 3_=!mIkp%'B4銜ЂdXi+lr%{SvVI E, '= -S4P-lڑ,WFJvNgolf/g0:PtPOۺmI'2'Ȫ!%5fA-t`䛔Ծ_UϪ SMvmMts*F i}`dL^/n!~LkYEc6sBRSAvp^<M7zL/.XfaY4qɥ&ntKRZ&2͚:#\HU ->;}a*omY+F_%r^M;c -"2SEs [A |]"캝:L Lo %Zxu8E)1H)Yhn-24Xb:\Lzq-*X kg=NBy[2_EQ_CnMK=Y@ፋׄ -i9+}({UJվUSRe:,̵au6i+&^�B817pesFvb/ Ɔ>m ;J\E;Tq%Y*�+%}/ed#/(iܩܨ'e#up 7gebH)JhVe")O"n%iL,`Ē2u4}T![oilw{c+k+ '$2W̻P?}s~:`� -endstream endobj 2411 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2409 0 obj <</BBox[0.0 383.809 384.0 -0.190979]/Group 2416 0 R/Length 54/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs --0 383.809 384 -384 re -f - -endstream endobj 2416 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2407 0 obj <</Filter/FlateDecode/Length 1008>>stream -H͎[7 ).0(QɦA1h<di~0k^җ?ʯ#_󕞯U5ϧۏo\>Ykw/TϏW3wʇm!8.#^'+:\Z17yZe&K%,>\6xѾnҢptRøZ*:ydV†4URƽ8N2u˨GQF"a^&hyJg&ˋkKʁ7,rfb>MϢsdXM:hJMi h[b`V1SF尉-m D4|m*۞ -SLKk.B16 eԖtK8ʰXM'75<2y=6<%wk^zP�Yy -q@F q;6PyL}= WGtGv R^@!!wCr"4׺ۧ$w0x/�7 -9@&a;[BfRښZȮ- 'DNi}�D-Ӈnf\* ZH0" Ru -ݐmK{)IS42,`Fr"H~16ʹ]im98%<sD`V"/9ja0;bj}fh6zH>7 f9ٹ;KA/toCӫ9UV l7}؜.DI%3OL7@.STOF�}m B4ve)ycWFAH-` Y H2r34j詇 UVv� Rmnݯgszl'O=vT݈Z1Ǯw3NF$f`FlUP؛+5Ŗ0yۆE;O=Sov:^,NaC=O?{FỿYY9CO�,6 -endstream endobj 2408 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2405 0 obj <</Filter/FlateDecode/Length 168>>stream -HTM -@ swIflmՍE[Vi?i"!|{=հmM65ԮbW+jI]|WWÙ0|d~9HhުpE%hh&iI"P3)62f&ǀ -?=T_T$bfoR. W�21y -endstream endobj 2406 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2404 0 obj <</BBox[0.0 384.0 384.0 0.0]/Group 2417 0 R/Length 50/Matrix[1.0 0.0 0.0 1.0 0.0 0.0]/Resources<</ExtGState<</GS0 2334 0 R>>>>/Subtype/Form>>stream -0.114 0.114 0.106 rg -/GS0 gs --0 384 384 -384 re -f - -endstream endobj 2417 0 obj <</I false/K false/S/Transparency/Type/Group>> endobj 2402 0 obj <</Filter/FlateDecode/Length 293>>stream -HRJ0}W4=vuA\VQdWY}=IS*d.̥owf ug̮b~;1=} ~_6ojFafOr*'/T`2V{ mRU ٬ 3uub:]C
Ʊ87Z?WAsJu6/Biv)3u1j:TmEGMaeI6`4|鬂lcXijf 09Zu~C\`�Ez( -endstream endobj 2403 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 335 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2418 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2419 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 481 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 336 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2420 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2421 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 481 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 491 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2422 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2423 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 481 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 492 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2424 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2425 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 481 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 493 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2426 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2427 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 481 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2426 0 obj <</Filter/FlateDecode/Length 926>>stream -Hlݎ7 zERݤ6�FHlGCӯ!ǟ^=NKv琣g#~z>_y/r|OxBw ? 3~oozjEbj9e1O>|P#QkORjJSlZfx ̩s夓 !:SPXɵ|p_IRu=ԒI62gfaqi7ԄVSaSZ[lU*)g9W IQ@: -a]q$j]BMǑ88@kc1AKhv8I접UFrVnz6<[aȴ̳7�MD@eu:*q C笓ZdԨ#fZ\l`\.cHGF:DR;Z}Y]"gL' [sqgRXv<PYY\RN<z/kӾ7|1)%31v]2Y]vV'9@1n K6y]EpCVʮ2 ߻\ Q/8&,Ï5M6WKHMCœ `ŒnCzmtJl\Q9mՋS+);]T3{ I.[_zsqqӡQ)Uץx ElwI=C>qn.z+|q`D3/uA>"lz o/ʨnV>5{01 -gWc�ٛ#qzꜮZqWW wlP/AJl|Oo;|�"!k*{.xTL<`�@p -endstream endobj 2427 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2424 0 obj <</Filter/FlateDecode/Length 228>>stream -HTJA yd3v[ by-z͸$?G qV/aF20dyX>wfb\~D% ogBgvTߠ(%q配,dENp%fO� 9x"D(E >bEISFL,ڞ/73 -I.m2AFo:c*L|蚿_`�ISD -endstream endobj 2425 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2422 0 obj <</Filter/FlateDecode/Length 894>>stream -HVn7 } .^Ep$xO!%񐇚r.o8.l2\2\7Ǘ//oq7G>m7: "|p,q0pHY؂BIKK ߙ*0y}\(4`[s_*aF�#; =fk<v;ob9Ql%ha *H<Պ-۹4Q+d';|,y"LG٪ʋFڠ6bI'=fba!D -0#.3c ? ',To'h|Kz|;(FbPƆ͡GҞ6cHCI D۔iFѧQZ26bBFjJ /f>jڙrpjF -XcGCQyY*Du;UJ +!h86#2r( - - -n5 OA -MItOcJ h$>TB%FhZ^u#$jxZ?‡tN{$8#D׭WQjGgu*0*mpAV*gJ) qIJffi~W4hsq5^;gP) d%P`PpkNco_gN*T_XM%/6 dg�jPQ+^FYzwLj)6_'@|p99YCAy)m1k*}~@"GǺ1ͩ& $`pT<;Ck*KG4qsOyt7c=G3<=C>[o -0�}, -endstream endobj 2423 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2420 0 obj <</Filter/FlateDecode/Length 851>>stream -HVKnA )]- DBD(DM@ ϫo0aee?sxal^]^5>M$M|<^>onÛG6ߗB,b߇%xjgS2x%'d&-1~y0XѨ$=.EU>WI\,Ff]9[Vdԥ-@\LsU=:u? xq\/<qjJmFNQ!I"II5DξK-ME-@ǵ<Tݵzn:,Գ;RcR2iƴZOqC{& =¬3/OX(:E"Gb_NG'B17,M"谫J%f#ڞE-҂1In-Fj0SHmcMb',R׉[-Vɱg)\Ā42C+P�j}(ڲ:!V_ sr2XEN> "@볅΢Cn@[a-^10?V8rk&Z-SJғڴ4^"r=L!G0 h(bN8O";J:Y 89Qp�GGweRzMrGn Ag vya[d%W \=F qv.szk0b 81P7jmR<T`u"X  ǩ.!,[+ s;,s- Κwpqxsd~nD7-ֈ9zDp;mz)I#}+%`Y/g.wIuY,�:?H -endstream endobj 2421 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2418 0 obj <</Filter/FlateDecode/Length 289>>stream -HtN0 y -@nJ02$`b@A^hABQwǟ>z7ΖJT fSˋ{wOa_\-Mx:&HlAĘ&  -ѕ蚈1ehUGP)Aèl!{;)-yDEXFʮ]N(m$bfKA!a7NJ@C0K//%B -Cqlf=c]fVS(>Staۙ,Pܷ��cir -endstream endobj 2419 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 23 0 obj <</Count 5/Kids[42 0 R 43 0 R 44 0 R 45 0 R 46 0 R]/Parent 331 0 R/Type/Pages>> endobj 24 0 obj <</Count 5/Kids[47 0 R 48 0 R 49 0 R 50 0 R 51 0 R]/Parent 331 0 R/Type/Pages>> endobj 25 0 obj <</Count 5/Kids[52 0 R 53 0 R 54 0 R 55 0 R 56 0 R]/Parent 331 0 R/Type/Pages>> endobj 191 0 obj <</Count 5/Kids[57 0 R 58 0 R 59 0 R 60 0 R 61 0 R]/Parent 331 0 R/Type/Pages>> endobj 332 0 obj <</Count 5/Kids[192 0 R 193 0 R 194 0 R 333 0 R 334 0 R]/Parent 331 0 R/Type/Pages>> endobj 192 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2428 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2429 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 332 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 193 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2430 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2431 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 332 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 194 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2432 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2433 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 332 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 333 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2434 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2435 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 332 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 334 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2436 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2437 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 332 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2436 0 obj <</Filter/FlateDecode/Length 404>>stream -HtSN$1 +qy92<. 4Z$>`;cju*;vÎΚ,[Sm(||5 v O+we&byl^Ҽ>�X l% -Y=VWZBN$gaq>RH4/yGibU6AVu S`^JY,"8KJ1Ŝ3s#pvŊRu LJ[$4bYċi D6D@ -1)fZRd9ȘB&`J!fJnicr-`0B$rqAFwZ5rRN: *OI)'*j3oE 0C2\/L fگEQFl#iQpu>| 0� -endstream endobj 2437 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2434 0 obj <</Filter/FlateDecode/Length 787>>stream -HtIT1 sʼn3xK3lhHlhW,P;wwtӋwi{uPT?ϟӛ9}맜^~IQM)>_"Fҧ9Omǧ-LO۞ -TuSDGO;Mq{e7t S[*eX!R(QUɨ(#TZ*=ØD%rNުTGR/"U]_ -f+@h2^@!d~ɥZ1b(L;MoW12~Qt L;Qh [?gK3K[T*wV@S/p;nMdbc>SlA,mzkbCX81GhmAR{hu0 -:( VR5]x&f[ -(AS�Crobu&�z03pj4CW2=,z0#&zG;! s- : jCP*c)w3ݹ 2bd  BKш#.HsfA"ǎ WgMNrkl kGkʁs<=:x×hbѥ]U -'vyjKf|�pрSs,~hfx 8E? 3up -\"bT+X:x<a%ؤgP)CH+*qxPXcqY#}<O4<n/G�7I -endstream endobj 2435 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2432 0 obj <</Filter/FlateDecode/Length 1478>>stream -HtWn7 ߯YOJIQ-0daH -{(Qׅxx,Q/ӣ?~x>?ῇ }#<?nW|D&H87?ሹ8jxyn'T ->_ =0!|;O 'D~}MmMZ'rz,ZreR\eh{`-U]#$wHVKDK3dsT\"+хKvB {d%u"BW9D*iޑo{A3wqGb&=ibfMU!r&|5~(GaX~5ЖFWR\MLs%z,Gv>NBq3%ߏUC"BZ"~Ŋvyz Br=̟ J1ݟި[ջy4װFDyϊ`8( 5zum  =^JBˎbS+PrCSeDHFFAKV#qjYᑓ}Ć PTb x8D\HB2,\mT]Y,,U8"UY2Y㚂ءB{)#c] ss7g|1Ѻb>X+|;*]UXm\yG#xC -K -F0O᳌0< T }&M{$ "\#dWx$,t a 5XZvQ躘1]$l bat-1݉_P qIhYMΠx5.CdK1> މ84y/hF,a�ClA#=\Jyf Ҍ[EɗFyIy )[~piݚQ*u-N$Bj/n1ͨĸ@=Og;taX e5 ,C,ÆsV=PgHҐ@:4p[3,#^d_%X-WڮF]Rԕ/2XָaU.aPXcKq{a1~;CVw83]2�:* E;uCگMq*{̴Z!M#I=`nr&43;-'c\ŧieDR|T"OC|`3k|a/Br5#ӸIri2q]y/[e#K>l'j%]>mΔ}6^E#n~<$y=8]U*=1သ-as\BsYXyX>v ͥ\_kBn>>.r"|qCc'ՅfD_e^B pDEx" - -|9o/ys+q?TO`6^,P|4 -3ht/?oϷO~'�T -endstream endobj 2433 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2430 0 obj <</Filter/FlateDecode/Length 466>>stream -Htn1 )?[P QH<@UP[T'ٮh39No}nw>FFu M_ ^<r(Er__=!QI|R:ZX1y u֓~Xfq!?es>WfEE=J=3+~,~"!N"~&I50d& bEC9uPBwGڰߘSC+sxּ1©="q=*}h(=sJ%U vϚWiM?ql .MVz§go[UwMp4ZiIn<O?#lUV/"^`J*<'b7V[HmTNUub~uHH"EsN9_`�Kk -endstream endobj 2431 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2428 0 obj <</Filter/FlateDecode/Length 943>>stream -HtV[7 S߬@#8@0H6l)�bf&Œ_SN?yJm˩ݾy1O?˻|ݞ_(qo3�[EWIpZbɔXˏ7IWgRfm/,ЩMmK&Hzl[+0,?சz.|G"ȘZFvTER["}4+um<a |ȈT**U3&F;iIUV R̮}aR<7&˕be+=�3S> L<=v:911 >(Ҥ: AEzf!nT$uZw98 -܈b_(k940>7#D )Yn�7k7[sѝÁw&  (44i+>bzM rxaŊUoL iWqi { + PW}@qBq`@X7sZ*:TX ^T;t+? \kEbvhɞ&*8p.!4G 5Cl�Np.JH 5dn֑i3TIF,e^]bMm@I8m4h<$U'd񋥍h v'Z^tt@*Ƃ-.pzc5ٺ%eFgeۉeeW2pKj#{$Ҹ-+8V2y8,QL\馣p_ǫyp+ϕGzLիl{X4Z)ƅ6}RhzF2A%cVS\wkDUC1j1f)-i!W7uyW�` -endstream endobj 2429 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 57 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2438 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2439 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 191 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 58 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2440 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2441 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 191 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 59 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2442 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2443 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 191 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 60 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2444 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2445 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 191 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 61 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2446 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2447 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 191 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2446 0 obj <</Filter/FlateDecode/Length 1041>>stream -H|Vn$7 WZHQkI.YF0NREuc <bU$Kcxg|=LSo[ -ڋGKx/?M!Ɂ_+3k &Q�xd+rJ1aA(ı"[x`@,)pűXإ^}8Ԛs5;. U yHlC|E z84c 8p=<4ɴ鑫Ml8X&{,t1G_#q!ϧ5,R׃7=Z˗smzIe?=%\ά,+9Jթx9ftWβ: kj,#Z/-fc5&|lҹXY^0$E5 -y`Jb3I^xhUQp\z xǥxuN !reA29+<`BoP.:~ƜDu$xBh?bSllLd`Wx]30g~x8 Jq Fi)'n&e<^s{^EnR3B`(c`e<W%rTeA5/btBFPHIu@j2nQ -,~~e1H Bة+5�]a&9jrQxl#lPHm-b[b.D:DI)ދ+mH%oMJ}2%PΏBhk1xgly7C/ -gFLg fnIX| G -( aw̪e(fcS G^!{:4dLmH<`dIɮ>mP9ߤ߅5ʟCC-$ȡx~ՠbh3R~Z." sTw0Bg}hqݢ9{C%kV]-6v#~{ An<ƒ/2oeFp_xLHRI;Ppdw?}9=m 0�7_ -endstream endobj 2447 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2444 0 obj <</Filter/FlateDecode/Length 291>>stream -HRJ1|Wf˽jA,R+(Snrm} C 4 trGdmC,6l:<l7U0} $u7 gP*od_N:jK'CE9N,HK/Q( = D%Mx -jUsq'hR2mdDQHRjQTa~hĩxλV'Rrb8?=ǣ4�"e;�"qxp ߴ �7 -endstream endobj 2445 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2442 0 obj <</Filter/FlateDecode/Length 1064>>stream -HtVKn7)xcZv1<J`S!0i_uu.?޼}ۻs9Trm)XO/?I?u9mw.p['AL:Xjd5oy{B,|vѲB!BԂX�o$D5j1EW9(dw8{S*UHڂ kXf -=ߎl<XDBH;PGzSuU쌩#Y-d5W*PJC6dܣ9!hp\Uyr|R bn5N=lMɂSHXk2t[[ /bPDme9tX-T2@_-uCKRteK%37>:'}PaT"Z-/(^袢\�M:ho<A!p"$:P/[I5&Gq- Nj{* i(;Ze $ɏaZ/ S#Ka#z-ț -ewr/,R�RES@ѥ,i�go$YL u1:j0T+lQsD1c곁FkE9`n@\A.<ԝ�NH H$UL2 $a2 jAQMyq--F -  ldh͡YS|91 -%RGF6Fgt?c`!{]\[WRms'Ac/�.Icít.1|ٴ]x)i?MX#B hI&c+Pc<Up -`wq^WE -kG#<".G!K<.0CͯKJ.iK>5~i(b*l7B z`H)ke{!7bՂ ֊TbH8c -!U�xJ! 1U >SBx7܀oN tr 0XSS-B?� -endstream endobj 2443 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2440 0 obj <</Filter/FlateDecode/Length 306>>stream -HN0 ~vιI !�lB q)"$%iwC .V=ˍ,1tR6:uYΏ^%ޭwtWG՛~ ̈0qV>d, - $.`0֢ h21쎪ʪmF&+1:&)YڝLs)RDCffLJ6< Z&!UAmK+K%yKy9zh - K'-U|ly`doE;#آ r y6_ %0Y}2ĕW ]EJ%]/?POӯ5O�o~L -endstream endobj 2441 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2438 0 obj <</Filter/FlateDecode/Length 330>>stream -HN0 ~seI !� !ڸqLVJqvzAp\\)RGC`+<Ֆ`@|7oICV&ç.^t\CsuKz19B%ER;I42Wܙ)c&;ةz㜠*oZT<Tqf[Z1*)s\㙺^QX{?{nCO{9` Zz -5Fb./,` 9)`ՙ PXfM0Mp I cifR~?l< | 0�ܸZ -endstream endobj 2439 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 52 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2448 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2449 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 25 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 53 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2450 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2451 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 25 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 54 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2452 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2453 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 25 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 55 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2454 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2455 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 25 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 56 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2456 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2457 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 25 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2456 0 obj <</Filter/FlateDecode/Length 299>>stream -HlRN0 |Wڎ&t0 11$>�&@>NLD^>nzUvcG;B<B'G)ͽzGHv -)kŇ{(\N֒-5rA -5v|Z(03fɃ}%NJ_f -F1 _bnCA)3\0aV�#Tnr3'9WصPR!!";ZBfD,b\m*YlQ -LȰ0Dyg/GO�C -endstream endobj 2457 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2454 0 obj <</Filter/FlateDecode/Length 623>>stream -HtTMo1 Wx8n *T1G+ZvA-_y&[Ճh799|>1ۣww;l.\.zy{_>~֗Oo6IXaF|pY -qş.N)'<J}T -&N蝄2 \g'[{\{k:*q\ ]#p8J[~Ӯ*7?#kԻͽuPɷJ9 4ZqQB5Kģ!Ɋ\(IA"sb1;J  .$%DHÃzcE$$ġV*R~&Mg=H9j9Zx4g.vؿ;.`3ʴlرv+'XQVxvM7U=lCۯvk[zɣjXӝ\oAZ_DY0NU>yS!Te|U M)*xqYK_K+UEq$5Sїdm}l=]^fֶ(<"l\Bˋe͒oXG*f=Y}| ӧwytU(Rg:Gu4&p\ܻ~+�8 -endstream endobj 2455 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2452 0 obj <</Filter/FlateDecode/Length 628>>stream -HtTnT1 +E<qPXEhIni.BW3>=]{{usml˃jۧX?~:|x{/a@~/OŊ ・˒}Lt1'L1.e-ې(y5p2Vv d*Mf'[Z뱯w2M(fcžta�-E(!.ڀ=e.vFHV;qs{sX-bgC59Qdk s[Ah(HF"r`>+L $ .%+xHÍjcE$V *R~&Eg=&Ok9]J�x®E3.5pwٸ]nn*ZĎ#ʿB,U;(Uswi ׻&m]o=ֆtkjx{#=yu[(?饚šz~kG rE8v\|*PeSUBiu6E̊j/y NCg8TEIj/ɘט&x=lvyޚYEY%\yYY[I_XG"ʪ*|7xpoM -1ms4ZE@}�GNjy'?q�.8 -endstream endobj 2453 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2450 0 obj <</Filter/FlateDecode/Length 623>>stream -HtTMo1 Wx8n *T1G+ZvA-_y&[Ճh799|>1ۣww;l.\.zy{_>~֗Oo6IXaF|pY -qş.N)'<J}T -&N蝄2 \g'[{\{k:*q\ ]#p8J[~Ӯ*7?#kԻͽuPɷJ9 4ZqQB5Kģ!Ɋ\(IA"sb1;J  .$%DHÃzcE$$ġV*R~&Mg=H9j9Zx4g.vؿ;.`3ʴlرv+'XQVxvM7U=lCۯvk[zɣjXӝ\oAZ_DY0NU>yS!Te|U M)*xqYK_K+UEq$5Sїdm}l=]^fֶ(<"l\Bˋe͒oXG*f=Y}| ӧwytU(Rg:Gu4&p\ܻ~+�8 -endstream endobj 2451 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2448 0 obj <</Filter/FlateDecode/Length 626>>stream -HtTMo1 Wx8n *T1G+ZvA-_y&[Ճh799|>1ۣww;l.\.zy{_>~֗Oo6IXaF|pD1Y -qş.N..SNy(>M^9; w djCONndt;!Tw.S.`ŏL%-ZWiH5SO:([?EgC|-Ը(!Úhd%d`.$i 91Hz"RB,K7I*$1!~PςxHӀĕ8 -rhxS qH=K%ʫHs=Rqa.r 6L[;aG^ر ˿By.en?7lׄ}Ss6dn -f>o</zfq5Y[FJmNd8p[S7BXVWPZD"'7 -A*8PUNR3}I Z0س5{kfm#b%X,uQbVГ(?7}GWR.u}֮s4ZG@cGŽOwl_�ހ9| -endstream endobj 2449 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 47 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2458 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2459 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 24 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 48 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2460 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2461 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 24 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 49 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2462 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2463 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 24 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 50 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2464 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2465 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 24 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 51 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2466 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2467 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 24 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2466 0 obj <</Filter/FlateDecode/Length 695>>stream -HtUn1 |WWZ -U +h8nЪgN<g^pg\x[N~^7߼}_.n1 -"LIX^`z<p`9fbnF7"S -.jؐ)x뵙EnvdT$ٿ6sZҁg\(GHw2d h{"F39tX;𲋧ծȒ(fnkoZPJj!{%Sl[ -K{Ehh6SA;-&ddP( b!+SBV"+�C@‹ VƀAhJdfX@)yRa*JdJC=eqWN9];u&#ĉw"ϝ_ <Nk甲ʷ]p 7So`w̙sz w5RLnQ,s^A^<rVs>QX? \ɟ@)`1D橂+|m82 bn5 -.p"fš+/I3dIF{ 2u s^ͩ.]n -nPYӤ+DъiA7l~}YdO,5;w*cZ/R1{XƵ]< [ETyq -H}8pc'X79|r9B,d |!^RqgTTWtԺ ?GO�R}m -endstream endobj 2467 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2464 0 obj <</Filter/FlateDecode/Length 551>>stream -HUێ@ }wb"Kj~I6UdQmon]<]}=D?߼=Fv+!vAhXlX0#.KgebGgo.t*7H\ITJ](RQP.TS(r+~[9etadށY3SJP$Z$Դ6$ ( -QRE O:ll+v흱S@V&EB -vg6)*4PNVJѓc)9tLbX1V4fޔbb[P 7mv^3{^<V, !iT ժ2DdHRےQ1>״kaaswレgb5w/*؉ A2lʹ4ǥ+趝^ЭQtlvϺk"΅~)WoMWPr>Zxؐ"Ůa_K㄀/;7[(XC] 8b~ -0�@ -endstream endobj 2465 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2462 0 obj <</Filter/FlateDecode/Length 263>>stream -HtMN0 >/It6P`XPF3_Nh:P\?U#èf7"tLEg/A\=j<~R^.w'~H*1+bZΔj:Ep^"$hF*>JX$/1ҦBk8C_лh>m*I!DLl&Hbn7$v{<l" ^ymmg9Zm ct{"T~ �y -endstream endobj 2463 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2460 0 obj <</Filter/FlateDecode/Length 263>>stream -HlN0 ~nLBLh@cC>NUQ"srO-ۖnՂYoGdGt6.aW+כ'X}ݕ;c!CdΚ. ,3RoɥT6F4G|Zd/ -phr(dg#gT -U|ok!A�`܌%'TGM`mEh#SBC v, -7@EMW�Tit` -endstream endobj 2461 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2458 0 obj <</Filter/FlateDecode/Length 1387>>stream -HWˎ7 WV[׬\ 0 DRݳ0r7tqZŢHQܧgy޿44}[O?_~|>\(¤UG" C{((Rkoxʮ#x(GvӂD.!V-1Rō}+.lx:Q"A wSgx\d{뼣@ -$pvqW؜P3>y{Ʃϻҗ&M5h40ee }rLp[K?p{w>tiN)F.@.8"2,WŐ:4VW,@&QIG*ϖduR(fC&ttTX>+䨍d3ECZ8We Tew&a,+jRjC٩sj-X <Ð\L 5h4Z&$]π%xCB#Tf,Ǡ -ppdtRG�bcv!\ʐK\C<ygdᱍtb|U! ,BeE>Ȫrr.N]!4KġE6p+"G=uRO  -a08NVjɒi0ƈ'2J:r)ސ1ˇZDKx<y5p?a,)w`qF^ -?ۧH,-`Mp<nB $U1lez@:B,.Ym͢d p[AVMZ2*YKʰY,AV}V]V,BL5\7<ˢ=׍6PZ|j> 1Qbi-ʠE}֢* խ 8Pb=uf>j$z>DVkD]6b;]9oX:e# mU:,yCC}7]*v 6 T9wj:gy*>֑GJ$il)H`k/lM,3L#c+C "OKѐģ35ZCs/x4fݗ!?}J&p\{ehÀL##TC=>5<bߣ�;%߄I~̙dO&~J8Nzz1!1Q -_waMpӜPDzIT~YrItyog!nHc_ GzƼQ16ҎKT 4ͮxB{cz^\zYdd}c(П|;\5o:HĆ�k<Is 1ʽ/8=Jf 'mu<}0p6/;>`� -endstream endobj 2459 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 42 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2468 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2469 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 23 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2470 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 43 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2471 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2472 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 23 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2470 0 R/T1_1 2473 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 44 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2474 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2475 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 23 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 45 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2476 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2477 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 23 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 46 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2478 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2479 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 23 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2478 0 obj <</Filter/FlateDecode/Length 267>>stream -HtPN1 +k -U τ(J̌ǣO ͇Eh_(ptIBϞq}K|~x:yWg:XuS�s+uc9账Ai20*[N;M9;j,Nij "`h Kn42�-uZ9Z=^YY - 9Ҁ<ho, gAmHT*g@ E -p)a -1=ZGCޑn?sK￿|L �+X -endstream endobj 2479 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2476 0 obj <</Filter/FlateDecode/Length 187>>stream -HlQ -0 {\`iqT�"8eM7a!_V`ۊ`QW`,3K<#շ͞acW=A0B&DgRZ]5א Øp)8&fQy,Cg6{9CK.c~f2 # p,4~`�^; -endstream endobj 2477 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2474 0 obj <</Filter/FlateDecode/Length 315>>stream -Ht?O07l'?t*PV |}8n�\M\N ')|2Ijg ^#bC -|h gAHB1>z8zN0jnpBT[(Xe :Ay�%HTDM#..˜CN5Θw'1cF8㷏%C5Jhס3RRiAb6} w{sƥx^@xW*Q_)T]߯Y RSh~ݷP07nX9u-# ԵE>>A/P6R;&50�@L -endstream endobj 2475 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2471 0 obj <</Filter/FlateDecode/Length 176>>stream -Ht -0}b)dnb.]iAb0i rSEʺ"Ѵ!Fodtƛpf?~`_#t$Etj)+݅ѐ9yHta%Rwej!7vq~ےj٤,T \S_�R>9 -endstream endobj 2472 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2470 0 obj <</BaseFont/HUHTVZ+FFDINPro-Regular/Encoding/WinAnsiEncoding/FirstChar 43/FontDescriptor 2480 0 R/LastChar 43/Subtype/Type1/Type/Font/Widths[522]>> endobj 2473 0 obj <</BaseFont/BDHJPL+FFDINPro-Medium/Encoding/WinAnsiEncoding/FirstChar 33/FontDescriptor 2481 0 R/LastChar 63/Subtype/Type1/Type/Font/Widths[332 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 511]>> endobj 2481 0 obj <</Ascent 1172/CapHeight 712/CharSet(/exclam/question)/Descent -211/Flags 32/FontBBox[-118 -211 1170 1172]/FontFamily(FF DIN Pro)/FontFile3 2482 0 R/FontName/BDHJPL+FFDINPro-Medium/FontStretch/Normal/FontWeight 500/ItalicAngle 0/StemV 104/Type/FontDescriptor/XHeight 507>> endobj 2482 0 obj <</Filter/FlateDecode/Length 401/Subtype/Type1C>>stream -Hbd`ab`ddwr -vss (MM,I)f!CG7tI2,SX|_1)9(3=DR1')D+1O! ??G4)'8#5E!R-?$8#@3$(/$3?/1G=7C!-H$#r2*݂C* RLRRAQ%p3\xyG_1s?ޗ }΢QΟ1`&` Y~3 R<Х;*|QˏEs\7GCkw:)>8XNkqvcaTǕ'-6KwV/6,ظ[ܟ ;XAvN?{D �P. -endstream endobj 2480 0 obj <</Ascent 1148/CapHeight 712/CharSet(/plus)/Descent -226/Flags 32/FontBBox[-107 -226 1172 1148]/FontFamily(FF DIN Pro)/FontFile3 2483 0 R/FontName/HUHTVZ+FFDINPro-Regular/FontStretch/Normal/FontWeight 400/ItalicAngle 0/StemV 72/Type/FontDescriptor/XHeight 492>> endobj 2483 0 obj <</Filter/FlateDecode/Length 285/Subtype/Type1C>>stream -Hbd`ab`dd vss ( JM/I,)f!CGTw =߃g|'Ș_PYQ`d``ZT땘PPYTW_WZX䡐_P -V -9IEEzn! -& -)i @XDZ}?c|}O~#Ķﯦocs+1^'zw'N]<v9݅u⏆߳&.`�Cl~ -endstream endobj 2468 0 obj <</Filter/FlateDecode/Length 146>>stream -Ht -0 yqI[nzqH1q'S|/tH]dvڨ S]X}jt3ޕ8.ڍҏE+ LC֙#1=++8kY] *Vk\nJ-�ex-E -endstream endobj 2469 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 18 0 obj <</Count 5/Kids[5 0 R 6 0 R 7 0 R 8 0 R 9 0 R]/Parent 330 0 R/Type/Pages>> endobj 19 0 obj <</Count 5/Kids[10 0 R 11 0 R 12 0 R 13 0 R 26 0 R]/Parent 330 0 R/Type/Pages>> endobj 20 0 obj <</Count 5/Kids[27 0 R 28 0 R 29 0 R 30 0 R 31 0 R]/Parent 330 0 R/Type/Pages>> endobj 21 0 obj <</Count 5/Kids[32 0 R 33 0 R 34 0 R 35 0 R 36 0 R]/Parent 330 0 R/Type/Pages>> endobj 22 0 obj <</Count 5/Kids[37 0 R 38 0 R 39 0 R 40 0 R 41 0 R]/Parent 330 0 R/Type/Pages>> endobj 37 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2484 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2485 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 22 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 38 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2486 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2487 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 22 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 39 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2488 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2489 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 22 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 40 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2490 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2491 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 22 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</C0_0 2492 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 41 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2493 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2494 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 22 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2473 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2493 0 obj <</Filter/FlateDecode/Length 143>>stream -HT1 @ :xIDI赺Xpt<$|%"#BӚPF ~{d/t2o뙎#c=AsD`eH6I6R!}⤔=o]W|@auX> �' -endstream endobj 2494 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2490 0 obj <</Filter/FlateDecode/Length 145>>stream -HT -@ D[.n=Ղ.2d /̄. u.e$lpNWz,UZA0iSLR9"}86,ro/أX1[ \y'?}�V_(a -endstream endobj 2491 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2492 0 obj <</BaseFont/IDVEJX+KozGoPr6N-Medium/DescendantFonts 2495 0 R/Encoding/Identity-H/Subtype/Type0/Type/Font>> endobj 2495 0 obj [2496 0 R] endobj 2496 0 obj <</BaseFont/IDVEJX+KozGoPr6N-Medium/CIDSystemInfo 2497 0 R/DW 1000/FontDescriptor 2498 0 R/Subtype/CIDFontType0/Type/Font>> endobj 2497 0 obj <</Ordering(Japan1)/Registry(Adobe)/Supplement 6>> endobj 2498 0 obj <</Ascent 1418/CIDSet 2499 0 R/CapHeight 763/Descent -374/Flags 4/FontBBox[-538 -374 1254 1418]/FontFamily(Kozuka Gothic Pr6N M)/FontFile3 2500 0 R/FontName/IDVEJX+KozGoPr6N-Medium/FontStretch/Normal/FontWeight 500/ItalicAngle 0/StemV 116/Type/FontDescriptor/XHeight 551>> endobj 2499 0 obj <</Filter/FlateDecode/Length 15>>stream -Hj`I �xw� -endstream endobj 2500 0 obj <</Filter/FlateDecode/Length 544/Subtype/CIDFontType0C>>stream -H|AhP_6QXX{ڋvK+]ن:Z5k5)/PxSы6Ǽ6TQ{�0 ;ta~Ԃv3-ԫl0N:q;Ϝ`ߎkquz8~(ME x~I| -jZ(ee! -+3Y4x - UͩE4"X@3(QLwzEB9(+E+F$!W7`DqU"?>MBWUţ:TyEDlJ9$߷L簊R_5�=a.?ًL.CݝFI:ot{_8KA5Vs\SGkp]szXoT<a=?ÿbz?rt -h:w}u I~]74=0 SSo4C[0|~ =~/��CF -endstream endobj 2488 0 obj <</Filter/FlateDecode/Length 162>>stream -HT1 @ лwv*HED;U}<$|=u!GBSogA+K73a/")8ش<d@`od6ʔyTV}̊ʢ0&]Zғ정G�zw- -endstream endobj 2489 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2486 0 obj <</Filter/FlateDecode/Length 145>>stream -HTA 0 9%Y;]U/ x4[ < _x/tHgl;hdFwv .#w=~a0UbVA0iSLRT@ƕ5roq[T\m,0zG�7N(r -endstream endobj 2487 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2484 0 obj <</Filter/FlateDecode/Length 159>>stream -HTN -@ ۡr]bbAAS@G^^^#fi=B+hq@h[Y -oV{{ٚD>`(b��c<3gFLj 2ɡ\072օCRf:J :a"$$`� - -endstream endobj 2485 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 32 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2501 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2502 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 21 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 33 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2503 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2504 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 21 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 34 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2505 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2506 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 21 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 35 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2507 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2508 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 21 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 36 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2509 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2510 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 21 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2509 0 obj <</Filter/FlateDecode/Length 144>>stream -HT -@ D`t[[v[lbcOZX̺ H0:y36Gz3JHz6і+\agmw t' yQL1&1F*#yl[vm]Y -VzNӣ��4Y(P -endstream endobj 2510 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2507 0 obj <</Filter/FlateDecode/Length 144>>stream -HTA 0 9&YvuӋC{aAy/:>06m@dTFwV+8O;@}WQy11RpBzkIƹEYW; 1ƥޡ#�8A( -endstream endobj 2508 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2505 0 obj <</Filter/FlateDecode/Length 157>>stream -HT EAثL}q1&~A4X$Ә6{A".ۈLArpS6_zw$^z'D`0<dɞI$%h&h^w0+όU\-Z/?|-�m0 -endstream endobj 2506 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2503 0 obj <</Filter/FlateDecode/Length 159>>stream -HT -0$VX(�(&@ Th钨4lpY+H\+FI_)=1CpL0Le%RD]KPNKo-ڭ2NVW|KHoo�1} -endstream endobj 2504 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2501 0 obj <</Filter/FlateDecode/Length 193>>stream -H\O91 - ;-р pvYn:ټCXlz/axPܮ׏]'~ZM#MҔ%0P3zhhQp`|ԜE5s_|KA*qҁĬC#1STϺc]$t)f"'2V '~�Ȓ? -endstream endobj 2502 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 27 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2511 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2512 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 20 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 28 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2513 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2514 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 20 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 29 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2515 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2516 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 20 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 30 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2517 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2518 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 20 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 31 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2519 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2520 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 20 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2519 0 obj <</Filter/FlateDecode/Length 177>>stream -HTM -0s@4[[ucQ�uaI[12dx QU[aݦf3 -f:" -g|&G槝 z8�c;wtT4&V4^zȣ\ }%]x/).ȥ`]+%XZyw}`�\< -endstream endobj 2520 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2517 0 obj <</Filter/FlateDecode/Length 508>>stream -HTQ1 )rxlI_+T*؟-h d2Qgb;{N|<ZV>_hׯn'O?-;^EȷբVLY$fk#i*Ԫ^AK (GrÎRU בpnk+0i}kD%1B $ X(}B5Oa\l�<L&:-3ַaBowTj"aکf4h+MB c[є 5݄ vBT y4٤) 0&X~'Vr^G5i l2(uS֡t3T3 3_-{go#H́jj'kMB2Y:I(*e&HSR<^hnCALs(sZvr9 -s:U+Sd<L0I&tW;l`�uBz -endstream endobj 2518 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2515 0 obj <</Filter/FlateDecode/Length 555>>stream -HtTn1 S>78nPP@/q|6 ϱ>XcN1T͇[/%?O%N7 Ncc=a[X ͪw19_64*E�H7bsthмiI9}vw7b`dεS35*sdhLý+ ,*s!iI"FW&P`]6�ik:h[4 pumҜЂ@tHvU yJ\ތQnMIgb a yB0W�$.֘@8 AIm:=qetŏ:c]"4+B^1;@x^gYԳU:e+!x%?f9<WuS:D?;cZp k.Y;lWƂBK<Rt mkQN9A"߻o& JXhj5!JXQ5]P%.N��Z -endstream endobj 2516 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2513 0 obj <</Filter/FlateDecode/Length 2566>>stream -HtM$ q@D=co06$E|{RdfdѕAE//a_ǯyK6~žzX_x?[qJl׿~._X쥍8?ۦW߶i퇵3ǾY )33߶#31ggemþOJıN|Eݶ{i KH -׳6~s3[)gu~sDܴ}Zt_>[SY -ߛ.wkҙJr3*<p%t}IN7+A)!b^R kRU2iogm/R{. -C.uGKrmrQ -{$$!/ad &Y% -E^Kw-D)g |tM)[JP -AW6W Ehd+!iL\ƼtSrZ%8s܋9<GVDRID [I_rT.%.ԎAMm='S!3ÎZKW*C$"[OȍՕZʟz\9> -$;?y|򓏸%)y谪`Rv%M.S] -IR̂%W;}e KFʥ3fnL�xf�N) 3t[@+'qH+Oe Wޥ?)+\8"=Vb]8׽(e24^ߦp> t^bLw ~unmB-{==ŪKmYpo gvLAo%5gJ>JgdpdJ".uj 4R+) -͓X;:*MG^PL5s u5ʲؑKR%R\e /4 $.<(JiϸysǣT?'0b.+|s{xr5и yB9^-,i(mHeȒ!! >fwfLٳt/Ő嗬$7BSr .lw@SMu.H0;(߼렘IM$(T+x_9D"4YjPl#~R+^zjAe99LnE<XH2/O~qW\uuVTv |Qd';Yt$yѿ(u~ʙ^kT2쩼 yQ+9(~ˁ]~8nɼU y6Bg~GܰFct-k;USSt\tXo{uk];f}2\eVN Yڄr9|Ik#@uZоks޶Ta,*o-UUISS\ -V]k2?G08{tPl!NC,Tgˣ\ '_J|7z2+$!BS7>! ^Q"8~ -.HsqvsL0mPtX=I@U )M -| ~_qy@+Lt#IFd)IS5 "bnQ:G: >7: ÀN%6z1Gq]&@P -FFX({ve;SIJ׳U;K145꺥עCݫh!GA<!+[S}ͦpsݣuq*m+GpcK>XyGh_DnG5Cj޺SrYL{ȫCdk\XPd Ս/sV5UE㈍MOEd69{ PSYҍhPKoѮ}St.}F#{ER^np;TE . j44(=S}bC06i܉\o8 F"=D6ӌ4(dNQ*TcwԊz+5a4E5y1AԩQ>!�Inn}-4GQ5F;m(ᲦɖUtG#2tv/ȵٔsԻ >xM1y7 x/wKPd&'/UO>57UsT; ]#m:0yRoU~.BHe_ -tItLe2{0N1vn -R$GF[[5lО@�!)2 ɕ<+t !aqv 8 -ԗLQ6*~®J6EKlB4g%!IHZWEmVق^7E[,Z*u!/\zr|9*]Egt,5gE!9J^J&XB$HcɂGgS潭"?L,(B&4G}DrozfJ * -vXטXb8NqLQSr)rDP{@6Y 8L S(,$ǯ_v~/�'59 -endstream endobj 2514 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2511 0 obj <</Filter/FlateDecode/Length 205>>stream -Ht -0 yinE0t^l`&K'ܖ(7%l^",6݀фuDv#\Gr1ίP$t/QQd-n)d Gё2@C18|bKL5-)21b irQM;Sԑ~Zt70nL6]~p>��PT -endstream endobj 2512 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 10 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2521 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2522 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 19 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 11 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2523 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2524 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 19 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 12 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2525 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2526 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 19 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Font<</T1_0 2343 0 R>>/ProcSet[/PDF/Text]/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 13 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2527 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2528 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 19 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 26 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2529 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2530 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 19 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2529 0 obj <</Filter/FlateDecode/Length 236>>stream -HJ1 E&mg:}uVEEqߴqP4iozmG8ی7K2K'b!iJx;{ûoőyψO-e|I% -X -[!!Nދ#B&d+5sIl_@F8a-ITO6"p=6 +u"rԖ|ɤd%uhhgW)^eO�גa -endstream endobj 2530 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2527 0 obj <</Filter/FlateDecode/Length 833>>stream -HtUA7 +qDk֎/6E>xcSzf4"Y,_S+?{*OloqͿ_?8~/k+>^~~iݷMS<o.9rqåAr}9Q_O;tAh,ףJiJnVط-4c&S.Bl@uTc~Z\nhr+eb0GQV/J[~ U:ނ�6j*vr_Q&Y'.ȋ:n5 Nt#Z(%!h2R S/GU3�@q̬T3IXË -<VdO@GE0Gd9BČ&Lvp\V^8zfHx}nG KfWf"5Q3,KrJhkzo`7w0!#oE|/1, EZpzbH׊ÈlGnє`ab$ -t+>5d$QP.14J$vw)A|F-4y=(`cJy+g\[!ׁPq tR<o$NJ.Dwc&niM\#k;䈱iSN,3:|&"S!j˽T ٣U ᐸ,3yE$Su#4޼8Gy8Ƀ58 }dUC;b^6 UOΘ!VIF�+�-hz[xGJi܊\%I-irBLB n 6c_R>/W�R -endstream endobj 2528 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2525 0 obj <</Filter/FlateDecode/Length 227>>stream -HTN1 w?Gα$J@J#12TR }&@-߉{Э|@Xjq Q]+gnaW<q~Xì`I[sE޹=r[/(PR&SS,#܅ru /9|Dd=1x&mS>Ih:{ #4iN35!QR#tɂL>cU�D -endstream endobj 2526 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2523 0 obj <</Filter/FlateDecode/Length 226>>stream -HTMKA 9f|\[+bJWi=͸7y3tq97#?ٵryg|7;çNlYb --.&mUyaCuY) -{dk/SbN(P֬X' -~YsG𥧔{͔΋ƈX=~gn}$IC:A&P%x0 (/6|2ߏ 0�D -endstream endobj 2524 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2521 0 obj <</Filter/FlateDecode/Length 227>>stream -HTOJ1 +rCӤiӣ;.SXAtaq]Àa@WagJf vm\^x2ۉq aê`˱٤|g6AVJjr -+5+ nu=f{Bo';PzroL] (iJ(E#q%R&M@SƗ 4BMӌ -SeG�� DH -endstream endobj 2522 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 5 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2531 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2532 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 18 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 6 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2533 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2534 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 18 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2344 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 7 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2535 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2536 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 18 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 8 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2537 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2538 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 18 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 9 0 obj <</ArtBox[0.0 0.0 384.0 384.0]/BleedBox[0.0 0.0 384.0 384.0]/Contents 2539 0 R/CropBox[0.0 0.0 384.0 384.0]/Group 2540 0 R/LastModified(D:20190425160752+02'00')/MediaBox[0.0 0.0 384.0 384.0]/Parent 18 0 R/PieceInfo<</Illustrator 2332 0 R>>/Resources<</ExtGState<</GS0 2333 0 R/GS1 2334 0 R>>/Properties<</MC0 2321 0 R/MC1 2322 0 R/MC2 2323 0 R>>/XObject<</Fm0 2404 0 R>>>>/TrimBox[0.0 0.0 384.0 384.0]/Type/Page>> endobj 2539 0 obj <</Filter/FlateDecode/Length 185>>stream -HTJA 6LgEj@ ]KoE%N/ n<&z),.օ6? =} _Aק3!ؓ˖^|\%E Q-h~@_E̕5eD+gꝙkS.Vq פwpl>}r_�4 -endstream endobj 2540 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2537 0 obj <</Filter/FlateDecode/Length 535>>stream -HUn@ }W؞+[R$>Eh jy9L6IӾZm2>c{2|>puzwqäI _Ϸ7py-t _? .~v MN\v~c񝪳Vg M2&.9Sk",59L^8$YyV}9X%s6~zdQҲ3 @5y@\[覐MF;[v%EaP5S֬)T3L,W."ENb @G2m=o5 be3nn柦K.l݆2&BwYЄzԘX><Z=N-c4rޜ (6NEI[{N)dVO8klLAhJ!#Ua#_bQbX V+ȱSFDvE:J~='\-Ś|:cf@Lc,]¬5GCd8[-c0@uv;,ցie W��Zq -endstream endobj 2538 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2535 0 obj <</Filter/FlateDecode/Length 646>>stream -HUn1 }vlBH|@sdvf/qrNvnwgb醴WxIqbKhO_/vw0 .'qt9Uߝ)'fJAL,bݼCwt7=&OQ8;D}t sB%$[4c10'oQԼB``{gWca7۪L&&ڭ")XStMKueM^ħ,ԴRbi)gy)ڐSY>1pđIСL녉[W0"m',TN -/ں�ؗY$T*X)b`Hz7J9"sFgN DZl/x0JWC6X b>G$!85kt<W}�4e&kF -ce1D%<H(")xApb'Μ + 1VrfP 7n=3pʹ$a!no8#))%QzE͠fGPR+0J;Q8(<Cu44A; /x^D,YP΄P.DimD]LhF3�Fe -endstream endobj 2536 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2533 0 obj <</Filter/FlateDecode/Length 553>>stream -HUێ@ }Wı=Wb"+ -uA<O&io&c9Ǘq熻77;׽cU2;v~@?޳{wOn~vMC;qtUΜŜ5R.N$S-$WXN{Ƌ<E4&=<ue^ -Ҍ|Mx?t=PԼlB`L5zE\OGO -ݸ\/\(ܚU41ҮɨLbP LtzI6."'ʬKInd5nb,v$v04JZm(c,dz1mMx<ɑI0G<E%y'޻p&}PD658o^jN򪓂EFkX�HHyH3PtM -Uӈc(j3\ϫ b)#,NŅ -x�𠓳54�ȍ?W4_$JFUQ24/EN+EEQկ ld0BBF7BՓ-ml_}G�jV_ -endstream endobj 2534 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 2531 0 obj <</Filter/FlateDecode/Length 389>>stream -HTKN1 xlmH -"q -Z\g&aڲcMb~y7shsB~亿)o/W]gf9bi.,b cKɣlC)�sĜt Kɘ<]Fi`3EzX?*m +=JLJ4kh@H(.էZ!#GZ�QWhٚDx6@h=D0rbSD.SM"_dVƌ0T{U脓jWةR%eM1ڐF1HzsiTs{DZ:c+~9'#Mֿq,݊bO:ni�:  -endstream endobj 2532 0 obj <</CS/DeviceRGB/I false/K false/S/Transparency>> endobj 14 0 obj <</Intent 89 0 R/Name(Sfondo)/Type/OCG/Usage 90 0 R>> endobj 15 0 obj <</Intent 91 0 R/Name(Icone)/Type/OCG/Usage 92 0 R>> endobj 16 0 obj <</Intent 93 0 R/Name(Guide)/Type/OCG/Usage 94 0 R>> endobj 187 0 obj <</Intent 217 0 R/Name(Sfondo)/Type/OCG/Usage 218 0 R>> endobj 188 0 obj <</Intent 219 0 R/Name(Icone)/Type/OCG/Usage 220 0 R>> endobj 189 0 obj <</Intent 221 0 R/Name(Guide)/Type/OCG/Usage 222 0 R>> endobj 326 0 obj <</Intent 357 0 R/Name(Sfondo)/Type/OCG/Usage 358 0 R>> endobj 327 0 obj <</Intent 359 0 R/Name(Icone)/Type/OCG/Usage 360 0 R>> endobj 328 0 obj <</Intent 361 0 R/Name(Guide)/Type/OCG/Usage 362 0 R>> endobj 477 0 obj <</Intent 560 0 R/Name(Sfondo)/Type/OCG/Usage 561 0 R>> endobj 478 0 obj <</Intent 562 0 R/Name(Icone)/Type/OCG/Usage 563 0 R>> endobj 476 0 obj <</Intent 564 0 R/Name(Guide)/Type/OCG/Usage 565 0 R>> endobj 798 0 obj <</Intent 811 0 R/Name(Guide)/Type/OCG/Usage 812 0 R>> endobj 799 0 obj <</Intent 813 0 R/Name(Sfondo)/Type/OCG/Usage 814 0 R>> endobj 800 0 obj <</Intent 815 0 R/Name(Icone)/Type/OCG/Usage 816 0 R>> endobj 951 0 obj <</Intent 964 0 R/Name(Guide)/Type/OCG/Usage 965 0 R>> endobj 952 0 obj <</Intent 966 0 R/Name(Sfondo)/Type/OCG/Usage 967 0 R>> endobj 953 0 obj <</Intent 968 0 R/Name(Icone)/Type/OCG/Usage 969 0 R>> endobj 1106 0 obj <</Intent 1149 0 R/Name(Guide)/Type/OCG/Usage 1150 0 R>> endobj 1107 0 obj <</Intent 1151 0 R/Name(Sfondo)/Type/OCG/Usage 1152 0 R>> endobj 1108 0 obj <</Intent 1153 0 R/Name(Icone)/Type/OCG/Usage 1154 0 R>> endobj 1321 0 obj <</Intent 1347 0 R/Name(Guide)/Type/OCG/Usage 1348 0 R>> endobj 1322 0 obj <</Intent 1349 0 R/Name(Sfondo)/Type/OCG/Usage 1350 0 R>> endobj 1323 0 obj <</Intent 1351 0 R/Name(Icone)/Type/OCG/Usage 1352 0 R>> endobj 1519 0 obj <</Intent 1545 0 R/Name(Guide)/Type/OCG/Usage 1546 0 R>> endobj 1520 0 obj <</Intent 1547 0 R/Name(Sfondo)/Type/OCG/Usage 1548 0 R>> endobj 1521 0 obj <</Intent 1549 0 R/Name(Icone)/Type/OCG/Usage 1550 0 R>> endobj 1717 0 obj <</Intent 1746 0 R/Name(Guide)/Type/OCG/Usage 1747 0 R>> endobj 1718 0 obj <</Intent 1748 0 R/Name(Sfondo)/Type/OCG/Usage 1749 0 R>> endobj 1719 0 obj <</Intent 1750 0 R/Name(Icone)/Type/OCG/Usage 1751 0 R>> endobj 1918 0 obj <</Intent 1946 0 R/Name(Guide)/Type/OCG/Usage 1947 0 R>> endobj 1919 0 obj <</Intent 1948 0 R/Name(Sfondo)/Type/OCG/Usage 1949 0 R>> endobj 1920 0 obj <</Intent 1950 0 R/Name(Icone)/Type/OCG/Usage 1951 0 R>> endobj 2118 0 obj <</Intent 2151 0 R/Name(Guide)/Type/OCG/Usage 2152 0 R>> endobj 2119 0 obj <</Intent 2153 0 R/Name(Sfondo)/Type/OCG/Usage 2154 0 R>> endobj 2120 0 obj <</Intent 2155 0 R/Name(Icone)/Type/OCG/Usage 2156 0 R>> endobj 2155 0 obj [/View/Design] endobj 2156 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2153 0 obj [/View/Design] endobj 2154 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2151 0 obj [/View/Design] endobj 2152 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1950 0 obj [/View/Design] endobj 1951 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1948 0 obj [/View/Design] endobj 1949 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1946 0 obj [/View/Design] endobj 1947 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1750 0 obj [/View/Design] endobj 1751 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1748 0 obj [/View/Design] endobj 1749 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1746 0 obj [/View/Design] endobj 1747 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1549 0 obj [/View/Design] endobj 1550 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1547 0 obj [/View/Design] endobj 1548 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1545 0 obj [/View/Design] endobj 1546 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1351 0 obj [/View/Design] endobj 1352 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1349 0 obj [/View/Design] endobj 1350 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1347 0 obj [/View/Design] endobj 1348 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1153 0 obj [/View/Design] endobj 1154 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1151 0 obj [/View/Design] endobj 1152 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 1149 0 obj [/View/Design] endobj 1150 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 968 0 obj [/View/Design] endobj 969 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 966 0 obj [/View/Design] endobj 967 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 964 0 obj [/View/Design] endobj 965 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 815 0 obj [/View/Design] endobj 816 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 813 0 obj [/View/Design] endobj 814 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 811 0 obj [/View/Design] endobj 812 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 564 0 obj [/View/Design] endobj 565 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 562 0 obj [/View/Design] endobj 563 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 560 0 obj [/View/Design] endobj 561 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 361 0 obj [/View/Design] endobj 362 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 359 0 obj [/View/Design] endobj 360 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 357 0 obj [/View/Design] endobj 358 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 221 0 obj [/View/Design] endobj 222 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 219 0 obj [/View/Design] endobj 220 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 217 0 obj [/View/Design] endobj 218 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 93 0 obj [/View/Design] endobj 94 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 91 0 obj [/View/Design] endobj 92 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 89 0 obj [/View/Design] endobj 90 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 23.0)/Subtype/Artwork>>>> endobj 2324 0 obj [2323 0 R 2322 0 R 2321 0 R] endobj 2541 0 obj <</CreationDate(D:20190321162652+01'00')/Creator(Adobe Illustrator CC 23.0 \(Windows\))/ModDate(D:20190425160753+02'00')>> endobj xref -0 2542 -0000000004 65535 f -0000000016 00000 n -0000000800 00000 n -0000036585 00000 n -0000000017 00000 f -0000343129 00000 n -0000343558 00000 n -0000343987 00000 n -0000344416 00000 n -0000344845 00000 n -0000338409 00000 n -0000338881 00000 n -0000339353 00000 n -0000339825 00000 n -0000348277 00000 n -0000348347 00000 n -0000348416 00000 n -0000000062 00000 f -0000322162 00000 n -0000322253 00000 n -0000322349 00000 n -0000322445 00000 n -0000322541 00000 n -0000291140 00000 n -0000291236 00000 n -0000291332 00000 n -0000340255 00000 n -0000331552 00000 n -0000331982 00000 n -0000332412 00000 n -0000332842 00000 n -0000333272 00000 n -0000327826 00000 n -0000328256 00000 n -0000328686 00000 n -0000329116 00000 n -0000329588 00000 n -0000322637 00000 n -0000323109 00000 n -0000323581 00000 n -0000324053 00000 n -0000324525 00000 n -0000316262 00000 n -0000316734 00000 n -0000317220 00000 n -0000317692 00000 n -0000318122 00000 n -0000310257 00000 n -0000310687 00000 n -0000311117 00000 n -0000311547 00000 n -0000311977 00000 n -0000304445 00000 n -0000304917 00000 n -0000305389 00000 n -0000305861 00000 n -0000306333 00000 n -0000298561 00000 n -0000298992 00000 n -0000299423 00000 n -0000299854 00000 n -0000300285 00000 n -0000000063 00000 f -0000000064 00000 f -0000000065 00000 f -0000000066 00000 f -0000000067 00000 f -0000000068 00000 f -0000000069 00000 f -0000000070 00000 f -0000000071 00000 f -0000000072 00000 f -0000000073 00000 f -0000000074 00000 f -0000000075 00000 f -0000000076 00000 f -0000000077 00000 f -0000000078 00000 f -0000000079 00000 f -0000000080 00000 f -0000000081 00000 f -0000000082 00000 f -0000000083 00000 f -0000000084 00000 f -0000000085 00000 f -0000000086 00000 f -0000000087 00000 f -0000000088 00000 f -0000000095 00000 f -0000355088 00000 n -0000355119 00000 n -0000354972 00000 n -0000355003 00000 n -0000354856 00000 n -0000354887 00000 n -0000000096 00000 f -0000000097 00000 f -0000000098 00000 f -0000000099 00000 f -0000000100 00000 f -0000000101 00000 f -0000000102 00000 f -0000000103 00000 f -0000000104 00000 f -0000000105 00000 f -0000000106 00000 f -0000000107 00000 f -0000000108 00000 f -0000000109 00000 f -0000000110 00000 f -0000000111 00000 f -0000000112 00000 f -0000000113 00000 f -0000000114 00000 f -0000000115 00000 f -0000000116 00000 f -0000000117 00000 f -0000000118 00000 f -0000000119 00000 f -0000000120 00000 f -0000000121 00000 f -0000000122 00000 f -0000000123 00000 f -0000000124 00000 f -0000000125 00000 f -0000000126 00000 f -0000000127 00000 f -0000000128 00000 f -0000000129 00000 f -0000000130 00000 f -0000000131 00000 f -0000000132 00000 f -0000000133 00000 f -0000000134 00000 f -0000000135 00000 f -0000000136 00000 f -0000000137 00000 f -0000000138 00000 f -0000000139 00000 f -0000000140 00000 f -0000000141 00000 f -0000000142 00000 f -0000000143 00000 f -0000000144 00000 f -0000000145 00000 f -0000000146 00000 f -0000000147 00000 f -0000000148 00000 f -0000000149 00000 f -0000000150 00000 f -0000000151 00000 f -0000000152 00000 f -0000000153 00000 f -0000000154 00000 f -0000000155 00000 f -0000000156 00000 f -0000000157 00000 f -0000000158 00000 f -0000000159 00000 f -0000000160 00000 f -0000000161 00000 f -0000000162 00000 f -0000000163 00000 f -0000000164 00000 f -0000000165 00000 f -0000000166 00000 f -0000000167 00000 f -0000000168 00000 f -0000000169 00000 f -0000000170 00000 f -0000000171 00000 f -0000000172 00000 f -0000000173 00000 f -0000000174 00000 f -0000000175 00000 f -0000000176 00000 f -0000000177 00000 f -0000000178 00000 f -0000000179 00000 f -0000000180 00000 f -0000000181 00000 f -0000000182 00000 f -0000000183 00000 f -0000000184 00000 f -0000000185 00000 f -0000000186 00000 f -0000000190 00000 f -0000348485 00000 n -0000348558 00000 n -0000348630 00000 n -0000000195 00000 f -0000291428 00000 n -0000291627 00000 n -0000292059 00000 n -0000292491 00000 n -0000000196 00000 f -0000000197 00000 f -0000000198 00000 f -0000000199 00000 f -0000000200 00000 f -0000000201 00000 f -0000000202 00000 f -0000000203 00000 f -0000000204 00000 f -0000000205 00000 f -0000000206 00000 f -0000000207 00000 f -0000000208 00000 f -0000000209 00000 f -0000000210 00000 f -0000000211 00000 f -0000000212 00000 f -0000000213 00000 f -0000000214 00000 f -0000000215 00000 f -0000000216 00000 f -0000000223 00000 f -0000354738 00000 n -0000354770 00000 n -0000354620 00000 n -0000354652 00000 n -0000354502 00000 n -0000354534 00000 n -0000000224 00000 f -0000000225 00000 f -0000000226 00000 f -0000000227 00000 f -0000000228 00000 f -0000000229 00000 f -0000000230 00000 f -0000000231 00000 f -0000000232 00000 f -0000000233 00000 f -0000000234 00000 f -0000000235 00000 f -0000000236 00000 f -0000000237 00000 f -0000000238 00000 f -0000000239 00000 f -0000000240 00000 f -0000000241 00000 f -0000000242 00000 f -0000000243 00000 f -0000000244 00000 f -0000000245 00000 f -0000000246 00000 f -0000000247 00000 f -0000000248 00000 f -0000000249 00000 f -0000000250 00000 f -0000000251 00000 f -0000000252 00000 f -0000000253 00000 f -0000000254 00000 f -0000000255 00000 f -0000000256 00000 f -0000000257 00000 f -0000000258 00000 f -0000000259 00000 f -0000000260 00000 f -0000000261 00000 f -0000000262 00000 f -0000000263 00000 f -0000000264 00000 f -0000000265 00000 f -0000000266 00000 f -0000000267 00000 f -0000000268 00000 f -0000000269 00000 f -0000000270 00000 f -0000000271 00000 f -0000000272 00000 f -0000000273 00000 f -0000000274 00000 f -0000000275 00000 f -0000000276 00000 f -0000000277 00000 f -0000000278 00000 f -0000000279 00000 f -0000000280 00000 f -0000000281 00000 f -0000000282 00000 f -0000000283 00000 f -0000000284 00000 f -0000000285 00000 f -0000000286 00000 f -0000000287 00000 f -0000000288 00000 f -0000000289 00000 f -0000000290 00000 f -0000000291 00000 f -0000000292 00000 f -0000000293 00000 f -0000000294 00000 f -0000000295 00000 f -0000000296 00000 f -0000000297 00000 f -0000000298 00000 f -0000000299 00000 f -0000000300 00000 f -0000000301 00000 f -0000000302 00000 f -0000000303 00000 f -0000000304 00000 f -0000000305 00000 f -0000000306 00000 f -0000000307 00000 f -0000000308 00000 f -0000000309 00000 f -0000000310 00000 f -0000000311 00000 f -0000000312 00000 f -0000000313 00000 f -0000000314 00000 f -0000000315 00000 f -0000000316 00000 f -0000000317 00000 f -0000000318 00000 f -0000000319 00000 f -0000000320 00000 f -0000000321 00000 f -0000000322 00000 f -0000000323 00000 f -0000000324 00000 f -0000000325 00000 f -0000000329 00000 f -0000348702 00000 n -0000348775 00000 n -0000348847 00000 n -0000000337 00000 f -0000036655 00000 n -0000036751 00000 n -0000291525 00000 n -0000292923 00000 n -0000293355 00000 n -0000285055 00000 n -0000285487 00000 n -0000000338 00000 f -0000000339 00000 f -0000000340 00000 f -0000000341 00000 f -0000000342 00000 f -0000000343 00000 f -0000000344 00000 f -0000000345 00000 f -0000000346 00000 f -0000000347 00000 f -0000000348 00000 f -0000000349 00000 f -0000000350 00000 f -0000000351 00000 f -0000000352 00000 f -0000000353 00000 f -0000000354 00000 f -0000000355 00000 f -0000000356 00000 f -0000000363 00000 f -0000354384 00000 n -0000354416 00000 n -0000354266 00000 n -0000354298 00000 n -0000354148 00000 n -0000354180 00000 n -0000000364 00000 f -0000000365 00000 f -0000000366 00000 f -0000000367 00000 f -0000000368 00000 f -0000000369 00000 f -0000000370 00000 f -0000000371 00000 f -0000000372 00000 f -0000000373 00000 f -0000000374 00000 f -0000000375 00000 f -0000000376 00000 f -0000000377 00000 f -0000000378 00000 f -0000000379 00000 f -0000000380 00000 f -0000000381 00000 f -0000000382 00000 f -0000000383 00000 f -0000000384 00000 f -0000000385 00000 f -0000000386 00000 f -0000000387 00000 f -0000000388 00000 f -0000000389 00000 f -0000000390 00000 f -0000000391 00000 f -0000000392 00000 f -0000000393 00000 f -0000000394 00000 f -0000000395 00000 f -0000000396 00000 f -0000000397 00000 f -0000000398 00000 f -0000000399 00000 f -0000000400 00000 f -0000000401 00000 f -0000000402 00000 f -0000000403 00000 f -0000000404 00000 f -0000000405 00000 f -0000000406 00000 f -0000000407 00000 f -0000000408 00000 f -0000000409 00000 f -0000000410 00000 f -0000000411 00000 f -0000000412 00000 f -0000000413 00000 f -0000000414 00000 f -0000000415 00000 f -0000000416 00000 f -0000000417 00000 f -0000000418 00000 f -0000000419 00000 f -0000000420 00000 f -0000000421 00000 f -0000000422 00000 f -0000000423 00000 f -0000000424 00000 f -0000000425 00000 f -0000000426 00000 f -0000000427 00000 f -0000000428 00000 f -0000000429 00000 f -0000000430 00000 f -0000000431 00000 f -0000000432 00000 f -0000000433 00000 f -0000000434 00000 f -0000000435 00000 f -0000000436 00000 f -0000000437 00000 f -0000000438 00000 f -0000000439 00000 f -0000000440 00000 f -0000000441 00000 f -0000000442 00000 f -0000000443 00000 f -0000000444 00000 f -0000000445 00000 f -0000000446 00000 f -0000000447 00000 f -0000000448 00000 f -0000000449 00000 f -0000000450 00000 f -0000000451 00000 f -0000000452 00000 f -0000000453 00000 f -0000000454 00000 f -0000000455 00000 f -0000000456 00000 f -0000000457 00000 f -0000000458 00000 f -0000000459 00000 f -0000000460 00000 f -0000000461 00000 f -0000000462 00000 f -0000000463 00000 f -0000000464 00000 f -0000000465 00000 f -0000000466 00000 f -0000000467 00000 f -0000000468 00000 f -0000000469 00000 f -0000000470 00000 f -0000000471 00000 f -0000000472 00000 f -0000000473 00000 f -0000000474 00000 f -0000000475 00000 f -0000000479 00000 f -0000349064 00000 n -0000348919 00000 n -0000348992 00000 n -0000000483 00000 f -0000036849 00000 n -0000036953 00000 n -0000037055 00000 n -0000000484 00000 f -0000000485 00000 f -0000000486 00000 f -0000000487 00000 f -0000000488 00000 f -0000000489 00000 f -0000000490 00000 f -0000000496 00000 f -0000285919 00000 n -0000286351 00000 n -0000286825 00000 n -0000276837 00000 n -0000277269 00000 n -0000000497 00000 f -0000000498 00000 f -0000000499 00000 f -0000000500 00000 f -0000000501 00000 f -0000000502 00000 f -0000000503 00000 f -0000000504 00000 f -0000000505 00000 f -0000000506 00000 f -0000000507 00000 f -0000000508 00000 f -0000000509 00000 f -0000000510 00000 f -0000000511 00000 f -0000000512 00000 f -0000000513 00000 f -0000000514 00000 f -0000000515 00000 f -0000000516 00000 f -0000000517 00000 f -0000000518 00000 f -0000000519 00000 f -0000000520 00000 f -0000000521 00000 f -0000000522 00000 f -0000000523 00000 f -0000000524 00000 f -0000000525 00000 f -0000000526 00000 f -0000000527 00000 f -0000000528 00000 f -0000000529 00000 f -0000000530 00000 f -0000000531 00000 f -0000000532 00000 f -0000000533 00000 f -0000000534 00000 f -0000000535 00000 f -0000000536 00000 f -0000000537 00000 f -0000000538 00000 f -0000000539 00000 f -0000000540 00000 f -0000000541 00000 f -0000000542 00000 f -0000000543 00000 f -0000000544 00000 f -0000000545 00000 f -0000000546 00000 f -0000000547 00000 f -0000000548 00000 f -0000000549 00000 f -0000000550 00000 f -0000000551 00000 f -0000000552 00000 f -0000000553 00000 f -0000000554 00000 f -0000000555 00000 f -0000000556 00000 f -0000000557 00000 f -0000000558 00000 f -0000000559 00000 f -0000000566 00000 f -0000354030 00000 n -0000354062 00000 n -0000353912 00000 n -0000353944 00000 n -0000353794 00000 n -0000353826 00000 n -0000000567 00000 f -0000000568 00000 f -0000000569 00000 f -0000000570 00000 f -0000000571 00000 f -0000000572 00000 f -0000000573 00000 f -0000000574 00000 f -0000000575 00000 f -0000000576 00000 f -0000000577 00000 f -0000000578 00000 f -0000000579 00000 f -0000000580 00000 f -0000000581 00000 f -0000000582 00000 f -0000000583 00000 f -0000000584 00000 f -0000000585 00000 f -0000000586 00000 f -0000000587 00000 f -0000000588 00000 f -0000000589 00000 f -0000000590 00000 f -0000000591 00000 f -0000000592 00000 f -0000000593 00000 f -0000000594 00000 f -0000000595 00000 f -0000000596 00000 f -0000000597 00000 f -0000000598 00000 f -0000000599 00000 f -0000000600 00000 f -0000000601 00000 f -0000000602 00000 f -0000000603 00000 f -0000000604 00000 f -0000000605 00000 f -0000000606 00000 f -0000000607 00000 f -0000000608 00000 f -0000000609 00000 f -0000000610 00000 f -0000000611 00000 f -0000000612 00000 f -0000000613 00000 f -0000000614 00000 f -0000000615 00000 f -0000000616 00000 f -0000000617 00000 f -0000000618 00000 f -0000000619 00000 f -0000000620 00000 f -0000000621 00000 f -0000000622 00000 f -0000000623 00000 f -0000000624 00000 f -0000000625 00000 f -0000000626 00000 f -0000000627 00000 f -0000000628 00000 f -0000000629 00000 f -0000000630 00000 f -0000000631 00000 f -0000000632 00000 f -0000000633 00000 f -0000000634 00000 f -0000000635 00000 f -0000000636 00000 f -0000000637 00000 f -0000000638 00000 f -0000000639 00000 f -0000000640 00000 f -0000000641 00000 f -0000000642 00000 f -0000000643 00000 f -0000000644 00000 f -0000000645 00000 f -0000000646 00000 f -0000000647 00000 f -0000000648 00000 f -0000000649 00000 f -0000000650 00000 f -0000000651 00000 f -0000000652 00000 f -0000000653 00000 f -0000000654 00000 f -0000000655 00000 f -0000000656 00000 f -0000000657 00000 f -0000000658 00000 f -0000000659 00000 f -0000000660 00000 f -0000000661 00000 f -0000000662 00000 f -0000000663 00000 f -0000000664 00000 f -0000000665 00000 f -0000000666 00000 f -0000000667 00000 f -0000000668 00000 f -0000000669 00000 f -0000000670 00000 f -0000000671 00000 f -0000000672 00000 f -0000000673 00000 f -0000000674 00000 f -0000000675 00000 f -0000000676 00000 f -0000000677 00000 f -0000000678 00000 f -0000000679 00000 f -0000000680 00000 f -0000000681 00000 f -0000000682 00000 f -0000000683 00000 f -0000000684 00000 f -0000000685 00000 f -0000000686 00000 f -0000000687 00000 f -0000000688 00000 f -0000000689 00000 f -0000000690 00000 f -0000000691 00000 f -0000000692 00000 f -0000000693 00000 f -0000000694 00000 f -0000000695 00000 f -0000000696 00000 f -0000000697 00000 f -0000000698 00000 f -0000000699 00000 f -0000000700 00000 f -0000000701 00000 f -0000000702 00000 f -0000000703 00000 f -0000000704 00000 f -0000000705 00000 f -0000000706 00000 f -0000000707 00000 f -0000000708 00000 f -0000000709 00000 f -0000000710 00000 f -0000000711 00000 f -0000000712 00000 f -0000000713 00000 f -0000000714 00000 f -0000000715 00000 f -0000000716 00000 f -0000000717 00000 f -0000000718 00000 f -0000000719 00000 f -0000000720 00000 f -0000000721 00000 f -0000000722 00000 f -0000000723 00000 f -0000000724 00000 f -0000000725 00000 f -0000000726 00000 f -0000000727 00000 f -0000000728 00000 f -0000000729 00000 f -0000000730 00000 f -0000000731 00000 f -0000000732 00000 f -0000000733 00000 f -0000000734 00000 f -0000000735 00000 f -0000000736 00000 f -0000000737 00000 f -0000000738 00000 f -0000000739 00000 f -0000000740 00000 f -0000000741 00000 f -0000000742 00000 f -0000000743 00000 f -0000000744 00000 f -0000000745 00000 f -0000000746 00000 f -0000000747 00000 f -0000000748 00000 f -0000000749 00000 f -0000000750 00000 f -0000000751 00000 f -0000000752 00000 f -0000000753 00000 f -0000000754 00000 f -0000000755 00000 f -0000000756 00000 f -0000000757 00000 f -0000000758 00000 f -0000000759 00000 f -0000000760 00000 f -0000000761 00000 f -0000000762 00000 f -0000000763 00000 f -0000000764 00000 f -0000000765 00000 f -0000000766 00000 f -0000000767 00000 f -0000000768 00000 f -0000000769 00000 f -0000000770 00000 f -0000000771 00000 f -0000000772 00000 f -0000000773 00000 f -0000000774 00000 f -0000000775 00000 f -0000000776 00000 f -0000000777 00000 f -0000000778 00000 f -0000000779 00000 f -0000000780 00000 f -0000000781 00000 f -0000000782 00000 f -0000000783 00000 f -0000000784 00000 f -0000000785 00000 f -0000000786 00000 f -0000000787 00000 f -0000000788 00000 f -0000000789 00000 f -0000000790 00000 f -0000000791 00000 f -0000000792 00000 f -0000000793 00000 f -0000000794 00000 f -0000000795 00000 f -0000000796 00000 f -0000000797 00000 f -0000000801 00000 f -0000349136 00000 n -0000349208 00000 n -0000349281 00000 n -0000000802 00000 f -0000000803 00000 f -0000000804 00000 f -0000000805 00000 f -0000000806 00000 f -0000000807 00000 f -0000000808 00000 f -0000000809 00000 f -0000000810 00000 f -0000000817 00000 f -0000353676 00000 n -0000353708 00000 n -0000353558 00000 n -0000353590 00000 n -0000353440 00000 n -0000353472 00000 n -0000000818 00000 f -0000000819 00000 f -0000000820 00000 f -0000000821 00000 f -0000000822 00000 f -0000000823 00000 f -0000000824 00000 f -0000000825 00000 f -0000000826 00000 f -0000000827 00000 f -0000000828 00000 f -0000000829 00000 f -0000000830 00000 f -0000000831 00000 f -0000000832 00000 f -0000000833 00000 f -0000000834 00000 f -0000000835 00000 f -0000000836 00000 f -0000000837 00000 f -0000000838 00000 f -0000000839 00000 f -0000000840 00000 f -0000000841 00000 f -0000000842 00000 f -0000000843 00000 f -0000000844 00000 f -0000000845 00000 f -0000000846 00000 f -0000000847 00000 f -0000000848 00000 f -0000000849 00000 f -0000000850 00000 f -0000000851 00000 f -0000000852 00000 f -0000000853 00000 f -0000000854 00000 f -0000000855 00000 f -0000000856 00000 f -0000000857 00000 f -0000000858 00000 f -0000000859 00000 f -0000000860 00000 f -0000000861 00000 f -0000000862 00000 f -0000000863 00000 f -0000000864 00000 f -0000000865 00000 f -0000000866 00000 f -0000000867 00000 f -0000000868 00000 f -0000000869 00000 f -0000000870 00000 f -0000000871 00000 f -0000000872 00000 f -0000000873 00000 f -0000000874 00000 f -0000000875 00000 f -0000000876 00000 f -0000000877 00000 f -0000000878 00000 f -0000000879 00000 f -0000000880 00000 f -0000000881 00000 f -0000000882 00000 f -0000000883 00000 f -0000000884 00000 f -0000000885 00000 f -0000000886 00000 f -0000000887 00000 f -0000000888 00000 f -0000000889 00000 f -0000000890 00000 f -0000000891 00000 f -0000000892 00000 f -0000000893 00000 f -0000000894 00000 f -0000000895 00000 f -0000000896 00000 f -0000000897 00000 f -0000000898 00000 f -0000000899 00000 f -0000000900 00000 f -0000000901 00000 f -0000000902 00000 f -0000000903 00000 f -0000000904 00000 f -0000000905 00000 f -0000000906 00000 f -0000000907 00000 f -0000000908 00000 f -0000000909 00000 f -0000000910 00000 f -0000000911 00000 f -0000000912 00000 f -0000000913 00000 f -0000000914 00000 f -0000000915 00000 f -0000000916 00000 f -0000000917 00000 f -0000000918 00000 f -0000000919 00000 f -0000000920 00000 f -0000000921 00000 f -0000000922 00000 f -0000000923 00000 f -0000000924 00000 f -0000000925 00000 f -0000000926 00000 f -0000000927 00000 f -0000000928 00000 f -0000000929 00000 f -0000000930 00000 f -0000000931 00000 f -0000000932 00000 f -0000000933 00000 f -0000000934 00000 f -0000000935 00000 f -0000000936 00000 f -0000000937 00000 f -0000000938 00000 f -0000000939 00000 f -0000000940 00000 f -0000000941 00000 f -0000000942 00000 f -0000000943 00000 f -0000000944 00000 f -0000000945 00000 f -0000000946 00000 f -0000000947 00000 f -0000000948 00000 f -0000000949 00000 f -0000000950 00000 f -0000000954 00000 f -0000349353 00000 n -0000349425 00000 n -0000349498 00000 n -0000000955 00000 f -0000000956 00000 f -0000000957 00000 f -0000000958 00000 f -0000000959 00000 f -0000000960 00000 f -0000000961 00000 f -0000000962 00000 f -0000000963 00000 f -0000000970 00000 f -0000353322 00000 n -0000353354 00000 n -0000353204 00000 n -0000353236 00000 n -0000353086 00000 n -0000353118 00000 n -0000000971 00000 f -0000000972 00000 f -0000000973 00000 f -0000000974 00000 f -0000000975 00000 f -0000000976 00000 f -0000000977 00000 f -0000000978 00000 f -0000000979 00000 f -0000000980 00000 f -0000000981 00000 f -0000000982 00000 f -0000000983 00000 f -0000000984 00000 f -0000000985 00000 f -0000000986 00000 f -0000000987 00000 f -0000000988 00000 f -0000000989 00000 f -0000000990 00000 f -0000000991 00000 f -0000000992 00000 f -0000000993 00000 f -0000000994 00000 f -0000000995 00000 f -0000000996 00000 f -0000000997 00000 f -0000000998 00000 f -0000000999 00000 f -0000001000 00000 f -0000001001 00000 f -0000001002 00000 f -0000001003 00000 f -0000001004 00000 f -0000001005 00000 f -0000001006 00000 f -0000001007 00000 f -0000001008 00000 f -0000001009 00000 f -0000001010 00000 f -0000001011 00000 f -0000001012 00000 f -0000001013 00000 f -0000001014 00000 f -0000001015 00000 f -0000001016 00000 f -0000001017 00000 f -0000001018 00000 f -0000001019 00000 f -0000001020 00000 f -0000001021 00000 f -0000001022 00000 f -0000001023 00000 f -0000001024 00000 f -0000001025 00000 f -0000001026 00000 f -0000001027 00000 f -0000001028 00000 f -0000001029 00000 f -0000001030 00000 f -0000001031 00000 f -0000001032 00000 f -0000001033 00000 f -0000001034 00000 f -0000001035 00000 f -0000001036 00000 f -0000001037 00000 f -0000001038 00000 f -0000001039 00000 f -0000001040 00000 f -0000001041 00000 f -0000001042 00000 f -0000001043 00000 f -0000001044 00000 f -0000001045 00000 f -0000001046 00000 f -0000001047 00000 f -0000001048 00000 f -0000001049 00000 f -0000001050 00000 f -0000001051 00000 f -0000001052 00000 f -0000001053 00000 f -0000001054 00000 f -0000001055 00000 f -0000001056 00000 f -0000001057 00000 f -0000001058 00000 f -0000001059 00000 f -0000001060 00000 f -0000001061 00000 f -0000001062 00000 f -0000001063 00000 f -0000001064 00000 f -0000001065 00000 f -0000001066 00000 f -0000001067 00000 f -0000001068 00000 f -0000001069 00000 f -0000001070 00000 f -0000001071 00000 f -0000001072 00000 f -0000001073 00000 f -0000001074 00000 f -0000001075 00000 f -0000001076 00000 f -0000001077 00000 f -0000001078 00000 f -0000001079 00000 f -0000001080 00000 f -0000001081 00000 f -0000001082 00000 f -0000001083 00000 f -0000001084 00000 f -0000001085 00000 f -0000001086 00000 f -0000001087 00000 f -0000001088 00000 f -0000001089 00000 f -0000001090 00000 f -0000001091 00000 f -0000001092 00000 f -0000001093 00000 f -0000001094 00000 f -0000001095 00000 f -0000001096 00000 f -0000001097 00000 f -0000001098 00000 f -0000001099 00000 f -0000001100 00000 f -0000001101 00000 f -0000001102 00000 f -0000001103 00000 f -0000001104 00000 f -0000001105 00000 f -0000001109 00000 f -0000349570 00000 n -0000349645 00000 n -0000349721 00000 n -0000001127 00000 f -0000037160 00000 n -0000037268 00000 n -0000277701 00000 n -0000278154 00000 n -0000278607 00000 n -0000267385 00000 n -0000267839 00000 n -0000268293 00000 n -0000268747 00000 n -0000269201 00000 n -0000256440 00000 n -0000256894 00000 n -0000257348 00000 n -0000257802 00000 n -0000258256 00000 n -0000037511 00000 n -0000037965 00000 n -0000001128 00000 f -0000001129 00000 f -0000001130 00000 f -0000001131 00000 f -0000001132 00000 f -0000001133 00000 f -0000001134 00000 f -0000001135 00000 f -0000001136 00000 f -0000001137 00000 f -0000001138 00000 f -0000001139 00000 f -0000001140 00000 f -0000001141 00000 f -0000001142 00000 f -0000001143 00000 f -0000001144 00000 f -0000001145 00000 f -0000001146 00000 f -0000001147 00000 f -0000001148 00000 f -0000001155 00000 f -0000352966 00000 n -0000352999 00000 n -0000352846 00000 n -0000352879 00000 n -0000352726 00000 n -0000352759 00000 n -0000001156 00000 f -0000001157 00000 f -0000001158 00000 f -0000001159 00000 f -0000001160 00000 f -0000001161 00000 f -0000001162 00000 f -0000001163 00000 f -0000001164 00000 f -0000001165 00000 f -0000001166 00000 f -0000001167 00000 f -0000001168 00000 f -0000001169 00000 f -0000001170 00000 f -0000001171 00000 f -0000001172 00000 f -0000001173 00000 f -0000001174 00000 f -0000001175 00000 f -0000001176 00000 f -0000001177 00000 f -0000001178 00000 f -0000001179 00000 f -0000001180 00000 f -0000001181 00000 f -0000001182 00000 f -0000001183 00000 f -0000001184 00000 f -0000001185 00000 f -0000001186 00000 f -0000001187 00000 f -0000001188 00000 f -0000001189 00000 f -0000001190 00000 f -0000001191 00000 f -0000001192 00000 f -0000001193 00000 f -0000001194 00000 f -0000001195 00000 f -0000001196 00000 f -0000001197 00000 f -0000001198 00000 f -0000001199 00000 f -0000001200 00000 f -0000001201 00000 f -0000001202 00000 f -0000001203 00000 f -0000001204 00000 f -0000001205 00000 f -0000001206 00000 f -0000001207 00000 f -0000001208 00000 f -0000001209 00000 f -0000001210 00000 f -0000001211 00000 f -0000001212 00000 f -0000001213 00000 f -0000001214 00000 f -0000001215 00000 f -0000001216 00000 f -0000001217 00000 f -0000001218 00000 f -0000001219 00000 f -0000001220 00000 f -0000001221 00000 f -0000001222 00000 f -0000001223 00000 f -0000001224 00000 f -0000001225 00000 f -0000001226 00000 f -0000001227 00000 f -0000001228 00000 f -0000001229 00000 f -0000001230 00000 f -0000001231 00000 f -0000001232 00000 f -0000001233 00000 f -0000001234 00000 f -0000001235 00000 f -0000001236 00000 f -0000001237 00000 f -0000001238 00000 f -0000001239 00000 f -0000001240 00000 f -0000001241 00000 f -0000001242 00000 f -0000001243 00000 f -0000001244 00000 f -0000001245 00000 f -0000001246 00000 f -0000001247 00000 f -0000001248 00000 f -0000001249 00000 f -0000001250 00000 f -0000001251 00000 f -0000001252 00000 f -0000001253 00000 f -0000001254 00000 f -0000001255 00000 f -0000001256 00000 f -0000001257 00000 f -0000001258 00000 f -0000001259 00000 f -0000001260 00000 f -0000001261 00000 f -0000001262 00000 f -0000001263 00000 f -0000001264 00000 f -0000001265 00000 f -0000001266 00000 f -0000001267 00000 f -0000001268 00000 f -0000001269 00000 f -0000001270 00000 f -0000001271 00000 f -0000001272 00000 f -0000001273 00000 f -0000001274 00000 f -0000001275 00000 f -0000001276 00000 f -0000001277 00000 f -0000001278 00000 f -0000001279 00000 f -0000001280 00000 f -0000001281 00000 f -0000001282 00000 f -0000001283 00000 f -0000001284 00000 f -0000001285 00000 f -0000001286 00000 f -0000001287 00000 f -0000001288 00000 f -0000001289 00000 f -0000001290 00000 f -0000001291 00000 f -0000001292 00000 f -0000001293 00000 f -0000001294 00000 f -0000001295 00000 f -0000001296 00000 f -0000001297 00000 f -0000001298 00000 f -0000001299 00000 f -0000001300 00000 f -0000001301 00000 f -0000001302 00000 f -0000001303 00000 f -0000001304 00000 f -0000001305 00000 f -0000001306 00000 f -0000001307 00000 f -0000001308 00000 f -0000001309 00000 f -0000001310 00000 f -0000001311 00000 f -0000001312 00000 f -0000001313 00000 f -0000001314 00000 f -0000001315 00000 f -0000001316 00000 f -0000001317 00000 f -0000001318 00000 f -0000001319 00000 f -0000001320 00000 f -0000001324 00000 f -0000349796 00000 n -0000349871 00000 n -0000349947 00000 n -0000001325 00000 f -0000001326 00000 f -0000001327 00000 f -0000001328 00000 f -0000001329 00000 f -0000001330 00000 f -0000001331 00000 f -0000001332 00000 f -0000001333 00000 f -0000001334 00000 f -0000001335 00000 f -0000001336 00000 f -0000001337 00000 f -0000001338 00000 f -0000001339 00000 f -0000001340 00000 f -0000001341 00000 f -0000001342 00000 f -0000001343 00000 f -0000001344 00000 f -0000001345 00000 f -0000001346 00000 f -0000001353 00000 f -0000352606 00000 n -0000352639 00000 n -0000352486 00000 n -0000352519 00000 n -0000352366 00000 n -0000352399 00000 n -0000001354 00000 f -0000001355 00000 f -0000001356 00000 f -0000001357 00000 f -0000001358 00000 f -0000001359 00000 f -0000001360 00000 f -0000001361 00000 f -0000001362 00000 f -0000001363 00000 f -0000001364 00000 f -0000001365 00000 f -0000001366 00000 f -0000001367 00000 f -0000001368 00000 f -0000001369 00000 f -0000001370 00000 f -0000001371 00000 f -0000001372 00000 f -0000001373 00000 f -0000001374 00000 f -0000001375 00000 f -0000001376 00000 f -0000001377 00000 f -0000001378 00000 f -0000001379 00000 f -0000001380 00000 f -0000001381 00000 f -0000001382 00000 f -0000001383 00000 f -0000001384 00000 f -0000001385 00000 f -0000001386 00000 f -0000001387 00000 f -0000001388 00000 f -0000001389 00000 f -0000001390 00000 f -0000001391 00000 f -0000001392 00000 f -0000001393 00000 f -0000001394 00000 f -0000001395 00000 f -0000001396 00000 f -0000001397 00000 f -0000001398 00000 f -0000001399 00000 f -0000001400 00000 f -0000001401 00000 f -0000001402 00000 f -0000001403 00000 f -0000001404 00000 f -0000001405 00000 f -0000001406 00000 f -0000001407 00000 f -0000001408 00000 f -0000001409 00000 f -0000001410 00000 f -0000001411 00000 f -0000001412 00000 f -0000001413 00000 f -0000001414 00000 f -0000001415 00000 f -0000001416 00000 f -0000001417 00000 f -0000001418 00000 f -0000001419 00000 f -0000001420 00000 f -0000001421 00000 f -0000001422 00000 f -0000001423 00000 f -0000001424 00000 f -0000001425 00000 f -0000001426 00000 f -0000001427 00000 f -0000001428 00000 f -0000001429 00000 f -0000001430 00000 f -0000001431 00000 f -0000001432 00000 f -0000001433 00000 f -0000001434 00000 f -0000001435 00000 f -0000001436 00000 f -0000001437 00000 f -0000001438 00000 f -0000001439 00000 f -0000001440 00000 f -0000001441 00000 f -0000001442 00000 f -0000001443 00000 f -0000001444 00000 f -0000001445 00000 f -0000001446 00000 f -0000001447 00000 f -0000001448 00000 f -0000001449 00000 f -0000001450 00000 f -0000001451 00000 f -0000001452 00000 f -0000001453 00000 f -0000001454 00000 f -0000001455 00000 f -0000001456 00000 f -0000001457 00000 f -0000001458 00000 f -0000001459 00000 f -0000001460 00000 f -0000001461 00000 f -0000001462 00000 f -0000001463 00000 f -0000001464 00000 f -0000001465 00000 f -0000001466 00000 f -0000001467 00000 f -0000001468 00000 f -0000001469 00000 f -0000001470 00000 f -0000001471 00000 f -0000001472 00000 f -0000001473 00000 f -0000001474 00000 f -0000001475 00000 f -0000001476 00000 f -0000001477 00000 f -0000001478 00000 f -0000001479 00000 f -0000001480 00000 f -0000001481 00000 f -0000001482 00000 f -0000001483 00000 f -0000001484 00000 f -0000001485 00000 f -0000001486 00000 f -0000001487 00000 f -0000001488 00000 f -0000001489 00000 f -0000001490 00000 f -0000001491 00000 f -0000001492 00000 f -0000001493 00000 f -0000001494 00000 f -0000001495 00000 f -0000001496 00000 f -0000001497 00000 f -0000001498 00000 f -0000001499 00000 f -0000001500 00000 f -0000001501 00000 f -0000001502 00000 f -0000001503 00000 f -0000001504 00000 f -0000001505 00000 f -0000001506 00000 f -0000001507 00000 f -0000001508 00000 f -0000001509 00000 f -0000001510 00000 f -0000001511 00000 f -0000001512 00000 f -0000001513 00000 f -0000001514 00000 f -0000001515 00000 f -0000001516 00000 f -0000001517 00000 f -0000001518 00000 f -0000001522 00000 f -0000350022 00000 n -0000350097 00000 n -0000350173 00000 n -0000001523 00000 f -0000001524 00000 f -0000001525 00000 f -0000001526 00000 f -0000001527 00000 f -0000001528 00000 f -0000001529 00000 f -0000001530 00000 f -0000001531 00000 f -0000001532 00000 f -0000001533 00000 f -0000001534 00000 f -0000001535 00000 f -0000001536 00000 f -0000001537 00000 f -0000001538 00000 f -0000001539 00000 f -0000001540 00000 f -0000001541 00000 f -0000001542 00000 f -0000001543 00000 f -0000001544 00000 f -0000001551 00000 f -0000352246 00000 n -0000352279 00000 n -0000352126 00000 n -0000352159 00000 n -0000352006 00000 n -0000352039 00000 n -0000001552 00000 f -0000001553 00000 f -0000001554 00000 f -0000001555 00000 f -0000001556 00000 f -0000001557 00000 f -0000001558 00000 f -0000001559 00000 f -0000001560 00000 f -0000001561 00000 f -0000001562 00000 f -0000001563 00000 f -0000001564 00000 f -0000001565 00000 f -0000001566 00000 f -0000001567 00000 f -0000001568 00000 f -0000001569 00000 f -0000001570 00000 f -0000001571 00000 f -0000001572 00000 f -0000001573 00000 f -0000001574 00000 f -0000001575 00000 f -0000001576 00000 f -0000001577 00000 f -0000001578 00000 f -0000001579 00000 f -0000001580 00000 f -0000001581 00000 f -0000001582 00000 f -0000001583 00000 f -0000001584 00000 f -0000001585 00000 f -0000001586 00000 f -0000001587 00000 f -0000001588 00000 f -0000001589 00000 f -0000001590 00000 f -0000001591 00000 f -0000001592 00000 f -0000001593 00000 f -0000001594 00000 f -0000001595 00000 f -0000001596 00000 f -0000001597 00000 f -0000001598 00000 f -0000001599 00000 f -0000001600 00000 f -0000001601 00000 f -0000001602 00000 f -0000001603 00000 f -0000001604 00000 f -0000001605 00000 f -0000001606 00000 f -0000001607 00000 f -0000001608 00000 f -0000001609 00000 f -0000001610 00000 f -0000001611 00000 f -0000001612 00000 f -0000001613 00000 f -0000001614 00000 f -0000001615 00000 f -0000001616 00000 f -0000001617 00000 f -0000001618 00000 f -0000001619 00000 f -0000001620 00000 f -0000001621 00000 f -0000001622 00000 f -0000001623 00000 f -0000001624 00000 f -0000001625 00000 f -0000001626 00000 f -0000001627 00000 f -0000001628 00000 f -0000001629 00000 f -0000001630 00000 f -0000001631 00000 f -0000001632 00000 f -0000001633 00000 f -0000001634 00000 f -0000001635 00000 f -0000001636 00000 f -0000001637 00000 f -0000001638 00000 f -0000001639 00000 f -0000001640 00000 f -0000001641 00000 f -0000001642 00000 f -0000001643 00000 f -0000001644 00000 f -0000001645 00000 f -0000001646 00000 f -0000001647 00000 f -0000001648 00000 f -0000001649 00000 f -0000001650 00000 f -0000001651 00000 f -0000001652 00000 f -0000001653 00000 f -0000001654 00000 f -0000001655 00000 f -0000001656 00000 f -0000001657 00000 f -0000001658 00000 f -0000001659 00000 f -0000001660 00000 f -0000001661 00000 f -0000001662 00000 f -0000001663 00000 f -0000001664 00000 f -0000001665 00000 f -0000001666 00000 f -0000001667 00000 f -0000001668 00000 f -0000001669 00000 f -0000001670 00000 f -0000001671 00000 f -0000001672 00000 f -0000001673 00000 f -0000001674 00000 f -0000001675 00000 f -0000001676 00000 f -0000001677 00000 f -0000001678 00000 f -0000001679 00000 f -0000001680 00000 f -0000001681 00000 f -0000001682 00000 f -0000001683 00000 f -0000001684 00000 f -0000001685 00000 f -0000001686 00000 f -0000001687 00000 f -0000001688 00000 f -0000001689 00000 f -0000001690 00000 f -0000001691 00000 f -0000001692 00000 f -0000001693 00000 f -0000001694 00000 f -0000001695 00000 f -0000001696 00000 f -0000001697 00000 f -0000001698 00000 f -0000001699 00000 f -0000001700 00000 f -0000001701 00000 f -0000001702 00000 f -0000001703 00000 f -0000001704 00000 f -0000001705 00000 f -0000001706 00000 f -0000001707 00000 f -0000001708 00000 f -0000001709 00000 f -0000001710 00000 f -0000001711 00000 f -0000001712 00000 f -0000001713 00000 f -0000001714 00000 f -0000001715 00000 f -0000001716 00000 f -0000001720 00000 f -0000350248 00000 n -0000350323 00000 n -0000350399 00000 n -0000001722 00000 f -0000038419 00000 n -0000001723 00000 f -0000001724 00000 f -0000001725 00000 f -0000001726 00000 f -0000001727 00000 f -0000001728 00000 f -0000001729 00000 f -0000001730 00000 f -0000001731 00000 f -0000001732 00000 f -0000001733 00000 f -0000001734 00000 f -0000001735 00000 f -0000001736 00000 f -0000001737 00000 f -0000001738 00000 f -0000001739 00000 f -0000001740 00000 f -0000001741 00000 f -0000001742 00000 f -0000001743 00000 f -0000001744 00000 f -0000001745 00000 f -0000001752 00000 f -0000351886 00000 n -0000351919 00000 n -0000351766 00000 n -0000351799 00000 n -0000351646 00000 n -0000351679 00000 n -0000001753 00000 f -0000001754 00000 f -0000001755 00000 f -0000001756 00000 f -0000001757 00000 f -0000001758 00000 f -0000001759 00000 f -0000001760 00000 f -0000001761 00000 f -0000001762 00000 f -0000001763 00000 f -0000001764 00000 f -0000001765 00000 f -0000001766 00000 f -0000001767 00000 f -0000001768 00000 f -0000001769 00000 f -0000001770 00000 f -0000001771 00000 f -0000001772 00000 f -0000001773 00000 f -0000001774 00000 f -0000001775 00000 f -0000001776 00000 f -0000001777 00000 f -0000001778 00000 f -0000001779 00000 f -0000001780 00000 f -0000001781 00000 f -0000001782 00000 f -0000001783 00000 f -0000001784 00000 f -0000001785 00000 f -0000001786 00000 f -0000001787 00000 f -0000001788 00000 f -0000001789 00000 f -0000001790 00000 f -0000001791 00000 f -0000001792 00000 f -0000001793 00000 f -0000001794 00000 f -0000001795 00000 f -0000001796 00000 f -0000001797 00000 f -0000001798 00000 f -0000001799 00000 f -0000001800 00000 f -0000001801 00000 f -0000001802 00000 f -0000001803 00000 f -0000001804 00000 f -0000001805 00000 f -0000001806 00000 f -0000001807 00000 f -0000001808 00000 f -0000001809 00000 f -0000001810 00000 f -0000001811 00000 f -0000001812 00000 f -0000001813 00000 f -0000001814 00000 f -0000001815 00000 f -0000001816 00000 f -0000001817 00000 f -0000001818 00000 f -0000001819 00000 f -0000001820 00000 f -0000001821 00000 f -0000001822 00000 f -0000001823 00000 f -0000001824 00000 f -0000001825 00000 f -0000001826 00000 f -0000001827 00000 f -0000001828 00000 f -0000001829 00000 f -0000001830 00000 f -0000001831 00000 f -0000001832 00000 f -0000001833 00000 f -0000001834 00000 f -0000001835 00000 f -0000001836 00000 f -0000001837 00000 f -0000001838 00000 f -0000001839 00000 f -0000001840 00000 f -0000001841 00000 f -0000001842 00000 f -0000001843 00000 f -0000001844 00000 f -0000001845 00000 f -0000001846 00000 f -0000001847 00000 f -0000001848 00000 f -0000001849 00000 f -0000001850 00000 f -0000001851 00000 f -0000001852 00000 f -0000001853 00000 f -0000001854 00000 f -0000001855 00000 f -0000001856 00000 f -0000001857 00000 f -0000001858 00000 f -0000001859 00000 f -0000001860 00000 f -0000001861 00000 f -0000001862 00000 f -0000001863 00000 f -0000001864 00000 f -0000001865 00000 f -0000001866 00000 f -0000001867 00000 f -0000001868 00000 f -0000001869 00000 f -0000001870 00000 f -0000001871 00000 f -0000001872 00000 f -0000001873 00000 f -0000001874 00000 f -0000001875 00000 f -0000001876 00000 f -0000001877 00000 f -0000001878 00000 f -0000001879 00000 f -0000001880 00000 f -0000001881 00000 f -0000001882 00000 f -0000001883 00000 f -0000001884 00000 f -0000001885 00000 f -0000001886 00000 f -0000001887 00000 f -0000001888 00000 f -0000001889 00000 f -0000001890 00000 f -0000001891 00000 f -0000001892 00000 f -0000001893 00000 f -0000001894 00000 f -0000001895 00000 f -0000001896 00000 f -0000001897 00000 f -0000001898 00000 f -0000001899 00000 f -0000001900 00000 f -0000001901 00000 f -0000001902 00000 f -0000001903 00000 f -0000001904 00000 f -0000001905 00000 f -0000001906 00000 f -0000001907 00000 f -0000001908 00000 f -0000001909 00000 f -0000001910 00000 f -0000001911 00000 f -0000001912 00000 f -0000001913 00000 f -0000001914 00000 f -0000001915 00000 f -0000001916 00000 f -0000001917 00000 f -0000001921 00000 f -0000350474 00000 n -0000350549 00000 n -0000350625 00000 n -0000001922 00000 f -0000001923 00000 f -0000001924 00000 f -0000001925 00000 f -0000001926 00000 f -0000001927 00000 f -0000001928 00000 f -0000001929 00000 f -0000001930 00000 f -0000001931 00000 f -0000001932 00000 f -0000001933 00000 f -0000001934 00000 f -0000001935 00000 f -0000001936 00000 f -0000001937 00000 f -0000001938 00000 f -0000001939 00000 f -0000001940 00000 f -0000001941 00000 f -0000001942 00000 f -0000001943 00000 f -0000001944 00000 f -0000001945 00000 f -0000001952 00000 f -0000351526 00000 n -0000351559 00000 n -0000351406 00000 n -0000351439 00000 n -0000351286 00000 n -0000351319 00000 n -0000001953 00000 f -0000001954 00000 f -0000001955 00000 f -0000001956 00000 f -0000001957 00000 f -0000001958 00000 f -0000001959 00000 f -0000001960 00000 f -0000001961 00000 f -0000001962 00000 f -0000001963 00000 f -0000001964 00000 f -0000001965 00000 f -0000001966 00000 f -0000001967 00000 f -0000001968 00000 f -0000001969 00000 f -0000001970 00000 f -0000001971 00000 f -0000001972 00000 f -0000001973 00000 f -0000001974 00000 f -0000001975 00000 f -0000001976 00000 f -0000001977 00000 f -0000001978 00000 f -0000001979 00000 f -0000001980 00000 f -0000001981 00000 f -0000001982 00000 f -0000001983 00000 f -0000001984 00000 f -0000001985 00000 f -0000001986 00000 f -0000001987 00000 f -0000001988 00000 f -0000001989 00000 f -0000001990 00000 f -0000001991 00000 f -0000001992 00000 f -0000001993 00000 f -0000001994 00000 f -0000001995 00000 f -0000001996 00000 f -0000001997 00000 f -0000001998 00000 f -0000001999 00000 f -0000002000 00000 f -0000002001 00000 f -0000002002 00000 f -0000002003 00000 f -0000002004 00000 f -0000002005 00000 f -0000002006 00000 f -0000002007 00000 f -0000002008 00000 f -0000002009 00000 f -0000002010 00000 f -0000002011 00000 f -0000002012 00000 f -0000002013 00000 f -0000002014 00000 f -0000002015 00000 f -0000002016 00000 f -0000002017 00000 f -0000002018 00000 f -0000002019 00000 f -0000002020 00000 f -0000002021 00000 f -0000002022 00000 f -0000002023 00000 f -0000002024 00000 f -0000002025 00000 f -0000002026 00000 f -0000002027 00000 f -0000002028 00000 f -0000002029 00000 f -0000002030 00000 f -0000002031 00000 f -0000002032 00000 f -0000002033 00000 f -0000002034 00000 f -0000002035 00000 f -0000002036 00000 f -0000002037 00000 f -0000002038 00000 f -0000002039 00000 f -0000002040 00000 f -0000002041 00000 f -0000002042 00000 f -0000002043 00000 f -0000002044 00000 f -0000002045 00000 f -0000002046 00000 f -0000002047 00000 f -0000002048 00000 f -0000002049 00000 f -0000002050 00000 f -0000002051 00000 f -0000002052 00000 f -0000002053 00000 f -0000002054 00000 f -0000002055 00000 f -0000002056 00000 f -0000002057 00000 f -0000002058 00000 f -0000002059 00000 f -0000002060 00000 f -0000002061 00000 f -0000002062 00000 f -0000002063 00000 f -0000002064 00000 f -0000002065 00000 f -0000002066 00000 f -0000002067 00000 f -0000002068 00000 f -0000002069 00000 f -0000002070 00000 f -0000002071 00000 f -0000002072 00000 f -0000002073 00000 f -0000002074 00000 f -0000002075 00000 f -0000002076 00000 f -0000002077 00000 f -0000002078 00000 f -0000002079 00000 f -0000002080 00000 f -0000002081 00000 f -0000002082 00000 f -0000002083 00000 f -0000002084 00000 f -0000002085 00000 f -0000002086 00000 f -0000002087 00000 f -0000002088 00000 f -0000002089 00000 f -0000002090 00000 f -0000002091 00000 f -0000002092 00000 f -0000002093 00000 f -0000002094 00000 f -0000002095 00000 f -0000002096 00000 f -0000002097 00000 f -0000002098 00000 f -0000002099 00000 f -0000002100 00000 f -0000002101 00000 f -0000002102 00000 f -0000002103 00000 f -0000002104 00000 f -0000002105 00000 f -0000002106 00000 f -0000002107 00000 f -0000002108 00000 f -0000002109 00000 f -0000002110 00000 f -0000002111 00000 f -0000002112 00000 f -0000002113 00000 f -0000002114 00000 f -0000002115 00000 f -0000002116 00000 f -0000002117 00000 f -0000000000 00000 f -0000350700 00000 n -0000350775 00000 n -0000350851 00000 n -0000000000 00000 f -0000038873 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000351166 00000 n -0000351199 00000 n -0000351046 00000 n -0000351079 00000 n -0000350926 00000 n -0000350959 00000 n -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000000000 00000 f -0000042955 00000 n -0000043030 00000 n -0000043106 00000 n -0000355204 00000 n -0000037376 00000 n -0000039349 00000 n -0000039803 00000 n -0000040257 00000 n -0000040711 00000 n -0000254761 00000 n -0000256069 00000 n -0000043666 00000 n -0000043541 00000 n -0000042840 00000 n -0000256136 00000 n -0000253735 00000 n -0000254694 00000 n -0000246344 00000 n -0000252973 00000 n -0000253668 00000 n -0000250218 00000 n -0000250433 00000 n -0000250793 00000 n -0000250500 00000 n -0000248584 00000 n -0000249847 00000 n -0000249914 00000 n -0000246650 00000 n -0000248517 00000 n -0000042535 00000 n -0000243121 00000 n -0000246277 00000 n -0000041165 00000 n -0000042468 00000 n -0000042775 00000 n -0000043421 00000 n -0000043454 00000 n -0000043301 00000 n -0000043334 00000 n -0000043181 00000 n -0000043214 00000 n -0000043744 00000 n -0000043974 00000 n -0000045254 00000 n -0000071263 00000 n -0000136854 00000 n -0000202445 00000 n -0000246585 00000 n -0000250153 00000 n -0000250728 00000 n -0000251086 00000 n -0000251420 00000 n -0000256375 00000 n -0000266119 00000 n -0000267318 00000 n -0000264455 00000 n -0000266052 00000 n -0000262988 00000 n -0000264388 00000 n -0000260490 00000 n -0000260795 00000 n -0000262615 00000 n -0000262682 00000 n -0000258710 00000 n -0000260423 00000 n -0000260730 00000 n -0000262923 00000 n -0000275001 00000 n -0000276465 00000 n -0000276532 00000 n -0000272770 00000 n -0000274934 00000 n -0000271902 00000 n -0000272703 00000 n -0000270591 00000 n -0000271835 00000 n -0000270286 00000 n -0000269655 00000 n -0000270219 00000 n -0000270526 00000 n -0000276772 00000 n -0000284623 00000 n -0000284988 00000 n -0000284329 00000 n -0000284022 00000 n -0000284262 00000 n -0000282874 00000 n -0000283955 00000 n -0000282568 00000 n -0000280642 00000 n -0000282501 00000 n -0000279060 00000 n -0000280270 00000 n -0000280337 00000 n -0000280577 00000 n -0000282809 00000 n -0000284558 00000 n -0000290712 00000 n -0000291073 00000 n -0000289722 00000 n -0000290645 00000 n -0000288689 00000 n -0000289655 00000 n -0000288322 00000 n -0000288622 00000 n -0000287257 00000 n -0000288255 00000 n -0000297479 00000 n -0000298494 00000 n -0000296874 00000 n -0000297412 00000 n -0000295256 00000 n -0000296807 00000 n -0000294330 00000 n -0000295189 00000 n -0000293787 00000 n -0000294263 00000 n -0000303976 00000 n -0000304378 00000 n -0000303531 00000 n -0000303909 00000 n -0000302327 00000 n -0000303464 00000 n -0000301897 00000 n -0000302260 00000 n -0000300716 00000 n -0000301830 00000 n -0000309492 00000 n -0000310190 00000 n -0000308730 00000 n -0000309425 00000 n -0000307963 00000 n -0000308663 00000 n -0000307201 00000 n -0000307896 00000 n -0000306763 00000 n -0000307134 00000 n -0000314735 00000 n -0000316195 00000 n -0000314333 00000 n -0000314668 00000 n -0000313931 00000 n -0000314266 00000 n -0000313241 00000 n -0000313864 00000 n -0000312407 00000 n -0000313174 00000 n -0000321877 00000 n -0000322095 00000 n -0000320053 00000 n -0000319738 00000 n -0000319986 00000 n -0000320219 00000 n -0000319284 00000 n -0000319671 00000 n -0000318958 00000 n -0000319217 00000 n -0000318552 00000 n -0000318891 00000 n -0000321225 00000 n -0000320446 00000 n -0000320737 00000 n -0000321505 00000 n -0000327528 00000 n -0000327759 00000 n -0000327244 00000 n -0000327461 00000 n -0000326943 00000 n -0000327177 00000 n -0000325279 00000 n -0000325496 00000 n -0000325563 00000 n -0000324997 00000 n -0000325212 00000 n -0000325688 00000 n -0000325717 00000 n -0000325859 00000 n -0000325928 00000 n -0000326219 00000 n -0000326305 00000 n -0000331220 00000 n -0000331485 00000 n -0000330922 00000 n -0000331153 00000 n -0000330626 00000 n -0000330855 00000 n -0000330343 00000 n -0000330559 00000 n -0000330060 00000 n -0000330276 00000 n -0000338065 00000 n -0000338342 00000 n -0000335359 00000 n -0000337998 00000 n -0000334665 00000 n -0000335292 00000 n -0000334018 00000 n -0000334598 00000 n -0000333702 00000 n -0000333951 00000 n -0000342763 00000 n -0000343062 00000 n -0000342398 00000 n -0000342696 00000 n -0000342032 00000 n -0000342331 00000 n -0000341060 00000 n -0000341965 00000 n -0000340685 00000 n -0000340993 00000 n -0000347749 00000 n -0000348210 00000 n -0000347057 00000 n -0000347682 00000 n -0000346272 00000 n -0000346990 00000 n -0000345598 00000 n -0000346205 00000 n -0000345274 00000 n -0000345531 00000 n -0000355251 00000 n -trailer -<</Size 2542/Root 1 0 R/Info 2541 0 R/ID[<21F51C5B9DD9C04EA8AE496A091969D3><3657344147E4A34E9BC72AEE116117FA>]>> -startxref -355392 -%%EOF diff --git a/resources/media/themes/default/thumb_add.png b/resources/media/themes/default/thumb_add.png deleted file mode 100644 index e2a76d06..00000000 Binary files a/resources/media/themes/default/thumb_add.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_autoplay.png b/resources/media/themes/default/thumb_autoplay.png deleted file mode 100644 index c8dfcfb0..00000000 Binary files a/resources/media/themes/default/thumb_autoplay.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_back.png b/resources/media/themes/default/thumb_back.png deleted file mode 100644 index 4213a1fa..00000000 Binary files a/resources/media/themes/default/thumb_back.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels.png b/resources/media/themes/default/thumb_channels.png deleted file mode 100644 index f7069641..00000000 Binary files a/resources/media/themes/default/thumb_channels.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_action.png b/resources/media/themes/default/thumb_channels_action.png deleted file mode 100644 index 546f28e6..00000000 Binary files a/resources/media/themes/default/thumb_channels_action.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_adult.png b/resources/media/themes/default/thumb_channels_adult.png deleted file mode 100644 index 1cf07524..00000000 Binary files a/resources/media/themes/default/thumb_channels_adult.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_adventure.png b/resources/media/themes/default/thumb_channels_adventure.png deleted file mode 100644 index 260779a1..00000000 Binary files a/resources/media/themes/default/thumb_channels_adventure.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_all.png b/resources/media/themes/default/thumb_channels_all.png deleted file mode 100644 index 02c9ef20..00000000 Binary files a/resources/media/themes/default/thumb_channels_all.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_animation.png b/resources/media/themes/default/thumb_channels_animation.png deleted file mode 100644 index 6fcb3caf..00000000 Binary files a/resources/media/themes/default/thumb_channels_animation.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_anime.png b/resources/media/themes/default/thumb_channels_anime.png deleted file mode 100644 index a8a83819..00000000 Binary files a/resources/media/themes/default/thumb_channels_anime.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_biographical.png b/resources/media/themes/default/thumb_channels_biographical.png deleted file mode 100644 index aecb2031..00000000 Binary files a/resources/media/themes/default/thumb_channels_biographical.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_biographical_1.png b/resources/media/themes/default/thumb_channels_biographical_1.png deleted file mode 100644 index 0f7dc970..00000000 Binary files a/resources/media/themes/default/thumb_channels_biographical_1.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_children.png b/resources/media/themes/default/thumb_channels_children.png deleted file mode 100644 index 8787abe6..00000000 Binary files a/resources/media/themes/default/thumb_channels_children.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_comedy.png b/resources/media/themes/default/thumb_channels_comedy.png deleted file mode 100644 index 486c9697..00000000 Binary files a/resources/media/themes/default/thumb_channels_comedy.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_community.png b/resources/media/themes/default/thumb_channels_community.png deleted file mode 100644 index 643000d4..00000000 Binary files a/resources/media/themes/default/thumb_channels_community.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_crime.png b/resources/media/themes/default/thumb_channels_crime.png deleted file mode 100644 index 58ccd455..00000000 Binary files a/resources/media/themes/default/thumb_channels_crime.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_direct.png b/resources/media/themes/default/thumb_channels_direct.png deleted file mode 100644 index f2dc0d76..00000000 Binary files a/resources/media/themes/default/thumb_channels_direct.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_documentary.png b/resources/media/themes/default/thumb_channels_documentary.png deleted file mode 100644 index f7d2dc00..00000000 Binary files a/resources/media/themes/default/thumb_channels_documentary.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_drama.png b/resources/media/themes/default/thumb_channels_drama.png deleted file mode 100644 index e720a5be..00000000 Binary files a/resources/media/themes/default/thumb_channels_drama.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_family.png b/resources/media/themes/default/thumb_channels_family.png deleted file mode 100644 index 12e152cb..00000000 Binary files a/resources/media/themes/default/thumb_channels_family.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_fantasy.png b/resources/media/themes/default/thumb_channels_fantasy.png deleted file mode 100644 index e79df4bb..00000000 Binary files a/resources/media/themes/default/thumb_channels_fantasy.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_historical.png b/resources/media/themes/default/thumb_channels_historical.png deleted file mode 100644 index 0ecdeeaa..00000000 Binary files a/resources/media/themes/default/thumb_channels_historical.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_italian.png b/resources/media/themes/default/thumb_channels_italian.png deleted file mode 100644 index c83954e7..00000000 Binary files a/resources/media/themes/default/thumb_channels_italian.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_latino.png b/resources/media/themes/default/thumb_channels_latino.png deleted file mode 100644 index ee0d1dc3..00000000 Binary files a/resources/media/themes/default/thumb_channels_latino.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_mistery.png b/resources/media/themes/default/thumb_channels_mistery.png deleted file mode 100644 index d86a5711..00000000 Binary files a/resources/media/themes/default/thumb_channels_mistery.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie.png b/resources/media/themes/default/thumb_channels_movie.png deleted file mode 100644 index 14995624..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie_4k.png b/resources/media/themes/default/thumb_channels_movie_4k.png deleted file mode 100644 index 6c55be90..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie_4k.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie_az.png b/resources/media/themes/default/thumb_channels_movie_az.png deleted file mode 100644 index 86aad3f8..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie_az.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie_genre.png b/resources/media/themes/default/thumb_channels_movie_genre.png deleted file mode 100644 index ffbba260..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie_genre.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie_hd.png b/resources/media/themes/default/thumb_channels_movie_hd.png deleted file mode 100644 index 3e5f5215..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie_hd.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_movie_year.png b/resources/media/themes/default/thumb_channels_movie_year.png deleted file mode 100644 index d956ba06..00000000 Binary files a/resources/media/themes/default/thumb_channels_movie_year.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_musical.png b/resources/media/themes/default/thumb_channels_musical.png deleted file mode 100644 index baf53a5f..00000000 Binary files a/resources/media/themes/default/thumb_channels_musical.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_noir.png b/resources/media/themes/default/thumb_channels_noir.png deleted file mode 100644 index 17f0a3f6..00000000 Binary files a/resources/media/themes/default/thumb_channels_noir.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_romance.png b/resources/media/themes/default/thumb_channels_romance.png deleted file mode 100644 index b5cf222a..00000000 Binary files a/resources/media/themes/default/thumb_channels_romance.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_spanish.png b/resources/media/themes/default/thumb_channels_spanish.png deleted file mode 100644 index b26f0a8b..00000000 Binary files a/resources/media/themes/default/thumb_channels_spanish.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_syfy.png b/resources/media/themes/default/thumb_channels_syfy.png deleted file mode 100644 index 9ed20a81..00000000 Binary files a/resources/media/themes/default/thumb_channels_syfy.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_torrent.png b/resources/media/themes/default/thumb_channels_torrent.png deleted file mode 100644 index ada8e116..00000000 Binary files a/resources/media/themes/default/thumb_channels_torrent.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow.png b/resources/media/themes/default/thumb_channels_tvshow.png deleted file mode 100644 index b0938dde..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow_4k.png b/resources/media/themes/default/thumb_channels_tvshow_4k.png deleted file mode 100644 index 3ed8f389..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow_4k.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow_az.png b/resources/media/themes/default/thumb_channels_tvshow_az.png deleted file mode 100644 index d0df1ed1..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow_az.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow_genre.png b/resources/media/themes/default/thumb_channels_tvshow_genre.png deleted file mode 100644 index ab09f7dc..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow_genre.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow_hd.png b/resources/media/themes/default/thumb_channels_tvshow_hd.png deleted file mode 100644 index 421808f9..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow_hd.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_tvshow_year.png b/resources/media/themes/default/thumb_channels_tvshow_year.png deleted file mode 100644 index 4ea1e082..00000000 Binary files a/resources/media/themes/default/thumb_channels_tvshow_year.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_vos.png b/resources/media/themes/default/thumb_channels_vos.png deleted file mode 100644 index 41065afb..00000000 Binary files a/resources/media/themes/default/thumb_channels_vos.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_war.png b/resources/media/themes/default/thumb_channels_war.png deleted file mode 100644 index af331a69..00000000 Binary files a/resources/media/themes/default/thumb_channels_war.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_channels_western.png b/resources/media/themes/default/thumb_channels_western.png deleted file mode 100644 index 1bc1c668..00000000 Binary files a/resources/media/themes/default/thumb_channels_western.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_downloads.png b/resources/media/themes/default/thumb_downloads.png deleted file mode 100644 index ff35491b..00000000 Binary files a/resources/media/themes/default/thumb_downloads.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_error.png b/resources/media/themes/default/thumb_error.png deleted file mode 100644 index 3fc80b66..00000000 Binary files a/resources/media/themes/default/thumb_error.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_favorites.png b/resources/media/themes/default/thumb_favorites.png deleted file mode 100644 index e151b000..00000000 Binary files a/resources/media/themes/default/thumb_favorites.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_folder.png b/resources/media/themes/default/thumb_folder.png deleted file mode 100644 index 551f2c26..00000000 Binary files a/resources/media/themes/default/thumb_folder.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_genres.png b/resources/media/themes/default/thumb_genres.png deleted file mode 100644 index e4b3f208..00000000 Binary files a/resources/media/themes/default/thumb_genres.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_help.png b/resources/media/themes/default/thumb_help.png deleted file mode 100644 index d2396d66..00000000 Binary files a/resources/media/themes/default/thumb_help.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_horror.png b/resources/media/themes/default/thumb_horror.png deleted file mode 100644 index c0ee6f36..00000000 Binary files a/resources/media/themes/default/thumb_horror.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_menu.png b/resources/media/themes/default/thumb_menu.png deleted file mode 100644 index 7b3b4a15..00000000 Binary files a/resources/media/themes/default/thumb_menu.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_more.png b/resources/media/themes/default/thumb_more.png deleted file mode 100644 index e2a76d06..00000000 Binary files a/resources/media/themes/default/thumb_more.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_mylink.png b/resources/media/themes/default/thumb_mylink.png deleted file mode 100644 index 570ea22e..00000000 Binary files a/resources/media/themes/default/thumb_mylink.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_news.png b/resources/media/themes/default/thumb_news.png deleted file mode 100644 index 91e723ad..00000000 Binary files a/resources/media/themes/default/thumb_news.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_next.png b/resources/media/themes/default/thumb_next.png deleted file mode 100644 index c724f3d2..00000000 Binary files a/resources/media/themes/default/thumb_next.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_nofolder.png b/resources/media/themes/default/thumb_nofolder.png deleted file mode 100644 index 485b4824..00000000 Binary files a/resources/media/themes/default/thumb_nofolder.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_now_playing.png b/resources/media/themes/default/thumb_now_playing.png deleted file mode 100644 index 8b9fa5f4..00000000 Binary files a/resources/media/themes/default/thumb_now_playing.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_on_the_air.png b/resources/media/themes/default/thumb_on_the_air.png deleted file mode 100644 index 5e0be56f..00000000 Binary files a/resources/media/themes/default/thumb_on_the_air.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_popular.png b/resources/media/themes/default/thumb_popular.png deleted file mode 100644 index b4007d79..00000000 Binary files a/resources/media/themes/default/thumb_popular.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_search.png b/resources/media/themes/default/thumb_search.png deleted file mode 100644 index 1ab444a1..00000000 Binary files a/resources/media/themes/default/thumb_search.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_search_genre.png b/resources/media/themes/default/thumb_search_genre.png deleted file mode 100644 index 424d688b..00000000 Binary files a/resources/media/themes/default/thumb_search_genre.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_search_movie.png b/resources/media/themes/default/thumb_search_movie.png deleted file mode 100644 index 3ba5aecf..00000000 Binary files a/resources/media/themes/default/thumb_search_movie.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_search_star.png b/resources/media/themes/default/thumb_search_star.png deleted file mode 100644 index 592e5490..00000000 Binary files a/resources/media/themes/default/thumb_search_star.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_search_tvshow.png b/resources/media/themes/default/thumb_search_tvshow.png deleted file mode 100644 index 05975e9b..00000000 Binary files a/resources/media/themes/default/thumb_search_tvshow.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_setting_0.png b/resources/media/themes/default/thumb_setting_0.png deleted file mode 100644 index 15de0b1c..00000000 Binary files a/resources/media/themes/default/thumb_setting_0.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_setting_1.png b/resources/media/themes/default/thumb_setting_1.png deleted file mode 100644 index ea705407..00000000 Binary files a/resources/media/themes/default/thumb_setting_1.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_setting_2.png b/resources/media/themes/default/thumb_setting_2.png deleted file mode 100644 index 04ec8de2..00000000 Binary files a/resources/media/themes/default/thumb_setting_2.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_setting_3.png b/resources/media/themes/default/thumb_setting_3.png deleted file mode 100644 index 81a0b2f9..00000000 Binary files a/resources/media/themes/default/thumb_setting_3.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_setting_4.png b/resources/media/themes/default/thumb_setting_4.png deleted file mode 100644 index 106f6cfc..00000000 Binary files a/resources/media/themes/default/thumb_setting_4.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_thriller.png b/resources/media/themes/default/thumb_thriller.png deleted file mode 100644 index f2c6c639..00000000 Binary files a/resources/media/themes/default/thumb_thriller.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_top_rated.png b/resources/media/themes/default/thumb_top_rated.png deleted file mode 100644 index 2d4fabf0..00000000 Binary files a/resources/media/themes/default/thumb_top_rated.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_update.png b/resources/media/themes/default/thumb_update.png deleted file mode 100644 index cac889fd..00000000 Binary files a/resources/media/themes/default/thumb_update.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_videolibrary.png b/resources/media/themes/default/thumb_videolibrary.png deleted file mode 100644 index 0d44943b..00000000 Binary files a/resources/media/themes/default/thumb_videolibrary.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_videolibrary_movie.png b/resources/media/themes/default/thumb_videolibrary_movie.png deleted file mode 100644 index 1055323a..00000000 Binary files a/resources/media/themes/default/thumb_videolibrary_movie.png and /dev/null differ diff --git a/resources/media/themes/default/thumb_videolibrary_tvshow.png b/resources/media/themes/default/thumb_videolibrary_tvshow.png deleted file mode 100644 index ab30a1f6..00000000 Binary files a/resources/media/themes/default/thumb_videolibrary_tvshow.png and /dev/null differ diff --git a/resources/settings.xml b/resources/settings.xml index 678b9ea6..e77fc16c 100644 --- a/resources/settings.xml +++ b/resources/settings.xml @@ -10,7 +10,6 @@ <setting id="channel_language" type="labelenum" values="auto|all|ita" label="30019" default="auto"/> <setting id="trakt_sync" type="bool" label="70109" default="false"/> <setting id="forceview" type="bool" label="30043" default="false"/> - <setting id="use_custom_url" type="bool" label="70705" default="false"/> <setting id="faster_item_serialization" type="bool" label="30300" default="false"/> <setting id="debug" type="bool" label="30003" default="false"/> <setting label="70169" type="lsep"/> @@ -44,16 +43,18 @@ <setting id="enable_library_menu" label="30131" type="bool" default="true"/> </category> - <category label="30501"> + <category label="30131"> <!-- <setting id="downloadpath" type="folder" label="30017" default=""/> <setting id="downloadlistpath" type="folder" label="30018" default=""/> --> + <setting label="30501" type="lsep"/> <setting id="videolibrarypath" type="folder" label="30067" default=""/> - <setting label="30131" type="lsep"/> <setting id="folder_tvshows" type="text" label="70118" default="SERIES"/> <setting id="folder_movies" type="text" label="70119" default="CINE"/> + <setting label="59997" type="lsep"/> <setting id="videolibrary_kodi_flag" type="number" label="" default="0" visible="false"/> <setting id="videolibrary_kodi_force" type="bool" label="" default="false" visible="false"/> <setting id="videolibrary_kodi" type="bool" label="70120" enable="lt(-1,2)+eq(0,false)" default="false"/> + <setting id="videolibrary_max_quality" type="bool" label="70729" default="false" visible="true"/> </category> <category label="70121"> <setting id="start_page" type="bool" label="70121" default="false"/> @@ -62,8 +63,8 @@ <setting id="news_start" type="bool" label="70123" default="false" visible="eq(-2,True)" enable="eq(-1,False)+eq(-2,True"/> <setting id="category" type="labelenum" label="70124" - lvalues="70137|30123|30124|70018|60513|70013|70014|59976|70171" - default="70137" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+(-2,false)"/> + lvalues="70137|30123|30124|60513" + default="Film" visible="eq(-3,True)+eq(-1,True)+eq(-2,False)" enable="eq(-3,True)+eq(-1,True)+(-2,false)"/> </category> <category label="70126"> <setting id="icon_set" type="labelenum" label="70108" values="default|light|dark|alfa|mike" default="default"/> @@ -104,7 +105,7 @@ <setting id="vose_color" type="labelenum" label="70142" values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]" default="white" visible="eq(-10,true)+eq(-11,true)"/> - <setting id="vosi_color" type="labelenum" label="70566" + <setting id="sub-ita_color" type="labelenum" label="70566" values="[COLOR white]white[/COLOR]|[COLOR cyan]cyan[/COLOR]|[COLOR deepskyblue]deepskyblue[/COLOR]|[COLOR firebrick]firebrick[/COLOR]|[COLOR gold]gold[/COLOR]|[COLOR goldenrod]goldenrod[/COLOR]|[COLOR hotpink]hotpink[/COLOR]|[COLOR limegreen]limegreen[/COLOR]|[COLOR orange]orange[/COLOR]|[COLOR orchid]orchid[/COLOR]|[COLOR red]red[/COLOR]|[COLOR salmon]salmon[/COLOR]|[COLOR yellow]yellow[/COLOR]" default="white" visible="eq(-11,true)+eq(-12,true)"/> <setting id="vos_color" type="labelenum" label="70143" diff --git a/servers/debriders/realdebrid.py b/servers/debriders/realdebrid.py index 63e50662..97b516e1 100644 --- a/servers/debriders/realdebrid.py +++ b/servers/debriders/realdebrid.py @@ -127,7 +127,7 @@ def authentication(): # Se solicita el token de acceso y el de actualización para cuando el primero caduque post = urllib.urlencode({"client_id": debrid_id, "client_secret": secret, "code": device_code, "grant_type": "http://oauth.net/grant_type/device/1.0"}) - data = httptools.downloadpage("https://api.real-debrid.com/oauth/v2/token", post=post, + data = htttools.downloadpage("https://api.real-debrid.com/oauth/v2/token", post=post, headers=headers.items()).data data = jsontools.load(data) diff --git a/servers/decrypters/zcrypt.py b/servers/decrypters/zcrypt.py index 50e2cb82..5372ea4a 100644 --- a/servers/decrypters/zcrypt.py +++ b/servers/decrypters/zcrypt.py @@ -12,15 +12,16 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= encontrados = { 'https://vcrypt.net/images/logo', 'https://vcrypt.net/css/out', 'https://vcrypt.net/images/favicon', 'https://vcrypt.net/css/open', - 'http://linkup.pro/js/jquery', 'https://linkup.pro/js/jquery', - 'http://www.rapidcrypt.net/open' + 'http://linkup.pro/js/jquery', 'https://linkup.pro/js/jquery'#, + #'http://www.rapidcrypt.net/open' } devuelve = [] patronvideos = [ r'(https?://(gestyy|rapidteria|sprysphere)\.com/[a-zA-Z0-9]+)', r'(https?://(?:www\.)?(vcrypt|linkup)\.[^/]+/[^/]+/[a-zA-Z0-9_]+)', - r'(https?://(?:www\.)?(bit)\.ly/[a-zA-Z0-9]+)', + r'(https?://(?:www\.)?(bit)\.ly/[a-zA-Z0-9]+)', + r'(https?://(?:www\.)?(xshield)\.[^/]+/[^/]+/[^/]+/[a-zA-Z0-9_\.]+)' ] for patron in patronvideos: @@ -41,15 +42,24 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= replace_headers=True, headers={'User-Agent': 'curl/7.59.0'}) data = resp.headers.get("location", "") - elif 'vcrypt.net' in url: + elif 'xshield' in url: from lib import unshortenit data, status = unshortenit.unshorten(url) - logger.info("Data - Status zcrypt vcrypt.net: [%s] [%s] " %(data, status)) + logger.info("Data - Status zcrypt xshield.net: [%s] [%s] " %(data, status)) + elif 'vcrypt.net' in url: + if 'myfoldersakstream.php' in url or '/verys/' in url: + continue + else: + from lib import unshortenit + data, status = unshortenit.unshorten(url) + logger.info("Data - Status zcrypt vcrypt.net: [%s] [%s] " %(data, status)) elif 'linkup' in url or 'bit.ly' in url: - idata = httptools.downloadpage(url).data - data = scrapertoolsV2.find_single_match(idata, "<iframe[^<>]*src=\\'([^'>]*)\\'[^<>]*>") - #fix by greko inizio - if not data: + if '/olink/' in url: continue + else: + idata = httptools.downloadpage(url).data + data = scrapertoolsV2.find_single_match(idata, "<iframe[^<>]*src=\\'([^'>]*)\\'[^<>]*>") + #fix by greko inizio + if not data: data = scrapertoolsV2.find_single_match(idata, 'action="(?:[^/]+.*?/[^/]+/([a-zA-Z0-9_]+))">') from lib import unshortenit data, status = unshortenit.unshorten(url) @@ -79,6 +89,8 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= for url in matches: if url not in encontrados: + if 'https://rapidcrypt.net/open/' in url or 'https://rapidcrypt.net/verys/' in url: + continue logger.info(" url=" + url) encontrados.add(url) @@ -91,5 +103,3 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= ret = page_url+" "+str(devuelve) if devuelve else page_url logger.info(" RET=" + str(ret)) return ret - - diff --git a/servers/directo.json b/servers/directo.json index abe594fd..b3ee714e 100644 --- a/servers/directo.json +++ b/servers/directo.json @@ -3,6 +3,11 @@ "find_videos": { "ignore_urls": [], "patterns": [ + { + "pattern": "((?:http://|https://).*?m3u8)", + "url": "\\1" + + }, { "pattern": "(http://[a-zA-Z0-9]+\\.mysites\\.com\\/get_file\\/.*?\\.mp4)", "url": "\\1" @@ -35,7 +40,7 @@ }, "free": true, "id": "directo", - "name": "directo", + "name": "direct", "settings": [ { "default": false, diff --git a/servers/directo.py b/servers/directo.py index 085092c4..d3db16e9 100644 --- a/servers/directo.py +++ b/servers/directo.py @@ -1,12 +1,13 @@ # -*- coding: utf-8 -*- -from platformcode import logger +from platformcode import logger, config # Returns an array of possible video url's from the page_url def get_video_url(page_url, premium=False, user="", password="", video_password=""): logger.info("(page_url='%s')" % page_url) + logger.info('PAGE URL= ' + page_url) - video_urls = [["%s [directo]" % page_url[-4:], page_url]] + video_urls = [["%s %s" % (page_url[-4:], config.get_localized_string(30137)), page_url]] return video_urls diff --git a/servers/vidcloud.json b/servers/hdload.json similarity index 69% rename from servers/vidcloud.json rename to servers/hdload.json index 3b65904e..7a3ace8b 100644 --- a/servers/vidcloud.json +++ b/servers/hdload.json @@ -4,14 +4,14 @@ "ignore_urls": [], "patterns": [ { - "pattern": "https://(?:vidcloud.co|vcstream.to)/embed/([a-z0-9]+)", - "url": "https://vidcloud.co/player?fid=\\1&page=embed" + "pattern": "https://hdload\\.space/public/dist/index\\.html\\?id=([a-z0-9]+)", + "url": "https://hdload.space/getHost/\\1" } ] }, "free": true, - "id": "vidcloud", - "name": "vidcloud", + "id": "hdload", + "name": "hdload", "settings": [ { "default": false, @@ -38,5 +38,5 @@ "visible": false } ], - "thumbnail": "https://i.postimg.cc/xjpwG0rK/0a-RVDzlb-400x400.jpg" + "thumbnail": "https://mixdrop.co/imgs/mixdrop-logo2.png" } diff --git a/servers/hdload.py b/servers/hdload.py new file mode 100644 index 00000000..c9306de4 --- /dev/null +++ b/servers/hdload.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from core import httptools, scrapertoolsV2 +from platformcode import config, logger +import base64 + + +def test_video_exists(page_url): + logger.info("(page_url='%s')" % page_url) + + data = httptools.downloadpage(page_url, cookies=False).data + if 'Not found id' in data: + return False, config.get_localized_string(70449) % "hdload" + + return True, "" + + +def get_video_url(page_url, premium=False, user="", password="", video_password=""): + logger.info() + itemlist = [] + + logger.info(page_url) + data = httptools.downloadpage(page_url, post='').data + logger.info(data) + url = base64.b64decode(data) + + itemlist.append([".mp4 [hdload]", url]) + + return itemlist diff --git a/servers/netutv.py b/servers/netutv.py index 116f5ce0..3204df2f 100644 --- a/servers/netutv.py +++ b/servers/netutv.py @@ -35,15 +35,17 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= page_url = page_url.replace('https://waaw.tv/', 'http://hqq.watch/') data = httptools.downloadpage(page_url).data - # ~ logger.debug(data) + logger.debug(data) - js_wise = scrapertools.find_single_match(data, "<script type=[\"']text/javascript[\"']>\s*;?(eval.*?)</script>") + # js_wise = scrapertools.find_single_match(data, "<script type=[\"']text/javascript[\"']>\s*;?(eval.*?)</script>") + js_wise = scrapertools.find_single_match(data, "<script>\s*;(eval.*?)\s*</script>") + logger.info('JS_WISE= '+ js_wise) data = jswise(js_wise).replace("\\", "") - # ~ logger.debug(data) + logger.debug(data) alea = str(random.random())[2:] data_ip = httptools.downloadpage('http://hqq.watch/player/ip.php?type=json&rand=%s' % alea).data - # ~ logger.debug(data_ip) + logger.debug(data_ip) json_data_ip = jsontools.load(data_ip) url = scrapertools.find_single_match(data, 'self\.location\.replace\("([^)]+)\)') @@ -51,14 +53,15 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= url = url.replace('"+data.ip+"', json_data_ip['ip']) url = url.replace('"+need_captcha+"', '0') #json_data_ip['need_captcha']) url = url.replace('"+token', '') - # ~ logger.debug(url) + # logger.info('URL= '+url) + # logger.debug(url) headers = { "User-Agent": 'Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.127 Large Screen Safari/533.4 GoogleTV/162671' } data = httptools.downloadpage('http://hqq.watch'+url, headers=headers).data - # ~ logger.debug(data) + # logger.debug(data) codigo_js = scrapertools.find_multiple_matches(data, '<script>document.write\(unescape\("([^"]+)') - # ~ logger.debug(codigo_js) + # logger.debug(codigo_js) js_aux = urllib.unquote(codigo_js[0]) at = scrapertools.find_single_match(js_aux, 'var at = "([^"]+)') diff --git a/servers/openload.py b/servers/openload.py index 2c7792c3..0b392675 100644 --- a/servers/openload.py +++ b/servers/openload.py @@ -35,6 +35,7 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= header = {'Referer': referer} data = httptools.downloadpage(page_url, cookies=False, headers=header).data + logger.info('OP DATA= ' + data) subtitle = scrapertools.find_single_match(data, '<track kind="captions" src="([^"]+)" srclang="es"') try: diff --git a/servers/supervideo.json b/servers/supervideo.json new file mode 100644 index 00000000..8b2a5304 --- /dev/null +++ b/servers/supervideo.json @@ -0,0 +1,46 @@ +{ + "active": true, + "find_videos": { + "ignore_urls": [], + "patterns": [ + { + "pattern": "supervideo.tv/embed-([a-z0-9]{12}).html", + "url": "https://supervideo.tv/embed-\\1.html" + }, + { + "pattern": "supervideo.tv/([a-z0-9]{12})", + "url": "https://supervideo.tv/embed-\\1.html" + } + ] + }, + "free": true, + "id": "supervideo", + "name": "SuperVideo", + "settings": [ + { + "default": false, + "enabled": true, + "id": "black_list", + "label": "@60654", + "type": "bool", + "visible": true + }, + { + "default": 0, + "enabled": true, + "id": "favorites_servers_list", + "label": "@60655", + "lvalues": [ + "No", + "1", + "2", + "3", + "4", + "5" + ], + "type": "list", + "visible": false + } + ], + "thumbnail": "https://supervideo.tv/images/logo-player.png" +} diff --git a/servers/supervideo.py b/servers/supervideo.py new file mode 100644 index 00000000..48eea092 --- /dev/null +++ b/servers/supervideo.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +from core import httptools +from core import scrapertoolsV2 +from lib import jsunpack +from platformcode import config, logger +import ast + + +def test_video_exists(page_url): + logger.info("(page_url='%s')" % page_url) + + data = httptools.downloadpage(page_url, cookies=False).data + if 'File Not Found' in data: + return False, config.get_localized_string(70449) % "SuperVideo" + + return True, "" + + +def get_video_url(page_url, premium=False, user="", password="", video_password=""): + logger.info("url=" + page_url) + video_urls = [] + data = httptools.downloadpage(page_url).data + code = jsunpack.unpack(scrapertoolsV2.find_single_match(data, "<script type='text/javascript'>(eval.*)")) + match = scrapertoolsV2.find_single_match(code, 'sources:(\[[^]]+\])') + lSrc = ast.literal_eval(match) + + lQuality = ['360p', '720p', '1080p', '4k'][:len(lSrc)-1] + lQuality.reverse() + + for n, source in enumerate(lSrc): + quality = 'auto' if n==0 else lQuality[n-1] + video_urls.append(['.' + source.split('.')[-1] + '(' + quality + ') [SuperVideo]', source]) + return video_urls diff --git a/servers/vcstream.json b/servers/vcstream.json new file mode 100644 index 00000000..3d51bc1a --- /dev/null +++ b/servers/vcstream.json @@ -0,0 +1,46 @@ +{ + "active": true, + "find_videos": { + "ignore_urls": [], + "patterns": [ + { + "pattern": "vcstream.to/(?:embed|f)/([A-z0-9]+)/([A-z0-9.]+)", + "url": "https://vcstream.to/embed/\\1/\\2" + }, + { + "pattern": "https://vidcloud.co/v/([a-z0-9A-Z]+)", + "url": "https:\/\/vidcloud.co\/v\/\\1" + } + ] + }, + "free": true, + "id": "vcstream", + "name": "vcstream", + "settings": [ + { + "default": false, + "enabled": true, + "id": "black_list", + "label": "@60654", + "type": "bool", + "visible": true + }, + { + "default": 0, + "enabled": true, + "id": "favorites_servers_list", + "label": "@60655", + "lvalues": [ + "No", + "1", + "2", + "3", + "4", + "5" + ], + "type": "list", + "visible": false + } + ], + "thumbnail": "http://i.imgur.com/l45Tk0G.png" +} diff --git a/servers/vcstream.py b/servers/vcstream.py new file mode 100644 index 00000000..ecd1afcb --- /dev/null +++ b/servers/vcstream.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +# Icarus pv7 +# Fix dentaku65 + +import urlparse + +from core import httptools +from core import scrapertools +from platformcode import logger, config + + +def test_video_exists(page_url): + logger.info("(page_url='%s')" % page_url) + data = httptools.downloadpage(page_url).data + if "We're Sorry" in data: + return False, config.get_localized_string(70292) % "vcstream" + + return True, "" + + +def get_video_url(page_url, premium=False, user="", password="", video_password=""): + logger.info("url=" + page_url) + + video_urls = [] + + data = httptools.downloadpage(page_url).data + + url = scrapertools.find_single_match(data, "url: '([^']+)',") + + if url: + headers = dict() + headers['X-Requested-With'] = "XMLHttpRequest" + + token = scrapertools.find_single_match(data, 'set-cookie: vidcloud_session=(.*?);') + token = token.replace("%3D", "") + if token: + headers['vidcloud_session'] = token + + referer = scrapertools.find_single_match(data, "pageUrl = '([^']+)'") + if referer: + headers['Referer'] = referer + + page_url = urlparse.urljoin(page_url, url) + data = httptools.downloadpage(page_url, headers=headers).data + data = data.replace('\\\\', '\\').replace('\\','') + + media_urls = scrapertools.find_multiple_matches(data, '\{"file"\s*:\s*"([^"]+)"\}') + + for media_url in media_urls: + ext = "mp4" + if "m3u8" in media_url: + ext = "m3u8" + video_urls.append(["%s [vcstream]" % ext, media_url]) + + for video_url in video_urls: + logger.info("%s - %s" % (video_url[0], video_url[1])) + return video_urls + diff --git a/servers/vidcloud.py b/servers/vidcloud.py deleted file mode 100644 index 41d5959d..00000000 --- a/servers/vidcloud.py +++ /dev/null @@ -1,28 +0,0 @@ -# Conector vidcloud By Alfa development Group -# -------------------------------------------------------- - -import re - -from core import httptools -from platformcode import logger - - -def test_video_exists(page_url): - logger.info("(page_url='%s')" % page_url) - data = httptools.downloadpage(page_url) - if data.code == 404: - return False, "[Cloud] El archivo no existe o ha sido borrado" - return True, "" - - -def get_video_url(page_url, premium=False, user="", password="", video_password=""): - logger.info("url=" + page_url) - video_urls = [] - data = httptools.downloadpage(page_url).data - data = data.replace('\\\\', '\\').replace('\\','') - patron = '"file":"([^"]+)"' - matches = re.compile(patron, re.DOTALL).findall(data) - for url in matches: - if not ".vtt" in url: - video_urls.append(['vidcloud', url]) - return video_urls diff --git a/servers/vvvvid.json b/servers/vvvvid.json new file mode 100644 index 00000000..d3205cfb --- /dev/null +++ b/servers/vvvvid.json @@ -0,0 +1,42 @@ +{ + "active": true, + "find_videos": { + "ignore_urls": [], + "patterns": [ + { + "pattern": "https://www.vvvvid.it/.*?show/([a-z0-9/-]+)", + "url": "https://www.vvvvid.it/show/\\1" + } + ] + }, + "free": true, + "id": "vvvvid", + "name": "vvvvid", + "settings": [ + { + "default": false, + "enabled": true, + "id": "black_list", + "label": "@60654", + "type": "bool", + "visible": true + }, + { + "default": 0, + "enabled": true, + "id": "favorites_servers_list", + "label": "@60655", + "lvalues": [ + "No", + "1", + "2", + "3", + "4", + "5" + ], + "type": "list", + "visible": false + } + ], + "thumbnail": "" +} diff --git a/servers/vvvvid.py b/servers/vvvvid.py new file mode 100644 index 00000000..36e7d305 --- /dev/null +++ b/servers/vvvvid.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +from core import httptools +from lib import vvvvid_decoder +from platformcode import logger +import requests +import re + +# Creating persistent session +current_session = requests.Session() +headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0'} + +# Getting conn_id token from vvvvid and creating payload +login_page = 'https://www.vvvvid.it/user/login' +conn_id = current_session.get(login_page, headers=headers).json()['data']['conn_id'] +payload = {'conn_id': conn_id} +# logger.info('CONNECTION ID= ' + str(payload)) + + +def test_video_exists(page_url): + logger.info("(page_url='%s')" % page_url) + data = httptools.downloadpage(page_url).data + if "Not Found" in data or "File was deleted" in data: + return False, "[VVVVID] The file does not exist or has been deleted" + else: + page_url = page_url.replace("/show/","/#!show/") + show_id = re.findall("#!show/([0-9]+)/", page_url)[0] + name = re.findall(show_id + "/(.+?)/", page_url) + if not name: return False, "[VVVVID] The file does not exist or has been deleted" + return True, "" + + +def get_video_url(page_url, premium=False, user="", password="", video_password=""): + video_urls = [] + + page_url = page_url.replace("/show/","/#!show/") + + # Getting info from given URL + show_id = re.findall("#!show/([0-9]+)/", page_url)[0] + name = re.findall(show_id + "/(.+?)/", page_url)[0] + season_id = re.findall(name + "/(.+?)/", page_url)[0] + video_id = re.findall(season_id + "/(.+?)/", page_url)[0] + + # Getting info from Site + json_url = "https://www.vvvvid.it/vvvvid/ondemand/" + show_id + '/season/' +season_id + '/' + # logger.info('URL= ' + json_url) + json_file = current_session.get(json_url, headers=headers, params=payload).json() + logger.info(json_file['data']) + + # Search for the correct episode + for episode in json_file['data']: + # import web_pdb; web_pdb.set_trace() + if episode['video_id'] == int(video_id): + ep_title = '[B]' + episode['title'] + '[/B]' + embed_info = vvvvid_decoder.dec_ei(episode['embed_info']) + embed_info = embed_info.replace('manifest.f4m','master.m3u8').replace('http://','https://').replace('/z/','/i/') + + # import web_pdb; web_pdb.set_trace() + + video_urls.append([ep_title, str(embed_info)]) + + return video_urls \ No newline at end of file diff --git a/servers/wstream.json b/servers/wstream.json index 45e65004..2b934bbc 100644 --- a/servers/wstream.json +++ b/servers/wstream.json @@ -6,13 +6,21 @@ "thumbnail": "http:\/\/media.tvalacarta.info\/servers\/server_wstream.png", "find_videos": { "patterns": [ - { - "pattern": "wstream\\.video/video\\.php\\?file_code=([a-z0-9A-Z]+)", - "url": "http:\/\/wstream.video\/\\1" + { + "pattern":"wstream.video\/(api\/vcmod\/fastredirect\/streaming.php\\?id=[0-9a-zA-Z]+)", + "url": "https://wstream.video/video.php?file_code=\\1" }, { - "pattern": "wstream\\.video/(?:embed-|videos/|video/|videow/|videoj/)?([a-z0-9A-Z]+)", - "url": "http:\/\/wstream.video\/\\1" + "pattern": "wstream\\.video/video\\.php\\?file_code=([a-z0-9A-Z]+)", + "url": "https://wstream.video/video.php?file_code=\\1" + }, + { + "pattern": "wstream\\.video\/(?:embed-|videos/|video/|videow/|videoj/)([a-z0-9A-Z]+)", + "url": "https://wstream.video/video.php?file_code=\\1" + }, + { + "pattern": "wstream\\.video\/(?!api/)([a-z0-9A-Z]+)", + "url": "https://wstream.video/video.php?file_code=\\1" } ], "ignore_urls": [ ] diff --git a/servers/wstream.py b/servers/wstream.py index 3b808c8d..53a2dc26 100644 --- a/servers/wstream.py +++ b/servers/wstream.py @@ -17,13 +17,17 @@ def test_video_exists(page_url): return False, "[wstream.py] Il File Non esiste" return True, "" + # Returns an array of possible video url's from the page_url def get_video_url(page_url, premium=False, user="", password="", video_password=""): - # import web_pdb; web_pdb.set_trace() logger.info("[wstream.py] url=" + page_url) video_urls = [] + code = page_url.split('=')[-1] + post = urllib.urlencode({ + 'videox': code + }) - data = httptools.downloadpage(page_url, headers=headers, follow_redirects=True).data.replace('https','http') + data = httptools.downloadpage(page_url, headers=headers, post=post, follow_redirects=True).data.replace('https','http') logger.info("[wstream.py] data=" + data) vid = scrapertools.find_multiple_matches(data, 'download_video.*?>.*?<.*?<td>([^\,,\s]+)') headers.append(['Referer', page_url]) @@ -33,48 +37,19 @@ def get_video_url(page_url, premium=False, user="", password="", video_password= data = jsunpack.unpack(post_data) logger.info("[wstream.py] data=" + data) block = scrapertools.find_single_match(data, 'sources:\s*\[[^\]]+\]') - if block: - data = block + data = block - media_urls = scrapertools.find_multiple_matches(data, '(http.*?\.mp4)') - _headers = urllib.urlencode(dict(headers)) - i = 0 + media_urls = scrapertools.find_multiple_matches(data, '(http.*?\.mp4)') + _headers = urllib.urlencode(dict(headers)) + i = 0 - for media_url in media_urls: - video_urls.append([vid[i] if vid else 'video' + " mp4 [wstream] ", media_url + '|' + _headers]) - i = i + 1 + for media_url in media_urls: + video_urls.append([vid[i] if vid else 'video' + " mp4 [wstream] ", media_url + '|' + _headers]) + i = i + 1 - for video_url in video_urls: - logger.info("[wstream.py] %s - %s" % (video_url[0], video_url[1])) + for video_url in video_urls: + logger.info("[wstream.py] %s - %s" % (video_url[0], video_url[1])) - logger.info(video_urls) + logger.info(video_urls) - return video_urls - else: - page_urls = scrapertools.find_multiple_matches(data, '''<a href=(?:"|')([^"']+)(?:"|')''') - for page_url in page_urls: - if '404 Not Found' not in httptools.downloadpage(page_url, headers=headers).data.replace('https', 'http'): - return get_video_url(page_url) - - - -def find_videos(data): - encontrados = set() - devuelve = [] - - patronvideos = r"wstream.video/(?:embed-|videos/|video/)?([a-z0-9A-Z]+)" - logger.info("[wstream.py] find_videos #" + patronvideos + "#") - matches = re.compile(patronvideos, re.DOTALL).findall(data) - - for match in matches: - titulo = "[wstream]" - url = 'http://wstream.video/%s' % match - - if url not in encontrados: - logger.info(" url=" + url) - devuelve.append([titulo, url, 'wstream']) - encontrados.add(url) - else: - logger.info(" url duplicada=" + url) - - return devuelve \ No newline at end of file + return video_urls diff --git a/servers/youtube.json b/servers/youtube.json index c8e0bb0c..39f5872d 100644 --- a/servers/youtube.json +++ b/servers/youtube.json @@ -15,6 +15,11 @@ "pattern": "youtube.com/v/([0-9A-Za-z_-]{11})", "url": "http://www.youtube.com/watch?v=\\1" } + , + { + "pattern": "youtu.be/([0-9A-Za-z_-]{11})", + "url": "http://www.youtube.com/watch?v=\\1" + } ] }, "free": true, diff --git a/servers/youtube.py b/servers/youtube.py index aa28acbe..b00e94ed 100644 --- a/servers/youtube.py +++ b/servers/youtube.py @@ -86,7 +86,7 @@ def extract_flashvars(data): def extract_videos(video_id): fmt_value = { 5: "240p h263 flv", - 6: "240p h263 flv", + 6: "270p h263 flv", 18: "360p h264 mp4", 22: "720p h264 mp4", 26: "???", @@ -108,10 +108,18 @@ def extract_videos(video_id): 85: "1080p h264 3D", 100: "360p vp8 3D", 101: "480p vp8 3D", - 102: "720p vp8 3D" + 102: "720p vp8 3D", + 91:"144 h264 mp4", + 92:"240 h264 mp4", + 93:"360 h264 mp4", + 94:"480 h264 mp4", + 95:"720 h264 mp4", + 96:"1080 h264 mp4", + 132:"240 h264 mp4", + 151:"72 h264 mp4" } - - url = 'http://www.youtube.com/get_video_info?video_id=%s&eurl=https://youtube.googleapis.com/v/%s&ssl_stream=1' % \ + # from core.support import dbg; dbg() + url = 'https://www.youtube.com/get_video_info?video_id=%s&eurl=https://youtube.googleapis.com/v/%s&ssl_stream=1' % \ (video_id, video_id) data = httptools.downloadpage(url).data @@ -132,53 +140,59 @@ def extract_videos(video_id): js_signature = "" youtube_page_data = httptools.downloadpage("http://www.youtube.com/watch?v=%s" % video_id).data params = extract_flashvars(youtube_page_data) + data_flashvars =[] + if params.get('adaptive_fmts'): + data_flashvars += scrapertools.find_multiple_matches(params['adaptive_fmts'], '(fps.*?url[^,]+)') if params.get('url_encoded_fmt_stream_map'): - data_flashvars = params["url_encoded_fmt_stream_map"].split(",") - for url_desc in data_flashvars: - url_desc_map = dict(urlparse.parse_qsl(url_desc)) - if not url_desc_map.get("url") and not url_desc_map.get("stream"): + data_flashvars += params["url_encoded_fmt_stream_map"].split(",") + + for url_desc in data_flashvars: + url_desc_map = dict(urlparse.parse_qsl(url_desc)) + if not url_desc_map.get("url") and not url_desc_map.get("stream"): + continue + try: + key = int(url_desc_map["itag"]) + if not fmt_value.get(key): continue - try: - key = int(url_desc_map["itag"]) - if not fmt_value.get(key): - continue + if url_desc_map.get("url"): + url = urllib.unquote(url_desc_map["url"]) + elif url_desc_map.get("conn") and url_desc_map.get("stream"): + url = urllib.unquote(url_desc_map["conn"]) + if url.rfind("/") < len(url) - 1: + url += "/" + url += urllib.unquote(url_desc_map["stream"]) + elif url_desc_map.get("stream") and not url_desc_map.get("conn"): + url = urllib.unquote(url_desc_map["stream"]) - if url_desc_map.get("url"): - url = urllib.unquote(url_desc_map["url"]) - elif url_desc_map.get("conn") and url_desc_map.get("stream"): - url = urllib.unquote(url_desc_map["conn"]) - if url.rfind("/") < len(url) - 1: - url += "/" - url += urllib.unquote(url_desc_map["stream"]) - elif url_desc_map.get("stream") and not url_desc_map.get("conn"): - url = urllib.unquote(url_desc_map["stream"]) + if url_desc_map.get("sig"): + url += "&signature=" + url_desc_map["sig"] + elif url_desc_map.get("s"): + sig = url_desc_map["s"] + if not js_signature: + urljs = scrapertools.find_single_match(youtube_page_data, '"assets":.*?"js":\s*"([^"]+)"') + urljs = urljs.replace("\\", "") + if urljs: + if not re.search(r'https?://', urljs): + urljs = urlparse.urljoin("https://www.youtube.com", urljs) + data_js = httptools.downloadpage(urljs).data + from jsinterpreter import JSInterpreter + funcname = scrapertools.find_single_match(data_js, '\.sig\|\|([A-z0-9$]+)\(') + if not funcname: + funcname = scrapertools.find_single_match(data_js, '["\']signature["\']\s*,\s*' + '([A-z0-9$]+)\(') + if not funcname: + funcname = scrapertools.find_single_match(data_js, r'\b[cs]\s*&&\s*[adf]\.set\([^,]+\s*,\s*encodeURIComponent\s*\(\s*(?P<sig>[a-zA-Z0-9$]+)\(') + jsi = JSInterpreter(data_js) + js_signature = jsi.extract_function(funcname) - if url_desc_map.get("sig"): - url += "&signature=" + url_desc_map["sig"] - elif url_desc_map.get("s"): - sig = url_desc_map["s"] - if not js_signature: - urljs = scrapertools.find_single_match(youtube_page_data, '"assets":.*?"js":\s*"([^"]+)"') - urljs = urljs.replace("\\", "") - if urljs: - if not re.search(r'https?://', urljs): - urljs = urlparse.urljoin("https://www.youtube.com", urljs) - data_js = httptools.downloadpage(urljs).data - from jsinterpreter import JSInterpreter - funcname = scrapertools.find_single_match(data_js, '\.sig\|\|([A-z0-9$]+)\(') - if not funcname: - funcname = scrapertools.find_single_match(data_js, '["\']signature["\']\s*,\s*' - '([A-z0-9$]+)\(') - jsi = JSInterpreter(data_js) - js_signature = jsi.extract_function(funcname) - signature = js_signature([sig]) - url += "&signature=" + signature - url = url.replace(",", "%2C") - video_urls.append(["(" + fmt_value[key] + ") [youtube]", url]) - except: - import traceback - logger.info(traceback.format_exc()) + signature = js_signature([sig]) + url += "&sig=" + signature + url = url.replace(",", "%2C") + video_urls.append(["(" + fmt_value[key] + ") [youtube]", url]) + except: + import traceback + logger.info(traceback.format_exc()) return video_urls diff --git a/specials/autoplay.py b/specials/autoplay.py index 451f18e3..8defa70b 100644 --- a/specials/autoplay.py +++ b/specials/autoplay.py @@ -16,6 +16,8 @@ PLAYED = False autoplay_node = {} +colorKOD = '0xFF65B3DA' + def context(): ''' @@ -36,7 +38,7 @@ def context(): context = context() -def show_option(channel, itemlist, text_color='yellow', thumbnail=None, fanart=None): +def show_option(channel, itemlist, text_color=colorKOD, thumbnail=None, fanart=None): ''' Agrega la opcion Configurar AutoPlay en la lista recibida @@ -54,8 +56,8 @@ def show_option(channel, itemlist, text_color='yellow', thumbnail=None, fanart=N if thumbnail == None: thumbnail = get_thumb('autoplay.png') - if fanart == None: - fanart = get_thumb('autoplay.png') + # if fanart == None: + # fanart = get_thumb('autoplay.png') plot_autoplay = config.get_localized_string(60399) itemlist.append( @@ -63,10 +65,12 @@ def show_option(channel, itemlist, text_color='yellow', thumbnail=None, fanart=N title=config.get_localized_string(60071), action="autoplay_config", text_color=text_color, + text_bold=True, thumbnail=thumbnail, - fanart=fanart, + # fanart=fanart, plot=plot_autoplay, - from_channel=channel + from_channel=channel, + folder=False )) return itemlist @@ -641,7 +645,7 @@ def get_languages(channel): :return: list ''' logger.info() - list_language = ['No filtrar'] + list_language = ['Non filtrare'] list_controls, dict_settings = channeltools.get_channel_controls_settings(channel) for control in list_controls: try: diff --git a/specials/autorenumber.py b/specials/autorenumber.py index 1bdc5339..a5bc8fb8 100644 --- a/specials/autorenumber.py +++ b/specials/autorenumber.py @@ -10,11 +10,11 @@ USO: 3) Aggiungere le seguinti stringhe nel json del canale (per attivare la configurazione di autonumerazione del canale) { - "id": "autorenumber", - "type": "bool", - "label": "@70712", - "default": false, - "enabled": true, + "id": "autorenumber", + "type": "bool", + "label": "@70712", + "default": false, + "enabled": true, "visible": true }, { @@ -31,10 +31,10 @@ try: import xbmcgui except: xbmcgui = None - -import re, base64, json, os +import xbmc +import re, base64, json, os, inspect from core import jsontools, tvdb, scrapertoolsV2 -from core.support import typo, log +from core.support import typo, log, dbg from platformcode import config, platformtools, logger from platformcode.config import get_setting @@ -44,6 +44,10 @@ TAG_SEASON = "Season" TAG_EPISODE = "Episode" TAG_SPECIAL = "Special" TAG_MODE = "Mode" +TAG_EPLIST = "EpList" +TAG_CHECK = "ReCheck" +TAG_SPLIST = "SpList" +TAG_TYPE = "Type" __channel__ = "autorenumber" @@ -59,11 +63,104 @@ def context(exist): if access(): modify = config.get_localized_string(70714) if exist else '' _context = [{"title": typo(modify + config.get_localized_string(70585), 'bold'), - "action": "semiautomatic_config_item", - "channel": "autorenumber"}] + "action": "select_type", + "channel": "autorenumber",}] return _context +def select_type(item): + select = platformtools.dialog_select(config.get_localized_string(70730),[typo(config.get_localized_string(70731),'bold'), typo(config.get_localized_string(70732),'bold')]) + if select == 0: semiautomatic_config_item(item) + else: manual_renumeration(item) + +def manual_renumeration(item, modify=False): + log() + _list = [] + if item.from_channel: item.channel = item.from_channel + title = item.show if item.show else item.fulltitle + + dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE) + if not dict_series.has_key(title): dict_series[title] = {} + + if dict_series[title].has_key(TAG_EPISODE) and dict_series[title][TAG_EPISODE]: + EpisodeDict = json.loads(base64.b64decode(dict_series[title][TAG_EPISODE])) + del dict_series[title][TAG_EPISODE] + else: EpisodeDict = {} + + if dict_series[title].has_key(TAG_EPLIST): del dict_series[title][TAG_EPLIST] + if dict_series[title].has_key(TAG_MODE): del dict_series[title][TAG_MODE] + if dict_series[title].has_key(TAG_CHECK): del dict_series[title][TAG_CHECK] + if dict_series[title].has_key(TAG_SEASON): del dict_series[title][TAG_SEASON] + if dict_series[title].has_key(TAG_SPECIAL): del dict_series[title][TAG_SPECIAL] + dict_series[title][TAG_TYPE] = 'manual' + + jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + if not dict_series[title].has_key(TAG_ID) or (dict_series[title].has_key(TAG_ID) and not dict_series[title][TAG_ID]): + tvdb.find_and_set_infoLabels(item) + + # Trova l'ID della serie + while not item.infoLabels['tvdb_id']: + try: + item.show = platformtools.dialog_input(default=item.show, heading=config.get_localized_string(30112)) # <- Enter title to search + tvdb.find_and_set_infoLabels(item) + except: + heading = config.get_localized_string(70704) # <- TMDB ID (0 to cancel) + info = platformtools.dialog_numeric(0, heading) + item.infoLabels['tvdb_id'] = '0' if info == '' else info + + if item.infoLabels['tvdb_id']: + ID = item.infoLabels['tvdb_id'] + dict_renumerate = {TAG_ID: ID} + dict_series[title] = dict_renumerate + + # channel = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) + itemlist = find_episodes(item) + for item in itemlist: + Title = re.sub(r'\d+x\d+ - ', '', item.title) + if modify == True: + ep = int(scrapertoolsV2.find_single_match(Title, r'(\d+)')) + if item.action == 'findvideos' and not EpisodeDict.has_key(str(ep)): + _list.append(Title) + else: + if item.action == 'findvideos': + _list.append(Title) + + count = 1 + preselect = platformtools.dialog_select(config.get_localized_string(70732),[typo(config.get_localized_string(70518),'bold'),typo(config.get_localized_string(70519),'bold')]) + selection = [] + if preselect == 0: + for i in _list: + selection.append(_list.index(i)) + while len(_list) > 0: + selected = platformtools.dialog_multiselect(config.get_localized_string(70734), _list, preselect=selection) + if selected == None: break + season = '' + while not season: + season = platformtools.dialog_numeric(0, config.get_localized_string(70733)) + for select in selected: + ep = int(scrapertoolsV2.find_single_match(_list[select], r'(\d+)')) + if season == '0': + episode = '' + while not episode: + episode = platformtools.dialog_numeric(0, config.get_localized_string(70735) % _list[select] ) + EpisodeDict[str(ep)] = '%sx%s' %(season, episode.zfill(2)) + else: + EpisodeDict[str(ep)] = '%sx%s' %(season, str(count).zfill(2)) + count += 1 + + for select in reversed(selected): + del _list[select] + + + dict_series[title][TAG_TYPE] = 'manual' + EpisodeDict = base64.b64encode(json.dumps(EpisodeDict)) + dict_series[title][TAG_EPISODE] = EpisodeDict + jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + xbmc.executebuiltin("Container.Refresh") + if modify == True: + return json.loads(base64.b64decode(EpisodeDict)) + + def semiautomatic_config_item(item): log() # Configurazione Semi Automatica, utile in caso la numerazione automatica fallisca @@ -72,8 +169,8 @@ def semiautomatic_config_item(item): item.channel = item.from_channel dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE) title = item.show - - # Trova l'ID dellla serie + + # Trova l'ID della serie while not item.infoLabels['tvdb_id']: try: item.show = platformtools.dialog_input(default=item.show, heading=config.get_localized_string(30112)) # <- Enter title to search @@ -83,7 +180,7 @@ def semiautomatic_config_item(item): info = platformtools.dialog_numeric(0, heading) item.infoLabels['tvdb_id'] = '0' if info == '' else info - + if item.infoLabels['tvdb_id']: ID = item.infoLabels['tvdb_id'] dict_renumerate = {TAG_ID: ID} @@ -101,52 +198,51 @@ def semiautomatic_config_item(item): heading = config.get_localized_string(70686) # <- Enter the number of the starting season (for season 1) season = platformtools.dialog_numeric(0, heading, '1') dict_renumerate[TAG_SEASON] = season - - ########### PROVVISORIO ################### + + mode = platformtools.dialog_yesno(config.get_localized_string(70687), config.get_localized_string(70688), nolabel=config.get_localized_string(30023), yeslabel=config.get_localized_string(30022)) - if mode == 1: + if mode == True: dict_renumerate[TAG_MODE] = False - specials = [] - stop = False - while not stop: - heading = config.get_localized_string(70718) + str(specials) - special = platformtools.dialog_numeric(0, heading, '') - if special: - specials.append(int(special)) - dict_renumerate[TAG_SPECIAL] = specials - else: stop = True + if dict_series[title].has_key(TAG_SPECIAL): + specials = dict_renumerate[TAG_SPECIAL] + else: + specials = [] + jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + _list = [] + # channel = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) + itemlist = find_episodes(item) + for item in itemlist: + Title = re.sub(r'\d+x\d+ - ', '', item.title) + if item.action == 'findvideos': + _list.append(Title) + + selected = platformtools.dialog_multiselect(config.get_localized_string(70734), _list) + # if len(selected) > 0: + for select in selected: + specials.append(int(scrapertoolsV2.find_single_match(_list[select],r'(\d+)'))) + dict_renumerate[TAG_SPECIAL] = specials + + # stop = False + # while not stop: + # heading = config.get_localized_string(70718) + str(specials) + # special = platformtools.dialog_numeric(0, heading, '') + # if special: + # specials.append(int(special)) + # dict_renumerate[TAG_SPECIAL] = specials + # else: stop = True dict_renumerate[TAG_MODE] = False - # Richede se ci sono speciali nella stagione - # mode = platformtools.dialog_yesno(config.get_localized_string(70687), config.get_localized_string(70688), nolabel=config.get_localized_string(30023), yeslabel=config.get_localized_string(30022)) - # if mode == 0: dict_renumerate[TAG_MODE] = False - # else: - # select = platformtools.dialog_yesno(config.get_localized_string(70687), config.get_localized_string(70717), nolabel=config.get_localized_string(30023), yeslabel=config.get_localized_string(30022)) - # if select == 0: - # dict_renumerate[TAG_MODE] = False - # specials = [] - # stop = False - # while not stop: - # heading = config.get_localized_string(70718) + str(specials) - # special = platformtools.dialog_numeric(0, heading, '') - # if special: - # specials.append(int(special)) - # dict_renumerate[TAG_SPECIAL] = specials - # else: stop = True - # else: - # dict_renumerate[TAG_MODE] = True - ########### PROVVISORIO ################### - + dict_renumerate[TAG_TYPE] = 'auto' # Imposta la voce Episode dict_renumerate[TAG_EPISODE] = '' # Scrive nel json jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + xbmc.executebuiltin("Container.Refresh") else: message = config.get_localized_string(60444) heading = item.show.strip() platformtools.dialog_notification(heading, message) - def config_item(item, itemlist=[], typography='', active=False): @@ -157,15 +253,14 @@ def config_item(item, itemlist=[], typography='', active=False): dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE) try: ID = dict_series[item.show.rstrip()][TAG_ID] except: ID = '' - - # Pulizia del Titolo + + # Pulizia del Titolo if any( word in title.lower() for word in ['specials', 'speciali']): item.show = re.sub(r'\sspecials|\sspeciali', '', item.show.lower()) - log('ITEM SHOW= ',item.show) - tvdb.find_and_set_infoLabels(item) + tvdb.find_and_set_infoLabels(item) elif not item.infoLabels['tvdb_id']: item.show = title.rstrip('123456789 ') - tvdb.find_and_set_infoLabels(item) + tvdb.find_and_set_infoLabels(item) if not ID and active: if item.infoLabels['tvdb_id']: @@ -192,40 +287,57 @@ def config_item(item, itemlist=[], typography='', active=False): def renumber(itemlist, item='', typography=''): log() + # Carica Impostazioni + if itemlist: + settings_node = jsontools.get_node_from_file(itemlist[0].channel, 'settings') + else: + settings_node = {} + try: dict_series = jsontools.get_node_from_file(itemlist[0].channel, TAG_TVSHOW_RENUMERATE) + except: dict_series = {} # Seleziona la funzione Adatta, Menu Contestuale o Rinumerazione if item: - settings_node = jsontools.get_node_from_file(item.channel, 'settings') - # Controlla se la Serie è già stata rinumerata - - try: - dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE) - TITLE = item.fulltitle.rstrip() + item.channel = item.from_channel if item.from_channel else item.channel + # Controlla se la Serie è già stata rinumerata + TITLE = item.fulltitle.rstrip() if item.fulltitle else item.contentTitle + + if inspect.stack()[2][3] == 'find_episodes': + return itemlist + + elif dict_series.has_key(TITLE) and dict_series[TITLE].has_key(TAG_ID): ID = dict_series[TITLE][TAG_ID] - - exist = True - except: - exist = False - - if exist: - ID = dict_series[TITLE][TAG_ID] - SEASON = dict_series[TITLE][TAG_SEASON] EPISODE = dict_series[TITLE][TAG_EPISODE] - MODE = dict_series[TITLE][TAG_MODE] - renumeration(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE) + + if dict_series[TITLE].has_key(TAG_SEASON): SEASON = dict_series[TITLE][TAG_SEASON] + else: SEASON = '' + + if dict_series[TITLE].has_key(TAG_MODE): MODE = dict_series[TITLE][TAG_MODE] + else: MODE = False + + if dict_series[TITLE].has_key(TAG_TYPE): + TYPE = dict_series[TITLE][TAG_TYPE] + else: + TYPE = 'auto' + dict_series[TITLE][TAG_TYPE] = TYPE + jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + + renumeration(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE, TYPE) + else: # se non è stata rinumerata controlla se è attiva la rinumerazione automatica - if 'autorenumber' not in settings_node: return itemlist + if 'autorenumber' not in settings_node: + return itemlist if settings_node['autorenumber'] == True: - config_item(item, itemlist, typography, True) + config_item(item, itemlist, typography, True) + else: for item in itemlist: - try: - dict_series = jsontools.get_node_from_file(itemlist[0].channel, TAG_TVSHOW_RENUMERATE) - TITLE = item.show.rstrip() + TITLE = item.show.rstrip() + if dict_series.has_key(TITLE) and dict_series[TITLE].has_key(TAG_ID): ID = dict_series[TITLE][TAG_ID] - exist = True - except: + exist = True + else: exist = False + if item.contentType != 'movie': if item.context: context2 = item.context @@ -234,9 +346,9 @@ def renumber(itemlist, item='', typography=''): else: item.show = TITLE item.context = context(exist) - -def renumeration (itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE): - log() + +def renumeration (itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE, TYPE): + # Se ID è 0 salta la rinumerazione if ID == '0': return itemlist @@ -245,54 +357,87 @@ def renumeration (itemlist, item, typography, dict_series, ID, SEASON, EPISODE, elif SEASON == '0': EpisodeDict = {} for item in itemlist: - number = scrapertoolsV2.find_single_match(item.title, r'\d+') - item.title = typo('0x' + number + ' - ', typography) + item.title - - + if config.get_localized_string(30992) not in item.title: + number = scrapertoolsV2.find_single_match(item.title, r'\d+') + item.title = typo('0x' + number + ' - ', typography) + item.title + + # Usa la lista degli Episodi se esiste nel Json - + elif EPISODE: EpisodeDict = json.loads(base64.b64decode(EPISODE)) # Controlla che la lista egli Episodi sia della stessa lunghezza di Itemlist if EpisodeDict == 'none': return error(itemlist) - if len(EpisodeDict) >= len(itemlist): + if TYPE == 'manual' and len(EpisodeDict) < len(itemlist): + EpisodeDict = manual_renumeration(item, True) + if len(EpisodeDict) >= len(itemlist) and EpisodeDict.has_key(scrapertoolsV2.find_single_match(itemlist[0].title, r'\d+')): for item in itemlist: - number = scrapertoolsV2.find_single_match(item.title, r'\d+') - item.title = typo(EpisodeDict[str(number)] + ' - ', typography) + item.title + if config.get_localized_string(30992) not in item.title: + number = scrapertoolsV2.find_single_match(item.title, r'\d+') + number = int(number) # if number !='0': number.lstrip('0') + item.title = typo(EpisodeDict[str(number)] + ' - ', typography) + item.title else: - make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE) + make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE) else: make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE) def make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE): log() - page = 1 - EpList = [] - EpisodeDict = {} exist = True item.infoLabels['tvdb_id'] = ID tvdb.set_infoLabels_item(item) FirstOfSeason= 0 + + if EPISODE: EpisodeDict = json.loads(base64.b64decode(EPISODE)) + else: EpisodeDict = {} try: SPECIAL = dict_series[TITLE][TAG_SPECIAL] except: SPECIAL = [] - - # Ricava Informazioni da TVDB - while exist: - data = tvdb.otvdb_global.get_list_episodes(ID,page) - if data: page = page + 1 - else: exist = False + try: EpList = json.loads(base64.b64decode(dict_series[TITLE][TAG_EPLIST])) + except: EpList = [] + try: Pages = dict_series[TITLE][TAG_CHECK] + except: Pages = [1] + # Ricava Informazioni da TVDB + checkpages = [] + check = True + Page = Pages[-1] + + while exist: + if check: + for page in Pages: + data = tvdb.otvdb_global.get_list_episodes(ID,page) + for episodes in data['data']: + if episodes['firstAired'] and [episodes['firstAired'], episodes['airedSeason'], episodes['airedEpisodeNumber']] not in EpList: + EpList.append([episodes['firstAired'], episodes['airedSeason'], episodes['airedEpisodeNumber']]) + else: + if page not in checkpages: + checkpages.append(page) + check = False + + data = tvdb.otvdb_global.get_list_episodes(ID,Page) if data: + Page = Page + 1 for episodes in data['data']: - EpList.append([episodes['firstAired'], episodes['airedSeason'], episodes['airedEpisodeNumber']]) - EpList.sort() - log(EpList) - + if episodes['firstAired'] and [episodes['firstAired'], episodes['airedSeason'], episodes['airedEpisodeNumber']] not in EpList: + EpList.append([episodes['firstAired'], episodes['airedSeason'], episodes['airedEpisodeNumber']]) + else: + if page not in checkpages: + checkpages.append(Page -1) + exist = False + + EpList.sort() + + dict_series[TITLE][TAG_CHECK] = checkpages + EpList = base64.b64encode(json.dumps(EpList)) + dict_series[TITLE][TAG_EPLIST] = EpList + jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] + # Crea Dizionari per la numerazione if EpList: + EpList = json.loads(base64.b64decode(dict_series[TITLE][TAG_EPLIST])) specials = [] regular = {} complete = {} @@ -308,7 +453,7 @@ def make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE regular[ep] = [str(episode[1]) + 'x' + str(episode[2]), str(episode[0]), allep - 1] ep = ep + 1 allep = allep + 1 - + # seleziona l'Episodio di partenza if int(SEASON) > 1: for numbers, data in regular.items(): @@ -316,45 +461,47 @@ def make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE FirstOfSeason = numbers - 1 if MODE == True: SPECIAL = specials - log(SPECIAL) - log(complete) - log(regular) - + addiction = 0 for item in itemlist: # Otiene Numerazione Episodi - episode = int(scrapertoolsV2.find_single_match(item.title, r'\d+')) - number = episode + FirstOfSeason - addiction - count = number + addiction - # find = episode + FirstOfSeason - # log('FIND= ',find, ' ',str(episode) + ' ' + str(FirstOfSeason)) - # Crea Dizionario Episodi - - # log(episode, ' ', number, ' ', count) - if episode == 0: - EpisodeDict[str(episode)] = str(complete[regular[FirstOfSeason+1][2]][0]) - elif addiction < len(SPECIAL): - if episode in SPECIAL: - season = complete[regular[count][2]][0] - EpisodeDict[str(episode)] = str(complete[regular[count][2]][0]) if season.startswith( '0' ) else '0x' + platformtools.dialog_numeric(0, item.title + '?', '') - addiction = addiction + 1 - else: - EpisodeDict[str(episode)] = str(regular[number][0]) - elif number <= len(regular): - EpisodeDict[str(episode)] = str(regular[number][0]) - else: - try: EpisodeDict[str(episode)] = str(complete[regular[number+2][2]][0]) - except: EpisodeDict[str(episode)] = '0x0' + if config.get_localized_string(30992) not in item.title: + episode = int(scrapertoolsV2.find_single_match(item.title, r'\d+')) + number = episode + FirstOfSeason - addiction + count = number + addiction + # Crea Dizionario Episodi - # Aggiunge numerazione agli Episodi - - item.title = typo(EpisodeDict[str(episode)] + ' - ', typography) + item.title + if episode == 0: + EpisodeDict[str(episode)] = str(complete[regular[FirstOfSeason+1][2]][0]) + elif addiction < len(SPECIAL): + if episode in SPECIAL: + try: + season = complete[regular[count][2]][0] + EpisodeDict[str(episode)] = str(complete[regular[count][2]][0]) if season.startswith( '0' ) else '0x' + platformtools.dialog_numeric(0, item.title + '?', '') + + except: + EpisodeDict[str(episode)] = '0x' + platformtools.dialog_numeric(0, item.title + '?', '') + addiction = addiction + 1 + elif number <= len(regular): + EpisodeDict[str(episode)] = str(regular[number][0]) + else: + try: EpisodeDict[str(episode)] = str(complete[regular[number+2][2]][0]) + except: EpisodeDict[str(episode)] = '0x0' + elif number <= len(regular) and regular.has_key(number): + EpisodeDict[str(episode)] = str(regular[number][0]) + else: + try: EpisodeDict[str(episode)] = str(complete[regular[number+2][2]][0]) + except: EpisodeDict[str(episode)] = '0x0' + + # Aggiunge numerazione agli Episodi + + item.title = typo(EpisodeDict[str(episode)] + ' - ', typography) + item.title # Scrive Dizionario Episodi sul json EpisodeDict = base64.b64encode(json.dumps(EpisodeDict)) dict_series[TITLE][TAG_EPISODE] = EpisodeDict jsontools.update_node(dict_series, item.channel, TAG_TVSHOW_RENUMERATE)[0] - + else: heading = config.get_localized_string(70704) ID = platformtools.dialog_numeric(0, heading) @@ -366,13 +513,13 @@ def make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE return make_list(itemlist, item, typography, dict_series, ID, SEASON, EPISODE, MODE, TITLE) # return itemlist - - + + def RepresentsInt(s): # Controllo Numro Stagione log() - try: + try: int(s) return True except ValueError: @@ -383,3 +530,20 @@ def error(itemlist): heading = itemlist[0].fulltitle.strip() platformtools.dialog_notification(heading, message) return itemlist + +def check(item): + try: + dict_series = jsontools.get_node_from_file(item.channel, TAG_TVSHOW_RENUMERATE) + TITLE = item.fulltitle.rstrip() + dict_series[TITLE][TAG_ID] + dict_series[TITLE][TAG_EPISODE] + exist = True + except: + exist = False + return exist + +def find_episodes(item): + log() + ch = __import__('channels.' + item.channel, fromlist=["channels.%s" % item.channel]) + itemlist = ch.episodios(item) + return itemlist \ No newline at end of file diff --git a/specials/checkhost.py b/specials/checkhost.py index 45671409..8291e0b5 100644 --- a/specials/checkhost.py +++ b/specials/checkhost.py @@ -13,10 +13,11 @@ addonname = addon.getAddonInfo('name') addonid = addon.getAddonInfo('id') LIST_SITE = ['https://www.google.com', 'https://www.google.it', - 'http://www.ansa.it/', 'https://www.debian.org/'] + 'http://www.ansa.it/']#, 'https://www.debian.org/'] # lista di siti che non verranno raggiunti con i DNS del gestore -LST_SITE_CHCK_DNS = ['https://www.italia-film.pw', 'https://casacinema.space'] +LST_SITE_CHCK_DNS = ['https://www.italia-film.pw', 'https://casacinema.space', + 'https://documentari-streaming-da.com'] class Kdicc(): @@ -67,7 +68,9 @@ class Kdicc(): http_errr = 0 for rslt in r: xbmc.log("check_Adsl rslt: %s" % rslt['code'], level=xbmc.LOGNOTICE) - if rslt['code'] == '111' or '[Errno -3]' in str(rslt['code']): + # Errno -2 potrebbe essere mancanza di connessione adsl o sito non raggiungibile.... + # anche nei casi in cui ci sia il cambio gestore. + if rslt['code'] == '111' or '[Errno -3]' in str(rslt['code']) or 'Errno -2' in str(rslt['code']): http_errr +=1 if len(LIST_SITE) == http_errr: @@ -133,11 +136,12 @@ class Kdicc(): # gli errori vengono inglobati in code = '111' in quanto in quel momento # non vengono raggiunti per una qualsiasi causa if '[Errno 111]' in str(conn_errr) or 'Errno 10060' in str(conn_errr) \ - or 'Errno 10061' in str(conn_errr) \ - or '[Errno 110]' in str(conn_errr) \ + or 'Errno 10061' in str(conn_errr) \ + or '[Errno 110]' in str(conn_errr) \ or 'ConnectTimeoutError' in str(conn_errr) \ or 'Errno 11002' in str(conn_errr) or 'ReadTimeout' in str(conn_errr) \ - or 'Errno 11001' in str(conn_errr): # questo errore è anche nel code: -2 + or 'Errno 11001' in str(conn_errr) \ + or 'Errno -2' in str(conn_errr): # questo errore è anche nel code: -2 rslt['code'] = '111' rslt['url'] = str(sito) rslt['http_err'] = 'Connection error' @@ -172,6 +176,8 @@ class Kdicc(): # per siti irraggiungibili senza DNS corretti #[Errno 111] Connection refused rslt['code'] = 111 + except: + rslt['code'] = 'Connection error' return rslt def view_Advise(self, txt = '' ): @@ -220,6 +226,10 @@ def test_conn(is_exit, check_dns, view_msg, if view_msg == True: ktest.view_Advise(config.get_localized_string(70722)) + xbmc.log("############ Inizio Check DNS ############", level=xbmc.LOGNOTICE) + xbmc.log("IP: %s" % (ktest.ip_addr), level=xbmc.LOGNOTICE) + xbmc.log("DNS: %s" % (ktest.dns), level=xbmc.LOGNOTICE) + xbmc.log("############ Fine Check DNS ############", level=xbmc.LOGNOTICE) if ktest.check_Ip() and ktest.check_Adsl() and ktest.check_Dns(): return True else: diff --git a/specials/community.json b/specials/community.json index f35640d1..ac2ad1f4 100644 --- a/specials/community.json +++ b/specials/community.json @@ -3,31 +3,28 @@ "name": "Community", "active": true, "adult": false, - "language": ["cast", "lat"], + "language": ["*"], "thumbnail": "", "banner": "", "fanart": "", - "categories": [ - "direct", - "movie", - "tvshow", - "vo" - ], + "categories": [], "settings": [ { - "id": "filterlanguages", + "id": "pagination", "type": "list", - "label": "Mostrar enlaces del canal en idioma...", - "default": 3, + "label": "Pagination", + "default": 2, "enabled": true, "visible": true, - "lvalues": [ - "No Filtrar", - "LAT", - "CAST", - "VO", - "VOSE" - ] + "lvalues": ["@70708", "20", "40", "60", "80", "100"] + }, + { + "id": "show_seasons", + "type": "bool", + "label": "Show Seasons", + "default": false, + "enabled": true, + "visible": true } ] } diff --git a/specials/community.py b/specials/community.py index fdf41330..ba6bda34 100644 --- a/specials/community.py +++ b/specials/community.py @@ -1,31 +1,32 @@ # -*- coding: utf-8 -*- # -*- Channel Community -*- -# -*- Created for Alfa-addon -*- -# -*- By the Alfa Develop Group -*- -import re -import urllib -import os +import re, os, inspect, requests, xbmc, xbmcaddon -from core import httptools -from core import scrapertools -from core import servertools -from core import jsontools -from channelselector import get_thumb -from core import tmdb +from core import httptools, scrapertoolsV2, servertools, jsontools, tmdb, support from core.item import Item -from platformcode import logger, config, platformtools +from core.support import typo +from channelselector import get_thumb +from platformcode import config, platformtools from specials import autoplay -from specials import filtertools + +addon = xbmcaddon.Addon('metadata.themoviedb.org') +lang = addon.getSetting('language') + +defpage = ["", "20", "40", "60", "80", "100"] +defp = defpage[config.get_setting('pagination','community')] +show_seasons = config.get_setting('show_seasons','community') list_data = {} -list_language = ['ITA', 'SUB-ITA'] list_servers = ['directo', 'akvideo', 'verystream', 'openload'] list_quality = ['SD', '720', '1080', '4k'] +tmdb_api = 'a1ab8b8669da03637a4b98fa39c39228' + + def mainlist(item): - logger.info() + support.log() path = os.path.join(config.get_data_path(), 'community_channels.json') if not os.path.exists(path): @@ -38,185 +39,560 @@ def mainlist(item): def show_channels(item): - logger.info() + support.log() itemlist = [] - + context = [{"title": config.get_localized_string(50005), - "action": "remove_channel", - "channel": "community"}] + "action": "remove_channel", + "channel": "community"}] path = os.path.join(config.get_data_path(), 'community_channels.json') file = open(path, "r") json = jsontools.load(file.read()) - itemlist.append(Item(channel=item.channel, title=config.get_localized_string(70676), action='add_channel', thumbnail=get_thumb('add.png'))) + itemlist.append(Item(channel=item.channel, + title=typo(config.get_localized_string(70676),'bold color kod'), + action='add_channel', + thumbnail=get_thumb('add.png'))) for key, channel in json['channels'].items(): - file_path = channel ['path'] - file_url = httptools.downloadpage(file_path, follow_redirects=True).data + # Find File Path + if 'http' in channel['path']: file_path = requests.get(channel['path']).url + else: file_path = channel['path'] + + # make relative path + path = os.path.dirname(os.path.abspath(file_path)) + if 'http' in path: path = path[path.find('http'):].replace('\\','/').replace(':/','://') + if file_path.startswith('http'): file_url = httptools.downloadpage(file_path, follow_redirects=True).data + else: file_url = open(file_path, "r").read() + + # load json json_url = jsontools.load(file_url) - thumbnail = json_url['thumbnail'] if 'thumbnail' in json_url else '' - fanart = json_url['fanart'] if 'fanart' in json_url else '' + + thumbnail = relative('thumbnail', json_url, path) + fanart = relative('fanart', json_url, path) + plot = json_url['plot'] if json_url.has_key('plot') else '' itemlist.append(Item(channel=item.channel, - title=channel['channel_name'], + title=typo(channel['channel_name'],'bold'), url=file_path, thumbnail=thumbnail, fanart=fanart, + plot=plot, action='show_menu', channel_id = key, - context=context)) + context=context, + path=path)) + + autoplay.show_option(item.channel, itemlist) + support.channel_config(item, itemlist) return itemlist -def load_json(item): - logger.info() - - if item.url.startswith('http'): - json_file = httptools.downloadpage(item.url).data - else: - json_file = open(item.url, "r").read() - - json_data = jsontools.load(json_file) - - return json_data def show_menu(item): global list_data - logger.info() itemlist = [] + support.log() - json_data = load_json(item) + # If Second Level Menu + if item.menu: + menu = item.menu + item.menu = None + itemlist.append(item) + for key in menu: + if key != 'search': + if type(menu[key]) == dict: + title = menu[key]['title'] if menu[key].has_key('title') else item.title + thumbnail = relative('thumbnail', menu[key], item.path) + plot = menu[key]['plot'] if menu[key].has_key('plot') else '' + else: + title = menu[key] + thumbnail = item.thumbnail + plot = '' - if "menu" in json_data: - for option in json_data['menu']: - if 'thumbnail' in json_data: - thumbnail = option['thumbnail'] - else: - thumbnail = '' - if 'fanart' in option and option['fanart']: - fanart = option['fanart'] - else: - fanart = item.fanart - itemlist.append(Item(channel=item.channel, title=option['title'], thumbnail=thumbnail, fanart=fanart, action='show_menu', url=option['link'])) - autoplay.show_option(item.channel, itemlist) + itemlist.append(Item(channel=item.channel, + title=typo(title,'submenu'), + url=item.url, + path=item.path, + thumbnail=thumbnail, + plot=plot, + action='submenu', + filterkey=key)) + + if menu.has_key('search'): + itemlist.append(Item(channel=item.channel, + title=typo('Cerca ' + item.fulltitle +'...','color kod bold'), + thumbnail=get_thumb('search.png'), + action='search', + url=item.url, + path=item.path)) return itemlist - if "movies_list" in json_data: - item.media_type='movies_list' + else: + json_data = load_json(item) - elif "tvshows_list" in json_data: - item.media_type = 'tvshows_list' + if "menu" in json_data: + for option in json_data['menu']: + thumbnail = relative('thumbnail', option, item.path) + fanart = relative('fanart', option, item.path) + plot = option['plot'] if option.has_key('plot') else item.plot + url = relative('link', option, item.path) + submenu = option['submenu'] if option.has_key('submenu') else [] + level2 = option['level2'] if option.has_key('level2') else [] + itemlist.append(Item(channel=item.channel, + title=format_title(option['title']), + fulltitle=option['title'], + thumbnail=thumbnail, + fanart=fanart, + plot=plot, + action='show_menu', + url=url, + path=item.path, + menu=level2)) - elif "episodes_list" in json_data: - item.media_type = 'episodes_list' + if submenu: + for key in submenu: + if key != 'search': + if type(submenu[key]) == dict: + title = submenu[key]['title'] if submenu[key].has_key('title') else item.title + thumbnail = relative('thumbnail', submenu[key], item.path) + plot = submenu[key]['plot'] if submenu[key].has_key('plot') else '' + else: + title = submenu[key] + thumbnail = item.thumbnail + plot = '' + + itemlist.append(Item(channel=item.channel, + title=typo(title,'submenu'), + url=url, + path=item.path, + thumbnail=thumbnail, + plot=plot, + action='submenu', + filterkey=key)) + if submenu.has_key('search'): + itemlist.append(Item(channel=item.channel, + title=typo('Cerca ' + option['title'] +'...','color kod bold'), + thumbnail=get_thumb('search.png'), + action='search', + url=url, + path=item.path)) + # add Search + itemlist.append(Item(channel=item.channel, + title=typo('Cerca nel Canale...','color kod bold'), + thumbnail=get_thumb('search.png'), + action='search', + url=item.url, + path=item.path)) + + return itemlist + + # select type of list + if json_data.has_key("movies_list"): + item.media_type = 'movies_list' + item.contentType = 'movie' + elif json_data.has_key("tvshows_list"): + item.media_type = 'tvshows_list' + item.contentType = 'tvshow' + elif json_data.has_key("episodes_list"): + item.media_type = 'episodes_list' + item.contentType = 'episode' + elif json_data.has_key("generic_list"): + item.media_type= 'generic_list' return list_all(item) + +def submenu(item): + support.log() + + itemlist = [] + filter_list = [] + plot = item.plot + + json_data = load_json(item) + if json_data.has_key("movies_list"): item.media_type= 'movies_list' + elif json_data.has_key("tvshows_list"): item.media_type = 'tvshows_list' + elif json_data.has_key("episodes_list"): item.media_type = 'episodes_list' + elif json_data.has_key("generic_list"): item.media_type= 'generic_list' + media_type = item.media_type + + for media in json_data[media_type]: + if media.has_key(item.filterkey): + if type(media[item.filterkey]) == str and media[item.filterkey] not in filter_list: + filter_list.append(media[item.filterkey]) + elif type(media[item.filterkey]) == list: + for f in media[item.filterkey]: + if f not in filter_list: + filter_list.append(f) + filter_list.sort() + + for filter in filter_list: + if item.filterkey in ['director','actors']: + load_info = load_json('http://api.themoviedb.org/3/search/person/?api_key=' + tmdb_api + '&language=' + lang + '&query=' + filter) + if load_info: + id = str(load_info['results'][0]['id']) + if id: + info = load_json('http://api.themoviedb.org/3/person/'+ id + '?api_key=' + tmdb_api + '&language=' + lang) + if not info['biography']: + bio = load_json('http://api.themoviedb.org/3/person/'+ id + '?api_key=' + tmdb_api + '&language=en')['biography'] + thumbnail = 'https://image.tmdb.org/t/p/w600_and_h900_bestv2' + info['profile_path'] if info['profile_path'] else item.thumbnail + plot += info['biography'] if info['biography'] else bio if bio else '' + + itemlist.append(Item(channel=item.channel, + title=typo(filter, 'bold'), + url=item.url, + media_type=item.media_type, + action='list_filtered', + thumbnail=thumbnail, + plot=plot, + filterkey=item.filterkey, + filter=filter)) + return itemlist + + def list_all(item): - logger.info() + support.log('CONTENT TYPE ', item.contentType) + + if inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: + pagination = int(defp) if defp.isdigit() else '' + else: pagination = '' + pag = item.page if item.page else 1 itemlist = [] media_type = item.media_type json_data = load_json(item) - for media in json_data[media_type]: + contentTitle = contentSerieName = '' + infoLabels = item.infoLabels if item.infoLabels else {} - quality, language, plot, poster = set_extra_values(media) + if json_data: + for i, media in enumerate(json_data[media_type]): + if pagination and (pag - 1) * pagination > i: continue # pagination + if pagination and i >= pag * pagination: break # pagination - title = media['title'] - title = set_title(title, language, quality) + quality, language, plot, poster = set_extra_values(media, item.path) - new_item = Item(channel=item.channel, title=title, quality=quality, - language=language, plot=plot, thumbnail=poster) + fulltitle = media['title'] + title = set_title(fulltitle, language, quality) - new_item.infoLabels['year'] = media['year'] if 'year' in media else '' - new_item.infoLabels['tmdb_id'] = media['tmdb_id'] if 'tmdb_id' in media else '' + infoLabels['year'] = media['year'] if media.has_key('year')else '' + infoLabels['tmdb_id'] = media['tmdb_id'] if media.has_key('tmdb_id') else '' - if 'movies_list' in json_data: - new_item.url = media - new_item.contentTitle = media['title'] - new_item.action = 'findvideos' - if 'year' in media: - new_item.infoLabels['year'] = media['year'] - if 'tmdb_id' in media: - new_item.infoLabels['tmdb_id'] = media['tmdb_id'] - else: - new_item.url = media['seasons_list'] - new_item.contentSerieName = media['title'] - new_item.action = 'seasons' - if 'year' in media: - new_item.infoLabels['year'] = media['year'] - if 'tmdb_id' in media: - new_item.infoLabels['tmdb_id'] = media['tmdb_id'] + if 'movies_list' in json_data or 'generic_list' in json_data: + url= media + contentTitle = fulltitle + contentType = 'movie' + action='findvideos' - itemlist.append(new_item) + else: + contentSerieName = fulltitle + contentType = 'tvshow' + if media.has_key('seasons_list'): + url = media['seasons_list'] + action = 'get_seasons' + else: + url = relative('link', media, item.path) + action = 'episodios' - tmdb.set_infoLabels(itemlist, seekTmdb=True) + itemlist.append(Item(channel=item.channel, + contentType=contentType, + title=format_title(title), + fulltitle=fulltitle, + show=fulltitle, + quality=quality, + language=language, + plot=plot, + personal_plot=plot, + thumbnail=poster, + path=item.path, + url=url, + contentTitle=contentTitle, + contentSerieName=contentSerieName, + infoLabels=infoLabels, + action=action)) + if pagination and len(json_data[media_type]) >= pag * pagination: + if inspect.stack()[1][3] != 'get_newest': + itemlist.append( + Item(channel=item.channel, + action = item.action, + contentType=contentType, + title=typo(config.get_localized_string(30992), 'color kod bold'), + fulltitle= item.fulltitle, + show= item.show, + url=item.url, + args=item.args, + page=pag + 1, + thumbnail=support.thumb())) + + if not 'generic_list' in json_data: + tmdb.set_infoLabels(itemlist, seekTmdb=True) + for item in itemlist: + if item.personal_plot != item.plot and item.personal_plot: + item.plot = '\n\n' + typo('','submenu') + '\n' + item.personal_plot + '\n' + typo('','submenu') + '\n\n' + item.plot + return itemlist + + +def list_filtered(item): + support.log() + + if inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: + pagination = int(defp) if defp.isdigit() else '' + else: pagination = '' + pag = item.page if item.page else 1 + + itemlist = [] + media_type = item.media_type + json_data = load_json(item) + contentTitle = contentSerieName = '' + infoLabels = item.infoLabels if item.infoLabels else {} + + if json_data: + for i, media in enumerate(json_data[media_type]): + if pagination and (pag - 1) * pagination > i: continue # pagination + if pagination and i >= pag * pagination: break # pagination + if media.has_key(item.filterkey): + filter_keys = [it.lower() for it in media[item.filterkey]] if type(media[item.filterkey]) == list else media[item.filterkey].lower() + if item.filter.lower() in filter_keys: + + quality, language, plot, poster = set_extra_values(media, item.path) + + fulltitle = media['title'] + title = set_title(fulltitle, language, quality) + + infoLabels['year'] = media['year'] if media.has_key('year')else '' + infoLabels['tmdb_id'] = media['tmdb_id'] if media.has_key('tmdb_id') else '' + + if 'movies_list' in json_data or 'generic_list' in json_data: + url= media + contentTitle = fulltitle + contentType = 'movie' + action='findvideos' + + else: + contentSerieName = fulltitle + contentType = 'tvshow' + if media.has_key('seasons_list'): + url = media['seasons_list'] + action = 'get_seasons' + else: + url = relative('link', media, item.path) + action = 'episodios' + + itemlist.append(Item(channel=item.channel, + contentType=contentType, + title=format_title(title), + fulltitle=fulltitle, + show=fulltitle, + quality=quality, + language=language, + plot=plot, + personal_plot=plot, + thumbnail=poster, + path=item.path, + url=url, + contentTitle=contentTitle, + contentSerieName=contentSerieName, + infoLabels=infoLabels, + action=action)) + + if pagination and len(json_data[media_type]) >= pag * pagination and len(itemlist) >= pag * pagination: + if inspect.stack()[1][3] != 'get_newest': + itemlist.append( + Item(channel=item.channel, + action = item.action, + contentType=contentType, + title=typo(config.get_localized_string(30992), 'color kod bold'), + fulltitle= item.fulltitle, + show= item.show, + url=item.url, + args=item.args, + page=pag + 1, + thumbnail=support.thumb())) + + if not 'generic_list' in json_data: + tmdb.set_infoLabels(itemlist, seekTmdb=True) + for item in itemlist: + if item.personal_plot != item.plot and item.personal_plot: + item.plot = '\n\n' + typo('','submenu') + '\n' + item.personal_plot + '\n' + typo('','submenu') + '\n\n' + item.plot return itemlist -def seasons(item): - logger.info() + +def get_seasons(item): + itm = item + support.log() itemlist = [] - infoLabels = item.infoLabels + infoLabels = item.infoLabels if item.infolabels else {} list_seasons = item.url + for season in list_seasons: infoLabels['season'] = season['season'] title = config.get_localized_string(60027) % season['season'] - itemlist.append(Item(channel=item.channel, title=title, url=season['link'], action='episodesxseason', - contentSeasonNumber=season['season'], infoLabels=infoLabels)) + url = relative('link', season, item.path) - tmdb.set_infoLabels(itemlist, seekTmdb=True) - itemlist = sorted(itemlist, key=lambda i: i.title) + itemlist.append(Item(channel=item.channel, + title=format_title(title), + fulltitle=item.fulltitle, + show=item.show, + thumbnails=item.thumbnails, + url=url, + action='episodios', + contentSeason=season['season'], + infoLabels=infoLabels, + contentType='tvshow')) + + + if inspect.stack()[1][3] in ['add_tvshow', "get_seasons"] or show_seasons == False: + it = [] + for item in itemlist: + if os.path.isfile(item.url): it += episodios(item) + itemlist = it + + if inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes', 'get_newest']: + pagination = int(defp) if defp.isdigit() else '' + pag = itm.page if itm.page else 1 + it = [] + for i, item in enumerate(itemlist): + if pagination and (pag - 1) * pagination > i: continue # pagination + if pagination and i >= pag * pagination: break # pagination + it.append(item) + + if pagination and len(itemlist) >= pag * pagination: + itm.page = pag + 1 + itm.title=typo(config.get_localized_string(30992), 'color kod bold') + itm.thumbnail=support.thumb() + it.append(itm) + itemlist = it + else: + tmdb.set_infoLabels(itemlist, seekTmdb=True) + itemlist = sorted(itemlist, key=lambda i: i.title) + support.videolibrary(itemlist,item) return itemlist -def episodesxseason(item): - logger.info() +def episodios(item): + # support.dbg() + support.log() + itm = item + + if inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes']: + pagination = int(defp) if defp.isdigit() else '' + else: pagination = '' + pag = item.page if item.page else 1 itemlist = [] json_data = load_json(item) infoLabels = item.infoLabels + ep = 1 + season = infoLabels['season'] if infoLabels.has_key('season') else item.contentSeason if item.contentSeason else 1 + + for i, episode in enumerate(json_data['episodes_list']): + if pagination and (pag - 1) * pagination > i: continue # pagination + if pagination and i >= pag * pagination: break # pagination + match = [] + if episode.has_key('number'): + match = support.match(episode['number'], r'(?P<season>\d+)x(?P<episode>\d+)')[0] + if match: + match = match[0] + if not match and episode.has_key('title'): + match = support.match(episode['title'], r'(?P<season>\d+)x(?P<episode>\d+)')[0] + if match: match = match[0] + if match: + episode_number = match[1] + ep = int(match[1]) + 1 + season_number = match[0] + else: + season_number = episode['season'] if episode.has_key('season') else season if season else 1 + episode_number = episode['number'] if episode.has_key('number') else '' + if not episode_number.isdigit(): + episode_number = support.match(episode['title'], r'(?P<episode>\d+)')[0][0] + ep = int(episode_number) if episode_number else ep + if not episode_number: + episode_number = str(ep).zfill(2) + ep += 1 - season_number = infoLabels['season'] - for episode in json_data['episodes_list']: - episode_number = episode['number'] infoLabels['season'] = season_number infoLabels['episode'] = episode_number - title = config.get_localized_string(70677) + ' %s' % (episode_number) + plot = episode['plot'] if episode.has_key('plot') else item.plot + thumbnail = episode['poster'] if episode.has_key('poster') else episode['thumbnail'] if episode.has_key('thumbnail') else item.thumbnail - itemlist.append(Item(channel=item.channel, title=title, url=episode, action='findvideos', - contentEpisodeNumber=episode_number, infoLabels=infoLabels)) + title = ' - ' + episode['title'] if episode.has_key('title') else '' + title = '%sx%s%s' % (season_number, episode_number, title) + if season_number == item.filter or not item.filterseason: + itemlist.append(Item(channel= item.channel, + title= format_title(title), + fulltitle = item.fulltitle, + show = item.show, + url= episode, + action= 'findvideos', + plot= plot, + thumbnail= thumbnail, + contentSeason= season_number, + contentEpisode= episode_number, + infoLabels= infoLabels, + contentType= 'episode')) + + + if show_seasons == True and inspect.stack()[1][3] not in ['add_tvshow', 'get_episodes', 'update', 'find_episodes'] and not item.filterseason: + itm.contentType='season' + season_list = [] + for item in itemlist: + if item.contentSeason not in season_list: + season_list.append(item.contentSeason) + itemlist = [] + for season in season_list: + itemlist.append(Item(channel=item.channel, + title=format_title(config.get_localized_string(60027) % season), + fulltitle=itm.fulltitle, + show=itm.show, + thumbnails=itm.thumbnails, + url=itm.url, + action='episodios', + contentSeason=season, + infoLabels=infoLabels, + filterseason=season)) + + elif pagination and len(json_data['episodes_list']) >= pag * pagination: + if inspect.stack()[1][3] != 'get_newest': + itemlist.append( + Item(channel=item.channel, + action = item.action, + contentType='episode', + title=typo(config.get_localized_string(30992), 'color kod bold'), + fulltitle= item.fulltitle, + show= item.show, + url=item.url, + args=item.args, + page=pag + 1, + thumbnail=support.thumb())) tmdb.set_infoLabels(itemlist, seekTmdb=True) return itemlist def findvideos(item): - logger.info() + support.log() itemlist = [] + if 'links' in item.url: + for url in item.url['links']: + quality, language, plot, poster = set_extra_values(url, item.path) + title = '' + title = set_title(title, language, quality) - for url in item.url['links']: - quality, language, plot, poster = set_extra_values(url) - title = '' - title = set_title(title, language, quality) + itemlist.append(Item(channel=item.channel, title=format_title('%s'+title), url=url['url'], action='play', quality=quality, + language=language, infoLabels = item.infoLabels)) - itemlist.append(Item(channel=item.channel, title='%s'+title, url=url['url'], action='play', quality=quality, - language=language, infoLabels = item.infoLabels)) + itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) - itemlist = servertools.get_servers_itemlist(itemlist, lambda i: i.title % i.server.capitalize()) + if inspect.stack()[2][3] != 'start_download': + autoplay.start(itemlist, item) - # Requerido para FilterTools - # itemlist = filtertools.get_links(itemlist, item, list_language) + return itemlist - # Requerido para AutoPlay - - autoplay.start(itemlist, item) - - return itemlist def add_channel(item): - logger.info() + support.log() import xbmc import xbmcgui channel_to_add = {} @@ -263,8 +639,9 @@ def add_channel(item): platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(70683) % json_file['channel_name']) return + def remove_channel(item): - logger.info() + support.log() import xbmc import xbmcgui path = os.path.join(config.get_data_path(), 'community_channels.json') @@ -284,8 +661,8 @@ def remove_channel(item): return -def set_extra_values(dict): - logger.info() +def set_extra_values(dict, path): + support.log() quality = '' language = '' plot = '' @@ -298,22 +675,117 @@ def set_extra_values(dict): if 'plot' in dict and dict['plot'] != '': plot = dict['plot'] if 'poster' in dict and dict['poster'] != '': - poster = dict['poster'] + poster = dict['poster']if ':/' in dict['poster'] else path + dict['poster'] if '/' in dict['poster'] else '' + elif 'thumbnail' in dict and dict['thumbnail'] != '': + poster = dict['thumbnail']if ':/' in dict['thumbnail'] else path + dict['thumbnail'] if '/' in dict['thumbnail'] else '' return quality, language, plot, poster def set_title(title, language, quality): - logger.info() + support.log() if not config.get_setting('unify'): if quality != '': - title += ' [%s]' % quality + title += typo(quality, '_ [] color kod') if language != '': if not isinstance(language, list): - title += ' [%s]' % language.upper() + title += typo(language.upper(), '_ [] color kod') else: - title += ' ' for lang in language: - title += '[%s]' % lang.upper() + title += typo(lang.upper(), '_ [] color kod') - return title.capitalize() + return title + + +def format_title(title): + t = scrapertoolsV2.find_single_match(title, r'\{([^\}]+)\}') + if 'bold' not in t: t += ' bold' + title = re.sub(r'(\{[^\}]+\})','',title) + return typo(title,t) + + +def search(item, text): + support.log('Search ', text) + itemlist = [] + json_data = load_json(item) + + return load_links(item, itemlist, json_data, text) + + +def load_links(item, itemlist, json_data, text): + support.log() + + def links(item, itemlist, json_data, text): + support.log() + if "movies_list" in json_data: media_type= 'movies_list' + elif "tvshows_list" in json_data: media_type = 'tvshows_list' + elif "episodes_list" in json_data: media_type = 'episodes_list' + if "generic_list" in json_data: media_type= 'generic_list' + + if json_data: + for media in json_data[media_type]: + if text.lower() in media['title'].lower(): + quality, language, plot, poster = set_extra_values(media, item.path) + + title = media['title'] + title = set_title(title, language, quality) + + new_item = Item(channel=item.channel, title=format_title(title), quality=quality, + language=language, plot=plot, personal_plot=plot, thumbnail=poster, path=item.path) + + new_item.infoLabels['year'] = media['year'] if 'year' in media else '' + new_item.infoLabels['tmdb_id'] = media['tmdb_id'] if 'tmdb_id' in media else '' + + if 'movies_list' in json_data or 'generic_list' in json_data: + new_item.url = media + new_item.contentTitle = media['title'] + new_item.action = 'findvideos' + else: + new_item.url = media['seasons_list'] + new_item.contentSerieName = media['title'] + new_item.action = 'seasons' + + itemlist.append(new_item) + + if not 'generic_list' in json_data: + tmdb.set_infoLabels(itemlist, seekTmdb=True) + for item in itemlist: + if item.personal_plot != item.plot and item.personal_plot: + item.plot = '\n\n' + typo('','submenu') + '\n' + item.personal_plot + '\n' + typo('','submenu') + '\n\n' + item.plot + + if json_data.has_key('menu'): + for option in json_data['menu']: + json_data = load_json(option['link'] if option['link'].startswith('http') else item.path+option['link']) + load_links(item, itemlist, json_data, text) + else: + links(item, itemlist, json_data, text) + + return itemlist + + +def relative(key, json, path): + if json.has_key(key): + if key == 'thumbnail': + ret = json[key] if ':/' in json[key] else path + json[key] if '/' in json[key] else get_thumb(json[key]) if json[key] else '' + else: + ret = json[key] if ':/' in json[key] else path + json[key] if '/' in json[key] else '' + else: + ret = '' + return ret + + +def load_json(item): + support.log() + url= item if type(item) == str else item.url + try: + if url.startswith('http'): + json_file = httptools.downloadpage(url).data + else: + json_file = open(url, "r").read() + + json_data = jsontools.load(json_file) + + except: + json_data = {} + + return json_data \ No newline at end of file diff --git a/specials/downloads.py b/specials/downloads.py index 0673d1d6..6320c6bc 100644 --- a/specials/downloads.py +++ b/specials/downloads.py @@ -8,11 +8,13 @@ import re import time import unicodedata + from core import filetools, jsontools, scraper, scrapertools, servertools, videolibrarytools, support from core.downloader import Downloader from core.item import Item from platformcode import config, logger from platformcode import platformtools +from core.support import log STATUS_COLORS = {0: "orange", 1: "orange", 2: "green", 3: "red"} STATUS_CODES = type("StatusCode", (), {"stoped": 0, "canceled": 1, "completed": 2, "error": 3}) @@ -20,6 +22,9 @@ DOWNLOAD_LIST_PATH = config.get_setting("downloadlistpath") DOWNLOAD_PATH = config.get_setting("downloadpath") STATS_FILE = os.path.join(config.get_data_path(), "servers.json") +FOLDER_MOVIES = config.get_setting("folder_movies") +FOLDER_TVSHOWS = config.get_setting("folder_tvshows") + TITLE_FILE = "[COLOR %s][%i%%][/COLOR] %s" TITLE_TVSHOW = "[COLOR %s][%i%%][/COLOR] %s [%s]" @@ -262,8 +267,18 @@ def menu(item): def move_to_libray(item): + if item.contentType == 'movie': + FOLDER = FOLDER_MOVIES + path_title = "%s [%s]" % (item.contentTitle.strip(), item.infoLabels['IMDBNumber']) + move_path = filetools.join(config.get_videolibrary_path(), FOLDER, path_title) + + else: + FOLDER = FOLDER_TVSHOWS + path_title = "%s [%s]" % (item.contentSerieName, item.infoLabels['IMDBNumber']) + move_path = filetools.join(config.get_videolibrary_path(), FOLDER) + download_path = filetools.join(config.get_setting("downloadpath"), item.downloadFilename) - library_path = filetools.join(config.get_videolibrary_path(), *filetools.split(item.downloadFilename)) + library_path = filetools.join(move_path, *filetools.split(item.downloadFilename)) final_path = download_path if config.get_setting("library_add", "downloads") == True and config.get_setting("library_move", "downloads") == True: @@ -280,7 +295,29 @@ def move_to_libray(item): if len(filetools.listdir(filetools.dirname(download_path))) == 0: filetools.rmdir(filetools.dirname(download_path)) - if config.get_setting("library_add", "downloads") == True: + + logger.info('ITEM = ' + str(item)) + name = item.contentTitle if item.contentType == 'movie' else str(item.infoLabels['season']) + 'x' + str(item.infoLabels['episode']).zfill(2) + list_item = os.listdir(filetools.join(config.get_videolibrary_path(), FOLDER, path_title)) + + clean = False + for File in list_item: + filename = File.lower() + name = name.lower() + if filename.startswith(name) and (filename.endswith('.strm') or filename.endswith('.json') or filename.endswith('.nfo')): + clean = True + logger.info('Delete File: ' + str(os.path.join(config.get_videolibrary_path(), FOLDER, path_title, File))) + os.remove(os.path.join(config.get_videolibrary_path(), FOLDER, path_title, File)) + from platformcode import xbmc_videolibrary + + xbmc_videolibrary.update(FOLDER) + if clean == True: + import xbmc + while xbmc.getCondVisibility('Library.IsScanningVideo()'): + xbmc.sleep(500) + xbmc_videolibrary.clean() + + if config.get_setting("library_add", "downloads") == True and config.get_setting("library_move", "downloads") == False: if filetools.isfile(final_path): if item.contentType == "movie" and item.infoLabels["tmdb_id"]: library_item = Item(title=config.get_localized_string(70228) % item.downloadFilename, channel="downloads", @@ -343,14 +380,14 @@ def get_match_list(data, match_list, order_list=None, only_ascii=False, ignoreca { "ID1" : ["Cadena 1", "Cadena 2", "Cadena 3"], "ID2" : ["Cadena 4", "Cadena 5", "Cadena 6"] } - + El diccionario no pude contener una misma cadena de busqueda en varías IDs. - + La busqueda se realiza por orden de tamaño de cadena de busqueda (de mas larga a mas corta) si una cadena coincide, se elimina de la cadena a buscar para las siguientes, para que no se detecten dos categorias si una cadena es parte de otra: - por ejemplo: "Idioma Español" y "Español" si la primera aparece en la cadena "Pablo sabe hablar el Idioma Español" + por ejemplo: "Idioma Español" y "Español" si la primera aparece en la cadena "Pablo sabe hablar el Idioma Español" coincidira con "Idioma Español" pero no con "Español" ya que la coincidencia mas larga tiene prioridad. - + """ match_dict = dict() matches = [] @@ -400,7 +437,7 @@ def get_match_list(data, match_list, order_list=None, only_ascii=False, ignoreca def sort_method(item): """ - Puntua cada item en funcion de varios parametros: + Puntua cada item en funcion de varios parametros: @type item: item @param item: elemento que se va a valorar. @return: puntuacion otenida @@ -467,7 +504,7 @@ def download_from_url(url, item): d.start_dialog(config.get_localized_string(60332)) # Descarga detenida. Obtenemos el estado: - # Se ha producido un error en la descarga + # Se ha producido un error en la descarga if d.state == d.states.error: logger.info("Error trying to download %s" % (url)) status = STATUS_CODES.error @@ -502,7 +539,10 @@ def download_from_server(item): unsupported_servers = ["torrent"] progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70178) % item.server) - channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) + if item.contentChannel == 'community': + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) if hasattr(channel, "play") and not item.play_menu: progreso.update(50, config.get_localized_string(70178) % item.server, config.get_localized_string(60003) % item.contentChannel) @@ -569,7 +609,10 @@ def download_from_best_server(item): result = {"downloadStatus": STATUS_CODES.error} progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179)) - channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) + if item.contentChannel == 'community': + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) @@ -615,7 +658,10 @@ def select_server(item): "contentAction: %s | contentChannel: %s | url: %s" % (item.contentAction, item.contentChannel, item.url)) progreso = platformtools.dialog_progress(config.get_localized_string(30101), config.get_localized_string(70179)) - channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel]) + if item.contentChannel == 'community': + channel = __import__('specials.%s' % item.contentChannel, None, None, ['specials.%s' % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ['channels.%s' % item.contentChannel]) progreso.update(50, config.get_localized_string(70184), config.get_localized_string(70180) % item.contentChannel) if hasattr(channel, item.contentAction): @@ -639,6 +685,8 @@ def select_server(item): "downloadServer": {"url": play_items[seleccion - 1].url, "server": play_items[seleccion - 1].server}}) elif seleccion == 0: update_json(item.path, {"downloadServer": {}}) + if seleccion == 0: + update_json(item.path, {"downloadServer": {}}) platformtools.itemlist_refresh() @@ -668,7 +716,12 @@ def start_download(item): def get_episodes(item): logger.info("contentAction: %s | contentChannel: %s | contentType: %s" % ( item.contentAction, item.contentChannel, item.contentType)) - + if 'dlseason' in item: + season = True + season_number = item.dlseason + else: + season = False + # El item que pretendemos descargar YA es un episodio if item.contentType == "episode": episodes = [item.clone()] @@ -676,8 +729,10 @@ def get_episodes(item): # El item es uma serie o temporada if item.contentType in ["tvshow", "season"]: # importamos el canal - channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel]) - # Obtenemos el listado de episodios + if item.contentChannel == 'community': + channel = __import__('specials.%s' % item.contentChannel, None, None, ["specials.%s" % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, None, None, ["channels.%s" % item.contentChannel]) episodes = getattr(channel, item.contentAction)(item) itemlist = [] @@ -714,15 +769,26 @@ def get_episodes(item): # Episodio, Temporada y Titulo if not episode.contentTitle: - episode.contentTitle = re.sub("\[[^\]]+\]|\([^\)]+\)|\d*x\d*\s*-", "", episode.title).strip() + episode.contentTitle = re.sub(r"\[[^\]]+\]|\([^\)]+\)|\d*x\d*\s*-", "", episode.title).strip() episode.downloadFilename = filetools.validate_path(os.path.join(item.downloadFilename, "%dx%0.2d - %s" % ( episode.contentSeason, episode.contentEpisodeNumber, episode.contentTitle.strip()))) - itemlist.append(episode) + if season: + log('SEASON= ',season) + log(int(scrapertools.find_single_match(episode.title, r'(\d+)x'))) + log(season_number,' ',type(season_number)) + if scrapertools.find_single_match(episode.title, r'(\d+)x') == season_number: + itemlist.append(episode) + else: + itemlist.append(episode) # Cualquier otro resultado no nos vale, lo ignoramos else: logger.info("Omitting invalid item: %s" % episode.tostring()) + # if Multiple Languages or Qualities + itemlist = videolibrarytools.filter_list(itemlist) + + return itemlist @@ -756,14 +822,20 @@ def save_download(item): if item.from_action and item.from_channel: item.channel = item.from_channel item.action = item.from_action - del item.from_action - del item.from_channel + item.from_action + item.from_channel - item.contentChannel = item.channel - item.contentAction = item.action + item.contentChannel = item.from_channel if item.from_channel else item.channel + item.contentAction = item.from_action if item.from_action else item.action if item.contentType in ["tvshow", "episode", "season"]: - save_download_tvshow(item) + if 'download' in item and config.get_setting('show_seasons',item.channel) == False: + heading = config.get_localized_string(70594) # <- Enter the season number + item.dlseason = platformtools.dialog_numeric(0, heading, '') + if item.dlseason: + save_download_tvshow(item) + else: + save_download_tvshow(item) elif item.contentType == "movie": save_download_movie(item) @@ -804,7 +876,7 @@ def save_download_movie(item): progreso.update(0, config.get_localized_string(60062)) - item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentTitle.strip(), item.contentChannel)) + item.downloadFilename = filetools.validate_path("%s [%s] [%s]" % (item.contentTitle.strip(), item.contentChannel, item.infoLabels['IMDBNumber'])) write_json(item) @@ -825,9 +897,11 @@ def save_download_tvshow(item): item.show = item.fulltitle scraper.find_and_set_infoLabels(item) + item.contentSerieName = item.fulltitle - item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.contentChannel)) - + item.downloadFilename = filetools.validate_path("%s [%s]" % (item.contentSerieName, item.infoLabels['IMDBNumber'])) + if config.get_setting("lowerize_title", "videolibrary") == 0: + item.downloadFilename = item.downloadFilename.lower() progreso.update(0, config.get_localized_string(70186), config.get_localized_string(70187) % item.contentChannel) episodes = get_episodes(item) @@ -842,7 +916,7 @@ def save_download_tvshow(item): if not platformtools.dialog_yesno(config.get_localized_string(30101), config.get_localized_string(70189)): platformtools.dialog_ok(config.get_localized_string(30101), - str(len(episodes)) + " capitulos de: " + item.contentSerieName, + str(len(episodes)) + config.get_localized_string(30110) + item.contentSerieName, config.get_localized_string(30109)) else: for i in episodes: diff --git a/specials/favorites.py b/specials/favorites.py index 38a997bd..f12e7944 100644 --- a/specials/favorites.py +++ b/specials/favorites.py @@ -49,7 +49,7 @@ def mainlist(item): "action": "delFavourite", "channel": "favorites", "from_title": item.title}, - {"title": "Renombrar", + {"title": config.get_localized_string(70278), # Rename "action": "renameFavourite", "channel": "favorites", "from_title": item.title} diff --git a/specials/filtertools.py b/specials/filtertools.py index df4f4c8d..0acdeacd 100644 --- a/specials/filtertools.py +++ b/specials/filtertools.py @@ -163,6 +163,8 @@ def load(item): def check_conditions(_filter, list_item, item, list_language, list_quality, quality_count=0, language_count=0): + if item.contentLanguage: item.language = item.contentLanguage + is_language_valid = True if _filter.language: # logger.debug("title es %s" % item.title) @@ -199,7 +201,8 @@ def check_conditions(_filter, list_item, item, list_language, list_quality, qual list_item.append(item) # logger.debug("{0} | context: {1}".format(item.title, item.context)) # logger.debug(" -Enlace añadido") - + elif not item.language: + list_item.append(item) logger.debug(" idioma valido?: %s, item.language: %s, filter.language: %s" % (is_language_valid, item.language, _filter.language)) logger.debug(" calidad valida?: %s, item.quality: %s, filter.quality_allowed: %s" @@ -300,7 +303,7 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l for i in list_item: list_item_all.append(i.tourl()) - _context = [{"title": "FILTRO: Borrar '%s'" % _filter.language, "action": "delete_from_context", + _context = [{"title": config.get_localized_string(60430) % _filter.language, "action": "delete_from_context", "channel": "filtertools", "to_channel": "seriesdanko"}] if _filter.quality_allowed: @@ -310,9 +313,7 @@ def get_links(list_item, item, list_language, list_quality=None, global_filter_l new_itemlist.append(Item(channel=__channel__, action="no_filter", list_item_all=list_item_all, show=item.show, - title="[COLOR %s]No hay elementos con idioma '%s'%s, pulsa para mostrar " - "sin filtro[/COLOR]" - % (COLOR.get("error", "auto"), _filter.language, msg_quality_allowed), + title=config.get_localized_string(60432) % (_filter.language, msg_quality_allowed), context=_context)) else: @@ -430,7 +431,7 @@ def config_item(item): if item.show.lower().strip() in dict_series: allow_option = True active = dict_series.get(item.show.lower().strip(), {}).get(TAG_ACTIVE, False) - custom_button = {'label': 'Borrar', 'function': 'delete', 'visible': True, 'close': True} + custom_button = {'label': config.get_localized_string(60437), 'function': 'delete', 'visible': True, 'close': True} list_controls = [] @@ -438,7 +439,7 @@ def config_item(item): active_control = { "id": "active", "type": "bool", - "label": "¿Activar/Desactivar filtro?", + "label": config.get_localized_string(60438), "color": "", "default": active, "enabled": allow_option, @@ -449,8 +450,8 @@ def config_item(item): language_option = { "id": "language", "type": "list", - "label": "Idioma", - "color": "0xFFee66CC", + "label": config.get_localized_string(60439), + # "color": "0xFFee66CC", "default": item.list_language.index(lang_selected), "enabled": True, "visible": True, @@ -482,7 +483,7 @@ def config_item(item): # concatenamos list_controls con list_controls_calidad list_controls.extend(list_controls_calidad) - title = "Filtrado de enlaces para: [COLOR %s]%s[/COLOR]" % (COLOR.get("selected", "auto"), item.show) + title = config.get_localized_string(60441) % (COLOR.get("selected", "auto"), item.show) platformtools.show_channel_settings(list_controls=list_controls, callback='save', item=item, caption=title, custom_button=custom_button) @@ -495,9 +496,8 @@ def delete(item, dict_values): dict_series = jsontools.get_node_from_file(item.from_channel, TAG_TVSHOW_FILTER) tvshow = item.show.strip().lower() - heading = "¿Está seguro que desea eliminar el filtro?" - line1 = "Pulse 'Si' para eliminar el filtro de [COLOR %s]%s[/COLOR], pulse 'No' o cierre la ventana para " \ - "no hacer nada." % (COLOR.get("selected", "auto"), item.show.strip()) + heading = config.get_localized_string(60442) + line1 = config.get_localized_string(60443) % (COLOR.get("selected", "auto"), item.show.strip()) if platformtools.dialog_yesno(heading, line1) == 1: lang_selected = dict_series.get(tvshow, {}).get(TAG_LANGUAGE, "") @@ -507,9 +507,9 @@ def delete(item, dict_values): sound = False if result: - message = "FILTRO ELIMINADO" + message = config.get_localized_string(60444) else: - message = "Error al guardar en disco" + message = config.get_localized_string(60445) sound = True heading = "%s [%s]" % (item.show.strip(), lang_selected) @@ -554,9 +554,9 @@ def save(item, dict_data_saved): sound = False if result: - message = "FILTRO GUARDADO" + message = config.get_localized_string(60446) else: - message = "Error al guardar en disco" + message = config.get_localized_string(70593) sound = True heading = "%s [%s]" % (item.show.strip(), lang_selected) diff --git a/specials/news.py b/specials/news.py index 734ddef1..f1274853 100644 --- a/specials/news.py +++ b/specials/news.py @@ -12,7 +12,7 @@ from threading import Thread from channelselector import get_thumb, auto_filter from core import channeltools from core import jsontools -from core import scrapertools +from core import scrapertools, support from core.item import Item from platformcode import config, logger from platformcode import platformtools @@ -28,8 +28,8 @@ perfil = [['0xFF0B7B92', '0xFF89FDFB', '0xFFACD5D4'], ['0xFFA5DEE5', '0xFFE0F9B5', '0xFFFEFDCA'], ['0xFFF23557', '0xFF22B2DA', '0xFFF0D43A']] -#color1, color2, color3 = ["white", "white", "white"] -color1, color2, color3 = perfil[__perfil__] +color1, color2, color3 = ["red", "0xFF65B3DA", "yellow"] +# color1, color2, color3 = perfil[__perfil__] list_newest = [] list_newest_tourl = [] @@ -124,9 +124,11 @@ def set_category_context(item): def get_channels_list(): logger.info() +## import web_pdb; web_pdb.set_trace() +## list_canales = {'peliculas': [], '4k': [], 'terror': [], 'infantiles': [], 'series': [], 'anime': [], +## 'castellano': [], 'latino':[], 'italiano':[], 'torrent':[], 'documentales': []} + list_canales = {'peliculas': [], 'series': [],'anime': [], 'italiano':[], 'documentales': []} - list_canales = {'peliculas': [], '4k': [], 'terror': [], 'infantiles': [], 'series': [], 'anime': [], - 'castellano': [], 'latino':[], 'italiano':[], 'torrent':[], 'documentales': []} any_active = False # Rellenar listas de canales disponibles channels_path = os.path.join(config.get_runtime_path(), "channels", '*.json') @@ -147,7 +149,7 @@ def get_channels_list(): continue # No incluir si el canal es en un idioma filtrado - if channel_language != "all" and channel_language not in channel_parameters["language"] \ + if channel_language != "all" and channel_language not in str(channel_parameters["language"]) \ and "*" not in channel_parameters["language"]: continue @@ -390,16 +392,20 @@ def get_newest(channel_id, categoria): def get_title(item): - if item.contentSerieName: # Si es una serie + #support.log("ITEM NEWEST ->", item) + # item.contentSerieName c'è anche se è un film + if item.contentSerieName and item.contentType != 'movie': # Si es una serie title = item.contentSerieName + #title = re.compile("\[.*?\]", re.DOTALL).sub("", item.contentSerieName) if not scrapertools.get_season_and_episode(title) and item.contentEpisodeNumber: + # contentSeason non c'è in support if not item.contentSeason: item.contentSeason = '1' - title = "%s - %sx%s" % (title, item.contentSeason, str(item.contentEpisodeNumber).zfill(2)) - #4l3x87 - fix to add Sub-ITA in newest - if item.contentLanguage: - title+=" "+item.contentLanguage - + title = "%sx%s - %s" % (item.contentSeason, str(item.contentEpisodeNumber).zfill(2), title) + else: + seas = scrapertools.get_season_and_episode(item.title) + if seas: + title = "%s - %s" % (seas, title) elif item.contentTitle: # Si es una pelicula con el canal adaptado title = item.contentTitle @@ -413,6 +419,24 @@ def get_title(item): title = re.compile("\[/*B\]", re.DOTALL).sub("", title) title = re.compile("\[/*I\]", re.DOTALL).sub("", title) + + title = '[B]'+title+'[/B]' + + if item.contentLanguage == '': + pass + elif type(item.contentLanguage) == list and len(item.contentLanguage) ==1: + title += support.typo(item.contentLanguage[0], '_ [] color kod') + elif type(item.contentLanguage) != '': + title += support.typo(item.contentLanguage, '_ [] color kod') + elif type(item.contentLanguage) == list: + title += item.contentLanguage + + if item.quality: + title += support.typo(item.quality, '_ [] color kod') + + season_ = support.typo(config.get_localized_string(70736), '_ [] color white bold') if (type(item.args) != bool and 'season_completed' in item.news and not item.episode) else '' + if season_: + title += season_ return title @@ -421,8 +445,11 @@ def no_group(list_result_canal): global channels_id_name for i in list_result_canal: - i.title = get_title(i) + " [" + channels_id_name[i.channel] + "]" - i.text_color = color3 + #support.log("NO GROUP i -> ", i) + canale = channels_id_name[i.channel] + canale = canale # per differenziarlo dal colore delle altre voci + i.title = get_title(i) + " [" + canale + "]" +# i.text_color = color3 itemlist.append(i.clone()) @@ -447,12 +474,12 @@ def group_by_channel(list_result_canal): itemlist.append(Item(channel="news", title=channels_id_name[c] + ':', text_color=color1, text_bold=True)) for i in dict_canales[c]: - if i.contentQuality: - i.title += ' (%s)' % i.contentQuality - if i.language: - i.title += ' [%s]' % i.language - i.title = ' %s' % i.title - i.text_color = color3 +## if i.contentQuality: +## i.title += ' (%s)' % i.contentQuality +## if i.contentLanguage: +## i.title += ' [%s]' % i.contentLanguage +## i.title = ' %s' % i.title +#### i.text_color = color3 itemlist.append(i.clone()) return itemlist @@ -503,7 +530,7 @@ def group_by_content(list_result_canal): else: new_item = v[0].clone(title=title) - new_item.text_color = color3 +## new_item.text_color = color3 list_result.append(new_item) return sorted(list_result, key=lambda it: it.title.lower()) @@ -519,11 +546,11 @@ def show_channels(item): new_item = Item() new_item = new_item.fromurl(i) # logger.debug(new_item.tostring()) - if new_item.contentQuality: - new_item.title += ' (%s)' % new_item.contentQuality - if new_item.language: - new_item.title += ' [%s]' % new_item.language - new_item.title += ' (%s)' % channels_id_name[new_item.channel] +## if new_item.contentQuality: +## new_item.title += ' (%s)' % new_item.contentQuality +## if new_item.language: +## new_item.title += ' [%s]' % new_item.language +## new_item.title += ' (%s)' % channels_id_name[new_item.channel] new_item.text_color = color1 itemlist.append(new_item.clone()) @@ -581,7 +608,7 @@ def setting_channel(item): channel_language = config.get_setting("channel_language", default="auto") if channel_language == 'auto': channel_language = auto_filter() - + list_controls = [] for infile in sorted(glob.glob(channels_path)): @@ -597,7 +624,7 @@ def setting_channel(item): continue # No incluir si el canal es en un idioma filtrado - if channel_language != "all" and channel_language not in channel_parameters["language"] \ + if channel_language != "all" and channel_language not in str(channel_parameters["language"]) \ and "*" not in channel_parameters["language"]: continue @@ -644,7 +671,7 @@ def cb_custom_button(item, dict_values): dict_values[v] = not value if config.set_setting("custom_button_value_news", not value, item.channel) == True: - return {"label": "Ninguno"} + return {"label": config.get_localized_string(59992)} else: - return {"label": "Todos"} + return {"label": config.get_localized_string(59991)} diff --git a/specials/search.py b/specials/search.py index 6369f390..196614f4 100644 --- a/specials/search.py +++ b/specials/search.py @@ -15,6 +15,7 @@ from core import tmdb from core.item import Item from platformcode import config, logger from platformcode import platformtools +from core.support import typo addon = xbmcaddon.Addon('metadata.themoviedb.org') def_lang = addon.getSetting('language') @@ -255,7 +256,7 @@ def setting_channel_old(item): continue # No incluir si el canal es en un idioma filtrado - if channel_language != "all" and channel_language not in channel_parameters["language"] \ + if channel_language != "all" and channel_language not in str(channel_parameters["language"]) \ and "*" not in channel_parameters["language"]: continue @@ -523,7 +524,7 @@ def do_search(item, categories=None): continue # No busca si el canal es en un idioma filtrado - if channel_language != "all" and channel_language not in channel_parameters["language"] \ + if channel_language != "all" and channel_language not in str(channel_parameters["language"]) \ and "*" not in channel_parameters["language"]: logger.info("%s -idioma no válido-" % basename_without_extension) continue @@ -628,7 +629,7 @@ def do_search(item, categories=None): channel="search", action="show_result", adult=element["adult"])) title = config.get_localized_string(59972) % ( tecleado, total, time.time() - start_time) - itemlist.insert(0, Item(title=title, text_color='yellow')) + itemlist.insert(0, Item(title=typo(title, 'bold color kod'))) progreso.close() #Para opcion Buscar en otros canales if item.contextual == True: @@ -645,7 +646,7 @@ def exact_results(results, wanted): if item.action=='': channel=item.from_channel if item.action != '' and item.contentTitle==wanted: - item.title = '%s [%s]' % (item.title, channel) + item.title = typo(item.title,'bold') + typo(channel,'_ [] color kod bold') #'%s [%s]' % (item.title, channel) itemlist.append(item) return itemlist @@ -702,7 +703,7 @@ def discover_list(item): title = unify.normalize(elem['name']).capitalize() tvshow = True - new_item = Item(channel='search', title=title, infoLabels=elem, action='do_search', extra=title, + new_item = Item(channel='search', title=typo(title, 'bold'), infoLabels=elem, action='do_search', extra=title, category=config.get_localized_string(70695), context ='') if tvshow: @@ -719,7 +720,7 @@ def discover_list(item): #if not 'similar' in item.list_type: # itemlist.append(item.clone(title='Pagina Siguente', page=next_page)) #else: - itemlist.append(Item(channel=item.channel, action='discover_list', title=config.get_localized_string(70065), + itemlist.append(Item(channel=item.channel, action='discover_list', title=typo(config.get_localized_string(30992), 'color kod bold'), search_type=item.search_type, list_type=item.list_type, type=item.type, page=next_page)) return itemlist diff --git a/specials/searchall.py b/specials/searchall.py index de795570..fa3db25f 100644 --- a/specials/searchall.py +++ b/specials/searchall.py @@ -705,7 +705,7 @@ def do_channels_search(item): continue # No busca si el canal es en un idioma filtrado - if channel_language != "all" and channel_parameters["language"] != channel_language: + if channel_language != "all" and channel_language not in str(channel_parameters["language"]): continue # No busca si es un canal excluido de la busqueda global diff --git a/specials/setting.py b/specials/setting.py index eca3acd3..40ae0042 100644 --- a/specials/setting.py +++ b/specials/setting.py @@ -25,7 +25,7 @@ def mainlist(item): else: autostart_mode = config.get_localized_string(70708) itemlist.append(Item(channel=CHANNELNAME, title=autostart_mode + " " + config.get_localized_string(70706), action="autostart", folder=False, thumbnail=get_thumb("setting_0.png"))) - + #itemlist.append(Item(channel=CHANNELNAME, title="", action="", folder=False, thumbnail=get_thumb("setting_0.png"))) itemlist.append(Item(channel=CHANNELNAME, title=config.get_localized_string(60536) + ":", text_bold=True, action="", folder=False, @@ -340,8 +340,8 @@ def submenu_tools(item): def check_quickfixes(item): - logger.info() - + logger.info() + if not config.dev_mode(): from platformcode import updater return updater.check_addon_init() @@ -351,7 +351,7 @@ def check_quickfixes(item): def update_quasar(item): logger.info() - + from platformcode import custom_code, platformtools stat = False stat = custom_code.update_external_addon("quasar") @@ -359,8 +359,8 @@ def update_quasar(item): platformtools.dialog_notification("Actualización Quasar", "Realizada con éxito") else: platformtools.dialog_notification("Actualización Quasar", "Ha fallado. Consulte el log") - - + + def conf_tools(item): logger.info() @@ -368,7 +368,7 @@ def conf_tools(item): if item.extra == "channels_onoff": if config.get_platform(True)['num_version'] >= 17.0: # A partir de Kodi 16 se puede usar multiselect, y de 17 con preselect return channels_onoff(item) - + import channelselector from core import channeltools @@ -686,6 +686,7 @@ def channel_status(item, dict_values): def overwrite_tools(item): import videolibrary_service from core import videolibrarytools + import os seleccion = platformtools.dialog_yesno(config.get_localized_string(60581), config.get_localized_string(60582), @@ -712,7 +713,9 @@ def overwrite_tools(item): continue # Eliminamos la carpeta con la serie ... - filetools.rmdirtree(path) + if tvshow_file.endswith('.strm') or tvshow_file.endswith('.json') or tvshow_file.endswith('.nfo'): + os.remove(os.path.join(path, tvshow_file)) + # filetools.rmdirtree(path) # ... y la volvemos a añadir videolibrary_service.update(path, p_dialog, i, t, serie, 3) diff --git a/specials/side_menu.py b/specials/side_menu.py index a8c27aa8..ef2818e7 100644 --- a/specials/side_menu.py +++ b/specials/side_menu.py @@ -85,7 +85,7 @@ def get_start_page(): config.get_localized_string(59976): 'latino', config.get_localized_string(70171): 'torrent', } - category = dictCategory[config.get_localized_string(config.get_setting("category"))] + category = dictCategory[config.get_setting("category")] custom_start= config.get_setting("custom_start") #if category != 'definido': @@ -104,6 +104,10 @@ def open_menu(item): main.doModal() del main +def open_shortcut_menu(item): + from platformcode import keymaptools + keymaptools.open_shortcut_menu() + class Main(xbmcgui.WindowXMLDialog): def __init__(self, *args, **kwargs): diff --git a/specials/videolibrary.py b/specials/videolibrary.py index 1eac3030..55793688 100644 --- a/specials/videolibrary.py +++ b/specials/videolibrary.py @@ -42,7 +42,7 @@ def list_movies(item, silent=False): for f in ficheros: if f.endswith(".nfo"): nfo_path = filetools.join(raiz, f) - + #Sincronizamos las películas vistas desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc(): #Si es Kodi, lo hacemos @@ -50,12 +50,12 @@ def list_movies(item, silent=False): xbmc_videolibrary.mark_content_as_watched_on_alfa(nfo_path) except: logger.error(traceback.format_exc()) - + head_nfo, new_item = videolibrarytools.read_nfo(nfo_path) if not new_item: #Si no ha leído bien el .nfo, pasamos a la siguiente continue - + if len(new_item.library_urls) > 1: multicanal = True else: @@ -67,8 +67,11 @@ def list_movies(item, silent=False): for canal_org in new_item.library_urls: canal = generictools.verify_channel(canal_org) try: - channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) - logger.debug('El canal %s parece correcto' % channel_verify) + if canal == 'community': + channel_verify = __import__('specials.%s' % canal, fromlist=["channels.%s" % canal]) + else: + channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) + logger.debug('Channel %s seems correct' % channel_verify) except: dead_item = Item(multicanal=multicanal, contentType='movie', @@ -78,9 +81,9 @@ def list_movies(item, silent=False): library_urls=new_item.library_urls, infoLabels={'title': new_item.contentTitle}) if canal not in dead_list and canal not in zombie_list: - confirm = platformtools.dialog_yesno('Videoteca', - 'Parece que el canal [COLOR red]%s[/COLOR] ya no existe.' % canal.upper(), - 'Deseas eliminar los enlaces de este canal?') + confirm = platformtools.dialog_yesno(config.get_localized_string(30131), + config.get_localized_string(30132) % canal.upper(), + config.get_localized_string(30133)) elif canal in zombie_list: confirm = False @@ -113,7 +116,7 @@ def list_movies(item, silent=False): if not filetools.exists(filetools.join(new_item.path, filetools.basename(strm_path))): # Si se ha eliminado el strm desde la bilbioteca de kodi, no mostrarlo continue - + # Menu contextual: Marcar como visto/no visto visto = new_item.library_playcounts.get(os.path.splitext(f)[0], 0) new_item.infoLabels["playcount"] = visto @@ -165,7 +168,7 @@ def list_tvshows(item): if f == "tvshow.nfo": tvshow_path = filetools.join(raiz, f) # logger.debug(tvshow_path) - + #Sincronizamos los episodios vistos desde la videoteca de Kodi con la de Alfa try: if config.is_xbmc(): #Si es Kodi, lo hacemos @@ -173,7 +176,7 @@ def list_tvshows(item): xbmc_videolibrary.mark_content_as_watched_on_alfa(tvshow_path) except: logger.error(traceback.format_exc()) - + head_nfo, item_tvshow = videolibrarytools.read_nfo(tvshow_path) if len(item_tvshow.library_urls) > 1: @@ -187,7 +190,10 @@ def list_tvshows(item): for canal in item_tvshow.library_urls: canal = generictools.verify_channel(canal) try: - channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) + if canal == 'community': + channel_verify = __import__('specials.%s' % canal, fromlist=["channels.%s" % canal]) + else: + channel_verify = __import__('channels.%s' % canal, fromlist=["channels.%s" % canal]) logger.debug('El canal %s parece correcto' % channel_verify) except: dead_item = Item(multicanal=multicanal, @@ -198,9 +204,9 @@ def list_tvshows(item): library_urls=item_tvshow.library_urls, infoLabels={'title': item_tvshow.contentTitle}) if canal not in dead_list and canal not in zombie_list: - confirm = platformtools.dialog_yesno('Videoteca', - 'Parece que el canal [COLOR red]%s[/COLOR] ya no existe.' % canal.upper(), - 'Deseas eliminar los enlaces de este canal?') + confirm = platformtools.dialog_yesno(config.get_localized_string(30131), + config.get_localized_string(30132) % canal.upper(), + config.get_localized_string(30133)) elif canal in zombie_list: confirm = False @@ -236,9 +242,9 @@ def list_tvshows(item): else: texto_visto = config.get_localized_string(60021) contador = 1 - + except: - logger.error('No encuentra: ' + str(tvshow_path)) + logger.error('Not find: ' + str(tvshow_path)) logger.error(traceback.format_exc()) continue @@ -435,7 +441,7 @@ def findvideos(item): autoplay.set_status(False) if not item.contentTitle or not item.strm_path: - logger.debug("No se pueden buscar videos por falta de parametros") + logger.debug("Unable to search for videos due to lack of parameters") return [] content_title = filter(lambda c: c not in ":*?<>|\/", item.contentTitle.strip().lower()) @@ -499,15 +505,18 @@ def findvideos(item): for nom_canal, json_path in list_canales.items(): if filtro_canal and filtro_canal != nom_canal.capitalize(): continue - + item_canal = Item() item_canal.channel = nom_canal nom_canal = item_canal.channel - + # Importamos el canal de la parte seleccionada try: - channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal]) + if nom_canal == 'community': + channel = __import__('specials.%s' % nom_canal, fromlist=["channels.%s" % nom_canal]) + else: + channel = __import__('channels.%s' % nom_canal, fromlist=["channels.%s" % nom_canal]) except ImportError: exec "import channels." + nom_canal + " as channel" @@ -533,7 +542,7 @@ def findvideos(item): from core import servertools list_servers = servertools.find_video_items(item_json) except Exception, ex: - logger.error("Ha fallado la funcion findvideos para el canal %s" % nom_canal) + logger.error("The findvideos function for the channel %s failed" % nom_canal) template = "An exception of type %s occured. Arguments:\n%r" message = template % (type(ex).__name__, ex.args) logger.error(message) @@ -549,7 +558,7 @@ def findvideos(item): server.channel = "videolibrary" server.nfo = item.nfo server.strm_path = item.strm_path - + #### Compatibilidad con Kodi 18: evita que se quede la ruedecedita dando vueltas en enlaces Directos if server.action == 'play': server.folder = False @@ -576,7 +585,10 @@ def play(item): # logger.debug("item:\n" + item.tostring('\n')) if not item.contentChannel == "local": - channel = __import__('channels.%s' % item.contentChannel, fromlist=["channels.%s" % item.contentChannel]) + if item.contentChannel == 'community': + channel = __import__('specials.%s' % item.contentChannel, fromlist=["channels.%s" % item.contentChannel]) + else: + channel = __import__('channels.%s' % item.contentChannel, fromlist=["channels.%s" % item.contentChannel]) if hasattr(channel, "play"): itemlist = getattr(channel, "play")(item) @@ -623,7 +635,7 @@ def update_videolibrary(item): break if ficheros and not strm: - logger.debug("Borrando carpeta de pelicula eliminada: %s" % raiz) + logger.debug("Deleting deleted movie folder: %s" % raiz) filetools.rmdirtree(raiz) @@ -646,31 +658,31 @@ def update_tvshow(item): def verify_playcount_series(item, path): logger.info() - + """ Este método revisa y repara el PlayCount de una serie que se haya desincronizado de la lista real de episodios en su carpeta. Las entradas de episodios, temporadas o serie que falten, son creado con la marca de "no visto". Posteriormente se envia a verificar los contadores de Temporadas y Serie - + En el retorno envía de estado de True si se actualizado o False si no, normalmente por error. Con este estado, el caller puede actualizar el estado de la opción "verify_playcount" en "videolibrary.py". La intención de este método es la de dar una pasada que repare todos los errores y luego desactivarse. Se puede volver a activar en el menú de Videoteca de Alfa. - + """ #logger.debug("item:\n" + item.tostring('\n')) - + #Si no ha hecho nunca la verificación, lo forzamos estado = config.get_setting("verify_playcount", "videolibrary") if not estado or estado == False: estado = True #Si no ha hecho nunca la verificación, lo forzamos else: estado = False - + if item.contentType == 'movie': #Esto es solo para Series return (item, False) if filetools.exists(path): nfo_path = filetools.join(path, "tvshow.nfo") head_nfo, it = videolibrarytools.read_nfo(nfo_path) #Obtenemos el .nfo de la Serie if not hasattr(it, 'library_playcounts') or not it.library_playcounts: #Si el .nfo no tiene library_playcounts se lo creamos - logger.error('** No tiene PlayCount') + logger.error('** It does not have PlayCount') it.library_playcounts = {} - + # Obtenemos los archivos de los episodios raiz, carpetas_series, ficheros = filetools.walk(path).next() # Crear un item en la lista para cada strm encontrado @@ -685,15 +697,15 @@ def verify_playcount_series(item, path): if season_episode not in it.library_playcounts: #No está incluido el episodio it.library_playcounts.update({season_episode: 0}) #actualizamos el playCount del .nfo estado_update = True #Marcamos que hemos actualizado algo - + if 'season %s' % season not in it.library_playcounts: #No está incluida la Temporada it.library_playcounts.update({'season %s' % season: 0}) #actualizamos el playCount del .nfo estado_update = True #Marcamos que hemos actualizado algo - + if it.contentSerieName not in it.library_playcounts: #No está incluida la Serie it.library_playcounts.update({item.contentSerieName: 0}) #actualizamos el playCount del .nfo estado_update = True #Marcamos que hemos actualizado algo - + if estado_update: logger.error('** Estado de actualización: ' + str(estado) + ' / PlayCount: ' + str(it.library_playcounts)) estado = estado_update @@ -713,35 +725,35 @@ def mark_content_as_watched2(item): # logger.debug("item:\n" + item.tostring('\n')) if filetools.exists(item.nfo): - head_nfo, it = videolibrarytools.read_nfo(item.nfo) - #logger.debug(it) + head_nfo, it = videolibrarytools.read_nfo(item.nfo) + #logger.debug(it) if item.contentType == 'movie': name_file = os.path.splitext(os.path.basename(item.nfo))[0] - + if name_file != 'tvshow' : - it.library_playcounts.update({name_file: item.playcount}) + it.library_playcounts.update({name_file: item.playcount}) if item.contentType == 'episode' or item.contentType == 'tvshow' or item.contentType == 'list' or name_file == 'tvshow': # elif item.contentType == 'episode': name_file = os.path.splitext(os.path.basename(item.strm_path))[0] num_season = name_file [0] - item.__setattr__('contentType', 'episode') - item.__setattr__('contentSeason', num_season) - #logger.debug(name_file) - + item.__setattr__('contentType', 'episode') + item.__setattr__('contentSeason', num_season) + #logger.debug(name_file) + else: name_file = item.contentTitle - # logger.debug(name_file) + # logger.debug(name_file) if not hasattr(it, 'library_playcounts'): it.library_playcounts = {} - it.library_playcounts.update({name_file: item.playcount}) + it.library_playcounts.update({name_file: item.playcount}) # se comprueba que si todos los episodios de una temporada están marcados, se marque tb la temporada if item.contentType != 'movie': it = check_season_playcount(it, item.contentSeason) - #logger.debug(it) + #logger.debug(it) # Guardamos los cambios en item.nfo if filetools.write(item.nfo, head_nfo + it.tojson()): @@ -756,9 +768,9 @@ def mark_content_as_watched2(item): if config.is_xbmc(): from platformcode import xbmc_videolibrary xbmc_videolibrary.mark_content_as_watched_on_kodi(item , item.playcount) - # logger.debug(item) + # logger.debug(item) - platformtools.itemlist_refresh() + platformtools.itemlist_refresh() def mark_content_as_watched(item): @@ -879,7 +891,7 @@ def delete(item): from platformcode import xbmc_videolibrary xbmc_videolibrary.clean() - logger.info("Eliminados todos los enlaces") + logger.info("All links removed") platformtools.itemlist_refresh() # logger.info(item.contentTitle) @@ -970,7 +982,7 @@ def check_tvshow_playcount(item, season): temporadas_vistas_serie += 1 #logger.debug(temporadas_serie) - if temporadas_serie == temporadas_vistas_serie: + if temporadas_serie == temporadas_vistas_serie: item.library_playcounts.update({item.title: 1}) else: item.library_playcounts.update({item.title: 0})