├── .github ├── ISSUE_TEMPLATE │ ├── article-template.md │ ├── consistency-review.md │ └── faq-submission.md └── workflows │ └── deploy.yml ├── .gitignore ├── .vscode └── settings.json ├── CITATION.cff ├── LICENCE.md ├── README.md ├── SPEC.md ├── assets ├── css │ └── styles.css ├── favicon.svg └── js │ └── compile.js ├── case-studies └── eshoppen.md ├── index.html ├── package-lock.json ├── package.json └── tailwind.config.js /.github/ISSUE_TEMPLATE/article-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Case Study Article Submission 3 | about: Case Study Article Submission 4 | title: Article Submission 5 | labels: Article Submission 6 | assignees: seanmcilroy29 7 | 8 | --- 9 | 10 | ## Executive Summary 11 | 12 | **Description of problem** 13 | 14 | ------- 15 | **How the use case solves the problem** 16 | 17 | -------- 18 | **Main benefits of the solution** 19 | 20 | ------- 21 | **What was the outcome, how were carbon emissions reduced** 22 | 23 | ------- 24 | **Problem statement** 25 | 26 | 27 | ------- 28 | **Solution statement** 29 | 30 | 31 | ------- 32 | **Process** 33 | 34 | ------- 35 | **Architecture** 36 | 37 | ------- 38 | **Conclusion** 39 | 40 | ------- 41 | **Looking ahead / where could this lead** 42 | 43 | ------- 44 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/consistency-review.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Consistency Review 3 | about: This is a template to used to submit comments during a Consistency Review 4 | title: "[Consistency Review submission]" 5 | labels: consistency review 6 | assignees: atg-abhishek, Henry-WattTime 7 | 8 | --- 9 | 10 | # Consistency Review Submission 11 | 12 | ## Comment 13 | 14 | {outline your observations and suggested changes} 15 | 16 | {Add text to the issue title before submitting} 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/faq-submission.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: FAQ submission 3 | about: FAQ Submissions for SCI 4 | title: '' 5 | labels: FAQ 6 | assignees: atg-abhishek, Henry-WattTime 7 | 8 | --- 9 | 10 | FAQ 11 | 12 | - **Question/Observation** 13 | {Text to outline of problem} 14 | 15 | - **Suggested Answer** 16 | {Text for suggested answer} 17 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # Simple workflow for deploying static content to GitHub Pages 2 | name: Deploy static content to Pages 3 | 4 | on: 5 | # Runs on pushes targeting the default branch 6 | push: 7 | branches: ["dev"] 8 | 9 | # Allows you to run this workflow manually from the Actions tab 10 | workflow_dispatch: 11 | 12 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 13 | permissions: 14 | contents: read 15 | pages: write 16 | id-token: write 17 | 18 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 19 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 20 | concurrency: 21 | group: "pages" 22 | cancel-in-progress: false 23 | 24 | jobs: 25 | # Single deploy job since we're just deploying 26 | deploy: 27 | environment: 28 | name: github-pages 29 | url: ${{ steps.deployment.outputs.page_url }} 30 | runs-on: ubuntu-latest 31 | steps: 32 | - name: Checkout 33 | uses: actions/checkout@v3 34 | - name: Install Node.js 35 | uses: actions/setup-node@v2 36 | with: 37 | node-version: '18' 38 | 39 | - name: Install dependencies and build 40 | run: | 41 | npm install 42 | npm run build 43 | 44 | - name: Setup Pages 45 | uses: actions/configure-pages@v3 46 | - name: Upload artifact 47 | uses: actions/upload-pages-artifact@v2 48 | with: 49 | # Upload entire repository 50 | path: '.' 51 | - name: Deploy to GitHub Pages 52 | id: deployment 53 | uses: actions/deploy-pages@v2 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } 4 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this standard, please cite it as below." 3 | authors: 4 | - family-names: "Green Software Foundation" 5 | given-names: "" 6 | title: "Software Carbon Intensity Standard" 7 | version: 1.0.0 8 | date-released: 2021-11-01 9 | url: "https://github.com/green-software-foundation/software_carbon_intensity" 10 | -------------------------------------------------------------------------------- /LICENCE.md: -------------------------------------------------------------------------------- 1 | Materials in this repository other than source code are provided as follows: 2 | 3 | Copyright (c) 2021 Joint Development Foundation Projects, LLC, GSF Series and 4 | its contributors. All rights reserved. THESE MATERIALS ARE PROVIDED "AS IS." The 5 | parties expressly disclaim any warranties (express, implied, or otherwise), 6 | including implied warranties of merchantability, non-infringement, fitness for a 7 | particular purpose, or title, related to the materials. The entire risk as to 8 | implementing or otherwise using the materials is assumed by the implementer and 9 | user. IN NO EVENT WILL THE PARTIES BE LIABLE TO ANY OTHER PARTY FOR LOST PROFITS 10 | OR ANY FORM OF INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY 11 | CHARACTER FROM ANY CAUSES OF ACTION OF ANY KIND WITH RESPECT TO THIS DELIVERABLE 12 | OR ITS GOVERNING AGREEMENT, WHETHER BASED ON BREACH OF CONTRACT, TORT (INCLUDING 13 | NEGLIGENCE), OR OTHERWISE, AND WHETHER OR NOT THE OTHER MEMBER HAS BEEN ADVISED 14 | OF THE POSSIBILITY OF SUCH DAMAGE. 15 | 16 | The patent mode selected for materials developed by this Working Group is W3C Mode. 17 | For specific details, see this Working Group's Charter at: 18 | 19 | 20 | Source code in this repository is provided under the MIT License, as follows: 21 | 22 | Copyright (c) 2021 Joint Development Foundation Projects, LLC, GSF Series and 23 | its contributors. 24 | 25 | Permission is hereby granted, free of charge, to any person obtaining a copy of 26 | this software and associated documentation files (the "Software"), to deal in 27 | the Software without restriction, including without limitation the rights to 28 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 29 | the Software, and to permit persons to whom the Software is furnished to do so, 30 | subject to the following conditions: 31 | 32 | The above copyright notice and this permission notice shall be included in all 33 | copies or substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 37 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 38 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 39 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 40 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Software Carbon Intensity (SCI) Specification 2 | 3 | A specification that describes how to calculate a carbon intensity score for software applications. 4 | 5 | Created and managed by the [Standards Working Group](https://github.com/Green-Software-Foundation/standards_wg) in the [greensoftware.foundation](https://greensoftware.foundation). 6 | 7 | ## Project Scope 8 | This document, the Software Carbon Intensity technical specification, describes how to calculate the carbon intensity of a software application. It describes the methodology of calculating the total carbon emissions and the selection criteria to turn the total into a rate that can be used to achieve real-world, physical emissions reductions, also known as abatement. 9 | 10 | Electricity has a carbon intensity depending on where and when it is consumed. An intensity is a rate. It has a numerator and a denominator. A rate provides you with helpful information when considering how to design, develop, and deploy software applications. This specification describes the carbon intensity of a software application or service. 11 | 12 | ## Getting Started 13 | - The development version of the specification is [here](https://github.com/Green-Software-Foundation/sci/blob/dev/SPEC.md). 14 | - The latest published version of the specification is [here](https://github.com/Green-Software-Foundation/sci/blob/main/SPEC.md). 15 | - The `dev` branch contains the current version that is being worked on and the `main` branch contains the latest published version. 16 | - Check the [issues tab](https://github.com/Green-Software-Foundation/software_carbon_intensity/issues) for active and closed conversations regarding the spec. 17 | 18 | ## GitHub Training 19 | - [Getting started with GitHub](https://green-software-foundation.github.io/github-training/) 20 | 21 | ## Contributing 22 | The recommended approach for getting involved with the specification is to: 23 | - Read the [development version](https://github.com/Green-Software-Foundation/software_carbon_intensity/blob/dev/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md) of the specification. 24 | - Raise an issue, question, or recommendation in the issues tab above and start a discussion with other members. 25 | - Once agreement has been reached, then raise a pull request to update the specification with your recommended changes. 26 | - Let others know about your pull request by either commenting on the relevant issue or posting in the Standards Working Group slack channel. 27 | - Pull requests are reviewed and merged during Standards Working Group meetings. 28 | - Only chairs of the Standards Working Group can merge pull requests. 29 | 30 | ## Versioning 31 | * We use [Semantic Versioning](http://semver.org/) for versioning. 32 | 33 | ## Copyright 34 | Standard WG projects are copyrighted under [Creative Commons Attribution 4.0](https://creativecommons.org/licenses/by/4.0/). 35 | 36 | ## License 37 | Standard WG projects are licensed under the MIT License - see the [LICENSE.md](Software_Carbon_Intensity/License.md) file for details. 38 | 39 | ## Patent 40 | Standard WG projects operate under the W3C Patent Mode. 41 | 42 | # Feedback 43 | * [GitHub discussions](https://github.com/Green-Software-Foundation/software_carbon_intensity/discussions/new?category=sci-feedback) 44 | * 45 | -------------------------------------------------------------------------------- /SPEC.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: 1.1.0 3 | --- 4 | # Software Carbon Intensity (SCI) Specification 5 | 6 | ## Introduction 7 | 8 | Software systems cause emissions through the hardware that they operate on, both through the energy that the physical hardware consumes and the emissions associated with manufacturing the hardware. This specification defines a methodology for calculating the rate of carbon emissions for a software system. The purpose is to help users and developers make informed choices about which tools, approaches, architectures, and services they use in the future. It is a score rather than a total; lower numbers are better than higher numbers, and reaching 0 is impossible. This specification is focused on helping users and developers understand how to improve software to reduce or avoid the creation of emissions. 9 | 10 | Reducing an SCI score is only possible through the elimination of emissions. That can be achieved by modifying a software system to use less physical hardware, less energy, or consume lower-carbon energy sources. Neutralization or avoidance offsets do not reduce an SCI score ([see exclusions section](#exclusions)). This makes the SCI an ideal strategy that organizations can adopt to meet climate targets focused on eliminating emissions, such as those specified by [1]. 11 | 12 | The SCI is for everyone. It is possible to calculate an SCI score for any software application, from a large, distributed cloud system to a small monolithic open source library, any on-premise application, or even a serverless function. The environment the product or service is running in can also vary; from personal computers, private data centers or a hyperscale cloud. 13 | 14 | Software practitioners have a significant role to play in collectively reducing the SCI score during the design, development, and delivery of software applications. The following list provides some strategies that can be used to do this across different software roles: 15 | - For a software programmer, this implies writing energy efficient code. 16 | - For an AI/ML developer, it implies model optimization, using pre-trained models or leveraging optimized hardware for training. 17 | - For a database engineer, this comprises choices like schema design, choice of storage, and query optimizations. 18 | - For a DevOps practitioner, this requires creating a carbon-aware pipeline and considering when to schedule builds and leverage clean energy. 19 | - For QA engineers, it involves creating energy efficient test automation and performance testing scripts across browsers and devices. 20 | - For an architect, this implies choices like serverless or event driven architectures, infrastructure optimization, and design for carbon-aware systems. 21 | 22 | The SCI encourages calculation using granular real-world data, which is challenging to obtain in some environments, particularly the public cloud. Access to the data needed for higher resolution calculations might not always be available. Where this is the case, users of this specification are strongly advised to request such data from their suppliers (be they hardware, hosting, or other). 23 | 24 | In situations where there is a lack of access, capability, or rights to the necessary real-world data, the SCI allows for data generated through modeling, using best estimates instead. 25 | 26 | ## Scope 27 | 28 | This specification describes a methodology for calculating the rate of carbon emissions for a software system; that is, its SCI score. The purpose of this score is to increase awareness and transparency of an application's sustainability credentials. The score will help software practitioners make better, evidence-based decisions during system design, development, and deployment, that will ultimately minimize carbon emissions. A reliable, consistent, fair and comparable measure allows targets to be defined during development and progress to be tracked. 29 | 30 | ## Normative references 31 | There are no normative references in this document. 32 | 33 | ## Terms and definitions 34 | 35 | For the purposes of this document, the following terms and definitions apply. 36 | 37 | ISO and IEC maintain terminological databases for use in standardization at the following addresses: 38 | - ISO Online browsing platform: available at https://www.iso.org/obp 39 | - IEC Electropedia: available at http://www.electropedia.org/ 40 | 41 | T.1 42 | **action** 43 | explicit outcome taken, or change avoided, depending on the quantifiable emissions measured by this specification 44 | 45 | Note to entry: Actions generally relate to using less electricity, using electricity more intelligently, or using less hardware. 46 | 47 | T.2 48 | **carbon-aware** 49 | attribute of software or hardware that adjusts its behavior (consumption of inputs, processing, or production of outputs) in response to the carbon intensity of the energy it consumes 50 | 51 | The following abbreviations are used throughout this specification: 52 | - E – Energy consumed by a software system 53 | - I – Region-specific carbon intensity 54 | - M – Embodied emissions of the hardware needed to operate a software system 55 | - O – Operational emissions based on the emissions caused by energy consumption 56 | - R – Functional unit 57 | 58 | T.3 59 | **carbon** 60 | Greenhouse gases are a group of gases contributing to global warming. In this specification we use 'carbon' as a broad term to refer to the impact of all types of emissions and activities on global warming. 61 | 62 | ## Software sustainability actions 63 | 64 | All actions that serve to reduce the carbon emissions of a piece of software fit into one of the following categories: 65 | 66 | - **Energy Efficiency**: Actions taken to make software use less electricity to perform the same function. 67 | - **Hardware Efficiency**: Actions taken to make software use fewer physical resources to perform the same function. 68 | - **Carbon Awareness**: Actions taken to time- or region-shift software computation to take advantage of cleaner, more renewable or lower carbon sources of electricity. 69 | 70 | It is the intent of this specification to encourage more of these actions to be taken during the design, development, and maintenance of software applications. 71 | 72 | ## Procedure 73 | 74 | The steps required to calculate and report an SCI score are: 75 | 76 | 1. **Bound**: Decide on the [software boundary](#software-boundary); i.e., the components of a software system to include. 77 | 1. **Scale**: As the SCI is a rate (carbon emissions per one [functional unit](#functional-unit-r)), pick the functional unit which best describes how the application scales. 78 | 1. **Define**: For each software component listed in the software boundary, decide on the [quantification method](#quantification-method); real-world measurements, based on telemetry, or lab-based measurements, based on models. 79 | 1. **Quantify**: Calculate a rate for every software component. The SCI value of the whole application is the sum of the SCI values for every software component in the system. 80 | 1. **Report**: Disclose the SCI score, software boundary, and the calculation methodology. 81 | 82 | ## Methodology summary 83 | 84 | ### General 85 | 86 | SCI is a rate; carbon emissions per one unit of `R`. The equation used to calculate the SCI value of a software system is: 87 | 88 | `SCI = C per R` 89 | 90 | Where: 91 | 92 | - The total amount of carbon `C` the software causes to be emitted. 93 | - All the elements in the SCI equation scale by the same functional unit of `R` (e.g., carbon emissions per additional user, API-call, or ML training run). 94 | 95 | This can be expanded to: 96 | 97 | `SCI = (O + M) per R` 98 | 99 | ### Operational emissions 100 | 101 | #### General 102 | 103 | To calculate the operational emissions associated with software, multiply the electricity consumption of the hardware the software is running on by the region-specific carbon intensity. 104 | 105 | To calculate the operational emissions `O` for a software application, use the following: 106 | 107 | `O = (E * I)` 108 | 109 | #### Energy 110 | 111 | This is the energy consumed by a software system for a functional unit of work. This could be applied to several taxonomies: 112 | 113 | - Datacenter 114 | - Individual machine (e.g., VM/Node) 115 | - Individual service (e.g., API call or ML training run) 116 | - Execution of code 117 | 118 | Units: this shall be in kilowatt hours (kWh). 119 | 120 | The energy consumption should include all energy consumed by hardware reserved or provisioned, not just the hardware actually used to meet the software needs. 121 | 122 | #### Region-specific carbon intensity 123 | 124 | The carbon intensity of electricity is a measure of how much carbon (CO2eq) emissions are produced per kilowatt-hour (kWh) of electricity consumed. 125 | 126 | Region-specific carbon intensity factors measure the grid carbon intensity of electricity in a grid region. If the electricity consumption is connected to a grid, the short run marginal, long run marginal, or average emissions grid intensity of that grid shall be used, which excludes any [market-based measures](#market-based-measures). If the electricity consumption is not connected to a larger regional grid, an appropriate emissions factor for that system shall be used. From a developer perspective, only the location-based info is important in terms of the impact on eliminating carbon emissions. This excludes [market-based measures](#market-based-measures) and is distinct from 100% renewable energy claims. 127 | 128 | Units: this shall be in grams of carbon per kilowatt hours (gCO2eq/kWh). 129 | 130 | ### Embodied emissions 131 | 132 | Embodied carbon (otherwise referred to as “embedded carbon”) is the amount of carbon emitted during the creation and disposal of a hardware device. 133 | 134 | When software runs on a device, a fraction of the total embodied emissions of the device is allocated to the software. This is the value of `M` that needs to be calculated in the SCI equation. 135 | 136 | This fraction consists of both a time- and resource-share. The length of time that the software runs on the device determines its time-share. The percentage of the device reserved just for that application during the time-share determines that application's resource-share. 137 | 138 | To calculate the time-share, amortize the total embodied carbon over the expected life span of the device and then extrapolate based on the time reserved for the usage. For example, if the device’s embodied carbon was 1000 kg with an expected lifespan of four years and it was reserved for use for one hour, the time-share embodied emissions would be 1000 * 1/(4\*365\*24) or around 28 g of the total. 139 | 140 | To calculate resource-share, look at the share of total available resources reserved for use by the software. For instance, the percentage of total virtual CPUs reserved for the software is a good choice for the resource-share metric in the virtualized cloud space. 141 | 142 | To calculate the share of `M` for a software application, use the equation: 143 | 144 | `M = TE * TS * RS` 145 | 146 | Where: 147 | 148 | - `TE` = Total Embodied Emissions; the sum of Life Cycle Assessment (LCA) emissions for all hardware components. 149 | - `TS` = Time-share; the share of the total life span of the hardware reserved for use by the software. 150 | - `RS` = Resource-share; the share of the total available resources of the hardware reserved for use by the software. 151 | 152 | The equation can be expanded further: 153 | 154 | `M = TE * (TiR/EL) * (RR/ToR)` 155 | 156 | Where: 157 | 158 | - `TiR` = Time Reserved; the length of time the hardware is reserved for use by the software. 159 | - `EL` = Expected Lifespan; the anticipated time that the equipment will be installed. 160 | - `RR` = Resources Reserved; the number of resources reserved for use by the software. 161 | - `ToR` = Total Resources; the total number of resources available. 162 | 163 | An estimate of all the embodied emissions for the hardware used within the software boundary shall be included. 164 | 165 | Simple models to estimate embodied emissions may be used; however, the most granular data possible and ideally emissions data from a device’s LCA when calculating the embodied carbon should be used. 166 | 167 | Since the purpose of the SCI is the elimination of emissions `M` shall not include any [market-based measures](#market-based-measures). 168 | 169 | Units: this shall be in grams of carbon (gCO2eq). 170 | 171 | ### Functional unit conversion 172 | 173 | An aggregate SCI score can be composed of multiple component SCI scores. 174 | 175 | Then, as long as the functional unit of `R` is the same across all the component SCI scores, these can be summed to calculate the aggregate SCI. To sum multiple component SCI scores into one aggregate score, the functional unit R shall be the same across all components. 176 | 177 | If the functional unit of a software component is not the same as the aggregate functional unit, then the component SCI score needs to be converted to match that of the aggregate SCI functional unit. Details of any unit conversion factors used in calculating the SCI score shall be disclosed. 178 | 179 | ## Software boundary 180 | 181 | The first step in generating an SCI score is deciding what the boundaries of the software system are; i.e., what software components to include or exclude in the calculation of the SCI score. 182 | 183 | The calculation of SCI shall include all supporting infrastructure and systems that significantly contribute to the software’s operation. 184 | 185 | Supporting infrastructure and systems may include: 186 | 187 | - compute resources 188 | - storage 189 | - networking equipment 190 | - memory 191 | - monitoring 192 | - idle machines 193 | - logging 194 | - scanning 195 | - build and deploy pipelines 196 | - testing 197 | - training ML models 198 | - operations 199 | - backup 200 | - resources to support redundancy 201 | - resources to support failover 202 | - End user devices 203 | - IoT devices 204 | - Edge devices 205 | 206 | If the boundary includes on-premise and/or cloud data center operations, `E` should take into account the efficiency of the data center, including cooling and other energy consumption necessary to operate a data center. The data center's energy efficiency is usually available as a PUE (Power Usage Effectiveness) value. 207 | 208 | ## Functional unit 209 | 210 | The second step in generating an SCI score is deciding which functional unit will be used to describe how the application scales. First, decide on the functional unit, using the choice of `R`. Then calculate how much `C` is emitted per unit of `R`. 211 | 212 | For instance, if the application scales by number of users then choose this as the functional unit. 213 | 214 | A consistent choice of `R` across all the components in the software boundary shall be used. 215 | 216 | A suggested list of functional units includes: 217 | 218 | - API call/request 219 | - Benchmark 220 | - User 221 | - Machine 222 | - Minute/time unit 223 | - Device 224 | - Physical site 225 | - Data volume 226 | - Batch/Scheduled Job 227 | - Transaction 228 | - Database read/write 229 | 230 | ## Quantification method 231 | 232 | ### General 233 | 234 | The third step in generating an SCI score is deciding the approach to take when quantifying the carbon emissions for *each component* in the software boundary. 235 | 236 | The goal of the SCI is to **quantify** how much `C` (carbon) is emitted per **one unit** of `R`. 237 | 238 | There are two main approaches to quantifying carbon emissions (`C`), [measurement](#measurement) via real-world data or [calculation](#calculation) via models. 239 | 240 | Each component in the software boundary may use either measurement or calculation to quantify the carbon emissions. 241 | 242 | It is strongly advised that suppliers (be they hardware, hosting, or other) be contacted regarding the data needed in the resolution required for quantifying the SCI score. 243 | 244 | ### Measurement 245 | 246 | Carbon emissions may be quantified by measuring the total real-world carbon emissions of the component (`C`) over a time period and dividing by the number of functional units (`R`) in the same time period to get `C` per `R`. For instance, data regarding the real-world usage of the application "in the wild" might be measured and then divided by the number of users serviced in the same time period to get `C` per user. 247 | 248 | ### Calculation 249 | 250 | What one unit of `R` looks like may be modelled and the total carbon (`C`) calculated for executing one functional unit of work (`R`) in a controlled lab environment. For instance, a benchmark may be created that models a user interacting with a software application and then measures the `C` emitted per run of that benchmark. The result is still a `C` per user. 251 | 252 | ## Comparing an SCI score to a baseline 253 | 254 | When taking an action to reduce the carbon intensity of a piece of software, the intensity should be compared to a baseline. The baseline shall be calculated using an identical methodology to how the proposed SCI was calculated, except excluding the proposed action(s). The measurements, assumptions, models, functional units, etc. shall remain the same between the baseline and proposed SCI. 255 | 256 | ## Core characteristics 257 | 258 | As this specification develops, the following core characteristics shall remain true: 259 | 260 | - **The SCI is sensitive to carbon awareness, energy efficiency, and hardware efficiency** 261 | - The purpose of the SCI is to encourage actions that reduce the carbon emissions of software. Therefore, the SCI shall be sensitive to those actions described in this document under **Software Sustainability Actions**; specifically, carbon awareness, energy efficiency, and hardware efficiency. 262 | - If an application's SCI is X, and then actions are taken to make the application more Carbon Awareness, more Energy Efficient, or more Hardware Efficient, the value of X shall go down. 263 | 264 | - **The SCI takes a systems-impact view** 265 | - The purpose of the SCI is to encourage actions that reduce carbon emissions of software in a way that creates reductions at a system-wide level rather than just at a local level. While local-level optimizations might lead to micro improvements, they might lead to negative downstream impacts at a macro level that negate the impact of those actions. 266 | - Such a systems view shall be adopted by articulating the [boundaries](#software-boundary) of the software and its associated infrastructure, keeping in mind the [exclusions](#exclusions) mentioned in this specification. 267 | 268 | - **The SCI is easy to implement** 269 | To achieve impact at scale, the SCI encourages adoption through ease of implementation. 270 | - Anyone without much experience or training shall be able to follow the SCI specification instructions. 271 | - Calculation of the SCI shall be possible without incurring any cost, for instance, for data, services, or tooling. 272 | - Where possible, teams should consider investing more time or money in calculating their SCI number to increase its accuracy. 273 | 274 | - **The SCI encourages the use of granular data** 275 | In calculating the SCI value, the highest granularity data available should be used to compute each of `O`, `E`, `I`, and `M`. In cases where temporal granular data is not available, annual values shall be used which are the lowest acceptable level of granularity. 276 | 277 | ## Exclusions 278 | 279 | ### General 280 | 281 | The focus is elimination, not offsetting. One tonne of carbon eliminated (meaning that it was not emitted into the atmosphere) is not the same as one tonne of carbon that has been offset. By far the more preferable goal is never to have emitted the carbon in the first place. 282 | 283 | Only actions that eliminate emissions reduce an SCI score. As such, an SCI score cannot be reduced through carbon offsets, such as [market-based measures](#market-based-measures). 284 | 285 | ### Market-based measures 286 | 287 | Market-based measures are financial instruments designed to neutralize or offset carbon emissions. Market-based measures include, but are not limited to the following: 288 | 289 | - Carbon offsets or credits 290 | - A Removal Unit (RMU) 291 | - An Emission Reduction Unit (ERU) 292 | - A Certified Emission Reduction (CER) 293 | - Electricity Attribute Certificates (EACs) 294 | - Power Purchase Agreements (PPAs) 295 | - Renewable Energy Credits (RECs) 296 | 297 | ## Bibliography 298 | 299 | The following documents are useful references for implementers and users of this document: 300 | 301 | [1] *The Net-Zero STANDARD*, Science Based Targets initiative (SBTi), https://sciencebasedtargets.org/net-zero 302 | -------------------------------------------------------------------------------- /assets/css/styles.css: -------------------------------------------------------------------------------- 1 | /* 2 | ! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com 3 | */ 4 | 5 | /* 6 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) 7 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) 8 | */ 9 | 10 | *, 11 | ::before, 12 | ::after { 13 | box-sizing: border-box; 14 | /* 1 */ 15 | border-width: 0; 16 | /* 2 */ 17 | border-style: solid; 18 | /* 2 */ 19 | border-color: #e5e7eb; 20 | /* 2 */ 21 | } 22 | 23 | ::before, 24 | ::after { 25 | --tw-content: ''; 26 | } 27 | 28 | /* 29 | 1. Use a consistent sensible line-height in all browsers. 30 | 2. Prevent adjustments of font size after orientation changes in iOS. 31 | 3. Use a more readable tab size. 32 | 4. Use the user's configured `sans` font-family by default. 33 | 5. Use the user's configured `sans` font-feature-settings by default. 34 | 6. Use the user's configured `sans` font-variation-settings by default. 35 | */ 36 | 37 | html { 38 | line-height: 1.5; 39 | /* 1 */ 40 | -webkit-text-size-adjust: 100%; 41 | /* 2 */ 42 | -moz-tab-size: 4; 43 | /* 3 */ 44 | -o-tab-size: 4; 45 | tab-size: 4; 46 | /* 3 */ 47 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; 48 | /* 4 */ 49 | font-feature-settings: normal; 50 | /* 5 */ 51 | font-variation-settings: normal; 52 | /* 6 */ 53 | } 54 | 55 | /* 56 | 1. Remove the margin in all browsers. 57 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. 58 | */ 59 | 60 | body { 61 | margin: 0; 62 | /* 1 */ 63 | line-height: inherit; 64 | /* 2 */ 65 | } 66 | 67 | /* 68 | 1. Add the correct height in Firefox. 69 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) 70 | 3. Ensure horizontal rules are visible by default. 71 | */ 72 | 73 | hr { 74 | height: 0; 75 | /* 1 */ 76 | color: inherit; 77 | /* 2 */ 78 | border-top-width: 1px; 79 | /* 3 */ 80 | } 81 | 82 | /* 83 | Add the correct text decoration in Chrome, Edge, and Safari. 84 | */ 85 | 86 | abbr:where([title]) { 87 | -webkit-text-decoration: underline dotted; 88 | text-decoration: underline dotted; 89 | } 90 | 91 | /* 92 | Remove the default font size and weight for headings. 93 | */ 94 | 95 | h1, 96 | h2, 97 | h3, 98 | h4, 99 | h5, 100 | h6 { 101 | font-size: inherit; 102 | font-weight: inherit; 103 | } 104 | 105 | /* 106 | Reset links to optimize for opt-in styling instead of opt-out. 107 | */ 108 | 109 | a { 110 | color: inherit; 111 | text-decoration: inherit; 112 | } 113 | 114 | /* 115 | Add the correct font weight in Edge and Safari. 116 | */ 117 | 118 | b, 119 | strong { 120 | font-weight: bolder; 121 | } 122 | 123 | /* 124 | 1. Use the user's configured `mono` font family by default. 125 | 2. Correct the odd `em` font sizing in all browsers. 126 | */ 127 | 128 | code, 129 | kbd, 130 | samp, 131 | pre { 132 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; 133 | /* 1 */ 134 | font-size: 1em; 135 | /* 2 */ 136 | } 137 | 138 | /* 139 | Add the correct font size in all browsers. 140 | */ 141 | 142 | small { 143 | font-size: 80%; 144 | } 145 | 146 | /* 147 | Prevent `sub` and `sup` elements from affecting the line height in all browsers. 148 | */ 149 | 150 | sub, 151 | sup { 152 | font-size: 75%; 153 | line-height: 0; 154 | position: relative; 155 | vertical-align: baseline; 156 | } 157 | 158 | sub { 159 | bottom: -0.25em; 160 | } 161 | 162 | sup { 163 | top: -0.5em; 164 | } 165 | 166 | /* 167 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) 168 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) 169 | 3. Remove gaps between table borders by default. 170 | */ 171 | 172 | table { 173 | text-indent: 0; 174 | /* 1 */ 175 | border-color: inherit; 176 | /* 2 */ 177 | border-collapse: collapse; 178 | /* 3 */ 179 | } 180 | 181 | /* 182 | 1. Change the font styles in all browsers. 183 | 2. Remove the margin in Firefox and Safari. 184 | 3. Remove default padding in all browsers. 185 | */ 186 | 187 | button, 188 | input, 189 | optgroup, 190 | select, 191 | textarea { 192 | font-family: inherit; 193 | /* 1 */ 194 | font-feature-settings: inherit; 195 | /* 1 */ 196 | font-variation-settings: inherit; 197 | /* 1 */ 198 | font-size: 100%; 199 | /* 1 */ 200 | font-weight: inherit; 201 | /* 1 */ 202 | line-height: inherit; 203 | /* 1 */ 204 | color: inherit; 205 | /* 1 */ 206 | margin: 0; 207 | /* 2 */ 208 | padding: 0; 209 | /* 3 */ 210 | } 211 | 212 | /* 213 | Remove the inheritance of text transform in Edge and Firefox. 214 | */ 215 | 216 | button, 217 | select { 218 | text-transform: none; 219 | } 220 | 221 | /* 222 | 1. Correct the inability to style clickable types in iOS and Safari. 223 | 2. Remove default button styles. 224 | */ 225 | 226 | button, 227 | [type='button'], 228 | [type='reset'], 229 | [type='submit'] { 230 | -webkit-appearance: button; 231 | /* 1 */ 232 | background-color: transparent; 233 | /* 2 */ 234 | background-image: none; 235 | /* 2 */ 236 | } 237 | 238 | /* 239 | Use the modern Firefox focus style for all focusable elements. 240 | */ 241 | 242 | :-moz-focusring { 243 | outline: auto; 244 | } 245 | 246 | /* 247 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) 248 | */ 249 | 250 | :-moz-ui-invalid { 251 | box-shadow: none; 252 | } 253 | 254 | /* 255 | Add the correct vertical alignment in Chrome and Firefox. 256 | */ 257 | 258 | progress { 259 | vertical-align: baseline; 260 | } 261 | 262 | /* 263 | Correct the cursor style of increment and decrement buttons in Safari. 264 | */ 265 | 266 | ::-webkit-inner-spin-button, 267 | ::-webkit-outer-spin-button { 268 | height: auto; 269 | } 270 | 271 | /* 272 | 1. Correct the odd appearance in Chrome and Safari. 273 | 2. Correct the outline style in Safari. 274 | */ 275 | 276 | [type='search'] { 277 | -webkit-appearance: textfield; 278 | /* 1 */ 279 | outline-offset: -2px; 280 | /* 2 */ 281 | } 282 | 283 | /* 284 | Remove the inner padding in Chrome and Safari on macOS. 285 | */ 286 | 287 | ::-webkit-search-decoration { 288 | -webkit-appearance: none; 289 | } 290 | 291 | /* 292 | 1. Correct the inability to style clickable types in iOS and Safari. 293 | 2. Change font properties to `inherit` in Safari. 294 | */ 295 | 296 | ::-webkit-file-upload-button { 297 | -webkit-appearance: button; 298 | /* 1 */ 299 | font: inherit; 300 | /* 2 */ 301 | } 302 | 303 | /* 304 | Add the correct display in Chrome and Safari. 305 | */ 306 | 307 | summary { 308 | display: list-item; 309 | } 310 | 311 | /* 312 | Removes the default spacing and border for appropriate elements. 313 | */ 314 | 315 | blockquote, 316 | dl, 317 | dd, 318 | h1, 319 | h2, 320 | h3, 321 | h4, 322 | h5, 323 | h6, 324 | hr, 325 | figure, 326 | p, 327 | pre { 328 | margin: 0; 329 | } 330 | 331 | fieldset { 332 | margin: 0; 333 | padding: 0; 334 | } 335 | 336 | legend { 337 | padding: 0; 338 | } 339 | 340 | ol, 341 | ul, 342 | menu { 343 | list-style: none; 344 | margin: 0; 345 | padding: 0; 346 | } 347 | 348 | /* 349 | Reset default styling for dialogs. 350 | */ 351 | 352 | dialog { 353 | padding: 0; 354 | } 355 | 356 | /* 357 | Prevent resizing textareas horizontally by default. 358 | */ 359 | 360 | textarea { 361 | resize: vertical; 362 | } 363 | 364 | /* 365 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) 366 | 2. Set the default placeholder color to the user's configured gray 400 color. 367 | */ 368 | 369 | input::-moz-placeholder, textarea::-moz-placeholder { 370 | opacity: 1; 371 | /* 1 */ 372 | color: #9ca3af; 373 | /* 2 */ 374 | } 375 | 376 | input::placeholder, 377 | textarea::placeholder { 378 | opacity: 1; 379 | /* 1 */ 380 | color: #9ca3af; 381 | /* 2 */ 382 | } 383 | 384 | /* 385 | Set the default cursor for buttons. 386 | */ 387 | 388 | button, 389 | [role="button"] { 390 | cursor: pointer; 391 | } 392 | 393 | /* 394 | Make sure disabled buttons don't get the pointer cursor. 395 | */ 396 | 397 | :disabled { 398 | cursor: default; 399 | } 400 | 401 | /* 402 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) 403 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) 404 | This can trigger a poorly considered lint error in some tools but is included by design. 405 | */ 406 | 407 | img, 408 | svg, 409 | video, 410 | canvas, 411 | audio, 412 | iframe, 413 | embed, 414 | object { 415 | display: block; 416 | /* 1 */ 417 | vertical-align: middle; 418 | /* 2 */ 419 | } 420 | 421 | /* 422 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) 423 | */ 424 | 425 | img, 426 | video { 427 | max-width: 100%; 428 | height: auto; 429 | } 430 | 431 | /* Make elements with the HTML hidden attribute stay hidden by default */ 432 | 433 | [hidden] { 434 | display: none; 435 | } 436 | 437 | *, ::before, ::after { 438 | --tw-border-spacing-x: 0; 439 | --tw-border-spacing-y: 0; 440 | --tw-translate-x: 0; 441 | --tw-translate-y: 0; 442 | --tw-rotate: 0; 443 | --tw-skew-x: 0; 444 | --tw-skew-y: 0; 445 | --tw-scale-x: 1; 446 | --tw-scale-y: 1; 447 | --tw-pan-x: ; 448 | --tw-pan-y: ; 449 | --tw-pinch-zoom: ; 450 | --tw-scroll-snap-strictness: proximity; 451 | --tw-gradient-from-position: ; 452 | --tw-gradient-via-position: ; 453 | --tw-gradient-to-position: ; 454 | --tw-ordinal: ; 455 | --tw-slashed-zero: ; 456 | --tw-numeric-figure: ; 457 | --tw-numeric-spacing: ; 458 | --tw-numeric-fraction: ; 459 | --tw-ring-inset: ; 460 | --tw-ring-offset-width: 0px; 461 | --tw-ring-offset-color: #fff; 462 | --tw-ring-color: rgb(59 130 246 / 0.5); 463 | --tw-ring-offset-shadow: 0 0 #0000; 464 | --tw-ring-shadow: 0 0 #0000; 465 | --tw-shadow: 0 0 #0000; 466 | --tw-shadow-colored: 0 0 #0000; 467 | --tw-blur: ; 468 | --tw-brightness: ; 469 | --tw-contrast: ; 470 | --tw-grayscale: ; 471 | --tw-hue-rotate: ; 472 | --tw-invert: ; 473 | --tw-saturate: ; 474 | --tw-sepia: ; 475 | --tw-drop-shadow: ; 476 | --tw-backdrop-blur: ; 477 | --tw-backdrop-brightness: ; 478 | --tw-backdrop-contrast: ; 479 | --tw-backdrop-grayscale: ; 480 | --tw-backdrop-hue-rotate: ; 481 | --tw-backdrop-invert: ; 482 | --tw-backdrop-opacity: ; 483 | --tw-backdrop-saturate: ; 484 | --tw-backdrop-sepia: ; 485 | } 486 | 487 | ::backdrop { 488 | --tw-border-spacing-x: 0; 489 | --tw-border-spacing-y: 0; 490 | --tw-translate-x: 0; 491 | --tw-translate-y: 0; 492 | --tw-rotate: 0; 493 | --tw-skew-x: 0; 494 | --tw-skew-y: 0; 495 | --tw-scale-x: 1; 496 | --tw-scale-y: 1; 497 | --tw-pan-x: ; 498 | --tw-pan-y: ; 499 | --tw-pinch-zoom: ; 500 | --tw-scroll-snap-strictness: proximity; 501 | --tw-gradient-from-position: ; 502 | --tw-gradient-via-position: ; 503 | --tw-gradient-to-position: ; 504 | --tw-ordinal: ; 505 | --tw-slashed-zero: ; 506 | --tw-numeric-figure: ; 507 | --tw-numeric-spacing: ; 508 | --tw-numeric-fraction: ; 509 | --tw-ring-inset: ; 510 | --tw-ring-offset-width: 0px; 511 | --tw-ring-offset-color: #fff; 512 | --tw-ring-color: rgb(59 130 246 / 0.5); 513 | --tw-ring-offset-shadow: 0 0 #0000; 514 | --tw-ring-shadow: 0 0 #0000; 515 | --tw-shadow: 0 0 #0000; 516 | --tw-shadow-colored: 0 0 #0000; 517 | --tw-blur: ; 518 | --tw-brightness: ; 519 | --tw-contrast: ; 520 | --tw-grayscale: ; 521 | --tw-hue-rotate: ; 522 | --tw-invert: ; 523 | --tw-saturate: ; 524 | --tw-sepia: ; 525 | --tw-drop-shadow: ; 526 | --tw-backdrop-blur: ; 527 | --tw-backdrop-brightness: ; 528 | --tw-backdrop-contrast: ; 529 | --tw-backdrop-grayscale: ; 530 | --tw-backdrop-hue-rotate: ; 531 | --tw-backdrop-invert: ; 532 | --tw-backdrop-opacity: ; 533 | --tw-backdrop-saturate: ; 534 | --tw-backdrop-sepia: ; 535 | } 536 | 537 | .prose { 538 | color: var(--tw-prose-body); 539 | max-width: 65ch; 540 | } 541 | 542 | .prose :where(p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 543 | margin-top: 1.25em; 544 | margin-bottom: 1.25em; 545 | } 546 | 547 | .prose :where([class~="lead"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 548 | color: var(--tw-prose-lead); 549 | font-size: 1.25em; 550 | line-height: 1.6; 551 | margin-top: 1.2em; 552 | margin-bottom: 1.2em; 553 | } 554 | 555 | .prose :where(a):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 556 | color: var(--tw-prose-links); 557 | text-decoration: underline; 558 | font-weight: 500; 559 | } 560 | 561 | .prose :where(strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 562 | color: var(--tw-prose-bold); 563 | font-weight: 600; 564 | } 565 | 566 | .prose :where(a strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 567 | color: inherit; 568 | } 569 | 570 | .prose :where(blockquote strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 571 | color: inherit; 572 | } 573 | 574 | .prose :where(thead th strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 575 | color: inherit; 576 | } 577 | 578 | .prose :where(ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 579 | list-style-type: decimal; 580 | margin-top: 1.25em; 581 | margin-bottom: 1.25em; 582 | padding-left: 1.625em; 583 | } 584 | 585 | .prose :where(ol[type="A"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 586 | list-style-type: upper-alpha; 587 | } 588 | 589 | .prose :where(ol[type="a"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 590 | list-style-type: lower-alpha; 591 | } 592 | 593 | .prose :where(ol[type="A" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 594 | list-style-type: upper-alpha; 595 | } 596 | 597 | .prose :where(ol[type="a" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 598 | list-style-type: lower-alpha; 599 | } 600 | 601 | .prose :where(ol[type="I"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 602 | list-style-type: upper-roman; 603 | } 604 | 605 | .prose :where(ol[type="i"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 606 | list-style-type: lower-roman; 607 | } 608 | 609 | .prose :where(ol[type="I" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 610 | list-style-type: upper-roman; 611 | } 612 | 613 | .prose :where(ol[type="i" s]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 614 | list-style-type: lower-roman; 615 | } 616 | 617 | .prose :where(ol[type="1"]):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 618 | list-style-type: decimal; 619 | } 620 | 621 | .prose :where(ul):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 622 | list-style-type: disc; 623 | margin-top: 1.25em; 624 | margin-bottom: 1.25em; 625 | padding-left: 1.625em; 626 | } 627 | 628 | .prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { 629 | font-weight: 400; 630 | color: var(--tw-prose-counters); 631 | } 632 | 633 | .prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *))::marker { 634 | color: var(--tw-prose-bullets); 635 | } 636 | 637 | .prose :where(dt):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 638 | color: var(--tw-prose-headings); 639 | font-weight: 600; 640 | margin-top: 1.25em; 641 | } 642 | 643 | .prose :where(hr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 644 | border-color: var(--tw-prose-hr); 645 | border-top-width: 1px; 646 | margin-top: 3em; 647 | margin-bottom: 3em; 648 | } 649 | 650 | .prose :where(blockquote):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 651 | font-weight: 500; 652 | font-style: italic; 653 | color: var(--tw-prose-quotes); 654 | border-left-width: 0.25rem; 655 | border-left-color: var(--tw-prose-quote-borders); 656 | quotes: "\201C""\201D""\2018""\2019"; 657 | margin-top: 1.6em; 658 | margin-bottom: 1.6em; 659 | padding-left: 1em; 660 | } 661 | 662 | .prose :where(blockquote p:first-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { 663 | content: open-quote; 664 | } 665 | 666 | .prose :where(blockquote p:last-of-type):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { 667 | content: close-quote; 668 | } 669 | 670 | .prose :where(h1):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 671 | color: var(--tw-prose-headings); 672 | font-weight: 800; 673 | font-size: 2.25em; 674 | margin-top: 0; 675 | margin-bottom: 0.8888889em; 676 | line-height: 1.1111111; 677 | } 678 | 679 | .prose :where(h1 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 680 | font-weight: 900; 681 | color: inherit; 682 | } 683 | 684 | .prose :where(h2):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 685 | color: var(--tw-prose-headings); 686 | font-weight: 700; 687 | font-size: 1.5em; 688 | margin-top: 2em; 689 | margin-bottom: 1em; 690 | line-height: 1.3333333; 691 | } 692 | 693 | .prose :where(h2 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 694 | font-weight: 800; 695 | color: inherit; 696 | } 697 | 698 | .prose :where(h3):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 699 | color: var(--tw-prose-headings); 700 | font-weight: 600; 701 | font-size: 1.25em; 702 | margin-top: 1.6em; 703 | margin-bottom: 0.6em; 704 | line-height: 1.6; 705 | } 706 | 707 | .prose :where(h3 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 708 | font-weight: 700; 709 | color: inherit; 710 | } 711 | 712 | .prose :where(h4):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 713 | color: var(--tw-prose-headings); 714 | font-weight: 600; 715 | margin-top: 1.5em; 716 | margin-bottom: 0.5em; 717 | line-height: 1.5; 718 | } 719 | 720 | .prose :where(h4 strong):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 721 | font-weight: 700; 722 | color: inherit; 723 | } 724 | 725 | .prose :where(img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 726 | margin-top: 2em; 727 | margin-bottom: 2em; 728 | } 729 | 730 | .prose :where(picture):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 731 | display: block; 732 | margin-top: 2em; 733 | margin-bottom: 2em; 734 | } 735 | 736 | .prose :where(kbd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 737 | font-weight: 500; 738 | font-family: inherit; 739 | color: var(--tw-prose-kbd); 740 | box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%); 741 | font-size: 0.875em; 742 | border-radius: 0.3125rem; 743 | padding-top: 0.1875em; 744 | padding-right: 0.375em; 745 | padding-bottom: 0.1875em; 746 | padding-left: 0.375em; 747 | } 748 | 749 | .prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 750 | color: var(--tw-prose-code); 751 | font-weight: 600; 752 | font-size: 0.875em; 753 | } 754 | 755 | .prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { 756 | content: "`"; 757 | } 758 | 759 | .prose :where(code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { 760 | content: "`"; 761 | } 762 | 763 | .prose :where(a code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 764 | color: inherit; 765 | } 766 | 767 | .prose :where(h1 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 768 | color: inherit; 769 | } 770 | 771 | .prose :where(h2 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 772 | color: inherit; 773 | font-size: 0.875em; 774 | } 775 | 776 | .prose :where(h3 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 777 | color: inherit; 778 | font-size: 0.9em; 779 | } 780 | 781 | .prose :where(h4 code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 782 | color: inherit; 783 | } 784 | 785 | .prose :where(blockquote code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 786 | color: inherit; 787 | } 788 | 789 | .prose :where(thead th code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 790 | color: inherit; 791 | } 792 | 793 | .prose :where(pre):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 794 | color: var(--tw-prose-pre-code); 795 | background-color: var(--tw-prose-pre-bg); 796 | overflow-x: auto; 797 | font-weight: 400; 798 | font-size: 0.875em; 799 | line-height: 1.7142857; 800 | margin-top: 1.7142857em; 801 | margin-bottom: 1.7142857em; 802 | border-radius: 0.375rem; 803 | padding-top: 0.8571429em; 804 | padding-right: 1.1428571em; 805 | padding-bottom: 0.8571429em; 806 | padding-left: 1.1428571em; 807 | } 808 | 809 | .prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 810 | background-color: transparent; 811 | border-width: 0; 812 | border-radius: 0; 813 | padding: 0; 814 | font-weight: inherit; 815 | color: inherit; 816 | font-size: inherit; 817 | font-family: inherit; 818 | line-height: inherit; 819 | } 820 | 821 | .prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::before { 822 | content: none; 823 | } 824 | 825 | .prose :where(pre code):not(:where([class~="not-prose"],[class~="not-prose"] *))::after { 826 | content: none; 827 | } 828 | 829 | .prose :where(table):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 830 | width: 100%; 831 | table-layout: auto; 832 | text-align: left; 833 | margin-top: 2em; 834 | margin-bottom: 2em; 835 | font-size: 0.875em; 836 | line-height: 1.7142857; 837 | } 838 | 839 | .prose :where(thead):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 840 | border-bottom-width: 1px; 841 | border-bottom-color: var(--tw-prose-th-borders); 842 | } 843 | 844 | .prose :where(thead th):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 845 | color: var(--tw-prose-headings); 846 | font-weight: 600; 847 | vertical-align: bottom; 848 | padding-right: 0.5714286em; 849 | padding-bottom: 0.5714286em; 850 | padding-left: 0.5714286em; 851 | } 852 | 853 | .prose :where(tbody tr):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 854 | border-bottom-width: 1px; 855 | border-bottom-color: var(--tw-prose-td-borders); 856 | } 857 | 858 | .prose :where(tbody tr:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 859 | border-bottom-width: 0; 860 | } 861 | 862 | .prose :where(tbody td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 863 | vertical-align: baseline; 864 | } 865 | 866 | .prose :where(tfoot):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 867 | border-top-width: 1px; 868 | border-top-color: var(--tw-prose-th-borders); 869 | } 870 | 871 | .prose :where(tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 872 | vertical-align: top; 873 | } 874 | 875 | .prose :where(figure > *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 876 | margin-top: 0; 877 | margin-bottom: 0; 878 | } 879 | 880 | .prose :where(figcaption):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 881 | color: var(--tw-prose-captions); 882 | font-size: 0.875em; 883 | line-height: 1.4285714; 884 | margin-top: 0.8571429em; 885 | } 886 | 887 | .prose { 888 | --tw-prose-body: #374151; 889 | --tw-prose-headings: #111827; 890 | --tw-prose-lead: #4b5563; 891 | --tw-prose-links: #111827; 892 | --tw-prose-bold: #111827; 893 | --tw-prose-counters: #6b7280; 894 | --tw-prose-bullets: #d1d5db; 895 | --tw-prose-hr: #e5e7eb; 896 | --tw-prose-quotes: #111827; 897 | --tw-prose-quote-borders: #e5e7eb; 898 | --tw-prose-captions: #6b7280; 899 | --tw-prose-kbd: #111827; 900 | --tw-prose-kbd-shadows: 17 24 39; 901 | --tw-prose-code: #111827; 902 | --tw-prose-pre-code: #e5e7eb; 903 | --tw-prose-pre-bg: #1f2937; 904 | --tw-prose-th-borders: #d1d5db; 905 | --tw-prose-td-borders: #e5e7eb; 906 | --tw-prose-invert-body: #d1d5db; 907 | --tw-prose-invert-headings: #fff; 908 | --tw-prose-invert-lead: #9ca3af; 909 | --tw-prose-invert-links: #fff; 910 | --tw-prose-invert-bold: #fff; 911 | --tw-prose-invert-counters: #9ca3af; 912 | --tw-prose-invert-bullets: #4b5563; 913 | --tw-prose-invert-hr: #374151; 914 | --tw-prose-invert-quotes: #f3f4f6; 915 | --tw-prose-invert-quote-borders: #374151; 916 | --tw-prose-invert-captions: #9ca3af; 917 | --tw-prose-invert-kbd: #fff; 918 | --tw-prose-invert-kbd-shadows: 255 255 255; 919 | --tw-prose-invert-code: #fff; 920 | --tw-prose-invert-pre-code: #d1d5db; 921 | --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%); 922 | --tw-prose-invert-th-borders: #4b5563; 923 | --tw-prose-invert-td-borders: #374151; 924 | font-size: 1rem; 925 | line-height: 1.75; 926 | } 927 | 928 | .prose :where(picture > img):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 929 | margin-top: 0; 930 | margin-bottom: 0; 931 | } 932 | 933 | .prose :where(video):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 934 | margin-top: 2em; 935 | margin-bottom: 2em; 936 | } 937 | 938 | .prose :where(li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 939 | margin-top: 0.5em; 940 | margin-bottom: 0.5em; 941 | } 942 | 943 | .prose :where(ol > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 944 | padding-left: 0.375em; 945 | } 946 | 947 | .prose :where(ul > li):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 948 | padding-left: 0.375em; 949 | } 950 | 951 | .prose :where(.prose > ul > li p):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 952 | margin-top: 0.75em; 953 | margin-bottom: 0.75em; 954 | } 955 | 956 | .prose :where(.prose > ul > li > *:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 957 | margin-top: 1.25em; 958 | } 959 | 960 | .prose :where(.prose > ul > li > *:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 961 | margin-bottom: 1.25em; 962 | } 963 | 964 | .prose :where(.prose > ol > li > *:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 965 | margin-top: 1.25em; 966 | } 967 | 968 | .prose :where(.prose > ol > li > *:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 969 | margin-bottom: 1.25em; 970 | } 971 | 972 | .prose :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 973 | margin-top: 0.75em; 974 | margin-bottom: 0.75em; 975 | } 976 | 977 | .prose :where(dl):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 978 | margin-top: 1.25em; 979 | margin-bottom: 1.25em; 980 | } 981 | 982 | .prose :where(dd):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 983 | margin-top: 0.5em; 984 | padding-left: 1.625em; 985 | } 986 | 987 | .prose :where(hr + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 988 | margin-top: 0; 989 | } 990 | 991 | .prose :where(h2 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 992 | margin-top: 0; 993 | } 994 | 995 | .prose :where(h3 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 996 | margin-top: 0; 997 | } 998 | 999 | .prose :where(h4 + *):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1000 | margin-top: 0; 1001 | } 1002 | 1003 | .prose :where(thead th:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1004 | padding-left: 0; 1005 | } 1006 | 1007 | .prose :where(thead th:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1008 | padding-right: 0; 1009 | } 1010 | 1011 | .prose :where(tbody td, tfoot td):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1012 | padding-top: 0.5714286em; 1013 | padding-right: 0.5714286em; 1014 | padding-bottom: 0.5714286em; 1015 | padding-left: 0.5714286em; 1016 | } 1017 | 1018 | .prose :where(tbody td:first-child, tfoot td:first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1019 | padding-left: 0; 1020 | } 1021 | 1022 | .prose :where(tbody td:last-child, tfoot td:last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1023 | padding-right: 0; 1024 | } 1025 | 1026 | .prose :where(figure):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1027 | margin-top: 2em; 1028 | margin-bottom: 2em; 1029 | } 1030 | 1031 | .prose :where(.prose > :first-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1032 | margin-top: 0; 1033 | } 1034 | 1035 | .prose :where(.prose > :last-child):not(:where([class~="not-prose"],[class~="not-prose"] *)) { 1036 | margin-bottom: 0; 1037 | } 1038 | 1039 | .absolute { 1040 | position: absolute; 1041 | } 1042 | 1043 | .relative { 1044 | position: relative; 1045 | } 1046 | 1047 | .left-0 { 1048 | left: 0px; 1049 | } 1050 | 1051 | .top-2 { 1052 | top: 0.5rem; 1053 | } 1054 | 1055 | .mx-auto { 1056 | margin-left: auto; 1057 | margin-right: auto; 1058 | } 1059 | 1060 | .my-16 { 1061 | margin-top: 4rem; 1062 | margin-bottom: 4rem; 1063 | } 1064 | 1065 | .my-8 { 1066 | margin-top: 2rem; 1067 | margin-bottom: 2rem; 1068 | } 1069 | 1070 | .-ml-5 { 1071 | margin-left: -1.25rem; 1072 | } 1073 | 1074 | .mb-2 { 1075 | margin-bottom: 0.5rem; 1076 | } 1077 | 1078 | .mb-5 { 1079 | margin-bottom: 1.25rem; 1080 | } 1081 | 1082 | .grid { 1083 | display: grid; 1084 | } 1085 | 1086 | .hidden { 1087 | display: none; 1088 | } 1089 | 1090 | .h-12 { 1091 | height: 3rem; 1092 | } 1093 | 1094 | .h-4 { 1095 | height: 1rem; 1096 | } 1097 | 1098 | .w-4 { 1099 | width: 1rem; 1100 | } 1101 | 1102 | .w-auto { 1103 | width: auto; 1104 | } 1105 | 1106 | .max-w-4xl { 1107 | max-width: 56rem; 1108 | } 1109 | 1110 | .border-l-4 { 1111 | border-left-width: 4px; 1112 | } 1113 | 1114 | .border-l-accent-default { 1115 | --tw-border-opacity: 1; 1116 | border-left-color: rgb(174 204 83 / var(--tw-border-opacity)); 1117 | } 1118 | 1119 | .bg-accent-lighter { 1120 | --tw-bg-opacity: 1; 1121 | background-color: rgb(235 242 212 / var(--tw-bg-opacity)); 1122 | } 1123 | 1124 | .bg-accent-lightest-1 { 1125 | --tw-bg-opacity: 1; 1126 | background-color: rgb(251 252 246 / var(--tw-bg-opacity)); 1127 | } 1128 | 1129 | .p-4 { 1130 | padding: 1rem; 1131 | } 1132 | 1133 | .px-8 { 1134 | padding-left: 2rem; 1135 | padding-right: 2rem; 1136 | } 1137 | 1138 | .pr-5 { 1139 | padding-right: 1.25rem; 1140 | } 1141 | 1142 | .text-center { 1143 | text-align: center; 1144 | } 1145 | 1146 | .text-sm { 1147 | font-size: 0.875rem; 1148 | line-height: 1.25rem; 1149 | } 1150 | 1151 | .font-bold { 1152 | font-weight: 700; 1153 | } 1154 | 1155 | .text-primary-dark { 1156 | --tw-text-opacity: 1; 1157 | color: rgb(0 82 79 / var(--tw-text-opacity)); 1158 | } 1159 | 1160 | .underline { 1161 | text-decoration-line: underline; 1162 | } 1163 | 1164 | .no-underline { 1165 | text-decoration-line: none; 1166 | } 1167 | 1168 | .hover\:underline:hover { 1169 | text-decoration-line: underline; 1170 | } 1171 | 1172 | .group:hover .group-hover\:block { 1173 | display: block; 1174 | } -------------------------------------------------------------------------------- /assets/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /assets/js/compile.js: -------------------------------------------------------------------------------- 1 | const marked = require("marked"); 2 | const fs = require("fs"); 3 | const matter = require('gray-matter'); 4 | 5 | // Read your Markdown content from a file or provide it as a string. 6 | const markdownContent = fs.readFileSync("SPEC.md", "utf8"); 7 | 8 | // Create a custom renderer with your HTML template. 9 | const customRenderer = new marked.Renderer(); 10 | 11 | // Get frontmatter from markdown 12 | const { data:frontmatter } = matter(markdownContent); 13 | 14 | // Remove the front matter from the markdown content. 15 | const markdownContentWithoutFrontmatter = markdownContent.replace(/^---[\s\S]*?---/, ""); 16 | 17 | // Add an 'id' attribute to headings with the heading text as the 'id' value. 18 | customRenderer.heading = function (text, level) { 19 | const id = text.toLowerCase().replace(/[^\w]+/g, "-"); 20 | return ` 21 | ${ level > 1 ? `` : ""} 26 | ${text}`; 27 | }; 28 | 29 | // Set the custom renderer in the marked options. 30 | marked.setOptions({ 31 | renderer: customRenderer, 32 | }); 33 | 34 | // Convert the Markdown content to HTML using marked. 35 | const contentHTML = marked.parse(markdownContentWithoutFrontmatter); 36 | 37 | // Replace the entire content of a
element with the HTML output. 38 | const htmlOutput = ` 39 | 40 | 41 | 42 | 43 | 44 | Software Carbon Intensity (SCI) Specification 45 | 46 | 47 | 48 | 49 | 54 |
55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |
78 |
${contentHTML}
79 |
80 |
81 | 82 |
83 | 86 |

87 | Copyright © ${new Date().getFullYear()} Joint Development Foundation Projects, LLC,
88 | Green Software Foundation Series 89 |

90 |
91 | 92 | 93 | 94 | `; 95 | 96 | // Write the HTML output to index.html. 97 | fs.writeFileSync("index.html", htmlOutput, "utf8"); 98 | 99 | console.log("index.html has been created."); 100 | -------------------------------------------------------------------------------- /case-studies/eshoppen.md: -------------------------------------------------------------------------------- 1 | # eShoppen - SCI Case Study 2 | 3 | ## Overview 4 | 5 | * The eShop Web application is a web application built on Asp.Net .It is built with monolithic architecture and follows MVC Design pattern 6 | * The application uses a relational database for storing data 7 | * The business use cases built demonstrates a simplified eCommerce site. 8 | * The case study focuses on calculating the Software Carbon Intensity (SCI) value of the application using the [formula](https://github.com/Green-Software-Foundation/software_carbon_intensity/blob/main/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md#methodology-summary) as defined in the latest version of the [specification](https://github.com/Green-Software-Foundation/software_carbon_intensity/blob/main/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md) 9 | 10 | The Software Carbon Intensity (SCI) is a rate, carbon emissions per one unit of R. The equation used to calculate the SCI value of a software system is: 11 | 12 | `SCI = ((E * I) + M) per R` 13 | 14 | Where: 15 | 16 | - E = Energy consumed by a software system 17 | - I = Location-based marginal carbon emissions 18 | - M = Embodied emissions of a software system 19 | - R = Functional unit (e.g. carbon per additional user, API-call, ML job, etc) 20 | 21 | All the elements in the SCI equation scale by the same functional unit of “R” 22 | 23 | ## Architecture 24 | 25 | The architecture consists of the following components. 26 | * App Service plan: An App Service plan provides the managed virtual machines (VMs) that host your app. All apps associated with a plan run on the same VM instances. 27 | 28 | * App Service app: Azure App Service is a fully managed platform for creating and deploying cloud applications. 29 | 30 | * Azure SQL Database: SQL Database is a relational database-as-a-service in the cloud. SQL Database shares its code base with the Microsoft SQL Server database engine. Depending on your application requirements, you can also use Azure Database for MySQL or Azure Database for PostgreSQL. These are fully managed database services based on the open-source MySQL Server and Postgres database engines. 31 | 32 | 33 | ![image](https://user-images.githubusercontent.com/10396742/162613391-f27ed693-84df-4c70-a17a-479d7288a57a.png) 34 | 35 | We did Load Test runs with Azure App service Premium configuration with 2 core – 7 GB RAM and database server of Gen 5 Processor and calculated the power consumed in these runs. The tests are meant to be a model only and can be extended to more infrastructure configurations. 36 | 37 | ## (What) Software boundary 38 | 39 | *Describe the components that are included in the software systems, if any major components are not included then please provide **reasons for exclusion**.* 40 | 41 | ### Included 42 | 43 | * App server for the Web application 44 | * Database server 45 | 46 | ### Excluded 47 | 48 | The following components and their carbon emissions have been excluded from the SCI calculation. 49 | 50 | * Front end browser .This is the browser client on the device that is displaying the application to the end users on their desktop/mobile/laptop etc._Will be added in the next version of the case study_ 51 | * Network traffic between browser client and application server ._We have the numbers in terms of the byte size that travelled across the network but don’t have the reference multiplication factor in terms of carbon emissions associated per byte. We have requested this info from SCI open data project_ 52 | * Network traffic between application servers and databases. _We have the numbers in terms of the byte size that travelled across the network but don’t have the reference multiplication factor in terms of carbon emissions associated per byte. We have requested this info from SCI open data project_ 53 | * Test infrastructure: These include the load test resources that were used to simulate virtual users and http requests to the web server._Since the infrastructure and the associated energy usage do not fit into the same functional unit scale as defined in the SCI formula, these components will be excluded from the software’s SCI calculation._ 54 | 55 | 56 | ## (Scale) Functional Unit 57 | 58 | *Describe the [functional unit](https://github.com/Green-Software-Foundation/software_carbon_intensity/blob/main/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md#functional-unit-r) that best controls the scaling of the software system.* 59 | 60 | The choice of functional unit applies to all components in your software boundary. 61 | 62 | R is 500 Users over a 1 hour period with 50 concurrent users 63 | 64 | ## (How) Quantification method 65 | 66 | *For each software component in your software boundary, decide whether you are going to **measure** using real-world data or **calculate** an estimate via models, provide a reason and any useful details for each choice. 67 | * 68 | 69 | ### App server for Web application 70 | 71 | ### Energy (`E`) 72 | 73 | The Quantification method used for calculating energy value is **Calculate**. We are measuring CPU utilization of the app servers and then using a model based on the Thermal Design Power (TDP) of the processors, number of cores etc to **estimate** the power consumption. 74 | 75 | The equation used to model the energy consumption is: 76 | 77 | P[kwH] = (Power consumed by CPU or Pc Number of cores + Power consumed by Memory or Pr + Power consumed by GPU or Pg Number of GPUs)/1000 78 | 79 | * CPU Utilization doesn’t scale linearly with power consumption, we will use the power curve as described in the [SCI Data Project “[E] Energy Estimation from Utilization Model” model](https://docs.google.com/spreadsheets/d/1Viv94rMKH-fJrfD9Nn9_qkiAg1PDfIfJUAHRX9slG7A/edit#gid=526989613) 80 | * TDP of server used in Azure App server Premium configuration (P2v2 ) -2nd Generation Intel® Xeon® Platinum 8272CL (Cascade Lake)= 205 W ( [https://ark.intel.com/content/www/us/en/ark/products/192482/intel-xeon-platinum-8270-processor-35-75m-cache-2-70-ghz.html](https://ark.intel.com/content/www/us/en/ark/products/192482/intel-xeon-platinum-8270-processor-35-75m-cache-2-70-ghz.html)) 81 | * From specs, we found that Power consumed by 4GB memory is close to 1.45 W and that by 8 GB memory is approximately 2.45 W. Also from this [article](https://medium.com/teads-engineering/estimating-aws-ec2-instances-power-consumption-c9745e347959) we can consider power consumed is approx 0.38 W/GB or close to 2.6 Watts.Since the energy values for memory are much lower than the calculated energy values for processors or CPUs, we consider these values negligible. Pr ~0 82 | * No GPU was used hence Pg ~0 83 | 84 | 85 | ### Carbon Intensity (`I`) 86 | 87 | * We will use regional yearly averages. 88 | * The region the application was run in was India. 89 | * We will source the Carbon Intensity from the SCI Data project and the [[I] Regional Yearly Marginal Carbon Intensity](https://docs.google.com/spreadsheets/d/1Viv94rMKH-fJrfD9Nn9_qkiAg1PDfIfJUAHRX9slG7A/edit#gid=1582216595) data set. 90 | 91 | ### Embodied Carbon (`M`) 92 | 93 | The equation to calculate `M = TE * (TR/EL) * (RR/TR)` 94 | 95 | Where: 96 | 97 | * TE = Total Embodied Emissions, the sum of LCA emissions for all hardware components associated with the application server. 98 | * TR = Time Reserved, the length of time the hardware is reserved for use by the software. 99 | * EL = Expected Lifespan, the anticipated time that the equipment will be installed. 100 | * RR = Resources Reserved, the number of resources reserved for use by the software. 101 | * TR = Total Resources, the total number of resources available. 102 | 103 | For this component: 104 | 105 | * TE: We will source the embodied carbon estimates for the servers from the [Cloud Carbon Footprint Coefficient](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/output/coefficients-azure-embodied.csv) Data Set. 106 | * TR: 1 hr. 107 | * EL: We will assume a 4 year lifespan or 35,040 hrs. 108 | * RR: A virtual machine with 2 vCPUs was used, this data was sourced from [Cloud Carbon Footprint Azure Instances Coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/azure-instances.csv). 109 | * TR: The bare metal host is split up into 16 vCPUs in total. This data was sourced from the [Cloud Carbon Footprint Azure Instances Coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/azure-instances.csv). 110 | 111 | ### Database server for Web application 112 | 113 | The database server used for the load test is Standard Gen 5 2 vCore 10 GB RAM machine from Azure SQL 114 | 115 | 116 | ### Energy (`E`) 117 | 118 | The Quantification method used for calculating energy value is **Calculate**. We are measuring CPU utilization of the database servers and then using a model based on the Thermal Design Power (TDP) of the processors, number of cores etc to **estimate** the power consumption. 119 | 120 | The equation used to model the energy consumption is: 121 | 122 | P[kwH] = (Power consumed by CPU or Pc Number of cores + Power consumed by Memory or Pr + Power consumed by GPU or Pg Number of GPUs)/1000 123 | 124 | * CPU Utilization doesn’t scale linearly with power consumption, we will use the power curve as described in the [SCI Data Project “[E] Energy Estimation from Utilization Model” model](https://docs.google.com/spreadsheets/d/1Viv94rMKH-fJrfD9Nn9_qkiAg1PDfIfJUAHRX9slG7A/edit#gid=526989613) 125 | * TDP of server used in Azure SQL server [Gen 5](https://azure.microsoft.com/en-us/pricing/details/azure-sql-database/single/#pricing) configuration - Intel SP8160 (Skylake)= 150 W ( [https://ark.intel.com/content/www/us/en/ark/products/192482/intel-xeon-platinum-8270-processor-35-75m-cache-2-70-ghz.html](https://www.intel.com/content/www/us/en/products/sku/120501/intel-xeon-platinum-8160-processor-33m-cache-2-10-ghz/specifications.html)) 126 | * From specs, we found that Power consumed by 4GB memory is close to 1.45 W and that by 10 GB memory is approximately 4 W. Also from this [article](https://medium.com/teads-engineering/estimating-aws-ec2-instances-power-consumption-c9745e347959) we can consider power consumed is approx 0.38 W/GB or close to 2.6 Watts.Since the energy values for memory are much lower than the calculated energy values for processors or CPUs, we consider these values negligible. Pr ~0 127 | * No GPU was used hence Pg ~0 128 | 129 | 130 | ### Carbon Intensity (`I`) 131 | 132 | * We will use regional yearly averages. 133 | * The region the application was run in was India. 134 | * We will source the Carbon Intensity from the SCI Data project and the [[I] Regional Yearly Marginal Carbon Intensity](https://docs.google.com/spreadsheets/d/1Viv94rMKH-fJrfD9Nn9_qkiAg1PDfIfJUAHRX9slG7A/edit#gid=1582216595) data set. 135 | 136 | ### Embodied Carbon (`M`) 137 | 138 | The equation to calculate `M = TE * (TR/EL) * (RR/TR)` 139 | 140 | Where: 141 | 142 | * TE = Total Embodied Emissions, the sum of LCA emissions for all hardware components associated with the database server. 143 | * TR = Time Reserved, the length of time the hardware is reserved for use by the software. 144 | * EL = Expected Lifespan, the anticipated time that the equipment will be installed. 145 | * RR = Resources Reserved, the number of resources reserved for use by the software. 146 | * TR = Total Resources, the total number of resources available. 147 | 148 | For this component: 149 | 150 | * TE: We will source the embodied carbon estimates for the servers from the [Cloud Carbon Footprint Coefficient](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/output/coefficients-azure-embodied.csv) Data Set. 151 | * TR: 1 hr. 152 | * EL: We will assume a 4 year lifespan or 35,040 hrs. 153 | * RR: A virtual machine with 2 vCPUs was used, this data was sourced from [Cloud Carbon Footprint Azure Instances Coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/azure-instances.csv). 154 | * TR: The bare metal host is split up into 16 vCPUs in total. This data was sourced from the [Cloud Carbon Footprint Azure Instances Coefficients](https://github.com/cloud-carbon-footprint/cloud-carbon-coefficients/blob/main/data/azure-instances.csv). 155 | 156 | ## (Quantify) SCI Value Calculation 157 | 158 | *Show your work! For each of the components of your software system, show how you arrived at the SCI value. Guidance for this is available in the [Methodology summary](https://github.com/Green-Software-Foundation/software_carbon_intensity/blob/main/Software_Carbon_Intensity/Software_Carbon_Intensity_Specification.md#methodology-summary) section. 159 | * 160 | 161 | 162 | ### App server for Web application 163 | 164 | #### Energy (`E`) 165 | 166 | _The workings of E, include raw numbers and calculations._ 167 | 168 | - Server utilization = 18.3922% 169 | - Number of hours = 1 170 | - Number of cores = 2 171 | - TDP = 205W 172 | - TDP Coefficient = 0.32 173 | 174 | ``` 175 | E = Server utilization * Number of hours * Number of cores * TDP * TDP co-efficient 176 | = (0.18 * 1 hour * 2 cores * 205 TDP * 0.32 TDP co-efficient)/1000 177 | = 0.023 178 | ``` 179 | 180 | E = **0.023 KwH** for a 1 hour period 181 | 182 | ### Carbon Intensity (`I`) 183 | 184 | I = **951 gCO2e/kWh** 185 | 186 | ### Embodied Carbon (`M`) 187 | 188 | `M = TE * (TR/EL) * (RR/TR)` 189 | 190 | - TE = 1205.52 kgCo2e 191 | - TR = 1 hour 192 | - EL = 35040 193 | - RR = 2 194 | - TR = 16 195 | 196 | M = 1205.52 * (1/35040) * (2/16) = 0.004305 KG =~ **4.305 gCO2e** 197 | 198 | ### SCI 199 | 200 | _The sum of the SCI calculation._ 201 | 202 | SCI = (E * I) + M = (0.02394 KwH * 951 gCO2e/kwH) + 4.305 gCO2e = **26.178 gCO2e** 203 | 204 | ### Database server for Web application 205 | 206 | #### Energy (`E`) 207 | 208 | _The workings of E, include raw numbers and calculations._ 209 | 210 | - Server utilization = 10% 211 | - Number of hours = 1 212 | - Number of cores = 2 213 | - TDP = 150W 214 | - TDP Coefficient = 0.32 215 | 216 | ``` 217 | E = Server utilization * Number of hours * Number of cores * TDP * TDP co-efficient 218 | = (0.10 * 1 hour * 2 cores * 150 TDP * 0.32 TDP co-efficient)/1000 219 | = 0.0096 220 | ``` 221 | 222 | E = **0.0096 KwH** for a 1 hour period 223 | 224 | ### Carbon Intensity (`I`) 225 | 226 | I = **951 gCO2e/kWh** 227 | 228 | ### Embodied Carbon (`M`) 229 | 230 | `M = TE * (TR/EL) * (RR/TR)` 231 | 232 | - TE = 1433.12 kgCo2e 233 | - TR = 1 hour 234 | - EL = 35040 235 | - RR = 2 236 | - TR = 16 237 | 238 | M = 1433.12 * (1/35040) * (2/16) = 0.005112 KG =~ **5.112 gCO2e** 239 | 240 | ### SCI 241 | 242 | _The sum of the SCI calculation._ 243 | 244 | SCI = (E * I) + M = (0.0096 KwH * 951 gCO2e/kwH) + 5.112 gCO2e = **14.2416 gCO2e** 245 | 246 | 247 | 248 | ## SCI Total 249 | 250 | _The total SCI for the whole application._ 251 | 252 | SCI = SCI(App server for Web application) + SCI for database server = **40.4196 gCO2e** 253 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Software Carbon Intensity (SCI) Specification 8 | 9 | 10 | 11 | 12 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |

