Advertisement
Guest User

Untitled

a guest
Sep 29th, 2018
269
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.45 KB | None | 0 0
  1. /* Tools Menu */
  2.  
  3. function create() {
  4. const footer = document.getElementById('footer')
  5. footer.classList.add('disabled','zeig');
  6. var spanT = document.createElement('span');
  7. var divT = document.createElement('div');
  8. divT.id = 'droptool';
  9. var btnT = document.createElement('button');
  10. btnT.id = 'tools';
  11. btnT.classList.add('button-toolbar');
  12. btnT.setAttribute('tabindex', '-1');
  13. btnT.setAttribute('title', 'Tools');
  14. btnT.innerHTML = '<svg width="26" height="26" viewBox="-150 -150 812 812" xmlns="http://www.w3.org/2000/svg"><path d="M483.97,105.709c-2.491-9.958-14.903-13.424-22.157-6.165l-58.913,58.914c-13.083,13.077-34.291,13.077-47.372,0 l-27.03-27.031c-13.082-13.081-13.082-34.289,0-47.372l58.196-58.197c7.307-7.307,3.751-19.838-6.306-22.193 c-13.772-3.218-28.327-4.406-43.339-3.208c-64.522,5.148-123.907,65.649-127.923,130.254c-1.521,24.503,3.43,47.667,13.077,68.186 L16.253,375.878c-9.263,7.96-14.81,19.401-15.323,31.602c-0.519,12.201,4.042,24.068,12.599,32.78l34.902,35.541 c8.64,8.802,20.57,13.586,32.899,13.19c12.33-0.399,23.928-5.936,31.986-15.271l178.388-206.684 c19.917,8.889,42.21,13.424,65.747,11.956c65.041-4.058,125.554-63.92,130.29-128.91 C488.863,134.686,487.482,119.777,483.97,105.709z"></path>';
  15. var infdiv = document.createElement('div');
  16. infdiv.id = 'divID';
  17. infdiv.innerHTML = '<button id="toggle-links" title="Hide Status Info" class="button-toolbar-small" tabindex="-1"><svg width="16" height="16" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"><path d="M17.6 20.4l-1.6 1.6-9-9 9-9 1.6 1.6-7.2 7.4 7.2 7.4z" fill="var(--colorHighlightBg)"></path></svg></button>';
  18. adr.insertBefore(spanT,document.querySelector('.searchfield').nextSibling);
  19. spanT.appendChild(btnT);
  20. spanT.appendChild(divT);
  21. divT.appendChild(footer);
  22. footer.appendChild(infdiv);
  23. };
  24.  
  25. function cssT() {
  26. var styleS = document.createElement('style');
  27. styleS.type = 'text/css';
  28. styleS.innerHTML = '#droptool {position: absolute;z-index: 1;right: 0;box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);}.callout {bottom: unset;margin-top: 1px;}.callout::before, .callout::after {display: none;}#divID {order: 1 }.sync-status {order: 2;}.status-toolbar {order: 3;}#footer {border-right: none;}#status_info {display: none;}#footer.zeig #status_info.visible {display: flex;max-width: 500px;}.paneltogglefooter {display: none !important;}';
  29. document.getElementsByTagName('head')[0].appendChild(styleS);
  30. };
  31.  
  32. function menuT() {
  33. if (footer.classList.contains('disabled')) {
  34. footer.classList.remove('disabled');
  35. }
  36. else {
  37. footer.classList.add('disabled');
  38. }
  39. };
  40.  
  41. function statusT() {
  42. const fill = document.querySelector('#toggle-links svg path');
  43. const infbtn = document.getElementById('toggle-links');
  44. if (footer.classList.contains('zeig')) {
  45. footer.classList.remove('zeig');
  46. fill.setAttribute('fill', 'var(--colorFg)');
  47. infbtn.setAttribute('title', 'Show Status Info');
  48. }
  49. else {
  50. footer.classList.add('zeig');
  51. fill.setAttribute('fill', 'var(--colorHighlightBg)');
  52. infbtn.setAttribute('title', 'Hide Status Info');
  53. }
  54. };
  55.  
  56. function toolsMenu() {
  57. create();
  58. cssT();
  59. document.getElementById('tools').addEventListener('click', menuT);
  60. document.getElementById('toggle-links').addEventListener('click', statusT);
  61. };
  62.  
  63. setTimeout(function wait() {
  64. adr = document.querySelector('.toolbar-addressbar.toolbar');
  65. if (adr) {
  66. toolsMenu();
  67. }
  68. else {
  69. setTimeout(wait, 300);
  70. }
  71. }, 300);
  72.  
  73. /*
  74. * Panel Actions (A Mod for Vivaldi)
  75. * LonM.vivaldi.net
  76. * No Copyright Reserved
  77. */
  78.  
  79. (function panel_actions(){
  80. "use strict";
  81.  
  82. const ZOOM_STEP = 0.1; /*Step amount. 0.1 is 10%*/
  83.  
  84. /*
  85. Dictionary of panel actions.
  86. They will be added to the toolbar in the order specified below.
  87. key must be unique
  88. title: string for tooltip
  89. script: (target, webview) => {}: void. target is button that was clicked. webview is the webview attached to the button
  90. for content scripts, Call doContentScript with the webview and a () => {}: void
  91. display: string of html - The innerHTML of the toolbar button
  92. display_class: string - One or more classes to give the button
  93. */
  94. const ACTIONS = {
  95.  
  96. zoom_out: {
  97. title: "Decrease zoom",
  98. script: function(target, webview){
  99. webview.getZoom(current => {
  100. changeZoom(webview, current -= ZOOM_STEP);
  101. });
  102. },
  103. display: `-`,
  104. display_class: `zoom-out`
  105. },
  106.  
  107. zoom_reset: {
  108. title: "Set zoom to 100%",
  109. script: function(target, webview){
  110. changeZoom(webview, 1);
  111. },
  112. display: `100%`,
  113. display_class: `zoom-reset`
  114. },
  115.  
  116. zoom_in: {
  117. title: "Increase zoom",
  118. script: function(target, webview){
  119. webview.getZoom(current => {
  120. changeZoom(webview, current += ZOOM_STEP);
  121. });
  122. },
  123. display: `+`,
  124. display_class: `zoom-in`
  125. },
  126.  
  127. invert: {
  128. title: "Invert the colours on the page",
  129. script: function(target, webview){
  130. doContentScript(webview, () => {
  131. const style_element = document.createElement('style');
  132. style_element.innerHTML = `
  133. html { background-color: white;}
  134. body.inverted {filter: invert(1) hue-rotate(180deg);}
  135. body.inverted img,
  136. body.inverted video {filter: invert(1) hue-rotate(180deg);}`;
  137. document.body.appendChild(style_element);
  138. document.body.classList.toggle("inverted");
  139. });
  140. },
  141. display: `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg">
  142. <path d="M 7.984375 0 A 7.9850645 7.9850645 0 0 0 0 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 15.970703 A 7.9850645 7.9850645 0 0 0 15.970703 7.984375 A 7.9850645 7.9850645 0 0 0 7.984375 0 z M 7.9960938 0.74804688 L 7.9960938 7.984375 L 7.9960938 15.222656 A 7.2378569 7.2378569 0 0 1 1.7265625 11.603516 A 7.2378569 7.2378569 0 0 1 1.7265625 4.3652344 A 7.2378569 7.2378569 0 0 1 7.9960938 0.74804688 z " fill=""></path>
  143. </svg>`,
  144. display_class: "panel-action-invert"
  145. },
  146.  
  147. terminate: {
  148. title: "Kills the panel to free memory. WARNING! This will also kill any tabs using the same process.",
  149. script: function(target, webview){
  150. webview.terminate();
  151. },
  152. display: `x`,
  153. display_class: `panel-action-terminate`
  154. },
  155.  
  156. mute: {
  157. title: "Mute this panel",
  158. script: function(target, webview){
  159. webview.isAudioMuted(mute => {
  160. webview.setAudioMuted(!mute);
  161. target.innerHTML = mute ? `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z"></path></svg>`
  162. : `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg"><path d="m 10.425781,-0.1412354 -5.5410155,4.96094 H 0.6503908 v 4.75 h 4.1074217 l 5.6679685,5.2285204 z m 0.853516,4.1211 -0.707031,0.70703 1.917969,1.91797 -1.917969,1.91992 0.707031,0.70703 1.917969,-1.91992 1.919922,1.91992 0.707031,-0.70703 -1.919922,-1.91992 1.919922,-1.91797 -0.707031,-0.70703 -1.919922,1.91796 z"></path></svg>`;
  163. target.title = mute ? "Mute this panel" : "Panel Muted. Click to Un-Mute";
  164. });
  165. },
  166. display: `<svg viewBox="-4 -4 20 20" xmlns="http://www.w3.org/2000/svg">
  167. <path d="m 10.425781,0 -5.5410155,4.96094 h -4.234375 v 4.74805 h 4.1074219 l 5.6679686,5.23047 z m 1.767579,1.50782 v 0.59961 c 0.628524,0 1.262682,0.52233 1.751953,1.49023 0.489269,0.96789 0.804686,2.34168 0.804686,3.86133 0,1.51964 -0.315417,2.89148 -0.804686,3.85937 -0.489271,0.9679 -1.123429,1.49219 -1.751953,1.49219 v 0.59961 c 0.949262,0 1.742407,-0.74276 2.287109,-1.82031 0.544702,-1.07756 0.869141,-2.52926 0.869141,-4.13086 0,-1.60161 -0.324439,-3.05525 -0.869141,-4.13281 -0.544702,-1.07755 -1.337847,-1.81836 -2.287109,-1.81836 z m -0.921875,1.97851 v 0.59961 c 0.378754,0 0.787693,0.3227 1.113281,0.9668 0.325586,0.64409 0.539061,1.57016 0.539061,2.5957 1e-6,1.02554 -0.213475,1.95161 -0.539061,2.5957 -0.325588,0.64409 -0.734527,0.9668 -1.113281,0.9668 v 0.59961 c 0.699491,0 1.267416,-0.54311 1.648436,-1.29687 0.381021,-0.75375 0.603517,-1.75774 0.603517,-2.86524 0,-1.1075 -0.222496,-2.11344 -0.603517,-2.86719 -0.38102,-0.75375 -0.948945,-1.29492 -1.648436,-1.29492 z"></path>
  168. </svg>`,
  169. display_class: `panel-action-mute`
  170. }/*,
  171.  
  172. template: {
  173. title: "",
  174. script: function(event, webview){
  175.  
  176. },
  177. display: ``,
  178. display_class: ``
  179. },*/
  180. };
  181.  
  182. /**
  183. * Change the zoom
  184. * @param webview to update
  185. * @param zoom new zoom factor
  186. */
  187. function changeZoom(webview, zoom){
  188. webview.setZoom(zoom, () => {
  189. updateZoomLabel(webview);
  190. });
  191. }
  192.  
  193. /**
  194. * Update the zoom label
  195. * @param webview to get zoom value from
  196. */
  197. function updateZoomLabel(webview){
  198. const panelZoom = webview.parentElement.parentElement.querySelector(".zoom-reset");
  199. if(!panelZoom){
  200. console.error("[lonm-panel-actions] Panel Zoom Label Missing");
  201. return;
  202. }
  203. webview.getZoom(current => {
  204. const newValue = Math.floor(current * 100);
  205. panelZoom.innerHTML = newValue + "%";
  206. });
  207. }
  208.  
  209. /**
  210. * Inject a script as a content script
  211. * @param webview to use
  212. * @param scriptMethod Method to inject
  213. */
  214. function doContentScript(webview, scriptMethod){
  215. const scriptText = "("+scriptMethod+")()";
  216. webview.executeScript({code: scriptText});
  217. }
  218.  
  219. /**
  220. * Create a panel action button
  221. * REMARK: For some reason the button click currentTarget is not always the button
  222. * @param action object
  223. * @param webview dom object button will attach to
  224. * @returns dom object
  225. */
  226. function createActionButton(action, webview){
  227. const newBtn = document.createElement("button");
  228. newBtn.className = action.display_class+" button-toolbar-small mod-panel-action";
  229. newBtn.innerHTML = action.display;
  230. newBtn.addEventListener("click", event => {
  231. let eventSource = event.target;
  232. while(eventSource.tagName.toLowerCase()!== "button"){
  233. eventSource = eventSource.parentElement;
  234. }
  235. action.script(eventSource, webview);
  236. });
  237. newBtn.title = action.title;
  238. return newBtn;
  239. }
  240.  
  241. /**
  242. * Add the panel action controls
  243. * @param panel dom node
  244. */
  245. function addPanelControls(panel){
  246. const alreadyAdded = panel.querySelector("footer");
  247. if(alreadyAdded){return;}
  248. const footer = document.createElement("footer");
  249. const webview = panel.querySelector("webview");
  250. for(const key in ACTIONS){
  251. const action = ACTIONS[key];
  252. const newButton = createActionButton(action, webview);
  253. footer.appendChild(newButton);
  254. }
  255. panel.appendChild(footer);
  256. }
  257.  
  258. /**
  259. * upgrade a web panel by adding controls, listeners, etc.
  260. * @param panel dom node
  261. */
  262. function upgradePanel(panel){
  263. addPanelControls(panel);
  264. const webview = panel.querySelector("webview");
  265. webview.addEventListener("zoomchange", () => {
  266. updateZoomLabel(webview);
  267. });
  268. webview.addEventListener("loadcommit", () => {
  269. updateZoomLabel(webview);
  270. });
  271. }
  272.  
  273. /**
  274. * Observe changes to the panels
  275. * Remark: This will either be to upgrade a panel when it is first created
  276. * or to re-add the panel controls if removed after a panel was toggled
  277. */
  278. const PANEL_CHANGE_OBSERVER = new MutationObserver(records => {
  279. records.forEach(record => {
  280. if(record.type==="attributes"){
  281. const targetClasses = record.target.classList;
  282. if(targetClasses.contains("visible") && targetClasses.contains("webpanel")){
  283. addPanelControls(record.target);
  284. }
  285. } else if (record.type==="childList") {
  286. record.addedNodes.forEach(node => {
  287. if(node.classList && node.classList.contains("webpanel")){
  288. upgradePanel(node);
  289. }
  290. });
  291. }
  292. });
  293. });
  294.  
  295. /**
  296. * Begin observing the changes to panels
  297. * @param webPanelStack The web panel stack div
  298. */
  299. function beginObservation(webPanelStack){
  300. PANEL_CHANGE_OBSERVER.observe(webPanelStack, {
  301. attributes: true,
  302. attributeFilter: ["class"],
  303. childList: true,
  304. subtree: true
  305. });
  306. }
  307.  
  308. /**
  309. * Initialise the mod
  310. */
  311. function initMod(){
  312. const webPanels = document.querySelector("#panels");
  313. if(webPanels){
  314. beginObservation(webPanels);
  315. const alreadyOpenPanel = document.querySelector(".panel.webpanel.visible");
  316. if(alreadyOpenPanel){
  317. upgradePanel(alreadyOpenPanel);
  318. }
  319. } else { setTimeout(initMod, 500); }
  320. }
  321.  
  322. /* Start 500ms after the browser is opened */
  323. setTimeout(initMod, 500);
  324. })();
  325.  
  326. /*
  327. * Site Security Box Favicons (a mod for Vivaldi)
  328. * Written by LonM
  329. * No Copyright Reserved
  330. * This mod takes the favicon from a tab and places it into the address bar site info box
  331. * Assumes presence of both the tab bar and the address bar
  332. */
  333.  
  334. // Constant CSS Selectors
  335. const SECURITY_ZONE_ICON = "div.addressfield > button.button-addressfield.addressfield-siteinfo > div > svg";
  336. const ACTIVE_TAB = ".tab.active .favicon";
  337. const SECURITY_ZONE = "div.addressfield > button.button-addressfield.addressfield-siteinfo > div.siteinfo-symbol";
  338.  
  339. // Selectors and config for observers
  340. const BROWSER_STATE_INDICATOR = "#browser"
  341. const BROWSER_STATE_INDICATOR_CONFIG = {attributes: true}
  342. const TAB_CHANGE_INDICATOR = ".tab-strip";
  343. const TAB_CHANGE_INDICATOR_CONFIG = {attributes: true, subtree: true}
  344.  
  345. // Observer for changes to tab and browser state
  346. const browserStateChangeObserver = new MutationObserver(browser_state_changed)
  347. const differentTabActivatedObserver = new MutationObserver(tab_changed);
  348.  
  349. // The browser changed state,
  350. // May need to re-observe deleted elements
  351. // E.g. if enter and exit of fullscreen / hide UI mode
  352. function browser_state_changed(m, o){
  353. //console.log("BROWSER STATE CHANGE");
  354. remove_existing_cloned_favicon();
  355. clone_favicon_and_add_to_security();
  356. differentTabActivatedObserver.disconnect();
  357. browserStateChangeObserver.disconnect();
  358. load_favicon_security_mod();
  359. }
  360.  
  361. // The tab was changed, so favicon needs changing
  362. // this will cover changes to the .active tab AND
  363. // cover changes to the favicon span thru subtree
  364. function tab_changed(m, o){
  365. //console.log("TAB STRIP ATTRIBUTE CHANGE");
  366. clone_favicon_and_add_to_security();
  367. }
  368.  
  369. // Clone the favicon and add a copy to the security zone
  370. // also style it appropriately
  371. function clone_favicon_and_add_to_security(){
  372. // make sure everything we need to access exists
  373. const sz_icon = document.querySelector(SECURITY_ZONE_ICON);
  374. const favicon_original = document.querySelector(ACTIVE_TAB);
  375. const siteinfo = document.querySelector(SECURITY_ZONE);
  376. if(!favicon_original || !sz_icon || !siteinfo){return;}
  377. remove_existing_cloned_favicon();
  378. // copy, style and set the favicon
  379. // use deep clone to also copy svg icons
  380. const favicon = favicon_original.cloneNode(true);
  381. favicon.style.width = "16px";
  382. favicon.style.height = "16px";
  383. favicon.style.display = "block";
  384. favicon.style.margin = "3px";
  385. siteinfo.style.display = "flex";
  386. sz_icon.parentNode.insertBefore(favicon, sz_icon);
  387. }
  388.  
  389. // Remove any existing cloned favicon
  390. function remove_existing_cloned_favicon(){
  391. const old_sz_favicon = document.querySelector(SECURITY_ZONE+" .favicon");
  392. if(old_sz_favicon){
  393. old_sz_favicon.parentElement.removeChild(old_sz_favicon);
  394. }
  395. }
  396.  
  397. // Load the mod
  398. function load_favicon_security_mod(){
  399. const browser = document.querySelector(BROWSER_STATE_INDICATOR)
  400. const tab_change_indicator = document.querySelector(TAB_CHANGE_INDICATOR);
  401. if (browser && tab_change_indicator) {
  402. browserStateChangeObserver.observe(browser, BROWSER_STATE_INDICATOR_CONFIG);
  403. differentTabActivatedObserver.observe(tab_change_indicator, TAB_CHANGE_INDICATOR_CONFIG);
  404. clone_favicon_and_add_to_security();
  405. } else {
  406. setTimeout(load_favicon_security_mod, 100);
  407. }
  408. }
  409.  
  410. // BROWSER LOADED - entry point
  411. setTimeout(load_favicon_security_mod, 500);
  412.  
  413. // Fixes the white flash when navigating away from the start page and the white blank page, by setting their color to the current theme's background color.
  414. (function() {
  415. var bodyStyles, colorBg;
  416. var observer = new MutationObserver(getBgColor);
  417.  
  418. observer.observe(document.body, {
  419. attributes: true,
  420. attributeFilter: ['style']
  421. });
  422.  
  423. function getBgColor() {
  424. bodyStyles = window.getComputedStyle(document.body);
  425. colorBg = bodyStyles.getPropertyValue('--colorBg');
  426. chrome.tabs.query({}, tabs => {
  427. tabs.forEach(tab => injectScript(tab.url, tab.id));
  428. });
  429. }
  430.  
  431. chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => injectScript(tab.url, tab.id));
  432.  
  433. function injectScript(tabUrl, tabId) {
  434. if(tabUrl === "about:blank" || tabUrl === "chrome-extension://mpognobbkildjkofajifpdfhcoklimli/components/startpage/startpage.html") {
  435. var css =`
  436. * {
  437. background-color: ${colorBg} !important;
  438. }`;
  439. var addCss =
  440. `if(!cssText){
  441. var cssText = document.createElement('style');
  442. cssText.setAttribute('description', 'Added by white-flash-fix.js');
  443. }
  444. cssText.textContent = \`${css}\`;
  445. document.head.appendChild(cssText);`;
  446. chrome.tabs.executeScript(tabId, {code: addCss, allFrames: true});
  447. }
  448. }
  449. })();
  450.  
  451. /* Panel Toggle */
  452.  
  453. function panelToggle() {
  454. var panel = document.getElementById('panels-container');
  455. var paneltog = document.querySelector('.paneltogglefooter');
  456. var panelsvg = document.querySelector('.paneltogglefooter svg');
  457. var panelpath = document.querySelector('.paneltogglefooter svg path');
  458. var sright = 'd: path("M20 8v10h-14v-10h14zm-2 8v-6h-4v6h4z")';
  459. var sleft = 'd: path("M20 8v10h-14v-10h14zm-8 8v-6h-4v6h4z")';
  460. paneltog.classList.add('button-toolbar');
  461. paneltog.classList.remove('button-toolbar-small');
  462. paneltog.style.order = 'unset';
  463. panelsvg.style.transform = 'none';
  464. panelsvg.setAttributeNS(null, 'viewBox', '0 0 26 26');
  465.  
  466. if (panel.classList.contains('right')) {
  467. adr.appendChild(paneltog);
  468. var pof = sright;
  469. var pon = sleft;
  470. }
  471. else {
  472. adr.insertBefore(paneltog,adr.firstChild);
  473. var pof = sleft;
  474. var pon = sright;
  475. }
  476. if (panel.classList.contains('switcher')) {
  477. panelpath.style = pof;
  478. }
  479. else {
  480. panelpath.style = pon;
  481. }
  482.  
  483. paneltog.addEventListener('click', function(event) {
  484. if (!event.altKey) {
  485. if (panel.classList.contains('switcher')) {
  486. panelpath.style = pon;
  487. }
  488. else {
  489. panelpath.style = pof;
  490. }
  491. }
  492. });
  493. };
  494.  
  495. // The code below is a loop waiting for the browser to load the UI. Something like this has to be used in all similar javascript mods, to ensure the interface has loaded before running dependent functions. You can call all functions you might use from just one instance.
  496.  
  497. setTimeout(function wait() {
  498. adr = document.querySelector('.toolbar-addressbar.toolbar');
  499. if (adr) {
  500. panelToggle();
  501. }
  502. else {
  503. setTimeout(wait, 300);
  504. }
  505. }, 300);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement