SHARE
TWEET

Untitled

a guest Jan 20th, 2019 66 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*=====================================================*
  2. * GM RP by: OuDayas
  3. * Version: 1.0
  4. *
  5. *======================================================*/
  6. // Sezione include
  7. #include <a_samp> // include base: NON ELIMINARE O NON PARTIÀ
  8. #include <a_mysql> // Include per la connessione al: MySQL
  9. #include <sscanf> // Include per sscanf
  10. #include <zcmd> // Include per i comandi
  11.  
  12. // Sezione define
  13. // Connessione MySQL (in caso di editing cambia solo i campi tra le ""
  14. #define MYSQL_HOST    "127.0.0.1"      //IP del server host (es: localhost/127.0.0.1
  15. #define MYSQL_USER    "root"           //Username a cui accedere (di default è root)
  16. #define MYSQL_PASS    "Pass123!"       //Password per accedere al protocollo MySQL
  17. #define MYSQL_DBSE    "dbrp"           //Nome del database
  18. new MySQL:handle; // l'Handle di connessione per connettersi al databse
  19.  
  20. // dialoghi registrazione/login
  21. #define DIALOG_REGISTER  1
  22. #define DIALOG_REGISTER_EMAIL 2
  23. #define DIALOG_REGISTER_AGE 3
  24. #define DIALOG_LOGIN     10
  25.  
  26. // colori
  27. // system color
  28. #define COLOR_SYSTEM_ERROR 0xAA3333AA
  29. #define COLOR_SYSTEM_TITLE 0xFFFFFFAA
  30. #define COLOR_SYSTEM_TEXT 0xFFFFFFAA
  31. #define COLOR_SYSTEM_SUCCESS 0x33AA33AA
  32. #define COLOR_SYSTEM_INFO 0xAFAFAFAA
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39. // protocollo di controllo se una string è numerica
  40. IsNumeric(const string[])
  41. {
  42.     for (new i = 0, j = strlen(string); i < j; i++)
  43.     {
  44.         if (string[i] > '9' || string[i] < '0') return 0;
  45.     }
  46.     return 1;
  47. }
  48.  
  49. // lista denominazioni delle statistiche
  50. enum pDataEnum
  51. {
  52.     p_id,
  53.     bool:pLoggedIn,
  54.     pName[MAX_PLAYER_NAME],
  55.     pLevel,
  56.     pMoney,
  57.     pKills,
  58.     pAge,
  59.     pPassTmp[128],
  60.     pEmail[64],
  61.     pDeaths
  62. }
  63. new PlayerInfo[MAX_PLAYERS][pDataEnum];
  64.  
  65.  
  66.  
  67. // non cancellare
  68. // usercheck, controllo del giocatore
  69. forward OnUserCheck(playerid);
  70. public OnUserCheck(playerid)
  71. {
  72.     //Query inizializzata con successo nella chache, passa al check
  73.     new rows;
  74.     cache_get_row_count(rows);
  75.     if(rows == 0)
  76.     {
  77.         //Giocatore nont rovato nel database, quindi passa alla registrazione
  78.         ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registrazione", "Inserisci una password per iniziare la registrazione:", "Continua", "Annulla");
  79.     }
  80.     else
  81.     {
  82.         //Giocatore trovato, quindi passa al login
  83.         ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "Prego inserisci la password per entrare nel server:", "Login", "Esci");
  84.     }
  85.     return 1;
  86. }
  87.  
  88. // non cancellare
  89. // onuserregister - quando il giocatore finisce di registrarsi
  90. forward OnUserRegister(playerid);
  91. public OnUserRegister(playerid)
  92. {
  93.     //L'utente ha finito la registrazione e viene inserito nel database
  94.     //Una volta finito inserirà l'id nella cache e imposterà l'accesso su true (accesso effettuato)
  95.     PlayerInfo[playerid][p_id] = cache_insert_id();
  96.     GivePlayerMoney(playerid, 250);
  97.     PlayerInfo[playerid][pLoggedIn]  = true;
  98.     SendClientMessage(playerid, 0x00FF00FF, "[SERVER:] Registrazione effettuata con successo.");
  99.     return 1;
  100. }
  101.  
  102. //non cancellare
  103. // quando un utente si collega al server
  104. forward OnUserLogin(playerid);
  105. public OnUserLogin(playerid)
  106. {
  107.     //Query wurde ausgeführt und das Ergebnis im Cache gespeichert
  108.     new rows;
  109.     cache_get_row_count(rows);
  110.     if(rows == 0)
  111.     {
  112.         //In caso di login l'utente inserisce una password errata
  113.         ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "{FF0000}ERRORE:\n{FF0000}Password errata\n{0F22FF}Riprova:!", "Login", "Esci");
  114.     }
  115.     else
  116.     {
  117.         //Es existiert ein Ergebnis, das heißt der Spieler hat das richtige Passwort eingegeben
  118.         //Wir lesen nun die erste Zeile des Caches aus (ID 0)
  119.         cache_get_value_name_int(0, "id", PlayerInfo[playerid][p_id]);
  120.         cache_get_value_name_int(0, "level", PlayerInfo[playerid][pLevel]);
  121.         cache_get_value_name_int(0, "money", PlayerInfo[playerid][pMoney]);
  122.         cache_get_value_name_int(0, "kills", PlayerInfo[playerid][pKills]);
  123.         cache_get_value_name_int(0, "age", PlayerInfo[playerid][pAge]);
  124.         cache_get_value_name_int(0, "deaths", PlayerInfo[playerid][pDeaths]);
  125.         cache_get_value_name(0, "email", PlayerInfo[playerid][pEmail],64);
  126.         PlayerInfo[playerid][pLoggedIn]  = true;
  127.         SendClientMessage(playerid, 0x00FF00FF, "[INFO:] Login con successo.");
  128.         GivePlayerMoney(playerid, PlayerInfo[playerid][pMoney]);
  129.     }
  130.     return 1;
  131. }
  132. // non cancellare
  133. // quando un utente si scollega salva prima le statistiche
  134. stock SaveUserStats(playerid)
  135. {
  136.     //Se non ha effettuato l'accesso il giocatore, non salva le statistiche
  137.     if(!PlayerInfo[playerid][pLoggedIn]) return 1;
  138.  
  139.     //Se ha già effettuato l'accesso salva le statistiche
  140.    
  141.     new playeremail[64];
  142.     format(playeremail, 64, PlayerInfo[playerid][pEmail]);
  143.     new livello = PlayerInfo[playerid][pLevel];
  144. //  new soldi = PlayerInfo[playerid][pMoney];
  145.     new soldi = GetPlayerMoney(playerid);
  146.     new kills = PlayerInfo[playerid][pKills];
  147.     new morti = PlayerInfo[playerid][pDeaths];
  148.     new giocaotreid = PlayerInfo[playerid][p_id];
  149.     new etagiocatore = PlayerInfo[playerid][pAge];
  150.  
  151.     new query[256];
  152.     mysql_format(handle, query, sizeof(query),
  153.         "UPDATE users SET age = '%d', email = '%s', level = '%d', money = '%d', kills = '%d', deaths = '%d' WHERE id = '%d'",
  154.         etagiocatore, playeremail, livello, soldi, kills, morti, giocaotreid);
  155.  
  156.  
  157.     //Query inviata
  158.     mysql_pquery(handle, query);
  159.     return 1;
  160. }
  161. // non cancellare/modificare
  162. // setup della connessione al MySQL
  163. stock MySQL_SetupConnection(ttl = 3)
  164. {
  165.     print("[MySQL] Connessione in corso...");
  166.     //mysql_log();  //<- Rimuovi il commento antecedente a mysql_log per attivare la modalità debug
  167.  
  168.     handle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DBSE);
  169.  
  170.     //Inizio della procedura di controllo e riconnessione se necessario ripeterla
  171.     if(mysql_errno(handle) != 0)
  172.     {
  173.         //In caso di errore della configurazione del MySQL verifica se necessario un nuovo tentativo
  174.         if(ttl > 1)
  175.         {
  176.             //Prova di riconnessione
  177.             print("[MySQL] Impossibile collegarsi al database.");
  178.             printf("[MySQL] Inizio nuovo tentativo di connessione in corso (TTL: %d).", ttl-1);
  179.             return MySQL_SetupConnection(ttl-1);
  180.         }
  181.         else
  182.         {
  183.             //Annulla e chiude il server
  184.             print("[MySQL] Impossibile collegarsi al database.");
  185.             print("[MySQL] Verifica i dati di connessione.");
  186.             print("[MySQL] Erresto server in corso.");
  187.             return SendRconCommand("exit");
  188.         }
  189.     }
  190.     printf("[MySQL] Connessione al MySQL con successo Handle: %d", _:handle);
  191.     return 1;
  192. }
  193.  
  194. #if defined FILTERSCRIPT
  195.  
  196. public OnFilterScriptInit()
  197. {
  198.     print("\n---------------------");
  199.     print(" Non è un filterscript ");
  200.     print("---------------------\n");
  201.     return 1;
  202. }
  203.  
  204. public OnFilterScriptExit()
  205. {
  206.     return 1;
  207. }
  208.  
  209. #else
  210.  
  211. main()
  212. {
  213.     print("\n-------------------------------------------------------------------------------");
  214.     print("GameMode RP By: OuDayas v1.0");
  215.     print("Non modificare la GM dove lo trovi indicato");
  216.     print("In tal caso vuoiu spegnere il server usa il comando in console 'exit'");
  217.     print("Per effettuare un riavvio usa invece 'gmx'(Fallo solo se strettamente necessario)");
  218.     print("Per ogni cosa trovi un piccolo aiuto dove puoi editare la GM su pawno");
  219.     print("--------------------------------------------------------------------------------\n");
  220. }
  221.  
  222. #endif
  223.  
  224. public OnGameModeInit()
  225. {
  226.     MySQL_SetupConnection(); // inizio della connessione al MySQL
  227.     SetGameModeText("Blank Script");
  228.     AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
  229.  
  230.     return 1;
  231. }
  232.  
  233. public OnGameModeExit()
  234. {
  235.     mysql_close(handle);
  236.     return 1;
  237. }
  238.  
  239. public OnPlayerRequestClass(playerid, classid)
  240. {
  241.     // da qui non modificare
  242.     //Quando il giocatore entra nella "request class" controlla se ha effettuato il login
  243.     if(!PlayerInfo[playerid][pLoggedIn])
  244.     {
  245.         SendClientMessage(playerid, 0xFF0000, "[ERRORE:] Devi prima effettuare l'accesso per entrare");
  246.         //In caso contrario controlla se ha un'account
  247.         //Invia una query di controllo dove viene richiamata
  248.         //%e sta per una stringa già verificata (usata al posto di %s nelle query)
  249.         new query[128];
  250.         mysql_format(handle, query, sizeof(query), "SELECT id FROM users WHERE name = '%e'", PlayerInfo[playerid][pName]);
  251.  
  252.         //La query dopo essere stata inviata, la passxa al "OnUserCheck"
  253.         mysql_pquery(handle, query, "OnUserCheck", "d", playerid);
  254.     }
  255.     return 1;
  256. }
  257.  
  258. public OnPlayerConnect(playerid)
  259. {
  260.     PlayerInfo[playerid][p_id]       = 0;
  261.     PlayerInfo[playerid][pLoggedIn]  = false;
  262.     PlayerInfo[playerid][pLevel]     = 0;
  263.     PlayerInfo[playerid][pMoney]     = 0;
  264.     PlayerInfo[playerid][pKills]     = 0;
  265.     PlayerInfo[playerid][pDeaths]    = 0;
  266.     format(PlayerInfo[playerid][pPassTmp], 128, "");
  267.     format(PlayerInfo[playerid][pEmail], 64, "");
  268.     GetPlayerName(playerid, PlayerInfo[playerid][pName], MAX_PLAYER_NAME);
  269.     return 1;
  270. }
  271.  
  272. public OnPlayerDisconnect(playerid, reason)
  273. {
  274.     SaveUserStats(playerid);
  275.     return 1;
  276. }
  277.  
  278. public OnPlayerSpawn(playerid)
  279. {
  280.     return 1;
  281. }
  282.  
  283. public OnPlayerDeath(playerid, killerid, reason)
  284. {
  285.     return 1;
  286. }
  287.  
  288. public OnVehicleSpawn(vehicleid)
  289. {
  290.     return 1;
  291. }
  292.  
  293. public OnVehicleDeath(vehicleid, killerid)
  294. {
  295.     return 1;
  296. }
  297.  
  298. public OnPlayerText(playerid, text[])
  299. {
  300.     return 1;
  301. }
  302. // comandi
  303.  
  304. // comando: pm
  305. CMD:pm(playerid, params[])
  306. {
  307.     new str[256], str2[256], id, Name1[MAX_PLAYER_NAME], Name2[MAX_PLAYER_NAME];
  308.     if(sscanf(params, "us", id, str2))
  309.     {
  310.         SendClientMessage(playerid, 0xFF0000FF, "Usage: /pm <id> <message>");
  311.         return 1;
  312.     }
  313.     if(!IsPlayerConnected(id)) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player not connected");
  314.     if(playerid == id) return SendClientMessage(playerid, 0xFF0000FF, "[ERRORE:]{AFAFAFAA} Npon puoi mandare un pm a te stesso!");
  315.     {
  316.         GetPlayerName(playerid, Name1, sizeof(Name1));
  317.         GetPlayerName(id, Name2, sizeof(Name2));
  318.         format(str, sizeof(str), "PM To %s(ID %d): %s", Name2, id, str2);
  319.         SendClientMessage(playerid, 0xFF0000FF, str);
  320.         format(str, sizeof(str), "PM From %s(ID %d): %s", Name1, playerid, str2);
  321.         SendClientMessage(id, 0xFF0000FF, str);
  322.     }
  323.     return 1;
  324. }
  325.  
  326. public OnPlayerCommandText(playerid, cmdtext[])
  327. {/*
  328.     if (strcmp("/mycommand", cmdtext, true, 10) == 0)
  329.     {
  330.         // Do something here
  331.         return 1;
  332.     }*/
  333.     new Messaggio[256];
  334.     format(Messaggio, sizeof (Messaggio), "[INFO]: Il comando %s non esiste usa /comandi per aiuto", cmdtext);
  335.     SendClientMessage(playerid, COLOR_SYSTEM_INFO, Messaggio);
  336.     return SendClientMessage(playerid, -1, Messaggio);
  337. }
  338.  
  339. public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
  340. {
  341.     return 1;
  342. }
  343.  
  344. public OnPlayerExitVehicle(playerid, vehicleid)
  345. {
  346.     return 1;
  347. }
  348.  
  349. public OnPlayerStateChange(playerid, newstate, oldstate)
  350. {
  351.     return 1;
  352. }
  353.  
  354. public OnPlayerEnterCheckpoint(playerid)
  355. {
  356.     return 1;
  357. }
  358.  
  359. public OnPlayerLeaveCheckpoint(playerid)
  360. {
  361.     return 1;
  362. }
  363.  
  364. public OnPlayerEnterRaceCheckpoint(playerid)
  365. {
  366.     return 1;
  367. }
  368.  
  369. public OnPlayerLeaveRaceCheckpoint(playerid)
  370. {
  371.     return 1;
  372. }
  373.  
  374. public OnRconCommand(cmd[])
  375. {
  376.     return 1;
  377. }
  378.  
  379. public OnPlayerRequestSpawn(playerid)
  380. {
  381.     return 1;
  382. }
  383.  
  384. public OnObjectMoved(objectid)
  385. {
  386.     return 1;
  387. }
  388.  
  389. public OnPlayerObjectMoved(playerid, objectid)
  390. {
  391.     return 1;
  392. }
  393.  
  394. public OnPlayerPickUpPickup(playerid, pickupid)
  395. {
  396.     return 1;
  397. }
  398.  
  399. public OnVehicleMod(playerid, vehicleid, componentid)
  400. {
  401.     return 1;
  402. }
  403.  
  404. public OnVehiclePaintjob(playerid, vehicleid, paintjobid)
  405. {
  406.     return 1;
  407. }
  408.  
  409. public OnVehicleRespray(playerid, vehicleid, color1, color2)
  410. {
  411.     return 1;
  412. }
  413.  
  414. public OnPlayerSelectedMenuRow(playerid, row)
  415. {
  416.     return 1;
  417. }
  418.  
  419. public OnPlayerExitedMenu(playerid)
  420. {
  421.     return 1;
  422. }
  423.  
  424. public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
  425. {
  426.     return 1;
  427. }
  428.  
  429. public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
  430. {
  431.     return 1;
  432. }
  433.  
  434. public OnRconLoginAttempt(ip[], password[], success)
  435. {
  436.     return 1;
  437. }
  438.  
  439. public OnPlayerUpdate(playerid)
  440. {
  441.     return 1;
  442. }
  443.  
  444. public OnPlayerStreamIn(playerid, forplayerid)
  445. {
  446.     return 1;
  447. }
  448.  
  449. public OnPlayerStreamOut(playerid, forplayerid)
  450. {
  451.     return 1;
  452. }
  453.  
  454. public OnVehicleStreamIn(vehicleid, forplayerid)
  455. {
  456.     return 1;
  457. }
  458.  
  459. public OnVehicleStreamOut(vehicleid, forplayerid)
  460. {
  461.     return 1;
  462. }
  463.  
  464. public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
  465. {
  466.     // registrazione password (fase 1)
  467.     if(dialogid == DIALOG_REGISTER)
  468.     {
  469.         //Se il giocatore seleziona Annulla/Esci
  470.         if(!response) return Kick(playerid);
  471.  
  472.         //In tal caso l'utente inserisci una password troppo breve o non inserisce niente ritorna sullo stesso dialogo
  473.         if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_REGISTER, DIALOG_STYLE_PASSWORD, "Registrazione", "{FF0000}ERRORE:\n{000000}Hai inserito una password troppo corta\n{00FF00}Consiglio: Usa almeno 3 caratteri ed una password sicura!", "Continua", "Annulla");
  474.         //Se va tutto bene inizierà a creare il giocatore nel database
  475.         //MD5 è il protocollo di criptografia per la password (puoi anche rimuoverlo dalla stringa lasciandolo: ('%e', '%e')
  476.         new infopass[145];
  477.         format(infopass, sizeof(infopass), "{f8ff33}[INFO:]{00FF00} La tua password sarà: %s - puoi cambiarla con /cambiapass", inputtext);
  478.         SendClientMessage(playerid, 0xFFFFFF, infopass);
  479.         new query[256];
  480.         mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password, email, age) VALUES ('%e', MD5('%e'))", PlayerInfo[playerid][pName], PlayerInfo[playerid][pPassTmp]);
  481.         format(PlayerInfo[playerid][pPassTmp], 128, inputtext);
  482.         //Dopo di chè la query viene inviata e passa al dialogo successivo
  483.         // email
  484.         ShowPlayerDialog(playerid, DIALOG_REGISTER_EMAIL, DIALOG_STYLE_INPUT, "Registrazione", "{00FF00}Non manca molto:\n{000000}Inserisci una email per continuare\n{00FF00}INFO: Serve per proteggere il tuo account!", "Continua", "Annulla");
  485.         return 1;
  486.     }
  487.     // registrazione email (fase 2)
  488.     if(dialogid == DIALOG_REGISTER_EMAIL)
  489.     {
  490.  
  491.         //Se il giocatore seleziona Annulla/Esci
  492.         if(!response) return Kick(playerid);
  493.         //In tal caso l'utente inserisci una password troppo breve o non inserisce niente ritorna sullo stesso dialogo
  494.         if(strlen(inputtext) < 5) return ShowPlayerDialog(playerid, DIALOG_REGISTER_EMAIL, DIALOG_STYLE_PASSWORD, "Registrazione", "{FF0000}ERRORE:\n{000000}Devi inserire una mail valide\n{00FF00}INFO: Servirà per proteggere meglio il tuo account!", "Continua", "Annulla");
  495.         format(PlayerInfo[playerid][pEmail], 64, inputtext);
  496.         new query[256];
  497.         mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password, email) VALUES ('%e', MD5('%e'), '%e')", PlayerInfo[playerid][pName], PlayerInfo[playerid][pPassTmp], inputtext);
  498.         format(PlayerInfo[playerid][pPassTmp], 128, "");
  499.         //Dopo di chè la query viene inviata e passa al dialogo successivo
  500.         // età
  501.         ShowPlayerDialog(playerid, DIALOG_REGISTER_AGE, DIALOG_STYLE_INPUT, "Registrazione", "Inserisci l'età che vuoi avere nel server\nNon influenzerà il gioco.", "Continua", "Annulla");
  502.         return 1;
  503.     }
  504.     // registrazione età (fase 3)
  505.     if(dialogid == DIALOG_REGISTER_AGE)
  506.     {
  507.  
  508.         //Se il giocatore seleziona Annulla/Esci
  509.         if(!response) return Kick(playerid);
  510.         //In tal caso l'utente inserisci una password troppo breve o non inserisce niente ritorna sullo stesso dialogo
  511.         if(!strlen(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER_EMAIL, DIALOG_STYLE_PASSWORD, "Registrazione", "{FF0000}ERRORE:\n{000000}Devi inserire una mail valide\n{00FF00}INFO: Servirà per proteggere meglio il tuo account!", "Continua", "Annulla");
  512.         if(!IsNumeric(inputtext)) return ShowPlayerDialog(playerid, DIALOG_REGISTER_AGE, DIALOG_STYLE_INPUT, "Registrazione", "{FF0000}Devi inserire un numero per l'età\n{FFFFFF}Inserisci l'età che vuoi avere nel server\nNon influenzerà il gioco.", "Continua", "Annulla");
  513.         //Dopo di chè la query viene inviata e passa al dialogo successivo
  514.         // età
  515.         new query[256];
  516.         mysql_format(handle, query, sizeof(query), "INSERT INTO users (name, password, email, age) VALUES ('%e', MD5('%e'), '%e', '%d')", PlayerInfo[playerid][pName], PlayerInfo[playerid][pPassTmp], PlayerInfo[playerid][pEmail], inputtext);
  517.         format(PlayerInfo[playerid][pPassTmp], 128, "");
  518.         mysql_pquery(handle, query, "OnUserRegister", "d", playerid);
  519.         return 1;
  520.     }
  521.    
  522.     if(dialogid == DIALOG_LOGIN)
  523.     {
  524.         //Spieler hat Abbrechen gewählt
  525.         if(!response) return Kick(playerid);
  526.  
  527.         //se l'utente inserisce una password troppo corta o non inserisce niente
  528.         if(strlen(inputtext) < 3) return ShowPlayerDialog(playerid, DIALOG_LOGIN, DIALOG_STYLE_PASSWORD, "Login", "ERRORE:\n{FF0000}Hai inserito una password troppo corta!", "Ok", "Abbrechen");
  529.  
  530.         //Wenn alles passt wird die Datenbank ausgelesen
  531.         new query[256];
  532.         mysql_format(handle, query, sizeof(query), "SELECT * FROM users WHERE name = '%e' AND password = MD5('%e')", PlayerInfo[playerid][pName], inputtext);
  533.  
  534.         //Das Query wird abgesendet und die playerid an OnUserLogin übergeben
  535.         mysql_pquery(handle, query, "OnUserLogin", "d", playerid);
  536.         return 1;
  537.     }
  538.     return 0;
  539. }
  540.  
  541. public OnPlayerClickPlayer(playerid, clickedplayerid, source)
  542. {
  543.     return 1;
  544. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top