42 | 43 | Software Carbon Intensity (SCI) Specification

44 | 49 | Introduction

Software systems cause emissions through the hardware that they operate on, both through the energy that the physical hardware consumes and the emissions associated with manufacturing the hardware. This specification defines a methodology for calculating the rate of carbon emissions for a software system. The purpose is to help users and developers make informed choices about which tools, approaches, architectures, and services they use in the future. It is a score rather than a total; lower numbers are better than higher numbers, and reaching 0 is impossible. This specification is focused on helping users and developers understand how to improve software to reduce or avoid the creation of emissions.

50 |

Reducing an SCI score is only possible through the elimination of emissions. That can be achieved by modifying a software system to use less physical hardware, less energy, or consume lower-carbon energy sources. Neutralization or avoidance offsets do not reduce an SCI score (see exclusions section). This makes the SCI an ideal strategy that organizations can adopt to meet climate targets focused on eliminating emissions, such as those specified by [1].

51 |

The SCI is for everyone. It is possible to calculate an SCI score for any software application, from a large, distributed cloud system to a small monolithic open source library, any on-premise application, or even a serverless function. The environment the product or service is running in can also vary; from personal computers, private data centers or a hyperscale cloud.

52 |

Software practitioners have a significant role to play in collectively reducing the SCI score during the design, development, and delivery of software applications. The following list provides some strategies that can be used to do this across different software roles:

