diff --git a/.DS_Store b/.DS_Store index bd01eb3..1a4a429 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/F1.qmd b/F1.qmd index 6bd7358..c107ad3 100644 --- a/F1.qmd +++ b/F1.qmd @@ -3,6 +3,7 @@ ## Programming Basics ::: {.callout-tip} + ## Chapter Information ### Author{.unlisted .unnumbered} @@ -1206,10 +1207,12 @@ In addition to band imagery and per-pixel quality flags, Earth Engine allows you Let’s examine the metadata for the Sentinel-2 MSI. +```js ///// // Metadata ///// print('MSI Image Metadata', msiImage); +``` Examine the object you’ve created in the Console (Fig. F1.3.20). Expand the image name, then the properties object. @@ -1219,11 +1222,12 @@ Fig. F1.3.20 Checking the “CLOUDY_PIXEL_PERCENTAGE” property in the metadata The first entry is the CLOUDY_PIXEL_PERCENTAGE information. Distinct from the cloudiness flag attached to every pixel, this is an image-level summary assessment of the overall cloudiness in the image. In addition to viewing the value, you might find it useful to print it to the screen, for example, or to record a list of cloudiness values in a set of images. Metadata properties can be extracted from an image’s properties using the get function, and printed to the Console. +```js // Image-level Cloud info var msiCloudiness = msiImage.get('CLOUDY_PIXEL_PERCENTAGE'); print('MSI CLOUDY_PIXEL_PERCENTAGE:', msiCloudiness); - +``` ::: {.callout-note} Code Checkpoint F13e. The book’s repository contains a script that shows what your code should look like at this point. ::: diff --git a/F2.qmd b/F2.qmd index 13cc6be..92f1d16 100644 --- a/F2.qmd +++ b/F2.qmd @@ -465,29 +465,12 @@ Map.addLayer(landsat, visParams, 'Landsat 8 image'); ![Fig. F2.1.2 Landsat image](F2/image44.png) -Using the Geometry Tools, we will create points on the Landsat image that represent land cover classes of interest to use as our training data. We’ll need to do two things: (1) identify where each land cover occurs on the ground, and (2) label the points with the proper class number. For this exercise, we will use the classes and codes shown in Table 2.1.1. +Using the Geometry Tools, we will create points on the Landsat image that represent land cover classes of interest to use as our training data. We’ll need to do two things: (1) identify where each land cover occurs on the ground, and (2) label the points with the proper class number. For this exercise, we will use the classes and codes shown below: -Table 2.1.1 Land cover classes - -Class - -Class code - -Forest - -0 - -Developed - -1 - -Water - -2 - -Herbaceous - -3 +* Forest: 0 +* Developed: 1 +* Water: 2 +* Herbaceous: 3 In the Geometry Tools, click on the marker option (Fig. F2.1.3). This will create a point geometry which will show up as an import named “geometry”. Click on the gear icon to configure this import. @@ -783,29 +766,14 @@ In a thorough accuracy assessment, we think carefully about the sampling design, If you have not already done so, be sure to add the book’s code repository to the Code Editor by entering [](https://www.google.com/url?q=https://code.earthengine.google.com/?accept_repo%3Dprojects/gee-edu/book&sa=D&source=editors&ust=1671458829937499&usg=AOvVaw3qqOwSX_A-Pllh6X3X31q4)[https://code.earthengine.google.com/?accept_repo=projects/gee-edu/book](https://www.google.com/url?q=https://code.earthengine.google.com/?accept_repo%3Dprojects/gee-edu/book&sa=D&source=editors&ust=1671458829937976&usg=AOvVaw0WioXIhzue8-WoaX4UtabH) into your browser. The book’s scripts will then be available in the script manager panel. If you have trouble finding the repo, you can visit [this link](https://www.google.com/url?q=https://docs.google.com/presentation/d/1Kt6wGNoesYm__Cu3k3bnlbbyPN6m9SF4hQHK-pIDHfc/edit%23slide%3Did.g18a7b4b055d_0_624&sa=D&source=editors&ust=1671458829938470&usg=AOvVaw2CH8V3-_qV99EcgMxUAaSO) for help. -To illustrate some of the basic ideas about classification accuracy, we will revisit the data and location of part of Chap. F2.1, where we tested different classifiers and classified a Landsat image of the area around Milan, Italy. We will name this dataset 'data'. This variable is a FeatureCollection with features containing the “class” values (Table F2.2.1) and spectral information of four land cover / land use classes: forest, developed, water, and herbaceous (see Fig. F2.1.8 and Fig. F2.1.9 for a refresher). We will also define a variable, predictionBands, which is a list of bands that will be used for prediction (classification)—the spectral information in the data variable. +To illustrate some of the basic ideas about classification accuracy, we will revisit the data and location of part of Chap. F2.1, where we tested different classifiers and classified a Landsat image of the area around Milan, Italy. We will name this dataset 'data'. This variable is a FeatureCollection with features containing the “class” values and spectral information of four land cover / land use classes: forest, developed, water, and herbaceous (see Fig. F2.1.8 and Fig. F2.1.9 for a refresher). We will also define a variable, predictionBands, which is a list of bands that will be used for prediction (classification)—the spectral information in the data variable. -Table F2.2.1 Land cover classes +Class Values: -Class - -Class value - -Forest - -0 - -Developed - -1 - -Water - -2 - -Herbaceous - -3 +* Forest: 0 +* Developed: 1 +* Water: 2 +* Herbaceous: 3 The first step is to partition the set of known values into training and testing sets in order to have something for the classifier to predict over that it has not been shown before (the testing set), mimicking unseen data that the model might see in the future. We add a column of random numbers to our FeatureCollection using the randomColumn method. Then, we filter the features into about 80% for training and 20% for testing using ee.Filter. Copy and paste the code below to partition the data and filter features based on the random number. @@ -842,25 +810,12 @@ Now, let’s discuss what a confusion matrix is. A confusion matrix describes th Table F2.2.1 Confusion matrix for a binary classification where the classes are “positive” and “negative” -Actual values +| | | Actual values | | +|------------------|----------|:-------------------:|:-------------------:| +| | | Positive | Negative | +| Predicted values | Positive | TP (true positive) | FP (false positive) | +| | Negative | FN (false negative) | TN (true negative) | -Positive - -Negative - -Predicted values - -Positive - -TP (true positive) - -FP (false positive) - -Negative - -FN (false negative) - -TN (true negative) In Table F2.2.1, the columns represent the actual values (the truth), while the rows represent the predictions (the classification). “True positive” (TP) and “true negative” (TN) mean that the classification of a pixel matches the truth (e.g., a water pixel correctly classified as water). “False positive” (FP) and “false negative” (FN) mean that the classification of a pixel does not match the truth (e.g., a non-water pixel incorrectly classified as water). @@ -873,25 +828,12 @@ We can extract some statistical information from a confusion matrix.. Let’s lo Table F2.2.2 Confusion matrix for a binary classification where the classes are “positive” (forest) and “negative” (non-forest) -Actual values +| | | Actual values | | +|------------------|----------|:-------------:|:--------:| +| | | Positive | Negative | +| Predicted values | Positive | 307 | 18 | +| | Negative | 14 | 661 | -Positive - -Negative - -Predicted values - -Positive - -307 - -18 - -Negative - -14 - -661 In this case, the classifier correctly identified 307 forest pixels, wrongly classified 18 non-forest pixels as forest, correctly identified 661 non-forest pixels, and wrongly classified 14 forest pixels as non-forest. Therefore, the classifier was correct 968 times and wrong 32 times. Let’s calculate the main accuracy metrics for this example. diff --git a/F4.qmd b/F4.qmd index 0ce5635..6623b31 100644 --- a/F4.qmd +++ b/F4.qmd @@ -1,4 +1,4 @@ -## Interpreting Image Series +## Image Series One of the paradigm-changing features of Earth Engine is the ability to access decades of imagery without the previous limitation of needing to download all the data to a local disk for processing. Because remote-sensing data files can be enormous, this used to limit many projects to viewing two or three images from different periods. With Earth Engine, users can access tens or hundreds of thousands of images to understand the status of places across decades. @@ -51,7 +51,9 @@ For users of other programming languages—R, MATLAB, C, Karel, and many others Suppose you need to go shopping for milk, and you have two criteria for determining where you will buy your milk: location and price. The store needs to be close to your home, and as a first step in deciding whether to buy milk today, you want to identify the lowest price among those stores. You don’t know the cost of milk at any store ahead of time, so you need to efficiently contact each one and determine the minimum price to know whether it fits in your budget. If we were discussing this with a friend, we might say, “I need to find out how much milk costs at all the stores around here.” To solve that problem in a programming language, these words imply precise operations on sets of information. We can write the following “pseudocode,” which uses words that indicate logical thinking but that cannot be pasted directly into a program: +``` AllStoresOnEarth.filterNearbyStores.filterStoresWithMilk.getMilkPricesFromEachStore.determineTheMinimumValue +``` Imagine doing these actions not on a computer but in a more old-fashioned way: calling on the telephone for milk prices, writing the milk prices on paper, and inspecting the list to find the lowest value. In this approach, we begin with AllStoresOnEarth, since there is at least some possibility that we could decide to visit any store on Earth, a set that could include millions of stores, with prices for millions or billions of items. A wise first action would be to limit ourselves to nearby stores. Asking to filterNearbyStores would reduce the number of potential stores to hundreds, depending on how far we are willing to travel for milk. Then, working with that smaller set, we further filterStoresWithMilk, limiting ourselves to stores that sell our target item. At that point in the filtering, imagine that just 10 possibilities remain. Then, by telephone, we getMilkPricesFromEachStore, making a short paper list of prices. We then scan the list to determineTheMinimumValue to decide which store to visit. @@ -59,8 +61,9 @@ In that example, each color plays a different role in the workflow. The AllStore The list of steps above might seem almost too obvious, but the choice and order of operations can have a big impact on the feasibility of the problem. Imagine if we had decided to do the same operations in a slightly different order: +``` AllStoresOnEarth.filterStoresWithMilk.getMilkPricesFromEachStore.filterNearbyStores.determineMinimumValue - +``` In this approach, we first identify all the stores on Earth that have milk, then contact them one by one to get their current milk price. If the contact is done by phone, this could be a painfully slow process involving millions of phone calls. It would take considerable “processing” time to make each call, and careful work to record each price onto a giant list. Processing the operations in this order would demand that only after entirely finishing the process of contacting every milk proprietor on Earth, we then identify the ones on our list that are not nearby enough to visit, then scan the prices on the list of nearby stores to find the cheapest one. This should ultimately give the same answer as the more efficient first example, but only after requiring so much effort that we might want to give up. In addition to the greater order of magnitude of the list size, you can see that there are also possible slow points in the process. Could you make a million phone calls yourself? Maybe, but it might be pretty appealing to hire, say, 1000 people to help. While being able to make a large number of calls in parallel would speed up the calling stage, it’s important to note that you would need to wait for all 1000 callers to return their sublists of prices. Why wait? Nearby stores could be on any caller’s sublist, so any caller might be the one to find the lowest nearby price. The identification of the lowest nearby price would need to wait for the slowest caller, even if it turned out that all of that last caller’s prices came from stores on the other side of the world. @@ -81,8 +84,9 @@ Below are three examples of limiting a Landsat 5 ImageCollection by characterist FilterDate This takes an ImageCollection as input and returns an ImageCollection whose members satisfy the specified date criteria. We’ll adapt the earlier filtering logic seen in Chap. F1.2: -var imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); + ```js +var imgCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2'); // How many Tier 1 Landsat 5 images have ever been collected? print("All images ever: ", imgCol.size()); // A very large number @@ -104,25 +108,27 @@ Map.centerObject(ShanghaiImage, 9); var imgColfilteredByDateHere = imgColfilteredByDate.filterBounds(Map .getCenter()); print("All images here, 2000-2010: ", imgColfilteredByDateHere .size()); // A smaller number - +``` If you’d like, you could take a few minutes to explore the behavior of the script in different parts of the world. To do that, you would need to comment out the Map.centerObject command to keep the map from moving to that location each time you run the script. - -Filter by Other Image Metadata As first explained in Chap. F1.3, the date and location of an image are characteristics stored with each image. Another important factor in image processing is the cloud cover, an image-level value computed for each image in many collections, including the Landsat and Sentinel-2 collections. The overall cloudiness score might be stored under different metadata tag names in different data sets. For example, for Sentinel-2, this overall cloudiness score is stored in the CLOUDY_PIXEL_PERCENTAGE metadata field. For Landsat 5, the ImageCollection we are using in this example, the image-level cloudiness score is stored using the tag CLOUD_COVER. If you are unfamiliar with how to find this information, these skills are first presented in Part F1. +*Filter by Other Image Metadata* +As first explained in Chap. F1.3, the date and location of an image are characteristics stored with each image. Another important factor in image processing is the cloud cover, an image-level value computed for each image in many collections, including the Landsat and Sentinel-2 collections. The overall cloudiness score might be stored under different metadata tag names in different data sets. For example, for Sentinel-2, this overall cloudiness score is stored in the CLOUDY_PIXEL_PERCENTAGE metadata field. For Landsat 5, the ImageCollection we are using in this example, the image-level cloudiness score is stored using the tag CLOUD_COVER. If you are unfamiliar with how to find this information, these skills are first presented in Part F1. Here, we will access the ImageCollection that we just built using filterBounds and filterDate, and then further filter the images by the image-level cloud cover score, using the filterMetadata function. Next, let’s remove any images with 50% or more cloudiness. As will be described in subsequent chapters working with per-pixel cloudiness information, you might want to retain those images in a real-life study, if you feel some values within cloudy images might be useful. For now, to illustrate the filtering concept, let’s keep only images whose image-level cloudiness values indicate that the cloud coverage is lower than 50%. Here, we will take the set already filtered by bounds and date, and further filter it using the cloud percentage into a new ImageCollection. Add this line to the script to filter by cloudiness and print the size to the Console. +```js var L5FilteredLowCloudImages = imgColfilteredByDateHere .filterMetadata('CLOUD_COVER', 'less_than', 50); print("Less than 50% clouds in this area, 2000-2010", L5FilteredLowCloudImages.size()); // A smaller number - +``` Filtering in an Efficient Order As you saw earlier in the hypothetical milk example, we typically filter, then map, and then reduce, in that order. In the same way that we would not want to call every store on Earth, preferring instead to narrow down the list of potential stores first, we filter images first in our workflow in Earth Engine. In addition, you may have noticed that the ordering of the filters within the filtering stage also mattered in the milk example. This is also true in Earth Engine. For problems with a non-global spatial component in which filterBounds is to be used, it is most efficient to do that spatial filtering first. In the code below, you will see that you can “chain” the filter commands, which are then executed from left to right. Below, we chain the filters in the same order as you specified above. Note that it gives an ImageCollection of the same size as when you applied the filters one at a time. +```js var chainedFilteredSet = imgCol.filterDate(startDate, endDate) .filterBounds(Map.getCenter()) .filterMetadata('CLOUD_COVER', 'less_than', 50); @@ -132,12 +138,13 @@ print('Chained: Less than 50% clouds in this area, 2000-2010', ``` In the code below, we chain the filters in a more efficient order, implementing filterBounds first. This, too, gives an ImageCollection of the same size as when you applied the filters in the less efficient order, whether the filters were chained or not. +```js var efficientFilteredSet = imgCol.filterBounds(Map.getCenter()) .filterDate(startDate, endDate) .filterMetadata('CLOUD_COVER', 'less_than', 50); print('Efficient filtering: Less than 50% clouds in this area, 2000-2010', efficientFilteredSet.size()); - +``` Each of the two chained sets of operations will give the same result as before for the number of images. While the second order is more efficient, both approaches are likely to return the answer to the Code Editor at roughly the same time for this very small example. The order of operations is most important in larger problems in which you might be challenged to manage memory carefully. As in the milk example in which you narrowed geographically first, it is good practice in Earth Engine to order the filters with the filterBounds first, followed by metadata filters in order of decreasing specificity. :::{.callout-note} @@ -154,22 +161,46 @@ Before beginning to code the EVI functionality, it’s worth noting that the wor To map a given set of operations efficiently over an entire ImageCollection, the processing needs to be set up in a particular way. Users familiar with other programming languages might expect to see “loop” code to do this, but the processing is not done exactly that way in Earth Engine. Instead, we will create a function, and then map it over the ImageCollection. To begin, envision creating a function that takes exactly one parameter, an ee.Image. The function is then designed to perform a specified set of operations on the input ee.Image and then, importantly, returns an ee.Image as the last step of the function. When we map that function over an ImageCollection, as we’ll illustrate below, the effect is that we begin with an ImageCollection, do operations to each image, and receive a processed ImageCollection as the output. What kinds of functions could we create? For example, you could imagine a function taking an image and returning an image whose pixels have the value 1 where the value of a given band was lower than a certain threshold, and 0 otherwise. The effect of mapping this function would be an entire ImageCollection of images with zeroes and ones representing the results of that test on each image. Or you could imagine a function computing a complex self-defined index and sending back an image of that index calculated in each pixel. Here, we’ll create a function to compute the EVI for any input Landsat 5 image and return the one-band image for which the index is computed for each pixel. Copy and paste the function definition below into the Code Editor, adding it to the end of the script from the previous section. +```js +var makeLandsat5EVI = function(oneL5Image) { + // compute the EVI for any Landsat 5 image. Note it's specific to + // Landsat 5 images due to the band numbers. Don't run this exact + // function for images from sensors other than Landsat 5. -var makeLandsat5EVI = function(oneL5Image) { // compute the EVI for any Landsat 5 image. Note it's specific to // Landsat 5 images due to the band numbers. Don't run this exact // function for images from sensors other than Landsat 5. // Extract the bands and divide by 1e4 to account for scaling done. var nirScaled = oneL5Image.select('SRvide(10000); var redScaled = oneL5Image.select('SR_B3').divide(10000); var blueScaled = oneL5Image.select('SR_B1').divide(10000); // Calculate the numerator, note that order goes from left to right. var numeratorEVI = (nirScaled.subtract(redScaled)).multiply( 2.5); // Calculate the denominator var denomClause1 = redScaled.multiply(6); var denomClause2 = blueScaled.multiply(7.5); var denominatorEVI = nirScaled.add(denomClause1).subtract( - denomClause2).add(1); // Calculate EVI and name it. var landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( 'EVI'); return (landsat5EVI); + // Extract the bands and divide by 1e4 to account for scaling done. + var nirScaled = oneL5Image.select('SR_B4').divide(10000); + var redScaled = oneL5Image.select('SR_B3').divide(10000); + var blueScaled = oneL5Image.select('SR_B1').divide(10000); + + // Calculate the numerator, note that order goes from left to right. + var numeratorEVI = (nirScaled.subtract(redScaled)).multiply( + 2.5); + + // Calculate the denominator + var denomClause1 = redScaled.multiply(6); + var denomClause2 = blueScaled.multiply(7.5); + var denominatorEVI = nirScaled.add(denomClause1).subtract( + denomClause2).add(1); + + // Calculate EVI and name it. + var landsat5EVI = numeratorEVI.divide(denominatorEVI).rename( + 'EVI'); + return (landsat5EVI); }; +``` It is worth emphasizing that, in general, band names are specific to each ImageCollection. As a result, if that function were run on an image without the band 'SR_B4', for example, the function call would fail. Here, we have emphasized in the function’s name that it is specifically for creating EVI for Landsat 5. The function makeLandsat5EVI is built to receive a single image, select the proper bands for calculating EVI, make the calculation, and return a one-banded image. If we had the name of each image comprising our ImageCollection, we could enter the names into the Code Editor and call the function one at a time for each, assembling the images into variables, and then combining them into an ImageCollection. This would be very tedious and highly prone to mistakes: lists of items might get mistyped, an image might be missed, etc. Instead, as mentioned above, we will use .map. With the code below, let’s print the information about the cloud-filtered collection and display it, execute the .map command, and explore the resulting ImageCollection. +```js var L5EVIimages = efficientFilteredSet.map(makeLandsat5EVI); print('Verifying that the .map gives back the same number of images: ', L5EVIimages.size()); print(L5EVIimages); Map.addLayer(L5EVIimages, {}, 'L5EVIimages', 1, 1); - +``` After entering and executing this code, you will see a grayscale image. If you look closely at the edges of the image, you might spot other images drawn behind it in a way that looks somewhat like a stack of papers on a table. This is the drawing of the ImageCollection made from the makeLandsat5EVI function. You can select the Inspector panel and click on one of the grayscale pixels to view the values of the entire ImageCollection. After clicking on a pixel, look for the Series tag by opening and closing the list of items. When you open that tag, you will see a chart of the EVI values at that pixel, created by mapping the makeLandsat5EVI function over the filtered ImageCollection. :::{.callout-note} @@ -183,6 +214,7 @@ Here, you can think of each location, after the calculation of EVI has been exec The code below computes the mean value, at every pixel, of the ImageCollection L5EVIimages created above. Add it at the bottom of your code. +```js var L5EVImean = L5EVIimages.reduce(ee.Reducer.mean()); print(L5EVImean); Map.addLayer(L5EVImean, { @@ -190,9 +222,9 @@ Map.addLayer(L5EVImean, { max: 2, palette: ['red', 'white', 'green'] }, 'Mean EVI'); - +``` Using the same principle, the code below computes and draws the median value of the ImageCollection in every pixel. - +```js var L5EVImedian = L5EVIimages.reduce(ee.Reducer.median()); print(L5EVImedian); Map.addLayer(L5EVImedian, { @@ -200,7 +232,7 @@ Map.addLayer(L5EVImedian, { max: 2, palette: ['red', 'white', 'green'] }, 'Median EVI'); - +``` ![](F4/image43.png) ![Fig. 4.0.2 The effects of two reducers on mapped EVI values in a filtered ImageCollection: mean image (above), and median image (below)](F4/image67.png) @@ -222,10 +254,8 @@ In this chapter, you learned about the paradigm of filter, map, reduce. You lear ## Exploring Image Collections - - - :::{.callout-tip} + ## Chapter Information #### Author {.unlisted .unnumbered} @@ -256,7 +286,7 @@ This chapter teaches how to explore image collections, including their spatiotem * Perform basic image analysis: select bands, compute indices, create masks (Part F2). * Summarize an ImageCollection with reducers (Chap. F4.0). -*** +::: In the previous chapter (Chap. F4.0), the filter, map, reduce paradigm was introduced. The main goal of this chapter is to demonstrate some of the ways that those concepts can be used within Earth Engine to better understand the variability of values stored in image collections. Sect. 1 demonstrates how time-dependent values stored in the images of an ImageCollection can be inspected using the Code Editor user interface after filtering them to a limited spatiotemporal range (i.e., geometry and time ranges). Sect. 2 shows how the extent of images, as well as basic statistics, such as the number of observations, can be visualized to better understand the spatiotemporal extent of image collections. Then, Sects. 3 and 4 demonstrate how simple reducers such as mean and median, and more advanced reducers such as percentiles, can be used to better understand how the values of a filtered ImageCollection are distributed. @@ -394,9 +424,9 @@ We can see that the resulting composite image (Fig. 4.1.3) has almost no cloudy We can explore the range of values in an entire ImageCollection by viewing a series of increasingly bright percentile images, as shown in Fig. F4.1.4. Paste and run the following code. +```js var percentiles = [0, 10, 20, 30, 40, 50, 60, 70, 80]; -```js // let's compute percentile images and add them as separate layers percentiles.map(function(p) { var image = filteredIC.reduce(ee.Reducer.percentile([p])); Map.addLayer(image, { min: 0.05, @@ -481,12 +511,14 @@ In this exercise, we will work with the CHIRPS dataset using the pentad. A penta We will start by accessing the CHIRPS Pentad collection and filtering it to create a time series for a single year. +```js var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); var startDate = '2019-01-01'; var endDate = '2020-01-01'; var yearFiltered = chirps.filter(ee.Filter.date(startDate, endDate)); print(yearFiltered, 'Date-filtered CHIRPS images'); +``` The CHIRPS collection contains one image for every pentad. The filtered collection above is filtered to contain one year, which equates to 72 global images. If you expand the printed collection in the Console, you will be able to see the metadata for individual images; note that their date stamps indicate that they are spaced evenly every five days (Fig. F4.2.1). @@ -504,28 +536,33 @@ To aggregate the time series, we need to learn how to create and manipulate date The Earth Engine API has a function called ee.Date.fromYMD that is designed to create a date object from year, month, and day values. The following code snippet shows how to define a variable containing the year value and create a date object from it. Paste the following code in a new script: +```js var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); var year = 2019; var startDate = ee.Date.fromYMD(year, 1, 1); +``` Now, let’s determine how to create an end date in order to be able to specify a desired time interval. The preferred way to create a date relative to another date is using the advance function. It takes two parameters—a delta value and the unit of time—and returns a new date. The code below shows how to create a date one year in the future from a given date. Paste it into your script. +```js var endDate = startDate.advance(1, 'year'); - +``` Next, paste the code below to perform filtering of the CHIRPS data using these calculated dates. After running it, check that you had accurately set the dates by looking for the dates of the images inside the printed result.. +```js var yearFiltered = chirps .filter(ee.Filter.date(startDate, endDate)); print(yearFiltered, 'Date-filtered CHIRPS images'); - +``` Another date function that is very commonly used across Earth Engine is millis. This function takes a date object and returns the number of milliseconds since the arbitrary reference date of the start of the year 1970: 1970-01-01T00:00:00Z. This is known as the “Unix Timestamp”; it is a standard way to convert dates to numbers and allows for easy comparison between dates with high precision. Earth Engine objects store the timestamps for images and features in special properties called system:time_start and system:time_end. Both of these properties need to be supplied with a number instead of dates, and the millis function can help you do that. You can print the result of calling this function and check for yourself. +```js print(startDate, 'Start date'); print(endDate, 'End date'); print('Start date as timestamp', startDate.millis()); print('End date as timestamp', endDate.millis()); - +``` We will use the millis function in the next section when we need to set the system:time_start and system:time_end properties of the aggregated images. :::{.callout-note} @@ -586,6 +623,7 @@ var point = ee.Geometry.Point(77.5946, 12.9716); ``` Earth Engine comes with a built-in ui.Chart.image.series function that can plot time series. In addition to the imageCollection and region parameters, we need to supply a scale value. The CHIRPS data catalog page indicates that the resolution of the data is ​​5566 meters, so we can use that as the scale. The resulting chart is printed in the Console. +```js var chart = ui.Chart.image.series({ imageCollection: monthlyCollection, region: point, @@ -593,9 +631,11 @@ var chart = ui.Chart.image.series({ scale: 5566, }); print(chart); +``` We can make the chart more informative by adding axis labels and a title. The setOptions function allows us to customize the chart using parameters from Google Charts. To customize the chart, paste the code below at the bottom of your script. The effect will be to see two charts in the editor: one with the old view of the data, and one with the customized chart. +```js var chart = ui.Chart.image.series({ imageCollection: monthlyCollection, region: point, @@ -612,8 +652,10 @@ var chart = ui.Chart.image.series({ gridlines: { count: 12 } } -});print(chart); +}); +print(chart); +``` The customized chart (Fig. F4.2.3) shows the typical rainfall pattern in the city of Bengaluru, India. Bengaluru has a temperate climate, with pre-monsoon rains in April and May cooling down the city and a moderate monsoon season lasting from June to September. ![Fig. F4.2.3 Monthly rainfall chart](F4/image32.png) @@ -1112,11 +1154,13 @@ Before beginning a change detection workflow, image preprocessing is essential. The code in the block below accesses the USGS Landsat 8 Level 2, Collection 2, Tier 1 dataset and assigns it to the variable landsat8. To improve readability when working with the Landsat 8 ImageCollection, the code selects bands 2–7 and renames them to band names instead of band numbers. +```js var landsat8 = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') .select( ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], ['blue', 'green', 'red', 'nir', 'swir1', 'swir2'] ); +``` Next, you will split the Landsat 8 ImageCollection into two collections, one for each time period, and apply some filtering and sorting to get an image for each of two time periods. In this example, we know there are few clouds for the months of the analysis; if you’re working in a different area, you may need to apply some cloud masking or mosaicing techniques (see Chap. F4.3). @@ -1124,6 +1168,7 @@ The code below does several things. First, it creates a new geometry variable to Now repeat the previous step, but assign it to a post-event image variable and change the filter date to a period after the pre-event image’s date range (e.g., June 2020). +```js var point = ee.Geometry.Point([-123.64, 42.96]); Map.centerObject(point, 11); @@ -1136,6 +1181,7 @@ var preImage = landsat8 .filterDate('2020-06-01', '2020-06-30') .sort('CLOUD_COVER', true) .first(); +``` ### Creating False-Color Composites @@ -1143,10 +1189,12 @@ Before running any sort of change detection analysis, it is useful to first visu Following the format in the code block below, first create a variable visParam to hold the display parameters, selecting the SWIR-2, NIR, and red bands, with values drawn that are between 7750 and 22200. Next, add the pre-event and post-event images to the map and click Run. Click and drag the opacity slider on the post-event image layer back and forth to view the changes between your two images. +```js var visParam = { 'bands': ['swir2', 'nir', 'red'], 'min': 7750, 'max': 22200 }; Map.addLayer(preImage, visParam, 'pre'); Map.addLayer(postImage, visParam, 'post'); +``` ![Fig. F4.4.3 False-color composite using SWIR2, NIR, and red. Vegetation shows up vividly in the green channel due to vegetation being highly reflective in the NIR band. Shades of green can be indicative of vegetation density; water typically shows up as black to dark blue; and burned or barren areas show up as brown.](F4/image31.png) @@ -1525,32 +1573,64 @@ First, we will give some very basic notation (Fig. F4.6.1). A scalar pixel at ti The first step in analysis of time-series data is to import data of interest and plot it at an interesting location. We will work with the USGS Landsat 8 Level 2, Collection 2, Tier 1 ImageCollection and a cloud-masking function (Chap. F4.3), scale the image values, and add variables of interest to the collection as bands. Copy and paste the code below to filter the Landsat 8 collection to a point of interest over California (variable roi) and specific dates, and to apply the defined function. The variables of interest added by the function are: (1) NDVI (Chap. F2.0), (2) a time variable that is the difference between the image’s current year and the year 1970 (a start point), and (3) a constant variable with value 1. ```js -///////////////////// Sections 1 & 2 ///////////////////////////// - -// Define function to mask clouds, scale, and add variables -// (NDVI, time and a constant) to Landsat 8 imagery. -function maskScaleAndAddVariable(image) { // Bit 0 - Fill // Bit 1 - Dilated Cloud // Bit 2 - Cirrus // Bit 3 - Cloud // Bit 4 - Cloud Shadow var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0); var saturationMask = image.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- 0.2); var thermalBands = image.select('ST_B.*').multiply(0.00341802) - .add(149.0); // Replace the original bands with the scaled ones and apply the masks. var img = image.addBands(opticalBands, null, true) - .addBands(thermalBands, null, true) - .updateMask(qaMask) - .updateMask(saturationMask); var imgScaled = image.addBands(img, null, true); // Now we start to add variables of interest. // Compute time in fractional years since the epoch. var date = ee.Date(image.get('system:time_start')); var years = date.difference(ee.Date('1970-01-01'), 'year'); // Return the image with the added bands. return imgScaled // Add an NDVI band. .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) - .rename('NDVI')) // Add a time band. .addBands(ee.Image(years).rename('t')) - .float() // Add a constant band. .addBands(ee.Image.constant(1)); -} - -// Import point of interest over California, USA. -var roi = ee.Geometry.Point([-121.059, 37.9242]); - -// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), -// filter, mask clouds, scale, and add variables. -var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') - .filterBounds(roi) - .filterDate('2013-01-01', '2018-01-01') - .map(maskScaleAndAddVariable); - -// Set map center over the ROI. +///////////////////// Sections 1 & 2 ///////////////////////////// + +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(ee.Image(years).rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import point of interest over California, USA. +var roi = ee.Geometry.Point([-121.059, 37.9242]); + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection), +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center over the ROI. Map.centerObject(roi, 6); + + ``` Next, to visualize the NDVI at the point of interest over time, copy and paste the code below to print a chart of the time series (Chap. F1.3) at the location of interest (Fig. F4.6.2). @@ -1601,7 +1681,7 @@ Time series datasets may contain not only trends but also seasonality, both of w Consider the following linear model, where et is a random error: -pt = β0 + β1t + et (Eq. F4.6.1) +$p_t = β_0 + β_1t + e_t$ (Eq. F4.6.1) This is the model behind the trend line added to the chart created in the previous section (Fig. F4.6.3). Identifying trends at different scales is a big topic, with many approaches being used (e.g., differencing, modeling). @@ -1626,7 +1706,8 @@ var trend = landsat8sr.select(independents.add(dependent)) Map.addLayer(trend, {}, 'trend array image'); // Flatten the coefficients into a 2-band image. -var coefficients = trend.select('coefficients') // Get rid of extra dimensions and convert back to a regular image .arrayProject([0]) +var coefficients = trend.select('coefficients') // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) .arrayFlatten([independents]); Map.addLayer(coefficients, {}, 'coefficients image'); @@ -1669,9 +1750,9 @@ Code Checkpoint F46b. The book’s repository contains a script that shows what A linear trend is one of several possible types of trends in time series. Time series can also present harmonic trends, in which a value goes up and down in a predictable wave pattern. These are of particular interest and usefulness in the natural world, where harmonic changes in greenness of deciduous vegetation can occur across the spring, summer, and autumn. Now we will return to the initial time series (landsat8sr) of Fig. F4.6.2 and fit a harmonic pattern through the data. Consider the following harmonic model, where A is amplitude, ω is frequency, φ is phase, and et is a random error. -pt = β0 + β1t + Acos(2πωt - φ) + et +$p_t = β_0 + β_1t + Acos(2πωt - φ) + e_t$ - = β0 + β1t + β2cos(2πωt) + β3sin(2πωt) + et (Eq. F4.6.2) + $= β_0 + β_1t + β2cos(2πωt) + β3sin(2πωt) + e_t$ (Eq. F4.6.2) Note that β2 = Acos(φ) and β3 = Asin(φ), implying A = (β22 + β32)½ and φ = atan(β3/β2) (as described in Shumway and Stoffer 2019). To fit this model to an annual time series, set ω = 1 (one cycle per year) and use ordinary least squares regression. @@ -1734,21 +1815,27 @@ We’ll compute and map the phase and amplitude of the estimated harmonic model Copy and paste the code below to compute phase and amplitude from the coefficients and add this image to the map (Fig. F4.6.8). ```js -// Compute phase and amplitude. -var phase = harmonicTrendCoefficients.select('sin') - .atan2(harmonicTrendCoefficients.select('cos')) // Scale to [0, 1] from radians. .unitScale(-Math.PI, Math.PI); - -var amplitude = harmonicTrendCoefficients.select('sin') - .hypot(harmonicTrendCoefficients.select('cos')) // Add a scale factor for visualization. .multiply(5); - -// Compute the mean NDVI. -var meanNdvi = landsat8sr.select('NDVI').mean(); - -// Use the HSV to RGB transformation to display phase and amplitude. -var rgb = ee.Image.cat([ - phase, // hue amplitude, // saturation (difference from white) meanNdvi // value (difference from black) -]).hsvToRgb(); - +// Compute phase and amplitude. +var phase = harmonicTrendCoefficients.select('sin') + .atan2(harmonicTrendCoefficients.select('cos')) + // Scale to [0, 1] from radians. + .unitScale(-Math.PI, Math.PI); + +var amplitude = harmonicTrendCoefficients.select('sin') + .hypot(harmonicTrendCoefficients.select('cos')) + // Add a scale factor for visualization. + .multiply(5); + +// Compute the mean NDVI. +var meanNdvi = landsat8sr.select('NDVI').mean(); + +// Use the HSV to RGB transformation to display phase and amplitude. +var rgb = ee.Image.cat([ + phase, // hue + amplitude, // saturation (difference from white) + meanNdvi // value (difference from black) +]).hsvToRgb(); + Map.addLayer(rgb, {}, 'phase (hue), amplitude (sat), ndvi (val)'); ``` @@ -1899,12 +1986,12 @@ var utils = require( 'users/parevalo_bu/gee-ccdc-tools:ccdcUtilities/api'); For the current exercise, we will obtain an ImageCollection of Landsat 4, 5, 7, and 8 data (Collection 2 Tier 1) that has been filtered for clouds, cloud shadows, haze, and radiometrically saturated pixels. If we were to do this manually, we would retrieve each ImageCollection for each satellite, apply the corresponding filters and then merge them all into a single ImageCollection. Instead, to simplify that process, we will use the function getLandsat, included in the “Inputs” module of our utilities, and then filter the resulting ImageCollection to a small study region for the period between 2000 and 2020. The getLandsat function will retrieve all surface reflectance bands (renamed and scaled to actual surface reflectance units) as well as other vegetation indices. To simplify the exercise, we will select only the surface reflectance bands we are going to use, adding the following code to your script: +```js var studyRegion = ee.Geometry.Rectangle([ [-63.9533, -10.1315], [-64.9118, -10.6813] ]); -```js // Define start, end dates and Landsat bands to use. var startDate = '2000-01-01'; var endDate = '2020-01-01'; @@ -1945,19 +2032,30 @@ print(ccdResults); ``` Notice that the output ccdResults contains a large number of bands, with some of them corresponding to two-dimensional arrays. We will explore these bands more in the following section. The process of running the algorithm interactively for more than a handful of pixels can become very taxing to the system very quickly, resulting in memory errors. To avoid having such issues, we typically export the results to an Earth Engine asset first, and then inspect the asset. This approach ensures that CCDC completes its run successfully, and also allows us to access the results easily later. In the following sections of this chapter, we will use a precomputed asset, instead of asking you to export the asset yourself. For your reference, the code required to export CCDC results is shown below, with the flag set to false to help you remember to not export the results now, but instead to use the precomputed asset in the following sections. -var exportResults = false -if (exportResults) { // Create a metadata dictionary with the parameters and arguments used. var metadata = ccdParams; - metadata['breakpointBands'] = - metadata['breakpointBands'].toString(); - metadata['tmaskBands'] = metadata['tmaskBands'].toString(); - metadata['startDate'] = startDate; - metadata['endDate'] = endDate; - metadata['bands'] = bands.toString(); // Export results, assigning the metadata as image properties. // Export.image.toAsset({ - image: ccdResults.set(metadata), - region: studyRegion, - pyramidingPolicy: { ".default": 'sample' }, - scale: 30 }); +```js +var exportResults = false +if (exportResults) { + // Create a metadata dictionary with the parameters and arguments used. + var metadata = ccdParams; + metadata['breakpointBands'] = + metadata['breakpointBands'].toString(); + metadata['tmaskBands'] = metadata['tmaskBands'].toString(); + metadata['startDate'] = startDate; + metadata['endDate'] = endDate; + metadata['bands'] = bands.toString(); + + // Export results, assigning the metadata as image properties. + // + Export.image.toAsset({ + image: ccdResults.set(metadata), + region: studyRegion, + pyramidingPolicy: { + ".default": 'sample' + }, + scale: 30 + }); } +``` Note the metadata variable above. This is not strictly required for exporting the per-pixel CCDC results, but it allows us to keep a record of important properties of the run by attaching this information as metadata to the image. Additionally, some of the tools we have created to interact with CCDC outputs use this user-created metadata to facilitate using the asset. Note also that setting the value of pyramidingPolicy to 'sample' ensures that all the bands in the output have the proper policy. @@ -1970,12 +2068,14 @@ Code Checkpoint F47b. The book’s repository contains a script that shows what We will now start exploring the pre-exported CCDC results mentioned in the previous section. We will make use of the third-party module palettes, described in detail in Chap. F6.0, that simplifies the use of palettes for visualization. Paste the following code in a new script: +```js var palettes = require('users/gena/packages:palettes'); var resultsPath = 'projects/gee-book/assets/F4-7/Rondonia_example_small'; var ccdResults = ee.Image(resultsPath); Map.centerObject(ccdResults, 10); print(ccdResults); +``` The first line calls a library that will facilitate visualizing the images. The second line contains the path to the precomputed results of the CCDC run shown in the previous section. The printed asset will contain the following bands: @@ -2094,6 +2194,7 @@ Question 3. Looking at the “max magnitude of change” layer, find places show In addition to the change information generated by the CCDC algorithm, we can use the coefficients of the time segments for multiple purposes, like land cover classification. Each time segment can be described as a harmonic function with an intercept, slope, and three pairs of sine and cosine terms that allow the time segments to represent seasonality occurring at different temporal scales. These coefficients, as well as the root-mean-square error (RMSE) obtained by comparing each predicted and actual Landsat value, are produced when the CCDC algorithm is run. The following example will show you how to retrieve the intercept coefficient for a segment intersecting a specific date. In a new script, paste the code below: +```js var palettes = require('users/gena/packages:palettes'); var resultsPath = 'projects/gee-book/assets/F4-7/Rondonia_example_small'; @@ -2101,7 +2202,6 @@ var ccdResults = ee.Image(resultsPath); Map.centerObject(ccdResults, 10); print(ccdResults); -```js // Display segment start and end times. var start = ccdResults.select('tStart'); var end = ccdResults.select('tEnd'); @@ -2344,54 +2444,16 @@ In this section, we will view the classification inputs to BULC, which were made Table F4.8.1 Images classified for updating Roosevelt River LULC with BULC -Sensor - -Date - -Spatial resolution - -Sentinel-2 - -2016: February 8 - -2017: July 7 - -2018: May 28 - -2019: June 17, June 17 - -2020: May 27, May 27 - -2021: May 27, July 11, August 15 - -10m - -Landsat 7 - -2017: August 16 - -30m - -Landsat 8 - -2021: July 18 - -30m - -ASTER - -2017: July 15 - -2018: August 19 - -2019: June 19 - -2020: August 8 - -15m–30m +| Sensor | Date | Spatial resolution | +|------------|-------------------------------------------------------------------------------------------------------------------------|--------------------| +| Sentinel-2 | 2016: February 8 2017: July 7 2018: May 28 2019: June 17, June 17 2020: May 27, May 27 2021: May 27, July 11, August 15 | 10m | +| Landsat 7 | 2017: August 16 | 30m | +| Landsat 8 | 2021: July 18 | 30m | +| ASTER | 2017: July 15 2018: August 19 2019: June 19 2020: August 8 | 15m–30m | As you have seen in earlier chapters, creating classifications can be very involved and time consuming. To allow you to concentrate on BULC’s efforts to clean noise from an existing ImageCollection, we have created the classifications already and stored them as an ImageCollection asset. You can view the Event time series using the ui.Thumbnail function, which creates an animation of the elements of the collection​​​​. Paste the code below into a new script to see those classifications drawn in sequence in the Console. +```js var events = ee.ImageCollection( 'projects/gee-book/assets/F4-8/cleanEvents'); print(events, 'List of Events'); print('Number of events:', events.size()); @@ -2403,6 +2465,7 @@ print(ui.Thumbnail(events, { framesPerSecond: 1, dimensions: 1000 })); +``` In the thumbnail sequence, the color palette shows Forest (class 1) as green, Water (class 2) as blue, and Active Agriculture (class 3) as yellow. Areas with no data in a particular Event are shown in black. @@ -2675,90 +2738,126 @@ In this chapter, we introduce lagged effects into our previous discussions on in Before we dive into autocovariance and autocorrelation, let’s set up an area of interest and dataset that we can use to illustrate these concepts. We will work with a detrended time series (as seen in Chap. F4.6) based on the USGS Landsat 8 Level 2, Collection 2, Tier 1 image collection. Copy and paste the code below to filter the Landsat 8 collection to a point of interest over California and specific dates, and apply the pre-processing function—to mask clouds (as seen in Chap. F4.3) and to scale and add variables of interest (as seen in Chap. F4.6). ```js -// Define function to mask clouds, scale, and add variables -// (NDVI, time and a constant) to Landsat 8 imagery. -function maskScaleAndAddVariable(image) { // Bit 0 - Fill // Bit 1 - Dilated Cloud // Bit 2 - Cirrus // Bit 3 - Cloud // Bit 4 - Cloud Shadow var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0); var saturationMask = image.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- 0.2); var thermalBands = image.select('ST_B.*').multiply(0.00341802) - .add(149.0); // Replace the original bands with the scaled ones and apply the masks. var img = image.addBands(opticalBands, null, true) - .addBands(thermalBands, null, true) - .updateMask(qaMask) - .updateMask(saturationMask); var imgScaled = image.addBands(img, null, true); // Now we start to add variables of interest. // Compute time in fractional years since the epoch. var date = ee.Date(image.get('system:time_start')); var years = date.difference(ee.Date('1970-01-01'), 'year'); var timeRadians = ee.Image(years.multiply(2 * Math.PI)); - // Return the image with the added bands. - return imgScaled - // Add an NDVI band. - .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) - .rename('NDVI')) // Add a time band. .addBands(timeRadians.rename('t')) - .float() // Add a constant band. .addBands(ee.Image.constant(1)); -} - -// Import region of interest. Area over California. -var roi = ee.Geometry.Polygon([ - [-119.44617458417066,35.92639730653253], - [-119.07675930096754,35.92639730653253], - [-119.07675930096754,36.201704711823844], - [-119.44617458417066,36.201704711823844], - [-119.44617458417066,35.92639730653253] -]); - - -// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, -// filter, mask clouds, scale, and add variables. -var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') - .filterBounds(roi) - .filterDate('2013-01-01', '2018-01-01') - .map(maskScaleAndAddVariable); - -// Set map center. -Map.centerObject(roi, 10); +// Define function to mask clouds, scale, and add variables +// (NDVI, time and a constant) to Landsat 8 imagery. +function maskScaleAndAddVariable(image) { + // Bit 0 - Fill + // Bit 1 - Dilated Cloud + // Bit 2 - Cirrus + // Bit 3 - Cloud + // Bit 4 - Cloud Shadow + var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = image.select('QA_RADSAT').eq(0); + // Apply the scaling factors to the appropriate bands. + var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- + 0.2); + var thermalBands = image.select('ST_B.*').multiply(0.00341802) + .add(149.0); + + // Replace the original bands with the scaled ones and apply the masks. + var img = image.addBands(opticalBands, null, true) + .addBands(thermalBands, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); + var imgScaled = image.addBands(img, null, true); + + // Now we start to add variables of interest. + // Compute time in fractional years since the epoch. + var date = ee.Date(image.get('system:time_start')); + var years = date.difference(ee.Date('1970-01-01'), 'year'); + var timeRadians = ee.Image(years.multiply(2 * Math.PI)); + // Return the image with the added bands. + return imgScaled + // Add an NDVI band. + .addBands(imgScaled.normalizedDifference(['SR_B5', 'SR_B4']) + .rename('NDVI')) + // Add a time band. + .addBands(timeRadians.rename('t')) + .float() + // Add a constant band. + .addBands(ee.Image.constant(1)); +} + +// Import region of interest. Area over California. +var roi = ee.Geometry.Polygon([ + [-119.44617458417066,35.92639730653253], + [-119.07675930096754,35.92639730653253], + [-119.07675930096754,36.201704711823844], + [-119.44617458417066,36.201704711823844], + [-119.44617458417066,35.92639730653253] +]); + + +// Import the USGS Landsat 8 Level 2, Collection 2, Tier 1 collection, +// filter, mask clouds, scale, and add variables. +var landsat8sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') + .filterBounds(roi) + .filterDate('2013-01-01', '2018-01-01') + .map(maskScaleAndAddVariable); + +// Set map center. +Map.centerObject(roi, 10); ``` Next, copy and paste the code below to estimate the linear trend using the linearRegression reducer, and remove that linear trend from the time series. ```js -// List of the independent variable names. -var independents = ee.List(['constant', 't']); - -// Name of the dependent variable. -var dependent = ee.String('NDVI'); - -// Compute a linear trend. This will have two bands: 'residuals' and -// a 2x1 band called coefficients (columns are for dependent variables). -var trend = landsat8sr.select(independents.add(dependent)) - .reduce(ee.Reducer.linearRegression(independents.length(), 1)); - -// Flatten the coefficients into a 2-band image -var coefficients = trend.select('coefficients') // Get rid of extra dimensions and convert back to a regular image .arrayProject([0]) - .arrayFlatten([independents]); - -// Compute a detrended series. -var detrended = landsat8sr.map(function(image) { return image.select(dependent) - .subtract(image.select(independents).multiply( - coefficients) - .reduce('sum')) - .rename(dependent) - .copyProperties(image, ['system:time_start']); -}); +// List of the independent variable names. +var independents = ee.List(['constant', 't']); +// Name of the dependent variable. +var dependent = ee.String('NDVI'); + +// Compute a linear trend. This will have two bands: 'residuals' and +// a 2x1 band called coefficients (columns are for dependent variables). +var trend = landsat8sr.select(independents.add(dependent)) + .reduce(ee.Reducer.linearRegression(independents.length(), 1)); + +// Flatten the coefficients into a 2-band image +var coefficients = trend.select('coefficients') + // Get rid of extra dimensions and convert back to a regular image + .arrayProject([0]) + .arrayFlatten([independents]); + +// Compute a detrended series. +var detrended = landsat8sr.map(function(image) { + return image.select(dependent) + .subtract(image.select(independents).multiply( + coefficients) + .reduce('sum')) + .rename(dependent) + .copyProperties(image, ['system:time_start']); +}); ``` Now let’s turn to autocovariance and autocorrelation. The autocovariance of a time series refers to the dependence of values in the time series at time t with values at time h = t − lag. The autocorrelation is the correlation between elements of a dataset at one time and elements of the same dataset at a different time. The autocorrelation is the autocovariance normalized by the standard deviations of the covariates. Specifically, we assume our time series is stationary, and define the autocovariance and autocorrelation following Shumway and Stoffer (2019). Comparing values at time t to previous values is useful not only for computing autocovariance, but also for a variety of other time series analyses as you'll see shortly. To combine image data with previous values in Earth Engine, the first step is to join the previous values to the current values. To do that, we will use a ee.Join function to create what we'll call a lagged collection. Copy and paste the code below to define a function that creates a lagged collection. ```js -// Function that creates a lagged collection. -var lag = function(leftCollection, rightCollection, lagDays) { var filter = ee.Filter.and( ee.Filter.maxDifference({ - difference: 1000 * 60 * 60 * 24 * lagDays, - leftField: 'system:time_start', - rightField: 'system:time_start' }), ee.Filter.greaterThan({ - leftField: 'system:time_start', - rightField: 'system:time_start' })); return ee.Join.saveAll({ - matchesKey: 'images', - measureKey: 'delta_t', - ordering: 'system:time_start', - ascending: false, // Sort reverse chronologically }).apply({ - primary: leftCollection, - secondary: rightCollection, - condition: filter - }); +// Function that creates a lagged collection. +var lag = function(leftCollection, rightCollection, lagDays) { + var filter = ee.Filter.and( + ee.Filter.maxDifference({ + difference: 1000 * 60 * 60 * 24 * lagDays, + leftField: 'system:time_start', + rightField: 'system:time_start' + }), + ee.Filter.greaterThan({ + leftField: 'system:time_start', + rightField: 'system:time_start' + })); + + return ee.Join.saveAll({ + matchesKey: 'images', + measureKey: 'delta_t', + ordering: 'system:time_start', + ascending: false, // Sort reverse chronologically + }).apply({ + primary: leftCollection, + secondary: rightCollection, + condition: filter + }); }; ``` @@ -2774,42 +2873,49 @@ Why 17 days? Recall that the temporal cadence of Landsat is 16 days. Specifying Now, we will compute the autocovariance using a reducer that expects a set of one-dimensional arrays as input. So pixel values corresponding to time t need to be stacked with pixel values at time t − lag as multiple bands in the same image. Copy and paste the code below to define a function to do so, and apply it to merge the bands from the lagged collection. ```js -// Function to stack bands. -var merge = function(image) { // Function to be passed to iterate. var merger = function(current, previous) { return ee.Image(previous).addBands(current); - }; return ee.ImageCollection.fromImages(image.get('images')) - .iterate(merger, image); -}; - -// Apply merge function to the lagged collection. -var merged17 = ee.ImageCollection(lagged17.map(merge)); +// Function to stack bands. +var merge = function(image) { + // Function to be passed to iterate. + var merger = function(current, previous) { + return ee.Image(previous).addBands(current); + }; + return ee.ImageCollection.fromImages(image.get('images')) + .iterate(merger, image); +}; +// Apply merge function to the lagged collection. +var merged17 = ee.ImageCollection(lagged17.map(merge)); ``` Now the bands from time t and h are all in the same image. Note that the band name of a pixel at time h, ph, was the same as time t, pt (band name is “NDVI” in this case). During the merging process, it gets a '_1' appended to it (e.g. NDVI_1). You can print the image collection to check the band names of one of the images. Copy and paste the code below to map a function to convert the merged bands to arrays with bands pt and ph, and then reduce it with the covariance reducer. We use a parallelScale factor of 8 in the reduce function to avoid the computation to run out of memory (this is not always needed). Note that the output of the covariance reducer is an array image, in which each pixel stores a 2x2 variance-covariance array. The off-diagonal elements are covariance, which you can map directly using the arrayGet function. ```js -// Function to compute covariance. -var covariance = function(mergedCollection, band, lagBand) { return mergedCollection.select([band, lagBand]).map(function( - image) { return image.toArray(); - }).reduce(ee.Reducer.covariance(), 8); -}; - -// Concatenate the suffix to the NDVI band. -var lagBand = dependent.cat('_1'); - -// Compute covariance. -var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) - .clip(roi); - -// The output of the covariance reducer is an array image, -// in which each pixel stores a 2x2 variance-covariance array. -// The off diagonal elements are covariance, which you can map -// directly using: -Map.addLayer(covariance17.arrayGet([0, 1]), - { - min: 0, - max: 0.02 }, 'covariance (lag = 17 days)'); +// Function to compute covariance. +var covariance = function(mergedCollection, band, lagBand) { + return mergedCollection.select([band, lagBand]).map(function( + image) { + return image.toArray(); + }).reduce(ee.Reducer.covariance(), 8); +}; + +// Concatenate the suffix to the NDVI band. +var lagBand = dependent.cat('_1'); + +// Compute covariance. +var covariance17 = ee.Image(covariance(merged17, dependent, lagBand)) + .clip(roi); + +// The output of the covariance reducer is an array image, +// in which each pixel stores a 2x2 variance-covariance array. +// The off diagonal elements are covariance, which you can map +// directly using: +Map.addLayer(covariance17.arrayGet([0, 1]), + { + min: 0, + max: 0.02 + }, + 'covariance (lag = 17 days)'); ``` Inspect the pixel values of the resulting covariance image (Fig. F4.9.1). The covariance is positive when the greater values of one variable (at time t) mainly correspond to the greater values of the other variable (at time h), and the same holds for the lesser values, therefore, the values tend to show similar behavior. In the opposite case, when the greater values of a variable correspond to the lesser values of the other variable, the covariance is negative. @@ -2820,17 +2926,23 @@ Inspect the pixel values of the resulting covariance image (Fig. F4.9.1). The co The diagonal elements of the variance-covariance array are variances. Copy and paste the code below to define and map a function to compute correlation (Fig. F4.9.2) from the variance-covariance array. ```js -// Define the correlation function. -var correlation = function(vcArrayImage) { var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); return covariance.divide(sd0).divide(sd1).rename( 'correlation'); -}; - -// Apply the correlation function. -var correlation17 = correlation(covariance17).clip(roi); -Map.addLayer(correlation17, - { - min: -1, - max: 1 }, 'correlation (lag = 17 days)'); +// Define the correlation function. +var correlation = function(vcArrayImage) { + var covariance = ee.Image(vcArrayImage).arrayGet([0, 1]); + var sd0 = ee.Image(vcArrayImage).arrayGet([0, 0]).sqrt(); + var sd1 = ee.Image(vcArrayImage).arrayGet([1, 1]).sqrt(); + return covariance.divide(sd0).divide(sd1).rename( + 'correlation'); +}; +// Apply the correlation function. +var correlation17 = correlation(covariance17).clip(roi); +Map.addLayer(correlation17, + { + min: -1, + max: 1 + }, + 'correlation (lag = 17 days)'); ``` ![Fig. F4.9.2 Autocorrelation image](F4/image33.png) @@ -2877,26 +2989,27 @@ What do you observe from this result? Looking at the cross-correlation image (Fi Perhaps precipitation in the month before the observed NDVI is relevant? Copy and paste the code below to test the 30-day lag idea. ```js -// Join the precipitation images from the previous month. -var lag30PrecipNDVI = lag(landsat8sr, chirps, 30); - -var sum30PrecipNDVI = ee.ImageCollection(lag30PrecipNDVI.map(function( - image) { var laggedImages = ee.ImageCollection.fromImages(image - .get('images')); return ee.Image(image).addBands(laggedImages.sum() - .rename('sum')); -})); - -// Compute covariance. -var cov30PrecipNDVI = covariance(sum30PrecipNDVI, 'NDVI', 'sum').clip( - roi); -Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, 'NDVI - sum cov (lag = 30)'); - -// Correlation. -var corr30PrecipNDVI = correlation(cov30PrecipNDVI).clip(roi); -Map.addLayer(corr30PrecipNDVI, { - min: -0.5, - max: 0.5}, 'NDVI - sum corr (lag = 30)'); +// Precipitation (covariate) +var chirps = ee.ImageCollection('UCSB-CHG/CHIRPS/PENTAD'); +// Join the t-l (l=1 pentad) precipitation images to the Landsat. +var lag1PrecipNDVI = lag(landsat8sr, chirps, 5); + +// Add the precipitation images as bands. +var merged1PrecipNDVI = ee.ImageCollection(lag1PrecipNDVI.map(merge)); + +// Compute and display cross-covariance. +var cov1PrecipNDVI = covariance(merged1PrecipNDVI, 'NDVI', + 'precipitation').clip(roi); +Map.addLayer(cov1PrecipNDVI.arrayGet([0, 1]), {}, + 'NDVI - PRECIP cov (lag = 5)'); + +// Compute and display cross-correlation. +var corr1PrecipNDVI = correlation(cov1PrecipNDVI).clip(roi); +Map.addLayer(corr1PrecipNDVI, { + min: -0.5, + max: 0.5 +}, 'NDVI - PRECIP corr (lag = 5)'); ``` Observe that the only change is to the merge method. Instead of merging the bands of the NDVI image and the covariate (precipitation), the entire list of precipitation is summed and added as a band (eliminating the need for iterate). @@ -2914,29 +3027,34 @@ Code Checkpoint F49b. The book’s repository contains a script that shows what The discussion of autocovariance preceded this section in order to introduce the concept of lag. Now that you have a way to get previous values of a variable, it's worth considering auto-regressive models. Suppose that pixel values at time t depend in some way on previous pixel values—auto-regressive models are time series models that use observations from previous time steps as input to a regression equation to predict the value at the next time step. If you have observed significant, non-zero autocorrelations in a time series, this is a good assumption. Specifically, you may postulate a linear model such as the following, where pt is a pixel at time t, and et is a random error (Chap. F4.6): -pt = β0 + β1pt-1 + β2pt-2 + et (F4.9.1) +$p_t = β_0 + β_1 p_{t-1} + β_2 p_{t-2} + e_t$ (F4.9.1) To fit this model, you need a lagged collection as created previously, except with a longer lag (e.g., lag = 34 days). The next steps are to merge the bands, then reduce with the linear regression reducer. Copy and paste the line below to the existing script to create a lagged collection, where the images list stores the two previous images: - +```js var lagged34 = ee.ImageCollection(lag(landsat8sr, landsat8sr, 34)); +``` Copy and paste the code below to merge the bands of the lagged collection such that each image has bands at time t and bands at times t - 1,..., t − lag. Note that it's necessary to filter out any images that don't have two previous temporal neighbors. -var merged34 = lagged34.map(merge).map(function(image) { return image.set('n', ee.List(image.get('images')) - .length()); +```js +var merged34 = lagged34.map(merge).map(function(image) { + return image.set('n', ee.List(image.get('images')) + .length()); }).filter(ee.Filter.gt('n', 1)); +``` Now, copy and paste the code below to fit the regression model using the linearRegression reducer. +```js + var arIndependents = ee.List(['constant', 'NDVI_1', 'NDVI_2']); var ar2 = merged34 .select(arIndependents.add(dependent)) .reduce(ee.Reducer.linearRegression(arIndependents.length(), 1)); -```js // Turn the array image into a multi-band image of coefficients. var arCoefficients = ar2.select('coefficients') .arrayProject([0]) @@ -2948,7 +3066,7 @@ We can compute the fitted values using the expression function in Earth Engine. ```js // Compute fitted values. var fittedAR = merged34.map(function(image) { return image.addBands( - image.expression( 'beta0 + beta1 * p1 + beta2 * p2', { + image.expression('beta0 + beta1 * p1 + beta2 * p2', { p1: image.select('NDVI_1'), p2: image.select('NDVI_2'), beta0: arCoefficients.select('constant'), diff --git a/F5.qmd b/F5.qmd index a88f3f4..ee38b62 100644 --- a/F5.qmd +++ b/F5.qmd @@ -165,7 +165,9 @@ Map.addLayer(usfTiger, {}, 'usf_Tiger'); In addition to filtering a FeatureCollection by the location of another feature, you can also filter it by its properties. First, let’s print the usfTiger variable to the Console and inspect the object. +```js print(usfTiger); +``` You can click on the feature collection name in the Console to uncover more information about the dataset. Click on the columns to learn about what attribute information is contained in this dataset. You will notice this feature collection contains information on both housing ('housing10') and population ('pop10'). @@ -181,11 +183,14 @@ var housing10_l250 = usfTiger ``` Now filter the already-filtered blocks to have more than 50 housing units. +```js var housing10_g50_l250 = housing10_l250.filter(ee.Filter.gt( 'housing10', 50)); - +``` Now, let’s visualize what this looks like. +```js Map.addLayer(housing10_g50_l250, { 'color': 'Magenta'}, 'housing'); +``` We have combined spatial and attribute information to narrow the set to only those blocks that meet our criteria of having between 50 and 250 housing units. @@ -193,17 +198,21 @@ We have combined spatial and attribute information to narrow the set to only tho We can print out attribute information about these features. The block of code below prints out the area of the resultant geometry in square meters. +```js var housing_area = housing10_g50_l250.geometry().area(); print('housing_area:', housing_area); +``` The next block of code reduces attribute information and prints out the mean of the housing10 column. +```js var housing10_mean = usfTiger.reduceColumns({ reducer: ee.Reducer.mean(), selectors: ['housing10'] }); - + print('housing10_mean', housing10_mean); +``` Both of the above sections of code provide meaningful information about each feature, but they do not tell us which block is the most green. The next section will address that question. @@ -235,28 +244,30 @@ var image = ee.Image( ``` The next section of code assigns the near-infrared band (B5) to variable nir and assigns the red band (B4) to red. Then the bands are combined together to compute NDVI as (nir − red)/(nir + red). +```js var nir = image.select('B5'); var red = image.select('B4'); var ndvi = nir.subtract(red).divide(nir.add(red)).rename('NDVI'); - +``` #### Clip the NDVI Image to the Blocks Near USF Next, you will clip the NDVI layer to only show NDVI over USF’s neighborhood. The first section of code provides visualization settings. - +```js var ndviParams = { min: -1, max: 1, palette: ['blue', 'white', 'green'] }; - +``` The second block of code clips the image to our filtered housing layer. +```js var ndviUSFblocks = ndvi.clip(housing10_g50_l250); Map.addLayer(ndviUSFblocks, ndviParams, 'NDVI image'); Map.centerObject(usf_point, 14); - +``` The NDVI map for all of San Francisco is interesting, and shows variability across the region. Now, let’s compute mean NDVI values for each block of the city. #### Compute NDVI Statistics by Block @@ -300,11 +311,15 @@ Code Checkpoint F50d. The book’s repository contains a script that shows what You are already familiar with filtering datasets by their attributes. Now you will sort a table and select the first element of the table. +```js ndviPerBlock = ndviPerBlock.select(['blockid10', 'mean']); print('ndviPerBlock', ndviPerBlock); + var ndviPerBlockSorted = ndviPerBlock.sort('mean', false); -var ndviPerBlockSortedFirst = ee.Feature(ndviPerBlock.sort('mean', false) //Sort by NDVI mean in descending order. .first()); //Select the block with the highest NDVI. +var ndviPerBlockSortedFirst = ee.Feature(ndviPerBlock.sort('mean',false) //Sort by NDVI mean in descending order. + .first()); //Select the block with the highest NDVI. print('ndviPerBlockSortedFirst', ndviPerBlockSortedFirst); +``` If you expand the feature of ndviPerBlockSortedFirst in the Console, you will be able to identify the blockid10 value of the greenest block and the mean NDVI value for that area. @@ -314,6 +329,7 @@ Another way to look at the data is by exporting the data to a table. Open the ta // Now filter by block and show on map! var GreenHousing = usfTiger.filter(ee.Filter.eq('blockid10', '###')); //< Put your id here prepend a 0! + Map.addLayer(GreenHousing, { 'color': 'yellow'}, 'Green Housing!'); ``` @@ -416,6 +432,7 @@ Map.addLayer(zones, { ``` We will convert this zonal elevation image in Colombia to polygon shapes, which is a vector format (termed a FeatureCollection in Earth Engine), using the ee.Image.reduceToVectors method. This will create polygons delineating connected pixels with the same value. In doing so, we will use the same projection and spatial resolution as the image. Please note that loading the vectorized image in the native resolution (231.92 m) takes time to execute. For faster visualization, we set a coarse scale of 1,000 m. +```js var projection = elevation.projection(); var scale = elevation.projection().nominalScale(); @@ -437,6 +454,7 @@ var elevationDrawn = elevationVector.draw({ strokeWidth: 1 }); Map.addLayer(elevationDrawn, {}, 'Elevation zone polygon'); +``` ![](F5/image50.png) @@ -449,6 +467,7 @@ Map.addLayer(elevationDrawn, {}, 'Elevation zone polygon'); You may have realized that polygons consist of complex lines, including some small polygons with just one pixel. That happens when there are no surrounding pixels of the same elevation zone. You may not need a vector map with such details—if, for instance, you want to produce a regional or global map. We can use a morphological reducer focalMode to simplify the shape by defining a neighborhood size around a pixel. In this example, we will set the kernel radius as four pixels. This operation makes the resulting polygons look much smoother, but less precise (Fig. F5.1.2). +```js var zonesSmooth = zones.focalMode(4, 'square'); zonesSmooth = zonesSmooth.reproject(projection.atScale(scale)); @@ -477,6 +496,8 @@ var smoothDrawn = elevationVectorSmooth.draw({ }); Map.addLayer(smoothDrawn, {}, 'Elevation zone polygon (smooth)'); +``` + We can see now that the polygons have more distinct shapes with many fewer small polygons in the new map (Fig. F5.1.2). It is important to note that when you use methods like focalMode (or other, similar methods such as connectedComponents and connectedPixelCount), you need to reproject according to the original image in order to display properly with zoom using the interactive Code Editor. ![](F5/image20.png) @@ -532,8 +553,10 @@ Export.table.toDrive({ }); ``` + We can also extract sample points per elevation zone. Below is an example of extracting 10 randomly selected points per elevation zone (Fig. F5.1.4). You can also set different values for each zone using classValues and classPoints parameters to modify the sampling intensity in each class. This may be useful, for instance, to generate point samples for a validation effort. +```js var elevationSamplesStratified = zones.stratifiedSample({ numPoints: 10, classBand: 'zone', @@ -545,13 +568,15 @@ var elevationSamplesStratified = zones.stratifiedSample({ Map.addLayer(elevationSamplesStratified, {}, 'Stratified samples'); +``` + ![Fig. F5.1.4 Stratified sampling over different elevation zones](F5/image23.png) :::{.callout-note} Code Checkpoint F51a. The book’s repository contains a script that shows what your code should look like at this point. ::: -###3. A More Complex Example +### 3. A More Complex Example In this section we’ll use two global datasets, one to represent raster formats and the other vectors: @@ -649,6 +674,7 @@ Fig. F5.1.6 shows a comparison of the raster versus vector representations of de Having converted from raster to vector, a new set of operations becomes available for post-processing the deforestation data. We might, for instance, be interested in the number of individual change events each year (Fig. F5.1.7): +```js var chart = ui.Chart.feature .histogram({ features: deforestationVector, @@ -661,6 +687,7 @@ var chart = ui.Chart.feature legend: { position: 'none' } });print(chart); +``` ![Fig. F5.1.7 Plot of the number of deforestation events in La Paya for the years 2001–2020](F5/image15.png) @@ -756,9 +783,10 @@ wdpaSubset = deforestation.gte(1) }); print(wdpaSubset); // Note the new 'deforestation_area' property. - +``` The output of this script is an estimate of deforested area in hectares for each reserve. However, as reserve sizes vary substantially by area, we can normalize by the total area of each reserve to quantify rates of change. +```js // Normalize by area. wdpaSubset = wdpaSubset.map( function(feat) { return feat.set('deforestation_rate', ee.Number(feat.get('deforestation_area')) .divide(feat.area().divide(10000)) // m2 to ha .divide(20) // number of years .multiply(100)); // to percentage points });// Print to identify rates of change per protected area. @@ -769,6 +797,7 @@ print(wdpaSubset.reduceColumns({ })); ``` + :::{.callout-note} Code Checkpoint F51c. The book’s repository contains a script that shows what your code should look like at this point. ::: @@ -892,6 +921,7 @@ Sometimes it makes sense to work with objects in raster imagery. This is an unus An example of this is estimating deforestation rates by distance to the edge of the protected area, as it is common that rates of change will be higher at the boundary of a protected area. We will create a distance raster with three zones from the La Paya boundary (>1 km, >2 km, >3 km, and >4 km) and to estimate the deforestation by distance from the boundary (Fig. F5.1.9). +```js var distanceZones = ee.Image(0) .where(distance.gt(0), 1) .where(distance.gt(1000), 2) @@ -917,6 +947,8 @@ Map.addLayer(deforestation5km, { max: 1, opacity: 0.5}, 'Deforestation within a 5km buffer'); +``` + ![](F5/image22.png) ![](F5/image6.png) @@ -928,10 +960,11 @@ Map.addLayer(deforestation5km, { Lastly, we can estimate the deforestation area within 1 km of the protected area but only outside of the boundary. +```js + var deforestation1kmOutside = deforestation1km .updateMask(protectedAreaRaster.unmask().not()); -```js // Get the value of each pixel in square meters // and divide by 10000 to convert to hectares. var deforestation1kmOutsideArea = deforestation1kmOutside.eq(1) @@ -1020,33 +1053,17 @@ Two functions are provided; copy and paste them into your script: #### Function: bufferPoints(radius, bounds) -Our first function, bufferPoints, returns a function for adding a buffer to points and optionally transforming to rectangular bounds (see Table F5.2.1). - -Table F5.2.1 Parameters for bufferPoints - -Parameter - -Type - -Description - -radius - -Number - -buffer radius (m). - -[bounds=false] - -Boolean - -An optional flag indicating whether to transform buffered point (i.e., a circle) to square bounds. - -function bufferPoints(radius, bounds) { return function(pt) { - pt = ee.Feature(pt); return bounds ? pt.buffer(radius).bounds() : pt.buffer( - radius); - }; +Our first function, bufferPoints, returns a function for adding a buffer to points and optionally transforming to rectangular bounds + +```js +function bufferPoints(radius, bounds) { + return function(pt) { + pt = ee.Feature(pt); + return bounds ? pt.buffer(radius).bounds() : pt.buffer( + radius); + }; } +``` #### Function: zonalStats(fc, params) @@ -1054,121 +1071,109 @@ The second function, zonalStats, reduces images in an ImageCollection by regions This function is written to include many optional parameters (see Table F5.2.2). Look at the function carefully and note how it is written to include defaults that make it easy to apply the basic function while allowing customization. -Table F5.2.2 Parameters for zonalStats - -Parameter - -Type - -Description - -ic - -ee.ImageCollection - -Image collection from which to extract values. - -fc - -ee.FeatureCollection - -Feature collection that provides regions/zones by which to reduce image pixels. - -[params] - -Object - -An optional Object that provides function arguments. - -[params.reducer=ee.Reducer.mean()] - -ee.Reducer - -The reducer to apply. Optional. - -[params.scale=null] - -Number - -A nominal scale in meters of the projection to work in. If null, the native nominal image scale is used. Optional. - -[params.crs=null] - -String - -The projection to work in. If null, the native image Coordinate Reference System (CRS) is used. Optional. - -[params.bands=null] - -Array - -A list of image band names for which to reduce values. If null, all bands will be reduced. Band names define column names in the resulting reduction table. Optional. - -[params.bandsRename=null] - -Array - -A list of desired image band names. The length and order must correspond to the params.bands list. If null, band names will be unchanged. Band names define column names in the resulting reduction table. Optional. - -[params.imgProps=null] - -Array - -A list of image properties to include in the table of region reduction results. If null, all image properties are included. Optional. - -[params.imgPropsRename=null] - -Array - -A list of image property names to replace those provided by params.imgProps. The length and order must match the params.imgProps entries. Optional. - -[params.datetimeName='datetime] - -String - -The desired name of the datetime field. The datetime refers to the 'system:time_start' value of the ee.Image being reduced. Optional. - -[params.datetimeFormat='YYYY-MM-dd HH:mm:ss] - -String - The desired datetime format. Use ISO 8601 data string standards. The datetime string is derived from the 'system:time_start' value of the ee.Image being reduced. Optional. -function zonalStats(ic, fc, params) { // Initialize internal params dictionary. var _params = { - reducer: ee.Reducer.mean(), - scale: null, - crs: null, - bands: null, - bandsRename: null, - imgProps: null, - imgPropsRename: null, - datetimeName: 'datetime', - datetimeFormat: 'YYYY-MM-dd HH:mm:ss' }; // Replace initialized params with provided params. if (params) { for (var param in params) { - _params[param] = params[param] || _params[param]; - } - } // Set default parameters based on an image representative. var imgRep = ic.first(); var nonSystemImgProps = ee.Feature(null) - .copyProperties(imgRep).propertyNames(); if (!_params.bands) _params.bands = imgRep.bandNames(); if (!_params.bandsRename) _params.bandsRename = _params.bands; if (!_params.imgProps) _params.imgProps = nonSystemImgProps; if (!_params.imgPropsRename) _params.imgPropsRename = _params - .imgProps; // Map the reduceRegions function over the image collection. var results = ic.map(function(img) { // Select bands (optionally rename), set a datetime & timestamp property. img = ee.Image(img.select(_params.bands, _params - .bandsRename)) // Add datetime and timestamp features. .set(_params.datetimeName, img.date().format( - _params.datetimeFormat)) .set('timestamp', img.get('system:time_start')); // Define final image property dictionary to set in output features. var propsFrom = ee.List(_params.imgProps) .cat(ee.List([_params.datetimeName, 'timestamp'])); var propsTo = ee.List(_params.imgPropsRename) .cat(ee.List([_params.datetimeName, 'timestamp'])); var imgProps = img.toDictionary(propsFrom).rename( - propsFrom, propsTo); // Subset points that intersect the given image. var fcSub = fc.filterBounds(img.geometry()); // Reduce the image by regions. return img.reduceRegions({ - collection: fcSub, - reducer: _params.reducer, scale: _params.scale, crs: _params.crs - }) // Add metadata to each feature. .map(function(f) { return f.set(imgProps); - }); // Converts the feature collection of feature collections to a single //feature collection. }).flatten(); return results; +```js +function zonalStats(ic, fc, params) { + // Initialize internal params dictionary. + var _params = { + reducer: ee.Reducer.mean(), + scale: null, + crs: null, + bands: null, + bandsRename: null, + imgProps: null, + imgPropsRename: null, + datetimeName: 'datetime', + datetimeFormat: 'YYYY-MM-dd HH:mm:ss' + }; + + // Replace initialized params with provided params. + if (params) { + for (var param in params) { + _params[param] = params[param] || _params[param]; + } + } + + // Set default parameters based on an image representative. + var imgRep = ic.first(); + var nonSystemImgProps = ee.Feature(null) + .copyProperties(imgRep).propertyNames(); + if (!_params.bands) _params.bands = imgRep.bandNames(); + if (!_params.bandsRename) _params.bandsRename = _params.bands; + if (!_params.imgProps) _params.imgProps = nonSystemImgProps; + if (!_params.imgPropsRename) _params.imgPropsRename = _params + .imgProps; + + // Map the reduceRegions function over the image collection. + var results = ic.map(function(img) { + // Select bands (optionally rename), set a datetime & timestamp property. + img = ee.Image(img.select(_params.bands, _params + .bandsRename)) + // Add datetime and timestamp features. + .set(_params.datetimeName, img.date().format( + _params.datetimeFormat)) + .set('timestamp', img.get('system:time_start')); + + // Define final image property dictionary to set in output features. + var propsFrom = ee.List(_params.imgProps) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var propsTo = ee.List(_params.imgPropsRename) + .cat(ee.List([_params.datetimeName, + 'timestamp'])); + var imgProps = img.toDictionary(propsFrom).rename( + propsFrom, propsTo); + + // Subset points that intersect the given image. + var fcSub = fc.filterBounds(img.geometry()); + + // Reduce the image by regions. + return img.reduceRegions({ + collection: fcSub, + reducer: _params.reducer, + scale: _params.scale, + crs: _params.crs + }) + // Add metadata to each feature. + .map(function(f) { + return f.set(imgProps); + }); + + // Converts the feature collection of feature collections to a single + //feature collection. + }).flatten(); + + return results; } +``` + ### Point Collection Creation Below, we create a set of points that form the basis of the zonal statistics calculations. Note that a unique plot_id property is added to each point. A unique plot or point ID is important to include in your vector dataset for future filtering and joining. -var pts = ee.FeatureCollection([ ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { - plot_id: 1 }), ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { - plot_id: 2 }), ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { - plot_id: 3 }), ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { - plot_id: 4 }), ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { - plot_id: 5 }) -]);print('Points of interest', pts); +```js +var pts = ee.FeatureCollection([ + ee.Feature(ee.Geometry.Point([-118.6010, 37.0777]), { + plot_id: 1 + }), + ee.Feature(ee.Geometry.Point([-118.5896, 37.0778]), { + plot_id: 2 + }), + ee.Feature(ee.Geometry.Point([-118.5842, 37.0805]), { + plot_id: 3 + }), + ee.Feature(ee.Geometry.Point([-118.5994, 37.0936]), { + plot_id: 4 + }), + ee.Feature(ee.Geometry.Point([-118.5861, 37.0567]), { + plot_id: 5 + }) +]); + +print('Points of interest', pts); +``` :::{.callout-note} Code Checkpoint F52a. The book’s repository contains a script that shows what your code should look like at this point. @@ -1256,83 +1261,33 @@ The result is a copy of the buffered point feature collection with new propertie Table F5.2.3 Example output from zonalStats organized as a table. Rows correspond to collection features and columns are feature properties. Note that elevation and slope values in this table are rounded to the nearest tenth for brevity. -plot_id - -timestamp - -datetime - -elevation - -slope - -1 - -946684800000 - -2000-01-01 00:00:00 - -2648.1 - -29.7 - -2 - -946684800000 - -2000-01-01 00:00:00 - -2888.2 - -33.9 - -3 - -946684800000 - -2000-01-01 00:00:00 - -3267.8 - -35.8 - -4 - -946684800000 - -2000-01-01 00:00:00 - -2790.7 - -25.1 - -5 - -946684800000 - -2000-01-01 00:00:00 - -2559.4 - -29.4 +| plot_id | timestamp | datetime | elevation | slope | +|---------|--------------|---------------------|-----------|-------| +| 1 | 946684800000 | 2000-01-01 00:00:00 | 2648.1 | 29.7 | +| 2 | 946684800000 | 2000-01-01 00:00:00 | 2888.2 | 33.9 | +| 3 | 946684800000 | 2000-01-01 00:00:00 | 3267.8 | 35.8 | +| 4 | 946684800000 | 2000-01-01 00:00:00 | 2790.7 | 25.1 | +| 5 | 946684800000 | 2000-01-01 00:00:00 | 2559.4 | 29.4 | #### MODIS Time Series A time series of MODIS eight-day surface reflectance composites demonstrates how to calculate zonal statistics for a multiband ImageCollection that requires no preprocessing, such as cloud masking or computation. Note that there is no built-in function for performing region reductions on ImageCollection objects. The zonalStats function that we are using for reduction is mapping the reduceRegions function over an ImageCollection. -####Buffer the Points +#### Buffer the Points In this example, suppose the point collection represents center points for field plots that are 100 m x 100 m, and apply a 50 m radius buffer to the points to match the size of the plot. Since we want zonal statistics for square plots, set the second argument of the bufferPoints function to true, so that the bounds of the buffered points are returned. var ptsModis = pts.map(bufferPoints(50, true)); -####Calculate Zonal Statistic +#### Calculate Zonal Statistic Import the MODIS 500 m global eight-day surface reflectance composite collection and filter the collection to include data for July, August, and September from 2015 through 2019. +```js var modisCol = ee.ImageCollection('MODIS/006/MOD09A1') .filterDate('2015-01-01', '2020-01-01') .filter(ee.Filter.calendarRange(183, 245, 'DAY_OF_YEAR')); +``` Reduce each image in the collection by each plot according to the following parameters. Note that this time the reducer is defined as the neighborhood median (ee.Reducer.median) instead of the default mean, and that scale, CRS, and properties for the datetime are explicitly defined. @@ -1360,22 +1315,38 @@ This example combines Landsat surface reflectance imagery across three instrumen The following section prepares these collections so that band names are consistent and cloud masks are applied. Reflectance among corresponding bands are roughly congruent for the three sensors when using the surface reflectance product; therefore the processing steps that follow do not address inter-sensor harmonization. Review the current literature on inter-sensor harmonization practices if you'd like to apply a correction. -####Prepare the Landsat Image Collection +#### Prepare the Landsat Image Collection First, define the function to mask cloud and shadow pixels (See Chap. F4.3 for more detail on cloud masking). ```js -// Mask clouds from images and apply scaling factors. -function maskScale(img) { var qaMask = img.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0); var saturationMask = img.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var getFactorImg = function(factorNames) { var factorList = img.toDictionary().select(factorNames) - .values(); return ee.Image.constant(factorList); - }; var scaleImg = getFactorImg(['REFLECTANCE_MULT_BAND_.']); var offsetImg = getFactorImg(['REFLECTANCE_ADD_BAND_.']); var scaled = img.select('SR_B.').multiply(scaleImg).add( - offsetImg); // Replace the original bands with the scaled ones and apply the masks. return img.addBands(scaled, null, true) - .updateMask(qaMask) - .updateMask(saturationMask); +// Mask clouds from images and apply scaling factors. +function maskScale(img) { + var qaMask = img.select('QA_PIXEL').bitwiseAnd(parseInt('11111', + 2)).eq(0); + var saturationMask = img.select('QA_RADSAT').eq(0); + + // Apply the scaling factors to the appropriate bands. + var getFactorImg = function(factorNames) { + var factorList = img.toDictionary().select(factorNames) + .values(); + return ee.Image.constant(factorList); + }; + var scaleImg = getFactorImg(['REFLECTANCE_MULT_BAND_.']); + var offsetImg = getFactorImg(['REFLECTANCE_ADD_BAND_.']); + var scaled = img.select('SR_B.').multiply(scaleImg).add( + offsetImg); + + // Replace the original bands with the scaled ones and apply the masks. + return img.addBands(scaled, null, true) + .updateMask(qaMask) + .updateMask(saturationMask); } +``` Next, define functions to select and rename the bands of interest for the Operational Land Imager (OLI) aboard Landsat 8, and for the TM/ETM+ imagers aboard earlier Landsats. This is important because the band numbers are different for OLI and TM/ETM+, and it will make future index calculations easier. +```js // Selects and renames bands of interest for Landsat OLI. function renameOli(img) { return img.select( ['SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B6', 'SR_B7'], @@ -1387,9 +1358,10 @@ function renameEtm(img) { return img.select( ['SR_B1', 'SR_B2', 'SR_B3', 'SR_B4', 'SR_B5', 'SR_B7'], ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2']); } - +``` Combine the cloud mask and band renaming functions into preparation functions for OLI and TM/ETM+. Add any other sensor-specific preprocessing steps that you’d like to the functions below. +```js // Prepares (cloud masks and renames) OLI images. function prepOli(img) { img = maskScale(img); @@ -1399,9 +1371,10 @@ function prepEtm(img) { img = maskScale(img); img = renameEtm(img); return img; } - +``` Get the Landsat surface reflectance collections for OLI, ETM+, and TM sensors. Filter them by the bounds of the point feature collection and apply the relevant image preparation function. +```js var ptsLandsat = pts.map(bufferPoints(15, true)); var oliCol = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') @@ -1415,13 +1388,14 @@ var etmCol = ee.ImageCollection('LANDSAT/LE07/C02/T1_L2') var tmCol = ee.ImageCollection('LANDSAT/LT05/C02/T1_L2') .filterBounds(ptsLandsat) .map(prepEtm); - ``` Merge the prepared sensor collections. +```js var landsatCol = oliCol.merge(etmCol).merge(tmCol); +``` -####Calculate Zonal Statistics +#### Calculate Zonal Statistics Reduce each image in the collection by each plot according to the following parameters. Note that this example defines the imgProps and imgPropsRename parameters to copy over and rename just two selected image properties: Landsat image ID and the satellite that collected the data. It also uses the max reducer, which, as an unweighted reducer, will return the maximum value from pixels that have their centroid within the buffer (see Sect. 4.1 below for more details). @@ -1446,12 +1420,13 @@ print('Limited Landsat zonal stats table', ptsLandsatStats.limit(50)); ``` The result is a feature collection with a feature for all combinations of plots and images. -####Dealing with Large Collections +#### Dealing with Large Collections If your browser times out, try exporting the results (as described in Chap. F6.2). It’s likely that point feature collections that cover a large area or contain many points (point-image observations) will need to be exported as a batch task by either exporting the final feature collection as an asset or as a CSV/shapefile/GeoJSON to Google Drive or GCS. Here is how you would export the above Landsat image-point feature collection to an asset and to Google Drive. Run the following code, activate the Code Editor Tasks tab, and then click the Run button. If you don’t specify your own existing folder in Drive, the folder “EEFA_outputs” will be created. +```js Export.table.toAsset({ collection: ptsLandsatStats, description: 'EEFA_export_Landsat_to_points', @@ -1463,6 +1438,7 @@ Export.table.toDrive({ folder: 'EEFA_outputs', // this will create a new folder if it doesn't exist description: 'EEFA_export_values_to_points', fileFormat: 'CSV' }); +``` :::{.callout-note} Code Checkpoint F52b. The book’s repository contains a script that shows what your code should look like at this point. @@ -1575,6 +1551,7 @@ Map.addLayer(pixelsFc, { color: 'purple'}, 'Pixels in reduction'); ``` + ![Fig. F5.2.3 Identifying pixels used in zonal statistics. By mapping the image and vector together, you can see which pixels are included in the unweighted statistic. For this example, three pixels would be included in the statistic because the polygon covers the center point of three pixels.](F5/image44.png) @@ -1697,6 +1674,7 @@ You will see that the population density values have a large range. We also have The result is an image with pixel values representing the population density of the polygons. We can now use the standard image visualization method to add this layer to the Map (Fig. F5.3.2). Then, we need to determine minimum and maximum values for the visualization parameters.A reliable technique to produce a good visualization is to find minimum and maximum values that are within one standard deviation. From the statistics that we calculated earlier, we can estimate good minimum and maximum values to be 0 and 50000, respectively. +```js var palette = ['fee5d9', 'fcae91', 'fb6a4a', 'de2d26', 'a50f15']; var visParams = { min: 0, @@ -1704,6 +1682,7 @@ var visParams = { palette: palette }; Map.addLayer(sfBlocksPaint.clip(geometry), visParams, 'Population Density'); +``` ![Fig. F5.3.2 San Francisco population density](F5/image41.png) @@ -1740,126 +1719,33 @@ Map.addLayer(sfRoadsDraw, {}, 'Roads (Draw)'); The road layer has a column called “MTFCC” (standing for the MAF/TIGER Feature Class Code). This contains the road priority codes, representing the various types of roads, such as primary and secondary. We can use this information to render each road segment according to its priority. The draw function doesn’t allow us to specify different styles for each feature. Instead, we need to make use of the style function. -The column contains string values indicating different road types as indicated in Table F5.3.1. This full list is available at the MAF/TIGER Feature Class Code Definitions page on the US Census Bureau website. - -Table F5.3.1 Census Bureau road priority codes - -MTFCC - -Feature Class - -S1100 - -Primary Road - -S1200 - -Secondary Road - -S1400 - -Local Neighborhood Road, Rural Road, City Street - -S1500 - -Vehicular Trail - -S1630 - -Ramp - -S1640 - -Service Drive - -S1710 - -Walkway/Pedestrian Trail - -S1720 - -Stairway - -S1730 - -Alley - -S1740 - -Private Road for service vehicles - -S1750 - -Internal U.S. Census Bureau use - -S1780 - -Parking Lot Road - -S1820 - -Bike Path or Trail - -S1830 - -Bridle Path - -S2000 - -Road Median - -Let’s say we want to create a map with rules based on the MTFCC values shown in Table F5.3.2. - -Table F5.3.2 Styling Parameters for Road Priority Codes - -MTFCC - -Color - -Line Width - -S1100 - -Blue - -3 - -S1200 - -Green - -2 - -S1400 - -Orange - -1 - -All Other Classes - -Gray - -1 +The column contains string values indicating different road types as indicated in at the MAF/TIGER Feature Class Code Definitions page on the US Census Bureau website. Let’s say we want to create a map with rules based on the MTFCC values. Let’s define a dictionary containing the styling information. +```js var styles = ee.Dictionary({ 'S1100': { 'color': 'blue', 'width': 3 }, 'S1200': { 'color': 'green', 'width': 2 }, 'S1400': { 'color': 'orange', 'width': 1 } });var defaultStyle = { color: 'gray', 'width': 1 }; +``` The style function needs a property in the FeatureCollection that contains a dictionary with the style parameters. This allows you to specify a different style for each feature. To create a new property, we map a function over the FeatureCollection and assign an appropriate style dictionary to a new property named 'style'. Note the use of the get function, which allows us to fetch the value for a key in the dictionary. It also takes a default value in case the specified key does not exist. We make use of this to assign different styles to the three road classes specified in Table 5.3.2 and a default style to all others. +```js var sfRoads = sfRoads.map(function(f) { var classcode = f.get('mtfcc'); var style = styles.get(classcode, defaultStyle); return f.set('style', style); }); +``` + Our collection is now ready to be styled. We call the style function to specify the property that contains the dictionary of style parameters. The output of the style function is an RGB image rendered from the FeatureCollection (Fig. F5.3.4). +```js var sfRoadsStyle = sfRoads.style({ styleProperty: 'style' }); Map.addLayer(sfRoadsStyle.clip(geometry), {}, 'Roads (Style)'); +``` ![Fig. F5.3.4 San Francisco roads rendered according to road priority](F5/image46.png) @@ -1886,6 +1772,7 @@ In this section, we will learn how to select features from one layer that are wi We start by loading the census blocks and roads collections and filtering the roads layer to the San Francisco boundary. +```js var blocks = ee.FeatureCollection('TIGER/2010/Blocks'); var roads = ee.FeatureCollection('TIGER/2016/Roads'); var sfNeighborhoods = ee.FeatureCollection( 'projects/gee-book/assets/F5-0/SFneighborhoods'); @@ -1893,7 +1780,6 @@ var sfNeighborhoods = ee.FeatureCollection( 'projects/gee-book/assets/F5-0/SFn var geometry = sfNeighborhoods.geometry(); Map.centerObject(geometry); -```js // Filter blocks and roads to San Francisco boundary. var sfBlocks = blocks.filter(ee.Filter.bounds(geometry)); var sfRoads = roads.filter(ee.Filter.bounds(geometry)); @@ -1901,10 +1787,13 @@ var sfRoads = roads.filter(ee.Filter.bounds(geometry)); ``` As we want to select all blocks within 1 km of an interstate highway, we first filter the sfRoads collection to select all segments with the rttyp property value of I. +```js var interstateRoads = sfRoads.filter(ee.Filter.eq('rttyp', 'I')); +``` We use the draw function to visualize the sfBlocks and interstateRoads layers (Fig. F5.3.5). +```js var sfBlocksDrawn = sfBlocks.draw({ color: 'gray', strokeWidth: 1 }) @@ -1915,34 +1804,41 @@ var interstateRoadsDrawn = interstateRoads.draw({ strokeWidth: 3 }) .clip(geometry); Map.addLayer(interstateRoadsDrawn, {}, 'Interstate Roads'); +``` ![Fig. F5.3.5 San Francisco blocks and interstate highways](F5/image2.png) Let’s define a join that will select all the features from the sfBlocks layer that are within 1 km of any feature from the interstateRoads layer. We start by defining a filter using the ee.Filter.withinDistance filter. We want to compare the geometries of features in both layers, so we use a special property called '.geo' to compare the collections. By default, the filter will work with exact distances between the geometries. If your analysis does not require a very precise tolerance of spatial uncertainty, specifying a small non-zero maxError distance value will help speed up the spatial operations. A larger tolerance also helps when testing or debugging code so you can get the result quickly instead of waiting longer for a more precise output. +```js var joinFilter = ee.Filter.withinDistance({ distance: 1000, leftField: '.geo', rightField: '.geo', maxError: 10 }); +``` We will use a simple join as we just want features from the first (primary) collection that match the features from the other (secondary) collection. +```js var closeBlocks = ee.Join.simple().apply({ primary: sfBlocks, secondary: interstateRoads, condition: joinFilter }); +``` We can visualize the results in a different color and verify that the join worked as expected (Fig. F5.3.6). +```js var closeBlocksDrawn = closeBlocks.draw({ color: 'orange', strokeWidth: 1 }) .clip(geometry); Map.addLayer(closeBlocksDrawn, {}, 'Blocks within 1km'); +``` ![Fig. F5.3.6 Selected blocks within 1 km of an interstate highway](F5/image40.png) @@ -1982,23 +1878,30 @@ Map.addLayer(sfTreesStyled, {}, 'SF Trees'); To find the tree points in each neighborhood polygon, we will use an ee.Filter.intersects filter. +```js var intersectFilter = ee.Filter.intersects({ leftField: '.geo', rightField: '.geo', maxError: 10 }); +``` We need a join that can give us a list of all tree features that intersect each neighborhood polygon, so we need to use a saving join. A saving join will find all the features from the secondary collection that match the filter and store them in a property in the primary collection. Once you apply this join, you will get a version of the primary collection with an additional property that has the matching features from the secondary collection. Here we use the ee.Join.saveAll join, since we want to store all matching features. We specify the matchesKey property that will be added to each feature with the results. +```js var saveAllJoin = ee.Join.saveAll({ matchesKey: 'trees', }); +``` Let’s apply the join and print the first feature of the resulting collection to verify (Fig. F5.3.8). +```js var joined = saveAllJoin .apply(sfNeighborhoods, sfTrees, intersectFilter); print(joined.first()); +``` + ![Fig. F5.3.8 Result of the save-all join](F5/image1.png) diff --git a/F6.qmd b/F6.qmd deleted file mode 100644 index 2136c87..0000000 --- a/F6.qmd +++ /dev/null @@ -1,2220 +0,0 @@ -## Advanced Topics - -Although you now know the most basic fundamentals of Earth Engine, there is still much more that can be done. The Part presents some advanced topics that can help expand your skill set for doing larger and more complex projects. These include tools for sharing code among users, scaling up with efficient project design, creating apps for non-expert users, and combining R with other information processing platforms. - -## Advanced Raster Visualization - - -:::{.callout-tip} -## Chapter Information - -#### Author {.unlisted .unnumbered} - - - -Gennadii Donchyts, Fedor Baart - - - -#### Overview {.unlisted .unnumbered} - - -This chapter should help users of Earth Engine to better understand raster data by applying visualization algorithms such as hillshading, hill shadows, and custom colormaps. We will also learn how image collection datasets can be explored by animating them as well as by annotating with text labels, using, for example, attributes of images or values queried from images. - -#### Learning Outcomes {.unlisted .unnumbered} - - -* Understanding why perceptually uniform colormaps are better to present data and using them efficiently for raster visualization. -* Using palettes with images before and after remapping values. -* Adding text annotations when visualizing images or features. -* Animating image collections in multiple ways (animated GIFs, exporting video clips, interactive animations with UI controls). -* Adding hillshading and shadows to help visualize raster datasets. - -#### Assumes you know how to:{.unlisted .unnumbered} - - -* Import images and image collections, filter, and visualize (Part F1). -* Write a function and map it over an ImageCollection (Chap. F4.0). -* Inspect an Image and an ImageCollection, as well as their properties (Chap. F4.1). - -::: -### Introduction {.unlisted .unnumbered} - - -Visualization is the step to transform data into a visual representation. You make a visualization as soon as you add your first layer to your map in Google Earth Engine. Sometimes you just want to have a first look at a dataset during the exploration phase. But as you move towards the dissemination phase, where you want to spread your results, it is good to think about a more structured approach to visualization. A typical workflow for creating visualization consists of the following steps: - -* Defining the story (what is the message?) -* Finding inspiration (for example by making a moodboard) -* Choosing a canvas/medium (here, this is the Earth Engine map canvas) -* Choosing datasets (co-visualized or combined using derived indicators) -* Data preparation (interpolating in time and space, filtering/mapping/reducing) -* Converting data into visual elements (shape and color) -* Adding annotations and interactivity (labels, scales, legend, zoom, time slider) - -A good standard work on all the choices that one can make while creating a visualization is provided by the Grammar of Graphics (GoG) by Wilkinson (1999). It was the inspiration behind many modern visualization libraries (ggplot, vega). The main concept is that you can subdivide your visualization into several aspects. - -In this chapter, we will cover several aspects mentioned in the Grammar of Graphics to convert (raster) data into visual elements. The accurate representation of data is essential in science communication. However, color maps that visually distort data through uneven color gradients or are unreadable to those with color-vision deficiency remain prevalent in science (Crameri, 2020). You will also learn how to add annotation text and symbology, while improving your visualizations by mixing images with hillshading as you explore some of the amazing datasets that have been collected in recent years in Earth Engine. - - -### Palettes - -In this section we will explore examples of colormaps to visualize raster data. Colormaps translate values to colors for display on a map. This requires a set of colors (referred to as a “palette” in Earth Engine) and a range of values to map (specified by the min and max values in the visualization parameters). - -There are multiple types of colormaps, each used for a different purpose. These include the following: - -Sequential: These are probably the most commonly used colormaps, and are useful for ordinal, interval, and ratio data. Also referred to as a linear colormap, a sequential colormap looks like the viridis colormap (Fig. F6.0.1) from matplotlib. It is popular because it is a perceptual uniform colormap, where an equal interval in values is mapped to an equal interval in the perceptual colorspace. If you have a ratio variable where zero means nothing, you can use a sequential colormap starting at white, transparent, or, when you have a black background, at black—for example, the turku colormap from Crameri (Fig. F6.0.1). You can use this for variables like population count or gross domestic product. - -Diverging: This type of colormap is used for visualizing data where you have positive and negative values and where zero has a meaning. Later in this tutorial, we will use the balance colormap from the cmocean package (Fig. F6.0.1) to show temperature change. - -Circular: Some variables are periodic, returning to the same value after a period of time. For example, the season, angle, and time of day are typically represented as circular variables. For variables like this, a circular colormap is designed to represent the first and last values with the same color. An example is the circular cet-c2 colormap (Fig. F6.0.1) from the colorcet package. - -Semantic: Some colormaps do not map to arbitrary colors but choose colors that provide meaning. We refer to these as semantic colormaps. Later in this tutorial, we will use the ice colormap (Fig. F6.0.1) from the cmocean package for our ice example. - -![Fig. F6.0.1 Examples of colormaps from a variety of packages: viridis from matplotlib, turku from Crameri, balance from cmocean, cet-c2 from colorcet and ice from cmocean](F6/image40.png) - - -Popular sources of colormaps include: - -* cmocean (semantic perceptual uniform colormaps for geophysical applications) -* colorcet (set of perceptual colormaps with varying colors and saturation) -* cpt-city (comprehensive overview of colormaps, -* colorbrewer (colormaps with variety of colors) -* Crameri (stylish colormaps for dark and light themes) - -Our first example in this section applies a diverging colormap to temperature. - -```js -// Load the ERA5 reanalysis monthly means. -var era5 = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY'); - -// Load the palettes package. -var palettes = require('users/gena/packages:palettes'); - -// Select temperature near ground. -era5 = era5.select('temperature_2m'); - -``` -Now we can visualize the data. Here we have a temperature difference. That means that zero has a special meaning. By using a divergent colormap we can give zero the color white, which denotes that there is no significant difference. Here we will use the colormap Balance from the cmocean package. The color red is associated with warmth, and the color blue is associated with cold. We will choose the minimum and maximum values for the palette to be symmetric around zero (-2, 2) so that white appears in the correct place. For comparison we also visualize the data with a simple ['blue', 'white', 'red'] palette. As you can see (Fig. F6.0.2), the Balance colormap has a more elegant and professional feel to it, because it uses a perceptual uniform palette and both saturation and value. - -```js -// Choose a diverging colormap for anomalies. -var balancePalette = palettes.cmocean.Balance[7]; -var threeColorPalette = ['blue', 'white', 'red']; - -// Show the palette in the Inspector window. -palettes.showPalette('temperature anomaly', balancePalette); -palettes.showPalette('temperature anomaly', threeColorPalette); - -// Select 2 time windows of 10 years. -var era5_1980 = era5.filterDate('1981-01-01', '1991-01-01').mean(); -var era5_2010 = era5.filterDate('2011-01-01', '2020-01-01').mean(); - -// Compute the temperature change. -var era5_diff = era5_2010.subtract(era5_1980); - -// Show it on the map. -Map.addLayer(era5_diff, { - palette: threeColorPalette, - min: -2, - max: 2}, 'Blue White Red palette'); - -Map.addLayer(era5_diff, { - palette: balancePalette, - min: -2, - max: 2}, 'Balance palette'); - -``` -![Fig. F6.0.2 Temperature difference of ERA5 (2011–2020, 1981–1990) using the balance colormap from cmocean (right) versus a basic blue-white-red colormap (left)](F6/image66.png)![Fig. F6.0.2 Temperature difference of ERA5 (2011–2020, 1981–1990) using the balance colormap from cmocean (right) versus a basic blue-white-red colormap (left)](F6/image53.png) - - -:::{.callout-note} -Code Checkpoint F60a. The book’s repository contains a script that shows what your code should look like at this point. -::: -Our second example in this section focuses on visualizing a region of the Antarctic, the Thwaites Glacier. This is one of the fast-flowing glaciers that causes concern because it loses so much mass that it causes the sea level to rise. If we want to visualize this region, we have a challenge. The Antarctic region is in the dark for four to five months each winter. That means that we can’t use optical images to see the ice flowing into the sea. We therefore will use radar images. Here we will use a semantic colormap to denote the meaning of the radar images. - -Let’s start by importing the dataset of radar images. We will use the images from the Sentinel-1 constellation of the Copernicus program. This satellite uses a C-band synthetic-aperture radar and has near-polar coverage. The radar senses images using a polarity for the sender and receiver. The collection has images of four different possible combinations of sender/receiver polarity pairs. The image that we’ll use has a band of the Horizontal/Horizontal polarity (HH). - -```js -// An image of the Thwaites glacier. -var imageId ='COPERNICUS/S1_GRD/S1B_EW_GRDM_1SSH_20211216T041925_20211216T042029_030045_03965B_AF0A'; - -// Look it up and select the HH band. -var img = ee.Image(imageId).select('HH'); - -``` -For the next step, we will use the palette library. We will stylize the radar images to look like optical images, so that viewers can contrast ice and sea ice from water (Lhermitte, 2020). We will use the Ice colormap from the cmocean package (Thyng, 2016). - -```js -// Use the palette library. -var palettes = require('users/gena/packages:palettes'); - -// Access the ice palette. -var icePalette = palettes.cmocean.Ice[7]; - -// Show it in the console. -palettes.showPalette('Ice', icePalette); - -// Use it to visualize the radar data. -Map.addLayer(img, { - palette: icePalette, - min: -15, - max: 1}, 'Sentinel-1 radar'); - -// Zoom to the grounding line of the Thwaites Glacier. -Map.centerObject(ee.Geometry.Point([-105.45882094907664, - 74.90419580705336]), 8); - -``` -If you zoom in (F6.0.3) you can see how long cracks have recently appeared near the pinning point (a peak in the bathymetry that functions as a buttress, see Wild, 2022) of the glacier. - -![Fig. F6.0.3. Ice observed in Antarctica by the Sentinel-1 satellite. The image is rendered using the ice color palette stretched to backscatter amplitude values [-15; 1].](F6/image13.png) - - -:::{.callout-note} -Code Checkpoint F60b. The book’s repository contains a script that shows what your code should look like at this point. -::: -### Remapping and Palettes - -Classified rasters in Earth Engine have metadata attached that can help with analysis and visualization. This includes lists of the names, values, and colors associated with class. These are used as the default color palette for drawing a classification, as seen next. The USGS National Land Cover Database (NLCD) is one such example. Let’s access the NLCD dataset, name it nlcd, and view it (Fig. F6.0.4) with its built-in palette. - -```js -// Advanced remapping using NLCD. -// Import NLCD. -var nlcd = ee.ImageCollection('USGS/NLCD_RELEASES/2016_REL'); - -// Use Filter to select the 2016 dataset. -var nlcd2016 = nlcd.filter(ee.Filter.eq('system:index', '2016')) - .first(); - -// Select the land cover band. -var landcover = nlcd2016.select('landcover'); - -// Map the NLCD land cover. -Map.addLayer(landcover, null, 'NLCD Landcover'); - -``` -![Fig. F6.0.4 The NLCD visualized with default colors for each class](F6/image54.png) - - -But suppose you want to change the display palette. For example, you might want to have multiple classes displayed using the same color, or use different colors for some classes. Let’s try having all three urban classes display as dark red ('ab0000'). - -```js -// Now suppose we want to change the color palette. -var newPalette = ['466b9f', 'd1def8', 'dec5c5', 'ab0000', 'ab0000', 'ab0000', 'b3ac9f', '68ab5f', '1c5f2c', 'b5c58f', 'af963c', 'ccb879', 'dfdfc2', 'd1d182', 'a3cc51', '82ba9e', 'dcd939', 'ab6c28', 'b8d9eb', '6c9fb8' -]; - -// Try mapping with the new color palette. -Map.addLayer(landcover, { - palette: newPalette -}, 'NLCD New Palette'); - -``` -However, if you map this, you will see an unexpected result (Fig. F6.0.5). - -![Fig. F6.0.5 Applying a new palette to a multi-class layer has some unexpected results](F6/image64.png) - - -This is because the numeric codes for the different classes are not sequential. Thus, Earth Engine stretches the given palette across the whole range of values and produces an unexpected color palette. To fix this issue, we will create a new index for the class values so that they are sequential. - -```js -// Extract the class values and save them as a list. -var values = ee.List(landcover.get('landcover_class_values')); - -// Print the class values to console. -print('raw class values', values); - -// Determine the maximum index value -var maxIndex = values.size().subtract(1); - -// Create a new index for the remap -var indexes = ee.List.sequence(0, maxIndex); - -// Print the updated class values to console. -print('updated class values', indexes); - -// Remap NLCD and display it in the map. -var colorized = landcover.remap(values, indexes) - .visualize({ - min: 0, - max: maxIndex, - palette: newPalette - }); -Map.addLayer(colorized, {}, 'NLCD Remapped Colors'); - -``` -Using this remapping approach, we can properly visualize the new color palette (Fig. F6.0.6). - -![Fig. F6.0.6 Expected results of the new color palette. All urban areas are now correctly showing as dark red and the other land cover types remain their original color.](F6/image57.png) - - -:::{.callout-note} -Code Checkpoint F60c. The book’s repository contains a script that shows what your code should look like at this point. -::: -### Annotations - -Annotations are the way to visualize data on maps to provide additional information about raster values or any other data relevant to the context. In this case, this additional information is usually shown as geometries, text labels, diagrams, or other visual elements. Some annotations in Earth Engine can be added by making use of the ui portion of the Earth Engine API, resulting in graphical user interface elements such as labels or charts added on top of the map. However, it is frequently useful to render annotations as a part of images, such as by visualizing various image properties or to highlight specific areas. - -In many cases, these annotations can be mixed with output images generated outside of Earth Engine, for example, by post-processing exported images using Python libraries or by annotating using GIS applications such as QGIS or ArcGIS. However, annotations could also be also very useful to highlight and/or label specific areas directly within the Code Editor. Earth Engine provides a sufficiently rich API to turn vector features and geometries into raster images which can serve as annotations. We recommend checking the ee.FeatureCollection.style function in the Earth Engine documentation to learn how geometries can be rendered. - -For textual annotation, we will make use of an external package 'users/gena/packages:text' that provides a way to render strings into raster images directly using the Earth Engine raster API. It is beyond the scope of the current tutorials to explain the implementation of this package, but internally this package makes use of bitmap fonts which are ingested into Earth Engine as raster assets and are used to turn every character of a provided string into image glyphs, which are then translated to desired coordinates. - -The API of the text package includes the following mandatory and optional arguments: - -/** -* Draws a string as a raster image at a given point. -* -* @param {string} str - string to draw -* @param {ee.Geometry} point - location the the string will be drawn -* @param {{string, Object}} options - optional properties used to style text -* -* The options dictionary may include one or more of the following: -* fontSize - 16|18|24|32 - the size of the font (default: 16) -* fontType - Arial|Consolas - the type of the font (default: Arial) -* alignX - left|center|right (default: left) -* alignY - top|center|bottom (default: top) -* textColor - text color string (default: ffffff - white) -* textOpacity - 0-1, opacity of the text (default: 0.9) -* textWidth - width of the text (default: 1) -* outlineColor - text outline color string (default: 000000 - black) -* outlineOpacity - 0-1, opacity of the text outline (default: 0.4) -* outlineWidth - width of the text outlines (default: 0) -*/ - -To demonstrate how to use this API, let’s render a simple 'Hello World!' text string placed at the map center using default text parameters. The code for this will be: - -```js -// Include the text package. -var text = require('users/gena/packages:text'); - -// Configure map (change center and map type). -Map.setCenter(0, 0, 10); -Map.setOptions('HYBRID'); - -// Draw text string and add to map. -var pt = Map.getCenter(); -var scale = Map.getScale(); -var image = text.draw('Hello World!', pt, scale); -Map.addLayer(image); - -``` -Running the above script will generate a new image containing the 'Hello World!' string placed in the map center. Notice that before calling the text.draw() function we configure the map to be centered at specific coordinates (0,0) and zoom level 10 because map parameters such as center and scale are passed as arguments to that text.draw() function. This ensures that the resulting image containing string characters is scaled properly. - -When exporting images containing rendered text strings, it is important to use proper scale to avoid distorted text strings that are difficult to read, depending on the selected font size, as shown in Fig. 6.0.7. - -:::{.callout-note} -Code Checkpoint F60d. The book’s repository contains a script that shows what your code should look like at this point. -::: -![Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()*1; (left), 2x: var scale = Map.getScale()*2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)](F6/image39.png)![Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()*1; (left), 2x: var scale = Map.getScale()*2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)](F6/image74.png)![Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()*1; (left), 2x: var scale = Map.getScale()*2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)](F6/image44.png) - - -These artifacts can be avoided to some extent by specifying a larger font size (e.g., 32). However, it is better to render text at the native 1:1 scale to achieve best results. The same applies to the text color and outline: They may need to be adjusted to achieve the best result. Usually, text needs to be rendered using colors that have opposite brightness and colors when compared to the surrounding background. Notice that in the above example, the map was configured to have a dark background ('HYBRID') to ensure that the white text (default color) would be visible. Multiple parameters listed in the above API documentation can be used to adjust text rendering. For example, let’s switch font size, font type, text, and outline parameters to render the same string, as below. Replace the existing one-line text.draw call in your script with the following code, and then run it again to see the difference (Fig. F6.0.8): - -var image = text.draw('Hello World!', pt, scale, { - fontSize: 32, - fontType: 'Consolas', - textColor: 'black', - outlineColor: 'white', - outlineWidth: 1, - outlineOpacity: 0.8 -}); - -```js -// Add the text image to the map. -Map.addLayer(image); - -``` -:::{.callout-note} -Code Checkpoint F60e. The book’s repository contains a script that shows what your code should look like at this point. -::: -![Fig. 6.0.8 Rendering text with adjusted parameters (font type: Consolas, fontSize: 32, textColor: 'black', outlineWidth: 1, outlineColor: 'white', outlineOpacity: 0.8)](F6/image33.png) - - -Of course, non-optional parameters such as pt and scale, as well as the text string, do not have to be hard-coded in the script; instead, they can be acquired by the code using, for example, properties coming from a FeatureCollection. Let's demonstrate this by showing the cloudiness of Landsat 8 images as text labels rendered in the center of every image. In addition to annotating every image with a cloudiness text string, we will also draw yellow outlines to indicate image boundaries. For convenience, we can also define the code to annotate an image as a function. We will then map that function (as described in Chap. F4.0) over the filtered ImageCollection. The code is as follows: - -var text = require('users/gena/packages:text'); - -var geometry = ee.Geometry.Polygon( - [ - [ - [-109.248, 43.3913], - [-109.248, 33.2689], - [-86.5283, 33.2689], - [-86.5283, 43.3913] - ] - ], null, false); - -Map.centerObject(geometry, 6); - -function annotate(image) { // Annotates an image by adding outline border and cloudiness // Cloudiness is shown as a text string rendered at the image center. // Add an edge around the image. var edge = ee.FeatureCollection([image]) - .style({ - color: 'cccc00cc', - fillColor: '00000000' }); // Draw cloudiness as text. var props = { - textColor: '0000aa', - outlineColor: 'ffffff', - outlineWidth: 2, - outlineOpacity: 0.6, - fontSize: 24, - fontType: 'Consolas' }; var center = image.geometry().centroid(1); var str = ee.Number(image.get('CLOUD_COVER')).format('%.2f'); var scale = Map.getScale(); var textCloudiness = text.draw(str, center, scale, props); // Shift left 25 pixels. textCloudiness = textCloudiness - .translate(-scale * 25, 0, 'meters', 'EPSG:3857'); // Merge results. return ee.ImageCollection([edge, textCloudiness]).mosaic(); -} - -```js -// Select images. -var images = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT_TOA') - .select([5, 4, 2]) - .filterBounds(geometry) - .filterDate('2018-01-01', '2018-01-7'); - -// dim background. -Map.addLayer(ee.Image(1), { - palette: ['black'] -}, 'black', true, 0.5); - -// Show images. -Map.addLayer(images, { - min: 0.05, - max: 1, - gamma: 1.4}, 'images'); - -// Show annotations. -var labels = images.map(annotate); -var labelsLayer = ui.Map.Layer(labels, {}, 'annotations'); -Map.layers().add(labelsLayer); - -``` -The result of defining and mapping this function over the filtered set of images is shown in Fig. F6.0.9. Notice that by adding an outline around the text, we can ensure the text is visible for both dark and light images. Earth Engine requires casting properties to their corresponding value type, which is why we’ve used ee.Number (as described in Chap. F1.0) before generating a formatted string. Also, we have shifted the resulting text image 25 pixels to the left. This was necessary to ensure that the text is positioned properly. In more complex text rendering applications, users may be required to compute the text position in a different way using ee.Geometry calls from the Earth Engine API: for example, by positioning text labels somewhere near the corners. - -![Fig. F6.0.9 Annotating Landsat 8 images with image boundaries, border, and text strings indicating cloudiness](F6/image3.png) - - -Because we render text labels using the Earth Engine raster API, they are not automatically scaled depending on map zoom size. This may cause unwanted artifacts; To avoid that, the text labels image needs to be updated every time the map zoom changes. To implement this in a script, we can make use of the Map API—in particular, the Map.onChangeZoom event handler. The following code snippet shows how the image containing text annotations can be re-rendered every time the map zoom changes. Add it to the end of your script. - -```js -// re-render (rescale) annotations when map zoom changes. -Map.onChangeZoom(function(zoom) { - labelsLayer.setEeObject(images.map(annotate)); -}); - -``` -:::{.callout-note} -Code Checkpoint F60f. The book’s repository contains a script that shows what your code should look like at this point. -::: -Try commenting that event handler and observe how annotation rendering changes when you zoom in or zoom out. - -### Animations - -Visualizing raster images as animations is a useful technique to explore changes in time-dependent datasets, but also, to render short animations to communicate how changing various parameters affects the resulting image—for example, varying thresholds of spectral indices resulting in different binary maps or the changing geometry of vector features. - -Animations are very useful when exploring satellite imagery, as they allow viewers to quickly comprehend dynamics of changes of earth surface or atmospheric properties. Animations can also help to decide what steps should be taken next to designing a robust algorithm to extract useful information from satellite image time series. Earth Engine provides two standard ways to generate animations: as animated GIFs, and as AVI video clips. Animation can also be rendered from a sequence of images exported from Earth Engine, using numerous tools such as ffmpeg or moviepy. However, in many cases it is useful to have a way to quickly explore image collections as animation without requiring extra steps. - -In this section, we will generate animations in three different ways: - -1. Generate animated GIF -2. Export video as an AVI file to Google Drive -3. Animate image collection interactively using UI controls and map layers - -We will use an image collection showing sea ice as an input dataset to generate animations with visualization parameters from earlier. However, instead of querying a single Sentinel-1 image, let’s generate a filtered image collection with all images intersecting with our area of interest. After importing some packages and palettes and defining a point and rectangle, we’ll build the image collection. Here we will use point geometry to define the location where the image date label will be rendered and the rectangle geometry to indicate the area of interest for the animation. To do this we will build the following logic in a new script. Open a new script and paste the following code into it: - -```js -// Include packages. -var palettes = require('users/gena/packages:palettes'); -var text = require('users/gena/packages:text'); - -var point = /* color: #98ff00 */ ee.Geometry.Point([- 106.15944300895228, -74.58262940096245 -]); - -var rect = /* color: #d63000 */ ee.Geometry.Polygon( - [ - [ - [-106.19789515738981, -74.56509549360152], - [-106.19789515738981, -74.78071448733921], - [-104.98115931754606, -74.78071448733921], - [-104.98115931754606, -74.56509549360152] - ] - ], null, false); - -// Lookup the ice palette. -var palette = palettes.cmocean.Ice[7]; - -// Show it in the console. -palettes.showPalette('Ice', palette); - -// Center map on geometry. -Map.centerObject(point, 9); - -// Select S1 images for the Thwaites glacier. -var images = ee.ImageCollection('COPERNICUS/S1_GRD') - .filterBounds(rect) - .filterDate('2021-01-01', '2021-03-01') - .select('HH') // Make sure we include only images which fully contain the region geometry. .filter(ee.Filter.isContained({ - leftValue: rect, - rightField: '.geo' })) - .sort('system:time_start'); - -// Print number of images. -print(images.size()); - -``` -As you see from the last last lines of the above code, it is frequently useful to print the number of images in an image collection: an example of what’s often known as a “sanity check.” - -Here we have used two custom geometries to configure animations: the green pin named point, used to filter image collection and to position text labels drawn on top of the image, and the blue rectangle rect, used to define a bounding box for the exported animations. To make sure that the point and rectangle geometries are shown under the Geometry Imports in the Code Editor, you need to click on these variables in the code and then select the Convert link. - -Notice that in addition to the bounds and date filter, we have also used a less known isContained filter to ensure that we get only images that fully cover our region. To better understand this filter, you could try commenting out the filter and compare the differences, observing images with empty (masked) pixels in the resulting image collection. - -:::{.callout-note} -Code Checkpoint F60g. The book’s repository contains a script that shows what your code should look like at this point. -::: -Next, to simplify the animation API calls, we will generate a composite RGB image collection out of satellite images and draw the image’s acquisition date as a label on every image, positioned within our region geometry. - -```js -// Render images. -var vis = { - palette: palette, - min: -15, - max: 1 -}; - -var scale = Map.getScale(); -var textProperties = { - outlineColor: '000000', - outlineWidth: 3, - outlineOpacity: 0.6 -}; - -var imagesRgb = images.map(function(i) { // Use the date as the label. var label = i.date().format('YYYY-MM-dd'); var labelImage = text.draw(label, point, scale, - textProperties); return i.visualize(vis) - .blend(labelImage) // Blend label image on top. .set({ - label: label - }); // Keep the text property. -}); -Map.addLayer(imagesRgb.first()); -Map.addLayer(rect, {color:'blue'}, 'rect', 1, 0.5); - -``` -In addition to printing the size of the ImageCollection, we also often begin by adding a single image to the map from a mapped collection to see that everything works as expected—another example of a sanity check. The resulting map layer will look like F6.0.10. - -![Fig. F6.0.10 The results of adding the first layer from the RGB composite image collection showing Sentinel-1 images with a label blended on top at a specified location. The blue geometry is used to define the bounds for the animation to be exported.](F6/image6.png) - - -:::{.callout-note} -Code Checkpoint F60h. The book’s repository contains a script that shows what your code should look like at this point. -::: -Animation 1: Animated GIF with ui.Thumbnail - -The quickest way to generate an animation in Earth Engine is to use the animated GIF API and either print it to the Console or print the URL to download the generated GIF. The following code snippet will result in an animated GIF as well as the URL to the animated GIF printed to Console. This is as shown in Fig. F6.0.11: - -```js -// Define GIF visualization parameters. -var gifParams = { - region: rect, - dimensions: 600, - crs: 'EPSG:3857', - framesPerSecond: 10 -}; - -// Print the GIF URL to the console. -print(imagesRgb.getVideoThumbURL(gifParams)); - -// Render the GIF animation in the console. -print(ui.Thumbnail(imagesRgb, gifParams)); - -``` -Earth Engine provides multiple options to specify the size of the resulting video. In this example we specify 600 as the size of the maximum dimension. We also specify the number of frames per second for the resulting animated GIF as well as the target projected coordinate system to be used (EPSG:3857 here, which is the projection used in web maps such as Google Maps and the Code Editor background). - -![Fig. F6.0.11 Console output after running the animated GIF code snippet, showing the GIF URL and an animation shown directly in the Console](F6/image56.png) - - -Animation 2: Exporting an Animation with Export.video.toDrive - -Animated GIFs can be useful to generate animations quickly. However, they have several limitations. In particular, they are limited to 256 colors, become large for larger animations, and most web players do not provide play controls when playing animated GIFs. To overcome these limitations, Earth Engine provides export of animations as video files in MP4 format. Let’s use the same RGB image collection we have used for the animated GIF to generate a short video. We can ask Earth Engine to export the video to the Google Drive using the following code snippet: - -Export.video.toDrive({ - collection: imagesRgb, - description: 'ice-animation', - fileNamePrefix: 'ice-animation', - framesPerSecond: 10, - dimensions: 600, - region: rect, - crs: 'EPSG:3857' -}); - -Here, many arguments to the Export.video.toDrive function resemble the ones we’ve used in the ee.Image.getVideoThumbURL code above. Additional arguments include description and fileNamePrefix, which are required to configure the name of the task and the target file of the video file to be saved to Google Drive. Running the above code will result in a new task created under the Tasks tab in the Code Editor. Starting the export video task (F6.0.12) will result in a video file saved in the Google Drive once completed. - -![Fig. F6.0.12 A new export video tasks in the Tasks panel of the Code Editor](F6/image9.png) - - -Animation 3: The Custom Animation Package - -For the last animation example, we will use the custom package 'users/gena/packages:animation', built using the Earth Engine User Interface API. The main difference between this package and the above examples is that it generates an interactive animation by adding Map layers individually to the layer set, and providing UI controls that allow users to play animations or interactively switch between frames. The animate function in that package generates an interactive animation of an ImageCollection, as described below. This function has a number of optional arguments allowing you to configure, for example, the number of frames to be animated, the number of frames to be preloaded, or a few others. The optional parameters to control the function are the following: - -* maxFrames: maximum number of frames to show (default: 30) -* vis: visualization parameters for every frame (default: {}) -* Label: text property of images to show in the animation controls (default: undefined) -* width: width of the animation panel (default: '600px') -* compact: show only play control and frame slider (default: false) -* position: position of the animation panel (default: 'top-center') -* timeStep: time step (ms) used when playing animation (default: 100) -* preloadCount: number of frames (map layers) to preload (default: all) - -Let’s call this function to add interactive animation controls to the current Map: - -```js -// include the animation package -var animation = require('users/gena/packages:animation'); - -// show animation controls -animation.animate(imagesRgb, { - label: 'label', - maxFrames: 50 -}); - -``` -Before using the interactive animation API, we need to include the corresponding package using require. Here we provide our pre-rendered image collection and two optional parameters (label and maxFrames). The first optional parameter label indicates that every image in our image collection has the 'label' text property. The animate function uses this property to name map layers as well as to visualize in the animation UI controls when switching between frames. This can be useful when inspecting image collections. The second optional parameter, maxFrames, indicates that the maximum number of animation frames that we would like to visualize is 50. To prevent the Code Editor from crashing, this parameter should not be too large: it is best to keep it below 100. For a much larger number of frames, it is better to use the Export video or animated GIF API. Running this code snippet will result in the animation control panel added to the map as shown in Fig. F6.0.13. - -It is important to note that the animation API uses asynchronous UI calls to make sure that the Code Editor does not hang when running the script. The drawback of this is that for complex image collections, a large amount of processing is required. Hence, it may take some time to process all images and to visualize the interactive animation panel. The same is true for map layer names: they are updated once the animation panel is visualized. Also, map layers used to visualize individual images in the provided image collection may require some time to be rendered. - -![Fig. F6.0.13 Interactive animation controls when using custom animation API](F6/image70.png) - - -The main advantage of the interactive animation API is that it provides a way to explore image collections at frame-by-frame basis, which can greatly improve our visual understanding of the changes captured in sets of images. - -:::{.callout-note} -Code Checkpoint F60i. The book’s repository contains a script that shows what your code should look like at this point. -::: -### Terrain Visualization - -This section introduces several raster visualization techniques useful to visualize terrain data such as: - -* Basic hillshading and parameters (light azimuth, elevation) -* Combining elevation data and colors using HSV transform (Wikipedia: HSL and HSV) -* Adding shadows - -One special type of raster data is data that represents height. Elevation data can include topography, bathymetry, but also other forms of height, such as sea surface height can be presented as a terrain. - -Height is often visualized using the concept of directional light with a technique called hillshading. Because height is such a common feature in our environment, we also have an expectancy of how height is visualized. If height is visualized using a simple grayscale colormap, it looks very unnatural (Fig. F6.0.14, top left). By using hillshading, data immediately looks more natural (Fig. F6.0.14, top middle). - -We can further improve the visualization by including shadows (Fig. F6.0.14, top right). A final step is to replace the simple grayscale colormap with a perceptual uniform topographic colormap and mix this with the hillshading and shadows (Fig. F6.0.14, bottom). This section explains how to apply these techniques. - -We’ll focus on elevation data stored in raster form. Elevation data is not always stored in raster formats. Other data formats include Triangulated Irregular Network (TIN), which allows storing information at varying resolutions and as 3D objects. This format allows one to have overlapping geometries, such as bridges with a road below it. In raster-based digital elevation models, in contrast, there can only be one height recorded for each pixel. - -Let’s start by loading data from a digital elevation model. This loads a topographic dataset from the Netherlands (Algemeen Hoogtebestand Nederland). It is a Digital Surface Model, based on airborne LIDAR measurements regridded to 0.5 m resolution. Enter the following code in a new script. - -var dem = ee.Image('AHN/AHN2_05M_RUW'); - -We can visualize this dataset using a sequential gradient colormap from black to white. This results in Fig. F6.0.14. One can infer which areas are lower and which are higher, but the visualization does not quite “feel” like a terrain. - -```js -// Change map style to HYBRID and center map on the Netherlands -Map.setOptions('HYBRID'); -Map.setCenter(4.4082, 52.1775, 18); - -// Visualize DEM using black-white color palette -var palette = ['black', 'white']; -var demRGB = dem.visualize({ - min: -5, - max: 5, - palette: palette -}); -Map.addLayer(demRGB, {},'DEM'); - -``` -An important step to visualize terrain is to add shadows created by a distant point source of light. This is referred to as hillshading or a shaded relief map. This type of map became popular in the 1940s through the work of Edward Imhoff, who also used grayscale colormaps (Imhoff, 2015). Here we’ll use the 'gena/packages:utils' library to combine the colormap image with the shadows. That Earth Engine package implements a hillshadeRGB function to simplify rendering of images enhanced with hillshading and shadow effects. One important argument this function takes is the light azimuth—an angle from the image plane upward to the light source (the Sun). This should always be set to the top left to avoid bistable perception artifacts, in which the DEM can be misperceived as inverted. - -var utils = require('users/gena/packages:utils'); - -var weight = 0.4; // Weight of Hillshade vs RGB (0 - flat, 1 - hillshaded). -var exaggeration = 5; // Vertical exaggeration. -var azimuth = 315; // Sun azimuth. -var zenith = 20; // Sun elevation. -var brightness = -0.05; // 0 - default. -var contrast = 0.05; // 0 - default. -var saturation = 0.8; // 1 - default. -var castShadows = false; - -var rgb = utils.hillshadeRGB( - demRGB, dem, weight, exaggeration, azimuth, zenith, - contrast, brightness, saturation, castShadows); - -Map.addLayer(rgb, {}, 'DEM (no shadows)'); - -Standard hillshading only determines per pixel if it will be directed to the light or not. One can also project shadows on the map. That is done using the ee.Algorithms.HillShadow algorithm. Here we’ll turn on castShadows in the hillshadeRGB function. This results in a more realistic map, as can be seen in Figure F6.0.14. - -var castShadows = true; - -var rgb = utils.hillshadeRGB( - demRGB, dem, weight, exaggeration, azimuth, zenith, - contrast, brightness, saturation, castShadows); - -Map.addLayer(rgb, {}, 'DEM (with shadows)'); - -The final step is to add a topographic colormap. To visualize topographic information, one often uses special topographic colormaps. Here we’ll use the oleron colormap from crameri. The colors get mixed with the shadows using the hillshadeRGB function. As you can see in Fig. F6.0.14, this gives a nice overview of the terrain. The area colored in blue is located below sea level. - -var palettes = require('users/gena/packages:palettes'); -var palette = palettes.crameri.oleron[50]; - -var demRGB = dem.visualize({ - min: -5, - max: 5, - palette: palette -}); - -var castShadows = true; - -var rgb = utils.hillshadeRGB( - demRGB, dem, weight, exaggeration, azimuth, zenith, - contrast, brightness, saturation, castShadows); - -Map.addLayer(rgb, {}, 'DEM colormap'); - -Steps to further improve a terrain visualization include using light sources from multiple directions. This allows the user to render terrain to appear more natural. In the real world light is often scattered by clouds and other reflections. - -One can also use lights to emphasize certain regions. To use even more advanced lighting techniques one can use a raytracing engine, such as the R rayshader library, as discussed earlier in this chapter. The raytracing engine in the Blender 3D program is also capable of producing stunning terrain visualizations using physical-based rendering, mist, environment lights, and camera effects such as depth of field. - -![](F6/image36.png)![](F6/image58.png)![](F6/image47.png) - -![](F6/image55.png) - -Figure F6.0.14 Hillshading with shadows - -Steps in visualizing a topographic dataset: - -1. Top left, topography with grayscale colormap -2. Top middle, topography with grayscale colormap and hillshading -3. Top right, topography with grayscale colormap, hillshading, and shadows -4. Bottom, topography with topographic colormap, hillshading, and shadows - -:::{.callout-note} -Code Checkpoint F60j. The book’s repository contains a script that shows what your code should look like at this point. -::: -### Conclusion {.unnumbered} - -In this chapter we have learned about several techniques that can greatly improve visualization and analysis of images and image collections. Using predefined palettes can help to better comprehend and communicate Earth observation data, and combining with other visualization techniques such as hillshading and annotations can help to better understand processes studied with Earth Engine. When working with image collections, it is often very helpful to analyze their properties through time by visualizing them as animations. Usually, this step helps to better understand dynamics of the changes that are stored in image collections and to develop a proper algorithm to study these changes. - -### References {.unnumbered} - -Burrough PA, McDonnell RA, Lloyd CD (2015) Principles of Geographical Information Systems. Oxford University Press - -Crameri F, Shephard GE, Heron PJ (2020) The misuse of colour in science communication. Nat Commun 11:1–10. https://doi.org/10.1038/s41467-020-19160-7 - -Imhof E (2015) Cartographic Relief Presentation. Walter de Gruyter GmbH & Co KG - -Lhermitte S, Sun S, Shuman C, et al (2020) Damage accelerates ice shelf instability and mass loss in Amundsen Sea Embayment. Proc Natl Acad Sci USA 117:24735–24741. https://doi.org/10.1073/pnas.1912890117 - -Thyng KM, Greene CA, Hetland RD, et al (2016) True colors of oceanography. Oceanography 29:9–13 - -Wikipedia (2022) Terrain cartography. https://en.wikipedia.org/wiki/Terrain_cartography#Shaded_relief. Accessed 1 Apr 2022 - -Wikipedia (2022) HSL and HSV. https://en.wikipedia.org/wiki/HSL_and_HSV. Accessed 1 Apr 2022 - -Wild CT, Alley KE, Muto A, et al (2022) Weakening of the pinning point buttressing Thwaites Glacier, West Antarctica. Cryosphere 16:397–417. https://doi.org/10.5194/tc-16-397-2022 - -Wilkinson L (2005) The Grammar of Graphics. Springer Verlag - - - -## Collaborating in Earth Engine with Scripts and Assets - - - - - -:::{.callout-tip} -## Chapter Information - -#### Author {.unlisted .unnumbered} - - - -Sabrina H. Szeto - - - -#### Overview {.unlisted .unnumbered} - - -Many users find themselves needing to collaborate with others in Earth Engine at some point. Students may need to work on a group project, people from different organizations might want to collaborate on research together, or people may want to share a script or an asset they created with others. This chapter will show you how to collaborate with others and share your work. - -#### Learning Outcomes {.unlisted .unnumbered} - - -* Understanding when it is important to share a script or asset. -* Understanding what roles and permission options are available. -* Sharing a script with others. -* Sharing an asset with others. -* Sharing an asset so it can be displayed in an app. -* Sharing a repository with others. -* Seeing who made changes to a script and what changes were made. -* Reverting to a previous version of a script. -* Using the require function to load modules. -* Creating a script to share as a module. - -#### Assumes you know how to:{.unlisted .unnumbered} - - -* Sign up for an Earth Engine account, open the Code Editor, and save your script (Chap. F1.0). - -::: -### Introduction {.unlisted .unnumbered} - - -Many people find themselves needing to share a script when they encounter a problem; they wish to share the script with someone else so they can ask a question. When this occurs, sharing a link to the script often suffices. The other person can then make comments or changes before sending a new link to the modified script. - -If you have included any assets from the Asset Manager in your script, you will also need to share these assets in order for your script to work for your colleague. The same goes for sharing assets to be displayed in an app. - -Another common situation involves collaborating with others on a project. They may have some scripts they have written that they want to reuse or modify for the new project. Alternatively, several people might want to work on the same script together. For this situation, sharing a repository would be the best way forward; team members will be able to see who made what changes to a script and even revert to a previous version. - -If you or your group members find yourselves repeatedly reusing certain functions for visualization or for part of your analysis, you could use the require module to call that function instead of having to copy and paste it into a new script each time. You could even make this function or module available to others to use via require. - - -Let’s get started. For this lab, you will need to work in small groups or pairs. - -### Using Get Link to Share a Script - -Copy and paste the following code into the Code Editor. - -print('The author of this script is MyName.'); - -Replace MyName with your name, then click on Save to save the script in your home repository. Next, click on the Get Link button and copy the link to this script onto your clipboard. Using your email program of choice, send this script to one of your group members. - -Now add the following code below the line of code that you pasted earlier. - -print('I just sent this script to GroupMemberName.'); - -Replace GroupMemberName with the name of the person you sent this script to, then save the script again. Next, click on the Get Link button and copy the link to this script onto your clipboard. Using your email program of choice, send this script to the same person. - -Question 1. You should also have received two emails from someone in your group who is also doing this exercise. Open the first and second links in your Code Editor by clicking on them. Is the content of both scripts the same? - -Answer: No, the scripts will be different, because Get Link sends a snapshot of the script at a particular point in time. Thus, even though the script was updated, the first link does not reflect that change. - -Question 2. What happens when you check the box for Hide code panel or Disable auto-run before sharing the script? - -Answer. Hide code panel will minimize the code panel so the person you send the script to will see the Map maximized. This is useful when you want to draw the person’s attention to the results rather than to the code. To expand the code panel, they have to click on the Show code button. Disable auto-run is helpful when you do not want the script to start running when the person you sent it to opens it. Perhaps your script takes very long to run or requires particular user inputs and you just want to share the code with the person. - -### Sharing Assets from Your Asset Manager - -When you clicked the Get Link button earlier, you may have noticed a note in the popup reading: “To give others access to assets in the code snapshot, you may need to share them.” If your script uses an asset that you have uploaded into your Asset Manager, you will need to share that asset as well. If not, an error message will appear when the person you shared the script with tries to run it. - -Before sharing an asset, think about whether you have permission to share it. Is this some data that is owned by you, or did you get it from somewhere else? Do you need permission to share this asset? Make sure you have the permission to share an asset before doing so. - -Now, let’s practice sharing assets. First, navigate to your Asset Manager by clicking on the Assets tab in the left panel. If you already have some assets uploaded, pick one that you have permission to share. If not, upload one to your Asset Manager. If you don’t have a shapefile or raster to upload, you can upload a small text file. Consult the Earth Engine documentation for how to do this; it will take only a few steps. - -Hover your cursor over that asset in your Asset Manager. The asset gets highlighted in gray and three buttons appear to the right of the asset. Click on the first button from the left (outlined in red in Fig. F6.1.1). This icon means “share.” - -![Fig. F6.1.1 Three assets in the Asset Manager](F6/image26.png) - - -After you click the share button, a Share Image popup will appear (Fig. F6.1.2). This popup contains information about the path of the asset and the email address of the owner. The owner of the asset can decide who can view and edit the asset. - -Click on the dropdown menu outlined in red in Fig. F6.1.2. You will see two options for permissions: Reader and Writer. A Reader can view the asset, while a Writer can both view and make changes to it. For example, a Writer could add a new image to an ImageCollection. A Writer can also add other people to view or edit the asset, and a Writer can delete the asset. When in doubt, give someone the Reader role rather than the Writer role. - -![Fig. F6.1.2 The Share Image popup window](F6/image10.png) - - -To share an asset with someone, you can type their email address into the Email or domain text field, choose Reader or Writer in the dropdown menu, and then click on Add Access. You can also share an asset with everyone with a certain email domain, which is useful if you want to share an asset with everyone in your organization, for instance. - -If you want to share reading access publicly, then check the box that says Anyone can read. Note that you still need to share the link to the asset in order for others to access it. The only exceptions to this are when you are using the asset in a script and sharing that script using the Get Link button or when you share the asset with an Earth Engine app. To do the latter, use the Select an app dropdown menu (outlined in orange in Fig. F6.1.2) and click Add App Access. - -Question 3. Share an asset with a group member and give them reader access. Send them the link to that asset. You will also receive a link from someone else in your group. Open that link. What can you do with that asset? What do you need to do to import it into a script? - -Answer: You can view details about the asset and import it for use in a script in the Code Editor. To import the asset, click on the blue Import button. - -Question 4. Share an asset with a group member and give them writer access. Send them the link to that asset. You will also receive a link from someone else in your group. Open that link. What can you do with that asset? Try sharing the asset with a different group member. - -Answer: You can view details about the asset and import it for use in a script in the Code Editor. You can also share the asset with others and delete the asset. - -### Working with Shared Repositories - -Now that you know how to share assets and scripts, let’s move on to sharing repositories. In this section, you will learn about different types of repositories and how to add a repository that someone else shared with you. You will also learn how to view previous versions of a script and how to revert back to an earlier version. - -Earlier, we learned how to share a script using the Get Link button. This link shares a code snapshot from a script. This snapshot does not reflect any changes made to the script after the time the link was shared. If you want to share a script that updates to reflect the most current version when it is opened, you need to share a repository with that script instead. - -If you look under the Scripts tab of the leftmost panel in the Code Editor, you will see that the first three categories are labeled Owner, Reader, and Writer. - -* Repositories categorized under Owner are created and owned by you. No one else has access to view or make changes to them until you share these repositories. -* Repositories categorized under Reader are repositories to which you have reader access. You can view the scripts but not make any changes to them. If you want to make any changes, you will need to save the script as a new file in a repository that you own. -* Repositories categorized under Writer are repositories to which you have writer access. This means you can view and make changes to the scripts. - -Let’s practice creating and sharing repositories. We will start by making a new repository. Click on the red New button located in the left panel. Select Repository from the dropdown menu. A New repository popup window will open (Fig. F6.1.3). - -![Fig. F6.1.3 The New repository popup window](F6/image25.png) - - -In the popup window’s text field, type a name for your new repository, such as “ForSharing1,” then click on the blue Create button. You will see the new repository appear under the Owner category in the Scripts tab (Fig. F6.1.4). - -Now, share this new repository with your group members: Hover your cursor over the repository you want to share. The repository gets highlighted in gray, and three buttons appear. Click on the Gear icon (outlined in red in Fig. F6.1.4). - -![Fig. F6.1.4 Three repositories under the Owner category](F6/image71.png) - - -A Share Repo popup window appears (Fig. F6.1.5) which is very similar to the Share Image popup window we saw in Fig. F6.1.2. The method for sharing a repository with a specific user or the general public is the same as for sharing assets. - -Type the email address of a group member in the Email or domain text field and give this person a writer role by selecting Writer in the dropdown menu, then click on Add Access. - -![Fig. F6.1.5. The Share Repo popup window](F6/image29.png) - - -Your group member should receive an email inviting them to edit the repository. Check your email inbox for the repository that your group member has shared with you. When you open that email, you will see content similar to what is shown in Fig. F6.1.6. - -![Fig. F6.1.6 The “Invitation to edit” email](F6/image50.png) - - -Now, click on the blue button that says Add [repository path] to your Earth Engine Code Editor. You will find the new repository added to the Writer category in your Scripts tab. The repository path will contain the username of your group member, such as users/username/sharing. - -Now, let’s add a script to the empty repository. Click on the red New button in the Scripts tab and select File from the dropdown menu. A Create file popup will appear, as shown in Fig. F6.1.7. Click on the gray arrow beside the default path to open a dropdown menu that will allow you to choose the path of the repository that your group member shared with you. Type a new File Name in the text field, such as “exercise,” then click on the blue OK button to create the file. - -![Fig. F6.1.7 The Create file popup window](F6/image69.png) - - -A new file should now appear in the shared repository in the Writer category. If you don’t see it, click on the Refresh icon, which is to the right of the red New button in the Scripts tab. - -Double-click on the new script in the shared repository to open it. Then, copy and paste the following code to your Code Editor. - -print('The owner of this repository is GroupMemberName.'); - -Replace GroupMemberName with the name of your group member, then click Save to save the script in the shared repository, which is under the Writer category. - -Now, navigate to the repository under Owner which you shared with your group member. Open the new script which they just created by double-clicking it. - -Add the following code below the line of code that you pasted earlier. - -print('This script is shared with MyName.'); - -Replace MyName with your name, then save the script. - -Next, we will compare changes made to the script. Click on the Versions icon (outlined in red in Fig. F6.1.8). - -![Fig. F6.1.8 Changes made and previous versions of the script](F6/image17.png) - - -A popup window will appear, titled Revision history, followed by the path of the script (Fig. F6.1.9). There are three columns of information below the title. - -* The left column contains the dates on which changes have been made. -* The middle column contains the usernames of the people who made changes. -* The right column contains information about what changes were made. - -The most recent version of the script is shown in the first row, while previous versions are listed in subsequent rows. (More advanced users may notice that this is actually a Git repository.) - -![Fig. F6.1.9 The Revision history popup window](F6/image19.png) - - -If you hover your cursor over a row, the row will be highlighted in gray and a button labeled Compare will appear. Clicking on this button allows you to compare differences between the current version of the script and a previous version in a Version comparison popup window (Fig. F6.1.10). - -![Fig. F6.1.10 The Version comparison popup window](F6/image30.png) - - -In the Version comparison popup, you will see text highlighted in two different colors. Text highlighted in red shows code that was present in the older version but is absent in the current version (the “latest commit”). Text highlighted in green shows code that is present in the current version but that was absent in the older version. Generally speaking, text highlighted in red has been removed in the current version and text highlighted in green has been added to the current version. Text that is not highlighted shows code that is present in both versions. - -Question 5. What text, if any, is highlighted in red when you click on Compare in your “exercise” script? - -Answer: No text is highlighted in red, because none was removed between the previous and current versions of the script. - -Question 6. What text, if any, is highlighted in green when you click on Compare in your “exercise” script? - -Answer: print('This script is shared with MyName.'); - -Question 7. What happens when you click on the blue Revert button? - -Answer: The script reverts to the previous version, in which the only line of code is - -print('The owner of this repository is GroupMemberName.'); - -### Using the Require Function to Load a Module - -In earlier chapters, you may have noticed that the require function allows you to reuse code that has already been written without having to copy and paste it into your current script. For example, you might have written a function for cloud masking that you would like to use in multiple scripts. Saving this function as a module enables you to share the code across your own scripts and with other people. Or you might discover a new module with capabilities you need written by other authors. This section will show you how to use the require function to create and share your own module or to load a module that someone else has shared. - -The module we will use is ee-palettes, which enables users to visualize raster data using common specialized color palettes (Donchyts et al. 2019). (If you would like to learn more about using these color palettes, the ee-palettes module is described and illustrated in detail in Chap. F6.0.) The first step is to go to this link to accept access to the repository as a reader: [https://code.earthengine.google.com/?accept_repo=users/gena/](https://www.google.com/url?q=https://code.earthengine.google.com/?accept_repo%3Dusers/gena/packages&sa=D&source=editors&ust=1671458841147867&usg=AOvVaw2lfbVvfKSe6Nym_B5h25Z7)[packages](https://www.google.com/url?q=https://code.earthengine.google.com/?accept_repo%3Dusers/gena/packages&sa=D&source=editors&ust=1671458841148247&usg=AOvVaw396ktWqHZ6LRi90IQjOwxZ) - -Now, if you navigate to your Reader directory in the Code Editor, you should see a new repository called 'users/gena/packages' listed. Look for a script called 'palettes' and click on it to load it in your Code Editor. - -If you scroll down, you will see that the script contains a nested series of dictionaries with lists of hexadecimal color specifications (as described in Chap. F2.1) that describe a color palette, as shown in the code block below. For example, the color palette named “Algae” stored in the cmocean variable consists of seven colors, ranging from dark green to light green (Fig. F6.1.11). - -exports.cmocean = { - Thermal: { 7: ['042333', '2c3395', '744992', 'b15f82', 'eb7958', 'fbb43d', 'e8fa5b' ] - }, - Haline: { 7: ['2a186c', '14439c', '206e8b', '3c9387', '5ab978', 'aad85c', 'fdef9a' ] - }, - Solar: { 7: ['331418', '682325', '973b1c', 'b66413', 'cb921a', 'dac62f', 'e1fd4b' ] - }, - Ice: { 7: ['040613', '292851', '3f4b96', '427bb7', '61a8c7', '9cd4da', 'eafdfd' ] - }, - Gray: { 7: ['000000', '232323', '4a4a49', '727171', '9b9a9a', 'cacac9', 'fffffd' ] - }, - Oxy: { 7: ['400505', '850a0b', '6f6f6e', '9b9a9a', 'cbcac9', 'ebf34b', 'ddaf19' ] - }, - Deep: { 7: ['fdfecc', 'a5dfa7', '5dbaa4', '488e9e', '3e6495', '3f396c', '281a2c' ] - }, - Dense: { 7: ['e6f1f1', 'a2cee2', '76a4e5', '7871d5', '7642a5', '621d62', '360e24' ] - }, - Algae: { 7: ['d7f9d0', 'a2d595', '64b463', '129450', '126e45', '1a482f', '122414' ] - }, - ... -} - -Notice that the variable is named exports.cmocean. Adding exports to the name of a function or variable makes it available to other scripts to use, as it gets added to a special global variable (Chang 2017). - -![Fig. F6.1.11 Some of the color palettes from the ee-palettes GitHub repository](F6/image52.png) - - -To see all the color palettes available in this module, go to [https://github.com/gee-community/ee-palettes](https://www.google.com/url?q=https://github.com/gee-community/ee-palettes&sa=D&source=editors&ust=1671458841155957&usg=AOvVaw30bltn2S4_BDlhyuKIvkZH). - -Now let’s try using the ee-palettes module. Look for a script in the same repository called 'palettes-test' and click on it to load it in your Code Editor. When you run the script, you will see digital elevation data from the National Aeronautics and Space Administration Shuttle Radar Topography Mission satellite visualized using two palettes, colorbrewer.Blues and cmocean.Algae. The map will have two layers that show the same data with different palettes. - -The script first imports the digital elevation model data in the Imports section of the Code Editor. - -var dem = ee.Image('USGS/SRTMGL1_003'); - -The script then loads the ee-palettes module by using the require function. The path to the module, 'users/gena/packages:palettes', is passed to the function. The require function is then stored in a variable named 'palettes', which will be used later to obtain the palettes for data visualization. - -var palettes = require('users/gena/packages:palettes'); - -As described by Donchyts et al. (2019), “Each palette is defined by a group and a name, which are separated by a period (JS object dot notation), and a color level. To retrieve a desired palette, use JS object notation to specify the group, name, and number of color levels.” We define the color palette Algae as palettes.cmocean.Algae[7] because it is part of the group cmocean and has 7 color levels. In the next code block, you can see that the palettes (i.e., lists of hex colors) have been defined for use by setting them as the value for the palette key in the visParams object supplied to the Map.addLayer function. - -```js -// colorbrewer -Map.addLayer(dem, { - min: 0, - max: 3000, - palette: palettes.colorbrewer.Blues[9] -}, 'colorbrewer Blues[9]'); - -// cmocean -Map.addLayer(dem, { - min: 0, - max: 3000, - palette: palettes.cmocean.Algae[7] -}, 'cmocean Algae[7]'); - -``` -Question 8. Try adding a third layer to the Map with a different color palette from ee-palettes. How easy was it to do? - -Now that you have loaded and used a module shared by someone else, you can try your hand at creating your own module and sharing it with someone else in your group. First, go to the shared repository that you created in Sect. 3, create a new script in that repository, and name it “cloudmasking.” - -Then, go to the Examples repository at the bottom of the Scripts tab and select a function from the Cloud Masking repository. Let’s use the Landsat8 Surface Reflectance cloud masking script as an example. In that script, you will see the code shown in the block below. Copy all of it into your empty script. - -```js -// This example demonstrates the use of the Landsat 8 Collection 2, Level 2 -// QA_PIXEL band (CFMask) to mask unwanted pixels. -function maskL8sr(image) { // Bit 0 - Fill // Bit 1 - Dilated Cloud // Bit 2 - Cirrus // Bit 3 - Cloud // Bit 4 - Cloud Shadow var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111', 2)).eq(0); var saturationMask = image.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select('SR_B.').multiply(0.0000275).add(- 0.2); var thermalBands = image.select('ST_B.*').multiply(0.00341802) - .add(149.0); // Replace the original bands with the scaled ones and apply the masks. return image.addBands(opticalBands, null, true) - .addBands(thermalBands, null, true) - .updateMask(qaMask) - .updateMask(saturationMask); -} - -// Map the function over one year of data. -var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') - .filterDate('2020-01-01', '2021-01-01') - .map(maskL8sr); - -var composite = collection.median(); - -// Display the results. -Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula -Map.addLayer(composite, { - bands: ['SR_B4', 'SR_B3', 'SR_B2'], - min: 0, - max: 0.3 -}); - -``` -Note that this code is well commented and has a header that describes what the script does. Don’t forget to comment your code and describe what you are doing each step of the way. This is a good practice for collaborative coding and for your own future reference. - -Imagine that you changed this maskL8sr function slightly for some reason and want to make it available to other users and scripts. To do that, you can turn the function into a module. Copy and modify the code from the example code into the new script you created called “cloudmasking.” (Hint: Store the function in a variable starting with exports. Be careful that you don’t accidentally use Export, which is used to export datasets.) - -Your script should be similar to the following code. - -exports.maskL8sr = function(image) { // Bit 0 - Fill // Bit 1 - Dilated Cloud // Bit 2 - Cirrus // Bit 3 - Cloud // Bit 4 - Cloud Shadow var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt( '11111', 2)).eq(0); var saturationMask = image.select('QA_RADSAT').eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select('SR_B.').multiply(0.0000275) - .add(-0.2); var thermalBands = image.select('ST_B.*').multiply(0.00341802) - .add(149.0); // Replace the original bands with the scaled ones and apply the masks. return image.addBands(opticalBands, null, true) - .addBands(thermalBands, null, true) - .updateMask(qaMask) - .updateMask(saturationMask); -} - -Next, you will create a test script that makes use of the cloud masking module you just made. Begin by creating a new script in your shared repository called “cloudmasking-test.” You can modify the last part of the example cloud masking script to use your module. - -```js -// Map the function over one year of data. -var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') - .filterDate('2020-01-01', '2021-01-01') - .map(maskL8sr); - -var composite = collection.median(); - -// Display the results. -Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula -Map.addLayer(composite, { - bands: ['SR_B4', 'SR_B3', 'SR_B2'], - min: 0, - max: 0.3 -}); - -``` -Question 9. How will you modify the cloud masking script to use your module? What does the script look like? - -Answer: Your code might look something like the code block below. - -```js -// Load the module -var myCloudFunctions = require( 'users/myusername/my-shared-repo:cloudmasking'); - -// Map the function over one year of data. -var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2') - .filterDate('2020-01-01', '2021-01-01') - .map(myCloudFunctions.maskL8sr); - -var composite = collection.median(); - -// Display the results. -Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula -Map.addLayer(composite, { - bands: ['SR_B4', 'SR_B3', 'SR_B2'], - min: 0, - max: 0.3 -}); - -``` -### Conclusion {.unnumbered} - -In this chapter, you learned how to collaborate with others in the Earth Engine Code Editor through sharing scripts, assets, and repositories. You learned about different roles and permissions available for sharing and when it is appropriate to use each. In addition, you are now able to see what changes have been made to a script and revert to a previous version. Lastly, you loaded and used a module that was shared with you and created your own module for sharing. You are now ready to start collaborating and developing scripts with others. - -### References {.unnumbered} - -Chang A (2017) Making it easier to reuse code with Earth Engine script modules. In: Google Earth and Earth Engine. https://medium.com/google-earth/making-it-easier-to-reuse-code-with-earth-engine-script-modules-2e93f49abb13. Accessed 24 Feb 2022 - -Donchyts G, Baart F, Braaten J (2019) ee-palettes. https://github.com/gee-community/ee-palettes. Accessed 24 Feb 2022 - - - -## Scaling Up in Earth Engine - - - - - -:::{.callout-tip} -## Chapter Information - -#### Author {.unlisted .unnumbered} - - - -Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick - - - -#### Overview {.unlisted .unnumbered} - - -Commonly, when Earth Engine users move from tutorials to developing their own processing scripts, they encounter the dreaded error messages, “computation timed out” or “user memory limit exceeded.” Computational resources are never unlimited, and the team at Earth Engine has designed a robust system with built-in checks to ensure server capacity is available to everyone. This chapter will introduce general tips for creating efficient Earth Engine workflows that accomplish users’ ambitious research objectives within the constraints of the Earth Engine ecosystem. We use two example case studies: 1) extracting a daily climate time series for many locations across two decades, and 2) generating a regional, cloud-free median composite from Sentinel-2 imagery. - -#### Learning Outcomes {.unlisted .unnumbered} - - -* Understanding constraints on Earth Engine resource use. -* Becoming familiar with multiple strategies to scale Earth Engine operations. -* Managing large projects and multistage workflows. -* Recognizing when using the Python API may be advantageous to execute large batches of tasks. - -#### Assumes you know how to:{.unlisted .unnumbered} - - -* Import images and image collections, filter, and visualize (Part F1). -* Write a function and map it over an ImageCollection (Chap. F4.0). -* Export and import results as Earth Engine assets (Chap. F5.0). -* Understand distinctions among Image, ImageCollection, Feature and FeatureCollection Earth Engine objects (Part F1, Part F2, Part F5). -* Use the require function to load code from existing modules (Chap. F6.1). - -::: -### Introduction {.unlisted .unnumbered} - - -Parts F1–F5 of this book have covered key remote sensing concepts and demonstrated how to implement them in Earth Engine. Most exercises have used local-scale examples to enhance understanding and complete tasks within a class-length time period. But Earth Engine’s power comes from its scalability—the ability to apply geospatial processing across large areas and many years. - -How we go from small to large scales is influenced by Earth Engine’s design. Earth Engine runs on many individual computer servers, and its functions are designed to split up processing onto these servers. This chapter focuses on common approaches to implement large jobs within Earth Engine’s constraints. To do so, we first discuss Earth Engine’s underlying infrastructure to provide context for existing limits. We then cover four core concepts for scaling: - -1. Using best coding practices. -2. Breaking up jobs across time. -3. Breaking up jobs across space. -4. Building a multipart workflow and exporting intermediate assets. - -#### Earth Engine: Under the Hood - -As you use Earth Engine, you may begin to have questions about how it works and how you can use that knowledge to optimize your workflow. In general, the inner workings are opaque to users. Typical fixes and approaches that data scientists use to manage memory constraints often don’t apply. It’s helpful to know what users can and cannot control, and how your scripts translate to Earth Engine’s server operations. - -Earth Engine is a parallel, distributed system (see Gorelick et al. 2017), which means that when you submit tasks, it breaks up pieces of your query onto different processors to complete them more efficiently. It then collects the results and returns them to you. For many users, not having to manually design this parallel, distributed processing is a huge benefit. For some advanced users, it can be frustrating to not have better control. We’d argue that leaving the details up to Earth Engine is a huge time-saver for most cases, and learning to work within a few constraints is a good time investment. - -One core concept useful to master is the relationship between client-side and server-side operations. Client-side operations are performed within your browser (for the JavaScript API Code Editor) or local system (for the Python API). These include things such as manipulating strings or numbers in JavaScript. Server-side operations are executed on Google’s servers and include all of the ee.* functions. By using the Earth Engine APIs—JavaScript or Python—you are building a chain of commands to send to the servers and later receive the result back. As much as possible, you want to structure your code to send all the heavy lifting to Google, and keep processing off of your local resources. - -In other words, your work in the Code Editor is making a description of a computation. All ee objects are just placeholders for server-side objects—their actual value does not exist locally on your computer. To see or use the actual value, it has to be evaluated by the server. If you print an Earth Engine object, it calls getInfo to evaluate and return the value. In contrast, you can also work with JavaScript/Python lists or numbers locally, and do basic JavaScript/Python things to them, like add numbers together or loop over items. These are client-side objects. Whenever you bring a server-side object into your local environment, there’s a computational cost. - -Table F6.2.1 describes some nuts and bolts about Earth Engine and their implications. Table F6.2.2 provides some of the existing limits on individual tasks. - -Table F6.2.1 Characterics of Google Earth Engine and implications for running large jobs - -Earth Engine characteristics - -Implications - -A parallel, distributed system - -Occasionally, doing the exact same thing in two different orders can result in different processing distributions, impacting the ability to complete the task within system limits. - -Most processing is done per tile (generally a square that is 256 x 256 pixels). - -Tasks that require many tiles are the most memory intensive. Some functions have a tileScale argument that reduces tile size, allowing processing-intensive jobs to succeed (at the cost of reduced speed). - -Export mode has higher memory and time allocations than interactive mode. - -It’s better to export large jobs. You can export to your Earth Engine assets, your Google Drive, or Google Cloud Storage. - -Some operations are cached temporarily. - -Running the same job twice could result in different run times. Occasionally tasks may run successfully on a second try. - -Underlying infrastructure is composed of clusters of low-end servers. - -There’s a hard limit on data size for any individual server; large computations need to be done in parallel using Earth Engine functions. - -The image processing domain, scale, and projection are defined by the specified output and applied backwards throughout the processing chain. - -There are not many cases when you will need to manually reproject images, and these operations are costly. Similarly, manually “clipping” images is typically unnecessary. - -Table F6.2.2 Size limits for Earth Engine tasks - -Earth Engine Component - -Limits - -Interactive mode - -Can print up to 5000 records. Computations must finish within five minutes. - -Export mode - -Jobs have no time limit as long as they continue to make reasonable progress (defined roughly as 600 seconds per feature, two hours per aggregation, and 10 minutes per tile). If any one tile, feature, or aggregation takes too long, the whole job will get canceled. Any jobs that take longer than one week to run will likely fail due to Earth Engine's software update release cycles. - -Table assets - -Maximum of 100 million features, 1000 properties (columns), and 100,000 vertices for a geometry. - -#### The Importance of Coding Best Practices - -Good code scales better than bad code. But what is good code? Generally, for Earth Engine, good code means 1) using Earth Engine’s server-side operators; 2) avoiding multiple passes through the same image collection; 3) avoiding unnecessary conversions; and 4) setting the processing scale or sample numbers appropriate for your use case, i.e., avoid using very fine scales or large samples without reason. - -We encourage readers to become familiar with the “Coding Best Practices” page in the online Earth Engine User Guide. This page provides examples for avoiding mixing client- and server-side functions, unnecessary conversions, costly algorithms, combining reducers, and other helpful tips. Similarly, the “Debugging Guide–Scaling Errors” page of the online Earth Engine User Guide covers some common problems and solutions. - -In addition, some Earth Engine functions are more efficient than others. For example, Image.reduceRegions is more efficient than Image.sampleRegions, because sampleRegions regenerates the geometries under the hood. These types of best practices are trickier to enumerate and somewhat idiosyncratic. We encourage users to learn about and make use of the Profiler tab, which will track and display the resources used for each operation within your script. This can help identify areas to focus efficiency improvements. Note that the profiler itself increases resource use, so only use it when necessary to develop a script and remove it for production-level execution. Other ways to discover best practices include following/posting questions to GIS StackExchange or the Earth Engine Developer’s Discussion Group, swapping code with others, and experimentation. - - -### Scaling Across Time - -In this section we use an example of extracting climate data at features (points or polygons) to demonstrate how to scale an operation across many features (Sect. 1.1) and how to break up large jobs by time units when necessary (e.g, by years; Sect. 1.2). - -#### 1.1. Scaling Up with Earth Engine Operators: Annual Daily Climate Data - -Earth Engine’s operators are designed to parallelize queries on the backend without user intervention. In many cases, they are sufficient to accomplish a scaling operation. - -As an example, we will extract a daily time series of precipitation, maximum temperature, and minimum temperature for county polygons in the United States. We will use the GRIDMET Climate Reanalysis product (Abatzoglou 2013), which provides daily, 4000 m resolution gridded meteorological data from 1979 to the present across the contiguous United States. To save time for this practicum, we will focus on the states of Indiana, Illinois, and Iowa in the central United States, which together include 293 counties (Fig. F6.2.1). - -![Fig. F6.2.1 Map of study area, showing 293 county features within the states of Iowa, Illinois, and Indiana in the United States](F6/image11.png) - - -This example uses the ee.Image.reduceRegions operator, which extracts statistics from an Image for each Feature (point or polygon) in a FeatureCollection. We will map the reduceRegions operator over each daily image in an ImageCollection, thus providing us with the daily climate information for each county of interest. - -Note that although our example uses a climate ImageCollection, this approach transfers to any ImageCollection, including satellite imagery, as well as image collections that you have already processed, such as cloud masking (Chap. F4.3) or time series aggregation (Chap. F4.2). - -First, define the FeatureCollection, ImageCollection, and time period: - -```js -// Load county dataset. -// Filter counties in Indiana, Illinois, and Iowa by state FIPS code. -// Select only the unique ID column for simplicity. -var countiesAll = ee.FeatureCollection('TIGER/2018/Counties'); -var states = ['17', '18', '19']; -var uniqueID = 'GEOID'; -var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) - .select(uniqueID); - -print(featColl.size()); -print(featColl.limit(1)); - -// Visualize target features (create Figure F6.2.1). -Map.centerObject(featColl, 5); -Map.addLayer(featColl); - -// specify years of interest -var startYear = 2020; -var endYear = 2020; - -// climate dataset info -var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'; -var bandsWanted = ['pr', 'tmmn', 'tmmx']; -var scale = 4000; - -``` -Printing the size of the FeatureCollection indicates that there are 293 counties in our subset. Since we want to pull a daily time series for one year, our final dataset will have 106,945 rows—one for each county-day. - -Note that from our county FeatureCollection, we select only the GEOID column, which represents a unique identifier for each record in this dataset. We do this here to simplify print outputs; we could also specify which properties to include in the export function (see below). - -Next, load and filter the climate data. Note we adjust the end date to January 1 of the following year, rather than December 31 of the specified year, since the filterDate function has an inclusive start date argument and an exclusive end date argument; without this modification the output would lack data for December 31. - -```js -// Load and format climate data. -var startDate = startYear + '-01-01'; - -var endYear_adj = endYear + 1; -var endDate = endYear_adj + '-01-01'; - -var imageCollection = ee.ImageCollection(imageCollectionName) - .select(bandsWanted) - .filterBounds(featColl) - .filterDate(startDate, endDate); - -``` -Now get the mean value for each climate attribute within each county feature. Here, we map the ee.Image.reduceRegions call over the ImageCollection, specifying an ee.Reducer.mean reducer. The reducer will apply to each band in the image, and it returns the FeatureCollection with new properties. We also add a 'date_ymd' time property extracted from the image to correctly associate daily values with their date. Finally, we flatten the output to reform a single FeatureCollection with one feature per county-day. - -```js -// get values at features -var sampledFeatures = imageCollection.map(function(image) { return image.reduceRegions({ - collection: featColl, - reducer: ee.Reducer.mean(), - scale: scale - }).filter(ee.Filter.notNull( - bandsWanted)) // drop rows with no data .map(function(f) { // add date property var time_start = image.get( 'system:time_start'); var dte = ee.Date(time_start).format( 'YYYYMMdd'); return f.set('date_ymd', dte); - }); -}).flatten(); - -print(sampledFeatures.limit(1)); - -``` -Note that we include a filter to remove feature-day rows that lacked data. While this is less common when using gridded climate products, missing data can be common when reducing satellite images. This is because satellite collections come in scene tiles, and each image tile likely does not overlap all of our features unless it has first been aggregated temporally. It can also occur if a cloud mask has been applied to an image prior to the reduction. By filtering out null values, we can reduce empty rows. - -Now explore the result. If we simply print(sampledFeatures) we get our first error message: “User memory limit exceeded.” This is because we’ve created a FeatureCollection that exceeds the size limits set for interactive mode. How many are there? We could try print(sampledFeatures.size()), but due to the larger size, we receive a “Computation timed out” message—it’s unable to tell us. Of course, we know that we expect 293 counties x 365 days = 106,945 features. We can, however, check that our reducer has worked as expected by asking Earth Engine for just one feature: print(sampledFeatures.limit(1)). - -![Fig. F6.2.2 Screenshot of the print output for one feature after the reduceRegions call](F6/image75.png) - - -Here, we can see the precipitation, minimum temperature, and maximum temperature for the county with GEOID = 17121 on January 1, 2020 (Fig. F6.2.2; note temperature is in Kelvin units). - -Next, export the full FeatureCollection as a CSV to a folder in your Google Drive. Specify the names of properties to include. Build part of the filename dynamically based on arguments used for year and data scale, so we don’t need to manually modify the filenames. - -```js -// export info -var exportFolder = 'GEE_scalingUp'; -var filename = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' + - startYear + '-' + endYear;// prepare export: specify properties/columns to include -var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted); -print(columnsWanted); - -Export.table.toDrive({ - collection: sampledFeatures, - description: filename, - folder: exportFolder, - fileFormat: 'CSV', - selectors: columnsWanted -}); - -``` -:::{.callout-note} -Code Checkpoint F62a. The book’s repository contains a script that shows what your code should look like at this point. -::: -On our first export, this job took about eight minutes to complete, producing a dataset 6.8 MB in size. The data is ready for downstream use but may need formatting to suit the user’s goals. You can see what the exported CSV looks like in Fig. F6.2.3. - -![Fig. F6.2.3 Top six rows of the exported CSV viewed in Microsoft Excel and sorted by county GEOID ](F6/image41.png) - - -Using the Selectors Argument - -There are two excellent reasons to use the selectors argument in your Export.table.toDrive call. First, if the argument is not specified, Earth Engine will generate the column names for the exported CSV from the first feature in your FeatureCollection. If that feature is missing properties, those properties will be dropped from the export for all features. - -Perhaps even more important if you are seeking to scale up an analysis, including unnecessary columns can greatly increase file size and even processing time. For example, Earth Engine includes a .geo field that contains a GeoJSON description of each spatial feature. For non-simple geometries, the field can be quite large, as it lists coordinates for each polygon vertex. For many purposes, it’s not necessary to include this information for each daily record (here, 365 daily rows per feature). - -For example, when we ran the same job as above but did not use the selectors argument, the output dataset was 5.7 GB (versus 6.8 MB!) and the runtime was slower. This is a cumbersomely large file, with no real benefit. We generally recommend dropping the .geo column and other unnecessary properties. To retain spatial information, a unique identifier for each feature can be used for downstream joins with the spatial data or other properties. If working with point data, latitude and longitude columns can be added prior to export to maintain easily accessible geographic information, although the .geo column for point data is far smaller than for irregularly shaped polygon features. - -#### 1.2. Scaling Across Time by Batching: Get 20 Years of Daily Climate Data - -Above, we extracted one year of daily data for our 293 counties. Let’s say we want to do the same thing, but for 2001–2020. We have already written our script to flexibly specify years, so it’s fairly adaptable to this new use case: - -```js -// specify years of interest -var startYear = 2020; -var endYear = 2020; - -``` -If we only wanted a few years for a small number of features, we could just modify the startYear or endYear and proceed. Indeed, our current example is modest in size and number of features, and we were able to run 2001–2020 in one export job that took about two hours, with an output file size of 299 MB. However, with larger feature collections, or hourly data, we will again start to bump up against Earth Engine’s limits. Generally, jobs of this sort do not fail quickly—exports are allowed to run as long as they continue making progress (see Table F6.2.2). It’s not uncommon, however, for a large job to take well over 24 hours to run, or even to fail after more than 24 hours of run time, as it accumulates too many records or a single aggregation fails. For users, this can be frustrating. - -We generally find it simpler to run several small jobs rather than one large job. Outputs can then be combined in external software. This avoids any frustration with long-running jobs or delayed failures, and it allows parts of the task to be run simultaneously. Earth Engine generally executes from 2–20 jobs per user at a time, depending on overall user load (although 20 is rare). As a counterpart, there is some overhead for generating separate jobs. - -Important note: When running a batch of jobs, it may be tempting to use multiple accounts to execute subsets of your batch and thus get your shared results faster. However, doing so is a direct violation of the Earth Engine terms of service and can result in your account(s) being terminated. - -For-Loops: They Are Sometimes OK - -Batching jobs in time is a great way to break up a task into smaller units. Other options include batching jobs by spatial regions defined by polygons (see Sect. 2), or for computationally heavy tasks, batching by both space and time. - -Because Export functions are client-side functions, however, you can’t create an export within an Earth Engine map command. Instead, we need to loop over the variable that will define our batches and create a set of export tasks. - -But wait! Aren’t we supposed to avoid for-loops at all costs? Yes, within a computational chain. Here, we are using a loop to send multiple computational chains to the server. - -First, we will start with the same script as in Sect. 1.1, but we will modify the start year. We will also modify the desired output filename to be a generic base filename, to which we will append the year for each task within the loop (in the next step). - -```js -// Load county dataset. -var countiesAll = ee.FeatureCollection('TIGER/2018/Counties'); -var states = ['17', '18', '19']; -var uniqueID = 'GEOID'; -var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states)) - .select(uniqueID); - -print(featColl.size()); -print(featColl.limit(1)); -Map.addLayer(featColl); - -// Specify years of interest. -var startYear = 2001; -var endYear = 2020; - -// Climate dataset info. -var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET'; -var bandsWanted = ['pr', 'tmmn', 'tmmx']; -var scale = 4000; - -// Export info. -var exportFolder = 'GEE_scalingUp'; -var filenameBase = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_'; - -``` -Now modify the code in Sect. 1.1 to use a looping variable, i, to represent each year. Here, we are using standard JavaScript looping syntax, where i will take on each value between our startYear (2001) and our endYear (2020) for each loop through this section of code, thus creating 20 queries to send to Earth Engine’s servers. - -```js -// Initiate a loop, in which the variable i takes on values of each year. -for (var i = startYear; i <= endYear; i++) { // for each year.... // Load climate collection for that year. var startDate = i + '-01-01'; - - var endYear_adj = i + 1; var endDate = endYear_adj + '-01-01'; var imageCollection = ee.ImageCollection(imageCollectionName) - .select(bandsWanted) - .filterBounds(featColl) - .filterDate(startDate, endDate); // Get values at feature collection. var sampledFeatures = imageCollection.map(function(image) { return image.reduceRegions({ - collection: featColl, - reducer: ee.Reducer.mean(), - tileScale: 1, - scale: scale - }).filter(ee.Filter.notNull(bandsWanted)) // remove rows without data .map(function(f) { // add date property var time_start = image.get('system:time_start'); var dte = ee.Date(time_start).format('YYYYMMdd'); return f.set('date_ymd', dte); - }); - }).flatten(); // Prepare export: specify properties and filename. var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted); var filename = filenameBase + i; Export.table.toDrive({ - collection: sampledFeatures, - description: filename, - folder: exportFolder, - fileFormat: 'CSV', - selectors: columnsWanted - }); - -} - -:::{.callout-note} -Code Checkpoint F62b. The book’s repository contains a script that shows what your code should look like at this point. -::: -When we run this script, it builds our computational query for each year, creating a batch of 20 individual jobs that will show up in the Task pane (Fig. F6.2.4). Each task name includes the year, since we used our looping variable i to modify the base filename we specified. - -![Fig. F6.2.4 Creation of batch tasks for each year](F6/image63.png) - - -We now encounter a downside to creating batch tasks within the JavaScript Code Editor: we need to click Run to execute each job in turn. Here, we made this easier by programmatically assigning each job the filename we want, so we can hold the Cmd/Ctrl key and click Run to avoid the export task option window and only need to click once per task. Still, one can imagine that at some number of tasks, one’s patience for clicking Run will be exceeded. We assume that number is different for everyone. - -Note: If at any time you have submitted several tasks to the server but want to cancel them all, you can do so more easily from the Earth Engine Task Manager that is linked at the top of the Task pane. You can read about that task manager in the Earth Engine User Guide. - -In order to auto-execute jobs in batch mode, we’d need to use the Python API. Interested users can see the Earth Engine User Guide Python API tutorial for further details about the Python API. - -### Scaling Across Space via Spatial Tiling - -Breaking up jobs in space is another key strategy for scaling operations in Earth Engine. Here, we will focus on making a cloud-free composite from the Sentinel-2 Level 2A Surface Reflectance product. The approach is similar to that in Chap. F4.3, which explores cloud-free compositing. The main difference is that Landsat scenes come with a reliable quality band for each scene, whereas the process for Sentinel-2 is a bit more complicated and computationally intense (see below). - -Our region of interest is the state of Washington in the United States for demonstration purposes, but the method will work at much larger continental scales as well. - -Cloud Masking Approach - -While we do not intend to cover the theory behind Sentinel-2 cloud masking, we do want to include a brief description of the process to convey the computational needs of this approach. - -The Sentinel-2 Level 2A collection does not come with a robust cloud mask. Instead, we will build one from related products that have been developed for this purpose. Following the existing Sentinel-2 cloud masking tutorials in the Earth Engine guides, this approach requires three Sentinel-2 image collections: - -* The Sentinel-2 Level 2A Surface Reflectance product. This is the dataset we want to use to build our final composite. -* The Sentinel-2 Cloud Probability Dataset, an ImageCollection that contains cloud probabilities for each Sentinel-2 scene. -* The Sentinel-2 Level 1C top-of-atmosphere product. This collection is needed to run the Cloud Displacement Index to identify cloud shadows, which is calculated using ee.Algorithms.Sentinel2.CDI (see Frantz et al. 2018 for algorithm description). - -These three image collections all contain 10 m resolution data for every Sentinel-2 scene. We will join them based on their 'system:index' property so we can relate each Level 2A scene with the corresponding cloud probability and cloud displacement index. Furthermore, there are two ee.Image.projection steps to control the scale when calculating clouds and their shadows. - -To sum up, the cloud masking approach is computationally costly, thus requiring some thought when applying it at scale. - -#### 2.1. Generate a Cloud-Free Satellite Composite: Limits to On-the-Fly Computing - -Note: Our focus here is on code structure for implementing spatial tiling. Below, we import existing tested functions for cloud masking using the require command. - -First, define our region and time of interest; then, load the module containing the cloud functions. - -// Set the Region of Interest:Seattle, Washington, United States -var roi = ee.Geometry.Point([-122.33524518034544, 47.61356183942883]); - -// Dates over which to create a median composite. -var start = ee.Date('2019-03-01'); -var end = ee.Date('2019-09-01'); - -// Specify module with cloud mask functions. -var s2mask_tools = require( 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' -); - -``` -Next, load and filter our three Sentinel-2 image collections. - -```js -// Sentinel-2 surface reflectance data for the composite. -var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') - .filterDate(start, end) - .filterBounds(roi) - .select(['B2', 'B3', 'B4', 'B5']); - -// Sentinel-2 Level 1C data (top-of-atmosphere). -// Bands B7, B8, B8A and B10 needed for CDI and the cloud mask function. -var s2 = ee.ImageCollection('COPERNICUS/S2') - .filterBounds(roi) - .filterDate(start, end) - .select(['B7', 'B8', 'B8A', 'B10']); - -// Cloud probability dataset - used in cloud mask function -var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') - .filterDate(start, end) - .filterBounds(roi); - -``` -Now apply the cloud mask: - -```js -// Join the cloud probability dataset to surface reflectance. -var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, 'cloud_probability'); - -// Join the L1C data to get the bands needed for CDI. -var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, 'l1c'); - -// Map the cloud masking function over the joined collection. -// Cast output to ImageCollection -var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools -.maskImage)); - -``` -Next, generate and visualize the median composite: - -```js -// Take the median, specifying a tileScale to avoid memory errors. -var median = masked.reduce(ee.Reducer.median(), 8); - -// Display the results. -Map.centerObject(roi, 12); -Map.addLayer(roi); - -var viz = { - bands: ['B4_median', 'B3_median', 'B2_median'], - min: 0, - max: 3000 -}; -Map.addLayer(median, viz, 'median'); - -``` -:::{.callout-note} -Code Checkpoint F62c. The book’s repository contains a script that shows what your code should look like at this point. -::: -After about 1–3 minutes, Earth Engine returns our composite to us on the fly (Fig. F6.2.5). Note that panning and zooming to a new area requires that Earth Engine must again issue the compositing request to calculate the image for new areas. Given the delay, this isn’t a very satisfying way to explore our composite. - -![Fig. F6.2.5 Map view of Seattle, Washington, USA (left) and the corresponding Sentinel-2 composite (right)](F6/image49.png)![Fig. F6.2.5 Map view of Seattle, Washington, USA (left) and the corresponding Sentinel-2 composite (right)](F6/image43.png) - - -Next, expand our view (set zoom to 9) to exceed the limits of on-the-fly computation (Fig. F6.2.6). - -Map.centerObject(roi, 9); -Map.addLayer(roi); -Map.addLayer(median, viz, 'median'); - -![Fig. F6.2.6 Error message for exceeding memory limits in interactive mode](F6/image42.png) - - -As you can see, this is an excellent candidate for an export task rather than running in “on-the-fly” interactive mode, as above. - -#### 2.2. Generate a Regional Composite Through Spatial Tiling - -Our goal is to apply the cloud masking method in Sect. 2.1 to the state of Washington, United States. In our testing, we successfully exported one Sentinel-2 composite for this area in about nine hours, but for this tutorial, let’s presume we need to split the task up to be successful. - -Essentially, we want to split our region of interest up into a regular grid. For each grid, we will export a composite image into a new ImageCollection asset. We can then load and mosaic our composite for use in downstream scripts (see below). - -First, generate a spatial polygon grid (FeatureCollection) of desired size over your region of interest (see Fig. F6.2.7): - -```js -// Specify helper functions. -var s2mask_tools = require( 'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js' -); - -// Set the Region of Interest: Washington, USA. -var roi = ee.FeatureCollection('TIGER/2018/States') - .filter(ee.Filter.equals('NAME', 'Washington')); - -// Specify grid size in projection, x and y units (based on projection). -var projection = 'EPSG:4326'; // WGS84 lat lon -var dx = 2.5; -var dy = 1.5; - -// Dates over which to create a median composite. -var start = ee.Date('2019-03-01'); -var end = ee.Date('2019-09-01'); - -// Make grid and visualize. -var proj = ee.Projection(projection).scale(dx, dy); -var grid = roi.geometry().coveringGrid(proj); - -Map.addLayer(roi, {}, 'roi'); -Map.addLayer(grid, {}, 'grid'); - -``` - -![Fig. F6.2.7 Visualization of the regular spatial grid generated for use in spatial batch processing](F6/image12.png) - -Next, create a new, empty ImageCollection asset to use as our export destination (Assets > New > Image Collection; Fig. F6.2.8). Name the image collection 'S2_composite_WA' and specify the asset location in your user folder (e.g., "path/to/your/asset/s2_composite_WA"). - -![Fig. F6.2.8 The “create new image collection asset” menu in the Code Editor](F6/image15.png) - - -Specify the ImageCollection to export to, along with a base name for each image (the tile number will be appended in the batch export). - -```js -// Export info. -var assetCollection = 'path/to/your/asset/s2_composite_WA'; -var imageBaseName = 'S2_median_'; - -``` -Extract grid numbers to use as looping variables. Note there is one getInfo call here, which should be used sparingly and never within a for-loop if you can help it. We use it to bring the number of grid cells we’ve generated onto the client-side to set up the for-loop over grids. Note that if your grid has too many elements, you may need a different strategy. - -```js -// Get a list based on grid number. -var gridSize = grid.size().getInfo(); -var gridList = grid.toList(gridSize); - -``` -Batch generate a composite image task export for each grid via looping: - -```js -// In each grid cell, export a composite -for (var i = 0; i < gridSize; i++) { // Extract grid polygon and filter S2 datasets for this region. var gridCell = ee.Feature(gridList.get(i)).geometry(); var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR') - .filterDate(start, end) - .filterBounds(gridCell) - .select(['B2', 'B3', 'B4', 'B5']); var s2 = ee.ImageCollection('COPERNICUS/S2') - .filterDate(start, end) - .filterBounds(gridCell) - .select(['B7', 'B8', 'B8A', 'B10']); var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY') - .filterDate(start, end) - .filterBounds(gridCell); // Apply the cloud mask. var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c, 'cloud_probability'); var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2, 'l1c'); var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools - .maskImage)); // Generate a median composite and export. var median = masked.reduce(ee.Reducer.median(), 8); // Export. var imagename = imageBaseName + 'tile' + i; Export.image.toAsset({ - image: median, - description: imagename, - assetId: assetCollection + '/' + imagename, - scale: 10, - region: gridCell, - maxPixels: 1e13 }); -} - -:::{.callout-note} -Code Checkpoint F62d. The book’s repository contains a script that shows what your code should look like at this point. -::: -Similar to Sect. 1.2, we now have a list of tasks to execute. We can hold the Cmd/Ctrl key and click Run to execute each task (Fig. F6.2.9). Again, users with applications requiring large batches may want to explore the Earth Engine Python API, which is well-suited to batching work. The output ImageCollection is 35.3 GB, so you may not want to execute all (or any) of these tasks but can access our pre-generated image, as discussed below. - -![Fig. F6.2.9 Spatial batch tasks have been generated and are ready to run](F6/image22.png) - - -In addition to being necessary for very large regions, batch processing can speed things up for moderate scales. In our tests, tiles averaged about one hour to complete. Because three jobs in our queue were running simultaneously, we covered the full state of Washington in about four hours (compared to about nine hours when tested for the full state of Washington at once). Users should note, however, that there is also an overhead to spinning up each batch task. Finding the balance between task size and task number is a challenge for most Earth Engine users that becomes easier with experience. - -In a new script, load the exported ImageCollection and mosaic for use. - -// load image collection and mosaic into single image -var assetCollection = 'projects/gee-book/assets/F6-2/s2_composite_WA'; -var composite = ee.ImageCollection(assetCollection).mosaic(); - -// Display the results -var geometry = ee.Geometry.Point([-120.5873563817392, 47.39035206888694 -]); -Map.centerObject(geometry, 6); -var vizParams = { - bands: ['B4_median', 'B3_median', 'B2_median'], - min: 0, - max: 3000 -}; -Map.addLayer(composite, vizParams, 'median'); - -``` -:::{.callout-note} -Code Checkpoint F62e. The book’s repository contains a script that shows what your code should look like at this point. -::: -![Fig. F6.2.10 Sentinel-2 composite covering the state of Washington, loaded from asset. The remaining white colors are snow-capped mountains, not clouds.](F6/image16.png) - - -Note the ease, speed, and joy of panning and zooming to explore the pre-computed composite asset (Fig. F6.2.10) compared to the on-the-fly version discussed in Sect. 2.1. - -### Multistep Workflows and Intermediate Assets - -Often, our goals require several processing steps that cannot be completed within one Earth Engine computational chain. In these cases, the best strategy becomes breaking down tasks into individual pieces that are created, stored in assets, and used across several scripts. Each sequential script creates an intermediate output, and this intermediate output becomes the input to the next script. - -As an example, consider the land use classification task of identifying irrigated agricultural lands. This type of classification can benefit from several types of evidence, including satellite composites, aggregated weather information, soil information, and/or crop type locations. Individual steps for this type of work might include: - -* Generating satellite composites of annual or monthly vegetation indices -* Processing climate data into monthly or seasonal values -* Generating random point locations from a ground truth layer for use as a feature training dataset and accuracy validation, and extracting composite and weather values at these features -* Training a classifier and applying it, possibly across multiple years; researchers will often implement multiple classifiers and compare the performance of different methods -* Implementing post-classification cleaning steps, such as removing “speckle” -* Evaluating accuracy at ground truth validation points, and against government statistics using total area per administrative boundary -* Exporting your work as spatial layers, visualizations, or other formats - -Multipart workflows can become unwieldy to manage, particularly if there are multiple collaborators or the project has a long timeline; it can be difficult to remember why each script was developed and where it fits in the overall workflow. - -Here, we provide tips for managing multipart workflows. These are somewhat opinionated and based largely on concepts from “Good Enough Practices in Scientific Computing” (Wilson et al. 2017). Ultimately, your personal workflow practices will be a combination of what works for you, what works for your larger team and organization, and, hopefully, what works for good documentation and reproducibility. - -Tip 1. Create a repository for each project - -The repository can be considered the fundamental project unit. In Earth Engine, sharing permissions are set for each individual repository, so this allows you to share a specific project with others (see Chap. F6.1). - -By default, Earth Engine saves new scripts in a “default” repository specific for each user (users//default). You can create new repositories on the Scripts tab of the Code Editor (Fig. F6.2.11). - -![Fig. F6.2.11 The Code Editor menu for creating new repositories](F6/image20.png) - - -To adjust permissions for each repository, click on the Gear icon (Fig. F6.2.12): - -![Fig. F6.2.12 Access the sharing and permissions menu for each repository by clicking the Gear icon](F6/image67.png) - - -For users familiar with version control, Earth Engine uses a git-based script manager, so each repository can also be managed, edited, and/or synced with your local copy or collaborative spaces like GitHub. - -Tip 2. Make a separate script for each step, and make script file names informative and self-sorting - -Descriptive, self-sorting filenames are an excellent “good enough” way to keep your projects organized. We recommend starting script names with zero-padded numeric values to take advantage of default ordering. Because we are generating assets in early scripts that are used in later scripts, it’s important to preserve the order of your workflow. The name should also include short descriptions of what the script does (Fig. F6.2.13). - -![Fig. F6.2.13 An example project repository with multiple scripts. Using leading numbers when naming scripts allows you to order them by their position in the workflow.](F6/image62.png) - - -Leaving some decimal places between successive scripts gives you the ability to easily insert any additional steps you didn’t originally anticipate. And zero-padding means your self-sorting still works once you move into double-digit numbers. - -Other script organization strategies might involve including subfolders to collect scripts related to main steps. For example, one could have a subfolder “04_classifiers” to keep alternative classification scripts in one place, using a more tree-based file structure. Again, each user or group will develop a system that works for them. The important part is to have an organizational system. - -Tip 3. Consider data types and file sizes when storing intermediates - -Images and image collections are common intermediate file types, since generating satellite composites or creating land use classifications tends to be computationally intensive. These assets can also be quite large, depending on the resolution and region size. Recall that our single-year, subregional Sentinel-2 composite in Sect. 2 was about 23 GB. - -Image values can be stored from 8-bit integers to 64-bit double floats (numbers with decimals). Higher bits allow for more precision, but have much larger file sizes and are not always necessary. For example, if we are generating a land use map with five classes, we can convert that to a signed or unsigned 8-bit integer using toInt8 or toUint8 prior to exporting to asset, which can accommodate 256 unique values. This results in a smaller file size. Selectively retaining only bands of interest is also helpful to reduce size. - -For cases requiring decimals and precision, consider whether a 32-bit float will do the job instead of a 64-bit double—toFloat will convert an image to a 32-bit float. If you find you need to conserve storage, you can also scale float values and store as an integer image (image.multiply(100).toInt16(), for example). This would retain precision to the second decimal place and reduce file size by a factor of two. Note that this may require you to unscale the values in downstream use. Ultimately, the appropriate data type will be specific to your needs. - -And of course, as mentioned above under “The Importance of Best Coding Practices,” be aware of the scale resolution you are working at, and avoid using unnecessarily high resolution when it’s not supported by either the input imagery or your research goals. - -Tip 4. Consider Google Cloud Platform for hosting larger intermediates - -If you are working with very large or very many files, you can link Earth Engine with Cloud Projects on Google Cloud Platform. See the Earth Engine documentation on “Setting Up Earth Engine Enabled Cloud Projects” for more information. - -### Conclusion {.unnumbered} - -In this chapter, you learned how to design Earth Engine Apps using both the Earth Engine User Interface API (JavaScript) and geemap (Python). You also learned how to deploy Earth Engine Apps on multiple platforms, such as the JavaScript Code Editor, a local web server, and Heroku. The skill of designing and deploying interactive Earth Engine Apps is essential for making your research and data products more accessible to the scientific community and the general public. Anyone with the link to your web App can analyze and visualize Earth Engine datasets without needing an Earth Engine account. - -### References {.unnumbered} - -* Earth Engine User Interface API: [https://developers.google.com/earth-engine/guides/ui](https://www.google.com/url?q=https://developers.google.com/earth-engine/guides/ui&sa=D&source=editors&ust=1671458841355402&usg=AOvVaw1ZgOA5XvSnn5Uo83ccgHPT) -* Earth Engine Apps: [https://developers.google.com/earth-engine/guides/apps](https://www.google.com/url?q=https://developers.google.com/earth-engine/guides/apps&sa=D&source=editors&ust=1671458841355890&usg=AOvVaw1ZYwRsMtxZ2RPAn-dC-E0n) -* Voilà: [https://voila.readthedocs.io](https://www.google.com/url?q=https://voila.readthedocs.io&sa=D&source=editors&ust=1671458841356320&usg=AOvVaw1_h1OkQnXAvfEh717DURMY) -* geemap: [https://geemap.org](https://www.google.com/url?q=https://geemap.org&sa=D&source=editors&ust=1671458841356762&usg=AOvVaw3ednZ3gbVzDuptXKRZgKCT) -* ngrok: [https://ngrok.com](https://www.google.com/url?q=https://ngrok.com&sa=D&source=editors&ust=1671458841357236&usg=AOvVaw11-kfA1McHDaqztFMUrmtP) -* Heroku: [https://heroku.com](https://www.google.com/url?q=https://heroku.com&sa=D&source=editors&ust=1671458841357713&usg=AOvVaw15mVX-rHKo54H2oq0Msd2Z) -* Earthengine-apps: [https://github.com/giswqs/earthengine-apps](https://www.google.com/url?q=https://github.com/giswqs/earthengine-apps&sa=D&source=editors&ust=1671458841358120&usg=AOvVaw2XD4jjXV9SfPmaC-oLbstc) - - - - - - -Chapter F6.4: Combining R and Earth Engine - - - - - -:::{.callout-tip} -## Chapter Information - -#### Author {.unlisted .unnumbered} - - - -Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza - - - -#### Overview {.unlisted .unnumbered} - - -The purpose of this chapter is to introduce rgee, a non-official API for Earth Engine. You will explore the main features available in rgee and how to set up an environment that integrates rgee with third-party R and Python packages. After this chapter, you will be able to combine R, Python, and JavaScript in the same workflow. - -#### Learning Outcomes {.unlisted .unnumbered} - - -* Becoming familiar with rgee, the Earth Engine R API interface. -* Integrating rgee with other R packages. -* Displaying interactive maps. -* Integrating Python and R packages using reticulate. -* Combining Earth Engine JavaScript and Python APIs with R. - -#### Assumes you know how to:{.unlisted .unnumbered} - - -* Install the Python environment (Chap. F6.3). -* Use the require function to load code from existing modules (Chap. F6.1). -* Use the basic functions and logic of Python. -* Configure an environment variable and use .Renviron files. -* Create Python virtual environments. - -::: -### Introduction {.unlisted .unnumbered} - - -R is a popular programming language established in statistical science with large support in reproducible research, geospatial analysis, data visualization, and much more. To get started with R, you will need to satisfy some extra software requirements. First, install an up-to-date R version (at least 4.0) in your work environment. The installation procedure will vary depending on your operating system (i.e., Windows, Mac, or Linux). Hands-On Programming with R (Garrett Grolemund 2014, Appendix A) explains step by step how to proceed. We strongly recommend that Windows users install Rtools to avoid compiling external static libraries. - -If you are new to R, a good starting point is the book Geocomputation with R (Lovelace et al. 2019) or Spatial Data Science with Application in R (Pebesma and Bivand 2021). In addition, we recommend using an integrated development environment (e.g., Rstudio) or a code editor (e.g., Visual Studio Code) to create a suitable setting to display and interact with R objects. - -The following R packages must be installed (find more information in the R manual) in order to go through the practicum section. - -## Use install.packages to install R packages from the CRAN repository. -install.packages('reticulate') # Connect Python with R. -install.packages('rayshader') # 2D and 3D data visualizations in R. -install.packages('remotes') # Install R packages from remote repositories. -remotes::install_github('r-earthengine/rgeeExtra') # rgee extended. -install.packages('rgee') # GEE from within R. -install.packages('sf') # Simple features in R. -install.packages('stars') # Spatiotemporal Arrays and Vector Data Cubes. -install.packages('geojsonio') # Convert data to 'GeoJSON' from various R classes. -install.packages('raster') # Reading, writing, manipulating, analyzing and modeling of spatial data. -install.packages('magick') # Advanced Graphics and Image-Processing in R -install.packages('leaflet.extras2') # Extra Functionality for leaflet -install.packages('cptcity') # colour gradients from the 'cpt-city' web archive - -Earth Engine officially supports client libraries only for the JavaScript and Python programming languages. While the Earth Engine Code Editor offers a convenient environment for rapid prototyping in JavaScript, the lack of a mechanism for integration with local environments makes the development of complex scripts tricky. On the other hand, the Python client library offers much versatility, enabling support for third-party packages. However, not all Earth and environmental scientists code in Python. Hence, a significant number of professionals are not members of the Earth Engine community. In the R ecosystem, rgee (Aybar et al. 2020) tries to fill this gap by wrapping the Earth Engine Python API via reticulate (Kevin Ushey et al. 2021). The rgee package extends and supports all the Earth Engine classes, modules, and functions, working as fast as the other APIs. - -![Fig. F6.4.1 A simplified diagram of rgee functionality](F6/image48.png) - - -Figure F6.4.1 illustrates how rgee bridges the Earth Engine platform with the R ecosystem. When an Earth Engine request is created in R, rgee transforms this piece of code into Python. Next, the Earth Engine Python API converts the Python code into JSON. Finally, the JSON file request is received by the server through a Web REST API. Users could get the response using the getInfo method by following the same path in reverse. - - -### Installing rgee - -To run, rgee needs a Python environment with two packages: NumPy and earthengine-api. Because instructions change frequently, installation is explained at the following checkpoint: - -:::{.callout-note} -Code Checkpoint F64a. The book’s repository contains information about setting up the rgee environment. -::: -After installing both the R and Python requirements, you can now initialize your Earth Engine account from within R. Consider that R, in contrast to Javascript and Python, supports three distinct Google APIs: Earth Engine, Google Drive, and Google Cloud Storage (GCS). - -The Google Drive and GCS APIs will allow you to transfer your Earth Engine completed task exports to a local environment automatically. In these practice sessions, we will use only the Earth Engine and Google Drive APIs. Users that are interested in GCS can look up and explore the GCS vignette. To initialize your Earth Engine account alongside Google Drive, use the following commands. - -## Initialize just Earth Engine -ee_Initialize() - -## Initialize Earth Engine and GDee_Initialize(drive = TRUE) - -If the Google account is verified and the permission is granted, you will be directed to an authentication token. Copy and paste this token into your R console. Consider that the GCS API requires setting up credentials manually; look up and explore the rgee vignette for more information. The verification step is only required once; after that, rgee saves the credentials in your system. - -:::{.callout-note} -Code Checkpoint F64b. The book’s repository contains information about what your code should look like at this point. -::: -### Creating a 3D Population Density Map with rgee and rayshader - -First, import the rgee, rayshader, and raster packages. - -library(rayshader) -library(raster) -library(rgee) - -Initialize the Earth Engine and Google Drive APIs using ee_Initialize. Both credentials must come from the same Google account. - -ee_Initialize(drive = TRUE) - -Then, we will access the WorldPop Global Project Population Data dataset. In rgee, the Earth Engine spatial classes (ee$Image, ee$ImageCollection, and ee$FeatureCollection) have a special attribute called Dataset. Users can use it along with autocompletion to quickly find the desired dataset. - -collections <- ee$ImageCollection$Dataset -population_data <- collections$CIESIN_GPWv411_GPW_Population_Density -population_data_max <- population_data$max() - -If you need more information about the Dataset, use ee_utils_dataset_display to go to the official documentation in the Earth Engine Data Catalog. - -population_data %>% ee_utils_dataset_display() - -The rgee package provides various built-in functions to retrieve data from Earth Engine (Aybar et al. 2020). In this example, we use ee_as_raster, which automatically converts an ee$Image (server object) into a RasterLayer (local object). - -sa_extent <- ee$Geometry$Rectangle( - coords = c(-100, -50, -20, 12), - geodesic = TRUE, - proj = "EPSG:4326") - -population_data_ly_local <- ee_as_raster( - image = population_data_max, - region = sa_extent, - dsn = "/home/pc-user01/population.tif", # change for your own path. scale = 5000 -) - -Now, turn a RasterLayer into a matrix suitable for rayshader. - -pop_matrix <- raster_to_matrix(population_data_ly_local) - -Next, modify the matrix population density values, adding: - -* Texture, based on five colors (lightcolor, shadowcolor, leftcolor, rightcolor, and centercolor; see rayshader::create_texture documentation) -* Color and shadows (rayshader::sphere_shade) - -pop_matrix %>% - sphere_shade( - texture = create_texture("#FFFFFF", "#0800F0", "#FFFFFF", "#FFFFFF", "#FFFFFF") - ) %>% - plot_3d( - pop_matrix, - zoom = 0.55, theta = 0, zscale = 100, soliddepth = -24, - solidcolor = "#525252", shadowdepth = -40, shadowcolor = "black", - shadowwidth = 25, windowsize = c(800, 720) - ) - -Lastly, define a title and subtitle for the plot. Use rayshader::render_snapshot to export the final results (Fig. F6.4.2). - -text <- paste0( "South Americanpopulation density", - strrep("n", 27), "Source:GPWv411: Population Density (Gridded Population of the World Version 4.11)") - -render_snapshot( - filename = "30_poblacionsudamerica.png", - title_text = text, - title_size = 20, - title_color = "black", - title_font = "Roboto bold", - clear = TRUE -) - -![Fig. F6.4.2 3D population density map of South America](F6/image2.png) - - -:::{.callout-note} -Code Checkpoint F64c. The book’s repository contains information about what your code should look like at this point. -::: -### Displaying Maps Interactively - -Similar to the Code Editor, rgee supports the interactive visualization of spatial Earth Engine objects by Map$addLayer. First, let’s import the rgee and cptcity packages. The cptcity R package is a wrapper to the cpt-city color gradients web archive. - -library(rgee) -library(cptcity) -ee_Initialize() - -We’ll select an ee$Image; in this case, the Shuttle Radar Topography Mission 90 m (SRTM-90) Version 4. - -dem <- ee$Image$Dataset$CGIAR_SRTM90_V4 - -Then, we’ll set the visualization parameters as a list with the following elements. - -* min: value(s) to map to 0 -* max: value(s) to map to 1 -* palette: a list of CSS-style color strings - -viz <- list( - min = 600, - max = 6000, - palette = cpt(pal = 'grass_elevation', rev = TRUE) -) - -Then, we’ll create a simple display using Map$addLayer. - -m1 <- Map$addLayer(dem, visParams = viz, name = "SRTM", shown = TRUE) - -Optionally, you could add a custom legend using Map$addLayer (Fig. F6.4.3). - -pal <- Map$addLegend(viz) -m1 + pal - -![Fig. F6.4.3 Interactive visualization of SRTM-90 Version 4 elevation values](F6/image28.png) - - -The procedure to display ee$Geometry, ee$Feature, and ee$FeatureCollections objects is similar to the previous example effected on an ee$Image. Users just need to change the arguments: eeObject and visParams. - -First, Earth Engine geometries (Fig. F6.4.4). - -vector <- ee$Geometry$Point(-77.011,-11.98) %>% - ee$Feature$buffer(50*1000) -Map$centerObject(vector) -Map$addLayer(vector) # eeObject is a ee$Geometry$Polygon. - -![Fig. F6.4.4 A polygon buffer surrounding the city of Lima, Peru](F6/image46.png) - - -Next, Earth Engine feature collections (Fig. F6.4.5). - -building <- ee$FeatureCollection$Dataset$ - `GOOGLE_Research_open-buildings_v1_polygon` -Map$setCenter(3.389, 6.492, 17) -Map$addLayer(building) # eeObject is a ee$FeatureCollection - -![Fig. F6.4.5 Building footprints in Lagos, Nigeria](F6/image23.png) - - -The rgee functionality also supports the display of ee$ImageCollection via Map$addLayers (note the extra “s” at the end). Map$addLayers will use the same visualization parameters for all the images (Fig. F6.4.6). If you need different visualization parameters per image, use a Map$addLayer within a for loop. - -## Define a ImageCollection -etp <- ee$ImageCollection$Dataset$MODIS_NTSG_MOD16A2_105 %>% - ee$ImageCollection$select("ET") %>% - ee$ImageCollection$filterDate('2014-04-01', '2014-06-01') - -## Set viz paramsviz <- list( - min = 0, max = 300, - palette = cpt(pal = "grass_bcyr", rev = TRUE) -) - -## Print map results interactively -Map$setCenter(0, 0, 1) -etpmap <- Map$addLayers(etp, visParams = viz) -etpmap - -![Fig. F6.4.6 MOD16A2 total evapotranspiration values (kg/m^2/8day)](F6/image21.png) - - -Another useful rgee feature is the comparison operator (|), which creates a slider in the middle of the canvas, permitting quick comparison of two maps. For instance, load a Landsat 4 image: - -landsat <- ee$Image('LANDSAT/LT04/C01/T1/LT04_008067_19890917') - -Calculate the Normalized Difference Snow Index. - -ndsi <- landsat$normalizedDifference(c('B3', 'B5')) - -Define a constant value and use ee$Image$gte to return a binary image where pixels greater than or equal to that value are set as 1 and the rest are set as 0. Next, filter 0 values using ee$Image$updateMask. - -ndsiMasked <- ndsi$updateMask(ndsi$gte(0.4)) - -Define the visualization parameters. - -vizParams <- list( - bands <- c('B5', 'B4', 'B3'), # vector of three bands (R, G, B). min = 40, - max = 240, - gamma = c(0.95, 1.1, 1) # Gamma correction factor.) - -ndsiViz <- list( - min = 0.5, - max = 1, - palette = c('00FFFF', '0000FF') -) - -Center the map on the Huayhuash mountain range in Peru. - -Map$setCenter(lon = -77.20, lat = -9.85, zoom = 10) - -Finally, visualize both maps using the | operator (Fig. F6.4.7). - -m2 <- Map$addLayer(ndsiMasked, ndsiViz, 'NDSI masked') -m1 <- Map$addLayer(landsat, vizParams, 'false color composite') -m2 | m1 - -![Fig. F6.4.7 False-color composite over the Huayhuash mountain range, Peru](F6/image35.png) - - -:::{.callout-note} -Code Checkpoint F64d. The book’s repository contains information about what your code should look like at this point. -::: -### Integrating rgee with Other Python Packages - -As noted in Sect. 1, rgee set up a Python environment with NumPy and earthengine-api in your system. However, there is no need to limit it to just two Python packages. In this section, you will learn how to use the Python package ndvi2gif to perform a Normalized Difference Vegetation Index (NDVI) multi-seasonal analysis in the Ocoña Valley without leaving R. - -Whenever you want to install a Python package, you must run the following. - -library(rgee) -library(reticulate) -ee_Initialize() - -The ee_Initialize function not only authenticates your Earth Engine account but also helps reticulate to set up a Python environment compatible with rgee. After running ee_Initialize, use reticulate::install_python to install the desired Python package. - -py_install("ndvi2gif") - -The previous procedure is needed just once for each Python environment. Once installed, we simply load the package using reticulate::import. - -ngif <- import("ndvi2gif") - -Then, we define our study area using ee$Geometry$Rectangle (Fig. F6.4.8), and use the leaflet layers control to switch between basemaps. - -colca <- c(-73.15315, -16.46289, -73.07465, -16.37857) -roi <- ee$Geometry$Rectangle(colca) -Map$centerObject(roi) -Map$addLayer(roi) - -![Fig. F6.4.8 A rectangle drawn over the Ocoña Valley, Peru](F6/image59.png) - - -In ndvi2gif, there is just one class: NdviSeasonality. It has the following four public methods. - -* get_export: Exports NDVI year composites in .GeoTIFF format to your local folder. -* get_export_single: Exports single composite as .GeoTIFF to your local folder. -* get_year_composite: Returns the NDVI composites for each year. -* get_gif: Exports NDVI year composites as a .gif to your local folder. - -To run, the NdviSeasonality constructor needs to define the following arguments. - -* roi: the region of interest -* start_year: the initial year to start to create yearly composites -* end_year: the end year to look for -* sat: the satellite sensor -* key: the aggregation rule that will be used to generate the yearly composite - -For each year, the get_year_composite method generates an NDVI ee$Image with four bands, one band per season. Color combination between images and bands will allow you to interpret the vegetation phenology over the seasons and years. In ndvi2gif, the seasons are defined as follows. - -* winter = c('-01-01', '-03-31') -* spring = c('-04-01', '-06-30') -* summer = c('-07-01', '-09-30') -* autumn = c('-10-01', '-12-31') - -myclass <- ngif$NdviSeasonality( - roi = roi, - start_year = 2016L, - end_year = 2020L, - sat = 'Sentinel', # 'Sentinel', 'Landsat', 'MODIS', 'sar' key = 'max' # 'max', 'median', 'perc_90' -) - -## Estimate the median of the yearly composites from 2016 to 2020. -median <- myclass$get_year_composite()$median() - -## Estimate the median of the winter season composites from 2016 to 2020. -wintermax <- myclass$get_year_composite()$select('winter')$max() - -We can display maps interactively using the Map$addLayer (Fig. F6.4.9), and use the leaflet layers control to switch between basemaps. - -Map$addLayer(wintermax, list(min = 0.1, max = 0.8), 'winterMax') | -Map$addLayer(median, list(min = 0.1, max = 0.8), 'median') - -![Fig. F6.4.9 Comparison between the maximum historic winter NDVI and the mean historic NDVI. Colors represent the season when the maximum value occurred.](F6/image24.png) - - -And we can export the results to a GIF format. - -myclass$get_gif() - -To get more information about the ndvi2gif package, visit its [GitHub](https://www.google.com/url?q=https://github.com/Digdgeo/Ndvi2Gif&sa=D&source=editors&ust=1671458841429620&usg=AOvVaw0cUiJ9wlrQB8a2-Whxs0zA) repository. - -:::{.callout-note} -Code Checkpoint F64e. The book’s repository contains information about what your code should look like at this point. -::: -### Converting JavaScript Modules to R - -In recent years, the Earth Engine community has developed a lot of valuable third-party modules. Some incredible ones are geeSharp (Zuspan 2020), ee-palettes (Donchyts et al. 2020), spectral (Montero 2021), and LandsatLST (Ermida et al. 2020). While some of these modules have been implemented in Python and JavaScript (e.g., geeSharp and spectral), most are available only for JavaScript. This is a critical drawback, because it divides the Earth Engine community by programming languages. For example, if an R user wants to use tagee (Safanelli et al. 2020), the user will have to first translate the entire module to R. - -In order to close this breach, the ee_extra Python package has been developed to unify the Earth Engine community. The philosophy behind ee_extra is that all of its extended functions, classes, and methods must be functional for the JavaScript, Julia, R, and Python client libraries. Currently, ee_extra is the base of the rgeeExtra (Aybar et al. 2021) and eemont (Montero 2021) packages. - -To demonstrate the potential of ee_extra, let’s study an example from the Landsat Land Surface Temperature (LST) JavaScript module. The Landsat LST module computes the land surface temperature for Landsat products (Ermida et al. 2020). First we will run it in the Earth Engine Code Editor; then we will replicate those results in R. - -First, JavaScript. In a new script in the Code Editor, we must require the Landsat LST module. - -var LandsatLST = require( 'users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js'); - -The Landsat LST module contains a function named collection. This function receives the following parameters. - -* The Landsat archive ID -* The starting date of the Landsat collection -* The ending date of the Landsat collection -* The region of interest as geometry -* A Boolean parameter specifying if we want to use the NDVI for computing a dynamic emissivity instead of using the emissivity from ASTER - -In the following code block, we are going to define all required parameters. - -var geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4]); -var satellite = 'L8'; -var date_start = '2018-05-15'; -var date_end = '2018-05-31'; -var use_ndvi = true; - -Now, with all our parameters defined, we can compute the land surface temperature by using the collection method from Landsat LST. - -var LandsatColl = LandsatLST.collection(satellite, date_start, - date_end, geometry, use_ndvi); - -The result is stored as an ImageCollection in the LandsatColl variable. Now select the first element of the collection as an example by using the first method. - -var exImage = LandsatColl.first(); - -This example image is now stored in a variable named 'exImage'. Let’s display the LST result on the Map. For visualization purposes, we’ll define a color palette. - -var cmap = ['blue', 'cyan', 'green', 'yellow', 'red']; - -Then, we’ll center the map in the region of interest. - -Map.centerObject(geometry); - -Finally, let’s display the LST with the cmap color palette by using the Map.addLayer method (Fig. F6.4.10). This method receives the image to visualize, the visualization parameters, the color palette, and the name of the layer to show in the layer control. The visualization parameters will be: - -* min: 290 (a minimum LST value of 290 K) -* max: 320 (a maximum LST value of 320 K) -* palette: cmap (the color palette that was created some steps before) - -The name of the layer in the Map layer set will be LST. - -Map.addLayer(exImage.select('LST'), { - min: 290, - max: 320, - palette: cmap -}, 'LST') - -![Fig. F6.4.10 A map illustrating LST, obtained by following the JavaScript example](F6/image45.png) - - -:::{.callout-note} -Code Checkpoint F64f. The book’s repository contains a script that shows what your code should look like at this point. -::: -Now, let’s use R to implement the same logic. As in the previous sections, import the R packages: rgee and rgeeExtra. Then, initialize your Earth Engine session. - -library(rgee) -library(rgeeExtra) -library(reticulate) - -ee_Initialize() - -Install rgeeExtra Python dependencies. - -py_install(packages = c("regex", "ee_extra", "jsbeautifier")) - -Using the function rgeeExtra::module loads the JavaScript module. - -LandsatLST <- module("users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js") - -The rest of the code is exactly the same as in JavaScript. - -geometry <- ee$Geometry$Rectangle(c(-8.91, 40.0, -8.3, 40.4)) -satellite <- 'L8'date_start <- '2018-05-15'date_end <- '2018-05-31'use_ndvi <- TRUE - -LandsatColl <- LandsatLST$collection(satellite, date_start, date_end, geometry, use_ndvi) -exImage <- LandsatColl$first() -cmap <- c('blue', 'cyan', 'green', 'yellow', 'red') - -lmod <- list(min = 290, max = 320, palette = cmap) -Map$centerObject(geometry) -Map$addLayer(exImage$select('LST'), lmod, 'LST') - -![Fig. F6.4.11 A map illustrating LST, obtained by following the R example](F6/image7.png) - - -:::{.callout-note} -Code Checkpoint F64g. The book’s repository contains information about what your code should look like at this point. -::: -Question 1. When and why might users prefer to use R instead of Python to connect to Earth Engine? - -Question 2. What are the advantages and disadvantages of using rgee instead of the Earth Engine JavaScript Code Editor? - -### Conclusion {.unnumbered} - -In this chapter, you learned how to use Earth Engine and R in the same workflow. Since rgee uses reticulate, rgee also permits integration with third-party Earth Engine Python packages. You also learned how to use Map$addLayer, which works similarly to the Earth Engine User Interface API (Code Editor). Finally, we also introduced rgeeExtra, a new R package that extends the Earth Engine API and supports JavaScript module execution. - -### References {.unnumbered} - -Aybar C, Wu Q, Bautista L, et al (2020) rgee: An R package for interacting with Google Earth Engine. J Open Source Softw 5:2272. https://doi.org/10.21105/joss.02272 - -Ermida SL, Soares P, Mantas V, et al (2020) Google Earth Engine open-source code for land surface temperature estimation from the Landsat series. Remote Sens 12:1471. https://doi.org/10.3390/RS12091471 - -Grolemund G (2014) Hands-On Programming with R - Write Your Own Functions and Simulations. O’Reilly Media, Inc. - -Lovelace R, Nowosad J, Muenchow J (2019) Geocomputation with R. Chapman and Hall/CRC - -Montero D (2021) eemont: A Python package that extends Google Earth Engine. J Open Source Softw 6:3168. https://doi.org/10.21105/joss.03168 - -Pebesma E, Bivand R (2019) Spatial Data Science. https://r-spatial.org/book/ - diff --git a/_quarto.yml b/_quarto.yml index f6c579e..85103ae 100644 --- a/_quarto.yml +++ b/_quarto.yml @@ -2,22 +2,24 @@ project: type: book output-dir: docs + book: - title: "Google Earth Engine for OSINT" + title: "Remote Sensing \n for OSINT" author: "[Dr. Ollie Ballinger](https://oballinger.github.io)" - date: "10/6/2022" + date: "03/15/2023" chapters: - - index.qmd - - part: "Learning" + - part: "A. Introduction" chapters: + - index.qmd - ch1.qmd - ch2.qmd + - part: "B. Google Earth Engine" + chapters: - F1.qmd - F2.qmd - F4.qmd - F5.qmd - - F6.qmd - - part: "Case Studies" + - part: "C. Case Studies" chapters: - lights.qmd - refineries.qmd @@ -32,6 +34,8 @@ book: favicon: favicon.ico sidebar: logo: logo_white.png + collapse-level: 1 + bibliography: references.bib @@ -44,9 +48,13 @@ format: code-copy: true code-overflow: wrap highlight-style: monokai.theme - linkcolor: "#34a832" + linkcolor: "#34a832" pdf: documentclass: scrreprt + header-includes: + - \makeatletter + - \@addtoreset{chapter}{part} + - \makeatother epub: cover-image: cover.png diff --git a/ch1.qmd b/ch1.qmd index 72fce64..6a05207 100644 --- a/ch1.qmd +++ b/ch1.qmd @@ -1,4 +1,4 @@ -# Remote Sensing +# Remote Sensing {.unnumbered} Before learning how to load, process, and analyze satellite imagery in Google Earth Engine, it will be helpful to know a few basic principles of remote sensing. This section provides a brief overview of some important concepts and terminology that will be used throughout the course, including active and passive sensors; spatial, spectral, and temporal resolution; and orbits. @@ -13,11 +13,10 @@ While most satellite imagery is optical, meaning it captures sunlight reflected ## Resolution -Resolution is one of the most important attributes of satellite imagery. - -here are three types of resolution: spatial, spectral, and temporal. +Resolution is one of the most important attributes of satellite imagery. There are three types of resolution: spatial, spectral, and temporal. Let's look at each of these. ### Spatial Resolution + Spatial resolution governs how "sharp" an image looks. The Google Maps satellite basemap, for example, is really sharp Most of the optical imagery that is freely available has relatively low spatial resolution (it looks more grainy than, for example, the Google satellite basemap), @@ -27,43 +26,44 @@ Most of the optical imagery that is freely available has relatively low spatial ### Spectral Resolution -What open source imagery lacks in spatial resolution it often makes up for with *spectral* resolution. Really sharp imagery from MAXAR, for example, collects +What open access imagery lacks in spatial resolution it often makes up for with *spectral* resolution. Really sharp imagery from MAXAR, for example, mostly collects light in the visible light spectrum, which is what our eyes can see. But there are other parts of the electromagnetic spectrum that we can't see, but which can be very useful for distinguishing between different materials. Many satellites that have a lower spatial resolution than MAXAR, such as Landsat and Sentinel-2, collect data in a wider range of the electromagnetic spectrum. -Different materials reflect light differently. An apple absorbs shorter wavelengths (e.g. blue and green), and reflects longer wavelengths (red). Our eyes use that information-- the color-- to distinguish between different objects. But our eyes can only see a relatively small sliver of the electromagnetic spectrum covering blue, yellow, and red; we can't see UV or infrared wavelengths, for example, though the extent to which different materials reflect or absorb these wavelengths is just as useful for distinguishing between them. For example, Astroturf (fake plastic grass) and real grass will both look green to us, espeically from a satellite image. But living plants absorb radiation from the sun in a part of the light spectrum that we can't see. There's a spectral index called the Normalized Difference Vegetation Index (NDVI) which exploits this fact to isolate vegetation in multispectral satellite imagery. So if we look at [Gilette Stadium](https://en.wikipedia.org/wiki/Gillette_Stadium) near Boston, we can tell that the three training fields south of the stadium are real grass (they generate high NDVI values, showing up red), while the pitch in the stadium itself is astroturf (generating low NDVI values, showing up blue). - -![VHR image of Gilette Stadium with Sentinel-2 derived NDVI overlay](images/NDVI.jpg) - -In other words, even though these fields are all green and indistinguishable to the human eye, their *spectral profiles* beyond the visible light spectrum differ, and we can use this information to distinguish between them. Below is a plot of the spectral profiles of different materials, including oil. +Different materials reflect light differently. An apple absorbs shorter wavelengths (e.g. blue and green), and reflects longer wavelengths (red). Our eyes use that information-- the color-- to distinguish between different objects. Below is a plot of the spectral profiles of different materials: -The European Space Agency's Sentinel-2 satellite collects spectral information well beyond the visible light spectrum, enabling this sort of analysis. It chops the electromagnetic spectrum up into "bands", and measures how strongly wavelengths in each of those bands is reflected: +The visible portion of the spectrum is highlighted on the left, ranging from 400nm (violet) to 700nm (red). Our eyes (and satellite imagery in the visible light spectrum) can only see this portion of the light spectrum; we can't see UV or infrared wavelengths, for example, though the extent to which different materials reflect or absorb these wavelengths is just as useful for distinguishing between them. The European Space Agency's Sentinel-2 satellite collects spectral information well beyond the visible light spectrum, enabling this sort of analysis. It chops the electromagnetic spectrum up into "bands", and measures how strongly wavelengths in each of those bands is reflected: ![](images/S2_bands.png) -We'll be using this satellite to distinguish between oil and other materials, similar to the way we were able to distinguish between real and fake grass at Gilette Stadium. First, we'll have to do a bit of pre-processing on the Sentinel-2 imagery after which we'll train a machine learning model to identify oil. +To illustrate why this is important, consider Astroturf (fake plastic grass). Astroturf and real grass will both look green to us, espeically from a satellite image. But living plants strongly reflect radiation from the sun in a part of the light spectrum that we can't see (near-infrared). There's a spectral index called the Normalized Difference Vegetation Index (NDVI) which exploits this fact to isolate vegetation in multispectral satellite imagery. So if we look at [Gilette Stadium](https://en.wikipedia.org/wiki/Gillette_Stadium) near Boston, we can tell that the three training fields south of the stadium are real grass (they generate high NDVI values, showing up red), while the pitch in the stadium itself is astroturf (generating low NDVI values, showing up blue). + +![VHR image of Gilette Stadium with Sentinel-2 derived NDVI overlay](images/NDVI.jpg) + +In other words, even though these fields are all green and indistinguishable to the human eye, their *spectral profiles* beyond the visible light spectrum differ, and we can use this information to distinguish between them. + +Astroturf is a trivial example. But suppose we were interested in identifying makeshift oil refineries in Northern Syria that constitute a key source of rents for whichever group controls them. As demonstrated in the ['Refinery Identification'](refineries.qmd) case study, we can train an algorithm to identify the spectral signatures of oil, and use that to automatically detect them in satellite imagery. + ### Temporal Resolution -Finally, the frequency with which we -There is often a tradeoff between spatial and temporal resolution. +Finally, the frequency with which we can access new imagery is an important consideration. This is called the **temporal resolution**. The Google Maps basemap is very high resolution, available globally, and is freely available. But it has no *temporal* dimension: it's a snapshot from one particular point in time. If the thing we're interested in involves *changes* over time, this basemap will be of limited use. -The **"revisit rate"** is the amount of time it takes for the satellite to pass over the same location twice. The revisit rate is inversely proportional to the satellite's altitude: the higher the satellite is, the more frequently it can pass over the same location. This generally means that there's a tradeoff between spatial resolution and temporal resolution: the higher the spatial resolution, the lower the revisit rate. However, some satellite constellations such as Planet's SkySat are able to achieve both high spatial and temporal resolution by launching lots of small satellites into orbit at once. Below is a comparison of revisit rates for various satellites: +The **"revisit rate"** is the amount of time it takes for the satellite to pass over the same location twice. For example, the Sentinel-2 constellation's two satellites can achieve a revisit rate of 5 days, as shown in this cool video from the European Space Agency: -* [Sentinel 1](https://sentinels.copernicus.eu/web/sentinel/user-guides/sentinel-1-sar/revisit-and-coverage): 3 days (6 days as of 23/12/21, since Sentinel-1B was decomisioned) -* [Sentinel 2](https://sentinel.esa.int/web/sentinel/missions/sentinel-2): 5 days -* [Landsat 8-9](https://landsat.gsfc.nasa.gov/satellites/landsat-9/#:~:text=Landsat%209%20replaces%20Landsat%207,for%20Landsat%208%20%2B%20Landsat%207.): 8 days -* [Planet SkySat](https://www.planet.com/pulse/12x-rapid-revisit-announcement/): 2-3 hours +{{< video https://dlmultimedia.esa.int/download/public/videos/2016/08/004/1608_004_AR_EN.mp4 >}} +Some satellite constellations are able to achieve much higher revisit rates. Sentinel-2 has a revisit rate of 5 days, but SkySat capable of imaging the same point on earth around 12 times per day! How is that possible? Well, as the video above demonstrated, the Sentinel-2 constellation is composed of two satellites that share the same orbit, 180 degrees apart. In contrast, the SkySat constellation comprises 21 satellites, each with its own orbital path: + +{{< video https://assets.planet.com/products/hi-res/Planet_Block_3_HD_1080p.mp4 >}} -## Orbits +This allows SkySat to achieve a revisit rate of 2-3 *hours*. The catch, however, is that you need to pay for it (and it [ain't cheap](https://apollomapping.com/blog/an-update-on-skysat-tasking-pricing-and-video-capabilities)). Below is a comparison of revisit rates for various other optical satellites: -The Landsat satellites are in a sun-synchronous orbit, meaning they pass over the same spot on Earth at the same time every day. The Sentinel satellites are in a polar orbit, meaning they pass over the same spot on Earth twice a day, once in the morning and once in the afternoon. NASA have created a great [visualisation](https://svs.gsfc.nasa.gov/4745) showing the orbits of the Landsat and Sentinel-2 satellites: +![A chart of revisit times for different satellites from [Sutlieff et. al.(2021)](https://link.springer.com/article/10.1007/s10712-021-09637-5)](images/revisit_chart.png) -{{< video https://svs.gsfc.nasa.gov/vis/a000000/a004700/a004745/landsat_w_sentinel_ls8ls9sAsB_fade_1080p60.mp4 >}} - -The Sentinel satellites are in a lower orbit than Landsat, meaning they are closer to the Earth and have a higher resolution. +## Summary +You should hopefully have a better understanding of what satellite imagery is, and how it can be used to answer questions about the world. In the [next section](ch2.qmd), we'll look at the various types of satellite imagery stored in the Google Earth Engine catalogue. diff --git a/ch2.qmd b/ch2.qmd index 2bda119..8130874 100644 --- a/ch2.qmd +++ b/ch2.qmd @@ -1,13 +1,12 @@ ---- -title: "Data Acquisition" ---- +# Data Acquisition {.unnumbered} + One of the main advantages of GEE is that it hosts several Petabytes of satellite imagery and other spatial data sets, [all in one place](https://developers.google.com/earth-engine/datasets). Among these are a many that could prove useful to those investigating illegal mining and logging, estimating conflict-induced damage, monitoring pollution from extractive industries, conducting maritime surveillance without relying on ship transponders, verifying the locations of artillery strikes, tracking missile defense systems, and many other topics. This section highlights ten categories of geospatial data available natively in the GEE catalogue ranging from optical satellite imagery, to atmospheric data, to building footprints. Each sub-section provides an overview of the given data type, suggests potential applications, and lists the corresponding datasets in the GEE catalogue. The datasets listed under each heading are **not** an exhaustive list-- there are over 500 in the whole catalogue, and the ones listed in this section are simply the ones with the most immediate relevance to open source investigations. If a particular geospatial dataset you want to work with isn't hosted in the GEE catalog, you can upload your own data. We'll cover that in the next section. ## Optical Imagery -![Sentinel-2 timelapse showing the ancient city of Hasankeyf being flooded following the construction of a dam by the Turkish government.](./images/hasankeyf.gif) +![Automatic detection of vehicles using artificial intelligence in high resolution optical imagery. See the [object detection](object_detection.qmd) tutorial.](./images/obj_det3.jpg) Optical satellite imagery is the bread and butter of many open source investiagtions. It would be tough to list off all of the possible use cases, so here's a handy flowchart: @@ -108,7 +107,9 @@ The timelapse above reveals a number of interesting things: The capture of Mosul ## Climate and Atmospheric Data -![Sulphur Dioxide plume resulting from ISIS attack on the Al-Mishraq Sulphur Plant in Iraq](./images/mishraq_small.gif) + + +![Sulphur Dioxide plume resulting from ISIS attack on the Al-Mishraq Sulphur Plant in Iraq](./images/mishraq_small.gif){width=100%} Climate and atmospheric data can be used to track the effects of conflict on the environment. The European Space Agency's Sentinel-5p satellites measure the concentration of a number of atmospheric gases, including nitrogen dioxide, methane, and ozone. Measurements are available on a daily basis at a fairly high resolution (1km), allowing for the detection of localized sources of pollution such as oil refineries or power plants. For example, see this [Bellingcat article](https://www.bellingcat.com/resources/2021/04/15/what-oil-satellite-technology-and-iraq-can-tell-us-about-pollution/) in which Wim Zwijnenburg and I trace pollution to specific facilities operated by multinational oil companies in Iraq. diff --git a/ch4.qmd b/ch4.qmd deleted file mode 100644 index f43ebc9..0000000 --- a/ch4.qmd +++ /dev/null @@ -1 +0,0 @@ -# Application Development \ No newline at end of file diff --git a/ch5.qmd b/ch5.qmd deleted file mode 100644 index dd608ca..0000000 --- a/ch5.qmd +++ /dev/null @@ -1 +0,0 @@ -# Case Studies \ No newline at end of file diff --git a/docs/F1.html b/docs/F1.html index be19067..3581a62 100644 --- a/docs/F1.html +++ b/docs/F1.html @@ -7,7 +7,7 @@ -Google Earth Engine for OSINT - 3  Getting Started +Remote Sensing for OSINT - 1  Getting Started - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- -
- -
- - - - - -
- -
-
-

7  Advanced Topics

-
- - - -
- - - - -
- - -
- -

Although you now know the most basic fundamentals of Earth Engine, there is still much more that can be done. The Part presents some advanced topics that can help expand your skill set for doing larger and more complex projects. These include tools for sharing code among users, scaling up with efficient project design, creating apps for non-expert users, and combining R with other information processing platforms.

-
-

7.1 Advanced Raster Visualization

-
-
-
- -
-
-Chapter Information -
-
-
-
-

Author

-

Gennadii Donchyts, Fedor Baart

-
-
-

Overview

-

This chapter should help users of Earth Engine to better understand raster data by applying visualization algorithms such as hillshading, hill shadows, and custom colormaps. We will also learn how image collection datasets can be explored by animating them as well as by annotating with text labels, using, for example, attributes of images or values queried from images.

-
-
-

Learning Outcomes

-
    -
  • Understanding why perceptually uniform colormaps are better to present data and using them efficiently for raster visualization.
  • -
  • Using palettes with images before and after remapping values.
  • -
  • Adding text annotations when visualizing images or features.
  • -
  • Animating image collections in multiple ways (animated GIFs, exporting video clips, interactive animations with UI controls).
  • -
  • Adding hillshading and shadows to help visualize raster datasets.
  • -
-
-
-

Assumes you know how to:

-
    -
  • Import images and image collections, filter, and visualize (Part F1).
  • -
  • Write a function and map it over an ImageCollection (Chap. F4.0).
  • -
  • Inspect an Image and an ImageCollection, as well as their properties (Chap. F4.1).
  • -
-
-
-
-
-

Introduction

-

Visualization is the step to transform data into a visual representation. You make a visualization as soon as you add your first layer to your map in Google Earth Engine. Sometimes you just want to have a first look at a dataset during the exploration phase. But as you move towards the dissemination phase, where you want to spread your results, it is good to think about a more structured approach to visualization. A typical workflow for creating visualization consists of the following steps:

-
    -
  • Defining the story (what is the message?)
  • -
  • Finding inspiration (for example by making a moodboard)
  • -
  • Choosing a canvas/medium (here, this is the Earth Engine map canvas)
  • -
  • Choosing datasets (co-visualized or combined using derived indicators)
  • -
  • Data preparation (interpolating in time and space, filtering/mapping/reducing)
  • -
  • Converting data into visual elements (shape and color)
  • -
  • Adding annotations and interactivity (labels, scales, legend, zoom, time slider)
  • -
-

A good standard work on all the choices that one can make while creating a visualization is provided by the Grammar of Graphics (GoG) by Wilkinson (1999). It was the inspiration behind many modern visualization libraries (ggplot, vega). The main concept is that you can subdivide your visualization into several aspects.

-

In this chapter, we will cover several aspects mentioned in the Grammar of Graphics to convert (raster) data into visual elements. The accurate representation of data is essential in science communication. However, color maps that visually distort data through uneven color gradients or are unreadable to those with color-vision deficiency remain prevalent in science (Crameri, 2020). You will also learn how to add annotation text and symbology, while improving your visualizations by mixing images with hillshading as you explore some of the amazing datasets that have been collected in recent years in Earth Engine.

-
-
-

7.1.1 Palettes

-

In this section we will explore examples of colormaps to visualize raster data. Colormaps translate values to colors for display on a map. This requires a set of colors (referred to as a “palette” in Earth Engine) and a range of values to map (specified by the min and max values in the visualization parameters).

-

There are multiple types of colormaps, each used for a different purpose. These include the following:

-

Sequential: These are probably the most commonly used colormaps, and are useful for ordinal, interval, and ratio data. Also referred to as a linear colormap, a sequential colormap looks like the viridis colormap (Fig. F6.0.1) from matplotlib. It is popular because it is a perceptual uniform colormap, where an equal interval in values is mapped to an equal interval in the perceptual colorspace. If you have a ratio variable where zero means nothing, you can use a sequential colormap starting at white, transparent, or, when you have a black background, at black—for example, the turku colormap from Crameri (Fig. F6.0.1). You can use this for variables like population count or gross domestic product.

-

Diverging: This type of colormap is used for visualizing data where you have positive and negative values and where zero has a meaning. Later in this tutorial, we will use the balance colormap from the cmocean package (Fig. F6.0.1) to show temperature change.

-

Circular: Some variables are periodic, returning to the same value after a period of time. For example, the season, angle, and time of day are typically represented as circular variables. For variables like this, a circular colormap is designed to represent the first and last values with the same color. An example is the circular cet-c2 colormap (Fig. F6.0.1) from the colorcet package.

-

Semantic: Some colormaps do not map to arbitrary colors but choose colors that provide meaning. We refer to these as semantic colormaps. Later in this tutorial, we will use the ice colormap (Fig. F6.0.1) from the cmocean package for our ice example.

-
-
-

-

Fig. F6.0.1 Examples of colormaps from a variety of packages: viridis from matplotlib, turku from Crameri, balance from cmocean, cet-c2 from colorcet and ice from cmocean

-
-
-

Popular sources of colormaps include:

-
    -
  • cmocean (semantic perceptual uniform colormaps for geophysical applications)
  • -
  • colorcet (set of perceptual colormaps with varying colors and saturation)
  • -
  • cpt-city (comprehensive overview of colormaps,
  • -
  • colorbrewer (colormaps with variety of colors)
  • -
  • Crameri (stylish colormaps for dark and light themes)
  • -
-

Our first example in this section applies a diverging colormap to temperature.

-
// Load the ERA5 reanalysis monthly means.  
-var era5 = ee.ImageCollection('ECMWF/ERA5_LAND/MONTHLY');  
-  
-// Load the palettes package.  
-var palettes = require('users/gena/packages:palettes');  
-  
-// Select temperature near ground.  
-era5 = era5.select('temperature_2m');
-

Now we can visualize the data. Here we have a temperature difference. That means that zero has a special meaning. By using a divergent colormap we can give zero the color white, which denotes that there is no significant difference. Here we will use the colormap Balance from the cmocean package. The color red is associated with warmth, and the color blue is associated with cold. We will choose the minimum and maximum values for the palette to be symmetric around zero (-2, 2) so that white appears in the correct place. For comparison we also visualize the data with a simple [‘blue’, ‘white’, ‘red’] palette. As you can see (Fig. F6.0.2), the Balance colormap has a more elegant and professional feel to it, because it uses a perceptual uniform palette and both saturation and value.

-
// Choose a diverging colormap for anomalies.  
-var balancePalette = palettes.cmocean.Balance[7];  
-var threeColorPalette = ['blue', 'white', 'red'];  
-  
-// Show the palette in the Inspector window.  
-palettes.showPalette('temperature anomaly', balancePalette);  
-palettes.showPalette('temperature anomaly', threeColorPalette);  
-  
-// Select 2 time windows of 10 years.  
-var era5_1980 = era5.filterDate('1981-01-01', '1991-01-01').mean();  
-var era5_2010 = era5.filterDate('2011-01-01', '2020-01-01').mean();  
-  
-// Compute the temperature change.  
-var era5_diff = era5_2010.subtract(era5_1980);  
-  
-// Show it on the map.  
-Map.addLayer(era5_diff, {  
-   palette: threeColorPalette,  
-   min: -2,  
-   max: 2}, 'Blue White Red palette');  
-  
-Map.addLayer(era5_diff, {  
-   palette: balancePalette,  
-   min: -2,  
-   max: 2}, 'Balance palette');
-

Fig. F6.0.2 Temperature difference of ERA5 (2011–2020, 1981–1990) using the balance colormap from cmocean (right) versus a basic blue-white-red colormap (left)Fig. F6.0.2 Temperature difference of ERA5 (2011–2020, 1981–1990) using the balance colormap from cmocean (right) versus a basic blue-white-red colormap (left)

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60a. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Our second example in this section focuses on visualizing a region of the Antarctic, the Thwaites Glacier. This is one of the fast-flowing glaciers that causes concern because it loses so much mass that it causes the sea level to rise. If we want to visualize this region, we have a challenge. The Antarctic region is in the dark for four to five months each winter. That means that we can’t use optical images to see the ice flowing into the sea. We therefore will use radar images. Here we will use a semantic colormap to denote the meaning of the radar images.

-

Let’s start by importing the dataset of radar images. We will use the images from the Sentinel-1 constellation of the Copernicus program. This satellite uses a C-band synthetic-aperture radar and has near-polar coverage. The radar senses images using a polarity for the sender and receiver. The collection has images of four different possible combinations of sender/receiver polarity pairs. The image that we’ll use has a band of the Horizontal/Horizontal polarity (HH).

-
// An image of the Thwaites glacier.  
-var imageId ='COPERNICUS/S1_GRD/S1B_EW_GRDM_1SSH_20211216T041925_20211216T042029_030045_03965B_AF0A';  
-  
-// Look it up and select the HH band.  
-var img = ee.Image(imageId).select('HH');
-

For the next step, we will use the palette library. We will stylize the radar images to look like optical images, so that viewers can contrast ice and sea ice from water (Lhermitte, 2020). We will use the Ice colormap from the cmocean package (Thyng, 2016).

-
// Use the palette library.  
-var palettes = require('users/gena/packages:palettes');  
-  
-// Access the ice palette.  
-var icePalette = palettes.cmocean.Ice[7];  
-  
-// Show it in the console.  
-palettes.showPalette('Ice', icePalette);  
-  
-// Use  it to visualize the radar data.  
-Map.addLayer(img, {  
-   palette: icePalette,  
-   min: -15,  
-   max: 1}, 'Sentinel-1 radar');  
-  
-// Zoom to the grounding line of the Thwaites Glacier.  
-Map.centerObject(ee.Geometry.Point([-105.45882094907664, -   74.90419580705336]), 8);
-

If you zoom in (F6.0.3) you can see how long cracks have recently appeared near the pinning point (a peak in the bathymetry that functions as a buttress, see Wild, 2022) of the glacier.

-
-
-

-

Fig. F6.0.3. Ice observed in Antarctica by the Sentinel-1 satellite. The image is rendered using the ice color palette stretched to backscatter amplitude values [-15; 1].

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60b. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

7.1.2 Remapping and Palettes

-

Classified rasters in Earth Engine have metadata attached that can help with analysis and visualization. This includes lists of the names, values, and colors associated with class. These are used as the default color palette for drawing a classification, as seen next. The USGS National Land Cover Database (NLCD) is one such example. Let’s access the NLCD dataset, name it nlcd, and view it (Fig. F6.0.4) with its built-in palette.

-
// Advanced remapping using NLCD.  
-// Import NLCD.  
-var nlcd = ee.ImageCollection('USGS/NLCD_RELEASES/2016_REL');  
-  
-// Use Filter to select the 2016 dataset.  
-var nlcd2016 = nlcd.filter(ee.Filter.eq('system:index', '2016'))  
-   .first();  
-  
-// Select the land cover band.  
-var landcover = nlcd2016.select('landcover');  
-  
-// Map the NLCD land cover.  
-Map.addLayer(landcover, null, 'NLCD Landcover');
-
-
-

-

Fig. F6.0.4 The NLCD visualized with default colors for each class

-
-
-

But suppose you want to change the display palette. For example, you might want to have multiple classes displayed using the same color, or use different colors for some classes. Let’s try having all three urban classes display as dark red (‘ab0000’).

-
// Now suppose we want to change the color palette.  
-var newPalette = ['466b9f', 'd1def8', 'dec5c5',   'ab0000', 'ab0000', 'ab0000',   'b3ac9f', '68ab5f', '1c5f2c',   'b5c58f', 'af963c', 'ccb879',   'dfdfc2', 'd1d182', 'a3cc51',   '82ba9e', 'dcd939', 'ab6c28',   'b8d9eb', '6c9fb8'  
-];  
-  
-// Try mapping with the new color palette.  
-Map.addLayer(landcover, {  
-   palette: newPalette  
-}, 'NLCD New Palette');
-

However, if you map this, you will see an unexpected result (Fig. F6.0.5).

-
-
-

-

Fig. F6.0.5 Applying a new palette to a multi-class layer has some unexpected results

-
-
-

This is because the numeric codes for the different classes are not sequential. Thus, Earth Engine stretches the given palette across the whole range of values and produces an unexpected color palette. To fix this issue, we will create a new index for the class values so that they are sequential.

-
// Extract the class values and save them as a list.  
-var values = ee.List(landcover.get('landcover_class_values'));  
-  
-// Print the class values to console.  
-print('raw class values', values);  
-  
-// Determine the maximum index value  
-var maxIndex = values.size().subtract(1);  
-  
-// Create a new index for the remap  
-var indexes = ee.List.sequence(0, maxIndex);  
-  
-// Print the updated class values to console.  
-print('updated class values', indexes);  
-  
-// Remap NLCD and display it in the map.  
-var colorized = landcover.remap(values, indexes)  
-   .visualize({  
-       min: 0,  
-       max: maxIndex,  
-       palette: newPalette  
-   });  
-Map.addLayer(colorized, {}, 'NLCD Remapped Colors');
-

Using this remapping approach, we can properly visualize the new color palette (Fig. F6.0.6).

-
-
-

-

Fig. F6.0.6 Expected results of the new color palette. All urban areas are now correctly showing as dark red and the other land cover types remain their original color.

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60c. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

7.1.3 Annotations

-

Annotations are the way to visualize data on maps to provide additional information about raster values or any other data relevant to the context. In this case, this additional information is usually shown as geometries, text labels, diagrams, or other visual elements. Some annotations in Earth Engine can be added by making use of the ui portion of the Earth Engine API, resulting in graphical user interface elements such as labels or charts added on top of the map. However, it is frequently useful to render annotations as a part of images, such as by visualizing various image properties or to highlight specific areas.

-

In many cases, these annotations can be mixed with output images generated outside of Earth Engine, for example, by post-processing exported images using Python libraries or by annotating using GIS applications such as QGIS or ArcGIS. However, annotations could also be also very useful to highlight and/or label specific areas directly within the Code Editor. Earth Engine provides a sufficiently rich API to turn vector features and geometries into raster images which can serve as annotations. We recommend checking the ee.FeatureCollection.style function in the Earth Engine documentation to learn how geometries can be rendered.

-

For textual annotation, we will make use of an external package ‘users/gena/packages:text’ that provides a way to render strings into raster images directly using the Earth Engine raster API. It is beyond the scope of the current tutorials to explain the implementation of this package, but internally this package makes use of bitmap fonts which are ingested into Earth Engine as raster assets and are used to turn every character of a provided string into image glyphs, which are then translated to desired coordinates.

-

The API of the text package includes the following mandatory and optional arguments:

-

/**
-* Draws a string as a raster image at a given point.
-*
-* (param?) {string} str - string to draw
-* (param?) {ee.Geometry} point - location the the string will be drawn
-* (param?) {{string, Object}} options - optional properties used to style text
-*
-* The options dictionary may include one or more of the following:
-* fontSize - 16|18|24|32 - the size of the font (default: 16)
-* fontType - Arial|Consolas - the type of the font (default: Arial)
-* alignX - left|center|right (default: left)
-* alignY - top|center|bottom (default: top)
-* textColor - text color string (default: ffffff - white)
-* textOpacity - 0-1, opacity of the text (default: 0.9)
-* textWidth - width of the text (default: 1)
-* outlineColor - text outline color string (default: 000000 - black)
-* outlineOpacity - 0-1, opacity of the text outline (default: 0.4)
-* outlineWidth - width of the text outlines (default: 0)
-*/

-

To demonstrate how to use this API, let’s render a simple ‘Hello World!’ text string placed at the map center using default text parameters. The code for this will be:

-
// Include the text package.  
-var text = require('users/gena/packages:text');  
-  
-// Configure map (change center and map type).  
-Map.setCenter(0, 0, 10);  
-Map.setOptions('HYBRID');  
-  
-// Draw text string and add to map.  
-var pt = Map.getCenter();  
-var scale = Map.getScale();  
-var image = text.draw('Hello World!', pt, scale);  
-Map.addLayer(image);
-

Running the above script will generate a new image containing the ‘Hello World!’ string placed in the map center. Notice that before calling the text.draw() function we configure the map to be centered at specific coordinates (0,0) and zoom level 10 because map parameters such as center and scale are passed as arguments to that text.draw() function. This ensures that the resulting image containing string characters is scaled properly.

-

When exporting images containing rendered text strings, it is important to use proper scale to avoid distorted text strings that are difficult to read, depending on the selected font size, as shown in Fig. 6.0.7.

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60d. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()1; (left), 2x: var scale = Map.getScale()2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()1; (left), 2x: var scale = Map.getScale()2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)Fig. 6.0.7 Results of the text.draw call, scaled to 1x: var scale = Map.getScale()1; (left), 2x: var scale = Map.getScale()2; (center), and 0.5x: var scale = Map.getScale()*0.5; (right)

-

These artifacts can be avoided to some extent by specifying a larger font size (e.g., 32). However, it is better to render text at the native 1:1 scale to achieve best results. The same applies to the text color and outline: They may need to be adjusted to achieve the best result. Usually, text needs to be rendered using colors that have opposite brightness and colors when compared to the surrounding background. Notice that in the above example, the map was configured to have a dark background (‘HYBRID’) to ensure that the white text (default color) would be visible. Multiple parameters listed in the above API documentation can be used to adjust text rendering. For example, let’s switch font size, font type, text, and outline parameters to render the same string, as below. Replace the existing one-line text.draw call in your script with the following code, and then run it again to see the difference (Fig. F6.0.8):

-

var image = text.draw(‘Hello World!’, pt, scale, {
-fontSize: 32,
-fontType: ‘Consolas’,
-textColor: ‘black’,
-outlineColor: ‘white’,
-outlineWidth: 1,
-outlineOpacity: 0.8
-});

-
// Add the text image to the map.  
-Map.addLayer(image);
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60e. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

-

Fig. 6.0.8 Rendering text with adjusted parameters (font type: Consolas, fontSize: 32, textColor: ‘black’, outlineWidth: 1, outlineColor: ‘white’, outlineOpacity: 0.8)

-
-
-

Of course, non-optional parameters such as pt and scale, as well as the text string, do not have to be hard-coded in the script; instead, they can be acquired by the code using, for example, properties coming from a FeatureCollection. Let’s demonstrate this by showing the cloudiness of Landsat 8 images as text labels rendered in the center of every image. In addition to annotating every image with a cloudiness text string, we will also draw yellow outlines to indicate image boundaries. For convenience, we can also define the code to annotate an image as a function. We will then map that function (as described in Chap. F4.0) over the filtered ImageCollection. The code is as follows:

-

var text = require(‘users/gena/packages:text’);

-

var geometry = ee.Geometry.Polygon(
-[
-[
-[-109.248, 43.3913],
-[-109.248, 33.2689],
-[-86.5283, 33.2689],
-[-86.5283, 43.3913]
-]
-], null, false);

-

Map.centerObject(geometry, 6);

-

function annotate(image) { // Annotates an image by adding outline border and cloudiness // Cloudiness is shown as a text string rendered at the image center. // Add an edge around the image. var edge = ee.FeatureCollection([image])
-.style({
-color: ‘cccc00cc’,
-fillColor: ‘00000000’ }); // Draw cloudiness as text. var props = {
-textColor: ‘0000aa’,
-outlineColor: ‘ffffff’,
-outlineWidth: 2,
-outlineOpacity: 0.6,
-fontSize: 24,
-fontType: ‘Consolas’ }; var center = image.geometry().centroid(1); var str = ee.Number(image.get(‘CLOUD_COVER’)).format(‘%.2f’); var scale = Map.getScale(); var textCloudiness = text.draw(str, center, scale, props); // Shift left 25 pixels. textCloudiness = textCloudiness
-.translate(-scale * 25, 0, ‘meters’, ‘EPSG:3857’); // Merge results. return ee.ImageCollection([edge, textCloudiness]).mosaic();
-}

-
// Select images.  
-var images = ee.ImageCollection('LANDSAT/LC08/C02/T1_RT_TOA')  
-   .select([5, 4, 2])  
-   .filterBounds(geometry)  
-   .filterDate('2018-01-01', '2018-01-7');  
-  
-// dim background.  
-Map.addLayer(ee.Image(1), {  
-   palette: ['black']  
-}, 'black', true, 0.5);  
-  
-// Show images.  
-Map.addLayer(images, {  
-   min: 0.05,  
-   max: 1,  
-   gamma: 1.4}, 'images');  
-  
-// Show annotations.  
-var labels = images.map(annotate);  
-var labelsLayer = ui.Map.Layer(labels, {}, 'annotations');  
-Map.layers().add(labelsLayer);
-

The result of defining and mapping this function over the filtered set of images is shown in Fig. F6.0.9. Notice that by adding an outline around the text, we can ensure the text is visible for both dark and light images. Earth Engine requires casting properties to their corresponding value type, which is why we’ve used ee.Number (as described in Chap. F1.0) before generating a formatted string. Also, we have shifted the resulting text image 25 pixels to the left. This was necessary to ensure that the text is positioned properly. In more complex text rendering applications, users may be required to compute the text position in a different way using ee.Geometry calls from the Earth Engine API: for example, by positioning text labels somewhere near the corners.

-
-
-

-

Fig. F6.0.9 Annotating Landsat 8 images with image boundaries, border, and text strings indicating cloudiness

-
-
-

Because we render text labels using the Earth Engine raster API, they are not automatically scaled depending on map zoom size. This may cause unwanted artifacts; To avoid that, the text labels image needs to be updated every time the map zoom changes. To implement this in a script, we can make use of the Map API—in particular, the Map.onChangeZoom event handler. The following code snippet shows how the image containing text annotations can be re-rendered every time the map zoom changes. Add it to the end of your script.

-
// re-render (rescale) annotations when map zoom changes.  
-Map.onChangeZoom(function(zoom) {  
-   labelsLayer.setEeObject(images.map(annotate));  
-});
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60f. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Try commenting that event handler and observe how annotation rendering changes when you zoom in or zoom out.

-
-
-

7.1.4 Animations

-

Visualizing raster images as animations is a useful technique to explore changes in time-dependent datasets, but also, to render short animations to communicate how changing various parameters affects the resulting image—for example, varying thresholds of spectral indices resulting in different binary maps or the changing geometry of vector features.

-

Animations are very useful when exploring satellite imagery, as they allow viewers to quickly comprehend dynamics of changes of earth surface or atmospheric properties. Animations can also help to decide what steps should be taken next to designing a robust algorithm to extract useful information from satellite image time series. Earth Engine provides two standard ways to generate animations: as animated GIFs, and as AVI video clips. Animation can also be rendered from a sequence of images exported from Earth Engine, using numerous tools such as ffmpeg or moviepy. However, in many cases it is useful to have a way to quickly explore image collections as animation without requiring extra steps.

-

In this section, we will generate animations in three different ways:

-
    -
  1. Generate animated GIF
  2. -
  3. Export video as an AVI file to Google Drive
  4. -
  5. Animate image collection interactively using UI controls and map layers
  6. -
-

We will use an image collection showing sea ice as an input dataset to generate animations with visualization parameters from earlier. However, instead of querying a single Sentinel-1 image, let’s generate a filtered image collection with all images intersecting with our area of interest. After importing some packages and palettes and defining a point and rectangle, we’ll build the image collection. Here we will use point geometry to define the location where the image date label will be rendered and the rectangle geometry to indicate the area of interest for the animation. To do this we will build the following logic in a new script. Open a new script and paste the following code into it:

-
// Include packages.  
-var palettes = require('users/gena/packages:palettes');  
-var text = require('users/gena/packages:text');  
-  
-var point = /* color: #98ff00 */ ee.Geometry.Point([-   106.15944300895228, -74.58262940096245  
-]);  
-  
-var rect = /* color: #d63000 */   ee.Geometry.Polygon(  
-       [  
-           [  
-               [-106.19789515738981, -74.56509549360152],  
-               [-106.19789515738981, -74.78071448733921],  
-               [-104.98115931754606, -74.78071448733921],  
-               [-104.98115931754606, -74.56509549360152]  
-           ]  
-       ], null, false);  
-  
-// Lookup the ice palette.  
-var palette = palettes.cmocean.Ice[7];  
-  
-// Show it in the console.  
-palettes.showPalette('Ice', palette);  
-  
-// Center map on geometry.  
-Map.centerObject(point, 9);  
-  
-// Select S1 images for the Thwaites glacier.  
-var images = ee.ImageCollection('COPERNICUS/S1_GRD')  
-   .filterBounds(rect)  
-   .filterDate('2021-01-01', '2021-03-01')  
-   .select('HH')   // Make sure we include only images which fully contain the region geometry.   .filter(ee.Filter.isContained({  
-       leftValue: rect,  
-       rightField: '.geo'   }))  
-   .sort('system:time_start');  
-  
-// Print number of images.  
-print(images.size());
-

As you see from the last last lines of the above code, it is frequently useful to print the number of images in an image collection: an example of what’s often known as a “sanity check.”

-

Here we have used two custom geometries to configure animations: the green pin named point, used to filter image collection and to position text labels drawn on top of the image, and the blue rectangle rect, used to define a bounding box for the exported animations. To make sure that the point and rectangle geometries are shown under the Geometry Imports in the Code Editor, you need to click on these variables in the code and then select the Convert link.

-

Notice that in addition to the bounds and date filter, we have also used a less known isContained filter to ensure that we get only images that fully cover our region. To better understand this filter, you could try commenting out the filter and compare the differences, observing images with empty (masked) pixels in the resulting image collection.

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60g. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Next, to simplify the animation API calls, we will generate a composite RGB image collection out of satellite images and draw the image’s acquisition date as a label on every image, positioned within our region geometry.

-
// Render images.  
-var vis = {  
-   palette: palette,  
-   min: -15,  
-   max: 1  
-};  
-  
-var scale = Map.getScale();  
-var textProperties = {  
-   outlineColor: '000000',  
-   outlineWidth: 3,  
-   outlineOpacity: 0.6  
-};  
-  
-var imagesRgb = images.map(function(i) {   // Use the date as the label.   var label = i.date().format('YYYY-MM-dd');   var labelImage = text.draw(label, point, scale,  
-       textProperties);   return i.visualize(vis)  
-       .blend(labelImage) // Blend label image on top.       .set({  
-           label: label  
-       }); // Keep the text property.  
-});  
-Map.addLayer(imagesRgb.first());  
-Map.addLayer(rect, {color:'blue'}, 'rect', 1, 0.5);
-

In addition to printing the size of the ImageCollection, we also often begin by adding a single image to the map from a mapped collection to see that everything works as expected—another example of a sanity check. The resulting map layer will look like F6.0.10.

-
-
-

-

Fig. F6.0.10 The results of adding the first layer from the RGB composite image collection showing Sentinel-1 images with a label blended on top at a specified location. The blue geometry is used to define the bounds for the animation to be exported.

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60h. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Animation 1: Animated GIF with ui.Thumbnail

-

The quickest way to generate an animation in Earth Engine is to use the animated GIF API and either print it to the Console or print the URL to download the generated GIF. The following code snippet will result in an animated GIF as well as the URL to the animated GIF printed to Console. This is as shown in Fig. F6.0.11:

-
// Define GIF visualization parameters.  
-var gifParams = {  
-   region: rect,  
-   dimensions: 600,  
-   crs: 'EPSG:3857',  
-   framesPerSecond: 10  
-};  
-  
-// Print the GIF URL to the console.  
-print(imagesRgb.getVideoThumbURL(gifParams));  
-  
-// Render the GIF animation in the console.  
-print(ui.Thumbnail(imagesRgb, gifParams));
-

Earth Engine provides multiple options to specify the size of the resulting video. In this example we specify 600 as the size of the maximum dimension. We also specify the number of frames per second for the resulting animated GIF as well as the target projected coordinate system to be used (EPSG:3857 here, which is the projection used in web maps such as Google Maps and the Code Editor background).

-
-
-

-

Fig. F6.0.11 Console output after running the animated GIF code snippet, showing the GIF URL and an animation shown directly in the Console

-
-
-

Animation 2: Exporting an Animation with Export.video.toDrive

-

Animated GIFs can be useful to generate animations quickly. However, they have several limitations. In particular, they are limited to 256 colors, become large for larger animations, and most web players do not provide play controls when playing animated GIFs. To overcome these limitations, Earth Engine provides export of animations as video files in MP4 format. Let’s use the same RGB image collection we have used for the animated GIF to generate a short video. We can ask Earth Engine to export the video to the Google Drive using the following code snippet:

-

Export.video.toDrive({
-collection: imagesRgb,
-description: ‘ice-animation’,
-fileNamePrefix: ‘ice-animation’,
-framesPerSecond: 10,
-dimensions: 600,
-region: rect,
-crs: ‘EPSG:3857’
-});

-

Here, many arguments to the Export.video.toDrive function resemble the ones we’ve used in the ee.Image.getVideoThumbURL code above. Additional arguments include description and fileNamePrefix, which are required to configure the name of the task and the target file of the video file to be saved to Google Drive. Running the above code will result in a new task created under the Tasks tab in the Code Editor. Starting the export video task (F6.0.12) will result in a video file saved in the Google Drive once completed.

-
-
-

-

Fig. F6.0.12 A new export video tasks in the Tasks panel of the Code Editor

-
-
-

Animation 3: The Custom Animation Package

-

For the last animation example, we will use the custom package ‘users/gena/packages:animation’, built using the Earth Engine User Interface API. The main difference between this package and the above examples is that it generates an interactive animation by adding Map layers individually to the layer set, and providing UI controls that allow users to play animations or interactively switch between frames. The animate function in that package generates an interactive animation of an ImageCollection, as described below. This function has a number of optional arguments allowing you to configure, for example, the number of frames to be animated, the number of frames to be preloaded, or a few others. The optional parameters to control the function are the following:

-
    -
  • maxFrames: maximum number of frames to show (default: 30)
  • -
  • vis: visualization parameters for every frame (default: {})
  • -
  • Label: text property of images to show in the animation controls (default: undefined)
  • -
  • width: width of the animation panel (default: ‘600px’)
  • -
  • compact: show only play control and frame slider (default: false)
  • -
  • position: position of the animation panel (default: ‘top-center’)
  • -
  • timeStep: time step (ms) used when playing animation (default: 100)
  • -
  • preloadCount: number of frames (map layers) to preload (default: all)
  • -
-

Let’s call this function to add interactive animation controls to the current Map:

-
// include the animation package  
-var animation = require('users/gena/packages:animation');  
-  
-// show animation controls  
-animation.animate(imagesRgb, {  
- label: 'label',  
- maxFrames: 50  
-});
-

Before using the interactive animation API, we need to include the corresponding package using require. Here we provide our pre-rendered image collection and two optional parameters (label and maxFrames). The first optional parameter label indicates that every image in our image collection has the ‘label’ text property. The animate function uses this property to name map layers as well as to visualize in the animation UI controls when switching between frames. This can be useful when inspecting image collections. The second optional parameter, maxFrames, indicates that the maximum number of animation frames that we would like to visualize is 50. To prevent the Code Editor from crashing, this parameter should not be too large: it is best to keep it below 100. For a much larger number of frames, it is better to use the Export video or animated GIF API. Running this code snippet will result in the animation control panel added to the map as shown in Fig. F6.0.13.

-

It is important to note that the animation API uses asynchronous UI calls to make sure that the Code Editor does not hang when running the script. The drawback of this is that for complex image collections, a large amount of processing is required. Hence, it may take some time to process all images and to visualize the interactive animation panel. The same is true for map layer names: they are updated once the animation panel is visualized. Also, map layers used to visualize individual images in the provided image collection may require some time to be rendered.

-
-
-

-

Fig. F6.0.13 Interactive animation controls when using custom animation API

-
-
-

The main advantage of the interactive animation API is that it provides a way to explore image collections at frame-by-frame basis, which can greatly improve our visual understanding of the changes captured in sets of images.

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60i. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

7.1.5 Terrain Visualization

-

This section introduces several raster visualization techniques useful to visualize terrain data such as:

-
    -
  • Basic hillshading and parameters (light azimuth, elevation)
  • -
  • Combining elevation data and colors using HSV transform (Wikipedia: HSL and HSV)
  • -
  • Adding shadows
  • -
-

One special type of raster data is data that represents height. Elevation data can include topography, bathymetry, but also other forms of height, such as sea surface height can be presented as a terrain.

-

Height is often visualized using the concept of directional light with a technique called hillshading. Because height is such a common feature in our environment, we also have an expectancy of how height is visualized. If height is visualized using a simple grayscale colormap, it looks very unnatural (Fig. F6.0.14, top left). By using hillshading, data immediately looks more natural (Fig. F6.0.14, top middle).

-

We can further improve the visualization by including shadows (Fig. F6.0.14, top right). A final step is to replace the simple grayscale colormap with a perceptual uniform topographic colormap and mix this with the hillshading and shadows (Fig. F6.0.14, bottom). This section explains how to apply these techniques.

-

We’ll focus on elevation data stored in raster form. Elevation data is not always stored in raster formats. Other data formats include Triangulated Irregular Network (TIN), which allows storing information at varying resolutions and as 3D objects. This format allows one to have overlapping geometries, such as bridges with a road below it. In raster-based digital elevation models, in contrast, there can only be one height recorded for each pixel.

-

Let’s start by loading data from a digital elevation model. This loads a topographic dataset from the Netherlands (Algemeen Hoogtebestand Nederland). It is a Digital Surface Model, based on airborne LIDAR measurements regridded to 0.5 m resolution. Enter the following code in a new script.

-

var dem = ee.Image(‘AHN/AHN2_05M_RUW’);

-

We can visualize this dataset using a sequential gradient colormap from black to white. This results in Fig. F6.0.14. One can infer which areas are lower and which are higher, but the visualization does not quite “feel” like a terrain.

-
// Change map style to HYBRID and center map on the Netherlands  
-Map.setOptions('HYBRID');  
-Map.setCenter(4.4082, 52.1775, 18);  
-  
-// Visualize DEM using black-white color palette  
-var palette = ['black', 'white'];  
-var demRGB = dem.visualize({  
-   min: -5,  
-   max: 5,  
-   palette: palette  
-});  
-Map.addLayer(demRGB, {},'DEM');
-

An important step to visualize terrain is to add shadows created by a distant point source of light. This is referred to as hillshading or a shaded relief map. This type of map became popular in the 1940s through the work of Edward Imhoff, who also used grayscale colormaps (Imhoff, 2015). Here we’ll use the ‘gena/packages:utils’ library to combine the colormap image with the shadows. That Earth Engine package implements a hillshadeRGB function to simplify rendering of images enhanced with hillshading and shadow effects. One important argument this function takes is the light azimuth—an angle from the image plane upward to the light source (the Sun). This should always be set to the top left to avoid bistable perception artifacts, in which the DEM can be misperceived as inverted.

-

var utils = require(‘users/gena/packages:utils’);

-

var weight = 0.4; // Weight of Hillshade vs RGB (0 - flat, 1 - hillshaded).
-var exaggeration = 5; // Vertical exaggeration.
-var azimuth = 315; // Sun azimuth.
-var zenith = 20; // Sun elevation.
-var brightness = -0.05; // 0 - default.
-var contrast = 0.05; // 0 - default.
-var saturation = 0.8; // 1 - default.
-var castShadows = false;

-

var rgb = utils.hillshadeRGB(
-demRGB, dem, weight, exaggeration, azimuth, zenith,
-contrast, brightness, saturation, castShadows);

-

Map.addLayer(rgb, {}, ‘DEM (no shadows)’);

-

Standard hillshading only determines per pixel if it will be directed to the light or not. One can also project shadows on the map. That is done using the ee.Algorithms.HillShadow algorithm. Here we’ll turn on castShadows in the hillshadeRGB function. This results in a more realistic map, as can be seen in Figure F6.0.14.

-

var castShadows = true;

-

var rgb = utils.hillshadeRGB(
-demRGB, dem, weight, exaggeration, azimuth, zenith,
-contrast, brightness, saturation, castShadows);

-

Map.addLayer(rgb, {}, ‘DEM (with shadows)’);

-

The final step is to add a topographic colormap. To visualize topographic information, one often uses special topographic colormaps. Here we’ll use the oleron colormap from crameri. The colors get mixed with the shadows using the hillshadeRGB function. As you can see in Fig. F6.0.14, this gives a nice overview of the terrain. The area colored in blue is located below sea level.

-

var palettes = require(‘users/gena/packages:palettes’);
-var palette = palettes.crameri.oleron[50];

-

var demRGB = dem.visualize({
-min: -5,
-max: 5,
-palette: palette
-});

-

var castShadows = true;

-

var rgb = utils.hillshadeRGB(
-demRGB, dem, weight, exaggeration, azimuth, zenith,
-contrast, brightness, saturation, castShadows);

-

Map.addLayer(rgb, {}, ‘DEM colormap’);

-

Steps to further improve a terrain visualization include using light sources from multiple directions. This allows the user to render terrain to appear more natural. In the real world light is often scattered by clouds and other reflections.

-

One can also use lights to emphasize certain regions. To use even more advanced lighting techniques one can use a raytracing engine, such as the R rayshader library, as discussed earlier in this chapter. The raytracing engine in the Blender 3D program is also capable of producing stunning terrain visualizations using physical-based rendering, mist, environment lights, and camera effects such as depth of field.

-

-

-

Figure F6.0.14 Hillshading with shadows

-

Steps in visualizing a topographic dataset:

-
    -
  1. Top left, topography with grayscale colormap
  2. -
  3. Top middle, topography with grayscale colormap and hillshading
  4. -
  5. Top right, topography with grayscale colormap, hillshading, and shadows
  6. -
  7. Bottom, topography with topographic colormap, hillshading, and shadows
  8. -
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F60j. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

Conclusion

-

In this chapter we have learned about several techniques that can greatly improve visualization and analysis of images and image collections. Using predefined palettes can help to better comprehend and communicate Earth observation data, and combining with other visualization techniques such as hillshading and annotations can help to better understand processes studied with Earth Engine. When working with image collections, it is often very helpful to analyze their properties through time by visualizing them as animations. Usually, this step helps to better understand dynamics of the changes that are stored in image collections and to develop a proper algorithm to study these changes.

-
-
-

References

-

Burrough PA, McDonnell RA, Lloyd CD (2015) Principles of Geographical Information Systems. Oxford University Press

-

Crameri F, Shephard GE, Heron PJ (2020) The misuse of colour in science communication. Nat Commun 11:1–10. https://doi.org/10.1038/s41467-020-19160-7

-

Imhof E (2015) Cartographic Relief Presentation. Walter de Gruyter GmbH & Co KG

-

Lhermitte S, Sun S, Shuman C, et al (2020) Damage accelerates ice shelf instability and mass loss in Amundsen Sea Embayment. Proc Natl Acad Sci USA 117:24735–24741. https://doi.org/10.1073/pnas.1912890117

-

Thyng KM, Greene CA, Hetland RD, et al (2016) True colors of oceanography. Oceanography 29:9–13

-

Wikipedia (2022) Terrain cartography. https://en.wikipedia.org/wiki/Terrain_cartography#Shaded_relief. Accessed 1 Apr 2022

-

Wikipedia (2022) HSL and HSV. https://en.wikipedia.org/wiki/HSL_and_HSV. Accessed 1 Apr 2022

-

Wild CT, Alley KE, Muto A, et al (2022) Weakening of the pinning point buttressing Thwaites Glacier, West Antarctica. Cryosphere 16:397–417. https://doi.org/10.5194/tc-16-397-2022

-

Wilkinson L (2005) The Grammar of Graphics. Springer Verlag

-
-
-
-

7.2 Collaborating in Earth Engine with Scripts and Assets

-
-
-
- -
-
-Chapter Information -
-
-
-
-

Author

-

Sabrina H. Szeto

-
-
-

Overview

-

Many users find themselves needing to collaborate with others in Earth Engine at some point. Students may need to work on a group project, people from different organizations might want to collaborate on research together, or people may want to share a script or an asset they created with others. This chapter will show you how to collaborate with others and share your work.

-
-
-

Learning Outcomes

-
    -
  • Understanding when it is important to share a script or asset.
  • -
  • Understanding what roles and permission options are available.
  • -
  • Sharing a script with others.
  • -
  • Sharing an asset with others.
  • -
  • Sharing an asset so it can be displayed in an app.
  • -
  • Sharing a repository with others.
  • -
  • Seeing who made changes to a script and what changes were made.
  • -
  • Reverting to a previous version of a script.
  • -
  • Using the require function to load modules.
  • -
  • Creating a script to share as a module.
  • -
-
-
-

Assumes you know how to:

-
    -
  • Sign up for an Earth Engine account, open the Code Editor, and save your script (Chap. F1.0).
  • -
-
-
-
-
-

Introduction

-

Many people find themselves needing to share a script when they encounter a problem; they wish to share the script with someone else so they can ask a question. When this occurs, sharing a link to the script often suffices. The other person can then make comments or changes before sending a new link to the modified script.

-

If you have included any assets from the Asset Manager in your script, you will also need to share these assets in order for your script to work for your colleague. The same goes for sharing assets to be displayed in an app.

-

Another common situation involves collaborating with others on a project. They may have some scripts they have written that they want to reuse or modify for the new project. Alternatively, several people might want to work on the same script together. For this situation, sharing a repository would be the best way forward; team members will be able to see who made what changes to a script and even revert to a previous version.

-

If you or your group members find yourselves repeatedly reusing certain functions for visualization or for part of your analysis, you could use the require module to call that function instead of having to copy and paste it into a new script each time. You could even make this function or module available to others to use via require.

-

Let’s get started. For this lab, you will need to work in small groups or pairs.

-
- -
-

7.2.2 Sharing Assets from Your Asset Manager

-

When you clicked the Get Link button earlier, you may have noticed a note in the popup reading: “To give others access to assets in the code snapshot, you may need to share them.” If your script uses an asset that you have uploaded into your Asset Manager, you will need to share that asset as well. If not, an error message will appear when the person you shared the script with tries to run it.

-

Before sharing an asset, think about whether you have permission to share it. Is this some data that is owned by you, or did you get it from somewhere else? Do you need permission to share this asset? Make sure you have the permission to share an asset before doing so.

-

Now, let’s practice sharing assets. First, navigate to your Asset Manager by clicking on the Assets tab in the left panel. If you already have some assets uploaded, pick one that you have permission to share. If not, upload one to your Asset Manager. If you don’t have a shapefile or raster to upload, you can upload a small text file. Consult the Earth Engine documentation for how to do this; it will take only a few steps.

-

Hover your cursor over that asset in your Asset Manager. The asset gets highlighted in gray and three buttons appear to the right of the asset. Click on the first button from the left (outlined in red in Fig. F6.1.1). This icon means “share.”

-
-
-

-

Fig. F6.1.1 Three assets in the Asset Manager

-
-
-

After you click the share button, a Share Image popup will appear (Fig. F6.1.2). This popup contains information about the path of the asset and the email address of the owner. The owner of the asset can decide who can view and edit the asset.

-

Click on the dropdown menu outlined in red in Fig. F6.1.2. You will see two options for permissions: Reader and Writer. A Reader can view the asset, while a Writer can both view and make changes to it. For example, a Writer could add a new image to an ImageCollection. A Writer can also add other people to view or edit the asset, and a Writer can delete the asset. When in doubt, give someone the Reader role rather than the Writer role.

-
-
-

-

Fig. F6.1.2 The Share Image popup window

-
-
-

To share an asset with someone, you can type their email address into the Email or domain text field, choose Reader or Writer in the dropdown menu, and then click on Add Access. You can also share an asset with everyone with a certain email domain, which is useful if you want to share an asset with everyone in your organization, for instance.

-

If you want to share reading access publicly, then check the box that says Anyone can read. Note that you still need to share the link to the asset in order for others to access it. The only exceptions to this are when you are using the asset in a script and sharing that script using the Get Link button or when you share the asset with an Earth Engine app. To do the latter, use the Select an app dropdown menu (outlined in orange in Fig. F6.1.2) and click Add App Access.

-

Question 3. Share an asset with a group member and give them reader access. Send them the link to that asset. You will also receive a link from someone else in your group. Open that link. What can you do with that asset? What do you need to do to import it into a script?

-

Answer: You can view details about the asset and import it for use in a script in the Code Editor. To import the asset, click on the blue Import button.

-

Question 4. Share an asset with a group member and give them writer access. Send them the link to that asset. You will also receive a link from someone else in your group. Open that link. What can you do with that asset? Try sharing the asset with a different group member.

-

Answer: You can view details about the asset and import it for use in a script in the Code Editor. You can also share the asset with others and delete the asset.

-
-
-

7.2.3 Working with Shared Repositories

-

Now that you know how to share assets and scripts, let’s move on to sharing repositories. In this section, you will learn about different types of repositories and how to add a repository that someone else shared with you. You will also learn how to view previous versions of a script and how to revert back to an earlier version.

-

Earlier, we learned how to share a script using the Get Link button. This link shares a code snapshot from a script. This snapshot does not reflect any changes made to the script after the time the link was shared. If you want to share a script that updates to reflect the most current version when it is opened, you need to share a repository with that script instead.

-

If you look under the Scripts tab of the leftmost panel in the Code Editor, you will see that the first three categories are labeled Owner, Reader, and Writer.

-
    -
  • Repositories categorized under Owner are created and owned by you. No one else has access to view or make changes to them until you share these repositories.
  • -
  • Repositories categorized under Reader are repositories to which you have reader access. You can view the scripts but not make any changes to them. If you want to make any changes, you will need to save the script as a new file in a repository that you own.
  • -
  • Repositories categorized under Writer are repositories to which you have writer access. This means you can view and make changes to the scripts.
  • -
-

Let’s practice creating and sharing repositories. We will start by making a new repository. Click on the red New button located in the left panel. Select Repository from the dropdown menu. A New repository popup window will open (Fig. F6.1.3).

-
-
-

-

Fig. F6.1.3 The New repository popup window

-
-
-

In the popup window’s text field, type a name for your new repository, such as “ForSharing1,” then click on the blue Create button. You will see the new repository appear under the Owner category in the Scripts tab (Fig. F6.1.4).

-

Now, share this new repository with your group members: Hover your cursor over the repository you want to share. The repository gets highlighted in gray, and three buttons appear. Click on the Gear icon (outlined in red in Fig. F6.1.4).

-
-
-

-

Fig. F6.1.4 Three repositories under the Owner category

-
-
-

A Share Repo popup window appears (Fig. F6.1.5) which is very similar to the Share Image popup window we saw in Fig. F6.1.2. The method for sharing a repository with a specific user or the general public is the same as for sharing assets.

-

Type the email address of a group member in the Email or domain text field and give this person a writer role by selecting Writer in the dropdown menu, then click on Add Access.

-
-
-

-

Fig. F6.1.5. The Share Repo popup window

-
-
-

Your group member should receive an email inviting them to edit the repository. Check your email inbox for the repository that your group member has shared with you. When you open that email, you will see content similar to what is shown in Fig. F6.1.6.

-
-
-

-

Fig. F6.1.6 The “Invitation to edit” email

-
-
-

Now, click on the blue button that says Add [repository path] to your Earth Engine Code Editor. You will find the new repository added to the Writer category in your Scripts tab. The repository path will contain the username of your group member, such as users/username/sharing.

-

Now, let’s add a script to the empty repository. Click on the red New button in the Scripts tab and select File from the dropdown menu. A Create file popup will appear, as shown in Fig. F6.1.7. Click on the gray arrow beside the default path to open a dropdown menu that will allow you to choose the path of the repository that your group member shared with you. Type a new File Name in the text field, such as “exercise,” then click on the blue OK button to create the file.

-
-
-

-

Fig. F6.1.7 The Create file popup window

-
-
-

A new file should now appear in the shared repository in the Writer category. If you don’t see it, click on the Refresh icon, which is to the right of the red New button in the Scripts tab.

-

Double-click on the new script in the shared repository to open it. Then, copy and paste the following code to your Code Editor.

-

print(‘The owner of this repository is GroupMemberName.’);

-

Replace GroupMemberName with the name of your group member, then click Save to save the script in the shared repository, which is under the Writer category.

-

Now, navigate to the repository under Owner which you shared with your group member. Open the new script which they just created by double-clicking it.

-

Add the following code below the line of code that you pasted earlier.

-

print(‘This script is shared with MyName.’);

-

Replace MyName with your name, then save the script.

-

Next, we will compare changes made to the script. Click on the Versions icon (outlined in red in Fig. F6.1.8).

-
-
-

-

Fig. F6.1.8 Changes made and previous versions of the script

-
-
-

A popup window will appear, titled Revision history, followed by the path of the script (Fig. F6.1.9). There are three columns of information below the title.

-
    -
  • The left column contains the dates on which changes have been made.
  • -
  • The middle column contains the usernames of the people who made changes.
  • -
  • The right column contains information about what changes were made.
  • -
-

The most recent version of the script is shown in the first row, while previous versions are listed in subsequent rows. (More advanced users may notice that this is actually a Git repository.)

-
-
-

-

Fig. F6.1.9 The Revision history popup window

-
-
-

If you hover your cursor over a row, the row will be highlighted in gray and a button labeled Compare will appear. Clicking on this button allows you to compare differences between the current version of the script and a previous version in a Version comparison popup window (Fig. F6.1.10).

-
-
-

-

Fig. F6.1.10 The Version comparison popup window

-
-
-

In the Version comparison popup, you will see text highlighted in two different colors. Text highlighted in red shows code that was present in the older version but is absent in the current version (the “latest commit”). Text highlighted in green shows code that is present in the current version but that was absent in the older version. Generally speaking, text highlighted in red has been removed in the current version and text highlighted in green has been added to the current version. Text that is not highlighted shows code that is present in both versions.

-

Question 5. What text, if any, is highlighted in red when you click on Compare in your “exercise” script?

-

Answer: No text is highlighted in red, because none was removed between the previous and current versions of the script.

-

Question 6. What text, if any, is highlighted in green when you click on Compare in your “exercise” script?

-

Answer: print(‘This script is shared with MyName.’);

-

Question 7. What happens when you click on the blue Revert button?

-

Answer: The script reverts to the previous version, in which the only line of code is

-

print(‘The owner of this repository is GroupMemberName.’);

-
-
-

7.2.4 Using the Require Function to Load a Module

-

In earlier chapters, you may have noticed that the require function allows you to reuse code that has already been written without having to copy and paste it into your current script. For example, you might have written a function for cloud masking that you would like to use in multiple scripts. Saving this function as a module enables you to share the code across your own scripts and with other people. Or you might discover a new module with capabilities you need written by other authors. This section will show you how to use the require function to create and share your own module or to load a module that someone else has shared.

-

The module we will use is ee-palettes, which enables users to visualize raster data using common specialized color palettes (Donchyts et al. 2019). (If you would like to learn more about using these color palettes, the ee-palettes module is described and illustrated in detail in Chap. F6.0.) The first step is to go to this link to accept access to the repository as a reader: https://code.earthengine.google.com/?accept_repo=users/gena/packages

-

Now, if you navigate to your Reader directory in the Code Editor, you should see a new repository called ‘users/gena/packages’ listed. Look for a script called ‘palettes’ and click on it to load it in your Code Editor.

-

If you scroll down, you will see that the script contains a nested series of dictionaries with lists of hexadecimal color specifications (as described in Chap. F2.1) that describe a color palette, as shown in the code block below. For example, the color palette named “Algae” stored in the cmocean variable consists of seven colors, ranging from dark green to light green (Fig. F6.1.11).

-

exports.cmocean = {
-Thermal: { 7: [‘042333’, ‘2c3395’, ‘744992’, ‘b15f82’, ‘eb7958’, ‘fbb43d’, ‘e8fa5b’ ]
-},
-Haline: { 7: [‘2a186c’, ‘14439c’, ‘206e8b’, ‘3c9387’, ‘5ab978’, ‘aad85c’, ‘fdef9a’ ]
-},
-Solar: { 7: [‘331418’, ‘682325’, ‘973b1c’, ‘b66413’, ‘cb921a’, ‘dac62f’, ‘e1fd4b’ ]
-},
-Ice: { 7: [‘040613’, ‘292851’, ‘3f4b96’, ‘427bb7’, ‘61a8c7’, ‘9cd4da’, ‘eafdfd’ ]
-},
-Gray: { 7: [‘000000’, ‘232323’, ‘4a4a49’, ‘727171’, ‘9b9a9a’, ‘cacac9’, ‘fffffd’ ]
-},
-Oxy: { 7: [‘400505’, ‘850a0b’, ‘6f6f6e’, ‘9b9a9a’, ‘cbcac9’, ‘ebf34b’, ‘ddaf19’ ]
-},
-Deep: { 7: [‘fdfecc’, ‘a5dfa7’, ‘5dbaa4’, ‘488e9e’, ‘3e6495’, ‘3f396c’, ‘281a2c’ ]
-},
-Dense: { 7: [‘e6f1f1’, ‘a2cee2’, ‘76a4e5’, ‘7871d5’, ‘7642a5’, ‘621d62’, ‘360e24’ ]
-},
-Algae: { 7: [‘d7f9d0’, ‘a2d595’, ‘64b463’, ‘129450’, ‘126e45’, ‘1a482f’, ‘122414’ ]
-},
-…
-}

-

Notice that the variable is named exports.cmocean. Adding exports to the name of a function or variable makes it available to other scripts to use, as it gets added to a special global variable (Chang 2017).

-
-
-

-

Fig. F6.1.11 Some of the color palettes from the ee-palettes GitHub repository

-
-
-

To see all the color palettes available in this module, go to https://github.com/gee-community/ee-palettes.

-

Now let’s try using the ee-palettes module. Look for a script in the same repository called ‘palettes-test’ and click on it to load it in your Code Editor. When you run the script, you will see digital elevation data from the National Aeronautics and Space Administration Shuttle Radar Topography Mission satellite visualized using two palettes, colorbrewer.Blues and cmocean.Algae. The map will have two layers that show the same data with different palettes.

-

The script first imports the digital elevation model data in the Imports section of the Code Editor.

-

var dem = ee.Image(‘USGS/SRTMGL1_003’);

-

The script then loads the ee-palettes module by using the require function. The path to the module, ‘users/gena/packages:palettes’, is passed to the function. The require function is then stored in a variable named ‘palettes’, which will be used later to obtain the palettes for data visualization.

-

var palettes = require(‘users/gena/packages:palettes’);

-

As described by Donchyts et al. (2019), “Each palette is defined by a group and a name, which are separated by a period (JS object dot notation), and a color level. To retrieve a desired palette, use JS object notation to specify the group, name, and number of color levels.” We define the color palette Algae as palettes.cmocean.Algae[7] because it is part of the group cmocean and has 7 color levels. In the next code block, you can see that the palettes (i.e., lists of hex colors) have been defined for use by setting them as the value for the palette key in the visParams object supplied to the Map.addLayer function.

-
// colorbrewer  
-Map.addLayer(dem, {  
-   min: 0,  
-   max: 3000,  
-   palette: palettes.colorbrewer.Blues[9]  
-}, 'colorbrewer Blues[9]');  
-  
-// cmocean  
-Map.addLayer(dem, {  
-   min: 0,  
-   max: 3000,  
-   palette: palettes.cmocean.Algae[7]  
-}, 'cmocean Algae[7]');
-

Question 8. Try adding a third layer to the Map with a different color palette from ee-palettes. How easy was it to do?

-

Now that you have loaded and used a module shared by someone else, you can try your hand at creating your own module and sharing it with someone else in your group. First, go to the shared repository that you created in Sect. 3, create a new script in that repository, and name it “cloudmasking.”

-

Then, go to the Examples repository at the bottom of the Scripts tab and select a function from the Cloud Masking repository. Let’s use the Landsat8 Surface Reflectance cloud masking script as an example. In that script, you will see the code shown in the block below. Copy all of it into your empty script.

-
// This example demonstrates the use of the Landsat 8 Collection 2, Level 2  
-// QA_PIXEL band (CFMask) to mask unwanted pixels.  
-function maskL8sr(image) {   // Bit 0 - Fill   // Bit 1 - Dilated Cloud   // Bit 2 - Cirrus   // Bit 3 - Cloud   // Bit 4 - Cloud Shadow   var qaMask = image.select('QA_PIXEL').bitwiseAnd(parseInt('11111',       2)).eq(0);   var saturationMask = image.select('QA_RADSAT').eq(0);   // Apply the scaling factors to the appropriate bands.   var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-       0.2);   var thermalBands = image.select('ST_B.*').multiply(0.00341802)  
-       .add(149.0);   // Replace the original bands with the scaled ones and apply the masks.   return image.addBands(opticalBands, null, true)  
-       .addBands(thermalBands, null, true)  
-       .updateMask(qaMask)  
-       .updateMask(saturationMask);  
-}  
-  
-// Map the function over one year of data.  
-var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')  
-   .filterDate('2020-01-01', '2021-01-01')  
-   .map(maskL8sr);  
-  
-var composite = collection.median();  
-  
-// Display the results.  
-Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula  
-Map.addLayer(composite, {  
-   bands: ['SR_B4', 'SR_B3', 'SR_B2'],  
-   min: 0,  
-   max: 0.3  
-});
-

Note that this code is well commented and has a header that describes what the script does. Don’t forget to comment your code and describe what you are doing each step of the way. This is a good practice for collaborative coding and for your own future reference.

-

Imagine that you changed this maskL8sr function slightly for some reason and want to make it available to other users and scripts. To do that, you can turn the function into a module. Copy and modify the code from the example code into the new script you created called “cloudmasking.” (Hint: Store the function in a variable starting with exports. Be careful that you don’t accidentally use Export, which is used to export datasets.)

-

Your script should be similar to the following code.

-

exports.maskL8sr = function(image) { // Bit 0 - Fill // Bit 1 - Dilated Cloud // Bit 2 - Cirrus // Bit 3 - Cloud // Bit 4 - Cloud Shadow var qaMask = image.select(‘QA_PIXEL’).bitwiseAnd(parseInt( ‘11111’, 2)).eq(0); var saturationMask = image.select(‘QA_RADSAT’).eq(0); // Apply the scaling factors to the appropriate bands. var opticalBands = image.select(‘SR_B.’).multiply(0.0000275)
-.add(-0.2); var thermalBands = image.select(’ST_B.*’).multiply(0.00341802)
-.add(149.0); // Replace the original bands with the scaled ones and apply the masks. return image.addBands(opticalBands, null, true)
-.addBands(thermalBands, null, true)
-.updateMask(qaMask)
-.updateMask(saturationMask);
-}

-

Next, you will create a test script that makes use of the cloud masking module you just made. Begin by creating a new script in your shared repository called “cloudmasking-test.” You can modify the last part of the example cloud masking script to use your module.

-
// Map the function over one year of data.  
-var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')  
-   .filterDate('2020-01-01', '2021-01-01')  
-   .map(maskL8sr);  
-  
-var composite = collection.median();  
-  
-// Display the results.  
-Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula  
-Map.addLayer(composite, {  
-   bands: ['SR_B4', 'SR_B3', 'SR_B2'],  
-   min: 0,  
-   max: 0.3  
-});
-

Question 9. How will you modify the cloud masking script to use your module? What does the script look like?

-

Answer: Your code might look something like the code block below.

-
// Load the module  
-var myCloudFunctions = require(   'users/myusername/my-shared-repo:cloudmasking');  
-  
-// Map the function over one year of data.  
-var collection = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')  
-   .filterDate('2020-01-01', '2021-01-01')  
-   .map(myCloudFunctions.maskL8sr);  
-  
-var composite = collection.median();  
-  
-// Display the results.  
-Map.setCenter(-4.52, 40.29, 7); // Iberian Peninsula  
-Map.addLayer(composite, {  
-   bands: ['SR_B4', 'SR_B3', 'SR_B2'],  
-   min: 0,  
-   max: 0.3  
-});
-
-
-

Conclusion

-

In this chapter, you learned how to collaborate with others in the Earth Engine Code Editor through sharing scripts, assets, and repositories. You learned about different roles and permissions available for sharing and when it is appropriate to use each. In addition, you are now able to see what changes have been made to a script and revert to a previous version. Lastly, you loaded and used a module that was shared with you and created your own module for sharing. You are now ready to start collaborating and developing scripts with others.

-
-
-

References

-

Chang A (2017) Making it easier to reuse code with Earth Engine script modules. In: Google Earth and Earth Engine. https://medium.com/google-earth/making-it-easier-to-reuse-code-with-earth-engine-script-modules-2e93f49abb13. Accessed 24 Feb 2022

-

Donchyts G, Baart F, Braaten J (2019) ee-palettes. https://github.com/gee-community/ee-palettes. Accessed 24 Feb 2022

-
-
-
-

7.3 Scaling Up in Earth Engine

-
-
-
- -
-
-Chapter Information -
-
-
-
-

Author

-

Jillian M. Deines, Stefania Di Tommaso, Nicholas Clinton, Noel Gorelick

-
-
-

Overview

-

Commonly, when Earth Engine users move from tutorials to developing their own processing scripts, they encounter the dreaded error messages, “computation timed out” or “user memory limit exceeded.” Computational resources are never unlimited, and the team at Earth Engine has designed a robust system with built-in checks to ensure server capacity is available to everyone. This chapter will introduce general tips for creating efficient Earth Engine workflows that accomplish users’ ambitious research objectives within the constraints of the Earth Engine ecosystem. We use two example case studies: 1) extracting a daily climate time series for many locations across two decades, and 2) generating a regional, cloud-free median composite from Sentinel-2 imagery.

-
-
-

Learning Outcomes

-
    -
  • Understanding constraints on Earth Engine resource use.
  • -
  • Becoming familiar with multiple strategies to scale Earth Engine operations.
  • -
  • Managing large projects and multistage workflows.
  • -
  • Recognizing when using the Python API may be advantageous to execute large batches of tasks.
  • -
-
-
-

Assumes you know how to:

-
    -
  • Import images and image collections, filter, and visualize (Part F1).
  • -
  • Write a function and map it over an ImageCollection (Chap. F4.0).
  • -
  • Export and import results as Earth Engine assets (Chap. F5.0).
  • -
  • Understand distinctions among Image, ImageCollection, Feature and FeatureCollection Earth Engine objects (Part F1, Part F2, Part F5).
  • -
  • Use the require function to load code from existing modules (Chap. F6.1).
  • -
-
-
-
-
-

Introduction

-

Parts F1–F5 of this book have covered key remote sensing concepts and demonstrated how to implement them in Earth Engine. Most exercises have used local-scale examples to enhance understanding and complete tasks within a class-length time period. But Earth Engine’s power comes from its scalability—the ability to apply geospatial processing across large areas and many years.

-

How we go from small to large scales is influenced by Earth Engine’s design. Earth Engine runs on many individual computer servers, and its functions are designed to split up processing onto these servers. This chapter focuses on common approaches to implement large jobs within Earth Engine’s constraints. To do so, we first discuss Earth Engine’s underlying infrastructure to provide context for existing limits. We then cover four core concepts for scaling:

-
    -
  1. Using best coding practices.
  2. -
  3. Breaking up jobs across time.
  4. -
  5. Breaking up jobs across space.
  6. -
  7. Building a multipart workflow and exporting intermediate assets.
  8. -
-
-

7.3.0.1 Earth Engine: Under the Hood

-

As you use Earth Engine, you may begin to have questions about how it works and how you can use that knowledge to optimize your workflow. In general, the inner workings are opaque to users. Typical fixes and approaches that data scientists use to manage memory constraints often don’t apply. It’s helpful to know what users can and cannot control, and how your scripts translate to Earth Engine’s server operations.

-

Earth Engine is a parallel, distributed system (see Gorelick et al. 2017), which means that when you submit tasks, it breaks up pieces of your query onto different processors to complete them more efficiently. It then collects the results and returns them to you. For many users, not having to manually design this parallel, distributed processing is a huge benefit. For some advanced users, it can be frustrating to not have better control. We’d argue that leaving the details up to Earth Engine is a huge time-saver for most cases, and learning to work within a few constraints is a good time investment.

-

One core concept useful to master is the relationship between client-side and server-side operations. Client-side operations are performed within your browser (for the JavaScript API Code Editor) or local system (for the Python API). These include things such as manipulating strings or numbers in JavaScript. Server-side operations are executed on Google’s servers and include all of the ee.* functions. By using the Earth Engine APIs—JavaScript or Python—you are building a chain of commands to send to the servers and later receive the result back. As much as possible, you want to structure your code to send all the heavy lifting to Google, and keep processing off of your local resources.

-

In other words, your work in the Code Editor is making a description of a computation. All ee objects are just placeholders for server-side objects—their actual value does not exist locally on your computer. To see or use the actual value, it has to be evaluated by the server. If you print an Earth Engine object, it calls getInfo to evaluate and return the value. In contrast, you can also work with JavaScript/Python lists or numbers locally, and do basic JavaScript/Python things to them, like add numbers together or loop over items. These are client-side objects. Whenever you bring a server-side object into your local environment, there’s a computational cost.

-

Table F6.2.1 describes some nuts and bolts about Earth Engine and their implications. Table F6.2.2 provides some of the existing limits on individual tasks.

-

Table F6.2.1 Characterics of Google Earth Engine and implications for running large jobs

-

Earth Engine characteristics

-

Implications

-

A parallel, distributed system

-

Occasionally, doing the exact same thing in two different orders can result in different processing distributions, impacting the ability to complete the task within system limits.

-

Most processing is done per tile (generally a square that is 256 x 256 pixels).

-

Tasks that require many tiles are the most memory intensive. Some functions have a tileScale argument that reduces tile size, allowing processing-intensive jobs to succeed (at the cost of reduced speed).

-

Export mode has higher memory and time allocations than interactive mode.

-

It’s better to export large jobs. You can export to your Earth Engine assets, your Google Drive, or Google Cloud Storage.

-

Some operations are cached temporarily.

-

Running the same job twice could result in different run times. Occasionally tasks may run successfully on a second try.

-

Underlying infrastructure is composed of clusters of low-end servers.

-

There’s a hard limit on data size for any individual server; large computations need to be done in parallel using Earth Engine functions.

-

The image processing domain, scale, and projection are defined by the specified output and applied backwards throughout the processing chain.

-

There are not many cases when you will need to manually reproject images, and these operations are costly. Similarly, manually “clipping” images is typically unnecessary.

-

Table F6.2.2 Size limits for Earth Engine tasks

-

Earth Engine Component

-

Limits

-

Interactive mode

-

Can print up to 5000 records. Computations must finish within five minutes.

-

Export mode

-

Jobs have no time limit as long as they continue to make reasonable progress (defined roughly as 600 seconds per feature, two hours per aggregation, and 10 minutes per tile). If any one tile, feature, or aggregation takes too long, the whole job will get canceled. Any jobs that take longer than one week to run will likely fail due to Earth Engine’s software update release cycles.

-

Table assets

-

Maximum of 100 million features, 1000 properties (columns), and 100,000 vertices for a geometry.

-
-
-

7.3.0.2 The Importance of Coding Best Practices

-

Good code scales better than bad code. But what is good code? Generally, for Earth Engine, good code means 1) using Earth Engine’s server-side operators; 2) avoiding multiple passes through the same image collection; 3) avoiding unnecessary conversions; and 4) setting the processing scale or sample numbers appropriate for your use case, i.e., avoid using very fine scales or large samples without reason.

-

We encourage readers to become familiar with the “Coding Best Practices” page in the online Earth Engine User Guide. This page provides examples for avoiding mixing client- and server-side functions, unnecessary conversions, costly algorithms, combining reducers, and other helpful tips. Similarly, the “Debugging Guide–Scaling Errors” page of the online Earth Engine User Guide covers some common problems and solutions.

-

In addition, some Earth Engine functions are more efficient than others. For example, Image.reduceRegions is more efficient than Image.sampleRegions, because sampleRegions regenerates the geometries under the hood. These types of best practices are trickier to enumerate and somewhat idiosyncratic. We encourage users to learn about and make use of the Profiler tab, which will track and display the resources used for each operation within your script. This can help identify areas to focus efficiency improvements. Note that the profiler itself increases resource use, so only use it when necessary to develop a script and remove it for production-level execution. Other ways to discover best practices include following/posting questions to GIS StackExchange or the Earth Engine Developer’s Discussion Group, swapping code with others, and experimentation.

-
-
-
-

7.3.1 Scaling Across Time

-

In this section we use an example of extracting climate data at features (points or polygons) to demonstrate how to scale an operation across many features (Sect. 1.1) and how to break up large jobs by time units when necessary (e.g, by years; Sect. 1.2).

-
-

7.3.1.1 1.1. Scaling Up with Earth Engine Operators: Annual Daily Climate Data

-

Earth Engine’s operators are designed to parallelize queries on the backend without user intervention. In many cases, they are sufficient to accomplish a scaling operation.

-

As an example, we will extract a daily time series of precipitation, maximum temperature, and minimum temperature for county polygons in the United States. We will use the GRIDMET Climate Reanalysis product (Abatzoglou 2013), which provides daily, 4000 m resolution gridded meteorological data from 1979 to the present across the contiguous United States. To save time for this practicum, we will focus on the states of Indiana, Illinois, and Iowa in the central United States, which together include 293 counties (Fig. F6.2.1).

-
-
-

-

Fig. F6.2.1 Map of study area, showing 293 county features within the states of Iowa, Illinois, and Indiana in the United States

-
-
-

This example uses the ee.Image.reduceRegions operator, which extracts statistics from an Image for each Feature (point or polygon) in a FeatureCollection. We will map the reduceRegions operator over each daily image in an ImageCollection, thus providing us with the daily climate information for each county of interest.

-

Note that although our example uses a climate ImageCollection, this approach transfers to any ImageCollection, including satellite imagery, as well as image collections that you have already processed, such as cloud masking (Chap. F4.3) or time series aggregation (Chap. F4.2).

-

First, define the FeatureCollection, ImageCollection, and time period:

-
// Load county dataset.  
-// Filter counties in Indiana, Illinois, and Iowa by state FIPS code.  
-// Select only the unique ID column for simplicity.  
-var countiesAll = ee.FeatureCollection('TIGER/2018/Counties');  
-var states = ['17', '18', '19'];  
-var uniqueID = 'GEOID';  
-var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states))  
-   .select(uniqueID);  
-  
-print(featColl.size());  
-print(featColl.limit(1));  
-  
-// Visualize target features (create Figure F6.2.1).  
-Map.centerObject(featColl, 5);  
-Map.addLayer(featColl);  
-  
-// specify years of interest  
-var startYear = 2020;  
-var endYear = 2020;  
-  
-// climate dataset info  
-var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET';  
-var bandsWanted = ['pr', 'tmmn', 'tmmx'];  
-var scale = 4000;
-

Printing the size of the FeatureCollection indicates that there are 293 counties in our subset. Since we want to pull a daily time series for one year, our final dataset will have 106,945 rows—one for each county-day.

-

Note that from our county FeatureCollection, we select only the GEOID column, which represents a unique identifier for each record in this dataset. We do this here to simplify print outputs; we could also specify which properties to include in the export function (see below).

-

Next, load and filter the climate data. Note we adjust the end date to January 1 of the following year, rather than December 31 of the specified year, since the filterDate function has an inclusive start date argument and an exclusive end date argument; without this modification the output would lack data for December 31.

-
// Load and format climate data.  
-var startDate = startYear + '-01-01';  
-  
-var endYear_adj = endYear + 1;  
-var endDate = endYear_adj + '-01-01';  
-  
-var imageCollection = ee.ImageCollection(imageCollectionName)  
-   .select(bandsWanted)  
-   .filterBounds(featColl)  
-   .filterDate(startDate, endDate);
-

Now get the mean value for each climate attribute within each county feature. Here, we map the ee.Image.reduceRegions call over the ImageCollection, specifying an ee.Reducer.mean reducer. The reducer will apply to each band in the image, and it returns the FeatureCollection with new properties. We also add a ‘date_ymd’ time property extracted from the image to correctly associate daily values with their date. Finally, we flatten the output to reform a single FeatureCollection with one feature per county-day.

-
// get values at features  
-var sampledFeatures = imageCollection.map(function(image) {   return image.reduceRegions({  
-           collection: featColl,  
-           reducer: ee.Reducer.mean(),  
-           scale: scale  
-       }).filter(ee.Filter.notNull(  
-       bandsWanted)) // drop rows with no data       .map(function(f) { // add date property           var time_start = image.get(               'system:time_start');           var dte = ee.Date(time_start).format(               'YYYYMMdd');           return f.set('date_ymd', dte);  
-       });  
-}).flatten();  
-  
-print(sampledFeatures.limit(1));
-

Note that we include a filter to remove feature-day rows that lacked data. While this is less common when using gridded climate products, missing data can be common when reducing satellite images. This is because satellite collections come in scene tiles, and each image tile likely does not overlap all of our features unless it has first been aggregated temporally. It can also occur if a cloud mask has been applied to an image prior to the reduction. By filtering out null values, we can reduce empty rows.

-

Now explore the result. If we simply print(sampledFeatures) we get our first error message: “User memory limit exceeded.” This is because we’ve created a FeatureCollection that exceeds the size limits set for interactive mode. How many are there? We could try print(sampledFeatures.size()), but due to the larger size, we receive a “Computation timed out” message—it’s unable to tell us. Of course, we know that we expect 293 counties x 365 days = 106,945 features. We can, however, check that our reducer has worked as expected by asking Earth Engine for just one feature: print(sampledFeatures.limit(1)).

-
-
-

-

Fig. F6.2.2 Screenshot of the print output for one feature after the reduceRegions call

-
-
-

Here, we can see the precipitation, minimum temperature, and maximum temperature for the county with GEOID = 17121 on January 1, 2020 (Fig. F6.2.2; note temperature is in Kelvin units).

-

Next, export the full FeatureCollection as a CSV to a folder in your Google Drive. Specify the names of properties to include. Build part of the filename dynamically based on arguments used for year and data scale, so we don’t need to manually modify the filenames.

-
// export info  
-var exportFolder = 'GEE_scalingUp';  
-var filename = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_' +  
-   startYear + '-' + endYear;// prepare export: specify properties/columns to include  
-var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted);  
-print(columnsWanted);  
-  
-Export.table.toDrive({  
-   collection: sampledFeatures,  
-   description: filename,  
-   folder: exportFolder,  
-   fileFormat: 'CSV',  
-   selectors: columnsWanted  
-});
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F62a. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

On our first export, this job took about eight minutes to complete, producing a dataset 6.8 MB in size. The data is ready for downstream use but may need formatting to suit the user’s goals. You can see what the exported CSV looks like in Fig. F6.2.3.

-
-
-

-

Fig. F6.2.3 Top six rows of the exported CSV viewed in Microsoft Excel and sorted by county GEOID

-
-
-

Using the Selectors Argument

-

There are two excellent reasons to use the selectors argument in your Export.table.toDrive call. First, if the argument is not specified, Earth Engine will generate the column names for the exported CSV from the first feature in your FeatureCollection. If that feature is missing properties, those properties will be dropped from the export for all features.

-

Perhaps even more important if you are seeking to scale up an analysis, including unnecessary columns can greatly increase file size and even processing time. For example, Earth Engine includes a .geo field that contains a GeoJSON description of each spatial feature. For non-simple geometries, the field can be quite large, as it lists coordinates for each polygon vertex. For many purposes, it’s not necessary to include this information for each daily record (here, 365 daily rows per feature).

-

For example, when we ran the same job as above but did not use the selectors argument, the output dataset was 5.7 GB (versus 6.8 MB!) and the runtime was slower. This is a cumbersomely large file, with no real benefit. We generally recommend dropping the .geo column and other unnecessary properties. To retain spatial information, a unique identifier for each feature can be used for downstream joins with the spatial data or other properties. If working with point data, latitude and longitude columns can be added prior to export to maintain easily accessible geographic information, although the .geo column for point data is far smaller than for irregularly shaped polygon features.

-
-
-

7.3.1.2 1.2. Scaling Across Time by Batching: Get 20 Years of Daily Climate Data

-

Above, we extracted one year of daily data for our 293 counties. Let’s say we want to do the same thing, but for 2001–2020. We have already written our script to flexibly specify years, so it’s fairly adaptable to this new use case:

-
// specify years of interest  
-var startYear = 2020;  
-var endYear = 2020;
-

If we only wanted a few years for a small number of features, we could just modify the startYear or endYear and proceed. Indeed, our current example is modest in size and number of features, and we were able to run 2001–2020 in one export job that took about two hours, with an output file size of 299 MB. However, with larger feature collections, or hourly data, we will again start to bump up against Earth Engine’s limits. Generally, jobs of this sort do not fail quickly—exports are allowed to run as long as they continue making progress (see Table F6.2.2). It’s not uncommon, however, for a large job to take well over 24 hours to run, or even to fail after more than 24 hours of run time, as it accumulates too many records or a single aggregation fails. For users, this can be frustrating.

-

We generally find it simpler to run several small jobs rather than one large job. Outputs can then be combined in external software. This avoids any frustration with long-running jobs or delayed failures, and it allows parts of the task to be run simultaneously. Earth Engine generally executes from 2–20 jobs per user at a time, depending on overall user load (although 20 is rare). As a counterpart, there is some overhead for generating separate jobs.

-

Important note: When running a batch of jobs, it may be tempting to use multiple accounts to execute subsets of your batch and thus get your shared results faster. However, doing so is a direct violation of the Earth Engine terms of service and can result in your account(s) being terminated.

-

For-Loops: They Are Sometimes OK

-

Batching jobs in time is a great way to break up a task into smaller units. Other options include batching jobs by spatial regions defined by polygons (see Sect. 2), or for computationally heavy tasks, batching by both space and time.

-

Because Export functions are client-side functions, however, you can’t create an export within an Earth Engine map command. Instead, we need to loop over the variable that will define our batches and create a set of export tasks.

-

But wait! Aren’t we supposed to avoid for-loops at all costs? Yes, within a computational chain. Here, we are using a loop to send multiple computational chains to the server.

-

First, we will start with the same script as in Sect. 1.1, but we will modify the start year. We will also modify the desired output filename to be a generic base filename, to which we will append the year for each task within the loop (in the next step).

-
// Load county dataset.  
-var countiesAll = ee.FeatureCollection('TIGER/2018/Counties');  
-var states = ['17', '18', '19'];  
-var uniqueID = 'GEOID';  
-var featColl = countiesAll.filter(ee.Filter.inList('STATEFP', states))  
-   .select(uniqueID);  
-  
-print(featColl.size());  
-print(featColl.limit(1));  
-Map.addLayer(featColl);  
-  
-// Specify years of interest.  
-var startYear = 2001;  
-var endYear = 2020;  
-  
-// Climate dataset info.  
-var imageCollectionName = 'IDAHO_EPSCOR/GRIDMET';  
-var bandsWanted = ['pr', 'tmmn', 'tmmx'];  
-var scale = 4000;  
-  
-// Export info.  
-var exportFolder = 'GEE_scalingUp';  
-var filenameBase = 'Gridmet_counties_IN_IL_IA_' + scale + 'm_';
-

Now modify the code in Sect. 1.1 to use a looping variable, i, to represent each year. Here, we are using standard JavaScript looping syntax, where i will take on each value between our startYear (2001) and our endYear (2020) for each loop through this section of code, thus creating 20 queries to send to Earth Engine’s servers.

-
// Initiate a loop, in which the variable i takes on values of each year.  
-for (var i = startYear; i <= endYear; i++) {        // for each year....  // Load climate collection for that year. var startDate = i + '-01-01';  
-  
-  var endYear_adj = i + 1; var endDate = endYear_adj + '-01-01'; var imageCollection = ee.ImageCollection(imageCollectionName)  
-     .select(bandsWanted)  
-     .filterBounds(featColl)  
-     .filterDate(startDate, endDate); // Get values at feature collection. var sampledFeatures = imageCollection.map(function(image) {   return image.reduceRegions({  
-     collection: featColl,  
-     reducer: ee.Reducer.mean(),          
-     tileScale: 1,  
-     scale: scale  
-   }).filter(ee.Filter.notNull(bandsWanted))  // remove rows without data     .map(function(f) {                  // add date property       var time_start = image.get('system:time_start');       var dte = ee.Date(time_start).format('YYYYMMdd');       return f.set('date_ymd', dte);  
-   });  
- }).flatten(); // Prepare export: specify properties and filename. var columnsWanted = [uniqueID].concat(['date_ymd'], bandsWanted); var filename = filenameBase + i; Export.table.toDrive({  
-   collection: sampledFeatures,  
-   description: filename,  
-   folder: exportFolder,  
-   fileFormat: 'CSV',  
-   selectors: columnsWanted  
- });  
-   
-}
-
-:::{.callout-note}
-Code Checkpoint F62b. The book’s repository contains a script that shows what your code should look like at this point.
-:::
-When we run this script, it builds our computational query for each year, creating a batch of 20 individual jobs that will show up in the Task pane (Fig. F6.2.4). Each task name includes the year, since we used our looping variable i to modify the base filename we specified.
-
-![Fig. F6.2.4 Creation of batch tasks for each year](F6/image63.png)
-
-
-We now encounter a downside to creating batch tasks within the JavaScript Code Editor: we need to click Run to execute each job in turn. Here, we made this easier by programmatically assigning each job the filename we want, so we can hold the Cmd/Ctrl key and click Run to avoid the export task option window and only need to click once per task. Still, one can imagine that at some number of tasks, one’s patience for clicking Run will be exceeded. We assume that number is different for everyone.
-
-Note: If at any time you have submitted several tasks to the server but want to cancel them all, you can do so more easily from the Earth Engine Task Manager that is linked at the top of the Task pane. You can read about that task manager in the Earth Engine User Guide.
-
-In order to auto-execute jobs in batch mode, we’d need to use the Python API. Interested users can see the Earth Engine User Guide Python API tutorial for further details about the Python API. 
-
-### Scaling Across Space via Spatial Tiling
-
-Breaking up jobs in space is another key strategy for scaling operations in Earth Engine. Here, we will focus on making a cloud-free composite from the Sentinel-2 Level 2A Surface Reflectance product. The approach is similar to that in Chap. F4.3, which explores cloud-free compositing. The main difference is that Landsat scenes come with a reliable quality band for each scene, whereas the process for Sentinel-2 is a bit more complicated and computationally intense (see below).
-
-Our region of interest is the state of Washington in the United States for demonstration purposes, but the method will work at much larger continental scales as well.
-
-Cloud Masking Approach
-
-While we do not intend to cover the theory behind Sentinel-2 cloud masking, we do want to include a brief description of the process to convey the computational needs of this approach.
-
-The Sentinel-2 Level 2A collection does not come with a robust cloud mask. Instead, we will build one from related products that have been developed for this purpose. Following the existing Sentinel-2 cloud masking tutorials in the Earth Engine guides, this approach requires three Sentinel-2 image collections:
-
-*   The Sentinel-2 Level 2A Surface Reflectance product. This is the dataset we want to use to build our final composite.
-*   The Sentinel-2 Cloud Probability Dataset, an ImageCollection that contains cloud probabilities for each Sentinel-2 scene.
-*   The Sentinel-2 Level 1C top-of-atmosphere product. This collection is needed to run the Cloud Displacement Index to identify cloud shadows, which is calculated using ee.Algorithms.Sentinel2.CDI (see Frantz et al. 2018 for algorithm description).
-
-These three image collections all contain 10 m resolution data for every Sentinel-2 scene. We will join them based on their 'system:index' property so we can relate each Level 2A scene with the corresponding cloud probability and cloud displacement index. Furthermore, there are two ee.Image.projection steps to control the scale when calculating clouds and their shadows.
-
-To sum up, the cloud masking approach is computationally costly, thus requiring some thought when applying it at scale.
-
-#### 2.1. Generate a Cloud-Free Satellite Composite: Limits to On-the-Fly Computing
-
-Note: Our focus here is on code structure for implementing spatial tiling. Below, we import existing tested functions for cloud masking using the require command.
-
-First, define our region and time of interest; then, load the module containing the cloud functions.
-
-// Set the Region of Interest:Seattle, Washington, United States  
-var roi = ee.Geometry.Point([-122.33524518034544, 47.61356183942883]);  
-  
-// Dates over which to create a median composite.  
-var start = ee.Date('2019-03-01');  
-var end = ee.Date('2019-09-01');  
-  
-// Specify module with cloud mask functions.  
-var s2mask_tools = require(   'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js'  
-);
-

Next, load and filter our three Sentinel-2 image collections.

-
// Sentinel-2 surface reflectance data for the composite.  
-var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR')  
-   .filterDate(start, end)  
-   .filterBounds(roi)  
-   .select(['B2', 'B3', 'B4', 'B5']);  
-  
-// Sentinel-2 Level 1C data (top-of-atmosphere).    
-// Bands B7, B8, B8A and B10 needed for CDI and the cloud mask function.  
-var s2 = ee.ImageCollection('COPERNICUS/S2')  
-   .filterBounds(roi)  
-   .filterDate(start, end)  
-   .select(['B7', 'B8', 'B8A', 'B10']);  
-  
-// Cloud probability dataset - used in cloud mask function  
-var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY')  
-   .filterDate(start, end)  
-   .filterBounds(roi);
-

Now apply the cloud mask:

-
// Join the cloud probability dataset to surface reflectance.  
-var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c,   'cloud_probability');  
-  
-// Join the L1C data to get the bands needed for CDI.  
-var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2,   'l1c');  
-  
-// Map the cloud masking function over the joined collection.  
-// Cast output to ImageCollection  
-var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools  
-.maskImage));
-

Next, generate and visualize the median composite:

-
// Take the median, specifying a tileScale to avoid memory errors.  
-var median = masked.reduce(ee.Reducer.median(), 8);  
-  
-// Display the results.  
-Map.centerObject(roi, 12);  
-Map.addLayer(roi);  
-  
-var viz = {  
-   bands: ['B4_median', 'B3_median', 'B2_median'],  
-   min: 0,  
-   max: 3000  
-};  
-Map.addLayer(median, viz, 'median');
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F62c. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

After about 1–3 minutes, Earth Engine returns our composite to us on the fly (Fig. F6.2.5). Note that panning and zooming to a new area requires that Earth Engine must again issue the compositing request to calculate the image for new areas. Given the delay, this isn’t a very satisfying way to explore our composite.

-

Fig. F6.2.5 Map view of Seattle, Washington, USA (left) and the corresponding Sentinel-2 composite (right)Fig. F6.2.5 Map view of Seattle, Washington, USA (left) and the corresponding Sentinel-2 composite (right)

-

Next, expand our view (set zoom to 9) to exceed the limits of on-the-fly computation (Fig. F6.2.6).

-

Map.centerObject(roi, 9);
-Map.addLayer(roi);
-Map.addLayer(median, viz, ‘median’);

-
-
-

-

Fig. F6.2.6 Error message for exceeding memory limits in interactive mode

-
-
-

As you can see, this is an excellent candidate for an export task rather than running in “on-the-fly” interactive mode, as above.

-
-
-

7.3.1.3 2.2. Generate a Regional Composite Through Spatial Tiling

-

Our goal is to apply the cloud masking method in Sect. 2.1 to the state of Washington, United States. In our testing, we successfully exported one Sentinel-2 composite for this area in about nine hours, but for this tutorial, let’s presume we need to split the task up to be successful.

-

Essentially, we want to split our region of interest up into a regular grid. For each grid, we will export a composite image into a new ImageCollection asset. We can then load and mosaic our composite for use in downstream scripts (see below).

-

First, generate a spatial polygon grid (FeatureCollection) of desired size over your region of interest (see Fig. F6.2.7):

-
// Specify helper functions.  
-var s2mask_tools = require(   'projects/gee-edu/book:Part F - Fundamentals/F6 - Advanced Topics/F6.2 Scaling Up/modules/s2cloudmask.js'  
-);  
-  
-// Set the Region of Interest: Washington, USA.  
-var roi = ee.FeatureCollection('TIGER/2018/States')  
-   .filter(ee.Filter.equals('NAME', 'Washington'));  
-  
-// Specify grid size in projection, x and y units (based on projection).  
-var projection = 'EPSG:4326'; // WGS84 lat lon  
-var dx = 2.5;  
-var dy = 1.5;  
-  
-// Dates over which to create a median composite.  
-var start = ee.Date('2019-03-01');  
-var end = ee.Date('2019-09-01');  
-  
-// Make grid and visualize.  
-var proj = ee.Projection(projection).scale(dx, dy);  
-var grid = roi.geometry().coveringGrid(proj);  
-  
-Map.addLayer(roi, {}, 'roi');  
-Map.addLayer(grid, {}, 'grid');
-
-
-

-

Fig. F6.2.7 Visualization of the regular spatial grid generated for use in spatial batch processing

-
-
-

Next, create a new, empty ImageCollection asset to use as our export destination (Assets > New > Image Collection; Fig. F6.2.8). Name the image collection ‘S2_composite_WA’ and specify the asset location in your user folder (e.g., “path/to/your/asset/s2_composite_WA”).

-
-
-

-

Fig. F6.2.8 The “create new image collection asset” menu in the Code Editor

-
-
-

Specify the ImageCollection to export to, along with a base name for each image (the tile number will be appended in the batch export).

-
// Export info.  
-var assetCollection = 'path/to/your/asset/s2_composite_WA';  
-var imageBaseName = 'S2_median_';
-

Extract grid numbers to use as looping variables. Note there is one getInfo call here, which should be used sparingly and never within a for-loop if you can help it. We use it to bring the number of grid cells we’ve generated onto the client-side to set up the for-loop over grids. Note that if your grid has too many elements, you may need a different strategy.

-
// Get a list based on grid number.  
-var gridSize = grid.size().getInfo();  
-var gridList = grid.toList(gridSize);
-

Batch generate a composite image task export for each grid via looping:

-
// In each grid cell, export a composite  
-for (var i = 0; i < gridSize; i++) {   // Extract grid polygon and filter S2 datasets for this region.   var gridCell = ee.Feature(gridList.get(i)).geometry();   var s2Sr = ee.ImageCollection('COPERNICUS/S2_SR')  
-       .filterDate(start, end)  
-       .filterBounds(gridCell)  
-       .select(['B2', 'B3', 'B4', 'B5']);   var s2 = ee.ImageCollection('COPERNICUS/S2')  
-       .filterDate(start, end)  
-       .filterBounds(gridCell)  
-       .select(['B7', 'B8', 'B8A', 'B10']);   var s2c = ee.ImageCollection('COPERNICUS/S2_CLOUD_PROBABILITY')  
-       .filterDate(start, end)  
-       .filterBounds(gridCell);   // Apply the cloud mask.   var withCloudProbability = s2mask_tools.indexJoin(s2Sr, s2c,       'cloud_probability');   var withS2L1C = s2mask_tools.indexJoin(withCloudProbability, s2,       'l1c');   var masked = ee.ImageCollection(withS2L1C.map(s2mask_tools  
-       .maskImage));   // Generate a median composite and export.   var median = masked.reduce(ee.Reducer.median(), 8);   // Export.   var imagename = imageBaseName + 'tile' + i;   Export.image.toAsset({  
-       image: median,  
-       description: imagename,  
-       assetId: assetCollection + '/' + imagename,  
-       scale: 10,  
-       region: gridCell,  
-       maxPixels: 1e13   });  
-}
-
-:::{.callout-note}
-Code Checkpoint F62d. The book’s repository contains a script that shows what your code should look like at this point.
-:::
-Similar to Sect. 1.2, we now have a list of tasks to execute. We can hold the Cmd/Ctrl key and click Run to execute each task (Fig. F6.2.9). Again, users with applications requiring large batches may want to explore the Earth Engine Python API, which is well-suited to batching work. The output ImageCollection is 35.3 GB, so you may not want to execute all (or any) of these tasks but can access our pre-generated image, as discussed below.
-
-![Fig. F6.2.9 Spatial batch tasks have been generated and are ready to run](F6/image22.png)
-
-
-In addition to being necessary for very large regions, batch processing can speed things up for moderate scales. In our tests, tiles averaged about one hour to complete. Because three jobs in our queue were running simultaneously, we covered the full state of Washington in about four hours (compared to about nine hours when tested for the full state of Washington at once). Users should note, however, that there is also an overhead to spinning up each batch task. Finding the balance between task size and task number is a challenge for most Earth Engine users that becomes easier with experience.
-
-In a new script, load the exported ImageCollection and mosaic for use.
-
-// load image collection and mosaic into single image  
-var assetCollection = 'projects/gee-book/assets/F6-2/s2_composite_WA';  
-var composite = ee.ImageCollection(assetCollection).mosaic();  
-  
-// Display the results  
-var geometry = ee.Geometry.Point([-120.5873563817392,   47.39035206888694  
-]);  
-Map.centerObject(geometry, 6);  
-var vizParams = {  
-   bands: ['B4_median', 'B3_median', 'B2_median'],  
-   min: 0,  
-   max: 3000  
-};  
-Map.addLayer(composite, vizParams, 'median');
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F62e. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-
-
-

-

Fig. F6.2.10 Sentinel-2 composite covering the state of Washington, loaded from asset. The remaining white colors are snow-capped mountains, not clouds.

-
-
-

Note the ease, speed, and joy of panning and zooming to explore the pre-computed composite asset (Fig. F6.2.10) compared to the on-the-fly version discussed in Sect. 2.1.

-
-
-
-

7.3.2 Multistep Workflows and Intermediate Assets

-

Often, our goals require several processing steps that cannot be completed within one Earth Engine computational chain. In these cases, the best strategy becomes breaking down tasks into individual pieces that are created, stored in assets, and used across several scripts. Each sequential script creates an intermediate output, and this intermediate output becomes the input to the next script.

-

As an example, consider the land use classification task of identifying irrigated agricultural lands. This type of classification can benefit from several types of evidence, including satellite composites, aggregated weather information, soil information, and/or crop type locations. Individual steps for this type of work might include:

-
    -
  • Generating satellite composites of annual or monthly vegetation indices
  • -
  • Processing climate data into monthly or seasonal values
  • -
  • Generating random point locations from a ground truth layer for use as a feature training dataset and accuracy validation, and extracting composite and weather values at these features
  • -
  • Training a classifier and applying it, possibly across multiple years; researchers will often implement multiple classifiers and compare the performance of different methods
  • -
  • Implementing post-classification cleaning steps, such as removing “speckle”
  • -
  • Evaluating accuracy at ground truth validation points, and against government statistics using total area per administrative boundary
  • -
  • Exporting your work as spatial layers, visualizations, or other formats
  • -
-

Multipart workflows can become unwieldy to manage, particularly if there are multiple collaborators or the project has a long timeline; it can be difficult to remember why each script was developed and where it fits in the overall workflow.

-

Here, we provide tips for managing multipart workflows. These are somewhat opinionated and based largely on concepts from “Good Enough Practices in Scientific Computing” (Wilson et al. 2017). Ultimately, your personal workflow practices will be a combination of what works for you, what works for your larger team and organization, and, hopefully, what works for good documentation and reproducibility.

-

Tip 1. Create a repository for each project

-

The repository can be considered the fundamental project unit. In Earth Engine, sharing permissions are set for each individual repository, so this allows you to share a specific project with others (see Chap. F6.1).

-

By default, Earth Engine saves new scripts in a “default” repository specific for each user (users//default). You can create new repositories on the Scripts tab of the Code Editor (Fig. F6.2.11).

-
-
-

-

Fig. F6.2.11 The Code Editor menu for creating new repositories

-
-
-

To adjust permissions for each repository, click on the Gear icon (Fig. F6.2.12):

-
-
-

-

Fig. F6.2.12 Access the sharing and permissions menu for each repository by clicking the Gear icon

-
-
-

For users familiar with version control, Earth Engine uses a git-based script manager, so each repository can also be managed, edited, and/or synced with your local copy or collaborative spaces like GitHub.

-

Tip 2. Make a separate script for each step, and make script file names informative and self-sorting

-

Descriptive, self-sorting filenames are an excellent “good enough” way to keep your projects organized. We recommend starting script names with zero-padded numeric values to take advantage of default ordering. Because we are generating assets in early scripts that are used in later scripts, it’s important to preserve the order of your workflow. The name should also include short descriptions of what the script does (Fig. F6.2.13).

-
-
-

-

Fig. F6.2.13 An example project repository with multiple scripts. Using leading numbers when naming scripts allows you to order them by their position in the workflow.

-
-
-

Leaving some decimal places between successive scripts gives you the ability to easily insert any additional steps you didn’t originally anticipate. And zero-padding means your self-sorting still works once you move into double-digit numbers.

-

Other script organization strategies might involve including subfolders to collect scripts related to main steps. For example, one could have a subfolder “04_classifiers” to keep alternative classification scripts in one place, using a more tree-based file structure. Again, each user or group will develop a system that works for them. The important part is to have an organizational system.

-

Tip 3. Consider data types and file sizes when storing intermediates

-

Images and image collections are common intermediate file types, since generating satellite composites or creating land use classifications tends to be computationally intensive. These assets can also be quite large, depending on the resolution and region size. Recall that our single-year, subregional Sentinel-2 composite in Sect. 2 was about 23 GB.

-

Image values can be stored from 8-bit integers to 64-bit double floats (numbers with decimals). Higher bits allow for more precision, but have much larger file sizes and are not always necessary. For example, if we are generating a land use map with five classes, we can convert that to a signed or unsigned 8-bit integer using toInt8 or toUint8 prior to exporting to asset, which can accommodate 256 unique values. This results in a smaller file size. Selectively retaining only bands of interest is also helpful to reduce size.

-

For cases requiring decimals and precision, consider whether a 32-bit float will do the job instead of a 64-bit double—toFloat will convert an image to a 32-bit float. If you find you need to conserve storage, you can also scale float values and store as an integer image (image.multiply(100).toInt16(), for example). This would retain precision to the second decimal place and reduce file size by a factor of two. Note that this may require you to unscale the values in downstream use. Ultimately, the appropriate data type will be specific to your needs.

-

And of course, as mentioned above under “The Importance of Best Coding Practices,” be aware of the scale resolution you are working at, and avoid using unnecessarily high resolution when it’s not supported by either the input imagery or your research goals.

-

Tip 4. Consider Google Cloud Platform for hosting larger intermediates

-

If you are working with very large or very many files, you can link Earth Engine with Cloud Projects on Google Cloud Platform. See the Earth Engine documentation on “Setting Up Earth Engine Enabled Cloud Projects” for more information.

-
-
-

Conclusion

-

In this chapter, you learned how to design Earth Engine Apps using both the Earth Engine User Interface API (JavaScript) and geemap (Python). You also learned how to deploy Earth Engine Apps on multiple platforms, such as the JavaScript Code Editor, a local web server, and Heroku. The skill of designing and deploying interactive Earth Engine Apps is essential for making your research and data products more accessible to the scientific community and the general public. Anyone with the link to your web App can analyze and visualize Earth Engine datasets without needing an Earth Engine account.

-
-
-

References

- -

Chapter F6.4: Combining R and Earth Engine

-
-
-
- -
-
-Chapter Information -
-
-
-
-

Author

-

Cesar Aybar, David Montero, Antony Barja, Fernando Herrera, Andrea Gonzales, and Wendy Espinoza

-
-
-

Overview

-

The purpose of this chapter is to introduce rgee, a non-official API for Earth Engine. You will explore the main features available in rgee and how to set up an environment that integrates rgee with third-party R and Python packages. After this chapter, you will be able to combine R, Python, and JavaScript in the same workflow.

-
-
-

Learning Outcomes

-
    -
  • Becoming familiar with rgee, the Earth Engine R API interface.
  • -
  • Integrating rgee with other R packages.
  • -
  • Displaying interactive maps.
  • -
  • Integrating Python and R packages using reticulate.
  • -
  • Combining Earth Engine JavaScript and Python APIs with R.
  • -
-
-
-

Assumes you know how to:

-
    -
  • Install the Python environment (Chap. F6.3).
  • -
  • Use the require function to load code from existing modules (Chap. F6.1).
  • -
  • Use the basic functions and logic of Python.
  • -
  • Configure an environment variable and use .Renviron files.
  • -
  • Create Python virtual environments.
  • -
-
-
-
-
-
-

Introduction

-

R is a popular programming language established in statistical science with large support in reproducible research, geospatial analysis, data visualization, and much more. To get started with R, you will need to satisfy some extra software requirements. First, install an up-to-date R version (at least 4.0) in your work environment. The installation procedure will vary depending on your operating system (i.e., Windows, Mac, or Linux). Hands-On Programming with R (Garrett Grolemund 2014, Appendix A) explains step by step how to proceed. We strongly recommend that Windows users install Rtools to avoid compiling external static libraries.

-

If you are new to R, a good starting point is the book Geocomputation with R (Lovelace et al. 2019) or Spatial Data Science with Application in R (Pebesma and Bivand 2021). In addition, we recommend using an integrated development environment (e.g., Rstudio) or a code editor (e.g., Visual Studio Code) to create a suitable setting to display and interact with R objects.

-

The following R packages must be installed (find more information in the R manual) in order to go through the practicum section.

-
-
-
-

7.4 Use install.packages to install R packages from the CRAN repository.

-

install.packages(‘reticulate’) # Connect Python with R.
-install.packages(‘rayshader’) # 2D and 3D data visualizations in R.
-install.packages(‘remotes’) # Install R packages from remote repositories.
-remotes::install_github(‘r-earthengine/rgeeExtra’) # rgee extended.
-install.packages(‘rgee’) # GEE from within R.
-install.packages(‘sf’) # Simple features in R.
-install.packages(‘stars’) # Spatiotemporal Arrays and Vector Data Cubes.
-install.packages(‘geojsonio’) # Convert data to ‘GeoJSON’ from various R classes.
-install.packages(‘raster’) # Reading, writing, manipulating, analyzing and modeling of spatial data.
-install.packages(‘magick’) # Advanced Graphics and Image-Processing in R
-install.packages(‘leaflet.extras2’) # Extra Functionality for leaflet
-install.packages(‘cptcity’) # colour gradients from the ‘cpt-city’ web archive

-

Earth Engine officially supports client libraries only for the JavaScript and Python programming languages. While the Earth Engine Code Editor offers a convenient environment for rapid prototyping in JavaScript, the lack of a mechanism for integration with local environments makes the development of complex scripts tricky. On the other hand, the Python client library offers much versatility, enabling support for third-party packages. However, not all Earth and environmental scientists code in Python. Hence, a significant number of professionals are not members of the Earth Engine community. In the R ecosystem, rgee (Aybar et al. 2020) tries to fill this gap by wrapping the Earth Engine Python API via reticulate (Kevin Ushey et al. 2021). The rgee package extends and supports all the Earth Engine classes, modules, and functions, working as fast as the other APIs.

-
-
-

-

Fig. F6.4.1 A simplified diagram of rgee functionality

-
-
-

Figure F6.4.1 illustrates how rgee bridges the Earth Engine platform with the R ecosystem. When an Earth Engine request is created in R, rgee transforms this piece of code into Python. Next, the Earth Engine Python API converts the Python code into JSON. Finally, the JSON file request is received by the server through a Web REST API. Users could get the response using the getInfo method by following the same path in reverse.

-
-

7.4.1 Installing rgee

-

To run, rgee needs a Python environment with two packages: NumPy and earthengine-api. Because instructions change frequently, installation is explained at the following checkpoint:

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64a. The book’s repository contains information about setting up the rgee environment.

-
-
-

After installing both the R and Python requirements, you can now initialize your Earth Engine account from within R. Consider that R, in contrast to Javascript and Python, supports three distinct Google APIs: Earth Engine, Google Drive, and Google Cloud Storage (GCS).

-

The Google Drive and GCS APIs will allow you to transfer your Earth Engine completed task exports to a local environment automatically. In these practice sessions, we will use only the Earth Engine and Google Drive APIs. Users that are interested in GCS can look up and explore the GCS vignette. To initialize your Earth Engine account alongside Google Drive, use the following commands.

-
-
-
-

7.5 Initialize just Earth Engine

-

ee_Initialize()

-
-
-

7.6 Initialize Earth Engine and GDee_Initialize(drive = TRUE)

-

If the Google account is verified and the permission is granted, you will be directed to an authentication token. Copy and paste this token into your R console. Consider that the GCS API requires setting up credentials manually; look up and explore the rgee vignette for more information. The verification step is only required once; after that, rgee saves the credentials in your system.

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64b. The book’s repository contains information about what your code should look like at this point.

-
-
-
-

7.6.1 Creating a 3D Population Density Map with rgee and rayshader

-

First, import the rgee, rayshader, and raster packages.

-

library(rayshader)
-library(raster)
-library(rgee)

-

Initialize the Earth Engine and Google Drive APIs using ee_Initialize. Both credentials must come from the same Google account.

-

ee_Initialize(drive = TRUE)

-

Then, we will access the WorldPop Global Project Population Data dataset. In rgee, the Earth Engine spatial classes (ee\(Image, ee\)ImageCollection, and ee$FeatureCollection) have a special attribute called Dataset. Users can use it along with autocompletion to quickly find the desired dataset.

-

collections <- ee\(ImageCollection\)Dataset
-population_data <- collections\(CIESIN_GPWv411_GPW_Population_Density population_data_max <- population_data\)max()

-

If you need more information about the Dataset, use ee_utils_dataset_display to go to the official documentation in the Earth Engine Data Catalog.

-

population_data %>% ee_utils_dataset_display()

-

The rgee package provides various built-in functions to retrieve data from Earth Engine (Aybar et al. 2020). In this example, we use ee_as_raster, which automatically converts an ee$Image (server object) into a RasterLayer (local object).

-

sa_extent <- ee\(Geometry\)Rectangle(
-coords = c(-100, -50, -20, 12),
-geodesic = TRUE,
-proj = “EPSG:4326”)

-

population_data_ly_local <- ee_as_raster(
-image = population_data_max,
-region = sa_extent,
-dsn = “/home/pc-user01/population.tif”, # change for your own path. scale = 5000
-)

-

Now, turn a RasterLayer into a matrix suitable for rayshader.

-

pop_matrix <- raster_to_matrix(population_data_ly_local)

-

Next, modify the matrix population density values, adding:

-
    -
  • Texture, based on five colors (lightcolor, shadowcolor, leftcolor, rightcolor, and centercolor; see rayshader::create_texture documentation)
  • -
  • Color and shadows (rayshader::sphere_shade)
  • -
-

pop_matrix %>%
-sphere_shade(
-texture = create_texture(“#FFFFFF”, “#0800F0”, “#FFFFFF”, “#FFFFFF”, “#FFFFFF”)
-) %>%
-plot_3d(
-pop_matrix,
-zoom = 0.55, theta = 0, zscale = 100, soliddepth = -24,
-solidcolor = “#525252”, shadowdepth = -40, shadowcolor = “black”,
-shadowwidth = 25, windowsize = c(800, 720)
-)

-

Lastly, define a title and subtitle for the plot. Use rayshader::render_snapshot to export the final results (Fig. F6.4.2).

-

text <- paste0( “South Americanpopulation density”,
-strrep(“n”, 27), “Source:GPWv411: Population Density (Gridded Population of the World Version 4.11)”)

-

render_snapshot(
-filename = “30_poblacionsudamerica.png”,
-title_text = text,
-title_size = 20,
-title_color = “black”,
-title_font = “Roboto bold”,
-clear = TRUE
-)

-
-
-

-

Fig. F6.4.2 3D population density map of South America

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64c. The book’s repository contains information about what your code should look like at this point.

-
-
-
-
-

7.6.2 Displaying Maps Interactively

-

Similar to the Code Editor, rgee supports the interactive visualization of spatial Earth Engine objects by Map$addLayer. First, let’s import the rgee and cptcity packages. The cptcity R package is a wrapper to the cpt-city color gradients web archive.

-

library(rgee)
-library(cptcity)
-ee_Initialize()

-

We’ll select an ee$Image; in this case, the Shuttle Radar Topography Mission 90 m (SRTM-90) Version 4.

-

dem <- ee\(Image\)Dataset$CGIAR_SRTM90_V4

-

Then, we’ll set the visualization parameters as a list with the following elements.

-
    -
  • min: value(s) to map to 0
  • -
  • max: value(s) to map to 1
  • -
  • palette: a list of CSS-style color strings
  • -
-

viz <- list(
-min = 600,
-max = 6000,
-palette = cpt(pal = ‘grass_elevation’, rev = TRUE)
-)

-

Then, we’ll create a simple display using Map$addLayer.

-

m1 <- Map$addLayer(dem, visParams = viz, name = “SRTM”, shown = TRUE)

-

Optionally, you could add a custom legend using Map$addLayer (Fig. F6.4.3).

-

pal <- Map$addLegend(viz)
-m1 + pal

-
-
-

-

Fig. F6.4.3 Interactive visualization of SRTM-90 Version 4 elevation values

-
-
-

The procedure to display ee\(Geometry, ee\)Feature, and ee\(FeatureCollections objects is similar to the previous example effected on an ee\)Image. Users just need to change the arguments: eeObject and visParams.

-

First, Earth Engine geometries (Fig. F6.4.4).

-

vector <- ee\(Geometry\)Point(-77.011,-11.98) %>%
-ee\(Feature\)buffer(50*1000)
-Map\(centerObject(vector) Map\)addLayer(vector) # eeObject is a ee\(Geometry\)Polygon.

-
-
-

-

Fig. F6.4.4 A polygon buffer surrounding the city of Lima, Peru

-
-
-

Next, Earth Engine feature collections (Fig. F6.4.5).

-

building <- ee\(FeatureCollection\)Dataset$
-GOOGLE_Research_open-buildings_v1_polygon
-Map\(setCenter(3.389, 6.492, 17) Map\)addLayer(building) # eeObject is a ee$FeatureCollection

-
-
-

-

Fig. F6.4.5 Building footprints in Lagos, Nigeria

-
-
-

The rgee functionality also supports the display of ee\(ImageCollection via Map\)addLayers (note the extra “s” at the end). Map\(addLayers will use the same visualization parameters for all the images (Fig. F6.4.6). If you need different visualization parameters per image, use a Map\)addLayer within a for loop.

-
-
-
-

7.7 Define a ImageCollection

-

etp <- ee\(ImageCollection\)Dataset\(MODIS_NTSG_MOD16A2_105 %>% ee\)ImageCollection\(select("ET") %>% ee\)ImageCollection$filterDate(‘2014-04-01’, ‘2014-06-01’)

-
-
-

7.8 Set viz paramsviz <- list(

-

min = 0, max = 300,
-palette = cpt(pal = “grass_bcyr”, rev = TRUE)
-)

-
- -
-

7.10 Estimate the median of the yearly composites from 2016 to 2020.

-

median <- myclass\(get_year_composite()\)median()

-
-
-

7.11 Estimate the median of the winter season composites from 2016 to 2020.

-

wintermax <- myclass\(get_year_composite()\)select(‘winter’)$max()

-

We can display maps interactively using the Map$addLayer (Fig. F6.4.9), and use the leaflet layers control to switch between basemaps.

-

Map\(addLayer(wintermax, list(min = 0.1, max = 0.8), 'winterMax') | Map\)addLayer(median, list(min = 0.1, max = 0.8), ‘median’)

-
-
-

-

Fig. F6.4.9 Comparison between the maximum historic winter NDVI and the mean historic NDVI. Colors represent the season when the maximum value occurred.

-
-
-

And we can export the results to a GIF format.

-

myclass$get_gif()

-

To get more information about the ndvi2gif package, visit its GitHub repository.

-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64e. The book’s repository contains information about what your code should look like at this point.

-
-
-
-

7.11.1 Converting JavaScript Modules to R

-

In recent years, the Earth Engine community has developed a lot of valuable third-party modules. Some incredible ones are geeSharp (Zuspan 2020), ee-palettes (Donchyts et al. 2020), spectral (Montero 2021), and LandsatLST (Ermida et al. 2020). While some of these modules have been implemented in Python and JavaScript (e.g., geeSharp and spectral), most are available only for JavaScript. This is a critical drawback, because it divides the Earth Engine community by programming languages. For example, if an R user wants to use tagee (Safanelli et al. 2020), the user will have to first translate the entire module to R.

-

In order to close this breach, the ee_extra Python package has been developed to unify the Earth Engine community. The philosophy behind ee_extra is that all of its extended functions, classes, and methods must be functional for the JavaScript, Julia, R, and Python client libraries. Currently, ee_extra is the base of the rgeeExtra (Aybar et al. 2021) and eemont (Montero 2021) packages.

-

To demonstrate the potential of ee_extra, let’s study an example from the Landsat Land Surface Temperature (LST) JavaScript module. The Landsat LST module computes the land surface temperature for Landsat products (Ermida et al. 2020). First we will run it in the Earth Engine Code Editor; then we will replicate those results in R.

-

First, JavaScript. In a new script in the Code Editor, we must require the Landsat LST module.

-

var LandsatLST = require( ‘users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js’);

-

The Landsat LST module contains a function named collection. This function receives the following parameters.

-
    -
  • The Landsat archive ID
  • -
  • The starting date of the Landsat collection
  • -
  • The ending date of the Landsat collection
  • -
  • The region of interest as geometry
  • -
  • A Boolean parameter specifying if we want to use the NDVI for computing a dynamic emissivity instead of using the emissivity from ASTER
  • -
-

In the following code block, we are going to define all required parameters.

-

var geometry = ee.Geometry.Rectangle([-8.91, 40.0, -8.3, 40.4]);
-var satellite = ‘L8’;
-var date_start = ‘2018-05-15’;
-var date_end = ‘2018-05-31’;
-var use_ndvi = true;

-

Now, with all our parameters defined, we can compute the land surface temperature by using the collection method from Landsat LST.

-

var LandsatColl = LandsatLST.collection(satellite, date_start,
-date_end, geometry, use_ndvi);

-

The result is stored as an ImageCollection in the LandsatColl variable. Now select the first element of the collection as an example by using the first method.

-

var exImage = LandsatColl.first();

-

This example image is now stored in a variable named ‘exImage’. Let’s display the LST result on the Map. For visualization purposes, we’ll define a color palette.

-

var cmap = [‘blue’, ‘cyan’, ‘green’, ‘yellow’, ‘red’];

-

Then, we’ll center the map in the region of interest.

-

Map.centerObject(geometry);

-

Finally, let’s display the LST with the cmap color palette by using the Map.addLayer method (Fig. F6.4.10). This method receives the image to visualize, the visualization parameters, the color palette, and the name of the layer to show in the layer control. The visualization parameters will be:

-
    -
  • min: 290 (a minimum LST value of 290 K)
  • -
  • max: 320 (a maximum LST value of 320 K)
  • -
  • palette: cmap (the color palette that was created some steps before)
  • -
-

The name of the layer in the Map layer set will be LST.

-

Map.addLayer(exImage.select(‘LST’), {
-min: 290,
-max: 320,
-palette: cmap
-}, ‘LST’)

-
-
-

-

Fig. F6.4.10 A map illustrating LST, obtained by following the JavaScript example

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64f. The book’s repository contains a script that shows what your code should look like at this point.

-
-
-

Now, let’s use R to implement the same logic. As in the previous sections, import the R packages: rgee and rgeeExtra. Then, initialize your Earth Engine session.

-

library(rgee)
-library(rgeeExtra)
-library(reticulate)

-

ee_Initialize()

-

Install rgeeExtra Python dependencies.

-

py_install(packages = c(“regex”, “ee_extra”, “jsbeautifier”))

-

Using the function rgeeExtra::module loads the JavaScript module.

-

LandsatLST <- module(“users/sofiaermida/landsat_smw_lst:modules/Landsat_LST.js”)

-

The rest of the code is exactly the same as in JavaScript.

-

geometry <- ee\(Geometry\)Rectangle(c(-8.91, 40.0, -8.3, 40.4))
-satellite <- ’L8’date_start <- ’2018-05-15’date_end <- ’2018-05-31’use_ndvi <- TRUE

-

LandsatColl <- LandsatLST\(collection(satellite, date_start, date_end, geometry, use_ndvi) exImage <- LandsatColl\)first()
-cmap <- c(‘blue’, ‘cyan’, ‘green’, ‘yellow’, ‘red’)

-

lmod <- list(min = 290, max = 320, palette = cmap)
-Map\(centerObject(geometry) Map\)addLayer(exImage$select(‘LST’), lmod, ‘LST’)

-
-
-

-

Fig. F6.4.11 A map illustrating LST, obtained by following the R example

-
-
-
-
-
- -
-
-Note -
-
-
-

Code Checkpoint F64g. The book’s repository contains information about what your code should look like at this point.

-
-
-

Question 1. When and why might users prefer to use R instead of Python to connect to Earth Engine?

-

Question 2. What are the advantages and disadvantages of using rgee instead of the Earth Engine JavaScript Code Editor?

-
-
-

Conclusion

-

In this chapter, you learned how to use Earth Engine and R in the same workflow. Since rgee uses reticulate, rgee also permits integration with third-party Earth Engine Python packages. You also learned how to use Map$addLayer, which works similarly to the Earth Engine User Interface API (Code Editor). Finally, we also introduced rgeeExtra, a new R package that extends the Earth Engine API and supports JavaScript module execution.

-
-
-

References

-

Aybar C, Wu Q, Bautista L, et al (2020) rgee: An R package for interacting with Google Earth Engine. J Open Source Softw 5:2272. https://doi.org/10.21105/joss.02272

-

Ermida SL, Soares P, Mantas V, et al (2020) Google Earth Engine open-source code for land surface temperature estimation from the Landsat series. Remote Sens 12:1471. https://doi.org/10.3390/RS12091471

-

Grolemund G (2014) Hands-On Programming with R - Write Your Own Functions and Simulations. O’Reilly Media, Inc.

-

Lovelace R, Nowosad J, Muenchow J (2019) Geocomputation with R. Chapman and Hall/CRC

-

Montero D (2021) eemont: A Python package that extends Google Earth Engine. J Open Source Softw 6:3168. https://doi.org/10.21105/joss.03168

-

Pebesma E, Bivand R (2019) Spatial Data Science. https://r-spatial.org/book/

- - -
-
- -
- - - -
- - - - \ No newline at end of file diff --git a/docs/F6/image10.png b/docs/F6/image10.png deleted file mode 100644 index e34a306..0000000 Binary files a/docs/F6/image10.png and /dev/null differ diff --git a/docs/F6/image11.png b/docs/F6/image11.png deleted file mode 100644 index bdcd522..0000000 Binary files a/docs/F6/image11.png and /dev/null differ diff --git a/docs/F6/image12.png b/docs/F6/image12.png deleted file mode 100644 index 6ea3cea..0000000 Binary files a/docs/F6/image12.png and /dev/null differ diff --git a/docs/F6/image13.png b/docs/F6/image13.png deleted file mode 100644 index e380cce..0000000 Binary files a/docs/F6/image13.png and /dev/null differ diff --git a/docs/F6/image15.png b/docs/F6/image15.png deleted file mode 100644 index d49c223..0000000 Binary files a/docs/F6/image15.png and /dev/null differ diff --git a/docs/F6/image16.png b/docs/F6/image16.png deleted file mode 100644 index 5b9c6c8..0000000 Binary files a/docs/F6/image16.png and /dev/null differ diff --git a/docs/F6/image17.png b/docs/F6/image17.png deleted file mode 100644 index 5476158..0000000 Binary files a/docs/F6/image17.png and /dev/null differ diff --git a/docs/F6/image19.png b/docs/F6/image19.png deleted file mode 100644 index 326de06..0000000 Binary files a/docs/F6/image19.png and /dev/null differ diff --git a/docs/F6/image2.png b/docs/F6/image2.png deleted file mode 100644 index 5f39103..0000000 Binary files a/docs/F6/image2.png and /dev/null differ diff --git a/docs/F6/image20.png b/docs/F6/image20.png deleted file mode 100644 index 5db5807..0000000 Binary files a/docs/F6/image20.png and /dev/null differ diff --git a/docs/F6/image21.png b/docs/F6/image21.png deleted file mode 100644 index ffb5c62..0000000 Binary files a/docs/F6/image21.png and /dev/null differ diff --git a/docs/F6/image23.png b/docs/F6/image23.png deleted file mode 100644 index fd8f6e2..0000000 Binary files a/docs/F6/image23.png and /dev/null differ diff --git a/docs/F6/image24.png b/docs/F6/image24.png deleted file mode 100644 index 999051e..0000000 Binary files a/docs/F6/image24.png and /dev/null differ diff --git a/docs/F6/image25.png b/docs/F6/image25.png deleted file mode 100644 index 55ade15..0000000 Binary files a/docs/F6/image25.png and /dev/null differ diff --git a/docs/F6/image26.png b/docs/F6/image26.png deleted file mode 100644 index b897993..0000000 Binary files a/docs/F6/image26.png and /dev/null differ diff --git a/docs/F6/image28.png b/docs/F6/image28.png deleted file mode 100644 index 62e9f0e..0000000 Binary files a/docs/F6/image28.png and /dev/null differ diff --git a/docs/F6/image29.png b/docs/F6/image29.png deleted file mode 100644 index 9a16b4c..0000000 Binary files a/docs/F6/image29.png and /dev/null differ diff --git a/docs/F6/image3.png b/docs/F6/image3.png deleted file mode 100644 index eea31f5..0000000 Binary files a/docs/F6/image3.png and /dev/null differ diff --git a/docs/F6/image30.png b/docs/F6/image30.png deleted file mode 100644 index e8f9b04..0000000 Binary files a/docs/F6/image30.png and /dev/null differ diff --git a/docs/F6/image33.png b/docs/F6/image33.png deleted file mode 100644 index ea58383..0000000 Binary files a/docs/F6/image33.png and /dev/null differ diff --git a/docs/F6/image35.png b/docs/F6/image35.png deleted file mode 100644 index 883a089..0000000 Binary files a/docs/F6/image35.png and /dev/null differ diff --git a/docs/F6/image36.png b/docs/F6/image36.png deleted file mode 100644 index cf98bee..0000000 Binary files a/docs/F6/image36.png and /dev/null differ diff --git a/docs/F6/image39.png b/docs/F6/image39.png deleted file mode 100644 index 086019f..0000000 Binary files a/docs/F6/image39.png and /dev/null differ diff --git a/docs/F6/image40.png b/docs/F6/image40.png deleted file mode 100644 index cd73a83..0000000 Binary files a/docs/F6/image40.png and /dev/null differ diff --git a/docs/F6/image41.png b/docs/F6/image41.png deleted file mode 100644 index e97ec6c..0000000 Binary files a/docs/F6/image41.png and /dev/null differ diff --git a/docs/F6/image42.png b/docs/F6/image42.png deleted file mode 100644 index 471359e..0000000 Binary files a/docs/F6/image42.png and /dev/null differ diff --git a/docs/F6/image43.png b/docs/F6/image43.png deleted file mode 100644 index aefa951..0000000 Binary files a/docs/F6/image43.png and /dev/null differ diff --git a/docs/F6/image44.png b/docs/F6/image44.png deleted file mode 100644 index ecd813d..0000000 Binary files a/docs/F6/image44.png and /dev/null differ diff --git a/docs/F6/image45.png b/docs/F6/image45.png deleted file mode 100644 index fa3fcce..0000000 Binary files a/docs/F6/image45.png and /dev/null differ diff --git a/docs/F6/image46.png b/docs/F6/image46.png deleted file mode 100644 index 6235552..0000000 Binary files a/docs/F6/image46.png and /dev/null differ diff --git a/docs/F6/image47.png b/docs/F6/image47.png deleted file mode 100644 index bf9f189..0000000 Binary files a/docs/F6/image47.png and /dev/null differ diff --git a/docs/F6/image48.png b/docs/F6/image48.png deleted file mode 100644 index 56ede49..0000000 Binary files a/docs/F6/image48.png and /dev/null differ diff --git a/docs/F6/image49.png b/docs/F6/image49.png deleted file mode 100644 index 6e6258e..0000000 Binary files a/docs/F6/image49.png and /dev/null differ diff --git a/docs/F6/image50.png b/docs/F6/image50.png deleted file mode 100644 index 60236ce..0000000 Binary files a/docs/F6/image50.png and /dev/null differ diff --git a/docs/F6/image52.png b/docs/F6/image52.png deleted file mode 100644 index b88a8fb..0000000 Binary files a/docs/F6/image52.png and /dev/null differ diff --git a/docs/F6/image53.png b/docs/F6/image53.png deleted file mode 100644 index 835c234..0000000 Binary files a/docs/F6/image53.png and /dev/null differ diff --git a/docs/F6/image54.png b/docs/F6/image54.png deleted file mode 100644 index ed3cb72..0000000 Binary files a/docs/F6/image54.png and /dev/null differ diff --git a/docs/F6/image55.png b/docs/F6/image55.png deleted file mode 100644 index 637f631..0000000 Binary files a/docs/F6/image55.png and /dev/null differ diff --git a/docs/F6/image56.png b/docs/F6/image56.png deleted file mode 100644 index 5dec064..0000000 Binary files a/docs/F6/image56.png and /dev/null differ diff --git a/docs/F6/image57.png b/docs/F6/image57.png deleted file mode 100644 index eb38d2c..0000000 Binary files a/docs/F6/image57.png and /dev/null differ diff --git a/docs/F6/image58.png b/docs/F6/image58.png deleted file mode 100644 index 25a8aee..0000000 Binary files a/docs/F6/image58.png and /dev/null differ diff --git a/docs/F6/image59.png b/docs/F6/image59.png deleted file mode 100644 index 2655cf3..0000000 Binary files a/docs/F6/image59.png and /dev/null differ diff --git a/docs/F6/image6.png b/docs/F6/image6.png deleted file mode 100644 index bd0afb6..0000000 Binary files a/docs/F6/image6.png and /dev/null differ diff --git a/docs/F6/image62.png b/docs/F6/image62.png deleted file mode 100644 index 71b9c37..0000000 Binary files a/docs/F6/image62.png and /dev/null differ diff --git a/docs/F6/image64.png b/docs/F6/image64.png deleted file mode 100644 index 7519f2c..0000000 Binary files a/docs/F6/image64.png and /dev/null differ diff --git a/docs/F6/image66.png b/docs/F6/image66.png deleted file mode 100644 index d52d1dc..0000000 Binary files a/docs/F6/image66.png and /dev/null differ diff --git a/docs/F6/image67.png b/docs/F6/image67.png deleted file mode 100644 index f442d31..0000000 Binary files a/docs/F6/image67.png and /dev/null differ diff --git a/docs/F6/image69.png b/docs/F6/image69.png deleted file mode 100644 index 921051a..0000000 Binary files a/docs/F6/image69.png and /dev/null differ diff --git a/docs/F6/image7.png b/docs/F6/image7.png deleted file mode 100644 index 4f1b242..0000000 Binary files a/docs/F6/image7.png and /dev/null differ diff --git a/docs/F6/image70.png b/docs/F6/image70.png deleted file mode 100644 index 87dc562..0000000 Binary files a/docs/F6/image70.png and /dev/null differ diff --git a/docs/F6/image71.png b/docs/F6/image71.png deleted file mode 100644 index d4d01b9..0000000 Binary files a/docs/F6/image71.png and /dev/null differ diff --git a/docs/F6/image74.png b/docs/F6/image74.png deleted file mode 100644 index e879d4c..0000000 Binary files a/docs/F6/image74.png and /dev/null differ diff --git a/docs/F6/image75.png b/docs/F6/image75.png deleted file mode 100644 index b887410..0000000 Binary files a/docs/F6/image75.png and /dev/null differ diff --git a/docs/F6/image9.png b/docs/F6/image9.png deleted file mode 100644 index 88f0468..0000000 Binary files a/docs/F6/image9.png and /dev/null differ diff --git a/docs/blast.html b/docs/blast.html index 50d2c3c..d790b5d 100644 --- a/docs/blast.html +++ b/docs/blast.html @@ -7,7 +7,7 @@ -Google Earth Engine for OSINT - Blast Damage Assessment +Remote Sensing for OSINT - Blast Damage Assessment - - - - - - - - - -
-
- - -
-

Labels

- -
-
-

Predictions

- - -
-
-
- - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/obj_train_val.qmd b/docs/obj_train_val.qmd deleted file mode 100644 index 2a29a18..0000000 --- a/docs/obj_train_val.qmd +++ /dev/null @@ -1,11 +0,0 @@ ---- -format: revealjs -background-opacity: 0 ---- - - -## Labels -![](images/val_batch0_labels.jpg) - -## Predictions -![](images/val_batch0_pred.jpg) diff --git a/docs/object_detection.html b/docs/object_detection.html index c4b884d..7ded0bc 100644 --- a/docs/object_detection.html +++ b/docs/object_detection.html @@ -7,7 +7,7 @@ -Google Earth Engine for OSINT - Deep Learning +Remote Sensing for OSINT - Object Detection @@ -152,7 +148,7 @@ background: #34a832;
-
-
-
-

Deep Learning

-
-
- - -
- - - - -
- - -
+
-
+
+ +
+
+

Object Detection

+
+
+ + + + +
+ + +
-
-

Introduction

The Ship Detection tutorial explored a use case in which we might want to monitor the activity of ships in a particular location. That was a fairly straightforward task: the sea is very flat, and ships (especially large cargo and military vessels) protrude significantly. Using radar imagery, we could just set a threshold because if anything on the water is reflecting radio waves, it’s probably a ship.

One shortcoming of this approach is that it doesn’t tell us what kind of ship we’ve detected. Sure, you could use the shape and size to distinguish between a fishing vessel and an aircraft carrier. But what about ships of similar sizes? Or what if you wanted to use satellite imagery to identify things other than ships, like airplanes, cars, or bridges? This sort of task– called “object detection” is a bit more complicated.

In this tutorial, we’ll be using a deep learning model called YOLOv5 to detect objects in satellite imagery. We’ll be training the model on a custom dataset, and then using it to dynamically identify objects in satellite imagery of different resolutions pulled from Google Earth Engine. The tutorial is broken up into three sections:

@@ -437,10 +437,133 @@ background: #34a832;

Inference

-

This image shows

+

Now that we’ve got a trained model, we can use it to conduct object detection on new images. we’ll build a data processing pipeline in three steps by:

+
    +
  1. Loading our trained model
  2. +
  3. Creating an interactive map to define the area we want to analyze.
  4. +
  5. Defining a function to run object detection within this area.
  6. +
+
+

1. Loading a trained model

+

During the training process, YOLO is iteratively tweaking the model to try to maximize mAP 0.5. It automatically saves the best version of the model in the following location: YOLOv5_RS/runs/train/exp/weights/best.pt. You can save this file for later use, which I have done in case you just want to use this model without having to train it yourself. I’ve also included several other pre-trained models which you can find in the YOLOv5_RS/weights/ directory, including:

+
    +
  • lowres_ships.pt: the model we just trained on Sentinel-2 imagery.

  • +
  • aircraft.pt: trained on the high resolution Airbus Aircraft Detection Dataset.

  • +
  • general.pt: trained on the DOTA dataset by Kevin Guo. This model works great on high resolution satellite imagery, and can detect the following classes: plane, ship, storage tank, baseball diamond, tennis court, basketball court, ground track field, harbor, bridge, large vehicle, small vehicle, helicopter, roundabout, soccer field, swimming pool, container crane, airport and helipad.

  • +
+

So far, we’ve trained a model to detect ships in Sentinel-2 imagery. But to show the versatility of this general approach, the rest of this tutorial will load up the general.pt model, and use it to detect a wide range of aircraft in high resolution imagery.

+
+
+

2. Loading the input imagery

+

To get started with object detection on satellite imagery using these pre-trained models, we need to define an Area of Interest (AOI) and load satellite imagery. We’ll do this by accessing Google Earth Engine from the Python notebook we’re working in, and creating an interactive map that will let us draw an AOI for analysis.

+

First, we first need to import a few packages:

+
!pip install geemap  -q
+import pandas as pd
+import ee
+import geemap
+import requests
+from PIL import Image
+from PIL import ImageDraw
+from io import BytesIO
+import torch
+import PIL
+

Once we’ve done this, we’ll also need to log in to Google Earth Engine using its Python API in order to access the satellite imagery. Running these two lines of code will generate a prompt with instructions; you have to click the link, confirm that you give the notebook permission to access your Earth Engine account, and paste the authentication code in the provided dialogue box.

+
ee.Authenticate()
+ee.Initialize()
+

Great– now we can load high resolution imagery from the National Agriculture Imagery Program (NAIP) and create an interactive map. For this example, I’m centering the map on the Davis-Monthan Airplane Boneyard. This is where the airforce retires and restores aircraft, so it will have lots of airplanes of different kinds for us to identify.

+

First, we want to define a function called detect that will accept four arguments:

+
    +
  • input: the satellite imagery we want to analyze.
  • +
  • visParams: a dictionary of visualization parameters for the imagery.
  • +
  • weight: the name of the pre-trained model we want to use.
  • +
  • labels: a boolean indicating whether we want to display the labels on the processed image.
  • +
+
def detect(input, visParams, weight, labels=True):
+
+  # Get the AOI from the map
+  aoi = ee.FeatureCollection(Map.draw_features)
+  mapScale=Map.getScale()
+
+  # Visualize the raster in Earth Engine and get a download URL
+  image_url=input.visualize(bands=visParams['bands'], max=visParams['max']).getThumbURL({"region":aoi.geometry(), 'scale':mapScale})
+
+  # Load the image into a PIL image
+  response = requests.get(image_url)
+  img = Image.open(BytesIO(response.content))
+
+  # Load the model
+  model =torch.hub.load('.','custom', path='weights/{}.pt'.format(weight),source='local',_verbose=False)
+  
+  # Run inference
+  results = model(img)
+
+  # Count the number of detections
+  counts=pd.DataFrame(results.pandas().xyxy[0].groupby('name').size()).reset_index().rename(columns={0:'count','name':'detected'}).set_index('count')
+
+  # Display the results
+  results.show(labels=labels)
+
+  # Print the number of detections and the date of the image
+  print(ee.Date(input.get('system:time_start')).format("dd-MM-yyyy").getInfo())
+  print(counts)
+  
+  return counts
+

Now, we can load the NAIP imagery and create an interactive map.

+
# load the past 10 years of NAIP imagery
+naip = ee.ImageCollection('USDA/NAIP/DOQQ').filter(ee.Filter.date('2012-01-01', '2022-01-01'))
+
+# set some thresholds
+trueColorVis = {
+  'bands':['R', 'G', 'B'],
+  'min': 0,
+  'max': 300,
+};
+
+# initialize our map
+Map = geemap.Map()
+Map.setCenter(-110.84,32.16,17)
+Map.addLayer(naip.first(), trueColorVis, "naip")
+Map
+

This will generate a small map with some drawing tools on the left side. We can use these tools to draw a polygon around the area we want to analyze. Use the drawing tools to draw a rectangle around an area of interest.

+

Finally, we can run the detection on the imagery. We’ll do this by iterating through the collection of images, and running the detect function on each one. We’ll also store the results in a dataframe so we can analyze them later.

+
# Get the polygon we just drew on the map 
+aoi=ee.FeatureCollection(Map.draw_features)
+
+# Get a list of all the images in the collection
+naip_list=naip.filterBounds(aoi).toList(naip.size())
+
+# Iterate through the list of images and run detection on each one
+for num in range(0,(img_list.size()).getInfo()):
+  detect(ee.Image(naip_list.get(num)), trueColorVis,'general',labels=False)
+  df=df.append(detection) # store the results in a dataframe
+

Below is the result of the detection on the latest image in the collection:

-

+
+
+

+

Davis-Monthan Airplane Boneyard, Tucson AZ. 32.139498, -110.868549

+
+
+

This image shows a remarkable degree of accuracy being achieved by our model. Inference took just 822.2 milliseconds, and it seems to be doing pretty well. The model identifies over 100 different kinds of aircraft (orange boxes) of many shapes and sizes, civilian and military, without missing a single one. It also identifies around 20 different types of helicopter (blue boxes) in the top right and even spots the cars on the highway and in the parking lots (red boxes). It’s not perfect– it thinks there’s a ship in the bottom left corner near the shed (yellow box); in reality this appears to be half of a plane’s fuselage, an understandable mistake given how long it took me to figure out what it was.

+
@@ -705,6 +828,7 @@ window.document.addEventListener("DOMContentLoaded", function (event) {
+ diff --git a/docs/object_detection.qmd b/docs/object_detection.qmd deleted file mode 100644 index bac813e..0000000 --- a/docs/object_detection.qmd +++ /dev/null @@ -1,43 +0,0 @@ -# Deep Learning {.unnumbered} - ---- -title-block-banner: "#34a832" -title-block-banner-color: 'white' ---- - -# Introduction - -The Ship Detection tutorial explored a use case in which we might want to monitor the activity of ships in a particular location. That was a fairly straightforward task: the sea is very flat, and ships (especially large cargo and military vessels) protrude significantly. Using radar imagery, we could just set a threshold because if anything on the water is reflecting radio waves, it's probably a ship. - -One shortcoming of this approach is that it doesn't tell us what *kind* of ship we've detected. Sure, you could use the shape and size to distinguish between a fishing vessel and an aircraft carrier. But what about ships of similar sizes? Or what if you wanted to use satellite imagery to identify things other than ships, like airplanes, cars, or bridges? This sort of task-- called **"object detection"** is a bit more complicated. - -In this tutorial, - -1. Object detection in satellite imagery -2. Training a deep learning model on a custom dataset -3. Dynamic inference using Google Earth Engine - - -## Object Detection in Satellite Imagery - -Object detction in satellite imagery has a variety of useful applications. Immediately prior to the invasion of Ukraine, for example, a number of articles emerged - - - monitoring a large area - - monitoring a smaller area over time - - lenvls - - - - -:::{.column-screen} - -![](images/obj_det2.jpg) - -::: - -## Training - -YOLO is - -## Inference - diff --git a/docs/refineries.html b/docs/refineries.html index 8145af1..225f317 100644 --- a/docs/refineries.html +++ b/docs/refineries.html @@ -7,7 +7,7 @@ -Google Earth Engine for OSINT - Refinery Identification +Remote Sensing for OSINT - Refinery Identification @@ -160,23 +154,7 @@ background: #34a832; -
-
-
-

Ship Detection

-
-
- - -
- - - - -
- - -
+
-
+
+ +
+
+

Ship Detection

+
+
+ + + + +
+ + +
-
-

Introduction

There’s a huge amount of data available on the internet about ship movements, most of which draw on the Automatic Identification System (AIS) which is a system that uses radio to broadcast the identity, position, course, speed, and other data about ships. MarineTraffic, for example, provides an API that allows you to query the location of ships in real time as well as historical vessel tracks and lots of other useful data. Unfortunately most sources of AIS data are paywalled, and AIS can be turned off or manipulated to hide the identity or position of the ship. In fact, most of the stuff we’re interested in investigating probably happens when AIS is turned off.

Though ships can hide by turning off their AIS transponders, they can’t hide from satellites. In this tutorial, we’re going to build an application that uses Synthetic Aperture Radar (SAR) from the European Space Agency’s Sentinel-1 satellite to automatically identify ships, regardless of whether they’ve got their transponders turned on or off. Here’s the finished application:

@@ -370,7 +369,6 @@ background: #34a832;

If you’re closely zoomed in to the map and load imagery from different days by clicking on the graph, you can compare the bright spots on the Sentinel image and the green dots. The ship detection process is pretty accurate, and we typically see one green dot per ship. However, you may notice that we occasionally miss a ship. This is because the ship detection process is based on a threshold, and if the ship is too small it may not generate a high enough return signal to be detected. You can increase the sensitivity of the ship detection process by moving the slider below the graph. This will increase the number of ships detected, but it may also increase the number of false positives.

The next section focuses on building this application. After that, we’ll have a look at a few different use cases for this sort of maritime surveillance.

-

Building the Application

@@ -655,18 +653,21 @@ background: #34a832;

Taking it for a spin

North Korea

-

Information on North Korea’s economy is pretty hard to come by. Ship traffic in and out of the country’s largest port, Nampo, is probably a pretty good indicator of the country’s economic activity. But we can’t just head on down to Marine Tracker or other services that use AIS data to track ship movements. According to the U.S. Treasury, “North Korean-flagged merchant vessels have been known to intentionally disable their AIS transponders to mask their movements. This tactic, whether employed by North Korean-flagged vessels or other vessels involved in trade with North Korea, could conceal the origin or destination of cargo destined for, or originating in, North Korea.” They should know– they’re the ones imposing the sanctions that make it illegal to trade with North Korea.

-

A New York Times investigation tracked the maritime voyage of luxury Mercedes cars from Germany to North Korea via the Netherlands, China, Japan, South Korea, and Russia. AIS transponders were turned off at several points throughout this journey, and the investigation had to rely on satellite imagery to fill in the gaps. Though they used high resolution optical imagery to follow individual ships,

+

In 2020, North Korea implemented one of the most severe COVID-19 lockdowns in the world including a near-total ban on “all cross-border exchanges, including trade, traffic, and tourism”.. Measures have been so severe that country appears to have experienced a significant famine. Though there were signs that things have gradually returned to normal, information on North Korea’s economy is pretty hard to come by. Ship traffic in and out of the country’s largest port, Nampo, is probably a pretty good indicator of the country’s economic activity.

+

But we can’t just head on down to Marine Tracker or other services that use AIS data to track ship movements. According to the U.S. Treasury, “North Korean-flagged merchant vessels have been known to intentionally disable their AIS transponders to mask their movements. This tactic, whether employed by North Korean-flagged vessels or other vessels involved in trade with North Korea, could conceal the origin or destination of cargo destined for, or originating in, North Korea.” They should know– they’re the ones imposing the sanctions that make it illegal to trade with North Korea.

+

A New York Times investigation tracked the maritime voyage of luxury Mercedes cars from Germany to North Korea via the Netherlands, China, Japan, South Korea, and Russia. AIS transponders were turned off at several points throughout this journey, and the investigation had to rely on satellite imagery to fill in the gaps.

+

Though they used high resolution optical imagery to follow individual ships, we want to identify lots of ships in a large area over a long period. That would get very expensive, and automatic ship detection in optical imagery is relatively difficult. Here’s how our SAR tool fares when we draw a box in the bay of Nampo:

+

Looking at imagery from 2021, we can see ship traffic increasing from nearly zero to around 40 ships per day.

-
-
-

Ukraine

-

The port of Odessa is Ukraine’s largest port, and Following its invasion of Ukraine in February 2022, Russia instituted a naval blockade against Ukrainian ports. The impact of this blockade is clearly visible using the tool we’ve just built:

+
+

Ukraine

+

Odessa is Ukraine’s largest port. Following its invasion of Ukraine in February 2022, Russia instituted a naval blockade against Ukrainian ports. The impact of this blockade is clearly visible using the tool we’ve just built:

The daily number of ships detected in the port of Odessa dropped from 40-50 to 0-5 following the invasion, and remained near zero until the blockade was lifted in September 2022.

+
diff --git a/images/.DS_Store b/images/.DS_Store index 1029fb7..92acd2d 100644 Binary files a/images/.DS_Store and b/images/.DS_Store differ diff --git a/images/obj_det3.jpg b/images/obj_det3.jpg new file mode 100644 index 0000000..7eeffd2 Binary files /dev/null and b/images/obj_det3.jpg differ diff --git a/images/revisit_chart.png b/images/revisit_chart.png new file mode 100644 index 0000000..7fa05a6 Binary files /dev/null and b/images/revisit_chart.png differ diff --git a/index.log b/index.log deleted file mode 100644 index 07bbf21..0000000 --- a/index.log +++ /dev/null @@ -1,267 +0,0 @@ -This is XeTeX, Version 3.141592653-2.6-0.999994 (TeX Live 2022) (preloaded format=xelatex 2022.10.26) 5 JAN 2023 19:07 -entering extended mode - restricted \write18 enabled. - %&-line parsing enabled. -**index.tex -(./index.tex -LaTeX2e <2022-06-01> patch level 5 -L3 programming layer <2022-09-28> (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrreprt.cls -Document Class: scrreprt 2022/10/12 v3.38 KOMA-Script document class (report) -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrkbase.sty -Package: scrkbase 2022/10/12 v3.38 KOMA-Script package (KOMA-Script-dependent basics and keyval usage) -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrbase.sty -Package: scrbase 2022/10/12 v3.38 KOMA-Script package (KOMA-Script-independent basics and keyval usage) -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrlfile.sty -Package: scrlfile 2022/10/12 v3.38 KOMA-Script package (file load hooks) -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrlfile-hook.sty -Package: scrlfile-hook 2022/10/12 v3.38 KOMA-Script package (using LaTeX hooks) -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrlogo.sty -Package: scrlogo 2022/10/12 v3.38 KOMA-Script package (logo) -))) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/graphics/keyval.sty -Package: keyval 2022/05/29 v1.15 key=value parser (DPC) -\KV@toks@=\toks16 -) -Applying: [2021/05/01] Usage of raw or classic option list on input line 252. -Already applied: [0000/00/00] Usage of raw or classic option list on input line 368. -)) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/tocbasic.sty -Package: tocbasic 2022/10/12 v3.38 KOMA-Script package (handling toc-files) -\scr@dte@tocline@numberwidth=\skip47 -\scr@dte@tocline@numbox=\box51 -) -Package tocbasic Info: omitting babel extension for `toc' -(tocbasic) because of feature `nobabel' available -(tocbasic) for `toc' on input line 137. -Class scrreprt Info: You've used standard option `oneside'. -(scrreprt) This is correct! -(scrreprt) Internally I'm using `twoside=false'. -(scrreprt) If you'd like to set the option with \KOMAoptions, -(scrreprt) you'd have to use `twoside=false' there -(scrreprt) instead of `oneside', too. -Class scrreprt Info: File `scrsize11pt.clo' used instead of -(scrreprt) file `scrsize11.clo' to setup font sizes on input line 2614. -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/scrsize11pt.clo -File: scrsize11pt.clo 2022/10/12 v3.38 KOMA-Script font size class option (11pt) -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/koma-script/typearea.sty -Package: typearea 2022/10/12 v3.38 KOMA-Script package (type area) -\ta@bcor=\skip48 -\ta@div=\count181 -Package typearea Info: You've used standard option `letterpaper'. -(typearea) This is correct! -(typearea) Internally I'm using `paper=letter'. -(typearea) If you'd like to set the option with \KOMAoptions, -(typearea) you'd have to use `paper=letter' there -(typearea) instead of `letterpaper', too. -Package typearea Info: You've used standard option `oneside'. -(typearea) This is correct! -(typearea) Internally I'm using `twoside=false'. -(typearea) If you'd like to set the option with \KOMAoptions, -(typearea) you'd have to use `twoside=false' there -(typearea) instead of `oneside', too. -\ta@hblk=\skip49 -\ta@vblk=\skip50 -\ta@temp=\skip51 -\footheight=\skip52 -Package typearea Info: These are the values describing the layout: -(typearea) DIV = 11 -(typearea) BCOR = 0.0pt -(typearea) \paperwidth = 614.295pt -(typearea) \textwidth = 446.76004pt -(typearea) DIV departure = -14% -(typearea) \evensidemargin = 11.49748pt -(typearea) \oddsidemargin = 11.49748pt -(typearea) \paperheight = 794.96999pt -(typearea) \textheight = 582.20026pt -(typearea) \topmargin = -37.40001pt -(typearea) \headheight = 17.0pt -(typearea) \headsep = 20.40001pt -(typearea) \topskip = 11.0pt -(typearea) \footskip = 47.6pt -(typearea) \baselineskip = 13.6pt -(typearea) on input line 1767. -) -\c@part=\count182 -\c@chapter=\count183 -\c@section=\count184 -\c@subsection=\count185 -\c@subsubsection=\count186 -\c@paragraph=\count187 -\c@subparagraph=\count188 -\scr@dte@chapter@maxnumwidth=\skip53 -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\chapter on input line 5902. -\scr@dte@section@maxnumwidth=\skip54 -Class scrreprt Info: using compatibility default `runin=bysign' -(scrreprt) for `\section on input line 5913. -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\section on input line 5913. -\scr@dte@part@maxnumwidth=\skip55 -Class scrreprt Info: using compatibility default `afterindent=true' -(scrreprt) for `\part on input line 5922. -\scr@dte@subsection@maxnumwidth=\skip56 -Class scrreprt Info: using compatibility default `runin=bysign' -(scrreprt) for `\subsection on input line 5932. -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\subsection on input line 5932. -\scr@dte@subsubsection@maxnumwidth=\skip57 -Class scrreprt Info: using compatibility default `runin=bysign' -(scrreprt) for `\subsubsection on input line 5942. -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\subsubsection on input line 5942. -\scr@dte@paragraph@maxnumwidth=\skip58 -Class scrreprt Info: using compatibility default `runin=bysign' -(scrreprt) for `\paragraph on input line 5953. -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\paragraph on input line 5953. -\scr@dte@subparagraph@maxnumwidth=\skip59 -Class scrreprt Info: using compatibility default `runin=bysign' -(scrreprt) for `\subparagraph on input line 5963. -Class scrreprt Info: using compatibility default `afterindent=bysign' -(scrreprt) for `\subparagraph on input line 5963. -\abovecaptionskip=\skip60 -\belowcaptionskip=\skip61 -\c@pti@nb@sid@b@x=\box52 -Package tocbasic Info: omitting babel extension for `lof' -(tocbasic) because of feature `nobabel' available -(tocbasic) for `lof' on input line 7140. -\scr@dte@figure@maxnumwidth=\skip62 -\c@figure=\count189 -Package tocbasic Info: omitting babel extension for `lot' -(tocbasic) because of feature `nobabel' available -(tocbasic) for `lot' on input line 7157. -\scr@dte@table@maxnumwidth=\skip63 -\c@table=\count190 -Class scrreprt Info: Redefining `\numberline' on input line 7328. -\bibindent=\dimen138 -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsmath/amsmath.sty -Package: amsmath 2022/04/08 v2.17n AMS math features -\@mathmargin=\skip64 -For additional information on amsmath, use the `?' option. -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsmath/amstext.sty -Package: amstext 2021/08/26 v2.01 AMS text -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsmath/amsgen.sty -File: amsgen.sty 1999/11/30 v2.0 generic functions -\@emptytoks=\toks17 -\ex@=\dimen139 -)) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsmath/amsbsy.sty -Package: amsbsy 1999/11/29 v1.2d Bold Symbols -\pmbraise@=\dimen140 -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsmath/amsopn.sty -Package: amsopn 2022/04/08 v2.04 operator names -) -\inf@bad=\count191 -LaTeX Info: Redefining \frac on input line 234. -\uproot@=\count192 -\leftroot@=\count193 -LaTeX Info: Redefining \overline on input line 399. -LaTeX Info: Redefining \colon on input line 410. -\classnum@=\count194 -\DOTSCASE@=\count195 -LaTeX Info: Redefining \ldots on input line 496. -LaTeX Info: Redefining \dots on input line 499. -LaTeX Info: Redefining \cdots on input line 620. -\Mathstrutbox@=\box53 -\strutbox@=\box54 -LaTeX Info: Redefining \big on input line 722. -LaTeX Info: Redefining \Big on input line 723. -LaTeX Info: Redefining \bigg on input line 724. -LaTeX Info: Redefining \Bigg on input line 725. -\big@size=\dimen141 -LaTeX Font Info: Redeclaring font encoding OML on input line 743. -LaTeX Font Info: Redeclaring font encoding OMS on input line 744. -\macc@depth=\count196 -LaTeX Info: Redefining \bmod on input line 905. -LaTeX Info: Redefining \pmod on input line 910. -LaTeX Info: Redefining \smash on input line 940. -LaTeX Info: Redefining \relbar on input line 970. -LaTeX Info: Redefining \Relbar on input line 971. -\c@MaxMatrixCols=\count197 -\dotsspace@=\muskip16 -\c@parentequation=\count198 -\dspbrk@lvl=\count199 -\tag@help=\toks18 -\row@=\count266 -\column@=\count267 -\maxfields@=\count268 -\andhelp@=\toks19 -\eqnshift@=\dimen142 -\alignsep@=\dimen143 -\tagshift@=\dimen144 -\tagwidth@=\dimen145 -\totwidth@=\dimen146 -\lineht@=\dimen147 -\@envbody=\toks20 -\multlinegap=\skip65 -\multlinetaggap=\skip66 -\mathdisplay@stack=\toks21 -LaTeX Info: Redefining \[ on input line 2953. -LaTeX Info: Redefining \] on input line 2954. -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsfonts/amssymb.sty -Package: amssymb 2013/01/14 v3.01 AMS font symbols -(/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/amsfonts/amsfonts.sty -Package: amsfonts 2013/01/14 v3.01 Basic AMSFonts support -\symAMSa=\mathgroup4 -\symAMSb=\mathgroup5 -LaTeX Font Info: Redeclaring math symbol \hbar on input line 98. -LaTeX Font Info: Overwriting math alphabet `\mathfrak' in version `bold' -(Font) U/euf/m/n --> U/euf/b/n on input line 106. -)) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/lm/lmodern.sty -Package: lmodern 2015/05/01 v1.6.1 Latin Modern Fonts -LaTeX Font Info: Overwriting symbol font `operators' in version `normal' -(Font) OT1/cmr/m/n --> OT1/lmr/m/n on input line 22. -LaTeX Font Info: Overwriting symbol font `letters' in version `normal' -(Font) OML/cmm/m/it --> OML/lmm/m/it on input line 23. -LaTeX Font Info: Overwriting symbol font `symbols' in version `normal' -(Font) OMS/cmsy/m/n --> OMS/lmsy/m/n on input line 24. -LaTeX Font Info: Overwriting symbol font `largesymbols' in version `normal' -(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 25. -LaTeX Font Info: Overwriting symbol font `operators' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 26. -LaTeX Font Info: Overwriting symbol font `letters' in version `bold' -(Font) OML/cmm/b/it --> OML/lmm/b/it on input line 27. -LaTeX Font Info: Overwriting symbol font `symbols' in version `bold' -(Font) OMS/cmsy/b/n --> OMS/lmsy/b/n on input line 28. -LaTeX Font Info: Overwriting symbol font `largesymbols' in version `bold' -(Font) OMX/cmex/m/n --> OMX/lmex/m/n on input line 29. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `normal' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 31. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `normal' -(Font) OT1/cmss/m/n --> OT1/lmss/m/n on input line 32. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `normal' -(Font) OT1/cmr/m/it --> OT1/lmr/m/it on input line 33. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `normal' -(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 34. -LaTeX Font Info: Overwriting math alphabet `\mathbf' in version `bold' -(Font) OT1/cmr/bx/n --> OT1/lmr/bx/n on input line 35. -LaTeX Font Info: Overwriting math alphabet `\mathsf' in version `bold' -(Font) OT1/cmss/bx/n --> OT1/lmss/bx/n on input line 36. -LaTeX Font Info: Overwriting math alphabet `\mathit' in version `bold' -(Font) OT1/cmr/bx/it --> OT1/lmr/bx/it on input line 37. -LaTeX Font Info: Overwriting math alphabet `\mathtt' in version `bold' -(Font) OT1/cmtt/m/n --> OT1/lmtt/m/n on input line 38. -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/generic/iftex/iftex.sty -Package: iftex 2022/02/03 v1.0f TeX engine tests -) (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/unicode-math/unicode-math.sty (/Users/ollieballinger/Library/TinyTeX/texmf-dist/tex/latex/l3kernel/expl3.sty -Package: expl3 2022-12-17 L3 programming layer (loader) - -! LaTeX Error: Mismatched LaTeX support files detected. -(LaTeX) Loading 'expl3.sty' aborted! -(LaTeX) -(LaTeX) The L3 programming layer in the LaTeX format -(LaTeX) is dated 2022-09-28, but in your TeX tree the files require -(LaTeX) at least 2022-12-17. - -For immediate help type H . - ... - -l.77 \ExplLoaderFileDate{expl3.sty}} - % -Here is how much of TeX's memory you used: - 4604 strings out of 477723 - 95476 string characters out of 5841548 - 564227 words of memory out of 5000000 - 25692 multiletter control sequences out of 15000+600000 - 469267 words of font info for 29 fonts, out of 8000000 for 9000 - 14 hyphenation exceptions out of 8191 - 108i,1n,106p,10600b,270s stack positions out of 10000i,1000n,20000p,200000b,200000s - -No pages of output. diff --git a/index.qmd b/index.qmd index 1ddff69..404150b 100644 --- a/index.qmd +++ b/index.qmd @@ -1,32 +1,35 @@ -# Introduction {.unnumbered} +# Overview {.unnumbered} The analysis of satellite imagery is a foundational element of open source investigations. In the past decade, the quantity, quality, and availability thereof has increased dramatically. Capabilities and insights that were once only available to governments are now accessible to the general public. Satellite imagery is being used to collect evidence of genocide and other war crimes in [Ukraine](https://www.nbcnews.com/science/science-news/ukraine-satellites-war-crimes-rcna26291), [Nigeria](https://www.amnesty.org/en/latest/news/2016/04/nigeria-military-cover-up-of-mass-slaughter-at-zaria-exposed/), [Burundi](https://www.amnesty.org/en/latest/news/2016/01/burundi-satellite-evidence-supports-witness-accounts-of-mass-graves/), [Cameroon](https://www.amnesty.org/en/latest/news/2021/07/cameroon-satellite-images-reveal-devastation-in-anglophone-regions-2/), [the DRC](https://www.aaas.org/resources/satellite-imagery-assessment-forced-relocations-near-luiswishi-mine), [South Sudan](https://gsp.yale.edu/case-studies/sudan/maps-satellite-images/other-darfur-satellite-imagery), [Papua](https://gsp.yale.edu/resources/maps-satellite-images/papua), and [Venezuela](https://www.hrw.org/report/2016/04/04/unchecked-power/police-and-military-raids-low-income-and-immigrant-communities). It has been used to [monitor environmental degradation](https://www.theguardian.com/environment/2016/mar/02/new-satellite-mapping-a-game-changer-against-illegal-logging) and hold extractive industries to account from [Iraq](https://www.bellingcat.com/resources/2021/04/15/what-oil-satellite-technology-and-iraq-can-tell-us-about-pollution/) to [Guatemala](https://www.planet.com/pulse/the-observatory-of-extractive-industries-oie-shines-a-light-on-the-mining-industry-using-planets-satellite-data/). The ability to analyze satellite imagery is a critical skill for anyone interested in open source investigations. Though no-code platforms such as Sentinelhub have been invaluable in allowing the OSINT community to access and process satellite imagery, the analytical capabilities of these platforms are limited. [Google Earth Engine (GEE)](https://earthengine.google.com/#intro) is a cloud-based platform that stores petabytes of satellite imagery from a variety of sources and allows users to perform advanced analyses on Google servers for free using a browser-based interface. This textbook is designed for investigators who want to perform more sophisticated analysis using geospatial data, and assumes no prior knowledge of coding or remote sensing (satellite imagery analysis). It is organized into two parts: an introduction to remote sensing and GEE, and a series of case studies that demonstrate how to use GEE for open source investigations. -## Table of Contents -- Learning - 1. [Remote Sensing](ch1.qmd) - 2. [Data Acquisition](ch2.qmd) - 4. [Application Development](ch4.qmd) -- Case Studies - 1. [War at Night](lights.qmd) - 2. [Refinery Detection](refineries.qmd) - 3. [Deforestation](trees.qmd) - 4. [Ship Detection](ships.qmd) - 5. [Object Detection](object_detection.qmd) - -Recently, a team of over 100 scientists came together to write a book called ["Cloud-Based Remote Sensing with Google Earth Engine: Fundamentals and Applications"](https://www.eefabook.org/). It's a great resource for learning about remote sensing and Earth Engine. The material in this chapter is a subset of the book, edited to fit the scope of this guide. If you're interested in learning more, check out the full book. - - - ## What is Google Earth Engine? - As geospatial datasets—particularly satellite imagery collections—increase in size, researchers are increasingly relying on cloud computing platforms such as Google Earth Engine (GEE) to analyze vast quantities of data. GEE is free and allows users to write open-source code that can be run by others in one click, thereby yielding fully reproducible results. These features have put GEE on the cutting edge of scientific research. The following plot visualizes the number of journal articles conducted using different geospatial analysis software platforms: ![](./images/WoS%20Articles.png) -Despite only being released in 2015, the number of geospatial journal articles using Google Earth Engine (shown in red above) has outpaced every other major geospatial analysis software, including ArcGIS, Python, and R in just five years. GEE applications have been developed and used to present interactive geospatial data visualizations by NGOs, Universities, the United Nations, and the European Commission. By storing and running computations on google servers, GEE is far more accessible to those who don’t have significant local computational resources; all you need is an internet connection. \ No newline at end of file +Despite only being released in 2015, the number of geospatial journal articles using Google Earth Engine (shown in red above) has outpaced every other major geospatial analysis software, including ArcGIS, Python, and R in just five years. GEE applications have been developed and used to present interactive geospatial data visualizations by NGOs, Universities, the United Nations, and the European Commission. By storing and running computations on google servers, GEE is far more accessible to those who don’t have significant local computational resources; all you need is an internet connection. + +## Table of Contents + +A) **Introduction** + * Two introductory chapters that provide an overview of remote sensing the different types of satellite imagery available on Google Earth Engine. + * [Remote Sensing](ch1.qmd) + * [Data Acquisition](ch2.qmd) +B) **Google Earth Engine** + * Recently, a team of over 100 scientists came together to write a book called ["Cloud-Based Remote Sensing with Google Earth Engine: Fundamentals and Applications"](https://www.eefabook.org/). It's a great resource for learning about remote sensing and Earth Engine. The material in this section is a subset of the book, edited to fit the scope of this guide. If you're interested in learning more, check out the full book. + * [Getting Started](F1.qmd) + * [Interpreting Images](F2.qmd) + * [Image Series](F4.qmd) + * [Vectors and Tables](F5.qmd) +C) **Case Studies** + * A series of case studies that demonstrate how to use Google Earth Engine for open source investigations. Each case study includes a brief introduction to the topic, a step-by-step guide to using Google Earth Engine to analyze satellite imagery, and a discussion of the results. + * [War at Night](lights.qmd) + * [Refinery Identification](refineries.qmd) + * [Ship Detection](ships.qmd) + * [Blast Damage Assessment](blast.qmd) + * [Object Detection](object_detection.qmd) diff --git a/lights.qmd b/lights.qmd index 5fef527..6183d43 100644 --- a/lights.qmd +++ b/lights.qmd @@ -1,22 +1,10 @@ # War at Night {.unnumbered} - ## Data + Satellite images of Syria taken at night capture a subtle trace left by human civilization: lights. Apartment buildings, street lights, highways, powerplants-- all are illuminated at night and can be seen from space. Researchers often use these nighttime lights signatures to track development; as cities grow, villages recieve power, and infrastructure is built, areas emit more light. But this works both ways. As cities are demolished, villages burned, and highways cutoff, they stop emitting lights. -The timelapse below uses imagery from the Defense Meteorological Satellite Program (DMSP), a joint program run by the U.S. Department of Defense and the National Oceanographic and Atmospheric Agency. One image is taken per year between 2005 and 2013: - - -## Ukraine - -### Pre-Processing - -### Analysis - - -## Iraq - -A link to the GEE code for this section can be found [here](https://code.earthengine.google.com/2cf77d8cb9afd76b73100637fbffdf5d). +In this tutorial, we'll use satellite images of Iraq taken at night to track the destruction caused by the fight against the Islamic State. We'll use the VIIRS nighttime lights dataset, which is a collection of satellite images taken by the Visible Infrared Imaging Radiometer Suite (VIIRS) on the Suomi NPP satellite. VIIRS is a sensor that can detect light in the visible and infrared spectrum, and is capable of taking images at night. A link to the GEE code for this section can be found [here](https://code.earthengine.google.com/2cf77d8cb9afd76b73100637fbffdf5d). ### Pre-Processing @@ -218,7 +206,7 @@ print(chart) We can clearly see Mosul (the red line) darkening in 2014 as the city is taken by ISIS. During this period the Qayyarah oilfileds are, as we might expect, quite dark. All of a sudden in 2016 Qayyarah becomes brighter at night than the city of Mosul ever was, as the oilfields are set on fire. Then, almost exactly when the blaze in Qayyarah is extinguished and the area darkens (i.e. when the blue line falls back to near zero), Mosul brightens once again (i.e. the red line rises) as the city is liberated. - + -### Fighting for Oil + diff --git a/obj_train_val.html b/obj_train_val.html deleted file mode 100644 index 55e5a7b..0000000 --- a/obj_train_val.html +++ /dev/null @@ -1,682 +0,0 @@ - - - - - - - - - - - - obj_train_val - - - - - - - - - - - - - - - -
-
- - -
-

Labels

- -
-
-

Predictions

- - -
-
-
- - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/obj_train_val.qmd b/obj_train_val.qmd deleted file mode 100644 index 11ad0a4..0000000 --- a/obj_train_val.qmd +++ /dev/null @@ -1,10 +0,0 @@ ---- -format: revealjs -background-opacity: 0 ---- - -## Labels -![](images/val_batch0_labels.jpg) - -## Predictions -![](images/val_batch0_pred.jpg) diff --git a/object_detection.qmd b/object_detection.qmd index 8eaefa9..6ac34f1 100644 --- a/object_detection.qmd +++ b/object_detection.qmd @@ -1,13 +1,4 @@ -# Deep Learning {.unnumbered} - ---- -title-block-banner: "#34a832" -title-block-banner-color: 'white' -slide-format: revealjs - ---- - -# Introduction +# Object Detection {.unnumbered} The Ship Detection tutorial explored a use case in which we might want to monitor the activity of ships in a particular location. That was a fairly straightforward task: the sea is very flat, and ships (especially large cargo and military vessels) protrude significantly. Using radar imagery, we could just set a threshold because if anything on the water is reflecting radio waves, it's probably a ship. @@ -145,7 +136,131 @@ This number is very useful when training a model in several different ways using ## Inference -The scene below is from an Air and Space Museum in Tucson, Arizona. It shows a large collection of aircraft that have been retired from service-- I picked this image because it has a lot of different types of aircraft, and it's a good test of our model's ability to detect different types of planes. +Now that we've got a trained model, we can use it to conduct object detection on new images. we'll build a data processing pipeline in three steps by: + +1. Loading our trained model +2. Creating an interactive map to define the area we want to analyze. +3. Defining a function to run object detection within this area. + +### 1. Loading a trained model + +During the training process, YOLO is iteratively tweaking the model to try to maximize mAP 0.5. It automatically saves the best version of the model in the following location: `YOLOv5_RS/runs/train/exp/weights/best.pt`. You can save this file for later use, which I have done in case you just want to use this model without having to train it yourself. I've also included several other pre-trained models which you can find in the `YOLOv5_RS/weights/` directory, including: + + * `lowres_ships.pt`: the model we just trained on Sentinel-2 imagery. + + * `aircraft.pt`: trained on the high resolution [Airbus Aircraft Detection Dataset](https://www.kaggle.com/datasets/airbusgeo/airbus-aircrafts-sample-dataset). + + * `general.pt`: trained on the [DOTA dataset](https://captain-whu.github.io/DOTA/dataset.html) by [Kevin Guo](https://github.com/KevinMuyaoGuo/yolov5s_for_satellite_imagery#readme). This model works great on high resolution satellite imagery, and can detect the following classes: plane, ship, storage tank, baseball diamond, tennis court, basketball court, ground track field, harbor, bridge, large vehicle, small vehicle, helicopter, roundabout, soccer field, swimming pool, container crane, airport and helipad. + +So far, we've trained a model to detect ships in Sentinel-2 imagery. But to show the versatility of this general approach, the rest of this tutorial will load up the `general.pt` model, and use it to detect a wide range of aircraft in high resolution imagery. + +### 2. Loading the input imagery + +To get started with object detection on satellite imagery using these pre-trained models, we need to define an Area of Interest (AOI) and load satellite imagery. We'll do this by accessing Google Earth Engine from the Python notebook we're working in, and creating an interactive map that will let us draw an AOI for analysis. + +First, we first need to import a few packages: + +```python +!pip install geemap -q +import pandas as pd +import ee +import geemap +import requests +from PIL import Image +from PIL import ImageDraw +from io import BytesIO +import torch +import PIL +``` + +Once we've done this, we'll also need to log in to Google Earth Engine using its Python API in order to access the satellite imagery. Running these two lines of code will generate a prompt with instructions; you have to click the link, confirm that you give the notebook permission to access your Earth Engine account, and paste the authentication code in the provided dialogue box. + +```python +ee.Authenticate() +ee.Initialize() +``` + +Great-- now we can load high resolution imagery from the National Agriculture Imagery Program (NAIP) and create an interactive map. For this example, I'm centering the map on the [Davis-Monthan Airplane Boneyard](https://en.wikipedia.org/wiki/309th_Aerospace_Maintenance_and_Regeneration_Group). This is where the airforce retires and restores aircraft, so it will have lots of airplanes of different kinds for us to identify. + +First, we want to define a function called `detect` that will accept four arguments: + + * `input`: the satellite imagery we want to analyze. + * `visParams`: a dictionary of visualization parameters for the imagery. + * `weight`: the name of the pre-trained model we want to use. + * `labels`: a boolean indicating whether we want to display the labels on the processed image. + + +```python +def detect(input, visParams, weight, labels=True): + + # Get the AOI from the map + aoi = ee.FeatureCollection(Map.draw_features) + mapScale=Map.getScale() + + # Visualize the raster in Earth Engine and get a download URL + image_url=input.visualize(bands=visParams['bands'], max=visParams['max']).getThumbURL({"region":aoi.geometry(), 'scale':mapScale}) + + # Load the image into a PIL image + response = requests.get(image_url) + img = Image.open(BytesIO(response.content)) + + # Load the model + model =torch.hub.load('.','custom', path='weights/{}.pt'.format(weight),source='local',_verbose=False) + + # Run inference + results = model(img) + + # Count the number of detections + counts=pd.DataFrame(results.pandas().xyxy[0].groupby('name').size()).reset_index().rename(columns={0:'count','name':'detected'}).set_index('count') + + # Display the results + results.show(labels=labels) + + # Print the number of detections and the date of the image + print(ee.Date(input.get('system:time_start')).format("dd-MM-yyyy").getInfo()) + print(counts) + + return counts +``` + +Now, we can load the NAIP imagery and create an interactive map. + +```python +# load the past 10 years of NAIP imagery +naip = ee.ImageCollection('USDA/NAIP/DOQQ').filter(ee.Filter.date('2012-01-01', '2022-01-01')) + +# set some thresholds +trueColorVis = { + 'bands':['R', 'G', 'B'], + 'min': 0, + 'max': 300, +}; + +# initialize our map +Map = geemap.Map() +Map.setCenter(-110.84,32.16,17) +Map.addLayer(naip.first(), trueColorVis, "naip") +Map +``` + +This will generate a small map with some drawing tools on the left side. We can use these tools to draw a polygon around the area we want to analyze. Use the drawing tools to draw a rectangle around an area of interest. + +Finally, we can run the detection on the imagery. We'll do this by iterating through the collection of images, and running the `detect` function on each one. We'll also store the results in a dataframe so we can analyze them later. + +``` python +# Get the polygon we just drew on the map +aoi=ee.FeatureCollection(Map.draw_features) + +# Get a list of all the images in the collection +naip_list=naip.filterBounds(aoi).toList(naip.size()) + +# Iterate through the list of images and run detection on each one +for num in range(0,(img_list.size()).getInfo()): + detect(ee.Image(naip_list.get(num)), trueColorVis,'general',labels=False) + df=df.append(detection) # store the results in a dataframe +``` + +Below is the result of the detection on the latest image in the collection: :::{.column-screen} @@ -153,6 +268,18 @@ The scene below is from an Air and Space Museum in Tucson, Arizona. It shows a l ::: -Inference took just 822.2 milliseconds, and it seems to be doing pretty well. The model identifies over 100 different kinds of aircraft (orange boxes) of many shapes and sizes, civilian and military, without missing a single one. It also identifies around 20 different types of helicopter (blue boxes) in the top right and even spots the cars on the highway and in the parking lots (red boxes). It's not perfect-- it thinks there's a ship in the bottom left corner near the shed (yellow box); in reality this appears to be half of a plane's fuselage, an understandable mistake given how long it took *me* to figure out what it was. +This image shows a remarkable degree of accuracy being achieved by our model. Inference took just 822.2 milliseconds, and it seems to be doing pretty well. The model identifies over 100 different kinds of aircraft (orange boxes) of many shapes and sizes, civilian and military, without missing a single one. It also identifies around 20 different types of helicopter (blue boxes) in the top right and even spots the cars on the highway and in the parking lots (red boxes). It's not perfect-- it thinks there's a ship in the bottom left corner near the shed (yellow box); in reality this appears to be half of a plane's fuselage, an understandable mistake given how long it took *me* to figure out what it was. -This image shows a remarkable degree of accuracy being achieved by our model. + + diff --git a/ships.qmd b/ships.qmd index cd21aeb..912ebe5 100644 --- a/ships.qmd +++ b/ships.qmd @@ -1,12 +1,5 @@ # Ship Detection {.unnumbered} ---- -title-block-banner: "#34a832" -title-block-banner-color: 'white' ---- - -# Introduction - There's a huge amount of data available on the internet about ship movements, most of which draw on the Automatic Identification System (AIS) which is a system that uses radio to broadcast the identity, position, course, speed, and other data about ships. [MarineTraffic](https://www.marinetraffic.com/en/ais-api-services), for example, provides an API that allows you to query the location of ships in real time as well as historical vessel tracks and lots of other useful data. Unfortunately most sources of AIS data are paywalled, and AIS can be turned off or manipulated to hide the identity or position of the ship. In fact, most of the stuff we're interested in investigating probably happens when AIS is turned off. Though ships can hide by turning off their AIS transponders, they can't hide from satellites. In this tutorial, we're going to build an application that uses Synthetic Aperture Radar (SAR) from the European Space Agency's Sentinel-1 satellite to automatically identify ships, regardless of whether they've got their transponders turned on or off. Here's the finished application: @@ -356,17 +349,21 @@ And there we have it. A fully functional, all weather, daytime/nighttime ship de ### North Korea -Information on North Korea's economy is pretty hard to come by. Ship traffic in and out of the country's largest port, Nampo, is probably a pretty good indicator of the country's economic activity. But we can't just head on down to Marine Tracker or other services that use AIS data to track ship movements. According to the [U.S. Treasury](https://home.treasury.gov/system/files/126/dprk_vessel_advisory_02232018.pdf), "North Korean-flagged merchant vessels have been known to intentionally disable their AIS transponders to mask their movements. This tactic, whether employed by North Korean-flagged vessels or other vessels involved in trade with North Korea, could conceal the origin or destination of cargo destined for, or originating in, North Korea." They should know-- they're the ones imposing the sanctions that make it illegal to trade with North Korea. +In 2020, North Korea implemented one of the most severe COVID-19 lockdowns in the world including a near-total ban on ["all cross-border exchanges, including trade, traffic, and tourism".](https://thediplomat.com/2023/01/north-korea-likely-to-lift-pandemic-border-restrictions-in-2023/). Measures have been so severe that country appears to have experienced a significant [famine](https://foreignpolicy.com/2022/05/16/kim-north-korea-covid-outbreak-pandemic/). Though there were signs that things have gradually returned to normal, information on North Korea's economy is pretty hard to come by. Ship traffic in and out of the country's largest port, Nampo, is probably a pretty good indicator of the country's economic activity. -A New York Times [investigation](https://www.nytimes.com/2019/07/16/world/asia/north-korea-luxury-goods-sanctions.html) tracked the maritime voyage of luxury Mercedes cars from Germany to North Korea via the Netherlands, China, Japan, South Korea, and Russia. AIS transponders were turned off at several points throughout this journey, and the investigation had to rely on satellite imagery to fill in the gaps. Though they used high resolution optical imagery to follow individual ships, +But we can't just head on down to Marine Tracker or other services that use AIS data to track ship movements. According to the [U.S. Treasury](https://home.treasury.gov/system/files/126/dprk_vessel_advisory_02232018.pdf), "North Korean-flagged merchant vessels have been known to intentionally disable their AIS transponders to mask their movements. This tactic, whether employed by North Korean-flagged vessels or other vessels involved in trade with North Korea, could conceal the origin or destination of cargo destined for, or originating in, North Korea." They should know-- they're the ones imposing the sanctions that make it illegal to trade with North Korea. + +A New York Times [investigation](https://www.nytimes.com/2019/07/16/world/asia/north-korea-luxury-goods-sanctions.html) tracked the maritime voyage of luxury Mercedes cars from Germany to North Korea via the Netherlands, China, Japan, South Korea, and Russia. AIS transponders were turned off at several points throughout this journey, and the investigation had to rely on satellite imagery to fill in the gaps. + +Though they used high resolution optical imagery to follow individual ships, we want to identify lots of ships in a large area over a long period. That would get very expensive, and automatic ship detection in optical imagery is relatively difficult. Here's how our SAR tool fares when we draw a box in the bay of Nampo: ![](/images/ships_north_korea.jpg) +Looking at imagery from 2021, we can see ship traffic increasing from nearly zero to around 40 ships per day. -## Ukraine +### Ukraine -The port of Odessa is Ukraine's largest port, and -Following its invasion of Ukraine in February 2022, Russia instituted a naval blockade against Ukrainian ports. The impact of this blockade is clearly visible using the tool we've just built: +Odessa is Ukraine's largest port. Following its invasion of Ukraine in February 2022, Russia instituted a naval blockade against Ukrainian ports. The impact of this blockade is clearly visible using the tool we've just built: ![](/images/ships_ukraine.jpg) diff --git a/ships_slider/Slide1.png b/ships_slider/Slide1.png deleted file mode 100644 index 5e20a78..0000000 Binary files a/ships_slider/Slide1.png and /dev/null differ diff --git a/ships_slider/Slide2.png b/ships_slider/Slide2.png deleted file mode 100644 index 0f632b0..0000000 Binary files a/ships_slider/Slide2.png and /dev/null differ diff --git a/ships_slider/Slide3.png b/ships_slider/Slide3.png deleted file mode 100644 index 286da9e..0000000 Binary files a/ships_slider/Slide3.png and /dev/null differ diff --git a/ships_slider/Slide4.png b/ships_slider/Slide4.png deleted file mode 100644 index c25fc8c..0000000 Binary files a/ships_slider/Slide4.png and /dev/null differ diff --git a/webcams.ipynb b/webcams.ipynb deleted file mode 100644 index b63b70b..0000000 --- a/webcams.ipynb +++ /dev/null @@ -1,84 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "## run an API request to get the latest webcam images\n", - "\n", - "import requests\n", - "import json\n", - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import matplotlib.image as mpimg\n", - "import seaborn as sns\n", - "import datetime\n", - "\n", - "base_url='https://api.windy.com/api/webcams/v2/'\n", - "\n", - "# set headers\n", - "headers = {\n", - " 'x-windy-key': 'ChL1D2HHtvcbpvwIq96uvFCwe2E4tEfd',\n", - "}\n", - "\n", - "#send request\n", - "response = requests.get(base_url+'list/webcam=1668778986?show=webcams:image', headers=headers)\n", - "\n", - "image=response.json()['result']['webcams'][0]['image']['current']['preview']\n", - "\n", - "# display image using pillow\n", - "from PIL import Image\n", - "from io import BytesIO\n", - "response = requests.get(image)\n", - "img = Image.open(BytesIO(response.content))\n", - "img\n", - "\n", - "\n", - "\n", - "\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.9.5 64-bit ('3.9.5')", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.5" - }, - "orig_nbformat": 4, - "vscode": { - "interpreter": { - "hash": "d34fbd810dd9652f8e464616181cf14dbb258b5c046bed5c2f54c6b5e518fed2" - } - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/webcams_files/figure-html/cell-2-output-1.png b/webcams_files/figure-html/cell-2-output-1.png deleted file mode 100644 index 966dbcf..0000000 Binary files a/webcams_files/figure-html/cell-2-output-1.png and /dev/null differ diff --git a/webcams_files/libs/bootstrap/bootstrap-icons.css b/webcams_files/libs/bootstrap/bootstrap-icons.css deleted file mode 100644 index f51d04b..0000000 --- a/webcams_files/libs/bootstrap/bootstrap-icons.css +++ /dev/null @@ -1,1704 +0,0 @@ -@font-face { - font-family: "bootstrap-icons"; - src: -url("./bootstrap-icons.woff?524846017b983fc8ded9325d94ed40f3") format("woff"); -} - -.bi::before, -[class^="bi-"]::before, -[class*=" bi-"]::before { - display: inline-block; - font-family: bootstrap-icons !important; - font-style: normal; - font-weight: normal !important; - font-variant: normal; - text-transform: none; - line-height: 1; - vertical-align: -.125em; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -.bi-123::before { content: "\f67f"; } -.bi-alarm-fill::before { content: "\f101"; } -.bi-alarm::before { content: "\f102"; } -.bi-align-bottom::before { content: "\f103"; } -.bi-align-center::before { content: "\f104"; } -.bi-align-end::before { content: "\f105"; } -.bi-align-middle::before { content: "\f106"; } -.bi-align-start::before { content: "\f107"; } -.bi-align-top::before { content: "\f108"; } -.bi-alt::before { content: "\f109"; } -.bi-app-indicator::before { content: "\f10a"; } -.bi-app::before { content: "\f10b"; } -.bi-archive-fill::before { content: "\f10c"; } -.bi-archive::before { content: "\f10d"; } -.bi-arrow-90deg-down::before { content: "\f10e"; } -.bi-arrow-90deg-left::before { content: "\f10f"; } -.bi-arrow-90deg-right::before { content: "\f110"; } -.bi-arrow-90deg-up::before { content: "\f111"; } -.bi-arrow-bar-down::before { content: "\f112"; } -.bi-arrow-bar-left::before { content: "\f113"; } -.bi-arrow-bar-right::before { content: "\f114"; } -.bi-arrow-bar-up::before { content: "\f115"; } -.bi-arrow-clockwise::before { content: "\f116"; } -.bi-arrow-counterclockwise::before { content: "\f117"; } -.bi-arrow-down-circle-fill::before { content: "\f118"; } -.bi-arrow-down-circle::before { content: "\f119"; } -.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } -.bi-arrow-down-left-circle::before { content: "\f11b"; } -.bi-arrow-down-left-square-fill::before { content: "\f11c"; } -.bi-arrow-down-left-square::before { content: "\f11d"; } -.bi-arrow-down-left::before { content: "\f11e"; } -.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } -.bi-arrow-down-right-circle::before { content: "\f120"; } -.bi-arrow-down-right-square-fill::before { content: "\f121"; } -.bi-arrow-down-right-square::before { content: "\f122"; } -.bi-arrow-down-right::before { content: "\f123"; } -.bi-arrow-down-short::before { content: "\f124"; } -.bi-arrow-down-square-fill::before { content: "\f125"; } -.bi-arrow-down-square::before { content: "\f126"; } -.bi-arrow-down-up::before { content: "\f127"; } -.bi-arrow-down::before { content: "\f128"; } -.bi-arrow-left-circle-fill::before { content: "\f129"; } -.bi-arrow-left-circle::before { content: "\f12a"; } -.bi-arrow-left-right::before { content: "\f12b"; } -.bi-arrow-left-short::before { content: "\f12c"; } -.bi-arrow-left-square-fill::before { content: "\f12d"; } -.bi-arrow-left-square::before { content: "\f12e"; } -.bi-arrow-left::before { content: "\f12f"; } -.bi-arrow-repeat::before { content: "\f130"; } -.bi-arrow-return-left::before { content: "\f131"; } -.bi-arrow-return-right::before { content: "\f132"; } -.bi-arrow-right-circle-fill::before { content: "\f133"; } -.bi-arrow-right-circle::before { content: "\f134"; } -.bi-arrow-right-short::before { content: "\f135"; } -.bi-arrow-right-square-fill::before { content: "\f136"; } -.bi-arrow-right-square::before { content: "\f137"; } -.bi-arrow-right::before { content: "\f138"; } -.bi-arrow-up-circle-fill::before { content: "\f139"; } -.bi-arrow-up-circle::before { content: "\f13a"; } -.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } -.bi-arrow-up-left-circle::before { content: "\f13c"; } -.bi-arrow-up-left-square-fill::before { content: "\f13d"; } -.bi-arrow-up-left-square::before { content: "\f13e"; } -.bi-arrow-up-left::before { content: "\f13f"; } -.bi-arrow-up-right-circle-fill::before { content: "\f140"; } -.bi-arrow-up-right-circle::before { content: "\f141"; } -.bi-arrow-up-right-square-fill::before { content: "\f142"; } -.bi-arrow-up-right-square::before { content: "\f143"; } -.bi-arrow-up-right::before { content: "\f144"; } -.bi-arrow-up-short::before { content: "\f145"; } -.bi-arrow-up-square-fill::before { content: "\f146"; } -.bi-arrow-up-square::before { content: "\f147"; } -.bi-arrow-up::before { content: "\f148"; } -.bi-arrows-angle-contract::before { content: "\f149"; } -.bi-arrows-angle-expand::before { content: "\f14a"; } -.bi-arrows-collapse::before { content: "\f14b"; } -.bi-arrows-expand::before { content: "\f14c"; } -.bi-arrows-fullscreen::before { content: "\f14d"; } -.bi-arrows-move::before { content: "\f14e"; } -.bi-aspect-ratio-fill::before { content: "\f14f"; } -.bi-aspect-ratio::before { content: "\f150"; } -.bi-asterisk::before { content: "\f151"; } -.bi-at::before { content: "\f152"; } -.bi-award-fill::before { content: "\f153"; } -.bi-award::before { content: "\f154"; } -.bi-back::before { content: "\f155"; } -.bi-backspace-fill::before { content: "\f156"; } -.bi-backspace-reverse-fill::before { content: "\f157"; } -.bi-backspace-reverse::before { content: "\f158"; } -.bi-backspace::before { content: "\f159"; } -.bi-badge-3d-fill::before { content: "\f15a"; } -.bi-badge-3d::before { content: "\f15b"; } -.bi-badge-4k-fill::before { content: "\f15c"; } -.bi-badge-4k::before { content: "\f15d"; } -.bi-badge-8k-fill::before { content: "\f15e"; } -.bi-badge-8k::before { content: "\f15f"; } -.bi-badge-ad-fill::before { content: "\f160"; } -.bi-badge-ad::before { content: "\f161"; } -.bi-badge-ar-fill::before { content: "\f162"; } -.bi-badge-ar::before { content: "\f163"; } -.bi-badge-cc-fill::before { content: "\f164"; } -.bi-badge-cc::before { content: "\f165"; } -.bi-badge-hd-fill::before { content: "\f166"; } -.bi-badge-hd::before { content: "\f167"; } -.bi-badge-tm-fill::before { content: "\f168"; } -.bi-badge-tm::before { content: "\f169"; } -.bi-badge-vo-fill::before { content: "\f16a"; } -.bi-badge-vo::before { content: "\f16b"; } -.bi-badge-vr-fill::before { content: "\f16c"; } -.bi-badge-vr::before { content: "\f16d"; } -.bi-badge-wc-fill::before { content: "\f16e"; } -.bi-badge-wc::before { content: "\f16f"; } -.bi-bag-check-fill::before { content: "\f170"; } -.bi-bag-check::before { content: "\f171"; } -.bi-bag-dash-fill::before { content: "\f172"; } -.bi-bag-dash::before { content: "\f173"; } -.bi-bag-fill::before { content: "\f174"; } -.bi-bag-plus-fill::before { content: "\f175"; } -.bi-bag-plus::before { content: "\f176"; } -.bi-bag-x-fill::before { content: "\f177"; } -.bi-bag-x::before { content: "\f178"; } -.bi-bag::before { content: "\f179"; } -.bi-bar-chart-fill::before { content: "\f17a"; } -.bi-bar-chart-line-fill::before { content: "\f17b"; } -.bi-bar-chart-line::before { content: "\f17c"; } -.bi-bar-chart-steps::before { content: "\f17d"; } -.bi-bar-chart::before { content: "\f17e"; } -.bi-basket-fill::before { content: "\f17f"; } -.bi-basket::before { content: "\f180"; } -.bi-basket2-fill::before { content: "\f181"; } -.bi-basket2::before { content: "\f182"; } -.bi-basket3-fill::before { content: "\f183"; } -.bi-basket3::before { content: "\f184"; } -.bi-battery-charging::before { content: "\f185"; } -.bi-battery-full::before { content: "\f186"; } -.bi-battery-half::before { content: "\f187"; } -.bi-battery::before { content: "\f188"; } -.bi-bell-fill::before { content: "\f189"; } -.bi-bell::before { content: "\f18a"; } -.bi-bezier::before { content: "\f18b"; } -.bi-bezier2::before { content: "\f18c"; } -.bi-bicycle::before { content: "\f18d"; } -.bi-binoculars-fill::before { content: "\f18e"; } -.bi-binoculars::before { content: "\f18f"; } -.bi-blockquote-left::before { content: "\f190"; } -.bi-blockquote-right::before { content: "\f191"; } -.bi-book-fill::before { content: "\f192"; } -.bi-book-half::before { content: "\f193"; } -.bi-book::before { content: "\f194"; } -.bi-bookmark-check-fill::before { content: "\f195"; } -.bi-bookmark-check::before { content: "\f196"; } -.bi-bookmark-dash-fill::before { content: "\f197"; } -.bi-bookmark-dash::before { content: "\f198"; } -.bi-bookmark-fill::before { content: "\f199"; } -.bi-bookmark-heart-fill::before { content: "\f19a"; } -.bi-bookmark-heart::before { content: "\f19b"; } -.bi-bookmark-plus-fill::before { content: "\f19c"; } -.bi-bookmark-plus::before { content: "\f19d"; } -.bi-bookmark-star-fill::before { content: "\f19e"; } -.bi-bookmark-star::before { content: "\f19f"; } -.bi-bookmark-x-fill::before { content: "\f1a0"; } -.bi-bookmark-x::before { content: "\f1a1"; } -.bi-bookmark::before { content: "\f1a2"; } -.bi-bookmarks-fill::before { content: "\f1a3"; } -.bi-bookmarks::before { content: "\f1a4"; } -.bi-bookshelf::before { content: "\f1a5"; } -.bi-bootstrap-fill::before { content: "\f1a6"; } -.bi-bootstrap-reboot::before { content: "\f1a7"; } -.bi-bootstrap::before { content: "\f1a8"; } -.bi-border-all::before { content: "\f1a9"; } -.bi-border-bottom::before { content: "\f1aa"; } -.bi-border-center::before { content: "\f1ab"; } -.bi-border-inner::before { content: "\f1ac"; } -.bi-border-left::before { content: "\f1ad"; } -.bi-border-middle::before { content: "\f1ae"; } -.bi-border-outer::before { content: "\f1af"; } -.bi-border-right::before { content: "\f1b0"; } -.bi-border-style::before { content: "\f1b1"; } -.bi-border-top::before { content: "\f1b2"; } -.bi-border-width::before { content: "\f1b3"; } -.bi-border::before { content: "\f1b4"; } -.bi-bounding-box-circles::before { content: "\f1b5"; } -.bi-bounding-box::before { content: "\f1b6"; } -.bi-box-arrow-down-left::before { content: "\f1b7"; } -.bi-box-arrow-down-right::before { content: "\f1b8"; } -.bi-box-arrow-down::before { content: "\f1b9"; } -.bi-box-arrow-in-down-left::before { content: "\f1ba"; } -.bi-box-arrow-in-down-right::before { content: "\f1bb"; } -.bi-box-arrow-in-down::before { content: "\f1bc"; } -.bi-box-arrow-in-left::before { content: "\f1bd"; } -.bi-box-arrow-in-right::before { content: "\f1be"; } -.bi-box-arrow-in-up-left::before { content: "\f1bf"; } -.bi-box-arrow-in-up-right::before { content: "\f1c0"; } -.bi-box-arrow-in-up::before { content: "\f1c1"; } -.bi-box-arrow-left::before { content: "\f1c2"; } -.bi-box-arrow-right::before { content: "\f1c3"; } -.bi-box-arrow-up-left::before { content: "\f1c4"; } -.bi-box-arrow-up-right::before { content: "\f1c5"; } -.bi-box-arrow-up::before { content: "\f1c6"; } -.bi-box-seam::before { content: "\f1c7"; } -.bi-box::before { content: "\f1c8"; } -.bi-braces::before { content: "\f1c9"; } -.bi-bricks::before { content: "\f1ca"; } -.bi-briefcase-fill::before { content: "\f1cb"; } -.bi-briefcase::before { content: "\f1cc"; } -.bi-brightness-alt-high-fill::before { content: "\f1cd"; } -.bi-brightness-alt-high::before { content: "\f1ce"; } -.bi-brightness-alt-low-fill::before { content: "\f1cf"; } -.bi-brightness-alt-low::before { content: "\f1d0"; } -.bi-brightness-high-fill::before { content: "\f1d1"; } -.bi-brightness-high::before { content: "\f1d2"; } -.bi-brightness-low-fill::before { content: "\f1d3"; } -.bi-brightness-low::before { content: "\f1d4"; } -.bi-broadcast-pin::before { content: "\f1d5"; } -.bi-broadcast::before { content: "\f1d6"; } -.bi-brush-fill::before { content: "\f1d7"; } -.bi-brush::before { content: "\f1d8"; } -.bi-bucket-fill::before { content: "\f1d9"; } -.bi-bucket::before { content: "\f1da"; } -.bi-bug-fill::before { content: "\f1db"; } -.bi-bug::before { content: "\f1dc"; } -.bi-building::before { content: "\f1dd"; } -.bi-bullseye::before { content: "\f1de"; } -.bi-calculator-fill::before { content: "\f1df"; } -.bi-calculator::before { content: "\f1e0"; } -.bi-calendar-check-fill::before { content: "\f1e1"; } -.bi-calendar-check::before { content: "\f1e2"; } -.bi-calendar-date-fill::before { content: "\f1e3"; } -.bi-calendar-date::before { content: "\f1e4"; } -.bi-calendar-day-fill::before { content: "\f1e5"; } -.bi-calendar-day::before { content: "\f1e6"; } -.bi-calendar-event-fill::before { content: "\f1e7"; } -.bi-calendar-event::before { content: "\f1e8"; } -.bi-calendar-fill::before { content: "\f1e9"; } -.bi-calendar-minus-fill::before { content: "\f1ea"; } -.bi-calendar-minus::before { content: "\f1eb"; } -.bi-calendar-month-fill::before { content: "\f1ec"; } -.bi-calendar-month::before { content: "\f1ed"; } -.bi-calendar-plus-fill::before { content: "\f1ee"; } -.bi-calendar-plus::before { content: "\f1ef"; } -.bi-calendar-range-fill::before { content: "\f1f0"; } -.bi-calendar-range::before { content: "\f1f1"; } -.bi-calendar-week-fill::before { content: "\f1f2"; } -.bi-calendar-week::before { content: "\f1f3"; } -.bi-calendar-x-fill::before { content: "\f1f4"; } -.bi-calendar-x::before { content: "\f1f5"; } -.bi-calendar::before { content: "\f1f6"; } -.bi-calendar2-check-fill::before { content: "\f1f7"; } -.bi-calendar2-check::before { content: "\f1f8"; } -.bi-calendar2-date-fill::before { content: "\f1f9"; } -.bi-calendar2-date::before { content: "\f1fa"; } -.bi-calendar2-day-fill::before { content: "\f1fb"; } -.bi-calendar2-day::before { content: "\f1fc"; } -.bi-calendar2-event-fill::before { content: "\f1fd"; } -.bi-calendar2-event::before { content: "\f1fe"; } -.bi-calendar2-fill::before { content: "\f1ff"; } -.bi-calendar2-minus-fill::before { content: "\f200"; } -.bi-calendar2-minus::before { content: "\f201"; } -.bi-calendar2-month-fill::before { content: "\f202"; } -.bi-calendar2-month::before { content: "\f203"; } -.bi-calendar2-plus-fill::before { content: "\f204"; } -.bi-calendar2-plus::before { content: "\f205"; } -.bi-calendar2-range-fill::before { content: "\f206"; } -.bi-calendar2-range::before { content: "\f207"; } -.bi-calendar2-week-fill::before { content: "\f208"; } -.bi-calendar2-week::before { content: "\f209"; } -.bi-calendar2-x-fill::before { content: "\f20a"; } -.bi-calendar2-x::before { content: "\f20b"; } -.bi-calendar2::before { content: "\f20c"; } -.bi-calendar3-event-fill::before { content: "\f20d"; } -.bi-calendar3-event::before { content: "\f20e"; } -.bi-calendar3-fill::before { content: "\f20f"; } -.bi-calendar3-range-fill::before { content: "\f210"; } -.bi-calendar3-range::before { content: "\f211"; } -.bi-calendar3-week-fill::before { content: "\f212"; } -.bi-calendar3-week::before { content: "\f213"; } -.bi-calendar3::before { content: "\f214"; } -.bi-calendar4-event::before { content: "\f215"; } -.bi-calendar4-range::before { content: "\f216"; } -.bi-calendar4-week::before { content: "\f217"; } -.bi-calendar4::before { content: "\f218"; } -.bi-camera-fill::before { content: "\f219"; } -.bi-camera-reels-fill::before { content: "\f21a"; } -.bi-camera-reels::before { content: "\f21b"; } -.bi-camera-video-fill::before { content: "\f21c"; } -.bi-camera-video-off-fill::before { content: "\f21d"; } -.bi-camera-video-off::before { content: "\f21e"; } -.bi-camera-video::before { content: "\f21f"; } -.bi-camera::before { content: "\f220"; } -.bi-camera2::before { content: "\f221"; } -.bi-capslock-fill::before { content: "\f222"; } -.bi-capslock::before { content: "\f223"; } -.bi-card-checklist::before { content: "\f224"; } -.bi-card-heading::before { content: "\f225"; } -.bi-card-image::before { content: "\f226"; } -.bi-card-list::before { content: "\f227"; } -.bi-card-text::before { content: "\f228"; } -.bi-caret-down-fill::before { content: "\f229"; } -.bi-caret-down-square-fill::before { content: "\f22a"; } -.bi-caret-down-square::before { content: "\f22b"; } -.bi-caret-down::before { content: "\f22c"; } -.bi-caret-left-fill::before { content: "\f22d"; } -.bi-caret-left-square-fill::before { content: "\f22e"; } -.bi-caret-left-square::before { content: "\f22f"; } -.bi-caret-left::before { content: "\f230"; } -.bi-caret-right-fill::before { content: "\f231"; } -.bi-caret-right-square-fill::before { content: "\f232"; } -.bi-caret-right-square::before { content: "\f233"; } -.bi-caret-right::before { content: "\f234"; } -.bi-caret-up-fill::before { content: "\f235"; } -.bi-caret-up-square-fill::before { content: "\f236"; } -.bi-caret-up-square::before { content: "\f237"; } -.bi-caret-up::before { content: "\f238"; } -.bi-cart-check-fill::before { content: "\f239"; } -.bi-cart-check::before { content: "\f23a"; } -.bi-cart-dash-fill::before { content: "\f23b"; } -.bi-cart-dash::before { content: "\f23c"; } -.bi-cart-fill::before { content: "\f23d"; } -.bi-cart-plus-fill::before { content: "\f23e"; } -.bi-cart-plus::before { content: "\f23f"; } -.bi-cart-x-fill::before { content: "\f240"; } -.bi-cart-x::before { content: "\f241"; } -.bi-cart::before { content: "\f242"; } -.bi-cart2::before { content: "\f243"; } -.bi-cart3::before { content: "\f244"; } -.bi-cart4::before { content: "\f245"; } -.bi-cash-stack::before { content: "\f246"; } -.bi-cash::before { content: "\f247"; } -.bi-cast::before { content: "\f248"; } -.bi-chat-dots-fill::before { content: "\f249"; } -.bi-chat-dots::before { content: "\f24a"; } -.bi-chat-fill::before { content: "\f24b"; } -.bi-chat-left-dots-fill::before { content: "\f24c"; } -.bi-chat-left-dots::before { content: "\f24d"; } -.bi-chat-left-fill::before { content: "\f24e"; } -.bi-chat-left-quote-fill::before { content: "\f24f"; } -.bi-chat-left-quote::before { content: "\f250"; } -.bi-chat-left-text-fill::before { content: "\f251"; } -.bi-chat-left-text::before { content: "\f252"; } -.bi-chat-left::before { content: "\f253"; } -.bi-chat-quote-fill::before { content: "\f254"; } -.bi-chat-quote::before { content: "\f255"; } -.bi-chat-right-dots-fill::before { content: "\f256"; } -.bi-chat-right-dots::before { content: "\f257"; } -.bi-chat-right-fill::before { content: "\f258"; } -.bi-chat-right-quote-fill::before { content: "\f259"; } -.bi-chat-right-quote::before { content: "\f25a"; } -.bi-chat-right-text-fill::before { content: "\f25b"; } -.bi-chat-right-text::before { content: "\f25c"; } -.bi-chat-right::before { content: "\f25d"; } -.bi-chat-square-dots-fill::before { content: "\f25e"; } -.bi-chat-square-dots::before { content: "\f25f"; } -.bi-chat-square-fill::before { content: "\f260"; } -.bi-chat-square-quote-fill::before { content: "\f261"; } -.bi-chat-square-quote::before { content: "\f262"; } -.bi-chat-square-text-fill::before { content: "\f263"; } -.bi-chat-square-text::before { content: "\f264"; } -.bi-chat-square::before { content: "\f265"; } -.bi-chat-text-fill::before { content: "\f266"; } -.bi-chat-text::before { content: "\f267"; } -.bi-chat::before { content: "\f268"; } -.bi-check-all::before { content: "\f269"; } -.bi-check-circle-fill::before { content: "\f26a"; } -.bi-check-circle::before { content: "\f26b"; } -.bi-check-square-fill::before { content: "\f26c"; } -.bi-check-square::before { content: "\f26d"; } -.bi-check::before { content: "\f26e"; } -.bi-check2-all::before { content: "\f26f"; } -.bi-check2-circle::before { content: "\f270"; } -.bi-check2-square::before { content: "\f271"; } -.bi-check2::before { content: "\f272"; } -.bi-chevron-bar-contract::before { content: "\f273"; } -.bi-chevron-bar-down::before { content: "\f274"; } -.bi-chevron-bar-expand::before { content: "\f275"; } -.bi-chevron-bar-left::before { content: "\f276"; } -.bi-chevron-bar-right::before { content: "\f277"; } -.bi-chevron-bar-up::before { content: "\f278"; } -.bi-chevron-compact-down::before { content: "\f279"; } -.bi-chevron-compact-left::before { content: "\f27a"; } -.bi-chevron-compact-right::before { content: "\f27b"; } -.bi-chevron-compact-up::before { content: "\f27c"; } -.bi-chevron-contract::before { content: "\f27d"; } -.bi-chevron-double-down::before { content: "\f27e"; } -.bi-chevron-double-left::before { content: "\f27f"; } -.bi-chevron-double-right::before { content: "\f280"; } -.bi-chevron-double-up::before { content: "\f281"; } -.bi-chevron-down::before { content: "\f282"; } -.bi-chevron-expand::before { content: "\f283"; } -.bi-chevron-left::before { content: "\f284"; } -.bi-chevron-right::before { content: "\f285"; } -.bi-chevron-up::before { content: "\f286"; } -.bi-circle-fill::before { content: "\f287"; } -.bi-circle-half::before { content: "\f288"; } -.bi-circle-square::before { content: "\f289"; } -.bi-circle::before { content: "\f28a"; } -.bi-clipboard-check::before { content: "\f28b"; } -.bi-clipboard-data::before { content: "\f28c"; } -.bi-clipboard-minus::before { content: "\f28d"; } -.bi-clipboard-plus::before { content: "\f28e"; } -.bi-clipboard-x::before { content: "\f28f"; } -.bi-clipboard::before { content: "\f290"; } -.bi-clock-fill::before { content: "\f291"; } -.bi-clock-history::before { content: "\f292"; } -.bi-clock::before { content: "\f293"; } -.bi-cloud-arrow-down-fill::before { content: "\f294"; } -.bi-cloud-arrow-down::before { content: "\f295"; } -.bi-cloud-arrow-up-fill::before { content: "\f296"; } -.bi-cloud-arrow-up::before { content: "\f297"; } -.bi-cloud-check-fill::before { content: "\f298"; } -.bi-cloud-check::before { content: "\f299"; } -.bi-cloud-download-fill::before { content: "\f29a"; } -.bi-cloud-download::before { content: "\f29b"; } -.bi-cloud-drizzle-fill::before { content: "\f29c"; } -.bi-cloud-drizzle::before { content: "\f29d"; } -.bi-cloud-fill::before { content: "\f29e"; } -.bi-cloud-fog-fill::before { content: "\f29f"; } -.bi-cloud-fog::before { content: "\f2a0"; } -.bi-cloud-fog2-fill::before { content: "\f2a1"; } -.bi-cloud-fog2::before { content: "\f2a2"; } -.bi-cloud-hail-fill::before { content: "\f2a3"; } -.bi-cloud-hail::before { content: "\f2a4"; } -.bi-cloud-haze-1::before { content: "\f2a5"; } -.bi-cloud-haze-fill::before { content: "\f2a6"; } -.bi-cloud-haze::before { content: "\f2a7"; } -.bi-cloud-haze2-fill::before { content: "\f2a8"; } -.bi-cloud-lightning-fill::before { content: "\f2a9"; } -.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } -.bi-cloud-lightning-rain::before { content: "\f2ab"; } -.bi-cloud-lightning::before { content: "\f2ac"; } -.bi-cloud-minus-fill::before { content: "\f2ad"; } -.bi-cloud-minus::before { content: "\f2ae"; } -.bi-cloud-moon-fill::before { content: "\f2af"; } -.bi-cloud-moon::before { content: "\f2b0"; } -.bi-cloud-plus-fill::before { content: "\f2b1"; } -.bi-cloud-plus::before { content: "\f2b2"; } -.bi-cloud-rain-fill::before { content: "\f2b3"; } -.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } -.bi-cloud-rain-heavy::before { content: "\f2b5"; } -.bi-cloud-rain::before { content: "\f2b6"; } -.bi-cloud-slash-fill::before { content: "\f2b7"; } -.bi-cloud-slash::before { content: "\f2b8"; } -.bi-cloud-sleet-fill::before { content: "\f2b9"; } -.bi-cloud-sleet::before { content: "\f2ba"; } -.bi-cloud-snow-fill::before { content: "\f2bb"; } -.bi-cloud-snow::before { content: "\f2bc"; } -.bi-cloud-sun-fill::before { content: "\f2bd"; } -.bi-cloud-sun::before { content: "\f2be"; } -.bi-cloud-upload-fill::before { content: "\f2bf"; } -.bi-cloud-upload::before { content: "\f2c0"; } -.bi-cloud::before { content: "\f2c1"; } -.bi-clouds-fill::before { content: "\f2c2"; } -.bi-clouds::before { content: "\f2c3"; } -.bi-cloudy-fill::before { content: "\f2c4"; } -.bi-cloudy::before { content: "\f2c5"; } -.bi-code-slash::before { content: "\f2c6"; } -.bi-code-square::before { content: "\f2c7"; } -.bi-code::before { content: "\f2c8"; } -.bi-collection-fill::before { content: "\f2c9"; } -.bi-collection-play-fill::before { content: "\f2ca"; } -.bi-collection-play::before { content: "\f2cb"; } -.bi-collection::before { content: "\f2cc"; } -.bi-columns-gap::before { content: "\f2cd"; } -.bi-columns::before { content: "\f2ce"; } -.bi-command::before { content: "\f2cf"; } -.bi-compass-fill::before { content: "\f2d0"; } -.bi-compass::before { content: "\f2d1"; } -.bi-cone-striped::before { content: "\f2d2"; } -.bi-cone::before { content: "\f2d3"; } -.bi-controller::before { content: "\f2d4"; } -.bi-cpu-fill::before { content: "\f2d5"; } -.bi-cpu::before { content: "\f2d6"; } -.bi-credit-card-2-back-fill::before { content: "\f2d7"; } -.bi-credit-card-2-back::before { content: "\f2d8"; } -.bi-credit-card-2-front-fill::before { content: "\f2d9"; } -.bi-credit-card-2-front::before { content: "\f2da"; } -.bi-credit-card-fill::before { content: "\f2db"; } -.bi-credit-card::before { content: "\f2dc"; } -.bi-crop::before { content: "\f2dd"; } -.bi-cup-fill::before { content: "\f2de"; } -.bi-cup-straw::before { content: "\f2df"; } -.bi-cup::before { content: "\f2e0"; } -.bi-cursor-fill::before { content: "\f2e1"; } -.bi-cursor-text::before { content: "\f2e2"; } -.bi-cursor::before { content: "\f2e3"; } -.bi-dash-circle-dotted::before { content: "\f2e4"; } -.bi-dash-circle-fill::before { content: "\f2e5"; } -.bi-dash-circle::before { content: "\f2e6"; } -.bi-dash-square-dotted::before { content: "\f2e7"; } -.bi-dash-square-fill::before { content: "\f2e8"; } -.bi-dash-square::before { content: "\f2e9"; } -.bi-dash::before { content: "\f2ea"; } -.bi-diagram-2-fill::before { content: "\f2eb"; } -.bi-diagram-2::before { content: "\f2ec"; } -.bi-diagram-3-fill::before { content: "\f2ed"; } -.bi-diagram-3::before { content: "\f2ee"; } -.bi-diamond-fill::before { content: "\f2ef"; } -.bi-diamond-half::before { content: "\f2f0"; } -.bi-diamond::before { content: "\f2f1"; } -.bi-dice-1-fill::before { content: "\f2f2"; } -.bi-dice-1::before { content: "\f2f3"; } -.bi-dice-2-fill::before { content: "\f2f4"; } -.bi-dice-2::before { content: "\f2f5"; } -.bi-dice-3-fill::before { content: "\f2f6"; } -.bi-dice-3::before { content: "\f2f7"; } -.bi-dice-4-fill::before { content: "\f2f8"; } -.bi-dice-4::before { content: "\f2f9"; } -.bi-dice-5-fill::before { content: "\f2fa"; } -.bi-dice-5::before { content: "\f2fb"; } -.bi-dice-6-fill::before { content: "\f2fc"; } -.bi-dice-6::before { content: "\f2fd"; } -.bi-disc-fill::before { content: "\f2fe"; } -.bi-disc::before { content: "\f2ff"; } -.bi-discord::before { content: "\f300"; } -.bi-display-fill::before { content: "\f301"; } -.bi-display::before { content: "\f302"; } -.bi-distribute-horizontal::before { content: "\f303"; } -.bi-distribute-vertical::before { content: "\f304"; } -.bi-door-closed-fill::before { content: "\f305"; } -.bi-door-closed::before { content: "\f306"; } -.bi-door-open-fill::before { content: "\f307"; } -.bi-door-open::before { content: "\f308"; } -.bi-dot::before { content: "\f309"; } -.bi-download::before { content: "\f30a"; } -.bi-droplet-fill::before { content: "\f30b"; } -.bi-droplet-half::before { content: "\f30c"; } -.bi-droplet::before { content: "\f30d"; } -.bi-earbuds::before { content: "\f30e"; } -.bi-easel-fill::before { content: "\f30f"; } -.bi-easel::before { content: "\f310"; } -.bi-egg-fill::before { content: "\f311"; } -.bi-egg-fried::before { content: "\f312"; } -.bi-egg::before { content: "\f313"; } -.bi-eject-fill::before { content: "\f314"; } -.bi-eject::before { content: "\f315"; } -.bi-emoji-angry-fill::before { content: "\f316"; } -.bi-emoji-angry::before { content: "\f317"; } -.bi-emoji-dizzy-fill::before { content: "\f318"; } -.bi-emoji-dizzy::before { content: "\f319"; } -.bi-emoji-expressionless-fill::before { content: "\f31a"; } -.bi-emoji-expressionless::before { content: "\f31b"; } -.bi-emoji-frown-fill::before { content: "\f31c"; } -.bi-emoji-frown::before { content: "\f31d"; } -.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } -.bi-emoji-heart-eyes::before { content: "\f31f"; } -.bi-emoji-laughing-fill::before { content: "\f320"; } -.bi-emoji-laughing::before { content: "\f321"; } -.bi-emoji-neutral-fill::before { content: "\f322"; } -.bi-emoji-neutral::before { content: "\f323"; } -.bi-emoji-smile-fill::before { content: "\f324"; } -.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } -.bi-emoji-smile-upside-down::before { content: "\f326"; } -.bi-emoji-smile::before { content: "\f327"; } -.bi-emoji-sunglasses-fill::before { content: "\f328"; } -.bi-emoji-sunglasses::before { content: "\f329"; } -.bi-emoji-wink-fill::before { content: "\f32a"; } -.bi-emoji-wink::before { content: "\f32b"; } -.bi-envelope-fill::before { content: "\f32c"; } -.bi-envelope-open-fill::before { content: "\f32d"; } -.bi-envelope-open::before { content: "\f32e"; } -.bi-envelope::before { content: "\f32f"; } -.bi-eraser-fill::before { content: "\f330"; } -.bi-eraser::before { content: "\f331"; } -.bi-exclamation-circle-fill::before { content: "\f332"; } -.bi-exclamation-circle::before { content: "\f333"; } -.bi-exclamation-diamond-fill::before { content: "\f334"; } -.bi-exclamation-diamond::before { content: "\f335"; } -.bi-exclamation-octagon-fill::before { content: "\f336"; } -.bi-exclamation-octagon::before { content: "\f337"; } -.bi-exclamation-square-fill::before { content: "\f338"; } -.bi-exclamation-square::before { content: "\f339"; } -.bi-exclamation-triangle-fill::before { content: "\f33a"; } -.bi-exclamation-triangle::before { content: "\f33b"; } -.bi-exclamation::before { content: "\f33c"; } -.bi-exclude::before { content: "\f33d"; } -.bi-eye-fill::before { content: "\f33e"; } -.bi-eye-slash-fill::before { content: "\f33f"; } -.bi-eye-slash::before { content: "\f340"; } -.bi-eye::before { content: "\f341"; } -.bi-eyedropper::before { content: "\f342"; } -.bi-eyeglasses::before { content: "\f343"; } -.bi-facebook::before { content: "\f344"; } -.bi-file-arrow-down-fill::before { content: "\f345"; } -.bi-file-arrow-down::before { content: "\f346"; } -.bi-file-arrow-up-fill::before { content: "\f347"; } -.bi-file-arrow-up::before { content: "\f348"; } -.bi-file-bar-graph-fill::before { content: "\f349"; } -.bi-file-bar-graph::before { content: "\f34a"; } -.bi-file-binary-fill::before { content: "\f34b"; } -.bi-file-binary::before { content: "\f34c"; } -.bi-file-break-fill::before { content: "\f34d"; } -.bi-file-break::before { content: "\f34e"; } -.bi-file-check-fill::before { content: "\f34f"; } -.bi-file-check::before { content: "\f350"; } -.bi-file-code-fill::before { content: "\f351"; } -.bi-file-code::before { content: "\f352"; } -.bi-file-diff-fill::before { content: "\f353"; } -.bi-file-diff::before { content: "\f354"; } -.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } -.bi-file-earmark-arrow-down::before { content: "\f356"; } -.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } -.bi-file-earmark-arrow-up::before { content: "\f358"; } -.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } -.bi-file-earmark-bar-graph::before { content: "\f35a"; } -.bi-file-earmark-binary-fill::before { content: "\f35b"; } -.bi-file-earmark-binary::before { content: "\f35c"; } -.bi-file-earmark-break-fill::before { content: "\f35d"; } -.bi-file-earmark-break::before { content: "\f35e"; } -.bi-file-earmark-check-fill::before { content: "\f35f"; } -.bi-file-earmark-check::before { content: "\f360"; } -.bi-file-earmark-code-fill::before { content: "\f361"; } -.bi-file-earmark-code::before { content: "\f362"; } -.bi-file-earmark-diff-fill::before { content: "\f363"; } -.bi-file-earmark-diff::before { content: "\f364"; } -.bi-file-earmark-easel-fill::before { content: "\f365"; } -.bi-file-earmark-easel::before { content: "\f366"; } -.bi-file-earmark-excel-fill::before { content: "\f367"; } -.bi-file-earmark-excel::before { content: "\f368"; } -.bi-file-earmark-fill::before { content: "\f369"; } -.bi-file-earmark-font-fill::before { content: "\f36a"; } -.bi-file-earmark-font::before { content: "\f36b"; } -.bi-file-earmark-image-fill::before { content: "\f36c"; } -.bi-file-earmark-image::before { content: "\f36d"; } -.bi-file-earmark-lock-fill::before { content: "\f36e"; } -.bi-file-earmark-lock::before { content: "\f36f"; } -.bi-file-earmark-lock2-fill::before { content: "\f370"; } -.bi-file-earmark-lock2::before { content: "\f371"; } -.bi-file-earmark-medical-fill::before { content: "\f372"; } -.bi-file-earmark-medical::before { content: "\f373"; } -.bi-file-earmark-minus-fill::before { content: "\f374"; } -.bi-file-earmark-minus::before { content: "\f375"; } -.bi-file-earmark-music-fill::before { content: "\f376"; } -.bi-file-earmark-music::before { content: "\f377"; } -.bi-file-earmark-person-fill::before { content: "\f378"; } -.bi-file-earmark-person::before { content: "\f379"; } -.bi-file-earmark-play-fill::before { content: "\f37a"; } -.bi-file-earmark-play::before { content: "\f37b"; } -.bi-file-earmark-plus-fill::before { content: "\f37c"; } -.bi-file-earmark-plus::before { content: "\f37d"; } -.bi-file-earmark-post-fill::before { content: "\f37e"; } -.bi-file-earmark-post::before { content: "\f37f"; } -.bi-file-earmark-ppt-fill::before { content: "\f380"; } -.bi-file-earmark-ppt::before { content: "\f381"; } -.bi-file-earmark-richtext-fill::before { content: "\f382"; } -.bi-file-earmark-richtext::before { content: "\f383"; } -.bi-file-earmark-ruled-fill::before { content: "\f384"; } -.bi-file-earmark-ruled::before { content: "\f385"; } -.bi-file-earmark-slides-fill::before { content: "\f386"; } -.bi-file-earmark-slides::before { content: "\f387"; } -.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } -.bi-file-earmark-spreadsheet::before { content: "\f389"; } -.bi-file-earmark-text-fill::before { content: "\f38a"; } -.bi-file-earmark-text::before { content: "\f38b"; } -.bi-file-earmark-word-fill::before { content: "\f38c"; } -.bi-file-earmark-word::before { content: "\f38d"; } -.bi-file-earmark-x-fill::before { content: "\f38e"; } -.bi-file-earmark-x::before { content: "\f38f"; } -.bi-file-earmark-zip-fill::before { content: "\f390"; } -.bi-file-earmark-zip::before { content: "\f391"; } -.bi-file-earmark::before { content: "\f392"; } -.bi-file-easel-fill::before { content: "\f393"; } -.bi-file-easel::before { content: "\f394"; } -.bi-file-excel-fill::before { content: "\f395"; } -.bi-file-excel::before { content: "\f396"; } -.bi-file-fill::before { content: "\f397"; } -.bi-file-font-fill::before { content: "\f398"; } -.bi-file-font::before { content: "\f399"; } -.bi-file-image-fill::before { content: "\f39a"; } -.bi-file-image::before { content: "\f39b"; } -.bi-file-lock-fill::before { content: "\f39c"; } -.bi-file-lock::before { content: "\f39d"; } -.bi-file-lock2-fill::before { content: "\f39e"; } -.bi-file-lock2::before { content: "\f39f"; } -.bi-file-medical-fill::before { content: "\f3a0"; } -.bi-file-medical::before { content: "\f3a1"; } -.bi-file-minus-fill::before { content: "\f3a2"; } -.bi-file-minus::before { content: "\f3a3"; } -.bi-file-music-fill::before { content: "\f3a4"; } -.bi-file-music::before { content: "\f3a5"; } -.bi-file-person-fill::before { content: "\f3a6"; } -.bi-file-person::before { content: "\f3a7"; } -.bi-file-play-fill::before { content: "\f3a8"; } -.bi-file-play::before { content: "\f3a9"; } -.bi-file-plus-fill::before { content: "\f3aa"; } -.bi-file-plus::before { content: "\f3ab"; } -.bi-file-post-fill::before { content: "\f3ac"; } -.bi-file-post::before { content: "\f3ad"; } -.bi-file-ppt-fill::before { content: "\f3ae"; } -.bi-file-ppt::before { content: "\f3af"; } -.bi-file-richtext-fill::before { content: "\f3b0"; } -.bi-file-richtext::before { content: "\f3b1"; } -.bi-file-ruled-fill::before { content: "\f3b2"; } -.bi-file-ruled::before { content: "\f3b3"; } -.bi-file-slides-fill::before { content: "\f3b4"; } -.bi-file-slides::before { content: "\f3b5"; } -.bi-file-spreadsheet-fill::before { content: "\f3b6"; } -.bi-file-spreadsheet::before { content: "\f3b7"; } -.bi-file-text-fill::before { content: "\f3b8"; } -.bi-file-text::before { content: "\f3b9"; } -.bi-file-word-fill::before { content: "\f3ba"; } -.bi-file-word::before { content: "\f3bb"; } -.bi-file-x-fill::before { content: "\f3bc"; } -.bi-file-x::before { content: "\f3bd"; } -.bi-file-zip-fill::before { content: "\f3be"; } -.bi-file-zip::before { content: "\f3bf"; } -.bi-file::before { content: "\f3c0"; } -.bi-files-alt::before { content: "\f3c1"; } -.bi-files::before { content: "\f3c2"; } -.bi-film::before { content: "\f3c3"; } -.bi-filter-circle-fill::before { content: "\f3c4"; } -.bi-filter-circle::before { content: "\f3c5"; } -.bi-filter-left::before { content: "\f3c6"; } -.bi-filter-right::before { content: "\f3c7"; } -.bi-filter-square-fill::before { content: "\f3c8"; } -.bi-filter-square::before { content: "\f3c9"; } -.bi-filter::before { content: "\f3ca"; } -.bi-flag-fill::before { content: "\f3cb"; } -.bi-flag::before { content: "\f3cc"; } -.bi-flower1::before { content: "\f3cd"; } -.bi-flower2::before { content: "\f3ce"; } -.bi-flower3::before { content: "\f3cf"; } -.bi-folder-check::before { content: "\f3d0"; } -.bi-folder-fill::before { content: "\f3d1"; } -.bi-folder-minus::before { content: "\f3d2"; } -.bi-folder-plus::before { content: "\f3d3"; } -.bi-folder-symlink-fill::before { content: "\f3d4"; } -.bi-folder-symlink::before { content: "\f3d5"; } -.bi-folder-x::before { content: "\f3d6"; } -.bi-folder::before { content: "\f3d7"; } -.bi-folder2-open::before { content: "\f3d8"; } -.bi-folder2::before { content: "\f3d9"; } -.bi-fonts::before { content: "\f3da"; } -.bi-forward-fill::before { content: "\f3db"; } -.bi-forward::before { content: "\f3dc"; } -.bi-front::before { content: "\f3dd"; } -.bi-fullscreen-exit::before { content: "\f3de"; } -.bi-fullscreen::before { content: "\f3df"; } -.bi-funnel-fill::before { content: "\f3e0"; } -.bi-funnel::before { content: "\f3e1"; } -.bi-gear-fill::before { content: "\f3e2"; } -.bi-gear-wide-connected::before { content: "\f3e3"; } -.bi-gear-wide::before { content: "\f3e4"; } -.bi-gear::before { content: "\f3e5"; } -.bi-gem::before { content: "\f3e6"; } -.bi-geo-alt-fill::before { content: "\f3e7"; } -.bi-geo-alt::before { content: "\f3e8"; } -.bi-geo-fill::before { content: "\f3e9"; } -.bi-geo::before { content: "\f3ea"; } -.bi-gift-fill::before { content: "\f3eb"; } -.bi-gift::before { content: "\f3ec"; } -.bi-github::before { content: "\f3ed"; } -.bi-globe::before { content: "\f3ee"; } -.bi-globe2::before { content: "\f3ef"; } -.bi-google::before { content: "\f3f0"; } -.bi-graph-down::before { content: "\f3f1"; } -.bi-graph-up::before { content: "\f3f2"; } -.bi-grid-1x2-fill::before { content: "\f3f3"; } -.bi-grid-1x2::before { content: "\f3f4"; } -.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } -.bi-grid-3x2-gap::before { content: "\f3f6"; } -.bi-grid-3x2::before { content: "\f3f7"; } -.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } -.bi-grid-3x3-gap::before { content: "\f3f9"; } -.bi-grid-3x3::before { content: "\f3fa"; } -.bi-grid-fill::before { content: "\f3fb"; } -.bi-grid::before { content: "\f3fc"; } -.bi-grip-horizontal::before { content: "\f3fd"; } -.bi-grip-vertical::before { content: "\f3fe"; } -.bi-hammer::before { content: "\f3ff"; } -.bi-hand-index-fill::before { content: "\f400"; } -.bi-hand-index-thumb-fill::before { content: "\f401"; } -.bi-hand-index-thumb::before { content: "\f402"; } -.bi-hand-index::before { content: "\f403"; } -.bi-hand-thumbs-down-fill::before { content: "\f404"; } -.bi-hand-thumbs-down::before { content: "\f405"; } -.bi-hand-thumbs-up-fill::before { content: "\f406"; } -.bi-hand-thumbs-up::before { content: "\f407"; } -.bi-handbag-fill::before { content: "\f408"; } -.bi-handbag::before { content: "\f409"; } -.bi-hash::before { content: "\f40a"; } -.bi-hdd-fill::before { content: "\f40b"; } -.bi-hdd-network-fill::before { content: "\f40c"; } -.bi-hdd-network::before { content: "\f40d"; } -.bi-hdd-rack-fill::before { content: "\f40e"; } -.bi-hdd-rack::before { content: "\f40f"; } -.bi-hdd-stack-fill::before { content: "\f410"; } -.bi-hdd-stack::before { content: "\f411"; } -.bi-hdd::before { content: "\f412"; } -.bi-headphones::before { content: "\f413"; } -.bi-headset::before { content: "\f414"; } -.bi-heart-fill::before { content: "\f415"; } -.bi-heart-half::before { content: "\f416"; } -.bi-heart::before { content: "\f417"; } -.bi-heptagon-fill::before { content: "\f418"; } -.bi-heptagon-half::before { content: "\f419"; } -.bi-heptagon::before { content: "\f41a"; } -.bi-hexagon-fill::before { content: "\f41b"; } -.bi-hexagon-half::before { content: "\f41c"; } -.bi-hexagon::before { content: "\f41d"; } -.bi-hourglass-bottom::before { content: "\f41e"; } -.bi-hourglass-split::before { content: "\f41f"; } -.bi-hourglass-top::before { content: "\f420"; } -.bi-hourglass::before { content: "\f421"; } -.bi-house-door-fill::before { content: "\f422"; } -.bi-house-door::before { content: "\f423"; } -.bi-house-fill::before { content: "\f424"; } -.bi-house::before { content: "\f425"; } -.bi-hr::before { content: "\f426"; } -.bi-hurricane::before { content: "\f427"; } -.bi-image-alt::before { content: "\f428"; } -.bi-image-fill::before { content: "\f429"; } -.bi-image::before { content: "\f42a"; } -.bi-images::before { content: "\f42b"; } -.bi-inbox-fill::before { content: "\f42c"; } -.bi-inbox::before { content: "\f42d"; } -.bi-inboxes-fill::before { content: "\f42e"; } -.bi-inboxes::before { content: "\f42f"; } -.bi-info-circle-fill::before { content: "\f430"; } -.bi-info-circle::before { content: "\f431"; } -.bi-info-square-fill::before { content: "\f432"; } -.bi-info-square::before { content: "\f433"; } -.bi-info::before { content: "\f434"; } -.bi-input-cursor-text::before { content: "\f435"; } -.bi-input-cursor::before { content: "\f436"; } -.bi-instagram::before { content: "\f437"; } -.bi-intersect::before { content: "\f438"; } -.bi-journal-album::before { content: "\f439"; } -.bi-journal-arrow-down::before { content: "\f43a"; } -.bi-journal-arrow-up::before { content: "\f43b"; } -.bi-journal-bookmark-fill::before { content: "\f43c"; } -.bi-journal-bookmark::before { content: "\f43d"; } -.bi-journal-check::before { content: "\f43e"; } -.bi-journal-code::before { content: "\f43f"; } -.bi-journal-medical::before { content: "\f440"; } -.bi-journal-minus::before { content: "\f441"; } -.bi-journal-plus::before { content: "\f442"; } -.bi-journal-richtext::before { content: "\f443"; } -.bi-journal-text::before { content: "\f444"; } -.bi-journal-x::before { content: "\f445"; } -.bi-journal::before { content: "\f446"; } -.bi-journals::before { content: "\f447"; } -.bi-joystick::before { content: "\f448"; } -.bi-justify-left::before { content: "\f449"; } -.bi-justify-right::before { content: "\f44a"; } -.bi-justify::before { content: "\f44b"; } -.bi-kanban-fill::before { content: "\f44c"; } -.bi-kanban::before { content: "\f44d"; } -.bi-key-fill::before { content: "\f44e"; } -.bi-key::before { content: "\f44f"; } -.bi-keyboard-fill::before { content: "\f450"; } -.bi-keyboard::before { content: "\f451"; } -.bi-ladder::before { content: "\f452"; } -.bi-lamp-fill::before { content: "\f453"; } -.bi-lamp::before { content: "\f454"; } -.bi-laptop-fill::before { content: "\f455"; } -.bi-laptop::before { content: "\f456"; } -.bi-layer-backward::before { content: "\f457"; } -.bi-layer-forward::before { content: "\f458"; } -.bi-layers-fill::before { content: "\f459"; } -.bi-layers-half::before { content: "\f45a"; } -.bi-layers::before { content: "\f45b"; } -.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } -.bi-layout-sidebar-inset::before { content: "\f45d"; } -.bi-layout-sidebar-reverse::before { content: "\f45e"; } -.bi-layout-sidebar::before { content: "\f45f"; } -.bi-layout-split::before { content: "\f460"; } -.bi-layout-text-sidebar-reverse::before { content: "\f461"; } -.bi-layout-text-sidebar::before { content: "\f462"; } -.bi-layout-text-window-reverse::before { content: "\f463"; } -.bi-layout-text-window::before { content: "\f464"; } -.bi-layout-three-columns::before { content: "\f465"; } -.bi-layout-wtf::before { content: "\f466"; } -.bi-life-preserver::before { content: "\f467"; } -.bi-lightbulb-fill::before { content: "\f468"; } -.bi-lightbulb-off-fill::before { content: "\f469"; } -.bi-lightbulb-off::before { content: "\f46a"; } -.bi-lightbulb::before { content: "\f46b"; } -.bi-lightning-charge-fill::before { content: "\f46c"; } -.bi-lightning-charge::before { content: "\f46d"; } -.bi-lightning-fill::before { content: "\f46e"; } -.bi-lightning::before { content: "\f46f"; } -.bi-link-45deg::before { content: "\f470"; } -.bi-link::before { content: "\f471"; } -.bi-linkedin::before { content: "\f472"; } -.bi-list-check::before { content: "\f473"; } -.bi-list-nested::before { content: "\f474"; } -.bi-list-ol::before { content: "\f475"; } -.bi-list-stars::before { content: "\f476"; } -.bi-list-task::before { content: "\f477"; } -.bi-list-ul::before { content: "\f478"; } -.bi-list::before { content: "\f479"; } -.bi-lock-fill::before { content: "\f47a"; } -.bi-lock::before { content: "\f47b"; } -.bi-mailbox::before { content: "\f47c"; } -.bi-mailbox2::before { content: "\f47d"; } -.bi-map-fill::before { content: "\f47e"; } -.bi-map::before { content: "\f47f"; } -.bi-markdown-fill::before { content: "\f480"; } -.bi-markdown::before { content: "\f481"; } -.bi-mask::before { content: "\f482"; } -.bi-megaphone-fill::before { content: "\f483"; } -.bi-megaphone::before { content: "\f484"; } -.bi-menu-app-fill::before { content: "\f485"; } -.bi-menu-app::before { content: "\f486"; } -.bi-menu-button-fill::before { content: "\f487"; } -.bi-menu-button-wide-fill::before { content: "\f488"; } -.bi-menu-button-wide::before { content: "\f489"; } -.bi-menu-button::before { content: "\f48a"; } -.bi-menu-down::before { content: "\f48b"; } -.bi-menu-up::before { content: "\f48c"; } -.bi-mic-fill::before { content: "\f48d"; } -.bi-mic-mute-fill::before { content: "\f48e"; } -.bi-mic-mute::before { content: "\f48f"; } -.bi-mic::before { content: "\f490"; } -.bi-minecart-loaded::before { content: "\f491"; } -.bi-minecart::before { content: "\f492"; } -.bi-moisture::before { content: "\f493"; } -.bi-moon-fill::before { content: "\f494"; } -.bi-moon-stars-fill::before { content: "\f495"; } -.bi-moon-stars::before { content: "\f496"; } -.bi-moon::before { content: "\f497"; } -.bi-mouse-fill::before { content: "\f498"; } -.bi-mouse::before { content: "\f499"; } -.bi-mouse2-fill::before { content: "\f49a"; } -.bi-mouse2::before { content: "\f49b"; } -.bi-mouse3-fill::before { content: "\f49c"; } -.bi-mouse3::before { content: "\f49d"; } -.bi-music-note-beamed::before { content: "\f49e"; } -.bi-music-note-list::before { content: "\f49f"; } -.bi-music-note::before { content: "\f4a0"; } -.bi-music-player-fill::before { content: "\f4a1"; } -.bi-music-player::before { content: "\f4a2"; } -.bi-newspaper::before { content: "\f4a3"; } -.bi-node-minus-fill::before { content: "\f4a4"; } -.bi-node-minus::before { content: "\f4a5"; } -.bi-node-plus-fill::before { content: "\f4a6"; } -.bi-node-plus::before { content: "\f4a7"; } -.bi-nut-fill::before { content: "\f4a8"; } -.bi-nut::before { content: "\f4a9"; } -.bi-octagon-fill::before { content: "\f4aa"; } -.bi-octagon-half::before { content: "\f4ab"; } -.bi-octagon::before { content: "\f4ac"; } -.bi-option::before { content: "\f4ad"; } -.bi-outlet::before { content: "\f4ae"; } -.bi-paint-bucket::before { content: "\f4af"; } -.bi-palette-fill::before { content: "\f4b0"; } -.bi-palette::before { content: "\f4b1"; } -.bi-palette2::before { content: "\f4b2"; } -.bi-paperclip::before { content: "\f4b3"; } -.bi-paragraph::before { content: "\f4b4"; } -.bi-patch-check-fill::before { content: "\f4b5"; } -.bi-patch-check::before { content: "\f4b6"; } -.bi-patch-exclamation-fill::before { content: "\f4b7"; } -.bi-patch-exclamation::before { content: "\f4b8"; } -.bi-patch-minus-fill::before { content: "\f4b9"; } -.bi-patch-minus::before { content: "\f4ba"; } -.bi-patch-plus-fill::before { content: "\f4bb"; } -.bi-patch-plus::before { content: "\f4bc"; } -.bi-patch-question-fill::before { content: "\f4bd"; } -.bi-patch-question::before { content: "\f4be"; } -.bi-pause-btn-fill::before { content: "\f4bf"; } -.bi-pause-btn::before { content: "\f4c0"; } -.bi-pause-circle-fill::before { content: "\f4c1"; } -.bi-pause-circle::before { content: "\f4c2"; } -.bi-pause-fill::before { content: "\f4c3"; } -.bi-pause::before { content: "\f4c4"; } -.bi-peace-fill::before { content: "\f4c5"; } -.bi-peace::before { content: "\f4c6"; } -.bi-pen-fill::before { content: "\f4c7"; } -.bi-pen::before { content: "\f4c8"; } -.bi-pencil-fill::before { content: "\f4c9"; } -.bi-pencil-square::before { content: "\f4ca"; } -.bi-pencil::before { content: "\f4cb"; } -.bi-pentagon-fill::before { content: "\f4cc"; } -.bi-pentagon-half::before { content: "\f4cd"; } -.bi-pentagon::before { content: "\f4ce"; } -.bi-people-fill::before { content: "\f4cf"; } -.bi-people::before { content: "\f4d0"; } -.bi-percent::before { content: "\f4d1"; } -.bi-person-badge-fill::before { content: "\f4d2"; } -.bi-person-badge::before { content: "\f4d3"; } -.bi-person-bounding-box::before { content: "\f4d4"; } -.bi-person-check-fill::before { content: "\f4d5"; } -.bi-person-check::before { content: "\f4d6"; } -.bi-person-circle::before { content: "\f4d7"; } -.bi-person-dash-fill::before { content: "\f4d8"; } -.bi-person-dash::before { content: "\f4d9"; } -.bi-person-fill::before { content: "\f4da"; } -.bi-person-lines-fill::before { content: "\f4db"; } -.bi-person-plus-fill::before { content: "\f4dc"; } -.bi-person-plus::before { content: "\f4dd"; } -.bi-person-square::before { content: "\f4de"; } -.bi-person-x-fill::before { content: "\f4df"; } -.bi-person-x::before { content: "\f4e0"; } -.bi-person::before { content: "\f4e1"; } -.bi-phone-fill::before { content: "\f4e2"; } -.bi-phone-landscape-fill::before { content: "\f4e3"; } -.bi-phone-landscape::before { content: "\f4e4"; } -.bi-phone-vibrate-fill::before { content: "\f4e5"; } -.bi-phone-vibrate::before { content: "\f4e6"; } -.bi-phone::before { content: "\f4e7"; } -.bi-pie-chart-fill::before { content: "\f4e8"; } -.bi-pie-chart::before { content: "\f4e9"; } -.bi-pin-angle-fill::before { content: "\f4ea"; } -.bi-pin-angle::before { content: "\f4eb"; } -.bi-pin-fill::before { content: "\f4ec"; } -.bi-pin::before { content: "\f4ed"; } -.bi-pip-fill::before { content: "\f4ee"; } -.bi-pip::before { content: "\f4ef"; } -.bi-play-btn-fill::before { content: "\f4f0"; } -.bi-play-btn::before { content: "\f4f1"; } -.bi-play-circle-fill::before { content: "\f4f2"; } -.bi-play-circle::before { content: "\f4f3"; } -.bi-play-fill::before { content: "\f4f4"; } -.bi-play::before { content: "\f4f5"; } -.bi-plug-fill::before { content: "\f4f6"; } -.bi-plug::before { content: "\f4f7"; } -.bi-plus-circle-dotted::before { content: "\f4f8"; } -.bi-plus-circle-fill::before { content: "\f4f9"; } -.bi-plus-circle::before { content: "\f4fa"; } -.bi-plus-square-dotted::before { content: "\f4fb"; } -.bi-plus-square-fill::before { content: "\f4fc"; } -.bi-plus-square::before { content: "\f4fd"; } -.bi-plus::before { content: "\f4fe"; } -.bi-power::before { content: "\f4ff"; } -.bi-printer-fill::before { content: "\f500"; } -.bi-printer::before { content: "\f501"; } -.bi-puzzle-fill::before { content: "\f502"; } -.bi-puzzle::before { content: "\f503"; } -.bi-question-circle-fill::before { content: "\f504"; } -.bi-question-circle::before { content: "\f505"; } -.bi-question-diamond-fill::before { content: "\f506"; } -.bi-question-diamond::before { content: "\f507"; } -.bi-question-octagon-fill::before { content: "\f508"; } -.bi-question-octagon::before { content: "\f509"; } -.bi-question-square-fill::before { content: "\f50a"; } -.bi-question-square::before { content: "\f50b"; } -.bi-question::before { content: "\f50c"; } -.bi-rainbow::before { content: "\f50d"; } -.bi-receipt-cutoff::before { content: "\f50e"; } -.bi-receipt::before { content: "\f50f"; } -.bi-reception-0::before { content: "\f510"; } -.bi-reception-1::before { content: "\f511"; } -.bi-reception-2::before { content: "\f512"; } -.bi-reception-3::before { content: "\f513"; } -.bi-reception-4::before { content: "\f514"; } -.bi-record-btn-fill::before { content: "\f515"; } -.bi-record-btn::before { content: "\f516"; } -.bi-record-circle-fill::before { content: "\f517"; } -.bi-record-circle::before { content: "\f518"; } -.bi-record-fill::before { content: "\f519"; } -.bi-record::before { content: "\f51a"; } -.bi-record2-fill::before { content: "\f51b"; } -.bi-record2::before { content: "\f51c"; } -.bi-reply-all-fill::before { content: "\f51d"; } -.bi-reply-all::before { content: "\f51e"; } -.bi-reply-fill::before { content: "\f51f"; } -.bi-reply::before { content: "\f520"; } -.bi-rss-fill::before { content: "\f521"; } -.bi-rss::before { content: "\f522"; } -.bi-rulers::before { content: "\f523"; } -.bi-save-fill::before { content: "\f524"; } -.bi-save::before { content: "\f525"; } -.bi-save2-fill::before { content: "\f526"; } -.bi-save2::before { content: "\f527"; } -.bi-scissors::before { content: "\f528"; } -.bi-screwdriver::before { content: "\f529"; } -.bi-search::before { content: "\f52a"; } -.bi-segmented-nav::before { content: "\f52b"; } -.bi-server::before { content: "\f52c"; } -.bi-share-fill::before { content: "\f52d"; } -.bi-share::before { content: "\f52e"; } -.bi-shield-check::before { content: "\f52f"; } -.bi-shield-exclamation::before { content: "\f530"; } -.bi-shield-fill-check::before { content: "\f531"; } -.bi-shield-fill-exclamation::before { content: "\f532"; } -.bi-shield-fill-minus::before { content: "\f533"; } -.bi-shield-fill-plus::before { content: "\f534"; } -.bi-shield-fill-x::before { content: "\f535"; } -.bi-shield-fill::before { content: "\f536"; } -.bi-shield-lock-fill::before { content: "\f537"; } -.bi-shield-lock::before { content: "\f538"; } -.bi-shield-minus::before { content: "\f539"; } -.bi-shield-plus::before { content: "\f53a"; } -.bi-shield-shaded::before { content: "\f53b"; } -.bi-shield-slash-fill::before { content: "\f53c"; } -.bi-shield-slash::before { content: "\f53d"; } -.bi-shield-x::before { content: "\f53e"; } -.bi-shield::before { content: "\f53f"; } -.bi-shift-fill::before { content: "\f540"; } -.bi-shift::before { content: "\f541"; } -.bi-shop-window::before { content: "\f542"; } -.bi-shop::before { content: "\f543"; } -.bi-shuffle::before { content: "\f544"; } -.bi-signpost-2-fill::before { content: "\f545"; } -.bi-signpost-2::before { content: "\f546"; } -.bi-signpost-fill::before { content: "\f547"; } -.bi-signpost-split-fill::before { content: "\f548"; } -.bi-signpost-split::before { content: "\f549"; } -.bi-signpost::before { content: "\f54a"; } -.bi-sim-fill::before { content: "\f54b"; } -.bi-sim::before { content: "\f54c"; } -.bi-skip-backward-btn-fill::before { content: "\f54d"; } -.bi-skip-backward-btn::before { content: "\f54e"; } -.bi-skip-backward-circle-fill::before { content: "\f54f"; } -.bi-skip-backward-circle::before { content: "\f550"; } -.bi-skip-backward-fill::before { content: "\f551"; } -.bi-skip-backward::before { content: "\f552"; } -.bi-skip-end-btn-fill::before { content: "\f553"; } -.bi-skip-end-btn::before { content: "\f554"; } -.bi-skip-end-circle-fill::before { content: "\f555"; } -.bi-skip-end-circle::before { content: "\f556"; } -.bi-skip-end-fill::before { content: "\f557"; } -.bi-skip-end::before { content: "\f558"; } -.bi-skip-forward-btn-fill::before { content: "\f559"; } -.bi-skip-forward-btn::before { content: "\f55a"; } -.bi-skip-forward-circle-fill::before { content: "\f55b"; } -.bi-skip-forward-circle::before { content: "\f55c"; } -.bi-skip-forward-fill::before { content: "\f55d"; } -.bi-skip-forward::before { content: "\f55e"; } -.bi-skip-start-btn-fill::before { content: "\f55f"; } -.bi-skip-start-btn::before { content: "\f560"; } -.bi-skip-start-circle-fill::before { content: "\f561"; } -.bi-skip-start-circle::before { content: "\f562"; } -.bi-skip-start-fill::before { content: "\f563"; } -.bi-skip-start::before { content: "\f564"; } -.bi-slack::before { content: "\f565"; } -.bi-slash-circle-fill::before { content: "\f566"; } -.bi-slash-circle::before { content: "\f567"; } -.bi-slash-square-fill::before { content: "\f568"; } -.bi-slash-square::before { content: "\f569"; } -.bi-slash::before { content: "\f56a"; } -.bi-sliders::before { content: "\f56b"; } -.bi-smartwatch::before { content: "\f56c"; } -.bi-snow::before { content: "\f56d"; } -.bi-snow2::before { content: "\f56e"; } -.bi-snow3::before { content: "\f56f"; } -.bi-sort-alpha-down-alt::before { content: "\f570"; } -.bi-sort-alpha-down::before { content: "\f571"; } -.bi-sort-alpha-up-alt::before { content: "\f572"; } -.bi-sort-alpha-up::before { content: "\f573"; } -.bi-sort-down-alt::before { content: "\f574"; } -.bi-sort-down::before { content: "\f575"; } -.bi-sort-numeric-down-alt::before { content: "\f576"; } -.bi-sort-numeric-down::before { content: "\f577"; } -.bi-sort-numeric-up-alt::before { content: "\f578"; } -.bi-sort-numeric-up::before { content: "\f579"; } -.bi-sort-up-alt::before { content: "\f57a"; } -.bi-sort-up::before { content: "\f57b"; } -.bi-soundwave::before { content: "\f57c"; } -.bi-speaker-fill::before { content: "\f57d"; } -.bi-speaker::before { content: "\f57e"; } -.bi-speedometer::before { content: "\f57f"; } -.bi-speedometer2::before { content: "\f580"; } -.bi-spellcheck::before { content: "\f581"; } -.bi-square-fill::before { content: "\f582"; } -.bi-square-half::before { content: "\f583"; } -.bi-square::before { content: "\f584"; } -.bi-stack::before { content: "\f585"; } -.bi-star-fill::before { content: "\f586"; } -.bi-star-half::before { content: "\f587"; } -.bi-star::before { content: "\f588"; } -.bi-stars::before { content: "\f589"; } -.bi-stickies-fill::before { content: "\f58a"; } -.bi-stickies::before { content: "\f58b"; } -.bi-sticky-fill::before { content: "\f58c"; } -.bi-sticky::before { content: "\f58d"; } -.bi-stop-btn-fill::before { content: "\f58e"; } -.bi-stop-btn::before { content: "\f58f"; } -.bi-stop-circle-fill::before { content: "\f590"; } -.bi-stop-circle::before { content: "\f591"; } -.bi-stop-fill::before { content: "\f592"; } -.bi-stop::before { content: "\f593"; } -.bi-stoplights-fill::before { content: "\f594"; } -.bi-stoplights::before { content: "\f595"; } -.bi-stopwatch-fill::before { content: "\f596"; } -.bi-stopwatch::before { content: "\f597"; } -.bi-subtract::before { content: "\f598"; } -.bi-suit-club-fill::before { content: "\f599"; } -.bi-suit-club::before { content: "\f59a"; } -.bi-suit-diamond-fill::before { content: "\f59b"; } -.bi-suit-diamond::before { content: "\f59c"; } -.bi-suit-heart-fill::before { content: "\f59d"; } -.bi-suit-heart::before { content: "\f59e"; } -.bi-suit-spade-fill::before { content: "\f59f"; } -.bi-suit-spade::before { content: "\f5a0"; } -.bi-sun-fill::before { content: "\f5a1"; } -.bi-sun::before { content: "\f5a2"; } -.bi-sunglasses::before { content: "\f5a3"; } -.bi-sunrise-fill::before { content: "\f5a4"; } -.bi-sunrise::before { content: "\f5a5"; } -.bi-sunset-fill::before { content: "\f5a6"; } -.bi-sunset::before { content: "\f5a7"; } -.bi-symmetry-horizontal::before { content: "\f5a8"; } -.bi-symmetry-vertical::before { content: "\f5a9"; } -.bi-table::before { content: "\f5aa"; } -.bi-tablet-fill::before { content: "\f5ab"; } -.bi-tablet-landscape-fill::before { content: "\f5ac"; } -.bi-tablet-landscape::before { content: "\f5ad"; } -.bi-tablet::before { content: "\f5ae"; } -.bi-tag-fill::before { content: "\f5af"; } -.bi-tag::before { content: "\f5b0"; } -.bi-tags-fill::before { content: "\f5b1"; } -.bi-tags::before { content: "\f5b2"; } -.bi-telegram::before { content: "\f5b3"; } -.bi-telephone-fill::before { content: "\f5b4"; } -.bi-telephone-forward-fill::before { content: "\f5b5"; } -.bi-telephone-forward::before { content: "\f5b6"; } -.bi-telephone-inbound-fill::before { content: "\f5b7"; } -.bi-telephone-inbound::before { content: "\f5b8"; } -.bi-telephone-minus-fill::before { content: "\f5b9"; } -.bi-telephone-minus::before { content: "\f5ba"; } -.bi-telephone-outbound-fill::before { content: "\f5bb"; } -.bi-telephone-outbound::before { content: "\f5bc"; } -.bi-telephone-plus-fill::before { content: "\f5bd"; } -.bi-telephone-plus::before { content: "\f5be"; } -.bi-telephone-x-fill::before { content: "\f5bf"; } -.bi-telephone-x::before { content: "\f5c0"; } -.bi-telephone::before { content: "\f5c1"; } -.bi-terminal-fill::before { content: "\f5c2"; } -.bi-terminal::before { content: "\f5c3"; } -.bi-text-center::before { content: "\f5c4"; } -.bi-text-indent-left::before { content: "\f5c5"; } -.bi-text-indent-right::before { content: "\f5c6"; } -.bi-text-left::before { content: "\f5c7"; } -.bi-text-paragraph::before { content: "\f5c8"; } -.bi-text-right::before { content: "\f5c9"; } -.bi-textarea-resize::before { content: "\f5ca"; } -.bi-textarea-t::before { content: "\f5cb"; } -.bi-textarea::before { content: "\f5cc"; } -.bi-thermometer-half::before { content: "\f5cd"; } -.bi-thermometer-high::before { content: "\f5ce"; } -.bi-thermometer-low::before { content: "\f5cf"; } -.bi-thermometer-snow::before { content: "\f5d0"; } -.bi-thermometer-sun::before { content: "\f5d1"; } -.bi-thermometer::before { content: "\f5d2"; } -.bi-three-dots-vertical::before { content: "\f5d3"; } -.bi-three-dots::before { content: "\f5d4"; } -.bi-toggle-off::before { content: "\f5d5"; } -.bi-toggle-on::before { content: "\f5d6"; } -.bi-toggle2-off::before { content: "\f5d7"; } -.bi-toggle2-on::before { content: "\f5d8"; } -.bi-toggles::before { content: "\f5d9"; } -.bi-toggles2::before { content: "\f5da"; } -.bi-tools::before { content: "\f5db"; } -.bi-tornado::before { content: "\f5dc"; } -.bi-trash-fill::before { content: "\f5dd"; } -.bi-trash::before { content: "\f5de"; } -.bi-trash2-fill::before { content: "\f5df"; } -.bi-trash2::before { content: "\f5e0"; } -.bi-tree-fill::before { content: "\f5e1"; } -.bi-tree::before { content: "\f5e2"; } -.bi-triangle-fill::before { content: "\f5e3"; } -.bi-triangle-half::before { content: "\f5e4"; } -.bi-triangle::before { content: "\f5e5"; } -.bi-trophy-fill::before { content: "\f5e6"; } -.bi-trophy::before { content: "\f5e7"; } -.bi-tropical-storm::before { content: "\f5e8"; } -.bi-truck-flatbed::before { content: "\f5e9"; } -.bi-truck::before { content: "\f5ea"; } -.bi-tsunami::before { content: "\f5eb"; } -.bi-tv-fill::before { content: "\f5ec"; } -.bi-tv::before { content: "\f5ed"; } -.bi-twitch::before { content: "\f5ee"; } -.bi-twitter::before { content: "\f5ef"; } -.bi-type-bold::before { content: "\f5f0"; } -.bi-type-h1::before { content: "\f5f1"; } -.bi-type-h2::before { content: "\f5f2"; } -.bi-type-h3::before { content: "\f5f3"; } -.bi-type-italic::before { content: "\f5f4"; } -.bi-type-strikethrough::before { content: "\f5f5"; } -.bi-type-underline::before { content: "\f5f6"; } -.bi-type::before { content: "\f5f7"; } -.bi-ui-checks-grid::before { content: "\f5f8"; } -.bi-ui-checks::before { content: "\f5f9"; } -.bi-ui-radios-grid::before { content: "\f5fa"; } -.bi-ui-radios::before { content: "\f5fb"; } -.bi-umbrella-fill::before { content: "\f5fc"; } -.bi-umbrella::before { content: "\f5fd"; } -.bi-union::before { content: "\f5fe"; } -.bi-unlock-fill::before { content: "\f5ff"; } -.bi-unlock::before { content: "\f600"; } -.bi-upc-scan::before { content: "\f601"; } -.bi-upc::before { content: "\f602"; } -.bi-upload::before { content: "\f603"; } -.bi-vector-pen::before { content: "\f604"; } -.bi-view-list::before { content: "\f605"; } -.bi-view-stacked::before { content: "\f606"; } -.bi-vinyl-fill::before { content: "\f607"; } -.bi-vinyl::before { content: "\f608"; } -.bi-voicemail::before { content: "\f609"; } -.bi-volume-down-fill::before { content: "\f60a"; } -.bi-volume-down::before { content: "\f60b"; } -.bi-volume-mute-fill::before { content: "\f60c"; } -.bi-volume-mute::before { content: "\f60d"; } -.bi-volume-off-fill::before { content: "\f60e"; } -.bi-volume-off::before { content: "\f60f"; } -.bi-volume-up-fill::before { content: "\f610"; } -.bi-volume-up::before { content: "\f611"; } -.bi-vr::before { content: "\f612"; } -.bi-wallet-fill::before { content: "\f613"; } -.bi-wallet::before { content: "\f614"; } -.bi-wallet2::before { content: "\f615"; } -.bi-watch::before { content: "\f616"; } -.bi-water::before { content: "\f617"; } -.bi-whatsapp::before { content: "\f618"; } -.bi-wifi-1::before { content: "\f619"; } -.bi-wifi-2::before { content: "\f61a"; } -.bi-wifi-off::before { content: "\f61b"; } -.bi-wifi::before { content: "\f61c"; } -.bi-wind::before { content: "\f61d"; } -.bi-window-dock::before { content: "\f61e"; } -.bi-window-sidebar::before { content: "\f61f"; } -.bi-window::before { content: "\f620"; } -.bi-wrench::before { content: "\f621"; } -.bi-x-circle-fill::before { content: "\f622"; } -.bi-x-circle::before { content: "\f623"; } -.bi-x-diamond-fill::before { content: "\f624"; } -.bi-x-diamond::before { content: "\f625"; } -.bi-x-octagon-fill::before { content: "\f626"; } -.bi-x-octagon::before { content: "\f627"; } -.bi-x-square-fill::before { content: "\f628"; } -.bi-x-square::before { content: "\f629"; } -.bi-x::before { content: "\f62a"; } -.bi-youtube::before { content: "\f62b"; } -.bi-zoom-in::before { content: "\f62c"; } -.bi-zoom-out::before { content: "\f62d"; } -.bi-bank::before { content: "\f62e"; } -.bi-bank2::before { content: "\f62f"; } -.bi-bell-slash-fill::before { content: "\f630"; } -.bi-bell-slash::before { content: "\f631"; } -.bi-cash-coin::before { content: "\f632"; } -.bi-check-lg::before { content: "\f633"; } -.bi-coin::before { content: "\f634"; } -.bi-currency-bitcoin::before { content: "\f635"; } -.bi-currency-dollar::before { content: "\f636"; } -.bi-currency-euro::before { content: "\f637"; } -.bi-currency-exchange::before { content: "\f638"; } -.bi-currency-pound::before { content: "\f639"; } -.bi-currency-yen::before { content: "\f63a"; } -.bi-dash-lg::before { content: "\f63b"; } -.bi-exclamation-lg::before { content: "\f63c"; } -.bi-file-earmark-pdf-fill::before { content: "\f63d"; } -.bi-file-earmark-pdf::before { content: "\f63e"; } -.bi-file-pdf-fill::before { content: "\f63f"; } -.bi-file-pdf::before { content: "\f640"; } -.bi-gender-ambiguous::before { content: "\f641"; } -.bi-gender-female::before { content: "\f642"; } -.bi-gender-male::before { content: "\f643"; } -.bi-gender-trans::before { content: "\f644"; } -.bi-headset-vr::before { content: "\f645"; } -.bi-info-lg::before { content: "\f646"; } -.bi-mastodon::before { content: "\f647"; } -.bi-messenger::before { content: "\f648"; } -.bi-piggy-bank-fill::before { content: "\f649"; } -.bi-piggy-bank::before { content: "\f64a"; } -.bi-pin-map-fill::before { content: "\f64b"; } -.bi-pin-map::before { content: "\f64c"; } -.bi-plus-lg::before { content: "\f64d"; } -.bi-question-lg::before { content: "\f64e"; } -.bi-recycle::before { content: "\f64f"; } -.bi-reddit::before { content: "\f650"; } -.bi-safe-fill::before { content: "\f651"; } -.bi-safe2-fill::before { content: "\f652"; } -.bi-safe2::before { content: "\f653"; } -.bi-sd-card-fill::before { content: "\f654"; } -.bi-sd-card::before { content: "\f655"; } -.bi-skype::before { content: "\f656"; } -.bi-slash-lg::before { content: "\f657"; } -.bi-translate::before { content: "\f658"; } -.bi-x-lg::before { content: "\f659"; } -.bi-safe::before { content: "\f65a"; } -.bi-apple::before { content: "\f65b"; } -.bi-microsoft::before { content: "\f65d"; } -.bi-windows::before { content: "\f65e"; } -.bi-behance::before { content: "\f65c"; } -.bi-dribbble::before { content: "\f65f"; } -.bi-line::before { content: "\f660"; } -.bi-medium::before { content: "\f661"; } -.bi-paypal::before { content: "\f662"; } -.bi-pinterest::before { content: "\f663"; } -.bi-signal::before { content: "\f664"; } -.bi-snapchat::before { content: "\f665"; } -.bi-spotify::before { content: "\f666"; } -.bi-stack-overflow::before { content: "\f667"; } -.bi-strava::before { content: "\f668"; } -.bi-wordpress::before { content: "\f669"; } -.bi-vimeo::before { content: "\f66a"; } -.bi-activity::before { content: "\f66b"; } -.bi-easel2-fill::before { content: "\f66c"; } -.bi-easel2::before { content: "\f66d"; } -.bi-easel3-fill::before { content: "\f66e"; } -.bi-easel3::before { content: "\f66f"; } -.bi-fan::before { content: "\f670"; } -.bi-fingerprint::before { content: "\f671"; } -.bi-graph-down-arrow::before { content: "\f672"; } -.bi-graph-up-arrow::before { content: "\f673"; } -.bi-hypnotize::before { content: "\f674"; } -.bi-magic::before { content: "\f675"; } -.bi-person-rolodex::before { content: "\f676"; } -.bi-person-video::before { content: "\f677"; } -.bi-person-video2::before { content: "\f678"; } -.bi-person-video3::before { content: "\f679"; } -.bi-person-workspace::before { content: "\f67a"; } -.bi-radioactive::before { content: "\f67b"; } -.bi-webcam-fill::before { content: "\f67c"; } -.bi-webcam::before { content: "\f67d"; } -.bi-yin-yang::before { content: "\f67e"; } -.bi-bandaid-fill::before { content: "\f680"; } -.bi-bandaid::before { content: "\f681"; } -.bi-bluetooth::before { content: "\f682"; } -.bi-body-text::before { content: "\f683"; } -.bi-boombox::before { content: "\f684"; } -.bi-boxes::before { content: "\f685"; } -.bi-dpad-fill::before { content: "\f686"; } -.bi-dpad::before { content: "\f687"; } -.bi-ear-fill::before { content: "\f688"; } -.bi-ear::before { content: "\f689"; } -.bi-envelope-check-1::before { content: "\f68a"; } -.bi-envelope-check-fill::before { content: "\f68b"; } -.bi-envelope-check::before { content: "\f68c"; } -.bi-envelope-dash-1::before { content: "\f68d"; } -.bi-envelope-dash-fill::before { content: "\f68e"; } -.bi-envelope-dash::before { content: "\f68f"; } -.bi-envelope-exclamation-1::before { content: "\f690"; } -.bi-envelope-exclamation-fill::before { content: "\f691"; } -.bi-envelope-exclamation::before { content: "\f692"; } -.bi-envelope-plus-fill::before { content: "\f693"; } -.bi-envelope-plus::before { content: "\f694"; } -.bi-envelope-slash-1::before { content: "\f695"; } -.bi-envelope-slash-fill::before { content: "\f696"; } -.bi-envelope-slash::before { content: "\f697"; } -.bi-envelope-x-1::before { content: "\f698"; } -.bi-envelope-x-fill::before { content: "\f699"; } -.bi-envelope-x::before { content: "\f69a"; } -.bi-explicit-fill::before { content: "\f69b"; } -.bi-explicit::before { content: "\f69c"; } -.bi-git::before { content: "\f69d"; } -.bi-infinity::before { content: "\f69e"; } -.bi-list-columns-reverse::before { content: "\f69f"; } -.bi-list-columns::before { content: "\f6a0"; } -.bi-meta::before { content: "\f6a1"; } -.bi-mortorboard-fill::before { content: "\f6a2"; } -.bi-mortorboard::before { content: "\f6a3"; } -.bi-nintendo-switch::before { content: "\f6a4"; } -.bi-pc-display-horizontal::before { content: "\f6a5"; } -.bi-pc-display::before { content: "\f6a6"; } -.bi-pc-horizontal::before { content: "\f6a7"; } -.bi-pc::before { content: "\f6a8"; } -.bi-playstation::before { content: "\f6a9"; } -.bi-plus-slash-minus::before { content: "\f6aa"; } -.bi-projector-fill::before { content: "\f6ab"; } -.bi-projector::before { content: "\f6ac"; } -.bi-qr-code-scan::before { content: "\f6ad"; } -.bi-qr-code::before { content: "\f6ae"; } -.bi-quora::before { content: "\f6af"; } -.bi-quote::before { content: "\f6b0"; } -.bi-robot::before { content: "\f6b1"; } -.bi-send-check-fill::before { content: "\f6b2"; } -.bi-send-check::before { content: "\f6b3"; } -.bi-send-dash-fill::before { content: "\f6b4"; } -.bi-send-dash::before { content: "\f6b5"; } -.bi-send-exclamation-1::before { content: "\f6b6"; } -.bi-send-exclamation-fill::before { content: "\f6b7"; } -.bi-send-exclamation::before { content: "\f6b8"; } -.bi-send-fill::before { content: "\f6b9"; } -.bi-send-plus-fill::before { content: "\f6ba"; } -.bi-send-plus::before { content: "\f6bb"; } -.bi-send-slash-fill::before { content: "\f6bc"; } -.bi-send-slash::before { content: "\f6bd"; } -.bi-send-x-fill::before { content: "\f6be"; } -.bi-send-x::before { content: "\f6bf"; } -.bi-send::before { content: "\f6c0"; } -.bi-steam::before { content: "\f6c1"; } -.bi-terminal-dash-1::before { content: "\f6c2"; } -.bi-terminal-dash::before { content: "\f6c3"; } -.bi-terminal-plus::before { content: "\f6c4"; } -.bi-terminal-split::before { content: "\f6c5"; } -.bi-ticket-detailed-fill::before { content: "\f6c6"; } -.bi-ticket-detailed::before { content: "\f6c7"; } -.bi-ticket-fill::before { content: "\f6c8"; } -.bi-ticket-perforated-fill::before { content: "\f6c9"; } -.bi-ticket-perforated::before { content: "\f6ca"; } -.bi-ticket::before { content: "\f6cb"; } -.bi-tiktok::before { content: "\f6cc"; } -.bi-window-dash::before { content: "\f6cd"; } -.bi-window-desktop::before { content: "\f6ce"; } -.bi-window-fullscreen::before { content: "\f6cf"; } -.bi-window-plus::before { content: "\f6d0"; } -.bi-window-split::before { content: "\f6d1"; } -.bi-window-stack::before { content: "\f6d2"; } -.bi-window-x::before { content: "\f6d3"; } -.bi-xbox::before { content: "\f6d4"; } -.bi-ethernet::before { content: "\f6d5"; } -.bi-hdmi-fill::before { content: "\f6d6"; } -.bi-hdmi::before { content: "\f6d7"; } -.bi-usb-c-fill::before { content: "\f6d8"; } -.bi-usb-c::before { content: "\f6d9"; } -.bi-usb-fill::before { content: "\f6da"; } -.bi-usb-plug-fill::before { content: "\f6db"; } -.bi-usb-plug::before { content: "\f6dc"; } -.bi-usb-symbol::before { content: "\f6dd"; } -.bi-usb::before { content: "\f6de"; } -.bi-boombox-fill::before { content: "\f6df"; } -.bi-displayport-1::before { content: "\f6e0"; } -.bi-displayport::before { content: "\f6e1"; } -.bi-gpu-card::before { content: "\f6e2"; } -.bi-memory::before { content: "\f6e3"; } -.bi-modem-fill::before { content: "\f6e4"; } -.bi-modem::before { content: "\f6e5"; } -.bi-motherboard-fill::before { content: "\f6e6"; } -.bi-motherboard::before { content: "\f6e7"; } -.bi-optical-audio-fill::before { content: "\f6e8"; } -.bi-optical-audio::before { content: "\f6e9"; } -.bi-pci-card::before { content: "\f6ea"; } -.bi-router-fill::before { content: "\f6eb"; } -.bi-router::before { content: "\f6ec"; } -.bi-ssd-fill::before { content: "\f6ed"; } -.bi-ssd::before { content: "\f6ee"; } -.bi-thunderbolt-fill::before { content: "\f6ef"; } -.bi-thunderbolt::before { content: "\f6f0"; } -.bi-usb-drive-fill::before { content: "\f6f1"; } -.bi-usb-drive::before { content: "\f6f2"; } -.bi-usb-micro-fill::before { content: "\f6f3"; } -.bi-usb-micro::before { content: "\f6f4"; } -.bi-usb-mini-fill::before { content: "\f6f5"; } -.bi-usb-mini::before { content: "\f6f6"; } -.bi-cloud-haze2::before { content: "\f6f7"; } -.bi-device-hdd-fill::before { content: "\f6f8"; } -.bi-device-hdd::before { content: "\f6f9"; } -.bi-device-ssd-fill::before { content: "\f6fa"; } -.bi-device-ssd::before { content: "\f6fb"; } -.bi-displayport-fill::before { content: "\f6fc"; } -.bi-mortarboard-fill::before { content: "\f6fd"; } -.bi-mortarboard::before { content: "\f6fe"; } -.bi-terminal-x::before { content: "\f6ff"; } -.bi-arrow-through-heart-fill::before { content: "\f700"; } -.bi-arrow-through-heart::before { content: "\f701"; } -.bi-badge-sd-fill::before { content: "\f702"; } -.bi-badge-sd::before { content: "\f703"; } -.bi-bag-heart-fill::before { content: "\f704"; } -.bi-bag-heart::before { content: "\f705"; } -.bi-balloon-fill::before { content: "\f706"; } -.bi-balloon-heart-fill::before { content: "\f707"; } -.bi-balloon-heart::before { content: "\f708"; } -.bi-balloon::before { content: "\f709"; } -.bi-box2-fill::before { content: "\f70a"; } -.bi-box2-heart-fill::before { content: "\f70b"; } -.bi-box2-heart::before { content: "\f70c"; } -.bi-box2::before { content: "\f70d"; } -.bi-braces-asterisk::before { content: "\f70e"; } -.bi-calendar-heart-fill::before { content: "\f70f"; } -.bi-calendar-heart::before { content: "\f710"; } -.bi-calendar2-heart-fill::before { content: "\f711"; } -.bi-calendar2-heart::before { content: "\f712"; } -.bi-chat-heart-fill::before { content: "\f713"; } -.bi-chat-heart::before { content: "\f714"; } -.bi-chat-left-heart-fill::before { content: "\f715"; } -.bi-chat-left-heart::before { content: "\f716"; } -.bi-chat-right-heart-fill::before { content: "\f717"; } -.bi-chat-right-heart::before { content: "\f718"; } -.bi-chat-square-heart-fill::before { content: "\f719"; } -.bi-chat-square-heart::before { content: "\f71a"; } -.bi-clipboard-check-fill::before { content: "\f71b"; } -.bi-clipboard-data-fill::before { content: "\f71c"; } -.bi-clipboard-fill::before { content: "\f71d"; } -.bi-clipboard-heart-fill::before { content: "\f71e"; } -.bi-clipboard-heart::before { content: "\f71f"; } -.bi-clipboard-minus-fill::before { content: "\f720"; } -.bi-clipboard-plus-fill::before { content: "\f721"; } -.bi-clipboard-pulse::before { content: "\f722"; } -.bi-clipboard-x-fill::before { content: "\f723"; } -.bi-clipboard2-check-fill::before { content: "\f724"; } -.bi-clipboard2-check::before { content: "\f725"; } -.bi-clipboard2-data-fill::before { content: "\f726"; } -.bi-clipboard2-data::before { content: "\f727"; } -.bi-clipboard2-fill::before { content: "\f728"; } -.bi-clipboard2-heart-fill::before { content: "\f729"; } -.bi-clipboard2-heart::before { content: "\f72a"; } -.bi-clipboard2-minus-fill::before { content: "\f72b"; } -.bi-clipboard2-minus::before { content: "\f72c"; } -.bi-clipboard2-plus-fill::before { content: "\f72d"; } -.bi-clipboard2-plus::before { content: "\f72e"; } -.bi-clipboard2-pulse-fill::before { content: "\f72f"; } -.bi-clipboard2-pulse::before { content: "\f730"; } -.bi-clipboard2-x-fill::before { content: "\f731"; } -.bi-clipboard2-x::before { content: "\f732"; } -.bi-clipboard2::before { content: "\f733"; } -.bi-emoji-kiss-fill::before { content: "\f734"; } -.bi-emoji-kiss::before { content: "\f735"; } -.bi-envelope-heart-fill::before { content: "\f736"; } -.bi-envelope-heart::before { content: "\f737"; } -.bi-envelope-open-heart-fill::before { content: "\f738"; } -.bi-envelope-open-heart::before { content: "\f739"; } -.bi-envelope-paper-fill::before { content: "\f73a"; } -.bi-envelope-paper-heart-fill::before { content: "\f73b"; } -.bi-envelope-paper-heart::before { content: "\f73c"; } -.bi-envelope-paper::before { content: "\f73d"; } -.bi-filetype-aac::before { content: "\f73e"; } -.bi-filetype-ai::before { content: "\f73f"; } -.bi-filetype-bmp::before { content: "\f740"; } -.bi-filetype-cs::before { content: "\f741"; } -.bi-filetype-css::before { content: "\f742"; } -.bi-filetype-csv::before { content: "\f743"; } -.bi-filetype-doc::before { content: "\f744"; } -.bi-filetype-docx::before { content: "\f745"; } -.bi-filetype-exe::before { content: "\f746"; } -.bi-filetype-gif::before { content: "\f747"; } -.bi-filetype-heic::before { content: "\f748"; } -.bi-filetype-html::before { content: "\f749"; } -.bi-filetype-java::before { content: "\f74a"; } -.bi-filetype-jpg::before { content: "\f74b"; } -.bi-filetype-js::before { content: "\f74c"; } -.bi-filetype-jsx::before { content: "\f74d"; } -.bi-filetype-key::before { content: "\f74e"; } -.bi-filetype-m4p::before { content: "\f74f"; } -.bi-filetype-md::before { content: "\f750"; } -.bi-filetype-mdx::before { content: "\f751"; } -.bi-filetype-mov::before { content: "\f752"; } -.bi-filetype-mp3::before { content: "\f753"; } -.bi-filetype-mp4::before { content: "\f754"; } -.bi-filetype-otf::before { content: "\f755"; } -.bi-filetype-pdf::before { content: "\f756"; } -.bi-filetype-php::before { content: "\f757"; } -.bi-filetype-png::before { content: "\f758"; } -.bi-filetype-ppt-1::before { content: "\f759"; } -.bi-filetype-ppt::before { content: "\f75a"; } -.bi-filetype-psd::before { content: "\f75b"; } -.bi-filetype-py::before { content: "\f75c"; } -.bi-filetype-raw::before { content: "\f75d"; } -.bi-filetype-rb::before { content: "\f75e"; } -.bi-filetype-sass::before { content: "\f75f"; } -.bi-filetype-scss::before { content: "\f760"; } -.bi-filetype-sh::before { content: "\f761"; } -.bi-filetype-svg::before { content: "\f762"; } -.bi-filetype-tiff::before { content: "\f763"; } -.bi-filetype-tsx::before { content: "\f764"; } -.bi-filetype-ttf::before { content: "\f765"; } -.bi-filetype-txt::before { content: "\f766"; } -.bi-filetype-wav::before { content: "\f767"; } -.bi-filetype-woff::before { content: "\f768"; } -.bi-filetype-xls-1::before { content: "\f769"; } -.bi-filetype-xls::before { content: "\f76a"; } -.bi-filetype-xml::before { content: "\f76b"; } -.bi-filetype-yml::before { content: "\f76c"; } -.bi-heart-arrow::before { content: "\f76d"; } -.bi-heart-pulse-fill::before { content: "\f76e"; } -.bi-heart-pulse::before { content: "\f76f"; } -.bi-heartbreak-fill::before { content: "\f770"; } -.bi-heartbreak::before { content: "\f771"; } -.bi-hearts::before { content: "\f772"; } -.bi-hospital-fill::before { content: "\f773"; } -.bi-hospital::before { content: "\f774"; } -.bi-house-heart-fill::before { content: "\f775"; } -.bi-house-heart::before { content: "\f776"; } -.bi-incognito::before { content: "\f777"; } -.bi-magnet-fill::before { content: "\f778"; } -.bi-magnet::before { content: "\f779"; } -.bi-person-heart::before { content: "\f77a"; } -.bi-person-hearts::before { content: "\f77b"; } -.bi-phone-flip::before { content: "\f77c"; } -.bi-plugin::before { content: "\f77d"; } -.bi-postage-fill::before { content: "\f77e"; } -.bi-postage-heart-fill::before { content: "\f77f"; } -.bi-postage-heart::before { content: "\f780"; } -.bi-postage::before { content: "\f781"; } -.bi-postcard-fill::before { content: "\f782"; } -.bi-postcard-heart-fill::before { content: "\f783"; } -.bi-postcard-heart::before { content: "\f784"; } -.bi-postcard::before { content: "\f785"; } -.bi-search-heart-fill::before { content: "\f786"; } -.bi-search-heart::before { content: "\f787"; } -.bi-sliders2-vertical::before { content: "\f788"; } -.bi-sliders2::before { content: "\f789"; } -.bi-trash3-fill::before { content: "\f78a"; } -.bi-trash3::before { content: "\f78b"; } -.bi-valentine::before { content: "\f78c"; } -.bi-valentine2::before { content: "\f78d"; } -.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } -.bi-wrench-adjustable-circle::before { content: "\f78f"; } -.bi-wrench-adjustable::before { content: "\f790"; } -.bi-filetype-json::before { content: "\f791"; } -.bi-filetype-pptx::before { content: "\f792"; } -.bi-filetype-xlsx::before { content: "\f793"; } diff --git a/webcams_files/libs/bootstrap/bootstrap-icons.woff b/webcams_files/libs/bootstrap/bootstrap-icons.woff deleted file mode 100644 index b26ccd1..0000000 Binary files a/webcams_files/libs/bootstrap/bootstrap-icons.woff and /dev/null differ diff --git a/webcams_files/libs/bootstrap/bootstrap.min.css b/webcams_files/libs/bootstrap/bootstrap.min.css deleted file mode 100644 index 62b4dbc..0000000 --- a/webcams_files/libs/bootstrap/bootstrap.min.css +++ /dev/null @@ -1,10 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors - * Copyright 2011-2021 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */:root{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-white: #ffffff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-default: #dee2e6;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-default-rgb: 222, 226, 230;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 18px;--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-bg: #ffffff}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1,.h1{font-size:calc(1.345rem + 1.14vw)}@media(min-width: 1200px){h1,.h1{font-size:2.2rem}}h2,.h2{font-size:calc(1.3rem + 0.6vw)}@media(min-width: 1200px){h2,.h2{font-size:1.75rem}}h3,.h3{font-size:calc(1.275rem + 0.3vw)}@media(min-width: 1200px){h3,.h3{font-size:1.5rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-bs-original-title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:#0d6efd;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr /* rtl:ignore */;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f6f6f6;padding:.5rem;border:1px solid #dee2e6;border-radius:.25rem}pre code{background-color:transparent;font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:#9753b8;background-color:#f6f6f6;border-radius:.25rem;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:.25rem;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #212529;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #212529;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #212529;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#212529;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #cfe2ff;--bs-table-striped-bg: #c5d7f2;--bs-table-striped-color: #000;--bs-table-active-bg: #bacbe6;--bs-table-active-color: #000;--bs-table-hover-bg: #bfd1ec;--bs-table-hover-color: #000;color:#000;border-color:#bacbe6}.table-secondary{--bs-table-bg: #e2e3e5;--bs-table-striped-bg: #d7d8da;--bs-table-striped-color: #000;--bs-table-active-bg: #cbccce;--bs-table-active-color: #000;--bs-table-hover-bg: #d1d2d4;--bs-table-hover-color: #000;color:#000;border-color:#cbccce}.table-success{--bs-table-bg: #d1e7dd;--bs-table-striped-bg: #c7dbd2;--bs-table-striped-color: #000;--bs-table-active-bg: #bcd0c7;--bs-table-active-color: #000;--bs-table-hover-bg: #c1d6cc;--bs-table-hover-color: #000;color:#000;border-color:#bcd0c7}.table-info{--bs-table-bg: #cff4fc;--bs-table-striped-bg: #c5e8ef;--bs-table-striped-color: #000;--bs-table-active-bg: #badce3;--bs-table-active-color: #000;--bs-table-hover-bg: #bfe2e9;--bs-table-hover-color: #000;color:#000;border-color:#badce3}.table-warning{--bs-table-bg: #fff3cd;--bs-table-striped-bg: #f2e7c3;--bs-table-striped-color: #000;--bs-table-active-bg: #e6dbb9;--bs-table-active-color: #000;--bs-table-hover-bg: #ece1be;--bs-table-hover-color: #000;color:#000;border-color:#e6dbb9}.table-danger{--bs-table-bg: #f8d7da;--bs-table-striped-bg: #eccccf;--bs-table-striped-color: #000;--bs-table-active-bg: #dfc2c4;--bs-table-active-color: #000;--bs-table-hover-bg: #e5c7ca;--bs-table-hover-color: #000;color:#000;border-color:#dfc2c4}.table-light{--bs-table-bg: #f8f9fa;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #212529;--bs-table-striped-bg: #2c3034;--bs-table-striped-color: #ffffff;--bs-table-active-bg: #373b3e;--bs-table-active-color: #ffffff;--bs-table-hover-bg: #323539;--bs-table-hover-color: #ffffff;color:#fff;border-color:#373b3e}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#212529;background-color:#fff;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#212529;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#212529;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px);padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em;border-radius:.25rem}.form-control-color::-webkit-color-swatch{height:1.5em;border-radius:.25rem}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:.25rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #212529}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem;border-radius:.2rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:.3rem}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.25em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-print-color-adjust:exact}.form-check-input[type=checkbox],.shiny-input-container .checkbox input[type=checkbox],.shiny-input-container .checkbox-inline input[type=checkbox],.shiny-input-container .radio input[type=checkbox],.shiny-input-container .radio-inline input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2386b7fe'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23ffffff'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:transparent;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(13,110,253,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#212529;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da;border-radius:.25rem}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3){border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4){border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px;border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#198754}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(25,135,84,.9);border-radius:.25rem}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#198754;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#198754}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#198754;box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#198754}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#198754}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#198754}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group .form-control:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#dc3545}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(220,53,69,.9);border-radius:.25rem}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#dc3545;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#dc3545}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#dc3545}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#dc3545}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#dc3545}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group .form-control:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#212529;text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;background-color:transparent;border:1px solid transparent;padding:.375rem .75rem;font-size:1rem;border-radius:.25rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#212529}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-default:hover{color:#000;background-color:#e3e6ea;border-color:#e1e5e9}.btn-check:focus+.btn-default,.btn-default:focus{color:#000;background-color:#e3e6ea;border-color:#e1e5e9;box-shadow:0 0 0 .25rem rgba(189,192,196,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#000;background-color:#e5e8eb;border-color:#e1e5e9}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(189,192,196,.5)}.btn-default:disabled,.btn-default.disabled{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-primary{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-primary:hover{color:#fff;background-color:#0b5ed7;border-color:#0a58ca}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#0b5ed7;border-color:#0a58ca;box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#0a58ca;border-color:#0a53be}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(49,132,253,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-secondary{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#5c636a;border-color:#565e64}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#5c636a;border-color:#565e64;box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#565e64;border-color:#51585e}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,145,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-success{color:#fff;background-color:#198754;border-color:#198754}.btn-success:hover{color:#fff;background-color:#157347;border-color:#146c43}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#157347;border-color:#146c43;box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#146c43;border-color:#13653f}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(60,153,110,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#198754;border-color:#198754}.btn-info{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-info:hover{color:#000;background-color:#31d2f2;border-color:#25cff2}.btn-check:focus+.btn-info,.btn-info:focus{color:#000;background-color:#31d2f2;border-color:#25cff2;box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#000;background-color:#3dd5f3;border-color:#25cff2}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(11,172,204,.5)}.btn-info:disabled,.btn-info.disabled{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-warning{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-warning:hover{color:#000;background-color:#ffca2c;border-color:#ffc720}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#000;background-color:#ffca2c;border-color:#ffc720;box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#000;background-color:#ffcd39;border-color:#ffc720}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(217,164,6,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-danger{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-danger:hover{color:#fff;background-color:#bb2d3b;border-color:#b02a37}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#bb2d3b;border-color:#b02a37;box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#b02a37;border-color:#a52834}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(225,83,97,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#212529;border-color:#212529}.btn-dark:hover{color:#fff;background-color:#1c1f23;border-color:#1a1e21}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#1c1f23;border-color:#1a1e21;box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#1a1e21;border-color:#191c1f}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(66,70,73,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#212529;border-color:#212529}.btn-outline-default{color:#dee2e6;border-color:#dee2e6;background-color:transparent}.btn-outline-default:hover{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(222,226,230,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#000;background-color:#dee2e6;border-color:#dee2e6}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(222,226,230,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#dee2e6;background-color:transparent}.btn-outline-primary{color:#0d6efd;border-color:#0d6efd;background-color:transparent}.btn-outline-primary:hover{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#fff;background-color:#0d6efd;border-color:#0d6efd}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(13,110,253,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#0d6efd;background-color:transparent}.btn-outline-secondary{color:#6c757d;border-color:#6c757d;background-color:transparent}.btn-outline-secondary:hover{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#fff;background-color:#6c757d;border-color:#6c757d}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(108,117,125,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#6c757d;background-color:transparent}.btn-outline-success{color:#198754;border-color:#198754;background-color:transparent}.btn-outline-success:hover{color:#fff;background-color:#198754;border-color:#198754}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#198754;border-color:#198754}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(25,135,84,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#198754;background-color:transparent}.btn-outline-info{color:#0dcaf0;border-color:#0dcaf0;background-color:transparent}.btn-outline-info:hover{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#000;background-color:#0dcaf0;border-color:#0dcaf0}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(13,202,240,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#0dcaf0;background-color:transparent}.btn-outline-warning{color:#ffc107;border-color:#ffc107;background-color:transparent}.btn-outline-warning:hover{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#000;background-color:#ffc107;border-color:#ffc107}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,193,7,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ffc107;background-color:transparent}.btn-outline-danger{color:#dc3545;border-color:#dc3545;background-color:transparent}.btn-outline-danger:hover{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#dc3545;border-color:#dc3545}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(220,53,69,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#dc3545;background-color:transparent}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:transparent}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:transparent}.btn-outline-dark{color:#212529;border-color:#212529;background-color:transparent}.btn-outline-dark:hover{color:#fff;background-color:#212529;border-color:#212529}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#212529;border-color:#212529}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(33,37,41,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#212529;background-color:transparent}.btn-link{font-weight:400;color:#0d6efd;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#0a58ca}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:.3rem}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:.2rem}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#212529;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:.25rem}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#0d6efd}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#343a40;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#0d6efd}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn~.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#0d6efd;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:#0a58ca}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid transparent;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{background:none;border:0;border-radius:.25rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#0d6efd}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:1.25rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:.25rem;transition:box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:transparent;border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#0d6efd}.navbar-light .navbar-brand{color:#fdfeff}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#fdfeff}.navbar-light .navbar-nav .nav-link{color:#fdfeff}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#fdfeff}.navbar-light .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,.4)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#fdfeff}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#fdfeff}.navbar-dark{background-color:#0d6efd}.navbar-dark .navbar-brand{color:#fdfeff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fdfeff}.navbar-dark .navbar-nav .nav-link{color:#fdfeff}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#fdfeff}.navbar-dark .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,.4)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#fdfeff}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fdfeff}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:.25rem}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:rgba(0,0,0,.03);border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(0.25rem - 1px) calc(0.25rem - 1px) 0 0}.card-footer{padding:.5rem 1rem;background-color:rgba(0,0,0,.03);border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(0.25rem - 1px) calc(0.25rem - 1px)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem;border-radius:calc(0.25rem - 1px)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.card-img,.card-img-bottom{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.card-group>.card{margin-bottom:.75rem}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child) .card-img-top,.card-group>.card:not(:last-child) .card-header{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-img-bottom,.card-group>.card:not(:last-child) .card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child) .card-img-top,.card-group>.card:not(:first-child) .card-header{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-img-bottom,.card-group>.card:not(:first-child) .card-footer{border-bottom-left-radius:0}}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#212529;text-align:left;background-color:#fff;border:0;border-radius:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#0c63e4;background-color:#e7f1ff;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%230c63e4'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:first-of-type{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:first-of-type .accordion-button{border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-item:last-of-type .accordion-button.collapsed{border-bottom-right-radius:calc(0.25rem - 1px);border-bottom-left-radius:calc(0.25rem - 1px)}.accordion-item:last-of-type .accordion-collapse{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#0d6efd;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#0a58ca;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#0a58ca;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-top-left-radius:.25rem;border-bottom-left-radius:.25rem}.page-item:last-child .page-link{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-lg .page-item:first-child .page-link{border-top-left-radius:.3rem;border-bottom-left-radius:.3rem}.pagination-lg .page-item:last-child .page-link{border-top-right-radius:.3rem;border-bottom-right-radius:.3rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.pagination-sm .page-item:first-child .page-link{border-top-left-radius:.2rem;border-bottom-left-radius:.2rem}.pagination-sm .page-item:last-child .page-link{border-top-right-radius:.2rem;border-bottom-right-radius:.2rem}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25rem}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:1px solid transparent;border-radius:.25rem}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#595a5c;background-color:#f8f9fa;border-color:#f5f6f8}.alert-default .alert-link{color:#47484a}.alert-primary{color:#084298;background-color:#cfe2ff;border-color:#b6d4fe}.alert-primary .alert-link{color:#06357a}.alert-secondary{color:#41464b;background-color:#e2e3e5;border-color:#d3d6d8}.alert-secondary .alert-link{color:#34383c}.alert-success{color:#0f5132;background-color:#d1e7dd;border-color:#badbcc}.alert-success .alert-link{color:#0c4128}.alert-info{color:#055160;background-color:#cff4fc;border-color:#b6effb}.alert-info .alert-link{color:#04414d}.alert-warning{color:#664d03;background-color:#fff3cd;border-color:#ffecb5}.alert-warning .alert-link{color:#523e02}.alert-danger{color:#842029;background-color:#f8d7da;border-color:#f5c2c7}.alert-danger .alert-link{color:#6a1a21}.alert-light{color:#636464;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#4f5050}.alert-dark{color:#141619;background-color:#d3d3d4;border-color:#bcbebf}.alert-dark .alert-link{color:#101214}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress{display:flex;display:-webkit-flex;height:1rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef;border-radius:.25rem}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#0d6efd;transition:width .6s ease}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:1rem 1rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;border-radius:.25rem}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#212529;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#0d6efd;border-color:#0d6efd}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.25rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-top-right-radius:.25rem;border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#595a5c;background-color:#f8f9fa}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#595a5c;background-color:#dfe0e1}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#595a5c;border-color:#595a5c}.list-group-item-primary{color:#084298;background-color:#cfe2ff}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#084298;background-color:#bacbe6}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#084298;border-color:#084298}.list-group-item-secondary{color:#41464b;background-color:#e2e3e5}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#41464b;background-color:#cbccce}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#41464b;border-color:#41464b}.list-group-item-success{color:#0f5132;background-color:#d1e7dd}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#0f5132;background-color:#bcd0c7}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#0f5132;border-color:#0f5132}.list-group-item-info{color:#055160;background-color:#cff4fc}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#055160;background-color:#badce3}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#055160;border-color:#055160}.list-group-item-warning{color:#664d03;background-color:#fff3cd}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#664d03;background-color:#e6dbb9}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#664d03;border-color:#664d03}.list-group-item-danger{color:#842029;background-color:#f8d7da}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#842029;background-color:#dfc2c4}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#842029;border-color:#842029}.list-group-item-light{color:#636464;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#636464;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#636464;border-color:#636464}.list-group-item-dark{color:#141619;background-color:#d3d3d4}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#141619;background-color:#bebebf}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#141619;border-color:#141619}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;border-radius:.25rem;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(13,110,253,.25);opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15);border-radius:.25rem}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05);border-top-left-radius:calc(0.25rem - 1px);border-top-right-radius:calc(0.25rem - 1px)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem;outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6;border-bottom-right-radius:calc(0.3rem - 1px);border-bottom-left-radius:calc(0.3rem - 1px)}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000;border-radius:.25rem}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);border-radius:.3rem}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2);border-top-left-radius:calc(0.3rem - 1px);border-top-right-radius:calc(0.3rem - 1px)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#212529}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23ffffff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:transparent;border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-default{color:#dee2e6}.link-default:hover,.link-default:focus{color:#e5e8eb}.link-primary{color:#0d6efd}.link-primary:hover,.link-primary:focus{color:#0a58ca}.link-secondary{color:#6c757d}.link-secondary:hover,.link-secondary:focus{color:#565e64}.link-success{color:#198754}.link-success:hover,.link-success:focus{color:#146c43}.link-info{color:#0dcaf0}.link-info:hover,.link-info:focus{color:#3dd5f3}.link-warning{color:#ffc107}.link-warning:hover,.link-warning:focus{color:#ffcd39}.link-danger{color:#dc3545}.link-danger:hover,.link-danger:focus{color:#b02a37}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#212529}.link-dark:hover,.link-dark:focus{color:#1a1e21}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: calc(3 / 4 * 100%)}.ratio-16x9{--bs-aspect-ratio: calc(9 / 16 * 100%)}.ratio-21x9{--bs-aspect-ratio: calc(9 / 21 * 100%)}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#dee2e6 !important}.border-primary{border-color:#0d6efd !important}.border-secondary{border-color:#6c757d !important}.border-success{border-color:#198754 !important}.border-info{border-color:#0dcaf0 !important}.border-warning{border-color:#ffc107 !important}.border-danger{border-color:#dc3545 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#212529 !important}.border-white{border-color:#fff !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.345rem + 1.14vw) !important}.fs-2{font-size:calc(1.3rem + 0.6vw) !important}.fs-3{font-size:calc(1.275rem + 0.3vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.5 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:#6c757d !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2rem !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#000}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#000}.bg-warning{color:#000}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2.2rem !important}.fs-2{font-size:1.75rem !important}.fs-3{font-size:1.5rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.tippy-box[data-theme~=quarto]{background-color:#fff;color:#212529;border-radius:.25rem;border:solid 1px #dee2e6;font-size:.875rem}.tippy-box[data-theme~=quarto] .tippy-arrow{color:#dee2e6}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:-1px}.tippy-box[data-placement^=bottom]>.tippy-content{padding:.75em 1em;z-index:1}.top-right{position:absolute;top:1em;right:1em}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:inline-block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p{text-align:left}.quarto-figure-center>figure>p{text-align:center}.quarto-figure-right>figure>p{text-align:right}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link,div[id^=tbl-]>.anchorjs-link{position:absolute;top:0;right:0}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,.table{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}div.ansi-escaped-output{font-family:monospace;display:block}/*! -* -* ansi colors from IPython notebook's -* -*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #ffffff;--quarto-body-color: #212529;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:transparent;border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:transparent;border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:transparent}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:transparent}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(850px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] 50px [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc(1200px - 3em)) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc(750px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(800px - 3em)) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc(750px - 3em)) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{margin-top:2rem;margin-bottom:1rem}h1.title,.title.h1{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3,h4,.h4{margin-top:1.5rem}.header-section-number{color:#5a6570}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:1rem}.panel-caption,.figure-caption,figcaption{color:#5a6570}.table-caption,caption{color:#212529}.quarto-layout-cell[data-ref-parent] caption{color:#5a6570}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#5a6570;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:transparent}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#5a6570}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code:not(.sourceCode),li code:not(.sourceCode){background-color:#f6f6f6;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode){background-color:transparent;padding:0}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:transparent;transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}.sidebar nav[role=doc-toc] ul>li>a.active{border-left:1px solid #0d6efd;color:#0d6efd !important}kbd,.kbd{color:#212529;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.table a{word-break:break-word}.table>:not(:first-child){border-top-width:1px;border-top-color:#dee2e6}.table>thead{border-bottom:1px solid currentColor}.table>tbody{border-top:1px solid #dee2e6}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout.callout-captioned .callout-body{margin-top:.2em}.callout:not(.no-icon).callout-captioned.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-captioned>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-captioned .callout-body>:last-child:not(.sourceCode),.callout.callout-captioned .callout-body>div>:last-child:not(.sourceCode){margin-bottom:.5rem}.callout:not(.callout-captioned) .callout-body>:first-child,.callout:not(.callout-captioned) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-captioned) .callout-body>:last-child,.callout:not(.callout-captioned) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-caption-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#0d6efd}div.callout-note.callout-style-default>.callout-header{background-color:#e7f1ff}div.callout-note:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-tip.callout{border-left-color:#198754}div.callout-tip.callout-style-default>.callout-header{background-color:#e8f3ee}div.callout-tip:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-warning.callout{border-left-color:#ffc107}div.callout-warning.callout-style-default>.callout-header{background-color:#fff9e6}div.callout-warning:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-caution.callout{border-left-color:#fd7e14}div.callout-caution.callout-style-default>.callout-header{background-color:#fff2e8}div.callout-caution:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,')}div.callout-important.callout{border-left-color:#dc3545}div.callout-important.callout-style-default>.callout-header{background-color:#fcebec}div.callout-important:not(.callout-captioned) .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important.callout-captioned .callout-icon::before{background-image:url('data:image/svg+xml,');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,')}.quarto-toggle-container{display:flex;align-items:center}@media(min-width: 992px){.navbar .quarto-color-scheme-toggle{padding-left:.5rem;padding-right:.5rem}}@media(max-width: 767.98px){.navbar .quarto-color-scheme-toggle{padding-left:0;padding-right:0;padding-bottom:.5em}}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.navbar-collapse .quarto-color-scheme-toggle{padding-left:.6rem;padding-right:0;margin-top:-12px}.sidebar-navigation{padding-left:20px}.sidebar-navigation .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.sidebar-tools-main .quarto-color-scheme-toggle .bi::before{padding-top:.2rem;margin-bottom:-0.2rem}.navbar .quarto-color-scheme-toggle .bi::before{padding-top:7px;margin-bottom:-7px;padding-left:2px;margin-right:2px}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#212529}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{color:#fefefe;background-color:#6c757d;border-color:#6c757d}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#fefefe;background-color:#828a91;border-color:#7b838a}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#fefefe;background-color:#828a91;border-color:#7b838a;box-shadow:0 0 0 .25rem rgba(130,138,144,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#000;background-color:#899197;border-color:#7b838a}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(130,138,144,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#6c757d;border-color:#6c757d}nav.quarto-secondary-nav.color-navbar{background-color:#0d6efd;color:#fdfeff}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfeff}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner,body.nav-sidebar .quarto-title-banner{display:none}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}}.quarto-video{margin-bottom:1em}a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,');background-repeat:no-repeat;background-size:.75rem .75rem}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file,.code-with-filename .code-with-filename-file pre{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file,.quarto-dark .code-with-filename .code-with-filename-file pre{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfeff;background:#0d6efd}.quarto-title-banner .code-tools-button{color:#97cbff}.quarto-title-banner .code-tools-button:hover{color:#fdfeff}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}main.quarto-banner-title-block section:first-of-type h2:first-of-type,main.quarto-banner-title-block section:first-of-type .h2:first-of-type,main.quarto-banner-title-block section:first-of-type h3:first-of-type,main.quarto-banner-title-block section:first-of-type .h3:first-of-type,main.quarto-banner-title-block section:first-of-type h4:first-of-type,main.quarto-banner-title-block section:first-of-type .h4:first-of-type{margin-top:0}.quarto-title .quarto-categories{display:flex;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-5px}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents a{color:#212529}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:1fr 1fr}/*# sourceMappingURL=397ef2e52d54cf686e4908b90039e9db.css.map */ diff --git a/webcams_files/libs/bootstrap/bootstrap.min.js b/webcams_files/libs/bootstrap/bootstrap.min.js deleted file mode 100644 index cc0a255..0000000 --- a/webcams_files/libs/bootstrap/bootstrap.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * Bootstrap v5.1.3 (https://getbootstrap.com/) - * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) - */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;sfunction(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;et===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;ij.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;ie+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:''},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); -//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/webcams_files/libs/clipboard/clipboard.min.js b/webcams_files/libs/clipboard/clipboard.min.js deleted file mode 100644 index 41c6a0f..0000000 --- a/webcams_files/libs/clipboard/clipboard.min.js +++ /dev/null @@ -1,7 +0,0 @@ -/*! - * clipboard.js v2.0.10 - * https://clipboardjs.com/ - * - * Licensed MIT © Zeno Rocha - */ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return o}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),c=n.n(e);function a(t){try{return document.execCommand(t)}catch(t){return}}var f=function(t){t=c()(t);return a("cut"),t};var l=function(t){var e,n,o,r=1.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); -// @license-end \ No newline at end of file diff --git a/webcams_files/libs/quarto-html/popper.min.js b/webcams_files/libs/quarto-html/popper.min.js deleted file mode 100644 index 2269d66..0000000 --- a/webcams_files/libs/quarto-html/popper.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @popperjs/core v2.11.4 - MIT License - */ - -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(e,t){void 0===t&&(t=!1);var n=e.getBoundingClientRect(),o=1,i=1;if(r(e)&&t){var a=e.offsetHeight,f=e.offsetWidth;f>0&&(o=s(n.width)/f||1),a>0&&(i=s(n.height)/a||1)}return{width:n.width/o,height:n.height/i,top:n.top/i,right:n.right/o,bottom:n.bottom/i,left:n.left/o,x:n.left/o,y:n.top/i}}function c(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function p(e){return e?(e.nodeName||"").toLowerCase():null}function u(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function l(e){return f(u(e)).left+c(e).scrollLeft}function d(e){return t(e).getComputedStyle(e)}function h(e){var t=d(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function m(e,n,o){void 0===o&&(o=!1);var i,a,d=r(n),m=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),v=u(n),g=f(e,m),y={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(d||!d&&!o)&&(("body"!==p(n)||h(v))&&(y=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:c(i)),r(n)?((b=f(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):v&&(b.x=l(v))),{x:g.left+y.scrollLeft-b.x,y:g.top+y.scrollTop-b.y,width:g.width,height:g.height}}function v(e){var t=f(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function g(e){return"html"===p(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||u(e)}function y(e){return["html","body","#document"].indexOf(p(e))>=0?e.ownerDocument.body:r(e)&&h(e)?e:y(g(e))}function b(e,n){var r;void 0===n&&(n=[]);var o=y(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],h(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(b(g(s)))}function x(e){return["table","td","th"].indexOf(p(e))>=0}function w(e){return r(e)&&"fixed"!==d(e).position?e.offsetParent:null}function O(e){for(var n=t(e),i=w(e);i&&x(i)&&"static"===d(i).position;)i=w(i);return i&&("html"===p(i)||"body"===p(i)&&"static"===d(i).position)?n:i||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&r(e)&&"fixed"===d(e).position)return null;var n=g(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(p(n))<0;){var i=d(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var j="top",E="bottom",D="right",A="left",L="auto",P=[j,E,D,A],M="start",k="end",W="viewport",B="popper",H=P.reduce((function(e,t){return e.concat([t+"-"+M,t+"-"+k])}),[]),T=[].concat(P,[L]).reduce((function(e,t){return e.concat([t,t+"-"+M,t+"-"+k])}),[]),R=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function S(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function q(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function V(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function N(e,r){return r===W?V(function(e){var n=t(e),r=u(e),o=n.visualViewport,i=r.clientWidth,a=r.clientHeight,s=0,f=0;return o&&(i=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(s=o.offsetLeft,f=o.offsetTop)),{width:i,height:a,x:s+l(e),y:f}}(e)):n(r)?function(e){var t=f(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(r):V(function(e){var t,n=u(e),r=c(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+l(e),p=-r.scrollTop;return"rtl"===d(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:p}}(u(e)))}function I(e,t,o){var s="clippingParents"===t?function(e){var t=b(g(e)),o=["absolute","fixed"].indexOf(d(e).position)>=0&&r(e)?O(e):e;return n(o)?t.filter((function(e){return n(e)&&q(e,o)&&"body"!==p(e)})):[]}(e):[].concat(t),f=[].concat(s,[o]),c=f[0],u=f.reduce((function(t,n){var r=N(e,n);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),N(e,c));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function _(e){return e.split("-")[1]}function F(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function U(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?_(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case j:t={x:s,y:n.y-r.height};break;case E:t={x:s,y:n.y+n.height};break;case D:t={x:n.x+n.width,y:f};break;case A:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?F(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case M:t[c]=t[c]-(n[p]/2-r[p]/2);break;case k:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function z(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function X(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function Y(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.boundary,s=void 0===a?"clippingParents":a,c=r.rootBoundary,p=void 0===c?W:c,l=r.elementContext,d=void 0===l?B:l,h=r.altBoundary,m=void 0!==h&&h,v=r.padding,g=void 0===v?0:v,y=z("number"!=typeof g?g:X(g,P)),b=d===B?"reference":B,x=e.rects.popper,w=e.elements[m?b:d],O=I(n(w)?w:w.contextElement||u(e.elements.popper),s,p),A=f(e.elements.reference),L=U({reference:A,element:x,strategy:"absolute",placement:i}),M=V(Object.assign({},x,L)),k=d===B?M:A,H={top:O.top-k.top+y.top,bottom:k.bottom-O.bottom+y.bottom,left:O.left-k.left+y.left,right:k.right-O.right+y.right},T=e.modifiersData.offset;if(d===B&&T){var R=T[i];Object.keys(H).forEach((function(e){var t=[D,E].indexOf(e)>=0?1:-1,n=[j,E].indexOf(e)>=0?"y":"x";H[e]+=R[n]*t}))}return H}var G={placement:"bottom",modifiers:[],strategy:"absolute"};function J(){for(var e=arguments.length,t=new Array(e),n=0;n=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[A,D].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},ie={left:"right",right:"left",bottom:"top",top:"bottom"};function ae(e){return e.replace(/left|right|bottom|top/g,(function(e){return ie[e]}))}var se={start:"end",end:"start"};function fe(e){return e.replace(/start|end/g,(function(e){return se[e]}))}function ce(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?T:f,p=_(r),u=p?s?H:H.filter((function(e){return _(e)===p})):P,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=Y(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var pe={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,g=C(v),y=f||(g===v||!h?[ae(v)]:function(e){if(C(e)===L)return[];var t=ae(e);return[fe(e),t,fe(t)]}(v)),b=[v].concat(y).reduce((function(e,n){return e.concat(C(n)===L?ce(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,P=!0,k=b[0],W=0;W=0,S=R?"width":"height",q=Y(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),V=R?T?D:A:T?E:j;x[S]>w[S]&&(V=ae(V));var N=ae(V),I=[];if(i&&I.push(q[H]<=0),s&&I.push(q[V]<=0,q[N]<=0),I.every((function(e){return e}))){k=B,P=!1;break}O.set(B,I)}if(P)for(var F=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return k=t,"break"},U=h?3:1;U>0;U--){if("break"===F(U))break}t.placement!==k&&(t.modifiersData[r]._skip=!0,t.placement=k,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ue(e,t,n){return i(e,a(t,n))}var le={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,g=n.tetherOffset,y=void 0===g?0:g,b=Y(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=_(t.placement),L=!w,P=F(x),k="x"===P?"y":"x",W=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,q={x:0,y:0};if(W){if(s){var V,N="y"===P?j:A,I="y"===P?E:D,U="y"===P?"height":"width",z=W[P],X=z+b[N],G=z-b[I],J=m?-H[U]/2:0,K=w===M?B[U]:H[U],Q=w===M?-H[U]:-B[U],Z=t.elements.arrow,$=m&&Z?v(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=ue(0,B[U],$[U]),oe=L?B[U]/2-J-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=L?-B[U]/2+J+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&O(t.elements.arrow),se=ae?"y"===P?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(V=null==S?void 0:S[P])?V:0,ce=z+ie-fe,pe=ue(m?a(X,z+oe-fe-se):X,z,m?i(G,ce):G);W[P]=pe,q[P]=pe-z}if(c){var le,de="x"===P?j:A,he="x"===P?E:D,me=W[k],ve="y"===k?"height":"width",ge=me+b[de],ye=me-b[he],be=-1!==[j,A].indexOf(x),xe=null!=(le=null==S?void 0:S[k])?le:0,we=be?ge:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ye,je=m&&be?function(e,t,n){var r=ue(e,t,n);return r>n?n:r}(we,me,Oe):ue(m?we:ge,me,m?Oe:ye);W[k]=je,q[k]=je-me}t.modifiersData[r]=q}},requiresIfExists:["offset"]};var de={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=F(s),c=[A,D].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return z("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:X(e,P))}(o.padding,n),u=v(i),l="y"===f?j:A,d="y"===f?E:D,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],g=O(i),y=g?"y"===f?g.clientHeight||0:g.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],L=y/2-u[c]/2+b,M=ue(x,L,w),k=f;n.modifiersData[r]=((t={})[k]=M,t.centerOffset=M-L,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&q(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function he(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function me(e){return[j,D,E,A].some((function(t){return e[t]>=0}))}var ve={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=Y(t,{elementContext:"reference"}),s=Y(t,{altBoundary:!0}),f=he(a,r),c=he(s,o,i),p=me(f),u=me(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},ge=K({defaultModifiers:[Z,$,ne,re]}),ye=[Z,$,ne,re,oe,pe,le,de,ve],be=K({defaultModifiers:ye});e.applyStyles=re,e.arrow=de,e.computeStyles=ne,e.createPopper=be,e.createPopperLite=ge,e.defaultModifiers=ye,e.detectOverflow=Y,e.eventListeners=Z,e.flip=pe,e.hide=ve,e.offset=oe,e.popperGenerator=K,e.popperOffsets=$,e.preventOverflow=le,Object.defineProperty(e,"__esModule",{value:!0})})); - diff --git a/webcams_files/libs/quarto-html/quarto-syntax-highlighting.css b/webcams_files/libs/quarto-html/quarto-syntax-highlighting.css deleted file mode 100644 index 36cb328..0000000 --- a/webcams_files/libs/quarto-html/quarto-syntax-highlighting.css +++ /dev/null @@ -1,171 +0,0 @@ -/* quarto syntax highlight colors */ -:root { - --quarto-hl-ot-color: #003B4F; - --quarto-hl-at-color: #657422; - --quarto-hl-ss-color: #20794D; - --quarto-hl-an-color: #5E5E5E; - --quarto-hl-fu-color: #4758AB; - --quarto-hl-st-color: #20794D; - --quarto-hl-cf-color: #003B4F; - --quarto-hl-op-color: #5E5E5E; - --quarto-hl-er-color: #AD0000; - --quarto-hl-bn-color: #AD0000; - --quarto-hl-al-color: #AD0000; - --quarto-hl-va-color: #111111; - --quarto-hl-bu-color: inherit; - --quarto-hl-ex-color: inherit; - --quarto-hl-pp-color: #AD0000; - --quarto-hl-in-color: #5E5E5E; - --quarto-hl-vs-color: #20794D; - --quarto-hl-wa-color: #5E5E5E; - --quarto-hl-do-color: #5E5E5E; - --quarto-hl-im-color: #00769E; - --quarto-hl-ch-color: #20794D; - --quarto-hl-dt-color: #AD0000; - --quarto-hl-fl-color: #AD0000; - --quarto-hl-co-color: #5E5E5E; - --quarto-hl-cv-color: #5E5E5E; - --quarto-hl-cn-color: #8f5902; - --quarto-hl-sc-color: #5E5E5E; - --quarto-hl-dv-color: #AD0000; - --quarto-hl-kw-color: #003B4F; -} - -/* other quarto variables */ -:root { - --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; -} - -pre > code.sourceCode > span { - color: #003B4F; -} - -code span { - color: #003B4F; -} - -code.sourceCode > span { - color: #003B4F; -} - -div.sourceCode, -div.sourceCode pre.sourceCode { - color: #003B4F; -} - -code span.ot { - color: #003B4F; -} - -code span.at { - color: #657422; -} - -code span.ss { - color: #20794D; -} - -code span.an { - color: #5E5E5E; -} - -code span.fu { - color: #4758AB; -} - -code span.st { - color: #20794D; -} - -code span.cf { - color: #003B4F; -} - -code span.op { - color: #5E5E5E; -} - -code span.er { - color: #AD0000; -} - -code span.bn { - color: #AD0000; -} - -code span.al { - color: #AD0000; -} - -code span.va { - color: #111111; -} - -code span.pp { - color: #AD0000; -} - -code span.in { - color: #5E5E5E; -} - -code span.vs { - color: #20794D; -} - -code span.wa { - color: #5E5E5E; - font-style: italic; -} - -code span.do { - color: #5E5E5E; - font-style: italic; -} - -code span.im { - color: #00769E; -} - -code span.ch { - color: #20794D; -} - -code span.dt { - color: #AD0000; -} - -code span.fl { - color: #AD0000; -} - -code span.co { - color: #5E5E5E; -} - -code span.cv { - color: #5E5E5E; - font-style: italic; -} - -code span.cn { - color: #8f5902; -} - -code span.sc { - color: #5E5E5E; -} - -code span.dv { - color: #AD0000; -} - -code span.kw { - color: #003B4F; -} - -.prevent-inlining { - content: " { - const sibling = el.previousElementSibling; - if (sibling && sibling.tagName === "A") { - return sibling.classList.contains("active"); - } else { - return false; - } - }; - - // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) - function fireSlideEnter(e) { - const event = window.document.createEvent("Event"); - event.initEvent("slideenter", true, true); - window.document.dispatchEvent(event); - } - const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); - tabs.forEach((tab) => { - tab.addEventListener("shown.bs.tab", fireSlideEnter); - }); - - // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) - document.addEventListener("tabby", fireSlideEnter, false); - - // Track scrolling and mark TOC links as active - // get table of contents and sidebar (bail if we don't have at least one) - const tocLinks = tocEl - ? [...tocEl.querySelectorAll("a[data-scroll-target]")] - : []; - const makeActive = (link) => tocLinks[link].classList.add("active"); - const removeActive = (link) => tocLinks[link].classList.remove("active"); - const removeAllActive = () => - [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); - - // activate the anchor for a section associated with this TOC entry - tocLinks.forEach((link) => { - link.addEventListener("click", () => { - if (link.href.indexOf("#") !== -1) { - const anchor = link.href.split("#")[1]; - const heading = window.document.querySelector( - `[data-anchor-id=${anchor}]` - ); - if (heading) { - // Add the class - heading.classList.add("reveal-anchorjs-link"); - - // function to show the anchor - const handleMouseout = () => { - heading.classList.remove("reveal-anchorjs-link"); - heading.removeEventListener("mouseout", handleMouseout); - }; - - // add a function to clear the anchor when the user mouses out of it - heading.addEventListener("mouseout", handleMouseout); - } - } - }); - }); - - const sections = tocLinks.map((link) => { - const target = link.getAttribute("data-scroll-target"); - if (target.startsWith("#")) { - return window.document.getElementById(decodeURI(`${target.slice(1)}`)); - } else { - return window.document.querySelector(decodeURI(`${target}`)); - } - }); - - const sectionMargin = 200; - let currentActive = 0; - // track whether we've initialized state the first time - let init = false; - - const updateActiveLink = () => { - // The index from bottom to top (e.g. reversed list) - let sectionIndex = -1; - if ( - window.innerHeight + window.pageYOffset >= - window.document.body.offsetHeight - ) { - sectionIndex = 0; - } else { - sectionIndex = [...sections].reverse().findIndex((section) => { - if (section) { - return window.pageYOffset >= section.offsetTop - sectionMargin; - } else { - return false; - } - }); - } - if (sectionIndex > -1) { - const current = sections.length - sectionIndex - 1; - if (current !== currentActive) { - removeAllActive(); - currentActive = current; - makeActive(current); - if (init) { - window.dispatchEvent(sectionChanged); - } - init = true; - } - } - }; - - const inHiddenRegion = (top, bottom, hiddenRegions) => { - for (const region of hiddenRegions) { - if (top <= region.bottom && bottom >= region.top) { - return true; - } - } - return false; - }; - - const categorySelector = "header.quarto-title-block .quarto-category"; - const activateCategories = (href) => { - // Find any categories - // Surround them with a link pointing back to: - // #category=Authoring - try { - const categoryEls = window.document.querySelectorAll(categorySelector); - for (const categoryEl of categoryEls) { - const categoryText = categoryEl.textContent; - if (categoryText) { - const link = `${href}#category=${encodeURIComponent(categoryText)}`; - const linkEl = window.document.createElement("a"); - linkEl.setAttribute("href", link); - for (const child of categoryEl.childNodes) { - linkEl.append(child); - } - categoryEl.appendChild(linkEl); - } - } - } catch { - // Ignore errors - } - }; - function hasTitleCategories() { - return window.document.querySelector(categorySelector) !== null; - } - - function offsetRelativeUrl(url) { - const offset = getMeta("quarto:offset"); - return offset ? offset + url : url; - } - - function offsetAbsoluteUrl(url) { - const offset = getMeta("quarto:offset"); - const baseUrl = new URL(offset, window.location); - - const projRelativeUrl = url.replace(baseUrl, ""); - if (projRelativeUrl.startsWith("/")) { - return projRelativeUrl; - } else { - return "/" + projRelativeUrl; - } - } - - // read a meta tag value - function getMeta(metaName) { - const metas = window.document.getElementsByTagName("meta"); - for (let i = 0; i < metas.length; i++) { - if (metas[i].getAttribute("name") === metaName) { - return metas[i].getAttribute("content"); - } - } - return ""; - } - - async function findAndActivateCategories() { - const currentPagePath = offsetAbsoluteUrl(window.location.href); - const response = await fetch(offsetRelativeUrl("listings.json")); - if (response.status == 200) { - return response.json().then(function (listingPaths) { - const listingHrefs = []; - for (const listingPath of listingPaths) { - const pathWithoutLeadingSlash = listingPath.listing.substring(1); - for (const item of listingPath.items) { - if ( - item === currentPagePath || - item === currentPagePath + "index.html" - ) { - // Resolve this path against the offset to be sure - // we already are using the correct path to the listing - // (this adjusts the listing urls to be rooted against - // whatever root the page is actually running against) - const relative = offsetRelativeUrl(pathWithoutLeadingSlash); - const baseUrl = window.location; - const resolvedPath = new URL(relative, baseUrl); - listingHrefs.push(resolvedPath.pathname); - break; - } - } - } - - // Look up the tree for a nearby linting and use that if we find one - const nearestListing = findNearestParentListing( - offsetAbsoluteUrl(window.location.pathname), - listingHrefs - ); - if (nearestListing) { - activateCategories(nearestListing); - } else { - // See if the referrer is a listing page for this item - const referredRelativePath = offsetAbsoluteUrl(document.referrer); - const referrerListing = listingHrefs.find((listingHref) => { - const isListingReferrer = - listingHref === referredRelativePath || - listingHref === referredRelativePath + "index.html"; - return isListingReferrer; - }); - - if (referrerListing) { - // Try to use the referrer if possible - activateCategories(referrerListing); - } else if (listingHrefs.length > 0) { - // Otherwise, just fall back to the first listing - activateCategories(listingHrefs[0]); - } - } - }); - } - } - if (hasTitleCategories()) { - findAndActivateCategories(); - } - - const findNearestParentListing = (href, listingHrefs) => { - if (!href || !listingHrefs) { - return undefined; - } - // Look up the tree for a nearby linting and use that if we find one - const relativeParts = href.substring(1).split("/"); - while (relativeParts.length > 0) { - const path = relativeParts.join("/"); - for (const listingHref of listingHrefs) { - if (listingHref.startsWith(path)) { - return listingHref; - } - } - relativeParts.pop(); - } - - return undefined; - }; - - const manageSidebarVisiblity = (el, placeholderDescriptor) => { - let isVisible = true; - - return (hiddenRegions) => { - if (el === null) { - return; - } - - // Find the last element of the TOC - const lastChildEl = el.lastElementChild; - - if (lastChildEl) { - // Find the top and bottom o the element that is being managed - const elTop = el.offsetTop; - const elBottom = - elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; - - // Converts the sidebar to a menu - const convertToMenu = () => { - for (const child of el.children) { - child.style.opacity = 0; - child.style.overflow = "hidden"; - } - - const toggleContainer = window.document.createElement("div"); - toggleContainer.style.width = "100%"; - toggleContainer.classList.add("zindex-over-content"); - toggleContainer.classList.add("quarto-sidebar-toggle"); - toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom - toggleContainer.id = placeholderDescriptor.id; - toggleContainer.style.position = "fixed"; - - const toggleIcon = window.document.createElement("i"); - toggleIcon.classList.add("quarto-sidebar-toggle-icon"); - toggleIcon.classList.add("bi"); - toggleIcon.classList.add("bi-caret-down-fill"); - - const toggleTitle = window.document.createElement("div"); - const titleEl = window.document.body.querySelector( - placeholderDescriptor.titleSelector - ); - if (titleEl) { - toggleTitle.append(titleEl.innerText, toggleIcon); - } - toggleTitle.classList.add("zindex-over-content"); - toggleTitle.classList.add("quarto-sidebar-toggle-title"); - toggleContainer.append(toggleTitle); - - const toggleContents = window.document.createElement("div"); - toggleContents.classList = el.classList; - toggleContents.classList.add("zindex-over-content"); - toggleContents.classList.add("quarto-sidebar-toggle-contents"); - for (const child of el.children) { - if (child.id === "toc-title") { - continue; - } - - const clone = child.cloneNode(true); - clone.style.opacity = 1; - clone.style.display = null; - toggleContents.append(clone); - } - toggleContents.style.height = "0px"; - toggleContainer.append(toggleContents); - el.parentElement.prepend(toggleContainer); - - // Process clicks - let tocShowing = false; - // Allow the caller to control whether this is dismissed - // when it is clicked (e.g. sidebar navigation supports - // opening and closing the nav tree, so don't dismiss on click) - const clickEl = placeholderDescriptor.dismissOnClick - ? toggleContainer - : toggleTitle; - - const closeToggle = () => { - if (tocShowing) { - toggleContainer.classList.remove("expanded"); - toggleContents.style.height = "0px"; - tocShowing = false; - } - }; - - const positionToggle = () => { - // position the element (top left of parent, same width as parent) - const elRect = el.getBoundingClientRect(); - toggleContainer.style.left = `${elRect.left}px`; - toggleContainer.style.top = `${elRect.top}px`; - toggleContainer.style.width = `${elRect.width}px`; - }; - - // Get rid of any expanded toggle if the user scrolls - window.document.addEventListener( - "scroll", - throttle(() => { - closeToggle(); - }, 50) - ); - - // Handle positioning of the toggle - window.addEventListener( - "resize", - throttle(() => { - positionToggle(); - }, 50) - ); - positionToggle(); - - // Process the click - clickEl.onclick = () => { - if (!tocShowing) { - toggleContainer.classList.add("expanded"); - toggleContents.style.height = null; - tocShowing = true; - } else { - closeToggle(); - } - }; - }; - - // Converts a sidebar from a menu back to a sidebar - const convertToSidebar = () => { - for (const child of el.children) { - child.style.opacity = 1; - child.style.overflow = null; - } - - const placeholderEl = window.document.getElementById( - placeholderDescriptor.id - ); - if (placeholderEl) { - placeholderEl.remove(); - } - - el.classList.remove("rollup"); - }; - - if (isReaderMode()) { - convertToMenu(); - isVisible = false; - } else { - if (!isVisible) { - // If the element is current not visible reveal if there are - // no conflicts with overlay regions - if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToSidebar(); - isVisible = true; - } - } else { - // If the element is visible, hide it if it conflicts with overlay regions - // and insert a placeholder toggle (or if we're in reader mode) - if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { - convertToMenu(); - isVisible = false; - } - } - } - } - }; - }; - - // Find any conflicting margin elements and add margins to the - // top to prevent overlap - const marginChildren = window.document.querySelectorAll( - ".column-margin.column-container > * " - ); - - nexttick(() => { - let lastBottom = 0; - for (const marginChild of marginChildren) { - const top = marginChild.getBoundingClientRect().top + window.scrollY; - if (top < lastBottom) { - const margin = lastBottom - top; - marginChild.style.marginTop = `${margin}px`; - } - const styles = window.getComputedStyle(marginChild); - const marginTop = parseFloat(styles["marginTop"]); - - lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; - } - }); - - // Manage the visibility of the toc and the sidebar - const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { - id: "quarto-toc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { - id: "quarto-sidebarnav-toggle", - titleSelector: ".title", - dismissOnClick: false, - }); - let tocLeftScrollVisibility; - if (leftTocEl) { - tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { - id: "quarto-lefttoc-toggle", - titleSelector: "#toc-title", - dismissOnClick: true, - }); - } - - // Find the first element that uses formatting in special columns - const conflictingEls = window.document.body.querySelectorAll( - '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' - ); - - // Filter all the possibly conflicting elements into ones - // the do conflict on the left or ride side - const arrConflictingEls = Array.from(conflictingEls); - const leftSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return false; - } - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - className.startsWith("column-") && - !className.endsWith("right") && - !className.endsWith("container") && - className !== "column-margin" - ); - }); - }); - const rightSideConflictEls = arrConflictingEls.filter((el) => { - if (el.tagName === "ASIDE") { - return true; - } - - const hasMarginCaption = Array.from(el.classList).find((className) => { - return className == "margin-caption"; - }); - if (hasMarginCaption) { - return true; - } - - return Array.from(el.classList).find((className) => { - return ( - className !== "column-body" && - !className.endsWith("container") && - className.startsWith("column-") && - !className.endsWith("left") - ); - }); - }); - - const kOverlapPaddingSize = 10; - function toRegions(els) { - return els.map((el) => { - const top = - el.getBoundingClientRect().top + - document.documentElement.scrollTop - - kOverlapPaddingSize; - return { - top, - bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, - }; - }); - } - - const hideOverlappedSidebars = () => { - marginScrollVisibility(toRegions(rightSideConflictEls)); - sidebarScrollVisiblity(toRegions(leftSideConflictEls)); - if (tocLeftScrollVisibility) { - tocLeftScrollVisibility(toRegions(leftSideConflictEls)); - } - }; - - window.quartoToggleReader = () => { - // Applies a slow class (or removes it) - // to update the transition speed - const slowTransition = (slow) => { - const manageTransition = (id, slow) => { - const el = document.getElementById(id); - if (el) { - if (slow) { - el.classList.add("slow"); - } else { - el.classList.remove("slow"); - } - } - }; - - manageTransition("TOC", slow); - manageTransition("quarto-sidebar", slow); - }; - - const readerMode = !isReaderMode(); - setReaderModeValue(readerMode); - - // If we're entering reader mode, slow the transition - if (readerMode) { - slowTransition(readerMode); - } - highlightReaderToggle(readerMode); - hideOverlappedSidebars(); - - // If we're exiting reader mode, restore the non-slow transition - if (!readerMode) { - slowTransition(!readerMode); - } - }; - - const highlightReaderToggle = (readerMode) => { - const els = document.querySelectorAll(".quarto-reader-toggle"); - if (els) { - els.forEach((el) => { - if (readerMode) { - el.classList.add("reader"); - } else { - el.classList.remove("reader"); - } - }); - } - }; - - const setReaderModeValue = (val) => { - if (window.location.protocol !== "file:") { - window.localStorage.setItem("quarto-reader-mode", val); - } else { - localReaderMode = val; - } - }; - - const isReaderMode = () => { - if (window.location.protocol !== "file:") { - return window.localStorage.getItem("quarto-reader-mode") === "true"; - } else { - return localReaderMode; - } - }; - let localReaderMode = null; - - // Walk the TOC and collapse/expand nodes - // Nodes are expanded if: - // - they are top level - // - they have children that are 'active' links - // - they are directly below an link that is 'active' - const walk = (el, depth) => { - // Tick depth when we enter a UL - if (el.tagName === "UL") { - depth = depth + 1; - } - - // It this is active link - let isActiveNode = false; - if (el.tagName === "A" && el.classList.contains("active")) { - isActiveNode = true; - } - - // See if there is an active child to this element - let hasActiveChild = false; - for (child of el.children) { - hasActiveChild = walk(child, depth) || hasActiveChild; - } - - // Process the collapse state if this is an UL - if (el.tagName === "UL") { - if (depth === 1 || hasActiveChild || prevSiblingIsActiveLink(el)) { - el.classList.remove("collapse"); - } else { - el.classList.add("collapse"); - } - - // untick depth when we leave a UL - depth = depth - 1; - } - return hasActiveChild || isActiveNode; - }; - - // walk the TOC and expand / collapse any items that should be shown - - if (tocEl) { - walk(tocEl, 0); - updateActiveLink(); - } - - // Throttle the scroll event and walk peridiocally - window.document.addEventListener( - "scroll", - throttle(() => { - if (tocEl) { - updateActiveLink(); - walk(tocEl, 0); - } - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 5) - ); - window.addEventListener( - "resize", - throttle(() => { - if (!isReaderMode()) { - hideOverlappedSidebars(); - } - }, 10) - ); - hideOverlappedSidebars(); - highlightReaderToggle(isReaderMode()); -}); - -// grouped tabsets -window.addEventListener("pageshow", (_event) => { - function getTabSettings() { - const data = localStorage.getItem("quarto-persistent-tabsets-data"); - if (!data) { - localStorage.setItem("quarto-persistent-tabsets-data", "{}"); - return {}; - } - if (data) { - return JSON.parse(data); - } - } - - function setTabSettings(data) { - localStorage.setItem( - "quarto-persistent-tabsets-data", - JSON.stringify(data) - ); - } - - function setTabState(groupName, groupValue) { - const data = getTabSettings(); - data[groupName] = groupValue; - setTabSettings(data); - } - - function toggleTab(tab, active) { - const tabPanelId = tab.getAttribute("aria-controls"); - const tabPanel = document.getElementById(tabPanelId); - if (active) { - tab.classList.add("active"); - tabPanel.classList.add("active"); - } else { - tab.classList.remove("active"); - tabPanel.classList.remove("active"); - } - } - - function toggleAll(selectedGroup, selectorsToSync) { - for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { - const active = selectedGroup === thisGroup; - for (const tab of tabs) { - toggleTab(tab, active); - } - } - } - - function findSelectorsToSyncByLanguage() { - const result = {}; - const tabs = Array.from( - document.querySelectorAll(`div[data-group] a[id^='tabset-']`) - ); - for (const item of tabs) { - const div = item.parentElement.parentElement.parentElement; - const group = div.getAttribute("data-group"); - if (!result[group]) { - result[group] = {}; - } - const selectorsToSync = result[group]; - const value = item.innerHTML; - if (!selectorsToSync[value]) { - selectorsToSync[value] = []; - } - selectorsToSync[value].push(item); - } - return result; - } - - function setupSelectorSync() { - const selectorsToSync = findSelectorsToSyncByLanguage(); - Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { - Object.entries(tabSetsByValue).forEach(([value, items]) => { - items.forEach((item) => { - item.addEventListener("click", (_event) => { - setTabState(group, value); - toggleAll(value, selectorsToSync[group]); - }); - }); - }); - }); - return selectorsToSync; - } - - const selectorsToSync = setupSelectorSync(); - for (const [group, selectedName] of Object.entries(getTabSettings())) { - const selectors = selectorsToSync[group]; - // it's possible that stale state gives us empty selections, so we explicitly check here. - if (selectors) { - toggleAll(selectedName, selectors); - } - } -}); - -function throttle(func, wait) { - let waiting = false; - return function () { - if (!waiting) { - func.apply(this, arguments); - waiting = true; - setTimeout(function () { - waiting = false; - }, wait); - } - }; -} - -function nexttick(func) { - return setTimeout(func, 0); -} diff --git a/webcams_files/libs/quarto-html/tippy.css b/webcams_files/libs/quarto-html/tippy.css deleted file mode 100644 index e6ae635..0000000 --- a/webcams_files/libs/quarto-html/tippy.css +++ /dev/null @@ -1 +0,0 @@ -.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/webcams_files/libs/quarto-html/tippy.umd.min.js b/webcams_files/libs/quarto-html/tippy.umd.min.js deleted file mode 100644 index ca292be..0000000 --- a/webcams_files/libs/quarto-html/tippy.umd.min.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='',F})); -