### Install Dependencies and Start Server Source: https://github.com/jsdelivr/globalping.io/blob/master/CONTRIBUTING.md Run these commands to set up the project locally and start the development server. ```bash npm install # to start the website npm start ``` -------------------------------- ### Production Configuration Example Source: https://github.com/jsdelivr/globalping.io/blob/master/CONTRIBUTING.md Example of how to configure the server port and other production-specific environment variables. ```javascript module.exports = { server: { port: "SERVER_PORT", // defaults to 4400 }, }; ``` -------------------------------- ### Hardware Probe Installation Guide Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Learn more about the Globalping hardware probe, its features, and how it simplifies network testing by removing the need for a 24/7 computer. The firmware is open source and secure. ```bash https://github.com/jsdelivr/globalping-hwprobe ``` -------------------------------- ### Install Globalping CLI Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Install the Globalping CLI to run and script network tests from your terminal. ```bash /cli ``` -------------------------------- ### Install Globalping Slack App Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Install the Globalping Slack App to allow members of your Slack organization to run global tests directly within any channel. ```bash /slack ``` -------------------------------- ### Setup Video Modal Event Handlers Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/video-modal.html Initializes the video modal by finding elements, setting up event listeners for Bootstrap modal events ('show.bs.modal', 'hide.bs.modal', 'hidden.bs.modal'), and a load handler for the video frame. This should be called once to set up the modal. ```javascript setupVideoModal () { if (this._videoModalHandlers) { return; } let modal = this.find('.c-gp-video-modal_modal'); let videoFrame = this.find('.c-gp-video-modal_iframe'); if (!modal) { return; } document.documentElement.classList.add('scrollbar-stable'); let $modal = $(modal); this.observe('view', (view) => { if (view === VIDEO_MODAL_VIEW) { this.openVideoModal(); } else if ($modal.hasClass('in')) { $modal.modal('hide'); } }, { init: false }); let showHandler = () => { this.activateVideoModalFrame(); }; let hideHandler = () => { this.moveVideoModalFocusOut(modal); }; let loadHandler = () => { if (videoFrame.getAttribute('src')) { videoFrame.classList.add('video-loaded'); this.getVideoModalPlayer(videoFrame); return; } videoFrame.classList.remove('video-loaded'); }; let hiddenHandler = () => { this.resetVideoModalState({ restoreFocus: true }); }; $modal.on('show.bs.modal', showHandler); $modal.on('hide.bs.modal', hideHandler); $modal.on('hidden.bs.modal', hiddenHandler); videoFrame?.addEventListener('load', loadHandler); this._videoModalHandlers = { modal, $modal, videoFrame, loadHandler, hideHandler, showHandler, hiddenHandler, }; } ``` -------------------------------- ### Module Imports for Globalping.io Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Imports necessary utility and decorator modules for the project. Ensure these modules are correctly installed and accessible. ```javascript const _ = require('../../assets/js/_.js'); const ipRegex = require('../../assets/js/utils/ip-regex'); const listeners = require('../../assets/js/utils/listeners'); const clipboard = require('../../assets/js/decorators/clipboard'); const http = require('../../assets/js/utils/http'); const dataCache = require('../../assets/js/utils/data-cache'); ``` -------------------------------- ### Initial Main Options for Network Tests Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Sets the initial default values for the main options when starting a network test. This includes the test type, target, location, and limit. ```javascript const INITIAL_MAIN_OPTS_VALUES = { type: 'ping', target: '', location: 'World', limit: '10', }; ``` -------------------------------- ### Initialize Session Timestamps and Counters Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/credits.html Sets the session start and current timestamps, and initializes consumed rate limit and credits to zero when the 'testInProgress' flag becomes true. Resets these values when 'testInProgress' becomes false. ```javascript this.observe('testInProgress', (testInProgress) => { if (testInProgress) { this.set('sessionTimestampStart', Date.now()); this.set('sessionTimestampCurrent', Date.now()); this.set('consumedRateLimit', 0); this.set('consumedCredits', 0); } else { this.set('sessionTimestampStart', null); this.set('sessionTimestampCurrent', null); this.set('overallProbesCount', 0); } }); ``` -------------------------------- ### Get Initial Raw Data from URL Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/network-tools.html Parses the URL to extract raw test type and location parameters, providing a display-friendly location name. ```javascript getInitialRawDataFromUrl () { let rawParamsValue = this.get('params'); let clearParamsValue = rawParamsValue.replace(/\/network-tools\/?/, '').toLowerCase(); let splitPoint = '-from-'; let splitPointIdx = clearParamsValue.indexOf(splitPoint); let [ rawTestType, rawLocation = 'world' ] = splitPointIdx === -1 ? clearParamsValue.split(splitPoint) : [ clearParamsValue.slice(0, splitPointIdx), clearParamsValue.slice(splitPointIdx + splitPoint.length) ]; let rawLocationToDisplay = _.capitalizeStrEveryFirstLetter((rawLocation || 'world').split('-').join(' '), CAPITALIZE_EXCLUDE_LIST); return { rawTestType, rawLocation, rawLocationToDisplay, }; } ``` -------------------------------- ### Initialize Ractive Component and Load Data Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Handles initial component setup, including loading map data, setting up screen width listeners, and initializing the map if the application is loaded. It also processes query parameters for measurement IDs to support share-result flows. ```javascript (!Ractive.isServer) { this.set('@shared.googleMapsLoaded', true); if (app.loaded) { setTimeout(this.initMap.bind(this)); } listeners.screenWidthListener(this); } }, oninit () { if (!Ractive.isServer) { this.on('c-header.main-logo-click', () => { this.set('measurement', ''); return false; }); // check if ids are present in query string // if so - it is a share-results-flow let measurement = this.get('measurement'); let qsMeasurementIdsArr = [] let isInfiniteMeas = false; let isMultiEpMeas = false; // A separator for IDs for regular link is a comma, for infinite one - plus sign if (measurement && measurement.includes(',')) { qsMeasurementIdsArr = measurement.split(','); isMultiEpMeas = true; } else if (measurement && measurement.includes('.')) { qsMeasurementIdsArr = measurement.split('.'); isInfiniteMeas = true; this.set('infiniteSwitchEnabled', true); this.set('isInfiniteModeRes', true); this.set('rawOutputMode', false); } else if (measurement) { qsMeasurementIdsArr = [ measurement ]; } if (qsMeasurementIdsArr.length) { this.set('qsMeasurementIdsArr', qsMeasurementIdsArr); this.set('shareResFlow', true); this.set('prevProbesMeasId', qsMeasurementIdsArr[0]); this.getMultipleTestMeasurementById(qsMeasurementIdsArr, isInfiniteMeas); } // read the map and display URL params and apply them let map = this.get('map'); let display = this.get('display'); if (map === 'hidden') { this.set('showMap', false); } let nonDefaultDisplayValue = isMultiEpMeas || isInfiniteMeas ? 'raw' : 'table'; if (display === nonDefaultDisplayValue) { // if valid, set the non-default value in params this.set('rawOutputMode', display === 'raw'); } else { // otherwise set the appropriate default value // for multi-endpoint tests, this always sets the display to table // if the test is not ping, it is changed back to raw in an observer this.set('rawOutputMode', nonDefaultDisplayValue !== 'raw'); } // read the sorting URL params and apply them let by = this.get('by'); let order = this.get('order'); let sortByVals = SORT_BY_OPTS.map(opt => opt.value); if (sortByVals.includes(by)) { this.set('sortBy', by); } if (SORT_ORDER_OPTS.includes(order)) { this.set('sortOrder', order); } // read the collapse URL param and apply it once results are available let collapse = this.get('collapse'); if (ALLOWED_COLLAPSE_OPTS.includes(collapse)) { this.set('collapseFromQuery', collapse); } // get probes from sessionStorage or fetch them and handle this.getProbesData(); let location = this.get('location'); if (location && !measurement) { this.set('locationAutofilled', true); } this.initResponseBodyCharWidth(); ``` -------------------------------- ### IPv6 HTTP GET from USA, Canada, Mexico Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/test-examples.html Perform an HTTP GET request using IPv6 from multiple specified locations. This example tests connectivity and response times for HTTP. ```javascript { type: 'HTTP', target: 'cdn.jsdelivr.net', location: 'USA, Canada, Mexico', limit: 10, ipVersion: 6, } ``` -------------------------------- ### Initialize Screen Width Observer Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/filtered-probe-list.html Sets up an observer to react to screen width changes, adjusting tooltip positions accordingly. Initializes screenWidth if not already set. ```javascript this.observe('screenWidth', (screenWidth) => { if (!screenWidth) { this.set('screenWidth', window.innerWidth); return; } // handle tooltips positions depending on the screen size let ttPositions = {}; if (screenWidth >= 1272) { ttPositions.targetTtPos = 'top'; ttPositions.locationTtPos = 'top'; ttPositions.limitTtPos = 'top'; } else if (screenWidth >= 768) { ttPositions.targetTtPos = 'top'; ttPositions.locationTtPos = 'right'; ttPositions.limitTtPos = 'top'; } else { ttPositions.targetTtPos = 'right'; ttPositions.locationTtPos = 'right'; ttPositions.limitTtPos = 'right'; } this.set('ttPositions', ttPositions); }); ``` -------------------------------- ### Get Location by IP Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves the location details for a given IP address. ```javascript getLocationByIp (ipAddr) { return this.getNetworkDataByIp(ipAddr)?.location || null; } ``` -------------------------------- ### Get Network Name Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves the name or domain of the network associated with an IP address. ```javascript getNetworkName (ipAddr) { let network = this.getNetworkDataByIp(ipAddr); return network?.name || network?.domain || null; } ``` -------------------------------- ### R-Meta Component Initialization Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/r-meta.html Handles the initialization of meta and SEO partials. It decorates these partials by filtering out specific nodes and injecting a class for SSR identification. It also sets up context links and updates the shared path. ```javascript const R_META_CLASS = 'r-meta-e'; Ractive.sharedSet('R_META_CLASS', R_META_CLASS); component.exports = { oninit () { let rPage = this.findParent('r-page'); let tMeta = rPage.partials.meta; let tSeo = rPage.partials.seo; let filterNodes = (o, predicate) => { if (Array.isArray(o)) { return o.filter(predicate).map(n => filterNodes(n, predicate)); } else if (o && typeof o === 'object') { return Object.fromEntries(Object.entries(o).map(([ key, value ]) => { return [ key, filterNodes(value, predicate) ]; })); } return o; }; let walkElements = (o, callback) => { if (Array.isArray(o)) { o.forEach(i => walkElements(i, callback)); } else if (o && typeof o === 'object') { if (o.t === 7) { callback(o); } Object.values(o).forEach(v => walkElements(v, callback)); } }; if (!tMeta._metaDecorated) { tMeta = filterNodes(tMeta, n => n.t !== 9); walkElements(tMeta, (e) => { e.m = e.m || []; e.m.push({ t: 13, n: 'class', f: R_META_CLASS }); }); tMeta._metaDecorated = true; } if (tSeo && !tSeo._metaDecorated) { tSeo = filterNodes(tSeo, n => n.t !== 9); walkElements(tSeo, (e) => { e.m = e.m || []; e.m.push({ t: 13, n: 'class', f: R_META_CLASS }); }); tSeo._metaDecorated = true; } // We need a way to identify the nodes rendered by the component via SSR // when running on the client. We do this by injecting a special class into // all elements in the template. rPage.partials.seo = tSeo; rPage.partials.meta = tMeta; this.partials = rPage.partials; this.resetPartial('meta', tMeta); // A bit of context hacking: // the meta partial itself renders with the context of r-page // the seo partial renders with the context of the current page (root context) this.link('', 'rootContext', { instance: rPage.parent }); this.link('', 'rPageContext', { instance: rPage }); // Update the shared path on page switch. this.set('@shared.actualPath', this.get('@shared')?.app?.router?.uri?.path); } }; ``` -------------------------------- ### Get Network Data by IP Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves the stored network data for a specific IP address. ```javascript getNetworkDataByIp (ipAddr) { return ipAddr ? this.get('networkDataByIp')[ipAddr] : null; } ``` -------------------------------- ### Initialize Component State and Options Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/network-tools.html Sets up the initial state for the network tools component, including default test types, options, and data structures for storing results and errors. ```javascript const = require('../../assets/js/_ '); const http = require('../../assets/js/utils/http'); const dataCache = require('../../assets/js/utils/data-cache'); const countries = require('../../assets/json/countries.json'); const continents = require('../../assets/json/continents.json'); const usaStates = require('../../assets/json/usa-states.json'); const DEFAULT_LIMIT = 3; const INITIAL_OPTS_VALUES = { type: 'Ping', target: 'cdn.jsdelivr.net', }; const CAPITALIZE_EXCLUDE_LIST = [ 'and', 'or', 'from', 'ltd', 'of' ]; const RATE_LIMIT_HEADERS = [ 'x-ratelimit-remaining', 'x-ratelimit-reset', 'x-credits-remaining', 'x-request-cost', ]; const PROBE_NO_TIMING_VALUE = _.getProbeTimeOutValue(); const PROBE_STATUS_OFFLINE = _.getProbeStatusOfflineValue(); component.exports = { data () { return { _, title: '', description: '', selectedTestType: null, displayingTestType: INITIAL_OPTS_VALUES.type, btnTestType: INITIAL_OPTS_VALUES.type, testTypesList: [ { name: 'Ping', toDisplay: 'Ping' }, { name: 'Traceroute', toDisplay: 'Traceroute' }, { name: 'DNS', toDisplay: 'DNS resolve' }, { name: 'MTR', toDisplay: 'MTR' }, { name: 'HTTP', toDisplay: 'HTTP' }, ], testOpts: { target: INITIAL_OPTS_VALUES.target, limit: '', }, inputErrors: {}, errorMessage: null, testResults: null, testInProgress: false, testReqCancelFn: null, defaultTestLimit: DEFAULT_LIMIT, probesResponse: null, locationData: null, totalProbesCnt: 0, parsedLocations: { cities: {}, asns: {}, networks: {}, countries: {}, continents: {}, regions: {}, states: {}, cloudRegions: {}, }, highLevelLocationHref: null, probesParsed: false, testReqParams: null, preparedTestResults: [], hiddenTestResults: { 0: [] }, rawLocation: null, rawLocationToDisplay: null, allRequiredDataReady: false, }; }, onconfig () { if (!Ractive.isServer) { let title, description; let { rawTestType, rawLocation, rawLocationToDisplay } = this.getInitialRawDataFromUrl(); // create temp title, descr before any checks, required by GA title = this.createMetaTitle(rawTestType, rawLocationToDisplay); description = this.createMetaDescr(rawTestType, rawLocationToDisplay); this.set('title', title); this.set('description', description); this.set('selectedTestType', rawTestType); this.set('rawLocation', rawLocation); this.set('rawLocationToDisplay', rawLocationToDisplay); } }, oninit () { if (!Ractive.isServer) { this.getGlobalpingProbesData(); this.observe('selectedTestType', (selectedTestType) => { if (selectedTestType) { switch (selectedTestType.toLowerCase()) { case 'mtr': case 'http': this.set('displayingTestType', selectedTestType.toUpperCase()); this.set('btnTestType', selectedTestType.toUpperCase()); break; case 'dns': this.set('displayingTestType', `${selectedTestType.toUpperCase()} resolve`); this.set('btnTestType', selectedTestType.toUpperCase()); break; default: this.set('displayingTestType', _.capitalizeStrEveryFirstLetter(selectedTestType)); this.set('btnTestType', _.capitalizeStrEveryFirstLetter(selectedTestType)); } } this.set('inputErrors', {}); this.set('testResults', null); this.expandAllRawOutput(); }); this.observe('realTimeTestResResponse', (realTimeTestResResponse) => { if (realTimeTestResResponse.status === 'finished') { this.get('testReqCancelFn')?.(); this.set('testInProgress', false); } let prevTestResults = this.get('testResults') || []; let updTestResults = realTimeTestResResponse.results.map((res, resIdx) => ({ ...res, clientSideId: res.clientSideId ?? resIdx, })); // filter out results that have already been drawn prevTestResults = prevTestResults.filter((prevRes) => { return !updTestResults.some(updRes => updRes.clientSideId === prevRes.clientSideId); }); this.set('testResults', [ ...prevTestResults, ...updTestResults, ]); }, { init: false }); // check if everything is already set and we can get LocationData etc. this.observe('probesParsed selectedTestType rawLocation', () => { let probesParsed = this.get('probesParsed'); let selectedTestType = this.get('selectedTestType'); let rawLocation = this.get('rawLocation'); if (probesParsed && selectedTestType && rawLocation) { this.set('allRequiredDataReady', true); } else { this.set('allRequiredDataReady', false); } }); // create and set meta title, description; locationData, highLevelLocationHref // check if location is correct or presented in the available probes locations this.observe('allRequiredDataReady', (allRequiredDataReady) => { if (allRequiredDataReady === false) { return; } let selectedTestType = this.get('selectedTestType'); let rawLocation = this.get('rawLocation'); // handle locationData, highLevelLocationHref if (rawLocation && rawLocation.toLowerCase() !== 'world') { let locationData = this.getLocDataByLocValue(rawLocation); if (locationData) { // if both location and testType are correct and present this.set('locationData', locationData); this.set('highLevelLocationHref', `${global.location.origin}${this.modifyQueryPart(selectedTestType, locationData.fromAsUrlPart)}`); } } }); } }; ``` -------------------------------- ### Get IP Location Country Code Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves the country code for the location associated with an IP address. ```javascript getIpLocationCountryCode (ipAddr) { return this.getLocationByIp(ipAddr)?.country || null; } ``` -------------------------------- ### Become a GitHub Sponsor Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Support the Globalping project by becoming a GitHub sponsor. Sponsors of $10/month or more receive a hardware probe. ```bash https://github.com/sponsors/jsdelivr ``` -------------------------------- ### Run Globalping Container Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Join the Globalping probe network by running the provided container. This container works on both x86 and ARM architectures. ```bash docker run -d --name globalping-agent -e GLOBALPING_TOKEN=YOUR_TOKEN ghcr.io/jsdelivr/globalping-agent:latest ``` -------------------------------- ### Ping from Amazon+Virginia Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/test-examples.html Perform a standard ping test from Amazon's US-VA location to a target. This example uses IPv4. ```javascript { type: 'ping', target: 'cdn.jsdelivr.net', location: 'Amazon.com+US-VA', limit: 10, ipVersion: 4, } ``` -------------------------------- ### Initialize Markdown Component with Libraries Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/markdown.html Initializes the Markdown component by injecting global styles and dynamically importing necessary libraries for markdown parsing and syntax highlighting. It sets up observers to re-render HTML when markdown content changes. ```javascript const _ = require('../../assets/js/_.js'); const ID_PREFIX = 'id-'; component.exports = { data() { return { _, html: '', markdown: '', }; }, oninit() { if (!Ractive.isServer) { _.injectGlobalStyle('https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.7.0/build/styles/github.min.css'); Promise.all([ // eslint-disable-next-line n/no-missing-import import('https://cdn.jsdelivr.net/npm/marked@17.0.1/+esm'), // eslint-disable-next-line n/no-missing-import import('https://cdn.jsdelivr.net/npm/marked-gfm-heading-id@4.1.3/+esm'), // eslint-disable-next-line n/no-missing-import import('https://cdn.jsdelivr.net/npm/marked-highlight@2.2.3/+esm'), // eslint-disable-next-line n/no-missing-import import('https://cdn.jsdelivr.net/npm/@highlightjs/cdn-assets@11.7.0/es/highlight.min.js'), ]).then(([{ marked }, { gfmHeadingId }, { markedHighlight }, { default: hljs }]) => { marked.use({ renderer: { table (...rows) { return `
${rows.join('')}
`; }, }, }); marked.use(gfmHeadingId({ prefix: ID_PREFIX })); marked.use(markedHighlight({ langPrefix: 'hljs language-', highlight (code, language) { return hljs.getLanguage(language) ? hljs.highlightAuto(code, [ 'html', 'javascript', 'sh', 'bash' ]).value : code; }, })); this.observe('markdown', (md) => { this.set('html', marked.parse(md)); }); }); } }, }; ``` -------------------------------- ### Initialize Network View Component Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/network.html Sets up the initial data structure for the network view component, including default grouping and sorting options, and state variables for probe data, loading status, and errors. ```javascript const _ = require('../../assets/js/_'); const listeners = require('../../assets/js/utils/listeners'); const dataCache = require('../../assets/js/utils/data-cache'); const http = require('../../assets/js/utils/http'); const GROUP_DEFAULT = 'city'; const DEFAULT_SORT_OPTIONS = { 'country': 'alphabetically', 'city': 'alphabetically', 'network': 'probe-count', 'country-network': 'alphabetically', 'city-network': 'alphabetically', 'disabled': 'alphabetically', }; component.exports = { data() { return { _, title: 'Network - Globalping', description: 'Explore the global network map of Globalping probes.', location: 'World', locationCompletedValue: '', groupBy: GROUP_DEFAULT, sortOrder: DEFAULT_SORT_OPTIONS[GROUP_DEFAULT], defaultSortOptions: DEFAULT_SORT_OPTIONS, probesResponse: null, probesLoading: false, probesError: null, filteredProbes: null, filteredMarkersData: null, filteredProbesStats: null, }; }, ``` -------------------------------- ### Get Network ASN by IP Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves the Autonomous System Number (ASN) for a given IP address from the network data. ```javascript getNetworkAsnByIp (ipAddr) { let network = this.getNetworkDataByIp(ipAddr); return network?.asn || null; } ``` -------------------------------- ### Initialize and Resize Handlers Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Sets up event listeners for window resize to recalculate layout states and handles initial rendering logic. It also observes changes in test results and active targets to update the UI. ```javascript onrender () { if (!Ractive.isServer) { this.set('networkLookupsActive', true); this. _resizeHeaderInfoHandler = () => { this.recalculateHeaderInfoLayoutStates(); }; this.initHeaderInfoCharWidths(); this.recalculateHeaderInfoLayoutStates(); listeners.addManagedListener(this, window, 'resize', this. _resizeHeaderInfoHandler); // open a specific item if it was scrolled to from the parent component this.observe('scrolledToResId', (clientSideId) => { if (clientSideId === null) { return; } let activeTargetIdx = this.get('activeTargetIdx'); let hiddenTestResults = this.get( `hiddenTestResults[${activeTargetIdx}] ` ); let targetId = hiddenTestResults.find(resId => resId === clientSideId); if (typeof targetId === 'number') { this.set('skipNextResize', true); this.hideShowTestResult(targetId); } this.set('scrolledToResId', null); }, { init: false }); this.observe('preparedTestResults testInProgress', () => { this.resetHeaderInfoEntityWidthCache(); this.recalculateHeaderInfoLayoutStates({ allowShrink: this.shouldAllowResultsBlockShrink(), }); requestAnimationFrame(() => { this.hideSetLocationButtonIfMoved(); }); }, { deep: true, defer: true }); this.observe('hiddenTestResults', () => { if (this.get('skipNextResize')) { this.set('skipNextResize', false); return; } this.setResultsBlockHeight({ allowShrink: false, }); }, { deep: true, defer: true, init: false }); this.observe('hiddenResponseBodies', () => { this.setResultsBlockHeight({ allowShrink: false, }); }, { deep: true, defer: true, init: false }); this.observe('preparedTestResults activeTargetIdx', () => { this.resetHeaderInfoEntityWidthCache(); this.populateNetworkData(); this.recalculateHeaderInfoLayoutStates({ allowShrink: false, }); }); this.observe('sortOrder sortBy activeTargetIdx', () => { let listEl = this.find('.c-gp-results-raw-output_list'); if (listEl) { listEl.scrollTop = 0; } this.recalculateHeaderInfoLayoutStates(); }, { init: false }); this. _onSetLocationViewportChange = (event) => { this.hideSetLocationButton(event); }; this. _setLocationListEl = this.find('.c-gp-results-raw-output_list'); listeners.addManagedListener(this, window, 'resize', this. _onSetLocationViewportChange); listeners.addManagedListener(this, window, 'scroll', this. _onSetLocationViewportChange); if (this. _setLocationListEl) { listeners.addManagedListener(this, this. _setLocationListEl, 'scroll', this. _onSetLocationViewportChange); } } } ``` -------------------------------- ### Compare bing.com to google.com from Eastern Europe Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/test-examples.html Compare network performance between two targets from a specified region. This example uses IPv4. ```javascript { type: 'ping', target: 'bing.com,google.com', location: 'Eastern Europe', limit: 10, ipVersion: 4, } ``` -------------------------------- ### Get Status Color Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Determines the appropriate color indicator for a target's status based on error status or average timing. ```javascript getStatusColor (targetStats) { if (targetStats.extraValues?.errorStatus) { return _.getGpProbeStatusColor(targetStats.extraValues.errorStatus); } return _.getGpProbeStatusColor(targetStats.avgTiming, this.get('testReqParams').type === 'http' ? 1000 : 200); } ``` -------------------------------- ### Globalping Probe GitHub Repository Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Examine the codebase for Globalping's software probes and firmware for hardware probes. Contribute to the development of the probe software. ```bash https://github.com/jsdelivr/globalping-probe ``` -------------------------------- ### Globalping CLI GitHub Repository Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Access the source code for the Globalping CLI, a simple-to-use command-line interface for network testing. Provide feedback and contribute. ```bash https://github.com/jsdelivr/globalping-cli ``` -------------------------------- ### Get Failure Probe Raw Output Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Retrieves the raw output for probes that have failed or are offline. This is useful for debugging and understanding the cause of failure. ```javascript getFailureProbeRawOutput (probeData) { let rawOutput; let { status = null } = probeData.result; if (status === PROBE_STATUS_OFFLINE || status === PROBE_STATUS_FAILED) { rawOutput = probeData.result.rawOutput; } return rawOutput; } ``` -------------------------------- ### Get IP Location Label Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Generates a human-readable location string (city, state, country) for an IP address, excluding Anycast IPs. ```javascript getIpLocationLabel (ipAddr) { let location = this.getLocationByIp(ipAddr); if (!location || location.isAnycast) { return null; } let values = [ location.city, location.state, location.country ].filter(Boolean); return values.length ? values.join(', ') : null; } ``` -------------------------------- ### Component Initialization and Probe Data Handling Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/network.html Handles component initialization, including setting up listeners and fetching probe data. It also observes changes in filtered probes to recalculate statistics and map marker data. ```javascript oninit() { if (!Ractive.isServer) { this.getProbesData(); this.observe('filteredProbes', (filteredProbes) => { if (filteredProbes === null) { return; } // recalculate ASNs let asns = filteredProbes.reduce((asns, probe) => { asns.add(probe.location.asn); return asns; }, new Set()); this.set('filteredProbesStats', { count: filteredProbes.length, asns: asns.size }); // recalculate map markers let groupedByCoords = filteredProbes.reduce((res, probe) => { let coords = `${probe.location.latitude}, ${probe.location.longitude}`; // group by Coordinates if (!Object.hasOwn(res, coords)) { res[coords] = []; } res[coords].push(probe); return res; }, {}); setTimeout(() => this.set('filteredMarkersData', groupedByCoords), 50); }); } }, onrender() { if (!Ractive.isServer) { listeners.screenWidthListener(this); } }, getProbesData() { this.set('probesLoading', true); this.set('probesError', null); dataCache.getCache('probesResponse', 60 * 1000, http.fetchGlobalpingProbes) .then(value => this.set('probesResponse', value)) .catch((error) => { console.error('Failed to fetch probes', error); this.set('probesError', error); }) .finally(() => this.set('probesLoading', false)); }, handleProbesByCoordsChange() { let locationCompletedValue = this.get('locationCompletedValue'); return !!locationCompletedValue?.length; }, }; ``` -------------------------------- ### Get Country Name from Code Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/filtered-probe-list.html Retrieves the full country name from its code using a predefined COUNTRIES_MAP. Returns the code itself if no mapping is found. ```javascript getCountryName (code) { return COUNTRIES_MAP[code] || code; } ``` -------------------------------- ### Proceed to Network Test Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/network-tools.html Initiates a network test by sending a POST request to the Globalping measurement API. Handles success by fetching the measurement by ID and catches errors, setting appropriate messages or input errors. ```javascript proceedToTest () { let type = this.get('selectedTestType'); let testOpts = this.get('testOpts'); let { name: magic = 'World' } = this.get('locationData'); let reqParams = { type, ...testOpts, locations: [ { magic } ], }; if (!reqParams.limit) { reqParams.limit = DEFAULT_LIMIT; } // clear all data from the previous test, show spinner this.set('testResults', null); this.set('testInProgress', true); this.set('testReqParams', null); this.set('errorMessage', null); this.set('preparedTestResults', []); this.expandAllRawOutput(); http.postGlobalpingMeasurement(reqParams, RATE_LIMIT_HEADERS).then((res) => { this.getTestMeasurementById(res.response.id); }).catch((err) => { let errBody = err?.error; this.set('testInProgress', false); if (errBody?.type === 'validation_error') { let inputErrors = _.parseValidationErrors(errBody); this.set('inputErrors', inputErrors); } else if (err.responseStatusCode === 429) { let measurementErrMsg = _.createMeasCreditsErrMsg( err.responseHeaders, this.get('@shared.user'), ); this.set('errorMessage', measurementErrMsg); } else { this.set('errorMessage', err.error?.message ?? 'An unexpected error occurred.'); } }); } ``` -------------------------------- ### Get Continent Name from Code Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/filtered-probe-list.html Retrieves the full continent name from its code using a predefined CONTINENT_MAP. Returns the code itself if no mapping is found. ```javascript getContinentName (code) { return CONTINENT_MAP[code] || code; } ``` -------------------------------- ### Set Initial Screen Width Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Sets the initial screen width if it hasn't been defined yet. ```javascript if (!screenWidth) { this.set('screenWidth', window.innerWidth); } ``` -------------------------------- ### DNS Resolve from China Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/test-examples.html Perform a DNS resolution test from China to a specified target. This example checks DNS query times and success rates. ```javascript { type: 'DNS', target: 'cdn.jsdelivr.net', location: 'China', limit: 10, } ``` -------------------------------- ### Detailed Podman Command for Probe Container Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Provides a detailed Podman command for the globalping-probe container, structured as an array of objects. This format allows for detailed explanations of each command part, including necessary sudo privileges, network settings, and restart policies. ```javascript const PODMAN_CMD_CONTENT_FULL = [ { cmd: 'sudo \\', comment: ' # Allows the --cap-add=NET_RAW option to work properly' }, { cmd: 'podman run -d \\', comment: ' # The container will NOT start on boot. You need to create a systemd service first.' }, { cmd: '--cap-add=NET_RAW \\', comment: ' # Network permissions to run ping' }, { cmd: '--network host \\', comment: '# Bypass overlay and mesh networking to ensure they dont impact latency tests' }, { cmd: '--restart=always \\', comment: ' # Restart the container if it crashes' }, { cmd: '--name globalping-probe globalping/globalping-probe', comment: '' }, ]; ``` -------------------------------- ### Initialize Input Value and Prepare Source Data Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/location-input.html Sets the initial query value and prepares the source data by normalizing and counting unique values. This function is designed to handle case-insensitive counting. ```javascript // Fill in the initial value and show the input. setQuery(this.get('value') || ''); setTimeout(() => { this.set('swapInputs', true); }); // Prepare the source data. let uniqCountSortNormalize = (values, caseInsensitive = false) => { let countValues = values.reduce((acc, value) => { let key = caseInsensitive ? value.toLowerCase() : value; if (!Object.hasOwn(acc, key)) { acc[key] = { count: 0, value, }; } acc[key].count += 1; return acc; }, {}); return Object.keys(countValues).map(key => ({ value: countValues[key].value, normalizedValue: key.toLowerCase(), count: countValues[key].count, })).sort((a, b) => b.count - a.count); }; let createNormalizedProbeList = (probes) => { normalizedProbes = probes.map((probe) => { let countryName = countriesByCode[probe.location.country]?.name || probe.location.country; let continentName = continentsByCode[probe.location.continent]?.name || probe.location.continent; let normalizedProbe = { city: `${probe.location.city}\n${probe.location.state ? `US-${probe.location.state}\n` : '\n'}${countryName}\n${probe.location.country}`, region: probe.location.region, state: probe.location.state ? `US-${probe.location.state}` : '', country: `${countryName}\n${probe.location.country}`, continent: `${continentName}\n${probe.location.continent}`, network: probe.location.network.trim(), tags: probe.tags.filter(tag => !tag.startsWith('u-')) }; if (probe.location.country === 'GB') { normalizedProbe.country += `\nUK\nGreat Britain\nEngland`.toLowerCase(); } return { ...normalizedProbe, original: probe, allValues: Object.values(normalizedProbe).map(value => Array.isArray(value) ? value.join('\n').toLowerCase() : value.toLowerCase()).join('\n') }; }); indexForConditions = Object.create(null); }; let filterProbesByCurrentParts = (query) => { if (!this.get('exposeProbes')) { return; } let uniq = new Set(); query.split(',').forEach((part) => { let partNormalized = part.split('+').map(q => q.trim()).filter(v => v).map(s => s.toLowerCase()).sort(); filterProbes(normalizedProbes, partNormalized).forEach(p => uniq.add(p.original)); }); this.set('results', Array.from(uniq)); }; let filterProbes = (normalizedProbes, conditions) => { return conditions.reduce((filteredProbes, condition) => { if (condition === 'world') { return normalizedProbes; } let exactPattern = new RegExp(`(?:^|\n)${escapeRegExp(condition)}(?:$|\n)`, 'm'); let exactMatchFound = false; let looseMatchFound = false; filteredProbes = filteredProbes.filter((probe) => { if (!probe.allValues.includes(condition)) { return false; } if (exactPattern.test(probe.allValues)) { exactMatchFound = true; } else { looseMatchFound = true; } return true; }); if (exactMatchFound && looseMatchFound) { filteredProbes = filteredProbes.filter(probe => exactPattern.test(probe.allValues)); } return filteredProbes; }); }; ``` -------------------------------- ### Initiate Infinite Ping Measurement Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Starts an infinite ping measurement if the conditions are met (ping type, single target, infinite switch enabled). ```javascript // run Infinite type of the measurement if (type === 'ping' && targetsArr.length === 1 && infiniteSwitchEnabled) { this.postInfiniteGlobalpingMeasurement({ reqParams, target: targetsArr[0], testRunId }); return; } ``` -------------------------------- ### Detailed Docker Command for Probe Container Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Constructs a detailed Docker command for running the globalping-probe container, broken down into an array of objects for clarity. Each object specifies a command part and an optional comment explaining its purpose, such as network configuration and restart policies. ```javascript const DOCKER_CMD_CONTENT_FULL = [ { cmd: 'docker run -d \\', comment: ' # Make sure the container runs on boot' }, { cmd: '--log-driver local \\', comment: ' # Use the modern logging driver to ensure old logs are deleted' }, { cmd: '--network host \\', comment: ' # Bypass overlay and mesh networking to ensure they dont impact latency tests' }, { cmd: '--restart=always \\', comment: ' # Restart the container if it crashes' }, { cmd: '--name globalping-probe globalping/globalping-probe', comment: '' }, ]; ``` -------------------------------- ### Get Multiple Test Measurements by ID Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Asynchronously fetches multiple test measurements by their IDs in sequence. Useful for retrieving results for a batch of tests. ```javascript async getMultipleTestMeasurementById (idsArr, isInfiniteMeas = false) { for (let i = 0; i < idsArr.length; i++) { await this.getTestMeasurementById({ measurementId: idsArr[i], resNumber: i, isShareResCase: true, isFirstShareReq: i === 0, isLastShareReq: idsArr.length - 1 === i, isInfiniteMeas, }); } } ``` -------------------------------- ### Get Header Primary Metrics Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Extracts primary metrics (DNS status, HTTP status, answers) from extra values, filtering out any falsy ones. ```javascript getHeaderPrimaryMetrics (extraValues = {}) { return [ extraValues.dnsStatus, extraValues.httpStatus, extraValues.answers, ].filter(Boolean); } ``` -------------------------------- ### Integrate Globalping REST API Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/pages/_index.html Use the free Globalping REST API to build custom tools, automate tests, and integrate Globalping into your existing workflows. ```bash /docs/api.globalping.io ``` -------------------------------- ### Get Cached Header Info Entity Widths Source: https://github.com/jsdelivr/globalping.io/blob/master/src/views/components/results-raw-output.html Retrieves pre-calculated widths for target and source entities from the cache. If not found, it calculates them and stores them in the cache. ```javascript getHeaderInfoEntityWidths (result) { let cacheKey = this.getHeaderInfoEntityWidthCacheKey(result); let headerInfoEntityWidthsByKey = this.get('headerInfoEntityWidthsByKey'); let cached = headerInfoEntityWidthsByKey.get(cacheKey); if (cached) { return cached; } let target = this.getHeaderInfoTargetEntityWidth(result); let source = target ? this.getHeaderInfoSourceEntityWidth(result) : 0; let widths = { target, source }; headerInfoEntityWidthsByKey.set(cacheKey, widths); return widths; } ```