53 |
    54 |
  • For a software programmer, this implies writing energy efficient code.
  • 55 |
  • For an AI/ML developer, it implies model optimization, using pre-trained models or leveraging optimized hardware for training.
  • 56 |
  • For a database engineer, this comprises choices like schema design, choice of storage, and query optimizations.
  • 57 |
  • For a DevOps practitioner, this requires creating a carbon-aware pipeline and considering when to schedule builds and leverage clean energy.
  • 58 |
  • For QA engineers, it involves creating energy efficient test automation and performance testing scripts across browsers and devices.
  • 59 |
  • For an architect, this implies choices like serverless or event driven architectures, infrastructure optimization, and design for carbon-aware systems.
  • 60 |
61 |

The SCI encourages calculation using granular real-world data, which is challenging to obtain in some environments, particularly the public cloud. Access to the data needed for higher resolution calculations might not always be available. Where this is the case, users of this specification are strongly advised to request such data from their suppliers (be they hardware, hosting, or other).

62 |

In situations where there is a lack of access, capability, or rights to the necessary real-world data, the SCI allows for data generated through modeling, using best estimates instead.

63 |

64 | 69 | Scope

This specification describes a methodology for calculating the rate of carbon emissions for a software system; that is, its SCI score. The purpose of this score is to increase awareness and transparency of an application's sustainability credentials. The score will help software practitioners make better, evidence-based decisions during system design, development, and deployment, that will ultimately minimize carbon emissions. A reliable, consistent, fair and comparable measure allows targets to be defined during development and progress to be tracked.

