Recensubs HQ

La vera guida a come cavolo si encoda per davvero - Episodio 5: Qualche altra nozione di Avisynth, CI FANNO CONCORRENZA!!!

« Older   Newer »
  Share  
view post Posted on 28/10/2014, 22:28     +1   -1
Avatar

Bimbosp

Group:
Administrator
Posts:
9,780
Reputation:
+929
Location:
Gallarate (VA)

Status:


Udite udite, ci fanno concorrenza.
Dacché ora c'è un forum alternativo a recensubs, per evitare che le mie guide vengano ignorate mi rinfaccino che non ho ancora finito le guide qui mentre lì c'è tutto finito, vedrò di andare ancora un po' avanti. Anche se tanto non se le cagava nessuno neanche prima.

Ci eravamo lasciati dopo una breve introduzione ad Avisynth, in cui ho spiegato un po' cos'è e ho introdotto il concetto di overloading.
Per concludere quest'introduzione ad Avisynth cercherò di spiegarvi come si programma tramite Avisynth. Oltre a questa seconda parte ce ne sarà una terza e ultima in cui spiegherò alcune ultime cose di programmazione in avisynth e la logica del filtraggio tramite avisynth.

Ok, ciò detto, cominciamo questa seconda lezione.


Capitolo 1: I tipi di dati e le variabili

Quando si programma con linguaggi più avanzati dell'assembly, viene dato per scontato l'uso di variabili che abbiano tipi diversi. Se vogliamo memorizzare del testo abbiamo delle stringhe di carattere, abbiamo tipi numerici di varia natura per numeri interi piuttosto che decimali, nonché un tipo booleano che assume normalmente un tipo vero o falso.
I linguaggi di programmazione si distinguono a questo livello in base alla loro tipizzazione. Normalmente si contrappongono linguaggi fortemente tipizzati con linguaggi dalla tipizzazione dinamica. Sapere la differenza tra queste due cose ci interessa relativamente, invero solo nella misura in cui vi sia chiaro che, essendo avisynth un linguaggio interpretato dalla tipizzazione dinamica, dovrete prestare MOLTA attenzione a come usate le variabili, perché se fate qualche errore nel modo in cui le usate e memorizzate, potranno nascere errori a catena giacché avisynth potrebbe non aver problemi a far funzionare lo stesso il codice, anche se non come intendevate voi.

Le variabili sono quindi pezzetti di memoria in cui si salvano dei dati di uno dei tipi consentiti dal linguaggio. Vi suggerisco di decidere già a priori un vostro standard di nomenclatura delle variabili, altrimenti si crea molta confusione. In generale nei linguaggi di programmazione si sfrutta il metodo denominato CamelCase, che consiste nell'unire varia parole mettendo la prima lettera di ogni parola in maiuscolo. A gusti si può decidere di iniziare il nome della variabile in minuscolo o maiuscolo. Ricordatevi però che avisynth non è case sensitive, quindi questa distinzione nel caso servirebbe solo a voi per leggibilità e comprensibilità di codice, e quindi due nomi in cui cambia solo il caps della lettera sono la stessa cosa per avisynth.
Ad ogni modo, le uniche vere regole per i nomi delle variabili in avisynth sono che deve iniziare con una lettera e che non può contenere altro oltre a lettere, cifre e underscore (_).

Ci sono fondamentalmente due modi per memorizzare una variabile in avisynth. Il primo è tramite l'assegnazione diretta di un valore all'interno di uno script, il secondo è tramite la definizione dei parametri in una funzione. Il secondo metodo lo analizzerò più avanti, concentriamoci intanto sul primo.
Poniamo caso di voler assegnare il valore numerico 2 ad una variabile di nome numeroDue. Si utilizza il simbolo uguale (=) per l'assegnazione di un valore ad una variabile (e quindi ricordate, in avisynth l'uguale non ha valore matematico di uguaglianza, ma ha l'abbastanza comune uso informatico di assegnazione di valore). Ciò che sta alla sinistra dell'uguale sarà il nome della variabile, ciò che sta a destra il valore assegnato. Semplicemente si scrive:

CODICE
numeroDue = 2


e più avanti nel codice, quando utilizzerete la variabile numeroDue avisynth starà internamente utilizzando il valore assegnato a quella variabile, ovvero 2.
Tenete presente che gli spazi vengono fondamentalmente ignorati da avisynth, per cui scrivere

