| 
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -22,32 +22,18 @@ import {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Hidden communities for transparency.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				const filteredCommunities = {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					tests: [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"2e9345+c7fb",  // TestRoom
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"762ba9+c7fb",  // TesterRoom
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"b4d829+c7fb",  // Test
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"e5853a+c7fb",  // testtest
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"fishing+8e2e", // Example group from PySOGS documentation
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"test+118d",    // Testing 1, 2, 3
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"test+13f6",    // Testing room
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"test+c01b",    // Testing room
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"test+13f6",    // Testing room2
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"test+fe93",    // 测试(Test)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"xyz+7908",     // XYZ Room
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"xyz+efca",     // XYZ Room
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					offensive: [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"60fa60+c7fb",    // "N-word" Community
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"ab1a4d+c7fb",    // zUnsensored Group (CSAM)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"AlexMed+e093",   //
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"AlexMed+e093",   // drug trading?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"gore+e5e0",      // gore
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"RU-STEROID+e093" //
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"RU-STEROID+e093" // drug trading?
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					],
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// These communities should be checked regularly
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// in case they update their PySOGS version
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					legacy: [
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						"Ukraine+02bd"  // https://reccacon.com/view/room/Ukraine
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// This can be achieved with `text-overflow: ellipsis` instead
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -60,13 +46,27 @@ const transformJoinURL = (join_link) => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function onLoad(timestamp) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function getTimestamp() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const timestampRaw = dom.meta_timestamp()
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						?.getAttribute('content');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (!timestampRaw) return null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const timestamp = parseInt(timestampRaw);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (Number.isNaN(timestamp)) return null;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					return timestamp;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function onLoad() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const timestamp = getTimestamp();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (timestamp !== null) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						setLastChecked(timestamp);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					hideBadCommunities();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					// Sort by server to show off new feature & align colors.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					sortTable(COLUMN.SERVER_ICON);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					createJoinLinkButtons();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					markSortableColumns();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					addQRModalHandlers();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					addServerIconInteractions();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function displayQRModal(communityID) {
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -77,6 +77,24 @@ function hideQRModal(communityID) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					dom.qr_modal(communityID).style.display = "none";
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function addQRModalHandlers() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const rows = dom.tbl_communities_content_rows();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					if (!rows) throw new Error("Rows not found");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (const row of rows) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const communityID = row.getAttribute('data-identifier');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						row.querySelector('.td_qr_code').addEventListener(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							'click',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							() => displayQRModal(communityID)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const closeButton =
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							dom.qr_modal(communityID).querySelector('.qr-code-modal-close');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						closeButton.addEventListener(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							'click',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							() => hideQRModal(communityID)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function createJoinLinkButtons() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const join_URLs = dom.join_urls();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					Array.from(join_URLs).forEach((td_url) => {
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -89,7 +107,7 @@ function createJoinLinkButtons() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function hideBadCommunities() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					let numberOfHiddenCommunities = 0;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (const category of ['tests', 'offensive', 'legacy']) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (const category of ['tests', 'offensive']) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						numberOfHiddenCommunities +=
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						  filteredCommunities[category]
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						    .map(hideElementByID)
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -138,6 +156,19 @@ function setLastChecked(last_checked) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					timestamp_element.innerText =	`${time_passed_in_minutes} minutes ago`;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// TODO: Move info into dynamic modal.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				function addServerIconInteractions() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					const rows = dom.tbl_communities_content_rows();
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (const row of rows) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const hostname = row.getAttribute('data-hostname');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const publicKey = row.getAttribute('data-pubkey');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						const serverIcon = row.querySelector('.td_server_icon');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						serverIcon.addEventListener('click', () => {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							alert(`Host: ${hostname}?>\n\nPublic key:\n${publicKey}?>`);
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/**
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 * Function comparing two elements.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				 *
 | 
			
		
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
			
			 | 
			 | 
			
				@ -255,7 +286,11 @@ function markSortableColumns() {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					for (let colno = 0; colno < header_cells.length; colno++) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						if (!columnIsSortable(colno)) continue;
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						header_cells[colno].classList.add('sortable');
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						header_cells[colno].addEventListener(
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							'click',
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
							() => sortTable(colno)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
						)
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					};
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				/**
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
			
			 | 
			 | 
			
				@ -279,13 +314,7 @@ function sortTable(column) {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					setSortState(table, { ascending, column });
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				}
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// html.js for styling purposes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				window.document.documentElement.classList.add("js");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Crude way to export from module script due to inline event handlers.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// Ideally, all handlers would be attached from JS via addEventListener.
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				Object.assign(window, {
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					onLoad, sortTable, displayQRModal,
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
					hideQRModal, copyToClipboard
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				});
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				// `html.js` selector for styling purposes
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				document.documentElement.classList.add("js");
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				
 | 
			
		
		
	
		
			
				 | 
				 | 
			
			 | 
			 | 
			
				document.addEventListener('DOMContentLoaded', () => onLoad());
 | 
			
		
		
	
	
		
			
				
					| 
						
						
						
					 | 
				
			
			 | 
			 | 
			
				
 
 |