70 |

71 | 76 | Terms and definitions

For the purposes of this document, the following terms and definitions apply.

77 |

ISO and IEC maintain terminological databases for use in standardization at the following addresses: 78 | - ISO Online browsing platform: available at https://www.iso.org/obp 79 | - IEC Electropedia: available at http://www.electropedia.org/

80 |

T.1
action
explicit outcome taken, or change avoided, depending on the quantifiable emissions measured by this specification

81 |

Note to entry: Actions generally relate to using less electricity, using electricity more intelligently, or using less hardware.

82 |

T.2
carbon-aware
attribute of software or hardware that adjusts its behavior (consumption of inputs, processing, or production of outputs) in response to the carbon intensity of the energy it consumes

83 |

The following abbreviations are used throughout this specification: 84 | - E – Energy consumed by a software system 85 | - I – Region-specific carbon intensity 86 | - M – Embodied emissions of the hardware needed to operate a software system 87 | - O – Operational emissions based on the emissions caused by energy consumption 88 | - R – Functional unit

89 |

T.3 90 | carbon
Greenhouse gases are a group of gases contributing to global warming. In this specification we use 'carbon' as a broad term to refer to the impact of all types of emissions and activities on global warming.

91 |

92 | 97 | Software sustainability actions

All actions that serve to reduce the carbon emissions of a piece of software fit into one of the following categories:

