(function (){
'use strict';
function initialize(root){
if(root.getAttribute('data-initialized')==='true') return;
root.setAttribute('data-initialized', 'true');
var input=root.querySelector('[data-input]');
var output=root.querySelector('[data-output]');
var format=root.querySelector('[data-output-format]');
var viewMode=root.querySelector('[data-view-mode]');
var removeDuplicates=root.querySelector('[data-remove-duplicates]');
var customWrap=root.querySelector('[data-custom-wrap]');
var customTemplate=root.querySelector('[data-custom-template]');
var fields=root.querySelector('[data-template-fields]');
var inputCount=root.querySelector('[data-input-count]');
var outputCount=root.querySelector('[data-output-count]');
var status=root.querySelector('[data-status]');
var alertBox=root.querySelector('[data-alert]');
var alertTitle=root.querySelector('[data-alert-title]');
var alertMessage=root.querySelector('[data-alert-message]');
var alertList=root.querySelector('[data-alert-list]');
var findButton=root.querySelector('[data-find]');
var emptyState=root.querySelector('[data-empty-state]');
var resultsBox=root.querySelector('[data-results]');
var resultSubtitle=root.querySelector('[data-result-subtitle]');
var tableWrap=root.querySelector('[data-table-wrap]');
var resultBody=root.querySelector('[data-result-body]');
var selectAll=root.querySelector('[data-select-all]');
var statTotal=root.querySelector('[data-stat-total]');
var statCountries=root.querySelector('[data-stat-countries]');
var statAsns=root.querySelector('[data-stat-asns]');
var statSkipped=root.querySelector('[data-stat-skipped]');
var statCached=root.querySelector('[data-stat-cached]');
var map=root.querySelector('[data-map]');
var mapCanvas=root.querySelector('[data-map-canvas]');
var mapStatus=root.querySelector('[data-map-status]');
var mapList=root.querySelector('[data-map-list]');
var mapDetails=root.querySelector('[data-map-details]');
var actionsDropdown=root.querySelector('[data-actions-dropdown]');
var actionsToggle=root.querySelector('[data-actions-toggle]');
var actionsMenu=root.querySelector('[data-actions-menu]');
var countryDistribution=root.querySelector('[data-country-distribution]');
var networkDistribution=root.querySelector('[data-network-distribution]');
var warningsBox=root.querySelector('[data-warnings]');
var resultSearch=root.querySelector('[data-result-search]');
var filterCountry=root.querySelector('[data-filter-country]');
var filterAsn=root.querySelector('[data-filter-asn]');
var filterNetwork=root.querySelector('[data-filter-network]');
var filterSource=root.querySelector('[data-filter-source]');
var clearFiltersButton=root.querySelector('[data-clear-filters]');
var ajaxUrl=root.getAttribute('data-ajax-url')||'';
var nonce=root.getAttribute('data-nonce')||'';
var maximum=Number(root.getAttribute('data-max'))||100;
var findButtonText=findButton ? findButton.textContent:'Find locations';
var testerStorageKey='buyproxiesProxyTesterInput';
var formatterStorageKey='buyproxiesProxyFormatterInput';
var locationsStorageKey='buyproxiesIpsLocationsInput';
var results=[];
var lastSummary={};
var activeCountryFilter='';
var activeCountryFilterLabel='';
var activeNetworkFilter='';
var activeNetworkFilterLabel='';
var leafletMap=null;
var leafletMarkers=null;
var countryCoordinates={
AD: [42.5, 1.6], AE: [24.4, 54.4], AF: [34.5, 69.2], AL: [41.3, 19.8], AM: [40.2, 44.5],
AO: [-8.8, 13.2], AR: [-34.6, -58.4], AT: [48.2, 16.4], AU: [-35.3, 149.1], AZ: [40.4, 49.9],
BA: [43.9, 18.4], BD: [23.8, 90.4], BE: [50.9, 4.4], BG: [42.7, 23.3], BH: [26.2, 50.6],
BR: [-15.8, -47.9], BY: [53.9, 27.6], CA: [45.4, -75.7], CH: [46.9, 7.4], CL: [-33.4, -70.7],
CN: [39.9, 116.4], CO: [4.7, -74.1], CR: [9.9, -84.1], CY: [35.2, 33.4], CZ: [50.1, 14.4],
DE: [52.5, 13.4], DK: [55.7, 12.6], DO: [18.5, -69.9], DZ: [36.8, 3.1], EC: [-0.2, -78.5],
EE: [59.4, 24.8], EG: [30.0, 31.2], ES: [40.4, -3.7], FI: [60.2, 24.9], FR: [48.9, 2.4],
GB: [51.5, -0.1], GE: [41.7, 44.8], GH: [5.6, -0.2], GR: [38.0, 23.7], GT: [14.6, -90.5],
HK: [22.3, 114.2], HR: [45.8, 16.0], HU: [47.5, 19.0], ID: [-6.2, 106.8], IE: [53.3, -6.3],
IL: [31.8, 35.2], IN: [28.6, 77.2], IQ: [33.3, 44.4], IR: [35.7, 51.4], IS: [64.1, -21.9],
IT: [41.9, 12.5], JP: [35.7, 139.7], KE: [-1.3, 36.8], KR: [37.6, 127.0], KW: [29.4, 47.9],
KZ: [51.2, 71.4], LB: [33.9, 35.5], LK: [6.9, 79.9], LT: [54.7, 25.3], LU: [49.6, 6.1],
LV: [56.9, 24.1], MA: [34.0, -6.8], MD: [47.0, 28.8], MX: [19.4, -99.1], MY: [3.1, 101.7],
NG: [9.1, 7.5], NL: [52.4, 4.9], NO: [59.9, 10.8], NZ: [-41.3, 174.8], PA: [9.0, -79.5],
PE: [-12.0, -77.0], PH: [14.6, 121.0], PK: [33.7, 73.1], PL: [52.2, 21.0], PR: [18.5, -66.1],
PT: [38.7, -9.1], QA: [25.3, 51.5], RO: [44.4, 26.1], RS: [44.8, 20.5], RU: [55.8, 37.6],
SA: [24.7, 46.7], SE: [59.3, 18.1], SG: [1.3, 103.8], SI: [46.1, 14.5], SK: [48.1, 17.1],
TH: [13.8, 100.5], TN: [36.8, 10.2], TR: [39.9, 32.9], TW: [25.0, 121.6], UA: [50.5, 30.5],
US: [38.9, -77.0], UY: [-34.9, -56.2], VE: [10.5, -66.9], VN: [21.0, 105.8], ZA: [-25.7, 28.2]
};
function clean(value){
return value===null||typeof value==='undefined' ? '':String(value).trim();
}
function setText(element, text){
if(element) element.textContent=text;
}
function escapeHtml(text){
return clean(text).replace(/[&<>"']/g, function (character){
return {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
}[character];
});
}
function mapUrl(lat, lon, zoom){
return 'https://www.openstreetmap.org/?mlat=' + encodeURIComponent(lat) + '&mlon=' + encodeURIComponent(lon) + '#map=' + encodeURIComponent(zoom||5) + '/' + encodeURIComponent(lat) + '/' + encodeURIComponent(lon);
}
function lines(){
return input.value.split(/\r?\n/).filter(function (line){ return clean(line)!==''; });
}
function plural(count, singular, pluralText){
return count + ' ' + (count===1 ? singular:(pluralText||singular + 's'));
}
function countryPercent(count, total){
total=total||results.length;
if(!total) return '0%';
return Math.round((count / total) * 100) + '%';
}
function setStatus(message, state){
if(!status) return;
status.textContent=message;
status.classList.toggle('is-error', state==='error');
status.classList.toggle('is-success', state==='success');
}
function hideAlert(){
if(!alertBox||!alertList) return;
alertBox.hidden=true;
alertList.textContent='';
}
function showAlert(title, message, invalid){
if(!alertBox||!alertTitle||!alertMessage||!alertList) return;
alertTitle.textContent=title;
alertMessage.textContent=message||'';
alertList.textContent='';
(invalid||[]).slice(0, 80).forEach(function (item){
var li=document.createElement('li');
li.textContent='Line ' + item.line + ': ' + item.value + (item.message ? ' - ' + item.message:'');
alertList.appendChild(li);
});
if((invalid||[]).length > 80){
var more=document.createElement('li');
more.textContent='Only the first 80 skipped lines are shown.';
alertList.appendChild(more);
}
alertBox.hidden=false;
}
function value(item, key){
return clean(item[key]);
}
function numericValue(item, key){
var number=Number(value(item, key));
return isFinite(number) ? number:null;
}
function countryCode(item){
return value(item, 'country_code').toUpperCase();
}
function countryName(item){
return value(item, 'country')||countryCode(item)||'Unknown country';
}
function isCached(item){
return item&&(item.cached===true||item.cached===1||item.cached==='1'||item.cached==='true');
}
function isUnknownCountry(item){
return !countryCode(item)&&(!value(item, 'country')||/^unknown/i.test(value(item, 'country')));
}
function flagImageUrl(code){
code=clean(code).toLowerCase();
if(!/^[a-z]{2}$/.test(code)) return '';
return 'https://flagcdn.com/w40/' + encodeURIComponent(code) + '.png';
}
function createFlagElement(itemOrCode){
var code=typeof itemOrCode==='string' ? clean(itemOrCode).toUpperCase():countryCode(itemOrCode);
var url=flagImageUrl(code);
var flag;
if(!url) return null;
flag=document.createElement('span');
flag.className='ips-locations__flag';
flag.style.backgroundImage='url("' + url + '")';
flag.setAttribute('role', 'img');
flag.setAttribute('aria-label', code + ' flag');
flag.title=code + ' flag';
return flag;
}
function flagHtml(item){
var code=countryCode(item);
var url=flagImageUrl(code);
if(!url) return '';
return '<span class="ips-locations__flag" role="img" aria-label="' + escapeHtml(code + ' flag') + '" style="background-image:url(&quot;' + escapeHtml(url) + '&quot;)"></span>';
}
function createCountryDisplay(item, prefix){
var display=document.createElement('span');
var flag=createFlagElement(item);
var name=document.createElement('span');
display.className='ips-locations__country-display';
if(prefix) display.appendChild(document.createTextNode(prefix));
if(flag) display.appendChild(flag);
name.className='ips-locations__country-name';
name.textContent=countryName(item);
display.appendChild(name);
return display;
}
function coordinatesForItem(item){
var lat=numericValue(item, 'latitude');
var lon=numericValue(item, 'longitude');
var fallback;
if(lat===null) lat=numericValue(item, 'lat');
if(lon===null) lon=numericValue(item, 'lon');
if(lon===null) lon=numericValue(item, 'lng');
if(lat!==null&&lon!==null&&lat >=-90&&lat <=90&&lon >=-180&&lon <=180){
return { lat: lat, lon: lon, source: 'coordinates' };}
fallback=countryCoordinates[value(item, 'country_code').toUpperCase()];
if(fallback){
return { lat: fallback[0], lon: fallback[1], source: 'country' };}
return null;
}
function accuracyDetails(item){
var coordinates=coordinatesForItem(item);
if(!coordinates){
return {label: 'No map point', source: 'missing', className: 'is-missing'};}
if(coordinates.source==='country'){
return {label: 'Country fallback', source: 'fallback', className: 'is-fallback'};}
return {label: 'Coordinates returned', source: 'coordinates', className: 'is-coordinates'};}
function locationParts(item){
return [value(item, 'city'), value(item, 'region'), value(item, 'country')].filter(Boolean).filter(function (part, index, all){
return all.indexOf(part)===index;
});
}
function applyTemplate(template, item){
return template.replace(/\{(ip|input|city|region|country|country_code|flag|postal|latitude|longitude|timezone|isp|organization|asn)\}/gi, function (_, key){
return value(item, key.toLowerCase());
});
}
function formatItem(item){
var selected=format ? format.value:'full';
if(selected==='compact') return item.ip + ' | ' + (value(item, 'city')||'Unknown') + ', ' + (value(item, 'country_code')||'XX');
if(selected==='country') return item.ip + ' | ' + (item.country||'Unknown');
if(selected==='country-code') return item.ip + ':' + (item.country_code||'XX');
if(selected==='network') return item.ip + ' | ' + (item.isp||item.organization||'Unknown') + ' | ' + asnLabel(item);
if(selected==='coordinates') return item.ip + ' | ' + value(item, 'latitude') + ',' + value(item, 'longitude');
if(selected==='csv'){
return [item.ip, item.input, item.city, item.region, item.country, item.country_code, item.flag, item.postal, item.latitude, item.longitude, item.timezone, item.isp, item.organization, item.asn].map(function (field){
return '"' + clean(field).replace(/"/g, '""') + '"';
}).join(',');
}
if(selected==='json') return JSON.stringify(item);
if(selected==='custom'&&customTemplate) return applyTemplate(customTemplate.value, item);
return item.ip + ' | ' + (locationParts(item).join(', ')||'Unknown');
}
function applyViewModeClass(){
root.classList.toggle('is-network-view', viewMode&&viewMode.value==='network');
}
function uniqueCount(items, getter){
var seen={};
items.forEach(function (item){
var key=clean(getter(item));
if(key) seen[key.toLowerCase()]=true;
});
return Object.keys(seen).length;
}
function asnLabel(item){
var asn=value(item, 'asn');
if(!asn) return 'ASN unknown';
return /^AS/i.test(asn) ? asn.toUpperCase():'AS' + asn;
}
function networkLabel(item){
var network=value(item, 'isp')||value(item, 'organization')||'Unknown network';
return asnLabel(item) + ' | ' + network;
}
function groupItems(items, labelGetter){
var groups={};
items.forEach(function (item){
var label=clean(labelGetter(item))||'Unknown';
var key=label.toLowerCase();
if(!groups[key]) groups[key]={ label: label, count: 0 };
groups[key].count +=1;
});
return Object.keys(groups).map(function (key){
return groups[key];
}).sort(function (a, b){
if(b.count!==a.count) return b.count - a.count;
return a.label.localeCompare(b.label);
});
}
function groupCountries(items){
var groups={};
items.forEach(function (item){
var key=countryCode(item)||countryName(item).toLowerCase();
if(!groups[key]){
groups[key]={
code: countryCode(item),
label: countryName(item),
count: 0
};}
groups[key].count +=1;
});
return Object.keys(groups).map(function (key){
return groups[key];
}).sort(function (a, b){
if(b.count!==a.count) return b.count - a.count;
return a.label.localeCompare(b.label);
});
}
function renderDistribution(groups){
if(!countryDistribution) return;
countryDistribution.textContent='';
if(!groups.length){
countryDistribution.hidden=true;
return;
}
countryDistribution.hidden=false;
groups.slice(0, 10).forEach(function (group){
var item=document.createElement('button');
var label=document.createElement('span');
var bar=document.createElement('strong');
var fill=document.createElement('em');
var flag=createFlagElement(group.code);
var key=(group.code||group.label).toLowerCase();
item.type='button';
item.className='ips-locations__distribution-item';
item.setAttribute('data-country-filter', key);
item.setAttribute('data-country-label', group.label);
item.setAttribute('aria-label', 'Show only ' + group.label + ' results');
item.classList.toggle('is-active', activeCountryFilter===key||(filterCountry&&filterCountry.value===key));
label.className='ips-locations__distribution-label';
if(flag) label.appendChild(flag);
label.appendChild(document.createTextNode(group.label));
fill.style.width=countryPercent(group.count);
fill.textContent=countryPercent(group.count) + ' | ' + plural(group.count, 'IP');
bar.appendChild(fill);
item.appendChild(label);
item.appendChild(bar);
countryDistribution.appendChild(item);
});
}
function renderNetworkDistribution(groups){
if(!networkDistribution) return;
networkDistribution.textContent='';
if(!groups.length){
networkDistribution.hidden=true;
return;
}
networkDistribution.hidden=false;
groups.slice(0, 10).forEach(function (group){
var item=document.createElement('button');
var label=document.createElement('span');
var bar=document.createElement('strong');
var fill=document.createElement('em');
var key=group.label.toLowerCase();
item.type='button';
item.className='ips-locations__distribution-item ips-locations__distribution-item--network';
item.setAttribute('data-network-filter', key);
item.setAttribute('data-network-label', group.label);
item.setAttribute('aria-label', 'Show only ' + group.label + ' results');
item.classList.toggle('is-active', activeNetworkFilter===key);
label.className='ips-locations__distribution-label';
label.textContent=group.label;
fill.style.width=countryPercent(group.count);
fill.textContent=countryPercent(group.count) + ' | ' + plural(group.count, 'IP');
bar.appendChild(fill);
item.appendChild(label);
item.appendChild(bar);
networkDistribution.appendChild(item);
});
}
function filterValue(control){
return clean(control&&control.value).toLowerCase();
}
function itemSearchText(item){
return [
item.ip,
item.input,
tableLocation(item),
countryName(item),
countryCode(item),
tableNetwork(item),
value(item, 'asn'),
value(item, 'timezone')
].join(' ').toLowerCase();
}
function filtersActive(){
return Boolean(
filterValue(resultSearch) ||
activeCountryFilter ||
filterValue(filterCountry) ||
filterValue(filterAsn) ||
filterValue(filterNetwork) ||
filterValue(filterSource) ||
activeNetworkFilter
);
}
function itemMatchesFilters(item){
var search=filterValue(resultSearch);
var country=filterValue(filterCountry);
var asn=filterValue(filterAsn);
var network=filterValue(filterNetwork);
var source=filterValue(filterSource);
var accuracy=accuracyDetails(item);
if(search&&itemSearchText(item).indexOf(search)===-1) return false;
if(activeCountryFilter&&(countryCode(item).toLowerCase()||countryName(item).toLowerCase())!==activeCountryFilter) return false;
if(country&&(countryCode(item).toLowerCase()||countryName(item).toLowerCase())!==country) return false;
if(asn&&value(item, 'asn').toLowerCase()!==asn) return false;
if(network&&tableNetwork(item).toLowerCase().indexOf(network)===-1) return false;
if(activeNetworkFilter&&networkLabel(item).toLowerCase()!==activeNetworkFilter) return false;
if(source==='coordinates'&&accuracy.source!=='coordinates') return false;
if(source==='fallback'&&accuracy.source!=='fallback') return false;
if(source==='missing'&&accuracy.source!=='missing') return false;
if(source==='cached'&&!isCached(item)) return false;
if(source==='fresh'&&isCached(item)) return false;
if(source==='unknown'&&!isUnknownCountry(item)) return false;
return true;
}
function filteredResultEntries(){
return results.map(function (item, index){
return {item: item, index: index};}).filter(function (entry){
return itemMatchesFilters(entry.item);
});
}
function selectOptionText(label, count){
return label + ' (' + count + ')';
}
function replaceOptions(select, placeholder, options, selectedValue){
if(!select) return;
select.textContent='';
select.appendChild(new Option(placeholder, ''));
options.forEach(function (option){
select.appendChild(new Option(selectOptionText(option.label, option.count), option.value));
});
select.value=selectedValue||'';
if(select.value!==(selectedValue||'')) select.value='';
}
function activeCountryLabel(){
var selected;
if(activeCountryFilterLabel) return activeCountryFilterLabel;
if(activeCountryFilter) return activeCountryFilter;
if(!filterCountry||!filterCountry.value) return '';
selected=filterCountry.options[filterCountry.selectedIndex];
return selected ? selected.text.replace(/\s+\(\d+\)$/, ''):'';
}
function activeNetworkLabel(){
if(activeNetworkFilterLabel) return activeNetworkFilterLabel;
if(!activeNetworkFilter) return '';
return activeNetworkFilter.replace(/\bas([a-z0-9]+)/i, function (match, id){
return 'AS' + id.toUpperCase();
}).replace(/\b[a-z]/g, function (character){
return character.toUpperCase();
});
}
function populateFilters(){
var selectedCountry=filterCountry ? filterCountry.value:'';
var selectedAsn=filterAsn ? filterAsn.value:'';
var asnGroups=groupItems(results.filter(function (item){
return value(item, 'asn')!=='';
}), function (item){
return value(item, 'asn');
}).map(function (group){
return {label: /^AS/i.test(group.label) ? group.label.toUpperCase():'AS' + group.label, value: group.label.toLowerCase(), count: group.count};});
var countryOptions=groupCountries(results).map(function (group){
var valueKey=(group.code||group.label).toLowerCase();
return {label: group.label, value: valueKey, count: group.count};});
replaceOptions(filterCountry, 'All countries', countryOptions, selectedCountry);
replaceOptions(filterAsn, 'All ASNs', asnGroups, selectedAsn);
}
function warningItem(message, tone){
var item=document.createElement('span');
item.className='ips-locations__warning' + (tone ? ' ' + tone:'');
item.textContent=message;
return item;
}
function renderWarnings(){
var countryGroups=groupCountries(results);
var asnGroups=groupItems(results.filter(function (item){
return value(item, 'asn')!=='';
}), function (item){
return value(item, 'asn');
});
var fallbackCount=results.filter(function (item){
return accuracyDetails(item).source==='fallback';
}).length;
var missingCount=results.filter(function (item){
return accuracyDetails(item).source==='missing';
}).length;
var unknownCount=results.filter(isUnknownCountry).length;
var warnings=[];
var topCountry=countryGroups[0];
var topAsn=asnGroups[0];
if(!warningsBox) return;
warningsBox.textContent='';
if(topCountry&&results.length >=5&&topCountry.count / results.length >=0.7){
warnings.push(warningItem(topCountry.label + ' is ' + countryPercent(topCountry.count) + ' of this list', 'is-caution'));
}
if(topAsn&&topAsn.count > 1){
warnings.push(warningItem('Repeated ASN: ' + (/^AS/i.test(topAsn.label) ? topAsn.label.toUpperCase():'AS' + topAsn.label) + ' has ' + plural(topAsn.count, 'IP'), 'is-info'));
}
if(fallbackCount){
warnings.push(warningItem(plural(fallbackCount, 'row') + ' use country-level map fallback', 'is-info'));
}
if(missingCount){
warnings.push(warningItem(plural(missingCount, 'row') + ' have no map point', 'is-caution'));
}
if(unknownCount){
warnings.push(warningItem(plural(unknownCount, 'row') + ' have unknown country data', 'is-caution'));
}
if(!warnings.length){
warningsBox.hidden=true;
return;
}
warnings.forEach(function (warning){
warningsBox.appendChild(warning);
});
warningsBox.hidden=false;
}
function renderStats(){
setText(statTotal, String(results.length));
setText(statCountries, String(uniqueCount(results, function (item){
return value(item, 'country_code')||value(item, 'country');
})));
setText(statAsns, String(uniqueCount(results, function (item){
return value(item, 'asn');
})));
setText(statSkipped, String(Number(lastSummary.skipped)||0));
setText(statCached, String(Number(lastSummary.cached)||0));
}
function renderInsights(){
var countries=groupCountries(results);
renderDistribution(countries);
renderNetworkDistribution(groupItems(results, networkLabel));
}
function mapPoints(){
return results.map(function (item){
var coordinates=coordinatesForItem(item);
return coordinates ? { item: item, coordinates: coordinates }:null;
}).filter(Boolean);
}
function mapLabel(point){
return point.item.ip + ' - ' + (tableLocation(point.item)||'Unknown') + ' - ' + networkLabel(point.item);
}
function clearLeafletMap(){
if(leafletMarkers) leafletMarkers.clearLayers();
}
function ensureLeafletMap(){
if(!mapCanvas||!window.L) return null;
if(!leafletMap){
mapCanvas.textContent='';
mapCanvas.classList.add('is-leaflet-map');
leafletMap=window.L.map(mapCanvas, {
scrollWheelZoom: false,
attributionControl: true
});
window.L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 18,
attribution: '&copy; OpenStreetMap contributors'
}).addTo(leafletMap);
leafletMarkers=window.L.layerGroup().addTo(leafletMap);
}
return leafletMap;
}
function renderMapList(points){
if(!mapList) return;
mapList.textContent='';
points.slice(0, 24).forEach(function (point){
var row=document.createElement('a');
var label=document.createElement('strong');
var meta=document.createElement('span');
var lat=point.coordinates.lat.toFixed(4);
var lon=point.coordinates.lon.toFixed(4);
row.href=mapUrl(lat, lon, point.coordinates.source==='country' ? 4:7);
row.target='_blank';
row.rel='noopener';
label.appendChild(createCountryDisplay(point.item, point.item.ip + ' - '));
meta.textContent=tableLocation(point.item) + ' | ' + lat + ', ' + lon + (point.coordinates.source==='country' ? ' | country fallback':'');
row.appendChild(label);
row.appendChild(meta);
mapList.appendChild(row);
});
}
function renderFallbackMap(points){
mapCanvas.classList.remove('is-leaflet-map');
mapCanvas.textContent='';
points.forEach(function (point, index){
var jitterX=((index % 7) - 3) * 0.65;
var jitterY=((Math.floor(index / 7) % 5) - 2) * 0.65;
var x=Math.max(2, Math.min(98, (((point.coordinates.lon + 180) / 360) * 100) + jitterX));
var y=Math.max(2, Math.min(98, (((90 - point.coordinates.lat) / 180) * 100) + jitterY));
var pin=document.createElement('button');
pin.type='button';
pin.className='ips-locations__pin' + (point.coordinates.source==='country' ? ' is-country-fallback':'');
pin.style.left=x + '%';
pin.style.top=y + '%';
pin.style.setProperty('--pin-delay', String(Math.min(index, 14) * 45) + 'ms');
pin.title=mapLabel(point) + (point.coordinates.source==='country' ? ' - country-level fallback':'');
pin.textContent='';
pin.appendChild(createFlagElement(point.item)||document.createTextNode(countryName(point.item)));
pin.addEventListener('click', function (){
setStatus(point.item.ip + ' - ' + (tableLocation(point.item)||'Unknown'), 'success');
});
mapCanvas.appendChild(pin);
});
}
function renderLeafletMap(points){
var instance=ensureLeafletMap();
var bounds;
if(!instance) return false;
clearLeafletMap();
bounds=window.L.latLngBounds([]);
points.forEach(function (point){
var latLng=[point.coordinates.lat, point.coordinates.lon];
var popup='<strong>' + escapeHtml(point.item.ip) + '</strong><br>' +
flagHtml(point.item) + ' ' + escapeHtml(countryName(point.item)) + '<br>' +
escapeHtml(tableLocation(point.item)) + '<br>' +
escapeHtml(networkLabel(point.item)) + '<br>' +
'<a href="' + escapeHtml(mapUrl(point.coordinates.lat.toFixed(6), point.coordinates.lon.toFixed(6), 8)) + '" target="_blank" rel="noopener">Open in OpenStreetMap</a>' +
(point.coordinates.source==='country' ? '<br><em>Country-level fallback position</em>':'');
window.L.marker(latLng, {
icon: window.L.divIcon({
className: 'ips-locations__leaflet-flag-icon',
html: flagHtml(point.item)||'<span class="ips-locations__leaflet-fallback">' + escapeHtml(countryCode(point.item)||'IP') + '</span>',
iconSize: [36, 26],
iconAnchor: [18, 13],
popupAnchor: [0, -14]
})
}).addTo(leafletMarkers).bindPopup(popup);
bounds.extend(latLng);
});
if(points.length===1){
instance.setView([points[0].coordinates.lat, points[0].coordinates.lon], points[0].coordinates.source==='country' ? 4:7);
}else if(bounds.isValid()){
instance.fitBounds(bounds, { padding: [28, 28], maxZoom: 7 });
}
window.setTimeout(function (){
instance.invalidateSize();
}, 80);
return true;
}
function renderMap(){
if(!map||!mapCanvas) return;
var points=mapPoints();
map.hidden=results.length===0;
if(!results.length){
if(mapList) mapList.textContent='';
if(mapStatus) mapStatus.textContent='Pins are based on geolocation coordinates and country fallback positions. IP geolocation is approximate, not GPS-level location.';
clearLeafletMap();
return;
}
if(mapDetails&&!mapDetails.open&&points.length) mapDetails.open=true;
if(!points.length){
clearLeafletMap();
mapCanvas.classList.remove('is-leaflet-map');
mapCanvas.textContent='';
if(mapStatus) mapStatus.textContent='No mappable coordinates or country codes were returned for these IPs.';
if(mapList) mapList.textContent='';
return;
}
renderMapList(points);
if(renderLeafletMap(points)){
if(mapStatus) mapStatus.textContent='Interactive OpenStreetMap view. Click a marker to see the IP, location, ASN/network, and map link.';
return;
}
renderFallbackMap(points);
if(mapStatus) mapStatus.textContent='Map tiles could not load, so a fallback location view is shown. Use the links below to open each location in OpenStreetMap.';
}
function scrollToResults(){
if(!resultsBox||resultsBox.hidden) return;
window.requestAnimationFrame(function (){
window.setTimeout(function (){
var target=root.querySelector('.ips-locations__result-section--overview')||resultsBox;
try {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
} catch (error){
target.scrollIntoView();
}}, 60);
});
}
function render(){
output.value=results.map(formatItem).join('\n');
setText(outputCount, results.length + (results.length===1 ? ' result':' results'));
if(emptyState) emptyState.hidden=results.length > 0;
if(resultSubtitle){
resultSubtitle.textContent=results.length
? 'Validated public IPs are ready for review, copy, and export.'
: 'Run a lookup to build the dashboard.';
}
populateFilters();
renderTable();
renderStats();
renderInsights();
renderWarnings();
renderMap();
applyViewModeClass();
}
function addCell(row, text, title, label){
var cell=document.createElement('td');
cell.textContent=clean(text)||'-';
if(title) cell.title=title;
if(label) cell.setAttribute('data-label', label);
row.appendChild(cell);
return cell;
}
function tableLocation(item){
return locationParts(item).join(', ')||'Unknown';
}
function networkName(item){
return value(item, 'isp')||value(item, 'organization')||'Unknown';
}
function tableNetwork(item){
var network=networkName(item);
if(value(item, 'asn')) network +=' / ' + asnLabel(item);
return network;
}
function addLocationCell(row, item, label){
var cell=document.createElement('td');
var text=document.createElement('span');
var flag=createFlagElement(item);
cell.className='ips-locations__location-cell';
if(label) cell.setAttribute('data-label', label);
text.textContent=tableLocation(item);
cell.appendChild(text);
if(flag) cell.appendChild(flag);
row.appendChild(cell);
return cell;
}
function addNetworkCell(row, item, label){
var cell=document.createElement('td');
var name=document.createElement('span');
var asn=document.createElement('small');
cell.className='ips-locations__network-cell';
if(label) cell.setAttribute('data-label', label);
name.textContent=networkName(item);
asn.textContent=asnLabel(item);
cell.appendChild(name);
cell.appendChild(asn);
row.appendChild(cell);
return cell;
}
function updateResultSubtitle(visibleCount){
var country=activeCountryLabel();
var network=activeNetworkLabel();
if(!resultSubtitle) return;
if(!results.length){
resultSubtitle.textContent='Run a lookup to build the dashboard.';
return;
}
if(country){
resultSubtitle.textContent='Country filter active: ' + country + '. Showing ' + visibleCount + ' of ' + results.length + ' rows, and only those country rows are selected below.';
return;
}
if(network){
resultSubtitle.textContent='Network filter active: ' + network + '. Showing ' + visibleCount + ' of ' + results.length + ' rows, and only those network rows are selected below.';
return;
}
if(filtersActive()){
resultSubtitle.textContent='Showing ' + visibleCount + ' of ' + results.length + ' rows that match your filters.';
return;
}
resultSubtitle.textContent='Validated public IPs are ready for review, copy, and export.';
}
function renderTable(){
if(!resultsBox||!resultBody) return;
var entries=filteredResultEntries();
resultBody.textContent='';
if(!entries.length&&results.length){
var emptyRow=document.createElement('tr');
var emptyCell=document.createElement('td');
emptyCell.colSpan=5;
emptyCell.className='ips-locations__table-empty';
emptyCell.textContent='No rows match the current filters.';
emptyRow.appendChild(emptyCell);
resultBody.appendChild(emptyRow);
}
entries.forEach(function (entry){
var item=entry.item;
var index=entry.index;
var row=document.createElement('tr');
var selectCell=document.createElement('td');
var checkbox=document.createElement('input');
checkbox.type='checkbox';
checkbox.checked=true;
checkbox.setAttribute('data-result-index', String(index));
checkbox.setAttribute('aria-label', 'Select ' + item.ip);
selectCell.setAttribute('data-label', 'Select');
selectCell.appendChild(checkbox);
row.appendChild(selectCell);
addCell(row, item.ip, '', 'IP');
addLocationCell(row, item, 'Location');
addNetworkCell(row, item, 'Network');
addCell(row, item.timezone, '', 'Timezone');
resultBody.appendChild(row);
});
if(tableWrap) tableWrap.classList.toggle('is-scrollable', entries.length > 20);
resultsBox.hidden=results.length===0;
updateResultSubtitle(entries.length);
updateSelectAll();
}
function updateSelectAll(){
if(!selectAll||!resultBody) return;
var enabled=resultBody.querySelectorAll('[data-result-index]');
var checked=resultBody.querySelectorAll('[data-result-index]:checked');
selectAll.disabled=enabled.length===0;
selectAll.checked=enabled.length > 0&&checked.length===enabled.length;
selectAll.indeterminate=checked.length > 0&&checked.length < enabled.length;
}
function selectedResults(){
var selected=[];
if(!resultBody) return selected;
Array.prototype.forEach.call(resultBody.querySelectorAll('[data-result-index]:checked'), function (checkbox){
var item=results[Number(checkbox.getAttribute('data-result-index'))];
if(item) selected.push(item);
});
return selected;
}
function visibleResults(){
return filteredResultEntries().map(function (entry){
return entry.item;
});
}
function presetScopeResults(){
return filtersActive() ? visibleResults():results;
}
function csvLine(values){
return values.map(function (field){
return '"' + clean(field).replace(/"/g, '""') + '"';
}).join(',');
}
function csvRows(items){
var rows=[csvLine(['IP', 'Input', 'City', 'Region', 'Country', 'Country Code', 'Postal', 'Latitude', 'Longitude', 'Accuracy', 'Timezone', 'ISP', 'Organization', 'ASN', 'Cached'])];
items.forEach(function (item){
rows.push(csvLine([item.ip, item.input, item.city, item.region, item.country, item.country_code, item.postal, item.latitude, item.longitude, accuracyDetails(item).label, item.timezone, item.isp, item.organization, item.asn, isCached(item) ? 'Yes':'No']));
});
return rows.join('\n');
}
function updateCount(){
var count=lines().length;
inputCount.textContent=count + ' / ' + maximum;
inputCount.classList.toggle('is-error', count > maximum);
}
function setLoading(loading){
root.classList.toggle('is-loading', loading);
if(emptyState&&loading&&!results.length) emptyState.hidden=false;
if(!findButton) return;
findButton.disabled=loading;
findButton.textContent=loading ? 'Finding locations...':findButtonText;
}
function lookup(){
var submittedLines=lines();
hideAlert();
if(!ajaxUrl||!nonce){
setStatus('Plugin setup error', 'error');
showAlert('Plugin setup error', 'The WordPress AJAX configuration is missing. Clear the page cache and reload.', []);
return;
}
if(!submittedLines.length){
setStatus('Enter at least one IP or proxy', 'error');
showAlert('No input found', 'Paste one IP address or proxy per line.', []);
return;
}
if(submittedLines.length > maximum){
setStatus('Too many entries', 'error');
showAlert('Maximum exceeded', 'Enter no more than ' + maximum + ' non-empty lines.', []);
return;
}
setLoading(true);
setStatus('Looking up locations...', '');
var body=new URLSearchParams();
body.append('action', 'ips_locations_lookup');
body.append('nonce', nonce);
body.append('remove_duplicates', removeDuplicates&&removeDuplicates.checked ? '1':'0');
submittedLines.forEach(function (line){ body.append('lines[]', line); });
fetch(ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
body: body.toString()
}).then(function (response){
return response.json().then(function (data){
if(!response.ok||!data.success){
throw data;
}
return data;
});
}).then(function (response){
results=response.data.results||[];
lastSummary=response.data.summary||{};
if(mapDetails) mapDetails.open=true;
clearFilters(false);
render();
if(results.length) scrollToResults();
var invalid=response.data.invalid||[];
var skipped=Number(lastSummary.skipped)||invalid.length;
if(invalid.length){
showAlert(plural(invalid.length, 'line') + ' skipped', 'The valid public IPs were still processed.', invalid);
setStatus(results.length + ' found, ' + skipped + ' skipped', 'error');
}else{
setStatus(results.length + ' locations found', 'success');
}}).catch(function (response){
var data=response&&response.data ? response.data:{};
results=[];
lastSummary={};
clearFilters(false);
render();
showAlert('Location lookup failed', data.message||'The request could not be completed.', data.invalid||[]);
setStatus('Lookup failed', 'error');
}).then(function (){
setLoading(false);
}, function (){
setLoading(false);
});
}
function fallbackCopyText(text){
var textarea=document.createElement('textarea');
textarea.value=text;
textarea.setAttribute('readonly', '');
textarea.style.position='fixed';
textarea.style.left='-9999px';
textarea.style.top='0';
document.body.appendChild(textarea);
textarea.select();
try {
return document.execCommand ('copy');
} finally {
document.body.removeChild(textarea);
}}
function copyText(text, emptyMessage){
if(!text){
setStatus(emptyMessage||'Nothing to copy', 'error');
return;
}
if(navigator.clipboard&&window.isSecureContext){
navigator.clipboard.writeText(text).then(function (){
setStatus('Copied to clipboard', 'success');
}).catch(function (){
var copied=fallbackCopyText(text);
setStatus(copied ? 'Copied to clipboard':'Select the result and copy it manually', copied ? 'success':'error');
});
}else{
var copied=fallbackCopyText(text);
setStatus(copied ? 'Copied to clipboard':'Select the result and copy it manually', copied ? 'success':'error');
}}
function copy(){
copyText(output.value, 'Nothing to copy');
}
function copyAllResults(){
copyText(presetScopeResults().map(formatItem).join('\n'), 'Nothing to copy');
}
function copySelected(){
copyText(selectedResults().map(formatItem).join('\n'), 'No rows selected');
}
function copyCountries(){
var groups=groupCountries(results);
copyText(groups.map(function (group){
return group.label + ' | ' + plural(group.count, 'IP') + ' | ' + countryPercent(group.count);
}).join('\n'), 'No countries to copy');
}
function copyIpCountry(){
copyText(presetScopeResults().map(function (item){
return item.ip + ':' + (value(item, 'country_code')||'XX');
}).join('\n'), 'No IP countries to copy');
}
function copyIpOnly(){
copyText(presetScopeResults().map(function (item){
return item.ip;
}).join('\n'), 'No IPs to copy');
}
function copyIpCountryLines(){
copyText(presetScopeResults().map(function (item){
return item.ip + ' | ' + countryName(item) + (countryCode(item) ? ' | ' + countryCode(item):'');
}).join('\n'), 'No IP countries to copy');
}
function copyIpAsn(){
copyText(presetScopeResults().map(function (item){
return item.ip + ' | ' + asnLabel(item) + ' | ' + (value(item, 'isp')||value(item, 'organization')||'Unknown network');
}).join('\n'), 'No ASN rows to copy');
}
function copyNetworks(){
var groups=groupItems(results, networkLabel);
copyText(groups.map(function (group){
return group.label + ' | ' + plural(group.count, 'IP');
}).join('\n'), 'No networks to copy');
}
function downloadFile(filename, content, type){
if(!content){
setStatus('Nothing to export', 'error');
return;
}
var blob=new Blob([content], {type: type});
var url=URL.createObjectURL(blob);
var link=document.createElement('a');
link.href=url;
link.download=filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
}
function exportCsv(){
var items=presetScopeResults();
if(!items.length){
setStatus('Nothing to export', 'error');
return;
}
downloadFile('ip-locations.csv', csvRows(items), 'text/csv;charset=utf-8');
setStatus('CSV exported', 'success');
}
function exportExcel(){
var items=presetScopeResults();
if(!items.length){
setStatus('Nothing to export', 'error');
return;
}
downloadFile('ip-locations-excel.csv', '\ufeff' + csvRows(items), 'text/csv;charset=utf-8');
setStatus('Excel CSV exported', 'success');
}
function exportJson(){
var items=presetScopeResults();
if(!items.length){
setStatus('Nothing to export', 'error');
return;
}
downloadFile('ip-locations.json', JSON.stringify(items, null, 2), 'application/json;charset=utf-8');
setStatus('JSON exported', 'success');
}
function updateCustomVisibility(){
if(!format||!customWrap||!fields) return;
var custom=format.value==='custom';
customWrap.classList.toggle('is-visible', custom);
fields.hidden = !custom;
}
function setActionsMenu(open){
if(!actionsToggle||!actionsMenu) return;
actionsMenu.hidden = !open;
actionsToggle.setAttribute('aria-expanded', open ? 'true':'false');
}
function loadFormatterHandoff(){
var stored='';
try {
stored=window.sessionStorage.getItem(locationsStorageKey)||'';
if(stored) window.sessionStorage.removeItem(locationsStorageKey);
} catch (error){
stored='';
}
if(!stored||!input) return;
input.value=stored;
updateCount();
setStatus('Loaded proxies from Proxy Formatter', 'success');
input.focus();
}
function clearFilters(renderAfter){
if(resultSearch) resultSearch.value='';
if(filterCountry) filterCountry.value='';
if(filterAsn) filterAsn.value='';
if(filterNetwork) filterNetwork.value='';
if(filterSource) filterSource.value='';
activeCountryFilter='';
activeCountryFilterLabel='';
activeNetworkFilter='';
activeNetworkFilterLabel='';
if(renderAfter!==false){
render();
setStatus('Filters cleared', 'success');
}}
function applyCountryFilter(key, labelText){
var label;
if(resultSearch) resultSearch.value='';
if(filterCountry) filterCountry.value=key||'';
if(filterAsn) filterAsn.value='';
if(filterNetwork) filterNetwork.value='';
if(filterSource) filterSource.value='';
activeCountryFilter=key||'';
activeCountryFilterLabel=labelText||'';
activeNetworkFilter='';
activeNetworkFilterLabel='';
render();
label=activeCountryLabel();
setStatus(label ? label + ' results selected':'Country filter cleared', label ? 'success':'');
if(tableWrap){
try {
tableWrap.scrollIntoView({behavior: 'smooth', block: 'nearest'});
} catch (error){
tableWrap.scrollIntoView();
}}
}
function applyNetworkFilter(key, labelText){
var label;
if(resultSearch) resultSearch.value='';
if(filterCountry) filterCountry.value='';
if(filterAsn) filterAsn.value='';
if(filterNetwork) filterNetwork.value='';
if(filterSource) filterSource.value='';
activeCountryFilter='';
activeCountryFilterLabel='';
activeNetworkFilter=key||'';
activeNetworkFilterLabel=labelText||'';
render();
label=activeNetworkLabel();
setStatus(label ? label + ' results selected':'Network filter cleared', label ? 'success':'');
if(tableWrap){
try {
tableWrap.scrollIntoView({behavior: 'smooth', block: 'nearest'});
} catch (error){
tableWrap.scrollIntoView();
}}
}
function appendSource(url){
return url + (url.indexOf('?')===-1 ? '?from=ips-locations':'&from=ips-locations');
}
function handoffText(){
var selected;
if(results.length){
selected=selectedResults();
if(!selected.length) return '';
return selected.map(function (item){
return value(item, 'input')||value(item, 'ip');
}).join('\n');
}
return lines().join('\n');
}
function sendToTool(button){
var tool=button.getAttribute('data-send-tool');
var url=button.getAttribute('data-tool-url')||'/';
var key=tool==='formatter' ? formatterStorageKey:testerStorageKey;
var text=handoffText();
if(!text){
setStatus('Nothing to send', 'error');
return;
}
try {
window.sessionStorage.setItem(key, text);
window.location.href=appendSource(url);
} catch (error){
copyText(text, 'Could not open the next tool, so the list was copied instead');
}}
if(findButton) findButton.addEventListener('click', lookup);
var copyButton=root.querySelector('[data-copy]');
var copySelectedButton=root.querySelector('[data-copy-selected]');
var copyAllButton=root.querySelector('[data-copy-all]');
var copyCountriesButton=root.querySelector('[data-copy-countries]');
var copyIpCountryButton=root.querySelector('[data-copy-ip-country]');
var copyIpOnlyButton=root.querySelector('[data-copy-ip-only]');
var copyIpCountryLinesButton=root.querySelector('[data-copy-ip-country-lines]');
var copyIpAsnButton=root.querySelector('[data-copy-ip-asn]');
var copyNetworksButton=root.querySelector('[data-copy-networks]');
var exportCsvButton=root.querySelector('[data-export-csv]');
var exportExcelButton=root.querySelector('[data-export-excel]');
var exportJsonButton=root.querySelector('[data-export-json]');
var clearButton=root.querySelector('[data-clear]');
if(copyButton) copyButton.addEventListener('click', copy);
if(copySelectedButton) copySelectedButton.addEventListener('click', copySelected);
if(copyAllButton) copyAllButton.addEventListener('click', copyAllResults);
if(copyCountriesButton) copyCountriesButton.addEventListener('click', copyCountries);
if(copyIpCountryButton) copyIpCountryButton.addEventListener('click', copyIpCountry);
if(copyIpOnlyButton) copyIpOnlyButton.addEventListener('click', copyIpOnly);
if(copyIpCountryLinesButton) copyIpCountryLinesButton.addEventListener('click', copyIpCountryLines);
if(copyIpAsnButton) copyIpAsnButton.addEventListener('click', copyIpAsn);
if(copyNetworksButton) copyNetworksButton.addEventListener('click', copyNetworks);
if(exportCsvButton) exportCsvButton.addEventListener('click', exportCsv);
if(exportExcelButton) exportExcelButton.addEventListener('click', exportExcel);
if(exportJsonButton) exportJsonButton.addEventListener('click', exportJson);
Array.prototype.forEach.call(root.querySelectorAll('[data-send-tool]'), function (button){
button.addEventListener('click', function (){
sendToTool(button);
});
});
root.addEventListener('click', function (event){
var countryChip=event.target&&event.target.closest ? event.target.closest('[data-country-filter]'):null;
var networkChip=event.target&&event.target.closest ? event.target.closest('[data-network-filter]'):null;
if(countryChip&&root.contains(countryChip)){
event.preventDefault();
applyCountryFilter(countryChip.getAttribute('data-country-filter'), countryChip.getAttribute('data-country-label'));
return;
}
if(networkChip&&root.contains(networkChip)){
event.preventDefault();
applyNetworkFilter(networkChip.getAttribute('data-network-filter'), networkChip.getAttribute('data-network-label'));
}});
[resultSearch, filterCountry, filterAsn, filterNetwork, filterSource].forEach(function (control){
if(!control) return;
control.addEventListener(control.tagName==='INPUT' ? 'input':'change', function (){
activeCountryFilter='';
activeCountryFilterLabel='';
activeNetworkFilter='';
activeNetworkFilterLabel='';
render();
});
});
if(clearFiltersButton) clearFiltersButton.addEventListener('click', clearFilters);
if(actionsToggle&&actionsMenu){
actionsToggle.addEventListener('click', function (event){
event.preventDefault();
event.stopPropagation();
setActionsMenu(actionsMenu.hidden);
});
actionsMenu.addEventListener('click', function (event){
if(event.target&&event.target.closest&&event.target.closest('button')) setActionsMenu(false);
});
root.addEventListener('click', function (event){
if(!actionsMenu.hidden&&actionsDropdown&&!actionsDropdown.contains(event.target)) setActionsMenu(false);
});
root.addEventListener('keydown', function (event){
if(event.key==='Escape') setActionsMenu(false);
});
}
if(mapDetails){
mapDetails.addEventListener('toggle', function (){
if(mapDetails.open) renderMap();
});
}
if(clearButton){
clearButton.addEventListener('click', function (){
input.value='';
output.value='';
results=[];
lastSummary={};
if(mapDetails) mapDetails.open=true;
clearFilters(false);
hideAlert();
render();
updateCount();
setText(outputCount, '0 results');
setStatus('Ready', '');
input.focus();
});
}
if(selectAll){
selectAll.addEventListener('change', function (){
Array.prototype.forEach.call(resultBody.querySelectorAll('[data-result-index]'), function (checkbox){
checkbox.checked=selectAll.checked;
});
updateSelectAll();
});
}
if(resultBody){
resultBody.addEventListener('change', function (event){
if(event.target&&event.target.hasAttribute('data-result-index')) updateSelectAll();
});
}
if(input){
input.addEventListener('input', updateCount);
input.addEventListener('keydown', function (event){
if((event.ctrlKey||event.metaKey)&&event.key==='Enter') lookup();
});
}
if(format){
format.addEventListener('change', function (){
updateCustomVisibility();
render();
});
}
if(viewMode){
viewMode.addEventListener('change', function (){
if(viewMode.value==='network'&&format&&format.value==='full'){
format.value='network';
updateCustomVisibility();
}else if(viewMode.value==='location'&&format&&format.value==='network'){
format.value='full';
updateCustomVisibility();
}
render();
});
}
if(removeDuplicates){
removeDuplicates.addEventListener('change', function (){
setStatus(removeDuplicates.checked ? 'Duplicate removal enabled':'Duplicate removal disabled', '');
});
}
if(customTemplate) customTemplate.addEventListener('input', render);
updateCount();
render();
updateCustomVisibility();
loadFormatterHandoff();
}
function boot(){
Array.prototype.forEach.call(document.querySelectorAll('[data-ips-locations]'), initialize);
}
if(document.readyState==='loading'){
document.addEventListener('DOMContentLoaded', boot);
}else{
boot();
}}());