### 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 `