98 |
    99 |
  • Energy Efficiency: Actions taken to make software use less electricity to perform the same function.
  • 100 |
  • Hardware Efficiency: Actions taken to make software use fewer physical resources to perform the same function.
  • 101 |
  • Carbon Awareness: Actions taken to time- or region-shift software computation to take advantage of cleaner, more renewable or lower carbon sources of electricity.
  • 102 |
103 |

It is the intent of this specification to encourage more of these actions to be taken during the design, development, and maintenance of software applications.

104 |

105 | 110 | Procedure

The steps required to calculate and report an SCI score are:

111 |
    112 |
  1. Bound: Decide on the software boundary; i.e., the components of a software system to include.
  2. 113 |
  3. Scale: As the SCI is a rate (carbon emissions per one functional unit), pick the functional unit which best describes how the application scales.
  4. 114 |
  5. Define: For each software component listed in the software boundary, decide on the quantification method; real-world measurements, based on telemetry, or lab-based measurements, based on models.
  6. 115 |
  7. Quantify: Calculate a rate for every software component. The SCI value of the whole application is the sum of the SCI values for every software component in the system.
  8. 116 |
  9. Report: Disclose the SCI score, software boundary, and the calculation methodology.
  10. 117 |
118 |

119 | 124 | Methodology summary

