Advertisement
Guest User

ROMfilteri V2.01.fixed

a guest
Oct 28th, 2015
373
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name         ROMFiltteri
  3. // @namespace    ROMFiltteri
  4. // @description  Piilottaa/korostaa valitsemiesi kayttajien viestit. V2.01
  5. // @include      http://keskustelu.kauppalehti.fi/*
  6. // @grant        GM_setValue
  7. // @grant        GM_getValue
  8. // @grant        GM_registerMenuCommand
  9. // ==/UserScript==
  10.  
  11. /* ROMfilteri V2.01 piilottaa ja korostaa haluamiesi käyttäjien viestejä ja tarjoaa linkkiä uusiin viesteihin.
  12.  
  13. VAATII: Firefox-selaimen ja Greasemonkey-lisäosan
  14.  
  15. OHJE:
  16.  
  17. 1) Asenna Greasemonkey Firefoxiin tästä
  18.     https://addons.mozilla.org/en-US/firefox/addon/748
  19.  
  20. 2) Avaa sitten tämä tiedosto uudelleen Firefoxilla ja salli Greasemonkeyn asentaa se.
  21.     http://userscripts.org/scripts/source/74673.user.js
  22.  
  23. 3) Suodatus on käytössä.
  24.  
  25. KOTISIVU
  26. http://userscripts.org/scripts/show/74673
  27.  
  28. POISTAMINEN:
  29.  
  30. Suodatuksen voi kytkeä tilapäisesti päälle/pois painamalla apinan naamaa selaimen oikeassa alakulmassa.
  31.  
  32. Kokonaan suodatuksen saa poistettua koneelta valitsemalla valikosta:
  33. Tools->Greasemonkey->Manage User Scripts
  34. ja painamalla Uninstall-nappia, kun tämä on valittuna.
  35.  
  36. ONGELMIA?
  37. Käytä Firefox-selainta ja asenna Greasemonkey.
  38. Onko Grease Monkey asennettu ja käytössä?
  39. Onko tämä scripta asennettu ja sallittu Greasemonkeyssä?
  40.  
  41. Tämän tiedoston nimen lopun pitää päättyä ".user.js", muutoin Greasemonkey ei älyä asentaa tätä.
  42.  
  43. */
  44. Nimimerkit= {};
  45.  
  46. RomInit();
  47. RomInit=null;
  48.  
  49. // Lisää valikot. Nämä näkee Tools>Greasemonkey>User script commands valikosta,
  50. // tai klikaamalla oikeanpuoleisella hiirellä apinan päätä selaimen oikeassa alakulmassa.
  51. if (GM_registerMenuCommand) {
  52.     GM_registerMenuCommand('Näytä/Aseta nimimerkkien pistelista',function() {
  53.         var tmp=prompt("Näytä/Aseta nimimerkkien pistelista."+
  54.                        "\nVoit kopioida nimimerkkilistan tästä ja ottaa sen käyttöön toisella tietokoneellasi liittämällä tähän.\n"+
  55.                        "\nLista on muotoa ({'nimimerkki1':1, 'nimimerkki2':-3})\n"+
  56.                        "Listan tulee alkaa ja päättyä sulkuihin ja kaarisulkuihin, kuten yllä.\n\n",GM_getValue("nimimerkit",Nimimerkit));     
  57.         if (tmp) {
  58.             try  {         
  59.             Nimimerkit = eval(tmp);
  60.             if (typeof(Nimimerkit) == "object") {
  61.                 GM_setValue("nimimerkit", uneval(Nimimerkit));
  62.             } else {
  63.                 alert("Nimimerkkilistassa oli virhe, listaa ei voitu ottaa käyttöön.");
  64.             }
  65.            } catch(e) {
  66.             alert("Nimimerkkilistassa oli virhe, listaa ei voitu ottaa käyttöön!");
  67.            }
  68.         }});           
  69.     GM_registerMenuCommand('Näytä luetut ketjut -lista',function() {prompt("Lista ketjujen viimeisimmistä luetuista viesteistä.",GM_getValue("ketjut","[]"));});
  70.     GM_registerMenuCommand('Unohda kaikki luetut ketjut',function() {if (confirm("Haluatko todella unohtaa kaikki luetut ketjut?")) GM_setValue("ketjut","[]");});
  71.     GM_registerMenuCommand('ROMfilterin kotisivu ja uusin versio',function() {window.location.href ="http://userscripts.org/scripts/show/74673";});
  72. }
  73.  
  74. function RomInit() {
  75.     // Asetuksia
  76.  
  77.     // Piilotetaanko myös viestin otsikkorivi
  78.     // 0; = ei piiloteta
  79.     // 1; = piilota otsikkorivi
  80.     var PiilotaOtsikkorivi=0;
  81.  
  82.     // Viestin taustaväriksi valitaan tältä listalta sen mukaan monta pistettä olet antanut kirjoittajalle.
  83.     // Ensimmäinen on taustaväri yhden pisteen saaneille. Pisteiden kasvaessa siirrytään värilistalla oikealle.
  84.     // Voit kirjoittaa listalle niin monta väriä kuin haluat.
  85.     var KorostusVari= ["#F4F4FB","#F2F2F8","#EBEBF6","#E0E0F3","#D9D9F0","#ddddee","#ccccdd","#bbbbcc"];
  86.     var HimmennysVari=["#555555","#888888","#aaaaaa","#bbbbbb","#cccccc","#dddddd","#eeeeee","#ffffff"];
  87.  
  88.     // --------------------------------------------------------------------------------------------------
  89.     // Alla on piilotuksen hoitava koodi, tätä ei tarvitse muuttaa, ellei keskustelupalstan rakenne muutu
  90.     // --------------------------------------------------------------------------------------------------
  91.  
  92.     //GM_setValue("anarray",uneval(Nimimerkit));
  93.     try {
  94.     Nimimerkit = eval(GM_getValue("nimimerkit",uneval(Nimimerkit)));
  95.    } catch(err) {
  96.     Nimimerkit={};
  97.    }
  98.     if (Nimimerkit==undefined) {
  99.         Nimimerkit={};
  100.     }
  101.     if (typeof(Nimimerkit) != "object") {
  102.         Nimimerkit={};
  103.     }
  104.    
  105.     // Hae listalta nimierkin saamat pisteet
  106.     var haePisteet=function(nimi) {
  107.         try {
  108.         var tmp=Nimimerkit[nimi];
  109.        } catch(err) {
  110.         tmp="";
  111.         }
  112.         if(isNaN(tmp)) return ""; else return tmp;
  113.     };
  114.  
  115.     // Luo hakutoiminnot valmiiksi, saattaa nopeuttaa hiukan
  116.     // Hae viestin tunnusnumero
  117.     var findMessageID=/messageID=([\w\d]+)/i;
  118.     // Hae viestiketjun tunnusnumero
  119.     var findThreadID=/threadID=([\w\d]+)/i;
  120.     // Hae sivun ensimmäisen viestin järjestysnumero ketjussa
  121.     var findStart=/[\?\&]+start=([\w\d]+)/i;
  122.  
  123.     // Aseta tyylit tämän scriptan lisäämille elementeille
  124.     var tmpStyle='line-height:40px; font-size:40px;text-decoration:none;color:#ddd;cursor: pointer;! important;'
  125.     addGlobalStyle('.GMVotePlus  { '+tmpStyle+' } a:hover .GMVotePlus {color:#0f0;! important;} .GMVotePlusH {color:#0f0;! important; }');
  126.     addGlobalStyle('.GMVoteMinus { '+tmpStyle+' } a:hover .GMVoteMinus {color:#f00;! important;}');
  127.     addGlobalStyle('.GMVoteBan   { '+tmpStyle+' } a:hover .GMVoteBan {color:#f00;! important;}');
  128.     addGlobalStyle('.GMVotePts   { '+tmpStyle+' } a:hover .GMVotePts {color:#f00;! important;}');
  129.     addGlobalStyle('.messagebox a:link, .messagebox a:visited {color:#026297; text-decoration:none;} .messagebox a:hover {text-decoration:underline;}');
  130.     addGlobalStyle('.jive-thread-row-paginator a:visited {color:#aaaaaa;}');
  131.     addGlobalStyle('a.GMuusi           { color:#080;}');
  132.     addGlobalStyle('.messagebox a.GMlukemattomia   { color:#ff6297;}');
  133.     addGlobalStyle('.messagebox a.GMkaikkiluettu   { color:#aaaaaa;}');
  134.     addGlobalStyle('.GMkaikkiluettu     { color:#aaaaaa;}');
  135.     //addGlobalStyle('.jive-thread-row-paginator a.GMkaikkiluettu:link {color:#026297;}');
  136.  
  137.     var Ketjut = {};
  138.     Ketjut = eval(GM_getValue("ketjut",uneval(Ketjut)));
  139.     var viestienLkm=0;
  140.     var allElements = document.getElementsByClassName("messagebox");
  141.     // Käy kaikki sivun viestit läpi
  142.     for (var i=0;i<allElements.length; i++) {
  143.         // Ota yksi viesti käsittelyyn
  144.         var viesti=allElements[i];
  145.         // Hae viestin sisältämä otsikkolaatiko
  146.         var header=getElementsByClassName("messagebox_header",viesti);
  147.         var Nimimerkki="";
  148.         // Hae otsikkolaatikon sisältä tämän viestin kirjoittajan nimimerkki
  149.         // Tämä kohta voi muuttua sivun rakenteen muuttuessa
  150.         var t=header[0];
  151.         if (t) { t=t.firstChild; while (t && t.nodeType!=1){ t=t.nextSibling;} }
  152.         if (t) { t=t.firstChild; while (t && t.nodeType!=1){ t=t.nextSibling;} }
  153.         if (t) if (t.title) { Nimimerkki=t.title;}
  154.  
  155.         // Hae viestin sivupalkki
  156.         var hide=getElementsByClassName("messagebox_sidebar",viesti);
  157.         var pisteet="";
  158.         if (hide[0] && header[0]) {
  159.                 viestienLkm++;
  160.                 // Valitse taulun rivi joka sisältää tämän viestin sisällön ja sivupalkin
  161.                 var tr=hide[0];
  162.  
  163.                 // Lisää sivupalkkiin + ja - napit ja nimierkin pisteet
  164.                 var newElement = document.createElement('a');
  165.                 newElement.className="GMVote";
  166.                 pisteet=haePisteet(Nimimerkki);
  167.                 if (0==pisteet) pisteet="";
  168.                 newElement.innerHTML=
  169.                 '<span class="GMVotePlus" title="'+Nimimerkki+'">+</span>&nbsp;'+
  170.                 '<span class="GMVoteMinus" title="'+Nimimerkki+'">-</span><br>'+
  171.                 '<span class="GMVotePts" title="pisteet">'+pisteet+'</span>';
  172.                 if (tr) tr.appendChild(newElement);
  173.                 newElement=newElement.firstChild;
  174.         }
  175.  
  176.         // Piilota viestit
  177.         if(header[0]) {
  178.             // Löytyikö viestille kirjoittaja?
  179.             if (Nimimerkki) {
  180.                 // Jos pisteet -5 tai vähemmän, piilota
  181.                 if (pisteet<=-5) {
  182.                     // Hae viestin sisältö piilotettavaksi
  183.                     // jos sisältö löytyi, piilota se
  184.                     if (hide[0]) {
  185.                         // Valitse taulun rivi joka sisältää tämän viestin sisällön ja sivupalkin
  186.                         var tr=hide[0].parentNode;
  187.                         if (PiilotaOtsikkorivi) tr=tr.parentNode;
  188.                         // Piilota taulun rivi jos se löytyi
  189.                         if (tr) tr.style.display = 'none';
  190.                         // Hae tämän viestin alapalkki
  191.                         var hideb=getElementsByClassName("messagebox_footer",viesti);
  192.                         // Jos alapalkki löytyi, piilota myös sen sisältävä taulun rivi
  193.                         if (hideb[0]) {var tr2=hideb[0].parentNode;
  194.                             if (tr2) tr2.style.display = 'none';
  195.                         }
  196.                         // Lisää nappi, jolla sisällön saa takaisin näkyviin
  197.                         var newElement = document.createElement('div');
  198.                         // Napin sisältö joka hakee viestin osat sisältävät taulun rivit ja palauttaa ne näkyviin tai piilottaa uudelleen
  199.                         newElement.innerHTML='<a href="" onClick="javascript:var elem=this.parentNode;'+
  200.                         ' do { elem = elem.nextSibling;} while(elem && elem.nodeType !== 1);'+
  201.                         ' if (elem) {if (elem.style.display==\'none\') {elem.style.display=\'block\';}else{elem.style.display=\'none\';}} '+
  202.                         ' do { elem = elem.nextSibling;} while(elem && elem.nodeType !== 1);'+
  203.                         ' if (elem) {if (elem.style.display==\'none\') {elem.style.display=\'block\';}else{elem.style.display=\'none\';}} '+
  204.                         ' return false;" >Näytä/piilota suodatettu viesti</a>';
  205.                         // Lisää näytä/piilota nappi sivulle ennen viestin sisältöä
  206.                         if (tr) tr.parentNode.insertBefore(newElement,tr);
  207.                     }
  208.                 }
  209.  
  210.                 //  Korosta viestit
  211.                 if (pisteet>0) {
  212.                     // Hae viestin sisältö korostettavaksi
  213.                     var korosta=getElementsByClassName("messagebox_content",viesti);
  214.                     // jos sisältö löytyi, korosta se
  215.                     if (korosta[0]) {
  216.                         // Valitse asetuslistalta korostusväri pisteiden määrän mukaan
  217.                         if (pisteet>KorostusVari.length) pisteet=KorostusVari.length;
  218.                         korosta[0].style.backgroundColor=KorostusVari[pisteet-1];
  219.                     }
  220.                 } else if (pisteet<0) {
  221.                     // Hae viestin sisältö korostettavaksi
  222.                     var korosta=getElementsByClassName("messagebox_content",viesti);
  223.                     // jos sisältö löytyi, korosta se
  224.                     var tpist=-pisteet;
  225.                     if (korosta[0]) {
  226.                         // Valitse asetuslistalta korostusväri pisteiden määrän mukaan
  227.                         if (tpist>HimmennysVari.length) tpist=HimmennysVari.length;
  228.                         korosta[0].style.color=HimmennysVari[tpist-1];
  229.                     }
  230.                 }
  231.             }
  232.             // Nouki sivun viimeisen viestin tunnus ja ketjun tunnus tallennettavaksi
  233.             if (allElements.length==(i+1)) {
  234.                 var footer=getElementsByClassName("messagebox_footer",viesti);
  235.                 if (footer[0]) {       
  236.                     //alert(footer[0]);
  237.                     var messageID=findMessageID.exec(footer[0].innerHTML);
  238.                     var threadID=findThreadID.exec(footer[0].innerHTML);
  239.                 }
  240.             }
  241.         }
  242.     } //<-- kaikkien viestien läpikäyntisilmukka
  243.        
  244.     // Jos viimeisin joskus aiemmin tässä ketjussa luettu viesti on tällä sivulla
  245.     // siirrä ruutu sitä seuraavan viestin kohdalle
  246.     // Hae sivun osoitteesta ketjun tunnusnumero
  247.     var tmpthreadID=findThreadID.exec(window.location.href);
  248.     if (tmpthreadID && tmpthreadID[1]) {
  249.         // Jos numero löytyi, hae sen perusteella muistista viimeisen ketjusta näytetyn viestin tunnus
  250.         var tmpmessageID=HaeViimeinenLuettu(tmpthreadID[1]);
  251.         if (tmpmessageID) {    
  252.             // hae kaikki sivun ankkurit ja linkit
  253.             var ankkurit = document.getElementsByTagName('a');
  254.             for (var i = 0; i < ankkurit.length; i++) {
  255.                 // Jos ankkurin nimi vastaa viimeksi luetun viestin tunnusta,
  256.                 if (ankkurit[i].name==tmpmessageID) {
  257.                     // etsi seuraavan viestin edessä oleva ankkuri
  258.                     for(var j=(i+1); j<ankkurit.length;j++) {
  259.                         // ankkurin erottaa linkistä, koska sillä on nimi ja ei ole linkin kohdetta
  260.                         if ((ankkurit[j].name) && (!ankkurit[j].href)) {
  261.                             var IkkunanYlalaitaan=true;
  262.                             // Siirrä ruutu ankkurin kohdalle niin, että se osuu ruudun ylälaitaan
  263.                             ankkurit[j].scrollIntoView(IkkunanYlalaitaan);
  264.                             // Oikea kohta löytyi, voi lopettaa
  265.                             break;
  266.                             // Miksi ei hypätty suoraan asettamalla sivun urlin perään #?
  267.                             // Jotta ei tarvitse painaa back nappia kahdesti
  268.                         }
  269.                     }
  270.                 }
  271.             }
  272.         }      
  273.     }
  274.    
  275.     // Tallenna aiemmin noukittu sivun viimeisimmän viestin tunnus tämän ketjun viimeisimmäksi luetuksi viestiksi
  276.     if(messageID && messageID[1] &&threadID && threadID[1]) {
  277.         var ketjunSivu=findStart.exec(window.location.href);
  278.         var viestiNro=viestienLkm;
  279.         if (ketjunSivu && ketjunSivu[1]) viestiNro-=-ketjunSivu[1];
  280.         MerkitseLuetuksi(threadID[1],messageID[1],viestiNro,false);
  281.         GM_registerMenuCommand('Unohda, että luin jo tätä ketjua',function() {MerkitseLuetuksi(threadID[1],"","",true);});
  282.         GM_registerMenuCommand('En halua seurata tätä ketjua',function() {MerkitseLuetuksi(threadID[1],"","100000",true);});
  283.     }
  284.    
  285.    
  286.     // Jos ollaan Aihelistasivulla, hae parilliset ja parittomat aihelistarivit
  287.     var aiheet=getElementsByClassName("jive-even");
  288.     LinkitLukemattomiin(aiheet);
  289.     aiheet=getElementsByClassName("odd");
  290.     LinkitLukemattomiin(aiheet);
  291.    
  292.     // Lisää keskustelun aloitussivulle kunkin aiheen yhteyteen linkki: "Uusia X"
  293.     function LinkitLukemattomiin(aiheet) {
  294.         for (var i=0;i<aiheet.length;i++) {
  295.             var ketjuID=findThreadID.exec(aiheet[i].innerHTML);    
  296.             if (ketjuID && ketjuID[1]) {
  297.                 var lkmE=getElementsByClassName("jive-msg-count",aiheet[i]);               
  298.                 if (lkmE[0]) {
  299.                     var vastauksiaKetjussa=trimmaa(lkmE[0].innerHTML);
  300.                     var aihe=getElementsByClassName("jive-thread-name",aiheet[i]);             
  301.                     if(aihe[0]) {                  
  302.                         var luettuja=HaeLuettujenLkm(ketjuID[1]);                  
  303.                         var viestiID=HaeViimeinenLuettu(ketjuID[1]);       
  304.                         var lukematta=vastauksiaKetjussa-(-1)-luettuja;
  305.                         var newElement = document.createElement('a');
  306.                         var luettuja15=parseInt(luettuja/15)*15;                       
  307.                         newElement.href="thread.jspa?threadID="+ketjuID[1]+"&tstart=0"
  308.                         if (luettuja15>0) newElement.href+="&start="+luettuja15;//+"#"+viestiID; //http://keskustelu.kauppalehti.fi/5/i/keskustelu/message.jspa?messageID=3995696#3995696
  309.                         // Välillä palvelimen pääsivu antaa liian pieniä viestimääriä, tämä estää hämmentävät negatiiviset luetut
  310.                         if(lukematta<0) lukematta=0;
  311.                         newElement.innerHTML="Uusia&nbsp;"+lukematta;
  312.                         if (lukematta>0) {
  313.                             if (luettuja>0) {
  314.                                 newElement.className="GMlukemattomia";
  315.                                 //if (aihe[0]) aihe[0].appendChild(newElement);
  316.                                 aihe[0].insertBefore(newElement,aihe[0].firstChild.nextSibling.nextSibling.nextSibling);
  317.                             } else {
  318.                                 //newElement.innerHTML="Uusi";
  319.                                 //newElement.className="GMuusi";
  320.                                 //if (aihe[0]) aihe[0].insertBefore(newElement,aihe[0].firstChild);
  321.                             }                          
  322.                         } else {
  323.                             newElement.className="GMkaikkiluettu";
  324.                             var linkit=aiheet[i].getElementsByTagName("a");
  325.                             aiheet[i].className+=" GMkaikkiluettu";
  326.                             for (var j=0;j<linkit.length;j++) {
  327.                                 linkit[j].className="GMkaikkiluettu";
  328.                             }
  329.                         }
  330.                     }
  331.                 }
  332.             }      
  333.         }
  334.     }
  335.        
  336.     // Poista ylimääräiset välilyönnit tekstin alusta ja lopusta
  337.     function trimmaa(str) { return str.replace(/^\s+|\s+$/g,""); }
  338.    
  339.     // Lisää sivulle lapsielementti after-lapsielementin perään
  340.     function insertAfter(after, newNode ) {
  341.         if (after.nextSibling) {
  342.             after.parent.insertBefore(newNode, after.nextSibling);
  343.         } else {
  344.             after.parent.appendChild(newNode)
  345.         }
  346.     }
  347.    
  348.     // Merkitse muistiin ketjun viimeinen luettu viesti ja luettujen lukumäärä
  349.     // Pakolla=true asettaa tiedot myös vaikka ne olisivat tyhjät tai viestinumero olisi pienempi kuin viimeisin
  350.     function MerkitseLuetuksi(threadID,messageID,lkm,pakolla) {    
  351.         var o=Ketjut[threadID];
  352.         if (o!=null) {
  353.             if (o[0]<messageID||pakolla) o[0]=messageID;
  354.             if (o[1]<lkm||pakolla) o[1]=lkm;
  355.         } else {
  356.             o=[messageID,lkm];
  357.             Ketjut[threadID]=o;
  358.         }
  359.         GM_setValue("ketjut",uneval(Ketjut));
  360.     }
  361.    
  362.     // Hae ketjun viimeisen luetun viestin tunnusnumero
  363.     function HaeViimeinenLuettu(threadID) {
  364.         var o=Ketjut[threadID];
  365.         if (o==null) return "";
  366.         return o[0];
  367.     }
  368.    
  369.     // Hae ketjun luettujen viestin lukumäärä
  370.     function HaeLuettujenLkm(threadID) {
  371.         var o=Ketjut[threadID];
  372.         if (o==null) return "";
  373.         return o[1];
  374.     }
  375.        
  376.     function addGlobalStyle(css) {
  377.          var head, style;
  378.          head = document.getElementsByTagName('head')[0];
  379.          if (!head) { return; }
  380.          style = document.createElement('style');
  381.          style.type = 'text/css';
  382.          style.innerHTML = css;
  383.          head.appendChild(style);
  384.     }
  385.  
  386. } //<-- RomInit() loppuu
  387.  
  388. // Hae sivulta annetun luokan lapsielementit luokan nimen perusteella
  389. function getElementsByClassName(classname, node) {
  390.     // Hae koko sivulta jos nodea ei annettu
  391.     if(!node) node = document.getElementsByTagName("body")[0];
  392.     var a = [];
  393.     var re = new RegExp('\\b' + classname + '\\b');
  394.     var els = node.getElementsByTagName("*");
  395.     // Käy läpi kaikki sivun elementit
  396.     for(var i=0,j=els.length; i<j; i++)
  397.         // jos elementti vastaa hakua lisää se listalle
  398.         if(re.test(els[i].className))a.push(els[i]);
  399.     return a;
  400. }
  401.  
  402. function plussaa(nimi,vote) {
  403.     var oli=false;
  404.     var pisteet=vote;
  405.     var oli=Nimimerkit[nimi];
  406.     if (!isNaN(oli)) pisteet+=oli;
  407.     Nimimerkit[nimi]=pisteet;
  408.     GM_setValue("nimimerkit", uneval(Nimimerkit));
  409.     return pisteet;
  410. };
  411.  
  412. function nayta(box,pisteet) {
  413.     var pts=getElementsByClassName("GMVotePts",box);
  414.     pts[0].innerHTML=pisteet;
  415. }
  416.  
  417. // Seuraa sivulla tapahtuvia + ja - painalluksia
  418. document.addEventListener('click', clickf,false);
  419.  
  420. function clickf(event) {
  421.     var t=event.target;
  422.     if(!t) return;
  423.     // Älä välitä muista painalluksista kuin + ja - nappeihin osuneista
  424.     if("GMVotePlus"==t.className) { nayta(t.parentNode,plussaa(t.title,1));}
  425.     if("GMVoteMinus"==t.className) { nayta(t.parentNode,plussaa(t.title,-1));}
  426. };
  427. RomInit=null;
  428. // LOPPU
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement