{"id":7549,"date":"2022-12-07T23:25:04","date_gmt":"2022-12-08T04:25:04","guid":{"rendered":"https:\/\/weather.umd.edu\/wordpress\/?page_id=7549"},"modified":"2023-08-18T13:21:19","modified_gmt":"2023-08-18T17:21:19","slug":"data-request","status":"publish","type":"page","link":"https:\/\/weather.umd.edu\/wordpress\/micronet\/data-request\/","title":{"rendered":"Data Download"},"content":{"rendered":"\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\"><\/div>\n\n\n\n\n<div class=\"widget widget_umdwx_data_request_widget\">\r\n            <div id=\"umdwx-data-request-1\" class=\"umdwx-data-request-widget\">\r\n                <form class=\"umdwx-data-request-form\">\r\n\r\n                    <fieldset>\r\n                        <legend>Date range and time format<\/legend>\r\n\r\n                        <p>\r\n                            <label>\r\n                                Start Date:\r\n                                <input type=\"date\" data-role=\"start-date\" required>\r\n                            <\/label>\r\n                        <\/p>\r\n\r\n                        <p>\r\n                            <label>\r\n                                End Date:\r\n                                <input type=\"date\" data-role=\"end-date\" required>\r\n                            <\/label>\r\n                        <\/p>\r\n\r\n                        <p>\r\n                            <span>Time Format:<\/span>\r\n\r\n                            <label>\r\n                                <input\r\n                                    type=\"radio\"\r\n                                    name=\"umdwx-data-request-1-time-format\"\r\n                                    data-role=\"time-format\"\r\n                                    value=\"unix\"\r\n                                    checked\r\n                                >\r\n                                Unix\r\n                            <\/label>\r\n\r\n                            <label>\r\n                                <input\r\n                                    type=\"radio\"\r\n                                    name=\"umdwx-data-request-1-time-format\"\r\n                                    data-role=\"time-format\"\r\n                                    value=\"UTC\"\r\n                                >\r\n                                UTC\r\n                            <\/label>\r\n\r\n                            <label>\r\n                                <input\r\n                                    type=\"radio\"\r\n                                    name=\"umdwx-data-request-1-time-format\"\r\n                                    data-role=\"time-format\"\r\n                                    value=\"EST\"\r\n                                >\r\n                                Eastern\r\n                            <\/label>\r\n                        <\/p>\r\n                    <\/fieldset>\r\n\r\n                    <br>\r\n\r\n                    <fieldset>\r\n                        <legend>Select Stations to Include<\/legend>\r\n\r\n                        <table style=\"display:inline-block; margin-right:30px; border:0;\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-atlantic\">Atlantic<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-atlantic\" type=\"checkbox\" data-role=\"station\" value=\"atlantic\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-golf\">Golf Course<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-golf\" type=\"checkbox\" data-role=\"station\" value=\"golf\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-williams\">AV Williams Building<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-williams\" type=\"checkbox\" data-role=\"station\" value=\"williams\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-vmh\">Van Munching Hall<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-vmh\" type=\"checkbox\" data-role=\"station\" value=\"vmh\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-chem\">Chemistry Building<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-chem\" type=\"checkbox\" data-role=\"station\" value=\"chem\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-observ\">Observatory Building<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-observ\" type=\"checkbox\" data-role=\"station\" value=\"observ\" checked><\/td>\r\n                                <\/tr>\r\n                            <\/tbody>\r\n                        <\/table>\r\n                    <\/fieldset>\r\n\r\n                    <br>\r\n\r\n                    <fieldset>\r\n                        <legend>Select Data to Include<\/legend>\r\n\r\n                        <table style=\"display:inline-block; border:0;\">\r\n                            <tbody>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-all-data\"><strong>Select All<\/strong><\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-all-data\" type=\"checkbox\" data-role=\"all-data\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-outTemp\">Temperature (F)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-outTemp\" type=\"checkbox\" data-role=\"data-column\" data-column=\"outTemp\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-dewpoint\">Dewpoint (F)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-dewpoint\" type=\"checkbox\" data-role=\"data-column\" data-column=\"dewpoint\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-barometer\">Pressure (inHg)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-barometer\" type=\"checkbox\" data-role=\"data-column\" data-column=\"barometer\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-windSpeed\">Wind Speed (mph)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-windSpeed\" type=\"checkbox\" data-role=\"data-column\" data-column=\"windSpeed\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-windGust\">Wind Gust (mph)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-windGust\" type=\"checkbox\" data-role=\"data-column\" data-column=\"windGust\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-windDir\">Wind Direction (deg)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-windDir\" type=\"checkbox\" data-role=\"data-column\" data-column=\"windDir\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-rainRate\">Rain Rate (in\/hr)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-rainRate\" type=\"checkbox\" data-role=\"data-column\" data-column=\"rainRate\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-rain\">1-min Rainfall (in)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-rain\" type=\"checkbox\" data-role=\"data-column\" data-column=\"rain\" checked><\/td>\r\n                                <\/tr>\r\n                                <tr>\r\n                                    <td><label for=\"umdwx-data-request-1-totalDailyRain\">Total Daily Rain (in)<\/label><\/td>\r\n                                    <td><input id=\"umdwx-data-request-1-totalDailyRain\" type=\"checkbox\" data-role=\"total-daily-rain\"><\/td>\r\n                                <\/tr>\r\n                            <\/tbody>\r\n                        <\/table>\r\n                    <\/fieldset>\r\n\r\n                    <br>\r\n\r\n                    <p>\r\n                        <label>\r\n                            Choose Output File Type:\r\n                            <select data-role=\"output\" style=\"-webkit-appearance:auto;\">\r\n                                <option value=\"CSV\">CSV (separate files)<\/option>\r\n                                <option value=\"XLSX\">XLSX (one file)<\/option>\r\n                            <\/select>\r\n                        <\/label>\r\n                    <\/p>\r\n\r\n                    <p>\r\n                        <button type=\"submit\">Download Data<\/button>\r\n                    <\/p>\r\n\r\n                    <p data-role=\"status\" aria-live=\"polite\"><\/p>\r\n                <\/form>\r\n            <\/div>\r\n\r\n            <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/xlsx\/0.18.5\/xlsx.full.min.js\"><\/script>\r\n            <script>\r\n            (function () {\r\n                'use strict';\r\n\r\n                const root = document.getElementById(\"umdwx-data-request-1\");\r\n                const endpoint = \"https:\\\/\\\/weather.umd.edu\\\/wordpress\\\/wp-content\\\/plugins\\\/meso-fsct\\\/functions\\\/get-data.php\";\r\n\r\n                if (!root) {\r\n                    return;\r\n                }\r\n\r\n                const form = root.querySelector('.umdwx-data-request-form');\r\n                const startInput = root.querySelector('[data-role=\"start-date\"]');\r\n                const endInput = root.querySelector('[data-role=\"end-date\"]');\r\n                const outputInput = root.querySelector('[data-role=\"output\"]');\r\n                const statusElement = root.querySelector('[data-role=\"status\"]');\r\n                const allDataCheckbox = root.querySelector('[data-role=\"all-data\"]');\r\n                const totalRainCheckbox = root.querySelector('[data-role=\"total-daily-rain\"]');\r\n                const dataCheckboxes = Array.from(root.querySelectorAll('[data-role=\"data-column\"]'));\r\n\r\n                const stationDbMap = {\r\n                    atlantic: 'mesoterp13DB',\r\n                    vmh: 'mesoterp1DB',\r\n                    williams: 'mesoterp8DB',\r\n                    golf: 'mesoterp6DB',\r\n                    chem: 'mesoterp3DB',\r\n                    observ: 'mesoterp2DB'\r\n                };\r\n\r\n                const headerMap = {\r\n                    dateTime: 'Date\/Time',\r\n                    outTemp: 'outTemp (F)',\r\n                    dewpoint: 'dewpoint (F)',\r\n                    barometer: 'barometer (inHg)',\r\n                    windSpeed: 'windSpeed (mph)',\r\n                    windGust: 'windGust (mph)',\r\n                    windDir: 'windDir (deg)',\r\n                    rainRate: 'rainRate (in\/hr)',\r\n                    rain: '1-min rain (in)',\r\n                    totalDailyRain: 'Total Daily Rain (in)'\r\n                };\r\n\r\n                function formatDateInput(date) {\r\n                    const adjusted = new Date(date.getTime() - date.getTimezoneOffset() * 60000);\r\n                    return adjusted.toISOString().slice(0, 10);\r\n                }\r\n\r\n                function setDefaultDates() {\r\n                    const today = new Date();\r\n                    const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);\r\n                    startInput.value = formatDateInput(yesterday);\r\n                    endInput.value = formatDateInput(today);\r\n                }\r\n\r\n                function getTimeZoneOffset(date, timeZone) {\r\n                    const formatter = new Intl.DateTimeFormat('en-US', {\r\n                        timeZone: timeZone,\r\n                        year: 'numeric',\r\n                        month: '2-digit',\r\n                        day: '2-digit',\r\n                        hour: '2-digit',\r\n                        minute: '2-digit',\r\n                        second: '2-digit',\r\n                        hourCycle: 'h23'\r\n                    });\r\n\r\n                    const parts = formatter.formatToParts(date);\r\n                    const values = {};\r\n\r\n                    parts.forEach(function (part) {\r\n                        if (part.type !== 'literal') {\r\n                            values[part.type] = Number(part.value);\r\n                        }\r\n                    });\r\n\r\n                    const representedAsUtc = Date.UTC(\r\n                        values.year,\r\n                        values.month - 1,\r\n                        values.day,\r\n                        values.hour,\r\n                        values.minute,\r\n                        values.second\r\n                    );\r\n\r\n                    return representedAsUtc - date.getTime();\r\n                }\r\n\r\n                function easternMidnightEpoch(dateString) {\r\n                    const parts = dateString.split('-').map(Number);\r\n                    const utcGuess = Date.UTC(parts[0], parts[1] - 1, parts[2], 0, 0, 0);\r\n\r\n                    let offset = getTimeZoneOffset(new Date(utcGuess), 'America\/New_York');\r\n                    let timestamp = utcGuess - offset;\r\n\r\n                    offset = getTimeZoneOffset(new Date(timestamp), 'America\/New_York');\r\n                    timestamp = utcGuess - offset;\r\n\r\n                    return Math.floor(timestamp \/ 1000);\r\n                }\r\n\r\n                function utcMidnightEpoch(dateString) {\r\n                    return Math.floor(Date.parse(dateString + 'T00:00:00Z') \/ 1000);\r\n                }\r\n\r\n                function formatEasternDate(unixSeconds) {\r\n                    return new Intl.DateTimeFormat('en-US', {\r\n                        timeZone: 'America\/New_York',\r\n                        year: 'numeric',\r\n                        month: '2-digit',\r\n                        day: '2-digit'\r\n                    }).format(new Date(Number(unixSeconds) * 1000));\r\n                }\r\n\r\n                function formatTimestamp(unixSeconds, timeFormat) {\r\n                    const timestamp = Number(unixSeconds);\r\n\r\n                    if (timeFormat === 'UTC') {\r\n                        return new Date(timestamp * 1000).toUTCString().replace(\/,\/g, '');\r\n                    }\r\n\r\n                    if (timeFormat === 'EST') {\r\n                        return new Date(timestamp * 1000).toLocaleString('en-US', {\r\n                            timeZone: 'America\/New_York'\r\n                        }).replace(\/,\/g, '');\r\n                    }\r\n\r\n                    return timestamp;\r\n                }\r\n\r\n                function csvEscape(value) {\r\n                    const text = value === null || value === undefined ? '' : String(value);\r\n\r\n                    if (\/[\",\\r\\n]\/.test(text)) {\r\n                        return '\"' + text.replace(\/\"\/g, '\"\"') + '\"';\r\n                    }\r\n\r\n                    return text;\r\n                }\r\n\r\n                function downloadBlob(blob, filename) {\r\n                    const url = URL.createObjectURL(blob);\r\n                    const link = document.createElement('a');\r\n\r\n                    link.href = url;\r\n                    link.download = filename;\r\n                    link.style.display = 'none';\r\n\r\n                    document.body.appendChild(link);\r\n                    link.click();\r\n                    document.body.removeChild(link);\r\n\r\n                    window.setTimeout(function () {\r\n                        URL.revokeObjectURL(url);\r\n                    }, 1000);\r\n                }\r\n\r\n                function updateSelectAllState() {\r\n                    allDataCheckbox.checked = dataCheckboxes.every(function (checkbox) {\r\n                        return checkbox.checked;\r\n                    });\r\n                }\r\n\r\n                allDataCheckbox.addEventListener('change', function () {\r\n                    dataCheckboxes.forEach(function (checkbox) {\r\n                        checkbox.checked = allDataCheckbox.checked;\r\n                    });\r\n\r\n                    if (allDataCheckbox.checked) {\r\n                        totalRainCheckbox.checked = false;\r\n                    }\r\n                });\r\n\r\n                dataCheckboxes.forEach(function (checkbox) {\r\n                    checkbox.addEventListener('change', function () {\r\n                        if (checkbox.checked) {\r\n                            totalRainCheckbox.checked = false;\r\n                        }\r\n\r\n                        updateSelectAllState();\r\n                    });\r\n                });\r\n\r\n                totalRainCheckbox.addEventListener('change', function () {\r\n                    if (!totalRainCheckbox.checked) {\r\n                        return;\r\n                    }\r\n\r\n                    allDataCheckbox.checked = false;\r\n\r\n                    dataCheckboxes.forEach(function (checkbox) {\r\n                        checkbox.checked = false;\r\n                    });\r\n                });\r\n\r\n                form.addEventListener('submit', async function (event) {\r\n                    event.preventDefault();\r\n                    statusElement.textContent = '';\r\n\r\n                    const selectedStations = Array.from(\r\n                        root.querySelectorAll('[data-role=\"station\"]:checked')\r\n                    ).map(function (checkbox) {\r\n                        return checkbox.value;\r\n                    });\r\n\r\n                    if (selectedStations.length === 0) {\r\n                        statusElement.textContent = 'Please select at least one station.';\r\n                        return;\r\n                    }\r\n\r\n                    const startDate = startInput.value;\r\n                    const endDate = endInput.value;\r\n\r\n                    if (!startDate || !endDate) {\r\n                        statusElement.textContent = 'Please select both a start date and an end date.';\r\n                        return;\r\n                    }\r\n\r\n                    if (startDate >= endDate) {\r\n                        statusElement.textContent = 'The end date must be later than the start date.';\r\n                        return;\r\n                    }\r\n\r\n                    const timeFormatRadio = root.querySelector('[data-role=\"time-format\"]:checked');\r\n                    const timeFormat = timeFormatRadio ? timeFormatRadio.value : 'unix';\r\n                    const wantsTotalRain = totalRainCheckbox.checked;\r\n\r\n                    let columns = ['dateTime'];\r\n                    let headers = [];\r\n\r\n                    if (wantsTotalRain) {\r\n                        columns = ['dateTime', 'totalDailyRain'];\r\n                        headers = ['Date', 'Total Daily Rain (in)'];\r\n                    } else {\r\n                        const selectedColumns = dataCheckboxes\r\n                            .filter(function (checkbox) {\r\n                                return checkbox.checked;\r\n                            })\r\n                            .map(function (checkbox) {\r\n                                return checkbox.dataset.column;\r\n                            });\r\n\r\n                        if (selectedColumns.length === 0) {\r\n                            statusElement.textContent = 'Please select at least one data field.';\r\n                            return;\r\n                        }\r\n\r\n                        columns = columns.concat(selectedColumns);\r\n                        headers = columns.map(function (column) {\r\n                            return headerMap[column];\r\n                        });\r\n                    }\r\n\r\n                    const apiColumns = columns.filter(function (column) {\r\n                        return column !== 'totalDailyRain';\r\n                    });\r\n\r\n                    if (wantsTotalRain && !apiColumns.includes('rain')) {\r\n                        apiColumns.push('rain');\r\n                    }\r\n\r\n                    const useEasternRange = timeFormat === 'EST';\r\n                    const startSeconds = useEasternRange\r\n                        ? easternMidnightEpoch(startDate)\r\n                        : utcMidnightEpoch(startDate);\r\n                    const endSeconds = useEasternRange\r\n                        ? easternMidnightEpoch(endDate)\r\n                        : utcMidnightEpoch(endDate);\r\n\r\n                    statusElement.textContent = 'Requesting data...';\r\n\r\n                    const results = await Promise.all(\r\n                        selectedStations.map(async function (station) {\r\n                            const requestBody = {\r\n                                startms: startSeconds,\r\n                                endms: endSeconds,\r\n                                table: 'archive',\r\n                                cols: apiColumns,\r\n                                db: stationDbMap[station]\r\n                            };\r\n\r\n                            console.log('UMDWx request for ' + station + ':', requestBody);\r\n\r\n                            try {\r\n                                const response = await fetch(endpoint, {\r\n                                    method: 'POST',\r\n                                    mode: 'same-origin',\r\n                                    cache: 'no-cache',\r\n                                    credentials: 'same-origin',\r\n                                    headers: {\r\n                                        'Content-Type': 'application\/json',\r\n                                        'Accept': 'application\/json'\r\n                                    },\r\n                                    redirect: 'follow',\r\n                                    referrerPolicy: 'no-referrer',\r\n                                    body: JSON.stringify(requestBody)\r\n                                });\r\n\r\n                                const rawText = await response.text();\r\n                                console.log('Raw get-data.php response for ' + station + ':', rawText);\r\n\r\n                                let payload;\r\n\r\n                                try {\r\n                                    payload = JSON.parse(rawText);\r\n                                } catch (parseError) {\r\n                                    throw new Error(\r\n                                        'get-data.php did not return valid JSON. Response: ' +\r\n                                        rawText.slice(0, 250)\r\n                                    );\r\n                                }\r\n\r\n                                if (payload && payload.error) {\r\n                                    throw new Error(payload.error);\r\n                                }\r\n\r\n                                if (!response.ok) {\r\n                                    throw new Error('Server returned HTTP ' + response.status + '.');\r\n                                }\r\n\r\n                                if (!payload || !Array.isArray(payload.data)) {\r\n                                    throw new Error(\r\n                                        'get-data.php returned JSON without a data array. Response: ' +\r\n                                        rawText.slice(0, 250)\r\n                                    );\r\n                                }\r\n\r\n                                let rows = [];\r\n\r\n                                if (wantsTotalRain) {\r\n                                    const totalsByDay = {};\r\n\r\n                                    payload.data.forEach(function (record) {\r\n                                        if (\r\n                                            !record ||\r\n                                            record.dateTime === undefined ||\r\n                                            record.rain === undefined\r\n                                        ) {\r\n                                            return;\r\n                                        }\r\n\r\n                                        const rainValue = Number.parseFloat(record.rain);\r\n\r\n                                        if (!Number.isFinite(rainValue)) {\r\n                                            return;\r\n                                        }\r\n\r\n                                        const day = formatEasternDate(record.dateTime);\r\n                                        totalsByDay[day] = (totalsByDay[day] || 0) + rainValue;\r\n                                    });\r\n\r\n                                    rows = Object.keys(totalsByDay)\r\n                                        .map(function (day) {\r\n                                            return [day, totalsByDay[day].toFixed(3)];\r\n                                        })\r\n                                        .sort(function (a, b) {\r\n                                            return new Date(a[0]) - new Date(b[0]);\r\n                                        });\r\n                                } else {\r\n                                    rows = payload.data.map(function (record) {\r\n                                        return columns.map(function (column) {\r\n                                            if (column === 'dateTime') {\r\n                                                return formatTimestamp(record.dateTime, timeFormat);\r\n                                            }\r\n\r\n                                            return Object.prototype.hasOwnProperty.call(record, column)\r\n                                                ? record[column]\r\n                                                : '';\r\n                                        });\r\n                                    });\r\n\r\n                                    rows.reverse();\r\n                                }\r\n\r\n                                return {\r\n                                    station: station,\r\n                                    data: rows,\r\n                                    error: null\r\n                                };\r\n                            } catch (error) {\r\n                                console.error('Data request failed for ' + station + ':', error);\r\n\r\n                                return {\r\n                                    station: station,\r\n                                    data: [],\r\n                                    error: error.message || 'Unknown error'\r\n                                };\r\n                            }\r\n                        })\r\n                    );\r\n\r\n                    const populatedResults = results.filter(function (result) {\r\n                        return result.data.length > 0;\r\n                    });\r\n\r\n                    const failedResults = results.filter(function (result) {\r\n                        return result.error;\r\n                    });\r\n\r\n                    if (populatedResults.length === 0) {\r\n                        if (failedResults.length > 0) {\r\n                            statusElement.textContent = failedResults\r\n                                .map(function (result) {\r\n                                    return result.station + ': ' + result.error;\r\n                                })\r\n                                .join(' | ');\r\n                        } else {\r\n                            statusElement.textContent = 'No data was returned for the selected date range.';\r\n                        }\r\n\r\n                        return;\r\n                    }\r\n\r\n                    if (outputInput.value === 'XLSX') {\r\n                        if (typeof window.XLSX === 'undefined') {\r\n                            statusElement.textContent = 'The XLSX library did not load. Please refresh and try again.';\r\n                            return;\r\n                        }\r\n\r\n                        const workbook = window.XLSX.utils.book_new();\r\n\r\n                        populatedResults.forEach(function (result) {\r\n                            const worksheet = window.XLSX.utils.aoa_to_sheet(\r\n                                [headers].concat(result.data)\r\n                            );\r\n\r\n                            window.XLSX.utils.book_append_sheet(\r\n                                workbook,\r\n                                worksheet,\r\n                                result.station\r\n                            );\r\n                        });\r\n\r\n                        window.XLSX.writeFile(\r\n                            workbook,\r\n                            'stationdata_' + startDate + '_' + endDate + '.xlsx'\r\n                        );\r\n                    } else {\r\n                        populatedResults.forEach(function (result, index) {\r\n                            const csvRows = [headers].concat(result.data);\r\n                            const csvText = csvRows\r\n                                .map(function (row) {\r\n                                    return row.map(csvEscape).join(',');\r\n                                })\r\n                                .join('\\r\\n');\r\n\r\n                            window.setTimeout(function () {\r\n                                downloadBlob(\r\n                                    new Blob([csvText], {\r\n                                        type: 'text\/csv;charset=utf-8'\r\n                                    }),\r\n                                    result.station + '_' + startDate + '_' + endDate + '.csv'\r\n                                );\r\n                            }, index * 200);\r\n                        });\r\n                    }\r\n\r\n                    if (failedResults.length > 0) {\r\n                        statusElement.textContent =\r\n                            'Download created, but these stations failed: ' +\r\n                            failedResults.map(function (result) {\r\n                                return result.station + ' (' + result.error + ')';\r\n                            }).join(', ');\r\n                    } else {\r\n                        statusElement.textContent = 'Download created successfully.';\r\n                    }\r\n                });\r\n\r\n                setDefaultDates();\r\n            })();\r\n            <\/script>\r\n\r\n            <\/div>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":82,"featured_media":0,"parent":7510,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-7549","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/pages\/7549","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/users\/82"}],"replies":[{"embeddable":true,"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/comments?post=7549"}],"version-history":[{"count":10,"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/pages\/7549\/revisions"}],"predecessor-version":[{"id":8923,"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/pages\/7549\/revisions\/8923"}],"up":[{"embeddable":true,"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/pages\/7510"}],"wp:attachment":[{"href":"https:\/\/weather.umd.edu\/wordpress\/wp-json\/wp\/v2\/media?parent=7549"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}