125 | 130 | General

SCI is a rate; carbon emissions per one unit of R. The equation used to calculate the SCI value of a software system is:

131 |

SCI = C per R

132 |

Where:

133 |
    134 |
  • The total amount of carbon C the software causes to be emitted.
  • 135 |
  • All the elements in the SCI equation scale by the same functional unit of R (e.g., carbon emissions per additional user, API-call, or ML training run).
  • 136 |
137 |

This can be expanded to:

138 |

SCI = (O + M) per R

139 |

140 | 145 | Operational emissions

146 | 151 | General

To calculate the operational emissions associated with software, multiply the electricity consumption of the hardware the software is running on by the region-specific carbon intensity.

152 |

To calculate the operational emissions O for a software application, use the following:

153 |

O = (E * I)

154 |

155 | 160 | Energy

This is the energy consumed by a software system for a functional unit of work. This could be applied to several taxonomies:

161 |
    162 |
  • Datacenter
  • 163 |
  • Individual machine (e.g., VM/Node)
  • 164 |
  • Individual service (e.g., API call or ML training run)
  • 165 |
  • Execution of code
  • 166 |
167 |

Units: this shall be in kilowatt hours (kWh).

168 |

The energy consumption should include all energy consumed by hardware reserved or provisioned, not just the hardware actually used to meet the software needs.

169 |

170 | 175 | Region-specific carbon intensity

The carbon intensity of electricity is a measure of how much carbon (CO2eq) emissions are produced per kilowatt-hour (kWh) of electricity consumed.

176 |

Region-specific carbon intensity factors measure the grid carbon intensity of electricity in a grid region. If the electricity consumption is connected to a grid, the short run marginal, long run marginal, or average emissions grid intensity of that grid shall be used, which excludes any market-based measures. If the electricity consumption is not connected to a larger regional grid, an appropriate emissions factor for that system shall be used. From a developer perspective, only the location-based info is important in terms of the impact on eliminating carbon emissions. This excludes market-based measures and is distinct from 100% renewable energy claims.

177 |

Units: this shall be in grams of carbon per kilowatt hours (gCO2eq/kWh).

178 |

179 | 184 | Embodied emissions

Embodied carbon (otherwise referred to as “embedded carbon”) is the amount of carbon emitted during the creation and disposal of a hardware device.

185 |

When software runs on a device, a fraction of the total embodied emissions of the device is allocated to the software. This is the value of M that needs to be calculated in the SCI equation.

186 |

This fraction consists of both a time- and resource-share. The length of time that the software runs on the device determines its time-share. The percentage of the device reserved just for that application during the time-share determines that application's resource-share.

187 |

To calculate the time-share, amortize the total embodied carbon over the expected life span of the device and then extrapolate based on the time reserved for the usage. For example, if the device’s embodied carbon was 1000kg with an expected lifespan of four years and it was reserved for use for one hour, the time-share embodied emissions would be 1000 * 1/(4*365*24) or around 28g of the total.

188 |

To calculate resource-share, look at the share of total available resources reserved for use by the software. For instance, the percentage of total virtual CPUs reserved for the software is a good choice for the resource-share metric in the virtualized cloud space.

189 |

To calculate the share of M for a software application, use the equation:

190 |

M = TE * TS * RS

191 |

Where:

192 |
    193 |
  • TE = Total Embodied Emissions; the sum of Life Cycle Assessment (LCA) emissions for all hardware components.
  • 194 |
  • TS = Time-share; the share of the total life span of the hardware reserved for use by the software.
  • 195 |
  • RS = Resource-share; the share of the total available resources of the hardware reserved for use by the software.
  • 196 |
197 |

The equation can be expanded further:

198 |

M = TE * (TiR/EL) * (RR/ToR)

199 |

Where:

200 |
    201 |
  • TiR = Time Reserved; the length of time the hardware is reserved for use by the software.
  • 202 |
  • EL = Expected Lifespan; the anticipated time that the equipment will be installed.
  • 203 |
  • RR = Resources Reserved; the number of resources reserved for use by the software.
  • 204 |
  • ToR = Total Resources; the total number of resources available.
  • 205 |
206 |

An estimate of all the embodied emissions for the hardware used within the software boundary shall be included.

207 |

Simple models to estimate embodied emissions may be used; however, the most granular data possible and ideally emissions data from a device’s LCA when calculating the embodied carbon should be used.

208 |

Since the purpose of the SCI is the elimination of emissions M shall not include any market-based measures.

209 |

Units: this shall be in grams of carbon (gCO2eq).

210 |

211 | 216 | Functional unit conversion

An aggregate SCI score can be composed of multiple component SCI scores.

217 |

Then, as long as the functional unit of R is the same across all the component SCI scores, these can be summed to calculate the aggregate SCI. To sum multiple component SCI scores into one aggregate score, the functional unit R shall be the same across all components.

218 |

If the functional unit of a software component is not the same as the aggregate functional unit, then the component SCI score needs to be converted to match that of the aggregate SCI functional unit. Details of any unit conversion factors used in calculating the SCI score shall be disclosed.

219 |

220 | 225 | Software boundary

The first step in generating an SCI score is deciding what the boundaries of the software system are; i.e., what software components to include or exclude in the calculation of the SCI score.

226 |

The calculation of SCI shall include all supporting infrastructure and systems that significantly contribute to the software’s operation.

227 |

Supporting infrastructure and systems may include:

228 |
    229 |
  • compute resources
  • 230 |
  • storage
  • 231 |
  • networking equipment
  • 232 |
  • memory
  • 233 |
  • monitoring
  • 234 |
  • idle machines
  • 235 |
  • logging
  • 236 |
  • scanning
  • 237 |
  • build and deploy pipelines
  • 238 |
  • testing
  • 239 |
  • training ML models
  • 240 |
  • operations
  • 241 |
  • backup
  • 242 |
  • resources to support redundancy
  • 243 |
  • resources to support failover
  • 244 |
  • End user devices
  • 245 |
  • IoT devices
  • 246 |
  • Edge devices
  • 247 |
248 |

If the boundary includes on-premise and/or cloud data center operations, E should take into account the efficiency of the data center, including cooling and other energy consumption necessary to operate a data center. The data center's energy efficiency is usually available as a PUE (Power Usage Effectiveness) value.

249 |

250 | 255 | Functional unit

The second step in generating an SCI score is deciding which functional unit will be used to describe how the application scales. First, decide on the functional unit, using the choice of R. Then calculate how much C is emitted per unit of R.

256 |

For instance, if the application scales by number of users then choose this as the functional unit.

257 |

A consistent choice of R across all the components in the software boundary shall be used.

258 |

A suggested list of functional units includes:

259 |
    260 |
  • API call/request
  • 261 |
  • Benchmark
  • 262 |
  • User
  • 263 |
  • Machine
  • 264 |
  • Minute/time unit
  • 265 |
  • Device
  • 266 |
  • Physical site
  • 267 |
  • Data volume
  • 268 |
  • Batch/Scheduled Job
  • 269 |
  • Transaction
  • 270 |
  • Database read/write
  • 271 |
272 |

273 | 278 | Quantification method

279 | 284 | General

The third step in generating an SCI score is deciding the approach to take when quantifying the carbon emissions for each component in the software boundary.

285 |

The goal of the SCI is to quantify how much C (carbon) is emitted per one unit of R.

286 |

There are two main approaches to quantifying carbon emissions (C), measurement via real-world data or calculation via models.

287 |

Each component in the software boundary may use either measurement or calculation to quantify the carbon emissions.

288 |

It is strongly advised that suppliers (be they hardware, hosting, or other) be contacted regarding the data needed in the resolution required for quantifying the SCI score.

289 |

290 | 295 | Measurement

Carbon emissions may be quantified by measuring the total real-world carbon emissions of the component (C) over a time period and dividing by the number of functional units (R) in the same time period to get C per R. For instance, data regarding the real-world usage of the application "in the wild" might be measured and then divided by the number of users serviced in the same time period to get C per user.

296 |

297 | 302 | Calculation

What one unit of R looks like may be modelled and the total carbon (C) calculated for executing one functional unit of work (R) in a controlled lab environment. For instance, a benchmark application may be created that models a user interacting with your application and then measure the C emitted per run of that benchmark. The result is still a C per user.

303 |

304 | 309 | Comparing an SCI score to a baseline

When taking an action to reduce the carbon intensity of a piece of software, the intensity should be compared to a baseline. The baseline shall be calculated using an identical methodology to how the proposed SCI was calculated, except excluding the proposed action(s). The measurements, assumptions, models, functional units, etc. shall remain the same between the baseline and proposed SCI.

310 |

311 | 316 | Core characteristics

As this specification develops, the following core characteristics shall remain true:

317 |
    318 |
  • The SCI is sensitive to carbon awareness, energy efficiency, and hardware efficiency

    319 |
      320 |
    • The purpose of the SCI is to encourage actions that reduce the carbon emissions of software. Therefore, the SCI shall be sensitive to those actions described in this document under Software Sustainability Actions; specifically, carbon awareness, energy efficiency, and hardware efficiency.
    • 321 |
    • If an application's SCI is X, and then actions are taken to make the application more carbon aware, more energy efficient, or more hardware efficient, the value of X shall go down.
    • 322 |
    323 |
  • 324 |
  • The SCI takes a systems-impact view

    325 |
      326 |
    • The purpose of the SCI is to encourage actions that reduce carbon emissions of software in a way that creates reductions at a system-wide level rather than just at a local level. Local-level optimizations may lead to micro improvements but may have negative downstream impacts at a macro level that negate the impact of those actions.
    • 327 |
    • Such a systems view shall be adopted by articulating the boundaries of the software and its associated infrastructure, keeping in mind the exclusions mentioned in this specification.
    • 328 |
    329 |
  • 330 |
  • The SCI is easy to implement
    To achieve impact at scale, the SCI encourages adoption through ease of implementation.

    331 |
      332 |
    • Anyone without much experience or training shall be able to follow the SCI specification instructions.
    • 333 |
    • Calculation of the SCI shall be possible without incurring any cost, for instance, for data, services, or tooling.
    • 334 |
    • Where possible, teams should consider investing more time or money in calculating their SCI number to increase its accuracy.
    • 335 |
    336 |
  • 337 |
  • The SCI encourages the use of granular data
    In calculating the SCI value, the highest granularity data available should be used to compute each of O, E, I, and M. In cases where temporal granular data is not available, annual values shall be used which are the lowest acceptable level of granularity.

    338 |
  • 339 |
340 |

341 | 346 | Exclusions

347 | 352 | General

The focus is elimination, not offsetting. One tonne of carbon eliminated (meaning that it was not emitted into the atmosphere) is not the same as one tonne of carbon that has been offset. By far the more preferable goal is never to have emitted the carbon in the first place.

353 |

Only actions that eliminate emissions reduce an SCI score. As such, an SCI score cannot be reduced through carbon offsets, such as market-based measures.

354 |

355 | 360 | Market-based measures

Market-based measures are financial instruments designed to neutralize or offset carbon emissions. Market-based measures include, but are not limited to the following:

361 |
    362 |
  • Carbon offsets or credits
  • 363 |
  • A Removal Unit (RMU)
  • 364 |
  • An Emission Reduction Unit (ERU)
  • 365 |
  • A Certified Emission Reduction (CER)
  • 366 |
  • Electricity Attribute Certificates (EACs)
  • 367 |
  • Power Purchase Agreements (PPAs)
  • 368 |
  • Renewable Energy Credits (RECs)
  • 369 |
370 |

371 | 376 | Bibliography

The following documents are useful references for implementers and users of this document:

377 |

[1] The Net-Zero STANDARD, Science Based Targets initiative (SBTi), https://sciencebasedtargets.org/net-zero

