Обратный инженер javascript веб-сайт с Python - PullRequest
0 голосов
/ 03 апреля 2020

Я пытаюсь перепроектировать сайт, который заполняет свой код, выполняя jquery javascript, чтобы очистить его.

Я уже справился с этой проблемой, используя селен, но, как и я, я собираюсь выполнить на многих браузерах параллельно, сохраняя их открытыми от 1 до 2 часов, и это слишком дорого, поэтому мне нужно что-то очень светлее.

Я пытался использовать запросы для вызова скрытого XHR, но у этого веб-сайта их нет, полагаясь заполнить страницу довольно длинным скриптом. Это то, что вы получаете, если проверяете исходный код.

<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><meta name="format-detection" content="telephone=no"/><meta name="google" content="notranslate"/><link rel="shortcut icon" href="/favicons/main-favicon.ico" type="image/x-icon"/>

**<script>...</script>**

<title>bet365 - Apuestas deportivas en la red</title>
<meta description="bet365 - La empresa de apuestas deportivas en línea más popular del mundo. El servicio en directo más completo. Vea Deportes en directo. 'Imágenes en directo' disponibles en el PC, dispositivo móvil y tableta. Apueste en Deportes. Apueste en Deportes ahora, incluido fútbol, tenis y baloncesto."\>
<meta keywords="Apuestas en deportes, apuestas en directo, imágenes en directo, mejores precios garantizados, bonus del 100% en fútbol, apostar, fútbol partidos destacados, Premier League, Champions League, Juegos"\>
<meta name="HandheldFriendly" content="true" />
<meta name="viewport" id="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=0, width=device-width, viewport-fit=cover" />
<meta name="apple-touch-fullscreen" content="YES" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-capable" content="YES" />
<meta name="format-detection" content="telephone=no" />
</head>
<body style="background-color:#585858;">

<div id="__-LoadingIcon"></div>

</body>
</html>

Если я не ошибаюсь, то, что фактически загружает данные, находится внутри тегов скрипта, а это