CODICE
numeroDue=2


oppure

CODICE
numeroDue   =   2


al posto della prima soluzione è assolutamente la stessa cosa per avisynth. Siate liberi di usare gli spazi come vi trovate più comodi.

Bene. Come vedete, indicando la variabile in questo modo, non viene specificato il tipo della variabile, ma avisynth lo dedurrà in base a ciò che viene assegnato.

Partiamo quindi con l'elencare i tipi di variabili presenti in avisyth. Se avete già dimestichezza con altri linguaggi dovrebbero esservi quasi tutti noti. Ci vorrà un poco.


string

Il tipo string serve per memorizzare del testo. Per assegnare una stringa di testo ad una variabile, la dovete scrivere tra virgolette ("). Se il testo che volete scrivere include a sua volta le virgolette, dovete racchiuderlo tra triple virgolette ("""). Per esempio, per memorizzare il testo Pokémon > Fansub nella variabile assiomaInconfutabile potete fare:

CODICE
assiomaInconfutabile = "Pokémon > Fansub"


oppure

CODICE
assiomaInconfutabile = """Pokémon > Fansub"""


indifferentemente senza problemi.

Se invece volete memorizzare il testo il fansub è "divertente" nella variabile noMaCredici dovrete necessariamente fare:

CODICE
noMaCredici = """il fansub è "divertente""""


e potete stare tranquilli che il testo verrà correttamente salvato da avisynth. Tenete presente che AvspMod è buggato (quantomeno nella versione che sto usando attualmente io, ovvero la 2.5.1), quindi quando si troverà quelle quattro virgolette di fila probabilmente il codice vi verrà evidenziato come errato, ma vi posso confermare che internamente avisynth funziona correttamente.


int

Il tipo int serve per memorizzare i numeri interi. Potete specificare anche il segno per indicare i numeri positivi e negativi, e inoltre è supportata la notazione esadecimale tramite l'utilizzo del carattere dollaro ($). Quest'ultima torna particolarmente utile quando serve specificare colori RGB o YUV (ma ne parleremo adeguatamente quando ne sarà il momento in futuro).

L'esempio iniziale di assegnazione variabile era proprio un int, e quindi:

CODICE
numeroDue = 2