378 |
379 | 391 | 392 | 393 | 394 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sci", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "sci", 9 | "version": "1.0.0", 10 | "devDependencies": { 11 | "@tailwindcss/typography": "^0.5.10", 12 | "gray-matter": "^4.0.3", 13 | "marked": "^9.0.0", 14 | "nodemon": "^3.0.1", 15 | "tailwindcss": "^3.3.3" 16 | } 17 | }, 18 | "node_modules/@alloc/quick-lru": { 19 | "version": "5.2.0", 20 | "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", 21 | "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", 22 | "dev": true, 23 | "engines": { 24 | "node": ">=10" 25 | }, 26 | "funding": { 27 | "url": "https://github.com/sponsors/sindresorhus" 28 | } 29 | }, 30 | "node_modules/@jridgewell/gen-mapping": { 31 | "version": "0.3.3", 32 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 33 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 34 | "dev": true, 35 | "dependencies": { 36 | "@jridgewell/set-array": "^1.0.1", 37 | "@jridgewell/sourcemap-codec": "^1.4.10", 38 | "@jridgewell/trace-mapping": "^0.3.9" 39 | }, 40 | "engines": { 41 | "node": ">=6.0.0" 42 | } 43 | }, 44 | "node_modules/@jridgewell/resolve-uri": { 45 | "version": "3.1.1", 46 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", 47 | "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", 48 | "dev": true, 49 | "engines": { 50 | "node": ">=6.0.0" 51 | } 52 | }, 53 | "node_modules/@jridgewell/set-array": { 54 | "version": "1.1.2", 55 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 56 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 57 | "dev": true, 58 | "engines": { 59 | "node": ">=6.0.0" 60 | } 61 | }, 62 | "node_modules/@jridgewell/sourcemap-codec": { 63 | "version": "1.4.15", 64 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 65 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", 66 | "dev": true 67 | }, 68 | "node_modules/@jridgewell/trace-mapping": { 69 | "version": "0.3.19", 70 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", 71 | "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", 72 | "dev": true, 73 | "dependencies": { 74 | "@jridgewell/resolve-uri": "^3.1.0", 75 | "@jridgewell/sourcemap-codec": "^1.4.14" 76 | } 77 | }, 78 | "node_modules/@nodelib/fs.scandir": { 79 | "version": "2.1.5", 80 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 81 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 82 | "dev": true, 83 | "dependencies": { 84 | "@nodelib/fs.stat": "2.0.5", 85 | "run-parallel": "^1.1.9" 86 | }, 87 | "engines": { 88 | "node": ">= 8" 89 | } 90 | }, 91 | "node_modules/@nodelib/fs.stat": { 92 | "version": "2.0.5", 93 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 94 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 95 | "dev": true, 96 | "engines": { 97 | "node": ">= 8" 98 | } 99 | }, 100 | "node_modules/@nodelib/fs.walk": { 101 | "version": "1.2.8", 102 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 103 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 104 | "dev": true, 105 | "dependencies": { 106 | "@nodelib/fs.scandir": "2.1.5", 107 | "fastq": "^1.6.0" 108 | }, 109 | "engines": { 110 | "node": ">= 8" 111 | } 112 | }, 113 | "node_modules/@tailwindcss/typography": { 114 | "version": "0.5.10", 115 | "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", 116 | "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", 117 | "dev": true, 118 | "dependencies": { 119 | "lodash.castarray": "^4.4.0", 120 | "lodash.isplainobject": "^4.0.6", 121 | "lodash.merge": "^4.6.2", 122 | "postcss-selector-parser": "6.0.10" 123 | }, 124 | "peerDependencies": { 125 | "tailwindcss": ">=3.0.0 || insiders" 126 | } 127 | }, 128 | "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { 129 | "version": "6.0.10", 130 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 131 | "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 132 | "dev": true, 133 | "dependencies": { 134 | "cssesc": "^3.0.0", 135 | "util-deprecate": "^1.0.2" 136 | }, 137 | "engines": { 138 | "node": ">=4" 139 | } 140 | }, 141 | "node_modules/abbrev": { 142 | "version": "1.1.1", 143 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", 144 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", 145 | "dev": true 146 | }, 147 | "node_modules/any-promise": { 148 | "version": "1.3.0", 149 | "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", 150 | "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", 151 | "dev": true 152 | }, 153 | "node_modules/anymatch": { 154 | "version": "3.1.3", 155 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", 156 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", 157 | "dev": true, 158 | "dependencies": { 159 | "normalize-path": "^3.0.0", 160 | "picomatch": "^2.0.4" 161 | }, 162 | "engines": { 163 | "node": ">= 8" 164 | } 165 | }, 166 | "node_modules/arg": { 167 | "version": "5.0.2", 168 | "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", 169 | "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", 170 | "dev": true 171 | }, 172 | "node_modules/argparse": { 173 | "version": "1.0.10", 174 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 175 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 176 | "dev": true, 177 | "dependencies": { 178 | "sprintf-js": "~1.0.2" 179 | } 180 | }, 181 | "node_modules/balanced-match": { 182 | "version": "1.0.2", 183 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 184 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 185 | "dev": true 186 | }, 187 | "node_modules/binary-extensions": { 188 | "version": "2.2.0", 189 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", 190 | "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", 191 | "dev": true, 192 | "engines": { 193 | "node": ">=8" 194 | } 195 | }, 196 | "node_modules/brace-expansion": { 197 | "version": "1.1.11", 198 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 199 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 200 | "dev": true, 201 | "dependencies": { 202 | "balanced-match": "^1.0.0", 203 | "concat-map": "0.0.1" 204 | } 205 | }, 206 | "node_modules/braces": { 207 | "version": "3.0.2", 208 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 209 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 210 | "dev": true, 211 | "dependencies": { 212 | "fill-range": "^7.0.1" 213 | }, 214 | "engines": { 215 | "node": ">=8" 216 | } 217 | }, 218 | "node_modules/camelcase-css": { 219 | "version": "2.0.1", 220 | "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", 221 | "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", 222 | "dev": true, 223 | "engines": { 224 | "node": ">= 6" 225 | } 226 | }, 227 | "node_modules/chokidar": { 228 | "version": "3.5.3", 229 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", 230 | "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", 231 | "dev": true, 232 | "funding": [ 233 | { 234 | "type": "individual", 235 | "url": "https://paulmillr.com/funding/" 236 | } 237 | ], 238 | "dependencies": { 239 | "anymatch": "~3.1.2", 240 | "braces": "~3.0.2", 241 | "glob-parent": "~5.1.2", 242 | "is-binary-path": "~2.1.0", 243 | "is-glob": "~4.0.1", 244 | "normalize-path": "~3.0.0", 245 | "readdirp": "~3.6.0" 246 | }, 247 | "engines": { 248 | "node": ">= 8.10.0" 249 | }, 250 | "optionalDependencies": { 251 | "fsevents": "~2.3.2" 252 | } 253 | }, 254 | "node_modules/chokidar/node_modules/glob-parent": { 255 | "version": "5.1.2", 256 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 257 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 258 | "dev": true, 259 | "dependencies": { 260 | "is-glob": "^4.0.1" 261 | }, 262 | "engines": { 263 | "node": ">= 6" 264 | } 265 | }, 266 | "node_modules/commander": { 267 | "version": "4.1.1", 268 | "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", 269 | "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", 270 | "dev": true, 271 | "engines": { 272 | "node": ">= 6" 273 | } 274 | }, 275 | "node_modules/concat-map": { 276 | "version": "0.0.1", 277 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 278 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", 279 | "dev": true 280 | }, 281 | "node_modules/cssesc": { 282 | "version": "3.0.0", 283 | "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", 284 | "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", 285 | "dev": true, 286 | "bin": { 287 | "cssesc": "bin/cssesc" 288 | }, 289 | "engines": { 290 | "node": ">=4" 291 | } 292 | }, 293 | "node_modules/debug": { 294 | "version": "3.2.7", 295 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", 296 | "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", 297 | "dev": true, 298 | "dependencies": { 299 | "ms": "^2.1.1" 300 | } 301 | }, 302 | "node_modules/didyoumean": { 303 | "version": "1.2.2", 304 | "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", 305 | "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", 306 | "dev": true 307 | }, 308 | "node_modules/dlv": { 309 | "version": "1.1.3", 310 | "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", 311 | "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", 312 | "dev": true 313 | }, 314 | "node_modules/esprima": { 315 | "version": "4.0.1", 316 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 317 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 318 | "dev": true, 319 | "bin": { 320 | "esparse": "bin/esparse.js", 321 | "esvalidate": "bin/esvalidate.js" 322 | }, 323 | "engines": { 324 | "node": ">=4" 325 | } 326 | }, 327 | "node_modules/extend-shallow": { 328 | "version": "2.0.1", 329 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 330 | "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", 331 | "dev": true, 332 | "dependencies": { 333 | "is-extendable": "^0.1.0" 334 | }, 335 | "engines": { 336 | "node": ">=0.10.0" 337 | } 338 | }, 339 | "node_modules/fast-glob": { 340 | "version": "3.3.1", 341 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", 342 | "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", 343 | "dev": true, 344 | "dependencies": { 345 | "@nodelib/fs.stat": "^2.0.2", 346 | "@nodelib/fs.walk": "^1.2.3", 347 | "glob-parent": "^5.1.2", 348 | "merge2": "^1.3.0", 349 | "micromatch": "^4.0.4" 350 | }, 351 | "engines": { 352 | "node": ">=8.6.0" 353 | } 354 | }, 355 | "node_modules/fast-glob/node_modules/glob-parent": { 356 | "version": "5.1.2", 357 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 358 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 359 | "dev": true, 360 | "dependencies": { 361 | "is-glob": "^4.0.1" 362 | }, 363 | "engines": { 364 | "node": ">= 6" 365 | } 366 | }, 367 | "node_modules/fastq": { 368 | "version": "1.15.0", 369 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", 370 | "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", 371 | "dev": true, 372 | "dependencies": { 373 | "reusify": "^1.0.4" 374 | } 375 | }, 376 | "node_modules/fill-range": { 377 | "version": "7.0.1", 378 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 379 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 380 | "dev": true, 381 | "dependencies": { 382 | "to-regex-range": "^5.0.1" 383 | }, 384 | "engines": { 385 | "node": ">=8" 386 | } 387 | }, 388 | "node_modules/fs.realpath": { 389 | "version": "1.0.0", 390 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 391 | "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", 392 | "dev": true 393 | }, 394 | "node_modules/fsevents": { 395 | "version": "2.3.3", 396 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", 397 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", 398 | "dev": true, 399 | "hasInstallScript": true, 400 | "optional": true, 401 | "os": [ 402 | "darwin" 403 | ], 404 | "engines": { 405 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 406 | } 407 | }, 408 | "node_modules/function-bind": { 409 | "version": "1.1.1", 410 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 411 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 412 | "dev": true 413 | }, 414 | "node_modules/glob": { 415 | "version": "7.1.6", 416 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", 417 | "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", 418 | "dev": true, 419 | "dependencies": { 420 | "fs.realpath": "^1.0.0", 421 | "inflight": "^1.0.4", 422 | "inherits": "2", 423 | "minimatch": "^3.0.4", 424 | "once": "^1.3.0", 425 | "path-is-absolute": "^1.0.0" 426 | }, 427 | "engines": { 428 | "node": "*" 429 | }, 430 | "funding": { 431 | "url": "https://github.com/sponsors/isaacs" 432 | } 433 | }, 434 | "node_modules/glob-parent": { 435 | "version": "6.0.2", 436 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 437 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 438 | "dev": true, 439 | "dependencies": { 440 | "is-glob": "^4.0.3" 441 | }, 442 | "engines": { 443 | "node": ">=10.13.0" 444 | } 445 | }, 446 | "node_modules/gray-matter": { 447 | "version": "4.0.3", 448 | "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", 449 | "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", 450 | "dev": true, 451 | "dependencies": { 452 | "js-yaml": "^3.13.1", 453 | "kind-of": "^6.0.2", 454 | "section-matter": "^1.0.0", 455 | "strip-bom-string": "^1.0.0" 456 | }, 457 | "engines": { 458 | "node": ">=6.0" 459 | } 460 | }, 461 | "node_modules/has": { 462 | "version": "1.0.3", 463 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 464 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 465 | "dev": true, 466 | "dependencies": { 467 | "function-bind": "^1.1.1" 468 | }, 469 | "engines": { 470 | "node": ">= 0.4.0" 471 | } 472 | }, 473 | "node_modules/has-flag": { 474 | "version": "3.0.0", 475 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 476 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 477 | "dev": true, 478 | "engines": { 479 | "node": ">=4" 480 | } 481 | }, 482 | "node_modules/ignore-by-default": { 483 | "version": "1.0.1", 484 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", 485 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", 486 | "dev": true 487 | }, 488 | "node_modules/inflight": { 489 | "version": "1.0.6", 490 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 491 | "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", 492 | "dev": true, 493 | "dependencies": { 494 | "once": "^1.3.0", 495 | "wrappy": "1" 496 | } 497 | }, 498 | "node_modules/inherits": { 499 | "version": "2.0.4", 500 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 501 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", 502 | "dev": true 503 | }, 504 | "node_modules/is-binary-path": { 505 | "version": "2.1.0", 506 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", 507 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", 508 | "dev": true, 509 | "dependencies": { 510 | "binary-extensions": "^2.0.0" 511 | }, 512 | "engines": { 513 | "node": ">=8" 514 | } 515 | }, 516 | "node_modules/is-core-module": { 517 | "version": "2.13.0", 518 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", 519 | "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", 520 | "dev": true, 521 | "dependencies": { 522 | "has": "^1.0.3" 523 | }, 524 | "funding": { 525 | "url": "https://github.com/sponsors/ljharb" 526 | } 527 | }, 528 | "node_modules/is-extendable": { 529 | "version": "0.1.1", 530 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 531 | "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", 532 | "dev": true, 533 | "engines": { 534 | "node": ">=0.10.0" 535 | } 536 | }, 537 | "node_modules/is-extglob": { 538 | "version": "2.1.1", 539 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 540 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", 541 | "dev": true, 542 | "engines": { 543 | "node": ">=0.10.0" 544 | } 545 | }, 546 | "node_modules/is-glob": { 547 | "version": "4.0.3", 548 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 549 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 550 | "dev": true, 551 | "dependencies": { 552 | "is-extglob": "^2.1.1" 553 | }, 554 | "engines": { 555 | "node": ">=0.10.0" 556 | } 557 | }, 558 | "node_modules/is-number": { 559 | "version": "7.0.0", 560 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 561 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", 562 | "dev": true, 563 | "engines": { 564 | "node": ">=0.12.0" 565 | } 566 | }, 567 | "node_modules/jiti": { 568 | "version": "1.20.0", 569 | "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz", 570 | "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==", 571 | "dev": true, 572 | "bin": { 573 | "jiti": "bin/jiti.js" 574 | } 575 | }, 576 | "node_modules/js-yaml": { 577 | "version": "3.14.1", 578 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", 579 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", 580 | "dev": true, 581 | "dependencies": { 582 | "argparse": "^1.0.7", 583 | "esprima": "^4.0.0" 584 | }, 585 | "bin": { 586 | "js-yaml": "bin/js-yaml.js" 587 | } 588 | }, 589 | "node_modules/kind-of": { 590 | "version": "6.0.3", 591 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", 592 | "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", 593 | "dev": true, 594 | "engines": { 595 | "node": ">=0.10.0" 596 | } 597 | }, 598 | "node_modules/lilconfig": { 599 | "version": "2.1.0", 600 | "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", 601 | "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", 602 | "dev": true, 603 | "engines": { 604 | "node": ">=10" 605 | } 606 | }, 607 | "node_modules/lines-and-columns": { 608 | "version": "1.2.4", 609 | "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", 610 | "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", 611 | "dev": true 612 | }, 613 | "node_modules/lodash.castarray": { 614 | "version": "4.4.0", 615 | "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", 616 | "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", 617 | "dev": true 618 | }, 619 | "node_modules/lodash.isplainobject": { 620 | "version": "4.0.6", 621 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 622 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", 623 | "dev": true 624 | }, 625 | "node_modules/lodash.merge": { 626 | "version": "4.6.2", 627 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 628 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 629 | "dev": true 630 | }, 631 | "node_modules/lru-cache": { 632 | "version": "6.0.0", 633 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 634 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 635 | "dev": true, 636 | "dependencies": { 637 | "yallist": "^4.0.0" 638 | }, 639 | "engines": { 640 | "node": ">=10" 641 | } 642 | }, 643 | "node_modules/marked": { 644 | "version": "9.0.0", 645 | "resolved": "https://registry.npmjs.org/marked/-/marked-9.0.0.tgz", 646 | "integrity": "sha512-37yoTpjU+TSXb9OBYY5n78z/CqXh76KiQj9xsKxEdztzU9fRLmbWO5YqKxgCVGKlNdexppnbKTkwB3RipVri8w==", 647 | "dev": true, 648 | "bin": { 649 | "marked": "bin/marked.js" 650 | }, 651 | "engines": { 652 | "node": ">= 16" 653 | } 654 | }, 655 | "node_modules/merge2": { 656 | "version": "1.4.1", 657 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 658 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", 659 | "dev": true, 660 | "engines": { 661 | "node": ">= 8" 662 | } 663 | }, 664 | "node_modules/micromatch": { 665 | "version": "4.0.5", 666 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", 667 | "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", 668 | "dev": true, 669 | "dependencies": { 670 | "braces": "^3.0.2", 671 | "picomatch": "^2.3.1" 672 | }, 673 | "engines": { 674 | "node": ">=8.6" 675 | } 676 | }, 677 | "node_modules/minimatch": { 678 | "version": "3.1.2", 679 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 680 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 681 | "dev": true, 682 | "dependencies": { 683 | "brace-expansion": "^1.1.7" 684 | }, 685 | "engines": { 686 | "node": "*" 687 | } 688 | }, 689 | "node_modules/ms": { 690 | "version": "2.1.3", 691 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 692 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", 693 | "dev": true 694 | }, 695 | "node_modules/mz": { 696 | "version": "2.7.0", 697 | "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", 698 | "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", 699 | "dev": true, 700 | "dependencies": { 701 | "any-promise": "^1.0.0", 702 | "object-assign": "^4.0.1", 703 | "thenify-all": "^1.0.0" 704 | } 705 | }, 706 | "node_modules/nanoid": { 707 | "version": "3.3.6", 708 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 709 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 710 | "dev": true, 711 | "funding": [ 712 | { 713 | "type": "github", 714 | "url": "https://github.com/sponsors/ai" 715 | } 716 | ], 717 | "bin": { 718 | "nanoid": "bin/nanoid.cjs" 719 | }, 720 | "engines": { 721 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 722 | } 723 | }, 724 | "node_modules/nodemon": { 725 | "version": "3.0.1", 726 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", 727 | "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", 728 | "dev": true, 729 | "dependencies": { 730 | "chokidar": "^3.5.2", 731 | "debug": "^3.2.7", 732 | "ignore-by-default": "^1.0.1", 733 | "minimatch": "^3.1.2", 734 | "pstree.remy": "^1.1.8", 735 | "semver": "^7.5.3", 736 | "simple-update-notifier": "^2.0.0", 737 | "supports-color": "^5.5.0", 738 | "touch": "^3.1.0", 739 | "undefsafe": "^2.0.5" 740 | }, 741 | "bin": { 742 | "nodemon": "bin/nodemon.js" 743 | }, 744 | "engines": { 745 | "node": ">=10" 746 | }, 747 | "funding": { 748 | "type": "opencollective", 749 | "url": "https://opencollective.com/nodemon" 750 | } 751 | }, 752 | "node_modules/nopt": { 753 | "version": "1.0.10", 754 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", 755 | "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", 756 | "dev": true, 757 | "dependencies": { 758 | "abbrev": "1" 759 | }, 760 | "bin": { 761 | "nopt": "bin/nopt.js" 762 | }, 763 | "engines": { 764 | "node": "*" 765 | } 766 | }, 767 | "node_modules/normalize-path": { 768 | "version": "3.0.0", 769 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", 770 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", 771 | "dev": true, 772 | "engines": { 773 | "node": ">=0.10.0" 774 | } 775 | }, 776 | "node_modules/object-assign": { 777 | "version": "4.1.1", 778 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 779 | "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", 780 | "dev": true, 781 | "engines": { 782 | "node": ">=0.10.0" 783 | } 784 | }, 785 | "node_modules/object-hash": { 786 | "version": "3.0.0", 787 | "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", 788 | "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", 789 | "dev": true, 790 | "engines": { 791 | "node": ">= 6" 792 | } 793 | }, 794 | "node_modules/once": { 795 | "version": "1.4.0", 796 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 797 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 798 | "dev": true, 799 | "dependencies": { 800 | "wrappy": "1" 801 | } 802 | }, 803 | "node_modules/path-is-absolute": { 804 | "version": "1.0.1", 805 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 806 | "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", 807 | "dev": true, 808 | "engines": { 809 | "node": ">=0.10.0" 810 | } 811 | }, 812 | "node_modules/path-parse": { 813 | "version": "1.0.7", 814 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 815 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 816 | "dev": true 817 | }, 818 | "node_modules/picocolors": { 819 | "version": "1.0.0", 820 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 821 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", 822 | "dev": true 823 | }, 824 | "node_modules/picomatch": { 825 | "version": "2.3.1", 826 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", 827 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", 828 | "dev": true, 829 | "engines": { 830 | "node": ">=8.6" 831 | }, 832 | "funding": { 833 | "url": "https://github.com/sponsors/jonschlinkert" 834 | } 835 | }, 836 | "node_modules/pify": { 837 | "version": "2.3.0", 838 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 839 | "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", 840 | "dev": true, 841 | "engines": { 842 | "node": ">=0.10.0" 843 | } 844 | }, 845 | "node_modules/pirates": { 846 | "version": "4.0.6", 847 | "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", 848 | "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", 849 | "dev": true, 850 | "engines": { 851 | "node": ">= 6" 852 | } 853 | }, 854 | "node_modules/postcss": { 855 | "version": "8.4.29", 856 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", 857 | "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", 858 | "dev": true, 859 | "funding": [ 860 | { 861 | "type": "opencollective", 862 | "url": "https://opencollective.com/postcss/" 863 | }, 864 | { 865 | "type": "tidelift", 866 | "url": "https://tidelift.com/funding/github/npm/postcss" 867 | }, 868 | { 869 | "type": "github", 870 | "url": "https://github.com/sponsors/ai" 871 | } 872 | ], 873 | "dependencies": { 874 | "nanoid": "^3.3.6", 875 | "picocolors": "^1.0.0", 876 | "source-map-js": "^1.0.2" 877 | }, 878 | "engines": { 879 | "node": "^10 || ^12 || >=14" 880 | } 881 | }, 882 | "node_modules/postcss-import": { 883 | "version": "15.1.0", 884 | "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", 885 | "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", 886 | "dev": true, 887 | "dependencies": { 888 | "postcss-value-parser": "^4.0.0", 889 | "read-cache": "^1.0.0", 890 | "resolve": "^1.1.7" 891 | }, 892 | "engines": { 893 | "node": ">=14.0.0" 894 | }, 895 | "peerDependencies": { 896 | "postcss": "^8.0.0" 897 | } 898 | }, 899 | "node_modules/postcss-js": { 900 | "version": "4.0.1", 901 | "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", 902 | "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", 903 | "dev": true, 904 | "dependencies": { 905 | "camelcase-css": "^2.0.1" 906 | }, 907 | "engines": { 908 | "node": "^12 || ^14 || >= 16" 909 | }, 910 | "funding": { 911 | "type": "opencollective", 912 | "url": "https://opencollective.com/postcss/" 913 | }, 914 | "peerDependencies": { 915 | "postcss": "^8.4.21" 916 | } 917 | }, 918 | "node_modules/postcss-load-config": { 919 | "version": "4.0.1", 920 | "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", 921 | "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", 922 | "dev": true, 923 | "dependencies": { 924 | "lilconfig": "^2.0.5", 925 | "yaml": "^2.1.1" 926 | }, 927 | "engines": { 928 | "node": ">= 14" 929 | }, 930 | "funding": { 931 | "type": "opencollective", 932 | "url": "https://opencollective.com/postcss/" 933 | }, 934 | "peerDependencies": { 935 | "postcss": ">=8.0.9", 936 | "ts-node": ">=9.0.0" 937 | }, 938 | "peerDependenciesMeta": { 939 | "postcss": { 940 | "optional": true 941 | }, 942 | "ts-node": { 943 | "optional": true 944 | } 945 | } 946 | }, 947 | "node_modules/postcss-nested": { 948 | "version": "6.0.1", 949 | "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", 950 | "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", 951 | "dev": true, 952 | "dependencies": { 953 | "postcss-selector-parser": "^6.0.11" 954 | }, 955 | "engines": { 956 | "node": ">=12.0" 957 | }, 958 | "funding": { 959 | "type": "opencollective", 960 | "url": "https://opencollective.com/postcss/" 961 | }, 962 | "peerDependencies": { 963 | "postcss": "^8.2.14" 964 | } 965 | }, 966 | "node_modules/postcss-selector-parser": { 967 | "version": "6.0.13", 968 | "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", 969 | "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", 970 | "dev": true, 971 | "dependencies": { 972 | "cssesc": "^3.0.0", 973 | "util-deprecate": "^1.0.2" 974 | }, 975 | "engines": { 976 | "node": ">=4" 977 | } 978 | }, 979 | "node_modules/postcss-value-parser": { 980 | "version": "4.2.0", 981 | "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", 982 | "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", 983 | "dev": true 984 | }, 985 | "node_modules/pstree.remy": { 986 | "version": "1.1.8", 987 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", 988 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", 989 | "dev": true 990 | }, 991 | "node_modules/queue-microtask": { 992 | "version": "1.2.3", 993 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 994 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 995 | "dev": true, 996 | "funding": [ 997 | { 998 | "type": "github", 999 | "url": "https://github.com/sponsors/feross" 1000 | }, 1001 | { 1002 | "type": "patreon", 1003 | "url": "https://www.patreon.com/feross" 1004 | }, 1005 | { 1006 | "type": "consulting", 1007 | "url": "https://feross.org/support" 1008 | } 1009 | ] 1010 | }, 1011 | "node_modules/read-cache": { 1012 | "version": "1.0.0", 1013 | "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", 1014 | "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", 1015 | "dev": true, 1016 | "dependencies": { 1017 | "pify": "^2.3.0" 1018 | } 1019 | }, 1020 | "node_modules/readdirp": { 1021 | "version": "3.6.0", 1022 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", 1023 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", 1024 | "dev": true, 1025 | "dependencies": { 1026 | "picomatch": "^2.2.1" 1027 | }, 1028 | "engines": { 1029 | "node": ">=8.10.0" 1030 | } 1031 | }, 1032 | "node_modules/resolve": { 1033 | "version": "1.22.4", 1034 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", 1035 | "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", 1036 | "dev": true, 1037 | "dependencies": { 1038 | "is-core-module": "^2.13.0", 1039 | "path-parse": "^1.0.7", 1040 | "supports-preserve-symlinks-flag": "^1.0.0" 1041 | }, 1042 | "bin": { 1043 | "resolve": "bin/resolve" 1044 | }, 1045 | "funding": { 1046 | "url": "https://github.com/sponsors/ljharb" 1047 | } 1048 | }, 1049 | "node_modules/reusify": { 1050 | "version": "1.0.4", 1051 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1052 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 1053 | "dev": true, 1054 | "engines": { 1055 | "iojs": ">=1.0.0", 1056 | "node": ">=0.10.0" 1057 | } 1058 | }, 1059 | "node_modules/run-parallel": { 1060 | "version": "1.2.0", 1061 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1062 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1063 | "dev": true, 1064 | "funding": [ 1065 | { 1066 | "type": "github", 1067 | "url": "https://github.com/sponsors/feross" 1068 | }, 1069 | { 1070 | "type": "patreon", 1071 | "url": "https://www.patreon.com/feross" 1072 | }, 1073 | { 1074 | "type": "consulting", 1075 | "url": "https://feross.org/support" 1076 | } 1077 | ], 1078 | "dependencies": { 1079 | "queue-microtask": "^1.2.2" 1080 | } 1081 | }, 1082 | "node_modules/section-matter": { 1083 | "version": "1.0.0", 1084 | "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", 1085 | "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", 1086 | "dev": true, 1087 | "dependencies": { 1088 | "extend-shallow": "^2.0.1", 1089 | "kind-of": "^6.0.0" 1090 | }, 1091 | "engines": { 1092 | "node": ">=4" 1093 | } 1094 | }, 1095 | "node_modules/semver": { 1096 | "version": "7.5.4", 1097 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", 1098 | "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", 1099 | "dev": true, 1100 | "dependencies": { 1101 | "lru-cache": "^6.0.0" 1102 | }, 1103 | "bin": { 1104 | "semver": "bin/semver.js" 1105 | }, 1106 | "engines": { 1107 | "node": ">=10" 1108 | } 1109 | }, 1110 | "node_modules/simple-update-notifier": { 1111 | "version": "2.0.0", 1112 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", 1113 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", 1114 | "dev": true, 1115 | "dependencies": { 1116 | "semver": "^7.5.3" 1117 | }, 1118 | "engines": { 1119 | "node": ">=10" 1120 | } 1121 | }, 1122 | "node_modules/source-map-js": { 1123 | "version": "1.0.2", 1124 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1125 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1126 | "dev": true, 1127 | "engines": { 1128 | "node": ">=0.10.0" 1129 | } 1130 | }, 1131 | "node_modules/sprintf-js": { 1132 | "version": "1.0.3", 1133 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1134 | "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", 1135 | "dev": true 1136 | }, 1137 | "node_modules/strip-bom-string": { 1138 | "version": "1.0.0", 1139 | "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", 1140 | "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", 1141 | "dev": true, 1142 | "engines": { 1143 | "node": ">=0.10.0" 1144 | } 1145 | }, 1146 | "node_modules/sucrase": { 1147 | "version": "3.34.0", 1148 | "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.34.0.tgz", 1149 | "integrity": "sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==", 1150 | "dev": true, 1151 | "dependencies": { 1152 | "@jridgewell/gen-mapping": "^0.3.2", 1153 | "commander": "^4.0.0", 1154 | "glob": "7.1.6", 1155 | "lines-and-columns": "^1.1.6", 1156 | "mz": "^2.7.0", 1157 | "pirates": "^4.0.1", 1158 | "ts-interface-checker": "^0.1.9" 1159 | }, 1160 | "bin": { 1161 | "sucrase": "bin/sucrase", 1162 | "sucrase-node": "bin/sucrase-node" 1163 | }, 1164 | "engines": { 1165 | "node": ">=8" 1166 | } 1167 | }, 1168 | "node_modules/supports-color": { 1169 | "version": "5.5.0", 1170 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1171 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1172 | "dev": true, 1173 | "dependencies": { 1174 | "has-flag": "^3.0.0" 1175 | }, 1176 | "engines": { 1177 | "node": ">=4" 1178 | } 1179 | }, 1180 | "node_modules/supports-preserve-symlinks-flag": { 1181 | "version": "1.0.0", 1182 | "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", 1183 | "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", 1184 | "dev": true, 1185 | "engines": { 1186 | "node": ">= 0.4" 1187 | }, 1188 | "funding": { 1189 | "url": "https://github.com/sponsors/ljharb" 1190 | } 1191 | }, 1192 | "node_modules/tailwindcss": { 1193 | "version": "3.3.3", 1194 | "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", 1195 | "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", 1196 | "dev": true, 1197 | "dependencies": { 1198 | "@alloc/quick-lru": "^5.2.0", 1199 | "arg": "^5.0.2", 1200 | "chokidar": "^3.5.3", 1201 | "didyoumean": "^1.2.2", 1202 | "dlv": "^1.1.3", 1203 | "fast-glob": "^3.2.12", 1204 | "glob-parent": "^6.0.2", 1205 | "is-glob": "^4.0.3", 1206 | "jiti": "^1.18.2", 1207 | "lilconfig": "^2.1.0", 1208 | "micromatch": "^4.0.5", 1209 | "normalize-path": "^3.0.0", 1210 | "object-hash": "^3.0.0", 1211 | "picocolors": "^1.0.0", 1212 | "postcss": "^8.4.23", 1213 | "postcss-import": "^15.1.0", 1214 | "postcss-js": "^4.0.1", 1215 | "postcss-load-config": "^4.0.1", 1216 | "postcss-nested": "^6.0.1", 1217 | "postcss-selector-parser": "^6.0.11", 1218 | "resolve": "^1.22.2", 1219 | "sucrase": "^3.32.0" 1220 | }, 1221 | "bin": { 1222 | "tailwind": "lib/cli.js", 1223 | "tailwindcss": "lib/cli.js" 1224 | }, 1225 | "engines": { 1226 | "node": ">=14.0.0" 1227 | } 1228 | }, 1229 | "node_modules/thenify": { 1230 | "version": "3.3.1", 1231 | "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", 1232 | "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", 1233 | "dev": true, 1234 | "dependencies": { 1235 | "any-promise": "^1.0.0" 1236 | } 1237 | }, 1238 | "node_modules/thenify-all": { 1239 | "version": "1.6.0", 1240 | "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", 1241 | "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", 1242 | "dev": true, 1243 | "dependencies": { 1244 | "thenify": ">= 3.1.0 < 4" 1245 | }, 1246 | "engines": { 1247 | "node": ">=0.8" 1248 | } 1249 | }, 1250 | "node_modules/to-regex-range": { 1251 | "version": "5.0.1", 1252 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 1253 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 1254 | "dev": true, 1255 | "dependencies": { 1256 | "is-number": "^7.0.0" 1257 | }, 1258 | "engines": { 1259 | "node": ">=8.0" 1260 | } 1261 | }, 1262 | "node_modules/touch": { 1263 | "version": "3.1.0", 1264 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", 1265 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", 1266 | "dev": true, 1267 | "dependencies": { 1268 | "nopt": "~1.0.10" 1269 | }, 1270 | "bin": { 1271 | "nodetouch": "bin/nodetouch.js" 1272 | } 1273 | }, 1274 | "node_modules/ts-interface-checker": { 1275 | "version": "0.1.13", 1276 | "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", 1277 | "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", 1278 | "dev": true 1279 | }, 1280 | "node_modules/undefsafe": { 1281 | "version": "2.0.5", 1282 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", 1283 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", 1284 | "dev": true 1285 | }, 1286 | "node_modules/util-deprecate": { 1287 | "version": "1.0.2", 1288 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1289 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", 1290 | "dev": true 1291 | }, 1292 | "node_modules/wrappy": { 1293 | "version": "1.0.2", 1294 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1295 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", 1296 | "dev": true 1297 | }, 1298 | "node_modules/yallist": { 1299 | "version": "4.0.0", 1300 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1301 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", 1302 | "dev": true 1303 | }, 1304 | "node_modules/yaml": { 1305 | "version": "2.3.2", 1306 | "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.2.tgz", 1307 | "integrity": "sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==", 1308 | "dev": true, 1309 | "engines": { 1310 | "node": ">= 14" 1311 | } 1312 | } 1313 | } 1314 | } 1315 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sci", 3 | "version": "1.0.0", 4 | "description": "Software Carbon Intensity (SCI) Specification", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "node assets/js/compile.js && tailwindcss -o assets/css/styles.css", 9 | "dev": "nodemon -e md,js --exec \"npm run build\"" 10 | }, 11 | "devDependencies": { 12 | "@tailwindcss/typography": "^0.5.10", 13 | "gray-matter": "^4.0.3", 14 | "marked": "^9.0.0", 15 | "nodemon": "^3.0.1", 16 | "tailwindcss": "^3.3.3" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: ["./index.html"], 4 | theme: { 5 | extend: { 6 | colors: { 7 | primary: { 8 | "darkest-2": "#002625", 9 | darkest: "#002c2a", 10 | darker: "#003734", 11 | dark: "#00524f", 12 | default: "#006d69", 13 | light: "#80b6b4", 14 | lighter: "#bfdbd9", 15 | "lightest-2": "#e5f0f0", 16 | "lightest-1": "#f2f8f7", 17 | }, 18 | accent: { 19 | darker: "#576629", 20 | dark: "#83993e", 21 | default: "#aecc53", 22 | light: "#d7e6a9", 23 | lighter: "#ebf2d4", 24 | "lightest-2": "#f7faee", 25 | "lightest-1": "#fbfcf6", 26 | }, 27 | }, 28 | }, 29 | }, 30 | plugins: [require("@tailwindcss/typography")], 31 | }; 32 | --------------------------------------------------------------------------------