(function(){if ("WebkitAppearance" in document.documentElement.style && ["zh", "zh-TW", "zh-CN", "zh-HK", "ja", "ko"].indexOf(navigator.language)>-1) document.getElementsByTagName("html")[0].className += " asia-browser";})();
var Modernizr = {};
var _websiteManifest = {"modulesInformation":{"MiniMatchLiveRugbyLeagueModule":{"loadLanguage":true,"deps":["gen5base","MiniMatchLiveLib"],"version":"4","loadCSS":false},"AudioPlayerModule":{"loadLanguage":true,"deps":["gen5base","LegacyUILib","WebConsoleLib","LiveViewLib","MediaPlayerCoreLib","InPlayViewLib","MediaLib","NavLib","SitePreferencesLib"],"version":"134","loadCSS":true},... REALLY LONG DICTIONARY, HIT MAXIMUM CHARACTERS IN THE POST...,"loadLanguage":false,"deps":["gen5base","BetslipCoreLib","BetslipStandardLib","BetslipUiLib","BetCalculationsLib","WebConsoleLib","MatchAlertsLib","SitePreferencesLib","LegacyLoginLib","PostBootLib","BetslipStandardUILib"],"version":"14","loadCSS":true},"LegacyInstantGamesModule-Default":{"loadLanguage":false,"deps":["gen5base"],"version":"2","loadCSS":false}},"version":"2434","timestamp":"Thu, 02 Apr 2020 16:04:34 GMT"}; var ns_weblib_util = {"WebsiteConfig":{"BLOB_LOCATION":"/Api/1/Blob?","SITE_CONFIG_LOCATION":"/defaultapi/sports-configuration","API_LOCATION":"/SportsBook.API/web","BETS_WEBAPI_LOCATION":"/BetsWebAPI","CONNECTION_DETAILS":["wss://premws-pt3.365lpodds.com,443,3","https://premlp-pt3.365lpodds.com,443,2"],"PRIVATE_CONNECTION_DETAILS":["wss://pshudws.365lpodds.com,443,3","https://pshudlp.365lpodds.com,443,2"],"IS_TLS_FORCED":true}}; var SITE_ROOT_PATH="sports";
function GetCookieAttributeValue(e,t){var n,o,i,r,a,s,l,u=null,c=document.cookie.split(";");for(r=0,a=c.length;a>r;r++)if(i=c[r],o=i.indexOf("="),n=i.substr(0,o),n=n.replace(/^\s+|\s+$/g,""),n==e){if(u=i.substr(o+1),t)for(s=u.split("&"),l=0;l<s.length;l++)if(t==s[l].split("=")[0]){u=s[l].split("=")[1];break}u=encodeURIComponent(u);break}return u}function CB64(e){for(var t,n=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","%2b","/"],o=[],i=0,r=0,a=0;4096>a;)t=n[i]+n[r],(a+1)%64==0&&(i++,r=-1),o[a]=t,r++,a++;return e.COUNTRY_GROUP_ID_B64=o[parseInt(e.COUNTRY_GROUP_ID)],e.COUNTRY_ID_B64=o[1024+parseInt(GetCookieAttributeValue("aps03","ct"))],e.COUNTRY_STATE_ID_B64=o[2048+parseInt(e.COUNTRY_STATE_ID)],!1}var boot,SITE_ROOT_PATH="sports";!(function(e){function t(){var e;if(-1!=navigator.userAgent.indexOf("Chrome")){for(e=1;29>=e;e++)if(-1!=navigator.userAgent.indexOf("Chrome/"+e+"."))return!0;return!1}if(-1!=navigator.userAgent.indexOf("Firefox")){for(e=1;27>=e;e++)if(-1!=navigator.userAgent.indexOf("Firefox/"+e+"."))return!0;return!1}if(-1!=navigator.userAgent.indexOf("Safari/")){for(e=1;7>=e;e++)if(-1!=navigator.userAgent.indexOf("Version/"+e+"."))return!0;return!1}return-1!=navigator.userAgent.indexOf("MSIE 10.")||-1!=navigator.userAgent.indexOf("MSIE 9.")||-1!=navigator.userAgent.indexOf("MSIE 8.")||-1!=navigator.userAgent.indexOf("MSIE 7.")||-1!=navigator.userAgent.indexOf("MSIE 6.")||-1!=navigator.userAgent.indexOf("MSIE 5.")}function n(){var e;if(-1!=navigator.userAgent.indexOf("Chrome")){for(e=1;29>=e;e++)if(-1!=navigator.userAgent.indexOf("Chrome/"+e+"."))return!0;return!1}if(-1!=navigator.userAgent.indexOf("Firefox")){for(e=1;23>=e;e++)if(-1!=navigator.userAgent.indexOf("Firefox/"+e+"."))return!0;return!1}if(-1!=navigator.userAgent.indexOf("Safari/")){for(e=1;6>=e;e++)if(-1!=navigator.userAgent.indexOf("Version/"+e+"."))return!0;return!1}return-1!=navigator.userAgent.indexOf("MSIE 9.")||-1!=navigator.userAgent.indexOf("MSIE 8.")||-1!=navigator.userAgent.indexOf("MSIE 7.")||-1!=navigator.userAgent.indexOf("MSIE 6.")||-1!=navigator.userAgent.indexOf("MSIE 5.")}function o(e,t,n){var o,r,a,l;void 0===n&&(n=-1),a=!1,l=new XMLHttpRequest,n>-1?o=n:(o=F++,r=setTimeout((function(){i(e,t,o,"100")}),6e3)),l.onreadystatechange=function(n){4!=l.readyState||a||(a=!0,l.onreadystatechange=null,r&&(clearTimeout(r),r=null),200==l.status?s(e,l.responseText,t,o):i(e,t,o,"125"))},l.open("GET",e,!0),l.send("")}function i(e,t,n,i){P[n].retryAttempt<5?("100"==i?L("Timeout from Blob, retrying attempt #"+ ++P[n].retryAttempt+" on "+e):"125"==i?L("Invalid response from Blob, retrying attempt #"+ ++P[n].retryAttempt+" on "+e):"150"==i&&L("Invalid file count returned from Blob, retrying attempt #"+ ++P[n].retryAttempt+" on "+e),window.caches&&ee?r(e,t,n):o(e,t,n)):L("Failed to load Blob 5 - Stopping")}function r(e,t,n){var o,r;void 0===n&&(n=-1),e!=E&&(n>-1?o=n:(o=F++,r=setTimeout((function(){i(e,t,o,"100")}),6e3)),caches.open(SITE_ROOT_PATH.toLowerCase()+"-blobCache").then((function(n){n.keys().then((function(s){var u,c,f,d,g,p=e.split("|");for(p[0]=p[0].split(",")[2],u=[],c=new Array(p.length),f=[],d=function(e){var t=p[e],o=e;f.push(n.match(new Request(t.split("/")[0])).then((function(e){var n=t.split("/")[2].indexOf("L")>-1;return!e||n&&e.headers.get("x-365-language")!==y||e.headers.get("x-365-version")!==t.split("/")[1]?(u.push(t),t):(c[o]=e,t)})))},g=0;g<p.length;g++)d(g);Promise.all(f).then((function(n){u.length?(fetch(E+u.join("|")).then((function(n){r&&(clearTimeout(r),r=null),n.ok?a(u,n).then((function(n){var i,r;for(i=0;i<n.length;i++)for(r=0;r<p.length;r++)if(n[i].headers.get("x-365-key")===p[r].split("/")[0]){c[r]=n[i];break}l(e,c,t,o)})):i(e,t,o,"125")})),c.length&&l(e,c,t,o)):(r&&(clearTimeout(r),r=null),l(e,c,t,o))}))["catch"]((function(n){ee=!1,r&&(clearTimeout(r),r=null),i(e,t,o,"125")}))}))["catch"]((function(n){ee=!1,r&&(clearTimeout(r),r=null),i(e,t,o,"125")}))}))["catch"]((function(n){ee=!1,r&&(clearTimeout(r),r=null),i(e,t,o,"125")})))}function a(e,t){return t.text().then((function(t){var n,o,i,r=t.split(""),a=0,s=[],l=function(e){var t,n,o,i,l,u=r[a];for(a++,t=e.split("/")[2]||"",n=0,o=t;n<o.length;n++)i=o[n],"S"!==i&&"L"!==i||(u=u+""+r[a],a++);l=new Headers({"x-365-language":y,"x-365-version":e.split("/")[1],"x-365-key":e.split("/")[0]}),s.push(new Response(u,{headers:l})),caches.open(SITE_ROOT_PATH.toLowerCase()+"-blobCache").then((function(t){var n=new Response(u,{headers:l});t.put(new Request(e.split("/")[0]),n)}))};for(n=0,o=e;n<o.length;n++)i=o[n],l(i);return s}))}function s(e,t,n,o){function r(){return"performance"in window&&"now"in performance?performance.now():+new Date}var a,l,c,f,d,g,p,h,m,b,w,v,A,x,O,C,S,T,_,L,y;if(o!==G)return void U.push([e,t,n,o]);if(a=4,l=5,c=r(),f=t.split(""),f.length-1!==P[o].expectedFiles)return i(e,n,o,"150");for(d=document.head||document.getElementsByTagName("head")[0],g=[],J="",p=0,h=f;p<h.length;p++)if(m=h[p],b=m.charCodeAt(0),m=m.slice(1))if(g[g.length]=Number(Number(m.length/1e3).toFixed(2)),b==a){w=document.createElement("script"),w.type="text/javascript",w.setAttribute("charset","UTF-8");try{w.appendChild(document.createTextNode(m))}catch(E){w.text=m}d.appendChild(w)}else b==l&&u(m,d);for(J&&u(J,d),I(g.length+" files. "+Number(t.length/1024).toFixed(2)+"kb. Parsed in "+Number(r()-c).toFixed(2)+"ms. Breakdown(kb): ("+g.join(", ")+")"),v=0,A=n;v<A.length;v++){x=A[v];try{x&&x()}catch(E){}}for(G++,O=0,C=U.length;C>O;O++)if(S=U[O],T=S[0],_=S[1],L=S[2],y=S[3],y===G){U.splice(O,1),s(T,_,L,y);break}Locator&&Locator.validationManager.processValidationCycleNow()}function l(e,t,n,o){var r,a,s,c,f=function(){return"performance"in window&&"now"in performance?performance.now():Date.now()};if(o!==G)return void D.push([e,t,n,o]);if(!z){for(z=!0,r=[],a=!0,s=Z;s<t.length;s++){if(!t[s]){a=!1,Z=s;break}r.push(t[s].text())}if(a&&(Z=0),!r.length)return void(z=!1);c=[],Promise.all(r).then((function(r){var a,s,d,g,p,h,m,b,w,v,A,x,O,C,S,T,_,L,y,E,B,M,N,R,k,F,H=f();for(a=0,s=r;a<s.length;a++)for(d=s[a],g=d.split(""),p=0,h=g;p<h.length;p++)m=h[p],c.push(m);if(b=c.length+$!==P[o].expectedFiles)$+=c.length;else if(c.length+$!==P[o].expectedFiles)return i(e,n,o,"150");for(w=document.head||document.getElementsByTagName("head")[0],v=0,A=c;v<A.length;v++)if(d=A[v],x=d.charCodeAt(0),d=d.slice(1))if(X[X.length]=Number(Number(d.length/1024).toFixed(2)),4==x){O=document.createElement("script"),O.type="text/javascript",O.setAttribute("charset","UTF-8");try{O.appendChild(document.createTextNode(d))}catch(V){O.text=d}w.appendChild(O)}else 5==x?u(d,w):u(d,w);for(C=0,S=X;C<S.length;C++)T=S[C],Q+=T;if(K+=Number(f()-H),b&&(z=!1,0!==Z&&l(e,t,n,o)),!b){for(I(X.length+" files. "+Number(Q).toFixed(2)+"kb. Parsed in "+K.toFixed(2)+"ms. Breakdown(kb): ("+X.join(", ")+")"),_=0,L=n;_<L.length;_++){y=L[_];try{y&&y()}catch(V){}}for($=0,Q=0,K=0,X=[],Z=0,z=!1,G++,E=0,B=D.length;B>E;E++)if(M=D[E],N=M[0],R=M[1],k=M[2],F=M[3],F===G){U.splice(E,1),l(N,R,k,F);break}"Locator"in window&&Locator.validationManager.processValidationCycleNow()}}))}}function u(e,t){var n=document.createElement("style");n.type="text/css",t.appendChild(n),n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e))}function c(e){S=e}function f(e){T=e}function d(e,t){var n,o=0;return N&&(N=!1,"Locator"in window&&Locator.validationManager.callLater(h)),n=_websiteManifest.modulesInformation[e],n&&(P[F]||(P[F]={expectedFiles:0,retryAttempt:0}),B!=E&&(B+="|"),B+=e,P[F].expectedFiles++,(location.toString().indexOf(":3")>-1||location.toString().indexOf("/local_")>-1)&&(n.version="debug"),B+="/"+n.version+"/",n.loadCSS&&(B+="S",P[F].expectedFiles++,o|=_.CSS),n.loadLanguage&&(B+="L",P[F].expectedFiles++,o|=_.LANGUAGE),t&&M.push(t)),o}function g(t){if(e.isAppRequest||W){var n=_websiteManifest.modulesInformation[t];n&&n.app&&d(t+"-App")}return d(t)}function p(){var e,t,n,o;for(e=0,t=H;e<t.length;e++)if(n=t[e],-1!==location.hostname.toLowerCase().indexOf(n.domain))return n.locale;return o=GetCookieAttributeValue("aps03","ct"),V[o]||"Default"}function h(){N=!0,window.caches&&ee?r(B,M.concat()):o(B,M.concat()),B=E,M.length=0}function m(){d("gen5base",v),d("WebConsoleLib"),d("NavLib"),d("SitePreferencesLib"),d("LoginLib"),d("PodLib"),d("ScrollerLib"),d("GridLoaderLib"),g("WebConsoleModule"),d("HeaderModule"),d("PodLoaderModule")}function b(){d("gen5base",v),d("WebConsoleLib"),d("AppConsoleLib"),d("NavLib"),d("SitePreferencesLib"),d("PodLib"),d("GridLoaderLib"),d("AppConsoleModule"),d("PodLoaderModule")}function w(e,t){try{window.webkit.messageHandlers[e].postMessage(t)}catch(n){I(n.name+" "+n.message)}}function v(){document.body||document.getElementsByTagName("body")[0]?(k=!0,A()):setTimeout(v,0)}function A(){if(R&&k){var e="";ne.length>0?e=te.join("")+String.fromCharCode(46)+ne.join(""):S&&T&&(e=S+String.fromCharCode(46)+T),W?ns_appconsolelib.EndBootSequence(e):ns_webconsolelib.EndBootSequence(e)}}function x(e){var t,n,o,i,r;void 0===e&&(e=0),n=!1,o=new XMLHttpRequest,i=GetCookieAttributeValue("aps03","lng"),t=setTimeout((function(){O(e,"100")}),6e3),o.onreadystatechange=function(r){4!=o.readyState||n||(n=!0,o.onreadystatechange=null,t&&(clearTimeout(t),t=null),200==o.status?C(o.responseText,i):O(e,"125"))},r=ns_weblib_util.WebsiteConfig.SITE_CONFIG_LOCATION,e>0&&(r=r.indexOf("?")>-1?r+"&rt="+e.toString():r+"?rt="+e.toString()),o.open("GET",r,!0),o.send("")}function O(e,t){5>e?("100"==t?L("Timeout from config, retrying attempt #"+ ++e):"125"==t&&L("Invalid response from config, retrying attempt #"+ ++e),x(e)):L("Failed to load config 5 - Stopping")}function C(e,t){var n,o,i;if(!R){if("redirectto:"==e.substr(0,11))return void(window.location.href=e.substr(11));if(n=GetCookieAttributeValue("aps03","lng"),n!=t)return void window.location.reload();W&&w("sportsconfig",e),o=JSON.parse(e),window.flashvars=o.flashvars,CB64(window.flashvars);for(i in o.ns_weblib_util.WebsiteConfig)ns_weblib_util.WebsiteConfig[i]=o.ns_weblib_util.WebsiteConfig[i];R=!0,A()}}var S,T,_,I,L,y,E,B,M,N,R,k,F,G,P,U,D,H,V,W,Y,j,q,J="",X=[],K=0,Q=0,Z=0,z=!1,$=0,ee=!0,te=[],ne=[];!(function(e){e.LANGUAGE=1,e.CSS=2})(_=e.LoadingFlags||(e.LoadingFlags={})),I=function(){if("console"in window){Array.prototype.splice.call(arguments,0,0,"BLOB>");try{console.log("%c "+Array.prototype.join.call(arguments,"  "),"color:#222; background-color: #4acfa5; line-height: 24px; font-weight:bold;")}catch(e){console.log(Array.prototype.join.call(arguments,"  "))}}},L=function(e){try{window.ns_gen5_util.InfoReporter?window.ns_gen5_util.InfoReporter.Trace("BLOB",e):I(e)}catch(t){I(e)}},y=GetCookieAttributeValue("aps03","lng"),E=ns_weblib_util.WebsiteConfig.BLOB_LOCATION+(y||"1")+","+SITE_ROOT_PATH+",",B=E,M=[],N=!0,R=!1,k=!1,F=0,G=0,P={},U=[],D=[],e.isAppRequest="bet365AndroidApp"in window||"webkit"in window&&"messageHandlers"in window.webkit,e.ab=c,e.cd=f,e.ef=(function(){var e=0,t=0,n=0;return function(o){e%2!=0&&(2>t?te[t++]=o:3>n&&(ne[n++]=o)),e++}})(),e.loadModule=d,H=[{domain:".nj.",locale:"NJ"},{domain:".dk",locale:"DK"},{domain:".com.au",locale:"AU"},{domain:".it",locale:"IT"},{domain:".gr",locale:"GR"},{domain:".es",locale:"ES"},{domain:".mx",locale:"MX"},{domain:".com.cy",locale:"CY"},{domain:".ee",locale:"EE"}],V={2:"AF",5:"AS",6:"AD",7:"AI",9:"AG",10:"AR",18:"BD",19:"BB",20:"BY",21:"BZ",22:"BE",23:"BJ",24:"BM",25:"BO",26:"BA",28:"BR",29:"VG",31:"BG",33:"BI",41:"CL",42:"CN",44:"CO",47:"CR",49:"CU",57:"DO",58:"EC",60:"SV",70:"FR",75:"DE",80:"GU",82:"GT",85:"GA",87:"HN",91:"IN",92:"ID",93:"IQ",94:"IR",96:"IL",112:"LY",116:"MO",126:"MX",139:"NI",146:"PS",147:"PA",149:"PY",150:"PE",154:"PR",156:"RO",174:"CH",175:"SD",181:"SE",182:"SY",190:"TR",197:"GB",198:"US",199:"UY",200:"VI",203:"VE",212:"TW",218:"GL",246:"MP"},e.getLocale=p,W=navigator.userAgent.indexOf(" Gen6 ")>-1,Y=ns_weblib_util.WebsiteConfig.IS_TLS_FORCED?t:n,Y()?-1!=navigator.userAgent.indexOf("MSIE 7.")||-1!=navigator.userAgent.indexOf("MSIE 6.")||-1!=navigator.userAgent.indexOf("MSIE 5.")?window.location.href="/sports-assets/"+SITE_ROOT_PATH+"/WebConsoleModule/assets/UnsupportedBrowserIE.html":window.location.href="/sports-assets/"+SITE_ROOT_PATH+"/WebConsoleModule/assets/UnsupportedBrowser.html":(j=m,W&&(j=b,ns_weblib_util.WebsiteConfig.DOMAIN=location.origin+location.pathname,w("websiteconfig",JSON.stringify(ns_weblib_util.WebsiteConfig))),j(),h(),window.flashvars?(R=!0,A()):x()),q=window,q.ns_testharness={TestHarness:function(){}},q.ns_testharness_events={StemTreeViewEvent:function(){}},q.ns_testharness_ui={StemTreeView:function(){}},q.StubLookup={},q.Harness_main=function(){}})(boot||(boot={}));!function(){var _,D={};D["w2vf3lD"+"pu3="]="0dM6yjNJ"+"T7r+Mh6=",D["5LqPIz"+"4kRr="]="n"+"q=",D["KgC"+"3FKGy2C"]="ZQS8QE9"+"mKXwl",D["nvld"+"y6fdlp=="]="dx"+"0j",D["E6OCOj"+"AfCQ"]="wsp1f"+"JU7kpqH=",D["XcEYZYz"+"x58=="]="e/F82Xs"+"T+MiuAY",D["2fG6"+"yCcKL9=="]="fc7F"+"RyE5ps0v",D["gw0i2R"+"VQKh"]="oKLqTI"+"9vPOlv=",D["923"+"HyXHnVX"]="t1Swy",D["D9cHu"+"F77Bl="]="AxsrFyY"+"acnju=",D["CQN"+"1yFFjHL"]="aW"+"==",D["FRMUr"+"tPcqA="]="863PRHS"+"kgfM00l",D["iFlOI"+"xkED9=="]="sIZPfU"+"1zx6iM",A=["923"+"HyXHnVX","nvld"+"y6fdlp==","D9cHu"+"F77Bl=","CQN"+"1yFFjHL","E6OCOj"+"AfCQ","XcEYZYz"+"x58==","2fG6"+"yCcKL9==","FRMUr"+"tPcqA=","gw0i2R"+"VQKh","w2vf3lD"+"pu3=","5LqPIz"+"4kRr=","KgC"+"3FKGy2C","iFlOI"+"xkED9==",],R=(_=0,function(){return D[A[_++]]});!function(){if(boot&&boot.ef)for(var _=0;_<A.length;_++)boot.ef(R())}()}();
</script>

Я не могу понять, как к этому подойти. Я выучил основы c javascript, поэтому я в некоторой степени могу понять структуру и грамматику, но помимо этого, как я собираюсь расшифровать, что это делается? Даже если я это сделаю, как мне скопировать ее в Python, чтобы получить данные?

Если я сохраню страницу в файле html и попытаюсь открыть ее в браузере, она не не показывать мне страницу, но больше похоже на предыдущий шаг, когда она начала бы загружаться при обычном просмотре веб-страниц.

Так что мои вопросы будут

Как бы вы подошли к этому анализу, учитывая его потребности? быть легче селена? Что мне нужно искать, чтобы перепроектировать это? Я широко просматривал inte rnet и не могу найти ничего полезного

Для тех из вас, кто действительно хочет посетить веб-сайт , нажмите здесь

...