quel 2 viene memorizzato come numero intero. E quindi se dividete per 2 usando QUEL 2, il risultato sarà intero (l'eventuale resto viene omesso, non viene effettuato alcun tipo di arrotondamento). Per cui, usando interi, sia 9/3, sia 10/3, sia 11/3 danno come risultato 3.
Per memorizzare gli esadecimali potete fare:

CODICE
rosso = $FF0000


Che equivale al numero decimale 16711680. Alcuni valori utili da memorizzare (esadecimale -> decimale):

00 -> 0 (duh)
10 -> 16
7F -> 127
80 -> 128
81 -> 129
EB -> 235
F0 -> 240 (F-ZERO, BITCHES)
FF -> 255

NOTA BENE: salvare tramite notazione esadecimale un valore NON VUOL DIRE AUTOMATICAMENTE che rappresenta un colore, semplicemente, non esistende un tipo specifico per i colori, si sfrutta l'intero e una notazione comoda allo scopo. Avisynth internamente lo memorizza ugualmente come numero decimale, la notazione torna semplicemente utile quando serve utilizzare delle variabili per identificare i colori: normalmente infatti i parametri che riguardano colori sono valori interi, e la notazione esadecimale torna comoda perché visivamente leggendo il codice separa bene i tre canali e quindi fa comprendere al volo quale colore sia (all'incirca).
Per la precisione, quando si tratta di RGB, le prime due cifre esadecimali corrispondono al rosso (R), la terza e la quarta al verde (G), e quinta e sesta al blu (B). Tenetelo a mente come $RRGGBB.
Se avete a che fare con una clip RGB32, potete specificare il valore dell'alpha: in tal caso la convenzione di avisynth è ARGB, ovvero anteporre l'alpha agli altri canali, quindi le prime due cifre sono al'alpha e il resto mantiene l'ordine solito. In sostanza, $AARRGGBB.
Per i colori YUV, le prime due cifre rappresentano la luminanza (Y), mentre le altre quattro cifre rappresentano la crominanza UV. I valori di crominanza sono neutri a metà, andando verso il massimo vi avvicinate a blu (U) e rosso (V), mentre verso il minimo avrete giallo (U) e verde (V). In sostanza potete memorizzare i valori YUV come $YYUUVV ma tanto specificare i valori in YUV è un macello.
Prima o poi farò una guida per comprendere meglio gli spazi di colore, ma quel giorno è lontano visto che prima ci sono molte cose che ancora devo comprendere bene pure io. (´・ω・`)


float

Per quando volete i decimali, beh, usate il punto come separatore decimale (maledetti ammeregani). Ne consegue, che se, avete bisogno di memorizzare un valore intero come decimale, o se avete bisogno di fare una divisone decimale, vi basta specificare il punto per avere un calcolo float anziché int. Per cui, per salvare il 2 come float:

CODICE
numeroDue = 2.0


E per avere il resto come si deve si può fare 10/3.0 al posto di semplicemente 10/3 come sopra.


bool

I valori booleani servono per indicare un vero/falso, per cui:

CODICE
valoreBooleano = true


oppure

CODICE
valoreBooleano = false


Nota: si possono usare anche yes e no rispettivamente al posto di true e false, ma è sconsigliato. Al contrario di altri linguaggi, non potete usare 0 e 1 con significati booleani diretti.


val

Questo tipo esiste solo quando si creano funzioni. Nella dichiarazione potete specificare val per indicare una variabile che può avere un tipo non certo al momento della dichiarazione, e che quindi verrà valutato di conseguenza più avanti, in base al valore che viene dato al parametro al momento dell'utilizzo della funzione. Vedremo poi come usarlo.


clip

Lascio per ultimo il tipo fondamentalmente esclusivo di avisynth. Il tipo clip serve per indicare per l'appunto un clip audio e/o video, che può essere o caricato esternamente o generato tramite altri filtri (ad esempio tramite Blankclip).


Ok, con questo abbiamo coperto tutti i tipi di avisynth, direi che possiamo passare alle strutture di controllo.


Capitolo 2: L'uso dei blocchi condizionali

Posto che ormai siate entrati nella mentalità che avisynth è un linguaggio di scripting a tutti gli effetti, è bene essere consci degli strumenti che ciò mette a disposizione.

Essendo avisynth un linguaggio sufficientemente sviluppato, abbiamo modo di creare script che ci consentono di ramificare il filtraggio in base a determinate condizioni. Se avete già pratica di programmazione, sapete sicuramente cosa sia una struttura if-then-else, ma se non lo sapete, ecco una spiegazione in breve già contestualizzata.

Talvolta capita di aver bisogno di filtrare un frame in modo diverso in base a una determinata condizione. Posto quindi in essere un sistema che faccia sapere se una certa condizione si verifica, e quindi è vera, o non si verifica, e quindi è falsa, possiamo stabilire come avisynth debba andare a comportarsi in ciascuno dei casi.

Nei linguaggi di programmazione normalmente questo avviene tramite blocchi di codice indentati e ben leggibili. HAH! Scordatevi certe comodità.
L'uso del blocco condizionale in avisynth avviene tramite due simboli, ovvero il punto di domanda (?) e i due punti (:). Ovvero:

condizione ? vero : falso

Che in realtà è una struttura in riga presente in altri linguaggi (sicuro c'è in java, anche se tendenzialmente si preferisce avere del codice più leggibile).
EDIT:
CITAZIONE
<mirkosp> se possibile è meglio usare if then else in generale
<mirkosp> anziché ? : in riga
<mirkosp> e sì, in java c'è ? :
<chibi_goku> derp, http://en.wikipedia.org/wiki/Ternary_operation
<chibi_goku> c'è in praticamente il 90% dei linguaggi usati
<chibi_goku> (in tutti quelli che si ispirano vagamento al C)
<chibi_goku> ed è usatissimo
<chibi_goku> piantala di scrivere puttanate imparate su un banco di scuola giocando a pokémon
<mirkosp> kek
<mirkosp> a scuola mi dicevano sempre di evitarlo
<mirkosp> °°b
<chibi_goku> dimostrando di non capire un cazzo
<helltilt> anche a me a scuola mi dicono di evitarlo, ma solo perché non capiscono un cazzo
<chibi_goku> in alcuni casi è pure più chiaro di if else
<chibi_goku> tipo prima di un return
<helltilt> già
<chibi_goku> o ci puoi modificare le stringhe inline che è parecchio comodo in svariati casi
<chibi_goku> insomma, è utile e chiunque programmi lo usa

Per la condizione potete semplicemente appoggiarvi ad una variabile bool oppure potete semplicemente fare un controllo. Fondamentalmente va bene qualsiasi cosa che dia come risposta un netto sì o no, vero o falso. Per cui, "x è maggiore di y?", "questo blocco di testo coincide con quest'altro?" sono domande legittime su cui basare un controllo, ma "quanto fa 2+2?" decisamente non va bene.
Per questo scopo potete usare gli operatori e le funzioni interne come più vi pare lecito.

Vi farò un esempio semplice prima, e uno complesso poi.

Posto che abbiate due variabili numeriche intere denominate x e y, se il x è maggiore di y, vogliamo mostrare una clip nera, altrimenti vogliamo mostrare una clip bianca.

CODICE
x > y ? blankclip() : blankclip(color=$FFFFFF)


Valorizzando le variabili prima di questo codice avremo...

CODICE
x = 1
y = 2
x > y ? blankclip() : blankclip(color=$FFFFFF)


...una clip bianca...

CODICE
x = 2
y = 1
x > y ? blankclip() : blankclip(color=$FFFFFF)


...o una nera in base al caso. E ricordatevi che se x è uguale a y, non ne è maggiore, quindi la condizione sarebbe, in questo codice di esempio, falsa (ma sono cose che spero bene abbiate saldamente compreso alle elementari).

Ora facciamo un esempio più complesso.

Dato un valore x di tipo ignoto, mostrare una clip grigia se non è numerico intero, bianca se è divisibile per y (che assumiamo come certamente numerico intero), nera se non è divisibile per y.

CODICE
IsInt(x) ? x % y == 0 ? blankclip(color=$FFFFFF) : blankclip() : blankclip(color=$808080)


Ammetto che non è molto leggibile così in riga. Se non vi trovate comodi, avete due modi per migliorare la leggibilità: usare parentesi a gusto (superflue ma utili per contribuire alla comprensibilità, talvolta), oppure usare il carattere backslash (\), che in avisynth serve per spezzare graficamente su più righe contenuti che da avisynth devono essere letti come su una riga unica. L'uso delle parentesi può essere ad esempio:

CODICE
IsInt(x) ? ( x % y == 0 ? blankclip(color=$FFFFFF) : blankclip() ) : blankclip(color=$808080)


Per separare graficamente i due if, in modo tale da non confondersi si quali : siano quelli dell'if interno e quali dell'if esterno.
L'uso del backslash invece può essere molto più utile per chi è abituato ad altri linguaggi di programmazione, visto che ci consente di creare visivamente una struttura del tipo
CODICE
if condizione then
  true
else
  false

In questo caso facendo una cosa tipo:
CODICE
IsInt(x) ? \
   x % y == 0 ? \
       blankclip(color=$FFFFFF) \
   : \
       blankclip() \
: \
   blankclip(color=$808080)


Sentitevi liberi di fare come preferite, ma il mio consiglio spassionato è, per quanto poco intuitivo, di abituarvi a scrivere in riga senza l'ausilio delle parentesi. Questo sembra un suggerimento assurdo da un punto di vista informatico, e probabilmente lo è (visto che indentare il codice è in realtà una delle buone regole del programmatore), ma a livello di avisynth abituarvi a leggere codice in riga senza grandi riferimenti visivi vi tornerà utile quando più avanti (non in questa guida) andremo a utilizzare i masktools e la notazione polacca inversa, che già vi linko così se avete voglia potete già studiarvi (se non ne avete tranquilli, quando arriverà il momento spiegherò anche quella).

Ora sorge una domanda (spero, se siete stati attenti): ma Mirko, in questo modo possiamo avere solo funzioni in riga come alternative dell'if, come facciamo se dopo il controllo abbiamo bisogno di fare più cose?
Ottima domanda.

Ci sono più vie, qui ve ne indico due.

Usare il punto (.) per concatenare in fila più filtri.

Ovvero...

CODICE
filtro1()
filtro2()
filtro3()


equivale a

CODICE
filtro1().filtro2().filtro3()


Tuttavia tenete presente che usando il . non andate a modificare il valore del last, per cui se avete bisogno di appoggiarvi a valori di last che cambiano dopo i vari filtri, dovete o tenerne conto quando scrivete il codice, o se non è possibile tenerne conto manualmente, dovrete usare l'altra soluzione.

Usare il comando Eval.

Ovvero...
CODICE
Eval("filtro 1()
filtro 2()
filtro3()")

...funziona tranquillamente.
NOTA BENE: ricordatevi di usare le triple virgolette se avete necessità di usare stringhe all'interno di eval. E quindi...

CODICE
Eval("""filtro1()
filtro2(parametro="stringa")
filtro3()""")


potete fare così, come spiegavo prima.

Ok, ora mettiamoci con l'ultima parte di questa guida, e la conclusione sarà la prossima volta.


Capitolo 3: la dichiarazione di nuove funzioni

Giunti a questo punto è bene dirvi finalmente quando viene usato il tipo val. Ovvero, quando si dichiara una nuova funzione. Ma facciamo un passo alla volta.

Per dichiarare una nuova funzione si utilizza l'istruzione function.

Poniamo caso di voler creare la funzione OraPari che ci mostra un video bianco se l'ora attuale è pari, mentre un video nero se l'ora attuale è dispari.

Possiamo fare:

CODICE
function OraPari() {
OraAttuale = Int(Value(Time("%­H")))
return OraAttuale % 2 == 0 ? blankclip(color=$FFFFFF) : blankclip()
}


Capite bene come si faccia a creare una funzione. Dopo la parola chiave function scriviamo il nome che vogliamo dare alla nostra funzione. Le parentesi tonde in questo caso sono vuote, a breve vedremo a cosa servono. Le parentesi graffe servono invece per racchiudere il codice effettivo della funzione.
La parola chiave return non è necessaria, semplicemente rende chiaro cosa verrà restituito dalla funzione. In assenza di esso, verrà restitutito ciò che c'è con l'ultima riga.

Ok, e ora sveliamo l'arcano.
Nelle tonde specificate i parametri!

E anche qui, mi trovo comodo a spiegare tramite un esempio. Un esempio complesso che racchiude più o meno tutto quello che abbiamo visto finora.

Vogliamo creare una funzione che deve assolutamente prendere un video YV12 in input, e come output restituisce un video YV12, basandosi sulle indicazioni che seguono per decidere come comportarsi in base al parametro di input:
- se non viene specificato altro, il video stesso in caso di ora pari.
- se non viene specificato altro, il video invertito in caso di ora dispari.
- se viene specificato un numero, il valore Y diventa 50 se è int, diventa 200 se è float (nota: un numero intero può essere memorizzato come float, e nel caso mostriamo 200).
- se viene specificata una stringa, il valore U del chroma verrà massimizzato in caso di lunghezza divisibile per 3, valore U del chroma Minimizzato (Pokéfaggata involontaria, loggiùro), altrimenti.
- se viene specificato un bool, il valore V del chroma verrà massimizzato in caso di valore vero, altrimenti verrà minimizzato.
- se viene specificata un'altra clip, verrà restituito l'overlay al 50% di opacità tra le due clip

Anf. Ok, è un bel casino, mi voglio male da solo. Ma è con esercizi del genere che si migliora (spero)! Almeno queste guide tornano utili anche a me, visto che mi tocca fare qualche sforzo... :shifty:

CODICE
function MasochismoInutile(clip c, val "parametro") {
assert(isyv12(c),"La funzione richiede un video YV12 come input!")
defined(parametro) ? \
   isint(parametro) ? ytouv(c.utoy(),c.vtoy(),blankclip(pixel_type="YV12",color_yuv=$320000)) :\
   isfloat(parametro) ? ytouv(c.utoy(),c.vtoy(),blankclip(pixel_type="YV12",color_yuv=$C80000)) :\
   isstring(parametro) ? \
       StrLen(parametro) % 3 == 0 ? ytouv(blankclip(pixel_type="YV12",color_yuv=$001000).utoy(),c.vtoy(),c) :\                    
                                    ytouv(blankclip(pixel_type="YV12",color_yuv=$00F000).utoy(),c.vtoy(),c) :\
   isbool(parametro) ? \
       parametro ? ytouv(c.utoy(),blankclip(pixel_type="YV12",color_yuv=$00010).vtoy(),c) :\
                   ytouv(c.utoy(),blankclip(pixel_type="YV12",color_yuv=$000F0).vtoy(),c) :\
   isclip(parametro) ? overlay(c,parametro,opacity=0.5) :\
   c.subtitle("Ho la ragionevole certezza che non sia possibile vedere questo messaggio.") :\
Int(Value(Time("%­H"))) % 2 == 0 ? \
   c : c.invert()
}


Ok... alcune informazioni e per il resto la comprensione del codice di cui sopra viene lasciata come esercizio per il lettore.
- Se il parametro viene specificato senza virgolette, è un parametro che viene richiesto obbligatoriamente in input. Se esiste, avisynth per default passa il last come clip in input.
- Se il parametro viene specificato con le virgolette, è facoltativo l'inserimento di un valore per il parametro da parte dell'utente in fase di utilizzo della funzione. In tal caso può essere utile l'utilizzo della funzione Default, che consente di valorizzare una variabile in caso sia priva di valore... l'uso è illustrato nel seguente esempio:
Vogliamo mostrare una clip bianca se il parametro in input è vero, altrimenti mostriamo nero. Se non viene specificato nulla, facciamo conto che sia vero.
CODICE
function Bianco (bool "parametro") {
parametro = Default(parametro,true)
return parametro ? blankclip(color=$FFFFFF) : blankclip()}

che mantiene il valore di parametro se è stato specificato, altrimenti lo valorizza come vero.
- Defined controlla se una variabile ha un valore specificato. Torna utile principalmente in congiunzione con val in caso di parametri facoltativi, visto che per il resto generalmente si riesce a usare Default più comodamente.
- Il messaggio in sottotitolo è un else che non può verificarsi. In teoria il controllo di isclip, giunti a quel punto, è superfluo, perché non ci sono altre alternative possibili, ma per poter mostrare anche la funzione isclip() ho deciso di aggiungere un if in più come scrupolo, per quanto superfluo.

Se ci fossero dubbi sentitevi liberi di fare domande qui sotto, e vedrò di rispondervi.

Bene, con questo manca ancora qualche cosa da trattare, ma vedremo la prossima volta.
A fra boh, quando mi girerà.

Edited by mirkosp - 29/10/2014, 00:23
 
Web  Top
view post Posted on 28/10/2014, 22:31     +1   -1
Avatar

Metal Resistance

Group:
Utente abilitato
Posts:
2,698
Reputation:
+981

Status:


Quanto tempo rubato allo subbare qualcosa...
 
Web  Top
view post Posted on 28/10/2014, 22:32     +1   -1

Junior Member

Group:
Member
Posts:
61
Reputation:
0

Status:


Mon dieu è un bel po' da studiacchiare, grazie per il tempo speso sp, mi sarà di aiuto.
 
Top
view post Posted on 28/10/2014, 23:14     +1   -1

Member

Group:
Utente abilitato
Posts:
968
Reputation:
+161
Location:
Trentino Alto Adige

Status:


Grazie anche per questo capitolo!
 
Top
view post Posted on 28/10/2014, 23:56     +1   -1
Avatar

Bastardo è bello

Group:
Administrator
Posts:
4,286
Reputation:
+740

Status:


Ma è tanto bello rimuxare raw altrui, io proprio non capisco...
 
Web Contacts  Top
view post Posted on 29/10/2014, 09:58     +1   -1
Avatar

Senior Member

Group:
Utente abilitato
Posts:
10,054
Reputation:
+385
Location:
|Monza|

Status:


mirko, le guide di recensub sono vintage.
 
Top
Satana-kun
view post Posted on 29/10/2014, 10:39     +1   -1




Mirkosp, aggiornati. Ormai le guide per fansubber hanno raggiunto ben altri livelli.
 
Top
Nihonjin
view post Posted on 29/10/2014, 11:14     +1   -1




Ma ancora qui stai SP? Sei out come tempistiche...
 
Top
Cadis Estrama Di Raizel
view post Posted on 6/12/2014, 03:00     +1   -1




Grazie, c'è qualche speranza che il sesto episodio arrivi prima del prossimo anno?
 
Top
view post Posted on 6/12/2014, 05:55     +1   -1
Avatar

Bimbosp

Group:
Administrator
Posts:
9,780
Reputation:
+929
Location:
Gallarate (VA)

Status:


Prima devo finire Love Lab.
 
Web  Top
view post Posted on 6/12/2014, 08:09     +1   -1
Avatar

G.O.D.

Group:
Utente abilitato
Posts:
950
Reputation:
+29
Location:
Svervegia

Status:


CITAZIONE (mirkosp @ 6/12/2014, 05:55) 
Prima devo finire Love Lab.

tl;dr No way.
 
Top
10 replies since 28/10/2014, 22:28   1154 views
  Share